| 1 | #include "ggml.h" |
| 2 | #include "gguf.h" |
| 3 | |
| 4 | #include <cstdio> |
| 5 | #include <string> |
| 6 | #include <sstream> |
| 7 | #include <vector> |
| 8 | |
| 9 | #undef MIN |
| 10 | #undef MAX |
| 11 | #define MIN(a, b) ((a) < (b) ? (a) : (b)) |
| 12 | #define MAX(a, b) ((a) > (b) ? (a) : (b)) |
| 13 | |
| 14 | template <typename T> |
| 15 | static std::string to_string(const T & val) { |
| 16 | std::stringstream ss; |
| 17 | ss << val; |
| 18 | return ss.str(); |
| 19 | } |
| 20 | |
| 21 | static bool gguf_ex_write(const std::string & fname) { |
| 22 | struct gguf_context * ctx = gguf_init_empty(); |
| 23 | |
| 24 | gguf_set_val_u8 (ctx, key: "some.parameter.uint8" , val: 0x12); |
| 25 | gguf_set_val_i8 (ctx, key: "some.parameter.int8" , val: -0x13); |
| 26 | gguf_set_val_u16 (ctx, key: "some.parameter.uint16" , val: 0x1234); |
| 27 | gguf_set_val_i16 (ctx, key: "some.parameter.int16" , val: -0x1235); |
| 28 | gguf_set_val_u32 (ctx, key: "some.parameter.uint32" , val: 0x12345678); |
| 29 | gguf_set_val_i32 (ctx, key: "some.parameter.int32" , val: -0x12345679); |
| 30 | gguf_set_val_f32 (ctx, key: "some.parameter.float32" , val: 0.123456789f); |
| 31 | gguf_set_val_u64 (ctx, key: "some.parameter.uint64" , val: 0x123456789abcdef0ull); |
| 32 | gguf_set_val_i64 (ctx, key: "some.parameter.int64" , val: -0x123456789abcdef1ll); |
| 33 | gguf_set_val_f64 (ctx, key: "some.parameter.float64" , val: 0.1234567890123456789); |
| 34 | gguf_set_val_bool(ctx, key: "some.parameter.bool" , val: true); |
| 35 | gguf_set_val_str (ctx, key: "some.parameter.string" , val: "hello world" ); |
| 36 | |
| 37 | gguf_set_arr_data(ctx, key: "some.parameter.arr.i16" , type: GGUF_TYPE_INT16, data: std::vector<int16_t>{ 1, 2, 3, 4, }.data(), n: 4); |
| 38 | gguf_set_arr_data(ctx, key: "some.parameter.arr.f32" , type: GGUF_TYPE_FLOAT32, data: std::vector<float>{ 3.145f, 2.718f, 1.414f, }.data(), n: 3); |
| 39 | gguf_set_arr_str (ctx, key: "some.parameter.arr.str" , data: std::vector<const char *>{ "hello" , "world" , "!" }.data(), n: 3); |
| 40 | |
| 41 | struct ggml_init_params params = { |
| 42 | /*.mem_size =*/ 128ull*1024ull*1024ull, |
| 43 | /*.mem_buffer =*/ NULL, |
| 44 | /*.no_alloc =*/ false, |
| 45 | }; |
| 46 | |
| 47 | struct ggml_context * ctx_data = ggml_init(params); |
| 48 | |
| 49 | const int n_tensors = 10; |
| 50 | |
| 51 | // tensor infos |
| 52 | for (int i = 0; i < n_tensors; ++i) { |
| 53 | const std::string name = "tensor_" + to_string(val: i); |
| 54 | |
| 55 | int64_t ne[GGML_MAX_DIMS] = { 1 }; |
| 56 | int32_t n_dims = rand() % GGML_MAX_DIMS + 1; |
| 57 | |
| 58 | for (int j = 0; j < n_dims; ++j) { |
| 59 | ne[j] = rand() % 10 + 1; |
| 60 | } |
| 61 | |
| 62 | struct ggml_tensor * cur = ggml_new_tensor(ctx: ctx_data, type: GGML_TYPE_F32, n_dims, ne); |
| 63 | ggml_set_name(tensor: cur, name: name.c_str()); |
| 64 | |
| 65 | { |
| 66 | float * data = (float *) cur->data; |
| 67 | for (int j = 0; j < ggml_nelements(tensor: cur); ++j) { |
| 68 | data[j] = 100 + i; |
| 69 | } |
| 70 | } |
| 71 | |
| 72 | gguf_add_tensor(ctx, tensor: cur); |
| 73 | } |
| 74 | |
| 75 | gguf_write_to_file(ctx, fname: fname.c_str(), only_meta: false); |
| 76 | |
| 77 | printf(format: "%s: wrote file '%s;\n" , __func__, fname.c_str()); |
| 78 | |
| 79 | ggml_free(ctx: ctx_data); |
| 80 | gguf_free(ctx); |
| 81 | |
| 82 | return true; |
| 83 | } |
| 84 | |
| 85 | // just read tensor info |
| 86 | static bool gguf_ex_read_0(const std::string & fname) { |
| 87 | struct gguf_init_params params = { |
| 88 | /*.no_alloc = */ false, |
| 89 | /*.ctx = */ NULL, |
| 90 | }; |
| 91 | |
| 92 | struct gguf_context * ctx = gguf_init_from_file(fname: fname.c_str(), params); |
| 93 | |
| 94 | if (!ctx) { |
| 95 | fprintf(stderr, format: "%s: failed to load '%s'\n" , __func__, fname.c_str()); |
| 96 | return false; |
| 97 | } |
| 98 | |
| 99 | printf(format: "%s: version: %d\n" , __func__, gguf_get_version(ctx)); |
| 100 | printf(format: "%s: alignment: %zu\n" , __func__, gguf_get_alignment(ctx)); |
| 101 | printf(format: "%s: data offset: %zu\n" , __func__, gguf_get_data_offset(ctx)); |
| 102 | |
| 103 | // kv |
| 104 | { |
| 105 | const int n_kv = gguf_get_n_kv(ctx); |
| 106 | |
| 107 | printf(format: "%s: n_kv: %d\n" , __func__, n_kv); |
| 108 | |
| 109 | for (int i = 0; i < n_kv; ++i) { |
| 110 | const char * key = gguf_get_key(ctx, key_id: i); |
| 111 | |
| 112 | printf(format: "%s: kv[%d]: key = %s\n" , __func__, i, key); |
| 113 | } |
| 114 | } |
| 115 | |
| 116 | // find kv string |
| 117 | { |
| 118 | const char * findkey = "some.parameter.string" ; |
| 119 | |
| 120 | const int keyidx = gguf_find_key(ctx, key: findkey); |
| 121 | if (keyidx == -1) { |
| 122 | printf(format: "%s: find key: %s not found.\n" , __func__, findkey); |
| 123 | } else { |
| 124 | const char * key_value = gguf_get_val_str(ctx, key_id: keyidx); |
| 125 | printf(format: "%s: find key: %s found, kv[%d] value = %s\n" , __func__, findkey, keyidx, key_value); |
| 126 | } |
| 127 | } |
| 128 | |
| 129 | // tensor info |
| 130 | { |
| 131 | const int n_tensors = gguf_get_n_tensors(ctx); |
| 132 | |
| 133 | printf(format: "%s: n_tensors: %d\n" , __func__, n_tensors); |
| 134 | |
| 135 | for (int i = 0; i < n_tensors; ++i) { |
| 136 | const char * name = gguf_get_tensor_name (ctx, tensor_id: i); |
| 137 | const size_t size = gguf_get_tensor_size (ctx, tensor_id: i); |
| 138 | const size_t offset = gguf_get_tensor_offset(ctx, tensor_id: i); |
| 139 | |
| 140 | printf(format: "%s: tensor[%d]: name = %s, size = %zu, offset = %zu\n" , __func__, i, name, size, offset); |
| 141 | } |
| 142 | } |
| 143 | |
| 144 | gguf_free(ctx); |
| 145 | |
| 146 | return true; |
| 147 | } |
| 148 | |
| 149 | // read and create ggml_context containing the tensors and their data |
| 150 | static bool gguf_ex_read_1(const std::string & fname, bool check_data) { |
| 151 | struct ggml_context * ctx_data = NULL; |
| 152 | |
| 153 | struct gguf_init_params params = { |
| 154 | /*.no_alloc = */ false, |
| 155 | /*.ctx = */ &ctx_data, |
| 156 | }; |
| 157 | |
| 158 | struct gguf_context * ctx = gguf_init_from_file(fname: fname.c_str(), params); |
| 159 | |
| 160 | printf(format: "%s: version: %d\n" , __func__, gguf_get_version(ctx)); |
| 161 | printf(format: "%s: alignment: %zu\n" , __func__, gguf_get_alignment(ctx)); |
| 162 | printf(format: "%s: data offset: %zu\n" , __func__, gguf_get_data_offset(ctx)); |
| 163 | |
| 164 | // kv |
| 165 | { |
| 166 | const int n_kv = gguf_get_n_kv(ctx); |
| 167 | |
| 168 | printf(format: "%s: n_kv: %d\n" , __func__, n_kv); |
| 169 | |
| 170 | for (int i = 0; i < n_kv; ++i) { |
| 171 | const char * key = gguf_get_key(ctx, key_id: i); |
| 172 | |
| 173 | printf(format: "%s: kv[%d]: key = %s\n" , __func__, i, key); |
| 174 | } |
| 175 | } |
| 176 | |
| 177 | // tensor info |
| 178 | { |
| 179 | const int n_tensors = gguf_get_n_tensors(ctx); |
| 180 | |
| 181 | printf(format: "%s: n_tensors: %d\n" , __func__, n_tensors); |
| 182 | |
| 183 | for (int i = 0; i < n_tensors; ++i) { |
| 184 | const char * name = gguf_get_tensor_name (ctx, tensor_id: i); |
| 185 | const size_t size = gguf_get_tensor_size (ctx, tensor_id: i); |
| 186 | const size_t offset = gguf_get_tensor_offset(ctx, tensor_id: i); |
| 187 | const auto type = gguf_get_tensor_type (ctx, tensor_id: i); |
| 188 | |
| 189 | const char * type_name = ggml_type_name(type); |
| 190 | const size_t type_size = ggml_type_size(type); |
| 191 | const size_t n_elements = size / type_size; |
| 192 | |
| 193 | printf(format: "%s: tensor[%d]: name = %s, size = %zu, offset = %zu, type = %s, n_elts = %zu\n" , __func__, i, name, size, offset, type_name, n_elements); |
| 194 | } |
| 195 | } |
| 196 | |
| 197 | // data |
| 198 | { |
| 199 | const int n_tensors = gguf_get_n_tensors(ctx); |
| 200 | |
| 201 | for (int i = 0; i < n_tensors; ++i) { |
| 202 | printf(format: "%s: reading tensor %d data\n" , __func__, i); |
| 203 | |
| 204 | const char * name = gguf_get_tensor_name(ctx, tensor_id: i); |
| 205 | |
| 206 | struct ggml_tensor * cur = ggml_get_tensor(ctx: ctx_data, name); |
| 207 | |
| 208 | printf(format: "%s: tensor[%d]: n_dims = %d, ne = (%d, %d, %d, %d), name = %s, data = %p\n" , |
| 209 | __func__, i, ggml_n_dims(tensor: cur), int(cur->ne[0]), int(cur->ne[1]), int(cur->ne[2]), int(cur->ne[3]), cur->name, cur->data); |
| 210 | |
| 211 | // print first 10 elements |
| 212 | const float * data = (const float *) cur->data; |
| 213 | |
| 214 | printf(format: "%s data[:10] : " , name); |
| 215 | for (int j = 0; j < MIN(10, ggml_nelements(cur)); ++j) { |
| 216 | printf(format: "%f " , data[j]); |
| 217 | } |
| 218 | printf(format: "\n\n" ); |
| 219 | |
| 220 | // check data |
| 221 | if (check_data) { |
| 222 | const float * data = (const float *) cur->data; |
| 223 | for (int j = 0; j < ggml_nelements(tensor: cur); ++j) { |
| 224 | if (data[j] != 100 + i) { |
| 225 | fprintf(stderr, format: "%s: tensor[%d], data[%d]: found %f, expected %f\n" , __func__, i, j, data[j], float(100 + i)); |
| 226 | gguf_free(ctx); |
| 227 | return false; |
| 228 | } |
| 229 | } |
| 230 | } |
| 231 | } |
| 232 | } |
| 233 | |
| 234 | printf(format: "%s: ctx_data size: %zu\n" , __func__, ggml_get_mem_size(ctx: ctx_data)); |
| 235 | |
| 236 | ggml_free(ctx: ctx_data); |
| 237 | gguf_free(ctx); |
| 238 | |
| 239 | return true; |
| 240 | } |
| 241 | |
| 242 | int main(int argc, char ** argv) { |
| 243 | if (argc < 3) { |
| 244 | printf(format: "usage: %s data.gguf r|w [n]\n" , argv[0]); |
| 245 | printf(format: "r: read data.gguf file\n" ); |
| 246 | printf(format: "w: write data.gguf file\n" ); |
| 247 | printf(format: "n: no check of tensor data\n" ); |
| 248 | return -1; |
| 249 | } |
| 250 | bool check_data = true; |
| 251 | if (argc == 4) { |
| 252 | check_data = false; |
| 253 | } |
| 254 | |
| 255 | srand(seed: 123456); |
| 256 | |
| 257 | const std::string fname(argv[1]); |
| 258 | const std::string mode (argv[2]); |
| 259 | |
| 260 | GGML_ASSERT((mode == "r" || mode == "w" ) && "mode must be r or w" ); |
| 261 | |
| 262 | if (mode == "w" ) { |
| 263 | GGML_ASSERT(gguf_ex_write(fname) && "failed to write gguf file" ); |
| 264 | } else if (mode == "r" ) { |
| 265 | GGML_ASSERT(gguf_ex_read_0(fname) && "failed to read gguf file" ); |
| 266 | GGML_ASSERT(gguf_ex_read_1(fname, check_data) && "failed to read gguf file" ); |
| 267 | } |
| 268 | |
| 269 | return 0; |
| 270 | } |
| 271 | |