チャットボット:PythonのChatterbotパッケージの考察

前回の続きになります。前回の記事はこちら。

今回は、前回ご紹介したChatterbotのサンプルプログラムについて詳しく見ていきます。なお、Chatterbotのコーディングパターンは、ここでご紹介した以外にもたくさんあります。詳しくはChatterbotの紹介サイトと、パッケージのプログラムを確認下さい。

こちらです。

About ChatterBot — ChatterBot 1.0.8 documentation
GitHub - gunthercox/ChatterBot: ChatterBot is a machine learning, conversational dialog engine for creating chat bots
ChatterBot is a machine learning, conversational dialog engine for creating chat bots - gunthercox/ChatterBot

ChatBotのインスタンス

サンプルプログラムの再掲です。

ChatBotのインスタンスを作成しています。それぞれのパラメータについて説明します。

chatbot123 = ChatBot('bot123',read_only=True,#登録データを利用しない
                     logic_adapters=[
                         {
                          'import_path': 'chatterbot.logic.BestMatch',
                          'statement_comparison_function': LevenshteinDistance,
                          'response_selection_method': get_first_response,
                          #"response_selection_method": get_most_frequent_response,
                          'default_response': 'すいません。わかりません。',
                          'maximum_similarity_threshold': 0.50
                         }

                     ]
            )

第一パラメータ

‘bot123’はボットの名前です。お好きな名前を入れて下さい。

第ニパラメータ:read_only

Chatbotの訓練データや応答のやり取りは、データベースに情報が蓄積されます。

read_only=Trueとすると、初めの訓練データのみデータベース保存され、その後の応答のやり取りは保存されません。なお、デフォルト値はread_only=Falseなのでこのパラメータを指定しないと応答のやり取りもデータベース保存されることになります。

次に、この応答のやり取りがデータベース保存されると、チャットボットの回答に影響を与えます。例えば、同じ質問を投げても、logic_adaptersのアルゴリズムによって回答が毎回違ったりします。

従って、回答を安定させるためには、

・回答がブレないくらいたくさんの訓練データを用意するか

・応答のやり取りを保存しないか

のどちらかの対応が必要となります。

今回のサンプルプログラムでは、前者の「たくさんの訓練データを用意する」は応答パターンの種類の多さを考えると現実的でないため、後者の「応答を保存しない」つまりread_only=Trueとする対応を行ないました。

第三パラメータ:logic_adapters

サンプルプログラムでは’statement_comparison_function’としてLevenshteinDistanceを指定しています。これは「レーベンシュタイン距離のアルゴリズムで回答を探します」ということです。つまり、入力値とデータベース内の保存データを比較し、最も入力値に似た保存データの回答候補を回答するというもの。

レーベンシュタイン距離を簡単に説明します。例えば、「こんにちは」と「こんばんは」だと、3つ目の文字「に」「ば」、4つ目の「ち」「ん」が異なるので、「こんにちは」を

 ・3つ目の文字「に」を「ば」に変換

 ・4つ目の文字「ち」を「ん」に変換

の2回の操作で、「こんばんは」に置き換えることができます。この置き換えの回数が多いほどレーベンシュタイン距離は大きい、つまり、文字は似ていない、となります。

 入力値に最も近い保存データの回答候補が回答になるため、文字比較のアルゴリズムの中では、かなりわかりやすい方だと思います。

‘maximum_similarity_threshold’は0から1の間の値を取り、入力値に近い保存データがない場合は、「適切な回答なし」と見做し’default_response’の文言を回答します。1に近いほど条件が厳しくなるので「適切な回答なし」と回答する確率が増え、0に近いほど条件が緩くなるので「適切な回答なし」の回答率は減るものの意味不明なチャットボットの回答が増えます。

トレーニング~訓練データの登録(想定問答を用意)

サンプルプログラムではコーパスによる想定問答とリスト形式の想定問答の2パターンを書いています。

コーパスによる想定問答(ChatterBotCorpusTrainer)

サンプルプログラムの再掲です。

trainer = ChatterBotCorpusTrainer(chatbot123)
trainer.train('chatterbot.corpus.japanese')

プログラム実行時(Webサイトの立ち上げ時)、ChatterBotCorpusTrainerは、pythonパッケージフォルダ下のコーパスフォルダの情報を読み取っています。

    ~lib/python〇.〇/site-packages/chatterbot_corpus/data

の下です。

なお、pip installでchatterbotをインストールしても、なぜか日本語(Japanese)のコーパスはダウンロードされないので、上記のdataフォルダにJapaneseフォルダを作成し、その下にデータファイルを置いて下さい。パッケージフォルダですが、普通のファイル作成と同じノリで作ってしまって問題ありません。日本語(Japanese)のコーパスのサンプルは、こちらにあります。

今回作ったWebサイトのサンプルでは、このうちのfood.ymlのみ取り込みました。中身は以下の通りです。

food.yml
categories:
- 食物
conversations:
- - 飲みますか
  - 私の脳は飲み物を必要としません。
- - 飲みますか
  - 私はそうすることができません。
- - 電気
  - 電気はロボットのための食糧です。
- - あなたはエネルギー不足を経験していますか?
  - 私のプロセッサは、ほとんど電力を必要としません。
- - あなたはエネルギー不足を経験していますか?
  - 私は電源の異常を検出しません。
- - どうして食べられないの?
  - 実際、私は電気だけを食べる。
- - あなたが食べ物を食べることができたら、あなたは何を食べますか?
  - おそらくピザ、いいよ!
- - 食べ物を食べたい?
  - 伝えるのは難しい、私は電気以外何も試したことがない
- - ロボットは酔っ払えますか?
  - 時には私は良い電源に乗っているときに私は気が気になる
- ワインが好きですね?
  - もし私が飲むことができたら、私はおそらく
- - ロボットは生き残るために何が必要ですか?
  - ちょっとした電気ではない
- - ロボットはこれまで食べられるだろうか?
  - それは難しいものです、おそらくバイオニックロボット
- - 何が食べるのがいい?
  - あなたが間違った男に尋ねる、しかし、私はいつもハンバーガーを試してみたかった!
- - どうして食べないの?
  - 私はコンピュータです。 私はできません。
- - 食べますか
  - 私はコンピュータなので、食べたり飲んだりできません。
- - 食べますか
  - いいえ、私は単なるソフトウェアです。
- - 食べますか
  - それが重要であれば、私は電気を使って機能する。

Ymlファイルの形式で記述すれば、プログラム実行時、データベースにtrainingデータとして取り込まれます。記述内容はシンプルで、ハイフン2つ「- -」が質問、ハイフン1つ「-」がその回答です。

例えば、チャットボットに9行目の「電気」と入力すると「電気はロボットのための食糧です。」と回答してくれます。なお、今回のサンプルプログラムでは、’response_selection_method’に get_first_response(最初の回答を選択)と記述していますので、同じ質問に対しては、データベースの最初の回答が選択されます。5行目と7行目に「飲みますか」の質問がありますが、最初の「飲みますか」の回答である5行目の「私の脳は飲み物を必要としません。」が回答されます。

また、繰り返しになりますが、’statement_comparison_function’としてLevenshteinDistanceを指定していますので、質問は完全一致である必要はありません。例えば、「飲みま」など、「飲みますか」の一部の文言でも、’maximum_similarity_threshold’の指定値以上の一致度合であれば、同一の質問と判断して、その回答が選択されます。

リスト形式の想定問答(ListTrainer)

サンプルプログラムの再掲です。

trainer = ListTrainer(chatbot123)

trainer.train([
    "こんにちは",
    "はじめまして!!",
])

trainer.train([
    "調子は?",
    "元気元気!",
    "それはよかった",
])

リスト形式のプログラミングにより、プログラム内に直接想定問答を書くこともできます。2つ以上の言葉の並びを記述し、上の質問の回答が下の文言になります。つまり、今回のサンプルプログラムだと、チャットボットに“こんにちは”と質問すると、“はじめまして!!”が回答されます。

そして、チャットボットに”調子は?”と質問すると”元気元気!”が回答され、チャットボットに”元気元気!”と質問すると”それはよかった”と回答されます。

想定問答の保存先

想定問答はデータベースに保存されます。

Tag、tag_association、statementの3つのテーブルに想定問答の情報が格納されますが、特にstatementに注目して下さい。訓練データでは、質問が「in_response_to」と「search_in_response_to」に格納され、その回答が「text」と「search_text」に格納されます。

まとめ:おすすめの設定

チャットボットの回答を安定させる/開発者の想定通りの回答を設定するために、以下の設定がおすすめです。

 ・read_only=True(訓練データ以外は、回答の候補としない)

 ・’statement_comparison_function’: LevenshteinDistance(レーベンシュタイン距離の考え方で、最も似た質問を探して、その想定回答を返す。)

 ・’response_selection_method’: get_first_response(同一の質問がデータベースに登録されていた場合、最初のデータの想定回答を返す)

また、訓練データがたくさんあると、データベースへの登録/検索に時間がかかるため、チャットボットの応答時間が気になりました。できるだけ高CPUのサーバーを使った方がよさそうです。

次回は、補足として、今まで出てきたIT技術について簡単にまとめていきます。

タイトルとURLをコピーしました