语音转文字——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路径:
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

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

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

相关文章

HarmonyOS 应用开发案例

本帖下方集中了HarmonyOS Next应用开发时&#xff0c;会遇到的常见应用案例。后续会持续更新大量案例&#xff0c;帮助开发者快速学习。欢迎感兴趣的同学加入Q&#xff1a;454901491 72.手写绘制及保存图片案例&#xff08;0319更新&#xff09;&#xff08;点此查看源码实现&…

Windows10无盘母盘制作-以云更新为例

Windows10无盘母盘制作-以云更新为例 缘起环境准备创建虚拟机安装系统导出系统 缘起 网吧客户端在实际环境中&#xff0c;经常要面对形形色色对无盘系统&#xff0c;五花八门对无盘镜像&#xff0c; 为了方便确认不同无盘环境对客户的对影响&#xff0c;决定自己制作一个无盘母…

【python + Django】Django模板语法 + 请求和响应

前言&#xff1a; 现在现在&#xff0c;我们要开始将变量的值展现在页面上面啦&#xff01; 要是只会显示静态页面&#xff0c;我们的页面也太难看和死板了&#xff0c; 并且数据库的数据也没法展现在页面上。 但是呢&#xff0c;模板语法学习之后就可以啦&#xff01;&…

【大模型服务】01EdgeFM: Leveraging Foundation Model for Open-set Learning on the Edge

该文发表在 SenSys’23(CCF B) 上&#xff0c;作者是来自港中文的鄢振宇。这是一篇关于云端协同的文章&#xff0c;主要解决边缘设备深度模型的泛化性不足问题&#xff0c;实现 Open-set Learning。 文章目录 背景Open-Set Recognition 的挑战EdgeFM 整体架构图云端&#xff1…

21---EEPROM电路设计

视频链接 EEPROM电路设计01_哔哩哔哩_bilibili EEPROM电路设计 1、存储器的分类 一般根据掉电丢失来划分的存储器。可分为易失性存储器和非易失性储存器。 ROM在系统停止供电的时候仍然可以保持数据&#xff0c;而RAM通常都是在掉电之后就丢失数据。 1.1、易失性存储器-R…

升级 HarmonyOS 4 版本,腕上智慧更进一步

HUAWEI WATCH GT 3 系列升级 HarmonyOS 4 新版本后&#xff0c;手表体验更进一步&#xff0c;快来看看有哪些变化吧~

如何进行端口映射端口转发?

在互联网时代&#xff0c;网络安全成为一项重要的任务。端口映射端口转发是一种常用的网络安全技术&#xff0c;它可以实现远程访问内部网络资源的需求。本文将介绍端口映射端口转发的基本原理和应用场景&#xff0c;以及一种名为"天联"的解决方案。 基本原理 端口映…

种植新革命:科技赋能绿色未来

《种植新革命&#xff1a;科技赋能绿色未来》 一、种植技术的颠覆式创新 随着科技的飞速发展&#xff0c;种植技术也在经历一场颠覆式的创新。传统的种植方式&#xff0c;虽然历史悠久&#xff0c;经验丰富&#xff0c;但在面对现代化、大规模、高效的需求时&#xff0c;逐渐…

LeetCode每日一题——最后一个单词的长度

最后一个单词的长度OJ链接&#xff1a;58. 最后一个单词的长度 - 力扣&#xff08;LeetCode&#xff09; 题目&#xff1a; 思路 &#xff1a; 统计字符串中最后一个单词的长度&#xff0c;那么我们可以定一一个指针&#xff0c;从后向前开始统计&#xff0c;当指针指向的元素…

【LabVIEW FPGA入门】局部变量和全局变量

局部变量 无法访问某前面板对象或需要在程序框图节点之间传递数据时&#xff0c;可创建前面板对象的局部变量。创建局部变量后&#xff0c;局部变量仅仅出现在程序框图上&#xff0c;而不在前面板上。 局部变量可对前面板上的输入控件或显示件进行数据读写。写入局部变量相当于…

流畅的 Python 第二版(GPT 重译)(十三)

第二十四章&#xff1a;类元编程 每个人都知道调试比一开始编写程序要困难两倍。所以如果你在编写时尽可能聪明&#xff0c;那么你将如何调试呢&#xff1f; Brian W. Kernighan 和 P. J. Plauger&#xff0c;《编程风格的要素》 类元编程是在运行时创建或自定义类的艺术。在 P…

局域网内怎么控制另一台电脑

局域网内怎么控制另一台电脑 在局域网内控制另一台电脑是一个相对高级的操作&#xff0c;通常用于远程管理、技术支持或资源共享等场景。要实现这一功能&#xff0c;需要确保两台电脑都连接到同一个局域网&#xff0c;并且已进行适当的配置。以下是几种常见的方法&#xff1a;…

【蓝桥杯选拔赛真题42】C++切蛋糕 第十四届蓝桥杯青少年创意编程大赛 算法思维 C++编程选拔赛真题解析

目录 C切蛋糕 一、题目要求 1、编程实现 2、输入输出 二、算法分析 三、程序编写 四、程序说明 五、运行结果 六、考点分析 七、推荐资料 C切蛋糕 第十四届蓝桥杯青少年创意编程大赛C选拔赛真题 一、题目要求 1、编程实现 有一块矩形蛋糕&#xff0c;小明从蛋糕…

GCN-Align论文翻译

GCN-Align翻译 Cross-lingual Knowledge Graph Alignment via Graph Convolutional Networks 基于图卷积网络的跨语言知识图谱对齐 Abstract 多语言知识图&#xff08;KGs&#xff09;&#xff0c;如DBpedia和YAGO&#xff0c;包含几种不同语言的实体结构化知识&#xff0c…

墨菲安全在软件供应链安全领域阶段性总结及思考

向外看&#xff1a;墨菲安全在软件供应链安全领域的一些洞察、思考、行动 洞察 现状&挑战&#xff1a; 过去开发安全体系是无法解决软件供应链安全问题的&#xff1b;一些过去专注开发安全领域的厂商正在错误的引导行业用开发安全思维解决软件供应链安全问题&#xff0c;治…

SpringCloud中的@EnableDiscoceryClient和@EnableFeignClients注解的作用解析、RPC远程过程调用

目录 EnableDiscoveryClient 服务发现的核心概念 服务注册中心 EnableDiscoveryClient注解的作用 服务心跳健康检查 使用示例 EnableFeignClients Feign简介 EnableFeignClients注解的作用 RPC&#xff08;Remote Procedure Call&#xff09; 参考链接 Spring Cloud…

javaScript——BFS结合队列求迷宫最短路径

这里推荐先去看下B站这个老师讲的BFS迷宫问题&#xff0c;只用看前五分钟就能懂用BFS队列实现的原理。[POJ] 3984 迷宫问题 BFS_哔哩哔哩_bilibili 问题描述&#xff1a;由m*n的矩阵构成了一个迷宫&#xff0c; 矩阵中为1的元素表示障碍物&#xff0c;不能走&#xff0c;为0表示…

如何在职场中提升自己的竞争力

随着社会的发展&#xff0c;职场竞争日益激烈。如何在职场中提升自己的竞争力&#xff0c;成为许多职场人士关注的焦点。本文将从以下几个方面为大家提供一些建议。 一、不断学习&#xff0c;提升专业技能 在职场中&#xff0c;专业技能是衡量一个人竞争力的重要标准。要想在职…

让数据在两个buckets之间传输 - Google Storage Transfer Service

在业务场景中&#xff0c; 有时我们不想直接暴露数据存储空间给上游系统&#xff0c; 而需要设置1个landing Path 让上游系统发送数据 如图&#xff1a; 我们只需grant landing bucket 的权限给上游系统&#xff0c; 而上游系统是访问不了storage bucket的保证了数据隔离 但是…

这个小技巧真不错!

大家好&#xff0c;我是前端队长。前端程序员&#xff0c;2023年开始玩副业。玩过AI绘画&#xff0c;公众号爆文项目&#xff0c;累计变现五位数。 今天看到萌萌在陪伴群分享了我公众号次图封面显示不全的问题。 这里我分享设计师萌萌的方法&#xff0c;很简单&#xff0c;但是…