PythonでWatson Speech To Textをカスタマイズしてみよう

# ＜目次＞
本記事の目次は、下記の通りです。
１．背景
２．そもそもSpeech To Textとは？
３．カスタマイズをする意義
４．【カスタマイズをしてみよう！①】事前準備
５．【カスタマイズをしてみよう！②】カスタマイズなしで書き起こしてみる
６．【カスタマイズをしてみよう！③】カスタマイズするためのモデルの準備
７．【カスタマイズをしてみよう！④】文章を追加してみる
８．【カスタマイズをしてみよう！⑤】単語を追加してみる
９．【カスタマイズをしてみよう！⑥】モデルに学習させてみる
10．【カスタマイズをしてみよう！⑦】カスタマイズされたモデルで書き起こしてみる
11．本記事のまとめ

# １．背景
初めまして、望月です。人生初のQiitaの記事の執筆になりますが、記念すべき第一回はWatson Speech To Text(STT)のカスタマイズ機能の実施方法を解説したいと思います。
最近、STTのカスタマイズ機能をお客様にご紹介する機会があったのですが、その際にカスタマイズを実行しているQiitaの記事が少なかったので、今回の経験を他の人も役立てられたらなと思い執筆することとしました。
この記事の内容がSTTのカスタマイズを実施したい人のお力になれば幸いです。


# ２．そもそもSpeech To Textとは？
[Watson Speech To Text](https://github.com/ishida330/Watson-STT-Customize-Sample)とは機械学習を活用して、文法、言語構造、および音声シグナルの構成に関する知識を組み合わせ、人間の音声を正確に書き起こすIBMのサービスです。
顧客セルフサービスや、通話分析、サービスの業務担当者の支援などに活用されています。


# ３．カスタマイズをする意義
STTがどんなサービスなのかは掴めたかと思いますので、今回のテーマであるカスタマイズをどうしてやる必要があるのかを解説します。
一言で言うと、**製品名などの固有名詞や独自の言い回しなどは、オリジナルのSTTではうまく書き起こすことができない**からです。
オリジナルのSTTは一般的な単語や言い回ししか認識できないので、もしドメイン固有の言葉や言い回しを正確に書き起こしたい場合にはSTTに教える必要があります。これがSTTの**カスタマイズ機能**です。
そしてSTTのカスタマイズ機能においては、音響モデルと言語モデルの二つをカスタマイズすることができ、以下のような違いがあります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3634669/9d172735-9c68-4a1e-028c-fc798f60d429.png)

今回は上記の二つのモデルのうち、言語モデルのカスタマイズを実行してみたいと思います。
言語モデルのカスタマイズの手順は以下のような順番です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3634669/a5738676-675e-ffb0-dda9-33b45a16c920.png)



# ４．【カスタマイズをしてみよう！①】事前準備
カスタマイズを実施するためには、いくつか用意するものがありますので、説明いたします。

## ①Watson Speech To Textの有料プラン
今回実施するカスタマイズ機能はライト・プランには実装されていません。そのため、実施する場合はライト・プランではないことを確認してください。
そして、IBM Cloudのリソース・リストの中からSpeech To Textを選択して以下のような画面を開いてください。
![スクリーンショット 2023-12-19 23.52.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3634669/44a5643c-3b1b-6608-519a-ca16576c4bee.png)

念の為、写真の一部をマスキングさせていただきましたが、上記のような画面から、API鍵とURLをコピーして記録してください。
後ほど使います。

## ②書き起こししたい音声ファイル
STTは音声の書き起こしサービスですので、書き起こすための音声ファイルを用意する必要があります。
STTでサポートされている音声フォーマットは[こちら](https://cloud.ibm.com/docs/speech-to-text?topic=speech-to-text-audio-formats)からご確認ください。

私の場合は[こちらのサイト](https://www.ibm.com/jp-ja/products/watsonx-assistant)を参考に、IBMの製品であるwatsonx Assistantを紹介した次のような文章を読み上げ、mp3形式で保存しました。

```
IBM watsonx Assistantは、従来型のサポート業務で生じるストレスを取り除き、
見込み客、顧客、従業員に卓越した体験を提供できるように設計された、市場をリードする対話型AIプラットフォームです。
信頼できる大規模言語モデルと直感的なユーザー・インターフェースを備えたwatsonx Assistantは、
AIを搭載した音声アシスタントやチャットボットを構築し、ビジネスを支えるツールとシームレスに連携できます。
```

## ③学習させる文書
STTのカスタマイズでは、ドメイン固有の言葉や言い回しを使った文章を登録して学習させると、文脈やオリジナルでは知らない単語を記憶してくれます。
今回は、書き起こししたい文章と同様にwatsonx Assistantについて説明した文章を学習させます。
形式はテキストファイルで、日本語の場合はutf-8にすることを忘れないでください。
テキストファイルの内容は以下の通りです。(参考にしたのは[こちらのサイト](https://www.ibm.com/jp-ja/products/watsonx-assistant/artificial-intelligence))
```txt:trainingtext.txt
watsonx Assistantは、watsonx.ai上に構築されたカスタマイズ済みの大規模言語モデルを組み込むことができる、ローコードの対話型AIプラットフォームで、インテリジェントなバーチャル・アシスタントやチャットボットを構築できます。IBMのAIソリューションにより、企業はセルフサービス形式でのアクションと回答を自動化して、卓越したユーザー体験の開発を加速できます。

```

## ④学習させる単語リスト
ドメイン固有の単語をSTTに学習させることもできます。今回は読み上げた文書の中で、書き起こしが難しそうな製品名などを単語リストに入力しました。
単語リストはJSON形式のファイルで作成し、sounds_likeにはカタカナで発音を、display_asはそのような発話があったときにどのように書き起こすのか指定しています。
単語リストは以下の通りです。
```json:customword.json
{
   "words":[
      {"word":"watsonx","sounds_like":["ワトソンエックス"],"display_as":"watsonx"},
      {"word":"アシスタント","sounds_like":["アシスタント"],"display_as":"Assistant"},      
      {"word":"ユーザー・インターフェース","sounds_like":["ユーザーインターフェース"],"display_as":"ユーザー・インターフェース"},
      {"word":"チャットボット","sounds_like":["チャットボット"],"display_as":"チャットボット"}
   ]
}
```

ここまでの①から④までが準備できたら、いよいよSTTの利用に進んでいきます。



# ５．【カスタマイズをしてみよう！②】カスタマイズなしで書き起こしてみる
まずは、カスタマイズしていないSTTでどの程度書き起こせるのか試してみましょう。
記事のタイトルに「**Pythonで**」と書いてある通り、今回はPython形式でSTTの書き起こしの実行やカスタマイズを行なっています。基本的には[こちらのドキュメント](https://cloud.ibm.com/apidocs/speech-to-text)を参考にしています。
以下のPythonコードを実行してみてください。引っかかりそうな部分にはコメントアウトで説明を入れているので参考にしてください。
```python:stt.py
from os.path import join, dirname
import json
from ibm_watson import SpeechToTextV1
from ibm_cloud_sdk_core.authenticators import IAMAuthenticator

authenticator = IAMAuthenticator('<4.①でコピーしたAPI鍵>')
speech_to_text = SpeechToTextV1(
    authenticator=authenticator
)

speech_to_text.set_service_url('<4.①でコピーしたURL>')

#↓ここでは読み込む音声ファイルのディレクトリを指定しています。このPythonファイルと同じディレクトリに音声ファイルがあればこの書き方通りで問題ないはずです。
with open(join(dirname(__file__), './.', '4.②で用意した音声ファイル'),
               'rb') as audio_file:
    speech_recognition_results = speech_to_text.recognize(
        audio=audio_file,
        #STTで利用するモデルに関しては https://cloud.ibm.com/docs/speech-to-text?topic=speech-to-text-models で確認してください。
        model='ja-JP_BroadbandModel',
        #ここでは音声ファイルの形式を指定しています。
        content_type='audio/mp3',
    ).get_result()
Transcript=json.dumps(speech_recognition_results, indent=2,ensure_ascii=False)
print(Transcript)
```
上記のPythonコードを実行すると次のような結果が出力されます。
```
{
  "result_index": 0,
  "results": [
    {
      "final": true,
      "alternatives": [
        {
          "transcript": "ＩＢＭ Ｗａｔｓｏｎ ｘ アシスタント は 従来 型 の サポート 業務 で 生じる ストレス を 取り除き 見込み 客 顧客 従業員 に 卓越 した 体験 を 提供 できる よう 設計 された 市場 を リード する 対話型 ＡＩ プラットホーム です ",
          "confidence": 0.85
        }
      ]
    },
    {
      "final": true,
      "alternatives": [
        {
          "transcript": "信頼 できる 大規模 言語 モデル と 直感的 な ユーザー インターフェース を 備えた Ｗａｔｓｏｎ ｘ アシスタント は ＡＩ を 搭載 した 音声 アシスタント や ちょっと もっと を 構築 し ビジネス を 支える ツール と シームレス に 連携 できます ",
          "confidence": 0.91
        }
      ]
    }
  ]
}
(nobu) aa449819760@aa449819760noMacBook-Pro ~ % 
```
上記の出力では読みづらいので以下の画像にまとめました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3634669/42d40850-d46d-fb95-5cb5-a9f9216a8736.png)



左側が読み上げた文章で、右側が書き起こされた文章で、赤字になったところが元の文章と異なる書き起こし部分です。
カスタマイズ前の書き起こしでもかなり精度が高いです。もしかしたら、IBMの製品に関する文章だから書き起こしの精度も高いのかもしれませんね笑
ただ、8行目のチャットボットの部分は「**ちょっともっと**」となっており、うまく書き起こしできていませんね。
カスタマイズで修正できるか気になるところです。


# 5．【カスタマイズをしてみよう！③】カスタマイズするためのモデルの準備
オリジナルでどの程度書き起こせるのか確認できたため、実際にカスタマイズを実行していきましょう。
まずカスタマイズするにあたって、カスタマイズするための言語モデルを作成する必要があります。
STTには様々な書き起こすためのモデルが存在しています。なので、[このサイト](https://cloud.ibm.com/docs/speech-to-text?topic=speech-to-text-models)に書いてあるモデルの情報を参考にご自身がカスタマイズしたいモデルを選んでみてください。
今回は日本語に対応したモデルである**ja-JP_BroadbandModel**を選択しました。
(*このモデルは前世代モデルに属し、現在次世代モデルへのマイグレーションを推奨されています。[こちらのサイト](https://www.ibm.com/blogs/solutions/jp-ja/watson-speech-to-text-new-japanese-next-generation-telephony-model/)などで最新の情報をご確認ください。)

カスタムしたいモデルを選択したら、下記のようなPythonコードに選択したモデルを記入し実行してみてください。
```py:sttcustom.py
import json
from ibm_watson import SpeechToTextV1
from ibm_cloud_sdk_core.authenticators import IAMAuthenticator

authenticator = IAMAuthenticator('<4.①でコピーしたAPI鍵>')
speech_to_text = SpeechToTextV1(
    authenticator=authenticator
)

speech_to_text.set_service_url('<4.①でコピーしたURL>')

language_model = speech_to_text.create_language_model(
    'version1model',
    #↓カスタムしたいモデルの情報を記入
    'ja-JP_BroadbandModel',
    description='カスタム用のモデル'
).get_result()
Transcript=json.dumps(language_model, indent=2)
print(json.dumps(language_model, indent=2))
```
上記のPythonコードを実行し、カスタム言語モデルの作成に成功すると以下のような結果が出力されるはずです。
```txt:出力例
{
  "customization_id": "9855922c-a578-4b89-bae6-28daa988c466"
}
```
上記のような数字やアルファベットの文字列がカスタム言語モデルのIDとなり、これからの作業で必要です。


# ７．【カスタマイズをしてみよう！④】文章を追加してみる
カスタム言語モデルの作成に成功したら、続いて学習させたい内容の追加に進みます。
まずは、学習させたい単語や文脈を含んだテキストを追加します。
以下のPythonコードを実行し、4.③で用意したテキストファイルを6で作成したカスタム言語モデルに追加します。
```py:addcorpus.py
from os.path import join, dirname
import json
from ibm_watson import SpeechToTextV1
from ibm_cloud_sdk_core.authenticators import IAMAuthenticator

authenticator = IAMAuthenticator('<4.①でコピーしたAPI鍵>')
speech_to_text = SpeechToTextV1(
    authenticator=authenticator
)

speech_to_text.set_service_url('<4.①でコピーしたURL>')
#↓ここでは読み込むテキストファイルのディレクトリを指定しています。このPythonファイルと同じディレクトリにテキストファイルがあればこの書き方通りで問題ないはずです。
with open(join(dirname(__file__), './.', '<4.③で用意したテキストファイル>'),
               'r',encoding="utf-8") as f:
    stt.add_corpus(
         customization_id="<6で取得したカスタム言語モデルのID>",
         corpus_name="Trainingtext",corpus_file=f,allow_overwrite=True).get_result()
```
今回はカスタム言語モデルにテキストファイルを追加するのに成功した場合、何も返さないはずです。


# 8．【カスタマイズをしてみよう！⑤】単語を追加してみる
テキストを追加し終えたら、4.④で作成した単語リストを追加しましょう。
以下のPythonコードを実行してください。
```py:addword.py
from os.path import join, dirname
import json
from ibm_watson import SpeechToTextV1
from ibm_cloud_sdk_core.authenticators import IAMAuthenticator

authenticator = IAMAuthenticator('<4.①でコピーしたAPI鍵>')
speech_to_text = SpeechToTextV1(
    authenticator=authenticator
)

speech_to_text.set_service_url('<4.①でコピーしたURL>')

#↓ここでは読み込むjsonファイルのディレクトリを指定しています。このPythonファイルと同じディレクトリにjsonファイルがあればこの書き方通りで問題ないはずです
with open(join(dirname(__file__), './.', '4.③で用意したjsonファイル'),
               'r',encoding="utf-8") as f:
    custom_words = json.load(f)["words"]
    stt.add_words(
         customization_id="9855922c-a578-4b89-bae6-28daa988c466",
         words=custom_words).get_result()
```
こちらも単語リストのカスタム言語モデルへの追加が成功した場合は何も返さないはずです。
## 注意点
もし、テキストファイルを追加した直後に単語リストの追加や、次の項で説明するモデルのトレーニングを行おうとして、以下のようなエラーが出た場合には少し時間をおいてください。
まだテキストファイルの追加の処理が終わっていないことが原因だと思われます。
```
raise ApiException(response.status_code, http_response=response)
ibm_cloud_sdk_core.api_exception.ApiException: Error: Customization '<カスタム言語モデルのID>' is currently locked to process your last request., Code: 409 , X-global-transaction-id: <カスタム言語モデルのID>
```


# ９．【カスタマイズをしてみよう！⑥】モデルに学習させてみる
テキストファイルや単語リストの追加を終えたら、いよいよモデルのトレーニングです！
以下のPythonコードを実行してください。
```py:training.py
from os.path import join, dirname
import json
from ibm_watson import SpeechToTextV1
from ibm_cloud_sdk_core.authenticators import IAMAuthenticator

authenticator = IAMAuthenticator('<4.①でコピーしたAPI鍵>')
speech_to_text = SpeechToTextV1(
    authenticator=authenticator
)

speech_to_text.set_service_url('<4.①でコピーしたURL>')
stt.train_language_model(
    customization_id="<6で取得したカスタム言語モデルのID>",
    word_type_to_add=None,
    #↓customization_weightに関しては　https://cloud.ibm.com/docs/speech-to-text?topic=speech-to-text-languageUse#weight　を参考にしてください。今回はデフォルトの0.3のままにしてあります。
    customization_weight=0.3).get_result()
```
上記のPythonを実行するとモデルのトレーニングが始まります。
トレーニングの進行状態を確認したい場合は以下のPythonコードを実行してください。

```py:training_status.py
from os.path import join, dirname
import json
from ibm_watson import SpeechToTextV1
from ibm_cloud_sdk_core.authenticators import IAMAuthenticator

authenticator = IAMAuthenticator('<4.①でコピーしたAPI鍵>')
speech_to_text = SpeechToTextV1(
    authenticator=authenticator
)

speech_to_text.set_service_url('<4.①でコピーしたURL>')

status=stt.get_language_model("<6で取得したカスタム言語モデルのID>").get_result()
print(json.dumps(status, indent=2))
```
上記のPythonコードを実行すると、以下のような出力がされるはずです。
```txt:出力例
{
  "owner": "f1d89576-5d02-472d-9182-109b3c271ea7",
  "base_model_name": "ja-JP_BroadbandModel",
  "customization_id": "<6で取得したカスタム言語モデルのID>",
  "dialect": "ja-JP",
  "versions": [
    "ja-JP_BroadbandModel.v2020-09-10"
  ],
  "created": "2023-12-19T11:30:36.629Z",
  "name": "version1model",
  "description": "カスタム用のモデル",
  "progress": 100,
  "language": "ja-JP",
  "updated": "2023-12-19T11:34:20.707Z",
  "status": "available"←"available"ならトレーニング完了、それ以外の場合はまだトレーニング中
}
```
出力結果のstatusを確認して、**available**ならトレーニング完了です!
筆者の感覚だと、学習させる内容の量にもよりますが、長くても20分程度のイメージです。(学習量が非常に多い場合どれくらいかかるかは保証できません。)


# 10．【カスタマイズをしてみよう！⑦】カスタマイズされたモデルで書き起こしてみる
トレーニングを終えたらカスタマイズの完了です！
以下のPythonコードでカスタム言語モデルによる書き起こしを試してみましょう！

```py:stt2.py
from os.path import join, dirname
import json
from ibm_watson import SpeechToTextV1
from ibm_cloud_sdk_core.authenticators import IAMAuthenticator

authenticator = IAMAuthenticator('<4.①でコピーしたAPI鍵>')
speech_to_text = SpeechToTextV1(
    authenticator=authenticator
)

speech_to_text.set_service_url('<4.①でコピーしたURL>')

#↓ここでは読み込む音声ファイルのディレクトリを指定しています。このPythonファイルと同じディレクトリに音声ファイルがあればこの書き方通りで問題ないはずです。
with open(join(dirname(__file__), './.', '4.②で用意した音声ファイル'),
               'rb') as audio_file:
    speech_recognition_results = speech_to_text.recognize(
        audio=audio_file,
        #STTで利用するモデルに関しては https://cloud.ibm.com/docs/speech-to-text?topic=speech-to-text-models で確認してください。
        model='ja-JP_BroadbandModel',
        language_customization_id="<6で取得したカスタム言語モデルのID>",
        #ここでは音声ファイルの形式を指定しています。
        content_type='audio/mp3',
    ).get_result()
Transcript=json.dumps(speech_recognition_results, indent=2,ensure_ascii=False)
print(Transcript)
```

書き起こし結果を以下の画像のようにまとめてみました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3634669/bb03de52-f5fe-a4bb-3b2d-5726b2c0bc7e.png)


左側がカスタマイズしない場合の書き起こしで、赤字の部分が読み上げた文章と書き起こしが異なっている部分です。
そして、右側がカスタマイズしたモデルによる書き起こしです。青字の部分がカスタマイズによって書き起こしが変わった部分で、
**なんと！読み上げた文章と全く同じ文章が書き起こされました！**
8行目の「ちょっともっと」という書き起こしも、きちんと「チャットボット」と書き起こされていますね！
STTのカスタマイズ、侮れません。


# 11．本記事のまとめ
ここまで、STTのカスタマイズの方法を説明してきました。
この記事の通りに実行すれば、PythonでSTTのカスタマイズを実行する方法が一通り体験できると思います。

**音声の書き起こしがうまくいかない！**
という際にはぜひカスタマイズ機能を試してみてください！



# 参考文献

### Speech To Text 製品ガイド
https://cloud.ibm.com/docs/speech-to-text

### Speech To Text APIドキュメント
https://cloud.ibm.com/apidocs/speech-to-text