You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

将SentencePiece Tokenizer转为ONNX:Android部署FAQ系统遇阻求助

解决multilingual-e5-small Tokenizer导出ONNX后效果不一致的问题

核心问题分析

你遇到的问题大概率是导出ONNX Tokenizer时未同步原Tokenizer的完整配置(如padding规则、截断长度、特殊token映射),或是用了不匹配的导出工具导致行为偏差。以下是经过验证的可行方案:

步骤1:安装依赖

确保安装版本兼容的必要库:

pip install transformers>=4.28.0 sentencepiece onnxruntime tokenizers>=0.13.3

步骤2:正确导出Tokenizer到ONNX

推荐两种官方导出方式,确保和原Tokenizer行为完全一致:

方式一:使用transformers内置导出工具

from transformers import AutoTokenizer, export_tokenizer_to_onnx

# 加载原模型的Tokenizer
tokenizer = AutoTokenizer.from_pretrained("intfloat/multilingual-e5-small")

# 导出ONNX模型,同步推理关键参数
export_tokenizer_to_onnx(
    tokenizer,
    "./e5_tokenizer/tokenizer.onnx",
    opset=13,  # 选择Android ONNX Runtime兼容的opset(13/14兼容性最佳)
    padding="max_length",
    truncation=True,
    max_length=512,  # 和Embedding模型的输入长度保持一致
    return_token_type_ids=False  # multilingual-e5-small无需token_type_ids,可省略
)

# 保存完整Tokenizer配置(用于Android端验证)
tokenizer.save_pretrained("./e5_tokenizer")

方式二:使用tokenizers库直接导出

若方式一仍有问题,可尝试底层tokenizers库的导出逻辑:

from transformers import AutoTokenizer
from tokenizers import Tokenizer

tokenizer = AutoTokenizer.from_pretrained("intfloat/multilingual-e5-small")
tokenizer.save_pretrained("./e5_tokenizer")

# 加载tokenizers原生格式的Tokenizer
tok = Tokenizer.from_file("./e5_tokenizer/tokenizer.json")

# 同步原Tokenizer的所有配置
tok.enable_padding(
    pad_id=tokenizer.pad_token_id,
    pad_token=tokenizer.pad_token,
    length=512
)
tok.enable_truncation(max_length=512)
tok.add_special_tokens(tokenizer.all_special_tokens)

# 导出ONNX
tok.onnx_export("./e5_tokenizer/tokenizer.onnx")

步骤3:验证导出结果

导出后必须验证ONNX Tokenizer的输出和原Tokenizer完全一致:

import onnxruntime as ort
import numpy as np

# 加载原Tokenizer和ONNX会话
tokenizer = AutoTokenizer.from_pretrained("./e5_tokenizer")
session = ort.InferenceSession("./e5_tokenizer/tokenizer.onnx")

# 测试多语言样本
test_texts = [
    "如何清理安卓手机的存储空间?",
    "How to connect to Wi-Fi on Android?",
    "¿Cómo restablecer la configuración de red?"
]

for text in test_texts:
    # 原Tokenizer处理结果
    original = tokenizer(
        text,
        return_tensors="np",
        padding="max_length",
        truncation=True,
        max_length=512
    )
    # ONNX Tokenizer处理结果
    onnx_output = session.run(None, {"input": [text]})
    # 对比input_ids和attention_mask
    assert (original["input_ids"][0] == onnx_output[0][0]).all(), f"文本{text}处理结果不一致"
    assert (original["attention_mask"][0] == onnx_output[1][0]).all(), f"文本{text}注意力掩码不一致"

print("所有测试样本验证通过")

关键注意事项

  • 参数同步:导出时必须和Embedding模型推理时的max_length、padding、truncation参数完全一致,否则会导致输入维度不匹配或分词结果偏差。
  • opset版本:选择Android ONNX Runtime支持的opset版本(推荐13或14),过高的opset可能在移动端无法兼容。
  • 特殊token:确保导出时包含所有特殊token(如[CLS]、[SEP]、<pad>),这些是multilingual-e5-small模型必需的输入标识。

内容的提问来源于stack exchange,提问作者ltu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 11:27:17