Coverage for  / home / jenkins / .local / lib / python3.10 / site-packages / hyper_parallel / components / functional / _triton / gated_delta_net / chunk_delta_h.py: 0%

370 statements  

« prev     ^ index     » next       coverage.py v7.13.1, created at 2026-11-15 07:18 +0800

1# Copyright 2026 Huawei Technologies Co., Ltd 

2# 

3# Licensed under the Apache License, Version 2.0 (the "License"); 

4# you may not use this file except in compliance with the License. 

5# You may obtain a copy of the License at 

6# 

7# http://www.apache.org/licenses/LICENSE-2.0 

8# 

9# Unless required by applicable law or agreed to in writing, software 

10# distributed under the License is distributed on an "AS IS" BASIS, 

11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 

12# See the License for the specific language governing permissions and 

13# limitations under the License. 

14# ============================================================================ 

15# Copyright (c) 2023-2025, Songlin Yang, Yu Zhang 

16 

17# pylint: disable=line-too-long,missing-public-type-hints,missing-public-docstring 

18# pylint: disable=used-before-assignment,unsupported-binary-operation,unused-argument 

19# pylint: disable=invalid-name,missing-module-docstring,missing-function-docstring 

20# pylint: disable=forbidden-backend-import 

21 

22from typing import Optional, Tuple 

23 

24import torch 

25import triton 

26import triton.language as tl 

27 

28from .utils import prepare_chunk_indices, prepare_chunk_offsets, get_autotune_config, get_npu_properties 

29 

30CUBE_CORE_NUM = get_npu_properties()['num_aicore'] 

31 

32 

33@triton.heuristics({ 

34 'USE_G': lambda args: args['g'] is not None, 

35 'USE_GK': lambda args: args['gk'] is not None, 

36 'USE_INITIAL_STATE': lambda args: args['h0'] is not None, 

37 'STORE_FINAL_STATE': lambda args: args['ht'] is not None, 

38 'SAVE_NEW_VALUE': lambda args: args['v_new'] is not None, 

39 'IS_VARLEN': lambda args: args['cu_seqlens'] is not None, 

40}) 

41@triton.autotune( 

42 configs=get_autotune_config(multibuffer_list=(False,)), 

43 key=['H', 'K', 'V', 'BT'], 

44) 

45@triton.jit(do_not_specialize=['T']) 

46def chunk_gated_delta_rule_fwd_kernel_h_blockdim64( 

47 k, 

48 v, 

49 w, 

50 v_new, 

51 g, 

52 gk, 

53 h, 

54 h0, 

55 ht, 

56 cu_seqlens, 

57 chunk_offsets, 

58 T, 

59 H: tl.constexpr, 

60 K: tl.constexpr, 

61 V: tl.constexpr, 

62 BT: tl.constexpr, 

63 BV: tl.constexpr, 

64 NT: tl.constexpr, 

65 USE_G: tl.constexpr, 

66 USE_GK: tl.constexpr, 

67 USE_INITIAL_STATE: tl.constexpr, 

68 STORE_FINAL_STATE: tl.constexpr, 

69 SAVE_NEW_VALUE: tl.constexpr, 

70 IS_VARLEN: tl.constexpr, 

71): 

72 T_all = T 

73 NT_all = NT 

74 i_v, i_nh = tl.program_id(0), tl.program_id(1) 

75 i_n, i_h = i_nh // H, i_nh % H 

76 if IS_VARLEN: 

77 bos, eos = tl.load(cu_seqlens + i_n).to(tl.int32), tl.load(cu_seqlens + i_n + 1).to(tl.int32) 

78 T = eos - bos 

79 NT = tl.cdiv(T, BT) 

80 boh = tl.load(chunk_offsets + i_n).to(tl.int32) 

81 else: 

82 bos, eos = i_n * T, i_n * T + T 

83 NT = tl.cdiv(T, BT) 

84 boh = i_n * NT 

85 

86 # Initialize hidden states 

87 b_h1 = tl.zeros([64, BV], dtype=tl.float32) 

88 if K > 64: 

89 b_h2 = tl.zeros([64, BV], dtype=tl.float32) 

90 if K > 128: 

91 b_h3 = tl.zeros([64, BV], dtype=tl.float32) 

92 if K > 192: 

93 b_h4 = tl.zeros([64, BV], dtype=tl.float32) 

94 

95 if IS_VARLEN: 

96 v = v + (i_h * T_all + bos) * V 

97 k = k + (i_h * T_all + bos) * K 

98 w = w + (i_h * T_all + bos) * K 

99 if USE_G: 

100 g = g + i_h * T_all + bos 

101 h = h + (i_h * NT_all + boh) * K * V 

102 if SAVE_NEW_VALUE: 

103 v_new_base = v_new + (i_h * T_all + bos) * V 

104 else: 

105 v = v + (i_n * H + i_h) * T * V 

106 k = k + (i_n * H + i_h) * T * K 

107 w = w + (i_n * H + i_h) * T * K 

108 if USE_G: 

109 g = g + (i_n * H + i_h) * T 

110 h = h + (i_n * H + i_h) * NT * K * V 

111 if SAVE_NEW_VALUE: 

112 v_new_base = v_new + (i_n * H + i_h) * T * V 

113 

114 if USE_INITIAL_STATE: 

115 h0_ptr = h0 + i_nh * K * V 

116 if STORE_FINAL_STATE: 

117 ht_ptr = ht + i_nh * K * V 

118 

119 # Load initial state 

120 if USE_INITIAL_STATE: 

121 p_h0_1 = tl.make_block_ptr(h0_ptr, (K, V), (V, 1), (0, i_v * BV), (64, BV), (1, 0)) 

122 b_h1 += tl.load(p_h0_1, boundary_check=(0, 1)).to(tl.float32) 

123 if K > 64: 

124 p_h0_2 = tl.make_block_ptr(h0_ptr, (K, V), (V, 1), (64, i_v * BV), (64, BV), (1, 0)) 

125 b_h2 += tl.load(p_h0_2, boundary_check=(0, 1)).to(tl.float32) 

126 if K > 128: 

127 p_h0_3 = tl.make_block_ptr(h0_ptr, (K, V), (V, 1), (128, i_v * BV), (64, BV), (1, 0)) 

128 b_h3 += tl.load(p_h0_3, boundary_check=(0, 1)).to(tl.float32) 

129 if K > 192: 

130 p_h0_4 = tl.make_block_ptr(h0_ptr, (K, V), (V, 1), (192, i_v * BV), (64, BV), (1, 0)) 

131 b_h4 += tl.load(p_h0_4, boundary_check=(0, 1)).to(tl.float32) 

132 

133 # Main recurrence over chunks 

134 for i_t in range(NT): 

135 # Store current hidden state h_t 

136 p_h1 = tl.make_block_ptr(h + i_t * K * V, (K, V), (V, 1), (0, i_v * BV), (64, BV), (1, 0)) 

137 tl.store(p_h1, b_h1.to(p_h1.dtype.element_ty), boundary_check=(0, 1)) 

138 if K > 64: 

139 p_h2 = tl.make_block_ptr(h + i_t * K * V, (K, V), (V, 1), (64, i_v * BV), (64, BV), (1, 0)) 

140 tl.store(p_h2, b_h2.to(p_h2.dtype.element_ty), boundary_check=(0, 1)) 

141 if K > 128: 

142 p_h3 = tl.make_block_ptr(h + i_t * K * V, (K, V), (V, 1), (128, i_v * BV), (64, BV), (1, 0)) 

143 tl.store(p_h3, b_h3.to(p_h3.dtype.element_ty), boundary_check=(0, 1)) 

144 if K > 192: 

145 p_h4 = tl.make_block_ptr(h + i_t * K * V, (K, V), (V, 1), (192, i_v * BV), (64, BV), (1, 0)) 

146 tl.store(p_h4, b_h4.to(p_h4.dtype.element_ty), boundary_check=(0, 1)) 

147 

148 # Compute v_residual = v - w @ h 

149 p_w = tl.make_block_ptr(w, (T, K), (K, 1), (i_t * BT, 0), (BT, 64), (1, 0)) 

150 b_w = tl.load(p_w, boundary_check=(0, 1)) 

151 b_v = tl.dot(b_w, b_h1.to(b_w.dtype)) 

152 if K > 64: 

153 p_w = tl.make_block_ptr(w, (T, K), (K, 1), (i_t * BT, 64), (BT, 64), (1, 0)) 

154 b_w = tl.load(p_w, boundary_check=(0, 1)) 

155 b_v += tl.dot(b_w, b_h2.to(b_w.dtype)) 

156 if K > 128: 

157 p_w = tl.make_block_ptr(w, (T, K), (K, 1), (i_t * BT, 128), (BT, 64), (1, 0)) 

158 b_w = tl.load(p_w, boundary_check=(0, 1)) 

159 b_v += tl.dot(b_w, b_h3.to(b_w.dtype)) 

160 if K > 192: 

161 p_w = tl.make_block_ptr(w, (T, K), (K, 1), (i_t * BT, 192), (BT, 64), (1, 0)) 

162 b_w = tl.load(p_w, boundary_check=(0, 1)) 

163 b_v += tl.dot(b_w, b_h4.to(b_w.dtype)) 

164 

165 p_v = tl.make_block_ptr(v, (T, V), (V, 1), (i_t * BT, i_v * BV), (BT, BV), (1, 0)) 

166 b_v = tl.load(p_v, boundary_check=(0, 1)) - b_v 

167 

168 if SAVE_NEW_VALUE: 

169 p_v_new = tl.make_block_ptr(v_new_base, (T, V), (V, 1), (i_t * BT, i_v * BV), (BT, BV), (1, 0)) 

170 tl.store(p_v_new, b_v.to(p_v_new.dtype.element_ty), boundary_check=(0, 1)) 

171 

172 last_idx = min((i_t + 1) * BT, T) - 1 

173 

174 # Apply output gate g 

175 if USE_G: 

176 m_t = (i_t * BT + tl.arange(0, BT)).to(tl.float32) < T 

177 b_g_last = tl.load(g + last_idx) 

178 p_g = tl.make_block_ptr(g, (T,), (1,), (i_t * BT,), (BT,), (0,)) 

179 b_g = tl.load(p_g, boundary_check=(0,)) 

180 b_v *= (m_t * tl.exp(b_g_last - b_g))[:, None] 

181 b_g_last_exp = tl.exp(b_g_last) 

182 b_h1 *= b_g_last_exp 

183 if K > 64: 

184 b_h2 *= b_g_last_exp 

185 if K > 128: 

186 b_h3 *= b_g_last_exp 

187 if K > 192: 

188 b_h4 *= b_g_last_exp 

189 

190 # Apply key gate gk 

191 if USE_GK: 

192 o_k1 = tl.arange(0, 64) 

193 if IS_VARLEN: 

194 gk_base_ptr = gk + (i_h * T_all + bos) * K 

195 else: 

196 gk_base_ptr = gk + (i_n * H + i_h) * T * K 

197 b_gk_last1 = tl.load(gk_base_ptr + last_idx * K + o_k1, mask=(o_k1 < K), other=0.) 

198 b_h1 *= tl.exp(b_gk_last1)[:, None] 

199 if K > 64: 

200 o_k2 = 64 + o_k1 

201 b_gk_last2 = tl.load(gk_base_ptr + last_idx * K + o_k2, mask=(o_k2 < K), other=0.) 

202 b_h2 *= tl.exp(b_gk_last2)[:, None] 

203 if K > 128: 

204 o_k3 = 128 + o_k1 

205 b_gk_last3 = tl.load(gk_base_ptr + last_idx * K + o_k3, mask=(o_k3 < K), other=0.) 

206 b_h3 *= tl.exp(b_gk_last3)[:, None] 

207 if K > 192: 

208 o_k4 = 192 + o_k1 

209 b_gk_last4 = tl.load(gk_base_ptr + last_idx * K + o_k4, mask=(o_k4 < K), other=0.) 

210 b_h4 *= tl.exp(b_gk_last4)[:, None] 

211 

212 b_v = b_v.to(k.dtype.element_ty) 

213 

214 # Update hidden state: h += k @ v 

215 p_k = tl.make_block_ptr(k, (K, T), (1, K), (0, i_t * BT), (64, BT), (0, 1)) 

216 b_k = tl.load(p_k, boundary_check=(0, 1)) 

217 if USE_GK: 

218 p_gk = tl.make_block_ptr(gk_base_ptr, (K, T), (1, K), (0, i_t * BT), (64, BT), (0, 1)) 

219 b_k = (b_k * tl.exp(b_gk_last1[:, None] - tl.load(p_gk, boundary_check=(0, 1)))).to(b_k.dtype) 

220 b_h1 += tl.dot(b_k, b_v) 

221 

222 if K > 64: 

223 p_k = tl.make_block_ptr(k, (K, T), (1, K), (64, i_t * BT), (64, BT), (0, 1)) 

224 b_k = tl.load(p_k, boundary_check=(0, 1)) 

225 if USE_GK: 

226 p_gk = tl.make_block_ptr(gk_base_ptr, (K, T), (1, K), (64, i_t * BT), (64, BT), (0, 1)) 

227 b_k = (b_k * tl.exp(b_gk_last2[:, None] - tl.load(p_gk, boundary_check=(0, 1)))).to(b_k.dtype) 

228 b_h2 += tl.dot(b_k, b_v) 

229 

230 if K > 128: 

231 p_k = tl.make_block_ptr(k, (K, T), (1, K), (128, i_t * BT), (64, BT), (0, 1)) 

232 b_k = tl.load(p_k, boundary_check=(0, 1)) 

233 if USE_GK: 

234 p_gk = tl.make_block_ptr(gk_base_ptr, (K, T), (1, K), (128, i_t * BT), (64, BT), (0, 1)) 

235 b_k = (b_k * tl.exp(b_gk_last3[:, None] - tl.load(p_gk, boundary_check=(0, 1)))).to(b_k.dtype) 

236 b_h3 += tl.dot(b_k, b_v) 

237 

238 if K > 192: 

239 p_k = tl.make_block_ptr(k, (K, T), (1, K), (192, i_t * BT), (64, BT), (0, 1)) 

240 b_k = tl.load(p_k, boundary_check=(0, 1)) 

241 if USE_GK: 

242 p_gk = tl.make_block_ptr(gk_base_ptr, (K, T), (1, K), (192, i_t * BT), (64, BT), (0, 1)) 

243 b_k = (b_k * tl.exp(b_gk_last4[:, None] - tl.load(p_gk, boundary_check=(0, 1)))).to(b_k.dtype) 

244 b_h4 += tl.dot(b_k, b_v) 

245 

246 # Store final state 

247 if STORE_FINAL_STATE: 

248 p_ht = tl.make_block_ptr(ht_ptr, (K, V), (V, 1), (0, i_v * BV), (64, BV), (1, 0)) 

249 tl.store(p_ht, b_h1.to(p_ht.dtype.element_ty), boundary_check=(0, 1)) 

250 if K > 64: 

251 p_ht = tl.make_block_ptr(ht_ptr, (K, V), (V, 1), (64, i_v * BV), (64, BV), (1, 0)) 

252 tl.store(p_ht, b_h2.to(p_ht.dtype.element_ty), boundary_check=(0, 1)) 

253 if K > 128: 

254 p_ht = tl.make_block_ptr(ht_ptr, (K, V), (V, 1), (128, i_v * BV), (64, BV), (1, 0)) 

255 tl.store(p_ht, b_h3.to(p_ht.dtype.element_ty), boundary_check=(0, 1)) 

256 if K > 192: 

257 p_ht = tl.make_block_ptr(ht_ptr, (K, V), (V, 1), (192, i_v * BV), (64, BV), (1, 0)) 

258 tl.store(p_ht, b_h4.to(p_ht.dtype.element_ty), boundary_check=(0, 1)) 

259 

260 

261def chunk_gated_delta_rule_fwd_h( 

262 k: torch.Tensor, 

263 w: torch.Tensor, 

264 u: torch.Tensor, 

265 g: Optional[torch.Tensor] = None, 

266 gk: Optional[torch.Tensor] = None, 

267 initial_state: Optional[torch.Tensor] = None, 

268 output_final_state: bool = False, 

269 chunk_size: int = 64, # default:64 

270 save_new_value: bool = True, 

271 cu_seqlens: Optional[torch.LongTensor] = None, 

272) -> Tuple[torch.Tensor, torch.Tensor, Optional[torch.Tensor]]: 

273 B, T, H, K, V = *k.shape, u.shape[-1] 

274 BT = chunk_size 

275 

276 chunk_indices = prepare_chunk_indices(cu_seqlens, chunk_size) if cu_seqlens is not None else None 

277 # N: the actual number of sequences in the batch with either equal or variable lengths 

278 if cu_seqlens is None: 

279 N, NT, chunk_offsets = B, triton.cdiv(T, BT), None 

280 else: 

281 N, NT, chunk_offsets = len(cu_seqlens) - 1, len(chunk_indices), prepare_chunk_offsets(cu_seqlens, BT) 

282 if K > 256: 

283 raise ValueError("current kernel does not support head dimension larger than 256.") 

284 

285 h = k.new_empty(B, NT, H, K, V).permute(0, 2, 1, 3, 4).contiguous() 

286 final_state = k.new_empty(N, H, K, V, dtype=torch.float32) if output_final_state else None 

287 

288 BV = 128 

289 

290 v_new = torch.empty_like(u).permute(0, 2, 1, 3).contiguous() if save_new_value else None 

291 k = k.permute(0, 2, 1, 3).contiguous() 

292 w = w.permute(0, 2, 1, 3).contiguous() 

293 u = u.permute(0, 2, 1, 3).contiguous() 

294 g = g.permute(0, 2, 1).contiguous() if g is not None else None 

295 # Match the head-major layout used by the forward kernel's token strides. 

296 gk = gk.permute(0, 2, 1, 3).contiguous() if gk is not None else None 

297 chunk_gated_delta_rule_fwd_kernel_h_blockdim64[(triton.cdiv(V, BV), N * H)]( 

298 k=k, 

299 v=u, 

300 w=w, 

301 v_new=v_new, 

302 g=g, 

303 gk=gk, 

304 h=h, 

305 h0=initial_state, 

306 ht=final_state, 

307 cu_seqlens=cu_seqlens, 

308 chunk_offsets=chunk_offsets, 

309 T=T, 

310 H=H, 

311 K=K, 

312 V=V, 

313 BT=BT, 

314 BV=BV, 

315 NT=NT, 

316 ) 

317 h = h.permute(0, 2, 1, 3, 4).contiguous() 

318 v_new = v_new.permute(0, 2, 1, 3).contiguous() if v_new is not None else None 

319 return h, v_new, final_state 

320 

321 

322@triton.heuristics({ 

323 'USE_G': lambda args: args['g'] is not None, 

324 'USE_GK': lambda args: args['gk'] is not None, 

325 'USE_INITIAL_STATE': lambda args: args['dh0'] is not None, 

326 'USE_FINAL_STATE_GRADIENT': lambda args: args['dht'] is not None, 

327 'IS_VARLEN': lambda args: args['cu_seqlens'] is not None, 

328}) 

329# Preserve all cache keys without interpreting them as automatic tiling axes. 

330@triton.runtime.autotuner.autotune( 

331 configs=get_autotune_config(multibuffer_list=(True, False)), 

332 key=['H', 'K', 'V', 'BT', 'BV', 'USE_G', 'IS_VARLEN'], 

333) 

334@triton.jit(do_not_specialize=['T']) 

335def chunk_gated_delta_rule_bwd_kernel_dhu_blockdim64( 

336 q, 

337 k, 

338 w, 

339 g, 

340 gk, 

341 dht, 

342 dh0, 

343 do, 

344 dh, 

345 dv, 

346 dv2, 

347 cu_seqlens, 

348 chunk_offsets, 

349 scale, 

350 T, 

351 H: tl.constexpr, 

352 K: tl.constexpr, 

353 V: tl.constexpr, 

354 BT: tl.constexpr, 

355 BV: tl.constexpr, 

356 USE_G: tl.constexpr, 

357 USE_GK: tl.constexpr, 

358 USE_INITIAL_STATE: tl.constexpr, 

359 USE_FINAL_STATE_GRADIENT: tl.constexpr, 

360 IS_VARLEN: tl.constexpr, 

361): 

362 T_all = T 

363 i_v, i_nh = tl.program_id(0), tl.program_id(1) 

364 i_n, i_h = i_nh // H, i_nh % H 

365 if IS_VARLEN: 

366 bos, eos = tl.load(cu_seqlens + i_n).to(tl.int32), tl.load(cu_seqlens + i_n + 1).to(tl.int32) 

367 T = eos - bos 

368 NT = tl.cdiv(T, BT) 

369 boh = tl.load(chunk_offsets + i_n).to(tl.int32) 

370 else: 

371 bos, eos = i_n * T, i_n * T + T 

372 NT = tl.cdiv(T, BT) 

373 boh = i_n * NT 

374 

375 b_dh1 = tl.zeros([64, BV], dtype=tl.float32) 

376 if K > 64: 

377 b_dh2 = tl.zeros([64, BV], dtype=tl.float32) 

378 if K > 128: 

379 b_dh3 = tl.zeros([64, BV], dtype=tl.float32) 

380 if K > 192: 

381 b_dh4 = tl.zeros([64, BV], dtype=tl.float32) 

382 

383 q += (bos * H + i_h) * K 

384 k += (bos * H + i_h) * K 

385 w += (bos * H + i_h) * K 

386 do += (bos * H + i_h) * V 

387 dv += (bos * H + i_h) * V 

388 dv2 += (bos * H + i_h) * V 

389 dh += (boh * H + i_h) * K * V 

390 if USE_GK: 

391 gk += (bos * H + i_h) * K 

392 

393 if USE_INITIAL_STATE: 

394 dh0 += i_nh * K * V 

395 if USE_FINAL_STATE_GRADIENT: 

396 dht += i_nh * K * V 

397 

398 stride_v = H * V 

399 stride_h = H * K * V 

400 stride_k = H * K 

401 

402 if USE_FINAL_STATE_GRADIENT: 

403 p_dht1 = tl.make_block_ptr(dht, (K, V), (V, 1), (0, i_v * BV), (64, BV), (1, 0)) 

404 b_dh1 += tl.load(p_dht1, boundary_check=(0, 1)) 

405 if K > 64: 

406 p_dht2 = tl.make_block_ptr(dht, (K, V), (V, 1), (64, i_v * BV), (64, BV), (1, 0)) 

407 b_dh2 += tl.load(p_dht2, boundary_check=(0, 1)) 

408 if K > 128: 

409 p_dht3 = tl.make_block_ptr(dht, (K, V), (V, 1), (128, i_v * BV), (64, BV), (1, 0)) 

410 b_dh3 += tl.load(p_dht3, boundary_check=(0, 1)) 

411 if K > 192: 

412 p_dht4 = tl.make_block_ptr(dht, (K, V), (V, 1), (192, i_v * BV), (64, BV), (1, 0)) 

413 b_dh4 += tl.load(p_dht4, boundary_check=(0, 1)) 

414 

415 for i_t in range(NT - 1, -1, -1): 

416 p_dh1 = tl.make_block_ptr(dh + i_t * stride_h, (K, V), (V, 1), (0, i_v * BV), (64, BV), (1, 0)) 

417 tl.store(p_dh1, b_dh1.to(p_dh1.dtype.element_ty), boundary_check=(0, 1)) 

418 if K > 64: 

419 p_dh2 = tl.make_block_ptr(dh + i_t * stride_h, (K, V), (V, 1), (64, i_v * BV), (64, BV), (1, 0)) 

420 tl.store(p_dh2, b_dh2.to(p_dh2.dtype.element_ty), boundary_check=(0, 1)) 

421 if K > 128: 

422 p_dh3 = tl.make_block_ptr(dh + i_t * stride_h, (K, V), (V, 1), (128, i_v * BV), (64, BV), (1, 0)) 

423 tl.store(p_dh3, b_dh3.to(p_dh3.dtype.element_ty), boundary_check=(0, 1)) 

424 if K > 192: 

425 p_dh4 = tl.make_block_ptr(dh + i_t * stride_h, (K, V), (V, 1), (192, i_v * BV), (64, BV), (1, 0)) 

426 tl.store(p_dh4, b_dh4.to(p_dh4.dtype.element_ty), boundary_check=(0, 1)) 

427 

428 last_idx = min((i_t + 1) * BT, T) - 1 

429 if USE_G: 

430 if IS_VARLEN: 

431 bos_g = i_h * T_all + bos 

432 else: 

433 bos_g = (i_n * H + i_h) * T_all 

434 bg_last = tl.load(g + bos_g + last_idx) 

435 bg_last_exp = tl.exp(bg_last) 

436 p_g = tl.make_block_ptr(base=g + bos_g, shape=(T,), strides=(1,), offsets=(i_t * BT,), block_shape=(BT,), order=(0,)) 

437 b_g = tl.load(p_g, boundary_check=(0,)) 

438 b_g_exp = tl.exp(b_g) 

439 

440 p_dv = tl.make_block_ptr(dv, (T, V), (stride_v, 1), (i_t * BT, i_v * BV), (BT, BV), (1, 0)) 

441 p_dv2 = tl.make_block_ptr(dv2, (T, V), (stride_v, 1), (i_t * BT, i_v * BV), (BT, BV), (1, 0)) 

442 p_do = tl.make_block_ptr(do, (T, V), (stride_v, 1), (i_t * BT, i_v * BV), (BT, BV), (1, 0)) 

443 

444 b_do = tl.load(p_do, boundary_check=(0, 1)) 

445 

446 # Update dv 

447 p_k = tl.make_block_ptr(k, (T, K), (stride_k, 1), (i_t * BT, 0), (BT, 64), (1, 0)) 

448 b_k = tl.load(p_k, boundary_check=(0, 1)) 

449 if USE_GK: 

450 o_k1 = tl.arange(0, 64) 

451 b_gk_last1 = tl.load(gk + last_idx * H * K + o_k1, mask=(o_k1 < K), other=0.) 

452 b_dv = tl.dot(b_k, b_dh1.to(b_k.dtype)) 

453 

454 if K > 64: 

455 p_k = tl.make_block_ptr(k, (T, K), (stride_k, 1), (i_t * BT, 64), (BT, 64), (1, 0)) 

456 b_k = tl.load(p_k, boundary_check=(0, 1)) 

457 if USE_GK: 

458 o_k2 = 64 + o_k1 

459 b_gk_last2 = tl.load(gk + last_idx * H * K + o_k2, mask=(o_k2 < K), other=0.) 

460 b_dv += tl.dot(b_k, b_dh2.to(b_k.dtype)) 

461 

462 if K > 128: 

463 p_k = tl.make_block_ptr(k, (T, K), (stride_k, 1), (i_t * BT, 128), (BT, 64), (1, 0)) 

464 b_k = tl.load(p_k, boundary_check=(0, 1)) 

465 if USE_GK: 

466 o_k3 = 128 + o_k1 

467 b_gk_last3 = tl.load(gk + last_idx * H * K + o_k3, mask=(o_k3 < K), other=0.) 

468 b_dv += tl.dot(b_k, b_dh3.to(b_k.dtype)) 

469 

470 if K > 192: 

471 p_k = tl.make_block_ptr(k, (T, K), (stride_k, 1), (i_t * BT, 192), (BT, 64), (1, 0)) 

472 b_k = tl.load(p_k, boundary_check=(0, 1)) 

473 if USE_GK: 

474 o_k4 = 192 + o_k1 

475 b_gk_last4 = tl.load(gk + last_idx * H * K + o_k4, mask=(o_k4 < K), other=0.) 

476 b_dv += tl.dot(b_k, b_dh4.to(b_k.dtype)) 

477 

478 if USE_G: 

479 m_t = (i_t * BT + tl.arange(0, BT)).to(tl.float32) < T 

480 b_dv *= (m_t * tl.exp(bg_last - b_g))[:, None] 

481 b_dv += tl.load(p_dv, boundary_check=(0, 1)) 

482 

483 tl.store(p_dv2, b_dv.to(p_dv.dtype.element_ty), boundary_check=(0, 1)) 

484 # Update dh 

485 p_w = tl.make_block_ptr(w, (K, T), (1, stride_k), (0, i_t * BT), (64, BT), (0, 1)) 

486 p_q = tl.make_block_ptr(q, (K, T), (1, stride_k), (0, i_t * BT), (64, BT), (0, 1)) 

487 b_w = tl.load(p_w, boundary_check=(0, 1)) 

488 b_q = tl.load(p_q, boundary_check=(0, 1)) 

489 if USE_G: 

490 b_dh1 *= bg_last_exp 

491 b_q = b_q * b_g_exp[None, :] 

492 if USE_GK: 

493 b_dh1 *= tl.exp(b_gk_last1[:, None]) 

494 b_dh1 += tl.dot(b_q.to(b_q.dtype), b_do.to(b_q.dtype)) * scale - tl.dot(b_w, b_dv.to(b_w.dtype)) 

495 if K > 64: 

496 p_q = tl.make_block_ptr(q, (K, T), (1, stride_k), (64, i_t * BT), (64, BT), (0, 1)) 

497 p_w = tl.make_block_ptr(w, (K, T), (1, stride_k), (64, i_t * BT), (64, BT), (0, 1)) 

498 b_q = tl.load(p_q, boundary_check=(0, 1)) 

499 b_w = tl.load(p_w, boundary_check=(0, 1)) 

500 if USE_G: 

501 b_dh2 *= bg_last_exp 

502 b_q = b_q * b_g_exp[None, :] 

503 if USE_GK: 

504 b_dh2 *= tl.exp(b_gk_last2[:, None]) 

505 b_dh2 += tl.dot(b_q.to(b_q.dtype), b_do.to(b_q.dtype)) * scale - tl.dot(b_w, b_dv.to(b_w.dtype)) 

506 if K > 128: 

507 p_q = tl.make_block_ptr(q, (K, T), (1, stride_k), (128, i_t * BT), (64, BT), (0, 1)) 

508 p_w = tl.make_block_ptr(w, (K, T), (1, stride_k), (128, i_t * BT), (64, BT), (0, 1)) 

509 b_q = tl.load(p_q, boundary_check=(0, 1)) 

510 b_w = tl.load(p_w, boundary_check=(0, 1)) 

511 if USE_G: 

512 b_dh3 *= bg_last_exp 

513 b_q = b_q * b_g_exp[None, :] 

514 if USE_GK: 

515 b_dh3 *= tl.exp(b_gk_last3[:, None]) 

516 b_dh3 += tl.dot(b_q.to(b_q.dtype), b_do.to(b_q.dtype)) * scale - tl.dot(b_w, b_dv.to(b_w.dtype)) 

517 if K > 192: 

518 p_q = tl.make_block_ptr(q, (K, T), (1, stride_k), (192, i_t * BT), (64, BT), (0, 1)) 

519 p_w = tl.make_block_ptr(w, (K, T), (1, stride_k), (192, i_t * BT), (64, BT), (0, 1)) 

520 b_q = tl.load(p_q, boundary_check=(0, 1)) 

521 b_w = tl.load(p_w, boundary_check=(0, 1)) 

522 if USE_G: 

523 b_dh4 *= bg_last_exp 

524 b_q = b_q * b_g_exp[None, :] 

525 if USE_GK: 

526 b_dh4 *= tl.exp(b_gk_last4[:, None]) 

527 b_dh4 += tl.dot(b_q.to(b_q.dtype), b_do.to(b_q.dtype)) * scale - tl.dot(b_w, b_dv.to(b_w.dtype)) 

528 

529 if USE_INITIAL_STATE: 

530 p_dh0 = tl.make_block_ptr(dh0, (K, V), (V, 1), (0, i_v * BV), (64, BV), (1, 0)) 

531 tl.store(p_dh0, b_dh1.to(p_dh0.dtype.element_ty), boundary_check=(0, 1)) 

532 if K > 64: 

533 p_dh1 = tl.make_block_ptr(dh0, (K, V), (V, 1), (64, i_v * BV), (64, BV), (1, 0)) 

534 tl.store(p_dh1, b_dh2.to(p_dh1.dtype.element_ty), boundary_check=(0, 1)) 

535 if K > 128: 

536 p_dh2 = tl.make_block_ptr(dh0, (K, V), (V, 1), (128, i_v * BV), (64, BV), (1, 0)) 

537 tl.store(p_dh2, b_dh3.to(p_dh2.dtype.element_ty), boundary_check=(0, 1)) 

538 if K > 192: 

539 p_dh3 = tl.make_block_ptr(dh0, (K, V), (V, 1), (192, i_v * BV), (64, BV), (1, 0)) 

540 tl.store(p_dh3, b_dh4.to(p_dh3.dtype.element_ty), boundary_check=(0, 1)) 

541 

542 

543def chunk_gated_delta_rule_bwd_dhu( 

544 q: torch.Tensor, 

545 k: torch.Tensor, 

546 w: torch.Tensor, 

547 do: torch.Tensor, 

548 dv: torch.Tensor, 

549 g: torch.Tensor | None = None, 

550 gk: torch.Tensor | None = None, 

551 h0: torch.Tensor | None = None, 

552 dht: torch.Tensor | None = None, 

553 scale: float | None = None, 

554 cu_seqlens: torch.LongTensor | None = None, 

555 chunk_size: int = 64, # SY: remove this argument and force chunk size 64? 

556 chunk_indices: torch.LongTensor | None = None, 

557 use_exp2: bool = False, 

558) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor]: 

559 B, T, H, K, V = *q.shape, do.shape[-1] 

560 # N: the actual number of sequences in the batch with either equal or variable lengths 

561 BT = 64 

562 if K > 256: 

563 raise ValueError("current kernel does not support head dimension being larger than 256.") 

564 

565 if chunk_indices is None and cu_seqlens is not None: 

566 chunk_indices = prepare_chunk_indices(cu_seqlens, chunk_size) 

567 if cu_seqlens is None: 

568 N, NT, chunk_offsets = B, triton.cdiv(T, BT), None 

569 else: 

570 N, NT, chunk_offsets = len(cu_seqlens) - 1, len(chunk_indices), prepare_chunk_offsets(cu_seqlens, BT) 

571 

572 dh = q.new_empty(B, NT, H, K, V) 

573 dh0 = torch.empty_like(h0, dtype=torch.float32) if h0 is not None else None 

574 dv2 = torch.empty_like(dv) 

575 

576 BV = 128 

577 

578 g = g.permute(0, 2, 1).contiguous() 

579 

580 chunk_gated_delta_rule_bwd_kernel_dhu_blockdim64[(triton.cdiv(V, BV), N * H)]( 

581 q=q, 

582 k=k, 

583 w=w, 

584 g=g, 

585 gk=gk, 

586 dht=dht, 

587 dh0=dh0, 

588 do=do, 

589 dh=dh, 

590 dv=dv, 

591 dv2=dv2, 

592 cu_seqlens=cu_seqlens, 

593 chunk_offsets=chunk_offsets, 

594 scale=scale, 

595 T=T, 

596 H=H, 

597 K=K, 

598 V=V, 

599 BT=BT, 

600 BV=BV, 

601 ) 

602 return dh, dh0, dv2