読者です 読者をやめる 読者になる 読者になる

ブログ

ブログです

ただいまシステムの中身① Raspberry Piで音声認識

まず前回のおさらい。↓みたいなシステムを作った。
f:id:hira-hide:20170416211614p:plain
外観写真で説明すると、USBマイクで音声命令を拾って、それをRaspberry Piで認識して、しかるべき制御をサーボモータに送るっていう流れになる。
f:id:hira-hide:20170422162903j:plain
今回は最初の音声認識部分について書いていくゾ。手順としては、まず音声入力デバイスの優先度を変更して、Juliusっていう音声認識ソフトのセットアップをするだけ。

参考ページ

音声認識を行う上で以下のWebページを参考にさせてもらった。
qiita.com
blog.livedoor.jp
blog.livedoor.jp

USBマイクのセットアップ

事前準備

USBマイクを使えるようにするために、まずはパッケージのアップデートと各種ドライバ・ソフトウェアのインストール、マイクの動作設定とかをやってくよ。

とりあえずパッケージのアップデートから

パッケージアップデート
$ sudo apt-get update
$ sudo apt-get upgrade
$ sudo rpi-update

アップデートが終わったらライブラリのインストール

ライブラリインストール
$ sudo apt-get install alsa-utils sox libsox-fmt-all

ちなみに、ALSA (Advanced Linux Sound Architecture)はLinux用音声ドライバ、soxは音声ファイル形式変換ソフトらしい(上記リンク先のコマンドそのまま打っただけ)

さて、ここまでやったらとりあえずUSBポートにマイクを差して、まずはちゃんとハードウェアが認識されているかのチェック。

ハードウェア認識チェック
$ lsusb
Bus 001 Device 004: ID 0d8c:0016 C-Media Electronics, Inc.
Bus 001 Device 003: ID 0424:ec00 Standard Microsystems Corp. SMSC9512/9514 Fast Ethernet Adapter
Bus 001 Device 002: ID 0424:9514 Standard Microsystems Corp.
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub

C-Media Electronics, Inc.がUSBマイクらしいから、これが表示されてれば認識はOK

オーディオモジュールの優先順位変更

おそらく初期設定だと内蔵オーディオモジュールの優先順位のほうが高いはずなので、/proc/asound/modules を見て確認。

モジュール優先度チェック
$ cat /proc/asound/modules
 0 snd_bcm2835
 1 snd_usb_audio

↑みたいに snd_bcm2835(内蔵オーディオモジュール)が0番だったら、/etc/modprobe.d/alsa-base.conf を変更してUSBマイクの優先順位を変えよう。
この設定ファイルが生成されていないこともあるから、そのときは新規作成

alsa-base.conf の変更(or新規作成)
options snd slots=snd_usb_audio,snd_bcm2835
options snd_usb_audio index=0
options snd_bcm2835 index=1

これでRebootすれば優先順位が入れ替わってるはず。

マイク感度設定

音声入力するにあたって、マイク感度を適当に調節しとかないといけないから、それの設定。と、その前にサウンドカードの番号をチェック!

サウンドカード番号チェック
$ arecord -l
**** List of CAPTURE Hardware Devices ****
card 0: Micophone [USB Micophone], device 0: USB Audio [USB Audio]
  Subdevices: 0/1
  Subdevice #0: subdevice #0

card 0 と書いてあればサウンドカード番号は0番だから、感度設定の引数で0を設定

マイク感度設定
$ amixer sset Mic 62 -c 0
Simple mixer control 'Mic',0
  Capabilities: cvolume cvolume-joined cswitch cswitch-joined penum
  Capture channels: Mono
  Limits: Capture 0 - 62
  Mono: Capture 62 [100%] [22.50dB] [on]

マイク感度は0 - 62の63段階で選ぶようになってるけど、まーたぶん最大値で設定して問題ないと思う(ぼくは今のところ問題ない)。

これでUSBマイクは使える状態になったから、こっから音声認識ソフトの設定をやってくよ。

Juliusのインストールと設定

そもそもこのJuliusっていうソフトは何なのかっつーことだけど、公式サイトからまんま引用した以下の文章を読んでくれ。

Julius は,音声認識システムの開発・研究のためのオープンソースの高性能な汎用大語彙連続音声認識エンジンです. 数万語彙の連続音声認識を一般のPCやスマートフォン上でほぼ実時間で実行できる軽量さとコンパクトさを持っています.

言語モデルとして単語N-gram,記述文法,ならびに単語辞書を用いることができます.また音響モデルとしてトライフォンのGMM-HMMおよびDNN-HMMを用いたリアルタイム認識を行うことができます.DNN-HMMの出力計算にnumpyを用いた外部モジュールを利用することも可能です.複数のモデルや複数の文法を並列で用いた同時認識も行うことができます.

Juliusの最大の特徴はその可搬性にあります.単語辞書や言語モデル・音響モデルなどの音声認識の各モジュールを組み替えることで,小語彙の音声対話システムからディクテーションまで様々な幅広い用途に応用できます.

Julius はオープンソースソフトウェアです.プログラムはC言語で書かれており、さまざまなプラットフォームへの移植や改造が容易です.ライセンスはオープンライセンスで,商用利用への制限もありません.

http://julius.osdn.jp/

細かい話は専門家じゃないからよく分からんけど、動きは下の画像のような感じ。
f:id:hira-hide:20170422204747p:plain
音声入力を文字データにして、あらかじめ用意してある辞書データと比較して合致するものを探すみたい。
wgetJulius本体ディクテーションキット文法認識キットの3つをインストール。バージョンは適宜変えてくれ。あとディクテーションキットは容量がデカイから時間かかるかも。

Julius本体、ディクテーションキット、文法認識キットのダウンロードとインストール
sudo wget -O julius-4.4.2.tar.gz 'http://sourceforge.jp/frs/redir.php?m=osdn&f=%2Fjulius%2F60273%2Fjulius-4.3.1.tar.gz'
sudo wget -O dictation-kit-v4.3.1-linux.tgz 'http://sourceforge.jp/frs/redir.php?m=jaist&f=%2Fjulius%2F60416%2Fdictation-kit-v4.3.1-linux.tgz'
sudo wget -O grammar-kit-v4.1.tar.gz 'http://sourceforge.jp/frs/redir.php?m=osdn&f=%2Fjulius%2F51159%2Fgrammar-kit-v4.1.tar.gz'

tar zxvf julius-4.4.2.tar.gz
cd julius-4.4.2/
./configure
make
sudo make install

cd ..
tar zxvf dictation-kit-v4.3.1-linux.tgz
tar zxvf grammar-kit-v4.1.tar.gz

これでとりあえず使えるようにはなってるから、テストしてみよう。

話しかけてみよう!

あらかじめ用意されてるグラマーキット testmic.jconf を使ってきちんと認識するかどうかのテスト。julius -C ./grammar-kit-v4.1/testmic.jconf -charconv EUC-JP UTF-8 を実行すると音声認識スタンバイ状態になるから、話しかけると「あんたが今言ったのこれやな!」って返してくれるよ。
ちなみに、このテスト設定だと「みかん・りんご・ぶどう」の3つの果物について反応するから、適当に「みかん!」とか「りんご!」とか言ってみてね。

Julius動作テスト
julius -C ./grammar-kit-v4.1/testmic.jconf -charconv EUC-JP UTF-8

Notice for feature extraction (01),
        *************************************************************
        * Cepstral mean normalization for real-time decoding:       *
        * NOTICE: The first input may not be recognized, since      *
        *         no initial mean is available on startup.          *
        *************************************************************
 
Stat: adin_oss: device name = /dev/dsp (application default)
Stat: adin_oss: sampling rate = 16000Hz
Stat: adin_oss: going to set latency to 50 msec
Stat: adin_oss: audio I/O Latency = 32 msec (fragment size = 512 samples)
STAT: AD-in thread created

この状態の時に話しかければOK。ちゃんと結果が返ってきたら設定とかは問題なし。

辞書データ作成

ここまで来たらあとは自分の用途に合わせて辞書データを作成してあげればOK。認識結果はsocketを介してxmlで渡せるから、それを使って後段のサーボモータ制御をやっていく流れ。
辞書ファイルは
(単語)(タブ区切り)(読み)
の形で記述して、拡張子は.yomiとして保存すること。今回の目的は「ただいま」に反応して動作してくれればいいから基本的には「ただいま」だけ辞書登録しとけば良いんだけど、どうせならいろいろやりたいな、と思って以下のような辞書データを作った。

ただいま    ただいま
おやすみ    おやすみ
部屋つけて   へやつけて
部屋消して   へやけして
廊下つけて   ろうかつけて
廊下消して   ろうかけして
おはよう    おはよう
いってきます  いってきます
パキン     ぱきん

機能としては、

ただいま   → 部屋も廊下もつく
おやすみ   → 部屋も廊下も消える
部屋つけて  → 部屋の電気がつく
部屋消して  → 部屋の電気が消える
廊下つけて  → 廊下の電気がつく
廊下消して  → 廊下の電気が消える
おはよう   → 部屋の電気がつく
いってきます → 部屋も廊下も消える
パキン    → 部屋も廊下もつく

ってなってる。パキンってなんだよパキンってと思うかもしれないけど、これは指パッチンで部屋の電気ついたらクソおもしれぇなと思ってあとから追加した辞書データ。ちなみに動きはこんな感じ。


超おもしろかった。その代わり判定しきい値をかなり高くしてるからめったに動作しない。隠しコマンド的立ち位置。

それはさておき、辞書データを作ったらJulius用の辞書形式ファイルに変換する。
あ、ルートディレクトリは基本的に home を考えて書いてるから、適宜読み替えてください。

辞書データ変換
cd julius-4.4.2/gramtools/yomi2voca
iconv -f utf8 -t eucjp ~/word.yomi | yomi2voca.pl > ~/dictation-kit-v4.3.1-linux/word.dic

そしたら最後に設定データを作成すれば音声認識基盤の完成!

$ vi ./dictation-kit-v4.3.1-linux/word.jconf

-w word.dic       #単語辞書ファイル
-v model/lang_m/bccwj.60k.htkdic  #N-gram、または文法用の単語辞書ファイルを指定
-h model/phone_m/jnas-tri-3k16-gid.binhmm #使用するHMM定義ファイル
-hlist model/phone_m/logicalTri   #HMMlistファイルを指定する
-n 5        #n個の文仮説数が見つかるまで検索を行う
-output 1     #見つかったN-best候補のうち、結果として出力する個数
-input mic      #マイク使用
-input oss      #オープンサウンドシステム使用
-rejectshort 600  #検出された入力が閾値以下なら棄却
-charconv euc-jp utf8 #入出力エンコード指定(内部euc-jp, 出力utf-8)
-lv 1000    #入力の振幅レベルの閾値(0~32767)

これで julius -C ./dictation-kit-v4.3.1-linux/word.jconf を実行すれば上で作った辞書データを元に音声認識してくれる。

認識結果の受け渡しとそれを利用したサーボ制御については次回。