Kaldiを用いたリアルタイム音声認識

最近音声認識研究業界では標準になっているＫａｌｄｉを用いて，リアルタイム音声認識をする方法です．音声が入力されている間にも，どんどん音声認識がされていく環境です（１発話が終わってから，音声が認識開始されるのではない．）．

Kaldi GStreamer serverを用いて音声認識を行いますが，この環境がDockerイメージで公開されているので，それを使います．使わなくてもできると思います．

以下の例では，DNNの音声認識モデルにて，英語の音声認識をします．kaldi用online_nnet2モデルがあれば，日本語でもできるようです．


- Kaldi GStreamer server：https://github.com/alumae/kaldi-gstreamer-server
- docker-kaldi-gstreamer-server：https://github.com/jcsilva/docker-kaldi-gstreamer-server

# １．マシン環境
```
OS : Ubuntu 16.04
```

# ２．docker インストール

## ２．１．旧バージョンのアンインストール
```
$ sudo apt-get remove docker docker-engine docker.io
```

## ２．２．　リポジトリのセットアップ
```
$ sudo apt-get update
$ sudo apt-get install apt-transport-https ca-certificates curl software-properties-common
$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
```

キーの確認

```
$ sudo apt-key fingerprint 0EBFCD88

pub   4096R/0EBFCD88 2017-02-22
      Key fingerprint = 9DC8 5822 9FC7 DD38 854A  E2D8 8D81 803C 0EBF CD88
uid                  Docker Release (CE deb) <docker@docker.com>
sub   4096R/F273FCD8 2017-02-22
```

リポジトリの追加

```
$ sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
```

## ２．３． インストール
```
$ sudo apt-get update
$ sudo apt-get install docker-ce
```

# ３．kaldiのdockerイ用イメージファイルをインストール
```
$ docker pull jcsilva/docker-kaldi-gstreamer-server
```

dockerのイメージは，`/var/lib/docker/` 内に格納されます．

エラーで実行できない場合は，dockerグループにユーザが登録されていない可能性があります．
https://qiita.com/naomichi-y/items/93819573a5a51ae8cc07


# ４．dockerイメージ起動
以下の ３．２．１．〜 ３．２．３．の３つの中で，自分の条件に合うものを一つ実行して，dockerイメージを起動してください．

## ４．１．dockerイメージ内で，認識サーバ＆クライアントの両方を起動する場合
```
$ docker run --name kaldi_server -it --privileged -v /dev/snd:/dev/snd -v /media/kaldi_models:/opt/models jcsilva/docker-kaldi-gstreamer-server:latest /bin/bash

-v /dev/snd:/dev/snd で，サウンドデバイスをdocker内で使用できるようにしている．
```

## ４．２．同一マシンでクライアントも走らせる場合（docker内ではなく，ホストOSでクライアントを起動する場合）
```
$ docker run --name kaldi_server -it --privileged -v /media/kaldi_models:/opt/models jcsilva/docker-kaldi-gstreamer-server:latest /bin/bash
```

## ４．３．別マシンでクライアントを走らせる場合（ポートフォワードをする）
```
$ docker run --name kaldi_server  -it -p 8888:8888 --privileged -v /media/kaldi_models:/opt/models jcsilva/docker-kaldi-gstreamer-server:latest /bin/bash

-p 8888:8888 で，docker内ポート(8888)を，ホストOSのポート(8888)にポートフォワードしている．
```

## ４．４．オプション説明 ＆ dockerについて
```
--name [string]                     ：名前を指定できます．
-v /media/kaldi_models:/opt/models  ：前半のディレクトリが，イメージ内の後半のディレクトリにマップされます．
```
  
dockerについて
`docker run`は，「イメージからコンテナを新規作成」するコマンドです．
`docker start`は，「既存コンテナを起動」するコマンドです．
毎回`docker run`すると，コンテナが新規作成されます．作成した（一度使った）コンテナを使う場合には，`docker start`を使いましょう．  

`docker ps -a`で，存在するコンテナを確認できます．
`docker start -i [コンテナID or NAME]`で，コンテナにログインできます．
`docker rm [コンテナID or NAME]`で，コンテナを削除できます．

# ５．docker内環境設定
## ５．１． ALSAインストール（aplay, arecord）
```
$ apt-get install alsa-utils
```

`aplay -l`，`arecord -l` デバイス番号の表示
`arecord -D hw:2,0 test.wav` デバイス[2]，サブデバイス[0]にて，`test.wav`に録音（Unsigned 8 bit, Rate 8000 Hz, Mono）

`aplay -l` でサウンドカードが見つからない場合，`$ sudo aplay -l` をしてサウンドカードが表示されるなら，以下を実行して，audioグループにユーザを追加してください．

```
$ sudo gpasswd -a [user] audio
```

再起動後，`$ aplay -l`をしてみてください．

## ５．２．音声認識用モデルのダウンロード（英語：TEDLIUM)
dockerの`/opt/models` 内にデータをダウンロードした（マップされて，ホストOSの `/media/kaldi_models` に入る）

```
$ mkdir -p /opt/models/test/models
$ cd /opt/models/test/models
$ wget --no-check-certificate https://phon.ioc.ee/~tanela/tedlium_nnet_ms_sp_online.tgz
$ tar zxvf tedlium_nnet_ms_sp_online.tgz
```

## ５．３．認識実行ディレクトリにて，音声認識用モデルにリンクを貼る
```
$ cd /opt/kaldi-gstreamer-server
$ ln -s /opt/models/test .
```

## ５．４． 環境変数設定
```
$ export GST_PLUGIN_PATH=/opt/gst-kaldi-nnet2-online/src
```
毎回入力しないといけないから，起動時に自動で適用されるように，`~/.bashrc` に書いておいてもいいかもね． 

## ５．５． 起動するか確認
```
$ gst-inspect-1.0 kaldinnet2onlinedecoder
```

オプション項目が表示されればOK．

# ６．音声認識：サーバ起動
## ６．１． masterサーバ起動（master_server.py）
masterサーバは，音声認識サーバではなく，workerとclientとのリクエストのやり取りを行うサーバです．

```
$ cd /opt/kaldi-gstreamer-server
$ python kaldigstserver/master_server.py --port=8888 &
```

## ６．２．workerサーバ起動（worker.py）
```
$ cd /opt/kaldi-gstreamer-server
$ python kaldigstserver/worker.py -u ws://localhost:8888/worker/ws/speech -c sample_english_nnet2.yaml &
```

# ７．音声認識：クライアント起動
## ７．１．ファイルからの音声認識
dockerの`/opt/models` 内にデータをダウンロードした

```
$ mkdir -p  /opt/models/data
$ cd /opt/models/data
$ wget https://raw.githubusercontent.com/alumae/kaldi-gstreamer-server/master/test/data/bill_gates-TED.mp3
$ wget https://raw.githubusercontent.com/alumae/kaldi-gstreamer-server/master/test/data/bill_gates-TED.txt
```

音声認識実行

```
$ cd /opt/kaldi-gstreamer-server
$ python kaldigstserver/client.py -r 8192 test/data/bill_gates-TED.mp3
```


## ７．２．マイクからの認識
実行する環境下で，`client.py`をダウンロードしてください．

```
$ wget https://raw.githubusercontent.com/alumae/kaldi-gstreamer-server/master/kaldigstserver/client.py
```
pythonのバージョンに気をつけること．client.pyは，python2用．python3では動きません．

そして，以下の ７．２．１．〜 ７．２．３．の３つの中で，自分の条件に合うものを実行してください．
なお，以下の例は，マイクのデバイス番号[2]，サブデバイス番号[0]の場合です．

### ７．２．１．dockerイメージ内で実行
```
$ arecord -f S16_LE -r 16000 -D plughw:2,0 | python2 kaldigstserver/client.py -r 32000 -
```

### ７．２．２．dockerイメージを起動しているマシンで実行（ホストOS）
```
$ arecord -f S16_LE -r 16000 -D plughw:2,0 | python2 client.py -u ws://localhost:8888/client/ws/speech -r 32000 -
```

### ７．２．３．別マシンから接続
```
$ arecord -f S16_LE -r 16000 -D plughw:2,0 | python2 client.py -u ws://[ASR SERVER IP]:8888/client/ws/speech -r 32000 -
```

### ７．２．４．オプション説明
```
[arecord]
-D: 録音デバイス指定

[client.py]
-u: サーバ指定
```

# ８．参考にしたページ
Kaldi GStreamer server （このページのREADME.mdの通りにやっていく）
https://github.com/alumae/kaldi-gstreamer-server

docker-kaldi-gstreamer-server
https://github.com/jcsilva/docker-kaldi-gstreamer-server

dockerのインストール
https://docs.docker.com/engine/installation/
https://docs.docker.com/engine/installation/linux/docker-ce/ubuntu/

kaldiオフィシャルページのオンライン認識  
http://kaldi-asr.org/doc/online_decoding.html

`aplay -l` で「サウンドカードが見つかりません．．．」と出る場合の対処方法  
https://raspberrypi.stackexchange.com/questions/3637/how-to-play-audio-without-being-root-via-sudo