llama.cpp-youtu-moe / prepare_vision_dir.py
gatilin's picture
Upload folder using huggingface_hub
7e0a8c6 verified
Raw History Blame Contribute Delete
1.86 kB
"""为视觉塔单独搭一个「仅含 shard24」的模型目录,便于在剩余分片下载完成前先导出 mmproj。
做法:只把含 model.visual.* 的分片软链进来,并把 index.json 过滤成只列该分片,
这样 convert_hf_to_gguf.py 的 index_tensors 不会去打开还没下完的分片。
"""
import json
import os
import shutil
from pathlib import Path
ROOT = Path(__file__).resolve().parent
SRC = ROOT / "models" / "Youtu-LLM-A7B-Base"
DST = ROOT / "models" / "youtu-vision-only"
DST.mkdir(parents=True, exist_ok=True)
idx = json.loads((SRC / "model.safetensors.index.json").read_text())
wm = idx["weight_map"]
vis = {k: v for k, v in wm.items() if k.startswith("model.visual.")}
if not vis:
raise SystemExit("没找到 model.visual.* 张量")
shards = sorted(set(vis.values()))
print(f"visual 张量 {len(vis)} 个,位于 {shards}")
if len(shards) != 1:
print("[warn] 视觉张量跨多个分片,需全部就绪")
# 过滤后的 index 必须把「就绪分片里的全部张量」都列上,
# 否则 index_tensors 的 weight_map / part 一致性校验会报 Extra tensors。
keep = {k: v for k, v in wm.items() if v in shards}
print(f"索引保留 {len(keep)} 个张量(含同分片的文本张量,转换时按名过滤)")
for s in shards:
src = SRC / s
if not src.exists():
raise SystemExit(f"缺少分片 {s},尚未下载完成")
dst = DST / s
if dst.exists() or dst.is_symlink():
dst.unlink()
os.symlink(os.path.relpath(src, DST), dst)
for f in SRC.iterdir():
if f.is_file() and f.suffix in (".json", ".jinja", ".txt", ".py") and not f.name.endswith(".parts.json"):
shutil.copy2(f, DST / f.name)
(DST / "model.safetensors.index.json").write_text(
json.dumps({"metadata": {"total_size": 0}, "weight_map": keep}, indent=2)
)
print(f"已准备 {DST}")