我来帮你分析这个问题。先搜索一下社区是否有类似的解决方案。
问题分析
你的模型在 S100P 上量化失败,核心问题是:
- ONNX 模型包含
isnan和isinf算子 - S100P 工具链不支持这两个算子 - 强行移除后校准出现 NaN - 说明模型本身存在数值不稳定问题
从日志看,错误发生在 Transformer 结构的 Attention 层和 Where 算子处,这是典型的数值溢出/下溢问题。
解决方案
方案一:模型层面修复(推荐)
在导出 ONNX 之前,在 PyTorch 模型中替换这两个算子:
import torch
import torch.nn as nn
# 替换 isnan
def safe_isnan(x):
return torch.isnan(x.clamp(-1e10, 1e10))
# 替换 isinf
def safe_isinf(x):
return torch.isinf(x.clamp(-1e10, 1e10))
# 或者更彻底的方案:在 Attention 机制中添加数值稳定处理
class StableAttention(nn.Module):
def forward(self, q, k, v, mask=None):
# 添加 clamp 防止数值溢出
scale = 1.0 / (q.size(-1) ** 0.5)
attn_weights = torch.matmul(q, k.transpose(-2, -1)) * scale
# 关键:在 softmax 前 clamp 数值
attn_weights = attn_weights.clamp(-1e4, 1e4)
if mask is not None:
# 用大负数替代 -inf,避免 isinf
attn_weights = attn_weights.masked_fill(mask == 0, -1e4)
attn_probs = torch.softmax(attn_weights, dim=-1)
return torch.matmul(attn_probs, v)
方案二:ONNX 层面替换
使用 ONNX Graph Surge 或 onnxruntime 替换算子:
import onnx
import onnx_graphsurgeon as gs
graph = gs.import_onnx(onnx.load("your_model.onnx"))
# 查找并替换 isnan/isinf 节点
for node in graph.nodes:
if node.op in ["IsNaN", "IsInf"]:
# 替换为 Constant + Equal 组合
# 或者替换为合理的数值判断逻辑
print(f"Found unsupported op: {node.op} at {node.name}")
# 保存修改后的模型
onnx.save(gs.export_onnx(graph), "fixed_model.onnx")
方案三:量化配置优化
在量化 YAML 配置中添加数值保护:
model_parameters:
onnx_model: 'your_model.onnx'
march: nash-m # S100P 使用 nash-m
calibration_parameters:
cal_data_dir: './calibration_data'
cal_data_type: 'float32'
calibration_type: 'default'
quant_config:
op_config:
# 对 Attention 相关算子特殊处理
"Softmax":
qtype: "fp16" # 保持 FP16 精度
"Where":
qtype: "fp16"
"Add":
qtype: "int8"
clamp_range: [-1e4, 1e4] # 添加数值范围限制
方案四:校准数据检查
你的日志显示 find non positive threshold 和 find inf threshold,说明校准数据有问题:
# 检查校准数据
import numpy as np
import os
cal_dir = './calibration_data'
for file in os.listdir(cal_dir):
data = np.load(os.path.join(cal_dir, file))
print(f"{file}: min={data.min()}, max={data.max()}, "
f"has_nan={np.isnan(data).any()}, has_inf={np.isinf(data).any()}")
# 如果存在 NaN/Inf,需要清理
if np.isnan(data).any() or np.isinf(data).any():
data = np.nan_to_num(data, nan=0.0, posinf=1e4, neginf=-1e4)
np.save(os.path.join(cal_dir, file), data)
排查步骤
- 先用 Netron 查看模型,定位
isnan/isinf具体在哪个层 - 检查训练时的 loss 曲线,确认模型是否完全收敛
- 验证校准数据质量,确保没有异常值
- 尝试 FP16 量化而非 INT8,看是否能通过
社区资源
推荐参考这篇详细的 S100 量化教程:万字长文,学妹吵着要学的 RDKS100 模型量化及部署
如果问题仍未解决,建议:
- 提供模型结构图(Netron 截图)
- 分享校准数据统计信息
- 说明模型训练框架和导出方式
这样社区能更精准地帮你定位问题。