char-fork/llama.cpp

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

Xuan-Son Nguyenmtmd: add mtmd_tokenize_from_parts() (#28250)733905474

char/aliceai-t5-moe
4.7 KiB158 linesraw
1#include "testing.h"
2
3#include "mtmd-image.h"
4#include "mtmd-internal.h"
5
6#include <iostream>
7#include <stdexcept>
8#include <string>
9#include <tuple>
10#include <utility>
11#include <vector>
12
13// this test file contains:
14// 1. test cases for mtmd helpers
15// 2. test cases for internal mtmd components
16// internal headers can be included here
17
18struct test_registry {
19    using fn_t = void (*)(testing &);
20
21    struct entry {
22        std::string name;
23        fn_t fn;
24    };
25
26    static std::vector<entry> & all() {
27        static std::vector<entry> entries;
28        return entries;
29    }
30
31    test_registry(const char * name, fn_t fn) {
32        all().push_back({ name, fn });
33    }
34};
35
36#define MAKE_TEST(name)                                               \
37    static void name(testing & t);                                    \
38    static const test_registry test_registry_ ## name(#name, &name);  \
39    static void name(testing & t)
40
41
42//
43// mtmd_image
44//
45
46MAKE_TEST(test_image_preprocessor_lfm2) {
47    clip_hparams hparams;
48    hparams.patch_size = 16;
49    hparams.n_merge = 2;
50    hparams.set_limit_image_tokens(64, 256);
51
52    // { image size, expected tiling }
53    const std::vector<std::pair<clip_image_size, bool>> cases = {
54        { {  704, 704 }, false },
55        // 720 / (patch_size * n_merge) is exactly 22.5, so this only matches HF
56        // if round_by_factor rounds half to even (22) instead of away from zero (23)
57        { {  720, 720 }, false },
58        { {  736, 736 }, true  },
59        { { 1024, 977 }, true  },
60        { { 1056, 384 }, false },
61    };
62
63    for (const auto & [size, expected] : cases) {
64        const bool actual = mtmd_image_preprocessor_lfm2::should_tile(hparams, size);
65
66        t.assert_equal(
67            "tiling for " + std::to_string(size.width) + "x" + std::to_string(size.height),
68            std::string(expected ? "tiled" : "single"),
69            std::string(actual   ? "tiled" : "single"));
70    }
71}
72
73//
74// mtmd temporal merge
75//
76
77MAKE_TEST(test_temporal_merge_grouping) {
78    std::vector<mtmd::bitmap_ptr> pool; // keeps the bitmaps alive until the end of the test
79
80    // spec chars:
81    //   v = video frame, w = video frame of another size, a = audio, i = plain image, t = text
82    auto make_parts = [&pool](const std::string & spec) {
83        std::vector<mtmd_internal_part> parts;
84        for (char c : spec) {
85            if (c == 't') {
86                parts.push_back({ "hello", nullptr });
87                continue;
88            }
89            mtmd_bitmap * bm = nullptr;
90            switch (c) {
91                case 'v': bm = mtmd_bitmap_init(100, 100, nullptr);   break;
92                case 'w': bm = mtmd_bitmap_init(200, 200, nullptr);   break;
93                case 'a': bm = mtmd_bitmap_init_from_audio(100, nullptr); break;
94                case 'i': bm = mtmd_bitmap_init(100, 100, nullptr);   break;
95                default: throw std::runtime_error(std::string("unknown spec char: ") + c);
96            }
97            mtmd_bitmap_set_mergeable(bm, c != 'i');
98            pool.emplace_back(bm);
99            parts.push_back({ "", bm });
100        }
101        return parts;
102    };
103
104    // { parts, n_merge, expected size of each group }
105    const std::vector<std::tuple<std::string, int, std::string>> cases = {
106        { "vv",   2, "2"    },
107        { "vvv",  2, "21"   },
108        { "vvvv", 2, "22"   },
109        { "vvi",  2, "21"   },
110        { "tvvt", 2, "2"    },
111        { "vtv",  2, "11"   }, // text in between breaks the merge
112        { "vw",   2, "11"   }, // different sizes cannot be merged
113        { "aa",   2, "11"   }, // audio is never merged
114        { "ii",   2, "11"   }, // two unrelated images must stay separated
115        { "iv",   2, "11"   },
116        { "vi",   2, "11"   },
117        { "vv",   1, "11"   }, // model without temporal merge
118    };
119
120    for (const auto & [spec, n_merge, expected] : cases) {
121        auto parts  = make_parts(spec);
122        auto groups = mtmd_group_mergeable_bitmaps(parts, n_merge);
123
124        std::string actual;
125        for (const auto & group : groups) {
126            actual += std::to_string(group.size());
127        }
128
129        const std::string name = "\"" + spec + "\" with n_merge=" + std::to_string(n_merge);
130        t.assert_equal("groups for " + name, expected, actual);
131
132        size_t n_bitmap_parts = 0;
133        for (const auto & p : parts) {
134            n_bitmap_parts += p.bitmap != nullptr ? 1 : 0;
135        }
136        t.assert_equal("remaining bitmap parts for " + name, groups.size(), n_bitmap_parts);
137    }
138}
139
140//
141// main
142//
143
144int main(int argc, char ** argv) {
145    testing t(std::cout);
146    t.verbose = true;
147
148    // usage: test-mtmd-impl [filter_regex]
149    for (int i = 1; i < argc; i++) {
150        t.set_filter(argv[i]);
151    }
152
153    for (const auto & e : test_registry::all()) {
154        t.test(e.name, e.fn);
155    }
156
157    return t.summary();
158}