| 5332 | // ggml_flash_attn_back |
| 5333 | |
| 5334 | struct ggml_tensor * ggml_flash_attn_back( |
| 5335 | struct ggml_context * ctx, |
| 5336 | struct ggml_tensor * q, |
| 5337 | struct ggml_tensor * k, |
| 5338 | struct ggml_tensor * v, |
| 5339 | struct ggml_tensor * d, |
| 5340 | bool masked) { |
| 5341 | GGML_ABORT("TODO: adapt to ggml_flash_attn_ext() changes"); |
| 5342 | |
| 5343 | GGML_ASSERT(ggml_can_mul_mat(k, q)); |
| 5344 | // TODO: check if vT can be multiplied by (k*qT) |
| 5345 | |
| 5346 | // d shape [D,N,ne2,ne3] |
| 5347 | // q shape [D,N,ne2,ne3] |
| 5348 | // k shape [D,M,kvne2,ne3] |
| 5349 | // v shape [M,D,kvne2,ne3] |
| 5350 | |
| 5351 | const int64_t D = q->ne[0]; |
| 5352 | const int64_t N = q->ne[1]; |
| 5353 | const int64_t M = k->ne[1]; |
| 5354 | const int64_t ne2 = q->ne[2]; |
| 5355 | const int64_t ne3 = q->ne[3]; |
| 5356 | const int64_t kvne2 = k->ne[2]; |
| 5357 | |
| 5358 | GGML_ASSERT(k->ne[0] == D); |
| 5359 | GGML_ASSERT(v->ne[0] == M); |
| 5360 | GGML_ASSERT(v->ne[1] == D); |
| 5361 | GGML_ASSERT(d->ne[0] == D); |
| 5362 | GGML_ASSERT(d->ne[1] == N); |
| 5363 | GGML_ASSERT(k->ne[2] == kvne2); |
| 5364 | GGML_ASSERT(k->ne[3] == ne3); |
| 5365 | GGML_ASSERT(v->ne[2] == kvne2); |
| 5366 | GGML_ASSERT(v->ne[3] == ne3); |
| 5367 | GGML_ASSERT(d->ne[2] == ne2); |
| 5368 | GGML_ASSERT(d->ne[3] == ne3); |
| 5369 | |
| 5370 | GGML_ASSERT(ne2 % kvne2 == 0); |
| 5371 | |
| 5372 | // store gradients of q, k and v as continuous tensors concatenated in result. |
| 5373 | // note: v and gradv are actually transposed, i.e. v->ne[0] != D. |
| 5374 | const int64_t elem_q = ggml_nelements(q); |
| 5375 | const int64_t elem_k = ggml_nelements(k); |
| 5376 | const int64_t elem_v = ggml_nelements(v); |
| 5377 | |
| 5378 | enum ggml_type result_type = GGML_TYPE_F32; |
| 5379 | GGML_ASSERT(ggml_blck_size(result_type) == 1); |
| 5380 | const size_t tsize = ggml_type_size(result_type); |
| 5381 | |
| 5382 | const size_t offs_q = 0; |
| 5383 | const size_t offs_k = offs_q + GGML_PAD(elem_q * tsize, GGML_MEM_ALIGN); |
| 5384 | const size_t offs_v = offs_k + GGML_PAD(elem_k * tsize, GGML_MEM_ALIGN); |
| 5385 | const size_t end = offs_v + GGML_PAD(elem_v * tsize, GGML_MEM_ALIGN); |
| 5386 | |
| 5387 | const size_t nelements = (end + tsize - 1)/tsize; |
| 5388 | |
| 5389 | struct ggml_tensor * result = ggml_new_tensor_1d(ctx, GGML_TYPE_F32, nelements); |
| 5390 | |
| 5391 | int32_t masked_i = masked ? 1 : 0; |
nothing calls this directly
no test coverage detected