You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

导出Coqui-TTS训练的VITS模型为ONNX时存在输入长度固定的问题

导出Coqui-TTS训练的VITS模型为ONNX时存在输入长度固定的问题

我之前踩过这个坑!VITS本身是支持动态输入长度的,但Coqui默认的导出脚本会把输入维度固定死,导致要么短文本生成的音频只有固定长度(比如你碰到的2秒情况),要么用长dummy输入时,短文本后面补的无效token会生成噪音。下面是我亲测有效的解决方法:

问题根源

Coqui自带的export_onnx方法里,默认用固定长度的dummy_input导出模型,而且没有配置动态轴(dynamic axes)。这会让ONNX模型被固化成只能处理和dummy_input长度完全一致的输入序列,短文本会被强制补到固定长度(补的内容无意义,生成噪音),长文本则会被截断。

具体修改步骤

1. 调整ONNX导出代码,开启动态轴

找到Coqui-TTS源码中VITS模型的export_onnx方法(一般在TTS/tts/models/vits.py文件里),修改代码添加动态轴配置:

def export_onnx(self, output_path: str, dummy_input_length: int = 100):
    self.eval()  # 确保模型处于eval模式,避免训练层影响
    dummy_input = torch.randint(0, self.config.vocab_size, (1, dummy_input_length)).to(self.device)
    
    # 配置动态轴:让模型支持可变的batch和序列长度
    dynamic_axes = {
        "input_ids": {0: "batch_size", 1: "sequence_length"},  # 输入的batch和序列长度动态
        "audio": {0: "batch_size", 1: "audio_length"}  # 输出的音频长度随输入动态变化
    }

    torch.onnx.export(
        self,
        dummy_input,
        output_path,
        opset_version=15,  # 建议用15及以上版本,兼容动态轴操作
        do_constant_folding=True,
        input_names=["input_ids"],
        output_names=["audio"],
        dynamic_axes=dynamic_axes,  # 关键:开启动态轴支持
        verbose=False
    )

如果你的VITS模型还有额外输入(比如说话人ID、情感嵌入),也要在dynamic_axes里对应添加这些输入的动态配置,比如:

dynamic_axes = {
    "input_ids": {0: "batch_size", 1: "sequence_length"},
    "speaker_ids": {0: "batch_size"},  # 说话人ID的batch维度动态
    "audio": {0: "batch_size", 1: "audio_length"}
}

2. 推理时传入对应长度的真实输入

导出完成后,用ONNX Runtime推理时,直接传入和真实文本长度匹配的token序列即可,不需要再对齐dummy_input的长度:

import onnxruntime as ort
import torch
from TTS.tts.utils.text.tokenizer import TTSTokenizer  # 用你训练时用的tokenizer

# 加载ONNX模型
sess = ort.InferenceSession("your_trained_vits.onnx")

# 处理真实文本
text = "你好,这是一段测试文本"
tokenizer = TTSTokenizer(config=your_model_config)  # 替换成你的模型配置
input_ids = tokenizer.text_to_ids(text)
input_tensor = torch.tensor([input_ids], dtype=torch.int64)  # 形状为(1, N),N是文本实际长度

# 执行推理
outputs = sess.run(["audio"], {"input_ids": input_tensor.numpy()})
audio = outputs[0][0]  # 得到和文本匹配长度的音频,无多余噪音

额外注意事项

  • 确保opset_version不低于15:低版本ONNX对动态轴的支持有限,可能导致导出失败或推理报错
  • 导出前必须切换到eval模式:避免batch normalization、dropout等训练专用层的随机行为影响导出结果
  • 如果导出时提示某个算子不支持动态轴,可以尝试升级PyTorch和ONNX的版本,或者在Coqui的GitHub仓库里看最新的修复PR(很多时候社区已经解决了这类算子兼容问题)

我当时改完之后,不管输入是3个词还是30个词,生成的音频长度都完全匹配文本,再也没有多余的噪音了,你可以试试这个方案!

火山引擎 最新活动