根因回顾:
ONNX Runtime 的 CPU EP 默认使用 Intel oneDNN(MKL-DNN)作为底层数学库,该库针对 Intel AMX/VNNI 指令集深度优化,在 AMD EPYC 上无法充分利用 AVX-512 VNNI 指令集,导致性能显著低于 PyTorch 原生路径。
最新进展(截至 2026-02):
- ONNX Runtime 最新版本(1.20/1.21/1.22)的 CPU EP 改进主要集中在 Intel AMX、QNN(高通)、TensorRT 等方向,未见针对 AMD EPYC AVX-512 的专项修复
- ONNX Runtime 官方 GitHub releases 页面(2026-02 最新版)的改进点:GenAI 解码支持、TensorRT EP 改进、QNN EP 改进,无 AMD CPU 专项优化
- AMD 官方的解决方案是通过 ZenDNN Plugin for ONNX Runtime(zentorch-ort)提供 AMD 专属优化,而非等待 ONNX Runtime 上游修复
- 结论:ONNX Runtime 原生 CPU EP 在 AMD EPYC 上慢的问题没有官方修复,短期内不会改变
AMD 官方推荐路径:
- ZenDNN 5.0(2025年发布)提供了 PyTorch Plugin(zentorch)和 ONNX Runtime Plugin 两条路径
- zentorch 通过 torch.compile 的 backend 接口接入,对 AMD EPYC Zen4/Zen5 有专项优化
- 参考:AMD ZenDNN 5.0 官方博客(https://www.amd.com/en/developer/resources/technical-articles/zendnn-5-0-supercharge-ai-on-amd-epyc-server-cpus.html)
结论:fastembed 官方尚未正式支持,但 PR 已存在,预计近期合并。
详细情况:
- fastembed 最新版本:v0.7.4(2025-12-05 发布)
- v0.7.4 改进点:网络调用优化、ONNX session 内存配置、依赖版本解锁,无 Qwen3 支持
- GitHub 上存在相关 issue 和 PR:
- Issue #528:请求支持 Qwen/Qwen3-Embedding-0.6B-GGUF(2025-06 提交)
- Issue #529:请求 last token pooling 支持(Qwen3 等 causal 架构 embedding 模型需要)
- PR 标题出现在搜索结果中:feat: add Qwen3-Embedding-0.6B and Qwen3-Reranker-0.6B support
- 另有 LinkedIn 帖子(2026-02-17)提到 fastembed 即将支持 bidirectional attention for Qwen3
- 当前状态:PR 存在但截至调研时(2026-02-27)尚未合并到 main,v0.7.4 不含此功能
- 技术障碍: fastembed 基于 ONNX Runtime,Qwen3-Embedding 是 causal LM 架构(需要 last token pooling),与 fastembed 原有 BERT 类模型的 mean pooling 路径不同,需要额外适配
参考来源:
- fastembed releases: https://github.com/qdrant/fastembed/releases
- Issue #528: https://github.com/qdrant/fastembed/issues/528
- Issue #529: https://github.com/qdrant/fastembed/issues/529
结论:有 workaround,但在 AMD EPYC 上效果有限。
问题根因:
- sentence_transformers 加载 BF16 模型后,在 CPU 推理时内部将权重 upcast 到 FP32
- 原因:PyTorch CPU 的 BF16 矩阵乘法在 AVX-512 BF16 指令集(VNNI-BF16)不可用时会 fallback 到软件模拟
- RS1000(AMD EPYC Zen4)支持 AVX-512 BF16,理论上可以硬件加速 BF16
可能的 workaround:
.to(torch.bfloat16) + 自定义推理循环python
model = SentenceTransformer("Qwen/Qwen3-Embedding-0.6B")
model[0].auto_model = model[0].auto_model.to(torch.bfloat16)
# 绕过 ST 的 encode() 方法,直接调用底层 transformer结论:GGUF 格式存在,但 llama.cpp 的 Qwen3 Embedding 实现有已知 bug,不推荐用于生产。
详细情况:
- Qwen3-Embedding-0.6B 的 GGUF 格式已存在:
- Mungert/Qwen3-Embedding-0.6B-GGUF(HuggingFace,2025-06)
- dengcao/Qwen3-Embedding-4B-GGUF(HuggingFace,2025-05)
- 已知 bug: Reddit r/LocalLLaMA 帖子(2025-07)和 issue 报告显示,llama.cpp 的 Qwen3 Embedding GGUF 结果质量很差
- 帖子标题:Are Qwen3 Embedding GGUF faulty?(2025-07)
- 问题:MTEB 分数高,但实际检索结果远差于竞品
- 根因:llama.cpp 的 last token pooling 实现有 patch 未合并
- 另一帖子(2025-07):Qwen 3 Embeddings 0.6B faring really poorly,多个推理引擎(vLLM、infinity-embed、HF TEI、sentence_transformers)均有问题,怀疑是 instruction prompt 使用方式问题
- 吞吐量: llama.cpp CPU embedding 模式(llama-embedding)在 4 vCPU 场景下,0.6B 模型预计 5~15 条/秒(基于 LLM 推理速度推算,无直接 embedding 基准数据)
- 量化效果: Q4/Q8 量化可减少内存占用,但 embedding 任务对精度敏感,量化可能影响检索质量
结论:llama.cpp GGUF 路径当前不成熟,有已知质量问题,不推荐。
参考来源:
- Mungert/Qwen3-Embedding-0.6B-GGUF: https://huggingface.co/Mungert/Qwen3-Embedding-0.6B-GGUF
- Reddit: https://www.reddit.com/r/LocalLLaMA/comments/1lt18hg/are_qwen3_embedding_gguf_faulty/
- Reddit: https://www.reddit.com/r/LocalLLaMA/comments/1lxvf0j/qwen_3_embeddings_06b_faring_really_poorly/
结论:CTranslate2 支持 encoder 类 embedding 模型,但不支持 Qwen3 这类 causal decoder 架构的 embedding 模型。
详细情况:
- CTranslate2 是 OpenNMT 团队开发的高效推理引擎,专注于 Transformer 模型
- 支持的 embedding 模型类型: BERT、RoBERTa、DistilBERT 等 encoder-only 架构
- 不支持: Qwen3-Embedding 是 causal decoder 架构(基于 Qwen3 LLM),CTranslate2 的 encoder 路径无法直接使用
- CTranslate2 主要用于 Whisper(STT)、NLLB(翻译)等任务,embedding 场景不是其主要用途
- ctransformers 库(不同于 CTranslate2)主要支持 GGUF 格式的 LLM,embedding 功能有限
- AMD EPYC 上的表现: CTranslate2 使用 Intel MKL 或 OpenBLAS,在 AMD 上性能与 ONNX Runtime 类似,无专项优化
结论:CTranslate2 不适用于 Qwen3-Embedding,不推荐。
**结论:O2/O3 优化可能有 5~15
结论:多进程并行在 4 vCPU 场景下理论可达 2~3x 吞吐,但有工程复杂度和内存代价。
详细情况:
- 当前方案:单进程,threads=4,充分利用 4 vCPU
- 多进程方案:启动 2~4 个独立 embedding worker 进程,每个进程独立加载模型
- 理论收益:
- 当前 threads=4 已经是单进程最优(4 vCPU 全用)
- 多进程会导致 CPU 超订(oversubscription),实际收益取决于任务是否 CPU bound
- 如果 embedding 任务是 CPU bound(当前场景是),多进程会导致 CPU 争抢,收益有限
- 如果有 I/O 等待(如批量读取文本),多进程可以掩盖 I/O 延迟
- 内存代价: 每个进程独立加载模型,2 进程 = 2x 内存(约 4GB),4 进程 = 8GB(接近可用内存上限)
- 适用场景: 离线批量建索引(可以接受内存翻倍),不适合在线查询(内存紧张)
- 实现方式:
python
from multiprocessing import Pool
# 每个 worker 独立加载模型,threads=1(避免超订)
# 主进程分发 batch,worker 返回 embeddings
- 预期收益: 离线建索引场景,2 进程约 +50~80
结论:zentorch 是 AMD EPYC 上最有潜力的加速方案,HuggingFace 实测 Turin vs Genoa 约 2x 提升。
详细情况:
ZenDNN 5.0(2025年发布):
- AMD 官方深度学习推理加速库,专为 AMD EPYC Zen 架构优化
- 底层使用 AOCL BLIS 5.0(AMD 优化的 BLAS 库),针对 AMD 矩阵乘法有专项优化
- 提供三个接入路径:
1. zentorch(PyTorch plugin):通过 torch.compile backend 接入
2. ZenDNN ONNX Runtime plugin:替换 ONNX Runtime 的底层数学库
3. ZenDNN TensorFlow plugin
zentorch 关键特性:
- pip install zentorch(AMD 官方 PyPI 包)
- 通过 torch.compile(model, backend="zentorch") 接入
- ZenDNN 5.0 新增:BF16 精度支持(AOCL BLIS 5.0 BF16 matmul 优化)
- 支持 INT4 WOQ(Weight-Only Quantization)
- 专为 AMD EPYC Zen4/Zen5 优化的 SDPA(Scaled Dot Product Attention)
HuggingFace 实测数据(AMD Turin vs Genoa,2024年底):
- 使用 zentorch + torch.compile + BF16 + ZenDNN 5.0
- Llama 3.1 8B 推理:Turin(Zen5)vs Genoa(Zen4)约 2x 吞吐提升
- 注意:这是 LLM 生成任务,embedding 任务的提升幅度可能不同
- 参考:https://huggingface.co/blog/huggingface-amd-turin
对 RS1000(AMD EPYC Zen4)的预期:
- zentorch 对 Zen4 也有优化(ZenDNN 4.2+ 开始支持 Zen4)
- torch.compile + zentorch 在 embedding 任务上的预期提升:+10~30
结论:fastembed 支持 Qwen3 后,ONNX 路径在 AMD 上仍可能慢于 PyTorch,但值得验证。
结论:不适用。
| 方案 | 可行性(1-5) | 预期收益 | 工程复杂度 | 推荐优先级 | 备注 |
|---|---|---|---|---|---|
| torch.compile + zentorch | 4 | +10~30 | |||
| #### 3.2 推荐测试顺序 |
前提:当前 17.3 条/秒已够用,以下测试按性价比排序,可选择性执行。
第一优先:torch.compile + zentorch(最高性价比)
pip install zentorch
import torch
import zentorch # noqa: F401 — 注册 zentorch backend
from sentence_transformers import SentenceTransformer
model = SentenceTransformer("Qwen/Qwen3-Embedding-0.6B")
model[0].auto_model = torch.compile(model[0].auto_model, backend="zentorch")
# 首次 encode 会触发编译(约 1~3 分钟预热)
embeddings = model.encode(texts, batch_size=8)
第二优先:BF16 手动 workaround(潜力最大,但有风险)
import torch
from sentence_transformers import SentenceTransformer
from transformers import AutoTokenizer
# 直接用 transformers 加载,绕过 ST 的 upcast
from transformers import AutoModel
tokenizer = AutoTokenizer.from_pretrained("Qwen/Qwen3-Embedding-0.6B")
model = AutoModel.from_pretrained("Qwen/Qwen3-Embedding-0.6B", torch_dtype=torch.bfloat16)
model.eval()
def last_token_pool(last_hidden_states, attention_mask):
# Qwen3-Embedding 使用 last token pooling
left_padding = (attention_mask[:, -1].sum() == attention_mask.shape[0])
if left_padding:
return last_hidden_states[:, -1]
else:
sequence_lengths = attention_mask.sum(dim=1) - 1
batch_size = last_hidden_states.shape[0]
return last_hidden_states[torch.arange(batch_size), sequence_lengths]
torch.backends.cpu.get_cpu_capability() 确认 BF16 支持第三优先:多进程并行(仅离线建索引场景)
from multiprocessing import Pool
import os
def worker_init():
# 每个 worker 独立加载模型,限制线程数避免超订
os.environ["OMP_NUM_THREADS"] = "2"
global model
from sentence_transformers import SentenceTransformer
model = SentenceTransformer("Qwen/Qwen3-Embedding-0.6B")
def worker_encode(texts_batch):
return model.encode(texts_batch, batch_size=8).tolist()
# 2 进程,每进程 2 线程,总计 4 vCPU
with Pool(2, initializer=worker_init) as pool:
results = pool.map(worker_encode, text_batches)
暂缓:ONNX O3 优化
- 工程成本中等,收益边际,暂不推荐
- 如果前三个方案均不满足需求,再考虑
Q1.1 ONNX Runtime 1.24+ 是否改善了 AMD EPYC AVX-512 利用率?
→ 否。 ONNX Runtime 最新版本(截至 2026-02)的 CPU EP 改进未针对 AMD EPYC。AMD 官方解决方案是 ZenDNN Plugin,而非等待 ONNX Runtime 上游修复。
Q1.2 fastembed 是否已支持 Qwen3-Embedding?
→ 尚未正式支持。 fastembed v0.7.4(最新版,2025-12)不含 Qwen3 支持。相关 PR 存在(feat: add Qwen3-Embedding-0.6B support),但截至 2026-02-27 未合并。预计 v0.8.x 会支持。
Q1.3 sentence_transformers BF16 upcast 是否有 workaround?
→ 有,但需要绕过 ST 的 encode() 方法。 直接用 transformers 加载 BF16 模型 + 手动实现 last token pooling,可以绕过 ST 的 upcast。AMD EPYC Zen4 支持 AVX-512 BF16,PyTorch 2.x 可以利用,预期 +20~40%。
Q2 其他方案总结:
→ OpenVINO(不推荐,Intel 专属)、llama.cpp GGUF(不推荐,有已知 bug)、CTranslate2(不支持 causal decoder embedding)、ONNX O3(边际收益)、多进程并行(离线场景有效)、ZenDNN/zentorch(最推荐)
Q3 推荐测试顺序:
1. torch.compile + zentorch(2行代码,最高性价比)
2. BF16 手动 workaround(潜力最大,需验证)
3. 多进程并行(仅离线建索引)
4. ONNX O3(暂缓)
| # | 来源 | URL | 用于 |
|---|---|---|---|
| 1 | AMD ZenDNN 5.0 官方博客 | https://www.amd.com/en/developer/resources/technical-articles/zendnn-5-0-supercharge-ai-on-amd-epyc-server-cpus.html | ZenDNN 5.0 特性、BF16 支持、INT4 WOQ |
| 2 | AMD ZenDNN 4.2 Plugin 架构 | https://www.amd.com/en/developer/resources/technical-articles/supercharge-your-ai-inference-with-zendnn-on-amd-epyc-cpus.html | zentorch 接入方式、AOCL BLIS 优化 |
| 3 | HuggingFace AMD Turin blog | https://huggingface.co/blog/huggingface-amd-turin | zentorch + torch.compile 实测数据(Turin vs Genoa 2x) |
| 4 | zentorch PyPI | https://pypi.org/project/zentorch/ | zentorch 安装方式 |
| 5 | fastembed releases | https://github.com/qdrant/fastembed/releases | v0.7.4 最新版确认,无 Qwen3 支持 |
| 6 | fastembed issue #528 | https://github.com/qdrant/fastembed/issues/528 | Qwen3-Embedding GGUF 支持请求 |
| 7 | fastembed issue #529 | https://github.com/qdrant/fastembed/issues/529 | last token pooling 支持请求 |
| 8 | OpenVINO GitHub issue #32647 | https://github.com/openvinotoolkit/openvino/issues/32647 | OpenVINO 不官方支持 AMD GPU 确认 |
| 9 | Phoronix Intel Xeon vs AMD EPYC | https://www.phoronix.com/review/xeon-6980p-epyc-9755-2025/3 | OpenVINO 在 Intel 上因 AMX 有优势,AMD 无此加速 |
| 10 | Mungert/Qwen3-Embedding-0.6B-GGUF | https://huggingface.co/Mungert/Qwen3-Embedding-0.6B-GGUF | Qwen3 GGUF 格式存在确认 |
| 11 | Reddit: Qwen3 Embedding GGUF faulty | https://www.reddit.com/r/LocalLLaMA/comments/1lt18hg/are_qwen3_embedding_gguf_faulty/ | llama.cpp Qwen3 Embedding 已知质量问题 |
| 12 | Reddit: Qwen3 Embeddings poorly | https://www.reddit.com/r/LocalLLaMA/comments/1lxvf0j/qwen_3_embeddings_06b_faring_really_poorly/ | 多引擎 Qwen3 Embedding 质量问题讨论 |
| 13 | ONNX Runtime releases | https://github.com/microsoft/onnxruntime/releases | 最新版本改进点确认(无 AMD 专项修复) |
| 14 | HuggingFace 论坛:embedding 延迟优化 | https://discuss.huggingface.co/t/how-can-i-reduce-latency-when-running-a-large-transformer-model-for-sentence-embeddings-in-production/172103 | CPU embedding 优化建议(ONNX/OpenVINO) |
| 15 | optimum ONNX O3 export 示例 | https://dev.to/mayu2008/building-sentence-transformers-in-rust-a-practical-guide-with-burn-onnx-runtime-and-candle-281k | O3 优化导出命令 |
| 16 | AMD ZenDNN archives | https://www.amd.com/en/developer/zendnn/zendnn-archives.html | INT8/INT4 量化支持、zentorch 历史版本 |
| 17 | AMD Quark 量化工具 | https://www.amd.com/en/developer/resources/technical-articles/2025/amd-quark-model-optimization-library-now-available-as-open-sourc.html | torch.compile + Quark 量化集成 |
| 18 | LinkedIn: fastembed Qwen3 bidirectional | https://www.linkedin.com/posts/alvarobartt_more-embedding-models-and-an-even-more-reliable-activity-7429555561928626177-0nRU | fastembed 即将支持 Qwen3 bidirectional attention |