OpenAIのChatGPTやGoogleのBardなど生成AIがこの頃盛んですね。
今回はそれに便乗(?)して、それっぽい文章を書くAIもどきを作りたいと思います。
この記事が向いている人
- Malkov連鎖で遊びたい人 or 学びたい人
- Macabをインストールしたい人(下までスクロールしてください)
Markov連鎖とは
未来に起こることを、現在の事象のみで予測すること。
確率的に未来の事象を予測。
天気での例
上の天気での例では、今日の天気が晴れの時、
- 40%で次の日も晴れ
- 50%で次の日は曇り
- 10%で次の日は雨
となります。
また、「現在の事象のみ」で未来のことが決まるため、「晴れ→雨→曇り→晴れ…」と現実ではありえないことが出力されることもあります。
文章にあてはめる
例として、「私はトマトが好きです。」と「私は休みが欲しいです。」という文があるとき、
その単語間の関係は次のようになります。
この関係をモデルといいます。
このマルコフモデルでは、形態素(各単語)をノード(結び目、集合点、節)としています。
この時、ランダムでノードを選択していくと、
「私はトマトが欲しいです。」という文が新たにできます。
これがMarkov連鎖での文章生成の仕組みとなります。
用意するもの
- Windows Python3環境(pip)
- 使いたいデータ
実際にやってみる
必要なものをインストール
MeCab
https://github.com/ikegami-yukino/mecab/releasesにアクセスし、LatestのexeをDL&実行
Pathも通しておきます。
<MeCabインストールフォルダ>\Mecab\bin
上記のパスをを環境変数に追加しておきましょう。(自分の環境のものに置き換えてください)
mecab -v
が正常に帰ってきたらOKです。(できなかったら再起動など)
Pythonライブラリ
pip install mecab-python3
pip install markovify
動作確認用に下記のコードを実行してみてください。下のような返答があればおけです。
import MeCab
mecab = MeCab.Tagger()
target_str = "私には、走っていると思っていた時期があった。"
print(mecab.parse(target_str))
私 名詞,代名詞,一般,*,*,*,私,ワタシ,ワタシ
に 助詞,格助詞,一般,*,*,*,に,ニ,ニ
は 助詞,係助詞,*,*,*,*,は,ハ,ワ
、 記号,読点,*,*,*,*,、,、,、
走っ 動詞,自立,*,*,五段・ラ行,連用タ接続,走る,ハシッ,ハシッ
て 助詞,接続助詞,*,*,*,*,て,テ,テ
いる 動詞,非自立,*,*,一段,基本形,いる,イル,イル
と 助詞,格助詞,引用,*,*,*,と,ト,ト
思っ 動詞,自立,*,*,五段・ワ行促音便,連用タ接続,思う,オモッ,オモッ
て 助詞,接続助詞,*,*,*,*,て,テ,テ
い 動詞,非自立,*,*,一段,連用形,いる,イ,イ
た 助動詞,*,*,*,特殊・タ,基本形,た,タ,タ
時期 名詞,副詞可能,*,*,*,*,時期,ジキ,ジキ
が 助詞,格助詞,一般,*,*,*,が,ガ,ガ
あっ 動詞,自立,*,*,五段・ラ行,連用タ接続,ある,アッ,アッ
た 助動詞,*,*,*,特殊・タ,基本形,た,タ,タ
。 記号,句点,*,*,*,*,。,。,。
EOS
もととなるデータを用意
今回は青空文庫にある「走れメロス」を使用しました。
そのままコピペするとルビ(以下)が紛れ込んでしまいます。
そのため、ブラウザのConsoleからコードを実行してコピペ、input.txtに保存。
Array.from(document.querySelectorAll('rt')).forEach(el => el.remove());
形態素解析でモデル生成&出力
import markovify
import MeCab
# 読み込み(input.txt)
with open("input.txt", "r", encoding="utf-8") as f:
text = f.read()
# 形態素解析
parsed_text = MeCab.Tagger('-Owakati').parse(text)
print(parsed_text)
# モデル作成
text_model = markovify.Text(parsed_text, state_size=2, well_formed=False)
# 出力
for _ in range(10):
sentence = text_model.make_short_sentence(100, 20, tries=100).replace(' ', '')
print(sentence)
メロスは、おまえらは、二度、口から血が噴き出た。
メロスは、ゆらゆら地平線に没し、まさに最後の死力を尽して、ほっと溜息をついた。
メロスは両手で掬って、「ただ、――」と言いかけて、てれていた。
メロスは、よくよく不幸な男であったが、喉がつぶれて嗄れた声で低く笑った。
メロスは疾風の如く走り出た。
メロスは悪びれずに答えた。この嘘つきに騙された。
メロスは、あたりをはばかる低声で低く笑った。
メロスは、よろよろ二、三日目の前に引き出されて走ったのだ。生意気なことを命じて居りました。
メロスは、王は、よろよろと歩き出し、家へ帰って来るというのです。三日目の前に一隊の山賊が躍り出た。
メロスは、嗄れた声で精一ぱいに努めて来た。「とんでもない嘘を言うわい。どうせ帰って来た。
…..\(^o^)/
だいぶ怪しいですが、一応出力はされました。
意味を理解しているわけではないため、いろいろ混ざってしまっていますが、文法上の間違いは少ないです。
まあ何にせよ成功したためよかったです。
「メロスは」以外から始まるよう改善
import markovify
import MeCab
text = ""
# 読み込み(input.txt)
with open("input.txt", "r", encoding="utf-8") as f:
for i in f.read().split('\n'):
text += MeCab.Tagger('-Owakati').parse(i)
print(text)
# モデル作成
text_model = markovify.NewlineText(text, state_size=2) #ピリオドではなく改行で1文を判定
#state_sizeを伸ばせば伸ばすほど長文になります(5が上限、あげるほど単調になる)
# 出力
for _ in range(10):
sentence = text_model.make_short_sentence(100, 20, tries=100).replace(' ', '')
print(sentence)
ロスは、すぐに出発した時から正直な男のままにして死なせて下さい。
メロスは口惜しく、地団駄踏んだ。再び立って走れるように深く眠った。
それを聞いて王は、すぐに出発した時、メロスの十六の妹も、きょうは兄の、正直者とかいう奴輩にうんと見せつけてやりたいものさ。
群衆の中からも、きょうは兄の、正直者とかいう奴輩にうんと見せつけてやりたいものさ。
勇者は、ひどく赤面した。暴君ディオニスは、ものも言いたくなくなった。
どっと群衆の中からも、きょうは兄の、疲労困憊の姿を見つけて驚いた。
山賊たちは、単純な男であった。メロスの懐中からは短剣が出て仕事をはじめていた。
妹は頬を殴った。メロスの右頬を殴った。
どっと群衆の中からも、消えようとした時、メロスをひしと抱きしめた。
セリヌンティウスは、正義の士として死ぬ事が出来るぞ。ああ、陽は既に高く昇って、
「メロスは」以外から始まるようになりました。
おわりに
今回は、PythonのライブラリであるMarkovifyを使用して、それっぽい文章を生成する方法を紹介しました。
ただ、原因不明の挙動をすることが多かったため、もっと勉強する必要がありそうです。
この記事がどなたかの役に立てば幸いです。
それでは!
参考にさせていただいたサイト
https://omedstu.jimdo.com/2018/05/06/マルコフ連鎖による文書生成/
コメント