char-fork/llama.cpp
git clone https://git.t4t.associates/char-fork/llama.cpp
020760adf
char/aliceai-t5-moe
1#!/usr/bin/env python3 2from __future__import annotations 3 4import logging 5import argparse 6import os 7import sys 8from tqdm import tqdm 9from pathlib import Path 10 11import numpy as np 12 13# Necessary to load the local gguf package 14if "NO_LOCAL_GGUF" not in os .environ and (Path (__file__ ).parent .parent .parent .parent / 'gguf-py' ).exists (): 15sys .path .insert (0 ,str (Path (__file__ ).parent .parent .parent )) 16 17import gguf 18 19logger = logging .getLogger ("gguf-convert-endian" ) 20 21 22def byteswap_noop (tensor ,block_offs ): 23# this function is used when byteswapping is not needed 24pass 25 26 27def byteswap_q4_0 (tensor ,block_offs ): 28# Each block_q4_0 consists of an f16 delta (scaling factor) followed by 16 int8 quantizations. 29 30# Byte-Swap f16 sized delta field 31delta = tensor .data [block_offs :block_offs + 2 ].view (dtype = np .uint16 ) 32delta .byteswap (inplace = True ) 33 34 35def byteswap_q8_0 (tensor ,block_offs ): 36# Each block_q8_0 consists of an f16 delta (scaling factor) followed by 32 int8 quantizations. 37 38# Byte-Swap f16 sized delta field 39delta = tensor .data [block_offs :block_offs + 2 ].view (dtype = np .uint16 ) 40delta .byteswap (inplace = True ) 41 42 43def byteswap_q4_k (tensor ,block_offs ): 44# Each block_q4_k consists of 2 f16 values followed by 140 int8 values. 45 46# Byte-Swap f16 sized fields 47delta = tensor .data [block_offs :block_offs + 2 ].view (dtype = np .uint16 ) 48delta .byteswap (inplace = True ) 49 50delta = tensor .data [block_offs + 2 :block_offs + 4 ].view (dtype = np .uint16 ) 51delta .byteswap (inplace = True ) 52 53 54def byteswap_q6_k (tensor ,block_offs ): 55# Each block_q6_k consists of 208 int8 values followed by 1 f16 value. 56 57# Byte-Swap f16 sized field 58delta = tensor .data [block_offs + 208 :block_offs + 210 ].view (dtype = np .uint16 ) 59delta .byteswap (inplace = True ) 60 61 62def byteswap_q1_0 (tensor ,block_offs ): 63# Each block_q1_0 consists of an f16 delta followed by 16 int8 quantizations. 64 65# Byte-Swap f16 sized delta field 66delta = tensor .data [block_offs :block_offs + 2 ].view (dtype = np .uint16 ) 67delta .byteswap (inplace = True ) 68 69 70def byteswap_tq2_0 (tensor ,block_offs ): 71# Each block_tq2_0 consists of 64 int8 values followed by 1 f16 value. 72 73# Byte-Swap f16 sized field 74delta = tensor .data [block_offs + 64 :block_offs + 66 ].view (dtype = np .uint16 ) 75delta .byteswap (inplace = True ) 76 77 78byteswap_tensors = { 79gguf .GGMLQuantizationType .Q1_0 :byteswap_q1_0 , 80gguf .GGMLQuantizationType .Q4_0 :byteswap_q4_0 , 81gguf .GGMLQuantizationType .Q8_0 :byteswap_q8_0 , 82gguf .GGMLQuantizationType .Q4_K :byteswap_q4_k , 83gguf .GGMLQuantizationType .Q6_K :byteswap_q6_k , 84gguf .GGMLQuantizationType .TQ2_0 :byteswap_tq2_0 , 85gguf .GGMLQuantizationType .MXFP4 :byteswap_noop , 86gguf .GGMLQuantizationType .NVFP4 :byteswap_noop , 87} 88 89 90def convert_byteorder (reader :gguf .GGUFReader ,args :argparse .Namespace )-> None : 91file_endian = reader .endianess .name 92if reader .byte_order == 'S' : 93host_endian = 'BIG' if file_endian == 'LITTLE' else 'LITTLE' 94else : 95host_endian = file_endian 96order = host_endian if args .order == "native" else args .order .upper () 97logger .info (f"* Host is { host_endian } endian, GGUF file seems to be { file_endian } endian" ) 98if file_endian == order : 99logger .info (f"* File is already { order } endian. Nothing to do." ) 100sys .exit (0 ) 101logger .info ("* Checking tensors for conversion compatibility" ) 102for tensor in reader .tensors : 103if tensor .tensor_type not in byteswap_tensors and \ 104tensor .tensor_type not in ( 105gguf .GGMLQuantizationType .F32 , 106gguf .GGMLQuantizationType .F16 , 107gguf .GGMLQuantizationType .BF16 , 108 ): 109raise ValueError (f"Cannot handle type { tensor . tensor_type . name } for tensor { repr ( tensor . name ) } " ) 110logger .info (f"* Preparing to convert from { file_endian } to { order } " ) 111if args .dry_run : 112return 113logger .warning ("*** Warning *** Warning *** Warning **" ) 114logger .warning ("* This conversion process may damage the file. Ensure you have a backup." ) 115if order != host_endian : 116logger .warning ("* Requested endian differs from host, you will not be able to load the model on this machine." ) 117logger .warning ("* The file will be modified immediately, so if conversion fails or is interrupted" ) 118logger .warning ("* the file will be corrupted. Enter exactly YES if you are positive you want to proceed:" ) 119response = input ("YES, I am sure> " ) 120if response != "YES" : 121logger .warning ("You didn't enter YES. Okay then, see ya!" ) 122sys .exit (0 ) 123logger .info (f"* Converting fields ( { len ( reader . fields ) } )" ) 124for idx ,field in enumerate (reader .fields .values ()): 125logger .info (f"- { idx :4 } : Converting field { repr ( field . name ) } , part count: { len ( field . parts ) } " ) 126for part in field .parts : 127part .byteswap (inplace = True ) 128logger .info (f"* Converting tensors ( { len ( reader . tensors ) } )" ) 129 130for idx ,tensor in enumerate (pbar := tqdm (reader .tensors ,desc = "Converting tensor" )): 131log_message = ( 132f"Converting tensor { repr ( tensor . name ) } , " 133f"type= { tensor . tensor_type . name } , " 134f"elements= { tensor . n_elements } " 135 ) 136 137# Byte-swap each part of the tensor's field 138for part in tensor .field .parts : 139part .byteswap (inplace = True ) 140 141# Byte-swap tensor data if necessary 142if tensor .tensor_type in byteswap_tensors : 143# first flatten structure 144oldshape = tensor .data .shape 145newshape = 1 146for i in tensor .data .shape : 147newshape *= i 148 149tensor .data .resize (newshape ) 150 151block_size = gguf .constants .GGML_QUANT_SIZES [tensor .tensor_type ][1 ] 152byteswap_func = byteswap_tensors [tensor .tensor_type ] 153 154n_blocks = len (tensor .data )// block_size 155for block_num in (inner_pbar := tqdm (range (n_blocks ),desc = "Byte-swapping Blocks" ,leave = False )): 156block_offs = block_num * block_size 157 158byteswap_func (tensor ,block_offs ) 159 160if block_num % 100000 == 0 : 161inner_pbar .set_description (f"Byte-swapping Blocks [ { ( n_blocks - block_num ) // n_blocks } ]" ) 162 163# restore old shape in case it's ever used 164tensor .data .resize (oldshape ) 165elif tensor .tensor_type == gguf .GGMLQuantizationType .BF16 : 166# Special case for BF16 167# It is 2-bytes data, but by default view loads it as 1-byte data. 168# Change to correct view before byteswapping. 169tensor .data .view (dtype = np .uint16 ).byteswap (inplace = True ) 170else : 171# Handle other tensor types 172tensor .data .byteswap (inplace = True ) 173 174pbar .set_description (log_message ) 175 176logger .info ("* Completion" ) 177 178 179def main ()-> None : 180parser = argparse .ArgumentParser (description = "Convert GGUF file byte order" ) 181parser .add_argument ( 182"model" ,type = str , 183help = "GGUF format model filename" , 184 ) 185parser .add_argument ( 186"order" ,type = str ,choices = ['big' ,'little' ,'native' ], 187help = "Requested byte order" , 188 ) 189parser .add_argument ( 190"--dry-run" ,action = "store_true" , 191help = "Don't actually change anything" , 192 ) 193parser .add_argument ("--verbose" ,action = "store_true" ,help = "increase output verbosity" ) 194 195args = parser .parse_args (None if len (sys .argv )> 1 else ["--help" ]) 196 197logging .basicConfig (level = logging .DEBUG if args .verbose else logging .INFO ) 198 199logger .info (f'* Loading: { args . model } ' ) 200reader = gguf .GGUFReader (args .model ,'r' if args .dry_run else 'r+' ) 201convert_byteorder (reader ,args ) 202 203 204if __name__ == "__main__" : 205main ()