如何执行Seq2Seq模型导出的ONNX解码器?Helsinki模型报错排查
ONNX版Helsinki-NLP/opus-mt-de-en模型对接问题解决
问题定位
你的代码存在三个核心错误:
- 复用编码器Session获取解码器输入名称:用
sess(编码器的InferenceSession)来获取解码器的输入名称,导致传入参数完全不匹配。 - 编码器输出未正确提取:
sess.run()返回的是结果列表,你直接把整个列表传给解码器,而非取出其中的hidden_states张量。 - 解码器输入参数错误:解码器需要的是自身的input_ids(初始为起始token)、编码器的hidden_states、编码器的attention_mask,你错误地将编码器输出传入了attention_mask参数位,导致维度不匹配。
修正后的完整代码
编码器执行代码(修正版)
import numpy as np import onnxruntime as rt from transformers import AutoTokenizer tokenizer = AutoTokenizer.from_pretrained("Helsinki-NLP/opus-mt-de-en") inputs = tokenizer("Das ist ein Test", return_tensors="np") # 直接用numpy格式避免类型转换 encoder_file = "DE_TO_EN_TRANSLATION_HELSINKI/encoder_model.onnx" decoder_file = "DE_TO_EN_TRANSLATION_HELSINKI/decoder_model.onnx" # 运行编码器 sess_encoder = rt.InferenceSession(encoder_file) encoder_input_names = {inp.name: inp for inp in sess_encoder.get_inputs()} encoder_output_name = sess_encoder.get_outputs()[0].name ort_encoder_inputs = { encoder_input_names["input_ids"].name: inputs["input_ids"], encoder_input_names["attention_mask"].name: inputs["attention_mask"] } # 提取编码器输出的hidden_states(取列表第一个元素) encoder_hidden_states = sess_encoder.run([encoder_output_name], ort_encoder_inputs)[0]
解码器执行代码(修正版)
# 运行解码器(初始生成第一个token) sess_decoder = rt.InferenceSession(decoder_file) decoder_input_names = {inp.name: inp for inp in sess_decoder.get_inputs()} # 初始化解码器输入:Helsinki模型用<s>作为生成起始token decoder_input_ids = tokenizer("<s>", return_tensors="np")["input_ids"] # 解码器自注意力掩码(初始为全1,因为只有一个token) decoder_attention_mask = np.ones_like(decoder_input_ids) ort_decoder_inputs = { "input_ids": decoder_input_ids, "encoder_hidden_states": encoder_hidden_states, "encoder_attention_mask": inputs["attention_mask"], "decoder_attention_mask": decoder_attention_mask } # 获取解码器输出的logits decoder_output_name = sess_decoder.get_outputs()[0].name decoder_logits = sess_decoder.run([decoder_output_name], ort_decoder_inputs)[0] # 解析第一个预测token并转为文本 predicted_token_id = np.argmax(decoder_logits[0, -1, :]) predicted_text = tokenizer.decode(predicted_token_id, skip_special_tokens=False) print(predicted_text)
关于decoder_with_past_model的说明
- decoder_model:普通解码器,每次需要输入完整的解码器序列,适合单次推理,但在自回归生成(如beam search)中效率极低——因为每次都要重新计算所有历史token的注意力。
- decoder_with_past_model:优化后的增量解码器,会缓存前一次生成的key/value张量(past_key_values)。首次生成第一个token后,后续只需要输入新生成的单个token,加上缓存的past_key_values即可,能大幅提升生成速度,是实现beam search的必选方案。
使用逻辑:
- 首次生成:用
decoder_model,输入初始token、encoder_hidden_states、encoder_attention_mask,得到第一个token和初始的past_key_values。 - 后续生成:切换到
decoder_with_past_model,输入新token、encoder_hidden_states、encoder_attention_mask、上一次的past_key_values,得到下一个token和更新后的past_key_values,循环直到生成结束符。
内容的提问来源于stack exchange,提问作者klsmgföl
相关产品推荐
相关产品推荐

