llama: properly handle KV on training

This commit is contained in:
Xuan Son Nguyen
2026-09-07 01:00:51 +02:00
parent 465e49b9ce
commit 3f6205741d
3 changed files with 28 additions and 4 deletions
+17 -4
View File
@@ -274,6 +274,7 @@ llama_context::llama_context(
// initialized later
cparams.pipeline_parallel = false;
cparams.training = false;
{
const char * LLAMA_GRAPH_REUSE_DISABLE = getenv("LLAMA_GRAPH_REUSE_DISABLE");
@@ -2349,6 +2350,11 @@ uint32_t llama_context::graph_max_nodes(uint32_t n_tokens) const {
if (n_sampling_outputs_max > 1) {
res += (n_sampling_outputs_max - 1) * n_sampling_nodes_max;
}
if (cparams.training) {
res *= 4;
}
return res;
}
@@ -3413,12 +3419,19 @@ void llama_context::opt_init(struct llama_model * model, struct llama_opt_params
if (cparams.flash_attn) {
LLAMA_LOG_INFO("%s: disabling flash attention, FLASH_ATTN_EXT has no backward pass\n", __func__);
cparams.flash_attn = false;
// the graph changes without flash attention, need to reserve again
sched_need_reserve = true;
sched_reserve();
}
// gradients cannot flow through the KV cache, so the attention reads the K and V of the current ubatch directly
if (n_ubatch == cparams.n_ctx) {
cparams.training = true;
} else {
LLAMA_LOG_WARN("%s: n_ubatch (%u) != n_ctx (%u), the K and V projections will not receive gradients\n", __func__, n_ubatch, cparams.n_ctx);
}
// the training graph is different, need to reserve again
sched_need_reserve = true;
sched_reserve();
ggml_opt_params opt_params = ggml_opt_default_params(sched.get(), GGML_OPT_LOSS_TYPE_CROSS_ENTROPY);
opt_params.opt_period = n_batch / n_ubatch;
opt_params.get_opt_pars = lopt_params.get_opt_pars;
+1
View File
@@ -53,6 +53,7 @@ struct llama_cparams {
bool op_offload;
bool kv_unified;
bool pipeline_parallel;
bool training; // set by llama_opt_init()
std::vector<bool> embeddings_layer_inp; // [n_layer()] extract input embeddings for layer
+10
View File
@@ -2884,6 +2884,11 @@ ggml_tensor * llm_graph_context::build_attn(
ggml_tensor * k = mctx_cur->get_k(ctx0, il);
ggml_tensor * v = mctx_cur->get_v(ctx0, il);
if (cparams.training && mctx_cur->get_n_kv() == n_tokens) {
k = k_cur;
v = v_cur;
}
ggml_tensor * cur = build_attn_mha(q, k, v, kq_b, kq_mask, sinks, v_mla, 0, kq_scale, il);
cb(cur, "kqv_out", il);
@@ -3139,6 +3144,11 @@ ggml_tensor * llm_graph_context::build_attn(
ggml_tensor * k = mctx_cur->get_k(ctx0, il);
ggml_tensor * v = mctx_cur->get_v(ctx0, il);
if (cparams.training && k_cur && v_cur && mctx_cur->get_n_kv() == n_tokens) {
k = k_cur;
v = v_cur;
}
ggml_tensor * cur = build_attn_mha(q, k, v, kq_b, kq_mask, sinks, v_mla, 0, kq_scale, il);
cb(cur, "kqv_out", il);