char-fork/llama.cpp
git clone https://git.t4t.associates/char-fork/llama.cpp
72b44c0d2
char/aliceai-t5-moe
1#!/usr/bin/env python3 2 3import argparse 4import json 5import os 6import re 7import struct 8import sys 9from pathlib import Path 10from typing import Optional 11from safetensors import safe_open 12 13 14MODEL_SAFETENSORS_FILE = "model.safetensors" 15MODEL_SAFETENSORS_INDEX = "model.safetensors.index.json" 16 17DTYPE_SIZES = { 18"F64" :8 ,"I64" :8 ,"U64" :8 , 19"F32" :4 ,"I32" :4 ,"U32" :4 , 20"F16" :2 ,"BF16" :2 ,"I16" :2 ,"U16" :2 , 21"I8" :1 ,"U8" :1 ,"BOOL" :1 , 22"F8_E4M3" :1 ,"F8_E5M2" :1 , 23} 24 25SIZE_UNITS = ['B' ,'KB' ,'MB' ,'GB' ,'TB' ] 26 27 28def get_weight_map (model_path :Path )-> Optional [dict [str ,str ]]: 29index_file = model_path / MODEL_SAFETENSORS_INDEX 30 31if index_file .exists (): 32with open (index_file ,'r' )as f : 33index = json .load (f ) 34return index .get ("weight_map" , {}) 35 36return None 37 38 39def get_all_tensor_names (model_path :Path )-> list [str ]: 40weight_map = get_weight_map (model_path ) 41 42if weight_map is not None : 43return list (weight_map .keys ()) 44 45single_file = model_path / MODEL_SAFETENSORS_FILE 46if single_file .exists (): 47try : 48with safe_open (single_file ,framework = "pt" ,device = "cpu" )as f : 49return list (f .keys ()) 50except Exception as e : 51f"Error reading { single_file } : { e } " ) 52sys .exit (1 ) 53 54f"Error: No safetensors files found in { model_path } " ) 55sys .exit (1 ) 56 57 58def find_tensor_file (model_path :Path ,tensor_name :str )-> Optional [str ]: 59weight_map = get_weight_map (model_path ) 60 61if weight_map is not None : 62return weight_map .get (tensor_name ) 63 64single_file = model_path / MODEL_SAFETENSORS_FILE 65if single_file .exists (): 66return single_file .name 67 68return None 69 70 71def read_safetensors_header (file_path :Path )-> dict : 72with open (file_path ,'rb' )as f : 73header_size = struct .unpack ('<Q' ,f .read (8 ))[0 ] 74return json .loads (f .read (header_size )) 75 76 77def get_tensor_size_bytes (tensor_meta :dict )-> int : 78offsets = tensor_meta .get ("data_offsets" ) 79if offsets and len (offsets )== 2 : 80return offsets [1 ]- offsets [0 ] 81n_elements = 1 82for d in tensor_meta .get ("shape" , []): 83n_elements *= d 84return n_elements * DTYPE_SIZES .get (tensor_meta .get ("dtype" ,"F32" ),4 ) 85 86 87def format_size (size_bytes :int )-> str : 88val = float (size_bytes ) 89for unit in SIZE_UNITS [:- 1 ]: 90if val < 1024.0 : 91return f" { val :.2f } { unit } " 92val /= 1024.0 93return f" { val :.2f } { SIZE_UNITS [ - 1 ] } " 94 95 96def get_all_tensor_metadata (model_path :Path )-> dict [str ,dict ]: 97weight_map = get_weight_map (model_path ) 98 99if weight_map is not None : 100file_to_tensors :dict [str ,list [str ]]= {} 101for tensor_name ,file_name in weight_map .items (): 102file_to_tensors .setdefault (file_name , []).append (tensor_name ) 103 104all_metadata :dict [str ,dict ]= {} 105for file_name ,tensor_names in file_to_tensors .items (): 106try : 107header = read_safetensors_header (model_path / file_name ) 108for tensor_name in tensor_names : 109if tensor_name in header : 110all_metadata [tensor_name ]= header [tensor_name ] 111except Exception as e : 112f"Warning: Could not read header from { file_name } : { e } " ,file = sys .stderr ) 113return all_metadata 114 115single_file = model_path / MODEL_SAFETENSORS_FILE 116if single_file .exists (): 117try : 118header = read_safetensors_header (single_file ) 119return {k :v for k ,v in header .items ()if k != "__metadata__" } 120except Exception as e : 121f"Error reading { single_file } : { e } " ) 122sys .exit (1 ) 123 124f"Error: No safetensors files found in { model_path } " ) 125sys .exit (1 ) 126 127 128def normalize_tensor_name (tensor_name :str )-> str : 129normalized = re .sub (r'\.\d+\.' ,'.#.' ,tensor_name ) 130normalized = re .sub (r'\.\d+$' ,'.#' ,normalized ) 131return normalized 132 133 134def list_all_tensors ( 135model_path :Path , 136short :bool = False , 137show_sizes :bool = False , 138): 139tensor_names = get_all_tensor_names (model_path ) 140 141metadata :Optional [dict [str ,dict ]]= None 142if show_sizes : 143metadata = get_all_tensor_metadata (model_path ) 144 145total_bytes = 0 146 147if short : 148seen :dict [str ,str ]= {} 149for tensor_name in sorted (tensor_names ): 150normalized = normalize_tensor_name (tensor_name ) 151if normalized not in seen : 152seen [normalized ]= tensor_name 153display_pairs = list (sorted (seen .items ())) 154name_width = max ((len (n )for n ,_ in display_pairs ),default = 0 ) 155for normalized ,first_name in display_pairs : 156if metadata and first_name in metadata : 157m = metadata [first_name ] 158size = get_tensor_size_bytes (m ) 159total_bytes += size 160f" { normalized :{ name_width } } { m . get ( 'dtype' , '?' ):6s } { str ( m . get ( 'shape' , '' )):30s } { format_size ( size ) } " ) 161else : 162normalized ) 163else : 164name_width = max ((len (n )for n in tensor_names ),default = 0 ) 165for tensor_name in sorted (tensor_names ): 166if metadata and tensor_name in metadata : 167m = metadata [tensor_name ] 168size = get_tensor_size_bytes (m ) 169total_bytes += size 170f" { tensor_name :{ name_width } } { m . get ( 'dtype' , '?' ):6s } { str ( m . get ( 'shape' , '' )):30s } { format_size ( size ) } " ) 171else : 172tensor_name ) 173 174if show_sizes : 175f"\nTotal: { format_size ( total_bytes ) } " ) 176 177 178def print_tensor_info (model_path :Path ,tensor_name :str ,num_values :Optional [int ]= None ): 179tensor_file = find_tensor_file (model_path ,tensor_name ) 180 181if tensor_file is None : 182f"Error: Could not find tensor ' { tensor_name } ' in model index" ) 183f"Model path: { model_path } " ) 184sys .exit (1 ) 185 186file_path = model_path / tensor_file 187 188try : 189header = read_safetensors_header (file_path ) 190tensor_meta = header .get (tensor_name , {}) 191dtype_str = tensor_meta .get ("dtype" ) 192 193with safe_open (file_path ,framework = "pt" ,device = "cpu" )as f : 194if tensor_name in f .keys (): 195tensor_slice = f .get_slice (tensor_name ) 196shape = tensor_slice .get_shape () 197f"Tensor: { tensor_name } " ) 198f"File: { tensor_file } " ) 199f"Shape: { shape } " ) 200if dtype_str : 201f"Dtype: { dtype_str } " ) 202if tensor_meta : 203f"Size: { format_size ( get_tensor_size_bytes ( tensor_meta )) } " ) 204if num_values is not None : 205tensor = f .get_tensor (tensor_name ) 206if not dtype_str : 207f"Dtype: { tensor . dtype } " ) 208flat = tensor .flatten () 209n = min (num_values ,flat .numel ()) 210f"Values: { flat [: n ]. tolist () } " ) 211else : 212f"Error: Tensor ' { tensor_name } ' not found in { tensor_file } " ) 213sys .exit (1 ) 214 215except FileNotFoundError : 216f"Error: The file ' { file_path } ' was not found." ) 217sys .exit (1 ) 218except Exception as e : 219f"An error occurred: { e } " ) 220sys .exit (1 ) 221 222 223def main (): 224parser = argparse .ArgumentParser ( 225description = "Print tensor information from a safetensors model" 226 ) 227parser .add_argument ( 228"tensor_name" , 229nargs = "?" , 230help = "Name of the tensor to inspect" 231 ) 232parser .add_argument ( 233"-m" ,"--model-path" , 234type = Path , 235help = "Path to the model directory (default: MODEL_PATH environment variable)" 236 ) 237parser .add_argument ( 238"-l" ,"--list-all-short" , 239action = "store_true" , 240help = "List unique tensor patterns (layer numbers replaced with #)" 241 ) 242parser .add_argument ( 243"-la" ,"--list-all" , 244action = "store_true" , 245help = "List all tensor names with actual layer numbers" 246 ) 247parser .add_argument ( 248"-n" ,"--num-values" , 249nargs = "?" , 250const = 10 , 251default = None , 252type = int , 253metavar = "N" , 254help = "Print the first N values of the tensor flattened (default: 10 if flag is given without a number)" 255 ) 256parser .add_argument ( 257"-s" ,"--sizes" , 258action = "store_true" , 259help = "Show dtype, shape, and size for each tensor when listing" 260 ) 261 262args = parser .parse_args () 263 264model_path = args .model_path 265if model_path is None : 266model_path_str = os .environ .get ("MODEL_PATH" ) 267if model_path_str is None : 268"Error: --model-path not provided and MODEL_PATH environment variable not set" ) 269sys .exit (1 ) 270model_path = Path (model_path_str ) 271 272if not model_path .exists (): 273f"Error: Model path does not exist: { model_path } " ) 274sys .exit (1 ) 275 276if not model_path .is_dir (): 277f"Error: Model path is not a directory: { model_path } " ) 278sys .exit (1 ) 279 280if args .list_all_short or args .list_all : 281list_all_tensors (model_path ,short = args .list_all_short ,show_sizes = args .sizes ) 282else : 283if args .tensor_name is None : 284"Error: tensor_name is required when not using --list-all-short or --list-all" ) 285sys .exit (1 ) 286print_tensor_info (model_path ,args .tensor_name ,args .num_values ) 287 288 289if __name__ == "__main__" : 290main ()