こんにちは。最近MC battleにハマっております、ISID 金融ソリューション事業部の若本です。
イベント現場にも何度か足を運んでおり、行くたびにその月で一番大きい声を出しています。
さて、そんなラップにがっつり影響を受け、今回はラップができるAIを作成してみます。
なぜ韻を検索するのか ~GPTでできるよね?~
その前に、2023初頭の現在、工夫なしにAIで高度なラップはできません。
なので、まずは韻を検索することから始めます。
「ChatGPTとかで普通にできるんじゃないの?」
と思われた方もいると思います。手始めにChatGPTに日本語でラップをさせてみましょう。
確かにラップしていますし、凄いことに違いはありません。が、真面目なラップすぎてヘッズには物足りません(個人の主観)。
これは、ChatGPTが韻を理解していないことが原因です。バースの意図はしっかり伝わりますが、肝心な韻がほぼ含まれていません。韻を理解していない理由は多々考えられますが、LLMにとって難しい問題設定になっているのと、データが足りていないの2つが主に考えられます。要は、ChatGPTに韻を踏ませることはできません。
ChatGPTが韻を理解していないことは確認できました。
とはいえ、ラップ自体はそれらしくできるので、韻だけ与えてラップさせてみましょう。
先ほどのラップよりいい感じです。ラップできるやつ感が増しました。
韻をあらかじめ与えてあげることで、実際のラッパーに近いラップが実現できそうです。
とはいえ、毎回韻を指定するのは面倒なことこの上ないですよね。なので、まずは似た韻を検索する仕組みを構築します。
韻について
そもそも韻には下記のような種類があります。
完踏み
母音が完全一致するフレーズの組み合わせ
e.g.) 「AI」(e-e-a-i)と「明細」(e-i(e)-a-i)語感踏み
母音を濁したフレーズの組み合わせ
e.g.) 機械学習(i-a-i-a-u-u-u)とハイ拍手(a-i-a-u-u)その他
頭韻
前方の母音を合わせた組み合わせ
e.g.)「機械学習」(i-a-i-…)と「嫌いなやつ」(i-a-i-…)脚韻
後方の母音を合わせた組み合わせ
e.g.)「AI」(e-e-a-i)と「限界」(e-n-a-i)
上記のうち、完踏みはフレーズの母音同士の一致率を計算するだけで済みます。これは、後述の古典的手法でも十分可能です。
しかし、語感踏みのような単語、例えば「文字数が明らかに違うけれど、早口にすると似て聞こえるような単語」は拾ってくることができません。
そこで、今回は「語感踏み」まで踏み込んだプログラムを目指します。
実用的な韻に必要なもの
上記を満たしていれば実用的な韻になるのかと問われると、答えは「否」です。
実際に使える"韻"を踏むためには、下記をはじめとして考慮すべき点があります。
- 英語も比較できる
ラップでは英語のフレーズもたびたび登場します。そのため、日本語と英語を比較できることも重要になります。 - 意味的結びつきが強い単語を重視できる
前述の「AI」と「明細」で韻は踏めていますが、これらの単語で話を繋げることに苦労します。韻を踏みつつ、話を繋げやすい単語を選択する必要があります。 - 結果がすぐ出る
次々と言葉を紡ぐ必要があるので、すぐ結果が出ることも重要です。
上記以外にも実用上の観点が諸々あるかとは思いますが、今回は最低限上記に対応したいと思います。
韻を検索するAI
今回ベースとするのは、Universal Sentence Encoderによって得られたベクトル表現です。
つまり、"韻"の情報をベクトル表現にします(以降、これを韻beddingと呼称します)。
やることは非常に簡単で、1) 単語の読み方のうち母音だけ残し、2) 母音を連結した文字列(韻)からベクトルを取得します。
韻をベクトルすることにより、下記のようなメリットが享受できます。
- 韻をベクトル化することにより、「全体的な語感が近い単語」を引っ張ってくることができる(仮説)
- 検索速度が早い(ベクトルの最近傍探索ができる)
- 単語の意味と同じ尺度で評価できるようになる
つまるところ「うまい、安い、早い」です。
事前に作成したフレーズ集の各単語について、2つのベクトル表現を取得します。
ここで、単語embeddingは単語の意味的な情報が、韻beddingは韻の情報が格納されています。
上記のようにして作成した韻bedding、単語embeddingをもとに、検索した単語と近いものを返します。
ベクトル近傍探索ライブラリであるfaissを用いて、韻beddingから近い韻を持つものをN件取得し、その後下記の計算式で昇順ソートします。
※今回はユークリッド距離を用いたため昇順ソートしています。cosine類似度×降順でも問題ありません。
類似度 = α×韻の類似度+(1.0-α) ×単語の類似度
αはお好みで0.0~1.0の間で変えてください。今回は単純に韻の精度が知りたいため、α=1.0の結果を見てみます。
使用したデータ
mecab-ipadic-NEologdの辞書の一部を使用しました。
データとしては約10万語ほどの量になります。
結果
韻beddingでは下記のような結果が得られました。検索ワードは「エンジニア」です。
別単語扱いの「engineer」が最上位に来ているのがポイント高いです。英語でも検索できていることが分かります。
次点の「メスシリンダー」も踏まれるとクスっとなりそうなので良いです。語感踏みのようなことができていますね。
とはいえ、そもそもベクトルでやる必要があるの?と思われるかもしれません。
そのため、文字同士の類似度を計算する手法で試した結果も確認してみます。
- レーベンシュタイン距離
- ジャロ・ウィンクラー距離
- ゲシュタルトパターンマッチング
既存の手法はどれも似た結果になりました。
検索速度に目を向けると、ベクトル検索が5倍以上の差を付けています。
今回の単語/フレーズ数は約10万です。1万を超えるとベクトル検索のほうが早くなってくる印象でした。
1検索速度 (s) | |
---|---|
韻bedding | 0.036 |
レーベンシュタイン距離 | 0.194 |
ジャロ・ウィンクラー距離 | 0.183 |
ゲシュタルトパターンマッチング | 3.708 |
検索の質としても、文字数の制約が緩いベクトル表現のほうが面白い韻は多く(完全に好みですが)、韻beddingの採用価値はあると感じました。
おわりに
今回作成したAIによって、登録したフレーズからそれらしき結果は得ることができました。
一方、検索だけでも下記のような課題が残っています。
- アクセントの考慮が不十分
今回の手法では、発音のアクセントまで考慮した検索はできていません。
アクセント記号を含める処理(pyopenjtalkなど)を噛ませることでアクセントもある程度考慮に含めることはできそうです。 - フレーズ数の不足
事前に登録するフレーズを増やすことが重要ですが、これを集めるのが大変です。
本記事ではmecab-ipadic-NEologdを使いましたが、「韻は踏めるものの使いづらいワード」も多くなってしまうので、データソースは気を付ける必要があります。 - 単語の組み合わせでマッチングできない
今回試した方法では、「登録してあるフレーズ」の中から韻を踏めるものを探しています。より実用的なものにしていくためには、単語の組み合わせからマッチングすることも考えていく必要もありそうです。
次回は、満を持して検索した韻から自動でラップ生成を行います。(Part. 2に続く)
ここまでお読みいただきありがとうございました。
執筆:@wakamoto.ryosuke、レビュー:@yamada.y
(Shodoで執筆されました)