将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
相关产品推荐
相关产品推荐

