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

如何执行Seq2Seq模型导出的ONNX解码器?Helsinki模型报错排查

ONNX版Helsinki-NLP/opus-mt-de-en模型对接问题解决

问题定位

你的代码存在三个核心错误:

  1. 复用编码器Session获取解码器输入名称:用sess(编码器的InferenceSession)来获取解码器的输入名称,导致传入参数完全不匹配。
  2. 编码器输出未正确提取:sess.run()返回的是结果列表,你直接把整个列表传给解码器,而非取出其中的hidden_states张量。
  3. 解码器输入参数错误:解码器需要的是自身的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的必选方案。

使用逻辑:

  1. 首次生成:用decoder_model,输入初始token、encoder_hidden_states、encoder_attention_mask,得到第一个token和初始的past_key_values。
  2. 后续生成:切换到decoder_with_past_model,输入新token、encoder_hidden_states、encoder_attention_mask、上一次的past_key_values,得到下一个token和更新后的past_key_values,循环直到生成结束符。

内容的提问来源于stack exchange,提问作者klsmgföl

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 04:24:57