きな粉もち.net

.NET関連仕事に携わっています。OSSのソースを読んで気がついたことを中心に呟いたりブログに投稿したりしています。最近はUiPathを使ったRPAも研究中。気軽にフォローやツッコミよろしくおねがいします! Gitはここを使っています https://github.com/kinakomotitti

音声認識(Speech Recognition) ×Speech Service × 比較してみた

この記事の目的

この記事では、
Microsoft.CognitiveServices.Speech.SpeechRecognizerとWindows.Media.SpeechRecognition.SpeechRecognizerの違いを探るために比較してみた実験をまとめること
を目的としています。
作成したアプリは、以下のURLで公開しています。
github.com


本題

Windows.Media.SpeechRecognition.SpeechRecognizerとは

以下のブログを参考にさせていただきました。
連続音声認識を使った音声入力のUWPサンプル – 高橋 忍のブログ

以下引用します。
=================

Windows 10 には Cortana がいます。Cortana は音声認識とAIと検索によって構成されているWindows 10 の機能の一つですが、この音声認識の部分は Windows 10 のOSからも提供されており、アプリケーションの中で単独で使うことが出来ます。
 
■UWPでの音声認識エンジン
この音声認識のためのAPIがSpeechRecognizer クラスです。
このSpeechRecognizer には2つの認識方法があって、1つは認識エンジンが起動し、認識し、終了するという1文ごとに使うものと、Cortana の待ち受けがそうであるように、話したことをずっと聞いていてその都度認識して結果を出すというもの。今回はこの連続認識(Constraint)の使い方の実装です。

=================
わかりやすい・・・!Windowsの機能の一部の音声認識ということですね(´▽`)それで、コルタナさんも同じエンジンを利用しているみたいです。

Microsoft.CognitiveServices.Speech.SpeechRecognizerとは

こちらは、Microsoftが提供しているCognitive Serviceの一つです。以下のMicrosoft Docを参考にしました。
Speech Service とは - Azure Cognitive Services | Microsoft Docs


こちらも一部引用します。
=================

他の Azure 音声サービスと同じように、Speech Service は、Cortana や Microsoft Office などの製品で使用されている音声認識テクノロジを利用しています。
Speech Service では、以前は Bing Speech API、Translator Speech、Custom Speech、および Custom Voice の各サービスで利用可能であった Azure 音声機能が統合されています。 現在は、1 つのサブスクリプションで、これらすべての機能にアクセスできます。

=================
Speech Serviceでもコルタナさんと同じ音声認識テクノロジを利用しているようです。ということは、どちらもあまり認識率に違いがないということでしょうか・・・素敵ですねMicrosoft

とはいえ、何かしらの違いがあるはず。ということで、以降では、それぞれの違いを比較するための簡単なUWPアプリを実装し、結果を比較していきます。

★実装のための下準備

ということで、2つの音声認識機能を実装するための環境を用意していきます。まず、新しいUWPアプリを作成します。
f:id:kinakomotitti:20181122220103p:plain
出来上がったプロジェクトは↓のようになります。
f:id:kinakomotitti:20181122220112p:plain

次に、Package.appxmanifestを開き機能の有効化をします。有効化する機能は「マイク」です。マイクは音声を入力するために利用します。
f:id:kinakomotitti:20181122220118p:plain

次に、認識結果を表示するための画面を作成します。テキストボックスを配置しただけの簡単な画面です。左が、Windowsの機能の音声認識結果を表示する場所で、反対が、Speech Serviceの結果を表示する場所です。
f:id:kinakomotitti:20181122220126p:plain

環境準備の最後に、MainPageのコードビハインドに実装を追加します。最終的に、OnNavigatedToイベントをオーバーロードして、以下の処理を追加しました。

        protected async override void OnNavigatedTo(NavigationEventArgs e)
        {
            //Windowsの音声認識機能を利用した音声認識機能の処理
            await this.WindowsSpeechRecognizerCore();

            //Cognitive Serviceを利用した音声認識機能の処理
            await this.MicrosoftSpeechRecofnizerCore();
        }

ここで呼び出しているそれぞれのメソッドは、次のセクションで紹介します。


★実装(Windows.Media編)

Windowsの機能の音声認識は以下のように実装しました。

        private win.SpeechRecognizer Recognizer { get; set; }

        private async Task WindowsSpeechRecognizerCore()
        {
            //Recognizerの作成
            this.Recognizer = new win.SpeechRecognizer();

            //継続して音声認識をするように設定。これがないと、一回きりの認識になる。
            await this.Recognizer.CompileConstraintsAsync();

            //音声認識中に発生する処理の登録
            this.Recognizer.HypothesisGenerated +=
                this.ContSpeechRecognizer_HypothesisGenerated;

            //音声認識処理が完了したときの処理の登録
            this.Recognizer.ContinuousRecognitionSession.ResultGenerated +=
                this.ContinuousRecognitionSession_ResultGenerated;

            //ここから音声認識を開始する
            this.WinTextBox.Text = "Start\r\n ";
            await this.Recognizer.ContinuousRecognitionSession.StartAsync();
        }

        #region 認識中イベント
        private async void ContSpeechRecognizer_HypothesisGenerated(
        win.SpeechRecognizer sender, win.SpeechRecognitionHypothesisGeneratedEventArgs args)
        {
            //認識途中に画面表示
            await this.WinOutput(args.Hypothesis.Text, true);
        }
        #endregion

        #region 認識完了後イベント

        private async void ContinuousRecognitionSession_ResultGenerated(
            win.SpeechContinuousRecognitionSession sender, win.SpeechContinuousRecognitionResultGeneratedEventArgs args)
        {
            await this.WinOutput(args.Result.Text, false);
        }

        #endregion

        #region private

        private async Task WinOutput(string text, bool isNotComplete)
        {
            await this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
            {
                var textlines = this.WinTextBox.Text.Split("\r\n");
                if (isNotComplete == false) textlines[textlines.Length - 1] = text + "\r\n ";
                else textlines[textlines.Length - 1] = text;

                this.WinTextBox.Text = string.Join("\r\n", textlines);
            });
        }

        #endregion


★実装(CognitiveService編)

SpeechServiceの実装は以下のようにしました。

Note:実装で必要となるので、あらかじめ、↓の案内に従い、SpeechServiceを有効化しておく必要があります。
docs.microsoft.com

private mic.SpeechRecognizer MicRecognizer;

        private async Task MicrosoftSpeechRecofnizerCore()
        {
            //Cognitive Serviceを使うための設定
            var config = mic.SpeechConfig.FromSubscription("Key1", "eastus(配置先のリージョン)");
            config.SpeechRecognitionLanguage = "ja-jp";

            //Recognizerのインスタンスを生成。↑の設定を反映させる
            this.MicRecognizer = new mic.SpeechRecognizer(config);

            //認識中、認識完了時の処理を登録
            this.MicRecognizer.Recognizing += Recognizer_Recognizing;
            this.MicRecognizer.Recognized += Recognizer_Recognized;

            //ここから音声認識処理を開始する
            this.MicTextBox.Text = "Start\r\n ";
            await this.MicRecognizer.StartContinuousRecognitionAsync();
        }

        #region 認識中イベント

        private async void Recognizer_Recognized(object sender, mic.SpeechRecognitionEventArgs e)
        {
            await this.MicOutput(e.Result.Text, false);
        }

        #endregion
        
        #region 認識完了後イベント

        private async void Recognizer_Recognizing(object sender, mic.SpeechRecognitionEventArgs e)
        {
            await this.MicOutput(e.Result.Text, true);
        }

        #endregion

        #region private

        private async Task MicOutput(string text, bool isNotComplete)
        {
            await this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
            {
                var textlines = this.MicTextBox.Text.Split("\r\n");
                if (isNotComplete == false) textlines[textlines.Length - 1] = text + "\r\n ";
                else textlines[textlines.Length - 1] = text;

                this.MicTextBox.Text = string.Join("\r\n", textlines);
            });
        }

        #endregion



★結果の比較と考察

試しに、以下の文章をできるだけ丁寧に読んだ結果をキャプチャします。
=================

この記事では、Cognitive Services Speech SDK を使用して C# のユニバーサル Windows プラットフォーム (UWP) アプリケーションを作成する方法について説明します。 デバイスのマイクからリアルタイムで音声をテキストに変換します。 このアプリケーションの構築には、Speech SDK NuGet パッケージと Microsoft Visual Studio 2017 (任意のエディション) を使用します。

=================

結果はこのようになりました。
Windowsの機能の音声認識← →Cognitive Serviceの音声認識
f:id:kinakomotitti:20181122220233p:plain
「スピーチ」と「Nugetパッケージ」と「任意の」が鬼門ですw活舌かな・・・(/ω\)
複数回実施してみましたが、だいたい平均的に上記のような結果になりました。
認識結果にはそんなに大きな違いはありませんでしたが、【認識判定処理の間隔】が少し違うなと感じました。
Windowsの機能の音声認識では、少しの時間間が開いただけで認識完了イベントが発火します。一方で、Cognitive Serviceの方は、文が区切られたタイミングでに認識処理が完了するような挙動をする気がしました。

認識結果以外では、音声認識機能のステータスの違いがありました。以下の例では、Windowsの機能の音声認識機能で、ステータスが変更されたときにその状態を表示するように変更した場合の例を示しています。
※「ここでアクティブウィンドウを・・・」のあと、Ctr+Altで別Windowに切り替え、またUWPに戻ってきたときの実験結果です。
f:id:kinakomotitti:20181122220244p:plain

このように、UWPの仕様上、アクティブWindowではなくなったとき、音声認識機能もIdle状態になります。こうなったら、Idle状態から復帰させる処理を実装しないと、ずっとIdle状態のままとなります。一方、Cognitive Serviceの方では、別Windowから戻ってきた後も音声認識を続けることができました。※「元に戻しました」の音声がそれにあたります。



まとめ

どちらが優れている。というものでもないので、適材適所で使い分けていきたいです(´▽`)