Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings
Discussion options

前提

python、conda环境(能完整运行funasr)、已经处理好的py文件(单个就行,其他的储存在conda环境中)、Pyinstaller(建议使用6.2.0,打包结果板块区分更清晰)

流程:

​ 编写py代码——本地执行——pyinstaller打包——解决依赖项未被打包程序携带问题——解决单个文件丢失问题——调试

编写py代码

  • 主要集中在路径问题,不要使用绝对路径,建议所有涉及到的路径均使用配置文件的形式,这样方便修改。

配置参数

  • 但是上述方法在使用exe文件时就会需要一同携带着配置参数文件

打包结果

  • 如果为了将exe变成完整的,不需要用户再额外配置的。就可以写绝对路径,但是需要在打包时将其收录进去。并且这会导致exe启动较慢。exe程序越小,启动速度越快!!!!!!!例如:将模型和依赖项全部打包进exe,将会把原本5秒启动时间提升到30秒

本地执行

  • 代码能够本地跑通就行,并且代码是依附于conda环境的,如果未使用conda环境,在打包时会出现文件丢失(也不是特别大的问题)

pyinstaller打包

pyinstall指令

3.额外指令:导入额外包(此包并不包含在当前版本的pyinstaller支持项中)、为某些库的缺失文件单独引入库中

pyinstaller -w --hidden-import=modelscope xxx.py
pyinstaller -w --add-binary "D:\conda\envs\torch1.12.1\Lib\site-packages\vosk-0.3.45-py3.7.egg\vosk\libvosk.dll;vosk" --add-binary "D:\conda\envs\torch1.12.1\Lib\site-packages\xpinyin\Mandarin.dat;xpinyin" --add-binary "D:\conda\envs\torch1.12.1\Lib\site-packages\torch\lib\shm.dll;torch" xxx.py

解决依赖项未被打包程序携带问题

在首次使用**pyinstaller -# ####.py打包时,打包后生成的exe一般都会出错,例如执行后,弹窗报错显示import错误。则此时import的整个库均未打包进exe中,需要使用上面的--hidden-import=modelscope**来将conda环境中的整个包直接放入打包后的文件夹。

解决单个文件丢失问题

在首次使用**pyinstaller -# ####.py打包时,打包后生成的exe一般都会出错,例如执行后,弹窗报错显示xxxx.xx文件不存在。则此时某个库的某个文件未打包进exe中,需要使用上面的--add-binary "D:\conda\envs\torch1.12.1\Lib\site-packages\torch\lib\shm.dll;torch"**来将conda环境中的某个文件直接放入打包后的对应包中(此处代码对应的torch包)。

You must be logged in to vote

可以,下面给一个完整的 SenseVoiceSmall 离线 CPU 示例。这个版本把 Python/FunASR/Torch 打进 one-dir 目录,模型保持为外置目录,运行时不需要原来的 Python 环境。

我实际验证的环境是 Linux x86_64、Python 3.12.3、FunASR 1.3.14、PyInstaller 6.21.0、Torch/Torchaudio 2.11.0 CPU。Windows 需要在 Windows 上执行同样的打包流程才能生成 .exe,PyInstaller 不能从 Linux 交叉编译 Windows 程序。

1. 目录结构

funasr-package/
├── funasr_offline.py
├── hooks/
│   └── hook-funasr.py
└── models/
    └── SenseVoiceSmall/
        ├── config.yaml
        ├── model.pt
        └── ...

2. 安装构建环境

建议新建干净虚拟环境,并使用 CPU 版 Torch,避免把 CUDA 和当前环境中的 Jupyter/开发包一起打进去。

Linux:

python3.12 -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip
python -m pip install \
  --index-url https://download.pytorch.org…

Replies: 2 comments

Comment options

谢谢分享,能发一个完整示例代码参考下吗

You must be logged in to vote
0 replies
Comment options

LauraGPT
Jul 15, 2026
Maintainer Author

可以,下面给一个完整的 SenseVoiceSmall 离线 CPU 示例。这个版本把 Python/FunASR/Torch 打进 one-dir 目录,模型保持为外置目录,运行时不需要原来的 Python 环境。

我实际验证的环境是 Linux x86_64、Python 3.12.3、FunASR 1.3.14、PyInstaller 6.21.0、Torch/Torchaudio 2.11.0 CPU。Windows 需要在 Windows 上执行同样的打包流程才能生成 .exe,PyInstaller 不能从 Linux 交叉编译 Windows 程序。

1. 目录结构

funasr-package/
├── funasr_offline.py
├── hooks/
│   └── hook-funasr.py
└── models/
    └── SenseVoiceSmall/
        ├── config.yaml
        ├── model.pt
        └── ...

2. 安装构建环境

建议新建干净虚拟环境,并使用 CPU 版 Torch,避免把 CUDA 和当前环境中的 Jupyter/开发包一起打进去。

Linux:

python3.12 -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip
python -m pip install \
  --index-url https://download.pytorch.org/whl/cpu \
  --extra-index-url https://pypi.org/simple \
  "torch==2.11.0+cpu" "torchaudio==2.11.0+cpu"
python -m pip install \
  "numpy==1.26.4" "scipy==1.16.3" \
  "funasr==1.3.14" "pyinstaller==6.21.0"
python -m pip check

Windows PowerShell 只需把前两行换成:

py -3.12 -m venv .venv
.\.venv\Scripts\Activate.ps1

模型提前下载到本地。下面固定到本次验证使用的完整官方版本:

hf download FunAudioLLM/SenseVoiceSmall \
  --revision 3847d57b6bdf2dd8875cb1508d2af43d80a16bf7 \
  --local-dir models/SenseVoiceSmall

3. 完整推理代码

funasr_offline.py

import argparse
import json
from pathlib import Path

from funasr import AutoModel
from funasr.utils.postprocess_utils import rich_transcription_postprocess


def parse_args():
    parser = argparse.ArgumentParser(description="Offline FunASR transcription")
    parser.add_argument("--model-dir", required=True, help="Complete local FunASR model directory")
    parser.add_argument("--audio", required=True, help="Audio file to transcribe")
    parser.add_argument("--language", default="auto")
    return parser.parse_args()


def main():
    args = parse_args()
    model_dir = Path(args.model_dir).resolve()
    audio_path = Path(args.audio).resolve()

    if not (model_dir / "config.yaml").is_file():
        raise FileNotFoundError(f"missing model config: {model_dir / 'config.yaml'}")
    if not (model_dir / "model.pt").is_file():
        raise FileNotFoundError(f"missing model weights: {model_dir / 'model.pt'}")
    if not audio_path.is_file():
        raise FileNotFoundError(f"missing audio: {audio_path}")

    model = AutoModel(
        model=str(model_dir),
        device="cpu",
        disable_update=True,
    )
    result = model.generate(
        input=str(audio_path),
        language=args.language,
        use_itn=False,
    )[0]
    raw_text = result.get("text", "")
    print(
        json.dumps(
            {
                "text": rich_transcription_postprocess(raw_text),
                "raw_text": raw_text,
            },
            ensure_ascii=False,
        )
    )


if __name__ == "__main__":
    main()

4. PyInstaller hook

仅写 --hidden-import 还不够。FunASR 的注册装饰器会调用 inspect.getsourcelines() 记录类的位置,而 PyInstaller 默认只保留冻结字节码;缺少 .py 源文件时,模块会在注册过程中以 OSError: could not get source code 中断。

建立 hooks/hook-funasr.py

from PyInstaller.utils.hooks import collect_data_files


hiddenimports = [
    "funasr.frontends.wav_frontend",
    "funasr.models.sense_voice.model",
    "funasr.models.specaug.specaug",
    "funasr.tokenizer.sentencepiece_tokenizer",
]

# FunASR uses these source files while registering the classes required by
# the tested SenseVoiceSmall config.
datas = collect_data_files(
    "funasr",
    include_py_files=True,
    includes=[
        "frontends/wav_frontend.py",
        "models/sense_voice/model.py",
        "models/specaug/specaug.py",
        "tokenizer/sentencepiece_tokenizer.py",
    ],
)

这里四项分别对应本次模型配置中的 WavFrontendSenseVoiceSmall / SenseVoiceEncoderSmallSpecAugLFRSentencepiecesTokenizer。如果换成其他 FunASR 模型,需要把该模型配置引用的动态注册模块也加入 hook。

5. 构建

在项目根目录执行:

pyinstaller \
  --noconfirm \
  --clean \
  --onedir \
  --name funasr-offline \
  --additional-hooks-dir hooks \
  --collect-data funasr \
  --exclude-module modelscope \
  --exclude-module huggingface_hub \
  --exclude-module transformers \
  --exclude-module torchvision \
  --exclude-module tensorflow \
  --exclude-module apex \
  --exclude-module umap \
  --exclude-module sklearn \
  funasr_offline.py

PowerShell 可以把上述参数写成一行。生成结果在 Linux 是 dist/funasr-offline/funasr-offline,Windows 是 dist\funasr-offline\funasr-offline.exe

这些 exclude 适用于“模型已经完整下载到本地”的示例。如果希望程序在运行时从 ModelScope/Hugging Face 自动下载模型,需要移除对应 exclude,并额外处理这些生态的依赖;构建时间和目录体积都会明显增加。

6. 运行

Linux:

HF_HUB_OFFLINE=1 ./dist/funasr-offline/funasr-offline \
  --model-dir ./models/SenseVoiceSmall \
  --audio ./models/SenseVoiceSmall/example/en.mp3

Windows PowerShell:

$env:HF_HUB_OFFLINE = "1"
.\dist\funasr-offline\funasr-offline.exe `
  --model-dir .\models\SenseVoiceSmall `
  --audio .\models\SenseVoiceSmall\example\en.mp3

本次 Linux CPU 实测输出为:

{"text": "the tribal chieftain called for the boy and presented him with fifty pieces of gold", "raw_text": "<|en|><|NEUTRAL|><|Speech|><|woitn|>the tribal chieftain called for the boy and presented him with fifty pieces of gold"}

验证时我使用了空 HOME、移除了 venv 的 PATH、把 HTTP/HTTPS 代理指向不可用地址,并在第二次运行前临时移走整个构建 venv;冻结程序仍以外置模型成功转写,结果与源码运行逐字一致。该 Linux CPU one-dir 构建实际占用约 676 MiB,未包含模型,首次完整加载加转写约 6 秒。

建议保留 --onedir 和外置模型。Torch 含大量原生动态库,--onefile 每次启动都要先解包;把约 1 GB 的模型也塞进单文件只会进一步增加启动时间和更新成本。

You must be logged in to vote
0 replies
Answer selected by LauraGPT
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Category
🙏
Q&A
Labels
None yet
2 participants
Morty Proxy This is a proxified and sanitized view of the page, visit original site.