char-fork/llama.cpp
git clone https://git.t4t.associates/char-fork/llama.cpp
c05e8c993
char/aliceai-t5-moe
1#!/usr/bin/env python3 2import logging 3import argparse 4import os 5import sys 6from pathlib import Path 7 8# Necessary to load the local gguf package 9if "NO_LOCAL_GGUF" not in os .environ and (Path (__file__ ).parent .parent .parent .parent / 'gguf-py' ).exists (): 10sys .path .insert (0 ,str (Path (__file__ ).parent .parent .parent )) 11 12from gguf import GGUFReader # noqa: E402 13 14logger = logging .getLogger ("gguf-set-metadata" ) 15 16 17def minimal_example (filename :str )-> None : 18reader = GGUFReader (filename ,'r+' ) 19field = reader .fields ['tokenizer.ggml.bos_token_id' ] 20if field is None : 21return 22part_index = field .data [0 ] 23field .parts [part_index ][0 ]= 2 # Set tokenizer.ggml.bos_token_id to 2 24# 25# So what's this field.data thing? It's helpful because field.parts contains 26# _every_ part of the GGUF field. For example, tokenizer.ggml.bos_token_id consists 27# of: 28# 29# Part index 0: Key length (27) 30# Part index 1: Key data ("tokenizer.ggml.bos_token_id") 31# Part index 2: Field type (4, the id for GGUFValueType.UINT32) 32# Part index 3: Field value 33# 34# Note also that each part is an NDArray slice, so even a part that 35# is only a single value like the key length will be a NDArray of 36# the key length type (numpy.uint32). 37# 38# The .data attribute in the Field is a list of relevant part indexes 39# and doesn't contain internal GGUF details like the key length part. 40# In this case, .data will be [3] - just the part index of the 41# field value itself. 42 43 44def set_metadata (reader :GGUFReader ,args :argparse .Namespace )-> None : 45field = reader .get_field (args .key ) 46if field is None : 47logger .error (f'! Field { repr ( args . key ) } not found' ) 48sys .exit (1 ) 49# Note that field.types is a list of types. This is because the GGUF 50# format supports arrays. For example, an array of UINT32 would 51# look like [GGUFValueType.ARRAY, GGUFValueType.UINT32] 52handler = reader .gguf_scalar_to_np .get (field .types [0 ])if field .types else None 53if handler is None : 54logger .error (f'! This tool only supports changing simple values, { repr ( args . key ) } has unsupported type { field . types } ' ) 55sys .exit (1 ) 56current_value = field .parts [field .data [0 ]][0 ] 57new_value = handler (args .value ) 58logger .info (f'* Preparing to change field { repr ( args . key ) } from { current_value } to { new_value } ' ) 59if current_value == new_value : 60logger .info (f'- Key { repr ( args . key ) } already set to requested value { current_value } ' ) 61sys .exit (0 ) 62if args .dry_run : 63sys .exit (0 ) 64if not args .force : 65logger .warning ('*** Warning *** Warning *** Warning **' ) 66logger .warning ('* Changing fields in a GGUF file can make it unusable. Proceed at your own risk.' ) 67logger .warning ('* Enter exactly YES if you are positive you want to proceed:' ) 68response = input ('YES, I am sure> ' ) 69if response != 'YES' : 70logger .info ("You didn't enter YES. Okay then, see ya!" ) 71sys .exit (0 ) 72field .parts [field .data [0 ]][0 ]= new_value 73logger .info ('* Field changed. Successful completion.' ) 74 75 76def main ()-> None : 77parser = argparse .ArgumentParser (description = "Set a simple value in GGUF file metadata" ) 78parser .add_argument ("model" ,type = str ,help = "GGUF format model filename" ) 79parser .add_argument ("key" ,type = str ,help = "Metadata key to set" ) 80parser .add_argument ("value" ,type = str ,help = "Metadata value to set" ) 81parser .add_argument ("--dry-run" ,action = "store_true" ,help = "Don't actually change anything" ) 82parser .add_argument ("--force" ,action = "store_true" ,help = "Change the field without confirmation" ) 83parser .add_argument ("--verbose" ,action = "store_true" ,help = "increase output verbosity" ) 84 85args = parser .parse_args (None if len (sys .argv )> 1 else ["--help" ]) 86 87logging .basicConfig (level = logging .DEBUG if args .verbose else logging .INFO ) 88 89logger .info (f'* Loading: { args . model } ' ) 90reader = GGUFReader (args .model ,'r' if args .dry_run else 'r+' ) 91set_metadata (reader ,args ) 92 93 94if __name__ == '__main__' : 95main ()