BAAI/bge-small-zh-v1.5 — 昇腾 NPU 适配与精度测评
✅ 适配结论:精度完全对齐,误差 < 0.001%
| 评估维度 | 最小余弦相似度 | 归一化误差 | 判定 |
|---|
| 纯中文文本 (8个样本) | 0.99999887 | < 0.0002% | ✅ 通过 |
| 中英混合/英文文本 (7个样本) | 0.99999702 | < 0.0003% | ✅ 通过 |
| 全局 (15个样本) | 0.99999702 | 0.0003% | ✅ 通过 |
关键发现: 之前报告中 10.5% 的偏差来源于 vLLM-Ascend 的 EncoderOnlyAttention 实现,而非 NPU 硬件本身。
通过 HuggingFace 模型直连 NPU(不经过 vLLM),余弦相似度在所有测试文本上均 > 0.999997。
📋 模型信息
| 属性 | 值 |
|---|
| 模型名称 | BAAI/bge-small-zh-v1.5 |
| 模型架构 | BERT (4层, 512 hidden, 8 heads) |
| 参数量 | ~30M |
| 嵌入维度 | 512 |
| 最大序列长度 | 512 |
| 预训练精度 | float32 |
| 推理引擎 | HuggingFace Transformers + torch_npu |
| 硬件平台 | Ascend 910 (NPU) |
| CANN 版本 | 8.5.1 |
📦 环境要求
| 组件 | 版本 |
|---|
| Python | ≥ 3.10 |
| CANN | 8.5.x |
| torch | ≥ 2.6.0 |
| torch_npu | ≥ 2.6.0 |
| transformers | ≥ 4.30.0 |
🚀 快速使用
命令行推理
# 单文本嵌入
python3 infer_npu.py --text "今天天气很好,适合出去玩"
# 批量嵌入
python3 infer_npu.py --text "文本1" --text "文本2" --text "文本3"
# 从文件读取
python3 infer_npu.py --input texts.txt
HTTP API 服务
# 启动服务
python3 infer_npu.py --serve --port 8000
# 调用 API
curl http://localhost:8000/v1/embeddings \
-H "Content-Type: application/json" \
-d '{"input": ["今天天气很好,适合出去玩", "The quick brown fox"]}'
Python API
from infer_npu import BGEEmbeddingNPU
engine = BGEEmbeddingNPU()
embs = engine.encode(["今天天气很好", "Hello world"], batch_size=32)
print(embs.shape) # (2, 512)
🎯 精度对比评测
评测方法
使用 HuggingFace Transformers 模型分别在 CPU (float32 黄金基线) 和 NPU 上运行,
确保完全相同的代码路径(相同的张量操作、相同的池化策略)。
对比维度:
- CPU float32 — 黄金基线 (全精度)
- NPU float32 — HuggingFace 直连 Ascend 910
嵌入提取方式 (CLS + L2 Normalize):
hidden_states → CLS token [0] → L2 normalize → output embedding
精度数据
| # | 类型 | 文本 | NPU-f32 vs CPU-f32 余弦 | MSE | 最大绝对误差 |
|---|
| 0 | 纯中文 | 今天天气很好,适合出去玩 | 0.99999928 | 3.1e-09 | 1.8e-04 |
| 1 | 纯中文 | 今天阳光明媚,适合户外活动 | 0.99999923 | 3.1e-09 | 1.9e-04 |
| 2 | 纯中文 | 机器学习是人工智能的一个重要分支 | 0.99999928 | 3.4e-09 | 1.8e-04 |
| 3 | 纯中文 | 自然语言处理技术正在快速发展 | 0.99999934 | 2.9e-09 | 1.5e-04 |
| 4 | 纯中文 | 北京是中国的首都 | 0.99999917 | 3.5e-09 | 1.6e-04 |
| 5 | 纯中文 | 上海是国际化大都市 | 0.99999928 | 3.1e-09 | 1.6e-04 |
| 6 | 纯中文 | 我想吃红烧肉 | 0.99999887 | 4.3e-09 | 2.3e-04 |
| 7 | 纯中文 | 深度学习模型需要大量训练数据 | 0.99999923 | 3.1e-09 | 2.2e-04 |
| 8 | 中英混合 | 注意力机制是Transformer的核心 | 0.99999928 | 3.2e-09 | 2.0e-04 |
| 9 | 中英混合 | 华为昇腾NPU支持大模型推理加速 | 0.99999911 | 3.7e-09 | 1.9e-04 |
| 10 | 中英混合 | BGE embedding model supports semantic search | 0.99999851 | 5.6e-09 | 2.2e-04 |
| 11 | 纯英文 | The quick brown fox jumps over the lazy dog | 0.99999893 | 4.5e-09 | 2.2e-04 |
| 12 | 纯英文 | NLU | 0.99999702 | 1.2e-08 | 3.6e-04 |
| 13 | 数字混合 | 第100层神经网络 | 0.99999905 | 3.5e-09 | 1.9e-04 |
| 14 | 标点混合 | Hello, 世界! | 0.99999940 | 2.7e-09 | 1.7e-04 |
分类统计
| 类别 | 样本数 | 平均余弦 | 最小余弦 |
|---|
| 纯中文 | 8 | 0.99999921 | 0.99999887 |
| 中英混合/英文 | 7 | 0.99999876 | 0.99999702 |
| 总计 | 15 | 0.99999900 | 0.99999702 |
精度判定
✅ 全局通过:最小余弦相似度 0.99999702,归一化误差 0.0003%,远低于 1% 要求。
🔬 关键诊断:vLLM-Ascend 注意力偏差
问题发现
在初始适配中,通过 vLLM-Ascend 运行时发现中英混合文本存在 10.5% 的余弦误差:
| 对比方式 | 纯中文最小余弦 | 混合文本最小余弦 |
|---|
| HF-NPU vs CPU (本方案) | 0.99999887 | 0.99999702 |
| vLLM-Ascend vs CPU (之前) | 0.99999887 | 0.895158 |
三重控制变量实验
| 对比组 | 纯中文 | 英/中混合 | 结论 |
|---|
| CPU-f32 vs CPU-f16 | 0.9999+ | 0.9999+ | float16 精度损失 < 0.04% |
| HF-CPU vs HF-NPU (本方案) | 0.999999 | 0.999997 | NPU 硬件精度完全对齐 |
| CPU vs vLLM-Ascend | 0.999999 | 0.895 | 偏差源 = vLLM 注意力后端 |
根因
偏差 不是 dtype 转换也不是 NPU 硬件问题,而是 vLLM-Ascend 的 EncoderOnlyAttention 后端在特定注意力分布下的数值差异。HF 直连 NPU 使用相同的 PyTorch 代码路径,所有文本的余弦相似度均 > 0.99999。
⚡ 性能数据
| 指标 | CPU (float32) | NPU (HF直连 float32) | 加速比 |
|---|
| 单文本平均延迟 | ~18 ms | ~17 ms | ~1.1x |
| 批处理 (batch=32) | — | 可线性扩展 | — |
注: 该模型仅 30M 参数,CPU 本身已很快。对于更大的 BERT 模型,NPU 加速比将更加显著。
📚 文件说明
| 文件 | 说明 |
|---|
infer_npu.py | HF 直连 NPU 推理脚本(支持 CLI + HTTP API) |
eval_precision_final.py | 最终精度评估脚本 |
precision_results.json | 精度评估结果 |
adaptation-report_BAAI_bge-small-zh-v1.5.md | 适配报告(含 vLLM 分析) |
eval_precision.py | 诊断脚本 (HF on NPU 隔离分析) |
📚 参考资料