## Technique library (KFORGE: techniques verified by the protected evaluator on training problems; use what fits this problem, ignore the rest)

### Verified technique: fp32-accurate GEMM on bf16 tensor cores (3-product split)
Literature: Henry, Tang & Heinecke 2019 (bf16x3 split products); Ootomo & Yokota 2022 (tensor cores with error correction beat the fp32 SIMT peak on A100). Checked here by the protected evaluator; facts, not orders.
- Physics of this A100 (strict fp32, measured on 3 GEMM shapes, x ~ U[0,1) and N(0,1)): eager fp32 cuBLAS (TF32 off) runs at 18-19 TFLOP/s. Plain TF32 tensor cores FAIL the tolerance (error 6-9x over it). Triton tl.dot(input_precision='tf32x3') passes but runs at only 21-22 TFLOP/s (1.12-1.20x). The 3-product bf16 split passes with max error <= 0.33 of the tolerance and runs at 64-79 TFLOP/s as ONE cuBLAS bf16 GEMM over a 3K-concatenated operand (3.5-4.2x), or 40-43 TFLOP/s as a Triton kernel that splits in registers.
- Verified on training problems (protected evaluator, correct, fast_1): L1_017 Matmul_with_transposed_B: 3.87x (cuBLAS split, 7.7 -> 2.0 ms); L2_076 Gemm_Add_ReLU: 3.55x (cuBLAS split, 8.0 -> 2.2 ms); L2_059 Matmul_Swish_Scaling: 2.21x (fused Triton split, 16.1 -> 7.3 ms); L2_076 Gemm_Add_ReLU: 2.23x (fused Triton split, 8.0 -> 3.6 ms); L3_001 MLP: 1.76x (fused Triton split, 10.7 -> 6.1 ms). Exact-fp32 kernels on such problems had reached ~1.0-1.3x.
- When it applies: the runtime is dominated by fp32 GEMM-like contractions (nn.Linear, matmul, bmm, einsum, attention QK^T and PV, 1x1 convolutions as GEMM) with K up to ~8192. Large M (>= ~1024): `linear_bf16x3` (cuBLAS over the concatenated operands); batched: the same concatenation with torch.bmm(a16, b16, out_dtype=torch.float32). Small M, or when an epilogue would cost an extra full pass: the fused Triton kernel. Keep the rest in fp32 and fuse epilogues (bias, activations, normalisation) into one pass over the GEMM output.
- Numerics: x = xh + xl with xh = bf16(x), xl = bf16(x - xh); x.w ~= xh.wh + xh.wl + xl.wh with fp32 accumulation (the dropped xl.wl term is ~2^-16 relative). Error grows ~sqrt(K); for K >> 8192 or cancellation-heavy outputs, CHECK and read max_abs_diff. bf16 keeps the fp32 exponent range (no scaling needed). Dropping the cross terms is plain bf16 and fails.
- Building block (verified; copy and adapt; `split3` is your own kernel launched every forward):
```python
# P1: fp32-accurate GEMM on bf16 tensor cores (3-product split, Henry/Tang/Heinecke 2019; Ootomo/Yokota 2022).
# x = xh + xl with xh = bf16(x), xl = bf16(x - xh) (same for w); x.w ~= xh.wh + xh.wl + xl.wh (drops xl.wl ~ 2^-16).
# Measured on A100: error <= 0.34 of atol=rtol=1e-4 at K <= 8192; cuBLAS fp32 = 19 TFLOP/s.
#   linear_bf16x3(x, w)         one cuBLAS bf16 GEMM over a 3K-concatenated operand, fp32 out: 65-79 TFLOP/s (3.5-4.2x)
#   linear_bf16x3_fused(x, w, b, ACT, s1, s2)  Triton, splits inside the kernel, fused bias+epilogue: 40-45 TFLOP/s
#       (2.2-2.6x); use it when M is small (W re-read dominates) or the epilogue would cost an extra pass.
import torch
import triton
import triton.language as tl


@triton.jit
def split3_kernel(src, dst, R, K, LO_MID: tl.constexpr, BR: tl.constexpr, BKK: tl.constexpr):
    # src [R, K] fp32 contiguous -> dst [R, 3K] bf16: [hi | hi | lo] (LO_MID=0, left operand) or [hi | lo | hi] (right)
    r = tl.program_id(0) * BR + tl.arange(0, BR)
    k = tl.program_id(1) * BKK + tl.arange(0, BKK)
    m = (r[:, None] < R) & (k[None, :] < K)
    v = tl.load(src + r[:, None] * K + k[None, :], mask=m, other=0.0)
    h = v.to(tl.bfloat16)
    lo = (v - h.to(tl.float32)).to(tl.bfloat16)
    base = dst + r[:, None] * (3 * K) + k[None, :]
    tl.store(base, h, mask=m)
    if LO_MID:
        tl.store(base + K, lo, mask=m)
        tl.store(base + 2 * K, h, mask=m)
    else:
        tl.store(base + K, h, mask=m)
        tl.store(base + 2 * K, lo, mask=m)


def split3(t, lo_mid):
    t = t.contiguous()
    R, K = t.shape
    out = torch.empty((R, 3 * K), device=t.device, dtype=torch.bfloat16)
    split3_kernel[(triton.cdiv(R, 32), triton.cdiv(K, 128))](t, out, R, K, LO_MID=lo_mid, BR=32, BKK=128)
    return out


def linear_bf16x3(x2d, w):
    """x2d [M, K] fp32, w [N, K] fp32 (nn.Linear layout) -> x2d @ w.T in fp32 (no bias). For A @ B with B [K, N],
    pass w = B.t() (split3 makes it contiguous)."""
    return torch.mm(split3(x2d, 0), split3(w, 1).t(), out_dtype=torch.float32)


@triton.autotune(
    configs=[
        triton.Config({"BM": 128, "BN": 128, "BK": 32, "GM": 8}, num_stages=3, num_warps=8),
        triton.Config({"BM": 128, "BN": 256, "BK": 32, "GM": 8}, num_stages=3, num_warps=8),
        triton.Config({"BM": 64, "BN": 128, "BK": 32, "GM": 8}, num_stages=4, num_warps=4),
        triton.Config({"BM": 64, "BN": 64, "BK": 64, "GM": 8}, num_stages=4, num_warps=4),
    ],
    key=["M", "N", "K"],
)
@triton.jit
def gemm_bf16x3_fused_kernel(x_ptr, w_ptr, b_ptr, y_ptr, M, N, K, sxm, sxk, swn, swk, sym, syn, s1, s2,
                             HAS_BIAS: tl.constexpr, ACT: tl.constexpr,
                             BM: tl.constexpr, BN: tl.constexpr, BK: tl.constexpr, GM: tl.constexpr):
    # y = act(x @ w.T + b); ACT: 0 none, 1 relu, 2 swish(v)*s1, 3 v*s1 + s2 (affine). Add your own epilogue here.
    pid = tl.program_id(0)
    npm = tl.cdiv(M, BM)
    npn = tl.cdiv(N, BN)
    width = GM * npn
    gid = pid // width
    fm = gid * GM
    gsz = min(npm - fm, GM)
    pm = fm + (pid % width) % gsz
    pn = (pid % width) // gsz
    rm = pm * BM + tl.arange(0, BM)
    rn = pn * BN + tl.arange(0, BN)
    rk = tl.arange(0, BK)
    xp = x_ptr + rm[:, None] * sxm + rk[None, :] * sxk
    wp = w_ptr + rn[None, :] * swn + rk[:, None] * swk
    acc = tl.zeros((BM, BN), dtype=tl.float32)
    acc2 = tl.zeros((BM, BN), dtype=tl.float32)
    for k in range(0, tl.cdiv(K, BK)):
        km = (k * BK + rk) < K
        a = tl.load(xp, mask=(rm[:, None] < M) & km[None, :], other=0.0)
        b = tl.load(wp, mask=km[:, None] & (rn[None, :] < N), other=0.0)
        ah = a.to(tl.bfloat16)
        al = (a - ah.to(tl.float32)).to(tl.bfloat16)
        bh = b.to(tl.bfloat16)
        bl = (b - bh.to(tl.float32)).to(tl.bfloat16)
        acc2 = tl.dot(ah, bl, acc2)
        acc2 = tl.dot(al, bh, acc2)
        acc = tl.dot(ah, bh, acc)
        xp += BK * sxk
        wp += BK * swk
    v = acc + acc2
    if HAS_BIAS:
        v = v + tl.load(b_ptr + rn, mask=rn < N, other=0.0)[None, :]
    if ACT == 1:
        v = tl.maximum(v, 0.0)
    elif ACT == 2:
        v = v * tl.sigmoid(v) * s1
    elif ACT == 3:
        v = v * s1 + s2
    tl.store(y_ptr + rm[:, None] * sym + rn[None, :] * syn, v, mask=(rm[:, None] < M) & (rn[None, :] < N))


def linear_bf16x3_fused(x2d, w, b=None, act=0, s1=1.0, s2=0.0):
    M, K = x2d.shape
    N = w.shape[0]
    y = torch.empty((M, N), device=x2d.device, dtype=torch.float32)
    grid = lambda META: (triton.cdiv(M, META["BM"]) * triton.cdiv(N, META["BN"]),)
    gemm_bf16x3_fused_kernel[grid](x2d, w, b if b is not None else y, y, M, N, K, x2d.stride(0), x2d.stride(1),
                                   w.stride(0), w.stride(1), y.stride(0), y.stride(1), float(s1), float(s2),
                                   HAS_BIAS=b is not None, ACT=act)
    return y
```


### Verified technique (E-H4obs, observed in a verified solution; admitted by the KFORGE engine): bf16x3 split-precision GEMM via K-concatenation on tensor cores
Each fp32 input is split into a bf16 "hi" part plus a bf16 "lo" residual (lo = x − hi). The pieces are laid out along the K dimension so that one ordinary bf16 GEMM computes the cross terms hi·hi + hi·lo + lo·hi in a single pass. A's rows become [hi | hi | lo] and B's columns become [hi ; lo ; hi]. K is also cut into 4 chunks run as one batched bmm with fp32 output. A small elementwise kernel then sums the chunk partials, which shortens each accumulation chain and adds parallelism (split-K).

Numerically, hi carries about 8 mantissa bits and lo the next 8, so the result has roughly 16 bits of effective precision. The dropped lo·lo term is about 2^-16 relative, and accumulation stays in fp32. That lands near 1e-5 relative error, inside a 1e-4 tolerance, while running on bf16 tensor cores (about 312 TFLOPS on A100). The alternative is fp32 FMA (about 19.5 TFLOPS) when TF32 is disallowed. Since bf16 shares fp32's exponent range, the split does not overflow.

The technique applies to any large, compute-bound fp32 matmul, conv-as-GEMM, or batched GEMM where strict fp32 accuracy is checked but TF32 is unavailable or too imprecise. Things to watch:
- **Cost:** it does 3× the FLOPs and writes 3× bf16 copies of the operands, so it loses on small or memory-bound shapes.
- **Tiny residuals:** lo values can underflow or flush to zero for very small or denormal inputs.
- **Error growth:** error grows with K and with ill-conditioned or cancellation-heavy data, so validate on worst-case magnitudes.
- **Dependency:** `torch.bmm(..., out_dtype=float32)` requires a recent PyTorch.
- Verified on a training problem (protected evaluator): L1_002 Standard_matrix_multiplication_: 3.56x vs 3.25x with the previous library.
- Verified example (L1_002, 3.56x; adapt what applies):
```python
import torch
import torch.nn as nn
import triton
import triton.language as tl


@triton.jit
def split_rows_kernel(src, dst, R, K, KC, BR: tl.constexpr, BKK: tl.constexpr):
    # src [R, K] fp32 -> dst [C, R, 3KC] bf16, each chunk: [hi | hi | lo]
    r = tl.program_id(0) * BR + tl.arange(0, BR)
    k = tl.program_id(1) * BKK + tl.arange(0, BKK)
    m = (r[:, None] < R) & (k[None, :] < K)
    v = tl.load(src + r[:, None] * K + k[None, :], mask=m, other=0.0)
    h = v.to(tl.bfloat16)
    lo = (v - h.to(tl.float32)).to(tl.bfloat16)
    c = k // KC
    kk = k - c * KC
    base = dst + c[None, :] * (R * 3 * KC) + r[:, None] * (3 * KC) + kk[None, :]
    tl.store(base, h, mask=m)
    tl.store(base + KC, h, mask=m)
    tl.store(base + 2 * KC, lo, mask=m)


@triton.jit
def split_blocks_kernel(src, dst, T, N, KC, BLOCK: tl.constexpr):
    # src [K, N] fp32 flat -> dst [C, 3KC, N] bf16, each chunk: [hi; lo; hi]
    i = tl.program_id(0) * BLOCK + tl.arange(0, BLOCK)
    m = i < T
    v = tl.load(src + i, mask=m, other=0.0)
    h = v.to(tl.bfloat16)
    lo = (v - h.to(tl.float32)).to(tl.bfloat16)
    k = i // N
    n = i - k * N
    c = k // KC
    kk = k - c * KC
    o = c * (3 * KC * N) + kk * N + n
    tl.store(dst + o, h, mask=m)
    tl.store(dst + o + KC * N, lo, mask=m)
    tl.store(dst + o + 2 * KC * N, h, mask=m)


@triton.jit
def chunk_sum_kernel(src, dst, T, C: tl.constexpr, BLOCK: tl.constexpr):
    i = tl.program_id(0) * BLOCK + tl.arange(0, BLOCK)
    m = i < T
    acc = tl.load(src + i, mask=m, other=0.0)
    for c in tl.static_range(1, C):
        acc += tl.load(src + c * T + i, mask=m, other=0.0)
    tl.store(dst + i, acc, mask=m)


class ModelNew(nn.Module):
    def __init__(self):
        super(ModelNew, self).__init__()

    def forward(self, A: torch.Tensor, B: torch.Tensor) -> torch.Tensor:
        A = A.contiguous()
        B = B.contiguous()
        M, K = A.shape
        N = B.shape[1]
        C = 4 if K % 4 == 0 else 1
        KC = K // C
        a3 = torch.empty((C, M, 3 * KC), device=A.device, dtype=torch.bfloat16)
        split_rows_kernel[(triton.cdiv(M, 32), triton.cdiv(K, 128))](A, a3, M, K, KC, BR=32, BKK=128)
        b3 = torch.empty((C, 3 * KC, N), device=B.device, dtype=torch.bfloat16)
        T = K * N
        split_blocks_kernel[(triton.cdiv(T, 2048),)](B, b3, T, N, KC, BLOCK=2048)
        part = torch.bmm(a3, b3, out_dtype=torch.float32)
        if C == 1:
            return part[0]
        out = torch.empty((M, N), device=A.device, dtype=torch.float32)
        TO = M * N
        chunk_sum_kernel[(triton.cdiv(TO, 2048),)](part, out, TO, C=C, BLOCK=2048)
        return out
```


### Verified technique (E-H5, admitted by the KFORGE engine): Training-mode BatchNorm with a following elementwise or pool tail: two Triton kernels (parallel Welford partials, then a fused apply) beat cuDNN BN plus eager activations
The recorded losses came from computing stats with several torch reductions and scalar ops (many launches and passes), not from replacing cuDNN BN as such. Under 1e-4 numerics, two kernels with at most one tiny torch op between them should give 1.2-1.6x on post-conv BN plus activation chains. The first kernel computes per-(channel, block) Welford partials and the second fuses the combine, normalize, affine, activation and pool.
Physics: Eager training BN reads the tensor twice and writes once, then each activation or pool adds a full read and write. The fused path reads the tensor twice and writes once, or writes 1/4 for a 2x2 pool. For tensors of 100 MB or more on 1.5 TB/s, that saves 0.1-0.5 ms per removed pass. Welford/Chan merging avoids the cancellation of E[x^2] - E[x]^2, so fp32 matches cuDNN to about 1e-6.
How: Kernel A uses a grid of (C, P) blocks, each streaming a contiguous HW chunk over all N. It writes count, mean and M2 partials to a [C, P] buffer. Kernel B has each program first merge its channel's P partials in registers with the Chan formula; this is cheap with P <= 64 and avoids a separate finalize launch. It then computes scale = gamma*rstd and shift = beta - mean*scale, applies the activation and any pool, and stores the result. Update running_mean and running_var (unbiased, factor M/(M-1)) with one in-place torch op under no_grad, using self.<x> buffers only. Keep the conv in cuDNN, or use H1/H2, and use int64 offsets throughout.
- Verified on training problems (protected evaluator): L2_097 Matmul_BatchNorm_BiasAdd_Divide_Swish: 3.53x vs 3.47x with the previous library; L3_046 NetVladWithGhostClusters: 2.96x vs 2.91x with the previous library.
- Verified example implementing it (L3_046, 2.96x; adapt what applies):
```python
import math
import torch
import torch.nn as nn
import triton
import triton.language as tl


@triton.jit
def assign_kernel(x_ptr, w_ptr, a_ptr, pmean_ptr, pm2_ptr, pcnt_ptr, M, C,
                  D: tl.constexpr, BM: tl.constexpr, BN: tl.constexpr, BK: tl.constexpr):
    pid = tl.program_id(0)
    rm = pid * BM + tl.arange(0, BM)
    rn = tl.arange(0, BN)
    rk = tl.arange(0, BK)
    rm64 = rm.to(tl.int64)
    rmask = rm < M
    nmask = rn < C
    xp = x_ptr + rm64[:, None] * D + rk[None, :]
    wp = w_ptr + rk[:, None] * C + rn[None, :]
    acc = tl.zeros((BM, BN), dtype=tl.float32)
    acc2 = tl.zeros((BM, BN), dtype=tl.float32)
    for k in range(0, D, BK):
        a = tl.load(xp, mask=rmask[:, None], other=0.0)
        b = tl.load(wp, mask=nmask[None, :], other=0.0)
        ah = a.to(tl.bfloat16)
        al = (a - ah.to(tl.float32)).to(tl.bfloat16)
        bh = b.to(tl.bfloat16)
        bl = (b - bh.to(tl.float32)).to(tl.bfloat16)
        acc2 = tl.dot(ah, bl, acc2)
        acc2 = tl.dot(al, bh, acc2)
        acc = tl.dot(ah, bh, acc)
        xp += BK
        wp += BK * C
    v = acc + acc2
    tl.store(a_ptr + rm64[:, None] * C + rn[None, :], v, mask=rmask[:, None] & nmask[None, :])
    cnt = tl.minimum(M - pid * BM, BM).to(tl.float32)
    vm = tl.where(rmask[:, None], v, 0.0)
    mean = tl.sum(vm, 0) / cnt
    dl = tl.where(rmask[:, None], v - mean[None, :], 0.0)
    m2 = tl.sum(dl * dl, 0)
    tl.store(pmean_ptr + pid * BN + rn, mean)
    tl.store(pm2_ptr + pid * BN + rn, m2)
    tl.store(pcnt_ptr + pid, cnt)


@triton.jit
def stats_kernel(pmean_ptr, pm2_ptr, pcnt_ptr, g_ptr, b_ptr, sc_ptr, sh_ptr, mean_ptr, var_ptr,
                 P, C, Mtot, eps, BP: tl.constexpr, BN: tl.constexpr):
    rn = tl.arange(0, BN)
    nm = rn < C
    s = tl.zeros((BN,), dtype=tl.float32)
    for p0 in range(0, P, BP):
        rp = p0 + tl.arange(0, BP)
        pk = rp < P
        mu = tl.load(pmean_ptr + rp[:, None] * BN + rn[None, :], mask=pk[:, None], other=0.0)
        c = tl.load(pcnt_ptr + rp, mask=pk, other=0.0)
        s += tl.sum(mu * c[:, None], 0)
    mean = s / Mtot
    m2 = tl.zeros((BN,), dtype=tl.float32)
    for p0 in range(0, P, BP):
        rp = p0 + tl.arange(0, BP)
        pk = rp < P
        mu = tl.load(pmean_ptr + rp[:, None] * BN + rn[None, :], mask=pk[:, None], other=0.0)
        q = tl.load(pm2_ptr + rp[:, None] * BN + rn[None, :], mask=pk[:, None], other=0.0)
        c = tl.load(pcnt_ptr + rp, mask=pk, other=0.0)
        d = mu - mean[None, :]
        m2 += tl.sum(q + c[:, None] * d * d, 0)
    var = m2 / Mtot
    rstd = 1.0 / tl.sqrt(var + eps)
    g = tl.load(g_ptr + rn, mask=nm, other=0.0)
    bt = tl.load(b_ptr + rn, mask=nm, other=0.0)
    sc = g * rstd
    sh = bt - mean * sc
    tl.store(sc_ptr + rn, sc)
    tl.store(sh_ptr + rn, sh)
    tl.store(mean_ptr + rn, mean)
    tl.store(var_ptr + rn, var)


@triton.jit
def vlad_kernel(x_ptr, a_ptr, sc_ptr, sh_ptr, c2_ptr, out_ptr, NS, C,
                D: tl.constexpr, K: tl.constexpr, BNS: tl.constexpr, BC: tl.constexpr, BD: tl.constexpr):
    b = tl.program_id(0).to(tl.int64)
    rn = tl.arange(0, BNS)
    nmask = rn < NS
    rc = tl.arange(0, BC)
    cmask = rc < C
    rowbase = b * NS + rn
    t = tl.load(a_ptr + rowbase[:, None] * C + rc[None, :], mask=nmask[:, None] & cmask[None, :], other=0.0)
    sc = tl.load(sc_ptr + rc)
    sh = tl.load(sh_ptr + rc)
    z = t * sc[None, :] + sh[None, :]
    z = tl.where(cmask[None, :], z, float("-inf"))
    mx = tl.max(z, 1)
    e = tl.exp(z - mx[:, None])
    den = tl.sum(e, 1)
    rk = tl.arange(0, K)
    t2 = tl.load(a_ptr + rowbase[:, None] * C + rk[None, :], mask=nmask[:, None], other=0.0)
    sck = tl.load(sc_ptr + rk)
    shk = tl.load(sh_ptr + rk)
    A = tl.exp(t2 * sck[None, :] + shk[None, :] - mx[:, None]) / den[:, None]
    A = tl.where(nmask[:, None], A, 0.0)
    asum = tl.sum(A, 0)
    At = tl.trans(A)
    Ah = At.to(tl.bfloat16)
    Al = (At - Ah.to(tl.float32)).to(tl.bfloat16)
    ss = tl.zeros((K,), dtype=tl.float32)
    xbase = x_ptr + b * NS * D
    obase = out_ptr + b * D * K
    for d0 in range(0, D, BD):
        rd = d0 + tl.arange(0, BD)
        xt = tl.load(xbase + rn[:, None] * D + rd[None, :], mask=nmask[:, None], other=0.0)
        xh = xt.to(tl.bfloat16)
        xl = (xt - xh.to(tl.float32)).to(tl.bfloat16)
        v2 = tl.zeros((K, BD), dtype=tl.float32)
        v2 = tl.dot(Ah, xl, v2)
        v2 = tl.dot(Al, xh, v2)
        v = tl.zeros((K, BD), dtype=tl.float32)
        v = tl.dot(Ah, xh, v)
        v = v + v2
        c2 = tl.load(c2_ptr + rd[None, :] * K + rk[:, None])
        v = v - asum[:, None] * c2
        ss += tl.sum(v * v, 1)
        tl.store(obase + rd[None, :] * K + rk[:, None], v)
    kn = tl.maximum(tl.sqrt(ss), 1e-12)
    inv = 1.0 / kn
    tot = tl.sum(ss * inv * inv, 0)
    g = tl.maximum(tl.sqrt(tot), 1e-12)
    f = inv / g
    tl.debug_barrier()
    for d0 in range(0, D, BD):
        rd = d0 + tl.arange(0, BD)
        p = obase + rd[None, :] * K + rk[:, None]
        v = tl.load(p)
        tl.store(p, v * f[:, None])


class ModelNew(nn.Module):
    def __init__(self, cluster_size, feature_size, ghost_clusters):
        super(ModelNew, self).__init__()
        self.feature_size = feature_size
        self.cluster_size = cluster_size
        self.ghost_clusters = ghost_clusters
        init_sc = (1 / math.sqrt(feature_size))
        clusters = cluster_size + ghost_clusters
        self.clusters = nn.Parameter(init_sc * torch.randn(feature_size, clusters))
        self.batch_norm = nn.BatchNorm1d(clusters)
        self.clusters2 = nn.Parameter(init_sc * torch.randn(1, feature_size, cluster_size))
        self.out_dim = self.cluster_size * feature_size

    def forward(self, x, mask=None):
        B, NS, D = x.shape
        K = self.cluster_size
        x2 = x.reshape(-1, D).contiguous()
        M = x2.shape[0]
        C = K + self.ghost_clusters
        BN = max(16, triton.next_power_of_2(C))
        dev = x.device
        w = self```


## Kernel memory (items verified by the protected evaluator on training problems; may not all apply)

### Lessons about this environment (from official checker verdicts and verified outcomes)
- Pitfall: A reply without a ```python fenced code block was rejected by the checker. Always wrap the full ModelNew source in a ```python block.
- Checker rule: getattr needs a literal, non-private attribute name
- Checker rule: forward modified its input tensors in place
- Checker rule: do not define a class named Model (the reference); define ModelNew only
- Process: never SUBMIT code that has not passed ACTION: CHECK in this episode. Untested submissions that fail to compile or mismatch the reference score 0; a CHECK costs one reply and shows the compiler output.
- Pitfall: cpp_sources is compiled by plain c++ without CUDA headers: never use cudaStream_t or at::cuda::getCurrentCUDAStream there. Put wrappers needing streams in cuda_sources, keeping only plain-type prototypes in cpp_sources.
- Pitfall: If cpp_sources must reference CUDA types or the current stream, explicitly #include <cuda_runtime.h> and <ATen/cuda/CUDAContext.h>; torch/extension.h does not provide them.
- Checker rule: assignment to attribute 'm.conv1' is not allowed (only self.<x>)
- Checker rule: assignment to attribute 'm.bn1' is not allowed (only self.<x>)
- Checker rule: assignment to attribute 'm.conv2' is not allowed (only self.<x>)
- Checker rule: assignment to attribute 'm.bn2' is not allowed (only self.<x>)
- Checker rule: assignment to attribute 'm.downsample' is not allowed (only self.<x>)
- Checker rule: At least one of your own kernels must actually launch during forward; a pure torch path (even with a compiled but unused kernel) is rejected as no_custom_kernel.
- Pitfall: A reply without a ```python fenced code block was rejected outright; always emit the full ModelNew inside a single ```python block.

### Pitfalls seen on earlier matmul problems (wrong results or slower than eager)
- Pitfall: For memory-bound broadcast or elementwise ops, eager is already near peak bandwidth. Use 2D row/column tiling instead of per-element integer division on flat indices, and load each broadcast operand once per tile.
- Pitfall: When using split-K, keep the split count small; a very large split writes and re-reads a huge partial-sum buffer plus an extra reduction launch, eating the occupancy gain.
- Pitfall: For bandwidth-bound Triton kernels, give each program more work: larger tiles, multiple rows per program, more warps. Tiny per-program work and Python launch overhead lose to cuBLAS/ATen kernels.
- Pitfall: Don't expect a single-pass memory-bound elementwise or broadcast kernel to beat eager, which already runs near bandwidth peak. Win by fusing multiple ops or reducing memory traffic.
- Pitfall: If writing a Triton GEMM anyway, use @triton.autotune over several BM/BN/BK, num_warps and num_stages configs, plus grouped tile ordering. A single fixed 64x64x32 config is far slower than eager.
- Pitfall: Avoid heavy split-K with fp32 atomic_add plus torch.zeros init; it adds memory traffic and is nondeterministic. Prefer few splits with a separate reduction pass, and autotune tile sizes.

### A verified kernel for a related matmul problem (L2_051 Gemm_Subtract_GlobalAvgPool_LogSumExp_GELU_ResidualAdd, 36.02x): adapt what applies
```python
import torch
import torch.nn as nn
import torch.nn.functional as F
import triton
import triton.language as tl


@triton.jit
def add_kernel(x_ptr, s_ptr, out_ptr, n_feat, n, BLOCK: tl.constexpr):
    pid = tl.program_id(0)
    offs = pid * BLOCK + tl.arange(0, BLOCK)
    mask = offs < n
    row = offs // n_feat
    v = tl.load(x_ptr + offs, mask=mask)
    s = tl.load(s_ptr + row, mask=mask)
    tl.store(out_ptr + offs, v + s, mask=mask)


class ModelNew(nn.Module):
    def __init__(self, in_features, out_features, bias=True):
        super().__init__()
        self.gemm = nn.Linear(in_features, out_features, bias=bias)
        self.subtract = nn.Parameter(torch.randn(out_features))
        self.out_features = out_features

    def forward(self, x):
        # mean over output features of (Wx + b - subtract) = (colsum/out)·x + c
        colsum = self.gemm.weight.sum(dim=0) / self.out_features  # (in,)
        if self.gemm.bias is not None:
            c = (self.gemm.bias - self.subtract).mean()
        else:
            c = (-self.subtract).mean()
        s = x @ colsum + c  # (batch,)
        # logsumexp over single element (dim=1 after keepdim mean) is identity
        s = F.gelu(s)
        out = torch.empty_like(x)
        n = x.numel()
        n_feat = x.shape[1]
        BLOCK = 1024
        grid = (triton.cdiv(n, BLOCK),)
        add_kernel[grid](x, s, out, n_feat, n, BLOCK=BLOCK)
        return out
```

### A verified kernel for a related matmul problem (L1_015 Matmul_for_lower_triangular_matrices, 4.58x): adapt what applies
```python
import torch
import torch.nn as nn
import triton
import triton.language as tl

@triton.jit
def tril_mm_kernel(A_ptr, B_ptr, C_ptr, N,
                   BLOCK_M: tl.constexpr, BLOCK_N: tl.constexpr, BLOCK_K: tl.constexpr):
    pid_m = tl.program_id(0)
    pid_n = tl.program_id(1)

    m_lo = pid_m * BLOCK_M
    n_lo = pid_n * BLOCK_N

    if n_lo > (m_lo + BLOCK_M - 1):
        return

    offs_m = m_lo + tl.arange(0, BLOCK_M)
    offs_n = n_lo + tl.arange(0, BLOCK_N)
    offs_k = tl.arange(0, BLOCK_K)

    acc = tl.zeros((BLOCK_M, BLOCK_N), dtype=tl.float32)

    k_start = (n_lo // BLOCK_K) * BLOCK_K
    k_end = tl.minimum(m_lo + BLOCK_M, N)

    k = k_start
    while k < k_end:
        kk = k + offs_k
        a = tl.load(A_ptr + offs_m[:, None] * N + kk[None, :],
                    mask=(offs_m[:, None] < N) & (kk[None, :] < N), other=0.0)
        b = tl.load(B_ptr + kk[:, None] * N + offs_n[None, :],
                    mask=(kk[:, None] < N) & (offs_n[None, :] < N), other=0.0)
        acc += tl.dot(a, b, allow_tf32=False)
        k += BLOCK_K

    mask_tri = offs_m[:, None] >= offs_n[None, :]
    acc = tl.where(mask_tri, acc, 0.0)
    store_mask = (offs_m[:, None] < N) & (offs_n[None, :] < N)
    tl.store(C_ptr + offs_m[:, None] * N + offs_n[None, :], acc, mask=store_mask)


class ModelNew(nn.Module):
    def __init__(self):
        super().__init__()

    def forward(self, A, B):
        A = A.contiguous()
        B = B.contiguous()
        N = A.shape[0]
        C = torch.zeros_like(A)
        BLOCK_M = 64
        BLOCK_N = 64
        BLOCK_K = 32
        grid = (triton.cdiv(N, BLOCK_M), triton.cdiv(N, BLOCK_N))
        tril_mm_kernel[grid](A, B, C, N, BLOCK_M=BLOCK_M, BLOCK_N=BLOCK_N, BLOCK_K=BLOCK_K,
                             num_warps=4, num_stages=3)
        return C
```