mirror of
https://github.com/LostRuins/koboldcpp.git
synced 2026-09-19 01:05:09 +02:00
safetensors file analyze
This commit is contained in:
+50
-11
@@ -1681,6 +1681,42 @@ def dump_gguf_metadata(file_path): #if you're gonna copy this into your own proj
|
||||
print(f"Error Analyzing File: {e}")
|
||||
return
|
||||
|
||||
def dump_safetensors_metadata(file_path):
|
||||
with open(file_path, 'rb') as f:
|
||||
size_bytes = f.read(8)
|
||||
if len(size_bytes) != 8:
|
||||
raise ValueError("Safetensors file is too small to contain a header.")
|
||||
header_size = struct.unpack('<Q', size_bytes)[0]
|
||||
# Bound the allocation before reading the JSON header. Tensor data is never read.
|
||||
if header_size > 100_000_000:
|
||||
raise ValueError("Safetensors header exceeds the 100 MB limit.")
|
||||
if header_size < 2 or header_size > os.fstat(f.fileno()).st_size - 8:
|
||||
raise ValueError("Invalid safetensors header length.")
|
||||
header_bytes = f.read(header_size)
|
||||
if len(header_bytes) != header_size:
|
||||
raise ValueError("Truncated safetensors header.")
|
||||
if not header_bytes.startswith(b'{'):
|
||||
raise ValueError("Safetensors header must start with a JSON object.")
|
||||
header = json.loads(header_bytes.decode('utf-8'))
|
||||
|
||||
metadata = header.pop('__metadata__', {})
|
||||
if not isinstance(metadata, dict) or any(not isinstance(v, str) for v in metadata.values()):
|
||||
raise ValueError("Invalid safetensors metadata: expected string values.")
|
||||
for name, tensor in header.items():
|
||||
if not isinstance(tensor, dict) or not isinstance(tensor.get('dtype'), str):
|
||||
raise ValueError(f"Invalid safetensors tensor descriptor: {name}")
|
||||
shape = tensor.get('shape')
|
||||
if not isinstance(shape, list) or any(type(d) is not int or d < 0 for d in shape):
|
||||
raise ValueError(f"Invalid safetensors tensor shape: {name}")
|
||||
|
||||
print(f"*** SAFETENSORS FILE METADATA ***\nSafetensors.tensor_count = {len(header)}\nSafetensors.kv_count = {len(metadata)}")
|
||||
for key, value in metadata.items():
|
||||
print(f"str: {key} = {value}")
|
||||
print("\n*** SAFETENSORS TENSOR INFO ***")
|
||||
for kn, (name, tensor) in enumerate(header.items()):
|
||||
print(f"{kn:<3}: {tensor['dtype']:<8} | {name:<30} | {tensor['shape']}")
|
||||
print(f"Metadata and TensorInfo Bytes: {8 + header_size}")
|
||||
|
||||
def read_gguf_metadata(file_path):
|
||||
chunk_size = 16384 # read only first 16kb of file
|
||||
try:
|
||||
@@ -9733,15 +9769,15 @@ def show_gui():
|
||||
# extra tab
|
||||
extra_tab = tabcontent["Extra"]
|
||||
makelabel(extra_tab, "Extract KoboldCpp Files", 3, 0,tooltiptxt="Unpack KoboldCpp to a local directory to modify its files. You can also launch via koboldcpp.py for faster startup.")
|
||||
ctk.CTkButton(extra_tab , text = "Unpack KoboldCpp To Folder", command = unpack_to_dir ).grid(row=3,column=0, stick="w", padx=(170), pady=2)
|
||||
ctk.CTkButton(extra_tab , text = "Unpack KoboldCpp To Folder", command = unpack_to_dir ).grid(row=3,column=0, stick="w", padx=(210), pady=2)
|
||||
makelabel(extra_tab, "Export as .kcppt template", 4, 0,tooltiptxt="Creates a KoboldCpp launch template for others to use.\nEmbeds JSON files directly into exported file when saving.\nWhen loaded, forces the backend to be automatically determined.\nWarning! Not recommended for beginners!")
|
||||
ctk.CTkButton(extra_tab , text = "Generate LaunchTemplate", command = kcpp_export_template ).grid(row=4,column=0, stick="w", padx=(170), pady=2)
|
||||
makelabel(extra_tab, "Analyze GGUF Metadata", 6, 0,tooltiptxt="Reads the metadata, weight types and tensor names in any GGUF file.")
|
||||
ctk.CTkButton(extra_tab , text = "Analyze GGUF", command = analyze_gguf_model_wrapper ).grid(row=6,column=0, stick="w", padx=(170), pady=2)
|
||||
ctk.CTkButton(extra_tab , text = "Generate LaunchTemplate", command = kcpp_export_template ).grid(row=4,column=0, stick="w", padx=(210), pady=2)
|
||||
makelabel(extra_tab, "Analyze GGUF/Safetensors File", 6, 0,tooltiptxt="Reads the metadata, weight types and tensor names in any GGUF or safetensors file.")
|
||||
ctk.CTkButton(extra_tab , text = "Analyze Model", command = analyze_gguf_model_wrapper ).grid(row=6,column=0, stick="w", padx=(210), pady=2)
|
||||
if os.name == 'nt':
|
||||
makelabel(extra_tab, "File Extensions Handler", 10, 0,tooltiptxt="Makes KoboldCpp the default handler for .kcpps, .kcppt, .ggml and .gguf files.")
|
||||
ctk.CTkButton(extra_tab , text = "Register", width=90, command = register_koboldcpp ).grid(row=10,column=0, stick="w", padx= (170), pady=2)
|
||||
ctk.CTkButton(extra_tab , text = "Unregister", width=90, command = unregister_koboldcpp ).grid(row=10,column=0, stick="w", padx= (264), pady=2)
|
||||
ctk.CTkButton(extra_tab , text = "Register", width=90, command = register_koboldcpp ).grid(row=10,column=0, stick="w", padx= (210), pady=2)
|
||||
ctk.CTkButton(extra_tab , text = "Unregister", width=90, command = unregister_koboldcpp ).grid(row=10,column=0, stick="w", padx= (304), pady=2)
|
||||
if sys.platform == "linux":
|
||||
def togglezenity(a,b,c):
|
||||
global zenity_permitted
|
||||
@@ -9775,7 +9811,7 @@ def show_gui():
|
||||
print(f"Spawn Extra Terminal Failed: {e}")
|
||||
if sys.platform == "linux":
|
||||
makelabel(extra_tab, "Spawn Terminal Logs", 12, 0,tooltiptxt="A simple terminal logger that duplicates the command line output.")
|
||||
ctk.CTkButton(extra_tab , text = "Spawn Terminal", command = showtermlogs ).grid(row=12,column=0, stick="w", padx= 170, pady=2)
|
||||
ctk.CTkButton(extra_tab , text = "Spawn Terminal", command = showtermlogs ).grid(row=12,column=0, stick="w", padx= 210, pady=2)
|
||||
|
||||
# refresh
|
||||
runopts_var.trace_add("write", changerunmode)
|
||||
@@ -11199,7 +11235,10 @@ def download_model_from_url(url, permitted_types=[".gguf",".safetensors", ".ggml
|
||||
def analyze_gguf_model(args,filename):
|
||||
try:
|
||||
stime = datetime.now()
|
||||
dump_gguf_metadata(filename)
|
||||
if os.path.splitext(filename)[1].lower() == '.safetensors':
|
||||
dump_safetensors_metadata(filename)
|
||||
else:
|
||||
dump_gguf_metadata(filename)
|
||||
atime = (datetime.now() - stime).total_seconds()
|
||||
print(f"---\nAnalyzing completed in {atime:.2f}s.\n---",flush=True)
|
||||
except Exception as e:
|
||||
@@ -11209,11 +11248,11 @@ def analyze_gguf_model(args,filename):
|
||||
def analyze_gguf_model_wrapper(filename=""):
|
||||
if not filename or filename=="":
|
||||
try:
|
||||
filename = zentk_askopenfilename(title="Select GGUF to analyze")
|
||||
filename = zentk_askopenfilename(title="Select GGUF or safetensors file to analyze")
|
||||
except Exception as e:
|
||||
print(f"Cannot select file to analyze: {e}")
|
||||
if not filename or filename=="" or not os.path.exists(filename):
|
||||
print("Selected GGUF file not found. Please select a valid GGUF file to analyze.")
|
||||
print("Selected model file not found. Please select a valid GGUF or safetensors file to analyze.")
|
||||
return
|
||||
print("---")
|
||||
print(f"Analyzing {filename}, please wait...\n---",flush=True)
|
||||
@@ -12797,7 +12836,7 @@ if __name__ == '__main__':
|
||||
|
||||
#more advanced params
|
||||
advparser = parser.add_argument_group('Advanced Commands')
|
||||
advparser.add_argument("--analyze", metavar=('[filename]'), help="Reads the metadata, weight types and tensor names in any GGUF file.", default="")
|
||||
advparser.add_argument("--analyze", metavar=('[filename]'), help="Reads the metadata, weight types and tensor names in any GGUF or safetensors file.", default="")
|
||||
advparser.add_argument("--autofit","--fit","-fit", help="Forces autofit, which attempts to fit the model in the best possible way. Overrides everything else.", action='store_true')
|
||||
advparser.add_argument("--autofitpadding", metavar=('[padding in MB]'), help="How much spare allowance in MB should autofit reserve? If it's too little, the load might fail.", type=int, default=default_autofit_padding)
|
||||
advparser.add_argument("--batchsize","--blasbatchsize","--batch-size","-b", help="Sets the batch size used in batched processing (default 512). Setting it to -1 disables batched mode, but keeps other benefits like GPU offload.", type=int,choices=[-1,16,32,64,128,256,512,1024,2048,4096], default=512)
|
||||
|
||||
Reference in New Issue
Block a user