char-fork/llama.cpp

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

DevVexusconvert : write explicit recurrent_layers for Qwen3-Next / Qwen3.5 (#28208)9a7570587

char/aliceai-t5-moe
68.8 KiB1634 linesraw
1from __future__ import annotations
2
3import logging
4import os
5import shutil
6import struct
7import sys
8import tempfile
9from dataclasses import dataclass
10from enum import Enum, auto
11from math import prod
12from pathlib import Path
13from io import BufferedWriter
14from typing import IO, Any, Sequence, Mapping
15from string import ascii_letters, digits
16
17import numpy as np
18
19from .constants import (
20    GGUF_DEFAULT_ALIGNMENT,
21    GGUF_MAGIC,
22    GGUF_VERSION,
23    GGMLQuantizationType,
24    GGUFEndian,
25    GGUFValueType,
26    Keys,
27    RopeScalingType,
28    PoolingType,
29    TokenType,
30    ExpertGatingFuncType,
31)
32
33from .quants import quant_shape_from_byte_shape
34
35logger = logging.getLogger(__name__)
36
37
38SHARD_NAME_FORMAT = "{:s}-{:05d}-of-{:05d}.gguf"
39
40
41@dataclass
42class TensorInfo:
43    shape: Sequence[int]
44    dtype: GGMLQuantizationType
45    nbytes: int
46    tensor: np.ndarray[Any, Any] | None = None
47
48
49@dataclass
50class GGUFValue:
51    value: Any
52    type: GGUFValueType
53    sub_type: GGUFValueType | None = None
54
55
56class WriterState(Enum):
57    NO_FILE = auto()
58    EMPTY   = auto()
59    HEADER  = auto()
60    KV_DATA = auto()
61    TI_DATA = auto()
62    WEIGHTS = auto()
63
64
65class GGUFWriter:
66    fout: list[BufferedWriter] | None
67    path: Path | None
68    temp_file: tempfile.SpooledTemporaryFile[bytes] | None
69    tensors: list[dict[str, TensorInfo]]
70    kv_data: list[dict[str, GGUFValue]]
71    state: WriterState
72    _simple_value_packing = {
73        GGUFValueType.UINT8:   "B",
74        GGUFValueType.INT8:    "b",
75        GGUFValueType.UINT16:  "H",
76        GGUFValueType.INT16:   "h",
77        GGUFValueType.UINT32:  "I",
78        GGUFValueType.INT32:   "i",
79        GGUFValueType.FLOAT32: "f",
80        GGUFValueType.UINT64:  "Q",
81        GGUFValueType.INT64:   "q",
82        GGUFValueType.FLOAT64: "d",
83        GGUFValueType.BOOL:    "?",
84    }
85
86    def __init__(
87        self, path: os.PathLike[str] | str | None, arch: str, use_temp_file: bool = False, endianess: GGUFEndian = GGUFEndian.LITTLE,
88        split_max_tensors: int = 0, split_max_size: int = 0, dry_run: bool = False, small_first_shard: bool = False
89    ):
90        self.fout = None
91        self.path = Path(path) if path else None
92        self.arch = arch
93        self.endianess = endianess
94        self.data_alignment = GGUF_DEFAULT_ALIGNMENT
95        self.use_temp_file = use_temp_file
96        self.temp_file = None
97        self.tensors = [{}]
98        self.kv_data = [{}]
99        self.split_max_tensors = split_max_tensors
100        self.split_max_size = split_max_size
101        self.dry_run = dry_run
102        self.small_first_shard = small_first_shard
103        logger.info("gguf: This GGUF file is for {0} Endian only".format(
104            "Big" if self.endianess == GGUFEndian.BIG else "Little",
105        ))
106        self.state = WriterState.NO_FILE
107
108        if self.small_first_shard:
109            self.tensors.append({})
110
111        self.add_architecture()
112
113    def get_total_parameter_count(self) -> tuple[int, int, int, int]:
114        total_params = 0
115        shared_params = 0
116        expert_params = 0
117
118        expert_sum = 0
119        n_expert_tensors = 0
120
121        last_lora_a: tuple[str, TensorInfo] | None = None
122
123        for tensors in self.tensors:
124            for name, info in tensors.items():
125
126                shape = info.shape
127
128                if name.endswith(".lora_a"):
129                    last_lora_a = (name, info)
130                    continue
131                elif name.endswith(".lora_b"):
132                    if last_lora_a is None or last_lora_a[0] != name[:-1] + "a":
133                        # Bail when the LoRA pair can't be found trivially
134                        logger.warning("can't measure LoRA size correctly, tensor order is unusual")
135                        return 0, 0, 0, 0
136                    else:
137                        shape = (*shape[:-1], last_lora_a[1].shape[-1])
138
139                size = prod(shape)
140
141                if "_exps." in name:
142                    if len(shape) >= 3:
143                        expert_count = shape[-2 if ".bias" in name else -3]
144                        expert_params += (size // expert_count)
145                        expert_sum += expert_count
146                        n_expert_tensors += 1
147                    else:
148                        shared_params += size
149                else:
150                    shared_params += size
151
152                total_params += size
153
154        # Hopefully this should work even for variable-expert-count models
155        expert_count = (expert_sum // n_expert_tensors) if n_expert_tensors > 0 else 0
156
157        # Negate the total to signal it's likely not exact
158        if last_lora_a is not None:
159            total_params = -total_params
160
161        # NOTE: keep the output in the same order as accepted by 'size_label' in gguf-py/gguf/utility.py
162        return total_params, shared_params, expert_params, expert_count
163
164    def format_shard_names(self, path: Path) -> list[Path]:
165        if len(self.tensors) == 1:
166            return [path]
167        return [path.with_name(SHARD_NAME_FORMAT.format(path.stem, i + 1, len(self.tensors))) for i in range(len(self.tensors))]
168
169    def open_output_file(self, path: Path | None = None) -> None:
170        if self.state is WriterState.EMPTY and self.fout is not None and (path is None or path == self.path):
171            # allow calling this multiple times as long as the path is the same
172            return
173
174        if self.state is not WriterState.NO_FILE:
175            raise ValueError(f'Expected output file to be not yet opened, got {self.state}')
176
177        if path is not None:
178            self.path = path
179
180        if self.path is not None:
181            filenames = self.print_plan()
182            self.fout = [open(filename, "wb") for filename in filenames]
183            self.state = WriterState.EMPTY
184
185    def print_plan(self) -> list[Path]:
186        logger.info("Writing the following files:")
187        assert self.path is not None
188        filenames = self.format_shard_names(self.path)
189        assert len(filenames) == len(self.tensors)
190        for name, tensors in zip(filenames, self.tensors):
191            logger.info(f"{name}: n_tensors = {len(tensors)}, total_size = {GGUFWriter.format_n_bytes_to_str(sum(ti.nbytes for ti in tensors.values()))}")
192
193        if self.dry_run:
194            logger.info("Dry run, not writing files")
195            for name in filenames:
196                print(name)  # noqa: NP100
197            exit()
198
199        return filenames
200
201    def add_shard_kv_data(self) -> None:
202        if len(self.tensors) == 1:
203            return
204
205        total_tensors = sum(len(t) for t in self.tensors)
206        assert self.fout is not None
207        total_splits = len(self.fout)
208        self.kv_data.extend({} for _ in range(len(self.kv_data), total_splits))
209        for i, kv_data in enumerate(self.kv_data):
210            kv_data[Keys.Split.LLM_KV_SPLIT_NO] = GGUFValue(i, GGUFValueType.UINT16)
211            kv_data[Keys.Split.LLM_KV_SPLIT_COUNT] = GGUFValue(total_splits, GGUFValueType.UINT16)
212            kv_data[Keys.Split.LLM_KV_SPLIT_TENSORS_COUNT] = GGUFValue(total_tensors, GGUFValueType.INT32)
213
214    def write_header_to_file(self, path: Path | None = None) -> None:
215        if len(self.tensors) == 1 and (self.split_max_tensors != 0 or self.split_max_size != 0):
216            logger.warning("Model fails split requirements, not splitting")
217
218        self.open_output_file(path)
219
220        if self.state is not WriterState.EMPTY:
221            raise ValueError(f'Expected output file to be empty, got {self.state}')
222
223        assert self.fout is not None
224        assert len(self.fout) == len(self.tensors)
225        assert len(self.kv_data) == 1
226
227        self.add_shard_kv_data()
228
229        for fout, tensors, kv_data in zip(self.fout, self.tensors, self.kv_data):
230            fout.write(self._pack("<I", GGUF_MAGIC, skip_pack_prefix = True))
231            fout.write(self._pack("I", GGUF_VERSION))
232            fout.write(self._pack("Q", len(tensors)))
233            fout.write(self._pack("Q", len(kv_data)))
234            fout.flush()
235        self.state = WriterState.HEADER
236
237    def write_kv_data_to_file(self) -> None:
238        if self.state is not WriterState.HEADER:
239            raise ValueError(f'Expected output file to contain the header, got {self.state}')
240        assert self.fout is not None
241
242        for fout, kv_data in zip(self.fout, self.kv_data):
243            kv_bytes = bytearray()
244
245            for key, val in kv_data.items():
246                kv_bytes += self._pack_val(key, GGUFValueType.STRING, add_vtype=False)
247                kv_bytes += self._pack_val(val.value, val.type, add_vtype=True, sub_type=val.sub_type)
248
249            fout.write(kv_bytes)
250
251        self.flush()
252        self.state = WriterState.KV_DATA
253
254    def write_ti_data_to_file(self) -> None:
255        if self.state is not WriterState.KV_DATA:
256            raise ValueError(f'Expected output file to contain KV data, got {self.state}')
257        assert self.fout is not None
258
259        for fout, tensors in zip(self.fout, self.tensors):
260            ti_data = bytearray()
261            offset_tensor = 0
262
263            for name, ti in tensors.items():
264                ti_data += self._pack_val(name, GGUFValueType.STRING, add_vtype=False)
265                n_dims = len(ti.shape)
266                ti_data += self._pack("I", n_dims)
267                for j in range(n_dims):
268                    ti_data += self._pack("Q", ti.shape[n_dims - 1 - j])
269                ti_data += self._pack("I", ti.dtype)
270                ti_data += self._pack("Q", offset_tensor)
271                offset_tensor += GGUFWriter.ggml_pad(ti.nbytes, self.data_alignment)
272
273            fout.write(ti_data)
274            fout.flush()
275        self.state = WriterState.TI_DATA
276
277    def add_key_value(self, key: str, val: Any, vtype: GGUFValueType, sub_type: GGUFValueType | None = None) -> None:
278        if any(key in kv_data for kv_data in self.kv_data):
279            logger.warning(f'Duplicated key name {key!r}, overwriting it with new value {val!r} of type {vtype.name}')
280
281        self.kv_data[0][key] = GGUFValue(value=val, type=vtype, sub_type=sub_type)
282
283    def remove_key(self, key: str) -> None:
284        for kv_data in self.kv_data:
285            kv_data.pop(key, None)
286
287    def add_uint8(self, key: str, val: int) -> None:
288        self.add_key_value(key,val, GGUFValueType.UINT8)
289
290    def add_int8(self, key: str, val: int) -> None:
291        self.add_key_value(key, val, GGUFValueType.INT8)
292
293    def add_uint16(self, key: str, val: int) -> None:
294        self.add_key_value(key, val, GGUFValueType.UINT16)
295
296    def add_int16(self, key: str, val: int) -> None:
297        self.add_key_value(key, val, GGUFValueType.INT16)
298
299    def add_uint32(self, key: str, val: int) -> None:
300        self.add_key_value(key, val, GGUFValueType.UINT32)
301
302    def add_int32(self, key: str, val: int) -> None:
303        self.add_key_value(key, val, GGUFValueType.INT32)
304
305    def add_float32(self, key: str, val: float) -> None:
306        self.add_key_value(key, val, GGUFValueType.FLOAT32)
307
308    def add_uint64(self, key: str, val: int) -> None:
309        self.add_key_value(key, val, GGUFValueType.UINT64)
310
311    def add_int64(self, key: str, val: int) -> None:
312        self.add_key_value(key, val, GGUFValueType.INT64)
313
314    def add_float64(self, key: str, val: float) -> None:
315        self.add_key_value(key, val, GGUFValueType.FLOAT64)
316
317    def add_bool(self, key: str, val: bool) -> None:
318        self.add_key_value(key, val, GGUFValueType.BOOL)
319
320    def add_string(self, key: str, val: str) -> None:
321        if not val:
322            return
323        self.add_key_value(key, val, GGUFValueType.STRING)
324
325    def add_array(self, key: str, val: Sequence[Any]) -> None:
326        if len(val) == 0:
327            return
328        self.add_key_value(key, val, GGUFValueType.ARRAY)
329
330    @staticmethod
331    def ggml_pad(x: int, n: int) -> int:
332        return ((x + n - 1) // n) * n
333
334    def add_tensor_info(
335        self, name: str, tensor_shape: Sequence[int], tensor_dtype: np.dtype,
336        tensor_nbytes: int, raw_dtype: GGMLQuantizationType | None = None,
337    ) -> None:
338        if self.state is not WriterState.NO_FILE:
339            raise ValueError(f'Expected output file to be not yet opened, got {self.state}')
340
341        if any(name in tensors for tensors in self.tensors):
342            raise ValueError(f'Duplicated tensor name {name!r}')
343
344        if raw_dtype is None:
345            if tensor_dtype == np.float16:
346                dtype = GGMLQuantizationType.F16
347            elif tensor_dtype == np.float32:
348                dtype = GGMLQuantizationType.F32
349            elif tensor_dtype == np.float64:
350                dtype = GGMLQuantizationType.F64
351            elif tensor_dtype == np.int8:
352                dtype = GGMLQuantizationType.I8
353            elif tensor_dtype == np.int16:
354                dtype = GGMLQuantizationType.I16
355            elif tensor_dtype == np.int32:
356                dtype = GGMLQuantizationType.I32
357            elif tensor_dtype == np.int64:
358                dtype = GGMLQuantizationType.I64
359            else:
360                raise ValueError("Only F16, F32, F64, I8, I16, I32, I64 tensors are supported for now")
361        else:
362            dtype = raw_dtype
363            if tensor_dtype == np.uint8:
364                tensor_shape = quant_shape_from_byte_shape(tensor_shape, raw_dtype)
365
366        # make sure there is at least one tensor before splitting
367        if len(self.tensors[-1]) > 0:
368            if (  # split when over tensor limit
369                self.split_max_tensors != 0
370                and len(self.tensors[-1]) >= self.split_max_tensors
371            ) or (   # split when over size limit
372                self.split_max_size != 0
373                and sum(ti.nbytes for ti in self.tensors[-1].values()) + tensor_nbytes > self.split_max_size
374            ):
375                self.tensors.append({})
376
377        self.tensors[-1][name] = TensorInfo(shape=tensor_shape, dtype=dtype, nbytes=tensor_nbytes)
378
379    def add_tensor(
380        self, name: str, tensor: np.ndarray[Any, Any], raw_shape: Sequence[int] | None = None,
381        raw_dtype: GGMLQuantizationType | None = None, tensor_endianess: GGUFEndian | None = None
382    ) -> None:
383        # if tensor endianness is not passed, assume it's native to system
384        if tensor_endianess is None:
385            tensor_endianess = GGUFEndian.BIG if sys.byteorder == 'big' else GGUFEndian.LITTLE
386
387        if tensor_endianess != self.endianess:
388            # Don't byteswap inplace since lazy copies cannot handle it
389            tensor = tensor.byteswap(inplace=False)
390        if self.use_temp_file and self.temp_file is None:
391            fp = tempfile.SpooledTemporaryFile(mode="w+b", max_size=256 * 1024 * 1024)
392            fp.seek(0)
393            self.temp_file = fp
394
395        shape: Sequence[int] = raw_shape if raw_shape is not None else tensor.shape
396        self.add_tensor_info(name, shape, tensor.dtype, tensor.nbytes, raw_dtype=raw_dtype)
397
398        if self.temp_file is None:
399            self.tensors[-1][name].tensor = tensor
400            return
401
402        tensor.tofile(self.temp_file)
403        self.write_padding(self.temp_file, tensor.nbytes)
404
405    def write_padding(self, fp: IO[bytes], n: int, align: int | None = None) -> None:
406        pad = GGUFWriter.ggml_pad(n, align if align is not None else self.data_alignment) - n
407        if pad != 0:
408            fp.write(bytes([0] * pad))
409
410    def write_tensor_data(self, tensor: np.ndarray[Any, Any], tensor_endianess: GGUFEndian | None = None) -> None:
411        if self.state is not WriterState.TI_DATA and self.state is not WriterState.WEIGHTS:
412            raise ValueError(f'Expected output file to contain tensor info or weights, got {self.state}')
413        assert self.fout is not None
414
415        # if tensor endianness is not passed, assume it's native to system
416        if tensor_endianess is None:
417            tensor_endianess = GGUFEndian.BIG if sys.byteorder == 'big' else GGUFEndian.LITTLE
418
419        if tensor_endianess != self.endianess:
420            # Don't byteswap inplace since lazy copies cannot handle it
421            tensor = tensor.byteswap(inplace=False)
422
423        file_id = -1
424        for i, tensors in enumerate(self.tensors):
425            if len(tensors) > 0:
426                file_id = i
427                break
428
429        fout = self.fout[file_id]
430
431        # pop the first tensor info
432        first_tensor_name = next(iter(self.tensors[file_id]))
433        ti = self.tensors[file_id].pop(first_tensor_name)
434        assert ti.nbytes == tensor.nbytes
435
436        self.write_padding(fout, fout.tell())
437        tensor.tofile(fout)
438        self.write_padding(fout, tensor.nbytes)
439
440        self.state = WriterState.WEIGHTS
441
442    def write_tensors_to_file(self, *, progress: bool = False) -> None:
443        self.write_ti_data_to_file()
444
445        assert self.fout is not None
446
447        for fout in self.fout:
448            self.write_padding(fout, fout.tell())
449
450        if self.temp_file is None:
451            shard_bar = None
452            bar = None
453
454            if progress:
455                from tqdm import tqdm
456
457                total_bytes = sum(ti.nbytes for t in self.tensors for ti in t.values())
458
459                if len(self.fout) > 1:
460                    shard_bar = tqdm(desc=f"Shard (0/{len(self.fout)})", total=None, unit="byte", unit_scale=True)
461                bar = tqdm(desc="Writing", total=total_bytes, unit="byte", unit_scale=True)
462
463            for i, (fout, tensors) in enumerate(zip(self.fout, self.tensors)):
464                if shard_bar is not None:
465                    shard_bar.set_description(f"Shard ({i + 1}/{len(self.fout)})")
466                    total = sum(ti.nbytes for ti in tensors.values())
467                    shard_bar.reset(total=(total if total > 0 else None))
468
469                # relying on the fact that Python dicts preserve insertion order (since 3.7)
470                for name, ti in tensors.items():
471                    assert ti.tensor is not None  # can only iterate once over the tensors
472                    assert ti.tensor.nbytes == ti.nbytes
473                    start = fout.tell()
474                    ti.tensor.tofile(fout)
475                    # a short write here would only surface as a corrupt file at load time
476                    if fout.tell() - start != ti.nbytes:
477                        raise ValueError(
478                            f"tensor {name!r} wrote {fout.tell() - start} bytes, expected {ti.nbytes}")
479                    if shard_bar is not None:
480                        shard_bar.update(ti.nbytes)
481                    if bar is not None:
482                        bar.update(ti.nbytes)
483                    self.write_padding(fout, ti.nbytes)
484                    ti.tensor = None
485        else:
486            self.temp_file.seek(0)
487
488            shutil.copyfileobj(self.temp_file, self.fout[0 if not self.small_first_shard else 1])
489            self.flush()
490            self.temp_file.close()
491
492        self.state = WriterState.WEIGHTS
493
494    def flush(self) -> None:
495        assert self.fout is not None
496        for fout in self.fout:
497            fout.flush()
498
499    def close(self) -> None:
500        if self.fout is not None:
501            for fout in self.fout:
502                fout.close()
503            self.fout = None
504
505    def add_type(self, type_name: str) -> None:
506        self.add_string(Keys.General.TYPE, type_name)
507
508    def add_architecture(self) -> None:
509        self.add_string(Keys.General.ARCHITECTURE, self.arch)
510
511    def add_quantization_version(self, quantization_version: int) -> None:
512        self.add_uint32(Keys.General.QUANTIZATION_VERSION, quantization_version)
513
514    def add_custom_alignment(self, alignment: int) -> None:
515        if alignment <= 0 or (alignment & (alignment - 1)) != 0:
516            raise ValueError('Invalid alignment: must be a non-zero power of two')
517        self.data_alignment = alignment
518        self.add_uint32(Keys.General.ALIGNMENT, alignment)
519
520    def add_file_type(self, ftype: int) -> None:
521        self.add_uint32(Keys.General.FILE_TYPE, ftype)
522
523    def add_sampling_sequence(self, sequence: str) -> None:
524        self.add_string(Keys.General.SAMPLING_SEQUENCE, sequence)
525
526    def add_sampling_top_k(self, top_k: int) -> None:
527        self.add_int32(Keys.General.SAMPLING_TOP_K, top_k)
528
529    def add_sampling_top_p(self, top_p: float) -> None:
530        self.add_float32(Keys.General.SAMPLING_TOP_P, top_p)
531
532    def add_sampling_min_p(self, min_p: float) -> None:
533        self.add_float32(Keys.General.SAMPLING_MIN_P, min_p)
534
535    def add_sampling_xtc_probability(self, xtc_probability: float) -> None:
536        self.add_float32(Keys.General.SAMPLING_XTC_PROBABILITY, xtc_probability)
537
538    def add_sampling_xtc_threshold(self, xtc_threshold: float) -> None:
539        self.add_float32(Keys.General.SAMPLING_XTC_THRESHOLD, xtc_threshold)
540
541    def add_sampling_temp(self, temp: float) -> None:
542        self.add_float32(Keys.General.SAMPLING_TEMP, temp)
543
544    def add_sampling_penalty_last_n(self, penalty_last_n: int) -> None:
545        self.add_int32(Keys.General.SAMPLING_PENALTY_LAST_N, penalty_last_n)
546
547    def add_sampling_penalty_repeat(self, penalty_repeat: float) -> None:
548        self.add_float32(Keys.General.SAMPLING_PENALTY_REPEAT, penalty_repeat)
549
550    def add_sampling_mirostat(self, mirostat: int) -> None:
551        self.add_int32(Keys.General.SAMPLING_MIROSTAT, mirostat)
552
553    def add_sampling_mirostat_tau(self, mirostat_tau: float) -> None:
554        self.add_float32(Keys.General.SAMPLING_MIROSTAT_TAU, mirostat_tau)
555
556    def add_sampling_mirostat_eta(self, mirostat_eta: float) -> None:
557        self.add_float32(Keys.General.SAMPLING_MIROSTAT_ETA, mirostat_eta)
558
559    def add_name(self, name: str) -> None:
560        self.add_string(Keys.General.NAME, name)
561
562    def add_author(self, author: str) -> None:
563        self.add_string(Keys.General.AUTHOR, author)
564
565    def add_version(self, version: str) -> None:
566        self.add_string(Keys.General.VERSION, version)
567
568    def add_organization(self, organization: str) -> None:
569        self.add_string(Keys.General.ORGANIZATION, organization)
570
571    def add_finetune(self, finetune: str) -> None:
572        self.add_string(Keys.General.FINETUNE, finetune)
573
574    def add_basename(self, basename: str) -> None:
575        self.add_string(Keys.General.BASENAME, basename)
576
577    def add_description(self, description: str) -> None:
578        self.add_string(Keys.General.DESCRIPTION, description)
579
580    def add_quantized_by(self, quantized: str) -> None:
581        self.add_string(Keys.General.QUANTIZED_BY, quantized)
582
583    def add_size_label(self, size_label: str) -> None:
584        self.add_string(Keys.General.SIZE_LABEL, size_label)
585
586    def add_license(self, license: str) -> None:
587        self.add_string(Keys.General.LICENSE, license)
588
589    def add_license_name(self, license: str) -> None:
590        self.add_string(Keys.General.LICENSE_NAME, license)
591
592    def add_license_link(self, license: str) -> None:
593        self.add_string(Keys.General.LICENSE_LINK, license)
594
595    def add_url(self, url: str) -> None:
596        self.add_string(Keys.General.URL, url)
597
598    def add_doi(self, doi: str) -> None:
599        self.add_string(Keys.General.DOI, doi)
600
601    def add_uuid(self, uuid: str) -> None:
602        self.add_string(Keys.General.UUID, uuid)
603
604    def add_repo_url(self, repo_url: str) -> None:
605        self.add_string(Keys.General.REPO_URL, repo_url)
606
607    def add_source_url(self, url: str) -> None:
608        self.add_string(Keys.General.SOURCE_URL, url)
609
610    def add_source_doi(self, doi: str) -> None:
611        self.add_string(Keys.General.SOURCE_DOI, doi)
612
613    def add_source_uuid(self, uuid: str) -> None:
614        self.add_string(Keys.General.SOURCE_UUID, uuid)
615
616    def add_source_repo_url(self, repo_url: str) -> None:
617        self.add_string(Keys.General.SOURCE_REPO_URL, repo_url)
618
619    def add_base_model_count(self, source_count: int) -> None:
620        self.add_uint32(Keys.General.BASE_MODEL_COUNT, source_count)
621
622    def add_base_model_name(self, source_id: int, name: str) -> None:
623        self.add_string(Keys.General.BASE_MODEL_NAME.format(id=source_id), name)
624
625    def add_base_model_author(self, source_id: int, author: str) -> None:
626        self.add_string(Keys.General.BASE_MODEL_AUTHOR.format(id=source_id), author)
627
628    def add_base_model_version(self, source_id: int, version: str) -> None:
629        self.add_string(Keys.General.BASE_MODEL_VERSION.format(id=source_id), version)
630
631    def add_base_model_organization(self, source_id: int, organization: str) -> None:
632        self.add_string(Keys.General.BASE_MODEL_ORGANIZATION.format(id=source_id), organization)
633
634    def add_base_model_description(self, source_id: int, description: str) -> None:
635        self.add_string(Keys.General.BASE_MODEL_DESCRIPTION.format(id=source_id), description)
636
637    def add_base_model_url(self, source_id: int, url: str) -> None:
638        self.add_string(Keys.General.BASE_MODEL_URL.format(id=source_id), url)
639
640    def add_base_model_doi(self, source_id: int, doi: str) -> None:
641        self.add_string(Keys.General.BASE_MODEL_DOI.format(id=source_id), doi)
642
643    def add_base_model_uuid(self, source_id: int, uuid: str) -> None:
644        self.add_string(Keys.General.BASE_MODEL_UUID.format(id=source_id), uuid)
645
646    def add_base_model_repo_url(self, source_id: int, repo_url: str) -> None:
647        self.add_string(Keys.General.BASE_MODEL_REPO_URL.format(id=source_id), repo_url)
648
649    def add_dataset_count(self, source_count: int) -> None:
650        self.add_uint32(Keys.General.DATASET_COUNT, source_count)
651
652    def add_dataset_name(self, source_id: int, name: str) -> None:
653        self.add_string(Keys.General.DATASET_NAME.format(id=source_id), name)
654
655    def add_dataset_author(self, source_id: int, author: str) -> None:
656        self.add_string(Keys.General.DATASET_AUTHOR.format(id=source_id), author)
657
658    def add_dataset_version(self, source_id: int, version: str) -> None:
659        self.add_string(Keys.General.DATASET_VERSION.format(id=source_id), version)
660
661    def add_dataset_organization(self, source_id: int, organization: str) -> None:
662        self.add_string(Keys.General.DATASET_ORGANIZATION.format(id=source_id), organization)
663
664    def add_dataset_description(self, source_id: int, description: str) -> None:
665        self.add_string(Keys.General.DATASET_DESCRIPTION.format(id=source_id), description)
666
667    def add_dataset_url(self, source_id: int, url: str) -> None:
668        self.add_string(Keys.General.DATASET_URL.format(id=source_id), url)
669
670    def add_dataset_doi(self, source_id: int, doi: str) -> None:
671        self.add_string(Keys.General.DATASET_DOI.format(id=source_id), doi)
672
673    def add_dataset_uuid(self, source_id: int, uuid: str) -> None:
674        self.add_string(Keys.General.DATASET_UUID.format(id=source_id), uuid)
675
676    def add_dataset_repo_url(self, source_id: int, repo_url: str) -> None:
677        self.add_string(Keys.General.DATASET_REPO_URL.format(id=source_id), repo_url)
678
679    def add_tags(self, tags: Sequence[str]) -> None:
680        self.add_array(Keys.General.TAGS, tags)
681
682    def add_languages(self, languages: Sequence[str]) -> None:
683        self.add_array(Keys.General.LANGUAGES, languages)
684
685    def add_tensor_data_layout(self, layout: str) -> None:
686        self.add_string(Keys.LLM.TENSOR_DATA_LAYOUT.format(arch=self.arch), layout)
687
688    def add_vocab_size(self, size: int) -> None:
689        self.add_uint32(Keys.LLM.VOCAB_SIZE.format(arch=self.arch), size)
690
691    def add_context_length(self, length: int) -> None:
692        self.add_uint32(Keys.LLM.CONTEXT_LENGTH.format(arch=self.arch), length)
693
694    def add_embedding_length(self, length: int) -> None:
695        self.add_uint32(Keys.LLM.EMBEDDING_LENGTH.format(arch=self.arch), length)
696
697    def add_embedding_length_out(self, length: int) -> None:
698        self.add_uint32(Keys.LLM.EMBEDDING_LENGTH_OUT.format(arch=self.arch), length)
699
700    def add_features_length(self, length: int) -> None:
701        self.add_uint32(Keys.LLM.FEATURES_LENGTH.format(arch=self.arch), length)
702
703    def add_posnet_embedding_length(self, length: int) -> None:
704        self.add_uint32(Keys.PosNet.EMBEDDING_LENGTH.format(arch=self.arch), length)
705
706    def add_posnet_block_count(self, length: int) -> None:
707        self.add_uint32(Keys.PosNet.BLOCK_COUNT.format(arch=self.arch), length)
708
709    def add_convnext_embedding_length(self, length: int) -> None:
710        self.add_uint32(Keys.ConvNext.EMBEDDING_LENGTH.format(arch=self.arch), length)
711
712    def add_convnext_block_count(self, length: int) -> None:
713        self.add_uint32(Keys.ConvNext.BLOCK_COUNT.format(arch=self.arch), length)
714
715    def add_shortconv_l_cache(self, length: int) -> None:
716        self.add_uint32(Keys.ShortConv.L_CACHE.format(arch=self.arch), length)
717
718    def add_block_count(self, length: int) -> None:
719        self.add_uint32(Keys.LLM.BLOCK_COUNT.format(arch=self.arch), length)
720
721    def add_leading_dense_block_count(self, length: int) -> None:
722        self.add_uint32(Keys.LLM.LEADING_DENSE_BLOCK_COUNT.format(arch=self.arch), length)
723
724    def add_full_attention_interval(self, interval: int) -> None:
725        self.add_uint32(Keys.LLM.FULL_ATTENTION_INTERVAL.format(arch=self.arch), interval)
726
727    def add_hash_layer_count(self, count: int) -> None:
728        self.add_uint32(Keys.LLM.HASH_LAYER_COUNT.format(arch=self.arch), count)
729
730    def add_feed_forward_length(self, length: int | Sequence[int]) -> None:
731        if isinstance(length, int):
732            self.add_uint32(Keys.LLM.FEED_FORWARD_LENGTH.format(arch=self.arch), length)
733        else:
734            self.add_array(Keys.LLM.FEED_FORWARD_LENGTH.format(arch=self.arch), length)
735
736    def add_expert_feed_forward_length(self, length: int | Sequence[int]) -> None:
737        if isinstance(length, int):
738            self.add_uint32(Keys.LLM.EXPERT_FEED_FORWARD_LENGTH.format(arch=self.arch), length)
739        else:
740            self.add_array(Keys.LLM.EXPERT_FEED_FORWARD_LENGTH.format(arch=self.arch), length)
741
742    def add_expert_shared_feed_forward_length(self, length: int) -> None:
743        self.add_uint32(Keys.LLM.EXPERT_SHARED_FEED_FORWARD_LENGTH.format(arch=self.arch), length)
744
745    def add_expert_chunk_feed_forward_length(self, length: int) -> None:
746        self.add_uint32(Keys.LLM.EXPERT_CHUNK_FEED_FORWARD_LENGTH.format(arch=self.arch), length)
747
748    def add_parallel_residual(self, use: bool) -> None:
749        self.add_bool(Keys.LLM.USE_PARALLEL_RESIDUAL.format(arch=self.arch), use)
750
751    def add_decoder_start_token_id(self, id: int) -> None:
752        self.add_uint32(Keys.LLM.DECODER_START_TOKEN_ID.format(arch=self.arch), id)
753
754    def add_decoder_block_count(self, value: int) -> None:
755        self.add_uint32(Keys.LLM.DECODER_BLOCK_COUNT.format(arch=self.arch), value)
756
757    def add_embedding_length_per_layer_input(self, value: int) -> None:
758        self.add_uint32(Keys.LLM.EMBD_LENGTH_PER_LAYER_INP.format(arch=self.arch), value)
759
760    def add_altup_active_idx(self, val: int) -> None:
761        self.add_uint32(Keys.LLM.ALTUP_ACTIVE_IDX.format(arch=self.arch), val)
762
763    def add_altup_num_inputs(self, val: int) -> None:
764        self.add_uint32(Keys.LLM.ALTUP_NUM_INPUTS.format(arch=self.arch), val)
765
766    def add_activation_sparsity_scale(self, values: Sequence[float]) -> None:
767        self.add_array(Keys.LLM.ACTIVATION_SPARSITY_SCALE.format(arch=self.arch), values)
768
769    def add_head_count(self, count: int | Sequence[int]) -> None:
770        if isinstance(count, int):
771            self.add_uint32(Keys.Attention.HEAD_COUNT.format(arch=self.arch), count)
772        else:
773            self.add_array(Keys.Attention.HEAD_COUNT.format(arch=self.arch), count)
774
775    def add_head_count_kv(self, count: int | Sequence[int]) -> None:
776        if isinstance(count, int):
777            self.add_uint32(Keys.Attention.HEAD_COUNT_KV.format(arch=self.arch), count)
778        else:
779            self.add_array(Keys.Attention.HEAD_COUNT_KV.format(arch=self.arch), count)
780
781    def add_key_length(self, length: int) -> None:
782        self.add_uint32(Keys.Attention.KEY_LENGTH.format(arch=self.arch), length)
783
784    def add_value_length(self, length: int) -> None:
785        self.add_uint32(Keys.Attention.VALUE_LENGTH.format(arch=self.arch), length)
786
787    def add_key_length_mla(self, length: int) -> None:
788        self.add_uint32(Keys.Attention.KEY_LENGTH_MLA.format(arch=self.arch), length)
789
790    def add_value_length_mla(self, length: int) -> None:
791        self.add_uint32(Keys.Attention.VALUE_LENGTH_MLA.format(arch=self.arch), length)
792
793    def add_key_length_swa(self, length: int) -> None:
794        self.add_uint32(Keys.Attention.KEY_LENGTH_SWA.format(arch=self.arch), length)
795
796    def add_key_length_mla_swa(self, length: int) -> None:
797        self.add_uint32(Keys.Attention.KEY_LENGTH_MLA_SWA.format(arch=self.arch), length)
798
799    def add_value_length_mla_swa(self, length: int) -> None:
800        self.add_uint32(Keys.Attention.VALUE_LENGTH_MLA_SWA.format(arch=self.arch), length)
801
802    def add_kv_lora_rank_swa(self, length: int) -> None:
803        self.add_uint32(Keys.Attention.KV_LORA_RANK_SWA.format(arch=self.arch), length)
804
805    def add_value_length_swa(self, length: int) -> None:
806        self.add_uint32(Keys.Attention.VALUE_LENGTH_SWA.format(arch=self.arch), length)
807
808    def add_indexer_head_count(self, count: int) -> None:
809        self.add_uint32(Keys.Attention.Indexer.HEAD_COUNT.format(arch=self.arch), count)
810
811    def add_indexer_key_length(self, length: int) -> None:
812        self.add_uint32(Keys.Attention.Indexer.KEY_LENGTH.format(arch=self.arch), length)
813
814    def add_indexer_top_k(self, top_k: int) -> None:
815        self.add_uint32(Keys.Attention.Indexer.TOP_K.format(arch=self.arch), top_k)
816
817    def add_indexer_block_size(self, block_size: int) -> None:
818        self.add_uint32(Keys.Attention.Indexer.BLOCK_SIZE.format(arch=self.arch), block_size)
819
820    def add_indexer_local_blocks(self, local_blocks: int) -> None:
821        self.add_uint32(Keys.Attention.Indexer.LOCAL_BLOCKS.format(arch=self.arch), local_blocks)
822
823    def add_indexer_types(self, value: Sequence[bool]) -> None:
824        key = Keys.Attention.Indexer.TYPES.format(arch=self.arch)
825        self.add_array(key, value)
826
827    def add_max_alibi_bias(self, bias: float) -> None:
828        self.add_float32(Keys.Attention.MAX_ALIBI_BIAS.format(arch=self.arch), bias)
829
830    def add_clamp_kqv(self, value: float) -> None:
831        self.add_float32(Keys.Attention.CLAMP_KQV.format(arch=self.arch), value)
832
833    def add_shared_kv_layers(self, value: int) -> None:
834        self.add_uint32(Keys.Attention.SHARED_KV_LAYERS.format(arch=self.arch), value)
835
836    # if input is array, true means SWA and false means full_attention for each layer
837    def add_sliding_window_pattern(self, value: int | Sequence[bool]) -> None:
838        key = Keys.Attention.SLIDING_WINDOW_PATTERN.format(arch=self.arch)
839        if isinstance(value, int):
840            self.add_uint32(key, value)
841        else:
842            self.add_array(key, value)
843
844    def add_recurrent_layers(self, value: Sequence[bool]) -> None:
845        self.add_array(Keys.Attention.RECURRENT_LAYERS.format(arch=self.arch), value)
846
847    def add_rope_pattern(self, value: Sequence[bool]) -> None:
848        self.add_array(Keys.Attention.ROPE_PATTERN.format(arch=self.arch), value)
849
850    def add_dense_features_dims(self, dense:str, in_f:int, out_f:int) -> None:
851        self.add_uint32(Keys.LLM.DENSE_FEAT_IN_SIZE.format(arch=self.arch, dense=dense), in_f)
852        self.add_uint32(Keys.LLM.DENSE_FEAT_OUT_SIZE.format(arch=self.arch, dense=dense), out_f)
853
854    def add_logit_scale(self, value: float) -> None:
855        self.add_float32(Keys.LLM.LOGIT_SCALE.format(arch=self.arch), value)
856
857    def add_attn_logit_softcapping(self, value: float) -> None:
858        self.add_float32(Keys.LLM.ATTN_LOGIT_SOFTCAPPING.format(arch=self.arch), value)
859
860    def add_router_logit_softcapping(self, value: float) -> None:
861        self.add_float32(Keys.LLM.ROUTER_LOGIT_SOFTCAPPING.format(arch=self.arch), value)
862
863    def add_final_logit_softcapping(self, value: float) -> None:
864        self.add_float32(Keys.LLM.FINAL_LOGIT_SOFTCAPPING.format(arch=self.arch), value)
865
866    def add_expert_count(self, count: int) -> None:
867        self.add_uint32(Keys.LLM.EXPERT_COUNT.format(arch=self.arch), count)
868
869    def add_expert_used_count(self, count: int | Sequence[int]) -> None:
870        if isinstance(count, int):
871            self.add_uint32(Keys.LLM.EXPERT_USED_COUNT.format(arch=self.arch), count)
872        else:
873            self.add_array(Keys.LLM.EXPERT_USED_COUNT.format(arch=self.arch), count)
874
875    def add_expert_shared_count(self, count: int) -> None:
876        self.add_uint32(Keys.LLM.EXPERT_SHARED_COUNT.format(arch=self.arch), count)
877
878    def add_expert_group_count(self, count: int) -> None:
879        self.add_uint32(Keys.LLM.EXPERT_GROUP_COUNT.format(arch=self.arch), count)
880
881    def add_expert_group_used_count(self, count: int) -> None:
882        self.add_uint32(Keys.LLM.EXPERT_GROUP_USED_COUNT.format(arch=self.arch), count)
883
884    def add_expert_weights_scale(self, value: float) -> None:
885        self.add_float32(Keys.LLM.EXPERT_WEIGHTS_SCALE.format(arch=self.arch), value)
886
887    def add_expert_weights_norm(self, value: bool) -> None:
888        self.add_bool(Keys.LLM.EXPERT_WEIGHTS_NORM.format(arch=self.arch), value)
889
890    def add_expert_gating_func(self, value: ExpertGatingFuncType) -> None:
891        self.add_uint32(Keys.LLM.EXPERT_GATING_FUNC.format(arch=self.arch), value.value)
892
893    def add_swiglu_clamp_exp(self, values: Sequence[float]) -> None:
894        self.add_array(Keys.LLM.SWIGLU_CLAMP_EXP.format(arch=self.arch), values)
895
896    def add_swiglu_clamp_shexp(self, values: Sequence[float]) -> None:
897        self.add_array(Keys.LLM.SWIGLU_CLAMP_SHEXP.format(arch=self.arch), values)
898
899    def add_hidden_act(self, value: str) -> None:
900        self.add_string(Keys.LLM.HIDDEN_ACT.format(arch=self.arch), value)
901
902    def add_expert_group_scale(self, value: float) -> None:
903        self.add_float32(Keys.LLM.EXPERT_GROUP_SCALE.format(arch=self.arch), value)
904
905    def add_experts_per_group(self, count: int) -> None:
906        self.add_uint32(Keys.LLM.EXPERTS_PER_GROUP.format(arch=self.arch), count)
907
908    def add_moe_every_n_layers(self, value: int) -> None:
909        self.add_uint32(Keys.LLM.MOE_EVERY_N_LAYERS.format(arch=self.arch), value)
910
911    def add_moe_latent_size(self, value: int) -> None:
912        self.add_uint32(Keys.LLM.MOE_LATENT_SIZE.format(arch=self.arch), value)
913
914    def add_nextn_predict_layers(self, count: int) -> None:
915        self.add_uint32(Keys.LLM.NEXTN_PREDICT_LAYERS.format(arch=self.arch), count)
916
917    def add_swin_norm(self, value: bool) -> None:
918        self.add_bool(Keys.LLM.SWIN_NORM.format(arch=self.arch), value)
919
920    def add_rescale_every_n_layers(self, count: int) -> None:
921        self.add_uint32(Keys.LLM.RESCALE_EVERY_N_LAYERS.format(arch=self.arch), count)
922
923    def add_time_mix_extra_dim(self, dim: int) -> None:
924        self.add_uint32(Keys.LLM.TIME_MIX_EXTRA_DIM.format(arch=self.arch), dim)
925
926    def add_time_decay_extra_dim(self, dim: int) -> None:
927        self.add_uint32(Keys.LLM.TIME_DECAY_EXTRA_DIM.format(arch=self.arch), dim)
928
929    def add_residual_scale(self, value: float) -> None:
930        self.add_float32(Keys.LLM.RESIDUAL_SCALE.format(arch=self.arch), value)
931
932    def add_embedding_scale(self, value: float) -> None:
933        self.add_float32(Keys.LLM.EMBEDDING_SCALE.format(arch=self.arch), value)
934
935    def add_adapter_count(self, count: int) -> None:
936        self.add_uint32(Keys.Adapters.COUNT.format(arch=self.arch), count)
937
938    def add_adapter_token_ids_activate(self, ids: Sequence[int]) -> None:
939        self.add_array(Keys.Adapters.TOKEN_IDS_ACTIVATE.format(arch=self.arch), ids)
940
941    def add_adapter_token_ids_substitute(self, ids: Sequence[int]) -> None:
942        self.add_array(Keys.Adapters.TOKEN_IDS_SUBSTITUTE.format(arch=self.arch), ids)
943
944    def add_adapter_lora_rank(self, rank: int) -> None:
945        self.add_uint32(Keys.Adapters.LORA_RANK.format(arch=self.arch), rank)
946
947    def add_adapter_router_gain(self, gain: float) -> None:
948        self.add_float32(Keys.Adapters.ROUTER_GAIN.format(arch=self.arch), gain)
949
950    def add_wkv_head_size(self, size: int) -> None:
951        self.add_uint32(Keys.WKV.HEAD_SIZE.format(arch=self.arch), size)
952
953    def add_token_shift_count(self, count: int) -> None:
954        self.add_uint32(Keys.LLM.TOKEN_SHIFT_COUNT.format(arch=self.arch), count)
955
956    def add_num_loops(self, count: int) -> None:
957        self.add_uint32(Keys.LLM.NUM_LOOPS.format(arch=self.arch), count)
958
959    def add_skip_loop_final_norm(self, value: bool) -> None:
960        self.add_bool(Keys.LLM.SKIP_LOOP_FINAL_NORM.format(arch=self.arch), value)
961
962    def add_interleave_moe_layer_step(self, value: int) -> None:
963        self.add_uint32(Keys.LLM.INTERLEAVE_MOE_LAYER_STEP.format(arch=self.arch), value)
964
965    def add_layer_norm_eps(self, value: float) -> None:
966        self.add_float32(Keys.Attention.LAYERNORM_EPS.format(arch=self.arch), value)
967
968    def add_layer_norm_rms_eps(self, value: float) -> None:
969        self.add_float32(Keys.Attention.LAYERNORM_RMS_EPS.format(arch=self.arch), value)
970
971    def add_group_norm_eps(self, value: float) -> None:
972        self.add_float32(Keys.Attention.GROUPNORM_EPS.format(arch=self.arch), value)
973
974    def add_group_norm_groups(self, value: int) -> None:
975        self.add_uint32(Keys.Attention.GROUPNORM_GROUPS.format(arch=self.arch), value)
976
977    def add_causal_attention(self, value: bool) -> None:
978        self.add_bool(Keys.Attention.CAUSAL.format(arch=self.arch), value)
979
980    def add_q_lora_rank(self, length: int) -> None:
981        self.add_uint32(Keys.Attention.Q_LORA_RANK.format(arch=self.arch), length)
982
983    def add_kv_lora_rank(self, length: int) -> None:
984        self.add_uint32(Keys.Attention.KV_LORA_RANK.format(arch=self.arch), length)
985
986    def add_decay_lora_rank(self, length: int) -> None:
987        self.add_uint32(Keys.Attention.DECAY_LORA_RANK.format(arch=self.arch), length)
988
989    def add_iclr_lora_rank(self, length: int) -> None:
990        self.add_uint32(Keys.Attention.ICLR_LORA_RANK.format(arch=self.arch), length)
991
992    def add_value_residual_mix_lora_rank(self, length: int) -> None:
993        self.add_uint32(Keys.Attention.VALUE_RESIDUAL_MIX_LORA_RANK.format(arch=self.arch), length)
994
995    def add_rope_freq_base_swa(self, value: float) -> None:
996        self.add_float32(Keys.Rope.FREQ_BASE_SWA.format(arch=self.arch), value)
997
998    def add_gate_lora_rank(self, length: int) -> None:
999        self.add_uint32(Keys.Attention.GATE_LORA_RANK.format(arch=self.arch), length)
1000
1001    def add_relative_attn_buckets_count(self, value: int) -> None:
1002        self.add_uint32(Keys.Attention.REL_BUCKETS_COUNT.format(arch=self.arch), value)
1003
1004    def add_sliding_window(self, value: int) -> None:
1005        self.add_uint32(Keys.Attention.SLIDING_WINDOW.format(arch=self.arch), value)
1006
1007    def add_block_size(self, value: int) -> None:
1008        self.add_uint32(Keys.LLM.BLOCK_SIZE.format(arch=self.arch), value)
1009
1010    def add_conv_kernel_size(self, value: int) -> None:
1011        self.add_uint32(Keys.LLM.CONV_KERNEL_SIZE.format(arch=self.arch), value)
1012
1013    def add_conv_group_size(self, value: int) -> None:
1014        self.add_uint32(Keys.LLM.CONV_GROUP_SIZE.format(arch=self.arch), value)
1015
1016    def add_selector_rank(self, value: int) -> None:
1017        self.add_uint32(Keys.LLM.SELECTOR_RANK.format(arch=self.arch), value)
1018
1019    def add_selector_top_k(self, value: int) -> None:
1020        self.add_uint32(Keys.LLM.SELECTOR_TOP_K.format(arch=self.arch), value)
1021
1022    def add_sample_from_anchor(self, value: bool) -> None:
1023        self.add_bool(Keys.LLM.SAMPLE_FROM_ANCHOR.format(arch=self.arch), value)
1024
1025    def add_has_confidence_head(self, value: bool) -> None:
1026        self.add_bool(Keys.LLM.HAS_CONFIDENCE_HEAD.format(arch=self.arch), value)
1027
1028    def add_target_layers(self, value: Sequence[int]) -> None:
1029        self.add_array(Keys.LLM.TARGET_LAYERS.format(arch=self.arch), value)
1030
1031    def add_target_hidden_size(self, value: int) -> None:
1032        self.add_uint32(Keys.LLM.TARGET_HIDDEN_SIZE.format(arch=self.arch), value)
1033
1034    def add_norm_before_residual(self, value: bool) -> None:
1035        self.add_bool(Keys.LLM.NORM_BEFORE_RESIDUAL.format(arch=self.arch), value)
1036
1037    def add_norm_before_fc(self, value: bool) -> None:
1038        self.add_bool(Keys.LLM.NORM_BEFORE_FC.format(arch=self.arch), value)
1039
1040    def add_attention_output_group_count(self, count: int) -> None:
1041        self.add_uint32(Keys.Attention.OUTPUT_GROUP_COUNT.format(arch=self.arch), count)
1042
1043    def add_attention_output_lora_rank(self, length: int) -> None:
1044        self.add_uint32(Keys.Attention.OUTPUT_LORA_RANK.format(arch=self.arch), length)
1045
1046    def add_attention_compress_ratios(self, values: Sequence[int]) -> None:
1047        self.add_array(Keys.Attention.COMPRESS_RATIOS.format(arch=self.arch), values)
1048
1049    def add_attention_compress_rope_freq_base(self, value: float) -> None:
1050        self.add_float32(Keys.Attention.COMPRESS_ROPE_FREQ_BASE.format(arch=self.arch), value)
1051
1052    def add_hyper_connection_count(self, count: int) -> None:
1053        self.add_uint32(Keys.HyperConnection.COUNT.format(arch=self.arch), count)
1054
1055    def add_hyper_connection_sinkhorn_iterations(self, count: int) -> None:
1056        self.add_uint32(Keys.HyperConnection.SINKHORN_ITERATIONS.format(arch=self.arch), count)
1057
1058    def add_hyper_connection_epsilon(self, value: float) -> None:
1059        self.add_float32(Keys.HyperConnection.EPSILON.format(arch=self.arch), value)
1060
1061    def add_hyper_connection_magnitude(self, value: float) -> None:
1062        self.add_float32(Keys.HyperConnection.MAGNITUDE.format(arch=self.arch), value)
1063
1064    def add_hyper_connection_low_rank(self, value: int) -> None:
1065        self.add_uint32(Keys.HyperConnection.LOW_RANK.format(arch=self.arch), value)
1066
1067    def add_ple_layers(self, values: Sequence[int]) -> None:
1068        self.add_array(Keys.PerLayerEmbedding.LAYERS.format(arch=self.arch), values)
1069
1070    def add_ple_ngram_size(self, value: int) -> None:
1071        self.add_uint32(Keys.PerLayerEmbedding.NGRAM_SIZE.format(arch=self.arch), value)
1072
1073    def add_ple_heads_per_ngram(self, value: int) -> None:
1074        self.add_uint32(Keys.PerLayerEmbedding.HEADS_PER_NGRAM.format(arch=self.arch), value)
1075
1076    def add_ple_conv_kernel(self, value: int) -> None:
1077        self.add_uint32(Keys.PerLayerEmbedding.CONV_KERNEL.format(arch=self.arch), value)
1078
1079    # multipliers reach ~2.4e13; default INT32 inference would truncate them
1080    def _add_u64_array(self, key: str, values: Sequence[int]) -> None:
1081        self.add_key_value(key, list(values), GGUFValueType.ARRAY, GGUFValueType.UINT64)
1082
1083    def add_ple_layer_multipliers(self, values: Sequence[int]) -> None:
1084        self._add_u64_array(Keys.PerLayerEmbedding.LAYER_MULTIPLIERS.format(arch=self.arch), values)
1085
1086    def add_ple_head_offsets(self, values: Sequence[int]) -> None:
1087        self._add_u64_array(Keys.PerLayerEmbedding.HEAD_OFFSETS.format(arch=self.arch), values)
1088
1089    def add_ple_head_vocab_sizes(self, values: Sequence[int]) -> None:
1090        self._add_u64_array(Keys.PerLayerEmbedding.HEAD_VOCAB_SIZES.format(arch=self.arch), values)
1091
1092    def add_ple_eos_token_id(self, value: int) -> None:
1093        self.add_uint32(Keys.PerLayerEmbedding.EOS_TOKEN_ID.format(arch=self.arch), value)
1094
1095    def add_ple_image_token_id(self, value: int) -> None:
1096        self.add_uint32(Keys.PerLayerEmbedding.IMAGE_TOKEN_ID.format(arch=self.arch), value)
1097
1098    def add_attention_scale(self, value: float) -> None:
1099        self.add_float32(Keys.Attention.SCALE.format(arch=self.arch), value)
1100
1101    def add_attn_output_scale(self, value: float) -> None:
1102        self.add_float32(Keys.Attention.OUTPUT_SCALE.format(arch=self.arch), value)
1103
1104    def add_attn_value_scale(self, value: float) -> None:
1105        self.add_float32(Keys.Attention.VALUE_SCALE.format(arch=self.arch), value)
1106
1107    def add_attn_temperature_length(self, value: int) -> None:
1108        self.add_uint32(Keys.Attention.TEMPERATURE_LENGTH.format(arch=self.arch), value)
1109
1110    def add_attn_temperature_scale(self, value: float) -> None:
1111        self.add_float32(Keys.Attention.TEMPERATURE_SCALE.format(arch=self.arch), value)
1112
1113    def add_pooling_type(self, value: PoolingType) -> None:
1114        self.add_uint32(Keys.LLM.POOLING_TYPE.format(arch=self.arch), value.value)
1115
1116    def add_num_deepstack_layers(self, count: int) -> None:
1117        """Add scalar deepstack layer count (qwen3vl format)"""
1118        self.add_uint32(Keys.LLM.NUM_DEEPSTACK_LAYERS.format(arch=self.arch), count)
1119
1120    def add_deepstack_mapping(self, layers: Sequence[int]) -> None:
1121        """Add per-layer deepstack projector indices (Granite4 Vision format)"""
1122        self.add_array(Keys.LLM.DEEPSTACK_MAPPING.format(arch=self.arch), list(layers))
1123
1124    def add_rope_dimension_count(self, count: int) -> None:
1125        self.add_uint32(Keys.Rope.DIMENSION_COUNT.format(arch=self.arch), count)
1126
1127    def add_rope_dimension_count_swa(self, count: int) -> None:
1128        self.add_uint32(Keys.Rope.DIMENSION_COUNT_SWA.format(arch=self.arch), count)
1129
1130    def add_rope_dimension_sections(self, dims: Sequence[int]) -> None:
1131        self.add_array(Keys.Rope.DIMENSION_SECTIONS.format(arch=self.arch), dims)
1132
1133    def add_rope_freq_base(self, value: float) -> None:
1134        self.add_float32(Keys.Rope.FREQ_BASE.format(arch=self.arch), value)
1135
1136    def add_rope_scaling_type(self, value: RopeScalingType) -> None:
1137        self.add_string(Keys.Rope.SCALING_TYPE.format(arch=self.arch), value.value)
1138
1139    def add_rope_scaling_factor(self, value: float) -> None:
1140        self.add_float32(Keys.Rope.SCALING_FACTOR.format(arch=self.arch), value)
1141
1142    def add_rope_scaling_alpha(self, value: float) -> None:
1143        self.add_float32(Keys.Rope.SCALING_ALPHA.format(arch=self.arch), value)
1144
1145    def add_rope_scaling_attn_factors(self, value: float) -> None:
1146        self.add_float32(Keys.Rope.SCALING_ATTN_FACTOR.format(arch=self.arch), value)
1147
1148    def add_rope_scaling_orig_ctx_len(self, value: int) -> None:
1149        self.add_uint32(Keys.Rope.SCALING_ORIG_CTX_LEN.format(arch=self.arch), value)
1150
1151    def add_rope_scaling_finetuned(self, value: bool) -> None:
1152        self.add_bool(Keys.Rope.SCALING_FINETUNED.format(arch=self.arch), value)
1153
1154    def add_rope_scaling_yarn_log_mul(self, value: float) -> None:
1155        self.add_float32(Keys.Rope.SCALING_YARN_LOG_MUL.format(arch=self.arch), value)
1156
1157    def add_rope_scaling_yarn_ext_factor(self, value: float) -> None:
1158        self.add_float32(Keys.Rope.SCALING_YARN_EXT_FACTOR.format(arch=self.arch), value)
1159
1160    def add_rope_scaling_yarn_attn_factor(self, value: float) -> None:
1161        self.add_float32(Keys.Rope.SCALING_YARN_ATTN_FACTOR.format(arch=self.arch), value)
1162
1163    def add_rope_scaling_yarn_beta_fast(self, value: float) -> None:
1164        self.add_float32(Keys.Rope.SCALING_YARN_BETA_FAST.format(arch=self.arch), value)
1165
1166    def add_rope_scaling_yarn_beta_slow(self, value: float) -> None:
1167        self.add_float32(Keys.Rope.SCALING_YARN_BETA_SLOW.format(arch=self.arch), value)
1168
1169    def add_ssm_conv_kernel(self, value: int) -> None:
1170        self.add_uint32(Keys.SSM.CONV_KERNEL.format(arch=self.arch), value)
1171
1172    def add_ssm_inner_size(self, value: int) -> None:
1173        self.add_uint32(Keys.SSM.INNER_SIZE.format(arch=self.arch), value)
1174
1175    def add_ssm_state_size(self, value: int) -> None:
1176        self.add_uint32(Keys.SSM.STATE_SIZE.format(arch=self.arch), value)
1177
1178    def add_ssm_time_step_rank(self, value: int) -> None:
1179        self.add_uint32(Keys.SSM.TIME_STEP_RANK.format(arch=self.arch), value)
1180
1181    def add_ssm_group_count(self, value: int) -> None:
1182        self.add_uint32(Keys.SSM.GROUP_COUNT.format(arch=self.arch), value)
1183
1184    def add_ssm_dt_b_c_rms(self, value: bool) -> None:
1185        self.add_bool(Keys.SSM.DT_B_C_RMS.format(arch=self.arch), value)
1186
1187    def add_expert_latent_length(self, value: int) -> None:
1188        self.add_uint32(Keys.LLM.EXPERT_LATENT_LENGTH.format(arch=self.arch), value)
1189
1190    def add_activation_situ_beta(self, value: float) -> None:
1191        self.add_float32(Keys.Activation.SITU_BETA.format(arch=self.arch), value)
1192
1193    def add_activation_situ_linear_beta(self, value: float) -> None:
1194        self.add_float32(Keys.Activation.SITU_LINEAR_BETA.format(arch=self.arch), value)
1195
1196    def add_attn_res_block_size(self, value: int) -> None:
1197        self.add_uint32(Keys.AttnRes.BLOCK_SIZE.format(arch=self.arch), value)
1198
1199    def add_kda_head_dim(self, value: int) -> None:
1200        self.add_uint32(Keys.KDA.HEAD_DIM.format(arch=self.arch), value)
1201
1202    def add_kda_safe_gate(self, value: bool) -> None:
1203        self.add_bool(Keys.KDA.SAFE_GATE.format(arch=self.arch), value)
1204
1205    def add_kda_gate_lower_bound(self, value: float) -> None:
1206        self.add_float32(Keys.KDA.GATE_LOWER_BOUND.format(arch=self.arch), value)
1207
1208    def add_tokenizer_model(self, model: str) -> None:
1209        self.add_string(Keys.Tokenizer.MODEL, model)
1210
1211    def add_tokenizer_pre(self, pre: str) -> None:
1212        self.add_string(Keys.Tokenizer.PRE, pre)
1213
1214    def add_token_list(self, tokens: Sequence[str] | Sequence[bytes] | Sequence[bytearray]) -> None:
1215        self.add_array(Keys.Tokenizer.LIST, tokens)
1216
1217    def add_token_merges(self, merges: Sequence[str] | Sequence[bytes] | Sequence[bytearray]) -> None:
1218        self.add_array(Keys.Tokenizer.MERGES, merges)
1219
1220    def add_token_types(self, types: Sequence[TokenType] | Sequence[int]) -> None:
1221        self.add_array(Keys.Tokenizer.TOKEN_TYPE, types)
1222
1223    def add_token_type_count(self, value: int) -> None:
1224        self.add_uint32(Keys.Tokenizer.TOKEN_TYPE_COUNT, value)
1225
1226    def add_token_scores(self, scores: Sequence[float]) -> None:
1227        self.add_array(Keys.Tokenizer.SCORES, scores)
1228
1229    def add_bos_token_id(self, id: int) -> None:
1230        self.add_uint32(Keys.Tokenizer.BOS_ID, id)
1231
1232    def add_eos_token_id(self, id: int) -> None:
1233        self.add_uint32(Keys.Tokenizer.EOS_ID, id)
1234
1235    def add_unk_token_id(self, id: int) -> None:
1236        self.add_uint32(Keys.Tokenizer.UNK_ID, id)
1237
1238    def add_sep_token_id(self, id: int) -> None:
1239        self.add_uint32(Keys.Tokenizer.SEP_ID, id)
1240
1241    def add_pad_token_id(self, id: int) -> None:
1242        self.add_uint32(Keys.Tokenizer.PAD_ID, id)
1243
1244    def add_mask_token_id(self, id: int) -> None:
1245        self.add_uint32(Keys.Tokenizer.MASK_ID, id)
1246
1247    def add_add_bos_token(self, value: bool) -> None:
1248        self.add_bool(Keys.Tokenizer.ADD_BOS, value)
1249
1250    def add_add_eos_token(self, value: bool) -> None:
1251        self.add_bool(Keys.Tokenizer.ADD_EOS, value)
1252
1253    def add_add_sep_token(self, value: bool) -> None:
1254        self.add_bool(Keys.Tokenizer.ADD_SEP, value)
1255
1256    def add_add_space_prefix(self, value: bool) -> None:
1257        self.add_bool(Keys.Tokenizer.ADD_PREFIX, value)
1258
1259    def add_remove_extra_whitespaces(self, value: bool) -> None:
1260        self.add_bool(Keys.Tokenizer.REMOVE_EXTRA_WS, value)
1261
1262    def add_precompiled_charsmap(self, charsmap: bytes) -> None:
1263        self.add_array(Keys.Tokenizer.PRECOMPILED_CHARSMAP, charsmap)
1264
1265    def add_chat_template(self, value: str | Sequence[Mapping[str, str]] | None) -> None:
1266        if value is None:
1267            self.remove_key(Keys.Tokenizer.CHAT_TEMPLATE)
1268            return
1269
1270        if not isinstance(value, str):
1271            template_default = None
1272            template_names = set()
1273
1274            for choice in value:
1275                name = choice.get('name', '')
1276                template = choice.get('template')
1277
1278                # Allowing non-alphanumerical characters in template name is probably not a good idea, so filter it
1279                name = ''.join((c if c in ascii_letters + digits else '_' for c in name))
1280
1281                if name and template is not None:
1282                    if name == 'default':
1283                        template_default = template
1284                    else:
1285                        template_names.add(name)
1286                        self.add_string(Keys.Tokenizer.CHAT_TEMPLATE_N.format(name=name), template)
1287
1288            if template_names:
1289                self.add_array(Keys.Tokenizer.CHAT_TEMPLATES, list(template_names))
1290
1291            if template_default is None:
1292                return
1293
1294            value = template_default
1295
1296        self.add_string(Keys.Tokenizer.CHAT_TEMPLATE, value)
1297
1298    def add_suppress_tokens(self, tokens: Sequence[int]) -> None:
1299        self.add_array(Keys.Tokenizer.SUPPRESS_TOKENS, tokens)
1300
1301    def add_normalizer_lowercase(self, value: bool) -> None:
1302        self.add_bool(Keys.Tokenizer.NORMALIZER_LOWERCASE, value)
1303
1304    def add_normalizer_strip_accents(self, value: bool) -> None:
1305        self.add_bool(Keys.Tokenizer.NORMALIZER_STRIP_ACCENTS, value)
1306
1307    def add_eot_token_id(self, id: int) -> None:
1308        self.add_uint32(Keys.Tokenizer.EOT_ID, id)
1309
1310    def add_eom_token_id(self, id: int) -> None:
1311        self.add_uint32(Keys.Tokenizer.EOM_ID, id)
1312
1313    def add_classifier_output_labels(self, labels: Sequence[str]) -> None:
1314        self.add_array(Keys.Classifier.OUTPUT_LABELS.format(arch=self.arch), labels)
1315
1316    # for vision models
1317
1318    def add_clip_has_vision_encoder(self, value: bool) -> None:
1319        self.add_bool(Keys.Clip.HAS_VISION_ENCODER, value)
1320
1321    def add_clip_has_audio_encoder(self, value: bool) -> None:
1322        self.add_bool(Keys.Clip.HAS_AUDIO_ENCODER, value)
1323
1324    def add_clip_has_gen_audio_encoder(self, value: bool) -> None:
1325        self.add_bool(Keys.Clip.HAS_GEN_AUDIO_ENCODER, value)
1326
1327    def add_clip_projector_type(self, value: str) -> None:
1328        self.add_string(Keys.Clip.PROJECTOR_TYPE, value)
1329
1330    def add_clip_vision_projector_type(self, value: str) -> None:
1331        self.add_string(Keys.ClipVision.PROJECTOR_TYPE, value)
1332
1333    def add_vision_projection_dim(self, value: int) -> None:
1334        self.add_uint32(Keys.ClipVision.PROJECTION_DIM, value)
1335
1336    def add_vision_patch_size(self, value: int) -> None:
1337        self.add_uint32(Keys.ClipVision.PATCH_SIZE, value)
1338
1339    def add_vision_embedding_length(self, value: int) -> None:
1340        self.add_uint32(Keys.ClipVision.EMBEDDING_LENGTH, value)
1341
1342    def add_vision_feed_forward_length(self, value: int) -> None:
1343        self.add_uint32(Keys.ClipVision.FEED_FORWARD_LENGTH, value)
1344
1345    def add_vision_block_count(self, value: int) -> None:
1346        self.add_uint32(Keys.ClipVision.BLOCK_COUNT, value)
1347
1348    def add_vision_head_count(self, value: int) -> None:
1349        self.add_uint32(Keys.ClipVision.Attention.HEAD_COUNT, value)
1350
1351    def add_vision_head_count_kv(self, value: int) -> None:
1352        self.add_uint32(Keys.ClipVision.Attention.HEAD_COUNT_KV, value)
1353
1354    def add_vision_head_dim(self, value: int) -> None:
1355        self.add_uint32(Keys.ClipVision.Attention.HEAD_DIM, value)
1356
1357    def add_vision_attention_layernorm_eps(self, value: float) -> None:
1358        self.add_float32(Keys.ClipVision.Attention.LAYERNORM_EPS, value)
1359
1360    def add_vision_image_size(self, value: int) -> None:
1361        self.add_uint32(Keys.ClipVision.IMAGE_SIZE, value)
1362
1363    def add_vision_max_pixels(self, value: int) -> None:
1364        self.add_uint32(Keys.ClipVision.IMAGE_MAX_PIXELS, value)
1365
1366    def add_vision_min_pixels(self, value: int) -> None:
1367        self.add_uint32(Keys.ClipVision.IMAGE_MIN_PIXELS, value)
1368
1369    def add_vision_preproc_max_tiles(self, value: int) -> None:
1370        self.add_uint32(Keys.ClipVision.PREPROC_MAX_TILES, value)
1371
1372    def add_vision_preproc_min_tiles(self, value: int) -> None:
1373        self.add_uint32(Keys.ClipVision.PREPROC_MIN_TILES, value)
1374
1375    def add_vision_preproc_image_size(self, value: int) -> None:
1376        self.add_uint32(Keys.ClipVision.PREPROC_IMAGE_SIZE, value)
1377
1378    def add_vision_projector_query_side(self, value: int) -> None:
1379        self.add_uint32(Keys.ClipVision.Projector.QUERY_SIDE, value)
1380
1381    def add_vision_projector_window_side(self, value: int) -> None:
1382        self.add_uint32(Keys.ClipVision.Projector.WINDOW_SIDE, value)
1383
1384    def add_vision_spatial_offsets(self, layers: Sequence[int]) -> None:
1385        self.add_array(Keys.ClipVision.Projector.SPATIAL_OFFSETS, layers)
1386
1387    def add_vision_image_mean(self, values: Sequence[float]) -> None:
1388        self.add_array(Keys.ClipVision.IMAGE_MEAN, values)
1389
1390    def add_vision_image_std(self, values: Sequence[float]) -> None:
1391        self.add_array(Keys.ClipVision.IMAGE_STD, values)
1392
1393    def add_vision_spatial_merge_size(self, value: int) -> None:
1394        self.add_uint32(Keys.ClipVision.SPATIAL_MERGE_SIZE, value)
1395
1396    def add_vision_expert_count_per_layer(self, value: Sequence[int]) -> None:
1397        self.add_array(Keys.ClipVision.EXPERT_COUNT_PER_LAYER, value)
1398
1399    def add_vision_expert_used_count(self, value: int) -> None:
1400        self.add_uint32(Keys.ClipVision.EXPERT_USED_COUNT, value)
1401
1402    def add_vision_use_gelu(self, value: bool) -> None:
1403        self.add_bool(Keys.ClipVision.USE_GELU, value)
1404
1405    def add_vision_use_silu(self, value: bool) -> None:
1406        self.add_bool(Keys.ClipVision.USE_SILU, value)
1407
1408    def add_vision_projector_scale_factor(self, value: int) -> None:
1409        self.add_uint32(Keys.ClipVision.Projector.SCALE_FACTOR, value)
1410
1411    def add_vision_n_wa_pattern(self, value: int) -> None:
1412        """Add window attention pattern interval for vision models.
1413
1414        This defines the pattern interval for window attention vs full attention layers.
1415        For example, if n_wa_pattern=4, then layers 3, 7, 11, ... use full attention,
1416        while other layers use window attention.
1417
1418        Used by models like Qwen2.5-VL where full attention layers follow a regular pattern.
1419        """
1420        self.add_uint32(Keys.ClipVision.N_WA_PATTERN, value)
1421
1422    def add_vision_wa_layer_indexes(self, layers: Sequence[int]) -> None:
1423        """Add explicit layer indexes that use full attention in vision models.
1424
1425        This specifies the exact layer indices (0-based) that should use full attention
1426        instead of window attention. All other layers will use window attention.
1427
1428        Args:
1429            layers: List of layer indices that use full attention (e.g., [3, 7, 11, 15])
1430
1431        Used by models like YoutuVL where full attention layers are explicitly specified
1432        rather than following a regular pattern.
1433
1434        Difference from add_vision_n_wa_pattern:
1435        - n_wa_pattern: Defines a regular interval pattern (every Nth layer uses full attention)
1436        - wa_layer_indexes: Explicitly lists which layers use full attention (irregular pattern)
1437        """
1438        self.add_array(Keys.ClipVision.WA_LAYER_INDEXES, layers)
1439
1440    def add_vision_is_deepstack_layers(self, layers: Sequence[bool]) -> None:
1441        self.add_array(Keys.ClipVision.IS_DEEPSTACK_LAYERS, layers)
1442
1443    def add_vision_wa_pattern_mode(self, modes: Sequence[int]) -> None:
1444        self.add_array(Keys.ClipVision.WA_PATTERN_MODE, modes)
1445
1446    def add_vision_window_size(self, value: int) -> None:
1447        self.add_uint32(Keys.ClipVision.WINDOW_SIZE, value)
1448
1449    def add_vision_feature_layers(self, layers: Sequence[int]) -> None:
1450        self.add_array(Keys.ClipVision.FEATURE_LAYERS, layers)
1451
1452    def add_vision_image_grid_pinpoints(self, layers: Sequence[Sequence[int]]) -> None:
1453        self.add_array(Keys.ClipVision.IMAGE_GRID_PINPOINTS, layers)
1454
1455    def add_vision_sam_layers_count(self, value: int) -> None:
1456        self.add_uint32(Keys.ClipVision.SAM.BLOCK_COUNT, value)
1457
1458    def add_vision_sam_embedding_length(self, value: int) -> None:
1459        self.add_uint32(Keys.ClipVision.SAM.EMBEDDING_LENGTH, value)
1460
1461    def add_vision_sam_head_count(self, value: int) -> None:
1462        self.add_uint32(Keys.ClipVision.SAM.HEAD_COUNT, value)
1463
1464    # audio models
1465
1466    def add_clip_audio_projector_type(self, value: str) -> None:
1467        self.add_string(Keys.ClipAudio.PROJECTOR_TYPE, value)
1468
1469    def add_audio_projection_dim(self, value: int) -> None:
1470        self.add_uint32(Keys.ClipAudio.PROJECTION_DIM, value)
1471
1472    def add_audio_embedding_length(self, value: int) -> None:
1473        self.add_uint32(Keys.ClipAudio.EMBEDDING_LENGTH, value)
1474
1475    def add_audio_feed_forward_length(self, value: int) -> None:
1476        self.add_uint32(Keys.ClipAudio.FEED_FORWARD_LENGTH, value)
1477
1478    def add_audio_block_count(self, value: int) -> None:
1479        self.add_uint32(Keys.ClipAudio.BLOCK_COUNT, value)
1480
1481    def add_audio_head_count(self, value: int) -> None:
1482        self.add_uint32(Keys.ClipAudio.Attention.HEAD_COUNT, value)
1483
1484    def add_audio_attention_layernorm_eps(self, value: float) -> None:
1485        self.add_float32(Keys.ClipAudio.Attention.LAYERNORM_EPS, value)
1486
1487    def add_audio_num_mel_bins(self, value: int) -> None:
1488        self.add_uint32(Keys.ClipAudio.NUM_MEL_BINS, value)
1489
1490    def add_audio_rvq_num_quantizers(self, value: int) -> None:
1491        self.add_uint32(Keys.ClipAudio.RVQ_NUM_QUANTIZERS, value)
1492
1493    def add_audio_rvq_codebook_size(self, values: Sequence[int]) -> None:
1494        self.add_array(Keys.ClipAudio.RVQ_CODEBOOK_SIZE, values)
1495
1496    def add_audio_wa_pattern_mode(self, modes: Sequence[int]) -> None:
1497        self.add_array(Keys.ClipAudio.WA_PATTERN_MODE, modes)
1498
1499    def add_audio_window_size(self, value: int) -> None:
1500        self.add_uint32(Keys.ClipAudio.WINDOW_SIZE, value)
1501
1502    def add_audio_local_block_count(self, value: int) -> None:
1503        self.add_uint32(Keys.ClipAudio.LOCAL_BLOCK_COUNT, value)
1504
1505    def add_audio_local_group_size(self, value: int) -> None:
1506        self.add_uint32(Keys.ClipAudio.LOCAL_GROUP_SIZE, value)
1507
1508    def add_audio_stack_factor(self, value: int) -> None:
1509        self.add_uint32(Keys.ClipAudio.Projector.STACK_FACTOR, value)
1510
1511    def add_audio_subsampling_factor(self, value: int) -> None:
1512        self.add_uint32(Keys.ClipAudio.SUBSAMPLING_FACTOR, value)
1513
1514    def add_audio_chunk_size(self, value: int) -> None:
1515        self.add_uint32(Keys.ClipAudio.CHUNK_SIZE, value)
1516
1517    def add_audio_conv_kernel_size(self, value: int) -> None:
1518        self.add_uint32(Keys.ClipAudio.CONV_KERNEL_SIZE, value)
1519
1520    def add_audio_max_pos_emb(self, value: int) -> None:
1521        self.add_uint32(Keys.ClipAudio.MAX_POS_EMB, value)
1522
1523    def add_audio_feature_layers(self, layers: Sequence[int]) -> None:
1524        self.add_array(Keys.ClipAudio.FEATURE_LAYERS, layers)
1525
1526    def add_audio_projector_window_size(self, value: int) -> None:
1527        self.add_uint32(Keys.ClipAudio.Projector.WINDOW_SIZE, value)
1528
1529    def add_audio_projector_downsample_rate(self, value: int) -> None:
1530        self.add_uint32(Keys.ClipAudio.Projector.DOWNSAMPLE_RATE, value)
1531
1532    def add_audio_projector_head_count(self, value: int) -> None:
1533        self.add_uint32(Keys.ClipAudio.Projector.HEAD_COUNT, value)
1534
1535    # audio generation (mmproj)
1536
1537    def add_clip_gen_audio_projector_type(self, value: str) -> None:
1538        self.add_string(Keys.ClipGenAudio.PROJECTOR_TYPE, value)
1539
1540    def add_gen_audio_projection_dim(self, value: int) -> None:
1541        self.add_uint32(Keys.ClipGenAudio.PROJECTION_DIM, value)
1542
1543    def add_gen_audio_embedding_length(self, value: int) -> None:
1544        self.add_uint32(Keys.ClipGenAudio.EMBEDDING_LENGTH, value)
1545
1546    def add_gen_audio_feed_forward_length(self, value: int) -> None:
1547        self.add_uint32(Keys.ClipGenAudio.FEED_FORWARD_LENGTH, value)
1548
1549    def add_gen_audio_block_count(self, value: int) -> None:
1550        self.add_uint32(Keys.ClipGenAudio.BLOCK_COUNT, value)
1551
1552    def add_gen_audio_head_count(self, value: int) -> None:
1553        self.add_uint32(Keys.ClipGenAudio.Attention.HEAD_COUNT, value)
1554
1555    def add_gen_audio_head_count_kv(self, value: int) -> None:
1556        self.add_uint32(Keys.ClipGenAudio.Attention.HEAD_COUNT_KV, value)
1557
1558    def add_gen_audio_attention_layernorm_eps(self, value: float) -> None:
1559        self.add_float32(Keys.ClipGenAudio.Attention.LAYERNORM_EPS, value)
1560
1561    def add_gen_audio_model_variant(self, value: str) -> None:
1562        self.add_string(Keys.ClipGenAudio.MODEL_VARIANT, value)
1563
1564    def add_xielu_alpha_p(self, values: Sequence[float]):
1565        self.add_array(Keys.xIELU.ALPHA_P, values)
1566
1567    def add_xielu_alpha_n(self, values: Sequence[float]):
1568        self.add_array(Keys.xIELU.ALPHA_N, values)
1569
1570    def add_xielu_beta(self, values: Sequence[float]):
1571        self.add_array(Keys.xIELU.BETA, values)
1572
1573    def add_xielu_eps(self, values: Sequence[float]):
1574        self.add_array(Keys.xIELU.EPS, values)
1575
1576    # diffusion models
1577
1578    def add_diffusion_shift_logits(self, value: bool) -> None:
1579        self.add_bool(Keys.Diffusion.SHIFT_LOGITS, value)
1580
1581    def _pack(self, fmt: str, value: Any, skip_pack_prefix: bool = False) -> bytes:
1582        pack_prefix = ''
1583        if not skip_pack_prefix:
1584            pack_prefix = '<' if self.endianess == GGUFEndian.LITTLE else '>'
1585        return struct.pack(f'{pack_prefix}{fmt}', value)
1586
1587    def _pack_val(self, val: Any, vtype: GGUFValueType, add_vtype: bool, sub_type: GGUFValueType | None = None) -> bytes:
1588        kv_data = bytearray()
1589
1590        if add_vtype:
1591            kv_data += self._pack("I", vtype)
1592
1593        pack_fmt = self._simple_value_packing.get(vtype)
1594        if pack_fmt is not None:
1595            kv_data += self._pack(pack_fmt, val, skip_pack_prefix = vtype == GGUFValueType.BOOL)
1596        elif vtype == GGUFValueType.STRING:
1597            encoded_val = val.encode("utf-8") if isinstance(val, str) else val
1598            kv_data += self._pack("Q", len(encoded_val))
1599            kv_data += encoded_val
1600        elif vtype == GGUFValueType.ARRAY:
1601
1602            if not isinstance(val, Sequence):
1603                raise ValueError("Invalid GGUF metadata array, expecting sequence")
1604
1605            if len(val) == 0:
1606                raise ValueError("Invalid GGUF metadata array. Empty array")
1607
1608            if sub_type is not None:
1609                ltype = sub_type
1610            elif isinstance(val, bytes):
1611                ltype = GGUFValueType.UINT8
1612            else:
1613                ltype = GGUFValueType.get_type(val[0])
1614                if not all(GGUFValueType.get_type(i) is ltype for i in val[1:]):
1615                    raise ValueError("All items in a GGUF array should be of the same type")
1616            kv_data += self._pack("I", ltype)
1617            kv_data += self._pack("Q", len(val))
1618            for item in val:
1619                kv_data += self._pack_val(item, ltype, add_vtype=False)
1620        else:
1621            raise ValueError("Invalid GGUF metadata value type or value")
1622
1623        return bytes(kv_data)
1624
1625    @staticmethod
1626    def format_n_bytes_to_str(num: int) -> str:
1627        if num == 0:
1628            return "negligible - metadata only"
1629        fnum = float(num)
1630        for unit in ("", "K", "M", "G"):
1631            if abs(fnum) < 1000.0:
1632                return f"{fnum:3.1f}{unit}"
1633            fnum /= 1000.0
1634        return f"{fnum:.1f}T - over 1TB, split recommended"