语音转文字——sherpa ncnn语音识别离线部署C++实现

简介

Sherpa是一个中文语音识别的项目,使用了PyTorch 进行语音识别模型的训练,然后训练好的模型导出成 torchscript 格式,以便在 C++ 环境中进行推理。尽管 PyTorch 在 CPU 和 GPU 上有良好的支持,但它可能对资源的要求较高,不太适合嵌入式环境或要求轻量级依赖的场景。

考虑到模型是使用 PyTorch 训练的,则优先选择 ONNX 格式的推理框架。虽然 PyTorch 提供了对 ONNX 的支持,但并不是所有的 PyTorch 算子都可以无缝地转换为 ONNX 格式。为了考虑多平台的支持,这里选择了 ncnn 推理框架。ncnn 提供了 PNNX 模型转换工具,可以将 PyTorch 模型转换为 ncnn 支持的格式。ncnn 和 PNNX 的代码可读性和可扩展性都很好,当遇到不支持的算子时,可以方便地扩展 ncnn 和 PNNX。
此外,尽管 ncnn 开源已有 5 年时间,但其开发者社区仍然非常活跃,并且持续更新和维护。因此,当遇到问题时,可以轻松地获取帮助。

项目地址:https://github.com/k2-fsa

项目流程

  1. 训练模型:使用 PyTorch 进行语音识别模型的训练。确保模型在训练集上表现良好,并且经过充分的验证和调优。

  2. 导出模型:将 PyTorch 模型导出为 ONNX 格式。这可以通过 PyTorch 提供的内置函数实现。但要注意,不是所有的 PyTorch 算子都能无缝地转换为 ONNX 格式,因此可能需要一些额外的工作来处理不受支持的算子。

  3. 转换为 ncnn 格式:使用 PNNX 模型转换工具,将 ONNX 格式的模型转换为 ncnn 支持的格式。确保在转换过程中模型的性能和准确率不受影响。

  4. 部署到 Sherpa:在 Sherpa 中部署转换后的 ncnn 模型。这可能需要一些 C++ 编程来集成模型并构建语音识别应用程序。确保在部署过程中考虑到性能、内存占用等因素。

  5. 扩展和优化:如果在转换模型或部署过程中遇到问题,可以利用 ncnn 和 PNNX 的可扩展性和活跃的开发者社区来解决。可能需要扩展 ncnn 或 PNNX 来处理不支持的算子或优化性能。

源码实现

C++调用代码:

#include <stdio.h>
#include <algorithm>
#include <chrono>
#include <iostream>

#include <ncnn/net.h>
#include <sherpa-ncnn/csrc/recognizer.h>
#include <sherpa-ncnn/csrc/wave-reader.h>

extern std::string WideByteToAcsi(std::wstring &wstrcode)
{
  int asciisize = ::WideCharToMultiByte(CP_OEMCP, 0, wstrcode.c_str(), -1, NULL,
                                        0, NULL, NULL);
  if (asciisize == ERROR_NO_UNICODE_TRANSLATION) 
  {
    throw std::exception("Invalid UTF-8 sequence.");
  }
  if (asciisize == 0) 
  {
    throw std::exception("Error in conversion.");
  }
  std::vector<char> resultstring(asciisize);
  int convresult =
      ::WideCharToMultiByte(CP_OEMCP, 0, wstrcode.c_str(), -1, &resultstring[0],
                            asciisize, NULL, NULL);

  if (convresult != asciisize) 
  {
    throw std::exception("La falla!");
  }

  return std::string(&resultstring[0]);
}

extern std::wstring Utf8ToUnicode(const std::string &utf8string) 
{
  int widesize =
      ::MultiByteToWideChar(CP_UTF8, 0, utf8string.c_str(), -1, NULL, 0);
  if (widesize == ERROR_NO_UNICODE_TRANSLATION) {
    throw std::exception("Invalid UTF-8 sequence.");
  }
  if (widesize == 0) {
    throw std::exception("Error in conversion.");
  }

  std::vector<wchar_t> resultstring(widesize);

  int convresult = ::MultiByteToWideChar(CP_UTF8, 0, utf8string.c_str(), -1,
                                         &resultstring[0], widesize);

  if (convresult != widesize) {
    throw std::exception("La falla!");
  }

  return std::wstring(&resultstring[0]);
}

extern std::string UTF8ToASCII(std::string &strUtf8Code) 
{
  std::string strRet("");
  std::wstring wstr = Utf8ToUnicode(strUtf8Code);
  strRet = WideByteToAcsi(wstr);
  return strRet;
}


int main()
{
    std::string wav_file_path = "short.wav";

    //初始化模型
    sherpa_ncnn::ModelConfig model_conf;
    model_conf.tokens = "models/tokens.txt";
    model_conf.encoder_param = "models/encoder_jit_trace.param";
    model_conf.encoder_bin = "models/encoder_jit_trace.bin";
    model_conf.decoder_param = "models/decoder_jit_trace.param";
    model_conf.decoder_bin = "models/decoder_jit_trace.bin";
    model_conf.joiner_param = "models/joiner_jit_trace.param";
    model_conf.joiner_bin = "models/joiner_jit_trace.bin";

    //线程
    int32_t num_threads = 4;
    model_conf.encoder_opt.num_threads = num_threads;
    model_conf.decoder_opt.num_threads = num_threads;
    model_conf.joiner_opt.num_threads = num_threads;

    float expected_sampling_rate = 16000;
    sherpa_ncnn::DecoderConfig decoder_conf;

    knf::FbankOptions fbank_opts;
    fbank_opts.frame_opts.dither = 0;
    fbank_opts.frame_opts.snip_edges = false;
    fbank_opts.frame_opts.samp_freq = expected_sampling_rate;
    fbank_opts.mel_opts.num_bins = 80;

    //读音频文件
    sherpa_ncnn::Recognizer recognizer(decoder_conf, model_conf, fbank_opts);
    bool is_ok = false;
    std::vector<float> samples = sherpa_ncnn::ReadWave(wav_file_path, expected_sampling_rate, &is_ok);
    if (!is_ok) 
    {
        fprintf(stderr, "Failed to read %s\n", wav_file_path.c_str());
        return -1;
    }

    //音频时长
    const float duration = samples.size() / expected_sampling_rate;
    std::cout << "wav duration (s): " << duration << "\n";

    //开始推理
    auto begin = std::chrono::steady_clock::now();
    std::cout << "Started!\n";

    recognizer.AcceptWaveform(expected_sampling_rate, samples.data(),samples.size());
    std::vector<float> tail_paddings(static_cast<int>(0.3 * expected_sampling_rate));
    recognizer.AcceptWaveform(expected_sampling_rate, tail_paddings.data(),tail_paddings.size());

    recognizer.Decode();
    auto result = recognizer.GetResult();
    std::cout << "Done!\n";

    std::cout << "Recognition result for " << wav_file_path << "\n"<< UTF8ToASCII(result.text) << "\n";

    auto end = std::chrono::steady_clock::now();
    float elapsed_seconds = std::chrono::duration_cast<std::chrono::milliseconds>(end - begin).count() /1000.0;

    printf("Elapsed seconds: %.3f s\n", elapsed_seconds);
    float rtf = elapsed_seconds / duration;
    printf("Real time factor (RTF): %.3f / %.3f = %.3f\n", duration,elapsed_seconds, rtf);

    return 0;
}

源码下载地址:https://download.csdn.net/download/matt45m/89002001?spm=1001.2014.3001.5503

下载之后,配置include和lib路径:
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/475411.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

面试算法-67-完全二叉树的节点个数

题目 给你一棵 完全二叉树 的根节点 root &#xff0c;求出该树的节点个数。 完全二叉树 的定义如下&#xff1a;在完全二叉树中&#xff0c;除了最底层节点可能没填满外&#xff0c;其余每层节点数都达到最大值&#xff0c;并且最下面一层的节点都集中在该层最左边的若干位置…

招聘系统开发招聘软件APP招聘小程序开发对标仿BOSS直聘

项目背景 一、市场前景&#xff1a;求职招聘市场的数字化革新 随着互联网的普及和人们对线上求职的接受度提高&#xff0c;求职招聘市场正经历一场数字化革新。招聘系统、软件APP与小程序等数字化产品不仅提供了便捷的求职和招聘服务&#xff0c;还通过智能算法和数据分析技术…

“美联储才是大多头”!鲍威尔推翻降息疑虑!今年降息三次,比特币直奔6.8万!

北京时间周四&#xff08;3月21日&#xff09;凌晨&#xff0c;美联储宣布将基准利率维持在5.25%-5.50%区间&#xff0c;为连续第五次保持利率不变&#xff0c;符合市场预期。 然而&#xff0c;更引人注目的是美联储对未来的降息计划。即使降低通胀的进展已经停滞&#xff0c;美…

创建maven项目

创建空项目 然后配置maven 然后&#xff0c;创建module

多线程实现

1.多线程&#xff1a;并发实现 主线程和子线程并行实现。 一个进程中有多个线程&#xff0c;可以同时进行多个任务。进程是系统分配的&#xff0c;线程的执行是由调度器决定的。 注意&#xff1a;线程开启不一定执行&#xff0c;由Cpu调度执行。 线程创建的三种方式&#xff…

js【详解】深拷贝

什么是深拷贝&#xff1f; 对于引用类型的数据&#xff0c;才有深浅拷贝的说法 浅拷贝 &#xff1a;执行拷贝的变量只复制被拷贝变量内存的引用数据的地址。 被拷贝变量内地址指向的数据发生变化时&#xff0c;执行拷贝的变量也会同步改变 深拷贝&#xff1a; 在堆内存中开…

高效输入关键词,瞬间生成惊艳图片:创意与速度的完美结合!

在数字化时代&#xff0c;图片已经成为我们生活中不可或缺的一部分。无论是社交媒体的分享、广告的创意&#xff0c;还是工作中的报告展示&#xff0c;高质量的图片都能为我们的内容增添不少色彩。但你是否曾遇到过这样的困扰&#xff1a;想要一张符合心意的图片&#xff0c;却…

VScode前端常用插件推荐

Color Highlight—查看css颜色 这个插件可以让我们在vscode中看到代码中的颜色&#xff0c;效果如图所示 Chinese (Simplified) (简体中文) Language Pack for Visual Studi ------ 简体中文语言包 把vscode翻译为中文 Auto Rename Tag—自动修改对应的标签 效果如图所示…

uniapp+uview实现城市选择器

1.效果 2.代码—在components中创建CitySelect组件 <template><view><text class"uni-input" style"background-color: #F8F8F8;display: block;line-height: 76rpx;padding:0 29rpx;" tap"open">{{value}}</text><…

01-java面试题八股文-----java基础——20题

文章目录 <font color"red">1、java语言有哪些特点&#xff1a;<font color"red">2、面向对象和面向过程的区别<font color"red">3、标识符的命名规则。<font color"red">4、八种基本数据类型的大小&#xff…

linux下用docker安装mysql及导入文件

目录 1. 非root用户设置docker权限2. user账号安装mysql2. root账号打开防火墙3. 启动mysql容器3.1 在指定工作目录下建立文件夹3.2 配置文件3.3 开启mysql容器 4. 进入容器4.1 通过容器进入mysql4.1 设置账号4.2 建立数据库4.3 导入文件 5. windows连接数据库参考文件 1. 非ro…

.locked勒索病毒是什么,企业数据被加密了如何恢复?

.locked勒索病毒介绍 .locked勒索病毒是一种恶意软件&#xff0c;它利用加密技术锁定用户的数据或系统&#xff0c;并以此进行勒索。用户一旦感染此病毒&#xff0c;将无法访问其重要文件&#xff0c;病毒会要求用户支付一笔赎金以获取解密密钥。这种病毒通常使用强大的加密算法…

ssm基于Vue.js的在线购物系统的设计与实现论文

摘 要 随着科学技术的飞速发展&#xff0c;各行各业都在努力与现代先进技术接轨&#xff0c;通过科技手段提高自身的优势&#xff1b;对于在线购物系统当然也不能排除在外&#xff0c;随着网络技术的不断成熟&#xff0c;带动了在线购物系统&#xff0c;它彻底改变了过去传统的…

C#配置连接数据库字段

在Web.config文件中 添加如下配置 <!--连接数据库字段--><connectionStrings><add name"sql" connectionString"server.;uidsa;pwd8888;databaseArticleWebSite" /></connectionStrings>

Harbor介绍

1.什么是Harbor Harbor是一个开源的企业级Docker Registry管理项目&#xff0c;由VMware公司开源。 Harbor提供了比Docker官方公共镜像仓库更为丰富和安全的功能&#xff0c;尤其适合企业环境使用。以下是Harbor的一些关键特性&#xff1a; 权限管理&#xff08;RBAC&#x…

mysql 空间查询 多边形内的点

数据库查询 # 1新增空间point类型坐标字段 ALTER TABLE gaoxin_isdp.business_master ADD COLUMN location2 point NULL AFTER location;# 2从原字段更新点位字段&#xff0c;原字段poi1是字符串106.474596,29.464360 UPDATE business_master SET location POINT(substr(poi…

BetterDisplay Pro:让屏幕管理更高效、更便捷

BetterDisplay Pro是一款功能强大的显示器管理软件&#xff0c;适用于Windows和Mac操作系统。其主要功能包括显示器校准、自动校准、多种预设模式、手动校准以及可视化数据等。 具体而言&#xff0c;这款软件可以根据用户的需求和环境条件调整显示器的颜色、亮度和对比度等参数…

YOLO改进模块出现的问题及改进方法

1.grid_sampler_2d_backward_cuda 在对YOLOv9进行改进的过程中&#xff0c;有的时候就会出现这种报错&#xff1a;RuntimeError: grid_sampler_2d_backward_cuda does not have a deterministic implementation&#xff0c;but you set torch.use_deterministic_algorithms(Tr…

免费阅读篇 | 芒果YOLOv8改进111:注意力机制CBAM:轻量级卷积块注意力模块,无缝集成到任何CNN架构中,开销可以忽略不计

&#x1f4a1;&#x1f680;&#x1f680;&#x1f680;本博客 改进源代码改进 适用于 YOLOv8 按步骤操作运行改进后的代码即可 该专栏完整目录链接&#xff1a; 芒果YOLOv8深度改进教程 该篇博客为免费阅读内容&#xff0c;YOLOv8CBAM改进内容&#x1f680;&#x1f680;&am…

Sora的前世今生:从文生图到文生视频

在2月16日凌晨&#xff0c;OpenAI首款文本生成视频模型Sora正式亮相&#xff0c;迅速在网络上引发广泛关注。对于Sora背后的技术原理&#xff0c;网络上已经充斥着各种分析和猜测&#xff0c;其中大多数分析都是从技术报告入手&#xff0c;对于普通读者来说难度相对较高。为了使…