Bug 描述
推理(inference)时,AutoModel 加载 CosyVoice-300M-Instruct 模型会因为缺少训练专用依赖 pyworld 而失败,报 ModuleNotFoundError: No module named 'pyworld'。推理代码路径本身不使用 pyworld,但由于推理配置文件 cosyvoice.yaml 引用了 cosyvoice.dataset.processor 模块中的类,导致 HyperPyYAML 在加载配置时触发了不必要的 import 链。
环境信息
- 模型来源: ModelScope
iic/CosyVoice-300M-Instruct(通过 AutoModel(model_dir="iic/CosyVoice-300M-Instruct") 加载)
- CosyVoice 版本: GitHub main 分支最新代码(clone from https://github.com/FunAudioLLM/CosyVoice)
- Python 版本: 3.12
- PyTorch 版本: 2.10.0
- 运行环境: ModelScope 创空间 xGPU(Linux x86_64, CUDA 12)
复现步骤
-
克隆 CosyVoice 仓库:
git clone --recursive https://github.com/FunAudioLLM/CosyVoice.git
cd CosyVoice
-
仅安装推理必需的依赖(不安装 pyworld、librosa 等训练专用包):
pip install torch torchaudio numpy transformers HyperPyYAML onnxruntime-gpu \
omegaconf einops scipy soundfile inflect regex wetext tqdm tiktoken \
conformer x-transformers diffusers==0.29.0 lightning
-
运行推理加载模型:
import sys
sys.path.insert(0, "CosyVoice")
sys.path.insert(0, "CosyVoice/third_party/Matcha-TTS")
from cosyvoice.cli.cosyvoice import AutoModel
cosyvoice = AutoModel(model_dir="iic/CosyVoice-300M-Instruct")
-
报错:
ModuleNotFoundError: No module named 'pyworld'
完整调用链:
cosyvoice/cli/cosyvoice.py:38 configs = load_hyperpyyaml(f)
→ hyperpyyaml/core.py:471 callable_ = pydoc.locate(callable_string)
→ pydoc.py:488 raise ErrorDuringImport(path, err)
→ cosyvoice/dataset/processor.py:25 import pyworld as pw
关于 pyworld 的额外说明
pyworld 是一个 C 扩展包(WORLD 声码器的 Python 封装),安装时需要编译 C 代码。在 Python 3.12 上:
- 可能因缺少预编译 wheel 而需要从源码编译,存在编译失败风险
- 编译依赖 Cython 和 numpy C API,增加了环境配置复杂度
- 对于只需要推理的用户来说,这是一个不必要且较重的依赖
原因分析
cosyvoice.yaml(推理配置文件)中引用了 cosyvoice.dataset.processor 模块中的类路径。当 HyperPyYAML 通过 pydoc.locate() 解析这些类路径时,会触发 cosyvoice.dataset.processor 模块的完整 import。而该模块顶部有:
# cosyvoice/dataset/processor.py
import pyworld as pw # 仅训练数据预处理需要
import librosa # 仅训练数据加载需要
这些 import 在推理代码路径中完全不会被调用(推理走的是 cli/cosyvoice.py → cli/frontend.py → cli/model.py → flow/ → hifigan/),但因为配置加载机制,它们在模型初始化时就被强制 import 了。
建议修复
方案 A:推理配置与训练配置分离
将 cosyvoice.yaml 中对 cosyvoice.dataset.processor 类的引用移除或替换为推理专用的实现。推理配置文件不应包含仅在训练/数据预处理阶段使用的模块引用。
方案 B:延迟导入(Lazy Import)
在 cosyvoice/dataset/processor.py 中将顶层 import 改为函数级延迟导入:
# 改前(顶层 import)
import pyworld as pw
import librosa
# 改后(函数内 import)
def extract_world_features(wav):
import pyworld as pw
...
def load_audio(path):
import librosa
...
这样只有真正调用这些函数时才会触发 import,不影响推理流程。
临时解决方案
目前可通过在 sys.modules 中创建占位模块绕过:
import types
for mod_name in ["pyworld", "librosa"]:
if mod_name not in sys.modules:
sys.modules[mod_name] = types.ModuleType(mod_name)
推理功能不受影响,因为 dataset.processor 中的函数在推理路径中不会被调用。
Bug 描述
推理(inference)时,
AutoModel加载CosyVoice-300M-Instruct模型会因为缺少训练专用依赖pyworld而失败,报ModuleNotFoundError: No module named 'pyworld'。推理代码路径本身不使用pyworld,但由于推理配置文件cosyvoice.yaml引用了cosyvoice.dataset.processor模块中的类,导致 HyperPyYAML 在加载配置时触发了不必要的 import 链。环境信息
iic/CosyVoice-300M-Instruct(通过AutoModel(model_dir="iic/CosyVoice-300M-Instruct")加载)复现步骤
克隆 CosyVoice 仓库:
git clone --recursive https://github.com/FunAudioLLM/CosyVoice.git cd CosyVoice仅安装推理必需的依赖(不安装
pyworld、librosa等训练专用包):运行推理加载模型:
报错:
完整调用链:
关于 pyworld 的额外说明
pyworld是一个 C 扩展包(WORLD 声码器的 Python 封装),安装时需要编译 C 代码。在 Python 3.12 上:原因分析
cosyvoice.yaml(推理配置文件)中引用了cosyvoice.dataset.processor模块中的类路径。当 HyperPyYAML 通过pydoc.locate()解析这些类路径时,会触发cosyvoice.dataset.processor模块的完整 import。而该模块顶部有:这些 import 在推理代码路径中完全不会被调用(推理走的是
cli/cosyvoice.py→cli/frontend.py→cli/model.py→flow/→hifigan/),但因为配置加载机制,它们在模型初始化时就被强制 import 了。建议修复
方案 A:推理配置与训练配置分离
将
cosyvoice.yaml中对cosyvoice.dataset.processor类的引用移除或替换为推理专用的实现。推理配置文件不应包含仅在训练/数据预处理阶段使用的模块引用。方案 B:延迟导入(Lazy Import)
在
cosyvoice/dataset/processor.py中将顶层 import 改为函数级延迟导入:这样只有真正调用这些函数时才会触发 import,不影响推理流程。
临时解决方案
目前可通过在
sys.modules中创建占位模块绕过:推理功能不受影响,因为
dataset.processor中的函数在推理路径中不会被调用。