src/ops_attention.cpp
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | // brotensor public op wrappers — attention, matmul, LSTM, RoPE, RMSNorm, SwiGLU, reductions. | ||
| 2 | |||
| 3 | #include <brotensor/ops.h> | ||
| 4 | #include <brotensor/tensor.h> | ||
| 5 | #include <brotensor/detail/dispatch.h> | ||
| 6 | |||
| 7 | #include <cstdint> | ||
| 8 | #include <stdexcept> | ||
| 9 | |||
| 10 | namespace brotensor { | ||
| 11 | |||
| 12 | // ─── FP16 linear + GEGLU ─────────────────────────────────────────────────── | ||
| 13 | |||
| 14 | 49 | void linear_forward_batched_fp16(const Tensor& W, const Tensor* bias, | |
| 15 | const Tensor& X_BD, Tensor& Y_BD) { | ||
| 16 | 49 | const auto& v = detail::dispatch_with_opts(W, X_BD, {bias, &Y_BD}); | |
| 17 |
1/2✓ Branch 0 taken 49 times.
✗ Branch 1 not taken.
|
49 | if (!v.linear_forward_batched_fp16) detail::throw_not_implemented("linear_forward_batched_fp16", W.device); |
| 18 | 49 | detail::adopt_output(Y_BD, W.device); | |
| 19 | 49 | v.linear_forward_batched_fp16(W, bias, X_BD, Y_BD); | |
| 20 | 49 | } | |
| 21 | |||
| 22 | 29 | void linear_forward_batched_fp16_act(const Tensor& W, const Tensor* bias, | |
| 23 | const Tensor& X_BD, int act, Tensor& Y_BD) { | ||
| 24 | 29 | const auto& v = detail::dispatch_with_opts(W, X_BD, {bias, &Y_BD}); | |
| 25 |
1/2✓ Branch 0 taken 29 times.
✗ Branch 1 not taken.
|
29 | if (!v.linear_forward_batched_fp16_act) |
| 26 | ✗ | detail::throw_not_implemented("linear_forward_batched_fp16_act", W.device); | |
| 27 | 29 | detail::adopt_output(Y_BD, W.device); | |
| 28 | 29 | v.linear_forward_batched_fp16_act(W, bias, X_BD, act, Y_BD); | |
| 29 | 29 | } | |
| 30 | |||
| 31 | 439 | void linear_forward_batched_ex(const Tensor& W, const Tensor* bias, const Tensor& X_BD, | |
| 32 | int act, int epilogue, Tensor* workspace, Tensor& Y_BD) { | ||
| 33 | 439 | const auto& v = detail::dispatch_with_opts(W, X_BD, {bias, &Y_BD, workspace}); | |
| 34 |
1/2✓ Branch 0 taken 439 times.
✗ Branch 1 not taken.
|
439 | if (!v.linear_forward_batched_ex) |
| 35 | ✗ | detail::throw_not_implemented("linear_forward_batched_ex", W.device); | |
| 36 | 439 | detail::adopt_output(Y_BD, W.device); | |
| 37 |
2/2✓ Branch 0 taken 285 times.
✓ Branch 1 taken 154 times.
|
439 | if (workspace) detail::adopt_output(*workspace, W.device); |
| 38 | 439 | v.linear_forward_batched_ex(W, bias, X_BD, act, epilogue, workspace, Y_BD); | |
| 39 | 439 | } | |
| 40 | |||
| 41 | 12 | void geglu_forward(const Tensor& X, Tensor& Y) { | |
| 42 | 12 | const auto& v = detail::dispatch(X, Y); | |
| 43 |
1/2✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
|
12 | if (!v.geglu_forward) detail::throw_not_implemented("geglu_forward", X.device); |
| 44 | 12 | detail::adopt_output(Y, X.device); | |
| 45 | 12 | v.geglu_forward(X, Y); | |
| 46 | 12 | } | |
| 47 | 8 | void geglu_backward(const Tensor& X, const Tensor& dY, Tensor& dX) { | |
| 48 | 8 | const auto& v = detail::dispatch(X, dY, dX); | |
| 49 |
1/2✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
|
8 | if (!v.geglu_backward) detail::throw_not_implemented("geglu_backward", X.device); |
| 50 | 8 | detail::adopt_output(dX, X.device); | |
| 51 | 8 | v.geglu_backward(X, dY, dX); | |
| 52 | 8 | } | |
| 53 | 11 | void geglu_exact_forward(const Tensor& X, Tensor& Y) { | |
| 54 | 11 | const auto& v = detail::dispatch(X, Y); | |
| 55 |
1/2✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
|
11 | if (!v.geglu_exact_forward) detail::throw_not_implemented("geglu_exact_forward", X.device); |
| 56 | 11 | detail::adopt_output(Y, X.device); | |
| 57 | 11 | v.geglu_exact_forward(X, Y); | |
| 58 | 11 | } | |
| 59 | 9 | void geglu_exact_backward(const Tensor& X, const Tensor& dY, Tensor& dX) { | |
| 60 | 9 | const auto& v = detail::dispatch(X, dY, dX); | |
| 61 |
1/2✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
|
9 | if (!v.geglu_exact_backward) detail::throw_not_implemented("geglu_exact_backward", X.device); |
| 62 | 9 | detail::adopt_output(dX, X.device); | |
| 63 | 9 | v.geglu_exact_backward(X, dY, dX); | |
| 64 | 9 | } | |
| 65 | |||
| 66 | // ─── Causal mask helper ──────────────────────────────────────────────────── | ||
| 67 | |||
| 68 | 23 | void build_causal_mask_row(int L, int q, Tensor& mask) { | |
| 69 | 23 | const auto& v = detail::dispatch(mask); | |
| 70 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 | if (!v.build_causal_mask_row) detail::throw_not_implemented("build_causal_mask_row", mask.device); |
| 71 | 23 | detail::adopt_output(mask, mask.device); | |
| 72 | 23 | v.build_causal_mask_row(L, q, mask); | |
| 73 | 23 | } | |
| 74 | |||
| 75 | // ─── Cross-attention family ──────────────────────────────────────────────── | ||
| 76 | |||
| 77 | 27 | void cross_attention_forward(const Tensor& X, const Tensor& Ctx, | |
| 78 | const Tensor& Wq, const Tensor& Wk, | ||
| 79 | const Tensor& Wv, const Tensor& Wo, | ||
| 80 | const float* d_mask, int num_heads, Tensor& O) { | ||
| 81 | 27 | const auto& v = detail::dispatch(X, Ctx, Wq, Wk, Wv, Wo, O); | |
| 82 |
1/2✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
|
27 | if (!v.cross_attention_forward) detail::throw_not_implemented("cross_attention_forward", X.device); |
| 83 | 27 | detail::adopt_output(O, X.device); | |
| 84 | 27 | v.cross_attention_forward(X, Ctx, Wq, Wk, Wv, Wo, d_mask, num_heads, O); | |
| 85 | 27 | } | |
| 86 | |||
| 87 | 17 | void cross_attention_forward_with_attn(const Tensor& X, const Tensor& Ctx, | |
| 88 | const Tensor& Wq, const Tensor& Wk, | ||
| 89 | const Tensor& Wv, const Tensor& Wo, | ||
| 90 | const float* d_mask, | ||
| 91 | const Tensor* attn_logit_bias, | ||
| 92 | int num_heads, Tensor& O, Tensor& AttnAvg) { | ||
| 93 | 17 | const auto& v = detail::dispatch_with_opts(X, Ctx, {&Wq, &Wk, &Wv, &Wo, attn_logit_bias, &O, &AttnAvg}); | |
| 94 |
1/2✓ Branch 0 taken 17 times.
✗ Branch 1 not taken.
|
17 | if (!v.cross_attention_forward_with_attn) |
| 95 | ✗ | detail::throw_not_implemented("cross_attention_forward_with_attn", X.device); | |
| 96 | 17 | detail::adopt_output(O, X.device); | |
| 97 | 17 | detail::adopt_output(AttnAvg, X.device); | |
| 98 | 34 | v.cross_attention_forward_with_attn(X, Ctx, Wq, Wk, Wv, Wo, d_mask, | |
| 99 | 17 | attn_logit_bias, num_heads, O, AttnAvg); | |
| 100 | 17 | } | |
| 101 | |||
| 102 | 21 | void self_attention_forward_train(const Tensor& X, | |
| 103 | const Tensor& Wq, const Tensor& Wk, | ||
| 104 | const Tensor& Wv, const Tensor& Wo, | ||
| 105 | const float* d_mask, int num_heads, | ||
| 106 | Tensor& Qh, Tensor& Kh, Tensor& Vh, | ||
| 107 | Tensor& Attnh, Tensor& Yconcat, Tensor& O) { | ||
| 108 | 21 | const auto& v = detail::dispatch(X, Wq, Wk, Wv, Wo, Qh, Kh, Vh); | |
| 109 |
1/2✓ Branch 0 taken 21 times.
✗ Branch 1 not taken.
|
21 | if (!v.self_attention_forward_train) |
| 110 | ✗ | detail::throw_not_implemented("self_attention_forward_train", X.device); | |
| 111 | 21 | detail::adopt_output(Qh, X.device); | |
| 112 | 21 | detail::adopt_output(Kh, X.device); | |
| 113 | 21 | detail::adopt_output(Vh, X.device); | |
| 114 | 21 | detail::adopt_output(Attnh, X.device); | |
| 115 | 21 | detail::adopt_output(Yconcat, X.device); | |
| 116 | 21 | detail::adopt_output(O, X.device); | |
| 117 | 42 | v.self_attention_forward_train(X, Wq, Wk, Wv, Wo, d_mask, num_heads, | |
| 118 | 21 | Qh, Kh, Vh, Attnh, Yconcat, O); | |
| 119 | 21 | } | |
| 120 | |||
| 121 | 19 | void self_attention_backward(const Tensor& dO, const Tensor& X, | |
| 122 | const Tensor& Qh, const Tensor& Kh, | ||
| 123 | const Tensor& Vh, const Tensor& Attnh, | ||
| 124 | const Tensor& Yconcat, | ||
| 125 | const Tensor& Wq, const Tensor& Wk, | ||
| 126 | const Tensor& Wv, const Tensor& Wo, | ||
| 127 | const float* d_mask, int num_heads, | ||
| 128 | Tensor& dX, | ||
| 129 | Tensor& dWq, Tensor& dWk, | ||
| 130 | Tensor& dWv, Tensor& dWo) { | ||
| 131 | 19 | const auto& v = detail::dispatch(dO, X, Qh, Kh, Vh, Attnh, Yconcat); | |
| 132 |
1/2✓ Branch 0 taken 19 times.
✗ Branch 1 not taken.
|
19 | if (!v.self_attention_backward) |
| 133 | ✗ | detail::throw_not_implemented("self_attention_backward", dO.device); | |
| 134 | 19 | detail::adopt_output(dX, dO.device); | |
| 135 | 19 | detail::adopt_output(dWq, dO.device); | |
| 136 | 19 | detail::adopt_output(dWk, dO.device); | |
| 137 | 19 | detail::adopt_output(dWv, dO.device); | |
| 138 | 19 | detail::adopt_output(dWo, dO.device); | |
| 139 | 38 | v.self_attention_backward(dO, X, Qh, Kh, Vh, Attnh, Yconcat, | |
| 140 | 19 | Wq, Wk, Wv, Wo, d_mask, num_heads, | |
| 141 | 19 | dX, dWq, dWk, dWv, dWo); | |
| 142 | 19 | } | |
| 143 | |||
| 144 | 16 | void attention_token_moments(const Tensor& Attn, int h_lat, int w_lat, | |
| 145 | Tensor& mass, Tensor& centroid) { | ||
| 146 |
1/2✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
|
16 | if (h_lat <= 0 || w_lat <= 0 || Attn.rows != h_lat * w_lat) { |
| 147 | ✗ | detail::throw_spatial_2d_error("attention_token_moments", "Attn", | |
| 148 | ✗ | h_lat * w_lat, Attn.cols, h_lat, w_lat, | |
| 149 | ✗ | Attn.rows, Attn.cols); | |
| 150 | } | ||
| 151 | 16 | const auto& v = detail::dispatch(Attn, mass, centroid); | |
| 152 |
1/2✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
|
16 | if (!v.attention_token_moments) detail::throw_not_implemented("attention_token_moments", Attn.device); |
| 153 | 16 | detail::adopt_output(mass, Attn.device); | |
| 154 | 16 | detail::adopt_output(centroid, Attn.device); | |
| 155 | 16 | v.attention_token_moments(Attn, h_lat, w_lat, mass, centroid); | |
| 156 | 16 | } | |
| 157 | |||
| 158 | 19 | void cross_attention_forward_train(const Tensor& X, const Tensor& Ctx, | |
| 159 | const Tensor& Wq, const Tensor& Wk, | ||
| 160 | const Tensor& Wv, const Tensor& Wo, | ||
| 161 | const float* d_mask, int num_heads, | ||
| 162 | Tensor& Qh, Tensor& Kh, Tensor& Vh, | ||
| 163 | Tensor& Attnh, Tensor& Yconcat, Tensor& O) { | ||
| 164 | 19 | const auto& v = detail::dispatch(X, Ctx, Wq, Wk, Wv, Wo, Qh, Kh); | |
| 165 |
1/2✓ Branch 0 taken 19 times.
✗ Branch 1 not taken.
|
19 | if (!v.cross_attention_forward_train) |
| 166 | ✗ | detail::throw_not_implemented("cross_attention_forward_train", X.device); | |
| 167 | 19 | detail::adopt_output(Qh, X.device); | |
| 168 | 19 | detail::adopt_output(Kh, X.device); | |
| 169 | 19 | detail::adopt_output(Vh, X.device); | |
| 170 | 19 | detail::adopt_output(Attnh, X.device); | |
| 171 | 19 | detail::adopt_output(Yconcat, X.device); | |
| 172 | 19 | detail::adopt_output(O, X.device); | |
| 173 | 38 | v.cross_attention_forward_train(X, Ctx, Wq, Wk, Wv, Wo, d_mask, num_heads, | |
| 174 | 19 | Qh, Kh, Vh, Attnh, Yconcat, O); | |
| 175 | 19 | } | |
| 176 | |||
| 177 | 19 | void cross_attention_backward(const Tensor& dO, const Tensor& X, const Tensor& Ctx, | |
| 178 | const Tensor& Qh, const Tensor& Kh, | ||
| 179 | const Tensor& Vh, const Tensor& Attnh, | ||
| 180 | const Tensor& Yconcat, | ||
| 181 | const Tensor& Wq, const Tensor& Wk, | ||
| 182 | const Tensor& Wv, const Tensor& Wo, | ||
| 183 | const float* d_mask, int num_heads, | ||
| 184 | Tensor& dX, Tensor& dCtx, | ||
| 185 | Tensor& dWq, Tensor& dWk, | ||
| 186 | Tensor& dWv, Tensor& dWo) { | ||
| 187 | 19 | const auto& v = detail::dispatch(dO, X, Ctx, Qh, Kh, Vh, Attnh, Yconcat); | |
| 188 |
1/2✓ Branch 0 taken 19 times.
✗ Branch 1 not taken.
|
19 | if (!v.cross_attention_backward) |
| 189 | ✗ | detail::throw_not_implemented("cross_attention_backward", dO.device); | |
| 190 | 19 | detail::adopt_output(dX, dO.device); | |
| 191 | 19 | detail::adopt_output(dCtx, dO.device); | |
| 192 | 19 | detail::adopt_output(dWq, dO.device); | |
| 193 | 19 | detail::adopt_output(dWk, dO.device); | |
| 194 | 19 | detail::adopt_output(dWv, dO.device); | |
| 195 | 19 | detail::adopt_output(dWo, dO.device); | |
| 196 | 38 | v.cross_attention_backward(dO, X, Ctx, Qh, Kh, Vh, Attnh, Yconcat, | |
| 197 | 19 | Wq, Wk, Wv, Wo, d_mask, num_heads, | |
| 198 | 19 | dX, dCtx, dWq, dWk, dWv, dWo); | |
| 199 | 19 | } | |
| 200 | |||
| 201 | // ─── FP16 LN inference + FP16 self-attention ─────────────────────────────── | ||
| 202 | |||
| 203 | 3 | void layernorm_forward_inference_batched_fp16(const Tensor& X_RD, | |
| 204 | const Tensor& gamma, | ||
| 205 | const Tensor& beta, | ||
| 206 | Tensor& Y_RD, float eps) { | ||
| 207 | 3 | const auto& v = detail::dispatch(X_RD, gamma, beta, Y_RD); | |
| 208 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | if (!v.layernorm_forward_inference_batched_fp16) |
| 209 | ✗ | detail::throw_not_implemented("layernorm_forward_inference_batched_fp16", X_RD.device); | |
| 210 | 3 | detail::adopt_output(Y_RD, X_RD.device); | |
| 211 | 3 | v.layernorm_forward_inference_batched_fp16(X_RD, gamma, &beta, Y_RD, eps); | |
| 212 | 3 | } | |
| 213 | |||
| 214 | 2 | void layernorm_forward_inference_batched_fp16(const Tensor& X_RD, | |
| 215 | const Tensor& gamma, | ||
| 216 | Tensor& Y_RD, float eps) { | ||
| 217 | 2 | const auto& v = detail::dispatch(X_RD, gamma, Y_RD); | |
| 218 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | if (!v.layernorm_forward_inference_batched_fp16) |
| 219 | ✗ | detail::throw_not_implemented("layernorm_forward_inference_batched_fp16", X_RD.device); | |
| 220 | 2 | detail::adopt_output(Y_RD, X_RD.device); | |
| 221 | 2 | v.layernorm_forward_inference_batched_fp16(X_RD, gamma, nullptr, Y_RD, eps); | |
| 222 | 2 | } | |
| 223 | |||
| 224 | 14 | void self_attention_forward(const Tensor& X, | |
| 225 | const Tensor& Wq, const Tensor& Wk, | ||
| 226 | const Tensor& Wv, const Tensor& Wo, | ||
| 227 | const float* d_mask, int num_heads, Tensor& O) { | ||
| 228 | 14 | const auto& v = detail::dispatch(X, Wq, Wk, Wv, Wo, O); | |
| 229 |
1/2✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
|
14 | if (!v.self_attention_forward) detail::throw_not_implemented("self_attention_forward", X.device); |
| 230 | 14 | detail::adopt_output(O, X.device); | |
| 231 | 14 | v.self_attention_forward(X, Wq, Wk, Wv, Wo, d_mask, num_heads, O); | |
| 232 | 14 | } | |
| 233 | |||
| 234 | 41 | void self_attention_bias_forward(const Tensor& X, | |
| 235 | const Tensor& Wq, const Tensor& Wk, | ||
| 236 | const Tensor& Wv, const Tensor& Wo, | ||
| 237 | const Tensor* bq, const Tensor* bk, | ||
| 238 | const Tensor* bv, const Tensor* bo, | ||
| 239 | const float* d_mask, | ||
| 240 | const Tensor* attn_bias, | ||
| 241 | int num_heads, float scale, Tensor& O) { | ||
| 242 | 41 | const auto& v = detail::dispatch_with_opts(X, Wq, {&Wk, &Wv, &Wo, bq, bk, bv, bo, attn_bias, &O}); | |
| 243 |
1/2✓ Branch 0 taken 41 times.
✗ Branch 1 not taken.
|
41 | if (!v.self_attention_bias_forward) |
| 244 | ✗ | detail::throw_not_implemented("self_attention_bias_forward", X.device); | |
| 245 | 41 | detail::adopt_output(O, X.device); | |
| 246 | 82 | v.self_attention_bias_forward(X, Wq, Wk, Wv, Wo, bq, bk, bv, bo, d_mask, attn_bias, | |
| 247 | 41 | num_heads, scale, O); | |
| 248 | 41 | } | |
| 249 | |||
| 250 | 8 | void rel_pos_bias_xl_forward(const Tensor& Qv, const Tensor& Pk, | |
| 251 | int num_heads, int head_dim, Tensor& Bias) { | ||
| 252 | 8 | const auto& v = detail::dispatch_with_opts(Qv, Pk, {&Bias}); | |
| 253 |
1/2✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
|
8 | if (!v.rel_pos_bias_xl_forward) |
| 254 | ✗ | detail::throw_not_implemented("rel_pos_bias_xl_forward", Qv.device); | |
| 255 | 8 | detail::adopt_output(Bias, Qv.device); | |
| 256 | 8 | v.rel_pos_bias_xl_forward(Qv, Pk, num_heads, head_dim, Bias); | |
| 257 | 8 | } | |
| 258 | |||
| 259 | 27 | void self_attention_decomposed_rel_pos_forward( | |
| 260 | const Tensor& X, | ||
| 261 | const Tensor& Wq, const Tensor* bq, | ||
| 262 | const Tensor& Wk, const Tensor* bk, | ||
| 263 | const Tensor& Wv, const Tensor* bv, | ||
| 264 | const Tensor& Wo, const Tensor* bo, | ||
| 265 | const Tensor& rel_pos_h, const Tensor& rel_pos_w, | ||
| 266 | int num_heads, int grid_h, int grid_w, float scale, Tensor& O) { | ||
| 267 |
1/2✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
|
27 | if (grid_h <= 0 || grid_w <= 0 || X.rows != grid_h * grid_w) { |
| 268 | ✗ | detail::throw_spatial_2d_error("self_attention_decomposed_rel_pos_forward", "X", | |
| 269 | ✗ | grid_h * grid_w, X.cols, grid_h, grid_w, | |
| 270 | ✗ | X.rows, X.cols); | |
| 271 | } | ||
| 272 | 27 | const auto& v = detail::dispatch_with_opts( | |
| 273 | 27 | X, Wq, {bq, &Wk, bk, &Wv, bv, &Wo, bo, &rel_pos_h, &rel_pos_w, &O}); | |
| 274 |
1/2✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
|
27 | if (!v.self_attention_decomposed_rel_pos_forward) |
| 275 | ✗ | detail::throw_not_implemented("self_attention_decomposed_rel_pos_forward", | |
| 276 | ✗ | X.device); | |
| 277 | 27 | detail::adopt_output(O, X.device); | |
| 278 | 54 | v.self_attention_decomposed_rel_pos_forward( | |
| 279 | 27 | X, Wq, bq, Wk, bk, Wv, bv, Wo, bo, rel_pos_h, rel_pos_w, | |
| 280 | 27 | num_heads, grid_h, grid_w, scale, O); | |
| 281 | 27 | } | |
| 282 | |||
| 283 | 19 | void self_attention_decomposed_rel_pos_windowed_forward( | |
| 284 | const Tensor& X, | ||
| 285 | const Tensor& Wq, const Tensor* bq, | ||
| 286 | const Tensor& Wk, const Tensor* bk, | ||
| 287 | const Tensor& Wv, const Tensor* bv, | ||
| 288 | const Tensor& Wo, const Tensor* bo, | ||
| 289 | const Tensor& rel_pos_h, const Tensor& rel_pos_w, | ||
| 290 | int num_heads, int grid_h, int grid_w, int window, float scale, | ||
| 291 | Tensor& O) { | ||
| 292 |
1/2✓ Branch 0 taken 19 times.
✗ Branch 1 not taken.
|
19 | if (grid_h <= 0 || grid_w <= 0 || X.rows != grid_h * grid_w) { |
| 293 | ✗ | detail::throw_spatial_2d_error( | |
| 294 | "self_attention_decomposed_rel_pos_windowed_forward", "X", | ||
| 295 | ✗ | grid_h * grid_w, X.cols, grid_h, grid_w, X.rows, X.cols); | |
| 296 | } | ||
| 297 | 19 | const auto& v = detail::dispatch_with_opts( | |
| 298 | 19 | X, Wq, {bq, &Wk, bk, &Wv, bv, &Wo, bo, &rel_pos_h, &rel_pos_w, &O}); | |
| 299 |
1/2✓ Branch 0 taken 19 times.
✗ Branch 1 not taken.
|
19 | if (!v.self_attention_decomposed_rel_pos_windowed_forward) |
| 300 | ✗ | detail::throw_not_implemented( | |
| 301 | ✗ | "self_attention_decomposed_rel_pos_windowed_forward", X.device); | |
| 302 | 19 | detail::adopt_output(O, X.device); | |
| 303 | 38 | v.self_attention_decomposed_rel_pos_windowed_forward( | |
| 304 | 19 | X, Wq, bq, Wk, bk, Wv, bv, Wo, bo, rel_pos_h, rel_pos_w, | |
| 305 | 19 | num_heads, grid_h, grid_w, window, scale, O); | |
| 306 | 19 | } | |
| 307 | |||
| 308 | 9 | void self_attention_bias_int8w_fp16(const Tensor& X, | |
| 309 | const Tensor& Wq_int8, const Tensor& sq, | ||
| 310 | const Tensor& Wk_int8, const Tensor& sk, | ||
| 311 | const Tensor& Wv_int8, const Tensor& sv, | ||
| 312 | const Tensor& Wo_int8, const Tensor& so, | ||
| 313 | const float* d_mask, | ||
| 314 | const Tensor* attn_bias, | ||
| 315 | int num_heads, float scale, Tensor& O) { | ||
| 316 | 9 | const auto& v = detail::dispatch_with_opts( | |
| 317 | 27 | X, Wq_int8, {&sq, &Wk_int8, &sk, &Wv_int8, &sv, &Wo_int8, &so, | |
| 318 | 18 | attn_bias, &O}); | |
| 319 |
1/2✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
|
9 | if (!v.self_attention_bias_int8w_fp16) |
| 320 | ✗ | detail::throw_not_implemented("self_attention_bias_int8w_fp16", X.device); | |
| 321 | 9 | detail::adopt_output(O, X.device); | |
| 322 | 18 | v.self_attention_bias_int8w_fp16(X, Wq_int8, sq, Wk_int8, sk, | |
| 323 | 9 | Wv_int8, sv, Wo_int8, so, | |
| 324 | 9 | d_mask, attn_bias, num_heads, scale, O); | |
| 325 | 9 | } | |
| 326 | |||
| 327 | // ─── Flash attention family ──────────────────────────────────────────────── | ||
| 328 | |||
| 329 | 165 | void flash_attention_forward(const Tensor& Q, const Tensor& K, const Tensor& V, | |
| 330 | const float* d_mask, int num_heads, bool causal, | ||
| 331 | Tensor& O) { | ||
| 332 | 165 | const auto& v = detail::dispatch(Q, K, V, O); | |
| 333 |
1/2✓ Branch 0 taken 165 times.
✗ Branch 1 not taken.
|
165 | if (!v.flash_attention_forward) detail::throw_not_implemented("flash_attention_forward", Q.device); |
| 334 | 165 | detail::adopt_output(O, Q.device); | |
| 335 | 165 | v.flash_attention_forward(Q, K, V, d_mask, num_heads, causal, O); | |
| 336 | 165 | } | |
| 337 | |||
| 338 | 28 | void flash_attention_gqa_forward(const Tensor& Q, const Tensor& K, const Tensor& V, | |
| 339 | const float* d_mask, int num_q_heads, int num_kv_heads, | ||
| 340 | bool causal, Tensor& O) { | ||
| 341 | 28 | const auto& v = detail::dispatch(Q, K, V, O); | |
| 342 |
1/2✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
|
28 | if (!v.flash_attention_gqa_forward) |
| 343 | ✗ | detail::throw_not_implemented("flash_attention_gqa_forward", Q.device); | |
| 344 | 28 | detail::adopt_output(O, Q.device); | |
| 345 | 28 | v.flash_attention_gqa_forward(Q, K, V, d_mask, num_q_heads, num_kv_heads, causal, O); | |
| 346 | 28 | } | |
| 347 | |||
| 348 | 51 | void flash_attention_windowed_forward(const Tensor& Q, const Tensor& K, const Tensor& V, | |
| 349 | const float* d_mask, int num_heads, int window, | ||
| 350 | Tensor& O, bool causal) { | ||
| 351 | 51 | const auto& v = detail::dispatch(Q, K, V, O); | |
| 352 |
1/2✓ Branch 0 taken 51 times.
✗ Branch 1 not taken.
|
51 | if (!v.flash_attention_windowed_forward) |
| 353 | ✗ | detail::throw_not_implemented("flash_attention_windowed_forward", Q.device); | |
| 354 | 51 | detail::adopt_output(O, Q.device); | |
| 355 | 51 | v.flash_attention_windowed_forward(Q, K, V, d_mask, num_heads, window, O, causal); | |
| 356 | 51 | } | |
| 357 | |||
| 358 | 57 | void flash_attention_varlen_forward(const Tensor& Q, const Tensor& K, const Tensor& V, | |
| 359 | const int32_t* cu_seqlens_q, | ||
| 360 | const int32_t* cu_seqlens_k, | ||
| 361 | int batch_size, int max_seqlen_q, int max_seqlen_k, | ||
| 362 | int num_heads, int head_dim, bool causal, | ||
| 363 | Tensor& O) { | ||
| 364 | 57 | const auto& v = detail::dispatch(Q, K, V, O); | |
| 365 |
1/2✓ Branch 0 taken 57 times.
✗ Branch 1 not taken.
|
57 | if (!v.flash_attention_varlen_forward) |
| 366 | ✗ | detail::throw_not_implemented("flash_attention_varlen_forward", Q.device); | |
| 367 | 57 | detail::adopt_output(O, Q.device); | |
| 368 | 114 | v.flash_attention_varlen_forward(Q, K, V, cu_seqlens_q, cu_seqlens_k, | |
| 369 | 57 | batch_size, max_seqlen_q, max_seqlen_k, | |
| 370 | 57 | num_heads, head_dim, causal, O); | |
| 371 | 57 | } | |
| 372 | |||
| 373 | 47 | void flash_attention_varlen_backward(const Tensor& Q, const Tensor& K, const Tensor& V, | |
| 374 | const Tensor& O, const Tensor& dO, | ||
| 375 | const int32_t* cu_seqlens_q, | ||
| 376 | const int32_t* cu_seqlens_k, | ||
| 377 | int batch_size, int max_seqlen_q, int max_seqlen_k, | ||
| 378 | int num_heads, int head_dim, bool causal, | ||
| 379 | Tensor& dQ, Tensor& dK, Tensor& dV) { | ||
| 380 | 47 | const auto& v = detail::dispatch(Q, K, V, O, dO, dQ, dK, dV); | |
| 381 |
1/2✓ Branch 0 taken 47 times.
✗ Branch 1 not taken.
|
47 | if (!v.flash_attention_varlen_backward) |
| 382 | ✗ | detail::throw_not_implemented("flash_attention_varlen_backward", Q.device); | |
| 383 | 47 | detail::adopt_output(dQ, Q.device); | |
| 384 | 47 | detail::adopt_output(dK, Q.device); | |
| 385 | 47 | detail::adopt_output(dV, Q.device); | |
| 386 | 94 | v.flash_attention_varlen_backward(Q, K, V, O, dO, | |
| 387 | 47 | cu_seqlens_q, cu_seqlens_k, | |
| 388 | 47 | batch_size, max_seqlen_q, max_seqlen_k, | |
| 389 | 47 | num_heads, head_dim, causal, | |
| 390 | 47 | dQ, dK, dV); | |
| 391 | 47 | } | |
| 392 | |||
| 393 | 39 | void flash_attention_qkvo_forward(const Tensor& X, const Tensor* Ctx, | |
| 394 | const Tensor& Wq, const Tensor* bq, | ||
| 395 | const Tensor& Wk, const Tensor* bk, | ||
| 396 | const Tensor& Wv, const Tensor* bv, | ||
| 397 | const Tensor& Wo, const Tensor* bo, | ||
| 398 | const float* d_mask, int num_heads, | ||
| 399 | bool causal, Tensor& O) { | ||
| 400 | 39 | const auto& v = detail::dispatch_with_opts( | |
| 401 | 39 | X, Wq, {Ctx, bq, &Wk, bk, &Wv, bv, &Wo, bo, &O}); | |
| 402 |
1/2✓ Branch 0 taken 39 times.
✗ Branch 1 not taken.
|
39 | if (!v.flash_attention_qkvo_forward) |
| 403 | ✗ | detail::throw_not_implemented("flash_attention_qkvo_forward", X.device); | |
| 404 | 39 | detail::adopt_output(O, X.device); | |
| 405 | 78 | v.flash_attention_qkvo_forward(X, Ctx, Wq, bq, Wk, bk, Wv, bv, Wo, bo, | |
| 406 | 39 | d_mask, num_heads, causal, O); | |
| 407 | 39 | } | |
| 408 | |||
| 409 | 39 | void flash_attention_qkvo_backward( | |
| 410 | const Tensor& X, const Tensor* Ctx, | ||
| 411 | const Tensor& Wq, const Tensor* bq, | ||
| 412 | const Tensor& Wk, const Tensor* bk, | ||
| 413 | const Tensor& Wv, const Tensor* bv, | ||
| 414 | const Tensor& Wo, const Tensor* bo, | ||
| 415 | const float* d_mask, int num_heads, bool causal, | ||
| 416 | const Tensor& dO, | ||
| 417 | Tensor& dX, Tensor* dCtx, | ||
| 418 | Tensor& dWq, Tensor* dbq, | ||
| 419 | Tensor& dWk, Tensor* dbk, | ||
| 420 | Tensor& dWv, Tensor* dbv, | ||
| 421 | Tensor& dWo, Tensor* dbo) { | ||
| 422 | 39 | const auto& v = detail::dispatch_with_opts( | |
| 423 | 429 | X, Wq, {Ctx, bq, &Wk, bk, &Wv, bv, &Wo, bo, &dO, | |
| 424 | 390 | &dX, dCtx, &dWq, dbq, &dWk, dbk, &dWv, dbv, &dWo, dbo}); | |
| 425 |
1/2✓ Branch 0 taken 39 times.
✗ Branch 1 not taken.
|
39 | if (!v.flash_attention_qkvo_backward) |
| 426 | ✗ | detail::throw_not_implemented("flash_attention_qkvo_backward", X.device); | |
| 427 | 39 | detail::adopt_output(dX, X.device); | |
| 428 |
2/2✓ Branch 0 taken 25 times.
✓ Branch 1 taken 14 times.
|
39 | if (dCtx) detail::adopt_output(*dCtx, X.device); |
| 429 | 39 | detail::adopt_output(dWq, X.device); | |
| 430 |
2/2✓ Branch 0 taken 13 times.
✓ Branch 1 taken 26 times.
|
39 | if (dbq) detail::adopt_output(*dbq, X.device); |
| 431 | 39 | detail::adopt_output(dWk, X.device); | |
| 432 |
2/2✓ Branch 0 taken 13 times.
✓ Branch 1 taken 26 times.
|
39 | if (dbk) detail::adopt_output(*dbk, X.device); |
| 433 | 39 | detail::adopt_output(dWv, X.device); | |
| 434 |
2/2✓ Branch 0 taken 13 times.
✓ Branch 1 taken 26 times.
|
39 | if (dbv) detail::adopt_output(*dbv, X.device); |
| 435 | 39 | detail::adopt_output(dWo, X.device); | |
| 436 |
2/2✓ Branch 0 taken 13 times.
✓ Branch 1 taken 26 times.
|
39 | if (dbo) detail::adopt_output(*dbo, X.device); |
| 437 | 78 | v.flash_attention_qkvo_backward(X, Ctx, Wq, bq, Wk, bk, Wv, bv, Wo, bo, | |
| 438 | 39 | d_mask, num_heads, causal, dO, | |
| 439 | 39 | dX, dCtx, dWq, dbq, dWk, dbk, | |
| 440 | 39 | dWv, dbv, dWo, dbo); | |
| 441 | 39 | } | |
| 442 | |||
| 443 | 74 | void flash_attention_backward(const Tensor& Q, const Tensor& K, const Tensor& V, | |
| 444 | const Tensor& O, const Tensor& dO, | ||
| 445 | const float* d_mask, int num_heads, bool causal, | ||
| 446 | Tensor& dQ, Tensor& dK, Tensor& dV) { | ||
| 447 | 74 | const auto& v = detail::dispatch(Q, K, V, O, dO, dQ, dK, dV); | |
| 448 |
1/2✓ Branch 0 taken 74 times.
✗ Branch 1 not taken.
|
74 | if (!v.flash_attention_backward) detail::throw_not_implemented("flash_attention_backward", Q.device); |
| 449 | 74 | detail::adopt_output(dQ, Q.device); | |
| 450 | 74 | detail::adopt_output(dK, Q.device); | |
| 451 | 74 | detail::adopt_output(dV, Q.device); | |
| 452 | 148 | v.flash_attention_backward(Q, K, V, O, dO, d_mask, num_heads, causal, | |
| 453 | 74 | dQ, dK, dV); | |
| 454 | 74 | } | |
| 455 | |||
| 456 | 11 | void flash_attention_project_kv(const Tensor& ctx, | |
| 457 | const Tensor& Wk, const Tensor* bk, | ||
| 458 | const Tensor& Wv, const Tensor* bv, | ||
| 459 | Tensor& K_out, Tensor& V_out) { | ||
| 460 | 11 | const auto& v = detail::dispatch_with_opts(ctx, Wk, {bk, &Wv, bv, &K_out, &V_out}); | |
| 461 |
1/2✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
|
11 | if (!v.flash_attention_project_kv) |
| 462 | ✗ | detail::throw_not_implemented("flash_attention_project_kv", ctx.device); | |
| 463 | 11 | detail::adopt_output(K_out, ctx.device); | |
| 464 | 11 | detail::adopt_output(V_out, ctx.device); | |
| 465 | 11 | v.flash_attention_project_kv(ctx, Wk, bk, Wv, bv, K_out, V_out); | |
| 466 | 11 | } | |
| 467 | |||
| 468 | 15 | void flash_attention_q_with_kv_cached_forward(const Tensor& X, | |
| 469 | const Tensor& K, const Tensor& V, | ||
| 470 | const Tensor& Wq, const Tensor* bq, | ||
| 471 | const Tensor& Wo, const Tensor* bo, | ||
| 472 | const float* d_mask, int num_heads, | ||
| 473 | bool causal, Tensor& O) { | ||
| 474 | 15 | const auto& v = detail::dispatch_with_opts(X, K, {&V, &Wq, bq, &Wo, bo, &O}); | |
| 475 |
1/2✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
|
15 | if (!v.flash_attention_q_with_kv_cached_forward) |
| 476 | ✗ | detail::throw_not_implemented("flash_attention_q_with_kv_cached_forward", X.device); | |
| 477 | 15 | detail::adopt_output(O, X.device); | |
| 478 | 30 | v.flash_attention_q_with_kv_cached_forward(X, K, V, Wq, bq, Wo, bo, | |
| 479 | 15 | d_mask, num_heads, causal, O); | |
| 480 | 15 | } | |
| 481 | |||
| 482 | // ─── Matmul + RoPE + RMSNorm + SwiGLU + KV-cache + Llama ─────────────────── | ||
| 483 | |||
| 484 | 114 | void matmul(const Tensor& A, const Tensor& B, Tensor& C) { | |
| 485 | 114 | const auto& v = detail::dispatch(A, B, C); | |
| 486 |
1/2✓ Branch 0 taken 114 times.
✗ Branch 1 not taken.
|
114 | if (!v.matmul) detail::throw_not_implemented("matmul", A.device); |
| 487 | 114 | detail::adopt_output(C, A.device); | |
| 488 | 114 | v.matmul(A, B, C); | |
| 489 | 114 | } | |
| 490 | |||
| 491 | 80 | void matmul_abt(const Tensor& A, const Tensor& B, Tensor& C, | |
| 492 | int batch, int M, int N, int K, | ||
| 493 | long long strideA, long long strideB, long long strideC, | ||
| 494 | const Tensor* bias, int act) { | ||
| 495 | 80 | const auto& v = detail::dispatch(A, B, C); | |
| 496 |
1/2✓ Branch 0 taken 80 times.
✗ Branch 1 not taken.
|
80 | if (!v.matmul_abt) detail::throw_not_implemented("matmul_abt", A.device); |
| 497 | 80 | detail::adopt_output(C, A.device); | |
| 498 | 80 | v.matmul_abt(A, B, C, batch, M, N, K, strideA, strideB, strideC, bias, act); | |
| 499 | 80 | } | |
| 500 | |||
| 501 | 62 | void matmul_backward(const Tensor& A, const Tensor& B, const Tensor& dC, | |
| 502 | Tensor& dA, Tensor& dB) { | ||
| 503 | 62 | const auto& v = detail::dispatch(A, B, dC, dA, dB); | |
| 504 |
1/2✓ Branch 0 taken 62 times.
✗ Branch 1 not taken.
|
62 | if (!v.matmul_backward) detail::throw_not_implemented("matmul_backward", A.device); |
| 505 | 62 | detail::adopt_output(dA, A.device); | |
| 506 | 62 | detail::adopt_output(dB, A.device); | |
| 507 | 62 | v.matmul_backward(A, B, dC, dA, dB); | |
| 508 | 62 | } | |
| 509 | |||
| 510 | 909 | void lstm_forward_train(const Tensor& X, const Tensor& W_ih, const Tensor& W_hh, | |
| 511 | const Tensor* b_ih, const Tensor* b_hh, | ||
| 512 | const Tensor* h0, const Tensor* c0, int T, int B, | ||
| 513 | Tensor& Y, Tensor& gates, Tensor& C, | ||
| 514 | Tensor* hT, Tensor* cT) { | ||
| 515 | 909 | const auto& v = detail::dispatch(X); | |
| 516 |
1/2✓ Branch 0 taken 909 times.
✗ Branch 1 not taken.
|
909 | if (!v.lstm_forward_train) detail::throw_not_implemented("lstm_forward_train", X.device); |
| 517 | 909 | detail::adopt_output(Y, X.device); | |
| 518 | 909 | detail::adopt_output(gates, X.device); | |
| 519 | 909 | detail::adopt_output(C, X.device); | |
| 520 |
2/2✓ Branch 0 taken 895 times.
✓ Branch 1 taken 14 times.
|
909 | if (hT) detail::adopt_output(*hT, X.device); |
| 521 |
2/2✓ Branch 0 taken 895 times.
✓ Branch 1 taken 14 times.
|
909 | if (cT) detail::adopt_output(*cT, X.device); |
| 522 | 909 | v.lstm_forward_train(X, W_ih, W_hh, b_ih, b_hh, h0, c0, T, B, Y, gates, C, hT, cT); | |
| 523 | 909 | } | |
| 524 | |||
| 525 | 415 | void lstm_backward(const Tensor& X, const Tensor& W_ih, const Tensor& W_hh, | |
| 526 | const Tensor* h0, const Tensor* c0, | ||
| 527 | const Tensor& Y, const Tensor& gates, const Tensor& C, | ||
| 528 | const Tensor& dY, int T, int B, | ||
| 529 | Tensor& dX, Tensor& dW_ih, Tensor& dW_hh, | ||
| 530 | Tensor* db_ih, Tensor* db_hh, | ||
| 531 | Tensor* dh0, Tensor* dc0) { | ||
| 532 | 415 | const auto& v = detail::dispatch(X); | |
| 533 |
1/2✓ Branch 0 taken 415 times.
✗ Branch 1 not taken.
|
415 | if (!v.lstm_backward) detail::throw_not_implemented("lstm_backward", X.device); |
| 534 | 415 | detail::adopt_output(dX, X.device); | |
| 535 | 415 | detail::adopt_output(dW_ih, X.device); | |
| 536 | 415 | detail::adopt_output(dW_hh, X.device); | |
| 537 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 415 times.
|
415 | if (db_ih) detail::adopt_output(*db_ih, X.device); |
| 538 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 413 times.
|
415 | if (db_hh) detail::adopt_output(*db_hh, X.device); |
| 539 |
2/2✓ Branch 0 taken 402 times.
✓ Branch 1 taken 13 times.
|
415 | if (dh0) detail::adopt_output(*dh0, X.device); |
| 540 |
2/2✓ Branch 0 taken 402 times.
✓ Branch 1 taken 13 times.
|
415 | if (dc0) detail::adopt_output(*dc0, X.device); |
| 541 | 830 | v.lstm_backward(X, W_ih, W_hh, h0, c0, Y, gates, C, dY, T, B, | |
| 542 | 415 | dX, dW_ih, dW_hh, db_ih, db_hh, dh0, dc0); | |
| 543 | 415 | } | |
| 544 | |||
| 545 | 16 | void rope_forward(const Tensor& X, int head_dim, int num_heads, | |
| 546 | int seq_offset, float theta_base, Tensor& Y) { | ||
| 547 | 16 | const auto& v = detail::dispatch(X, Y); | |
| 548 |
1/2✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
|
16 | if (!v.rope_forward) detail::throw_not_implemented("rope_forward", X.device); |
| 549 | 16 | detail::adopt_output(Y, X.device); | |
| 550 | 16 | v.rope_forward(X, head_dim, num_heads, seq_offset, theta_base, Y); | |
| 551 | 16 | } | |
| 552 | |||
| 553 | 10 | void rope_backward(const Tensor& dY, int head_dim, int num_heads, | |
| 554 | int seq_offset, float theta_base, Tensor& dX) { | ||
| 555 | 10 | const auto& v = detail::dispatch(dY, dX); | |
| 556 |
1/2✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
|
10 | if (!v.rope_backward) detail::throw_not_implemented("rope_backward", dY.device); |
| 557 | 10 | detail::adopt_output(dX, dY.device); | |
| 558 | 10 | v.rope_backward(dY, head_dim, num_heads, seq_offset, theta_base, dX); | |
| 559 | 10 | } | |
| 560 | |||
| 561 | 38 | void rope_apply(const Tensor& X, const Tensor& cos_tbl, const Tensor& sin_tbl, | |
| 562 | int head_dim, int num_heads, Tensor& Y) { | ||
| 563 | 38 | const auto& v = detail::dispatch(X, cos_tbl, sin_tbl, Y); | |
| 564 |
1/2✓ Branch 0 taken 38 times.
✗ Branch 1 not taken.
|
38 | if (!v.rope_apply) detail::throw_not_implemented("rope_apply", X.device); |
| 565 | 38 | detail::adopt_output(Y, X.device); | |
| 566 | 38 | v.rope_apply(X, cos_tbl, sin_tbl, head_dim, num_heads, Y); | |
| 567 | 38 | } | |
| 568 | |||
| 569 | 6 | void rope_apply_perhead(const Tensor& X, const Tensor& cos_tbl, | |
| 570 | const Tensor& sin_tbl, int head_dim, int num_heads, | ||
| 571 | Tensor& Y) { | ||
| 572 | 6 | const auto& v = detail::dispatch(X, cos_tbl, sin_tbl, Y); | |
| 573 |
1/2✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
|
6 | if (!v.rope_apply_perhead) |
| 574 | ✗ | detail::throw_not_implemented("rope_apply_perhead", X.device); | |
| 575 | 6 | detail::adopt_output(Y, X.device); | |
| 576 | 6 | v.rope_apply_perhead(X, cos_tbl, sin_tbl, head_dim, num_heads, Y); | |
| 577 | 6 | } | |
| 578 | |||
| 579 | 4 | void rope_apply_backward(const Tensor& dY, const Tensor& cos_tbl, | |
| 580 | const Tensor& sin_tbl, int head_dim, int num_heads, | ||
| 581 | Tensor& dX) { | ||
| 582 | 4 | const auto& v = detail::dispatch(dY, cos_tbl, sin_tbl, dX); | |
| 583 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | if (!v.rope_apply_backward) |
| 584 | ✗ | detail::throw_not_implemented("rope_apply_backward", dY.device); | |
| 585 | 4 | detail::adopt_output(dX, dY.device); | |
| 586 | 4 | v.rope_apply_backward(dY, cos_tbl, sin_tbl, head_dim, num_heads, dX); | |
| 587 | 4 | } | |
| 588 | |||
| 589 | 15 | void rope_apply_mrope(const Tensor& X, | |
| 590 | const Tensor& cos_t, const Tensor& sin_t, | ||
| 591 | const Tensor& cos_h, const Tensor& sin_h, | ||
| 592 | const Tensor& cos_w, const Tensor& sin_w, | ||
| 593 | const int32_t* pos_t, const int32_t* pos_h, | ||
| 594 | const int32_t* pos_w, | ||
| 595 | int head_dim, int num_heads, | ||
| 596 | int d_t, int d_h, int d_w, | ||
| 597 | Tensor& Y) { | ||
| 598 | 30 | const auto& v = detail::dispatch(X, cos_t, sin_t, cos_h, sin_h, cos_w, | |
| 599 | 15 | sin_w, Y); | |
| 600 |
1/2✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
|
15 | if (!v.rope_apply_mrope) |
| 601 | ✗ | detail::throw_not_implemented("rope_apply_mrope", X.device); | |
| 602 | 15 | detail::adopt_output(Y, X.device); | |
| 603 | 30 | v.rope_apply_mrope(X, cos_t, sin_t, cos_h, sin_h, cos_w, sin_w, | |
| 604 | 15 | pos_t, pos_h, pos_w, head_dim, num_heads, | |
| 605 | 15 | d_t, d_h, d_w, Y); | |
| 606 | 15 | } | |
| 607 | |||
| 608 | 754 | void rms_norm_forward(const Tensor& X, const Tensor& gamma, float eps, Tensor& Y) { | |
| 609 | 754 | const auto& v = detail::dispatch(X, gamma, Y); | |
| 610 |
1/2✓ Branch 0 taken 754 times.
✗ Branch 1 not taken.
|
754 | if (!v.rms_norm_forward) detail::throw_not_implemented("rms_norm_forward", X.device); |
| 611 | 754 | detail::adopt_output(Y, X.device); | |
| 612 | 754 | v.rms_norm_forward(X, gamma, eps, Y); | |
| 613 | 754 | } | |
| 614 | |||
| 615 | 16 | void rms_norm_backward(const Tensor& X, const Tensor& gamma, const Tensor& dY, | |
| 616 | float eps, Tensor& dX, Tensor& dGamma) { | ||
| 617 | 16 | const auto& v = detail::dispatch(X, gamma, dY, dX, dGamma); | |
| 618 |
1/2✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
|
16 | if (!v.rms_norm_backward) detail::throw_not_implemented("rms_norm_backward", X.device); |
| 619 | 16 | detail::adopt_output(dX, X.device); | |
| 620 | 16 | detail::adopt_output(dGamma, X.device); | |
| 621 | 16 | v.rms_norm_backward(X, gamma, dY, eps, dX, dGamma); | |
| 622 | 16 | } | |
| 623 | |||
| 624 | 496 | void swiglu_forward(const Tensor& X, Tensor& Y) { | |
| 625 | 496 | const auto& v = detail::dispatch(X, Y); | |
| 626 |
1/2✓ Branch 0 taken 496 times.
✗ Branch 1 not taken.
|
496 | if (!v.swiglu_forward) detail::throw_not_implemented("swiglu_forward", X.device); |
| 627 | 496 | detail::adopt_output(Y, X.device); | |
| 628 | 496 | v.swiglu_forward(X, Y); | |
| 629 | 496 | } | |
| 630 | 12 | void swiglu_backward(const Tensor& X, const Tensor& dY, Tensor& dX) { | |
| 631 | 12 | const auto& v = detail::dispatch(X, dY, dX); | |
| 632 |
1/2✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
|
12 | if (!v.swiglu_backward) detail::throw_not_implemented("swiglu_backward", X.device); |
| 633 | 12 | detail::adopt_output(dX, X.device); | |
| 634 | 12 | v.swiglu_backward(X, dY, dX); | |
| 635 | 12 | } | |
| 636 | |||
| 637 | 36 | void kv_cache_append(const Tensor& K_new, const Tensor& V_new, int cur_len, | |
| 638 | Tensor& K_cache, Tensor& V_cache) { | ||
| 639 | 36 | const auto& v = detail::dispatch(K_new, V_new, K_cache, V_cache); | |
| 640 |
1/2✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
|
36 | if (!v.kv_cache_append) detail::throw_not_implemented("kv_cache_append", K_new.device); |
| 641 | 36 | detail::adopt_output(K_cache, K_new.device); | |
| 642 | 36 | detail::adopt_output(V_cache, K_new.device); | |
| 643 | 36 | v.kv_cache_append(K_new, V_new, cur_len, K_cache, V_cache); | |
| 644 | 36 | } | |
| 645 | |||
| 646 | 61 | void flash_attention_decode(const Tensor& Q, | |
| 647 | const Tensor& K_cache, const Tensor& V_cache, | ||
| 648 | int valid_len, int num_q_heads, int num_kv_heads, | ||
| 649 | Tensor& O, float attn_softcap, int window) { | ||
| 650 | 61 | const auto& v = detail::dispatch(Q, K_cache, V_cache, O); | |
| 651 |
1/2✓ Branch 0 taken 61 times.
✗ Branch 1 not taken.
|
61 | if (!v.flash_attention_decode) detail::throw_not_implemented("flash_attention_decode", Q.device); |
| 652 | 61 | detail::adopt_output(O, Q.device); | |
| 653 | 122 | v.flash_attention_decode(Q, K_cache, V_cache, valid_len, | |
| 654 | 61 | num_q_heads, num_kv_heads, O, attn_softcap, window); | |
| 655 | 61 | } | |
| 656 | |||
| 657 | 16 | void flash_attention_decode_masked(const Tensor& Q, | |
| 658 | const Tensor& K_cache, | ||
| 659 | const Tensor& V_cache, | ||
| 660 | const float* d_mask, | ||
| 661 | int num_q_heads, int num_kv_heads, | ||
| 662 | Tensor& O, float attn_softcap, int window) { | ||
| 663 | 16 | const auto& v = detail::dispatch(Q, K_cache, V_cache, O); | |
| 664 |
1/2✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
|
16 | if (!v.flash_attention_decode_masked) { |
| 665 | ✗ | detail::throw_not_implemented("flash_attention_decode_masked", Q.device); | |
| 666 | } | ||
| 667 | 16 | detail::adopt_output(O, Q.device); | |
| 668 | 32 | v.flash_attention_decode_masked(Q, K_cache, V_cache, d_mask, | |
| 669 | 16 | num_q_heads, num_kv_heads, O, | |
| 670 | 16 | attn_softcap, window); | |
| 671 | 16 | } | |
| 672 | |||
| 673 | 52 | void flash_attention_decode_len(const Tensor& Q, const Tensor& K_cache, const Tensor& V_cache, | |
| 674 | const int32_t* d_len, int num_q_heads, int num_kv_heads, Tensor& O) { | ||
| 675 | 52 | const auto& v = detail::dispatch(Q, K_cache, V_cache, O); | |
| 676 |
1/2✓ Branch 0 taken 52 times.
✗ Branch 1 not taken.
|
52 | if (!v.flash_attention_decode_len) detail::throw_not_implemented("flash_attention_decode_len", Q.device); |
| 677 | 52 | detail::adopt_output(O, Q.device); | |
| 678 | 52 | v.flash_attention_decode_len(Q, K_cache, V_cache, d_len, num_q_heads, num_kv_heads, O); | |
| 679 | 52 | } | |
| 680 | |||
| 681 | // ─── Public reductions ───────────────────────────────────────────────────── | ||
| 682 | |||
| 683 | 15 | void sum_rows(const Tensor& X, Tensor& Y) { | |
| 684 | 15 | const auto& v = detail::dispatch(X, Y); | |
| 685 |
1/2✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
|
15 | if (!v.sum_rows) detail::throw_not_implemented("sum_rows", X.device); |
| 686 | 15 | detail::adopt_output(Y, X.device); | |
| 687 | 15 | v.sum_rows(X, Y); | |
| 688 | 15 | } | |
| 689 | 14 | void sum_cols(const Tensor& X, Tensor& Y) { | |
| 690 | 14 | const auto& v = detail::dispatch(X, Y); | |
| 691 |
1/2✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
|
14 | if (!v.sum_cols) detail::throw_not_implemented("sum_cols", X.device); |
| 692 | 14 | detail::adopt_output(Y, X.device); | |
| 693 | 14 | v.sum_cols(X, Y); | |
| 694 | 14 | } | |
| 695 | 23 | void argmax_rows(const Tensor& X, Tensor& Idx) { | |
| 696 | 23 | const auto& v = detail::dispatch(X, Idx); | |
| 697 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 | if (!v.argmax_rows) detail::throw_not_implemented("argmax_rows", X.device); |
| 698 | 23 | detail::adopt_output(Idx, X.device); | |
| 699 | 23 | v.argmax_rows(X, Idx); | |
| 700 | 23 | } | |
| 701 | 5 | void segment_softmax_stats(const Tensor& logits, const Tensor& seg_offsets, Tensor& out) { | |
| 702 | 5 | const auto& v = detail::dispatch(logits, seg_offsets, out); | |
| 703 |
1/2✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
|
5 | if (!v.segment_softmax_stats) |
| 704 | ✗ | detail::throw_not_implemented("segment_softmax_stats", logits.device); | |
| 705 | 5 | detail::adopt_output(out, logits.device); | |
| 706 | 5 | v.segment_softmax_stats(logits, seg_offsets, out); | |
| 707 | 5 | } | |
| 708 | 1203 | void flash_attention_packed_qkv_forward(const Tensor& QKV, const Tensor& seq_bounds, | |
| 709 | int num_heads, int window, Tensor& O) { | ||
| 710 | 1203 | const auto& v = detail::dispatch(QKV, seq_bounds, O); | |
| 711 |
1/2✓ Branch 0 taken 1203 times.
✗ Branch 1 not taken.
|
1203 | if (!v.flash_attention_packed_qkv_forward) |
| 712 | ✗ | detail::throw_not_implemented("flash_attention_packed_qkv_forward", QKV.device); | |
| 713 | 1203 | detail::adopt_output(O, QKV.device); | |
| 714 | 1203 | v.flash_attention_packed_qkv_forward(QKV, seq_bounds, num_heads, window, O); | |
| 715 | 1203 | } | |
| 716 | 22 | void flash_attention_packed_qkv_backward(const Tensor& QKV, const Tensor& dO, const Tensor& seq_bounds, | |
| 717 | int num_heads, int window, Tensor& dQKV) { | ||
| 718 | 22 | const auto& v = detail::dispatch(QKV, dO, seq_bounds, dQKV); | |
| 719 |
1/2✓ Branch 0 taken 22 times.
✗ Branch 1 not taken.
|
22 | if (!v.flash_attention_packed_qkv_backward) |
| 720 | ✗ | detail::throw_not_implemented("flash_attention_packed_qkv_backward", QKV.device); | |
| 721 | 22 | detail::adopt_output(dQKV, QKV.device); | |
| 722 | 22 | v.flash_attention_packed_qkv_backward(QKV, dO, seq_bounds, num_heads, window, dQKV); | |
| 723 | 22 | } | |
| 724 | 8 | void rope_qkv_packed_inplace(Tensor& QKV, const Tensor& cos_tbl, const Tensor& sin_tbl, | |
| 725 | const Tensor& pos, int num_heads, int head_dim) { | ||
| 726 | 8 | const auto& v = detail::dispatch(QKV, cos_tbl, sin_tbl, pos); | |
| 727 |
1/2✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
|
8 | if (!v.rope_qkv_packed_inplace) |
| 728 | ✗ | detail::throw_not_implemented("rope_qkv_packed_inplace", QKV.device); | |
| 729 | 8 | v.rope_qkv_packed_inplace(QKV, cos_tbl, sin_tbl, pos, num_heads, head_dim); | |
| 730 | 8 | } | |
| 731 | 13 | void rows_count_above(const Tensor& X, float t_lo, float t_hi, Tensor& counts) { | |
| 732 | 13 | const auto& v = detail::dispatch(X, counts); | |
| 733 |
1/2✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
|
13 | if (!v.rows_count_above) |
| 734 | ✗ | detail::throw_not_implemented("rows_count_above", X.device); | |
| 735 | 13 | detail::adopt_output(counts, X.device); | |
| 736 | 13 | v.rows_count_above(X, t_lo, t_hi, counts); | |
| 737 | 13 | } | |
| 738 | 11 | void threshold_u8(const Tensor& X, float t, Tensor& Y) { | |
| 739 | 11 | const auto& v = detail::dispatch(X, Y); | |
| 740 |
1/2✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
|
11 | if (!v.threshold_u8) detail::throw_not_implemented("threshold_u8", X.device); |
| 741 | 11 | detail::adopt_output(Y, X.device); | |
| 742 | 11 | v.threshold_u8(X, t, Y); | |
| 743 | 11 | } | |
| 744 | |||
| 745 | } // namespace brotensor | ||
| 746 |