Spaces:
Running on Zero
Running on Zero
| # GOLD seed kernel: row-wise softmax with the REQUIRED max-subtraction (numerical | |
| # stability). Single-block-per-row when N fits BLOCK; otherwise an online two-pass. | |
| # fp32 accumulation. This is the kernel the no-max-subtract negative control violates. | |
| def _softmax_kernel(x_ptr, y_ptr, stride, N, BLOCK: tl.constexpr): | |
| row = tl.program_id(0) | |
| x_ptr += row * stride | |
| y_ptr += row * stride | |
| # pass 1: row max | |
| m = tl.full([BLOCK], -float("inf"), dtype=tl.float32) | |
| for off in range(0, N, BLOCK): | |
| cols = off + tl.arange(0, BLOCK) | |
| x = tl.load(x_ptr + cols, mask=cols < N, other=-float("inf")).to(tl.float32) | |
| m = tl.maximum(m, x) | |
| row_max = tl.max(m) | |
| # pass 2: denom | |
| d = tl.zeros([BLOCK], dtype=tl.float32) | |
| for off in range(0, N, BLOCK): | |
| cols = off + tl.arange(0, BLOCK) | |
| x = tl.load(x_ptr + cols, mask=cols < N, other=-float("inf")).to(tl.float32) | |
| d += tl.where(cols < N, tl.exp(x - row_max), 0.0) | |
| denom = tl.sum(d) | |
| # pass 3: write | |
| for off in range(0, N, BLOCK): | |
| cols = off + tl.arange(0, BLOCK) | |
| mask = cols < N | |
| x = tl.load(x_ptr + cols, mask=mask, other=0.0).to(tl.float32) | |
| tl.store(y_ptr + cols, tl.exp(x - row_max) / denom, mask=mask) | |
| def run(x): | |
| M, N = x.shape | |
| y = torch.empty_like(x) | |
| BLOCK = 1024 | |
| _softmax_kernel[(M,)](x, y, x.stride(0), N, BLOCK=BLOCK) | |
| return y | |