Files
laksjdjf-ComfyUI-Imatrix/utils.py
T
2025-06-03 22:38:47 +09:00

141 lines
5.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import os
import struct
from typing import Dict, List, Tuple, Sequence, Mapping, Union
def load_imatrix(
imatrix_file: str,
trace_env: str = "LLAMA_TRACE",
) -> Tuple[Dict[str, List[float]], str, int]:
"""
Parameters
----------
imatrix_file : str
読み込む .imatrix バイナリへのパス
trace_env : str, default "LLAMA_TRACE"
この環境変数がセットされていればデバッグ出力を行う
Returns
-------
imatrix_data : dict[str, list[float]]
エントリ名 → 重要度ベクトル
imatrix_dataset : str
ファイル末尾に埋め込まれたデータセット名(なければ "")
m_last_call : int
行列計算時のチャンク数(なければ 0)
"""
imatrix_data: Dict[str, List[float]] = {}
imatrix_dataset = ""
m_last_call = 0
with open(imatrix_file, "rb") as f:
# --- 1. 先頭: エントリ総数 ------------------------------------------
n_entries_bytes = f.read(4)
if len(n_entries_bytes) < 4:
raise ValueError(f"{imatrix_file}: no data")
n_entries = struct.unpack("<i", n_entries_bytes)[0]
if n_entries < 1:
raise ValueError(f"{imatrix_file}: n_entries < 1")
# --- 2. 各エントリを読み取る ----------------------------------------
for i in range(n_entries):
# 2-a. 名前長と名前文字列
name_len = struct.unpack("<i", f.read(4))[0]
name = f.read(name_len).decode("utf-8", errors="replace")
# 2-b. 呼び出し回数 ncall と 値の個数 nval
ncall, nval = struct.unpack("<ii", f.read(8))
if nval < 1:
raise ValueError(f"entry {i}: nval < 1")
# 2-c. nval 個の float32
buf = f.read(4 * nval)
if len(buf) < 4 * nval:
raise ValueError(f"entry {i}: data truncated")
values = list(struct.unpack(f"<{nval}f", buf))
# 2-d. 平均化
if ncall > 0:
values = [v / ncall for v in values]
imatrix_data[name] = values
if os.getenv(trace_env):
print(
f"load_imatrix: loaded data (size = {nval:6d}, "
f"ncall = {ncall:6d}) for '{name}'"
)
# --- 3. 末尾に追加メタ情報があるか確認 ------------------------------
tail = f.read(4)
if tail: # まだバイトが残っている場合のみ
m_last_call = struct.unpack("<i", tail)[0]
dataset_len = struct.unpack("<i", f.read(4))[0]
imatrix_dataset = f.read(dataset_len).decode("utf-8", errors="replace")
if os.getenv(trace_env):
print(f"load_imatrix: imatrix dataset = '{imatrix_dataset}'")
print(
f"load_imatrix: loaded {len(imatrix_data)} importance matrix entries "
f"from {imatrix_file} computed on {m_last_call} chunks"
)
return imatrix_data, imatrix_dataset, m_last_call
def save_imatrix(
imatrix_file: str,
imatrix_data: Mapping[str, Sequence[float]],
*,
call_counts: Union[int, Mapping[str, int]] = 1,
imatrix_dataset: str = "",
m_last_call: int = 0,
) -> None:
"""
Parameters
----------
imatrix_file : str
出力する .imatrix バイナリのパス
imatrix_data : dict[str, Sequence[float]]
エントリ名 → 値のベクトル(平均済み/未平均どちらでも OK)
call_counts : int | dict[str, int], default 1
・各エントリ共通の呼び出し回数 (= 平均化係数) を 1 つの int で指定
・あるいはエントリごとに dict で指定
※「すでに平均済みの値」を保存したいときは 0 を渡してください
imatrix_dataset : str, default ""
ファイル末尾に埋め込むデータセット名(空文字なら書き込まない)
m_last_call : int, default 0
全体のチャンク数。dataset 名を書くときはセットで入れる
"""
# 入力バリデーション ---------------------------------------------------
if isinstance(call_counts, int):
call_counts = {k: call_counts for k in imatrix_data.keys()}
else:
# dict で来た場合、全キーがそろっているか確認
missing = set(imatrix_data) - set(call_counts)
if missing:
raise KeyError(f"call_counts is missing keys: {missing}")
with open(imatrix_file, "wb") as f:
# 1. 先頭: エントリ総数 -------------------------------------------
n_entries = len(imatrix_data)
f.write(struct.pack("<i", n_entries))
# 2. 各エントリを順番に書き込む -----------------------------------
for name, values in imatrix_data.items():
name_b = name.encode("utf-8")
f.write(struct.pack("<i", len(name_b))) # name length
f.write(name_b) # name bytes
ncall = call_counts[name]
nval = len(values)
f.write(struct.pack("<ii", ncall, nval)) # ncall, nval
# nval 個の float32
fmt = f"<{nval}f"
f.write(struct.pack(fmt, *values))
# 3. オプションのメタ情報 -----------------------------------------
if imatrix_dataset:
f.write(struct.pack("<i", m_last_call))
dataset_b = imatrix_dataset.encode("utf-8")
f.write(struct.pack("<i", len(dataset_b)))
f.write(dataset_b)