我非常激动地今天向大家分享 transcribe.cpp。
transcribe.cpp 是一个基于 ggml 的转录库,支持所有最新的转录模型。handy-computer HF 组织下发布的每一个模型都经过了数值验证和 WER 测试,确保与参考实现一致。它在所有平台上都经过了加速。
我是 Handy 的作者和维护者。这个库源于将跨平台语音转文字应用分发给众多用户时所遇到的种种痛点。
这是一个 v0.1.0 版本的库,这意味着存在一些我独自无法发现的粗糙之处!请报告它们,让我们一起修复!
动机
请允许我直言。我认为,使用当前的 ASR 推理栈来分发跨平台应用是一件非常糟糕的事情。
基本上你只有 whisper.cpp 和 ONNX 可选。就这两个。你可以为苹果设备引入 MLX,但这样一来你就得支持两个不同的引擎,并且需要为每个引擎移植模型。我一直是 ONNX 的粉丝,因为它能让我快速为 Handy 添加模型支持,但仅靠 CPU 的话,会浪费大量性能。
市面上有一些零散的库声称支持大量模型,但据我所见,它们作者不明,测试情况也不清楚。它们给我带来的疑问远多于答案。
他们什么时候会停止维护这个库?创建者是否考虑过绑定,以便你能在真正的桌面或移动应用中使用它?这本质上是不是只是演示代码?他们做过基准测试吗?它比 ONNX 快吗?
正是这些问题催生了 transcribe.cpp。作为 Handy 的维护者,我需要一个我能信赖的库。一个我能下载文件并在其上运行推理的库。一个我能知道引擎中模型产生的推理结果与参考实现一样好的库。推理应该在 GPU 上运行以获得最佳性能。它应该能轻松嵌入到 Handy 中,不能是一个庞大的 PyTorch 库。它必须能在 Mac、Windows 和 Linux 上运行。而 ggml 显然是目前最好的前进方向。它拥有强大的社区和出色的分发能力。
那么你能得到什么呢?
你将得到一个快速且准确的推理引擎,并拥有广泛的模型支持。
- 支持 16 个 ASR 模型族(60 多个模型),更多模型即将加入。
- 通过 Vulkan、Metal、CUDA 和 TinyBLAS 实现加速
- 每个模型均经过数值验证和 WER 测试
- 支持流式转录
- 支持批量转录
- 基本可作为 whisper.cpp 的即插即用替代方案
- Maintainer supported bindings in 4 Languages
- Python
- JavaScript/TypeScript
- Rust
- Objective-C/Swift
广泛的模型支持
我们计划支持尽可能多的最先进转录模型。截至目前,我们已经支持了大多数公开可用的现代转录模型。仍有少数模型尚未支持,但很快会陆续添加。
加速支持
我的首要目标之一是在 Vulkan 上运行任何我想要的 ASR 模型。在我看来,这是任何需要本地推理的应用程序的底线。对于我们支持的每个模型,我们都在 Fedora 系统上的 Ryzen 4750U(CPU + Vulkan)以及我的 M4 Max 上进行了相应的基准测试。
数值验证
我还希望确保 transcribe.cpp 中的推理是准确的,并且尽可能接近参考实现。这很大程度上源于我在 Hugging Face 上发现使用 .onnx 模型时推理准确性存在极大的不确定性。为了确保我们的推理正确无误,我们针对每个模型与参考实现进行了数值验证。在数值验证的基础上,我们还进行了完整的 WER 扫描,以确保参考实现输出什么,我们就输出什么。这意味着每个模型都经过了数千条语音片段的测试,其结果与参考实现非常接近或完全相同。这些数据的结果会发布在 transcribe.cpp 仓库中,以及 Hugging Face 上每个模型的页面中。
即插即用的 whisper.cpp 替代方案
transcribe.cpp 基本可以作为 whisper.cpp 的即插即用替代方案。主要原因是:Handy 使用了 whisper.cpp,而我需要用 transcribe.cpp 发布一个更新来替换它。我需要保持与 whisper.cpp 中运行且随 Handy 一起发布的、非常流行的 .bin 文件的一定兼容性。transcribe.cpp 可以运行这些文件。whisper.cpp 中的某些标志和功能我们尚未支持。但我认为,对于绝大多数用例来说,我们的 whisper 实现是可靠的,并且可以在保持性能大致相当的情况下替代 whisper.cpp。
真正的分发
语言绑定从一开始就是我考虑的重点。虽然这个库是用 C/C++ 编写的,但我需要 Rust 语言的绑定。而且我也知道,为了让本地语音转录能够尽可能广泛地分发,至少需要提供像样的官方绑定支持。我选择了四种我认为能比较有代表性地覆盖人们使用该库场景的语言。我也欢迎其他人直接向该项目贡献绑定,前提是他们愿意承担相应的维护工作。
当然,归根结底,很多决策都是由 Handy 驱动的。由于 Handy 很受欢迎,我打算维护这个库,就像我尽力维护 Handy 一样。我希望能成为一个持续维护开源项目、并在力所能及的范围内为生态系统做出贡献的人。
如果没有 Handy,这个库根本不会存在,因为我不会遇到需要支持一大堆不同 ASR 模型的问题。我也永远不会了解到人们使用 ASR 的所有用例。我已经尽力覆盖了我听到的最常见的那些。当然,库中目前还有一些情况没有处理到。如果我有遗漏的地方,欢迎你为这个库贡献代码!
让本地语音转文字更加便捷
transcribe.cpp 的目标就是让本地运行的 ASR 变得更简单。我们知道,语音转录在大多数设备上都能以极高的准确率运行,完全没有必要将你的语音发送到云端服务。RK3566 可以通过 transcribe.cpp 在其性能羸弱的 CPU 上以快于实时的速度运行模型。使用 SOTA 模型进行快于实时的转录,功耗仅有几瓦。这不是希望或梦想,而是事实。
我认为,展望未来,出于这样或那样的原因,更多的推理将在本地进行。这使得分发问题变得至关重要。为了让更多应用在本地运行推理,我们需要让运行推理变得更容易。当然,transcribe.cpp 并没有从整体上解决这个问题,还有很长的路要走,但我希望这是向前迈出的一小步。我确实学到了很多。
致谢
我非常感谢所有支持这个项目的人。
首先要感谢 Mozilla AI、他们的 BiR 项目,以及 Mozilla AI 的 Davide。这个项目很大程度上是我脑海中的一个难题,我带着它去找他们,而他们决定支持我解决这个问题。当时 transcribe.cpp 甚至还不是一个具体的想法,我只是在探索如何在 Handy 中实现加速分发。所以非常感谢他们,感谢他们的支持,以及帮助将这个项目变为现实。
ggml。没有 ggml 及其所有贡献者,这个项目就不可能实现。非常感谢各位所做的工作。我认为 ggml 在帮助简化本地推理应用的分发、使其变得简单可行方面,确实做出了卓越的贡献。
Modal 也为我提供了至关重要的帮助。我联系了他们,他们给了我积分。这些积分被用于进行 WER 测试,并确保该库在 CUDA 上运行良好。能够验证工作的正确性,这对我帮助巨大。
Blacksmith 为 transcribe.cpp 的部分 CI/CD 提供了支持。同样,我联系了他们,他们立即回应并提供了积分。当然,CI/CD 对于确保发布的每一项内容都至少经过一定程度的测试至关重要。
Hugging Face 既是本地 AI 社区的支柱,也提供了 handy-computer 组织的私有存储空间,这样我就可以按自己的意愿上传模型。
有 AI 辅助吗?
当然有。我认为单凭一个人,在没有外部帮助的情况下,用 ggml 在几个月内从头编写一个如此规模的引擎是不可能的。这里的文字有哪部分是 AI 写的吗?没有。它们都出自我的口或我的手。
I'm super excited to share transcribe.cpp today.
transcribe.cpp is a ggml based transcription library which supports all the latest transcription models. Every model published under the handy-computer HF org has been numerically validated and WER tested to match the reference implementation. It's accelerated everywhere.
I'm the author and maintainer of Handy. This library grew from the pains of distributing a cross-platform speech-to-text application to many people.
This is a v0.1.0 library which means that there are some rough edges which I cannot discover alone! Please report them, and let's fix them together!
Motivation
Let me say this. I think distributing a cross-platform application with the current ASR inference stack is terrible.
You've basically got whisper.cpp and ONNX. That's it. You could roll MLX in for Apple devices, but now you've to support two different engines and port models to each. I've been a fan of ONNX for getting model support into Handy quickly, but so much performance is left on the table with CPU only.
There are a few random libraries out there which claim to support a lot of models, but they have unknown authors, and unknown testing, as far as I've seen. They leave me with more questions than answers.
When will they stop maintaining this library? Has the creator thought about bindings so you can actually use it in a real desktop or mobile app? Is this effectively demo code? Have they benchmarked it? Is it faster than ONNX?
And this is what led to transcribe.cpp. As Handy's maintainer I needed a library I could trust. Where I could download a file and run inference on it. Where I can know that the inference coming from the model in the engine is as good as the reference implementation. The inference should run on the GPU for the best performance. It should be trivially embeddable in Handy, it cannot be a huge pytorch lib. It must be something that works on Mac, Windows, and Linux. And ggml seemed like by far the best way forward. It has a strong community, and a great distribution story.
So what do you get?
You get a fast and accurate inference engine with wide ranging model support.
- Support for 16 ASR Families (60+ models) with more coming
- Acceleration via Vulkan, Metal, CUDA, and TinyBLAS
- Every model has been numerically verified and WER tested
- Support for Streaming Transcription
- Support for Batch Transcription
- More or less drop in whisper.cpp replacement
- Maintainer supported bindings in 4 Languages
- Python
- Javascript/Typescript
- Rust
- ObjC/Swift
Wide Model Support
We intend to support as many state-of-the-art transcription models as possible. As of today, we support most of the modern transcription models that are publicly available. There are a few missing still, but they will be added soon.
Acceleration Support
One of my top goals was to run any ASR model I wanted on Vulkan. In my opinion this is the floor for any application shipping local inference. For every model we support, there is a corresponding benchmark run from a Ryzen 4750U (CPU + Vulkan) on Fedora as well as on my M4 Max.
Numerically Verified
I also wanted to make sure that inference in transcribe.cpp is accurate and as close to the reference implementation as possible. This largely came from a huge degree of uncertainty of inference accuracy when using .onnx models I found on Hugging Face. In order to ensure the inference we do is correct we numerically validate every model versus the reference. On top of numerical validation, we run full WER sweeps to make sure that whatever the reference is outputting, we output the same thing. That means every model has run through thousands of utterances and is very close or same as the reference. And the results of this data are published in the transcribe.cpp repo as well as with each model on Hugging Face.
Drop In whisper.cpp replacement
transcribe.cpp is more or less a drop in support for whisper.cpp. The main reason for this is: Handy used whisper.cpp and I needed to ship an update with transcribe.cpp which would replace it. I needed to keep some compatibility with the very popular .bin files which run in whisper.cpp and shipped with Handy. transcribe.cpp can run them. There are some flags and features in whisper.cpp which we do not support yet. But I think for the vast majority of use cases our whisper implementation is solid and can replace whisper.cpp while having about equal performance.
Real Distribution
Language bindings were on my mind to begin with. While this library is written in C/C++, I needed bindings in Rust. And I also knew that in order for us to distribute local transcription as widely as possible, it requires at minimum decent first-party support of bindings. I've chosen 4 languages that I think are fairly representative of where people will use the library. I welcome others to contribute bindings directly to the project as well, assuming that they are willing to take on the maintenance burden of doing so.
And of course, at the end of the day, a lot of the decisions were driven by Handy. As a result of Handy being popular, I intend to maintain this library, just as I've done my best to maintain Handy. I intend to be someone who continues to maintain open source projects and contribute to the ecosystem where I can.
This library never would have existed without Handy because I wouldn't have had the problem of trying to support a bunch of different ASR models. I would have never learned all the use cases that people have for ASR. I've done my best to cover the ones that I hear about the most. Certainly, there are cases in the library that are not currently handled. If there are things that I missed, you are free to contribute to the library!
Making Local Speech to Text More Accessible
transcribe.cpp is aimed squarely at making locally run ASR easier. We know that transcription can run extremely accurately on most devices, and there should be no need to send your voice to a cloud service. An RK3566 can run models via transcribe.cpp faster than real time on its anemic CPU. Faster than real time transcription with SOTA models runs in a handful of watts. It's not a hope or a dream, it's a fact.
I think as we look forward to the future, more inference will start happening locally for one reason or the other. This brings the distribution story front and center. In order to have more applications running inference locally, we need to make running inference easier. Certainly transcribe.cpp does not solve this on the whole, and there is a long way to go, but I hope it's a small step forward. I've certainly learned a lot.
Gratitude
I am extremely thankful for all the folks who have supported this project.
First and foremost is to Mozilla AI, their BiR program, and Davide from Mozilla AI. This project was largely a problem in my head that I came to them with, and they decided to support me in solving the problem. At the time transcribe.cpp wasn't even a concrete idea, I was just exploring how to solve accelerated distribution in Handy. So a huge thanks to them, their support, and helping to bring this project into existence.
ggml. This project wouldn't be possible without ggml and all of the contributors to it. Thank you all so much for the work you've done. I think ggml really does amazing work in helping to make distributing local inference applications easy and possible.
Modal has also been a critical help for me. I reached out to them, and they gave me credits. These credits are put towards doing the WER testing and ensuring the library works well on CUDA. It is an immense help being able to verify the correctness of the work.
Blacksmith helps to power some of the CI/CD for transcribe.cpp. Again I reached out to them and they immediately responded with credits. Of course CI/CD is critical for making sure everything put out has been tested to at least some degree.
Hugging Face both for being a pillar in the local AI community, as well as providing the handy-computer org private storage, so I could upload models at my own will.
AI Assisted?
Yes absolutely. I don't think it's possible for a single individual to write an engine from scratch of this size using ggml in a handful of months without outside assistance. Were any of the words here written using AI? Nope. They came from my mouth or my fingers.