Install to Claude Code
npx -y skills add https://github.com/aradotso/trending-skills --skill pyre-code-ml-practiceDescription
pyre code ml practice
SKILL.md
---
name: pyre-code-ml-practice
description: Self-hosted ML coding practice platform with 68 problems covering Transformers, diffusion, RLHF, and more — instant browser feedback, no GPU required.
triggers:
- "set up pyre code practice platform"
- "add a new ml coding problem to pyre"
- "how do I run the grading service"
- "configure AI help for pyre code"
- "pyre code problem set and learning paths"
- "implement a coding challenge in pyre"
- "troubleshoot pyre code submission grading"
- "deploy pyre code with docker"
---
# Pyre Code ML Practice Platform
> Skill by [ara.so](https://ara.so) — Daily 2026 Skills collection.
Pyre Code is a self-hosted ML coding practice platform with 68 problems ranging from ReLU to flow matching. Users implement internals of modern AI systems (Transformers, vLLM, TRL, diffusion models) in a browser editor with instant pass/fail feedback, no GPU required.
---
## Installation
### Option A — One-liner (recommended)
```bash
git clone https://github.com/whwangovo/pyre-code.git
cd pyre-code
./setup.sh
npm run dev
```
`setup.sh` creates a `.venv` (prefers `uv`, falls back to `python3 -m venv`), installs all Python deps, then prints the start command.
### Option B — Conda
```bash
git clone https://github.com/whwangovo/pyre-code.git
cd pyre-code
conda create -n pyre python=3.11 -y && conda activate pyre
pip install -e ".[dev]"
npm install
npm run dev
```
### Option C — Docker
```bash
git clone https://github.com/whwangovo/pyre-code.git
cd pyre-code
docker compose up --build
```
Progress persists in a Docker volume. Reset with `docker compose down -v`.
### After installation
- **Grading service**: `http://localhost:8000`
- **Web app**: `http://localhost:3000`
---
## Project Structure
```
pyre/
├── web/ # Next.js frontend
│ ├── src/app/ # Pages and API routes
│ ├── src/components/ # UI components
│ └── src/lib/ # Utilities, problem data
├── grading_service/ # FastAPI backend (grading API)
├── torch_judge/ # Judge engine — problem definitions + test runner
│ ├── problems/ # Individual problem modules
│ └── runner.py # Test execution logic
├── setup.sh # Environment bootstrap script
├── package.json # Dev scripts (runs frontend + backend concurrently)
└── pyproject.toml # Python package config
```
---
## Key Commands
```bash
# Start both frontend and backend concurrently
npm run dev
# Start only the grading service (FastAPI)
cd grading_service && uvicorn main:app --reload --port 8000
# Start only the frontend (Next.js)
cd web && npm run dev
# Run Python tests
pytest torch_judge/
# Install Python package in editable mode with dev deps
pip install -e ".[dev]"
# Docker: build and start
docker compose up --build
# Docker: stop and remove volumes (reset progress)
docker compose down -v
```
---
## Configuration
### Environment Variables
Create `web/.env.local` to override defaults:
```bash
# URL of the FastAPI grading service
GRADING_SERVICE_URL=http://localhost:8000
# SQLite database path for progress tracking
DB_PATH=./data/pyre.db
```
### AI Help (Optional)
Copy `web/.env.example` to `web/.env` and configure:
```bash
AI_HELP_BASE_URL=https://api.openai.com/v1
AI_HELP_API_KEY=$OPENAI_API_KEY
AI_HELP_MODEL=gpt-4o-mini
```
Any OpenAI-compatible endpoint works: OpenAI, Anthropic via proxy, Ollama, etc. Users can also set their own key in the UI if no server-side config is present.
---
## Problem Categories
| Category | Examples |
|---|---|
| **Fundamentals** | ReLU, Softmax, GELU, SwiGLU, Dropout, Embedding, Linear, Kaiming Init |
| **Normalization** | LayerNorm, BatchNorm, RMSNorm |
| **Attention** | Scaled Dot-Product, Multi-Head, Causal, GQA, Flash, Differential, MLA |
| **Position Encoding** | Sinusoidal PE, RoPE, ALiBi, NTK-aware RoPE |
| **Architecture** | GPT-2 Block, ViT Block, Conv2D, MoE, Depthwise Conv |
| **Training** | Adam, Cosine LR, Gradient Clipping, Mixed Precision, Activation Checkpointing |
| **Distributed** | Tensor Parallel, FSDP, Ring Attention |
| **Inference** | KV Cache, Top-k Sampling, Beam Search, Speculative Decoding, Paged Attention |
| **Alignment** | DPO, GRPO, PPO, Reward Model |
| **Diffusion** | Noise Schedule, DDIM Step, Flow Matching, adaLN-Zero |
| **Adaptation** | LoRA, QLoRA |
| **Reasoning** | MCTS, Multi-Token Prediction |
| **SSM** | Mamba SSM |
---
## Adding a New Problem
Problems live in `torch_judge/problems/`. Each problem is a Python module with a standard structure:
```python
# torch_judge/problems/my_new_problem.py
import torch
import torch.nn as nn
from typing import Any
PROBLEM_ID = "my_new_problem"
TITLE = "My New Problem: Implement Foo"
DIFFICULTY = "medium" # "easy" | "medium" | "hard"
CATEGORY = "Fundamentals"
DESCRIPTION = """
## My New Problem
Implement the `foo` function that does XYZ.
### Input
- `x` (Tensor): shape `(batch, dim)`
### Output
- Tensor of shape `(batch, dim)`
### Formula
$$\\text{foo}(x) = x^2 + 1$$
"""
STARTER_CODE = """
import torch
def foo(x: torch.Tensor) -> torch.Tensor:
# Your implementation here
pass
"""
REFERENCE_SOLUTION = """
import torch
def foo(x: torch.Tensor) -> torch.Tensor:
return x ** 2 + 1
"""
def make_test_cases() -> list[dict[str, Any]]:
\"\"\"Return a list of test cases, each with inputs and expected outputs.\"\"\"
cases = []
# Basic case
x = torch.tensor([[1.0, 2.0, 3.0]])
cases.append({
"input": {"x": x},
"expected": x ** 2 + 1,
"description": "Basic 1x3 tensor",
})
# Batch case
x = torch.randn(4, 16)
cases.append({
"input": {"x": x},
"expected": x ** 2 + 1,
"description": "Batch of 4, dim 16",
})
# Edge case: zeros
x = torch.zeros(2, 8)
cases.append({
"input": {"x": x},
"expected": torch.ones(2, 8),
"description": "Zero tensor",
})
return cases
def grade(submission_code: str) -> dict[str, Any]:
\"\"\"Execute submission and return grading results.\"\"\"
namespace = {}
exec(submission_code, namespace)
if "foo" not in namespace:
return {"passed": 0, "total": 0, "error": "Function 'foo' not found"}
fn = namespace["foo"]
test_cases = make_test_cases()
results = []
for i, case in enumerate(test_cases):
try:
output = fn(**case["input"])
passed = torch.allclose(output, case["expected"], atol=1e-5)
results.append({
"case": i + 1,
"description": case["description"],
"passed": passed,
"error": None if passed else f"Output mismatch: got {output}, expected {case['expected']}",
})
except Exception as e:
results.append({
"case": i + 1,
"description": case["description"],
"passed": False,
"error": str(e),
})
passed = sum(r["passed"] for r in results)
return {
"passed": passed,
"total": len(results),
"results": results,
}
```
### Register the problem
After creating the module, register it in the problem registry (typically `torch_judge/registry.py` or equivalent):
```python
from torch_judge.problems import my_new_problem
PROBLEMS = [
# ... existing problems ...
my_new_problem,
]
```
---
## Grading Service API
The FastAPI grading service at `http://localhost:8000` exposes:
```bash
# Health check
GET /health
# List all problems
GET /problems
# Get a specific problem
GET /problems/{problem_id}
# Submit a solution
POST /submit
Content-Type: application/json
{
"problem_id": "relu",
"code": "import torch\n\ndef relu(x):\n return torch.clamp(x, min=0)"
}
# Response
{
"problem_id": "relu",
"passed": 3,
"total": 3,
"results": [
{"case": 1, "description": "Basic positive values", "passed": true, "error": null},
{"case": 2, "description": "Negative values", "passed": true, "error": null},
{"case": 3, "description": "Mixed values", "passed": true, "error": null}
]
}
```
### Calling the grading API from Python
```python
import requests
response = requests.post(
"http://localhost:8000/submit",
json={
"problem_id": "softmax",
"code": """
import torch
def softmax(x: torch.Tensor, dim: int = -1) -> torch.Tensor:
x_max = x.max(dim=dim, keepdim=True).values
x_exp = torch.exp(x - x_max)
return x_exp / x_exp.sum(dim=dim, keepdim=True)
"""
}
)
result = response.json()
print(f"Passed {result['passed']}/{result['total']} test cases")
for r in result["results"]:
status = "✓" if r["passed"] else "✗"
print(f" {status} Case {r['case']}: {r['description']}")
if r["error"]:
print(f" Error: {r['error']}")
```
---
## Example Implementations
### Scaled Dot-Product Attention
```python
import torch
import torch.nn.functional as F
import math
def scaled_dot_product_attention(
q: torch.Tensor, # (batch, heads, seq, d_k)
k: torch.Tensor,
v: torch.Tensor,
mask: torch.Tensor | None = None,
) -> torch.Tensor:
d_k = q.size(-1)
scores = torch.matmul(q, k.transpose(-2, -1)) / math.sqrt(d_k)
if mask is not None:
scores = scores.masked_fill(mask == 0, float('-inf'))
weights = F.softmax(scores, dim=-1)
return torch.matmul(weights, v)
```
### RMSNorm
```python
import torch
def rms_norm(x: torch.Tensor, weight: torch.Tensor, eps: float = 1e-6) -> torch.Tensor:
rms = x.pow(2).mean(dim=-1, keepdim=True).add(eps).sqrt()
return x / rms * weight
```
### LoRA Linear Layer
```python
import torch
import torch.nn as nn
class LoRALinear(nn.Module):
def __init__(self, in_features: int, out_features: int, rank: int = 4, alpha: float = 1.0):
super().__init__()
self.weight = nn.Parameter(torch.randn(out_features, in_features) * 0.02)
self.lora_A = nn.Parameter(torch.randn(rank, in_features) * 0.02)
self.lora_B = nn.Parameter(torch.zeros(out_features, rank))
self.scale = alpha / rank
def forward(self, x: torch.Tensor) -> torch.Tensor:
base = x @ self.weight.T
lora = x @ self.lora_A.T @ self.lora_B.T
return base + self.scale * lora
```
### Cosine Learning Rate Schedule
```python
import math
def cosine_lr(step: int, max_steps: int, lr_max: float, lr_min: float = 0.0) -> float:
if step >= max_steps:
return lr_min
progress = step / max_steps
return lr_min + 0.5 * (lr_max - lr_min) * (1 + math.cos(math.pi * progress))
```
### KV Cache (Inference)
```python
import torch
from dataclasses import dataclass, field
@dataclass
class KVCache:
keys: list[torch.Tensor] = field(default_factory=list)
values: list[torch.Tensor] = field(default_factory=list)
def update(self, new_k: torch.Tensor, new_v: torch.Tensor):
self.keys.append(new_k)
self.values.append(new_v)
def get(self) -> tuple[torch.Tensor, torch.Tensor]:
return torch.cat(self.keys, dim=-2), torch.cat(self.values, dim=-2)
def __len__(self) -> int:
return len(self.keys)
```
---
## Learning Paths
Choose a path based on your goal:
| Path | Focus |
|---|---|
| **Transformer Internals** | Activations → Normalization → Attention → GPT-2 Block |
| **Attention & Position Encoding** | Every attention variant + RoPE, ALiBi, NTK-RoPE |
| **Train a GPT from Scratch** | Embeddings → architecture → loss → optimizer → tricks |
| **Inference & Distributed** | KV cache, quantization, sampling, tensor parallel, FSDP |
| **Alignment & Reasoning** | Reward model → DPO → GRPO → PPO → MCTS |
| **Vision Transformer** | Conv → patch embedding → ViT block |
| **Diffusion & DiT** | Noise schedule → DDIM → flow matching → adaLN-Zero |
| **LLM Frontier Architectures** | GQA, Differential Attention, MLA, MoE, MTP |
Recommended progression:
```
Fundamentals → Transformer Internals → Train a GPT from Scratch
│ │
▼ ▼
Attention & PE Inference & Distributed
│ │
▼ ▼
LLM Frontier Archs Alignment & Reasoning
```
---
## Troubleshooting
### Grading service not reachable
```bash
# Check if the service is running
curl http://localhost:8000/health
# If not, start it manually
cd grading_service
source ../.venv/bin/activate
uvicorn main:app --reload --port 8000
```
### Python environment issues
```bash
# Verify correct Python is active
which python && python --version # should be 3.11+
# Reinstall deps
pip install -e ".[dev]"
# With uv
uv pip install -e ".[dev]"
```
### Frontend can't connect to grading service
Check `web/.env.local`:
```bash
GRADING_SERVICE_URL=http://localhost:8000
```
Restart Next.js after changing `.env.local`.
### Docker: port conflicts
```bash
# Check what's on port 3000 or 8000
lsof -i :3000
lsof -i :8000
# Stop conflicting processes, then retry
docker compose up --build
```
### Submission always fails with import errors
Ensure the submission code only uses packages available in the environment. Core deps include `torch`, `numpy`, `math`. Check `pyproject.toml` for the full list.
### Progress not persisting
The SQLite DB lives at `./data/pyre.db` by default. For Docker, ensure the volume is mounted:
```yaml
# docker-compose.yml
volumes:
- pyre_data:/app/data
```
---
## Contributing a Problem
1. Create `torch_judge/problems/{problem_id}.py` using the structure above
2. Include `PROBLEM_ID`, `TITLE`, `DIFFICULTY`, `CATEGORY`, `DESCRIPTION`, `STARTER_CODE`, `REFERENCE_SOLUTION`, `make_test_cases()`, and `grade()`
3. Register in the problem registry
4. Write at least 3 test cases: basic, edge case, and a larger/random tensor case
5. Verify with `pytest torch_judge/` before opening a PR
6. Open an issue first for new categories or structural changes
