Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ Practice implementing operators and architectures from scratch — the exact ski

[![GitHub Container Registry](https://img.shields.io/badge/ghcr.io-TorchCode-blue?style=flat-square&logo=github)](https://ghcr.io/duoan/torchcode)
[![Hugging Face Spaces](https://img.shields.io/badge/%F0%9F%A4%97%20Spaces-TorchCode-blue?style=flat-square)](https://huggingface.co/spaces/duoan/TorchCode)
![Problems](https://img.shields.io/badge/problems-39-orange?style=flat-square)
![Problems](https://img.shields.io/badge/problems-40-orange?style=flat-square)
![GPU](https://img.shields.io/badge/GPU-not%20required-brightgreen?style=flat-square)

</div>
Expand Down Expand Up @@ -97,6 +97,7 @@ The bread and butter of ML coding interviews. You'll be asked to write these wit
| 20 | <a href="https://github.com/duoan/TorchCode/blob/master/templates/20_weight_init.ipynb" target="_blank">Kaiming Init</a> <a href="https://colab.research.google.com/github/duoan/TorchCode/blob/master/templates/20_weight_init.ipynb" target="_blank"><img src="https://colab.research.google.com/assets/colab-badge.svg" alt="Open In Colab" height="20"></a> | `kaiming_init(weight)` | ![Easy](https://img.shields.io/badge/Easy-4CAF50?style=flat-square) | ⭐ | `std = sqrt(2/fan_in)`, variance scaling |
| 21 | <a href="https://github.com/duoan/TorchCode/blob/master/templates/21_gradient_clipping.ipynb" target="_blank">Gradient Clipping</a> <a href="https://colab.research.google.com/github/duoan/TorchCode/blob/master/templates/21_gradient_clipping.ipynb" target="_blank"><img src="https://colab.research.google.com/assets/colab-badge.svg" alt="Open In Colab" height="20"></a> | `clip_grad_norm(params, max_norm)` | ![Easy](https://img.shields.io/badge/Easy-4CAF50?style=flat-square) | ⭐ | Norm-based clipping, direction preservation |
| 31 | <a href="https://github.com/duoan/TorchCode/blob/master/templates/31_gradient_accumulation.ipynb" target="_blank">Gradient Accumulation</a> <a href="https://colab.research.google.com/github/duoan/TorchCode/blob/master/templates/31_gradient_accumulation.ipynb" target="_blank"><img src="https://colab.research.google.com/assets/colab-badge.svg" alt="Open In Colab" height="20"></a> | `accumulated_step(model, opt, ...)` | ![Easy](https://img.shields.io/badge/Easy-4CAF50?style=flat-square) | 💡 | Micro-batching, loss scaling |
| 40 | <a href="https://github.com/duoan/TorchCode/blob/master/templates/40_linear_regression.ipynb" target="_blank">Linear Regression</a> <a href="https://colab.research.google.com/github/duoan/TorchCode/blob/master/templates/40_linear_regression.ipynb" target="_blank"><img src="https://colab.research.google.com/assets/colab-badge.svg" alt="Open In Colab" height="20"></a> | `LinearRegression` (3 methods) | ![Medium](https://img.shields.io/badge/Medium-FF9800?style=flat-square) | 🔥 | Normal equation, GD from scratch, nn.Linear |
| 3 | <a href="https://github.com/duoan/TorchCode/blob/master/templates/03_linear.ipynb" target="_blank">Linear Layer</a> <a href="https://colab.research.google.com/github/duoan/TorchCode/blob/master/templates/03_linear.ipynb" target="_blank"><img src="https://colab.research.google.com/assets/colab-badge.svg" alt="Open In Colab" height="20"></a> | `SimpleLinear` (nn.Module) | ![Medium](https://img.shields.io/badge/Medium-FF9800?style=flat-square) | 🔥 | `y = xW^T + b`, Kaiming init, `nn.Parameter` |
| 4 | <a href="https://github.com/duoan/TorchCode/blob/master/templates/04_layernorm.ipynb" target="_blank">LayerNorm</a> <a href="https://colab.research.google.com/github/duoan/TorchCode/blob/master/templates/04_layernorm.ipynb" target="_blank"><img src="https://colab.research.google.com/assets/colab-badge.svg" alt="Open In Colab" height="20"></a> | `my_layer_norm(x, γ, β)` | ![Medium](https://img.shields.io/badge/Medium-FF9800?style=flat-square) | 🔥 | Normalization, running stats, affine transform |
| 7 | <a href="https://github.com/duoan/TorchCode/blob/master/templates/07_batchnorm.ipynb" target="_blank">BatchNorm</a> <a href="https://colab.research.google.com/github/duoan/TorchCode/blob/master/templates/07_batchnorm.ipynb" target="_blank"><img src="https://colab.research.google.com/assets/colab-badge.svg" alt="Open In Colab" height="20"></a> | `my_batch_norm(x, γ, β)` | ![Medium](https://img.shields.io/badge/Medium-FF9800?style=flat-square) | ⭐ | Batch vs layer statistics, train/eval behavior |
Expand Down
125 changes: 125 additions & 0 deletions solutions/40_linear_regression_solution.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# 🟡 Solution: Linear Regression\n",
"\n",
"Reference solution demonstrating closed-form, gradient descent, and nn.Linear approaches."
]
},
{
"cell_type": "code",
"metadata": {},
"outputs": [],
"source": [
"import torch\n",
"import torch.nn as nn"
],
"execution_count": null
},
{
"cell_type": "code",
"metadata": {},
"outputs": [],
"source": [
"# ✅ SOLUTION\n",
"\n",
"class LinearRegression:\n",
" def closed_form(self, X: torch.Tensor, y: torch.Tensor):\n",
" \"\"\"Normal equation via augmented matrix.\"\"\"\n",
" N, D = X.shape\n",
" # Augment X with ones column for bias\n",
" X_aug = torch.cat([X, torch.ones(N, 1)], dim=1) # (N, D+1)\n",
" # Solve (X^T X) theta = X^T y\n",
" theta = torch.linalg.lstsq(X_aug, y).solution # (D+1,)\n",
" w = theta[:D]\n",
" b = theta[D]\n",
" return w.detach(), b.detach()\n",
"\n",
" def gradient_descent(self, X: torch.Tensor, y: torch.Tensor,\n",
" lr: float = 0.01, steps: int = 1000):\n",
" \"\"\"Manual gradient computation — no autograd.\"\"\"\n",
" N, D = X.shape\n",
" w = torch.zeros(D)\n",
" b = torch.tensor(0.0)\n",
"\n",
" for _ in range(steps):\n",
" pred = X @ w + b # (N,)\n",
" error = pred - y # (N,)\n",
" grad_w = (2.0 / N) * (X.T @ error) # (D,)\n",
" grad_b = (2.0 / N) * error.sum() # scalar\n",
" w = w - lr * grad_w\n",
" b = b - lr * grad_b\n",
"\n",
" return w, b\n",
"\n",
" def nn_linear(self, X: torch.Tensor, y: torch.Tensor,\n",
" lr: float = 0.01, steps: int = 1000):\n",
" \"\"\"PyTorch nn.Linear with autograd training loop.\"\"\"\n",
" N, D = X.shape\n",
" layer = nn.Linear(D, 1)\n",
" optimizer = torch.optim.SGD(layer.parameters(), lr=lr)\n",
" loss_fn = nn.MSELoss()\n",
"\n",
" for _ in range(steps):\n",
" optimizer.zero_grad()\n",
" pred = layer(X).squeeze(-1) # (N,)\n",
" loss = loss_fn(pred, y)\n",
" loss.backward()\n",
" optimizer.step()\n",
"\n",
" w = layer.weight.data.squeeze(0) # (D,)\n",
" b = layer.bias.data.squeeze(0) # scalar ()\n",
" return w, b"
],
"execution_count": null
},
{
"cell_type": "code",
"metadata": {},
"outputs": [],
"source": [
"# Verify\n",
"torch.manual_seed(42)\n",
"X = torch.randn(100, 3)\n",
"true_w = torch.tensor([2.0, -1.0, 0.5])\n",
"y = X @ true_w + 3.0\n",
"\n",
"model = LinearRegression()\n",
"for name, method in [(\"Closed-form\", model.closed_form),\n",
" (\"Grad Descent\", lambda X, y: model.gradient_descent(X, y, lr=0.05, steps=2000)),\n",
" (\"nn.Linear\", lambda X, y: model.nn_linear(X, y, lr=0.05, steps=2000))]:\n",
" w, b = method(X, y)\n",
" print(f\"{name:13s} w={w.tolist()} b={b.item():.4f}\")\n",
"print(f\"{'True':13s} w={true_w.tolist()} b=3.0000\")"
],
"execution_count": null
},
{
"cell_type": "code",
"metadata": {},
"outputs": [],
"source": [
"# ✅ SUBMIT\n",
"from torch_judge import check\n",
"check(\"linear_regression\")"
],
"execution_count": null
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"name": "python",
"version": "3.11.0"
}
},
"nbformat": 4,
"nbformat_minor": 4
}
Loading