Raspberry Pi ではじめるホットワード音声認識（snowboyバイナリ版編）

# 1. はじめに
今回は、自分自身への備忘録を兼ねて、Raspberry Piでsnowboyバイナリ版を用いたホットワード音声認識をはじめる方法を、お伝えしたいと思います。

- 参考：[Raspberry Pi Snowboy Hotword Detection](https://pimylifeup.com/raspberry-pi-snowboy/)
- 参考：[公式サイト](https://snowboy.kitt.ai/)
- 参考：[公式サイトDocs](http://docs.kitt.ai/snowboy/)
- 参考：[GitHub](https://github.com/kitt-ai/snowboy)

# 2. この記事を読んでできること
- Raspberry Piでsnowboyバイナリ版を用いたホットワード音声認識ができるようになる。

# 3. 必要なもの
- Raspberry Pi（この記事では Raspberry Pi 3 Model B+ および 2018-11-13-raspbian-stretch-lite.zip を利用しました）
- SDカード
- インターネット環境
- パソコン（Windows10など）
- sshクライアントソフト（[TeraTerm](https://ja.osdn.net/projects/ttssh2/releases/)）
- scpクライアントソフト（[WinSCP](https://forest.watch.impress.co.jp/library/software/winscp/download_10950.html)）
- USBマイク（[サンワサプライ USBマイクロホン MM-MCU02BK](https://amzn.to/30PK9YP)であれば、ドライバインストール不要で利用できるそうです。）
- 3.5mm ステレオミニプラグ スピーカーアンプ付きが好ましい（音声出力先：TVのHDMI出力にスピーカー出力できることを確認済み）

- 参考：RaspberryPiにIPアドレスではなくホスト名で接続したい方は、あらかじめ[iTunes](https://support.apple.com/ja_JP/downloads/itunes)（正確には『[Bonjourサービス](https://support.apple.com/kb/DL999?locale=ja_JP&viewlocale=ja_JP)』単体）をインストールしておくと『ホスト名.local』にてIPアドレスを使わずともアクセスできるようになると思います。

![IMG_20201109_102903.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/240522/385c80f4-1f16-6ea3-5cd0-17396ca939ba.jpeg)

# 4. Raspberry Pi OS Lite(2018-11-13-raspbian-stretch-lite.zip)の入手
- 以下のURLから、OSイメージファイル（[Raspberry Pi OS Lite(2018-11-13-raspbian-stretch-lite.zip)](http://ftp.jaist.ac.jp/pub/raspberrypi/raspbian_lite/images/raspbian_lite-2018-11-15/2018-11-13-raspbian-stretch-lite.zip)）をダウンロードする。
- snowboyバイナリ版がRaspberry Pi OS 8.0対応と書かれてあったので、2018-11-13-raspbian-stretch-lite.zipを採用しました。
- 他のバージョンでの動作未検証となります。

```plaintext:Raspbian_Buster_LiteダウンロードサイトURL
http://ftp.jaist.ac.jp/pub/raspberrypi/raspbian_lite/images/raspbian_lite-2018-11-15/2018-11-13-raspbian-stretch-lite.zip
```

参考：この記事作成時のファイルバージョン：2018-11-13-raspbian-stretch-lite.zip

# 5. microSDカードのフォーマット
- [SD Formatter for Windows](https://www.sdcard.org/jp/downloads/formatter/index.html)などのソフトを用いて、使用するmicroSDカードをフォーマットする。
- フォーマット形式は「FAT32」を選択することを推奨します。

- 参考：参考画面
![fomatter.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/240522/94af63eb-346c-229e-d908-886b65a9339b.png)

# 6. microSDカードへOSイメージの書き込み（所要時間：10分）
- [Etcher](https://www.balena.io/etcher/)などのソフトを用いて、使用するmicroSDカードへOSイメージを書き込む。
- Etcherは、圧縮されたままのOSイメージ（拡張子が.img以外）を解凍せずにそのまま扱えておすすめです。

- 参考：Etcher起動時の画面
![etcher_1.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/240522/4d57f18a-994c-eb48-9ddf-f70545395fe6.png)

# 7. Raspberry Pi のSSH有効化の設定
- microSDカード直下フォルダにファイル名「ssh」（空ファイル拡張子なし）で新規作成する。保存の際は、不要なファイル拡張子（.txt等）が付かないよう注意すること。
- OSイメージ書き込み直後にmicroSDカード直下フォルダにアクセスできない場合は、いったんmicroSDカードを抜き＆差しすると、ドライブ認識するのでアクセスできるようになると思います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/240522/9dbc02c8-bc46-05f3-08e8-569e4888ba9a.png)

# 8. Raspberry Pi のWi-Fi設定
- あらかじめ以下の設定をおこない、Wi-Fi設定を済ませておきます。
- microSDカード直下フォルダにファイル名「wpa_supplicant.conf」（改行コード：LF、文字コード：UTF-8）で新規作成し、ファイルの内容を以下のとおり設定する。（ssidとパスワードpskは、各自の環境に合わせて設定してください。）

```plaintext:wpa_supplicant.conf
country=JP
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1
network={
        ssid="----Your-WiFi-SSID----"
        psk="----PLAIN-PASSPHRASE----"
}
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/240522/0ffac7cd-6e03-e034-471e-546c31abb4bf.png)

# 9. microSDカード の完成
- 完成した microSDカード を、PCからおもむろに抜き取る。

# 10. Raspberry Piの起動
- Raspberry PiにmicroSDカードを挿入し、Raspberry Piを起動する。

# 11. SSHクライアントでRaspberry Piに接続
- PCで、SSHクライアント（TeraTerm 等）を起動し、ホストにRaspberry PiのIPアドレス「192.168.XXX.XXX」またはホスト名「raspberrypi.local」を入力し、OKボタンをクリックし、ssh接続する。
-  SSH認証画面で、ユーザ名とパスフレーズを入力し、「OK」ボタンをクリックする。
- SSHクライアントの使い方がわからない、またはRaspberry PiのIPアドレスがわからない、ホスト名接続できない方は、Raspberry PiにHDMIモニタ、マウス、キーボードを接続して以降の操作をおこなっても大丈夫です。

```plaintext:デフォルトユーザ名／パスワード
ユーザ名　：pi
パスワード：raspberry
```

# 12. RaspberryPiのオーディオ構成の準備
- 以下のコマンドを実行し、接続デバイス（USBマイク、3.5mmジャックスピーカー）のカード番号およびデバイス番号を確認します。- 確認したカード番号およびデバイス番号を新規ファイルの/home/pi/.asoundrcへ設定します。
- 私の試した限りでは、サンワサプライ USBマイクロホン MM-MCU02BKを利用する場合、サンプリング周波数は `rate 16000` を指定するとよさそうです。また、みんな大好き[MI-305ドングルマイク](https://eleshop.jp/shop/g/gJ5S311/)を利用する場合は、サンプリング周波数を `rate 48000` を指定することで正常動作が確認できました。

```plaintext:コマンドプロンプト
// ホームディレクトリに移動（/home/pi/を想定）
$ cd

// 接続デバイス（USBマイクのカード番号、デバイス番号）の確認
//  コマンド結果の2行目の、`card ~:`、`device ~:`の番号を控えておきます。
$ arecord -l

**** List of CAPTURE Hardware Devices ****
card 1: Microphone [USB Microphone], device 0: USB Audio [USB Audio]
  Subdevices: 1/1
  Subdevice #0: subdevice #0

// 接続デバイス（3.5mmジャックスピーカーのカード番号、デバイス番号）の確認
// コマンド結果の[bcm2835 ALSA]のほうの、`card ~:`、`device ~:`の番号を控えておきます。
$ aplay -l

**** List of PLAYBACK Hardware Devices ****
card 0: ALSA [bcm2835 ALSA], device 0: bcm2835 ALSA [bcm2835 ALSA]
  Subdevices: 7/7
  Subdevice #0: subdevice #0
  Subdevice #1: subdevice #1
  Subdevice #2: subdevice #2
  Subdevice #3: subdevice #3
  Subdevice #4: subdevice #4
  Subdevice #5: subdevice #5
  Subdevice #6: subdevice #6
card 0: ALSA [bcm2835 ALSA], device 1: bcm2835 ALSA [bcm2835 IEC958/HDMI]
  Subdevices: 1/1
  Subdevice #0: subdevice #0
```

```plaintext:コマンドプロンプト
// .asoundrcファイルの新規作成
$ vi .asoundrc
````

```plaintext:/home/pi/.asoundrcファイル内容
pcm.!default {
  type asym
  capture.pcm "mic"
  playback.pcm "speaker"
}
pcm.mic {
  type plug
  slave {
    pcm "hw:1,0"    // マイクの[カード番号,デバイス番号]で設定する（このコメント文は記述不要）
    rate 16000      // マイクのサンプリング周波数。サンワサプライ USBマイクロホン MM-MCU02BKの場合、rate 16000を指定しておくと『IOError: [Errno -9997] Invalid sample rate』エラーを回避できるとおもいます（このコメント文は記述不要）
  }
}
pcm.speaker {
  type plug
  slave {
    pcm "hw:0,0"    // スピーカーの[カード番号,デバイス番号]で設定する（このコメント文は記述不要）
  }
}
```

#13. Raspberry Piの最新化
- 以下のコマンドを実行し、Raspberry Piを最新化します。

```plaintext:コマンドプロンプト
// リポジトリ一覧を更新
$ sudo apt update

// アップグレードの実行（10分程度）
$ sudo apt upgrade
途中、Yキー押下
途中、qキー押下
```

#14. 必要パッケージの導入
- 以下のコマンドを実行し、必要パッケージを導入します。

```plaintext:コマンドプロンプト
// 依存関係パッケージの導入
$ sudo apt install python3 python3-pyaudio python3-pip libatlas-base-dev portaudio19-dev
途中、Yキー押下

// pyaudioのインストール
$ sudo pip3 install pyaudio

// requestsのインストール
$ sudo pip3 install requests

// soxのインストール
$ sudo apt-get install python-pyaudio sox
途中、Yキー押下

// 必要ライブラリのインストール
$ sudo apt-get install swig3.0

// Python2の開発用パッケージをインストール
$ sudo apt-get -y install python-dev

// Python2のpipをインストール
$ sudo apt-get -y install python-pip

// pyaudioのインストール
$ pip install pyaudio

// 必要ライブラリのインストール
$ sudo apt-get install libatlas-base-dev
途中、Yキー押下
```

#15. snowboyバイナリ版のインストール
- 以下のコマンドを実行し、snowboyバイナリ版のダウンロードおよび解凍します。

```plaintext:コマンドプロンプト
// snowboyバイナリ版1.3.0のダウンロード
$ wget -O rpi-arm-raspbian-8.0-1.3.0.tar.bz2 https://go.pimylifeup.com/napoRs/snowboy

// ダウンロードファイルの解凍
$ tar xvjf rpi-arm-raspbian-8.0-1.3.0.tar.bz2

// フォルダ名のリネーム
$ mv rpi-arm-raspbian-8.0-1.3.0/ snowboy/

```

# 16.ホットワードモデルファイル（.pmdl）の入手
- ホットワード（音声認識時の呼びかけフレーズ）モデルファイルは、2種類ありpersonalには.pmdl拡張子、universalには.umdl拡張子が付いています。
- snowboy/resources/ディレクトリ配下にはsnowboy.umdlのホットワードモデルが用意されていますが、日本人の発音では音声認識されないことが多いようです。
- [snowboy公式サイト](https://snowboy.kitt.ai/)には、日本語で録音登録された.pmdlホットワードモデルも用意されているため、日本語用のホットワードモデルファイルを[公式サイト](https://snowboy.kitt.ai/)から入手します。
- [参考サイト](http://35.239.24.28/raspberry-pi/avs-snowboy/)を参考に、『こんにちは.pmdl』ファイルを入手してみてください。
- その際、「Language Filter」からJapaneseを選択し、日本語を選ぶことで音声認識の精度を高められるようです。
- ファイルのダウンロードには、ダウンロードしたいフレーズ（こんにちは）を自分の声で3回録音登録することで、音声学習ファイルの提供の対価としてダウンロードすることができるようです。

```
ダウンロード入手したファイル名：こんにちは.pmdl
```

#17. .pmdlファイルをRasberry Piへコピー
- 入手した.pmdlファイルは、Raspberry Piへコピーする必要があります。
- WinSCPソフトなどのscpクライアントソフトを使って、Raspberry Pi内の/home/pi/snowboy/resources/ディレクトリ配下にファイルコピーしてください。
- その際、日本語ファイル名では扱いにくいため、konnitiwa.pmdlファイル名にリネームしましょう。

```
リネーム前：こんいちは.pmdl
リネーム後：konnitiwa.pmdl
```

#18. デモ（demo.py）の実行
- 以下のコマンドを実行し、snowboyデモを実行します。

```plaintext:コマンドプロンプト
// snowboyディレクトリに移動
$ cd ~/snowboy/

$ python demo.py ./resources/konnitiwa.pmdl

// snowboyが起動されホットワードの検知待機状態となります
Listening... Press Ctrl+C to exit

// ホットワード「こんにちは」が検出されると、検知音『ピン！』と合わせて以下の検知ログが出力されます。
INFO:snowboy:Keyword 1 detected at time: 2020-11-08 07:00:01
INFO:snowboy:Keyword 1 detected at time: 2020-11-08 07:00:03
```

# 19. 補足：マイクのテスト
- マイクまたはスピーカーが正しく動作しているか、以下のコマンドで確認することができます。
- snowboyのdemo.pyは実行できるが、音声認識されない場合はデバイス（マイク、スピーカ）を確認してみてください。

```plaintext:コマンドプロンプト
// マイクの録音
$ rec temp.wav

// 録音されていますので、何か話してください
// 録音されている場合は、画面上のインジケータが左右に広がる（動く）かと思います
// 終了は、Ctrl＋Cキー押下

// 録音音声の再生
$ play temp.wav

// 録音されていた場合は、画面上のインジケータが左右に広がる（動く）かと思います
// 実際にスピーカーを接続している場合は、実音での確認もできるかとおもいます

// 録音ファイルの削除
$ rm temp.wav
```

# 20. 補足：サンプルプログラム（Python）
- 参考サイト：[Raspberry Pi Snowboy Hotword Detection](https://pimylifeup.com/raspberry-pi-snowboy/)には、簡単なPythonプログラム例も掲示されていましたので、載せておきますね。
- こちらのサンプルプログラムの方が癖がなく簡単に動く印象を受けました。demo.pyで『IOError: [Errno -9997] Invalid sample rate』などのエラーが出力された場合かこちらのサンプルプログラムで試してみるとよいかと思います。ご参考まで。

```plaintext:コマンドプロンプト
// snowboyディレクトリに移動
$ cd ~/snowboy/

// ホットワードモデルファイルをsaved_model.pmdlの名前でコピー
$ cp -pr ./resources/konnitiwa.pmdl ./saved_model.pmdl

// サンプルプログラムを新規作成
$ vi snowboy_sample.py

// サンプルプログラムを実行（音声認識がスタートします）
$ python snowboy_sample.py

// ホットワードを認識すると、以下のログが出力されます
INFO:snowboy:Keyword 1 detected at time: 2020-11-09 02:06:56
Hotword Detected
```

```plaintext:snowboy_sample.py
import snowboydecoder

def detected_callback():
    print ("Hotword Detected")

detector = snowboydecoder.HotwordDetector("saved_model.pmdl", sensitivity=0.5, audio_gain=1)

detector.start(detected_callback)
````

![スクリーンショット 2020-11-09 112430.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/240522/e13e8304-867e-8392-a2cd-7c2f7fc73d0d.jpeg)

# 22. 補足：トラブルシューティング
- demo.pyで『IOError: [Errno -9997] Invalid sample rate』などのエラーが出力された場合、手順の途中で作成した『.asoundrc』に設定誤りがあるか、もしくは16,000 HZで録音できるマイクを利用していないことが原因のようです。一般的なUSBマイクであれば16,000 HZでの録音は可能のようです。
- 私の環境では、はじめはうまく動いているのですが、OS再起動を何度か繰り返していると何かをきっかけにマイクのサンプリング周波数が48,000 HZにかわり、『IOError: [Errno -9997] Invalid sample rate』エラーが出力されているように感じます。この状態になるきっかけ（トリガー）まではまだ把握できてない状況です。何かご存知の方がいましたらコメントいただけると助かります。

- （追記：2020/11/15）/home/pi/.asoundrcファイルに`rate 16000`の設定記述を追記することで、『IOError: [Errno -9997] Invalid sample rate』エラーを解消することができました。お使いのマイクによって`rate 16000`ではなく`rate 48000`に設定することで改善することもあるようです。同じ症状でお困りの方はお試しあれ。

# 23. 補足：snowboyビルド版
- snowboyビルド版の記事も書こうかなといろいろ調べていると、すでに記事がでていましたのでご紹介します。各自の環境に合わせてメイクビルドされたい方はぜひご参照ください。
- 参考：[【RaspberryPi】Hot Word検出SnowboyでオリジナルのHot Wordを検知してみる（前編：設定）](https://uepon.hatenadiary.com/entry/2020/10/26/022159)
- 参考：[【RaspberryPi】Hot Word検出SnowboyでオリジナルのHot Wordを検知してみる（後編：オリジナルモデル作成）](https://uepon.hatenadiary.com/entry/2020/11/01/210915)

# 24. 追記：snowboyの自動起動設定ファイルの新規作成
- 手動でsnowboyを起動するのも面倒かと思いますので、systemdを利用した自動起動設定ファイルを新規作成します。
- ポイントとしては、User指定に/home/pi/.asoundrcファイルを保存した当該ユーザを指定することで、うまくマイク＆スピーカー認識を済ませることができるかと思います。

```plaintext:コマンドプロンプト
// 作業ディレクトリへ移動
$ cd

// 自動起動設定ファイルの新規作成
$ sudo vi snowboyd.service
````

```plaintext:/home/pi/snowboy/snowboyd.serviceファイル内容
[Unit]
Description=snowboy is executed and resides at OS startup.
After=multi-user.target

[Service]
Type=idle
User=pi
WorkingDirectory=/home/pi/snowboy
ExecStart=/usr/bin/python /home/pi/snowboy/demo.py /home/pi/snowboy/resources/konnitiwa.pmdl > /tmp/snowboyd.log 2>&1

[Install]
WantedBy=multi-user.target
````

# 25. 追記：snowboyd.serviceの起動確認＆自動起動有効化
- 作成した自動起動設定ファイルを所定のディレクトリに移動し、snowboyd.serviceの起動確認および有効化をおこないます。

```plaintext:コマンドプロンプト
// 自動起動設定ファイルを所定ディレクトリに移動
$ sudo mv snowboyd.service /etc/systemd/system/

// パーミッションの設定
$ sudo chmod 644 /etc/systemd/system/snowboyd.service

// systemctlのリロード（設定再読み込み）
$ sudo systemctl daemon-reload

// snowboyd.serviceの起動確認
$ sudo systemctl start snowboyd.service

// 起動状況確認（設定内容が正しいか動作確認します）
$ sudo systemctl status snowboyd.service

// snowboyd.serviceの自動起動有効化（再起動後に自動起動するようになります）
$ sudo systemctl enable snowboyd.service

// OS再起動
$ sudo shutdown -r now

// OS再起動後の実行ログ確認
$ tail -f /tmp/snowboyd.log
````
- 補足：snowboyd.serviceファイルの設定変更を反映する際は ``` sudo systemctl daemon-reload ``` コマンドを実行して反映する必要があります。
- 補足：systemdのバージョンによっては、ログ出力がされていないかもしれません、あしからず。

# 25. スピーカーテストコマンド
- スピーカーよりもマイクトラブルの方が多いかとは思いますが、以下のコマンドでスピーカーのテスト確認ができます、お試しあれ。

```plaintext:コマンドプロンプト
// 女性の声で「フロント、センター」と鳴ります
$ aplay /usr/share/sounds/alsa/Front_Center.wav

// ザー音が鳴ります（Ctrl+Cキーで停止）
$ speaker-test

// ピー音が鳴ります（Ctrl+Cキーで停止）
$ speaker-test -t sine -f 1000
```

# 26. マイク＆スピーカーテストコマンド
- マイクで録音した音を直接スピーカーから再生するテストコマンドです、お試しあれ。

```plaintext:コマンドプロンプト
// マイクで録音した音を直接スピーカーから再生される（やまびこエコーのように聞こえます）
$ arecord --format=S16_LE --rate=16000 | aplay --format=S16_LE --rate=16000
```

# 27. マイク感度の調整方法
- マイク感度（ゲイン調整）は、[こちら](http://marchan.e5.valueserver.jp/cabin/comp/jbox/arc300/doc3007.html#sect5)のサイトを参考に、以下のコマンドから調整可能できるかと思います。

```plaintext:コマンドプロンプト
// コマンド実行後、以下の手順でゲイン調整ができます
$ alsamixer

// F6:  Select sound card・・・対象マイクを選択します
// [Capture]を選択後、上下キー押下でゲイン調整ができます、1つだけ赤表示が飛び出るくらいでまずは試すとよいかもです
// Esc: Exit・・・終了します
```

# 27. おわりに
いかがでしたでしょうか？snowboyを用いたホットワード音声認識を体験できたのではないかなと思います。snowboyサイトにて自分の好きなホットワードを登録してみたり、demo.pyを自分なりにカスタマイズしてみるのも面白いかもしれません。
また、snowboyバイナリ版がRaspberry Pi 8.0でメイクビルドされていたようで、最新版のRaspberry Pi OSでの動作ではなく今回は2018-11-13-raspbian-stretch-lite.zipを用いました。最新のRaspberry Pi OSで試されたい方は、snowboyバイナリ版ではなく、[GitHub](https://github.com/kitt-ai/snowboy)に公開されているソースからのメイクビルドにぜひチャレンジしてください。
今回の記事が、みなさまの学習の参考になれば幸いです。

2020/11/08 TAKAHIRO NISHIZONO