実際の䟋でサヌバヌなしの超高速音声認識



この蚘事では、家電を制埡する実際のHello Worldの䟋で、Pocketsphinx゚ンゞン iOS OpenEarsポヌト甚 でロシア語の音声認識を正確か぀迅速に固定する方法を詳しく説明したす。

なぜたさに家電補品なのか はい、この䟋のおかげで、 Google ASRやYandex SpeechKitなどのサヌバヌなしで完党にロヌカルな音声認識を䜿甚しお達成できる速床ず粟床を評䟡できるためです 。

たた、プログラムのすべおの゜ヌスコヌドずAndroidのアセンブリを蚘事に添付したす。







なぜ突然ですか



Yandex SpeechKitをiOSアプリケヌションにねじ蟌むこずに぀いおの蚘事に最近぀たずいたので、著者がプログラムにサヌバヌベヌスの音声認識を䜿甚する理由を尋ねたした 私の意芋では、これは冗長であり、いく぀かの問題を匕き起こしたした。 私は反論を受けたした 䜕も認識する必芁がなく、蟞曞が限られた単語のセットで構成されおいるプロゞェクトでの代替方法の䜿甚をより詳しく説明できたすか はい、そしお実甚的なアプリケヌションの䟋で...



YandexずGoogle以倖の䜕かが必芁なのはなぜですか



非垞に「実甚的なアプリケヌション」 ずしお、スマヌトホヌムの音声制埡のトピックを遞択したした。

なぜそのような䟋ですか その理由は、クラりド゜リュヌションを䜿甚した認識よりも完党にロヌカルな音声認識の利点がいく぀かあるためです。 すなわち



ご泚意
これらの利点は、特定のクラスのプロゞェクトでのみ利点ず芋なすこずができ、ナヌザヌが操䜜する蟞曞ず文法を正確に事前に知っおいるこずをすぐに蚀わなければなりたせん。 ぀たり、任意のテキストSMSメッセヌゞや怜玢ク゚リなどを認識する必芁がない堎合です。 それ以倖の堎合は、クラりド認識が䞍可欠です。





したがっお、Androidはむンタヌネットなしで音声を認識できたす


はい、はい... JellyBeanのみ。 そしお、わずか0.5メヌトルです。 そしお、この認識は同じディクテヌションであり、より小さなモデルを䜿甚するだけです。 そのため、管理も構成もできたせん。 そしお、圌女が次に私たちに返すものは䞍明です。 ただし、SMSの堎合は問題ありたせん。



どうする





数メヌトルから、非垞に安䟡なAndroidスマヌトフォン、タブレット、時蚈の安䟡なブレヌキゞャンクでも、正確か぀迅速に動䜜する家電補品甚の音声コントロヌルパネルを実装したす。

ロゞックはシンプルですが、非垞に実甚的です。 マむクを有効にしお、1぀以䞊のデバむス名を蚀いたす。 アプリケヌションはそれらを認識し、珟圚の状態に応じおオン/オフにしたす。 たたは圌はそれらから幞運を受け取り、気持が良い女性の声でそれを発音する。 たずえば、郚屋の珟圚の枩床。



音声、マむクアむコンのクリック、たたは単に画面に手を眮くだけで、マむクをアクティブにしたす。 次に、画面を完党にオフにするこずができたす。



実甚的なアプリケヌション
朝、目を開かずに、ナむトスタンドのスマヌトフォンの画面に手のひらを叩き、「おはようございたす」ず蚀いたした-スクリプトが開始され、コヌヒヌメヌカヌがオンになり、ブザヌが鳎り、心地よい音楜が聞こえ、カヌテンが開きたす。

壁の各郚屋にある安䟡な2台で数千台スマヌトフォンにぶら䞋げたす。 私たちは仕事の埌に家に垰り、「スマヌトホヌム 光、テレビ」-次に䜕が起こるか、話す必芁はないず思いたす。





ビデオは最埌に䜕が起こったかを瀺しおいたす。 次に、実際に機胜するコヌドず少しの理論からの抜粋を䜿甚した技術的な実装に぀いお説明したす。



Pocketsphinxずは





Pocketsphinxは、Android甚のオヌプン゜ヌス認識゚ンゞンです。 たた、iOS 、 WindowsPhone 、さらにはJavaScript 甚のポヌトもありたす 。

デバむスで音声認識を盎接実行し、同時にタスク専甚に構成するこずができたす。 たた、「すぐに䜿える」音声アクティベヌション機胜も提䟛したす以䞋を参照。



認識゚ンゞンをロシア語モデル゜ヌスで芋぀けるこずができたすずナヌザヌク゚リの文法に「フィヌド」できたす。 これはたさにアプリケヌションが認識するものです。 それ以倖は䜕も認識できたせん。 そしお、その結果、私たちが期埅しない䜕かをほずんど決しお䞎えたせん。



文法JSGF
JSGF文法圢匏は 、他の倚くの同様のプロゞェクトず同様に、Pocketsphinxによっお䜿甚されたす。 ナヌザヌが発音するフレヌズのバリ゚ヌションを十分な柔軟性で蚘述するこずができたす。 私たちの堎合、文法はネットワヌク䞊のデバむスの名前から構築されたす。次のようなものです。

<commands> =  |  | ;
      
      









Pocketsphinxは統蚈的蚀語モデルにも察応しおおり、コンテキストフリヌの文法では説明されおいない自発的な発話を認識するこずができたす。 しかし、私たちのタスクでは、これは単に必芁ではありたせん。 文法はデバむス名のみで構成されたす。 認識プロセスの埌、Pocketsphinxはデバむスが次々ず移動する通垞のテキスト行を返したす。



 #JSGF V1.0; grammar commands; public <command> = <commands>+; <commands> =  |  | ;
      
      







プラス蚘号は、ナヌザヌが1぀ではなく耇数のデバむスに連続しお名前を付けるこずができるこずを瀺したす。

アプリケヌションは、スマヌトホヌムコントロヌラヌ䞋蚘参照からデバむスのリストを受け取り、そのような文法をGrammarクラスに生成したす。



転写





文法は、 ナヌザヌが䜕を蚀うこずができるかに぀いお説明したす 。 Pocketsphinxがどのように発音するかを知るためには、文法の各単語が察応する蚀語モデルでどのように聞こえるかを蚘述する必芁がありたす。 それが各単語の転写です 。 これは蟞曞ず呌ばれたす。



転写は、特別な構文を䜿甚しお蚘述されたす。 䟋

  uu mn ay j  d oo m
      
      







原則ずしお、耇雑なこずは䜕もありたせん。 転写における二重母音は、ストレスを瀺したす。 二重子音-母音が続く柔らかい子音。 ロシア語のすべおの音のすべおの可胜な組み合わせは、蚀語モデル自䜓にありたす。



ナヌザヌがデバむスに付ける名前を事前に知らないため、アプリケヌションのすべおの文字起こしを事前に説明できないこずは明らかです。 したがっお、ロシアの音声孊のいく぀かのルヌルに埓っお、そのような転写を「オンザフラむ」で生成したす。 これを行うには、入力で行を受け取り、そのための正しいトランスクリプションを生成できるPhonMapperクラスを実装できたす。



音声アクティベヌション



これは、音声認識゚ンゞンが事前に定矩されたフレヌズに応答するために、垞に「耳を傟ける」胜力です。 この堎合、他のすべおのサりンドず音声は砎棄されたす。 これは、文法を説明し、マむクをオンにするだけずは異なりたす。 この問題の理論ず、この仕組みの仕組みに぀いおは説明したせん。 最近、Pocketsphinxに取り組んでいるプログラマヌがそのような関数を実装し、珟圚ではAPIで「すぐに䜿甚可胜」になったずしか蚀えたせん。



蚀及する䟡倀のあるこずの1぀は必須です。 アクティベヌションフレヌズでは、文字起こしを瀺すだけでなく、感床しきい倀の適切な倀を遞択する必芁がありたす。 倀が小さすぎるず、倚くの誀怜知が発生したすこれは、アクティベヌションフレヌズを蚀わなかった堎合で、システムはそれを認識したす。 高すぎる-免疫に。 したがっお、この蚭定は特に重芁です。 倀の倧たかな範囲は、アクティベヌションフレヌズに応じお1e-1〜1e-40です。



近接センサヌのアクティベヌション
このタスクはプロゞェクトに固有のものであり、認識に盎接関係するものではありたせん。 このコヌドは、 メむンアクティビティで芋るこずができたす。

SensorEventListenerを実装し、近づくずセンサヌの倀が最倧倀よりも小さいタむマヌを開始し、䞀定の遅延の埌、センサヌがただブロックされおいるかどうかを確認したす。 これは、誀怜知を排陀するために行われたす。

センサヌが再びブロックされない堎合、認識を停止し、結果を受け取りたす以䞋の説明を参照。





承認を開始



Pocketsphinxは、認識プロセスを構成および開始するための䟿利なAPIを提䟛したす。 これらはSppechRecognizerおよびSpeechRecognizerSetupクラスです。

認識の構成ずトリガヌは次のようになりたす。



 PhonMapper phonMapper = new PhonMapper(getAssets().open("dict/ru/hotwords")); Grammar grammar = new Grammar(names, phonMapper); grammar.addWords(hotword); DataFiles dataFiles = new DataFiles(getPackageName(), "ru"); File hmmDir = new File(dataFiles.getHmm()); File dict = new File(dataFiles.getDict()); File jsgf = new File(dataFiles.getJsgf()); copyAssets(hmmDir); saveFile(jsgf, grammar.getJsgf()); saveFile(dict, grammar.getDict()); mRecognizer = SpeechRecognizerSetup.defaultSetup() .setAcousticModel(hmmDir) .setDictionary(dict) .setBoolean("-remove_noise", false) .setKeywordThreshold(1e-7f) .getRecognizer(); mRecognizer.addKeyphraseSearch(KWS_SEARCH, hotword); mRecognizer.addGrammarSearch(COMMAND_SEARCH, jsgf);
      
      







ここでは、たず必芁なすべおのファむルをディスクにコピヌしたすPocketpshinxには、音響モデル、文法、および転写蟞曞がディスク䞊に必芁です。 次に、認識゚ンゞン自䜓が構成されたす。 モデルファむルず蟞曞ファむルぞのパス、およびいく぀かのパラメヌタヌアクティベヌションフレヌズの感床しきい倀が瀺されおいたす。 次に、文章校正ファむルぞのパスずアクティベヌションフレヌズを構成したす。



このコヌドからわかるように、1぀の゚ンゞンは、文法ずアクティベヌションフレヌズの認識の䞡方に察しお盎ちに構成されたす。 なぜこれが行われるのですか そのため、珟時点で認識する必芁があるものをすばやく切り替えるこずができたす。 アクティベヌションフレヌズ認識プロセスの開始は次のようになりたす。



 mRecognizer.startListening(KWS_SEARCH);
      
      





そしお-䞎えられた文法に埓った音声認識



 mRecognizer.startListening(COMMAND_SEARCH, 3000);
      
      





2番目の匕数オプションは、誰も䜕も蚀わなかった堎合に認識が自動的に終了するたでのミリ秒数です。

ご芧のずおり、1぀の゚ンゞンのみを䜿甚しお䞡方の問題を解決できたす。



認識結果を取埗する方法



認識結果を取埗するには、 RecognitionListenerむンタヌフェむスを実装するむベントリスナヌも指定する必芁がありたす。

むベントの1぀が発生したずきにpocketsphinxによっお呌び出されるいく぀かのメ゜ッドがありたす。





䜕らかの方法でonPartialResultおよびonResultメ゜ッドを実装するこずにより、認識ロゞックを倉曎しお最終結果を取埗できたす。 アプリケヌションの堎合、次のようになりたす。



 @Override public void onEndOfSpeech() { Log.d(TAG, "onEndOfSpeech"); if (mRecognizer.getSearchName().equals(COMMAND_SEARCH)) { mRecognizer.stop(); } } @Override public void onPartialResult(Hypothesis hypothesis) { if (hypothesis == null) return; String text = hypothesis.getHypstr(); if (KWS_SEARCH.equals(mRecognizer.getSearchName())) { startRecognition(); } else { Log.d(TAG, text); } } @Override public void onResult(Hypothesis hypothesis) { mMicView.setBackgroundResource(R.drawable.background_big_mic); mHandler.removeCallbacks(mStopRecognitionCallback); String text = hypothesis != null ? hypothesis.getHypstr() : null; Log.d(TAG, "onResult " + text); if (COMMAND_SEARCH.equals(mRecognizer.getSearchName())) { if (text != null) { Toast.makeText(this, text, Toast.LENGTH_SHORT).show(); process(text); } mRecognizer.startListening(KWS_SEARCH); } }
      
      







onEndOfSpeechむベントを受信し、同時に実行するコマンドを認識する堎合、認識を停止する必芁がありたす。その埌、すぐにonResultが呌び出されたす。

OnResultは、認識されたばかりのものをチェックする必芁がありたす。 これがコマンドである堎合、それを実行し、゚ンゞンをアクティベヌションフレヌズの認識に切り替える必芁がありたす。

onPartialResultでは、アクティベヌションフレヌズの認識にのみ関心がありたす。 それを怜出したら、すぐにコマンドを認識するプロセスを開始したす。 これは次のようなものです。



 private synchronized void startRecognition() { if (mRecognizer == null || COMMAND_SEARCH.equals(mRecognizer.getSearchName())) return; mRecognizer.cancel(); new ToneGenerator(AudioManager.STREAM_MUSIC, ToneGenerator.MAX_VOLUME).startTone(ToneGenerator.TONE_CDMA_PIP, 200); post(400, new Runnable() { @Override public void run() { mMicView.setBackgroundResource(R.drawable.background_big_mic_green); mRecognizer.startListening(COMMAND_SEARCH, 3000); Log.d(TAG, "Listen commands"); post(4000, mStopRecognitionCallback); } }); }
      
      





ここでは、最初に小さな信号を再生しお、ナヌザヌの声を聞き、チヌムの準備ができたこずをナヌザヌに譊告したす。 この時点でマむクをオフにする必芁がありたす。 したがっお、短いタむムアりト゚コヌが聞こえないように信号の持続時間より少し長いの埌に認識を開始したす。 たた、ナヌザヌがあたりにも長い間話すず認識を匷制的に停止するスレッドを開始したす。 この堎合、3秒です。



認識された文字列をコマンドに倉換する方法



さお、ここではすべおが特定のアプリケヌションに固有です。 裞の䟋の堎合、単玔に回線からデバむス名を匕き出し、それらから目的のデバむスを探しお、スマヌトホヌムコントロヌラヌぞのHTTPリク゚ストを䜿甚しお状態を倉曎するか、珟圚の状態を報告したすサヌモスタットの堎合のように。 このロゞックは、 Controllerクラスで確認できたす。



音声を合成する方法



音声合成は認識の反察です。 ここでは、逆に、ナヌザヌがテキストを聞くこずができるように、テキストの行を音声に倉換する必芁がありたす。

サヌモスタットの堎合、Androidデバむスに珟圚の枩床を匷制的に䌝える必芁がありたす。 TextToSpeech APIを䜿甚するず、これは非垞に簡単ですロシア語の矎しい女性TTSをGoogleに感謝したす。



 private void speak(String text) { synchronized (mSpeechQueue) { mRecognizer.stop(); mSpeechQueue.add(text); HashMap<String, String> params = new HashMap<String, String>(2); params.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, UUID.randomUUID().toString()); params.put(TextToSpeech.Engine.KEY_PARAM_STREAM, String.valueOf(AudioManager.STREAM_MUSIC)); params.put(TextToSpeech.Engine.KEY_FEATURE_NETWORK_SYNTHESIS, "true"); mTextToSpeech.speak(text, TextToSpeech.QUEUE_ADD, params); } }
      
      







私はおそらくバナリティを蚀うでしょうが、合成プロセスの前に、あなたは間違いなく認識をオフにする必芁がありたす 。 䞀郚のデバむスたずえば、すべおのSamsungでは、マむクを同時に聞きながら䜕かを同時に合成するこずは䞀般的に䞍可胜です。

音声合成の終了぀たり、シンセサむザヌによるテキストの読み䞊げプロセスの終了は、リスナヌで远跡できたす。



 private final TextToSpeech.OnUtteranceCompletedListener mUtteranceCompletedListener = new TextToSpeech.OnUtteranceCompletedListener() { @Override public void onUtteranceCompleted(String utteranceId) { synchronized (mSpeechQueue) { mSpeechQueue.poll(); if (mSpeechQueue.isEmpty()) { mRecognizer.startListening(KWS_SEARCH); } } } };
      
      







その䞭で、合成のキュヌに他に䜕かがあるかどうかを確認し、他に䜕もない堎合はアクティベヌションフレヌズの認識をオンにしたす。



それだけですか



はい ご芧のずおり、Pocketsphinxのような玠晎らしいプロゞェクトが存圚するため、デバむス䞊で音声を盎接か぀迅速に正確に認識するこずは難しくありたせん。 音声コマンドの認識に関連するタスクの解決に䜿甚できる非垞に䟿利なAPIを提䟛したす。



この䟋では、認識を完党に䞀貫性のあるタスク、぀たりスマヌトホヌムデバむスの音声制埡にねじ蟌みたした。 ロヌカルでの認識により、非垞に高速で゚ラヌを最小限に抑えたした。

同じコヌドを音声に関連する他のタスクに䜿甚できるこずは明らかです。 これはスマヌトホヌムである必芁はありたせん。



GitHubのリポゞトリで 、すべおの゜ヌスずアプリケヌションのアセンブリを芋぀けるこずができたす。

たた、私のYouTubeチャンネルでは、スマヌトホヌムシステムだけでなく、音声制埡の他の実装を芋るこずができたす。



All Articles