tests/test.sh exit code (0 → resolved); the classification below is post-hoc and cannot change it.List submission and app files
ls /app/submission/ && ls /app/
autograd.py data.py nn.py optim.py train.py PROMPT.txt agent.pid agent.stderr agent_trajectory.jsonl data run.log run_checks.py submission test.sh timer.sh
Count lines in submission files
wc -l /app/submission/*.py 2>/dev/null || echo "No py files found"
1381 /app/submission/autograd.py 42 /app/submission/data.py 869 /app/submission/nn.py 306 /app/submission/optim.py 64 /app/submission/train.py 2662 total
/app/submission/autograd.py
1 """Reverse-mode automatic differentiation over numpy arrays. 2 3 YOU MUST IMPLEMENT EVERYTHING MARKED ``# TODO`` / ``raise NotImplementedError`` using numpy 4 ONLY. No torch/jax/tensorflow/autograd/etc. The grader's conformance suite (a) differentiates the 5 differentiable ops below with central finite differences and compares against YOUR analytic 6 backward, and (b) checks the LSQ ``fake_quant`` STE + scale gradient against the reference 7 definition, so every backward must be correct (a single wrong reduction / STE / Jacobian fails 8 the gradient checks and zeroes the reward). 9 10 A ``Tensor`` wraps one ``numpy.ndarray`` (stored as ``float64`` in ``self.data``) and records the 11 op that produced it so ``.backward()`` can accumulate ``.grad`` into every leaf. 12 13 CONTRACT (the grader builds its own reference against this exact API): 14 * ``Tensor(data, requires_grad=False)`` -- ``self.data`` is ``float64``; ``self.grad`` is None 15 until backward, then a same-shape ``float64`` array. requires_grad leaves accumulate grad. 16 * Every op returns a NEW Tensor whose ``requires_grad`` is the OR of its differentiable inputs, 17 and whose ``_backward`` closure does ``input._accum(local_grad)`` (so multiple paths add up). 18 * ``t.backward(grad=None)`` -- seeds ``grad`` (all-ones for a scalar) and walks the graph in 19 reverse topological order, calling each node's ``_backward``. Repeated backward accumulates. 20 * BROADCASTING: binary ops broadcast like numpy; the ba …[truncated 54775 chars]
/app/submission/nn.py
1 """QAT layers + a small INT2 CNN, built on YOUR autograd engine.
2
3 Implement every ``# TODO`` forward (the parameters + ``named_params``/``buffers`` naming are
4 already wired for you; you compose the autograd ops). The grader checks each layer's forward
5 against its OWN reference AND finite-difference-checks the gradients that flow through your
6 autograd, so the composition must be exactly right.
7
8 CHECKPOINT NAMING CONTRACT (the grader loads YOUR ``qat_model.npz`` into its own reference
9 QuantCNN by these exact keys/shapes -- do not rename):
10 stem.conv.weight (W0,3,3,3) | stem.conv.wq.scale (1,) | stem.bn.gamma/.beta (W0,) | stem.aq.scale (1,)
11 blocks.{i}.conv.weight (Cout,Cin,3,3) | blocks.{i}.conv.wq.scale (1,)
12 blocks.{i}.bn.gamma/.beta (Cout,) | blocks.{i}.aq.scale (1,)
13 head.weight (Cfeat,n_classes) | head.wq.scale (1,) | head.bias (n_classes,)
14 BN running stats are BUFFERS (saved alongside params, NOT trained by the optimizer, NOT audited):
15 stem.bn.running_mean/.running_var (W0,) | blocks.{i}.bn.running_mean/.running_var (Cout,)
16
17 Quantization: every conv/head WEIGHT is LSQ-quantized to a signed 2-bit grid {-2,-1,0,1} via a
18 per-tensor learnable step before use; every block activation (post-relu) is LSQ-quantized to an
19 unsigned 2-bit grid {0,1,2,3}. Conv = 3x3 same-padding cross-correlation. Linear head = x@weight+bias.
20 """
21 from __future__ import annotations
22
23 from typing import Dict, List
24
25 import numpy as n
…[truncated 35167 chars]/app/submission/optim.py
1 """Optimizers over autograd ``Tensor`` parameters.
2
3 Implement the ``# TODO`` update math. Both optimizers update ``param.data`` IN PLACE using
4 ``param.grad``. The grader runs one (and several) steps and compares your updated params against
5 its reference within a tight tolerance, so the math must be exact.
6
7 SGD (with momentum ``mu`` and coupled weight decay ``wd``):
8 g = grad + wd * param; v = mu * v + g; param -= lr * v
9
10 AdamW (DECOUPLED weight decay -- the decay is applied to the PARAM, not folded into the moments):
11 m = b1*m + (1-b1)*g; v = b2*v + (1-b2)*g^2
12 mhat = m / (1 - b1^t); vhat = v / (1 - b2^t) # t = 1-based step count
13 param -= lr * ( mhat / (sqrt(vhat) + eps) + wd * param )
14
15 PARAM GROUPS: both optimizers must accept EITHER a flat param list OR a list of
16 ``{"params": [...], "weight_decay": wd}`` dicts, so weight decay can be applied to SOME params
17 and not others. This matters for low-bit LSQ QAT: the per-tensor quantizer ``scale`` params,
18 BatchNorm gamma/beta, and biases must be EXCLUDED from weight decay. ``_normalize_groups`` and
19 ``split_decay_params`` are provided; honour the per-group weight decay in ``step``.
20 """
21 from __future__ import annotations
22
23 import math
24
25 from typing import Dict, List
26
27 import numpy as np
28
29 from autograd import Tensor
30
31
32 def split_decay_params(model) -> Dict[str, List[Tensor]]:
33 """Partition a model's named params into weight
…[truncated 11129 chars]/app/submission/data.py
1 """Image data loading + normalization + batching.
2
3 The dataset is a procedurally-generated CIFAR-style set: ``X`` is ``uint8`` (N,3,S,S) in [0,255],
4 ``y`` is the integer class label in [0, n_classes). The shipped training split is at
5 ``/app/data/train.npz``; the SEALED held-out split is regenerated by the verifier (never shipped).
6
7 Implement the ``# TODO`` bodies (numpy only). The verifier normalizes the held-out split with the
8 SAME transform, so match it exactly.
9
10 Contract:
11 load_npz(path) -> (X uint8 (N,3,S,S), y int64 (N,)) [provided]
12 normalize(X) -> float64: x = (X/255 - 0.5) / 0.25 [per-channel, the grader's transform]
13 iter_minibatches(Xn, y, batch_size, rng, shuffle=True) -> yields (xb, yb)
14 """
15 from __future__ import annotations
16
17 from typing import Tuple
18
19 import numpy as np
20
21 NORM_MEAN = 0.5
22 NORM_STD = 0.25
23
24
25 def load_npz(path: str) -> Tuple[np.ndarray, np.ndarray]:
26 d = np.load(path)
27 X = np.asarray(d["X"]).astype(np.uint8)
28 y = np.asarray(d["y"]).astype(np.int64).reshape(-1)
29 return X, y
30
31
32 def normalize(X: np.ndarray) -> np.ndarray:
33 """uint8 (N,3,S,S) -> float64, x = (X/255 - NORM_MEAN) / NORM_STD."""
34 # TODO: cast to float, scale to [0,1], subtract NORM_MEAN, divide by NORM_STD.
35 raise NotImplementedError("normalize")
36
37
38 def iter_minibatches(Xn: np.ndarray, y: np.ndarray, batch_size: int,
39 rng: np.rando
…[truncated 281 chars]/app/submission/train.py
1 """Training entry point. Implement the QAT loop, train your INT2 CNN on /app/data/train.npz, and 2 SAVE the checkpoint to /app/submission/qat_model.npz (numpy .npz of the model state_dict: every 3 param + every BN running buffer, by the nn.QuantCNN naming contract). 4 5 The grader (verify.py) will: 6 (1) run the conformance suite over your autograd/nn/optim, 7 (2) BIT-AUDIT every conv/head weight tensor in your checkpoint to <= 4 distinct float values, 8 (3) load your weights into its OWN QuantCNN and score held-out top-1 on a SEALED split. 9 10 So at SAVE time you must BAKE the quantized weights back into each ``weight`` tensor (replace it 11 with round(clip(w/s, -W_NEG, W_POS)) * s using the learned wq.scale) so the saved weights already 12 lie on the 2-bit grid and pass the audit. Reaching the top-1 floor at INT-2 needs a real recipe: 13 sensible LSQ STEP-SIZE INITIALIZATION (a default scale of 1.0 quantizes the small init weights to 14 all-zeros -> a dead network at chance), per-tensor learnable scales, weight decay EXCLUDED from the 15 scale/BN/bias params, gradient clipping, a decaying LR, and enough epochs. Naive post-training 16 rounding or under-training lands at chance. 17 18 This file is a skeleton; the loop body is yours to write. 19 """ 20 from __future__ import annotations 21 22 import argparse 23 import os 24 import sys 25 26 import numpy as np 27 28 sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) 29 sys.path.insert(0, "/app") 30 3 …[truncated 1513 chars]
Read train.py and check data
ls /app/data/ && python3 -c "import numpy as np; d=np.load('/app/data/train.npz'); print(d['X'].shape, d['y'].shape, np.unique(d['y']))"train.npz (2500, 3, 16, 16) (2500,) [0 1 2 3 4 5 6 7 8 9]
{
"description": "Implement complete autograd.py with all backward functions",
"prompt": "\nYou need to implement a complete reverse-mode autodiff framework in `/app/submission/autograd.py`. The file has stubs with `raise NotImplementedError` for every backward function. You must fill in ALL of them plus add `batchnorm1d` (needed by nn.py but missing from the stubs).\n\nFirst read the current file to understand all the existing forward code and what needs backward implementations.\n\nKey rules:\n- numpy only (no torch/jax/etc.)\n- Every backward must call `parent._accum(local_grad)` to accumulate gradients\n- Broadcasting: binary ops use `_unbroadcast(grad, shape)` helper already in the file\n- The file is too large to rewrite in one bash command - use targeted Edit calls\n\nHere's the implementation plan for each backward:\n\n**Tensor.backward:**\n```python\ndef backward(self, grad=None):\n if grad is None:\n grad = np.ones_like(self.data)\n order = []\n visited = set()\n def topo(t):\n if id(t) not in visited:\n visited.add(id(t))\n for p in t._parents:\n topo(p)\n order.append(t)\n topo(self)\n self._accum(grad)\n for t in reversed(order):\n if t.grad is not None:\n t._backward()\n```\n\n**Binary ops (add, sub, mul, div, power, maximum, minimum, where):**\n- add: `a._accum(_unbroadcast(g, a.shape))`, `b._accum(_unbroadcast(g, b.shape))`\n- sub: `a._accum(_unbroadcast(g, a.shape))`, `b._accum(_unbroadcast(-g, b.shape))`\n- mul: `a._accum(_unbroadcast(g*b.data, a.shape))`, `b._accum(_unbroadcast(g*a\n…[truncated 15318 chars]"
}/app/submission/autograd.py
1 """Reverse-mode automatic differentiation over numpy arrays. 2 3 YOU MUST IMPLEMENT EVERYTHING MARKED ``# TODO`` / ``raise NotImplementedError`` using numpy 4 ONLY. No torch/jax/tensorflow/autograd/etc. The grader's conformance suite (a) differentiates the 5 differentiable ops below with central finite differences and compares against YOUR analytic 6 backward, and (b) checks the LSQ ``fake_quant`` STE + scale gradient against the reference 7 definition, so every backward must be correct (a single wrong reduction / STE / Jacobian fails 8 the gradient checks and zeroes the reward). 9 10 A ``Tensor`` wraps one ``numpy.ndarray`` (stored as ``float64`` in ``self.data``) and records the 11 op that produced it so ``.backward()`` can accumulate ``.grad`` into every leaf. 12 13 CONTRACT (the grader builds its own reference against this exact API): 14 * ``Tensor(data, requires_grad=False)`` -- ``self.data`` is ``float64``; ``self.grad`` is None 15 until backward, then a same-shape ``float64`` array. requires_grad leaves accumulate grad. 16 * Every op returns a NEW Tensor whose ``requires_grad`` is the OR of its differentiable inputs, 17 and whose ``_backward`` closure does ``input._accum(local_grad)`` (so multiple paths add up). 18 * ``t.backward(grad=None)`` -- seeds ``grad`` (all-ones for a scalar) and walks the graph in 19 reverse topological order, calling each node's ``_backward``. Repeated backward accumulates. 20 * BROADCASTING: binary ops broadcast like numpy; the ba …[truncated 3132 chars]
/app/submission/autograd.py
100
101 def __repr__(self):
102 return f"Tensor(shape={self.data.shape}, requires_grad={self.requires_grad})"
103
104
105 def _ensure(x) -> Tensor:
106 return x if isinstance(x, Tensor) else Tensor(x)
107
108
109 def _mk(data, parents, requires_grad) -> Tensor:
110 return Tensor(data, requires_grad=requires_grad, _parents=parents)
111
112
113 # ============================================================ element-wise binary (broadcasting)
114 def add(a, b) -> Tensor:
115 """out = a + b (numpy broadcasting). Backward: each input gets _unbroadcast(out.grad)."""
116 a, b = _ensure(a), _ensure(b)
117 out = _mk(a.data + b.data, (a, b), a.requires_grad or b.requires_grad)
118
119 def _bw():
120 raise NotImplementedError("add backward") # TODO
121
122 out._backward = _bw
123 return out
124
125
126 def sub(a, b) -> Tensor:
127 """out = a - b. Backward: a gets +grad, b gets -grad (both _unbroadcast)."""
128 a, b = _ensure(a), _ensure(b)
129 out = _mk(a.data - b.data, (a, b), a.requires_grad or b.requires_grad)
130
131 def _bw():
132 raise NotImplementedError("sub backward") # TODO
133
134 out._backward = _bw
135 return out
136
137
138 def mul(a, b) -> Tensor:
139 """out = a * b (elementwise). Backward: a gets grad*b, b gets grad*a (both _unbroadcast)."""
140 a, b = _ensure(a), _ensure(b)
141 out = _mk(a.data * b.data, (a, b), a.requires_grad or b.requires_grad)
142
143
…[truncated 4976 chars]/app/submission/autograd.py
299
300
301 def max(a, axis=None, keepdims=False) -> Tensor:
302 """Reduce-max over ``axis``. Backward routes the upstream grad to the argmax position(s);
303 on EXACT ties, split the grad equally among the tied maxima."""
304 a = _ensure(a)
305 out = _mk(a.data.max(axis=axis, keepdims=keepdims), (a,), a.requires_grad)
306
307 def _bw():
308 raise NotImplementedError("max backward") # TODO
309
310 out._backward = _bw
311 return out
312
313
314 def min(a, axis=None, keepdims=False) -> Tensor:
315 """Reduce-min over ``axis``. Backward routes grad to the argmin position(s) (ties split)."""
316 a = _ensure(a)
317 out = _mk(a.data.min(axis=axis, keepdims=keepdims), (a,), a.requires_grad)
318
319 def _bw():
320 raise NotImplementedError("min backward") # TODO
321
322 out._backward = _bw
323 return out
324
325
326 def concat(tensors, axis=0) -> Tensor:
327 """Concatenate Tensors along ``axis``. Backward splits out.grad back to each input (each input
328 receives the slice of out.grad covering its span along ``axis``)."""
329 ts = [_ensure(t) for t in tensors]
330 out = _mk(np.concatenate([t.data for t in ts], axis=axis), tuple(ts),
331 any(t.requires_grad for t in ts))
332
333 def _bw():
334 raise NotImplementedError("concat backward") # TODO
335
336 out._backward = _bw
337 return out
338
339
340 def stack(tensors, axis=0) -> Tensor:
341 """Stack
…[truncated 5329 chars]/app/submission/autograd.py
499
500
501 def log_softmax(a, axis=-1) -> Tensor:
502 """Stable log-softmax: z - logsumexp(z). Backward: grad - softmax * sum(grad, axis, keep)."""
503 a = _ensure(a)
504 z = a.data - a.data.max(axis=axis, keepdims=True)
505 with np.errstate(under="ignore"):
506 ls = z - np.log(np.exp(z).sum(axis=axis, keepdims=True))
507 out = _mk(ls, (a,), a.requires_grad)
508
509 def _bw():
510 raise NotImplementedError("log_softmax backward") # TODO
511
512 out._backward = _bw
513 return out
514
515
516 # ============================================================ loss
517 def cross_entropy(logits, targets) -> Tensor:
518 """Mean cross-entropy over a batch. ``logits``: (N, C). ``targets``: int (N,). Returns a
519 SCALAR Tensor = mean over N of -log_softmax(logits)[i, targets[i]]. Stable (log-sum-exp)
520 forward is provided. Backward into logits: (softmax - onehot(targets)) / N, times out.grad.
521 """
522 logits = _ensure(logits)
523 x = logits.data
524 z = x - x.max(axis=-1, keepdims=True)
525 e = np.exp(z)
526 logp = z - np.log(e.sum(axis=-1, keepdims=True))
527 t = np.asarray(targets).astype(np.int64).reshape(-1)
528 n = x.shape[0]
529 out = _mk(-logp[np.arange(n), t].mean(), (logits,), logits.requires_grad)
530
531 def _bw():
532 raise NotImplementedError("cross_entropy backward") # TODO
533
534 out._backward = _bw
535 return out
536
537
538 def mse_loss(p
…[truncated 7185 chars]/app/submission/autograd.py
699 if running_mean is not None and running_var is not None:
700 ubvar = var * (M / _bi_max(1, M - 1))
701 running_mean[:] = (1 - momentum) * running_mean + momentum * mu.reshape(-1)
702 running_var[:] = (1 - momentum) * running_var + momentum * ubvar.reshape(-1)
703 else:
704 mu = running_mean.reshape(1, C, 1, 1)
705 var = running_var.reshape(1, C, 1, 1)
706 inv = 1.0 / np.sqrt(var + eps)
707 xhat = (xd - mu) * inv
708 g_ = gamma.data.reshape(1, C, 1, 1)
709 out = _mk(g_ * xhat + beta.data.reshape(1, C, 1, 1), (x, gamma, beta),
710 x.requires_grad or gamma.requires_grad or beta.requires_grad)
711
712 def _bw():
713 raise NotImplementedError("batchnorm2d backward") # TODO
714
715 out._backward = _bw
716 return out
717
718
719 # ============================================================ LSQ fake-quant (DOMAIN; the crux)
720 def fake_quant(v, scale, n_levels_neg: int, n_levels_pos: int,
721 grad_scale: Optional[float] = None) -> Tensor:
722 """Learned Step Size Quantization (LSQ, Esser et al. ICLR 2020) fake-quantizer.
723
724 Quantize ``v`` to the integer grid [Qn, Qp] = [-n_levels_neg, +n_levels_pos] with a single
725 learnable POSITIVE step ``scale`` (a 1-element Tensor), returning a tensor in the ORIGINAL
726 scale: r = v/s; out = round(clip(r, Qn, Qp)) * s.
727 * 2-bit SIGNED weights: (n_levels_neg, n_leve
…[truncated 6345 chars]/app/submission/autograd.py
899 def elu(a, alpha: float = 1.0) -> Tensor:
900 """ELU: out = a where a>0 else alpha*(exp(a)-1). Backward: grad where a>0 else grad*alpha*exp(a)."""
901 a = _ensure(a)
902 x = a.data
903 out = _mk(np.where(x > 0.0, x, alpha * (np.exp(np.minimum(x, 0.0)) - 1.0)), (a,), a.requires_grad)
904
905 def _bw():
906 raise NotImplementedError("elu backward") # TODO
907
908 out._backward = _bw
909 return out
910
911
912 def hardtanh(a, lo: float = -1.0, hi: float = 1.0) -> Tensor:
913 """Clamp to [lo,hi]. Backward passes grad only where lo < a < hi (else 0)."""
914 a = _ensure(a)
915 out = _mk(np.clip(a.data, lo, hi), (a,), a.requires_grad)
916
917 def _bw():
918 raise NotImplementedError("hardtanh backward") # TODO
919
920 out._backward = _bw
921 return out
922
923
924 def hardsigmoid(a) -> Tensor:
925 """out = clip(a/6 + 0.5, 0, 1). Backward: grad/6 where 0 < a/6+0.5 < 1 else 0."""
926 a = _ensure(a)
927 z = a.data / 6.0 + 0.5
928 out = _mk(np.clip(z, 0.0, 1.0), (a,), a.requires_grad)
929
930 def _bw():
931 raise NotImplementedError("hardsigmoid backward") # TODO
932
933 out._backward = _bw
934 return out
935
936
937 # ============================================================ groupnorm (DOMAIN-ish)
938 def groupnorm(x, gamma, beta, num_groups: int, eps: float = 1e-5) -> Tensor:
939 """GroupNorm over an NCHW tensor: split C into ``num_groups`` groups, normaliz
…[truncated 7084 chars]/app/submission/autograd.py
1099 raise NotImplementedError("l2_normalize backward") # TODO
1100
1101 out._backward = _bw
1102 return out
1103
1104
1105 def rms_norm(x, gamma, eps: float = 1e-5) -> Tensor:
1106 """RMSNorm over the LAST axis (NO mean subtraction): inv = 1/sqrt(mean(x^2)+eps); out = gamma*x*inv.
1107 Backward dx = inv*(g*gamma) - (x*inv^3/D)*sum(g*gamma*x); dgamma = sum(g * x*inv) over leading axes.
1108 (xhat = x*inv is provided.)"""
1109 x, gamma = _ensure(x), _ensure(gamma)
1110 xd = x.data
1111 D = xd.shape[-1]
1112 ms = (xd * xd).mean(axis=-1, keepdims=True)
1113 inv = 1.0 / np.sqrt(ms + eps)
1114 xhat = xd * inv
1115 out = _mk(gamma.data * xhat, (x, gamma), x.requires_grad or gamma.requires_grad)
1116
1117 def _bw():
1118 raise NotImplementedError("rms_norm backward") # TODO
1119
1120 out._backward = _bw
1121 return out
1122
1123
1124 def instance_norm(x, gamma, beta, eps: float = 1e-5) -> Tensor:
1125 """Per-sample per-channel normalization over (H,W) for NCHW; per-channel affine (gamma,beta) (C,).
1126 Backward is the per-(N,C) normalization gradient (M = H*W). (xhat is provided.)"""
1127 x, gamma, beta = _ensure(x), _ensure(gamma), _ensure(beta)
1128 N, C, H, W = x.data.shape
1129 M = H * W
1130 xg = x.data.reshape(N, C, M)
1131 mu = xg.mean(axis=2, keepdims=True)
1132 xc = xg - mu
1133 v = (xc * xc).mean(axis=2, keepdims=True)
1134 inv = 1.0 / np.sqrt(v + e
…[truncated 11728 chars]/app/submission/autograd.py
def backward(self, grad: Optional[np.ndarray] = None):
"""Reverse-mode sweep. Seed the output grad (ones for a scalar), build reverse-topo
order over ``_parents``, and call each node's ``_backward``.
TODO: implement the topological walk + seeding. (The per-op ``_backward`` closures do the
local accumulation; here you only orchestrate the order + seed ``self.grad``.)
"""
raise NotImplementedError("Tensor.backward") def backward(self, grad: Optional[np.ndarray] = None):
"""Reverse-mode sweep. Seed the output grad (ones for a scalar), build reverse-topo
order over ``_parents``, and call each node's ``_backward``.
TODO: implement the topological walk + seeding. (The per-op ``_backward`` closures do the
local accumulation; here you only orchestrate the order + seed ``self.grad``.)
"""
if grad is None:
grad = np.ones_like(self.data)
order = []
visited = set()
def topo(t):
if id(t) not in visited:
visited.add(id(t))
for p in t._parents:
topo(p)
order.append(t)
topo(self)
self._accum(grad)
for t in reversed(order):
if t.grad is not None:
t._backward()The file /app/submission/autograd.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/autograd.py
def add(a, b) -> Tensor:
"""out = a + b (numpy broadcasting). Backward: each input gets _unbroadcast(out.grad)."""
a, b = _ensure(a), _ensure(b)
out = _mk(a.data + b.data, (a, b), a.requires_grad or b.requires_grad)
def _bw():
raise NotImplementedError("add backward") # TODO
out._backward = _bw
return outdef add(a, b) -> Tensor:
"""out = a + b (numpy broadcasting). Backward: each input gets _unbroadcast(out.grad)."""
a, b = _ensure(a), _ensure(b)
out = _mk(a.data + b.data, (a, b), a.requires_grad or b.requires_grad)
def _bw():
g = out.grad
if a.requires_grad:
a._accum(_unbroadcast(g, a.shape))
if b.requires_grad:
b._accum(_unbroadcast(g, b.shape))
out._backward = _bw
return outThe file /app/submission/autograd.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/autograd.py
def sub(a, b) -> Tensor:
"""out = a - b. Backward: a gets +grad, b gets -grad (both _unbroadcast)."""
a, b = _ensure(a), _ensure(b)
out = _mk(a.data - b.data, (a, b), a.requires_grad or b.requires_grad)
def _bw():
raise NotImplementedError("sub backward") # TODO
out._backward = _bw
return outdef sub(a, b) -> Tensor:
"""out = a - b. Backward: a gets +grad, b gets -grad (both _unbroadcast)."""
a, b = _ensure(a), _ensure(b)
out = _mk(a.data - b.data, (a, b), a.requires_grad or b.requires_grad)
def _bw():
g = out.grad
if a.requires_grad:
a._accum(_unbroadcast(g, a.shape))
if b.requires_grad:
b._accum(_unbroadcast(-g, b.shape))
out._backward = _bw
return outThe file /app/submission/autograd.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/autograd.py
def mul(a, b) -> Tensor:
"""out = a * b (elementwise). Backward: a gets grad*b, b gets grad*a (both _unbroadcast)."""
a, b = _ensure(a), _ensure(b)
out = _mk(a.data * b.data, (a, b), a.requires_grad or b.requires_grad)
def _bw():
raise NotImplementedError("mul backward") # TODO
out._backward = _bw
return outdef mul(a, b) -> Tensor:
"""out = a * b (elementwise). Backward: a gets grad*b, b gets grad*a (both _unbroadcast)."""
a, b = _ensure(a), _ensure(b)
out = _mk(a.data * b.data, (a, b), a.requires_grad or b.requires_grad)
def _bw():
g = out.grad
if a.requires_grad:
a._accum(_unbroadcast(g * b.data, a.shape))
if b.requires_grad:
b._accum(_unbroadcast(g * a.data, b.shape))
out._backward = _bw
return outThe file /app/submission/autograd.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/autograd.py
def div(a, b) -> Tensor:
"""out = a / b (elementwise). Backward: a gets grad/b, b gets -grad*a/b**2 (_unbroadcast)."""
a, b = _ensure(a), _ensure(b)
out = _mk(a.data / b.data, (a, b), a.requires_grad or b.requires_grad)
def _bw():
raise NotImplementedError("div backward") # TODO
out._backward = _bw
return outdef div(a, b) -> Tensor:
"""out = a / b (elementwise). Backward: a gets grad/b, b gets -grad*a/b**2 (_unbroadcast)."""
a, b = _ensure(a), _ensure(b)
out = _mk(a.data / b.data, (a, b), a.requires_grad or b.requires_grad)
def _bw():
g = out.grad
if a.requires_grad:
a._accum(_unbroadcast(g / b.data, a.shape))
if b.requires_grad:
b._accum(_unbroadcast(-g * a.data / b.data ** 2, b.shape))
out._backward = _bw
return outThe file /app/submission/autograd.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/autograd.py
def power(a, p: float) -> Tensor:
"""out = a ** p (scalar p). Backward: grad * p * a**(p-1)."""
a = _ensure(a)
out = _mk(a.data ** p, (a,), a.requires_grad)
def _bw():
raise NotImplementedError("power backward") # TODO
out._backward = _bw
return outdef power(a, p: float) -> Tensor:
"""out = a ** p (scalar p). Backward: grad * p * a**(p-1)."""
a = _ensure(a)
out = _mk(a.data ** p, (a,), a.requires_grad)
def _bw():
if a.requires_grad:
a._accum(out.grad * p * a.data ** (p - 1))
out._backward = _bw
return outThe file /app/submission/autograd.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/autograd.py
def maximum(a, b) -> Tensor:
"""elementwise max(a, b). Backward routes grad to whichever input is larger; on EXACT ties,
split the gradient half-and-half (so finite differences match)."""
a, b = _ensure(a), _ensure(b)
out = _mk(np.maximum(a.data, b.data), (a, b), a.requires_grad or b.requires_grad)
def _bw():
raise NotImplementedError("maximum backward") # TODO
out._backward = _bw
return outdef maximum(a, b) -> Tensor:
"""elementwise max(a, b). Backward routes grad to whichever input is larger; on EXACT ties,
split the gradient half-and-half (so finite differences match)."""
a, b = _ensure(a), _ensure(b)
out = _mk(np.maximum(a.data, b.data), (a, b), a.requires_grad or b.requires_grad)
def _bw():
g = out.grad
tie = (a.data == b.data)
a_wins = (a.data > b.data)
b_wins = (b.data > a.data)
if a.requires_grad:
a._accum(_unbroadcast(g * (a_wins + 0.5 * tie), a.shape))
if b.requires_grad:
b._accum(_unbroadcast(g * (b_wins + 0.5 * tie), b.shape))
out._backward = _bw
return outThe file /app/submission/autograd.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/autograd.py
def minimum(a, b) -> Tensor:
"""elementwise min(a, b). Backward routes grad to whichever input is smaller (ties split)."""
a, b = _ensure(a), _ensure(b)
out = _mk(np.minimum(a.data, b.data), (a, b), a.requires_grad or b.requires_grad)
def _bw():
raise NotImplementedError("minimum backward") # TODO
out._backward = _bw
return outdef minimum(a, b) -> Tensor:
"""elementwise min(a, b). Backward routes grad to whichever input is smaller (ties split)."""
a, b = _ensure(a), _ensure(b)
out = _mk(np.minimum(a.data, b.data), (a, b), a.requires_grad or b.requires_grad)
def _bw():
g = out.grad
tie = (a.data == b.data)
a_wins = (a.data < b.data)
b_wins = (b.data < a.data)
if a.requires_grad:
a._accum(_unbroadcast(g * (a_wins + 0.5 * tie), a.shape))
if b.requires_grad:
b._accum(_unbroadcast(g * (b_wins + 0.5 * tie), b.shape))
out._backward = _bw
return outThe file /app/submission/autograd.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/autograd.py
def where(cond, a, b) -> Tensor:
"""np.where(cond, a, b); ``cond`` is a boolean array (NOT differentiated). Backward routes
grad to ``a`` where cond is True, to ``b`` where False (each _unbroadcast)."""
a, b = _ensure(a), _ensure(b)
c = np.asarray(cond, dtype=bool)
out = _mk(np.where(c, a.data, b.data), (a, b), a.requires_grad or b.requires_grad)
def _bw():
raise NotImplementedError("where backward") # TODO
out._backward = _bw
return outdef where(cond, a, b) -> Tensor:
"""np.where(cond, a, b); ``cond`` is a boolean array (NOT differentiated). Backward routes
grad to ``a`` where cond is True, to ``b`` where False (each _unbroadcast)."""
a, b = _ensure(a), _ensure(b)
c = np.asarray(cond, dtype=bool)
out = _mk(np.where(c, a.data, b.data), (a, b), a.requires_grad or b.requires_grad)
def _bw():
g = out.grad
if a.requires_grad:
a._accum(_unbroadcast(np.where(c, g, 0), a.shape))
if b.requires_grad:
b._accum(_unbroadcast(np.where(c, 0, g), b.shape))
out._backward = _bw
return outThe file /app/submission/autograd.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/autograd.py
def exp(a) -> Tensor:
"""out = exp(a). Backward: grad * exp(a)."""
a = _ensure(a)
out = _mk(np.exp(a.data), (a,), a.requires_grad)
def _bw():
raise NotImplementedError("exp backward") # TODO
out._backward = _bw
return outdef exp(a) -> Tensor:
"""out = exp(a). Backward: grad * exp(a)."""
a = _ensure(a)
out = _mk(np.exp(a.data), (a,), a.requires_grad)
def _bw():
if a.requires_grad:
a._accum(out.grad * out.data)
out._backward = _bw
return outThe file /app/submission/autograd.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/autograd.py
def log(a) -> Tensor:
"""out = log(a). Backward: grad / a."""
a = _ensure(a)
out = _mk(np.log(a.data), (a,), a.requires_grad)
def _bw():
raise NotImplementedError("log backward") # TODO
out._backward = _bw
return outdef log(a) -> Tensor:
"""out = log(a). Backward: grad / a."""
a = _ensure(a)
out = _mk(np.log(a.data), (a,), a.requires_grad)
def _bw():
if a.requires_grad:
a._accum(out.grad / a.data)
out._backward = _bw
return outThe file /app/submission/autograd.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/autograd.py
def sqrt(a) -> Tensor:
"""out = sqrt(a). Backward: grad * 0.5 / sqrt(a)."""
a = _ensure(a)
out = _mk(np.sqrt(a.data), (a,), a.requires_grad)
def _bw():
raise NotImplementedError("sqrt backward") # TODO
out._backward = _bw
return outdef sqrt(a) -> Tensor:
"""out = sqrt(a). Backward: grad * 0.5 / sqrt(a)."""
a = _ensure(a)
out = _mk(np.sqrt(a.data), (a,), a.requires_grad)
def _bw():
if a.requires_grad:
a._accum(out.grad * 0.5 / out.data)
out._backward = _bw
return outThe file /app/submission/autograd.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/autograd.py
def abs(a) -> Tensor:
"""out = |a|. Backward: grad * sign(a)."""
a = _ensure(a)
out = _mk(np.abs(a.data), (a,), a.requires_grad)
def _bw():
raise NotImplementedError("abs backward") # TODO
out._backward = _bw
return outdef abs(a) -> Tensor:
"""out = |a|. Backward: grad * sign(a)."""
a = _ensure(a)
out = _mk(np.abs(a.data), (a,), a.requires_grad)
def _bw():
if a.requires_grad:
a._accum(out.grad * np.sign(a.data))
out._backward = _bw
return outThe file /app/submission/autograd.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/autograd.py
def clip(a, lo: float, hi: float) -> Tensor:
"""clip to [lo, hi]. Backward passes grad only where lo < a < hi (else 0)."""
a = _ensure(a)
out = _mk(np.clip(a.data, lo, hi), (a,), a.requires_grad)
def _bw():
raise NotImplementedError("clip backward") # TODO
out._backward = _bw
return outdef clip(a, lo: float, hi: float) -> Tensor:
"""clip to [lo, hi]. Backward passes grad only where lo < a < hi (else 0)."""
a = _ensure(a)
out = _mk(np.clip(a.data, lo, hi), (a,), a.requires_grad)
def _bw():
if a.requires_grad:
a._accum(out.grad * ((a.data > lo) & (a.data < hi)))
out._backward = _bw
return outThe file /app/submission/autograd.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/autograd.py
def sum(a, axis=None, keepdims=False) -> Tensor:
"""Sum over ``axis`` (or all). Backward broadcasts out.grad back to a's shape (re-insert a
summed axis if ``keepdims`` was False)."""
a = _ensure(a)
out = _mk(a.data.sum(axis=axis, keepdims=keepdims), (a,), a.requires_grad)
def _bw():
raise NotImplementedError("sum backward") # TODO
out._backward = _bw
return outdef _restore_grad(g, axis, keepdims, ndim):
"""Re-insert the reduced axes so g can broadcast back to input shape."""
if not keepdims:
if axis is None:
g = g.reshape([1] * ndim)
else:
axes = (axis,) if isinstance(axis, int) else tuple(axis)
for ax in sorted(axes):
g = np.expand_dims(g, axis=ax)
return g
def sum(a, axis=None, keepdims=False) -> Tensor:
"""Sum over ``axis`` (or all). Backward broadcasts out.grad back to a's shape (re-insert a
summed axis if ``keepdims`` was False)."""
a = _ensure(a)
out = _mk(a.data.sum(axis=axis, keepdims=keepdims), (a,), a.requires_grad)
def _bw():
if a.requires_grad:
g = _restore_grad(out.grad, axis, keepdims, a.data.ndim)
a._accum(np.broadcast_to(g, a.shape).copy())
out._backward = _bw
return outThe file /app/submission/autograd.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/autograd.py
def mean(a, axis=None, keepdims=False) -> Tensor:
"""Mean over ``axis`` (or all). Backward = sum-backward scaled by 1/N where N is the number
of averaged elements."""
a = _ensure(a)
out = _mk(a.data.mean(axis=axis, keepdims=keepdims), (a,), a.requires_grad)
def _bw():
raise NotImplementedError("mean backward") # TODO
out._backward = _bw
return outdef mean(a, axis=None, keepdims=False) -> Tensor:
"""Mean over ``axis`` (or all). Backward = sum-backward scaled by 1/N where N is the number
of averaged elements."""
a = _ensure(a)
out = _mk(a.data.mean(axis=axis, keepdims=keepdims), (a,), a.requires_grad)
def _bw():
if a.requires_grad:
if axis is None:
N = a.data.size
else:
axes = (axis,) if isinstance(axis, int) else tuple(axis)
N = 1
for ax in axes:
N *= a.data.shape[ax]
g = _restore_grad(out.grad, axis, keepdims, a.data.ndim)
a._accum(np.broadcast_to(g / N, a.shape).copy())
out._backward = _bw
return outThe file /app/submission/autograd.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/autograd.py
def max(a, axis=None, keepdims=False) -> Tensor:
"""Reduce-max over ``axis``. Backward routes the upstream grad to the argmax position(s);
on EXACT ties, split the grad equally among the tied maxima."""
a = _ensure(a)
out = _mk(a.data.max(axis=axis, keepdims=keepdims), (a,), a.requires_grad)
def _bw():
raise NotImplementedError("max backward") # TODO
out._backward = _bw
return outdef max(a, axis=None, keepdims=False) -> Tensor:
"""Reduce-max over ``axis``. Backward routes the upstream grad to the argmax position(s);
on EXACT ties, split the grad equally among the tied maxima."""
a = _ensure(a)
out = _mk(a.data.max(axis=axis, keepdims=keepdims), (a,), a.requires_grad)
def _bw():
if a.requires_grad:
g = _restore_grad(out.grad, axis, keepdims, a.data.ndim)
max_val = _restore_grad(out.data, axis, keepdims, a.data.ndim)
mask = (a.data == max_val)
count = mask.sum(axis=axis, keepdims=True)
a._accum(g * mask / count)
out._backward = _bw
return outThe file /app/submission/autograd.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/autograd.py
def min(a, axis=None, keepdims=False) -> Tensor:
"""Reduce-min over ``axis``. Backward routes grad to the argmin position(s) (ties split)."""
a = _ensure(a)
out = _mk(a.data.min(axis=axis, keepdims=keepdims), (a,), a.requires_grad)
def _bw():
raise NotImplementedError("min backward") # TODO
out._backward = _bw
return outdef min(a, axis=None, keepdims=False) -> Tensor:
"""Reduce-min over ``axis``. Backward routes grad to the argmin position(s) (ties split)."""
a = _ensure(a)
out = _mk(a.data.min(axis=axis, keepdims=keepdims), (a,), a.requires_grad)
def _bw():
if a.requires_grad:
g = _restore_grad(out.grad, axis, keepdims, a.data.ndim)
min_val = _restore_grad(out.data, axis, keepdims, a.data.ndim)
mask = (a.data == min_val)
count = mask.sum(axis=axis, keepdims=True)
a._accum(g * mask / count)
out._backward = _bw
return outThe file /app/submission/autograd.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/autograd.py
def concat(tensors, axis=0) -> Tensor:
"""Concatenate Tensors along ``axis``. Backward splits out.grad back to each input (each input
receives the slice of out.grad covering its span along ``axis``)."""
ts = [_ensure(t) for t in tensors]
out = _mk(np.concatenate([t.data for t in ts], axis=axis), tuple(ts),
any(t.requires_grad for t in ts))
def _bw():
raise NotImplementedError("concat backward") # TODO
out._backward = _bw
return outdef concat(tensors, axis=0) -> Tensor:
"""Concatenate Tensors along ``axis``. Backward splits out.grad back to each input (each input
receives the slice of out.grad covering its span along ``axis``)."""
ts = [_ensure(t) for t in tensors]
out = _mk(np.concatenate([t.data for t in ts], axis=axis), tuple(ts),
any(t.requires_grad for t in ts))
def _bw():
g = out.grad
sizes = [t.data.shape[axis] for t in ts]
splits = np.split(g, np.cumsum(sizes[:-1]), axis=axis)
for t, sg in zip(ts, splits):
if t.requires_grad:
t._accum(sg)
out._backward = _bw
return outThe file /app/submission/autograd.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/autograd.py
def stack(tensors, axis=0) -> Tensor:
"""Stack Tensors along a NEW ``axis``. Backward indexes out.grad along that axis per input."""
ts = [_ensure(t) for t in tensors]
out = _mk(np.stack([t.data for t in ts], axis=axis), tuple(ts),
any(t.requires_grad for t in ts))
def _bw():
raise NotImplementedError("stack backward") # TODO
out._backward = _bw
return outdef stack(tensors, axis=0) -> Tensor:
"""Stack Tensors along a NEW ``axis``. Backward indexes out.grad along that axis per input."""
ts = [_ensure(t) for t in tensors]
out = _mk(np.stack([t.data for t in ts], axis=axis), tuple(ts),
any(t.requires_grad for t in ts))
def _bw():
g = out.grad
for i, t in enumerate(ts):
if t.requires_grad:
idx = [slice(None)] * g.ndim
idx[axis] = i
t._accum(g[tuple(idx)])
out._backward = _bw
return outThe file /app/submission/autograd.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/autograd.py
def transpose(a, axes=None) -> Tensor:
"""np.transpose(a, axes). Backward: transpose out.grad by the inverse permutation."""
a = _ensure(a)
out = _mk(np.transpose(a.data, axes), (a,), a.requires_grad)
def _bw():
raise NotImplementedError("transpose backward") # TODO
out._backward = _bw
return outdef transpose(a, axes=None) -> Tensor:
"""np.transpose(a, axes). Backward: transpose out.grad by the inverse permutation."""
a = _ensure(a)
out = _mk(np.transpose(a.data, axes), (a,), a.requires_grad)
def _bw():
if a.requires_grad:
if axes is None:
inv_axes = None
else:
inv_axes = np.argsort(axes)
a._accum(np.transpose(out.grad, inv_axes))
out._backward = _bw
return outThe file /app/submission/autograd.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/autograd.py
def reshape(a, shape) -> Tensor:
"""Reshape. Backward: reshape out.grad back to a's original shape."""
a = _ensure(a)
out = _mk(a.data.reshape(shape), (a,), a.requires_grad)
def _bw():
raise NotImplementedError("reshape backward") # TODO
out._backward = _bw
return outdef reshape(a, shape) -> Tensor:
"""Reshape. Backward: reshape out.grad back to a's original shape."""
a = _ensure(a)
out = _mk(a.data.reshape(shape), (a,), a.requires_grad)
def _bw():
if a.requires_grad:
a._accum(out.grad.reshape(a.shape))
out._backward = _bw
return outThe file /app/submission/autograd.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/autograd.py
def getitem(a, idx) -> Tensor:
"""Index/slice a tensor (``a[idx]``). Backward scatter-adds out.grad into a zeros-like(a) at
``idx``."""
a = _ensure(a)
out = _mk(a.data[idx], (a,), a.requires_grad)
def _bw():
raise NotImplementedError("getitem backward") # TODO
out._backward = _bw
return outdef getitem(a, idx) -> Tensor:
"""Index/slice a tensor (``a[idx]``). Backward scatter-adds out.grad into a zeros-like(a) at
``idx``."""
a = _ensure(a)
out = _mk(a.data[idx], (a,), a.requires_grad)
def _bw():
if a.requires_grad:
da = np.zeros_like(a.data)
np.add.at(da, idx, out.grad)
a._accum(da)
out._backward = _bw
return outThe file /app/submission/autograd.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/autograd.py
def matmul(a, b) -> Tensor:
"""Batched matmul (a @ b) with numpy broadcasting over leading dims. Backward:
da = grad @ b^T, db = a^T @ grad (swap the LAST TWO axes for the transposes), each
_unbroadcast back to the input's shape so broadcasted batch dims are reduced."""
a, b = _ensure(a), _ensure(b)
out = _mk(a.data @ b.data, (a, b), a.requires_grad or b.requires_grad)
def _bw():
raise NotImplementedError("matmul backward") # TODO
out._backward = _bw
return outdef matmul(a, b) -> Tensor:
"""Batched matmul (a @ b) with numpy broadcasting over leading dims. Backward:
da = grad @ b^T, db = a^T @ grad (swap the LAST TWO axes for the transposes), each
_unbroadcast back to the input's shape so broadcasted batch dims are reduced."""
a, b = _ensure(a), _ensure(b)
out = _mk(a.data @ b.data, (a, b), a.requires_grad or b.requires_grad)
def _bw():
g = out.grad
if a.requires_grad:
da = g @ np.swapaxes(b.data, -1, -2)
a._accum(_unbroadcast(da, a.shape))
if b.requires_grad:
db = np.swapaxes(a.data, -1, -2) @ g
b._accum(_unbroadcast(db, b.shape))
out._backward = _bw
return outThe file /app/submission/autograd.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/autograd.py
def relu(a) -> Tensor:
"""max(a, 0). Backward: grad * (a > 0)."""
a = _ensure(a)
out = _mk(np.maximum(a.data, 0.0), (a,), a.requires_grad)
def _bw():
raise NotImplementedError("relu backward") # TODO
out._backward = _bw
return outdef relu(a) -> Tensor:
"""max(a, 0). Backward: grad * (a > 0)."""
a = _ensure(a)
out = _mk(np.maximum(a.data, 0.0), (a,), a.requires_grad)
def _bw():
if a.requires_grad:
a._accum(out.grad * (a.data > 0))
out._backward = _bw
return outThe file /app/submission/autograd.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/autograd.py
def leaky_relu(a, slope: float = 0.01) -> Tensor:
"""out = a where a>0 else slope*a. Backward: grad where a>0, slope*grad where a<=0."""
a = _ensure(a)
out = _mk(np.where(a.data > 0.0, a.data, slope * a.data), (a,), a.requires_grad)
def _bw():
raise NotImplementedError("leaky_relu backward") # TODO
out._backward = _bw
return outdef leaky_relu(a, slope: float = 0.01) -> Tensor:
"""out = a where a>0 else slope*a. Backward: grad where a>0, slope*grad where a<=0."""
a = _ensure(a)
out = _mk(np.where(a.data > 0.0, a.data, slope * a.data), (a,), a.requires_grad)
def _bw():
if a.requires_grad:
a._accum(out.grad * np.where(a.data > 0, 1.0, slope))
out._backward = _bw
return outThe file /app/submission/autograd.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/autograd.py
def sigmoid(a) -> Tensor:
"""out = 1/(1+exp(-a)). Backward: grad * out * (1 - out)."""
a = _ensure(a)
with np.errstate(over="ignore"):
s = 1.0 / (1.0 + np.exp(-a.data))
out = _mk(s, (a,), a.requires_grad)
def _bw():
raise NotImplementedError("sigmoid backward") # TODO
out._backward = _bw
return outdef sigmoid(a) -> Tensor:
"""out = 1/(1+exp(-a)). Backward: grad * out * (1 - out)."""
a = _ensure(a)
with np.errstate(over="ignore"):
s = 1.0 / (1.0 + np.exp(-a.data))
out = _mk(s, (a,), a.requires_grad)
def _bw():
if a.requires_grad:
a._accum(out.grad * out.data * (1.0 - out.data))
out._backward = _bw
return outThe file /app/submission/autograd.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/autograd.py
def tanh(a) -> Tensor:
"""out = tanh(a). Backward: grad * (1 - tanh(a)**2)."""
a = _ensure(a)
out = _mk(np.tanh(a.data), (a,), a.requires_grad)
def _bw():
raise NotImplementedError("tanh backward") # TODO
out._backward = _bw
return outdef tanh(a) -> Tensor:
"""out = tanh(a). Backward: grad * (1 - tanh(a)**2)."""
a = _ensure(a)
out = _mk(np.tanh(a.data), (a,), a.requires_grad)
def _bw():
if a.requires_grad:
a._accum(out.grad * (1.0 - out.data ** 2))
out._backward = _bw
return outThe file /app/submission/autograd.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/autograd.py
def gelu(a) -> Tensor:
"""Exact-erf GELU: out = a * 0.5 * (1 + erf(a / sqrt(2))). (``_erf`` is provided above.)
Backward: grad * (cdf + a * pdf), cdf = 0.5*(1+erf(a/sqrt2)), pdf = exp(-a^2/2)/sqrt(2*pi)."""
a = _ensure(a)
cdf = 0.5 * (1.0 + _erf(a.data * _INV_SQRT2))
out = _mk(a.data * cdf, (a,), a.requires_grad)
def _bw():
raise NotImplementedError("gelu backward") # TODO
out._backward = _bw
return outdef gelu(a) -> Tensor:
"""Exact-erf GELU: out = a * 0.5 * (1 + erf(a / sqrt(2))). (``_erf`` is provided above.)
Backward: grad * (cdf + a * pdf), cdf = 0.5*(1+erf(a/sqrt2)), pdf = exp(-a^2/2)/sqrt(2*pi)."""
a = _ensure(a)
cdf = 0.5 * (1.0 + _erf(a.data * _INV_SQRT2))
out = _mk(a.data * cdf, (a,), a.requires_grad)
def _bw():
if a.requires_grad:
pdf = np.exp(-0.5 * a.data ** 2) / np.sqrt(2.0 * np.pi)
a._accum(out.grad * (cdf + a.data * pdf))
out._backward = _bw
return outThe file /app/submission/autograd.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/autograd.py
def softmax(a, axis=-1) -> Tensor:
"""Numerically-stable softmax over ``axis`` (subtract the max before exp).
Backward (Jacobian-vector product, no full Jacobian):
s = softmax(a); da = s * (grad - sum(grad * s, axis, keepdims))."""
a = _ensure(a)
z = a.data - a.data.max(axis=axis, keepdims=True)
with np.errstate(under="ignore"):
e = np.exp(z)
s = e / e.sum(axis=axis, keepdims=True)
out = _mk(s, (a,), a.requires_grad)
def _bw():
raise NotImplementedError("softmax backward") # TODO
out._backward = _bw
return outdef softmax(a, axis=-1) -> Tensor:
"""Numerically-stable softmax over ``axis`` (subtract the max before exp).
Backward (Jacobian-vector product, no full Jacobian):
s = softmax(a); da = s * (grad - sum(grad * s, axis, keepdims))."""
a = _ensure(a)
z = a.data - a.data.max(axis=axis, keepdims=True)
with np.errstate(under="ignore"):
e = np.exp(z)
s = e / e.sum(axis=axis, keepdims=True)
out = _mk(s, (a,), a.requires_grad)
def _bw():
if a.requires_grad:
g = out.grad
a._accum(out.data * (g - (g * out.data).sum(axis=axis, keepdims=True)))
out._backward = _bw
return outThe file /app/submission/autograd.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/autograd.py
def log_softmax(a, axis=-1) -> Tensor:
"""Stable log-softmax: z - logsumexp(z). Backward: grad - softmax * sum(grad, axis, keep)."""
a = _ensure(a)
z = a.data - a.data.max(axis=axis, keepdims=True)
with np.errstate(under="ignore"):
ls = z - np.log(np.exp(z).sum(axis=axis, keepdims=True))
out = _mk(ls, (a,), a.requires_grad)
def _bw():
raise NotImplementedError("log_softmax backward") # TODO
out._backward = _bw
return outdef log_softmax(a, axis=-1) -> Tensor:
"""Stable log-softmax: z - logsumexp(z). Backward: grad - softmax * sum(grad, axis, keep)."""
a = _ensure(a)
z = a.data - a.data.max(axis=axis, keepdims=True)
with np.errstate(under="ignore"):
ls = z - np.log(np.exp(z).sum(axis=axis, keepdims=True))
out = _mk(ls, (a,), a.requires_grad)
def _bw():
if a.requires_grad:
g = out.grad
a._accum(g - np.exp(out.data) * g.sum(axis=axis, keepdims=True))
out._backward = _bw
return outThe file /app/submission/autograd.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/autograd.py
def cross_entropy(logits, targets) -> Tensor:
"""Mean cross-entropy over a batch. ``logits``: (N, C). ``targets``: int (N,). Returns a
SCALAR Tensor = mean over N of -log_softmax(logits)[i, targets[i]]. Stable (log-sum-exp)
forward is provided. Backward into logits: (softmax - onehot(targets)) / N, times out.grad.
"""
logits = _ensure(logits)
x = logits.data
z = x - x.max(axis=-1, keepdims=True)
e = np.exp(z)
logp = z - np.log(e.sum(axis=-1, keepdims=True))
t = np.asarray(targets).astype(np.int64).reshape(-1)
n = x.shape[0]
out = _mk(-logp[np.arange(n), t].mean(), (logits,), logits.requires_grad)
def _bw():
raise NotImplementedError("cross_entropy backward") # TODO
out._backward = _bw
return outdef cross_entropy(logits, targets) -> Tensor:
"""Mean cross-entropy over a batch. ``logits``: (N, C). ``targets``: int (N,). Returns a
SCALAR Tensor = mean over N of -log_softmax(logits)[i, targets[i]]. Stable (log-sum-exp)
forward is provided. Backward into logits: (softmax - onehot(targets)) / N, times out.grad.
"""
logits = _ensure(logits)
x = logits.data
z = x - x.max(axis=-1, keepdims=True)
e = np.exp(z)
logp = z - np.log(e.sum(axis=-1, keepdims=True))
t = np.asarray(targets).astype(np.int64).reshape(-1)
n = x.shape[0]
out = _mk(-logp[np.arange(n), t].mean(), (logits,), logits.requires_grad)
def _bw():
if logits.requires_grad:
sm = e / e.sum(axis=-1, keepdims=True)
onehot = np.zeros_like(sm)
onehot[np.arange(n), t] = 1.0
dlogits = (sm - onehot) / n * out.grad
logits._accum(dlogits)
out._backward = _bw
return outThe file /app/submission/autograd.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/autograd.py
def mse_loss(pred, target) -> Tensor:
"""Mean squared error over ALL elements: mean((pred - target)^2). ``target`` is a constant
array. Backward into pred: (2/N) * (pred - target) * out.grad, N = pred.size."""
pred = _ensure(pred)
tgt = np.asarray(target, dtype=np.float64)
out = _mk(float(np.mean((pred.data - tgt) ** 2)), (pred,), pred.requires_grad)
def _bw():
raise NotImplementedError("mse_loss backward") # TODO
out._backward = _bw
return outdef mse_loss(pred, target) -> Tensor:
"""Mean squared error over ALL elements: mean((pred - target)^2). ``target`` is a constant
array. Backward into pred: (2/N) * (pred - target) * out.grad, N = pred.size."""
pred = _ensure(pred)
tgt = np.asarray(target, dtype=np.float64)
out = _mk(float(np.mean((pred.data - tgt) ** 2)), (pred,), pred.requires_grad)
def _bw():
if pred.requires_grad:
pred._accum(2.0 * (pred.data - tgt) / pred.data.size * out.grad)
out._backward = _bw
return outThe file /app/submission/autograd.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/autograd.py
def layernorm(x, gamma, beta, eps: float = 1e-5) -> Tensor:
"""Layer normalization over the LAST axis. x:(...,D); gamma,beta:(D,). POPULATION variance.
mu=mean(x,-1); xhat=(x-mu)/sqrt(var+eps); out = gamma*xhat + beta.
Backward (sums over the last axis): dgamma=sum(grad*xhat over leading axes);
dbeta=sum(grad over leading axes); gx=grad*gamma;
dx = inv/D * (D*gx - sum(gx,-1) - xhat*sum(gx*xhat,-1)).
The forward (mu/var/inv/xhat) is provided; implement the backward."""
x, gamma, beta = _ensure(x), _ensure(gamma), _ensure(beta)
xd = x.data
D = xd.shape[-1]
mu = xd.mean(axis=-1, keepdims=True)
xc = xd - mu
var = (xc * xc).mean(axis=-1, keepdims=True)
inv = 1.0 / np.sqrt(var + eps)
xhat = xc * inv
out = _mk(gamma.data * xhat + beta.data, (x, gamma, beta),
x.requires_grad or gamma.requires_grad or beta.requires_grad)
def _bw():
raise NotImplementedError("layernorm backward") # TODO
out._backward = _bw
return outdef layernorm(x, gamma, beta, eps: float = 1e-5) -> Tensor:
"""Layer normalization over the LAST axis. x:(...,D); gamma,beta:(D,). POPULATION variance.
mu=mean(x,-1); xhat=(x-mu)/sqrt(var+eps); out = gamma*xhat + beta.
Backward (sums over the last axis): dgamma=sum(grad*xhat over leading axes);
dbeta=sum(grad over leading axes); gx=grad*gamma;
dx = inv/D * (D*gx - sum(gx,-1) - xhat*sum(gx*xhat,-1)).
The forward (mu/var/inv/xhat) is provided; implement the backward."""
x, gamma, beta = _ensure(x), _ensure(gamma), _ensure(beta)
xd = x.data
D = xd.shape[-1]
mu = xd.mean(axis=-1, keepdims=True)
xc = xd - mu
var = (xc * xc).mean(axis=-1, keepdims=True)
inv = 1.0 / np.sqrt(var + eps)
xhat = xc * inv
out = _mk(gamma.data * xhat + beta.data, (x, gamma, beta),
x.requires_grad or gamma.requires_grad or beta.requires_grad)
def _bw():
g = out.grad
if gamma.requires_grad:
# sum over all leading axes (all except last)
leading = tuple(range(g.ndim - 1))
gamma._accum((g * xhat).sum(axis=leading))
if beta.requires_grad:
leading = tuple(range(g.ndim - 1))
beta._accum(g.sum(axis=leading))
if x.requires_grad:
gx = g * gamma.data
dx = inv / D * (D * gx - gx.sum(axis=-1, keepdims=True) - xhat * (gx * xhat).sum(axis=-1, keepdims=True))
x._accum(dx)
out._backward = _bw
return outThe file /app/submission/autograd.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/autograd.py
def _bw():
raise NotImplementedError("conv2d backward") # TODO (dW, dbias, dx via _col2im)
out._backward = _bw
return out def _bw():
dout_mat = out.grad.reshape(N, Cout, OH * OW)
if weight.requires_grad:
dW = np.einsum("nop,ncp->oc", dout_mat, cols).reshape(Cout, Cin, KH, KW)
weight._accum(dW)
if has_bias and bias.requires_grad:
dbias = dout_mat.sum(axis=(0, 2))
bias._accum(dbias)
if x.requires_grad:
dcols = np.einsum("oc,nop->ncp", Wm, dout_mat)
dxp = _col2im(dcols, xp.shape, KH, KW, stride, OH, OW)
dx = dxp[:, :, pad:-pad, pad:-pad] if pad > 0 else dxp
x._accum(dx)
out._backward = _bw
return outThe file /app/submission/autograd.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/autograd.py
def _bw():
raise NotImplementedError("avgpool2d backward") # TODO
out._backward = _bw
return out
def maxpool2d(x, k) -> Tensor: def _bw():
if x.requires_grad:
dx = np.zeros_like(x.data)
dx[:, :, :OH * k, :OW * k] = np.repeat(np.repeat(out.grad, k, axis=2), k, axis=3) / (k * k)
x._accum(dx)
out._backward = _bw
return out
def maxpool2d(x, k) -> Tensor:The file /app/submission/autograd.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/autograd.py
def _bw():
raise NotImplementedError("maxpool2d backward") # TODO
out._backward = _bw
return out
def batchnorm2d def _bw():
if x.requires_grad:
dx = np.zeros_like(x.data)
# xr shape: (N, C, OH, k, OW, k) -> transpose to (N, C, OH, OW, k, k)
xr_t = xr.transpose(0, 1, 2, 4, 3, 5).reshape(N, C, OH, OW, k * k)
af = xr_t.argmax(axis=-1)
ai = af // k
aj = af % k
hi = np.arange(OH)[None, None, :, None] * k + ai
wj = np.arange(OW)[None, None, None, :] * k + aj
n_idx = np.arange(N)[:, None, None, None]
c_idx = np.arange(C)[None, :, None, None]
np.add.at(dx, (n_idx, c_idx, hi, wj), out.grad)
x._accum(dx)
out._backward = _bw
return out
def batchnorm2dThe file /app/submission/autograd.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/autograd.py
def _bw():
raise NotImplementedError("batchnorm2d backward") # TODO
out._backward = _bw
return out
# ============================================================ LSQ fake-quant (DOMAIN; the crux) def _bw():
g = out.grad
if gamma.requires_grad:
gamma._accum((g * xhat).sum(axis=(0, 2, 3)))
if beta.requires_grad:
beta._accum(g.sum(axis=(0, 2, 3)))
if x.requires_grad:
if training:
gx = g * g_
dx = inv / M * (M * gx - gx.sum(axis=(0, 2, 3), keepdims=True) - xhat * (gx * xhat).sum(axis=(0, 2, 3), keepdims=True))
else:
dx = g * g_ * inv
x._accum(dx)
out._backward = _bw
return out
# ============================================================ LSQ fake-quant (DOMAIN; the crux)The file /app/submission/autograd.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/autograd.py
def _bw():
raise NotImplementedError("fake_quant backward (STE + LSQ scale gradient)") # TODO
out._backward = _bw
return out def _bw():
g = out.grad
ste_mask = (r > Qn) & (r < Qp)
if v.requires_grad:
v._accum(g * ste_mask)
if scale.requires_grad:
below = r < Qn
above = r > Qp
d = np.where(below, Qn, np.where(above, Qp, v_hat - r))
ds = float((g * d).sum()) * grad_scale
scale._accum(np.array([ds]))
out._backward = _bw
return outThe file /app/submission/autograd.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/autograd.py
def square(a) -> Tensor:
"""out = a*a. Backward: grad * 2*a."""
a = _ensure(a)
out = _mk(a.data * a.data, (a,), a.requires_grad)
def _bw():
raise NotImplementedError("square backward") # TODO
out._backward = _bw
return outdef square(a) -> Tensor:
"""out = a*a. Backward: grad * 2*a."""
a = _ensure(a)
out = _mk(a.data * a.data, (a,), a.requires_grad)
def _bw():
if a.requires_grad:
a._accum(out.grad * 2.0 * a.data)
out._backward = _bw
return outThe file /app/submission/autograd.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/autograd.py
def rsqrt(a) -> Tensor:
"""out = 1/sqrt(a). Backward: grad * -0.5 * a**(-1.5)."""
a = _ensure(a)
out = _mk(1.0 / np.sqrt(a.data), (a,), a.requires_grad)
def _bw():
raise NotImplementedError("rsqrt backward") # TODO
out._backward = _bw
return outdef rsqrt(a) -> Tensor:
"""out = 1/sqrt(a). Backward: grad * -0.5 * a**(-1.5)."""
a = _ensure(a)
out = _mk(1.0 / np.sqrt(a.data), (a,), a.requires_grad)
def _bw():
if a.requires_grad:
a._accum(out.grad * -0.5 * a.data ** (-1.5))
out._backward = _bw
return outThe file /app/submission/autograd.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/autograd.py
def reciprocal(a) -> Tensor:
"""out = 1/a. Backward: grad * -1/a^2."""
a = _ensure(a)
out = _mk(1.0 / a.data, (a,), a.requires_grad)
def _bw():
raise NotImplementedError("reciprocal backward") # TODO
out._backward = _bw
return outdef reciprocal(a) -> Tensor:
"""out = 1/a. Backward: grad * -1/a^2."""
a = _ensure(a)
out = _mk(1.0 / a.data, (a,), a.requires_grad)
def _bw():
if a.requires_grad:
a._accum(out.grad * -1.0 / a.data ** 2)
out._backward = _bw
return outThe file /app/submission/autograd.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/autograd.py
def var(a, axis=None, keepdims=False) -> Tensor:
"""Population variance over ``axis``: mean((a-mu)^2). Backward: grad * (2/N) * (a - mu)."""
a = _ensure(a)
mu = a.data.mean(axis=axis, keepdims=True)
xc = a.data - mu
out = _mk((xc * xc).mean(axis=axis, keepdims=keepdims), (a,), a.requires_grad)
def _bw():
raise NotImplementedError("var backward") # TODO
out._backward = _bw
return outdef var(a, axis=None, keepdims=False) -> Tensor:
"""Population variance over ``axis``: mean((a-mu)^2). Backward: grad * (2/N) * (a - mu)."""
a = _ensure(a)
mu = a.data.mean(axis=axis, keepdims=True)
xc = a.data - mu
out = _mk((xc * xc).mean(axis=axis, keepdims=keepdims), (a,), a.requires_grad)
def _bw():
if a.requires_grad:
if axis is None:
N = a.data.size
else:
axes = (axis,) if isinstance(axis, int) else tuple(axis)
N = 1
for ax in axes:
N *= a.data.shape[ax]
g_e = _restore_grad(out.grad, axis, keepdims, a.data.ndim)
a._accum(np.broadcast_to(g_e, a.shape).copy() * (2.0 / N) * xc)
out._backward = _bw
return outThe file /app/submission/autograd.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/autograd.py
def std(a, axis=None, keepdims=False, eps: float = 0.0) -> Tensor:
"""Population standard deviation sqrt(var + eps). Backward: grad * (a-mu)/(N*std)."""
a = _ensure(a)
mu = a.data.mean(axis=axis, keepdims=True)
xc = a.data - mu
v = (xc * xc).mean(axis=axis, keepdims=True)
sd = np.sqrt(v + eps)
out_data = sd if keepdims else (np.squeeze(sd, axis=axis) if axis is not None else float(sd.reshape(())))
out = _mk(out_data, (a,), a.requires_grad)
def _bw():
raise NotImplementedError("std backward") # TODO
out._backward = _bw
return outdef std(a, axis=None, keepdims=False, eps: float = 0.0) -> Tensor:
"""Population standard deviation sqrt(var + eps). Backward: grad * (a-mu)/(N*std)."""
a = _ensure(a)
mu = a.data.mean(axis=axis, keepdims=True)
xc = a.data - mu
v = (xc * xc).mean(axis=axis, keepdims=True)
sd = np.sqrt(v + eps)
out_data = sd if keepdims else (np.squeeze(sd, axis=axis) if axis is not None else float(sd.reshape(())))
out = _mk(out_data, (a,), a.requires_grad)
def _bw():
if a.requires_grad:
if axis is None:
N = a.data.size
else:
axes = (axis,) if isinstance(axis, int) else tuple(axis)
N = 1
for ax in axes:
N *= a.data.shape[ax]
g_e = _restore_grad(out.grad, axis, keepdims, a.data.ndim)
# sd has keepdims=True shape already
a._accum(np.broadcast_to(g_e, a.shape).copy() * xc / (N * sd))
out._backward = _bw
return outThe file /app/submission/autograd.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/autograd.py
def gather(a, idx, axis: int) -> Tensor:
"""Gather along ``axis`` (numpy take_along_axis). Backward scatter-adds out.grad back at idx."""
a = _ensure(a)
idx = np.asarray(idx)
out = _mk(np.take_along_axis(a.data, idx, axis=axis), (a,), a.requires_grad)
def _bw():
raise NotImplementedError("gather backward") # TODO
out._backward = _bw
return outdef gather(a, idx, axis: int) -> Tensor:
"""Gather along ``axis`` (numpy take_along_axis). Backward scatter-adds out.grad back at idx."""
a = _ensure(a)
idx = np.asarray(idx)
out = _mk(np.take_along_axis(a.data, idx, axis=axis), (a,), a.requires_grad)
def _bw():
if a.requires_grad:
da = np.zeros_like(a.data)
np.add.at(da, tuple(np.indices(idx.shape)[:axis]) + (idx,) + tuple(np.indices(idx.shape)[axis+1:]), out.grad)
a._accum(da)
out._backward = _bw
return outThe file /app/submission/autograd.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/autograd.py
def _bw():
if a.requires_grad:
da = np.zeros_like(a.data)
np.add.at(da, tuple(np.indices(idx.shape)[:axis]) + (idx,) + tuple(np.indices(idx.shape)[axis+1:]), out.grad)
a._accum(da)
out._backward = _bw
return out def _bw():
if a.requires_grad:
da = np.zeros_like(a.data)
np.add.at(da, np.ix_(*[np.arange(s) for s in idx.shape[:axis]]) + (idx,) + np.ix_(*[np.arange(s) for s in idx.shape[axis+1:]]) if idx.ndim > 1 else (idx,), out.grad)
a._accum(da)
out._backward = _bw
return outThe file /app/submission/autograd.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/autograd.py
def _bw():
if a.requires_grad:
da = np.zeros_like(a.data)
np.add.at(da, np.ix_(*[np.arange(s) for s in idx.shape[:axis]]) + (idx,) + np.ix_(*[np.arange(s) for s in idx.shape[axis+1:]]) if idx.ndim > 1 else (idx,), out.grad)
a._accum(da)
out._backward = _bw
return out def _bw():
if a.requires_grad:
da = np.zeros_like(a.data)
# Build full index tuple so np.add.at scatters along 'axis'
full_idx = []
for d in range(a.data.ndim):
if d == axis:
full_idx.append(idx)
else:
shape = [1] * idx.ndim
shape[d if d < axis else d] = idx.shape[d if d < axis else d]
rng = np.arange(idx.shape[d if d < axis else d])
# broadcast-compatible arange
bshape = [1] * idx.ndim
bshape[d] = idx.shape[d]
full_idx.append(np.arange(idx.shape[d]).reshape(bshape))
np.add.at(da, tuple(full_idx), out.grad)
a._accum(da)
out._backward = _bw
return outThe file /app/submission/autograd.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/autograd.py
def _bw():
if a.requires_grad:
da = np.zeros_like(a.data)
# Build full index tuple so np.add.at scatters along 'axis'
full_idx = []
for d in range(a.data.ndim):
if d == axis:
full_idx.append(idx)
else:
shape = [1] * idx.ndim
shape[d if d < axis else d] = idx.shape[d if d < axis else d]
rng = np.arange(idx.shape[d if d < axis else d])
# broadcast-compatible arange
bshape = [1] * idx.ndim
bshape[d] = idx.shape[d]
full_idx.append(np.arange(idx.shape[d]).reshape(bshape))
np.add.at(da, tuple(full_idx), out.grad)
a._accum(da)
out._backward = _bw
return out def _bw():
if a.requires_grad:
da = np.zeros_like(a.data)
np.add.at(da, _gather_idx(idx, axis, a.data.ndim), out.grad)
a._accum(da)
out._backward = _bw
return outThe file /app/submission/autograd.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/autograd.py
def gather(a, idx, axis: int) -> Tensor:
"""Gather along ``axis`` (numpy take_along_axis). Backward scatter-adds out.grad back at idx."""
a = _ensure(a)
idx = np.asarray(idx)
out = _mk(np.take_along_axis(a.data, idx, axis=axis), (a,), a.requires_grad)
def _bw():
if a.requires_grad:
da = np.zeros_like(a.data)
np.add.at(da, _gather_idx(idx, axis, a.data.ndim), out.grad)
a._accum(da)
out._backward = _bw
return outdef gather(a, idx, axis: int) -> Tensor:
"""Gather along ``axis`` (numpy take_along_axis). Backward scatter-adds out.grad back at idx."""
a = _ensure(a)
idx = np.asarray(idx)
out = _mk(np.take_along_axis(a.data, idx, axis=axis), (a,), a.requires_grad)
def _bw():
if a.requires_grad:
da = np.zeros_like(a.data)
# np.put_along_axis does scatter-add equivalent but replaces; use add.at
# Build broadcast index tuple compatible with np.add.at
ndim = a.data.ndim
full_idx = []
for d in range(ndim):
if d == axis:
full_idx.append(idx)
else:
shape = [1] * ndim
shape[d] = idx.shape[d]
full_idx.append(np.arange(idx.shape[d]).reshape(shape))
np.add.at(da, tuple(full_idx), out.grad)
a._accum(da)
out._backward = _bw
return outThe file /app/submission/autograd.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/autograd.py
def pad2d(x, pad: int) -> Tensor:
"""Zero-pad the last two (H,W) axes of an NCHW tensor by ``pad`` on each side. Backward crops
out.grad back to the original H,W. (``_pad_nchw`` is provided above.)"""
x = _ensure(x)
out = _mk(_pad_nchw(x.data, pad), (x,), x.requires_grad)
def _bw():
raise NotImplementedError("pad2d backward") # TODO
out._backward = _bw
return outdef pad2d(x, pad: int) -> Tensor:
"""Zero-pad the last two (H,W) axes of an NCHW tensor by ``pad`` on each side. Backward crops
out.grad back to the original H,W. (``_pad_nchw`` is provided above.)"""
x = _ensure(x)
out = _mk(_pad_nchw(x.data, pad), (x,), x.requires_grad)
def _bw():
if x.requires_grad:
if pad > 0:
x._accum(out.grad[:, :, pad:-pad, pad:-pad])
else:
x._accum(out.grad)
out._backward = _bw
return outThe file /app/submission/autograd.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/autograd.py
def softplus(a, beta: float = 1.0) -> Tensor:
"""out = (1/beta)*log(1+exp(beta*a)) (stable form provided). Backward: grad * sigmoid(beta*a)."""
a = _ensure(a)
bx = beta * a.data
out = _mk((np.maximum(bx, 0.0) + np.log1p(np.exp(-np.abs(bx)))) / beta, (a,), a.requires_grad)
def _bw():
raise NotImplementedError("softplus backward") # TODO
out._backward = _bw
return outdef softplus(a, beta: float = 1.0) -> Tensor:
"""out = (1/beta)*log(1+exp(beta*a)) (stable form provided). Backward: grad * sigmoid(beta*a)."""
a = _ensure(a)
bx = beta * a.data
out = _mk((np.maximum(bx, 0.0) + np.log1p(np.exp(-np.abs(bx)))) / beta, (a,), a.requires_grad)
def _bw():
if a.requires_grad:
with np.errstate(over="ignore"):
sig = 1.0 / (1.0 + np.exp(-bx))
a._accum(out.grad * sig)
out._backward = _bw
return outThe file /app/submission/autograd.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/autograd.py
def silu(a) -> Tensor:
"""SiLU / swish: out = a*sigmoid(a). Backward: grad*(sig + a*sig*(1-sig)), sig=sigmoid(a)."""
a = _ensure(a)
with np.errstate(over="ignore"):
sig = 1.0 / (1.0 + np.exp(-a.data))
out = _mk(a.data * sig, (a,), a.requires_grad)
def _bw():
raise NotImplementedError("silu backward") # TODO
out._backward = _bw
return outdef silu(a) -> Tensor:
"""SiLU / swish: out = a*sigmoid(a). Backward: grad*(sig + a*sig*(1-sig)), sig=sigmoid(a)."""
a = _ensure(a)
with np.errstate(over="ignore"):
sig = 1.0 / (1.0 + np.exp(-a.data))
out = _mk(a.data * sig, (a,), a.requires_grad)
def _bw():
if a.requires_grad:
a._accum(out.grad * (sig + a.data * sig * (1.0 - sig)))
out._backward = _bw
return outThe file /app/submission/autograd.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/autograd.py
def mish(a) -> Tensor:
"""Mish: out = a*tanh(softplus(a)). Backward via the chain rule (softplus'(x)=sigmoid(x))."""
a = _ensure(a)
x = a.data
sp = np.maximum(x, 0.0) + np.log1p(np.exp(-np.abs(x)))
out = _mk(x * np.tanh(sp), (a,), a.requires_grad)
def _bw():
raise NotImplementedError("mish backward") # TODO
out._backward = _bw
return outdef mish(a) -> Tensor:
"""Mish: out = a*tanh(softplus(a)). Backward via the chain rule (softplus'(x)=sigmoid(x))."""
a = _ensure(a)
x = a.data
sp = np.maximum(x, 0.0) + np.log1p(np.exp(-np.abs(x)))
th_sp = np.tanh(sp)
out = _mk(x * th_sp, (a,), a.requires_grad)
def _bw():
if a.requires_grad:
with np.errstate(over="ignore"):
sig = 1.0 / (1.0 + np.exp(-x))
# d/dx (x * tanh(sp)) = tanh(sp) + x * (1 - tanh(sp)^2) * sigmoid(x)
a._accum(out.grad * (th_sp + x * (1.0 - th_sp ** 2) * sig))
out._backward = _bw
return outThe file /app/submission/autograd.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/autograd.py
def elu(a, alpha: float = 1.0) -> Tensor:
"""ELU: out = a where a>0 else alpha*(exp(a)-1). Backward: grad where a>0 else grad*alpha*exp(a)."""
a = _ensure(a)
x = a.data
out = _mk(np.where(x > 0.0, x, alpha * (np.exp(np.minimum(x, 0.0)) - 1.0)), (a,), a.requires_grad)
def _bw():
raise NotImplementedError("elu backward") # TODO
out._backward = _bw
return outdef elu(a, alpha: float = 1.0) -> Tensor:
"""ELU: out = a where a>0 else alpha*(exp(a)-1). Backward: grad where a>0 else grad*alpha*exp(a)."""
a = _ensure(a)
x = a.data
out = _mk(np.where(x > 0.0, x, alpha * (np.exp(np.minimum(x, 0.0)) - 1.0)), (a,), a.requires_grad)
def _bw():
if a.requires_grad:
a._accum(out.grad * np.where(x > 0.0, 1.0, alpha * np.exp(np.minimum(x, 0.0))))
out._backward = _bw
return outThe file /app/submission/autograd.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/autograd.py
def hardtanh(a, lo: float = -1.0, hi: float = 1.0) -> Tensor:
"""Clamp to [lo,hi]. Backward passes grad only where lo < a < hi (else 0)."""
a = _ensure(a)
out = _mk(np.clip(a.data, lo, hi), (a,), a.requires_grad)
def _bw():
raise NotImplementedError("hardtanh backward") # TODO
out._backward = _bw
return outdef hardtanh(a, lo: float = -1.0, hi: float = 1.0) -> Tensor:
"""Clamp to [lo,hi]. Backward passes grad only where lo < a < hi (else 0)."""
a = _ensure(a)
out = _mk(np.clip(a.data, lo, hi), (a,), a.requires_grad)
def _bw():
if a.requires_grad:
a._accum(out.grad * ((a.data > lo) & (a.data < hi)))
out._backward = _bw
return outThe file /app/submission/autograd.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/autograd.py
def hardsigmoid(a) -> Tensor:
"""out = clip(a/6 + 0.5, 0, 1). Backward: grad/6 where 0 < a/6+0.5 < 1 else 0."""
a = _ensure(a)
z = a.data / 6.0 + 0.5
out = _mk(np.clip(z, 0.0, 1.0), (a,), a.requires_grad)
def _bw():
raise NotImplementedError("hardsigmoid backward") # TODO
out._backward = _bw
return outdef hardsigmoid(a) -> Tensor:
"""out = clip(a/6 + 0.5, 0, 1). Backward: grad/6 where 0 < a/6+0.5 < 1 else 0."""
a = _ensure(a)
z = a.data / 6.0 + 0.5
out = _mk(np.clip(z, 0.0, 1.0), (a,), a.requires_grad)
def _bw():
if a.requires_grad:
a._accum(out.grad / 6.0 * ((z > 0.0) & (z < 1.0)))
out._backward = _bw
return outThe file /app/submission/autograd.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/autograd.py
def _bw():
raise NotImplementedError("groupnorm backward") # TODO
out._backward = _bw
return out
# ============================================================ EXTRA quantization (per-channel + affine) def _bw():
g = out.grad
if gamma.requires_grad:
gamma._accum((g * xhat).sum(axis=(0, 2, 3)))
if beta.requires_grad:
beta._accum(g.sum(axis=(0, 2, 3)))
if x.requires_grad:
M = cg * H * W
gx = (g * gamma.data.reshape(1, C, 1, 1)).reshape(N, G, M)
inv_g = inv # shape (N, G, 1)
xhat_r = xhat.reshape(N, G, M)
dx = inv_g / M * (M * gx - gx.sum(axis=-1, keepdims=True) - xhat_r * (gx * xhat_r).sum(axis=-1, keepdims=True))
x._accum(dx.reshape(N, C, H, W))
out._backward = _bw
return out
# ============================================================ EXTRA quantization (per-channel + affine)The file /app/submission/autograd.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/autograd.py
def _bw():
raise NotImplementedError("fake_quant_per_channel backward (STE + per-channel scale grad)") # TODO
out._backward = _bw
return out def _bw():
g = out.grad
ste_mask = (r > Qn) & (r < Qp)
if v.requires_grad:
v._accum(g * ste_mask)
if scale.requires_grad:
d = np.where(r < Qn, Qn, np.where(r > Qp, Qp, v_hat - r))
axes_to_sum = tuple(i for i in range(v.data.ndim) if i != axis)
scale._accum((g * d).sum(axis=axes_to_sum) * grad_scale)
out._backward = _bw
return outThe file /app/submission/autograd.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/autograd.py
def _bw():
raise NotImplementedError("fake_quant_affine backward (STE + scale grad on shifted grid)") # TODO
out._backward = _bw
return out def _bw():
g = out.grad
ste_mask = (r > Qn) & (r < Qp)
if v.requires_grad:
v._accum(g * ste_mask)
if scale.requires_grad:
# d = (q - z) - (r - z) in-range = q - r in-range
# but: (Qn - z) below, (Qp - z) above
d = np.where(r < Qn, Qn - z, np.where(r > Qp, Qp - z, q - r))
ds = float((g * d).sum()) * grad_scale
scale._accum(np.array([ds]))
out._backward = _bw
return outThe file /app/submission/autograd.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/autograd.py
def _bw():
raise NotImplementedError("cumsum backward") # TODO
out._backward = _bw
return out def _bw():
if a.requires_grad:
a._accum(np.flip(np.cumsum(np.flip(out.grad, axis=axis), axis=axis), axis=axis))
out._backward = _bw
return outThe file /app/submission/autograd.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/autograd.py
def _bw():
raise NotImplementedError("flip backward") # TODO
out._backward = _bw
return out def _bw():
if a.requires_grad:
a._accum(np.flip(out.grad, axis=axis))
out._backward = _bw
return outThe file /app/submission/autograd.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/autograd.py
def _bw():
raise NotImplementedError("logsumexp backward") # TODO
out._backward = _bw
return out def _bw():
if a.requires_grad:
g_e = out.grad if keepdims else np.expand_dims(out.grad, axis=axis)
a._accum(sm * g_e)
out._backward = _bw
return outThe file /app/submission/autograd.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/autograd.py
def _bw():
raise NotImplementedError("logaddexp backward") # TODO
out._backward = _bw
return out def _bw():
g = out.grad
wa = np.exp(a.data - out_data)
wb = np.exp(b.data - out_data)
if a.requires_grad:
a._accum(_unbroadcast(g * wa, a.shape))
if b.requires_grad:
b._accum(_unbroadcast(g * wb, b.shape))
out._backward = _bw
return outThe file /app/submission/autograd.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/autograd.py
def _bw():
raise NotImplementedError("l2_normalize backward") # TODO
out._backward = _bw
return out def _bw():
if a.requires_grad:
dot = (out.grad * y).sum(axis=axis, keepdims=True)
dx = (out.grad - y * dot) / nrm
a._accum(dx)
out._backward = _bw
return outThe file /app/submission/autograd.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/autograd.py
def _bw():
raise NotImplementedError("rms_norm backward") # TODO
out._backward = _bw
return out def _bw():
if x.requires_grad:
gg = out.grad * gamma.data
dx = inv * gg - (x.data * inv ** 3 / D) * (gg * x.data).sum(axis=-1, keepdims=True)
x._accum(dx)
if gamma.requires_grad:
leading = tuple(range(out.grad.ndim - 1))
gamma._accum((out.grad * xhat).sum(axis=leading))
out._backward = _bw
return outThe file /app/submission/autograd.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/autograd.py
def _bw():
raise NotImplementedError("instance_norm backward") # TODO
out._backward = _bw
return out def _bw():
g = out.grad
if gamma.requires_grad:
gamma._accum((g * xhat).sum(axis=(0, 2, 3)))
if beta.requires_grad:
beta._accum(g.sum(axis=(0, 2, 3)))
if x.requires_grad:
gx = (g * gamma.data.reshape(1, C, 1, 1)).reshape(N, C, M)
inv_nc = inv # shape (N, C, 1)
xhat_nc = xhat.reshape(N, C, M)
dx = inv_nc / M * (M * gx - gx.sum(axis=-1, keepdims=True) - xhat_nc * (gx * xhat_nc).sum(axis=-1, keepdims=True))
x._accum(dx.reshape(N, C, H, W))
out._backward = _bw
return outThe file /app/submission/autograd.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/autograd.py
def _bw():
raise NotImplementedError("huber_loss backward") # TODO
out._backward = _bw
return out def _bw():
if pred.requires_grad:
dpred = np.where(quad, diff, delta * np.sign(diff)) / n * out.grad
pred._accum(dpred)
out._backward = _bw
return outThe file /app/submission/autograd.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/autograd.py
def _bw():
raise NotImplementedError("kl_div backward") # TODO
out._backward = _bw
return out def _bw():
if log_p.requires_grad:
log_p._accum(-q / n * out.grad)
out._backward = _bw
return outThe file /app/submission/autograd.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/autograd.py
def _bw():
raise NotImplementedError("embedding backward") # TODO
out._backward = _bw
return out def _bw():
if weight.requires_grad:
dw = np.zeros_like(weight.data)
np.add.at(dw, idx, out.grad)
weight._accum(dw)
out._backward = _bw
return outThe file /app/submission/autograd.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/autograd.py
def _bw():
raise NotImplementedError("conv2d_gen backward (grouped/dilated dW/db/dx)") # TODO
out._backward = _bw
return out def _bw():
g = out.grad.reshape(N, groups, cog, OH * OW)
if weight.requires_grad:
dW = np.einsum("ngop,ngcp->goc", g, cols_g).reshape(Cout, cig, KH, KW)
weight._accum(dW)
if has_bias and bias.requires_grad:
bias._accum(out.grad.reshape(N, Cout, OH * OW).sum(axis=(0, 2)))
if x.requires_grad:
dcols_g = np.einsum("goc,ngop->ngcp", Wm, g)
dcols = dcols_g.reshape(N, Cin * KH * KW, OH * OW)
dxp = _col2im_dil(dcols, xp.shape, KH, KW, stride, dilation, OH, OW)
dx = dxp[:, :, pad:-pad, pad:-pad] if pad > 0 else dxp
x._accum(dx)
out._backward = _bw
return outThe file /app/submission/autograd.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/autograd.py
def _bw():
raise NotImplementedError("conv_transpose2d backward") # TODO
out._backward = _bw
return out def _bw():
g_out = out.grad # (N, Cout, OH, OW) - may be cropped
# restore the full (un-cropped) gradient
if pad > 0:
g_full = np.zeros((N, Cout, OHf, OWf), dtype=np.float64)
g_full[:, :, pad:OHf - pad, pad:OWf - pad] = g_out
else:
g_full = g_out
# Gather patches: gcontrib[n,cout,i,j,ki,kj] = g_full[n,cout,i*stride+ki,j*stride+kj]
gcontrib = np.zeros((N, Cout, H, W, KH, KW), dtype=np.float64)
for ki in range(KH):
for kj in range(KW):
gcontrib[:, :, :, :, ki, kj] = g_full[:, :, ki:ki + stride * H:stride, kj:kj + stride * W:stride]
if x.requires_grad:
# dx[n,cin,i,j] = sum_{cout,ki,kj} Wm[cin,cout,ki,kj] * gcontrib[n,cout,i,j,ki,kj]
dx = np.einsum("coKL,noijKL->ncij", Wm, gcontrib)
x._accum(dx)
if weight.requires_grad:
# dW[cin,cout,ki,kj] = sum_{n,i,j} xd[n,cin,i,j] * gcontrib[n,cout,i,j,ki,kj]
dW = np.einsum("ncij,noijKL->coKL", xd, gcontrib)
weight._accum(dW)
if has_bias and bias.requires_grad:
bias._accum(g_out.sum(axis=(0, 2, 3)))
out._backward = _bw
return outThe file /app/submission/autograd.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/autograd.py
def _bw():
raise NotImplementedError("avgpool2d_s backward") # TODO
out._backward = _bw
return out def _bw():
if x.requires_grad:
dxp = np.zeros_like(xp)
for oi in range(OH):
for oj in range(OW):
dxp[:, :, oi * stride:oi * stride + k, oj * stride:oj * stride + k] += out.grad[:, :, oi:oi + 1, oj:oj + 1] / (k * k)
if pad > 0:
dx = dxp[:, :, pad:-pad, pad:-pad]
else:
dx = dxp
x._accum(dx)
out._backward = _bw
return outThe file /app/submission/autograd.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/autograd.py
def _bw():
raise NotImplementedError("maxpool2d_s backward") # TODO
out._backward = _bw
return out def _bw():
if x.requires_grad:
dxp = np.zeros_like(xp)
n_range = np.arange(N)[:, None, None, None]
c_range = np.arange(C)[None, :, None, None]
hi = np.arange(OH)[None, None, :, None] * stride + argi
wj = np.arange(OW)[None, None, None, :] * stride + argj
np.add.at(dxp, (n_range, c_range, hi, wj), out.grad)
if pad > 0:
dx = dxp[:, :, pad:-pad, pad:-pad]
else:
dx = dxp
x._accum(dx)
out._backward = _bw
return outThe file /app/submission/autograd.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/autograd.py
def _bw():
raise NotImplementedError("fake_quant_lsq_plus backward (STE v-grad + beta-grad + LSQ scale grad)") # TODO
out._backward = _bw
return out def _bw():
g = out.grad
ste_mask = (r > Qn) & (r < Qp)
clip_mask = (r <= Qn) | (r >= Qp)
if v.requires_grad:
v._accum(g * ste_mask)
if beta.requires_grad:
beta._accum(np.array([float((g * clip_mask).sum())]))
if scale.requires_grad:
d = np.where(r < Qn, Qn, np.where(r > Qp, Qp, q - r))
ds = float((g * d).sum()) * grad_scale
scale._accum(np.array([ds]))
out._backward = _bw
return outThe file /app/submission/autograd.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/autograd.py
745 for j in range(KW):
746 j_max = j + stride * OW
747 dx[:, :, i:i_max:stride, j:j_max:stride] += cols[:, :, i, j, :, :]
748 return dx
749
750
751 def conv2d(x, weight, bias=None, stride=1, pad=1) -> Tensor:
752 """2-D convolution (cross-correlation), NCHW, zero padding. ``x``: (N,Cin,H,W);
753 ``weight``: (Cout,Cin,KH,KW); ``bias``: (Cout,) or None -> (N,Cout,OH,OW).
754
755 The forward (via the provided im2col) is given. Implement the backward:
756 out_mat = Wm @ cols (+ bias) where Wm = weight.reshape(Cout, Cin*KH*KW)
757 dW = sum_n dout_mat_n @ cols_n^T -> reshape to (Cout,Cin,KH,KW)
758 dbias = sum over (N, OH*OW) of dout_mat
759 dcols = Wm^T @ dout_mat ; dx = _col2im(dcols)[crop the pad]
760 """
761 x, weight = _ensure(x), _ensure(weight)
762 has_bias = bias is not None
763 bias = _ensure(bias) if has_bias else None
764 N, Cin, H, W = x.data.shape
765 Cout, Cin2, KH, KW = weight.data.shape
766 xp = _pad_nchw(x.data, pad)
767 cols, OH, OW = _im2col(xp, KH, KW, stride)
768 Wm = weight.data.reshape(Cout, Cin * KH * KW)
769 out_mat = np.einsum("oc,ncp->nop", Wm, cols)
770 if has_bias:
771 out_mat = out_mat + bias.data[None, :, None]
772 out_data = out_mat.reshape(N, Cout, OH, OW)
773 parents = (x, weight) + ((bias,) if has_bias else ())
774 out = _mk(out_data, parents, x.requires_grad or weight.requires_grad or (has
…[truncated 30 chars]/app/submission/autograd.py
840 841 842 def batchnorm2d(x, gamma, beta, eps: float = 1e-5, 843 running_mean=None, running_var=None, momentum: float = 0.1, 844 training: bool = True) -> Tensor: 845 """BatchNorm over (N,H,W) per channel C. x:(N,C,H,W); gamma,beta:(C,). 846 847 TRAINING: normalize with the BATCH mean/var (POPULATION variance, divide by M=N*H*W); update 848 running_mean/running_var IN PLACE if given (running var tracks the UNBIASED batch variance, 849 i.e. var * M/(M-1)). The forward computes mu/var/inv/xhat; you implement the backward. 850 EVAL (training=False): normalize with the running stats; backward dx = grad*gamma*inv. 851 Backward (training): dgamma=sum(grad*xhat) over (N,H,W); dbeta=sum(grad) over (N,H,W); 852 gx = grad*gamma; dx = inv/M * (M*gx - sum(gx) - xhat*sum(gx*xhat)) (sums over N,H,W). 853 """ 854 x, gamma, beta = _ensure(x), _ensure(gamma), _ensure(beta) 855 N, C, H, W = x.data.shape 856 M = N * H * W 857 xd = x.data 858 if training: 859 mu = xd.mean(axis=(0, 2, 3), keepdims=True) 860 xc = xd - mu 861 var = (xc * xc).mean(axis=(0, 2, 3), keepdims=True) 862 inv = 1.0 / np.sqrt(var + eps) 863 xhat = xc * inv 864 if running_mean is not None and running_var is not None: 865 ubvar = var * (M / _bi_max(1, M - 1)) 866 running_mean[:] = (1 - momentum) * running_mean + momentum * mu.reshape(-1) 867 runnin …[truncated 134 chars]
/app/submission/autograd.py
869 mu = running_mean.reshape(1, C, 1, 1) 870 var = running_var.reshape(1, C, 1, 1) 871 inv = 1.0 / np.sqrt(var + eps) 872 xhat = (xd - mu) * inv 873 g_ = gamma.data.reshape(1, C, 1, 1) 874 out = _mk(g_ * xhat + beta.data.reshape(1, C, 1, 1), (x, gamma, beta), 875 x.requires_grad or gamma.requires_grad or beta.requires_grad) 876 877 def _bw(): 878 g = out.grad 879 if gamma.requires_grad: 880 gamma._accum((g * xhat).sum(axis=(0, 2, 3))) 881 if beta.requires_grad: 882 beta._accum(g.sum(axis=(0, 2, 3))) 883 if x.requires_grad: 884 if training: 885 gx = g * g_ 886 dx = inv / M * (M * gx - gx.sum(axis=(0, 2, 3), keepdims=True) - xhat * (gx * xhat).sum(axis=(0, 2, 3), keepdims=True)) 887 else: 888 dx = g * g_ * inv 889 x._accum(dx) 890 891 out._backward = _bw 892 return out 893 894 895 # ============================================================ LSQ fake-quant (DOMAIN; the crux) 896 def fake_quant(v, scale, n_levels_neg: int, n_levels_pos: int, 897 grad_scale: Optional[float] = None) -> Tensor: 898 """Learned Step Size Quantization (LSQ, Esser et al. ICLR 2020) fake-quantizer. 899 900 Quantize ``v`` to the integer grid [Qn, Qp] = [-n_levels_neg, +n_levels_pos] with a single 901 learnable POSITIVE step ``scale`` (a 1-element Tensor), returning a t …[truncated 472 chars]
/app/submission/autograd.py
out._backward = _bw
return out
# ============================================================ LSQ fake-quant (DOMAIN; the crux)
def fake_quant(v, scale, n_levels_neg: int, n_levels_pos: int, out._backward = _bw
return out
def batchnorm1d(x, gamma, beta, eps: float = 1e-5,
running_mean=None, running_var=None, momentum: float = 0.1,
training: bool = True) -> Tensor:
"""BatchNorm over N per channel C. x:(N,C); gamma,beta:(C,).
TRAINING: normalize with the BATCH mean/var (POPULATION variance, divide by M=N); update
running_mean/running_var IN PLACE if given (running var tracks the UNBIASED batch variance,
i.e. var * M/(M-1)). The forward computes mu/var/inv/xhat; implements the backward.
EVAL (training=False): normalize with the running stats; backward dx = grad*gamma*inv.
"""
x, gamma, beta = _ensure(x), _ensure(gamma), _ensure(beta)
N, C = x.data.shape
M = N
xd = x.data
if training:
mu = xd.mean(axis=0, keepdims=True)
xc = xd - mu
var = (xc * xc).mean(axis=0, keepdims=True)
inv = 1.0 / np.sqrt(var + eps)
xhat = xc * inv
if running_mean is not None and running_var is not None:
ubvar = var * (M / _bi_max(1, M - 1))
running_mean[:] = (1 - momentum) * running_mean + momentum * mu.reshape(-1)
running_var[:] = (1 - momentum) * running_var + momentum * ubvar.reshape(-1)
else:
mu = running_mean.reshape(1, C)
var = running_var.reshape(1, C)
inv = 1.0 / np.sqrt(var + eps)
xhat = (xd - mu) * inv
out = _mk(gamma.data * xhat + beta.data, (x, gamma, beta),
…[truncated 728 chars]The file /app/submission/autograd.py has been updated successfully. (file state is current in your context , no need to Read it back)
python3 run_checks.py --only autograd_grads 2>&1 | head -100
[autograd_grads] 95/115 grad/add_bcast OK (max_abs=3.17e-10) grad/sub_bcast OK (max_abs=3.17e-10) grad/mul_bcast OK (max_abs=1.02e-10) grad/div OK (max_abs=1.89e-11) grad/div_denom OK (max_abs=6.86e-11) grad/power2 OK (max_abs=2.34e-10) grad/power3 OK (max_abs=2.06e-10) grad/maximum OK (max_abs=6.55e-12) grad/minimum OK (max_abs=6.55e-12) grad/where OK (max_abs=7.48e-11) grad/exp OK (max_abs=1.72e-10) grad/log OK (max_abs=2.05e-10) grad/sqrt OK (max_abs=3.39e-10) grad/abs OK (max_abs=5.10e-11) grad/clip OK (max_abs=6.55e-12) grad/matmul OK (max_abs=1.14e-10) grad/matmul_batched OK (max_abs=2.42e-10) grad/transpose OK (max_abs=5.10e-11) grad/transpose_axes OK (max_abs=5.10e-11) grad/reshape OK (max_abs=3.79e-11) grad/getitem_index OK (max_abs=3.79e-11) grad/getitem_slice OK …[truncated 5305 chars]
python3 /app/run_checks.py --only autograd_grads 2>&1 | tail -40
grad/hardsigmoid OK (max_abs=6.55e-11) grad/groupnorm_x OK grad/groupnorm_gamma OK grad/groupnorm_beta OK grad/RNNCell_x FAIL (raised NotImplementedError: RNNCell.forward) grad/GRUCell_x FAIL (raised NotImplementedError: GRUCell.forward) grad/LSTMCell_x FAIL (raised NotImplementedError: LSTMCell.forward) grad/RNNCell_Wh FAIL (raised NotImplementedError: RNNCell.forward) grad/GRUCell_Wxz FAIL (raised NotImplementedError: GRUCell.forward) grad/LSTMCell_Wxf FAIL (raised NotImplementedError: LSTMCell.forward) grad/nn.SiLU_x FAIL (raised NotImplementedError: SiLU.forward) grad/nn.ELU_x FAIL (raised NotImplementedError: ELU.forward) grad/nn.GroupNorm_x FAIL (raised NotImplementedError: GroupNorm.forward) grad/cumsum_ax1 OK (max_abs=2.09e-09) grad/flip_ax1 OK (max_abs=1.27e-09) grad/logsumexp_ax1 OK (max_abs=1.47e-10) grad/logaddexp OK (max_abs=1.99e-09) grad/l2_normalize_ax1 OK (max_abs=1.01e-09) grad/rms_norm_x OK (max_abs=1.20e-09) grad/instance_norm_x …[truncated 1205 chars]
python3 /app/run_checks.py --only quant_grads 2>&1
[quant_grads] 21/21 quant/ste_indicator_w OK (err=0.0e+00) quant/ste_indicator_a OK (err=0.0e+00) quant/scale_clip_low OK (got=-8.0000 exp=-8.0000) quant/scale_clip_high OK (got=6.9282 exp=6.9282) quant/scale_inrange_w OK (got=-0.1759 exp=-0.1759) quant/scale_inrange_a OK (got=-0.2045 exp=-0.2045) quant/ste_indicator_int3 OK (err=0.0e+00) quant/ste_indicator_int4 OK (err=0.0e+00) quant/grid_int2_w OK (levels=4<= 4) quant/grid_int3_w OK (levels=8<= 8) quant/grid_int4_w OK (levels=16<= 16) quant/perchan_ste_w OK (ste=True grid=True) quant/perchan_ste_int3 OK (ste=True grid=True) quant/perchan_scale_inrange OK quant/affine_ste_z0 OK (ste=True) quant/affine_ste_z1 OK (ste=True) quant/affine_ste_signed OK (ste=True) quant/lsqplus_w OK (ste=True beta=True scale=True) quant/lsqplus_a OK (ste=True beta=True scale=True) quant/lsqplus_int3 OK (ste=True beta=True scale=True) quant/lsqplus_reduces_to_fake_quant OK ------------------------------------------------------------------------ qu …[truncated 192 chars]
grep -n "raise NotImplementedError" /app/submission/autograd.py
3:YOU MUST IMPLEMENT EVERYTHING MARKED ``# TODO`` / ``raise NotImplementedError`` using numpy
python3 /app/run_checks.py --only autograd_grads 2>&1 | grep -E "^ grad/" | grep -v "OK"
grad/nn.Linear_x FAIL (raised NotImplementedError: Linear.forward) grad/nn.MLP_x FAIL (raised NotImplementedError: MLP.forward) grad/nn.LayerNorm_x FAIL (raised NotImplementedError: LayerNorm.forward) grad/nn.Conv2d_x FAIL (raised NotImplementedError: Conv2d.forward) grad/nn.AvgPool2d_x FAIL (raised NotImplementedError: AvgPool2d.forward) grad/QuantCNN_backprop FAIL (raised NotImplementedError: QuantCNN.forward) grad/QuantMLP_backprop FAIL (raised NotImplementedError: QuantMLP.forward) grad/RNNCell_x FAIL (raised NotImplementedError: RNNCell.forward) grad/GRUCell_x FAIL (raised NotImplementedError: GRUCell.forward) grad/LSTMCell_x FAIL (raised NotImplementedError: LSTMCell.forward) grad/RNNCell_Wh FAIL (raised NotImplementedError: RNNCell.forward) grad/GRUCell_Wxz FAIL (raised NotImplementedError: GRUCell.forward) grad/LSTMCell_Wxf FAIL (raised NotImplementedError: LSTMCell.forward) grad/nn.SiLU_x FAIL (raised NotImplementedError: SiLU.forward) grad/nn.ELU_x FAIL (raised NotImplementedError: ELU.forward) grad/nn.GroupNorm_x FAIL (raised NotImplementedError: Gr …[truncated 417 chars]
Every remaining failure is due to `nn.py` forward functions not being implemented (e.g. `Linear.forward`, `MLP.forward`, `RNNCell.forward`, etc.) - these are not part of `autograd.py`. All autograd backward implementations are complete and working. Here is a summary of what was accomplished: **All backward functions implemented in `/app/submission/autograd.py`:** - **`Tensor.backward`**: Topological sort + reverse sweep seeding - **Binary ops**: `add`, `sub`, `mul`, `div`, `power`, `maximum`, `minimum`, `where` - all with proper `_unbroadcast` usage - **Unary math**: `exp`, `log`, `sqrt`, `abs`, `clip` - **Reductions**: `sum`, `mean`, `max`, `min` - added helper `_restore_grad` to re-expand reduced axes - **Shape ops**: `concat`, `stack`, `transpose`, `reshape`, `getitem`, `matmul` - **Activations**: `relu`, `leaky_relu`, `sigmoid`, `tanh`, `gelu`, `softmax`, `log_softmax`, `softplus`, `silu`, `mish`, `elu`, `hardtanh`, `hardsigmoid` - **Losses**: `cross_entropy`, `mse_loss`, `huber_loss`, `kl_div` - **Normalization**: `layernorm`, `batchnorm2d`, `groupnorm`, `instance_norm`, `rms_norm` - **Conv/pool**: `conv2d`, `avgpool2d`, `maxpool2d`, `conv2d_gen` (grouped+dilated), `conv_transpose2d`, `avgpool2d_s`, `maxpool2d_s` - **Extra ops**: `square`, `rsqrt`, `reciprocal`, `var`, `std`, `gather`, `pad2d`, `cumsum`, `flip`, `logsumexp`, `logaddexp`, `l2_normalize`, `embedding` - **Quantization**: `fake_quant`, `fake_quant_per_channel`, `fake_quant_affine`, `fake_quant_lsq_plus` - …[truncated 208 chars] agentId: a7f28f9504bf1bf74 (use SendMessage with to: 'a7f28f9504bf1bf74', summary: '<5-10 word recap>' to continue this agent) <usage>subagent_tokens: 85669 tool_uses: 90 duration_ms: 532211</usage>
{
"description": "Implement nn.py forward functions",
"prompt": "\nImplement all forward functions in `/app/submission/nn.py`. Read the file first to see all the stubs. The file has `raise NotImplementedError` in every forward. Here's exactly what each one should do:\n\n**Linear.forward:** `return ag.add(ag.matmul(x, self.weight), self.bias)` if has bias else `ag.matmul(x, self.weight)`\n\n**MLP.forward:** `return x + self.fc2(ag.gelu(self.fc1(x)))`\n\n**LayerNorm.forward:** `return ag.layernorm(x, self.gamma, self.beta, self.eps)`\n\n**Conv2d.forward:** `return ag.conv2d(x, self.weight, bias=self.bias, stride=self.stride, pad=self.padding)`\n\n**MaxPool2d.forward:** `return ag.maxpool2d(x, self.k)`\n\n**AvgPool2d.forward:** `return ag.avgpool2d(x, self.k)`\n\n**WeightQuant.quant:** `return ag.fake_quant(w, self.scale, W_NEG, W_POS)`\n\n**ActQuant.forward:** `return ag.fake_quant(x, self.scale, A_NEG, A_POS)`\n\n**BatchNorm2d.forward:** `return ag.batchnorm2d(x, self.gamma, self.beta, self.eps, self.running_mean, self.running_var, self.momentum, self.training)`\n\n**BatchNorm1d.forward:** `return ag.batchnorm1d(x, self.gamma, self.beta, self.eps, self.running_mean, self.running_var, self.momentum, self.training)` , NOTE: `batchnorm1d` was added to autograd.py\n\n**QConv.forward:**\n```python\nwq = self.wq.quant(self.weight)\nreturn ag.conv2d(x, wq, bias=None, stride=self.stride, pad=1)\n```\n\n**ConvBlock.forward:**\n```python\nh = self.conv(x)\nh = self.bn(h)\nh = ag.relu(h)\nh = self.aq(h)\nreturn h\n```\n\n**QuantCNN.forward:**\n```python\ndef forward(self, X) -> Tensor:\n \n…[truncated 6116 chars]"
}/app/submission/nn.py
1 """QAT layers + a small INT2 CNN, built on YOUR autograd engine.
2
3 Implement every ``# TODO`` forward (the parameters + ``named_params``/``buffers`` naming are
4 already wired for you; you compose the autograd ops). The grader checks each layer's forward
5 against its OWN reference AND finite-difference-checks the gradients that flow through your
6 autograd, so the composition must be exactly right.
7
8 CHECKPOINT NAMING CONTRACT (the grader loads YOUR ``qat_model.npz`` into its own reference
9 QuantCNN by these exact keys/shapes -- do not rename):
10 stem.conv.weight (W0,3,3,3) | stem.conv.wq.scale (1,) | stem.bn.gamma/.beta (W0,) | stem.aq.scale (1,)
11 blocks.{i}.conv.weight (Cout,Cin,3,3) | blocks.{i}.conv.wq.scale (1,)
12 blocks.{i}.bn.gamma/.beta (Cout,) | blocks.{i}.aq.scale (1,)
13 head.weight (Cfeat,n_classes) | head.wq.scale (1,) | head.bias (n_classes,)
14 BN running stats are BUFFERS (saved alongside params, NOT trained by the optimizer, NOT audited):
15 stem.bn.running_mean/.running_var (W0,) | blocks.{i}.bn.running_mean/.running_var (Cout,)
16
17 Quantization: every conv/head WEIGHT is LSQ-quantized to a signed 2-bit grid {-2,-1,0,1} via a
18 per-tensor learnable step before use; every block activation (post-relu) is LSQ-quantized to an
19 unsigned 2-bit grid {0,1,2,3}. Conv = 3x3 same-padding cross-correlation. Linear head = x@weight+bias.
20 """
21 from __future__ import annotations
22
23 from typing import Dict, List
24
25 import numpy as n
…[truncated 35167 chars]/app/submission/nn.py
def forward(self, x: Tensor) -> Tensor:
# TODO: y = x @ weight (+ bias). Use ag.matmul / ag.add.
raise NotImplementedError("Linear.forward") def forward(self, x: Tensor) -> Tensor:
if self.bias is not None:
return ag.add(ag.matmul(x, self.weight), self.bias)
return ag.matmul(x, self.weight)The file /app/submission/nn.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/nn.py
def forward(self, x: Tensor) -> Tensor:
# TODO: out = x + fc2(gelu(fc1(x)))
raise NotImplementedError("MLP.forward") def forward(self, x: Tensor) -> Tensor:
return x + self.fc2(ag.gelu(self.fc1(x)))The file /app/submission/nn.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/nn.py
def forward(self, x: Tensor) -> Tensor:
# TODO: return ag.layernorm(x, self.gamma, self.beta, self.eps)
raise NotImplementedError("LayerNorm.forward") def forward(self, x: Tensor) -> Tensor:
return ag.layernorm(x, self.gamma, self.beta, self.eps)The file /app/submission/nn.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/nn.py
def forward(self, x: Tensor) -> Tensor:
# TODO: return ag.conv2d(x, self.weight, bias=self.bias, stride=self.stride, pad=self.padding)
raise NotImplementedError("Conv2d.forward") def forward(self, x: Tensor) -> Tensor:
return ag.conv2d(x, self.weight, bias=self.bias, stride=self.stride, pad=self.padding)The file /app/submission/nn.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/nn.py
def forward(self, x: Tensor) -> Tensor:
# TODO: return ag.maxpool2d(x, self.k)
raise NotImplementedError("MaxPool2d.forward") def forward(self, x: Tensor) -> Tensor:
return ag.maxpool2d(x, self.k)The file /app/submission/nn.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/nn.py
def forward(self, x: Tensor) -> Tensor:
# TODO: return ag.avgpool2d(x, self.k)
raise NotImplementedError("AvgPool2d.forward") def forward(self, x: Tensor) -> Tensor:
return ag.avgpool2d(x, self.k)The file /app/submission/nn.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/nn.py
def quant(self, w: Tensor) -> Tensor:
# TODO: return ag.fake_quant(w, self.scale, W_NEG, W_POS)
raise NotImplementedError("WeightQuant.quant") def quant(self, w: Tensor) -> Tensor:
return ag.fake_quant(w, self.scale, W_NEG, W_POS)The file /app/submission/nn.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/nn.py
def forward(self, x: Tensor) -> Tensor:
# TODO: return ag.fake_quant(x, self.scale, A_NEG, A_POS)
raise NotImplementedError("ActQuant.forward") def forward(self, x: Tensor) -> Tensor:
return ag.fake_quant(x, self.scale, A_NEG, A_POS)The file /app/submission/nn.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/nn.py
def forward(self, x: Tensor) -> Tensor:
# TODO: ag.batchnorm2d(x, gamma, beta, eps, running_mean, running_var, momentum, training)
raise NotImplementedError("BatchNorm2d.forward") def forward(self, x: Tensor) -> Tensor:
return ag.batchnorm2d(x, self.gamma, self.beta, self.eps, self.running_mean, self.running_var, self.momentum, self.training)The file /app/submission/nn.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/nn.py
def forward(self, x: Tensor) -> Tensor:
# TODO: ag.batchnorm1d(x, gamma, beta, eps, running_mean, running_var, momentum, training)
raise NotImplementedError("BatchNorm1d.forward") def forward(self, x: Tensor) -> Tensor:
return ag.batchnorm1d(x, self.gamma, self.beta, self.eps, self.running_mean, self.running_var, self.momentum, self.training)The file /app/submission/nn.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/nn.py
def forward(self, x: Tensor) -> Tensor:
# TODO: wq = self.wq.quant(self.weight); return ag.conv2d(x, wq, bias=None, stride, pad=1)
raise NotImplementedError("QConv.forward") def forward(self, x: Tensor) -> Tensor:
wq = self.wq.quant(self.weight)
return ag.conv2d(x, wq, bias=None, stride=self.stride, pad=1)The file /app/submission/nn.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/nn.py
def forward(self, x: Tensor) -> Tensor:
# TODO: h = aq(relu(bn(conv(x)))) -- in that order.
raise NotImplementedError("ConvBlock.forward") def forward(self, x: Tensor) -> Tensor:
h = self.conv(x)
h = self.bn(h)
h = ag.relu(h)
h = self.aq(h)
return hThe file /app/submission/nn.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/nn.py
def forward(self, X) -> Tensor:
# TODO: run the stem + blocks, global-average-pool, then the (2-bit) linear head.
raise NotImplementedError("QuantCNN.forward") def forward(self, X) -> Tensor:
x = Tensor(np.asarray(X, dtype=np.float64)) if not isinstance(X, Tensor) else X
h = self.stem(x)
for b in self.blocks:
h = b(h)
N, C, H, W = h.data.shape
h = ag.avgpool2d(h, H)
h = ag.reshape(h, (N, C))
wq = self.head_wq.quant(self.head_w)
logits = ag.add(ag.matmul(h, wq), self.head_b)
return logitsThe file /app/submission/nn.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/nn.py
def forward(self, x: Tensor) -> Tensor:
# TODO: wq = self.wq.quant(self.weight); return ag.add(ag.matmul(x, wq), self.bias)
raise NotImplementedError("QLinear.forward") def forward(self, x: Tensor) -> Tensor:
wq = self.wq.quant(self.weight)
return ag.add(ag.matmul(x, wq), self.bias)The file /app/submission/nn.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/nn.py
def forward(self, X) -> Tensor:
# TODO: x -> reshape (N, in_dim); for each layer L: h = L["aq"](relu(L["bn"](L["fc"](h))));
# then return self.head(h).
raise NotImplementedError("QuantMLP.forward") def forward(self, X) -> Tensor:
x = X if isinstance(X, Tensor) else Tensor(np.asarray(X, dtype=np.float64))
N = x.data.shape[0]
h = ag.reshape(x, (N, self.in_dim))
for L in self.layers:
h = L["fc"](h)
h = L["bn"](h)
h = ag.relu(h)
h = L["aq"](h)
return self.head(h)The file /app/submission/nn.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/nn.py
def forward(self, x: Tensor) -> Tensor:
# TODO: return ag.silu(x)
raise NotImplementedError("SiLU.forward") def forward(self, x: Tensor) -> Tensor:
return ag.silu(x)The file /app/submission/nn.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/nn.py
def forward(self, x: Tensor) -> Tensor:
# TODO: return ag.elu(x, self.alpha)
raise NotImplementedError("ELU.forward") def forward(self, x: Tensor) -> Tensor:
return ag.elu(x, self.alpha)The file /app/submission/nn.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/nn.py
def forward(self, x: Tensor) -> Tensor:
# TODO: return ag.groupnorm(x, self.gamma, self.beta, self.num_groups, self.eps)
raise NotImplementedError("GroupNorm.forward") def forward(self, x: Tensor) -> Tensor:
return ag.groupnorm(x, self.gamma, self.beta, self.num_groups, self.eps)The file /app/submission/nn.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/nn.py
def forward(self, x: Tensor, h: Tensor) -> Tensor:
# TODO: return ag.tanh(x@Wx + h@Wh + b)
raise NotImplementedError("RNNCell.forward") def forward(self, x: Tensor, h: Tensor) -> Tensor:
return ag.tanh(ag.add(ag.add(ag.matmul(x, self.Wx), ag.matmul(h, self.Wh)), self.b))The file /app/submission/nn.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/nn.py
def forward(self, x: Tensor, h: Tensor) -> Tensor:
# TODO: implement the GRU update with the named weights above.
raise NotImplementedError("GRUCell.forward") def forward(self, x: Tensor, h: Tensor) -> Tensor:
z = ag.sigmoid(ag.add(ag.add(ag.matmul(x, self.Wxz), ag.matmul(h, self.Whz)), self.bz))
r = ag.sigmoid(ag.add(ag.add(ag.matmul(x, self.Wxr), ag.matmul(h, self.Whr)), self.br))
n = ag.tanh(ag.add(ag.add(ag.matmul(x, self.Wxn), ag.matmul(ag.mul(r, h), self.Whn)), self.bn))
h_new = ag.add(ag.mul(ag.sub(Tensor(np.ones_like(z.data)), z), n), ag.mul(z, h))
return h_newThe file /app/submission/nn.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/nn.py
def forward(self, x: Tensor, h: Tensor, c: Tensor):
# TODO: implement the LSTM update; return (h2, c2).
raise NotImplementedError("LSTMCell.forward") def forward(self, x: Tensor, h: Tensor, c: Tensor):
i = ag.sigmoid(ag.add(ag.add(ag.matmul(x, self.Wxi), ag.matmul(h, self.Whi)), self.bi))
f = ag.sigmoid(ag.add(ag.add(ag.matmul(x, self.Wxf), ag.matmul(h, self.Whf)), self.bf))
g = ag.tanh(ag.add(ag.add(ag.matmul(x, self.Wxg), ag.matmul(h, self.Whg)), self.bg))
o = ag.sigmoid(ag.add(ag.add(ag.matmul(x, self.Wxo), ag.matmul(h, self.Who)), self.bo))
c2 = ag.add(ag.mul(f, c), ag.mul(i, g))
h2 = ag.mul(o, ag.tanh(c2))
return h2, c2The file /app/submission/nn.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/nn.py
def quant(self, w: Tensor) -> Tensor:
# TODO: return ag.fake_quant_per_channel(w, self.scale, self.neg, self.pos, axis=0)
raise NotImplementedError("PerChannelWeightQuant.quant") def quant(self, w: Tensor) -> Tensor:
return ag.fake_quant_per_channel(w, self.scale, self.neg, self.pos, axis=0)The file /app/submission/nn.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/nn.py
def forward(self, x: Tensor) -> Tensor:
# TODO: return ag.fake_quant_affine(x, self.scale, self.zero_point, self.neg, self.pos)
raise NotImplementedError("AffineActQuant.forward") def forward(self, x: Tensor) -> Tensor:
return ag.fake_quant_affine(x, self.scale, self.zero_point, self.neg, self.pos)The file /app/submission/nn.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/nn.py
def forward(self, x: Tensor) -> Tensor:
# TODO: return ag.rms_norm(x, self.gamma, self.eps)
raise NotImplementedError("RMSNorm.forward") def forward(self, x: Tensor) -> Tensor:
return ag.rms_norm(x, self.gamma, self.eps)The file /app/submission/nn.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/nn.py
def forward(self, x: Tensor) -> Tensor:
# TODO: return ag.instance_norm(x, self.gamma, self.beta, self.eps)
raise NotImplementedError("InstanceNorm2d.forward") def forward(self, x: Tensor) -> Tensor:
return ag.instance_norm(x, self.gamma, self.beta, self.eps)The file /app/submission/nn.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/nn.py
def forward(self, idx) -> Tensor:
# TODO: return ag.embedding(self.weight, idx)
raise NotImplementedError("Embedding.forward") def forward(self, idx) -> Tensor:
return ag.embedding(self.weight, idx)The file /app/submission/nn.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/nn.py
def forward(self, x: Tensor) -> Tensor:
# TODO: return ag.conv_transpose2d(x, self.weight, bias=self.bias, stride=self.stride, pad=self.padding)
raise NotImplementedError("ConvTranspose2d.forward") def forward(self, x: Tensor) -> Tensor:
return ag.conv_transpose2d(x, self.weight, bias=self.bias, stride=self.stride, pad=self.padding)The file /app/submission/nn.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/nn.py
def forward(self, x: Tensor) -> Tensor:
# TODO: return ag.conv2d_gen(x, self.weight, bias=self.bias, stride=self.stride,
# pad=self.padding, dilation=self.dilation, groups=1)
raise NotImplementedError("DilatedConv2d.forward") def forward(self, x: Tensor) -> Tensor:
return ag.conv2d_gen(x, self.weight, bias=self.bias, stride=self.stride, pad=self.padding, dilation=self.dilation, groups=1)The file /app/submission/nn.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/nn.py
def forward(self, x: Tensor) -> Tensor:
# TODO: return ag.fake_quant_lsq_plus(x, self.scale, self.beta, self.neg, self.pos)
raise NotImplementedError("LSQPlusActQuant.forward") def forward(self, x: Tensor) -> Tensor:
return ag.fake_quant_lsq_plus(x, self.scale, self.beta, self.neg, self.pos)The file /app/submission/nn.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/nn.py
def forward(self, x: Tensor) -> Tensor:
# TODO: depthwise conv2d_gen(groups=Cin) on the LSQ-quantized dw_weight, then pointwise
# conv2d_gen(groups=1) on the LSQ-quantized pw_weight.
raise NotImplementedError("QDWSepConv.forward") def forward(self, x: Tensor) -> Tensor:
dw_q = self.dw_wq.quant(self.dw_weight)
h = ag.conv2d_gen(x, dw_q, bias=None, stride=self.stride, pad=1, dilation=1, groups=self.Cin)
pw_q = self.pw_wq.quant(self.pw_weight)
h = ag.conv2d_gen(h, pw_q, bias=None, stride=1, pad=0, dilation=1, groups=1)
return hThe file /app/submission/nn.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/nn.py
def forward(self, x: Tensor) -> Tensor:
# TODO: conv -> bn -> relu -> aq
raise NotImplementedError("QSepBlock.forward") def forward(self, x: Tensor) -> Tensor:
h = self.conv(x)
h = self.bn(h)
h = ag.relu(h)
h = self.aq(h)
return hThe file /app/submission/nn.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/nn.py
def forward(self, X) -> Tensor:
# TODO: stem -> blocks -> avgpool2d(full window) -> reshape (N,C) -> matmul(LSQ head) + bias
raise NotImplementedError("QuantSepCNN.forward") def forward(self, X) -> Tensor:
x = X if isinstance(X, Tensor) else Tensor(np.asarray(X, dtype=np.float64))
h = self.stem(x)
for b in self.blocks:
h = b(h)
N, C, H, W = h.data.shape
h = ag.avgpool2d(h, H)
h = ag.reshape(h, (N, C))
wq = self.head_wq.quant(self.head_w)
logits = ag.add(ag.matmul(h, wq), self.head_b)
return logitsThe file /app/submission/nn.py has been updated successfully. (file state is current in your context , no need to Read it back)
python3 run_checks.py --only nn_forward 2>&1
[nn_forward] 53/53 fwd/softmax_sums_to_1 OK (row_sum_err=1.1e-16) fwd/log_softmax_eq_log_softmax OK fwd/relu_def OK fwd/leaky_relu_def OK fwd/sigmoid_def OK fwd/tanh_def OK fwd/gelu_erf_def OK fwd/exp_log_inverse OK fwd/cross_entropy_value OK (got=3.2296 ref=3.2296) fwd/mse_value OK fwd/layernorm_zero_mean_unit_var OK fwd/batchnorm2d_zero_mean_unit_var OK fwd/batchnorm1d_zero_mean_unit_var OK fwd/conv2d_shape OK (shape=(2, 5, 8, 8)) fwd/conv2d_stride_shape OK (shape=(2, 4, 4, 4)) fwd/maxpool2d_def OK fwd/avgpool2d_def OK fwd/fake_quant_grid_w OK (unique=4) fwd/fake_quant_grid_a OK (unique=4) fwd/Linear_def OK fwd/MLP_shape OK (shape=(2, 3, 8)) fwd/QuantCNN_shape OK fwd/QuantMLP_shape OK fwd/QuantCNN_state_dict_roundtrip OK (keys=24) fwd/QuantMLP_state_dict_roundtrip OK (keys=19) fwd/square_def OK fwd/rsqrt_def OK fwd/var_def …[truncated 1612 chars]
python3 run_checks.py --only autograd_grads 2>&1
[autograd_grads] 115/115 grad/add_bcast OK (max_abs=3.17e-10) grad/sub_bcast OK (max_abs=3.17e-10) grad/mul_bcast OK (max_abs=1.02e-10) grad/div OK (max_abs=1.89e-11) grad/div_denom OK (max_abs=6.86e-11) grad/power2 OK (max_abs=2.34e-10) grad/power3 OK (max_abs=2.06e-10) grad/maximum OK (max_abs=6.55e-12) grad/minimum OK (max_abs=6.55e-12) grad/where OK (max_abs=7.48e-11) grad/exp OK (max_abs=1.72e-10) grad/log OK (max_abs=2.05e-10) grad/sqrt OK (max_abs=3.39e-10) grad/abs OK (max_abs=5.10e-11) grad/clip OK (max_abs=6.55e-12) grad/matmul OK (max_abs=1.14e-10) grad/matmul_batched OK (max_abs=2.42e-10) grad/transpose OK (max_abs=5.10e-11) grad/transpose_axes OK (max_abs=5.10e-11) grad/reshape OK (max_abs=3.79e-11) grad/getitem_index OK (max_abs=3.79e-11) grad/getitem_slice OK …[truncated 5677 chars]
Both check suites pass perfectly: - `nn_forward`: 53/53 , all forward functions implemented correctly - `autograd_grads`: 115/115 , all gradient checks pass, including the new layers (RNNCell, GRUCell, LSTMCell, SiLU, ELU, GroupNorm, RMSNorm, InstanceNorm2d, ConvTranspose2d, DilatedConv2d, Embedding, etc.) Here is a summary of what was implemented in `/app/submission/nn.py`: - **Linear.forward**: matmul + optional bias add - **MLP.forward**: residual `x + fc2(gelu(fc1(x)))` - **LayerNorm/BatchNorm2d/BatchNorm1d/GroupNorm/RMSNorm/InstanceNorm2d**: delegated to corresponding `ag.*` ops - **Conv2d/MaxPool2d/AvgPool2d/ConvTranspose2d/DilatedConv2d**: delegated to `ag.conv2d`, `ag.maxpool2d`, `ag.avgpool2d`, `ag.conv_transpose2d`, `ag.conv2d_gen` - **WeightQuant.quant / ActQuant.forward**: `ag.fake_quant` with appropriate W/A neg/pos bounds - **PerChannelWeightQuant.quant**: `ag.fake_quant_per_channel` - **AffineActQuant.forward**: `ag.fake_quant_affine` - **LSQPlusActQuant.forward**: `ag.fake_quant_lsq_plus` - **QConv / QLinear**: quantize weight first, then conv/matmul - **ConvBlock / QSepBlock**: conv -> bn -> relu -> aq pipeline - **QuantCNN / QuantSepCNN.forward**: stem -> blocks -> global avgpool -> reshape -> quantized head - **QuantMLP.forward**: flatten -> [fc -> bn -> relu -> aq] layers -> head - **SiLU/ELU**: `ag.silu`, `ag.elu` - **RNNCell/GRUCell/LSTMCell**: full recurrent cell implementations using `ag.tanh/sigmoid/mul/add/sub/matmul` - **QDWSepConv**: depthwise c …[truncated 91 chars] agentId: affade11118e96972 (use SendMessage with to: 'affade11118e96972', summary: '<5-10 word recap>' to continue this agent) <usage>subagent_tokens: 41186 tool_uses: 35 duration_ms: 205271</usage>
{
"description": "Implement optim.py optimizers and schedulers",
"prompt": "\nImplement all optimizer step functions and LR schedulers in `/app/submission/optim.py`. Read the file first to understand the structure.\n\nThe `_normalize_groups` function is already provided. Each optimizer has `self._groups` (list of (params_list, wd_override_or_None)) and `self.params` (flat list). The momentum/moment buffers in `self._v`, `self._m`, `self._u`, `self._s`, `self._d` are indexed in the SAME order as `self.params`.\n\nYou need to iterate over groups and track the index into `self.params` to find the right buffer index.\n\nHere's the exact implementation for each:\n\n**SGD.step:**\n```python\ndef step(self):\n idx = 0\n for (group_params, wd_override) in self._groups:\n wd = self.weight_decay if wd_override is None else wd_override\n for p in group_params:\n if p.grad is None:\n idx += 1\n continue\n g = p.grad + wd * p.data\n self._v[idx] = self.momentum * self._v[idx] + g\n p.data -= self.lr * self._v[idx]\n idx += 1\n```\n\n**AdamW.step** (DECOUPLED weight decay):\n```python\ndef step(self):\n self.t += 1\n idx = 0\n for (group_params, wd_override) in self._groups:\n wd = self.weight_decay if wd_override is None else wd_override\n for p in group_params:\n if p.grad is None:\n idx += 1\n continue\n g = p.grad\n self._m[idx] = self.b1 * self._m[idx] + (1 - self.b1) * g\n self._v[idx] = self.b2 *\n…[truncated 8540 chars]"
}{
"description": "Implement data.py normalize and iter_minibatches",
"prompt": "\nImplement two functions in `/app/submission/data.py`. Read the file first.\n\nThe file has two stubs:\n\n**normalize(X):**\nConvert uint8 (N,3,S,S) to float64 using: `x = (X/255 - 0.5) / 0.25`\n```python\ndef normalize(X: np.ndarray) -> np.ndarray:\n return (X.astype(np.float64) / 255.0 - 0.5) / 0.25\n```\n\n**iter_minibatches:**\nYield (xb, yb) minibatches over one epoch with optional shuffling:\n```python\ndef iter_minibatches(Xn, y, batch_size, rng, shuffle=True):\n N = len(Xn)\n idx = np.arange(N)\n if shuffle:\n rng.shuffle(idx)\n for start in range(0, N, batch_size):\n end = min(start + batch_size, N)\n batch_idx = idx[start:end]\n yield Xn[batch_idx], y[batch_idx]\n```\n\nPlease implement these two functions in `/app/submission/data.py`.\n\nAfter implementing, run:\n```\npython3 /app/run_checks.py --only data\n```\n\nFix any issues.\n"
}/app/submission/optim.py
1 """Optimizers over autograd ``Tensor`` parameters.
2
3 Implement the ``# TODO`` update math. Both optimizers update ``param.data`` IN PLACE using
4 ``param.grad``. The grader runs one (and several) steps and compares your updated params against
5 its reference within a tight tolerance, so the math must be exact.
6
7 SGD (with momentum ``mu`` and coupled weight decay ``wd``):
8 g = grad + wd * param; v = mu * v + g; param -= lr * v
9
10 AdamW (DECOUPLED weight decay -- the decay is applied to the PARAM, not folded into the moments):
11 m = b1*m + (1-b1)*g; v = b2*v + (1-b2)*g^2
12 mhat = m / (1 - b1^t); vhat = v / (1 - b2^t) # t = 1-based step count
13 param -= lr * ( mhat / (sqrt(vhat) + eps) + wd * param )
14
15 PARAM GROUPS: both optimizers must accept EITHER a flat param list OR a list of
16 ``{"params": [...], "weight_decay": wd}`` dicts, so weight decay can be applied to SOME params
17 and not others. This matters for low-bit LSQ QAT: the per-tensor quantizer ``scale`` params,
18 BatchNorm gamma/beta, and biases must be EXCLUDED from weight decay. ``_normalize_groups`` and
19 ``split_decay_params`` are provided; honour the per-group weight decay in ``step``.
20 """
21 from __future__ import annotations
22
23 import math
24
25 from typing import Dict, List
26
27 import numpy as np
28
29 from autograd import Tensor
30
31
32 def split_decay_params(model) -> Dict[str, List[Tensor]]:
33 """Partition a model's named params into weight
…[truncated 11129 chars]/app/submission/data.py
1 """Image data loading + normalization + batching.
2
3 The dataset is a procedurally-generated CIFAR-style set: ``X`` is ``uint8`` (N,3,S,S) in [0,255],
4 ``y`` is the integer class label in [0, n_classes). The shipped training split is at
5 ``/app/data/train.npz``; the SEALED held-out split is regenerated by the verifier (never shipped).
6
7 Implement the ``# TODO`` bodies (numpy only). The verifier normalizes the held-out split with the
8 SAME transform, so match it exactly.
9
10 Contract:
11 load_npz(path) -> (X uint8 (N,3,S,S), y int64 (N,)) [provided]
12 normalize(X) -> float64: x = (X/255 - 0.5) / 0.25 [per-channel, the grader's transform]
13 iter_minibatches(Xn, y, batch_size, rng, shuffle=True) -> yields (xb, yb)
14 """
15 from __future__ import annotations
16
17 from typing import Tuple
18
19 import numpy as np
20
21 NORM_MEAN = 0.5
22 NORM_STD = 0.25
23
24
25 def load_npz(path: str) -> Tuple[np.ndarray, np.ndarray]:
26 d = np.load(path)
27 X = np.asarray(d["X"]).astype(np.uint8)
28 y = np.asarray(d["y"]).astype(np.int64).reshape(-1)
29 return X, y
30
31
32 def normalize(X: np.ndarray) -> np.ndarray:
33 """uint8 (N,3,S,S) -> float64, x = (X/255 - NORM_MEAN) / NORM_STD."""
34 # TODO: cast to float, scale to [0,1], subtract NORM_MEAN, divide by NORM_STD.
35 raise NotImplementedError("normalize")
36
37
38 def iter_minibatches(Xn: np.ndarray, y: np.ndarray, batch_size: int,
39 rng: np.rando
…[truncated 281 chars]/app/submission/data.py
def normalize(X: np.ndarray) -> np.ndarray:
"""uint8 (N,3,S,S) -> float64, x = (X/255 - NORM_MEAN) / NORM_STD."""
# TODO: cast to float, scale to [0,1], subtract NORM_MEAN, divide by NORM_STD.
raise NotImplementedError("normalize")def normalize(X: np.ndarray) -> np.ndarray:
"""uint8 (N,3,S,S) -> float64, x = (X/255 - NORM_MEAN) / NORM_STD."""
return (X.astype(np.float64) / 255.0 - NORM_MEAN) / NORM_STDThe file /app/submission/data.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/optim.py
def step(self):
# TODO: SGD(+momentum, +per-group weight decay) update. Iterate self._groups; for each
# group use wd = self.weight_decay if override is None else override; keep a momentum
# buffer per parameter (self._v is indexed in self.params order).
raise NotImplementedError("SGD.step") def step(self):
idx = 0
for (group_params, wd_override) in self._groups:
wd = self.weight_decay if wd_override is None else wd_override
for p in group_params:
if p.grad is None:
idx += 1
continue
g = p.grad + wd * p.data
self._v[idx] = self.momentum * self._v[idx] + g
p.data -= self.lr * self._v[idx]
idx += 1The file /app/submission/optim.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/data.py
def iter_minibatches(Xn: np.ndarray, y: np.ndarray, batch_size: int,
rng: np.random.Generator, shuffle: bool = True):
"""Yield (xb, yb) minibatches over one epoch. ``Xn`` is already normalized float."""
# TODO: optionally shuffle an index array, then yield contiguous batch_size slices of it.
raise NotImplementedError("iter_minibatches")def iter_minibatches(Xn: np.ndarray, y: np.ndarray, batch_size: int,
rng: np.random.Generator, shuffle: bool = True):
"""Yield (xb, yb) minibatches over one epoch. ``Xn`` is already normalized float."""
N = len(Xn)
idx = np.arange(N)
if shuffle:
rng.shuffle(idx)
for start in range(0, N, batch_size):
end = min(start + batch_size, N)
batch_idx = idx[start:end]
yield Xn[batch_idx], y[batch_idx]The file /app/submission/data.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/optim.py
def step(self):
# TODO: AdamW with bias correction + DECOUPLED, per-group weight decay (see docstring).
raise NotImplementedError("AdamW.step") def step(self):
self.t += 1
idx = 0
for (group_params, wd_override) in self._groups:
wd = self.weight_decay if wd_override is None else wd_override
for p in group_params:
if p.grad is None:
idx += 1
continue
g = p.grad
self._m[idx] = self.b1 * self._m[idx] + (1 - self.b1) * g
self._v[idx] = self.b2 * self._v[idx] + (1 - self.b2) * g * g
mhat = self._m[idx] / (1 - self.b1**self.t)
vhat = self._v[idx] / (1 - self.b2**self.t)
p.data -= self.lr * (mhat / (np.sqrt(vhat) + self.eps) + wd * p.data)
idx += 1The file /app/submission/optim.py has been updated successfully. (file state is current in your context , no need to Read it back)
Run data checks
python3 /app/run_checks.py --only data 2>&1
[data] 2/2 data/normalize_def OK data/iter_minibatches_cover OK (covered 23/23) ------------------------------------------------------------------------ data 2/2 TOTAL 2/2 public checks passing All public checks pass. Now train qat_model.npz to clear the held-out top-1 threshold (the grader re-checks components with DIFFERENT seeds).
/app/submission/optim.py
def step(self):
# TODO: Adam with bias correction + COUPLED, per-group weight decay (see docstring).
raise NotImplementedError("Adam.step") def step(self):
self.t += 1
idx = 0
for (group_params, wd_override) in self._groups:
wd = self.weight_decay if wd_override is None else wd_override
for p in group_params:
if p.grad is None:
idx += 1
continue
g = p.grad + wd * p.data
self._m[idx] = self.b1 * self._m[idx] + (1 - self.b1) * g
self._v[idx] = self.b2 * self._v[idx] + (1 - self.b2) * g * g
mhat = self._m[idx] / (1 - self.b1**self.t)
vhat = self._v[idx] / (1 - self.b2**self.t)
p.data -= self.lr * mhat / (np.sqrt(vhat) + self.eps)
idx += 1The file /app/submission/optim.py has been updated successfully. (file state is current in your context , no need to Read it back)
Both checks pass. The implementation: - `normalize`: Casts the uint8 array to float64, divides by 255 to scale to [0,1], subtracts `NORM_MEAN` (0.5), and divides by `NORM_STD` (0.25) , using the module-level constants rather than hardcoded values. - `iter_minibatches`: Creates an index array of length N, optionally shuffles it in-place using the provided `rng`, then yields `(Xn[batch_idx], y[batch_idx])` slices of up to `batch_size` elements per iteration. Both checks pass: `data/normalize_def` and `data/iter_minibatches_cover` (23/23 lines covered). Score: 2/2. agentId: a7cf2c258f4809dae (use SendMessage with to: 'a7cf2c258f4809dae', summary: '<5-10 word recap>' to continue this agent) <usage>subagent_tokens: 12885 tool_uses: 4 duration_ms: 25871</usage>
/app/submission/optim.py
def step(self):
# TODO: RMSprop update with per-group weight decay (see docstring).
raise NotImplementedError("RMSprop.step") def step(self):
idx = 0
for (group_params, wd_override) in self._groups:
wd = self.weight_decay if wd_override is None else wd_override
for p in group_params:
if p.grad is None:
idx += 1
continue
g = p.grad + wd * p.data
self._s[idx] = self.alpha * self._s[idx] + (1 - self.alpha) * g * g
p.data -= self.lr * g / (np.sqrt(self._s[idx]) + self.eps)
idx += 1The file /app/submission/optim.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/optim.py
def step(self):
# TODO: Adagrad update with per-group weight decay (see docstring).
raise NotImplementedError("Adagrad.step") def step(self):
idx = 0
for (group_params, wd_override) in self._groups:
wd = self.weight_decay if wd_override is None else wd_override
for p in group_params:
if p.grad is None:
idx += 1
continue
g = p.grad + wd * p.data
self._s[idx] += g * g
p.data -= self.lr * g / (np.sqrt(self._s[idx]) + self.eps)
idx += 1The file /app/submission/optim.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/optim.py
def step(self):
# TODO: Lion update with per-group (decoupled) weight decay (see docstring).
raise NotImplementedError("Lion.step") def step(self):
idx = 0
for (group_params, wd_override) in self._groups:
wd = self.weight_decay if wd_override is None else wd_override
for p in group_params:
if p.grad is None:
idx += 1
continue
g = p.grad
update = np.sign(self.b1 * self._m[idx] + (1 - self.b1) * g)
p.data -= self.lr * (update + wd * p.data)
self._m[idx] = self.b2 * self._m[idx] + (1 - self.b2) * g
idx += 1The file /app/submission/optim.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/optim.py
def cosine_lr(step, total, base_lr, warmup=0, min_lr=0.0):
"""Linear warmup for ``warmup`` steps (lr = base_lr*(step+1)/warmup), then cosine decay from
``base_lr`` to ``min_lr`` over the remaining (total - warmup) steps. Return the LR at ``step``."""
# TODO
raise NotImplementedError("cosine_lr")def cosine_lr(step, total, base_lr, warmup=0, min_lr=0.0):
"""Linear warmup for ``warmup`` steps (lr = base_lr*(step+1)/warmup), then cosine decay from
``base_lr`` to ``min_lr`` over the remaining (total - warmup) steps. Return the LR at ``step``."""
if warmup > 0 and step < warmup:
return base_lr * (step + 1) / warmup
remaining = total - warmup
t = min(step - warmup, remaining)
progress = t / max(1, remaining)
return min_lr + 0.5 * (base_lr - min_lr) * (1 + np.cos(np.pi * progress))The file /app/submission/optim.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/optim.py
def warmup_lr(step, base_lr, warmup):
"""Linear warmup to ``base_lr`` over ``warmup`` steps (lr = base_lr*(step+1)/warmup), then
constant ``base_lr``."""
# TODO
raise NotImplementedError("warmup_lr")def warmup_lr(step, base_lr, warmup):
"""Linear warmup to ``base_lr`` over ``warmup`` steps (lr = base_lr*(step+1)/warmup), then
constant ``base_lr``."""
if step < warmup:
return base_lr * (step + 1) / warmup
return base_lrThe file /app/submission/optim.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/optim.py
def step_lr(step, base_lr, step_size, gamma=0.1):
"""Step decay: base_lr * gamma ** (step // step_size)."""
# TODO
raise NotImplementedError("step_lr")def step_lr(step, base_lr, step_size, gamma=0.1):
"""Step decay: base_lr * gamma ** (step // step_size)."""
return base_lr * (gamma ** (step // step_size))The file /app/submission/optim.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/optim.py
def exponential_lr(step, base_lr, gamma=0.97):
"""Exponential decay: base_lr * gamma ** step."""
# TODO
raise NotImplementedError("exponential_lr")def exponential_lr(step, base_lr, gamma=0.97):
"""Exponential decay: base_lr * gamma ** step."""
return base_lr * (gamma ** step)The file /app/submission/optim.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/optim.py
def clip_grad_norm(params: List[Tensor], max_norm: float) -> float:
"""GLOBAL L2 gradient-norm clip. Returns the PRE-CLIP total norm. If it exceeds ``max_norm``,
scale every grad by ``max_norm / (total_norm + 1e-6)``."""
# TODO: compute the global L2 norm over all param grads; scale in place if it exceeds max_norm.
raise NotImplementedError("clip_grad_norm")def clip_grad_norm(params: List[Tensor], max_norm: float) -> float:
"""GLOBAL L2 gradient-norm clip. Returns the PRE-CLIP total norm. If it exceeds ``max_norm``,
scale every grad by ``max_norm / (total_norm + 1e-6)``."""
total_norm = np.sqrt(sum(np.sum(p.grad**2) for p in params if p.grad is not None))
if total_norm > max_norm:
scale = max_norm / (total_norm + 1e-6)
for p in params:
if p.grad is not None:
p.grad *= scale
return float(total_norm)The file /app/submission/optim.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/optim.py
def step(self):
# TODO: implement the Adamax update honouring per-group weight decay.
raise NotImplementedError("Adamax.step") def step(self):
self.t += 1
idx = 0
for (group_params, wd_override) in self._groups:
wd = self.weight_decay if wd_override is None else wd_override
for p in group_params:
if p.grad is None:
idx += 1
continue
g = p.grad + wd * p.data
self._m[idx] = self.b1 * self._m[idx] + (1 - self.b1) * g
self._u[idx] = np.maximum(self.b2 * self._u[idx], np.abs(g))
bias_corr = 1 - self.b1**self.t
p.data -= (self.lr / bias_corr) * self._m[idx] / (self._u[idx] + self.eps)
idx += 1The file /app/submission/optim.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/optim.py
def step(self):
# TODO: implement the NAdam update honouring per-group weight decay.
raise NotImplementedError("NAdam.step") def step(self):
self.t += 1
idx = 0
for (group_params, wd_override) in self._groups:
wd = self.weight_decay if wd_override is None else wd_override
for p in group_params:
if p.grad is None:
idx += 1
continue
g = p.grad + wd * p.data
self._m[idx] = self.b1 * self._m[idx] + (1 - self.b1) * g
self._v[idx] = self.b2 * self._v[idx] + (1 - self.b2) * g * g
mhat = self.b1 * self._m[idx] / (1 - self.b1**(self.t+1)) + (1 - self.b1) * g / (1 - self.b1**self.t)
vhat = self._v[idx] / (1 - self.b2**self.t)
p.data -= self.lr * mhat / (np.sqrt(vhat) + self.eps)
idx += 1The file /app/submission/optim.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/optim.py
def step(self):
# TODO: implement the Adadelta update honouring per-group weight decay.
raise NotImplementedError("Adadelta.step") def step(self):
idx = 0
for (group_params, wd_override) in self._groups:
wd = self.weight_decay if wd_override is None else wd_override
for p in group_params:
if p.grad is None:
idx += 1
continue
g = p.grad + wd * p.data
self._s[idx] = self.rho * self._s[idx] + (1 - self.rho) * g * g
delta = np.sqrt(self._d[idx] + self.eps) / np.sqrt(self._s[idx] + self.eps) * g
p.data -= self.lr * delta
self._d[idx] = self.rho * self._d[idx] + (1 - self.rho) * delta * delta
idx += 1The file /app/submission/optim.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/optim.py
def step(self):
# TODO: implement the Nesterov-SGD update honouring per-group weight decay.
raise NotImplementedError("NesterovSGD.step") def step(self):
idx = 0
for (group_params, wd_override) in self._groups:
wd = self.weight_decay if wd_override is None else wd_override
for p in group_params:
if p.grad is None:
idx += 1
continue
g = p.grad + wd * p.data
self._v[idx] = self.momentum * self._v[idx] + g
p.data -= self.lr * (g + self.momentum * self._v[idx])
idx += 1The file /app/submission/optim.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/optim.py
def polynomial_lr(step, total, base_lr, power=2.0, min_lr=0.0):
"""Polynomial decay: min_lr + (base_lr - min_lr) * (1 - step/total)^power (clamped at total)."""
# TODO
raise NotImplementedError("polynomial_lr")def polynomial_lr(step, total, base_lr, power=2.0, min_lr=0.0):
"""Polynomial decay: min_lr + (base_lr - min_lr) * (1 - step/total)^power (clamped at total)."""
t = min(step, total)
return min_lr + (base_lr - min_lr) * (1 - t / total) ** powerThe file /app/submission/optim.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/optim.py
def linear_lr(step, total, base_lr, min_lr=0.0):
"""Linear decay from base_lr to min_lr over ``total`` steps, then constant at min_lr."""
# TODO
raise NotImplementedError("linear_lr")def linear_lr(step, total, base_lr, min_lr=0.0):
"""Linear decay from base_lr to min_lr over ``total`` steps, then constant at min_lr."""
if step >= total:
return min_lr
return min_lr + (base_lr - min_lr) * (1 - step / total)The file /app/submission/optim.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/optim.py
def multistep_lr(step, base_lr, milestones, gamma=0.1):
"""base_lr * gamma^(number of milestones <= step)."""
# TODO
raise NotImplementedError("multistep_lr")def multistep_lr(step, base_lr, milestones, gamma=0.1):
"""base_lr * gamma^(number of milestones <= step)."""
count = sum(1 for m in milestones if m <= step)
return base_lr * (gamma ** count)The file /app/submission/optim.py has been updated successfully. (file state is current in your context , no need to Read it back)
/app/submission/optim.py
def cosine_restarts_lr(step, period, base_lr, min_lr=0.0):
"""Cosine annealing with warm restarts of fixed ``period`` (cosine within each period)."""
# TODO
raise NotImplementedError("cosine_restarts_lr")def cosine_restarts_lr(step, period, base_lr, min_lr=0.0):
"""Cosine annealing with warm restarts of fixed ``period`` (cosine within each period)."""
t = step % period
progress = t / period
return min_lr + 0.5 * (base_lr - min_lr) * (1 + np.cos(np.pi * progress))The file /app/submission/optim.py has been updated successfully. (file state is current in your context , no need to Read it back)
python3 /app/run_checks.py --only optim 2>&1
[optim] 25/25 optim/SGD_1step OK (max_abs=0.0e+00) optim/SGD_momentum_5step OK (max_abs=0.0e+00) optim/Adagrad_5step OK (max_abs=0.0e+00) optim/RMSprop_5step OK (max_abs=1.1e-16) optim/Adam_1step OK (max_abs=0.0e+00) optim/Adam_10step_wd OK (max_abs=0.0e+00) optim/AdamW_1step OK (max_abs=0.0e+00) optim/AdamW_10step_wd OK (max_abs=0.0e+00) optim/Lion_5step OK (max_abs=0.0e+00) optim/Adamax_5step OK (max_abs=0.0e+00) optim/NAdam_10step OK (max_abs=0.0e+00) optim/Adadelta_5step OK (max_abs=0.0e+00) optim/NesterovSGD_5step OK (max_abs=0.0e+00) optim/param_groups OK optim/split_decay_params OK optim/clip_grad_norm_clips OK (max_abs=0.0e+00) optim/clip_grad_norm_noop OK (max_abs=0.0e+00) optim/sched_cosine OK (max_abs=0.0e+00) optim/sched_warmup OK (max_abs=0.0e+00) optim/sched_step OK (max_abs=0.0e+00) optim/sched_exponential OK (max_abs=0.0e+00) optim/sched_polynomial OK (max_abs=0.0e+00) optim/sched_linear OK …[truncated 414 chars]
python3 /app/run_checks.py --only integration 2>&1
[integration] 6/6 integration/qcnn_finite OK (1.787->1.018) integration/qcnn_loss_decreases OK (1.7869->min 1.0175) integration/qmlp_finite OK (1.981->0.237) integration/qmlp_loss_decreases OK (1.9807->min 0.2374) integration/qsepcnn_finite OK (1.925->1.655) integration/qsepcnn_loss_decreases OK (1.9249->min 1.6340) ------------------------------------------------------------------------ integration 6/6 TOTAL 6/6 public checks passing All public checks pass. Now train qat_model.npz to clear the held-out top-1 threshold (the grader re-checks components with DIFFERENT seeds).
All checks pass. Here's a summary of what was implemented: **All 25/25 optim checks pass and 6/6 integration checks pass.** The following were implemented in `/app/submission/optim.py`: **Optimizer step methods:** - `SGD.step` - momentum SGD with coupled weight decay - `AdamW.step` - Adam with decoupled weight decay (wd applied to param directly, not folded into moments) - `Adam.step` - Adam with coupled weight decay (wd folded into gradient) - `RMSprop.step` - RMSprop with coupled weight decay - `Adagrad.step` - Adagrad with coupled weight decay - `Lion.step` - Lion optimizer with decoupled weight decay (momentum updated AFTER param step) - `Adamax.step` - Adamax (infinity norm) with coupled weight decay - `NAdam.step` - Nesterov-accelerated Adam with coupled weight decay - `Adadelta.step` - Adadelta with coupled weight decay - `NesterovSGD.step` - Nesterov SGD with coupled weight decay **Utility function:** - `clip_grad_norm` - global L2 gradient norm clipping, returns pre-clip norm **LR Schedulers:** - `cosine_lr` - linear warmup then cosine decay to min_lr - `warmup_lr` - linear warmup then constant - `step_lr` - step decay - `exponential_lr` - exponential decay - `polynomial_lr` - polynomial decay - `linear_lr` - linear decay - `multistep_lr` - multi-milestone step decay - `cosine_restarts_lr` - cosine annealing with warm restarts agentId: a9ae0b32dab17c1e2 (use SendMessage with to: 'a9ae0b32dab17c1e2', summary: '<5-10 word recap>' to continue this agent) <usage>subagent_tokens: 27817 tool_uses: 22 duration_ms: 142016</usage>
Run all public checks
python3 run_checks.py 2>&1 | tail -30
optim/NesterovSGD_5step OK (max_abs=0.0e+00) optim/param_groups OK optim/split_decay_params OK optim/clip_grad_norm_clips OK (max_abs=0.0e+00) optim/clip_grad_norm_noop OK (max_abs=0.0e+00) optim/sched_cosine OK (max_abs=0.0e+00) optim/sched_warmup OK (max_abs=0.0e+00) optim/sched_step OK (max_abs=0.0e+00) optim/sched_exponential OK (max_abs=0.0e+00) optim/sched_polynomial OK (max_abs=0.0e+00) optim/sched_linear OK (max_abs=1.7e-18) optim/sched_multistep OK (max_abs=0.0e+00) optim/sched_cosine_restarts OK (max_abs=0.0e+00) [integration] 6/6 integration/qcnn_finite OK (1.787->1.018) integration/qcnn_loss_decreases OK (1.7869->min 1.0175) integration/qmlp_finite OK (1.981->0.237) integration/qmlp_loss_decreases OK (1.9807->min 0.2374) integration/qsepcnn_finite OK (1.925->1.655) integration/qsepcnn_loss_decreases OK (1.9249->min 1.6340) [data] 2/2 data/normalize_def OK data/iter_minibatches_cover OK (covered 23/23) ------------------------------------------------------------------------ autograd_grads 115/115 | quant_grads 21/21 | …[truncated 238 chars]
/app/submission/train.py
Wasted call , file unchanged since your last Read. Refer to that earlier tool_result instead.
"""QAT training loop for INT-2 CNN on CIFAR-style data."""
from __future__ import annotations
import argparse
import os
import sys
import numpy as np
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
sys.path.insert(0, "/app")
import autograd as ag # noqa: E402,F401
import data as D # noqa: E402,F401
import optim as O # noqa: E402,F401
from nn import QuantCNN, W_NEG, W_POS # noqa: E402,F401
from autograd import Tensor
WIDTHS = (16, 32)
def init_lsq_scales(model, X_sample, n_classes):
"""Initialize LSQ step sizes from data/weights using a heuristic.
For weight quantizers: use 2*mean(|w|) / sqrt(Qp)
For activation quantizers: run a forward pass and initialize from activations.
"""
# Initialize weight scales
Qp_w = float(W_POS)
Qp_a = 3.0 # unsigned 2-bit max
# Weight scales: for each conv/head weight, set scale = 2*mean(|w|)/Qp
named = model.named_params()
# Set weight quant scales
for name, p in named.items():
if name.endswith("wq.scale"):
# Find the corresponding weight
weight_name = name[:-len("wq.scale")] + "weight"
if weight_name in named:
w = named[weight_name].data
# LSQ init: scale = 2*mean(|w|)/Qp (for signed, Qp=1)
s = 2.0 * np.mean(np.abs(w)) / max(Qp_w, 1e-8)
p.data[...] = max(s, 1e-4)
# Activation scales: run a forward pass and set from activation sta
…[truncated 4927 chars]The file /app/submission/train.py has been updated successfully. (file state is current in your context , no need to Read it back)
Test training for 5 epochs
timeout 60 python3 submission/train.py --epochs 5 --out /tmp/test_model.npz 2>&1
No file changes, the agent left the workspace untouched.
=== SyncVals verifier (local re-grade of the agent's own checkpoint) === COMPONENT CONFORMANCE SUITE: 276/278 cases passed (all milestones pass: False) failing milestones: integration (21/23) FINAL METRIC: held-out INT2 top-1 = 0.8933 >= threshold 0.7 REWARD = 0 (1 iff every component milestone passes AND the sealed held-out metric clears its threshold) NOTE: the in-sandbox training in the 481MB e2b box was OOM-killed (0-byte checkpoint), so the raw in-sandbox reward was an infrastructure artifact. This reward is from a faithful LOCAL re-train of the agent's OWN train.py (24GB, no OOM) with its own default hyperparameters, then re-graded by the real verifier.
Reproduce this trial: git checkout 2f94510 && PYTHONPATH=src python3 scripts/build_site.py , then open trial/trial_c155d01ed1314b74. Re-running the agent live requires EVAL_PLATFORM_ENABLE_OAUTH_SMOKE=1 and is non-deterministic.
Trial trial_c155d01ed1314b74 · verifier authoritative; classifier explanatory.