Chienomi

情緒的AIと形態素解析のおはなし

開発::EQAI

Erinaは情緒的AIである。 当然ながら「会話する」という機能は重要であり、Surtrにとっても「相手の言っていることを理解する」ということは非常に重要な要素であり、実のところ「一番最初に実装された機能」である。

私がErinaを「文系AI」と呼ぶ最大の理由がこの解析機能である。 Erinaは大した統計機能を持っていない。その理由は、私に統計学に関する十分な知識がないためだ。 そこで、私は膨大な会話や文章を読みながら、「片っ端から触れたテキストを解析できるように」解析エンジンを改良していったのである。

ここで紹介するのは実装ではなく、考え方やアプローチについてだが、ここに書いてあることを元にすれば(労力を厭わなければ)Erinaと同じようなエンジンを実装することが可能である。

Erinaと形態素解析

いきなりタイトル詐欺のようだが、実はErinaに形態素解析が使用されはじめたのは2016年からで、それまでは「形態素解析は」行っていなかった。

これは、(Erinaが非ディープラーニングであるように)特別な意図を持って形態素解析を排したわけではなく、単純に形態素解析の精度に満足しなかったためである。

2016年からは、複数の解釈がどちらも同じスコアで成立するような場合に形態素解析を行うようになったほか、パート分け後の精度を上げるために使用している(特に、名詞と助詞を検出したい)。

使用しているのはMeCab/ipadicである。 恐らく最も無難な選択だろう。 他の選択肢としてはChaSenも試したのだが、MeCab/ipadicのほうが「使いやすかったので」この構成で使用している。

形態素解析が万能でないことは例えば次の例でわかる。 次はMeCab/ipadicに「おはようございます」を与えたときだ

おはようございます
おはよう    感動詞,*,*,*,*,*,おはよう,オハヨウ,オハヨー
ござい 助動詞,*,*,*,五段・ラ行特殊,連用形,ござる,ゴザイ,ゴザイ
ます  助動詞,*,*,*,特殊・マス,基本形,ます,マス,マス

しかし、これが「おはようごじゃいましゅ」になると

おはようごじゃいましゅ
おはよう    感動詞,*,*,*,*,*,おはよう,オハヨウ,オハヨー
ご   接頭詞,名詞接続,*,*,*,*,ご,ゴ,ゴ
じゃい 動詞,非自立,*,*,五段・ワ行促音便,連用形,じゃう,ジャイ,ジャイ
まし  助動詞,*,*,*,特殊・マス,連用形,ます,マシ,マシ
ゅ   名詞,一般,*,*,*,*,*

とだいぶ甘い。これはIPA NEologdを使ったとしても

おはようごじゃいましゅ
おはよう    感動詞,*,*,*,*,*,おはよう,オハヨウ,オハヨー
ご   接頭詞,名詞接続,*,*,*,*,ご,ゴ,ゴ
じゃい 動詞,非自立,*,*,五段・ワ行促音便,連用形,じゃう,ジャイ,ジャイ
ましゅ 名詞,一般,*,*,*,*,魔手,マシュ,マシュ

とやはりチャットで使うような崩し方には対応できない。同様に綺麗に書けば

小波さんが可愛すぎて苦しい
小波  名詞,固有名詞,人名,名,*,*,小波,サザナミ,サザナミ
さん  名詞,接尾,人名,*,*,*,さん,サン,サン
が   助詞,格助詞,一般,*,*,*,が,ガ,ガ
可愛  形容詞,自立,*,*,形容詞・イ段,ガル接続,可愛い,カワイ,カワイ
すぎ  動詞,非自立,*,*,一段,連用形,すぎる,スギ,スギ
て   助詞,接続助詞,*,*,*,*,て,テ,テ
苦しい 形容詞,自立,*,*,形容詞・イ段,基本形,苦しい,クルシイ,クルシイ

スランギーに書くと

小波さんかわゆすぎてくるしす
小波  名詞,固有名詞,人名,名,*,*,小波,サザナミ,サザナミ
さん  名詞,接尾,人名,*,*,*,さん,サン,サン
かわゆ 形容詞,自立,*,*,形容詞・アウオ段,ガル接続,かわゆい,カワユ,カワユ
すぎ  動詞,非自立,*,*,一段,連用形,すぎる,スギ,スギ
て   助詞,接続助詞,*,*,*,*,て,テ,テ
くる  動詞,非自立,*,*,カ変・クル,基本形,くる,クル,クル
しす  動詞,自立,*,*,五段・サ行,基本形,しす,シス,シス

と、「かわゆい」を認識するのは良いが、「くるしす」は解釈できない。 なお、小波さんは見てて苦しくなるというより悶えるような可愛さである。念の為。

私は口語でもかなり綺麗に話すほうなので解析はあまり難しくないけれど

Amazonのリラックスジャズステーションが、本当に私の欲している曲を流してくれているので、心が少し平穏を取り戻しつつあるような気がしないでもない
Amazon  名詞,固有名詞,組織,*,*,*,*
の   助詞,連体化,*,*,*,*,の,ノ,ノ
リラックスジャズステーション  名詞,一般,*,*,*,*,*
が   助詞,格助詞,一般,*,*,*,が,ガ,ガ
、   記号,読点,*,*,*,*,、,、,、
本当に 副詞,一般,*,*,*,*,本当に,ホントウニ,ホントーニ
私   名詞,代名詞,一般,*,*,*,私,ワタシ,ワタシ
の   助詞,連体化,*,*,*,*,の,ノ,ノ
欲   名詞,サ変接続,*,*,*,*,欲,ホッ,ホッ
し   動詞,自立,*,*,サ変・スル,連用形,する,シ,シ
て   助詞,接続助詞,*,*,*,*,て,テ,テ
いる  動詞,非自立,*,*,一段,基本形,いる,イル,イル
曲   名詞,一般,*,*,*,*,曲,キョク,キョク
を   助詞,格助詞,一般,*,*,*,を,ヲ,ヲ
流し  動詞,自立,*,*,五段・サ行,連用形,流す,ナガシ,ナガシ
て   助詞,接続助詞,*,*,*,*,て,テ,テ
くれ  動詞,非自立,*,*,一段・クレル,連用形,くれる,クレ,クレ
て   助詞,接続助詞,*,*,*,*,て,テ,テ
いる  動詞,非自立,*,*,一段,基本形,いる,イル,イル
ので  助詞,接続助詞,*,*,*,*,ので,ノデ,ノデ
、   記号,読点,*,*,*,*,、,、,、
心   名詞,一般,*,*,*,*,心,ココロ,ココロ
が   助詞,格助詞,一般,*,*,*,が,ガ,ガ
少し  副詞,助詞類接続,*,*,*,*,少し,スコシ,スコシ
平穏  名詞,形容動詞語幹,*,*,*,*,平穏,ヘイオン,ヘイオン
を   助詞,格助詞,一般,*,*,*,を,ヲ,ヲ
取り戻し    動詞,自立,*,*,五段・サ行,連用形,取り戻す,トリモドシ,トリモドシ
つつ  助詞,接続助詞,*,*,*,*,つつ,ツツ,ツツ
ある  動詞,自立,*,*,五段・ラ行,基本形,ある,アル,アル
よう  名詞,非自立,助動詞語幹,*,*,*,よう,ヨウ,ヨー
な   助動詞,*,*,*,特殊・ダ,体言接続,だ,ナ,ナ
気   名詞,非自立,一般,*,*,*,気,キ,キ
が   助詞,格助詞,一般,*,*,*,が,ガ,ガ
し   動詞,自立,*,*,サ変・スル,未然形,する,シ,シ
ない  助動詞,*,*,*,特殊・ナイ,連用デ接続,ない,ナイ,ナイ
で   助詞,接続助詞,*,*,*,*,で,デ,デ
も   助詞,係助詞,*,*,*,*,も,モ,モ
ない  形容詞,自立,*,*,形容詞・アウオ段,基本形,ない,ナイ,ナイ

kkcを使うと

>> Amazonのリラックスジャズステーションが、本当に私の欲している曲を流してくれているので、心が少し平穏を取り戻しつつあるような気がしないでもない 3
0: <Amazon/Amazon><の/の><リラックスジャズステ/リラックスジャズステ><ー/ー><ション/ション><が/が><、/、><本当/本当><に/に><私/私><の/の><欲/欲><し/し><て/て><い/い><る/る><曲/曲><を/を><流/流><し/し><て/て><くれ/くれ><て/て><い/い><る/る><の/の><で/で><、/、><心/心><が/が><少/少><し/し><平穏/平穏><を/を><取/取><り/り><戻/戻><し/し><つつ/つつ><あ/あ><る/る><よう/よう><な/な><気/気><が/が><市内/しない><で/で><も/も><な/な><い/い>
1: <Amazon/Amazon><の/の><リラックスジャズステ/リラックスジャズステ><ー/ー><ション/ション><が/が><、/、><本当/本当><に/に><私/私><の/の><欲/欲><し/し><て/て><い/い><る/る><曲/曲><を/を><流/流><し/し><て/て><くれ/くれ><て/て><い/い><る/る><の/の><で/で><、/、><心/心><が/が><少/少><市/し><平穏/平穏><を/を><取/取><り/り><戻/戻><し/し><つつ/つつ><あ/あ><る/る><よう/よう><な/な><気/気><が/が><市内/しない><で/で><も/も><な/な><い/い>
2: <Amazon/Amazon><の/の><リラックスジャズステ/リラックスジャズステ><ー/ー><ション/ション><が/が><、/、><本当/本当><に/に><私/私><の/の><欲/欲><し/し><て/て><い/い><る/る><曲/曲><を/を><流/流><し/し><て/て><くれ/くれ><て/て><い/い><る/る><の/の><で/で><、/、><心/心><が/が><少/少><し/し><平穏/平穏><を/を><取/取><り/り><戻/戻><し/し><つつ/つつ><あ/あ><る/る><よう/よう><な/な><気/気><が/が><し/し><な/な><い/い><で/で><も/も><な/な><い/い>

JUMANでは

Amazonのリラックスジャズステーションが、本当に私の欲している曲を流してくれているので、心が少し平穏を取り戻しつつあるような気がしないでもない
Amazon Amazon Amazon 名詞 6 普通名詞 1 * 0 * 0 "自動獲得:Wikipedia 読み不明 Wikipediaリダイレクト:アマゾン"
@ Amazon Amazon Amazon 未定義語 15 アルファベット 3 * 0 * 0 NIL
の の の 助詞 9 接続助詞 3 * 0 * 0 NIL
リラックス りらっくす リラックス 名詞 6 サ変名詞 2 * 0 * 0 "代表表記:リラックス/りらっくす カテゴリ:抽象物"
ジャズ じゃず ジャズ 名詞 6 普通名詞 1 * 0 * 0 "代表表記:ジャズ/じゃず カテゴリ:抽象物 ドメイン:文化・芸術"
ステーション すてーしょん ステーション 名詞 6 普通名詞 1 * 0 * 0 "代表表記:ステーション/すてーしょん カテゴリ:場所-施設 ドメイン:交通"
が が が 助詞 9 格助詞 1 * 0 * 0 NIL
、 、 、 特殊 1 読点 2 * 0 * 0 NIL
本当に ほんとうに 本当だ 形容詞 3 * 0 ナノ形容詞 22 ダ列基本連用形 8 "代表表記:本当だ/ほんとうだ 反義:名詞-普通名詞:嘘/うそ"
私 わたし 私 名詞 6 普通名詞 1 * 0 * 0 "代表表記:私/わたし 漢字読み:訓 カテゴリ:人"
の の の 助詞 9 格助詞 1 * 0 * 0 NIL
欲して ほっして 欲す 動詞 2 * 0 子音動詞サ行 5 タ系連用テ形 14 "代表表記:欲す/ほっす 同義:動詞:欲する/ほっする"
@ 欲して ほっして 欲する 動詞 2 * 0 サ変動詞 16 タ系連用テ形 14 "代表表記:欲する/ほっする"
いる いる いる 接尾辞 14 動詞性接尾辞 7 母音動詞 1 基本形 2 "代表表記:いる/いる"
曲 きょく 曲 名詞 6 普通名詞 1 * 0 * 0 "代表表記:曲/きょく 漢字読み:音 カテゴリ:抽象物 ドメイン:文化・芸術"
を を を 助詞 9 格助詞 1 * 0 * 0 NIL
流して ながして 流す 動詞 2 * 0 子音動詞サ行 5 タ系連用テ形 14 "代表表記:流す/ながす 自他動詞:自:流れる/ながれる"
くれて くれて くれる 接尾辞 14 動詞性接尾辞 7 母音動詞 1 タ系連用テ形 14 "代表表記:くれる/くれる"
いる いる いる 接尾辞 14 動詞性接尾辞 7 母音動詞 1 基本形 2 "代表表記:いる/いる"
ので ので のだ 助動詞 5 * 0 ナ形容詞 21 ダ列タ系連用テ形 12 NIL
、 、 、 特殊 1 読点 2 * 0 * 0 NIL
心 こころ 心 名詞 6 普通名詞 1 * 0 * 0 "代表表記:心/こころ 漢字読み:訓 カテゴリ:抽象物"
@ 心 しん 心 名詞 6 普通名詞 1 * 0 * 0 "代表表記:心/しん 漢字読み:音 カテゴリ:抽象物"
が が が 助詞 9 格助詞 1 * 0 * 0 NIL
少し すこし 少し 副詞 8 * 0 * 0 * 0 "代表表記:少し/すこし 相対名詞修飾 用言弱修飾 修飾(デ格)"
平穏 へいおん 平穏だ 形容詞 3 * 0 ナ形容詞 21 語幹 1 "代表表記:平穏だ/へいおんだ"
を を を 助詞 9 格助詞 1 * 0 * 0 NIL
取り戻し とりもどし 取り戻す 動詞 2 * 0 子音動詞サ行 5 基本連用形 8 "代表表記:取り戻す/とりもどす"
つつ つつ つつ 助詞 9 接続助詞 3 * 0 * 0 NIL
ある ある ある 動詞 2 * 0 子音動詞ラ行 10 基本形 2 "代表表記:有る/ある 補文ト 反義:形容詞:無い/ない"
ような ような ようだ 助動詞 5 * 0 ナ形容詞 21 ダ列基本連体形 3 NIL
気 き 気 名詞 6 普通名詞 1 * 0 * 0 "代表表記:気/き 漢字読み:音 カテゴリ:抽象物"
が が が 助詞 9 格助詞 1 * 0 * 0 NIL
し し する 動詞 2 * 0 サ変動詞 16 基本連用形 8 "代表表記:する/する 付属動詞候補(基本) 自他動詞:自:成る/なる"
ないで ないで ぬ 助動詞 5 * 0 助動詞ぬ型 27 タ系連用テ形 9 NIL
も も も 助詞 9 副助詞 2 * 0 * 0 "連語"
ない ない ない 接尾辞 14 形容詞性述語接尾辞 5 イ形容詞アウオ段 18 基本形 2 "連語"
EOS

だが、もっとスランギーだったりすると結構厳しい。

そしてもっと問題なのは、MeCabから提示される情報は、喉から手が出るほど欲しいということだ。 そのため、形態素解析を使う前提にすると、MeCabが提示する情報を信じ切ってしまい、かなり特徴的な間違え方をするようになる。 これは、ある程度使っていればどんな風に話せばAIが混乱するか予測するのは難しくないレベルだ。

結局、形態素解析を使って解析する方法は自分の望む目的を達成できなかったため、断念したのである。

Erinaの文章解析

まず根本的な話として、テキストは

  • 形式的な文章として書かれたもの
  • コラム記事など口語的文章として書かれたもの
  • チャットなど口語を表現したのも
  • 音声を文字起こししたもの

で全く違う構造を持っている。

このことから、それぞれに合わせて「実用上出現する」言葉の構造を正規表現を用いて解析する手法を採用した。

これは、形態素解析エンジンを自前で実装するのに近い作業だが、手法が邪道もいいところである。

まず、原則としてこの解析器は句読点を信じる。 実際には特に統合失調症患者の書いた文章など、句読点がランダムである可能性もあるのだが、解析の余地がある限り句読点を信じて解析することになっている。

そして、例えば次のような正規表現を使うのである。

/.*?は.*?(?:[。..\s…‥]*|$)

これによってその文が「〇〇は△△だ」の形式たりえるかどうかを判定する。 実際にはこのケースにおいては「だ」の言い換えで構造が変わらない言葉があり、また終助詞がつく場合も構造は変わらないと考えられるから

/.*?は.*?(?:|です|じゃ|である)(?:|)?(?:[。..\s…‥]*|$)

のようになる。 もちろん、実際はもっと幅広い表記ゆれに対応しているため、ここまで単純なパターンを利用しているわけではない。

これで用意された構造のパターンすべてに対してマッチを行う。そして、マッチしたパターンをストアする。 場合によっては読点を挟まずに複合文になっている可能性があるため、このような場合はパターンの複合としてストアされる。

この状態から、文を起り部、目的部といった形に分割する。この分類の仕方は一般的な日本語学的共通認識のあるものではなく、Erinaの動作上それを確定させるのに必要な形式である。

ここで例えば「〇〇は△△だ」の形式に当てはまるものの、あまりらしくない認識になるもの(例えば「綺麗は僕だね」)には低いスコアがつき、自然なもの(「君は綺麗だ」)には高いスコアがつく。 つまり、この分類時にそのパートにおける核となるもの(特に名詞)を抽出するようになっている。

この段階ではものすごくマッチングインデックスを使うのだが、マッチングインデックスを使った操作というのは私が書いた中ではほとんど経験がなく、私としては「マッチでインデックスを利用したコード」というとこのコードが一番に思い浮かぶ。

だから、細かい言葉の違いというのはこのタイミングでは一旦捨てられる。

そして、最も高いスコアとなった構造がこの文における構造であるとみなす。

これにつづいて、意味的な認識を行う。 これは例えば「君は綺麗だからね」といった場合、単純に受け取れば賛辞なのだが、ひょっとしたら皮肉かもしれないし、そもそもこの文は「君」のことを言っているわけではないかもしれない。 例えば次の会話を考えみよう。

「あのアイドル、そんなに言うほど可愛くなくない?」 「君は綺麗だからね」

この場合、「君は綺麗だから大したことないと感じるのかもしれないが、君でなければ十分可愛いと感じられるだろう」という意味合いとなり、話題にしているのは「そのアイドルの可愛さ」についてであり、「君の綺麗さ」についてではない。

この解析器はこのような「取りうるニュアンス」を推定するようになっている。 解析器自体がどのようなニュアンスが正解であるかということを確定するわけではない。 これは、文脈を解釈する部分でexpectedとかaboutといった項目があり、それに基づいて「予期される話の流れとして最も自然なもの」を選択するという方法になっている。 (わからない時は素直な理解を選択する)

ちなみに、推定される言語的感情というパラメータもあるが、これは一般的なAIの挙動に近いものである。 (パラメータの算出方法が手動で調整されたという以外は)

文章解析手法の理由と目的

一番には、Erinaが扱うものの中心にあるのが綺麗な文章ではない、という点が大きい。

そもそも話者が怪しい日本語を話す可能性はかなり高く、であれば日本語的な正しさに基づく判定というのは実用性に乏しい。

そして実用的に考えると、言葉というのは

  • 意味
  • 意図
  • 感情

の3要素に分離できるので、分離された3アプローチをそれぞれ(解析結果を利用しつつも)別のパラメータとすることによりどういう観点から行動が連続しているのかということが理解できるようになっている。

そして、「意味」においては、言語を「正しく」認識する必要はなく、正しき認識しようとするとハマってしまうような問題を、「認識できればそれで良い」と考えれば怪しい日本語も比較的理解できるようになる。

これは、人が言葉を「意味的に近い語群」「音的に近い語群」に分類し、その近い語群をコレクト対象にした上で、記号化して解釈するからだ。例えば次の文

“あなたのことを今まであまり良く見ていなかったけど、こうして改めてみるととても綺麗な人だとわかった。”

に対して、意味的理解としては

“YOU be AD+ 綺麗 (update)”

で良いのである。

AD+というのは「とても」「すごく」「大変」など程度を増やす形容詞のことで、ここでのbeは実際にbeが入るかどうかはおいといて、「左辺の定義を右辺で行う」ということを意味している。 そして、それ以外の箇所は、「従来の定義を捨てて、新たな定義を獲得する」ことを意味する言葉であるから、updateであるということが分かればそれ以上の情報は必要ない。

これはあくまで意味的理解の話である。 意図としては評価を改めたことをYOUに伝えるというのは、YOUに対する接し方の変更を通知するものである可能性が高い。 また、与えられた文はこれだけだが、ここからさらに続くのであれば、これは全体をもって動機の説明である可能性がある(つまり、意味的にはbecauseであり、構造的には前置きである)。

こうした解釈は「意図的解釈」とするわけだ。

このような手法を採用する最大の理由は、「日本語が任意の箇所を省略できる言語である」という私の理解による。

例えばうなぎ文であるが、形態素解析に頼るとうなぎ文(「僕はウナギだ。」)というのは完全にハマる。 しかし、これを「任意の箇所を省略できる」と定義すると「僕(が注文するの)はウナギだ。」と解釈することができ、解決する。 同様にこんにゃく文も「コンニャクは(食べても)太らない(食べ物だ)」と解釈することができる。

ここで問題になるのが、「省略される/登場する助詞、接続詞が登場している言葉についているか否かは一定でない」ということである。 だが、意味を推定するための粒度にすると“I be うなぎ”あるいは“I do うなぎ”が得られ、“I do うなぎ”は正しい(X do Yというのは、Xが主体となる動詞の目的語としてYがあるという意味である)。 こんにゃくの場合、“こんにゃく be 太らない”で良い。この場合、こんにゃくの定義として「太らない」が与えられているという情報があるだけなので、こんにゃく自体が太らないのか、こんにゃくが太らないという属性を持っているのかというのは分からないのである。もし、これを明確に定義してしまうと未知語に対応できないものが出来上がるので、“こんにゃく be 太らない”という情報は“こんにゃく”が参照されたときに含みおくことで十分なのである。

こうした「言葉に対する曖昧な理解」を適用することで、「安定して会話がだいたい通じる」AIが出来上がる。 私が考えるに、結局のところこれが一番まともに言葉を理解するメソッドだし、そもそもこのメソッドは人間の言語認識・思考組み立ての手順にかなり近いのでAIの思考ロジックとしても適当である。

実際にこれを正解にするまでには、サンプルになったテキストに対してすべて正解できるようになるまで、繰り返し構造の追加、スコアリングの調整などを行った。 ここで機械学習に頼らず、教師データに対する正解をプログラム的に導けるように調整するのは、結局のところそっちのほうが早い上に精度が高いと判断したためである (もちろん、手間はよりかかるが)。

言葉の正しい認識と定義は言葉単独ではできない、と考えているので、この解析はあくまで文脈機能と組み合わせることを前提としている。

これがErinaの出発点となる実装であり、このアプローチをとったことがErinaがうまくいく原動力となった。

そして、このアプローチは単純な人工無能によるマッチングアプローチに対して発展的に到達できるというのもポイントだ。 単純なワードの検索から、助詞を挟んだ形式への対応に広げるのはPerlであれば(マッチングが常に正規表現であることから)難しくなく、そうして発展してきたことをうかがわせるものでもある。

実用主義的解析手段

このように構造だけを切り出して、結果が論理的に整合するように切り出していくと、捕らわれがちなディティールを切り落として本質だけをまとめることができ、そうすると「意外とパターンは少ない」ということに気づくことができる。 これは、複数の全く異なる語義が与えられていると思われている単語が、いずれの語義も底では共通しているということに気づくことができるのに似ている。

そしてまた、様々な手法やツールが、「正しい定義」に基づいているために実用上のものを処理できないという問題を抱えていることにも直面する。

Erinaの解析器が文章タイプによって異なる複数のメソッドを持っているのはこのためである。 文章タイプによって「実際に使われる言葉」が違うので、「想定される期待値と言い回しの一般性」が大きく変わってしまう。 だから、有力視する順序を変えなければならないし、中には文章タイプによってまず登場しないために無駄にひっかかってしまう構造もあったりするので、それらを除外するために異なる定義が使用されている。

特に会話起こしテキストに対して処理を行う場合、文脈依存や前提知識依存が激しいため、単独の文で意味を確定することはほとんどできない。これは、余人が聞いたときに話の内容が理解できないとの同じ問題であるため、言葉をより外形的にとらえてストアしていくことが必要になる。 (もっとも、これは解析器の振る舞いとして大きな違いがあるわけではない)