在 Windows 上实现 Sherpa-ONNX 生产就绪的实用方案

Jan 29, 2026

ASR 与 Sherpa-ONNX

自动语音识别 (ASR) 是现代语音驱动类应用(如虚拟助手、实时转录系统和基于语音的用户界面)的核心技术。尽管模型准确性和推理速度备受关注,但生产部署往往会因一些更微不足道的问题(例如构建系统、运行时库和特定平台的限制)而失败或停滞。

Sherpa-ONNX 是一个功能强大且灵活的开源工具包,用于通过 ONNX Runtime 部署 ASR 模型。然而,在将 Sherpa-ONNX 集成到基于 Windows 的现有生产系统时,由于需要使用 MT(静态 CRT)运行时,而大多数生产级应用使用 MD(动态 CRT)运行时,这就会导致冲突。 

本博客将解释此问题出现的原因、其在实际项目中的表现形式,并提供一种在 MD 模式下构建 Sherpa-ONNX 的实用工程方案。该方案将使 Sherpa-ONNX 能够无缝集成到生产环境中,而无需打乱已有的构建配置。

Visual Studio 中的 MT 与 MD 运行时库模式

在 Windows 上,Visual Studio 提供两种运行时库选项,用于控制 C/C++ 运行时 (CRT) 的链接方式:

  • MD(多线程动态运行时) 
    通过共享 DLL 动态链接 CRT。
  • MT(多线程静态运行时)  
    将 CRT 静态链接到每个二进制文件中。

MD 与 MT 的比较

维度

MD

MT

CRT 实例

在所有 EXE 和 DLL 之间共享

每个 EXE/DLL 拥有专属的 CRT

跨 DLL 内存管理

可跨 DLL 安全调用 malloc/free 和 new/delete

内存必须在同一模块中释放

第三方库兼容性

通常需要重建依赖关系

二进制文件大小

较小

较大

以上对比表明,MD 模式是实际生产环境中的标准选择,尤其适用于涉及 DLL、插件或第三方库的项目。

Sherpa-ONNX 默认使用 MT 模式

默认情况下,Sherpa-ONNX 以 MT 模式构建,而且其构建系统未提供更改此行为的配置选项。

这一点可从官方代码库的以下代码片段中得到验证:https://github.com/k2-fsa/sherpa-onnx/blob/master/CMakeLists.txt#L137

		if(MSVC)
  add_compile_options(
      $<$<CONFIG:>:/MT> #---------|
      $<$<CONFIG:Debug>:/MTd> #---|-- Statically link the runtime libraries
      $<$<CONFIG:Release>:/MT> #--|
      $<$<CONFIG:RelWithDebInfo>:/MT>
      $<$<CONFIG:MinSizeRel>:/MT>
  )
endif()
	

如上所示,Sherpa-ONNX 对所有目标(包括库和示例应用)强制使用 MT 运行时。因此,任何链接到 Sherpa-ONNX 的下游项目也必须在 MT 模式下构建。

如果 Sherpa-ONNX 使用其默认配置构建,然后集成到客户项目中,则客户将被迫更改其现有构建的运行时库链接模式。在实际生产环境中,此类更改几乎是不可接受的。运行时库设置通常是标准化且严格受控的,偏离默认或推荐配置会引入不必要的风险和潜在的不稳定性。因此,这一要求成为了在生产系统中采用 Sherpa-ONNX 的重大障碍。

实际示例:在自定义项目中使用 Sherpa-ONNX

为说明此问题及其产生的实际影响,我们将通过一个具体示例进行演示。

1) 准备模型
下载本示例中使用的标点模型并解压到某个目录:

		# wget https://github.com/k2-fsa/sherpa-onnx/releases/download/punctuation-models/sherpa-onnx-punct-ct-transformer-zh-en-vocab272727-2024-04-12-int8.tar.bz2
	

2) 在 Windows 上构建 Sherpa-ONNX
按照官方指南克隆代码库并构建 Sherpa-ONNX:https://k2-fsa.github.io/sherpa/onnx/install/windows.html?highlight=windows

构建步骤示例:

		# git clone https://github.com/k2-fsa/sherpa-onnx
# cd sherpa-onnx
# cmake -G "Visual Studio 17 2022" -A x64 -B build . \
       -DCMAKE_BUILD_TYPE=Release \
       -DSHERPA_ONNX_ENABLE_BINARY=OFF  \
       -DSHERPA_ONNX_ENABLE_WEBSOCKET=OFF  \
       -DSHERPA_ONNX_ENABLE_TTS=OFF
# cd build
# cmake --build . --config release -j 16
	

生成的库文件可在以下位置找到:
build\lib\Release

3) 创建示例项目
项目结构:

		include\
    sherpa-onnx\
        csrc\
            offline-punctuation.h
            offline-punctuation-model-config.h
            parse-options.h
src\
    test_punctuation.cpp
lib\
    sherpa-onnx-core.lib
    onnxruntime.lib
    onnxruntime.dll
CMakeLists.txt
	

准备步骤:

  • 将 Sherpa-ONNX 源码中的三个头文件复制到项目的 include\ 目录。
  • 将 sherpa-onnx\build\lib\Release\ 中的 sherpa-onnx-core.lib 复制到 lib\ 目录。
  • 按照官方说明安装 Ryzen AI 软件:https://ryzenai.docs.amd.com/en/latest/inst.html
  • 将 C:\Program Files\RyzenAI\1.7.0\onnxruntime\bin 中的 onnxruntime.dll 复制到 lib\ 目录。
  • 将 C:\Program Files\RyzenAI\1.7.0\onnxruntime\lib 中的 onnxruntime.lib 复制到 lib\ 目录。

示例 CMakeLists.txt:

		cmake_minimum_required(VERSION 3.18.1)
project(test_punctuation)
set(CMAKE_CXX_STANDARD 20)
add_compile_options($<$<CONFIG:>:/MT>  $<$<CONFIG:Release>:/MT>)
add_executable(test_punctuation ${CMAKE_SOURCE_DIR}/src/test_punctuation.cpp)
target_link_directories(test_punctuation PRIVATE ${CMAKE_SOURCE_DIR}/lib )
target_include_directories(test_punctuation PRIVATE ${CMAKE_SOURCE_DIR}/include )
target_link_libraries(test_punctuation PRIVATE  sherpa-onnx-core  onnxruntime)
	

test_punctuation.cpp 的示例代码:

		#include <iostream>
#include <fstream>
#include "sherpa-onnx/csrc/offline-punctuation.h"

int32_t main(int32_t argc, char *argv[]) {
  sherpa_onnx::OfflinePunctuationConfig cfg;
  cfg.model.ct_transformer = argv[1];
  cfg.model.num_threads = 1;
  cfg.model.debug = false;
  cfg.model.provider = "cpu";
  std::string stringv = "你好吗how are you Fantasitic 谢谢我很好你怎么样呢";
  auto punct = std::make_unique<sherpa_onnx::OfflinePunctuation>(cfg);
  auto text_with_punct = punct->AddPunctuation(stringv);
  std::cout<< text_with_punct <<"\n";
  return 0;
}
	

4) 构建并运行 

		# cmake -G "Visual Studio 17 2022" -A x64 -S . -B build
# cd build
# cmake --build . --config release
# copy ..\lib\onnxruntime.dll .
# release\test_punctuation.exe some_dir\model.int8.onnx 
	

输出: 

		你好吗?how are you Fantasitic?谢谢我很好,你怎么样呢?
	

程序能够成功运行,但这仅仅是因为项目被明确强制使用 MT 模式。

MT/MD 不匹配问题

从示例项目的 CMakeLists.txt 中移除以下行:

add_compile_options($<$<CONFIG:>:/MT>  $<$<CONFIG:Release>:/MT>)

在默认的 MD 模式下重新构建项目,此时将出现以下链接器错误:

		sherpa-onnx-core.lib(offline-punctuation.obj) : error LNK2038: mismatch detected for 'RuntimeLibrary': value 'MT_Static
Release' doesn't match value 'MD_DynamicRelease' in test_punctuation.obj [test_punct
uation.vcxproj]
	

此错误清楚地表明应用与 sherpa-onnx-core.lib 之间存在运行时库不匹配问题。

 使 Sherpa-ONNX 使用 MD 模式

在 sherpa-onnx\build 目录中搜索“$<$<CONFIG:>:/MT>”,它出现在 sherpa-onnx\build\_deps\kaldi_decoder-src\CMakeLists.txt.

这意味着:依赖的 kaldi Decoder 项目使用了 MT 模式,这导致 Sherpa-onnx 项目必须使用 MT 模式。

要解决此问题,必须在 Kaldi Decoder 构建配置中启用 MD 模式。

在 sherpa-onnx\cmake\kaldi-decoder.cmake 中,定义了以下配置:

		  set(kaldi_decoder_URL  "https://github.com/k2-fsa/kaldi-decoder/archive/refs/tags/v0.2.10.tar.gz")
  set(kaldi_decoder_URL2 "https://hf-mirror.com/csukuangfj/sherpa-onnx-cmake-deps/resolve/main/kaldi-decoder-0.2.10.tar.gz")
  set(kaldi_decoder_HASH "SHA256=a3d602edc1f422acfe663153faf3f0a716305ec1f95b8fcf9d28d301d6827309")
	

此配置表明 Sherpa-ONNX 依赖于 kaldi-decoder 版本 v0.2.10。

构建 Sherpa-ONNX 后,相应的源码归档文件会缓存在本地: 

`sherpa-onnx\build\_deps\kaldi_decoder-subbuild\kaldi_decoder-populate-prefix\srcv0.2.10.tar.gz`.

修改步骤:

1.将归档文件传输到 Linux 环境(例如通过 SSH),并解压: # tar zxvf v0.2.10.tar.gz

2.在解压后的目录中,编辑 kaldi-decoder-0.2.10\CMakeLists.txt,注释掉以下行(大约从第 59 行开始)以禁用 MT 运行时:

		     # add_compile_options(
     #     $<$<CONFIG:>:/MT> #---------|
     #     $<$<CONFIG:Debug>:/MTd> #---|-- Statically link the runtime libraries
     #     $<$<CONFIG:Release>:/MT> #--|
     # )
	

3.  重新打包修改后的源码目录:
# tar zcvf kaldi-decoder-0.2.10.tar.gz  ./ kaldi-decoder-0.2.10

4.  计算更新后归档文件的 SHA256 校验和:
# sha256sum kaldi-decoder-0.2.10.tar.gz 
记录新生成的 SHA256 值。

5.将更新后的归档文件传输回 Windows 环境,并将其放置在 Sherpa-ONNX 根目录中。这将强制 Sherpa-ONNX 构建使用修改后的 kaldi-decoder 包,而不是从互联网下载。

6.更新 sherpa-onnx\cmake\kaldi-decoder.cmake 中的 SHA256 值: set(kaldi_decoder_HASH "SHA256=NEW_SHA256_VALUE_FROM_SHA256SUM")

将原始校验和替换为上一步中获得的值。

7.修改 sherpa-onnx\CMakeLists.txt,注释掉以下代码块,以允许 Sherpa-ONNX 本身在 MD 模式下构建:  

		 # if(MSVC)
 # add_compile_options(
 #     $<$<CONFIG:>:/MT> #---------|
 #     $<$<CONFIG:Debug>:/MTd> #---|-- Statically link the runtime libraries
 #     $<$<CONFIG:Release>:/MT> #--|
 #     $<$<CONFIG:RelWithDebInfo>:/MT>
 #     $<$<CONFIG:MinSizeRel>:/MT>
 # )
 # endif()
	

8.删除 sherpa-onnx\build 目录,并从头开始重新构建 Sherpa-ONNX。

9.将新生成的 sherpa-onnx-core.lib 复制到示例项目的 lib 目录中。

10.重新构建示例项目。现在,应该可以成功完成构建,而不会出现任何 MT/MD 运行时不匹配错误。

11.再次运行项目。输出应与使用 MT 模式时获得的结果相同。

总结

将 ASR 框架集成到生产系统中时,常常会遇到除模型设计或推理速度以外的其他挑战。运行时库配置,尤其是在 Windows 上,在决定技术是否可用方面起着至关重要的作用。

在本博客中,我们:

  • 解释了什么是 Sherpa-ONNX,以及为什么运行时库配置在生产环境中至关重要
  • 演示了生产场景中遇到的实际 MT/MD 运行时不匹配问题
  • 提出了一种在 MD 模式下构建 Sherpa-ONNX 的实用工程方案
  • 在无需更改现有构建配置的情况下,使 Sherpa-ONNX 能够集成到生产环境中

这种方案使 Sherpa-ONNX 能够在 AMD Ryzen AI 平台上与大型语言和语音模型紧密协作,确保在实际生产系统中实现稳定、可靠的部署。

 

Share:

Related Blogs