Compare commits

..

16 Commits

Author SHA1 Message Date
Nickolay Shmyrev 5c4dd4644e Update version 2020-05-03 20:52:43 +02:00
Nickolay Shmyrev 9bbd172cfd Some more links 2020-05-02 01:37:10 +02:00
Nickolay Shmyrev dbf9de77c3 Document model training and model structure 2020-05-02 01:11:25 +02:00
Nickolay Shmyrev 8b790cd162 Better android logging 2020-05-01 20:02:46 +02:00
Nickolay Shmyrev 80219066e9 Expose verbose level in the API 2020-05-01 19:02:57 +02:00
Nickolay Shmyrev 26fa5f098f Updated link to English model 2020-04-30 15:19:13 +02:00
Nickolay Shmyrev d75bb36131 Fix model download path 2020-04-30 11:04:35 +02:00
Nickolay Shmyrev 30c5e8ca79 Link to lm library for rescoring 2020-04-30 10:52:15 +02:00
Nickolay Shmyrev c00e36fab6 Rearrange models 2020-04-30 10:47:10 +02:00
Nickolay Shmyrev 80e60b9118 LM Rescoring 2020-04-28 22:17:34 +02:00
Nickolay Shmyrev e3a95a44bc Added Turkish model 2020-04-28 10:10:35 +02:00
Nickolay Shmyrev 86caf526f5 New model layout and model config file with beams for decoding 2020-04-28 01:06:41 +02:00
Nickolay Shmyrev e09f32b4b4 Properly stop listening so it can continue later 2020-04-27 09:00:32 +02:00
Nickolay Shmyrev 3803ab345d Proper reference couting of the models to avoid memory issus 2020-04-23 23:37:52 +02:00
Nickolay V. Shmyrev 889b43136f Update README.zh.md 2020-04-23 12:43:00 +02:00
John Baber-Lucero b517cf46af Fix some grammar/punctuation 2020-04-23 00:28:34 -04:00
33 changed files with 540 additions and 236 deletions
+12 -12
View File
@@ -6,14 +6,14 @@
Vosk is a speech recognition toolkit. The best things in Vosk are:
1. Supports 8 languages - English, German, French, Spanish, Portuguese, Chinese, Russian, Vietnamese. More is coming.
1. Works offline even on lightweight devices - Raspberry Pi, Android, iOS
1. Supports 9 languages - English, German, French, Spanish, Portuguese, Chinese, Russian, Turkish, Vietnamese. More to come.
1. Works offline, even on lightweight devices - Raspberry Pi, Android, iOS
1. Installs with simple `pip3 install vosk`
1. Portable models per language is just only 50Mb but there are much bigger server models available.
1. Provides streaming API for the best user experience (unlike popular speech-recognition python package)
1. There bindings for different prograbmming languages too - java/csharp/javascript etc.
1. Portable per-language models are only 50Mb each, but there are much bigger server models available.
1. Provides streaming API for the best user experience (unlike popular speech-recognition python packages)
1. There are bindings for different programming languages, too - java/csharp/javascript etc.
1. Allows quick reconfiguration of vocabulary for best accuracy.
1. Supports speaker identification beside simple speech recognition
1. Supports speaker identification beside simple speech recognition.
## Android build
@@ -95,8 +95,8 @@ Run like this:
```
cd vosk-api/python/example
wget https://github.com/alphacep/kaldi-android-demo/releases/download/2020-01/alphacep-model-android-en-us-0.3.tar.gz
tar xf alphacep-model-android-en-us-0.3.tar.gz
wget https://alphacephei.com/kaldi/models/vosk-model-small-en-us-0.3.zip
unzip alphacep-model-android-en-us-0.3.zip
mv alphacep-model-android-en-us-0.3 model-en
python3 ./test_simple.py test.wav
```
@@ -111,8 +111,8 @@ Or Java
```
cd java && KALDI_ROOT=<KALDI_ROOT> make
wget https://github.com/alphacep/kaldi-android-demo/releases/download/2020-01/alphacep-model-android-en-us-0.3.tar.gz
tar xf alphacep-model-android-en-us-0.3.tar.gz
wget https://alphacephei.com/kaldi/models/vosk-model-small-en-us-0.3.zip
unzip alphacep-model-android-en-us-0.3.zip
mv alphacep-model-android-en-us-0.3 model
make run
```
@@ -123,8 +123,8 @@ Or C#
```
cd csharp && KALDI_ROOT=<KALDI_ROOT> make
wget https://github.com/alphacep/kaldi-android-demo/releases/download/2020-01/alphacep-model-android-en-us-0.3.tar.gz
tar xf alphacep-model-android-en-us-0.3.tar.gz
wget https://alphacephei.com/kaldi/models/vosk-model-small-en-us-0.3.zip
unzip alphacep-model-android-en-us-0.3.zip
mv alphacep-model-android-en-us-0.3 model
mono test.exe
```
+7 -7
View File
@@ -6,7 +6,7 @@
Библитека для распознавания речи "Воск". Преимущества библиотеки:
1. Поддерживает 8 языков - русский, английский, немецкий, французский, португальский, испанский, китайский, вьетнамский. В скором времени будут добавлены и другие
1. Поддерживает 9 языков - русский, английский, немецкий, французский, португальский, испанский, китайский, турецкий, вьетнамский. В скором времени будут добавлены и другие
1. Работает без доступа к сети даже на мобильных устройствах - Raspberry Pi, Android, iOS
1. Устанавливается с помощью простой команды `pip3 install vosk` без дополнительных шагов
1. Модели для каждого языка занимают всего 50Мб, но есть и гораздо более точные большие модели для более точного распознавания
@@ -100,8 +100,8 @@ python3 setup.py install
```
cd vosk-api/python/example
wget https://github.com/alphacep/kaldi-android-demo/releases/download/2020-01/alphacep-model-android-en-us-0.3.tar.gz
tar xf alphacep-model-android-en-us-0.3.tar.gz
wget https://alphacephei.com/kaldi/models/vosk-model-small-en-us-0.3.zip
unzip alphacep-model-android-en-us-0.3.zip
mv alphacep-model-android-en-us-0.3 model-en
python3 ./test_simple.py test.wav
```
@@ -116,8 +116,8 @@ python3 ./test_simple.py test.wav
```
cd java && KALDI_ROOT=<KALDI_ROOT> make
wget https://github.com/alphacep/kaldi-android-demo/releases/download/2020-01/alphacep-model-android-en-us-0.3.tar.gz
tar xf alphacep-model-android-en-us-0.3.tar.gz
wget https://alphacephei.com/kaldi/models/vosk-model-small-en-us-0.3.zip
unzip alphacep-model-android-en-us-0.3.zip
mv alphacep-model-android-en-us-0.3 model
make run
```
@@ -128,8 +128,8 @@ make run
```
cd csharp && KALDI_ROOT=<KALDI_ROOT> make
wget https://github.com/alphacep/kaldi-android-demo/releases/download/2020-01/alphacep-model-android-en-us-0.3.tar.gz
tar xf alphacep-model-android-en-us-0.3.tar.gz
wget https://alphacephei.com/kaldi/models/vosk-model-small-en-us-0.3.zip
unzip alphacep-model-android-en-us-0.3.zip
mv alphacep-model-android-en-us-0.3 model
mono test.exe
```
+5 -5
View File
@@ -2,11 +2,11 @@
Vosk是言语识别工具包。Vosk最好的事情是:
1. 支持种语言 - 中文, 英语,德语,法语,西班牙语,葡萄牙语,俄语,越南语
1. 移动设备上脱机工作-Raspberry PiAndroidiOS
1. 支持种语言 - 中文, 英语,德语,法语,西班牙语,葡萄牙语,俄语,土耳其语,越南语
1. 移动设备上脱机工作-Raspberry PiAndroidiOS
1. 使用简单的 pip3 install vosk 安装
1. 每种语言的手提式模型只有是50Mb, 但还有更大的服务器模型可用
1. 提供流媒体API,以提供最佳用户体验(与流行的语音识别python包不同)
1. 也有针对不同编程语言的绑定-java / csharp / javascript等
1. 允许快速重新配置词汇以获得最佳准确性
1. 除了简单的语音识别外,还支持说话人识别
1. 还有用于不同编程语言的包装器-java / csharp / javascript等
1. 可以快速重新配置词汇以实现最佳准确性
1. 支持说话人识别
+1
View File
@@ -45,6 +45,7 @@ target_link_libraries( kaldi_jni
${KALDI_ROOT}/src/tree/kaldi-tree.a
${KALDI_ROOT}/src/feat/kaldi-feat.a
${KALDI_ROOT}/src/lat/kaldi-lat.a
${KALDI_ROOT}/src/lm/kaldi-lm.a
${KALDI_ROOT}/src/hmm/kaldi-hmm.a
${KALDI_ROOT}/src/transform/kaldi-transform.a
${KALDI_ROOT}/src/cudamatrix/kaldi-cudamatrix.a
@@ -241,10 +241,6 @@ public class Assets {
if (!items.get(path).equals(externalItems.get(path))
|| !(new File(externalDir, path).exists()))
newItems.add(path);
else
Log.i(TAG,
String.format("Skipping asset %s: checksums are equal", path));
}
unusedItems.addAll(externalItems.keySet());
@@ -252,13 +248,11 @@ public class Assets {
for (String path : newItems) {
File file = copy(path);
Log.i(TAG, String.format("Copying asset %s to %s", path, file));
}
for (String path : unusedItems) {
File file = new File(externalDir, path);
file.delete();
Log.i(TAG, String.format("Removing asset %s", file));
}
updateItemList(items);
@@ -148,8 +148,7 @@ public class SpeechRecognizer {
public boolean stop() {
boolean result = stopRecognizerThread();
if (result) {
Log.i(TAG, "Stop recognition");
mainHandler.post(new ResultEvent(recognizer.FinalResult(), true));
mainHandler.post(new ResultEvent(recognizer.Result(), true));
}
return result;
}
@@ -162,10 +161,7 @@ public class SpeechRecognizer {
*/
public boolean cancel() {
boolean result = stopRecognizerThread();
if (result) {
Log.i(TAG, "Cancel recognition");
}
recognizer.Result(); // Reset recognizer state
return result;
}
@@ -206,8 +202,6 @@ public class SpeechRecognizer {
return;
}
Log.d(TAG, "Starting decoding");
short[] buffer = new short[bufferSize];
while (!interrupted()
+3 -2
View File
@@ -11,6 +11,7 @@ KALDI_LIBS = \
${KALDI_ROOT}/src/tree/kaldi-tree.a \
${KALDI_ROOT}/src/feat/kaldi-feat.a \
${KALDI_ROOT}/src/lat/kaldi-lat.a \
${KALDI_ROOT}/src/lm/kaldi-lm.a \
${KALDI_ROOT}/src/hmm/kaldi-hmm.a \
${KALDI_ROOT}/src/transform/kaldi-transform.a \
${KALDI_ROOT}/src/cudamatrix/kaldi-cudamatrix.a \
@@ -43,10 +44,10 @@ libkaldiwrap.so: $(VOSK_SOURCES)
$(CXX) -fpermissive $(CFLAGS) $(CPPFLAGS) -shared -o $@ $(VOSK_SOURCES) $(KALDI_LIBS)
vosk_wrap.c: ../src/vosk.i
swig -csharp -DSWIG_CSHARP_NO_EXCEPTION_HELPER -dllimport "libkaldiwrap.so" \
swig -csharp -DSWIG_CSHARP_NO_EXCEPTION_HELPER -dllimport "libkaldiwrap" \
-namespace "Kaldi" -outdir gen -o vosk_wrap.c ../src/vosk.i
run:
run: test.exe
mono test.exe
clean:
+1
View File
@@ -7,6 +7,7 @@ public class Test
public static void Main()
{
Vosk.SetLogLevel(0);
Model model = new Model("model");
KaldiRecognizer rec = new KaldiRecognizer(model, 16000.0f);
+62 -48
View File
@@ -4,64 +4,78 @@ This is the list of models compatible with Vosk-API.
To add a new model here create an issue on Github.
### English
| Model | Size | Accuracy | Notes |
|-----------------------------------------------------------------------------------------------------------|-------|------------|----------------------------------------------------------------------------------------------|
| [kaldi-en-us-aspire-0.1](http://alphacephei.com/kaldi/kaldi-en-us-aspire-0.1.tar.gz) | 363M | TBD | Trained on Fisher + more or less recent LM. Pretty outdated but still ok even even for calls |
| [alphacep-model-android-en-us-0.3](http://alphacephei.com/kaldi/alphacep-model-android-en-us-0.3.tar.gz) | 36M | TBD | Lightweight wideband model for Android and RPi |
### Chinese
| Model | Size | Accuracy | Notes |
|-----------------------------------------------------------------------------------------------------------|-------|------------|----------------------------------------------------------------------------------------------|
| [kaldi-cn-0.1.tar.gz](http://alphacephei.com/kaldi/kaldi-cn-0.1.tar.gz) | 195M | TBD | Big narrowband Chinese model for server processing |
| [alphacep-model-android-cn-0.3](http://alphacephei.com/kaldi/alphacep-model-android-cn-0.3.tar.gz) | 32M | TBD | Lightweight wideband model for Android and RPi |
### Russian
| Model | Size | Accuracy | Notes |
|-----------------------------------------------------------------------------------------------------------|-------|------------|----------------------------------------------------------------------------------------------|
| [kaldi-ru-0.9.tar.gz](http://alphacephei.com/kaldi/kaldi-ru-0.9.tar.gz) | 2.5G | TBD | Big narrowband Russian model for server processing |
| [alphacep-model-android-ru-0.3](http://alphacephei.com/kaldi/alphacep-model-android-ru-0.3.tar.gz) | 39M | TBD | Lightweight wideband model for Android and RPi |
### French
| Model | Size | Accuracy | Notes |
|-------------------------------------------------------------------------------------------------------------------------|-------|------------|----------------------------------------------------------------------------------------------|
| [alphacep-model-android-fr-pguyot-0.3](http://alphacephei.com/kaldi/alphacep-model-android-fr-pguyot-0.3.tar.gz) | 39M | TBD | Lightweight wideband model for Android and RPi trained by [Paul Guyot](https://github.com/pguyot/zamia-speech/releases) |
| **English** | | | |
| [vosk-model-en-us-aspire-0.2](http://alphacephei.com/kaldi/models/vosk-model-en-us-aspire-0.2.zip) | 1.4G | TBD | Trained on Fisher + more or less recent LM. Should be pretty good for generic US English transcription |
| [vosk-model-small-en-us-0.3](http://alphacephei.com/kaldi/models/vosk-model-small-en-us-0.3.zip) | 36M | TBD | Lightweight wideband model for Android and RPi |
| **Chinese** | | | |
| [vosk-model-cn-0.1.zip](http://alphacephei.com/kaldi/models/vosk-model-cn-0.1.zip) | 195M | TBD | Big narrowband Chinese model for server processing |
| [vosk-model-small-cn-0.3](http://alphacephei.com/kaldi/models/vosk-model-small-cn-0.3.zip) | 32M | TBD | Lightweight wideband model for Android and RPi |
| **Russian** | | | |
| [vosk-model-ru-0.10.zip](http://alphacephei.com/kaldi/models/vosk-model-ru-0.10.zip) | 2.5G | TBD | Big narrowband Russian model for server processing |
| [vosk-model-small-ru-0.4](http://alphacephei.com/kaldi/models/vosk-model-small-ru-0.4.zip) | 39M | TBD | Lightweight wideband model for Android and RPi |
| **French** | | | |
| [vosk-model-small-fr-pguyot-0.3](http://alphacephei.com/kaldi/models/vosk-model-small-fr-pguyot-0.3.zip) | 39M | TBD | Lightweight wideband model for Android and RPi trained by [Paul Guyot](https://github.com/pguyot/zamia-speech/releases) |
| **German** | | | |
| [tuda-de](http://ltdata1.informatik.uni-hamburg.de/kaldi_tuda_de/de_400k_nnet3chain_tdnn1f_2048_sp_bi.tar.bz2) | 566M | TBD | Wideband server model from [tuda-de](https://github.com/uhh-lt/vosk-model-tuda-de) |
| [vosk-model-small-de-zamia-0.3](http://alphacephei.com/kaldi/models/vosk-model-small-de-zamia-0.3.zip) | 49M | TBD | Lightweight wideband model for Android and RPi |
| **Spanish** | | | |
| [vosk-model-small-es-0.3](http://alphacephei.com/kaldi/models/vosk-model-small-es-0.3.zip) | 33M | TBD | Lightweight wideband model for Android and RPi |
| **Portuguese** | | | |
| [vosk-model-small-pt-0.3](http://alphacephei.com/kaldi/models/vosk-model-small-pt-0.3.zip) | 31M | TBD | Lightweight wideband model for Android and RPi |
| **Greek** | | | |
| [vosk-model-el-gr-0.6.zip](http://alphacephei.com/kaldi/models/vosk-model-el-gr-0.6.zip) | 1.1G | TBD | Big narrowband Greek model for server processing, not extremely accurate though |
| **Turkish** | | | |
| [vosk-model-small-tr-0.3](http://alphacephei.com/kaldi/models/vosk-model-small-tr-0.3.zip) | 35M | TBD | Lightweight wideband model for Android and RPi |
| **Vietnamese** | | | |
| [vosk-model-small-vn-0.3](http://alphacephei.com/kaldi/models/vosk-model-small-vn-0.3.zip) | 32M | TBD | Lightweight wideband model for Android and RPi |
| **Speaker identification model** | | | |
| [vosk-model-spk-0.3](http://alphacephei.com/kaldi/models/vosk-model-spk-0.3.zip) | 13M | TBD | Model for speaker identification, should work for all languages |
### German
| Model | Size | Accuracy | Notes |
|-----------------------------------------------------------------------------------------------------------|-------|------------|------------------------------------------------------------------------------------------------------|
| [tuda-de](http://ltdata1.informatik.uni-hamburg.de/kaldi_tuda_de/de_400k_nnet3chain_tdnn1f_2048_sp_bi.tar.bz2) | 566M | TBD | Wideband server model from [tuda-de](https://github.com/uhh-lt/kaldi-tuda-de) |
| [alphacep-model-android-de-zamia-0.3](http://alphacephei.com/kaldi/alphacep-model-android-de-zamia-0.3.tar.gz) | 49M | TBD | Lightweight wideband model for Android and RPi |
## Other models
### Spanish
Other places where you can check for models which might be compatible:
| Model | Size | Accuracy | Notes |
|-----------------------------------------------------------------------------------------------------------|-------|------------|----------------------------------------------------------------------------------------------|
| [alphacep-model-android-es-0.3](http://alphacephei.com/kaldi/alphacep-model-android-es-0.3.tar.gz) | 33M | TBD | Lightweight wideband model for Android and RPi |
* http://kaldi-asr.org/models.html - variety of models from Kaldi - librispeech, aspire, chinese models
* https://github.com/daanzu/kaldi-active-grammar/blob/master/docs/models.md - Big dictation models
* http://zamia-speech.org/asr/ - German and English model from Zamia
* https://github.com/pguyot/zamia-speech/releases - French models for Zamia
* https://github.com/opensource-spraakherkenning-nl/Kaldi_NL - Dutch model
* https://montreal-forced-aligner.readthedocs.io/en/latest/pretrained_models.html (GMM models, not compatible but might be still useful)
* https://github.com/goodatlas/zeroth - Korean Kaldi (just a recipe and data to train)
* https://github.com/undertheseanlp/automatic_speech_recognition - Vietnamese Kaldi project
### Portuguese
## Training your own model
| Model | Size | Accuracy | Notes |
|-----------------------------------------------------------------------------------------------------------|-------|------------|----------------------------------------------------------------------------------------------|
| [alphacep-model-android-pt-0.3](http://alphacephei.com/kaldi/alphacep-model-android-pt-0.3.tar.gz) | 31M | TBD | Lightweight wideband model for Android and RPi |
You can train your model with Kaldi toolkit. The training is pretty standard - you need tdnn nnet3 model with ivectors. You can
check mini_librispeech recipe for details. Some notes on training:
### Dutch
* For smaller mobile models watch number of parameters
* Train the model without pitch. It might be helpful for small amount of data, but for large database it doesn't give the advantage
but complicates the processing and increases response time.
* Train ivector of dim 30 instead of standard 100 to save memory of mobile models.
https://github.com/opensource-spraakherkenning-nl/Kaldi_NL
## Model structure
### Greek
Once you trained the model arrange the files according to the following layout (see en-us-aspire for details):
| Model | Size | Accuracy | Notes |
|-----------------------------------------------------------------------------------------------------------|-------|------------|----------------------------------------------------------------------------------------------|
| [kaldi-el-gr-0.6.tar.gz](http://alphacephei.com/kaldi/kaldi-el-gr-0.6.tar.gz) | 1.1G | TBD | Big narrowband Greek model for server processing, not extremely accurate though |
* `am/final.mdl` - acoustic model
* `conf/mfcc.conf` - mfcc config file. Make sure you take mfcc_hires.conf version if you are using hires model (most external ones)
* `conf/model.conf` - provide default decoding beams and silence phones. you have to create this file yourself, it is not present in kaldi model
* `ivector/final.dubm` - take ivector files from ivector extractor
* `ivector/final.ie`
* `ivector/final.mat`
* `ivector/splice.conf`
* `ivector/global_cmvn.stats`
* `ivector/online_cmvn.conf`
* `graph/phones/word_boundary.int` - from the graph
* `graph/HCLG.fst` - this is the decoding graph, if you are not using lookahead
* `graph/HCLr.fst` - use Gr.fst and HCLr.fst instead of one big HCLG.fst if you want to run rescoring
* `graph/Gr.fst`
* `graph/phones.txt` - from the graph
* `graph/words.txt` - from the graph
* `rescore/G.carpa` - carpa rescoring is optional but helpful in big models. Usually located inside data/lang_test_rescore
* `rescore/G.fst` - also optional if you want to use rescoring
### Vietnamese
| Model | Size | Accuracy | Notes |
|-----------------------------------------------------------------------------------------------------------|-------|------------|----------------------------------------------------------------------------------------------|
| [alphacep-model-android-vn-0.3](http://alphacephei.com/kaldi/alphacep-model-android-vn-0.3.tar.gz) | 32M | TBD | Lightweight wideband model for Android and RPi |
+9 -8
View File
@@ -11,6 +11,7 @@ KALDI_LIBS = \
${KALDI_ROOT}/src/tree/kaldi-tree.a \
${KALDI_ROOT}/src/feat/kaldi-feat.a \
${KALDI_ROOT}/src/lat/kaldi-lat.a \
${KALDI_ROOT}/src/lm/kaldi-lm.a \
${KALDI_ROOT}/src/hmm/kaldi-hmm.a \
${KALDI_ROOT}/src/transform/kaldi-transform.a \
${KALDI_ROOT}/src/cudamatrix/kaldi-cudamatrix.a \
@@ -49,16 +50,16 @@ clean:
$(RM) *.so *_wrap.cc *_wrap.o test/*.class
$(RM) -r org model-en
model-en:
wget https://github.com/alphacep/kaldi-android-demo/releases/download/2020-01/alphacep-model-android-en-us-0.3.tar.gz
tar xf alphacep-model-android-en-us-0.3.tar.gz && rm alphacep-model-android-en-us-0.3.tar.gz
mv alphacep-model-android-en-us-0.3 model-en
model:
wget https://alphacephei.com/kaldi/models/vosk-model-small-en-us-0.3.zip
unzip vosk-model-small-en-us-0.3.zip && rm vosk-model-small-en-us-0.3.zip
mv vosk-model-small-en-us-0.3 model
model-spk:
wget https://github.com/alphacep/kaldi-android-demo/releases/download/2020-01/alphacep-spk-model-0.3.tar.gz
tar xf alphacep-spk-model-0.3.tar.gz && rm alphacep-spk-model-0.3.tar.gz
mv alphacep-spk-model-0.3 model-spk
wget https://alphacephei.com/kaldi/models/vosk-model-spk-0.3.zip
unzip vosk-model-spk-0.3.zip && rm vosk-model-spk-0.3.zip
mv vosk-model-spk-0.3 model-spk
run: model-en model-spk
run: model model-spk
javac test/*.java org/kaldi/*.java
java -Djava.library.path=. -cp . test.DecoderTest
+4 -1
View File
@@ -11,6 +11,7 @@ import java.nio.*;
import org.kaldi.KaldiRecognizer;
import org.kaldi.Model;
import org.kaldi.SpkModel;
import org.kaldi.Vosk;
public class DecoderTest {
static {
@@ -18,8 +19,10 @@ public class DecoderTest {
}
public static void main(String args[]) throws IOException {
Vosk.SetLogLevel(-10);
FileInputStream ais = new FileInputStream(new File("../python/example/test.wav"));
Model model = new Model("model-en");
Model model = new Model("model");
SpkModel spkModel = new SpkModel("model-spk");
KaldiRecognizer rec = new KaldiRecognizer(model, spkModel, 16000.0f);
+5 -4
View File
@@ -3,18 +3,18 @@ project(vosk)
set(TOP_SRCDIR "${CMAKE_SOURCE_DIR}/..")
if("x$ENV{WHEEL_FLAGS}" STREQUAL "x")
find_package (Python COMPONENTS Interpreter Development)
find_package (Python3 COMPONENTS Interpreter Development)
else()
# docker case
set(Python_INCLUDE_DIRS "")
set(Python3_INCLUDE_DIRS "")
set(TOP_SRCDIR "/io")
endif()
set(KALDI_ROOT "$ENV{KALDI_ROOT}")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3 -DFST_NO_DYNAMIC_LINKING")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DFST_NO_DYNAMIC_LINKING")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} $ENV{WHEEL_FLAGS}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CMAKE_C_FLAGS} -std=c++11")
include_directories("${TOP_SRCDIR}/src" "${KALDI_ROOT}/src" "${KALDI_ROOT}/tools/openfst/include" ${Python_INCLUDE_DIRS})
include_directories("${TOP_SRCDIR}/src" "${KALDI_ROOT}/src" "${KALDI_ROOT}/tools/openfst/include" ${Python3_INCLUDE_DIRS})
find_package(SWIG REQUIRED)
include(${SWIG_USE_FILE})
@@ -35,6 +35,7 @@ swig_link_libraries(vosk
${KALDI_ROOT}/src/tree/kaldi-tree.a
${KALDI_ROOT}/src/feat/kaldi-feat.a
${KALDI_ROOT}/src/lat/kaldi-lat.a
${KALDI_ROOT}/src/lm/kaldi-lm.a
${KALDI_ROOT}/src/hmm/kaldi-hmm.a
${KALDI_ROOT}/src/transform/kaldi-transform.a
${KALDI_ROOT}/src/cudamatrix/kaldi-cudamatrix.a
+1 -1
View File
@@ -4,7 +4,7 @@ from vosk import Model, KaldiRecognizer
import sys
import json
model = Model("model-en")
model = Model("model")
rec = KaldiRecognizer(model, 8000)
res = json.loads(rec.FinalResult())
+4 -4
View File
@@ -3,8 +3,8 @@
from vosk import Model, KaldiRecognizer
import os
if not os.path.exists("model-en"):
print ("Please download the model from https://github.com/alphacep/kaldi-android-demo/releases and unpack as 'model-en' in the current folder.")
if not os.path.exists("model"):
print ("Please download the model from https://github.com/alphacep/vosk-api/blob/master/doc/models.md and unpack as 'model' in the current folder.")
exit (1)
import pyaudio
@@ -13,11 +13,11 @@ p = pyaudio.PyAudio()
stream = p.open(format=pyaudio.paInt16, channels=1, rate=16000, input=True, frames_per_buffer=8000)
stream.start_stream()
model = Model("model-en")
model = Model("model")
rec = KaldiRecognizer(model, 16000)
while True:
data = stream.read(2000)
data = stream.read(4000)
if len(data) == 0:
break
if rec.AcceptWaveform(data):
+7 -5
View File
@@ -1,12 +1,14 @@
#!/usr/bin/python3
from vosk import Model, KaldiRecognizer
from vosk import Model, KaldiRecognizer, SetLogLevel
import sys
import os
import wave
if not os.path.exists("model-en"):
print ("Please download the model from https://github.com/alphacep/kaldi-android-demo/releases and unpack as 'model-en' in the current folder.")
SetLogLevel(0)
if not os.path.exists("model"):
print ("Please download the model from https://github.com/alphacep/vosk-api/blob/master/doc/models.md and unpack as 'model' in the current folder.")
exit (1)
wf = wave.open(sys.argv[1], "rb")
@@ -14,11 +16,11 @@ if wf.getnchannels() != 1 or wf.getsampwidth() != 2 or wf.getcomptype() != "NONE
print ("Audio file must be WAV format mono PCM.")
exit (1)
model = Model("model-en")
model = Model("model")
rec = KaldiRecognizer(model, wf.getframerate())
while True:
data = wf.readframes(1000)
data = wf.readframes(4000)
if len(data) == 0:
break
if rec.AcceptWaveform(data):
+4 -4
View File
@@ -7,15 +7,15 @@ import json
import os
import numpy as np
model_path = "model-en"
model_path = "model"
spk_model_path = "model-spk"
if not os.path.exists(model_path):
print ("Please download the model from https://github.com/alphacep/kaldi-android-demo/releases and unpack as {} in the current folder.".format(model_path))
print ("Please download the model from https://github.com/alphacep/vosk-api/blob/master/doc/models.md and unpack as {} in the current folder.".format(model_path))
exit (1)
if not os.path.exists(spk_model_path):
print ("Please download the speaker model from https://github.com/alphacep/kaldi-android-demo/releases and unpack as {} in the current folder.".format(spk_model_path))
print ("Please download the speaker model from https://github.com/alphacep/vosk-api/blob/master/doc/models.md and unpack as {} in the current folder.".format(spk_model_path))
exit (1)
wf = wave.open(sys.argv[1], "rb")
@@ -38,7 +38,7 @@ def cosine_dist(x, y):
return 1 - np.dot(nx, ny) / np.linalg.norm(nx) / np.linalg.norm(ny)
while True:
data = wf.readframes(1000)
data = wf.readframes(4000)
if len(data) == 0:
break
if rec.AcceptWaveform(data):
+4 -4
View File
@@ -5,12 +5,12 @@ import sys
import json
import os
if not os.path.exists("model-en"):
print ("Please download the model from https://github.com/alphacep/kaldi-android-demo/releases and unpack as 'model-en' in the current folder.")
if not os.path.exists("model"):
print ("Please download the model from https://github.com/alphacep/vosk-api/blob/master/doc/models.md and unpack as 'model' in the current folder.")
exit (1)
model = Model("model-en")
model = Model("model")
# Large vocabulary free form recognition
rec = KaldiRecognizer(model, 16000)
@@ -22,7 +22,7 @@ wf = open(sys.argv[1], "rb")
wf.read(44) # skip header
while True:
data = wf.read(2000)
data = wf.read(4000)
if len(data) == 0:
break
if rec.AcceptWaveform(data):
+4 -4
View File
@@ -5,8 +5,8 @@ import sys
import os
import wave
if not os.path.exists("model-en"):
print ("Please download the model from https://github.com/alphacep/kaldi-android-demo/releases and unpack as 'model-en' in the current folder.")
if not os.path.exists("model"):
print ("Please download the model from https://github.com/alphacep/vosk-api/blob/master/doc/models.md and unpack as 'model' in the current folder.")
exit (1)
wf = wave.open(sys.argv[1], "rb")
@@ -14,12 +14,12 @@ if wf.getnchannels() != 1 or wf.getsampwidth() != 2 or wf.getcomptype() != "NONE
print ("Audio file must be WAV format mono PCM.")
exit (1)
model = Model("model-en")
model = Model("model")
# You can also specify the possible word list
rec = KaldiRecognizer(model, wf.getframerate(), "zero oh one two three four five six seven eight nine")
while True:
data = wf.readframes(1000)
data = wf.readframes(4000)
if len(data) == 0:
break
if rec.AcceptWaveform(data):
+1 -1
View File
@@ -7,7 +7,7 @@ with open("README.md", "r") as fh:
setuptools.setup(
name="vosk", # Replace with your own username
version="0.3.5",
version="0.3.7",
author="Alpha Cephei Inc",
author_email="contact@alphacephei.com",
description="API for Kaldi and Vosk",
+27
View File
@@ -0,0 +1,27 @@
#!/usr/bin/python3
from vosk import Model, KaldiRecognizer
import sys
import os
import wave
import json
model = Model("model")
for line in open(sys.argv[1]):
uid, fn = line.split()
wf = wave.open(fn, "rb")
rec = KaldiRecognizer(model, wf.getframerate())
text = ""
while True:
data = wf.readframes(1000)
if len(data) == 0:
break
if rec.AcceptWaveform(data):
jres = json.loads(rec.Result())
text = text + " " + jres['text']
jres = json.loads(rec.FinalResult())
text = text + " " + jres['text']
print (uid + text)
+2 -1
View File
@@ -1 +1,2 @@
from .vosk import KaldiRecognizer, Model, SpkModel
from .vosk import KaldiRecognizer, Model, SpkModel, SetLogLevel
+102 -52
View File
@@ -20,40 +20,46 @@
using namespace fst;
using namespace kaldi::nnet3;
KaldiRecognizer::KaldiRecognizer(Model &model, float sample_frequency) : model_(model), spk_model_(0), sample_frequency_(sample_frequency) {
KaldiRecognizer::KaldiRecognizer(Model *model, float sample_frequency) : model_(model), spk_model_(0), sample_frequency_(sample_frequency) {
feature_pipeline_ = new kaldi::OnlineNnet2FeaturePipeline (model_.feature_info_);
silence_weighting_ = new kaldi::OnlineSilenceWeighting(*model_.trans_model_, model_.feature_info_.silence_weighting_config, 3);
model_->Ref();
feature_pipeline_ = new kaldi::OnlineNnet2FeaturePipeline (model_->feature_info_);
silence_weighting_ = new kaldi::OnlineSilenceWeighting(*model_->trans_model_, model_->feature_info_.silence_weighting_config, 3);
g_fst_ = NULL;
decode_fst_ = NULL;
if (!model_.hclg_fst_) {
if (model_.hcl_fst_ && model_.g_fst_) {
decode_fst_ = LookaheadComposeFst(*model_.hcl_fst_, *model_.g_fst_, model_.disambig_);
if (!model_->hclg_fst_) {
if (model_->hcl_fst_ && model_->g_fst_) {
decode_fst_ = LookaheadComposeFst(*model_->hcl_fst_, *model_->g_fst_, model_->disambig_);
} else {
KALDI_ERR << "Can't create decoding graph";
}
}
decoder_ = new kaldi::SingleUtteranceNnet3Decoder(model_.nnet3_decoding_config_,
*model_.trans_model_,
*model_.decodable_info_,
model_.hclg_fst_ ? *model.hclg_fst_ : *decode_fst_,
decoder_ = new kaldi::SingleUtteranceNnet3Decoder(model_->nnet3_decoding_config_,
*model_->trans_model_,
*model_->decodable_info_,
model_->hclg_fst_ ? *model_->hclg_fst_ : *decode_fst_,
feature_pipeline_);
frame_offset_ = 0;
input_finalized_ = false;
spk_feature_ = NULL;
InitRescoring();
}
KaldiRecognizer::KaldiRecognizer(Model &model, float sample_frequency, char const *grammar) : model_(model), spk_model_(0), sample_frequency_(sample_frequency)
KaldiRecognizer::KaldiRecognizer(Model *model, float sample_frequency, char const *grammar) : model_(model), spk_model_(0), sample_frequency_(sample_frequency)
{
feature_pipeline_ = new kaldi::OnlineNnet2FeaturePipeline (model_.feature_info_);
silence_weighting_ = new kaldi::OnlineSilenceWeighting(*model_.trans_model_, model_.feature_info_.silence_weighting_config, 3);
model_->Ref();
feature_pipeline_ = new kaldi::OnlineNnet2FeaturePipeline (model_->feature_info_);
silence_weighting_ = new kaldi::OnlineSilenceWeighting(*model_->trans_model_, model_->feature_info_.silence_weighting_config, 3);
g_fst_ = new StdVectorFst();
if (model_.hcl_fst_) {
if (model_->hcl_fst_) {
g_fst_->AddState();
g_fst_->SetStart(0);
g_fst_->AddState();
@@ -61,58 +67,65 @@ KaldiRecognizer::KaldiRecognizer(Model &model, float sample_frequency, char cons
g_fst_->AddArc(1, StdArc(0, 0, fst::TropicalWeight::One(), 0));
// Create simple word loop FST
std::stringstream ss(grammar);
std::string token;
stringstream ss(grammar);
string token;
while (std::getline(ss, token, ' ')) {
int32 id = model_.word_syms_->Find(token);
while (getline(ss, token, ' ')) {
int32 id = model_->word_syms_->Find(token);
g_fst_->AddArc(0, StdArc(id, id, fst::TropicalWeight::One(), 1));
}
ArcSort(g_fst_, ILabelCompare<StdArc>());
decode_fst_ = LookaheadComposeFst(*model_.hcl_fst_, *g_fst_, model_.disambig_);
decode_fst_ = LookaheadComposeFst(*model_->hcl_fst_, *g_fst_, model_->disambig_);
} else {
decode_fst_ = NULL;
KALDI_ERR << "Can't create decoding graph";
}
decoder_ = new kaldi::SingleUtteranceNnet3Decoder(model_.nnet3_decoding_config_,
*model_.trans_model_,
*model_.decodable_info_,
model_.hclg_fst_ ? *model.hclg_fst_ : *decode_fst_,
decoder_ = new kaldi::SingleUtteranceNnet3Decoder(model_->nnet3_decoding_config_,
*model_->trans_model_,
*model_->decodable_info_,
model_->hclg_fst_ ? *model_->hclg_fst_ : *decode_fst_,
feature_pipeline_);
frame_offset_ = 0;
input_finalized_ = false;
spk_feature_ = NULL;
InitRescoring();
}
KaldiRecognizer::KaldiRecognizer(Model *model, SpkModel *spk_model, float sample_frequency) : model_(model), spk_model_(spk_model), sample_frequency_(sample_frequency) {
KaldiRecognizer::KaldiRecognizer(Model &model, SpkModel *spk_model, float sample_frequency) : model_(model), spk_model_(spk_model), sample_frequency_(sample_frequency) {
feature_pipeline_ = new kaldi::OnlineNnet2FeaturePipeline (model_.feature_info_);
silence_weighting_ = new kaldi::OnlineSilenceWeighting(*model_.trans_model_, model_.feature_info_.silence_weighting_config, 3);
model_->Ref();
spk_model->Ref();
feature_pipeline_ = new kaldi::OnlineNnet2FeaturePipeline (model_->feature_info_);
silence_weighting_ = new kaldi::OnlineSilenceWeighting(*model_->trans_model_, model_->feature_info_.silence_weighting_config, 3);
decode_fst_ = NULL;
g_fst_ = NULL;
if (!model_.hclg_fst_) {
if (model_.hcl_fst_ && model_.g_fst_) {
decode_fst_ = LookaheadComposeFst(*model_.hcl_fst_, *model_.g_fst_, model_.disambig_);
if (!model_->hclg_fst_) {
if (model_->hcl_fst_ && model_->g_fst_) {
decode_fst_ = LookaheadComposeFst(*model_->hcl_fst_, *model_->g_fst_, model_->disambig_);
} else {
KALDI_ERR << "Can't create decoding graph";
}
}
decoder_ = new kaldi::SingleUtteranceNnet3Decoder(model_.nnet3_decoding_config_,
*model_.trans_model_,
*model_.decodable_info_,
model_.hclg_fst_ ? *model.hclg_fst_ : *decode_fst_,
decoder_ = new kaldi::SingleUtteranceNnet3Decoder(model_->nnet3_decoding_config_,
*model_->trans_model_,
*model_->decodable_info_,
model_->hclg_fst_ ? *model_->hclg_fst_ : *decode_fst_,
feature_pipeline_);
frame_offset_ = 0;
input_finalized_ = false;
spk_feature_ = new OnlineMfcc(spk_model_->spkvector_mfcc_opts);
InitRescoring();
}
KaldiRecognizer::~KaldiRecognizer() {
@@ -122,12 +135,29 @@ KaldiRecognizer::~KaldiRecognizer() {
delete g_fst_;
delete decode_fst_;
delete spk_feature_;
delete lm_fst_;
model_->Unref();
if (spk_model_)
spk_model_->Unref();
}
void KaldiRecognizer::InitRescoring()
{
if (model_->std_lm_fst_) {
fst::CacheOptions cache_opts(true, 50000);
fst::MapFstOptions mapfst_opts(cache_opts);
fst::StdToLatticeMapper<kaldi::BaseFloat> mapper;
lm_fst_ = new fst::MapFst<fst::StdArc, kaldi::LatticeArc, fst::StdToLatticeMapper<kaldi::BaseFloat> >(*model_->std_lm_fst_, mapper, mapfst_opts);
} else {
lm_fst_ = NULL;
}
}
void KaldiRecognizer::CleanUp()
{
delete silence_weighting_;
silence_weighting_ = new kaldi::OnlineSilenceWeighting(*model_.trans_model_, model_.feature_info_.silence_weighting_config, 3);
silence_weighting_ = new kaldi::OnlineSilenceWeighting(*model_->trans_model_, model_->feature_info_.silence_weighting_config, 3);
frame_offset_ += decoder_->NumFramesDecoded();
decoder_->InitDecoding(frame_offset_);
@@ -137,7 +167,7 @@ void KaldiRecognizer::UpdateSilenceWeights()
{
if (silence_weighting_->Active() && feature_pipeline_->NumFramesReady() > 0 &&
feature_pipeline_->IvectorFeature() != NULL) {
std::vector<std::pair<int32, BaseFloat> > delta_weights;
vector<pair<int32, BaseFloat> > delta_weights;
silence_weighting_->ComputeCurrentTraceback(decoder_->Decoder());
silence_weighting_->GetDeltaWeights(feature_pipeline_->NumFramesReady(),
frame_offset_ * 3,
@@ -188,14 +218,13 @@ bool KaldiRecognizer::AcceptWaveform(Vector<BaseFloat> &wdata)
spk_feature_->AcceptWaveform(sample_frequency_, wdata);
}
if (decoder_->EndpointDetected(model_.endpoint_config_)) {
if (decoder_->EndpointDetected(model_->endpoint_config_)) {
return true;
}
return false;
}
// Computes an xvector from a chunk of speech features.
static void RunNnetComputation(const MatrixBase<BaseFloat> &features,
const nnet3::Nnet &nnet, nnet3::CachingOptimizingCompiler *compiler,
@@ -212,7 +241,7 @@ static void RunNnetComputation(const MatrixBase<BaseFloat> &features,
output_spec.indexes.resize(1);
request.outputs.resize(1);
request.outputs[0].Swap(&output_spec);
std::shared_ptr<const nnet3::NnetComputation> computation = compiler->Compile(request);
shared_ptr<const nnet3::NnetComputation> computation = compiler->Compile(request);
nnet3::Nnet *nnet_to_update = NULL; // we're not doing any update.
nnet3::NnetComputer computer(nnet3::NnetComputeOptions(), *computation,
nnet, nnet_to_update);
@@ -225,7 +254,6 @@ static void RunNnetComputation(const MatrixBase<BaseFloat> &features,
xvector->CopyFromVec(cu_output.Row(0));
}
void KaldiRecognizer::GetSpkVector(Vector<BaseFloat> &xvector)
{
int num_frames = spk_feature_->NumFramesReady() - frame_offset_ * 3;
@@ -246,7 +274,6 @@ void KaldiRecognizer::GetSpkVector(Vector<BaseFloat> &xvector)
RunNnetComputation(features, spk_model_->speaker_nnet, &compiler, &xvector);
}
const char* KaldiRecognizer::Result()
{
@@ -262,30 +289,53 @@ const char* KaldiRecognizer::Result()
kaldi::CompactLattice clat;
decoder_->GetLattice(true, &clat);
fst::ScaleLattice(fst::LatticeScale(8.0, 10.0), &clat);
if (model_->std_lm_fst_) {
Lattice lat1;
ConvertLattice(clat, &lat1);
fst::ScaleLattice(fst::GraphLatticeScale(-1.0), &lat1);
fst::ArcSort(&lat1, fst::OLabelCompare<kaldi::LatticeArc>());
kaldi::Lattice composed_lat;
fst::Compose(lat1, *lm_fst_, &composed_lat);
fst::Invert(&composed_lat);
kaldi::CompactLattice determinized_lat;
DeterminizeLattice(composed_lat, &determinized_lat);
fst::ScaleLattice(fst::GraphLatticeScale(-1), &determinized_lat);
fst::ArcSort(&determinized_lat, fst::OLabelCompare<kaldi::CompactLatticeArc>());
kaldi::ConstArpaLmDeterministicFst const_arpa_fst(model_->const_arpa_);
kaldi::CompactLattice composed_clat;
kaldi::ComposeCompactLatticeDeterministic(determinized_lat, &const_arpa_fst, &composed_clat);
kaldi::Lattice composed_lat1;
ConvertLattice(composed_clat, &composed_lat1);
fst::Invert(&composed_lat1);
DeterminizeLattice(composed_lat1, &clat);
}
fst::ScaleLattice(fst::LatticeScale(9.0, 10.0), &clat);
CompactLattice aligned_lat;
if (model_.winfo_) {
WordAlignLattice(clat, *model_.trans_model_, *model_.winfo_, 0, &aligned_lat);
if (model_->winfo_) {
WordAlignLattice(clat, *model_->trans_model_, *model_->winfo_, 0, &aligned_lat);
} else {
aligned_lat = clat;
}
MinimumBayesRisk mbr(aligned_lat);
const std::vector<BaseFloat> &conf = mbr.GetOneBestConfidences();
const std::vector<int32> &words = mbr.GetOneBest();
const std::vector<std::pair<BaseFloat, BaseFloat> > &times =
const vector<BaseFloat> &conf = mbr.GetOneBestConfidences();
const vector<int32> &words = mbr.GetOneBest();
const vector<pair<BaseFloat, BaseFloat> > &times =
mbr.GetOneBestTimes();
int size = words.size();
json::JSON obj;
std::stringstream text;
stringstream text;
// Create JSON object
for (int i = 0; i < size; i++) {
json::JSON word;
word["word"] = model_.word_syms_->Find(words[i]);
word["word"] = model_->word_syms_->Find(words[i]);
word["start"] = (frame_offset_ + times[i].first) * 0.03;
word["end"] = (frame_offset_ + times[i].second) * 0.03;
word["conf"] = conf[i];
@@ -294,7 +344,7 @@ const char* KaldiRecognizer::Result()
if (i) {
text << " ";
}
text << model_.word_syms_->Find(words[i]);
text << model_->word_syms_->Find(words[i]);
}
obj["text"] = text.str();
@@ -321,16 +371,16 @@ const char* KaldiRecognizer::PartialResult()
kaldi::Lattice lat;
decoder_->GetBestPath(false, &lat);
std::vector<kaldi::int32> alignment, words;
vector<kaldi::int32> alignment, words;
LatticeWeight weight;
GetLinearSymbolSequence(lat, &alignment, &words, &weight);
std::ostringstream text;
ostringstream text;
for (size_t i = 0; i < words.size(); i++) {
if (i) {
text << " ";
}
text << model_.word_syms_->Find(words[i]);
text << model_->word_syms_->Find(words[i]);
}
res["partial"] = text.str();
+8 -5
View File
@@ -31,9 +31,9 @@ using namespace kaldi;
class KaldiRecognizer {
public:
KaldiRecognizer(Model &model, float sample_frequency);
KaldiRecognizer(Model &model, SpkModel *spk_model, float sample_frequency);
KaldiRecognizer(Model &model, float sample_frequency, char const *grammar);
KaldiRecognizer(Model *model, float sample_frequency);
KaldiRecognizer(Model *model, SpkModel *spk_model, float sample_frequency);
KaldiRecognizer(Model *model, float sample_frequency, char const *grammar);
~KaldiRecognizer();
bool AcceptWaveform(const char *data, int len);
bool AcceptWaveform(const short *sdata, int len);
@@ -43,12 +43,13 @@ class KaldiRecognizer {
const char* PartialResult();
private:
void InitRescoring();
void CleanUp();
void UpdateSilenceWeights();
bool AcceptWaveform(Vector<BaseFloat> &wdata);
void GetSpkVector(Vector<BaseFloat> &xvector);
Model &model_;
Model *model_;
SingleUtteranceNnet3Decoder *decoder_;
fst::LookaheadFst<fst::StdArc, int32> *decode_fst_;
fst::StdVectorFst *g_fst_; // dynamically constructed grammar
@@ -58,8 +59,10 @@ class KaldiRecognizer {
SpkModel *spk_model_;
OnlineBaseFeature *spk_feature_;
fst::MapFst<fst::StdArc, kaldi::LatticeArc, fst::StdToLatticeMapper<kaldi::BaseFloat> > *lm_fst_;
float sample_frequency_;
int32 frame_offset_;
bool input_finalized_;
std::string last_result_;
string last_result_;
};
+193 -43
View File
@@ -45,19 +45,97 @@ static FstRegisterer<NGramFst<StdArc>> NGramFst_StdArc_registerer;
#ifdef __ANDROID__
#include <android/log.h>
static void AndroidLogHandler(const LogMessageEnvelope &env, const char *message)
static void KaldiLogHandler(const LogMessageEnvelope &env, const char *message)
{
__android_log_print(ANDROID_LOG_VERBOSE, "KaldiDemo", message, 1);
int priority;
if (env.severity > GetVerboseLevel())
return;
if (env.severity > LogMessageEnvelope::kInfo) {
priority = ANDROID_LOG_VERBOSE;
} else {
switch (env.severity) {
case LogMessageEnvelope::kInfo:
priority = ANDROID_LOG_INFO;
break;
case LogMessageEnvelope::kWarning:
priority = ANDROID_LOG_WARN;
break;
case LogMessageEnvelope::kAssertFailed:
priority = ANDROID_LOG_FATAL;
break;
case LogMessageEnvelope::kError:
default: // If not the ERROR, it still an error!
priority = ANDROID_LOG_ERROR;
break;
}
}
std::stringstream full_message;
full_message << env.func << "():" << env.file << ':'
<< env.line << ") " << message;
__android_log_print(priority, "VoskAPI", "%s", full_message.str().c_str());
}
#else
static void KaldiLogHandler(const LogMessageEnvelope &env, const char *message)
{
if (env.severity > GetVerboseLevel())
return;
// Modified default Kaldi logging so we can disable LOG messages.
std::stringstream full_message;
if (env.severity > LogMessageEnvelope::kInfo) {
full_message << "VLOG[" << env.severity << "] (";
} else {
switch (env.severity) {
case LogMessageEnvelope::kInfo:
full_message << "LOG (";
break;
case LogMessageEnvelope::kWarning:
full_message << "WARNING (";
break;
case LogMessageEnvelope::kAssertFailed:
full_message << "ASSERTION_FAILED (";
break;
case LogMessageEnvelope::kError:
default: // If not the ERROR, it still an error!
full_message << "ERROR (";
break;
}
}
// Add other info from the envelope and the message text.
full_message << "VoskAPI" << ':'
<< env.func << "():" << env.file << ':'
<< env.line << ") " << message;
// Print the complete message to stderr.
full_message << "\n";
std::cerr << full_message.str();
}
#endif
Model::Model(const char *model_path) {
Model::Model(const char *model_path) : model_path_str_(model_path) {
#ifdef __ANDROID__
SetLogHandler(AndroidLogHandler);
#endif
SetLogHandler(KaldiLogHandler);
const char *usage = "Read the docs";
struct stat buffer;
string am_path = model_path_str_ + "/am/final.mdl";
if (stat(am_path.c_str(), &buffer) == 0) {
ConfigureV2();
} else {
ConfigureV1();
}
ReadDataFiles();
ref_cnt_ = 1;
}
// Old model layout without model configuration file
void Model::ConfigureV1()
{
const char *extra_args[] = {
"--min-active=200",
"--max-active=3000",
@@ -71,55 +149,98 @@ Model::Model(const char *model_path) {
"--endpoint.rule2.min-trailing-silence=0.5",
"--endpoint.rule3.min-trailing-silence=1.0",
"--endpoint.rule4.min-trailing-silence=2.0",
};
std::string model_path_str(model_path);
kaldi::ParseOptions po(usage);
"--print-args=false",
};
kaldi::ParseOptions po("");
nnet3_decoding_config_.Register(&po);
endpoint_config_.Register(&po);
decodable_opts_.Register(&po);
std::vector<const char*> args;
vector<const char*> args;
args.push_back("vosk");
args.insert(args.end(), extra_args, extra_args + sizeof(extra_args) / sizeof(extra_args[0]));
po.Read(args.size(), args.data());
feature_info_.feature_type = "mfcc";
ReadConfigFromFile(model_path_str + "/mfcc.conf", &feature_info_.mfcc_opts);
ReadConfigFromFile(model_path_str_ + "/mfcc.conf", &feature_info_.mfcc_opts);
feature_info_.mfcc_opts.frame_opts.allow_downsample = true; // It is safe to downsample
feature_info_.silence_weighting_config.silence_weight = 1e-3;
feature_info_.silence_weighting_config.silence_phones_str = "1:2:3:4:5:6:7:8:9:10";
feature_info_.silence_weighting_config.silence_phones_str = endpoint_config_.silence_phones;
OnlineIvectorExtractionConfig ivector_extraction_opts;
ivector_extraction_opts.splice_config_rxfilename = model_path_str + "/ivector/splice.conf";
ivector_extraction_opts.cmvn_config_rxfilename = model_path_str + "/ivector/online_cmvn.conf";
ivector_extraction_opts.lda_mat_rxfilename = model_path_str + "/ivector/final.mat";
ivector_extraction_opts.global_cmvn_stats_rxfilename = model_path_str + "/ivector/global_cmvn.stats";
ivector_extraction_opts.diag_ubm_rxfilename = model_path_str + "/ivector/final.dubm";
ivector_extraction_opts.ivector_extractor_rxfilename = model_path_str + "/ivector/final.ie";
ivector_extraction_opts.num_gselect = 5;
ivector_extraction_opts.min_post = 0.025;
ivector_extraction_opts.posterior_scale = 0.1;
ivector_extraction_opts.max_remembered_frames = 1000;
ivector_extraction_opts.max_count = 100;
ivector_extraction_opts.ivector_period = 200;
ivector_extraction_opts.splice_config_rxfilename = model_path_str_ + "/ivector/splice.conf";
ivector_extraction_opts.cmvn_config_rxfilename = model_path_str_ + "/ivector/online_cmvn.conf";
ivector_extraction_opts.lda_mat_rxfilename = model_path_str_ + "/ivector/final.mat";
ivector_extraction_opts.global_cmvn_stats_rxfilename = model_path_str_ + "/ivector/global_cmvn.stats";
ivector_extraction_opts.diag_ubm_rxfilename = model_path_str_ + "/ivector/final.dubm";
ivector_extraction_opts.ivector_extractor_rxfilename = model_path_str_ + "/ivector/final.ie";
feature_info_.use_ivectors = true;
feature_info_.ivector_extractor_info.Init(ivector_extraction_opts);
std::string nnet3_rxfilename = model_path_str + "/final.mdl";
std::string hclg_fst_rxfilename = model_path_str + "/HCLG.fst";
std::string hcl_fst_rxfilename = model_path_str + "/HCLr.fst";
std::string g_fst_rxfilename = model_path_str + "/Gr.fst";
std::string disambig_rxfilename = model_path_str + "/disambig_tid.int";
std::string word_syms_rxfilename = model_path_str + "/words.txt";
std::string winfo_rxfilename = model_path_str + "/word_boundary.int";
nnet3_rxfilename_ = model_path_str_ + "/final.mdl";
hclg_fst_rxfilename_ = model_path_str_ + "/HCLG.fst";
hcl_fst_rxfilename_ = model_path_str_ + "/HCLr.fst";
g_fst_rxfilename_ = model_path_str_ + "/Gr.fst";
disambig_rxfilename_ = model_path_str_ + "/disambig_tid.int";
word_syms_rxfilename_ = model_path_str_ + "/words.txt";
winfo_rxfilename_ = model_path_str_ + "/word_boundary.int";
carpa_rxfilename_ = model_path_str_ + "/rescore/G.carpa";
std_fst_rxfilename_ = model_path_str_ + "/rescore/G.fst";
}
void Model::ConfigureV2()
{
kaldi::ParseOptions po("something");
nnet3_decoding_config_.Register(&po);
endpoint_config_.Register(&po);
decodable_opts_.Register(&po);
po.ReadConfigFile(model_path_str_ + "/conf/model.conf");
KALDI_LOG << "Decoding params beam=" << nnet3_decoding_config_.beam <<
" max-active=" << nnet3_decoding_config_.max_active <<
" lattice-beam=" << nnet3_decoding_config_.lattice_beam;
KALDI_LOG << "Silence phones " << endpoint_config_.silence_phones;
feature_info_.feature_type = "mfcc";
ReadConfigFromFile(model_path_str_ + "/conf/mfcc.conf", &feature_info_.mfcc_opts);
feature_info_.mfcc_opts.frame_opts.allow_downsample = true; // It is safe to downsample
feature_info_.silence_weighting_config.silence_weight = 1e-3;
feature_info_.silence_weighting_config.silence_phones_str = endpoint_config_.silence_phones;
OnlineIvectorExtractionConfig ivector_extraction_opts;
ivector_extraction_opts.splice_config_rxfilename = model_path_str_ + "/ivector/splice.conf";
ivector_extraction_opts.cmvn_config_rxfilename = model_path_str_ + "/ivector/online_cmvn.conf";
ivector_extraction_opts.lda_mat_rxfilename = model_path_str_ + "/ivector/final.mat";
ivector_extraction_opts.global_cmvn_stats_rxfilename = model_path_str_ + "/ivector/global_cmvn.stats";
ivector_extraction_opts.diag_ubm_rxfilename = model_path_str_ + "/ivector/final.dubm";
ivector_extraction_opts.ivector_extractor_rxfilename = model_path_str_ + "/ivector/final.ie";
feature_info_.use_ivectors = true;
feature_info_.ivector_extractor_info.Init(ivector_extraction_opts);
nnet3_rxfilename_ = model_path_str_ + "/am/final.mdl";
hclg_fst_rxfilename_ = model_path_str_ + "/graph/HCLG.fst";
hcl_fst_rxfilename_ = model_path_str_ + "/graph/HCLr.fst";
g_fst_rxfilename_ = model_path_str_ + "/graph/Gr.fst";
disambig_rxfilename_ = model_path_str_ + "/graph/disambig_tid.int";
word_syms_rxfilename_ = model_path_str_ + "/graph/words.txt";
winfo_rxfilename_ = model_path_str_ + "/graph/phones/word_boundary.int";
carpa_rxfilename_ = model_path_str_ + "/rescore/G.carpa";
std_fst_rxfilename_ = model_path_str_ + "/rescore/G.fst";
}
void Model::ReadDataFiles()
{
struct stat buffer;
trans_model_ = new kaldi::TransitionModel();
nnet_ = new kaldi::nnet3::AmNnetSimple();
{
bool binary;
kaldi::Input ki(nnet3_rxfilename, &binary);
kaldi::Input ki(nnet3_rxfilename_, &binary);
trans_model_->Read(ki.Stream(), binary);
nnet_->Read(ki.Stream(), binary);
SetBatchnormTestMode(true, &(nnet_->GetNnet()));
@@ -129,16 +250,17 @@ Model::Model(const char *model_path) {
decodable_info_ = new nnet3::DecodableNnetSimpleLoopedInfo(decodable_opts_,
nnet_);
struct stat buffer;
if (stat(hclg_fst_rxfilename.c_str(), &buffer) == 0) {
hclg_fst_ = fst::ReadFstKaldiGeneric(hclg_fst_rxfilename);
if (stat(hclg_fst_rxfilename_.c_str(), &buffer) == 0) {
KALDI_LOG << "Loading HCLG from " << hclg_fst_rxfilename_;
hclg_fst_ = fst::ReadFstKaldiGeneric(hclg_fst_rxfilename_);
hcl_fst_ = NULL;
g_fst_ = NULL;
} else {
KALDI_LOG << "Loading HCL and G from " << hcl_fst_rxfilename_ << " " << g_fst_rxfilename_;
hclg_fst_ = NULL;
hcl_fst_ = fst::StdFst::Read(hcl_fst_rxfilename);
g_fst_ = fst::StdFst::Read(g_fst_rxfilename);
ReadIntegerVectorSimple(disambig_rxfilename, &disambig_);
hcl_fst_ = fst::StdFst::Read(hcl_fst_rxfilename_);
g_fst_ = fst::StdFst::Read(g_fst_rxfilename_);
ReadIntegerVectorSimple(disambig_rxfilename_, &disambig_);
}
word_syms_ = NULL;
@@ -148,18 +270,46 @@ Model::Model(const char *model_path) {
word_syms_ = g_fst_->OutputSymbols();
}
if (!word_syms_) {
if (!(word_syms_ = fst::SymbolTable::ReadText(word_syms_rxfilename)))
KALDI_LOG << "Loading words from " << word_syms_rxfilename_;
if (!(word_syms_ = fst::SymbolTable::ReadText(word_syms_rxfilename_)))
KALDI_ERR << "Could not read symbol table from file "
<< word_syms_rxfilename;
<< word_syms_rxfilename_;
}
KALDI_ASSERT(word_syms_);
if (stat(winfo_rxfilename.c_str(), &buffer) == 0) {
if (stat(winfo_rxfilename_.c_str(), &buffer) == 0) {
KALDI_LOG << "Loading winfo " << winfo_rxfilename_;
kaldi::WordBoundaryInfoNewOpts opts;
winfo_ = new kaldi::WordBoundaryInfo(opts, winfo_rxfilename);
winfo_ = new kaldi::WordBoundaryInfo(opts, winfo_rxfilename_);
} else {
winfo_ = NULL;
}
if (stat(carpa_rxfilename_.c_str(), &buffer) == 0) {
KALDI_LOG << "Loading CARPA model from " << carpa_rxfilename_;
std_lm_fst_ = fst::ReadFstKaldi(std_fst_rxfilename_);
fst::Project(std_lm_fst_, fst::PROJECT_OUTPUT);
if (std_lm_fst_->Properties(fst::kILabelSorted, true) == 0) {
fst::ILabelCompare<fst::StdArc> ilabel_comp;
fst::ArcSort(std_lm_fst_, ilabel_comp);
}
ReadKaldiObject(carpa_rxfilename_, &const_arpa_);
} else {
std_lm_fst_ = NULL;
}
}
void Model::Ref()
{
ref_cnt_++;
}
void Model::Unref()
{
ref_cnt_--;
if (ref_cnt_ == 0) {
delete this;
}
}
Model::~Model() {
+25 -2
View File
@@ -32,6 +32,7 @@
#include "rnnlm/rnnlm-utils.h"
using namespace kaldi;
using namespace std;
class KaldiRecognizer;
@@ -39,11 +40,28 @@ class Model {
public:
Model(const char *model_path);
~Model();
void Ref();
void Unref();
protected:
~Model();
void ConfigureV1();
void ConfigureV2();
void ReadDataFiles();
friend class KaldiRecognizer;
string model_path_str_;
string nnet3_rxfilename_;
string hclg_fst_rxfilename_;
string hcl_fst_rxfilename_;
string g_fst_rxfilename_;
string disambig_rxfilename_;
string word_syms_rxfilename_;
string winfo_rxfilename_;
string carpa_rxfilename_;
string std_fst_rxfilename_;
kaldi::OnlineEndpointConfig endpoint_config_;
kaldi::LatticeFasterDecoderConfig nnet3_decoding_config_;
kaldi::nnet3::NnetSimpleLoopedComputationOptions decodable_opts_;
@@ -54,11 +72,16 @@ protected:
kaldi::nnet3::AmNnetSimple *nnet_;
const fst::SymbolTable *word_syms_;
kaldi::WordBoundaryInfo *winfo_;
std::vector<int32> disambig_;
vector<int32> disambig_;
fst::Fst<fst::StdArc> *hclg_fst_;
fst::Fst<fst::StdArc> *hcl_fst_;
fst::Fst<fst::StdArc> *g_fst_;
fst::VectorFst<fst::StdArc> *std_lm_fst_;
kaldi::ConstArpaLm const_arpa_;
int ref_cnt_;
};
#endif /* MODEL_H_ */
+15
View File
@@ -24,4 +24,19 @@ SpkModel::SpkModel(const char *speaker_path) {
SetBatchnormTestMode(true, &speaker_nnet);
SetDropoutTestMode(true, &speaker_nnet);
CollapseModel(nnet3::CollapseModelConfig(), &speaker_nnet);
ref_cnt_ = 1;
}
void SpkModel::Ref()
{
ref_cnt_++;
}
void SpkModel::Unref()
{
ref_cnt_--;
if (ref_cnt_ == 0) {
delete this;
}
}
+5
View File
@@ -27,12 +27,17 @@ class SpkModel {
public:
SpkModel(const char *spk_path);
void Ref();
void Unref();
protected:
friend class KaldiRecognizer;
~SpkModel() {};
kaldi::nnet3::Nnet speaker_nnet;
MfccOptions spkvector_mfcc_opts;
int ref_cnt_;
};
#endif /* SPK_MODEL_H_ */
+7
View File
@@ -1,4 +1,8 @@
#if SWIGPYTHON
%module(package="vosk", "threads"=1) vosk
#else
%module Vosk
#endif
%include <typemaps.i>
@@ -113,3 +117,6 @@ typedef struct {} KaldiRecognizer;
return vosk_recognizer_final_result($self);
}
}
%rename(SetLogLevel) vosk_set_log_level;
void vosk_set_log_level(int level);
+10 -5
View File
@@ -28,7 +28,7 @@ VoskModel *vosk_model_new(const char *model_path)
void vosk_model_free(VoskModel *model)
{
delete (Model *)model;
((Model *)model)->Unref();
}
VoskSpkModel *vosk_spk_model_new(const char *model_path)
@@ -38,22 +38,22 @@ VoskSpkModel *vosk_spk_model_new(const char *model_path)
void vosk_spk_model_free(VoskSpkModel *model)
{
delete (SpkModel *)model;
((SpkModel *)model)->Unref();
}
VoskRecognizer *vosk_recognizer_new(VoskModel *model, float sample_rate)
{
return (VoskRecognizer *)new KaldiRecognizer(*(Model *)model, sample_rate);
return (VoskRecognizer *)new KaldiRecognizer((Model *)model, sample_rate);
}
VoskRecognizer *vosk_recognizer_new_spk(VoskModel *model, VoskSpkModel *spk_model, float sample_rate)
{
return (VoskRecognizer *)new KaldiRecognizer(*(Model *)model, (SpkModel *)spk_model, sample_rate);
return (VoskRecognizer *)new KaldiRecognizer((Model *)model, (SpkModel *)spk_model, sample_rate);
}
VoskRecognizer *vosk_recognizer_new_grm(VoskModel *model, float sample_rate, const char *grammar)
{
return (VoskRecognizer *)new KaldiRecognizer(*(Model *)model, sample_rate, grammar);
return (VoskRecognizer *)new KaldiRecognizer((Model *)model, sample_rate, grammar);
}
int vosk_recognizer_accept_waveform(VoskRecognizer *recognizer, const char *data, int length)
@@ -90,3 +90,8 @@ void vosk_recognizer_free(VoskRecognizer *recognizer)
{
delete (KaldiRecognizer *)(recognizer);
}
void vosk_set_log_level(int log_level)
{
SetVerboseLevel(log_level);
}
+8
View File
@@ -41,6 +41,14 @@ const char *vosk_recognizer_partial_result(VoskRecognizer *recognizer);
const char *vosk_recognizer_final_result(VoskRecognizer *recognizer);
void vosk_recognizer_free(VoskRecognizer *recognizer);
/**
* Set log level for Kaldi messages
* 0 - default value to print info and error messages but no debug
* less than 0 - don't print info messages
* greather than 0 - more verbose mode
*/
void vosk_set_log_level(int log_level);
#ifdef __cplusplus
}
#endif
+1 -1
View File
@@ -35,7 +35,7 @@ RUN cd /opt \
&& sed -i "s:-mfloat-abi=hard -mfpu=neon:${ARM_HARDWARE_OPTS}:g" makefiles/linux_openblas_arm.mk \
&& sed -i "s: -O1 : -O3 :g" makefiles/linux_openblas_arm.mk \
&& ./configure --mathlib=OPENBLAS --shared --use-cuda=no \
&& make -j 10 online2 \
&& make -j 10 online2 lm \
&& find /opt/kaldi -name "*.o" -exec rm {} \;
RUN cd /opt \
+1 -1
View File
@@ -27,7 +27,7 @@ RUN cd /opt \
&& make -j 10 openfst \
&& cd ../src \
&& ./configure --mathlib=OPENBLAS --shared --use-cuda=no \
&& make -j 10 online2 \
&& make -j 10 online2 lm \
&& find /opt/kaldi -name "*.o" -exec rm {} \;
RUN cd /opt \
-2
View File
@@ -3,11 +3,9 @@
set -e
set -x
skip() {
docker build --build-arg="DOCKCROSS_IMAGE=linux-armv7" --build-arg="OPENBLAS_ARCH=ARMV7" --file Dockerfile.dockcross --tag alphacep/kaldi-dockcross-armv7:latest .
docker build --build-arg="DOCKCROSS_IMAGE=linux-armv6" --build-arg="OPENBLAS_ARCH=ARMV6" --build-arg="ARM_HARDWARE_OPTS=" --file Dockerfile.dockcross --tag alphacep/kaldi-dockcross-armv6:latest .
docker build --build-arg="DOCKCROSS_IMAGE=linux-arm64" --build-arg="OPENBLAS_ARCH=ARMV8" --file Dockerfile.dockcross --tag alphacep/kaldi-dockcross-arm64:latest .
}
docker run --rm -v /home/shmyrev/travis/vosk-api/:/io alphacep/kaldi-dockcross-armv6 /io/travis/build-wheels-dockcross.sh
docker run --rm -v /home/shmyrev/travis/vosk-api/:/io alphacep/kaldi-dockcross-armv7 /io/travis/build-wheels-dockcross.sh