char-fork/llama.cpp

git clone https://git.t4t.associates/char-fork/llama.cpp

Hemanth Battumtmd: fix Granite4 Vision image sequence assembly (#26653)9d57ce456

char/aliceai-t5-moe
15.5 KiB397 linesraw
1#include "models.h"
2#include "../clip-impl.h"
3#include "../clip-model.h"
4
5#include <algorithm>
6#include <cmath>
7#include <cstring>
8#include <string>
9#include <vector>
10
11/*
12 * Granite Vision 4.1 clip graph
13 *
14 *   Stage 1a: SigLIP vision tower (N layers, post-norm)
15 *   Stage 1b: WindowQFormer blocks (deepstack + spatial)
16 *   Stage 1c: Concatenate and pack outputs
17 *   Stage 1d: Assemble the anyres tiles into one token sequence
18 */
19
20// ---------------------------------------------------------------------------
21// Member method implementations
22// ---------------------------------------------------------------------------
23
24// split the stacked tiles into the batch axis, then run the usual patch embedding
25ggml_tensor * clip_graph_granite4_vision::build_tile_inp() {
26    ggml_tensor * inp_raw = build_inp_raw();
27
28    if (n_tiles > 1) {
29        const int px = img.nx();
30        inp_raw = ggml_reshape_4d(ctx0, inp_raw, px * px, n_tiles, 3, 1);
31        inp_raw = ggml_cont(ctx0, ggml_permute(ctx0, inp_raw, 0, 2, 1, 3));
32        inp_raw = ggml_reshape_4d(ctx0, inp_raw, px, px, 3, n_tiles);
33    }
34
35    ggml_tensor * inp = ggml_conv_2d(ctx0, model.patch_embeddings_0, inp_raw, patch_size, patch_size, 0, 0, 1, 1);
36    inp = ggml_reshape_3d(ctx0, inp, tile_side * tile_side, n_embd, n_tiles);
37    inp = ggml_cont(ctx0, ggml_transpose(ctx0, inp));
38    if (model.patch_bias) {
39        inp = ggml_add(ctx0, inp, model.patch_bias);
40    }
41    return inp;
42}
43
44ggml_tensor * clip_graph_granite4_vision::gather(
45        ggml_tensor * src,
46        const std::string & name,
47        int idx_len) {
48    // one index row per tile, all rows hold the same permutation
49    ggml_tensor * idx = ggml_new_tensor_2d(ctx0, GGML_TYPE_I32, idx_len, n_tiles);
50    ggml_set_name(idx, name.c_str());
51    ggml_set_input(idx);
52    return ggml_get_rows(ctx0, src, idx);
53}
54
55ggml_tensor * clip_graph_granite4_vision::interp_down(
56        ggml_tensor * src,
57        int side,
58        int new_side) {
59    const int n_embd = src->ne[0];
60    ggml_tensor * t = ggml_reshape_4d(ctx0, src, n_embd, side, side, n_tiles);
61    t = ggml_cont(ctx0, ggml_permute(ctx0, t, 2, 0, 1, 3));
62    // fold the tile axis into the channel axis, ggml_pool_2d only pools the first two axes
63    t = ggml_reshape_3d(ctx0, t, side, side, n_embd * n_tiles);
64    const int kernel = side / new_side;
65    t = ggml_pool_2d(ctx0, t, GGML_OP_POOL_AVG, kernel, kernel, kernel, kernel, 0, 0);
66    t = ggml_reshape_4d(ctx0, t, new_side, new_side, n_embd, n_tiles);
67    t = ggml_cont(ctx0, ggml_permute(ctx0, t, 1, 2, 0, 3));
68    return ggml_reshape_3d(ctx0, t, n_embd, new_side * new_side, n_tiles);
69}
70
71// ---------------------------------------------------------------------------
72// build_block - WindowQFormer block implementation
73// ---------------------------------------------------------------------------
74
75ggml_tensor * clip_graph_granite4_vision::build_block(
76        const qf_block & blk,
77        ggml_tensor * h,
78        int bid,
79        int spatial_offset,
80        int image_side,
81        int window_side,
82        int query_side,
83        float qformer_eps) {
84
85    const int n_embd = h->ne[0];
86    GGML_ASSERT(h->ne[1] == image_side * image_side);
87    const int n = image_side / window_side;
88    const int new_side = n * query_side;
89    const int n_windows = n * n;
90    const int n_win_all = n_windows * n_tiles; // windows of every tile, batched together
91    const int enc_len = window_side * window_side;
92    const int query_len = query_side * query_side;
93
94    auto cbx = [&](ggml_tensor * & t, const char * step) {
95        const std::string name = "g4v_blk" + std::to_string(bid) + "_" + step;
96        ggml_set_name(t, name.c_str());
97    };
98
99    // 1. Top-level LN
100    cbx(h, "inp");
101    ggml_tensor * x = build_norm(h, blk.qf_proj_norm_w, blk.qf_proj_norm_b, NORM_TYPE_NORMAL, eps, bid);
102    cbx(x, "norm");
103
104    // 2. enc = _win(x, image_side, window_side)
105    ggml_tensor * enc;
106    {
107        ggml_tensor * enc_flat = gather(x,
108            "g4v_blk" + std::to_string(bid) + "_win_idx",
109            image_side * image_side);
110        enc = ggml_reshape_3d(ctx0, enc_flat, n_embd, enc_len, n_win_all);
111    }
112    cbx(enc, "enc");
113
114    // 3. downsampled = downsampler(x)
115    ggml_tensor * d;
116    (void) spatial_offset;
117    if (spatial_offset >= 0) {
118        d = gather(x,
119            "g4v_blk" + std::to_string(bid) + "_spatial_idx",
120            new_side * new_side);
121    } else {
122        d = interp_down(x, image_side, new_side);
123    }
124    cbx(d, "downsampled");
125
126    // 4. query_embeds = query + _win(d, new_side, query_side)
127    ggml_tensor * q_in;
128    {
129        ggml_tensor * dw_flat = gather(d,
130            "g4v_blk" + std::to_string(bid) + "_qwin_idx",
131            new_side * new_side);
132        ggml_tensor * dw = ggml_reshape_3d(ctx0, dw_flat, n_embd, query_len, n_win_all);
133        q_in = ggml_add(ctx0, dw, blk.qf_proj_query);
134    }
135    cbx(q_in, "query_embeds");
136
137    // 5. encoder_embeds = enc + image_positions → (C, enc_len, n_windows)
138    ggml_tensor * e_in = ggml_add(ctx0, enc, blk.qf_proj_img_pos);
139    cbx(e_in, "encoder_embeds");
140
141    // 6. Qformer forward.
142    ggml_tensor * q = build_norm(q_in, blk.qf_proj_post_norm_w, blk.qf_proj_post_norm_b, NORM_TYPE_NORMAL, qformer_eps, bid);
143
144    // Helper for linear projections with window batching
145    auto linear = [&](ggml_tensor * x, ggml_tensor * w, ggml_tensor * b) -> ggml_tensor * {
146        ggml_tensor * t = ggml_reshape_2d(ctx0, x, x->ne[0], x->ne[1] * x->ne[2]);
147        t = build_mm(w, t);
148        if (b) t = ggml_add(ctx0, t, b);
149        return t;
150    };
151
152    // Get the single QFormer layer
153    GGML_ASSERT(blk.qf_proj_layers.size() == 1);
154    const auto & pl = blk.qf_proj_layers[0];
155
156    // 6a. Self-attention
157    ggml_tensor * sa_out;
158    {
159        const int d_h = 64;
160        const int n_head = n_embd / d_h;
161        const int nq = q->ne[1];
162        const float scale = 1.0f / std::sqrt((float) d_h);
163
164        ggml_tensor * Q = linear(q, pl.q_w, pl.q_b);
165        ggml_tensor * K = linear(q, pl.k_w, pl.k_b);
166        ggml_tensor * V = linear(q, pl.v_w, pl.v_b);
167
168        Q = ggml_reshape_4d(ctx0, Q, d_h, n_head, nq, n_win_all);
169        K = ggml_reshape_4d(ctx0, K, d_h, n_head, nq, n_win_all);
170        V = ggml_reshape_4d(ctx0, V, d_h, n_head, nq, n_win_all);
171
172        sa_out = build_attn(pl.o_w, pl.o_b, Q, K, V, nullptr, scale, bid);
173        sa_out = ggml_reshape_3d(ctx0, sa_out, n_embd, nq, n_win_all);
174
175        sa_out = ggml_add(ctx0, sa_out, q);
176        sa_out = build_norm(sa_out, pl.ln_1_w, pl.ln_1_b,
177                            NORM_TYPE_NORMAL, qformer_eps, bid);
178    }
179    cbx(sa_out, "sa_out");
180
181    // 6b. Cross-attention
182    ggml_tensor * ca_out;
183    {
184        const int d_h = 64;
185        const int n_head = n_embd / d_h;
186        const int nq = sa_out->ne[1];
187        const int nkv = e_in->ne[1];
188        const float scale = 1.0f / std::sqrt((float) d_h);
189
190        ggml_tensor * Q = linear(sa_out, pl.cross_attn_q_w, pl.cross_attn_q_b);
191        ggml_tensor * K = linear(e_in, pl.cross_attn_k_w, pl.cross_attn_k_b);
192        ggml_tensor * V = linear(e_in, pl.cross_attn_v_w, pl.cross_attn_v_b);
193
194        Q = ggml_reshape_4d(ctx0, Q, d_h, n_head, nq, n_win_all);
195        K = ggml_reshape_4d(ctx0, K, d_h, n_head, nkv, n_win_all);
196        V = ggml_reshape_4d(ctx0, V, d_h, n_head, nkv, n_win_all);
197
198        ca_out = build_attn(pl.cross_attn_o_w, pl.cross_attn_o_b,
199                            Q, K, V, nullptr, scale, bid);
200        ca_out = ggml_reshape_3d(ctx0, ca_out, n_embd, nq, n_win_all);
201
202        ca_out = ggml_add(ctx0, ca_out, sa_out);
203        ca_out = build_norm(ca_out, pl.cross_attn_norm_w, pl.cross_attn_norm_b,
204                            NORM_TYPE_NORMAL, qformer_eps, bid);
205    }
206    cbx(ca_out, "ca_out");
207
208    // 6c. FFN
209    ggml_tensor * ffn;
210    {
211        ggml_tensor * t = ggml_reshape_2d(ctx0, ca_out, n_embd, query_len * n_win_all);
212        t = build_mm(pl.ff_up_w, t);
213        if (pl.ff_up_b) t = ggml_add(ctx0, t, pl.ff_up_b);
214        t = ggml_gelu_erf(ctx0, t);
215        t = build_mm(pl.ff_down_w, t);
216        if (pl.ff_down_b) t = ggml_add(ctx0, t, pl.ff_down_b);
217        t = ggml_reshape_3d(ctx0, t, n_embd, query_len, n_win_all);
218        ffn = ggml_add(ctx0, t, ca_out);
219        ffn = build_norm(ffn, pl.ln_2_w, pl.ln_2_b, NORM_TYPE_NORMAL, qformer_eps, bid);
220    }
221    cbx(ffn, "qformer_out");
222
223    // 7. _unwin back to raster
224    ggml_tensor * unwinned;
225    {
226        ggml_tensor * flat = ggml_reshape_3d(ctx0, ffn, n_embd, query_len * n_windows, n_tiles);
227        unwinned = gather(flat,
228            "g4v_blk" + std::to_string(bid) + "_unwin_idx",
229            new_side * new_side);
230    }
231    cbx(unwinned, "unwin");
232
233    // 8. out_linear
234    ggml_tensor * out = build_mm(blk.qf_proj_linear_w, unwinned);
235    if (blk.qf_proj_linear_b) out = ggml_add(ctx0, out, blk.qf_proj_linear_b);
236    cbx(out, "out");
237
238    return out;
239}
240
241// ---------------------------------------------------------------------------
242// build() - top-level graph
243// ---------------------------------------------------------------------------
244
245// Build the K-tiled, base-scaled newline row tensor.
246// Shape: (n_mmproj_embd, 1)
247ggml_tensor * clip_graph_granite4_vision::build_newline_row(ggml_context * ctx0) {
248    const int K = (int) model.qf_proj_blocks.size();
249    GGML_ASSERT(K > 0);
250    GGML_ASSERT(n_mmproj_embd % K == 0);
251    const int projection_dim = n_mmproj_embd / K;
252    GGML_ASSERT(model.image_newline != nullptr);
253    GGML_ASSERT(ggml_nelements(model.image_newline) == projection_dim);
254
255    // Build newline_row[k*projection_dim + d] = nl[d] * (k == 0 ? base : 1.0)
256    ggml_tensor * nl = model.image_newline; // (projection_dim,)
257    ggml_tensor * nl_first_2d = ggml_reshape_2d(ctx0, nl, projection_dim, 1);
258    ggml_tensor * nl_row_2d;
259    if (K == 1) {
260        nl_row_2d = nl_first_2d;
261    } else {
262        ggml_tensor * nl_2d = ggml_reshape_2d(ctx0, nl, projection_dim, 1);
263        ggml_tensor * rest_template = ggml_new_tensor_2d(
264            ctx0, GGML_TYPE_F32, projection_dim, K - 1);
265        ggml_tensor * nl_rest = ggml_repeat(ctx0, nl_2d, rest_template);
266        nl_row_2d = ggml_concat(ctx0, nl_first_2d, nl_rest, 1); // (projection_dim, K)
267    }
268    nl_row_2d = ggml_cont(ctx0, nl_row_2d);
269    return ggml_reshape_2d(ctx0, nl_row_2d, n_mmproj_embd, 1);
270}
271
272// Assemble [overview, tile(0,0), tile(0,1), ...] into one token sequence:
273// the overview tokens first, then the tile grid read in raster order with one newline per row.
274// ref: https://github.com/huggingface/transformers/blob/v5.0.0/src/transformers/models/llava_next/modeling_llava_next.py#L266
275ggml_tensor * clip_graph_granite4_vision::build_anyres_assembly(ggml_tensor * cur, int out_side) {
276    const int n_dim  = cur->ne[0];
277    const int grid_x = anyres.grid_x;
278    const int grid_y = anyres.grid_y;
279    const int cur_w  = grid_x * out_side;
280    const int cur_h  = grid_y * out_side;
281    GGML_ASSERT(cur->ne[1] == out_side * out_side);
282    GGML_ASSERT(cur->ne[2] == 1 + grid_x * grid_y);
283
284    ggml_tensor * base = ggml_view_2d(ctx0, cur, n_dim, out_side * out_side, cur->nb[1], 0);
285
286    ggml_tensor * tiles = ggml_view_3d(ctx0, cur, n_dim, out_side * out_side, grid_x * grid_y,
287                                       cur->nb[1], cur->nb[2], cur->nb[2]);
288
289    // (n_dim*out_side, out_side, grid_x, grid_y) -> interleave the tiles of a grid row
290    tiles = ggml_reshape_4d(ctx0, tiles, n_dim * out_side, out_side, grid_x, grid_y);
291    tiles = ggml_cont(ctx0, ggml_permute(ctx0, tiles, 0, 2, 1, 3));
292    tiles = ggml_reshape_3d(ctx0, tiles, n_dim, cur_w, cur_h);
293
294    // drop the tokens that only cover the padding added when resizing to the grid
295    int off_x, off_y, w, h;
296    clip_anyres_unpad(cur_w, cur_h, anyres.orig_nx, anyres.orig_ny, off_x, off_y, w, h);
297    if (w != cur_w || h != cur_h) {
298        tiles = ggml_cont(ctx0, ggml_view_3d(ctx0, tiles, n_dim, w, h,
299                                             tiles->nb[1], tiles->nb[2],
300                                             off_x * tiles->nb[1] + off_y * tiles->nb[2]));
301    }
302
303    ggml_tensor * nl = ggml_repeat_4d(ctx0, build_newline_row(ctx0), n_dim, 1, h, 1);
304    tiles = ggml_concat(ctx0, tiles, nl, 1);
305    tiles = ggml_reshape_2d(ctx0, tiles, n_dim, (w + 1) * h);
306
307    return ggml_concat(ctx0, base, tiles, 1);
308}
309
310ggml_cgraph * clip_graph_granite4_vision::build() {
311    GGML_ASSERT(model.patch_embeddings_0 != nullptr);
312    GGML_ASSERT(model.position_embeddings != nullptr);
313    GGML_ASSERT(model.class_embedding == nullptr);
314    GGML_ASSERT(!model.qf_proj_blocks.empty());
315
316    // --- Stage 1a: SigLIP encoder producing intermediate hidden states ---
317    ggml_tensor * inp = build_tile_inp();
318    inp = ggml_add(ctx0, inp, model.position_embeddings);
319    cb(inp, "pos_embed", -1);
320
321    const int tile_n_patches = tile_side * tile_side;
322
323    ggml_tensor * inpL = inp;
324    std::vector<ggml_tensor *> layer_outs(n_layer, nullptr);
325
326    for (int il = 0; il < n_layer; ++il) {
327        const auto & layer = model.layers[il];
328        ggml_tensor * cur = inpL;
329
330        cur = build_norm(cur, layer.ln_1_w, layer.ln_1_b, NORM_TYPE_NORMAL, eps, il);
331
332        // Self-attention
333        ggml_tensor * Qcur = build_mm(layer.q_w, cur);
334        if (layer.q_b) Qcur = ggml_add(ctx0, Qcur, layer.q_b);
335        ggml_tensor * Kcur = build_mm(layer.k_w, cur);
336        if (layer.k_b) Kcur = ggml_add(ctx0, Kcur, layer.k_b);
337        ggml_tensor * Vcur = build_mm(layer.v_w, cur);
338        if (layer.v_b) Vcur = ggml_add(ctx0, Vcur, layer.v_b);
339
340        Qcur = ggml_reshape_4d(ctx0, Qcur, d_head, n_head, tile_n_patches, n_tiles);
341        Kcur = ggml_reshape_4d(ctx0, Kcur, d_head, n_head, tile_n_patches, n_tiles);
342        Vcur = ggml_reshape_4d(ctx0, Vcur, d_head, n_head, tile_n_patches, n_tiles);
343
344        cur = build_attn(layer.o_w, layer.o_b,
345                         Qcur, Kcur, Vcur, nullptr, kq_scale, il);
346        cur = ggml_reshape_3d(ctx0, cur, n_embd, tile_n_patches, n_tiles);
347
348        cur = ggml_add(ctx0, cur, inpL);
349        inpL = cur;
350
351        cur = build_norm(cur, layer.ln_2_w, layer.ln_2_b, NORM_TYPE_NORMAL, eps, il);
352        cur = build_ffn(cur,
353                        layer.ff_up_w, layer.ff_up_b,
354                        layer.ff_gate_w, layer.ff_gate_b,
355                        layer.ff_down_w, layer.ff_down_b,
356                        hparams.ffn_op, il);
357        cur = ggml_add(ctx0, inpL, cur);
358        cb(cur, "layer_out", il);
359        layer_outs[il] = cur;
360        inpL = cur;
361    }
362
363    // --- Stage 1b/1c: WindowQFormer blocks ---
364    const int projector_count = hparams.feature_layers.size();
365    const float qformer_eps = 1e-12f;
366
367    ggml_tensor * mmproj = nullptr;
368    for (int bid = 0; bid < projector_count; ++bid) {
369        const auto & blk = model.qf_proj_blocks[bid];
370
371        int vlayer = hparams.feature_layers[bid];
372        GGML_ASSERT(vlayer >= 0 && vlayer < n_layer);
373        ggml_tensor * h = layer_outs[vlayer];
374
375        ggml_tensor * stream = build_block(
376            blk, h, bid,
377            hparams.proj_spatial_offsets[bid],
378            tile_side,
379            hparams.downsample_window_side,
380            hparams.downsample_query_side,
381            qformer_eps);
382        cb(stream, (std::string("proj_") + std::to_string(bid) + std::string("_v_out")).c_str(), vlayer);
383        mmproj = mmproj ? ggml_concat(ctx0, mmproj, stream, 0) : stream;
384    }
385
386    // --- Stage 1d: assemble the tiles and weave in the newline tokens ---
387    if (anyres.is_tiled()) {
388        const int out_side = tile_side / hparams.downsample_window_side * hparams.downsample_query_side;
389        mmproj = build_anyres_assembly(mmproj, out_side);
390        ggml_set_name(mmproj, "g4v_mmproj_out_anyres");
391    } else {
392        ggml_set_name(mmproj, "g4v_mmproj_out");
393    }
394    ggml_build_forward_expand(gf, mmproj);
395
396    return gf;
397}