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

news2024/11/15 8:24:21

简介

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路径:
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【4月】CDA Club 第2期数据分析组队打卡学习活动开启!

活动名称 CDA Club 第2期数据分析组队打卡学习活动 活动介绍 本次打卡活动由CDA俱乐部旗下学术部主办。目的是通过数据分析科普内容&#xff0c;为数据分析爱好者提供学习和交流的机会。方便大家利用碎片化时间在线学习&#xff0c;以组队打卡的形式提升学习效果&#xff0c…

MySQL 中 聚集索引、非聚集索引、覆盖索引、索引下推 到底是什么

一、什么是 聚集索引、非聚集索引 在MySQL数据库中&#xff0c;索引是提高查询效率的关键。而聚集索引、非聚集索引、覆盖索引、索引下推其实是索引优化的重要策略之一。那这些名词的含义到底是什么呢&#xff1f; 在开始分析前&#xff0c;先来了解下 B 树的索引结构 和 回表…

Java面试必问题17:ArrayList与LinkedList区别

是否保证线程安全&#xff1a; ArrayList 和LinkedList 都是不同步的&#xff0c;也就是不保证线程安全&#xff1b;底层数据结构&#xff1a; Arraylist 底层使用的是Object 数组&#xff1b;LinkedList 底层使用的是双向链表 数据结构&#xff08;JDK1.6 之前为循环链表&…

Frida 官方手册 中文版 ( 机翻+人翻 )

Frida 英文文档&#xff1a;https://frida.re/docs/home/ Frida 中文文档&#xff1a;https://pypi.org/project/frida-zhongwen-wendang/ 目的&#xff1a;给自己一个认真阅读文档的机会&#xff01;&#xff01;&#xff01; 部分名词找不到合适的中文表达&#xff0c;直接使…

Day18 代码随想录(1刷) 二叉树

513. 找树左下角的值 给定一个二叉树的 根节点 root&#xff0c;请找出该二叉树的 最底层 最左边 节点的值。 假设二叉树中至少有一个节点。 示例 1: 输入: root [2,1,3] 输出: 1示例 2: 输入: [1,2,3,4,null,5,6,null,null,7] 输出: 7提示: 二叉树的节点个数的范围是 [1,104]…

echarts 柱形图如何让其中一个柱子的颜色跟其他柱子不同

如何让其中一个柱子的颜色跟其他柱子不同 series: [{data: [120,// 使用对象的形式&#xff0c; value代表当前值, itemStyle设置样式{value: 200,itemStyle: {color: #a90000}},150,80,70,110,130],type: bar}]设置单个柱子颜色&#xff1a; 柱形图单个柱子颜色: https://e…

AI预测福彩3D第17弹【2024年3月25日预测--第4套算法重新开始计算第3次测试】

昨天对第4套算法进行了第二次测试&#xff0c;其中第二套方案已成功命中。测试的目的主要是为了记录统计两套方案的稳定性和命中率。今天继续对第4套算法进行测试&#xff0c;今天是第3次测试&#xff0c;同样测试两个方案。废话不多说&#xff0c;直接上结果。 2024…

【Qt问题】Qt中文乱码问题解决方案(详细汇总)

【Qt问题】Qt中文乱码问题解决方案&#xff08;详细汇总&#xff09; 一、问题描述&#xff1a; 由于Qt对中文的支持不是很好&#xff0c;使用QtCreator进行开发的过程中&#xff0c;经常会出现各种乱七八糟的中文乱码问题&#xff0c;比如我前面遇到的 【Qt问题】初始化菜单…

一个开源的分布式在线教育系统

项目介绍 roncoo-education —— 一个分布式在线教育系统。目前主要功能有课程点播功能&#xff0c;支持多家视频云的接入&#xff0c;课程附件管理功能&#xff0c;支持多家存储云的接入&#xff0c;可以帮助个人或者企业快速搭建一个轻量级的在线教育平台。 系统分为后台、前…

Python数据匹配和记录链接库之recordlinkage使用详解

概要 Python的recordlinkage库为数据匹配和记录链接提供了一个强大的工具集,使得从不同数据源识别重复或相关记录变得简单高效。这对于数据清洗、合并数据集、实体识别等任务至关重要。 recordlinkage库简介 recordlinkage提供了一套全面的工具来进行复杂的记录比较、匹配和…

程序人生 - 某程序员哀叹:辛辛苦苦写几年代码,做了些业务,有了点成就感,但回头一看80%都没用,没法写到简历上!

什么事情会让你脊背一凉&#xff0c;细思极恐&#xff1f; 一位程序员说了一件很可怕的事&#xff1a; 辛辛苦苦写了几年代码&#xff0c;做了些业务&#xff0c;在一片祥和中有了点成就感。然而回头一看&#xff0c;80&#xff05;是没啥用的&#xff0c;甚至没法写到简历上&…

[ Linux ] git工具的基本使用(仓库的构建,提交)

1.安装git yum install -y git 2.打开Gitee&#xff0c;创建你的远程仓库&#xff0c;根据提示初始化本地仓库&#xff08;这里以我的仓库为例&#xff09; 新建好仓库之后跟着网页的提示初始化便可以了 3.add、commit、push三板斧 git add . //add仓库新增&#xff08;变…

HTTP状态码(3)

HTTP 状态码负责表示客户端 HTTP 请求的返回结果、标记服务器端的处理是否正常、通知出现的错误等工作 状态码告知从服务器端返回的请求结果 状态码的职责是当客户端向服务器端发送请求时&#xff0c;描述返回的请求结果。借助状态码&#xff0c;用户可以知道服务器端是正常…

vue+elementUI实现树形穿梭框

1.实现效果 2.整体思路 将左侧选中的节点移动到右侧&#xff0c;还要保持树结构&#xff0c;意味着移动子节点&#xff0c;需要把该子节点对应的父节点甚至父节点的父节点一并移到右侧形成一个新的树结构&#xff0c;树结构的层级和原来的树保持一致&#xff0c;只是右侧展示…

TOP、CCF、IEEE-Trans系列SCI,均2个月左右录用!进展超顺!

能源工程类SCIE&#xff08;中科院TOP&#xff0c;周期短&#xff09; 【期刊简介】IF&#xff1a;11.0-12.0&#xff0c;JCR1区&#xff0c;中科院1区TOP 【出版社】ELSEVIER出版社 【版面情况】正刊&#xff0c;2024.03.31截稿 【预警情况】2020-2024年无预警记录 【检索…

机器学习(27)

文章目录 文献阅读1. 题目2. abstract3. 网络架构3.1 Theoretical Results 4. 文献解读4.1 Introduction4.2 创新点4.3 实验过程4.3.1 数据集4.3.2 参数设置 4.4 结论 三、实现GAN1. 任务要求2. 实验结果3.实验代码3.1数据准备3.2 模型构建3.3 展示函数3.4 训练过程 小结本周内…

在线一问一答网页版源码系统 源码全开源可二次开发 带完整的安装代码包以及系统搭建教程

在信息化社会&#xff0c;知识共享和互动交流成为了人们日常生活和工作中不可或缺的一部分。在线问答系统作为连接知识提供者和需求者的桥梁&#xff0c;具有广阔的市场前景和巨大的社会价值。然而&#xff0c;传统的问答系统往往存在功能单一、定制性差、开发成本高等问题&…

数据库读写分离分案

环境&#xff1a;MySQL主从数据库。如需要搭建可参考上一篇文章&#xff1a;MySQL主从数据库简单搭建 数据库使用主从可确保数据一致性&#xff0c;示例是基于一个完整的项目之上做了一些修改&#xff0c;为测试效果直接连接了两个非主从配置的数据库&#xff0c;其中只有测试…

Linux cp、mv命令显示进度条

1.advcpmv 平常使用cp 拷贝大文件时&#xff0c;看不到多久可以完成&#xff0c;虽然加上-v参数也只能看到正在拷贝文件&#xff0c;那就使用以下方法实现 git clone https://github.com/jarun/advcpmv.git cd advcpmv/ bash install.shmv ./advcp /usr/local/bin/ mv ./advmv …

Vite+Vue3+TS+Vue-Router+Axios+Pinia开发模板

一、模板介绍 VUE3开发全家桶模板&#xff0c;安装了ts,router,axios,pinia并提供了简单示例并提供了它们的官网链接。 对axios进行了简单封装。 二、下载地址 https://github.com/yigedayouzi/ViteTemplateOne 三、快速开始 1、git clone gitgithub.com:yigedayouzi/Vite…