char-fork/llama.cpp

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

Xuan-Son Nguyenmtmd: support DeepSeek-V4-Flash-Vision-Exp (#28133)7798007a2

char/aliceai-t5-moe
4.0 KiB102 linesraw
1#include "models.h"
2
3// DeepSeek-V4-Flash-Vision encoder (deepseek4v)
4//
5// native-resolution ViT (RMSNorm, SwiGLU, 2D RoPE, no CLS / learned pos-embd)
6// then the "aligner": 3x3 patch merge (torch.nn.functional.unfold) + 2-layer GELU MLP
7//
8// the graph outputs the complete LLM token block, built from the aligner output and 4 learned sentinel embeddings:
9//
10//   [PAD]*lead_pad [START] <interleaved rows> [PAD]*pad_last [END]
11//
12// each aligner row ends with a NEWLINE, an odd row count is padded with a full row of PADs
13// pairs of adjacent rows are interleaved column-wise ("N-layout")
14// the mapping is precomputed on CPU as the "layout_idx" input (see set_input in clip.cpp)
15//
16// ref: inference/vision.py and inference/image_processor.py in the HF repo
17
18ggml_cgraph * clip_graph_deepseek4v::build() {
19    const int n_merge = hparams.n_merge;
20
21    // 2D input positions
22    ggml_tensor * positions = ggml_new_tensor_1d(ctx0, GGML_TYPE_I32, n_patches * 4);
23    ggml_set_name(positions, "positions");
24    ggml_set_input(positions);
25
26    int sections[4] = {d_head/4, d_head/4, 0, 0};
27    auto add_pos = [&](ggml_tensor * cur, const clip_layer &) {
28        return ggml_rope_multi(ctx0, cur, positions, nullptr,
29            d_head/2, sections, GGML_ROPE_TYPE_VISION,
30            0, hparams.rope_theta, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f);
31    };
32
33    ggml_tensor * inp = build_inp();
34    ggml_tensor * cur = build_vit(
35                            inp, n_patches,
36                            NORM_TYPE_RMS,
37                            hparams.ffn_op,
38                            nullptr, // no learned pos embd
39                            add_pos);
40    cb(cur, "vit_out", -1);
41
42    // aligner patch merge: zero-pad the patch grid to a multiple of n_merge
43    // then F.unfold == im2col with a dummy kernel (same trick as pixtral)
44    {
45        cur = ggml_reshape_3d(ctx0, cur, n_embd, n_patches_x, n_patches_y);
46        cur = ggml_permute(ctx0, cur, 2, 0, 1, 3); // [x, y, n_embd]
47        cur = ggml_cont(ctx0, cur);
48
49        const int pad_x = (n_merge - n_patches_x % n_merge) % n_merge;
50        const int pad_y = (n_merge - n_patches_y % n_merge) % n_merge;
51        if (pad_x || pad_y) {
52            cur = ggml_pad(ctx0, cur, pad_x, pad_y, 0, 0);
53        }
54
55        ggml_tensor * kernel = ggml_view_3d(ctx0, cur, n_merge, n_merge, cur->ne[2], 0, 0, 0);
56        cur = ggml_im2col(ctx0, kernel, cur, n_merge, n_merge, 0, 0, 1, 1, true, inp->type);
57        cur = ggml_reshape_2d(ctx0, cur, cur->ne[0], cur->ne[1] * cur->ne[2]);
58
59        // aligner MLP (F.gelu in the reference == erf-based gelu)
60        cur = build_ffn(cur,
61            model.mm_1_w, model.mm_1_b,
62            nullptr, nullptr,
63            model.mm_2_w, model.mm_2_b,
64            FFN_GELU_ERF,
65            -1);
66        cb(cur, "aligner_out", -1);
67    }
68
69    // assemble the token block: append the sentinel embeddings as extra rows
70    // then reorder everything with the precomputed layout index
71    {
72        const int64_t n_embd_out = cur->ne[0];
73        const int64_t n_grid     = cur->ne[1]; // n_llm_w * n_llm_h
74
75        // rows n_grid + 0..3, keep in sync with the index computation in set_input
76        ggml_tensor * sentinels[] = {
77            model.token_embd_img_start,
78            model.token_embd_img_end,
79            model.image_newline,
80            model.token_embd_img_pad,
81        };
82        for (ggml_tensor * tok : sentinels) {
83            cur = ggml_concat(ctx0, cur, ggml_reshape_2d(ctx0, tok, n_embd_out, 1), 1);
84        }
85
86        const int n_llm_w = CLIP_ALIGN(n_patches_x, n_merge) / n_merge;
87        const int n_llm_h = CLIP_ALIGN(n_patches_y, n_merge) / n_merge;
88        const int n_out   = dsv4_get_block_layout(n_llm_w, n_llm_h, img.lead_pad).n_out;
89        GGML_ASSERT(n_grid == n_llm_w * n_llm_h);
90
91        ggml_tensor * layout_idx = ggml_new_tensor_1d(ctx0, GGML_TYPE_I32, n_out);
92        ggml_set_name(layout_idx, "layout_idx");
93        ggml_set_input(layout_idx);
94
95        cur = ggml_get_rows(ctx0, cur, layout_idx);
96    }
97
98    // build the graph
99    ggml_build_forward_expand(gf, cur);
100
101    return gf;
102}