技能创建器
skill-creator
创建、改进和评估自定义技能,把专业流程转化为可重复使用的 AI 能力。
re-ai-model【数据与研究】AI 模型文件逆向与静态分析:ONNX/PyTorch/Safetensors/TFLite 格式解析、 网络结构还原、权重提取、文件级水印分析(权重 pattern/metadata/tensor hash/embedding 异常)。 触发词:模型文件、权重提取、ONNX解析、safetensors、pth分析、pt文件、模型结构还原、文件级水印
独立 GitHub 快照 · 自动分类 · 以原作者文档为准
参考 [[re-analyze/platform-tips]]——模型文件 GB 级常见,静态分析按「静态优先(大型样本)」思路:先格式识别与结构解析,按需提取权重,不整载内存(坑 1)。
apt install python3 / dnf install python3 / pacman -S pythonbrew install python3;Windows: choco install pythonpython3 --version(本技能脚本均为 Python 3)pip install onnx(官方 PyPI;当前 onnx 要求 Python 3.10+,具体版本以 PyPI Requires-Python 为准;自带 protobuf 依赖与 onnx.proto3 类型定义)python3 -c "import onnx; print(onnx.__version__)"pip install netron(官方 PyPI,无 Python 版本上界);桌面独立版可选: macOS brew install --cask netron、Windows winget install netron、Linux snap snap install netronnetron --help 有输出(pip show netron 查版本)netron model.onnx(本地起 http 服务并开浏览器可视化;--no-browser 无头模式)pip install torch(默认 PyPI 轮子为带 CUDA 全量包,数 GB;仅 CPU 分析用 pip install torch --index-url https://download.pytorch.org/whl/cpu)requires-python;torchvision 同步为 >=3.10)——3.9 环境要装需 pin 到仍支持 3.9 的旧版(2.8.x 及更早)。torch / torchvision / Python 的具体组合以官方 compatibility matrix 为准,别按「3.9+」泛化pip install torch(官方 wheel 为 CPU/arm64)python3 -c "import torch; print(torch.__version__)"weights_only=True,旧版本/显式 weights_only=False 仍有任意代码执行风险;未知模型先 unzip -l/xxd 粗查(坑 2),在隔离环境用 weights_only=True 加载,能转 safetensors 就转pip install safetensors;验证: python3 -c "import safetensors; print(safetensors.__version__)"pip install protobuf(当前 7.x 要求 Python >=3.10,6.x 起下限已在抬升;3.8/3.9 需 pin 对应旧版本。onnx 已自带依赖、通常无需单独装)apt install protobuf-compiler、Fedora dnf install protobuf-compiler、Arch pacman -S protobuf、macOS brew install protobufprotoc --version;python3 -c "import google.protobuf; print(google.protobuf.__version__)"按顺序执行,每步产物(模型哈希/结构摘要/权重清单)存档 sha256 + 路径([[re-ioc]] 证据链)。
模型格式识别(onnx / safetensors / pytorch pkl / tflite):
file model.bin && sha256sum model.bin > model.sha256 && xxd model.bin | head -2
0x08 + 变长值;值随 ONNX 版本递增:IR 8 对应 ONNX 1.10,当前发布已到 IR 13——所以第二个字节不是常量 08,不能拿 08 08 12 当识别特征);producer_name(tag 0x12,长度前缀)按规范只 SHOULD 出现,不保证紧跟其后;onnx.checker.check_model 可验证合法性struct.unpack("<Q", data[:8])),随后是 JSON 头(张量名/形状/dtype/偏移)file 显示 Zip archive(PK\x03\x04 头)——unzip -l model.pt 看条目(state_dict 含 data.pkl;torch.jit.script 含 data.pkl/constants.pkl/bytecode.pkl);老式纯 pkl 是裸 pickle 流(无 PK 头)——不直接 load,先 xxd/strings 粗看(坑 2)TFL3(对应 schema 的 __model_identifier 字段),xxd/strings 可见;结构解析可用 Netron(支持 .tflite 可视化),权重提取分支思路同 onnx(flatbuffers 解析,超出本技能深度时标注"结构化 dump 为准")结构解析(图/层/算子):
netron model.onnx --no-browser # 可视化(有图形界面再开浏览器)
python3 - <<'PY'
import onnx
m = onnx.load("model.onnx")
print("producer:", m.producer_name, m.producer_version) # 框架/优化器指纹(见坑 3)
g = m.graph
print("inputs:", [(i.name, [d.dim_value for d in i.type.tensor_type.shape.dim]) for i in g.input])
print("nodes:", len(g.node), "initializers:", len(g.initializer), "outputs:", [o.name for o in g.output])
for n in g.node[:20]:
print(n.op_type, n.name, list(n.input), "->", list(n.output))
PY
torch.jit.load 得 ScriptModule 可打印 model.graph(TorchScript 结构);torch.load 的 state_dict 只有张量没有网络结构——结构在训练/推理脚本里,需配合源码还原(见跨域 [[re-script-deob]])权重提取(张量 dump):
mkdir -p weights
# ONNX:逐 tensor 惰性落地(大模型见坑 1)
# 注意:这不是"流式"——to_array() 对使用 external data 的 tensor 会先把该张量【完整】读进 ndarray,
# 只是"一次一个张量"而不是"一次整个模型";显存/内存峰值取决于最大的那个张量
python3 - <<'PY'
import onnx, numpy as np
m = onnx.load("model.onnx", load_external_data=False) # 只载图结构,不载外部权重
for init in m.graph.initializer:
# base_dir 默认为空字符串——外部权重不在 CWD 时必须显式指定其所在目录
arr = onnx.numpy_helper.to_array(init, base_dir=".") # 该张量在此处被完整 materialize
np.save(f"weights/{init.name.replace('/', '_')}.npy", arr)
print(init.name, arr.shape, arr.dtype)
del arr # 及时释放,为下一张量让出内存
PY
# Safetensors:惰性按张量读取(不整载内存)
python3 - <<'PY'
from safetensors import safe_open
with safe_open("model.safetensors", framework="numpy") as f:
print(len(f.keys()), "tensors")
for k in list(f.keys())[:10]:
t = f.get_tensor(k); print(k, t.shape, t.dtype)
PY
# PyTorch state_dict(weights_only 安全加载,见坑 2)
python3 - <<'PY'
import torch
sd = torch.load("model.pth", weights_only=True)
for k, v in list(sd.items())[:10]:
print(k, tuple(v.shape) if hasattr(v, "shape") else type(v))
PY
模型水印/指纹检测(嵌入权重):
模型窃取判定(架构相似度):
python3 - <<'PY'
import onnx
from difflib import SequenceMatcher
m1 = onnx.load("suspect.onnx"); m2 = onnx.load("original.onnx")
s1 = [n.op_type for n in m1.graph.node]; s2 = [n.op_type for n in m2.graph.node]
print("op-seq similarity:", SequenceMatcher(None, s1, s2).ratio()) # 算子序列相似度
# 层对齐后逐层权重余弦/L2 距离:见步骤 4 的每层距离矩阵
PY
m.metadata_props(ONNX metadata 藏字符串/代码)、zip 条目中多余文件(坑 2 相关)、权重中形状/数值分布特异的异常张量onnx.load/torch.load 吃满内存卡死,netron 打开超时,np.save 批量写盘满;原因——权重数 GB,一次性整体加载到内存;对策——分析前先 du -sh/sha256sum 存档;ONNX 用 onnx.load(..., load_external_data=False) 只载图结构,再逐 tensor 取值——注意 numpy_helper.to_array() 对该 tensor 是完整读出(不是流式),所以峰值取决于最大的张量,且用 external data 时要显式给 base_dir(默认空字符串,权重不在 CWD 时直接失败);Safetensors 用 safe_open 惰性按张量读;PyTorch 大模型 torch.load(..., mmap=True);处理对象是"结构摘要 + 定向张量",不是整个文件AttributeError/ModuleNotFoundError;原因——pickle 协议可注入任意代码(__reduce__/__setstate__),torch.load 底层就是 pickle,恶意模型是投毒载荷载体;对策——安全提示:未知模型绝不直接 torch.load;先 unzip -l/xxd/strings 粗查(zip 头 PK vs 裸 pickle、条目有无可疑模块名),用 weights_only=True(PyTorch 2.6+ 默认)加载,需要全功能加载时在隔离环境([[re-sandbox]])执行;可转 safetensors 的样本直接转(纯数据无代码执行)m.producer_name/m.producer_version 识别优化器与版本(融合 ConvBN 的特征:BN 层消失且 scale 并入 conv 权重);架构比较前先规范化算子序列(按算子类别抽象,忽略名字与常量差异);可用 onnx-simplifier/onnxruntime graph_optimization_level 对比优化前后 diff 还原原始层