Tryswift marc brown facebook

ウソだと言ってくれよ: アプリにおける音声認識の実装

今年のWWDCでは、SiriKitが主要な機能として大きく取り上げられました。しかし残念ながら、最初のリリースでは特定の少しのユースケースでしか使えないように制限されています。しかし、諦めてはいけません!AppleはiOS 10で汎用のSpeech APIを発表しました。これにより、50以上の言語でストリーミング音声やオーディオファイルから簡単に音声からテキストへの変換が行えます。このtry! Swiftの講演では、Marc Brownは新しいSpeech APIの紹介と、その限界について説明し、テキストベースの検索アプリに音声認識を追加するという実用的な使用例を示します。


イントロダクション (0:00)

私はBlue Apronでモバイルチームのマネジメントをしています。我々のミッションは、誰もが信じられないほど、家庭で料理ができるようにすることです。我々のモバイルチームは100% Swiftで書いています。また、私はBrooklyn Swift Developers meetupを主催しています。今日は、アプリで音声認識を実装する話をします

音声認識の歴史 (1:03)

  • 1952年、Bell Labsが最初の音声認識デバイスを作成しましたが、番号しか認識できませんでした。
  • 1950年代後半、10単語まで認識可能になりましたが、1人の発話のみで、訓練をうけた人だけが使えるものでした。
  • 60年代、ソビエト連邦の研究者たちがDynamic time warping algorithmを開発し、異なるスピードの会話の中で、同じ単語を発見しやすくしました。Dynamic time warpingによって、認識できる単語数が200語と、飛躍的に増加しました。
  • 70年代、DARPAはSpeech Understanding Research Programに資金提供しました。Speech Understanding Research Programは、1000語(3歳の語彙)の認識が可能なシステムを作り上げることを目標とした5年間のイニシアチブです。 Carnegie Mellonのグループが、1976年にビーム走査を使用してこれを達成しました。
  • 80年代には大きく進歩しました。そのうちの1つはIBMのTangoraという音声認識タイプライターです。語彙は2万語で、音声認識における隠れマルコフモデルの初めての実用例でもあります。
  • 90年代、システムの語彙は普通の成人よりも増えました。他のブレークスルーとして、
    • 継続的な音声認識:1単語ごとに一時停止するのではなく、より会話らしくなりました。
    • スピーカーの独立:ある人が訓練を受けると、他の人も最小限のボイスオンボードによって、使うことができます。Dragon社が作った”NaturallySpeaking”というプログラムによって、音声認識製品のビジネスへの道が開かれました。
  • 2000年代初頭、音声認識は約80%まで上昇しました(5単語のうち1単語を自動訂正する必要があることに気づくまでは高く聞こえます)。LSTM (Long short-term memory)の最初の導入事例で、音声認識に適応されたディープラーニングの手法としては初めてのものとなりました。
  • 2007年まで、LSTMは従来のどの方法よりも優れていました。スマートフォンの登場により、2007年も成功した年となりました。 新たに利用できるようになった、Google 音声検索や後のSiriは、モデルを訓練するための膨大な量のデータを取得することができました。現在のところ、正答率は90%に近づいています。

WWDC 2016: SiriKitの紹介 (5:00)

今年のWWDCを簡単にまとめます。AppleはSiriを(長年待ちわびていた)サードパーティの開発者に開放しました。

記事の更新情報を受け取る

どんな影響があるかを把握するために、Weezer Payという今ホットで新しいスタートアップで働いたとしましょう。これは、Weezerのバンドメンバーとお金をやりとりできます。ニッチな市場ですが、非常に手堅いです。SiriKitをサポートした場合、「Hey Siri、Blue Albumを録音するためにWeezer PayでRivers Cuomoに5ドルを送ってください」といったようなことができます。SiriKitはそれを解析します。それは、ドメインが「支払い」であり、その意図が実際に支払いを送ることであると判断することができます。そこから、Weezer Payアプリを使用したいと考えているので、支払い対象の詳細(受取人、送信したい金額、送信する理由など)をさらに詳しく調べます。

最初にサポートされたドメインのリストを除けば、これは素晴らしいことです。Slack、Uber、あるいはWeezer Payで働いていてもそうでしょう。でも、他の人にとってはそうでもないですね。

しかし、救いとなるのが、WWDCでSpeech APIが紹介されたことです。

Speech Framework (7:21)

Speech FrameworkはSiriと同じ音声技術が使われています。マイク用のライブストリームのライブオーディオを使用することも、ディスクからあらかじめ録音したファイルをプルすることもできます。推奨される転写を返すだけでなく、代替転写の配列とそれに関連する信頼値も返します。 50以上の言語と方言をサポートしています。

Info.plist (7:57)

iOS 10の登場で、他のサービスにアクセスする理由を説明することが必須となりました。例えば、位置情報や、プッシュ通知です。Speech Frameworkを使うために、音声認識とマイクの2つのサービスへのアクセスが必要です。Info.plistNSSpeechRecognitionUsageDescriptionNSMicrophoneUsageDescriptionを追加してください。

Speechのインポート (8:26)

次にSpeechをインポートします。これで楽しいAPIが使えるようになります。

Speech Recognizer (8:55)

// Specific language
private let speechRecognizer = SFSpeechRecognizer(locale: Locale(identifier: "en-US"))

// Native language
private let speechRecognizer = SFSpeechRecognizer(locale: Locale.current)

Speech RecognizerはLocaleを指定できます。(US English)などの特定の言語を指定するか、ユーザの現在のLocaleを使用できます。

Speech APIがこれらの異なるLocaleをサポートしているか気になるかもしれませんが、合計58のLocaleがあり、おそらくカバーされています。ユーザの使う言語でつながることができるのはすごいことです。

Request Authorization (9:21)

SFSpeechRecognizer.requestAuthorization { authStatus in
    OperationQueue.main.addOperation {

        switch authStatus {
            case .authorized:

            case .denied:

            case .restricted:

            case .notDetermined:
        }
    }
}

ユーザが最初のリクエストを開始するとき、音声認識とマイクの両方へのアクセスが求められるは、ユーザが最初のリクエストを開始したときです。アプリ起動時にそれを行うのは適していません。彼らがマイクボタンを押して話す準備ができたときに、アクセス許可を求めるべきです。

ライブのSpeech to Textクエリを構築しましょう。

Recognition Request (9:52)

recognitionRequest は音声ソースを定義します。

private var recognitionRequest: SFSpeechAudioBufferRecognitionRequest?

...

recognitionRequest = SFSpeechAudioBufferRecognitionRequest()

recognitionRequest.shouldReportPartialResults = true

ここに、ライブと録音の違いがあります。ライブストリームを行うときは、SFSpeechAudioBufferRecognitionRequest()を使います。ディスクのファイルを参照するときは、 SFSpeechURLRecognitionRequest()を使います。プロセッシングの間にクエリを表示するときは、shouldReportPartialResultsをtrueにしてください。ユーザが長い文章をしゃべったり、すぐにフィードバックを表示したいときに有効です。

Recognition Task (10:31)

recognitionTaskrecognitionRequestの結果を処理します。

private var recognitionTask: SFSpeechRecognitionTask?

...

recognitionTask = speechRecognizer?.recognitionTask(with: recognitionRequest) {
    result, error in
    var isFinal = false

    if let result = result {
        print(result.bestTranscription.formattedString)
        isFinal = result.isFinal
    }

    if error != nil || isFinal {
        // 60 sec limit reached
    }
}

ここで、ユーザに返した結果を表示しています。Appleは一つのスピーチリクエストに60秒の制限を設けているので、閾値に到達したら、isFinalをtrueで返します。

Audio Session (11:05)

音声を初期化するのに AVAudioSession を使います。

let audioSession = AVAudioSession.sharedInstance()

try audioSession.setCategory(AVAudioSessionCategoryRecord)

try audioSession.setMode(AVAudioSessionModeMeasurement)

try audioSession.setActive(true, with: .notifyOthersOnDeactivation)

Capture Audio Stream (11:28)

これはデバイスのほとんどのオーディオストリームを中断するので、入力準備が整ったときのみ行います。(電話など)優先度の高いオーディオストリームがあります。

private let audioEngine = AVAudioEngine()

...

let recordingFormat = audioEngine.inputNode.outputFormat(forBus: 0)

audioEngine.inputNode.installTap(onBus: 0, bufferSize: 1024, format: recordingFormat) {
    (buffer: AVAudioPCMBuffer, when: AVAudioTime) in
    self.recognitionRequest?.append(buffer)
}

audioEngine.prepare()

try audioEngine.start()

AVAudioEngineaudioEngineの状態を管理します。これは、出力フォーマット、オーディオタップのインストール、全体を始めるところを定義しています。audioEngine.prepare()を呼んで、すべて初期化したら、audioEngine.startを呼びます。

SFSpeechRecognizerDelegate (11:51)

SFSpeechRecognizerDelegateについても話しておきましょう。

import Speech

public class ViewController: UIViewController, SFSpeechRecognizerDelegate {

    ...

    speechRecognizer?.delegate = self

    ...

    public func speechRecognizer(_ speechRecognizer: SFSpeechRecognizer,
        availabilityDidChange available: Bool) {

availabilityDidChangeというメソッドが1個あるだけです。リクエストの処理中で、何かの理由でオフラインになったら、サーバはレスポンスを中止します。 オンラインになったら、適切に処理することができます。

落とし穴 (13:40)

  1. Info.plist には正しいPermissionをセットしてください。サービスにアクセスする理由を説明する必要があります。セットしなければ、アプリはクラッシュします。
  2. デバイスごと、アプリごとに利用制限があります。残念ながら、Appleは公開していません。あるユースケースで、多くの利用が予想される場合は、なんとかしたいと思うかもしれません。
  3. 繰り返しですが、ライブオーディオは60秒までです。

UXへの配慮 (14:25)

  • コンテキストを賢く選択してください。音声認識を使うのが理にかなっているシナリオについて考えてみましょう。テキスト検索は意味があり、短い書き起こし(例えば、予定リストなど)がある場所では理にかなっています。小説を書き起こすアプリを作っているなら、それはうまくいかないでしょう。
  • ユーザーのセキュリティに対する意識は非常に重要です。信頼を失ったら、それを取り戻すことは非常に難しいでしょう。このように、自分の声を録音しているときに、常にユーザーに警告する必要があります。さらに、60秒を超えると思われる場合は、残り少なくなったらアラートをだしてください。そうでないと、ユーザーはアプリが機能しなくなったと捉えます。
  • ローカライズ対応:英語をデフォルトにする代わりに、ユーザーが母国語を話すようにできるチャンスです。これにより、どのユーザーに対しても、全体的なUXが向上します。2つ注意することがあります。:
    1. あなたのアプリが他の母国語に翻訳されていない場合は、母国語の音声認識をサポートしている旨をアプリのどこかに表示してください。
    2. エンドポイント、サードパーティのAPI、またはプライベートAPIを使用している場合は、それらのエンドポイントが母国語もサポートする必要があります。

参考 (16:18)

Speech recognition video from WWDC を見ることをおすすめします。とても短いです( 12分! )。Henry Masonが話しています。ここから多くの情報を得ました。それからSpeech Recognition Demoというサンプルを公開しています。自由に遊んでみてください!

About the content

2016年9月のtry! Swift NYCの講演です。映像はRealmによって撮影・録音され、主催者の許可を得て公開しています。

Marc Brown

Marc is the Mobile Engineering Manager at Blue Apron and has been building iOS apps since 2009. Previously, he worked for Etsy and a handful of startups. Marc runs the Brooklyn Swift Meetup and loves encouraging others to learn Swift. In his spare time, he enjoys retweeting Arrested Development quotes.

4 design patterns for a RESTless mobile integration »

close