# HappyTorch grades your PyTorch code by running it, in a namespace it had to grow

> A self-hosted practice platform with 36 problems from ReLU to RLHF, a LeetCode-style Monaco editor and a Jupyter mode, auto-grading by execution rather than by comparison. The changelog is the interesting part: it records a namespace that had to be widened, a suffix matcher that had to be replaced, and a 60 second ceiling on a submission.

**Rivflyyy/HappyTorch** — A PyTorch coding practice platform — covering LLM, Diffusion, PEFT, and more  A friendly environment to help you deeply understand deep learning components through hands-on practice.  Like LeetCode, but for tensors. Self-hosted. Supports both Jupyter and Web interfaces. 

- Repository: https://github.com/Rivflyyy/HappyTorch
- Stars: 463 · Forks: 26
- Language: Jupyter Notebook
- License: MIT
- Published: 2026-09-10 · Updated: 2026-09-10 · Language: en
- Canonical page: https://hysenlabs.com/projects/rivflyyy-happytorch

## Grading runs your code, so the execution namespace is the real specification

Auto-grading here means executing your solution and comparing behaviour, which is the only way to grade a class that has to be constructed. That has a consequence, and the changelog documents it directly. On 2026-03-10 class-based tasks, including LoRA and SwiGLU, were fixed to work correctly, and in the same entry `nn`, `F`, `numpy` and `math` were added to the execution namespace.

Read that as a specification rather than a bug fix. Your code is not diffed against a reference, it is run in a prepared namespace, and anything you reference has to be in that namespace or your submission fails before it is judged. A problem expecting you to write `SwiGLU` as a class will not work until the harness gives you `torch.nn`, and it did not until March.

The same entry records a 60 second request timeout, which is the boundary on what you can submit. A hand-written forward and backward pass over a toy tensor fits comfortably. A training loop that is slow enough to teach you something does not, which is why the MLP XOR contribution from the same day is specified as pure NumPy with a manual forward and backward rather than as a PyTorch training run.

## The notebook matcher was suffix-based until someone reported attention vs multihead_attention

On 2026-03-16 a contributor reported the notebook matching bug, named precisely as attention versus multihead_attention, and the fix was to replace fragile suffix-based matching with an explicit name mapping for long-term reliability.

This is the part of the project that explains its shape. Notebooks are prepared from the problems, reference solutions live in `solutions/`, and a solution has to line up with the right problem. Suffix matching meant a notebook for one problem could be paired with the wrong solution, and the failure was silent and confusing: your code runs, it just gets graded against something else. An explicit mapping is more work to maintain and fails loudly instead.

Two things follow for anyone using it. Function names in the problem tables are exact, so `my_softmax`, `rms_norm`, `sliding_window_attention` and `linear_attention` are the names your solution has to expose. And the existence of `prepare_notebooks.py` as a separate step in the quick start is not ceremony; it is the script that reconciles the problems, the notebooks and the solutions, and it is why skipping it produces a broken environment rather than a slightly wrong one.

## Problem numbers run across categories, and every difficulty cell is empty

The problem set is 36 items, and reading the tables closely shows two things about how the set was assembled.

First, the numbering is global rather than per section, which is why the order looks wrong. Fundamentals lists 1, 2, 3, 4, 7 and 8, skipping 5 and 6, because those two are attention problems listed in the section below it. Attention then runs 5, 6 and continues 9 through 12. Full Architecture has 13, the GPT-2 block, and the sections marked V2 for modern activations and parameter-efficient fine-tuning pick up from 14. So the numbers are a stable identifier, and a category is a filter rather than a range.

Second, every Difficulty column in every table is blank. The column exists and nothing populates it, which removes the one signal that would help a beginner decide whether to start with ReLU or with grouped query attention. Ordering is the only guide available.

The spread is respectable for a set this size. Fundamentals has ReLU, softmax with its numerical stability tricks, a linear layer with Kaiming initialisation and `nn.Parameter`, BatchNorm and RMSNorm. Attention has scaled dot-product, multi-head, causal, grouped query with KV sharing, sliding window and linear attention via the kernel trick. Then the GPT-2 block, GELU, SiLU, SwiGLU, and LoRA as a low-rank BA with zero-initialised B and alpha over r scaling.

## The Docker image runs as uid 1000 and mounts one directory for progress

The container is the recommended path and it is small enough to read in full. The base is `python:3.11-slim`, a user is created with `useradd -m -u 1000 user`, and the image installs the CPU build of torch from the PyTorch wheel index together with jupyterlab 4 or newer, numpy, fastapi 0.104 or newer, uvicorn 0.24 or newer and python-multipart. The `torch_judge` package is installed with `pip install -e .`, the application code and templates and solutions are copied in, `entrypoint.sh` is made executable, and the container switches to the unprivileged user with `MODE=web` and port 8000 exposed.

The compose file maps 8000, sets `MODE=web` and `HOST=0.0.0.0`, mounts `./data` at `/app/data`, and asks for a restart unless stopped. That single volume is the only persistent thing, and it holds `data/progress.json`.

So the whole state of a learner's progress is one JSON file in a bind mount, and the two modes are the same image with a different `MODE`: `docker compose up -d` for the web UI on 8000, and `MODE=jupyter docker compose up -d` for JupyterLab on 8888 through a second compose file.

## make push calls docker even on a machine where make run calls podman

The Makefile opens with a compatibility line that picks `podman compose` when podman is on PATH and `docker compose` otherwise, stored in a variable used by `run`, `stop`, `clean` and `jupyter`. Then the `push` target ignores that variable entirely and calls `docker build` and `docker push` directly.

On a podman-only machine, `make run` works and `make push` does not. That is a small inconsistency rather than a design problem, and it is the kind of thing you find by reading the file instead of following the documentation.

Two more details from the same file. The `clean` target runs `compose down -v` and then deletes `data/progress.json`, so it removes progress along with the containers, which is worth knowing before running it by reflex. And the image tag is `:latest` in both the Makefile and the compose file, with no versioned tags, so the published image and the checkout are not tied to a release and the repository has no GitHub releases either.

## The installed package is torch_judge 0.2.0, and three files disagree on the Python version

The naming is a small trap. The project is HappyTorch, the directory is `torch_judge/`, the Docker image is `ghcr.io/rivflyyy/happytorch`, and `setup.py` declares `name="torch_judge"` at version 0.2.0 with `python_requires=">=3.10"`. So after `pip install -e .` you have a package called `torch_judge` installed, and the import name in your solutions is not `happytorch`.

Three places state a Python version and they do not agree exactly. `setup.py` says 3.10 or newer, the quick start creates a conda environment with 3.11, and the Dockerfile is built on `python:3.11-slim`. Those are consistent enough to ignore, but if you are pinning a base image for a classroom, 3.11 is the one both the quick start and the container use.

What is worth doing is following the quick start in order, because the third step is the one that prepares the notebooks and the fourth is the one that starts a server:

```bash
# 3. Prepare notebooks
python prepare_notebooks.py

# 4a. Launch Web Mode (recommended)
pip install fastapi uvicorn python-multipart
python start_web.py
# Open http://localhost:8000
```

Jupyter mode is `python start_jupyter.py` on port 8888. The web UI is the one with the Monaco editor, random or sequential problem order, one-click testing with Ctrl+Enter, a solution tab, a progress dashboard and dark theme.

## An online instance exists, and a plugin was released for editors

Since 2026-04-03 there has been an online instance at `happytorch.wavetao.top`, reachable without installation. That is the cheapest way to try the problem set, and it also means the graded exercise is available to anyone rather than only to whoever self-hosts it.

A companion plugin, `happytorch-plugin`, was released on 2026-03-06, which suggests the intent is to reach the problem set from inside a coding agent or editor rather than through the web page.

Worth separating from that is the difference against the tool the project names as its model. LeetCode grades algorithm submissions against hidden test cases on a hosted service with a points economy. This platform executes PyTorch modules you write from a paper, hands you hints instead of solutions, keeps the reference solutions for afterwards, and stores your progress in a JSON file on your own disk. The trade is the one the README states plainly: no GPU required, self-hosted, and a set of 36 drills rather than a track with levels.

Licence is MIT, and the last push to the repository was 2026-05-27.

## Conclusion

Adopt HappyTorch if you are preparing for interviews that ask you to write Transformer components from scratch and want graded feedback without a GPU, since the CPU wheel install and the Docker image make it a laptop project. Do not adopt it as a curriculum: 36 problems is a set of drills, and the difficulty column in every problem table is empty, so nothing tells you where to start. Verify three things before you submit anything: that your function name matches exactly, because the notebook matcher was rewritten from suffix matching to an explicit mapping after a bug report, that your code only uses names in the execution namespace, which is `nn`, `F`, `numpy` and `math`, and that your solution runs inside the 60 second request timeout. Licence is MIT, the installed package is `torch_judge` 0.2.0, and the last push was 2026-05-27.

## FAQ

### What is HappyTorch?

It is a self-hosted PyTorch practice platform with 36 curated problems covering fundamentals, attention mechanisms, full architecture, modern activations, parameter-efficient fine-tuning, diffusion and RLHF. It offers a LeetCode-style web UI built on the Monaco editor and a Jupyter mode, with auto-grading, hints, reference solutions and progress tracking.

### Do I need a GPU to use HappyTorch?

No. The README states that no GPU is required, and the quick start installs torch from the CPU wheel index at `https://download.pytorch.org/whl/cpu`. The Docker image does the same on a `python:3.11-slim` base.

### How do I run HappyTorch locally?

Create a conda environment with Python 3.11, install the CPU torch wheel plus jupyterlab and numpy, run `pip install -e .`, then `python prepare_notebooks.py` before starting an interface. Web mode is `python start_web.py` on port 8000 after adding fastapi, uvicorn and python-multipart, and Jupyter mode is `python start_jupyter.py` on port 8888. Docker offers `docker compose up -d` or `MODE=jupyter docker compose up -d`.

### How does HappyTorch grade my code?

By running it. The execution namespace was extended with `nn`, `F`, `numpy` and `math` so class-based tasks such as LoRA and SwiGLU work, and a 60 second request timeout bounds each submission. Function names must match exactly, since suffix-based notebook matching was replaced with an explicit name mapping in March 2026.

### Where is HappyTorch progress stored?

In `data/progress.json`, which the Docker compose file persists through a bind mount of `./data` at `/app/data`. The Makefile's `clean` target runs `compose down -v` and deletes that file, so it removes progress as well as containers.

### What licence and version does HappyTorch use?

MIT. The installed Python package is named `torch_judge` at version 0.2.0 with `python_requires` of 3.10 or newer, the image is published as `ghcr.io/rivflyyy/happytorch:latest`, there are no GitHub releases, and the last push was 2026-05-27. An online instance is also available at happytorch.wavetao.top.

## Sources

- [Issues](https://github.com/Rivflyyy/HappyTorch/issues)
- [License: MIT](https://github.com/Rivflyyy/HappyTorch/blob/main/LICENSE)
- [README](https://github.com/Rivflyyy/HappyTorch/blob/main/README.md)
- [Rivflyyy/HappyTorch on GitHub](https://github.com/Rivflyyy/HappyTorch)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/rivflyyy-happytorch
