koboldcpp/tools/mtmd/models/voxtral-rt.cpp
Xuan-Son Nguyen 2851b3bcbf
mtmd: add mtmd_audio_stream + support voxtral-realtime (#30629)
* mtmd: add mtmd_audio_stream + support voxtral-realtime

* address review
2026-10-16 01:46:42 +02:00

111 lines
4.6 KiB
C++

#include "models.h"
// the input holds 2 context mel frames followed by the new frames, so the causal conv stem
// sees the same left context as on the full spectrogram
ggml_cgraph * clip_graph_voxtral_rt::build() {
const int n_frames_in = img.nx();
const int n_new = (n_frames_in - 2) / 2; // encoder frames, the conv stem has stride 2
const int n_window = hparams.attn_window_size;
const int stack = hparams.proj_stack_factor;
const int n_embd_kv = n_head_kv * d_head;
const int n_ctx = state ? state->n_ctx : n_window + n_new;
GGML_ASSERT(n_window > 0 && stack > 0);
GGML_ASSERT(n_new > 0 && n_new % stack == 0);
GGML_ASSERT(n_new <= n_ctx - n_window);
ggml_tensor * inp = build_inp_raw(1); // [n_frames_in, n_mel]
ggml_tensor * stem_tail = ggml_new_tensor_2d(ctx0, GGML_TYPE_F32, 1, n_embd);
ggml_set_name(stem_tail, "inp_stem_tail");
ggml_set_input(stem_tail);
ggml_tensor * pos = ggml_new_tensor_1d(ctx0, GGML_TYPE_I32, n_new);
ggml_set_name(pos, "inp_pos");
ggml_set_input(pos);
ggml_tensor * kv_idx = ggml_new_tensor_1d(ctx0, GGML_TYPE_I64, n_new);
ggml_set_name(kv_idx, "inp_kv_idx");
ggml_set_input(kv_idx);
ggml_tensor * kq_mask = build_inp_attn_mask(n_ctx, n_new);
// causal conv stem
ggml_tensor * cur = ggml_conv_1d(ctx0, model.conv1d_1_w, inp, 1, 0, 1);
cur = ggml_add(ctx0, cur, model.conv1d_1_b);
cur = ggml_gelu_erf(ctx0, cur); // [2*n_new, n_embd]
// the last frame is the left context of the second conv on the next call
ggml_tensor * tail = ggml_view_2d(ctx0, cur, 1, n_embd, cur->nb[1], (2*n_new - 1) * ggml_element_size(cur));
tail = ggml_cont(ctx0, tail);
ggml_set_name(tail, "out_stem_tail");
ggml_set_output(tail);
ggml_build_forward_expand(gf, tail);
cur = ggml_concat(ctx0, stem_tail, cur, 0); // [2*n_new + 1, n_embd]
cur = ggml_conv_1d(ctx0, model.conv1d_2_w, cur, 2, 0, 1);
cur = ggml_add(ctx0, cur, model.conv1d_2_b);
cur = ggml_gelu_erf(ctx0, cur); // [n_new, n_embd]
cur = ggml_cont(ctx0, ggml_transpose(ctx0, cur)); // [n_embd, n_new]
cb(cur, "after_conv1d", -1);
for (int il = 0; il < n_layer; il++) {
const auto & layer = model.layers[il];
ggml_tensor * x = build_norm(cur, layer.ln_1_w, nullptr, NORM_TYPE_RMS, eps, il);
ggml_tensor * q = ggml_add(ctx0, build_mm(layer.q_w, x), layer.q_b);
ggml_tensor * k = build_mm(layer.k_w, x);
ggml_tensor * v = ggml_add(ctx0, build_mm(layer.v_w, x), layer.v_b);
q = ggml_reshape_3d(ctx0, q, d_head, n_head, n_new);
k = ggml_reshape_3d(ctx0, k, d_head, n_head_kv, n_new);
// interleaved rope on absolute frame positions
q = ggml_rope_ext(ctx0, q, pos, nullptr, d_head, GGML_ROPE_TYPE_NORMAL, 0, hparams.rope_theta, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f);
k = ggml_rope_ext(ctx0, k, pos, nullptr, d_head, GGML_ROPE_TYPE_NORMAL, 0, hparams.rope_theta, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f);
cb(q, "q", il);
cb(k, "k", il);
cb(v, "v", il);
ggml_tensor * k_cache;
ggml_tensor * v_cache;
if (state) {
k_cache = state->k[il];
v_cache = state->v[il];
} else {
k_cache = ggml_new_tensor_2d(ctx0, GGML_TYPE_F16, n_embd_kv, n_ctx);
v_cache = ggml_new_tensor_2d(ctx0, GGML_TYPE_F16, n_embd_kv, n_ctx);
ggml_set_input(k_cache);
ggml_set_input(v_cache);
}
// write the new frames into the ring, the mask selects the window out of the whole ring
ggml_build_forward_expand(gf, ggml_set_rows(ctx0, k_cache, ggml_reshape_2d(ctx0, k, n_embd_kv, n_new), kv_idx));
ggml_build_forward_expand(gf, ggml_set_rows(ctx0, v_cache, v, kv_idx));
ggml_tensor * k_all = ggml_reshape_3d(ctx0, k_cache, d_head, n_head_kv, n_ctx);
ggml_tensor * v_all = ggml_reshape_3d(ctx0, v_cache, d_head, n_head_kv, n_ctx);
x = build_attn(layer.o_w, layer.o_b, q, k_all, v_all, kq_mask, kq_scale, il);
cur = ggml_add(ctx0, cur, x);
x = build_norm(cur, layer.ln_2_w, nullptr, NORM_TYPE_RMS, eps, il);
x = build_ffn(x, layer.ff_up_w, nullptr, layer.ff_gate_w, nullptr, layer.ff_down_w, layer.ff_down_b, hparams.ffn_op, il);
cur = ggml_add(ctx0, cur, x);
cb(cur, "layer_out", il);
}
cur = build_norm(cur, model.post_ln_w, nullptr, NORM_TYPE_RMS, eps, -1);
cb(cur, "after_transformer", -1);
cur = build_stack(cur, stack, n_embd);
cur = build_mm(model.mm_1_w, cur);
cur = ggml_gelu_erf(ctx0, cur);
cur = build_mm(model.mm_2_w, cur);
cb(cur, "projected", -1);
ggml_build_forward_expand(gf, cur);
return gf;
}