kernel-fun 0.2.0.dev1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- kernel_fun/__init__.py +67 -0
- kernel_fun/_common/__init__.py +11 -0
- kernel_fun/_common/cache.py +99 -0
- kernel_fun/_common/compat.py +168 -0
- kernel_fun/_common/support.py +267 -0
- kernel_fun/cconv/__init__.py +24 -0
- kernel_fun/cconv/_kernels/__init__.py +6 -0
- kernel_fun/cconv/_kernels/strip.py +450 -0
- kernel_fun/cconv/_provenance.py +11 -0
- kernel_fun/cconv/ops.py +256 -0
- kernel_fun/kda/__init__.py +23 -0
- kernel_fun/kda/_kernels/__init__.py +7 -0
- kernel_fun/kda/_kernels/bwd_dhu.py +994 -0
- kernel_fun/kda/_kernels/bwd_intra.py +1089 -0
- kernel_fun/kda/_kernels/bwd_intra_triton.py +328 -0
- kernel_fun/kda/_kernels/bwd_scan.py +1105 -0
- kernel_fun/kda/_kernels/bwd_wy.py +320 -0
- kernel_fun/kda/_kernels/bwd_wy_t.py +309 -0
- kernel_fun/kda/_kernels/fwd_intra_triton.py +101 -0
- kernel_fun/kda/_kernels/fwd_state.py +1065 -0
- kernel_fun/kda/_provenance.py +18 -0
- kernel_fun/kda/autograd.py +114 -0
- kernel_fun/kda/chain.py +150 -0
- kernel_fun/kda/ops.py +342 -0
- kernel_fun-0.2.0.dev1.dist-info/METADATA +347 -0
- kernel_fun-0.2.0.dev1.dist-info/RECORD +30 -0
- kernel_fun-0.2.0.dev1.dist-info/WHEEL +4 -0
- kernel_fun-0.2.0.dev1.dist-info/licenses/LICENSE +201 -0
- kernel_fun-0.2.0.dev1.dist-info/licenses/NOTICE +60 -0
- kernel_fun-0.2.0.dev1.dist-info/licenses/THIRD_PARTY_NOTICES.md +175 -0
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
"""Phase 1: bwd_intra restructured — one CTA per (chunk, K-slab), sub-chunks internal.
|
|
2
|
+
|
|
3
|
+
fla's `chunk_kda_bwd_intra` runs grid (NK*NC, NT, B*HV) = 524k CTAs of [BC=16, BK=32] work
|
|
4
|
+
at prod8192 and costs 12.6ms, ~5x its floors (ALGORITHM.md). This kernel is the SAME math,
|
|
5
|
+
expression for expression — including the one-sided exp2(g_i - g_j) scalar diagonal loops,
|
|
6
|
+
which are the numerics law of this op and must never be refactored through a reference row
|
|
7
|
+
(see ALGORITHM.md "the numerics law"; the gx16 dbg arm enforces it) — with two structural
|
|
8
|
+
changes only:
|
|
9
|
+
|
|
10
|
+
1. The NC sub-chunk axis moves inside the CTA (tl.static_range unroll). Each CTA touches
|
|
11
|
+
the same dAqk/dAkk [BT,BT] tiles and partner q/k/g tiles up to NC times; in fla those
|
|
12
|
+
hits are spread across 4 CTAs on different SMs (DRAM/L2 re-reads), here they are
|
|
13
|
+
same-CTA L1/L2 hits, and the launch count drops 4x. (Measured alone: 12.62 -> 10.44ms
|
|
14
|
+
at prod8192; widening BK past that measured flat, so it is pinned, not autotuned.)
|
|
15
|
+
2. BK is pinned per call (default 64, KDA002_INTRA_BK to A/B) instead of autotuned: with
|
|
16
|
+
one NK for every config, every autotune config writes every db slab, closing the
|
|
17
|
+
staleness hazard measured as db abs-err up to 3.9 (fla's CachedAutotuner does not run
|
|
18
|
+
reset_to_zero's pre_hook on cached-config launches). BK=128 (NK=1) measured 13.34ms —
|
|
19
|
+
register pressure — so small-BK slabs stay.
|
|
20
|
+
3. The diagonal [BC,BC] blocks are VECTORIZED: fla's two 16-iteration serial scalar
|
|
21
|
+
j-loops (attributed at ~7.2ms of the 10.4ms kernel via KDA002_INTRA_SKIP=diag) become
|
|
22
|
+
j-axis tensor reductions over [BC,BC,BK] elementwise products — still exactly one
|
|
23
|
+
one-sided exp2(g_r - g_s) per (r,s,d) pair, nothing factorized; the dA diag tile loads
|
|
24
|
+
once for both passes. Reduction-tree reassociation puts outputs at ~1e-6 abs of fla
|
|
25
|
+
instead of bit-exact; dbg_intra budgets 1e-5.
|
|
26
|
+
|
|
27
|
+
Interface mirrors fla's wrapper (fresh dq2/dk2/dg2 outputs, incoming dq/dk/dg added
|
|
28
|
+
in-kernel). Fixed-length only, BT=64, K <= 128; everything else (varlen, safe_gate)
|
|
29
|
+
falls back to fla's kernel unchanged.
|
|
30
|
+
|
|
31
|
+
Falsified here, kept out: merging the two diagonal scalar loops into one (shared k_j/g_j
|
|
32
|
+
loads, half the sequential iterations) bought only ~0.1ms of 10.4 and cost the bit-exact
|
|
33
|
+
gate (~1e-6 FMA-contraction drift on dk/dg) — the diagonals are throughput-bound, not
|
|
34
|
+
iteration-count-bound.
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
from __future__ import annotations
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
import torch
|
|
41
|
+
import triton
|
|
42
|
+
import triton.language as tl
|
|
43
|
+
|
|
44
|
+
from fla.ops.utils.cache import fla_cache_autotune
|
|
45
|
+
from fla.ops.utils.op import exp2
|
|
46
|
+
from fla.utils import autotune_cache_kwargs
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
@fla_cache_autotune(
|
|
50
|
+
configs=[
|
|
51
|
+
triton.Config({}, num_warps=num_warps, num_stages=num_stages)
|
|
52
|
+
for num_warps in [2, 4, 8]
|
|
53
|
+
for num_stages in [2, 3, 4]
|
|
54
|
+
],
|
|
55
|
+
key=['BT', 'BC', 'BK', 'K', 'HV'],
|
|
56
|
+
**autotune_cache_kwargs,
|
|
57
|
+
)
|
|
58
|
+
@triton.jit(do_not_specialize=['B', 'T'])
|
|
59
|
+
def kda_cute_bwd_intra_kernel(
|
|
60
|
+
q,
|
|
61
|
+
k,
|
|
62
|
+
g,
|
|
63
|
+
beta,
|
|
64
|
+
dAqk,
|
|
65
|
+
dAkk,
|
|
66
|
+
dq,
|
|
67
|
+
dq2,
|
|
68
|
+
dk,
|
|
69
|
+
dk2,
|
|
70
|
+
dg,
|
|
71
|
+
dg2,
|
|
72
|
+
db,
|
|
73
|
+
T,
|
|
74
|
+
B,
|
|
75
|
+
H: tl.constexpr,
|
|
76
|
+
HV: tl.constexpr,
|
|
77
|
+
K: tl.constexpr,
|
|
78
|
+
BT: tl.constexpr,
|
|
79
|
+
BC: tl.constexpr,
|
|
80
|
+
BK: tl.constexpr,
|
|
81
|
+
NC: tl.constexpr,
|
|
82
|
+
SKIP_DIAG: tl.constexpr,
|
|
83
|
+
SKIP_OFFDIAG: tl.constexpr,
|
|
84
|
+
):
|
|
85
|
+
# SKIP_* are timing-attribution knobs (KDA002_INTRA_SKIP=diag|offdiag): they delete one
|
|
86
|
+
# half of the work at compile time to see what the other half costs. Results are WRONG
|
|
87
|
+
# with either set; dbg_intra.py --time is the only intended caller.
|
|
88
|
+
i_k, i_t, i_bh = tl.program_id(0), tl.program_id(1).to(tl.int64), tl.program_id(2).to(tl.int64)
|
|
89
|
+
i_b, i_hv = i_bh // HV, i_bh % HV
|
|
90
|
+
i_h = i_hv // (HV // H)
|
|
91
|
+
|
|
92
|
+
all = B * T
|
|
93
|
+
bos = i_b * T
|
|
94
|
+
if i_t * BT >= T:
|
|
95
|
+
return
|
|
96
|
+
|
|
97
|
+
o_k = i_k * BK + tl.arange(0, BK)
|
|
98
|
+
m_k = o_k < K
|
|
99
|
+
|
|
100
|
+
q += (bos * H + i_h) * K
|
|
101
|
+
k += (bos * H + i_h) * K
|
|
102
|
+
g += (bos * HV + i_hv) * K
|
|
103
|
+
beta += bos * HV + i_hv
|
|
104
|
+
|
|
105
|
+
dAqk += (bos * HV + i_hv) * BT
|
|
106
|
+
dAkk += (bos * HV + i_hv) * BT
|
|
107
|
+
dq += (bos * HV + i_hv) * K
|
|
108
|
+
dq2 += (bos * HV + i_hv) * K
|
|
109
|
+
dk += (bos * HV + i_hv) * K
|
|
110
|
+
dk2 += (bos * HV + i_hv) * K
|
|
111
|
+
dg += (bos * HV + i_hv) * K
|
|
112
|
+
dg2 += (bos * HV + i_hv) * K
|
|
113
|
+
db += (i_k * all + bos) * HV + i_hv
|
|
114
|
+
|
|
115
|
+
o_i = tl.arange(0, BC)
|
|
116
|
+
# partial-chunk sub-chunk count, fla's clamp for pass B's upper loop
|
|
117
|
+
NCc = min(NC, tl.cdiv(T - i_t * BT, BC))
|
|
118
|
+
|
|
119
|
+
for i_i in tl.static_range(NC):
|
|
120
|
+
i_ti = i_t * BT + i_i * BC
|
|
121
|
+
if i_ti < T:
|
|
122
|
+
o_c = i_ti + o_i
|
|
123
|
+
m_c = o_c < T
|
|
124
|
+
m_ck = m_c[:, None] & m_k[None, :]
|
|
125
|
+
m_dAf = m_c[:, None] & (o_i[None, :] < BT)
|
|
126
|
+
|
|
127
|
+
p_g = g + o_c[:, None] * (HV * K) + o_k[None, :]
|
|
128
|
+
b_g = tl.load(p_g, mask=m_ck, other=0.0).to(tl.float32)
|
|
129
|
+
p_b = beta + o_c * HV
|
|
130
|
+
b_b = tl.load(p_b, mask=m_c, other=0.0)
|
|
131
|
+
|
|
132
|
+
# ---- pass A: row side. dq_intra and the dAkk->dwk products for rows in
|
|
133
|
+
# this sub-chunk, from columns in earlier sub-chunks + the diagonal.
|
|
134
|
+
b_dq2 = tl.zeros([BC, BK], dtype=tl.float32)
|
|
135
|
+
b_dk2 = tl.zeros([BC, BK], dtype=tl.float32)
|
|
136
|
+
if (i_i > 0) & (SKIP_OFFDIAG == 0):
|
|
137
|
+
p_gn = g + i_ti * HV * K + o_k
|
|
138
|
+
b_gn = tl.load(p_gn, mask=m_k, other=0).to(tl.float32)[None, :]
|
|
139
|
+
for i_j in range(0, i_i):
|
|
140
|
+
o_j = i_t * BT + i_j * BC + o_i
|
|
141
|
+
m_jk = (o_j < T)[:, None] & m_k[None, :]
|
|
142
|
+
p_kj = k + o_j[:, None] * (H * K) + o_k[None, :]
|
|
143
|
+
p_gk = g + o_j[:, None] * (HV * K) + o_k[None, :]
|
|
144
|
+
p_dAqk = dAqk + o_c[:, None] * (HV * BT) + (i_j * BC + o_i)[None, :]
|
|
145
|
+
p_dAkk = dAkk + o_c[:, None] * (HV * BT) + (i_j * BC + o_i)[None, :]
|
|
146
|
+
b_kj = tl.load(p_kj, mask=m_jk, other=0.0)
|
|
147
|
+
b_gk = tl.load(p_gk, mask=m_jk, other=0.0)
|
|
148
|
+
b_kg = b_kj * exp2(b_gn - b_gk)
|
|
149
|
+
b_dAqk = tl.load(p_dAqk, mask=m_dAf, other=0.0)
|
|
150
|
+
b_dAkk = tl.load(p_dAkk, mask=m_dAf, other=0.0)
|
|
151
|
+
b_dq2 += tl.dot(b_dAqk, b_kg)
|
|
152
|
+
b_dk2 += tl.dot(b_dAkk, b_kg)
|
|
153
|
+
b_gqn = exp2(b_g - b_gn)
|
|
154
|
+
b_dq2 *= b_gqn
|
|
155
|
+
b_dk2 *= b_gqn
|
|
156
|
+
|
|
157
|
+
# ---- the diagonal [BC,BC] block, BOTH passes, vectorized: still one exp2 per
|
|
158
|
+
# (r, s, d) pair with a one-sided exponent (the numerics law — nothing is
|
|
159
|
+
# factorized through a reference row); only the serial j-loop becomes a j-axis
|
|
160
|
+
# tensor reduction, and the [BC,BC] dA diag tiles are loaded once for the two
|
|
161
|
+
# passes instead of 2*BC scalar-column loads.
|
|
162
|
+
p_q = q + o_c[:, None] * (H * K) + o_k[None, :]
|
|
163
|
+
p_k = k + o_c[:, None] * (H * K) + o_k[None, :]
|
|
164
|
+
b_q = tl.load(p_q, mask=m_ck, other=0.0)
|
|
165
|
+
b_k = tl.load(p_k, mask=m_ck, other=0.0)
|
|
166
|
+
|
|
167
|
+
if SKIP_DIAG == 0:
|
|
168
|
+
m_cc = m_c[:, None] & m_c[None, :]
|
|
169
|
+
p_dAd_qk = dAqk + o_c[:, None] * (HV * BT) + (i_i * BC + o_i)[None, :]
|
|
170
|
+
p_dAd_kk = dAkk + o_c[:, None] * (HV * BT) + (i_i * BC + o_i)[None, :]
|
|
171
|
+
b_dAd_qk = tl.load(p_dAd_qk, mask=m_cc, other=0.0) # [r, s]
|
|
172
|
+
b_dAd_kk = tl.load(p_dAd_kk, mask=m_cc, other=0.0)
|
|
173
|
+
b_kf = b_k.to(tl.float32)
|
|
174
|
+
|
|
175
|
+
# pass A rows: dq/dwk[r,d] += sum_j dA[r,j] * k[j,d] * exp2(g_r - g_j), r >= j
|
|
176
|
+
m_jr = (o_i[:, None] <= o_i[None, :])[:, :, None] # [j, r, 1]
|
|
177
|
+
e_jr = exp2(b_g[None, :, :] - b_g[:, None, :]) # [j, r, d]
|
|
178
|
+
b_kx = b_kf[:, None, :] # k_j -> [j, 1, d]
|
|
179
|
+
b_dq2 += tl.sum(
|
|
180
|
+
tl.where(m_jr, tl.trans(b_dAd_qk)[:, :, None] * b_kx * e_jr, 0.), 0)
|
|
181
|
+
b_dk2 += tl.sum(
|
|
182
|
+
tl.where(m_jr, tl.trans(b_dAd_kk)[:, :, None] * b_kx * e_jr, 0.), 0)
|
|
183
|
+
|
|
184
|
+
# pass B columns: dkt[s,d] += sum_r (dAqk[r,s]*q[r,d] + dAkk[r,s]*β_r*k[r,d])
|
|
185
|
+
# * exp2(g_r - g_s), r >= s
|
|
186
|
+
m_rs = (o_i[:, None] >= o_i[None, :])[:, :, None] # [r, s, 1]
|
|
187
|
+
e_rs = exp2(b_g[:, None, :] - b_g[None, :, :]) # [r, s, d]
|
|
188
|
+
b_qx = b_q.to(tl.float32)[:, None, :]
|
|
189
|
+
b_kbx = (b_kf * b_b[:, None])[:, None, :]
|
|
190
|
+
b_dktd = tl.sum(
|
|
191
|
+
tl.where(
|
|
192
|
+
m_rs,
|
|
193
|
+
(b_dAd_qk[:, :, None] * b_qx + b_dAd_kk[:, :, None] * b_kbx) * e_rs,
|
|
194
|
+
0.,
|
|
195
|
+
),
|
|
196
|
+
0,
|
|
197
|
+
)
|
|
198
|
+
else:
|
|
199
|
+
b_dktd = tl.zeros([BC, BK], dtype=tl.float32)
|
|
200
|
+
|
|
201
|
+
b_db = tl.sum(b_dk2 * b_k, 1)
|
|
202
|
+
b_dk2 *= b_b[:, None]
|
|
203
|
+
|
|
204
|
+
p_dq = dq + o_c[:, None] * (HV * K) + o_k[None, :]
|
|
205
|
+
p_dq2 = dq2 + o_c[:, None] * (HV * K) + o_k[None, :]
|
|
206
|
+
p_db = db + o_c * HV
|
|
207
|
+
|
|
208
|
+
b_dg2 = b_q * b_dq2
|
|
209
|
+
b_dq2 = b_dq2 + tl.load(p_dq, mask=m_ck, other=0.0)
|
|
210
|
+
tl.store(p_dq2, b_dq2.to(p_dq2.dtype.element_ty), mask=m_ck)
|
|
211
|
+
tl.store(p_db, b_db.to(p_db.dtype.element_ty), mask=m_c)
|
|
212
|
+
|
|
213
|
+
# ---- pass B: column side. dkt for columns in this sub-chunk, from rows in
|
|
214
|
+
# later sub-chunks + the diagonal.
|
|
215
|
+
b_dkt = tl.zeros([BC, BK], dtype=tl.float32)
|
|
216
|
+
if (i_i < NCc - 1) & (SKIP_OFFDIAG == 0):
|
|
217
|
+
p_gn = g + (min(i_ti + BC, T) - 1) * HV * K + o_k
|
|
218
|
+
b_gn = tl.load(p_gn, mask=m_k, other=0).to(tl.float32)[None, :]
|
|
219
|
+
for i_j in range(i_i + 1, NC):
|
|
220
|
+
if i_j < NCc:
|
|
221
|
+
o_j = i_t * BT + i_j * BC + o_i
|
|
222
|
+
m_j = o_j < T
|
|
223
|
+
m_jk = m_j[:, None] & m_k[None, :]
|
|
224
|
+
m_dAj = (o_i[:, None] < BT) & m_j[None, :]
|
|
225
|
+
p_qj = q + o_j[:, None] * (H * K) + o_k[None, :]
|
|
226
|
+
p_kj2 = k + o_j[:, None] * (H * K) + o_k[None, :]
|
|
227
|
+
p_gk = g + o_j[:, None] * (HV * K) + o_k[None, :]
|
|
228
|
+
p_bj = beta + o_j * HV
|
|
229
|
+
p_dAqk = dAqk + (i_i * BC + o_i)[:, None] + o_j[None, :] * (HV * BT)
|
|
230
|
+
p_dAkk = dAkk + (i_i * BC + o_i)[:, None] + o_j[None, :] * (HV * BT)
|
|
231
|
+
b_bj = tl.load(p_bj, mask=m_j, other=0.0)
|
|
232
|
+
b_qj = tl.load(p_qj, mask=m_jk, other=0.0)
|
|
233
|
+
b_kbj = tl.load(p_kj2, mask=m_jk, other=0.0) * b_bj[:, None]
|
|
234
|
+
b_gk = tl.load(p_gk, mask=m_jk, other=0.0).to(tl.float32)
|
|
235
|
+
b_dAqk = tl.load(p_dAqk, mask=m_dAj, other=0.0)
|
|
236
|
+
b_dAkk = tl.load(p_dAkk, mask=m_dAj, other=0.0)
|
|
237
|
+
b_gkn = exp2(b_gk - b_gn)
|
|
238
|
+
b_qg = b_qj * tl.where(m_j[:, None], b_gkn, 0)
|
|
239
|
+
b_kbg = b_kbj * tl.where(m_j[:, None], b_gkn, 0)
|
|
240
|
+
# (SY 09/17, kept) important to not use bf16 here for precision
|
|
241
|
+
b_dkt += tl.dot(b_dAqk, b_qg)
|
|
242
|
+
b_dkt += tl.dot(b_dAkk, b_kbg)
|
|
243
|
+
b_dkt *= exp2(b_gn - b_g)
|
|
244
|
+
|
|
245
|
+
# diagonal contribution, computed vectorized above (added after the off-diag
|
|
246
|
+
# scaling, matching fla's accumulation order)
|
|
247
|
+
b_dkt += b_dktd
|
|
248
|
+
|
|
249
|
+
p_dk = dk + o_c[:, None] * (HV * K) + o_k[None, :]
|
|
250
|
+
p_dk2 = dk2 + o_c[:, None] * (HV * K) + o_k[None, :]
|
|
251
|
+
p_dg = dg + o_c[:, None] * (HV * K) + o_k[None, :]
|
|
252
|
+
p_dg2 = dg2 + o_c[:, None] * (HV * K) + o_k[None, :]
|
|
253
|
+
|
|
254
|
+
b_dg2 += (b_dk2 - b_dkt) * b_k + tl.load(p_dg, mask=m_ck, other=0.0)
|
|
255
|
+
b_dk2 += tl.load(p_dk, mask=m_ck, other=0.0)
|
|
256
|
+
b_dk2 += b_dkt
|
|
257
|
+
|
|
258
|
+
tl.store(p_dk2, b_dk2.to(p_dk2.dtype.element_ty), mask=m_ck)
|
|
259
|
+
tl.store(p_dg2, b_dg2.to(p_dg2.dtype.element_ty), mask=m_ck)
|
|
260
|
+
|
|
261
|
+
|
|
262
|
+
# The K slab width, pinned (see the call site for the sweep that chose it).
|
|
263
|
+
_BK = 64
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
def chunk_kda_bwd_intra_cute(
|
|
267
|
+
q: torch.Tensor,
|
|
268
|
+
k: torch.Tensor,
|
|
269
|
+
g: torch.Tensor,
|
|
270
|
+
beta: torch.Tensor,
|
|
271
|
+
dAqk: torch.Tensor,
|
|
272
|
+
dAkk: torch.Tensor,
|
|
273
|
+
dq: torch.Tensor,
|
|
274
|
+
dk: torch.Tensor,
|
|
275
|
+
db: torch.Tensor,
|
|
276
|
+
dg: torch.Tensor,
|
|
277
|
+
cu_seqlens: torch.LongTensor | None = None,
|
|
278
|
+
chunk_indices: torch.LongTensor | None = None,
|
|
279
|
+
chunk_size: int = 64,
|
|
280
|
+
safe_gate: bool = False,
|
|
281
|
+
):
|
|
282
|
+
"""Drop-in for fla's chunk_kda_bwd_intra; falls back to it off the supported box."""
|
|
283
|
+
if (
|
|
284
|
+
cu_seqlens is not None
|
|
285
|
+
or safe_gate
|
|
286
|
+
or chunk_size != 64
|
|
287
|
+
or k.shape[-1] > 128
|
|
288
|
+
):
|
|
289
|
+
from fla.ops.kda.chunk_intra import chunk_kda_bwd_intra
|
|
290
|
+
|
|
291
|
+
return chunk_kda_bwd_intra(
|
|
292
|
+
q=q, k=k, g=g, beta=beta, dAqk=dAqk, dAkk=dAkk,
|
|
293
|
+
dq=dq, dk=dk, db=db, dg=dg,
|
|
294
|
+
cu_seqlens=cu_seqlens, chunk_indices=chunk_indices,
|
|
295
|
+
chunk_size=chunk_size, safe_gate=safe_gate,
|
|
296
|
+
)
|
|
297
|
+
|
|
298
|
+
B, T, H, K, HV = *k.shape, g.shape[2]
|
|
299
|
+
BT = chunk_size
|
|
300
|
+
BC = min(16, BT)
|
|
301
|
+
NT = triton.cdiv(T, BT)
|
|
302
|
+
NC = triton.cdiv(BT, BC)
|
|
303
|
+
|
|
304
|
+
dq2 = torch.empty_like(dq)
|
|
305
|
+
dk2 = torch.empty_like(dk)
|
|
306
|
+
dg2 = torch.empty_like(dg, dtype=torch.float)
|
|
307
|
+
|
|
308
|
+
# BK is PINNED per call (not autotuned): every autotune config then has the same NK
|
|
309
|
+
# and writes every db slab, so no benchmarked config can leave stale slab garbage —
|
|
310
|
+
# the hazard only exists when configs differ in NK (fla's CachedAutotuner skips the
|
|
311
|
+
# reset_to_zero pre_hook on cached-config launches).
|
|
312
|
+
# BK sweep with the vectorized diagonal (prod8192): 64 -> 9.26ms, 32 -> 10.19,
|
|
313
|
+
# 16 -> 11.56, 128 -> 13.34 (register pressure). 64 it is.
|
|
314
|
+
BK = min(_BK, triton.next_power_of_2(K))
|
|
315
|
+
NK = triton.cdiv(K, BK)
|
|
316
|
+
db2 = beta.new_empty(NK, *beta.shape, dtype=torch.float)
|
|
317
|
+
|
|
318
|
+
kda_cute_bwd_intra_kernel[(NK, NT, B * HV)](
|
|
319
|
+
q=q, k=k, g=g, beta=beta, dAqk=dAqk, dAkk=dAkk,
|
|
320
|
+
dq=dq, dq2=dq2, dk=dk, dk2=dk2, dg=dg, dg2=dg2, db=db2,
|
|
321
|
+
T=T, B=B, H=H, HV=HV, K=K, BT=BT, BC=BC, BK=BK, NC=NC,
|
|
322
|
+
# attribution knobs in the research tree; wrong results by construction, so
|
|
323
|
+
# they are wired off here.
|
|
324
|
+
SKIP_DIAG=0,
|
|
325
|
+
SKIP_OFFDIAG=0,
|
|
326
|
+
)
|
|
327
|
+
db_out = db2.sum(0).add_(db)
|
|
328
|
+
return dq2, dk2, db_out, dg2
|