Files
wehub-resource-sync 770d92cb1f
Lint / lint (push) Has been cancelled
Build Docs / Deploy Docs (push) Has been cancelled
Windows CI / Windows (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:23:58 +08:00

179 lines
6.1 KiB
Python

"""Help functions for detecting weight paths and weight formats."""
import json
from pathlib import Path
from typing import List, Optional, Tuple # noqa: UP035
from . import logging
from .style import bold, green, red
logger = logging.getLogger(__name__)
FOUND = green("Found")
NOT_FOUND = red("Not found")
def detect_weight(
weight_path: Path,
config_json_path: Path,
weight_format: str = "auto",
) -> Tuple[Path, str]: # noqa: UP006
"""Detect the weight directory, and detect the weight format.
Parameters
---------
weight_path : pathlib.Path
The path to weight files. If `weight_path` is not None, check if it exists. Otherwise, find
`weight_path` in `config.json` or use the same directory as `config.json`.
config_json_path: pathlib.Path
The path to `config.json`.
weight_format : str
The hint for the weight format. If it is "auto", guess the weight format.
Otherwise, check the weights are in that format.
Available weight formats:
- auto (guess the weight format)
- huggingface-torch (validate via checking pytorch_model.bin.index.json)
- huggingface-safetensor (validate via checking model.safetensors.index.json)
- awq
- ggml
- gguf
Returns
-------
weight_config_path : pathlib.Path
The path that points to the weights config file or the weights directory.
weight_format : str
The valid weight format.
"""
if weight_path is None:
assert config_json_path is not None and config_json_path.exists(), (
"Please provide config.json path."
)
# 1. Find the weight_path in config.json
with open(config_json_path, encoding="utf-8") as i_f:
config = json.load(i_f)
if "weight_path" in config:
weight_path = Path(config["weight_path"])
logger.info('Found "weight_path" in config.json: %s', weight_path)
if not weight_path.exists():
raise ValueError(f"weight_path doesn't exist: {weight_path}")
else:
# 2. Find the weights file in the same directory as config.json
weight_path = config_json_path.parent
else:
if not weight_path.exists():
raise ValueError(f"weight_path doesn't exist: {weight_path}")
logger.info("Finding weights in: %s", weight_path)
# check weight format
# weight_format = "auto", guess the weight format.
# otherwise, check the weight format is valid.
if weight_format == "auto":
return _guess_weight_format(weight_path)
if weight_format not in AVAILABLE_WEIGHT_FORMAT:
raise ValueError(
f"Available weight format list: {AVAILABLE_WEIGHT_FORMAT}, but got {weight_format}"
)
if weight_format in CHECK_FORMAT_METHODS:
check_func = CHECK_FORMAT_METHODS[weight_format]
weight_config_path = check_func(weight_path)
if not weight_config_path:
raise ValueError(f"The weight is not in {weight_format} format.")
else:
weight_config_path = weight_path
return weight_config_path, weight_format
def _guess_weight_format(weight_path: Path) -> Tuple[Path, str]: # noqa: UP006
possible_formats: List[Tuple[Path, str]] = [] # noqa: UP006
for weight_format, check_func in CHECK_FORMAT_METHODS.items():
weight_config_path = check_func(weight_path)
if weight_config_path:
possible_formats.append((weight_config_path, weight_format))
if len(possible_formats) == 0:
raise ValueError(
"Fail to detect source weight format. "
"Use `--source-format` to explicitly specify the format."
)
weight_config_path, selected_format = possible_formats[0]
logger.info(
"Using source weight configuration: %s. Use `--source` to override.",
bold(str(weight_config_path)),
)
logger.info(
"Using source weight format: %s. Use `--source-format` to override.",
bold(selected_format),
)
return weight_config_path, selected_format
def _check_pytorch(weight_path: Path) -> Optional[Path]:
pytorch_json_path = weight_path / "pytorch_model.bin.index.json"
if pytorch_json_path.exists():
logger.info(
"%s source weight format: huggingface-torch. Source configuration: %s",
FOUND,
pytorch_json_path,
)
return pytorch_json_path
pytorch_file_path = weight_path / "pytorch_model.bin"
if pytorch_file_path.exists():
logger.info(
"%s source weight format: huggingface-torch. Source configuration: %s",
FOUND,
pytorch_file_path,
)
return pytorch_file_path
logger.info("%s Huggingface PyTorch", NOT_FOUND)
return None
def _check_safetensor(weight_path: Path) -> Optional[Path]:
safetensor_json_path = weight_path / "model.safetensors.index.json"
if safetensor_json_path.exists():
logger.info(
"%s source weight format: huggingface-safetensor. Source configuration: %s",
FOUND,
safetensor_json_path,
)
return safetensor_json_path
safetensor_file_path = weight_path / "model.safetensors"
if safetensor_file_path.exists():
from safetensors.torch import (
load_file,
)
weights = load_file(safetensor_file_path, device="cpu")
weight_map = {key: "model.safetensors" for key in weights}
with open(safetensor_json_path, "w", encoding="utf-8") as file:
json.dump({"weight_map": weight_map}, file, indent=2)
logger.info(
"%s source weight format: huggingface-safetensor. Source configuration: %s",
FOUND,
safetensor_json_path,
)
return safetensor_json_path
logger.info("%s Huggingface Safetensor", NOT_FOUND)
return None
CHECK_FORMAT_METHODS = {
"huggingface-torch": _check_pytorch,
"huggingface-safetensor": _check_safetensor,
}
# "ggml", "gguf" are not supported yet.
AVAILABLE_WEIGHT_FORMAT = ["huggingface-torch", "huggingface-safetensor", "awq"]