Files
iluvatar_w4a8_w8a8_quant/dev/functions/dequant.py
2026-10-23 15:00:59 +08:00

157 lines
4.2 KiB
Python

import re
import os
import json
import torch
from safetensors.torch import load_file
from .specs import *
from .utils import compile_ignore, get_ignore, estimate_gpu_bytes
from .dequant_register import DEQUANT_KERNEL_TABLE
from .config_builder import create_quant_config_builder, resolve_quant_artifacts, to_dequant_spec
from safetensors import safe_open
class LazyTensorDict(dict):
def __init__(self, base_tensors, tensor_index, input_dir):
super().__init__(base_tensors)
self.tensor_index = tensor_index
self.input_dir = input_dir
self.file_cache = {}
def _load_tensor(self, name):
file_name = self.tensor_index[name]
path = os.path.join(self.input_dir, file_name)
if file_name not in self.file_cache:
self.file_cache[file_name] = safe_open(path, framework="pt")
return self.file_cache[file_name].get_tensor(name)
def __getitem__(self, key):
try:
return super().__getitem__(key)
except KeyError:
# 键不在字典中,检查是否在索引中
if self.tensor_index and key in self.tensor_index:
tensor = self._load_tensor(key)
self[key] = tensor # 现在可以安全地添加
return tensor
else:
raise KeyError(key)
def __contains__(self, key):
if super().__contains__(key):
return True
if self.tensor_index and key in self.tensor_index:
return True
return False
def dequantize_(
tensors: dict[str, torch.Tensor],
qconfig: dict,
custom_dequant_config,
output_dtype=torch.bfloat16,
device: torch.device = "cpu",
**kwargs
):
ignore_exact, ignore_regex = compile_ignore(
get_ignore(qconfig),
get_ignore(custom_dequant_config),
)
builder = create_quant_config_builder(
qconfig,
custom_dequant_config,
model_type=kwargs.get("model_type")
)
outputs = {}
gpu_cache = {}
gpu_cache_size = 0
max_gpu_cache_size = 16 * (1024**3)
weight_names = list(tensors.keys())
# for weight_name in tensors.keys():
for weight_name in weight_names:
rq = builder.resolve(weight_name)
if rq is None: # 包含scale的一定不会在这里
assert "scale" not in weight_name, f"{weight_name}"
outputs[weight_name] = tensors[weight_name]
continue
assert not rq.dynamic, "Dynamic quantization not supported in offline dequant"
artifacts = resolve_quant_artifacts(weight_name, tensors, rq)
if artifacts is None:
# 跳过scale, shape等
continue
spec = to_dequant_spec(rq)
if spec not in DEQUANT_KERNEL_TABLE:
raise RuntimeError(f"No dequant kernel registered for {spec}")
kernel = DEQUANT_KERNEL_TABLE[spec]
gpu_cache_size += estimate_gpu_bytes(artifacts, rq)
try:
output = kernel(
artifacts=artifacts,
rq=rq,
output_dtype=output_dtype,
device=device,
)
except Exception as e:
print(weight_name)
raise e
# 处理名称
weight_name = weight_name.replace("weight_packed", "weight").replace("qweight", "weight")
gpu_cache[weight_name] = output
if gpu_cache_size >= max_gpu_cache_size:
for k, v in gpu_cache.items():
outputs[k] = v.cpu()
gpu_cache.clear()
gpu_cache_size = 0
for k, v in gpu_cache.items():
outputs[k] = v.cpu()
gpu_cache.clear()
gpu_cache_size = 0
return outputs
def dequant(file_name: str,
quant_config,
custom_dequant_config,
device: torch.device,
model_type,
tensor_index=None,
input_dir=None):
base_tensors = load_file(file_name)
if tensor_index is not None:
tensors = LazyTensorDict(base_tensors, tensor_index, input_dir)
else:
tensors = base_tensors
return dequantize_(tensors, quant_config, custom_dequant_config, device=device, model_type=model_type)
if __name__ == "__main__":
...