地平線まで行ってくる。

記録あるいは忘備録。時には検討事項。

マルコフ連鎖による文章自動生成 #4 しっかり学習させると。

 pythonのお勉強とおもって「文章自動生成」にチャレンジ中。これまで分かち書きした文章の教師用データを作ってお試しでの文章自動生成に成功しました。今回は「猫」という言葉が入っている応答形式のツイートを一週間かけて集めたデータを使います。

 幾つかのテキストファイルにしちゃっているので、学習データのディレクトリに.txtファイルを置いておくと順に読み込んでくれるようにしました。トラブルで再開しやすいように、学習データは学習したら削除することにしました。

 

 ./corpus_data : 学習ファイル

 tweet_learned_data.json : 学習結果

 

#!/usr/bin/env python3
# -*- coding:utf-8 -*-
from glob import iglob
import re
import markovify
import os
import gc

def main():

learned_data = "tweet_learned_data.json"

if os.path.exists(learned_data):
with open(learned_data) as f:
combined_model = markovify.Text.from_json(f.read())
else:
print("no learned data.")
combined_model = None

#

for (dirpath, _, filenames) in os.walk('./corpus_data'):
for filename in filenames:
with open(os.path.join(dirpath, filename)) as f:
print(filename)
text_model = markovify.NewlineText(f, retain_original=False, state_size=2)

if combined_model:
combined_model = markovify.combine(models=[combined_model, text_model], weights=[1.0,1])
else:
combined_model = text_model

sentence = combined_model.make_sentence()
print(''.join(sentence.split()))
gc.collect()

with open(learned_data, 'w') as f:
f.write(combined_model.to_json())
print("saved")

#remove learned file.
os.remove(os.path.join(dirpath, filename))


if __name__ == '__main__':
main()

  Qiitaを中心に色々と参考にさせていただきました。ありがとうございます。

 

 これで学習させると・・・116Mの学習ファイルが出来上がり。

 

 文章を生成します。

 malkov_sentences.txt に200文例を表示します。単なる単語になりがちなので短い20文字以下は保存しません。

import os
import markovify

def main():

learned_data = "tweet_learned_data.json"

if os.path.exists(learned_data):
with open(learned_data) as f:
text_model = markovify.Text.from_json(f.read())
else:
print("no learned data.")
exit()

#
sentence = text_model.make_short_sentence(130, tries=10, max_overlap_ratio=0.7, max_overlap_total = 10)
print(str(len(sentence)) + ":" + ''.join(sentence.split()))

if len(sentence) > 20:
# save make sentences data
with open('malkov_sentences.txt', 'a', encoding = 'UTF-8') as f:
f.write(''.join(sentence.split()) + "\n")
else:
print("canceled")

if __name__ == '__main__':
for var in range(0,200):
main()

 で結果。

  • 猫を好きになる犬種分からんもんまで買っててドラズの中にはヒトのことなんだけど、野良猫でした。ガルボ食べるのにゃ!
  • 猫のやつをいつでもダンボールの可能性もありませんが可愛いので野良がいたので里親さん募集。Twitterログアウトしちゃった
  • 人慣れしてるんだけど最後らへんですね。️
  • そんで、これはたまらんですが、新猫が飼いたい。とても猫が、馬だけでも癒されます。
  • 1猫みたいにしてればあまり分からないが、神明かけてたら、次のゲーム。⁇何系男子高校生の頃から猫って毛玉ができて綺麗にするのよ。ボランティア減るぜ」→ちゅき。

 

 なんとなく、変な文書の生成に成功!しかし、ツイートの文章だからか、文章らしからないものが多い場合も。

 

 マルコフ連鎖の場合は、前後の言葉の関係性を学習するけれども、それが2つの言葉なのか3つなのか・・・で決定される。ツイートの場合は文書が短いためか、3つ以上にすると学習したデータが似かよることが多い。また、複数学習データをまとめて学習データにするという手法の場合は、それぞれのモデルの weights を調整することもできる。もうちょっと工夫できるところも多い。

 

 データが大きくなるとメモリーをあっという間に食い尽くして慌てたりと勉強しながらなんとか文章の自動生成ができるようになって、ほっとしました。 

 

 と、ここまでで、分かち書きまで前処理したデータを使って学習データを作成し、文章を生成するところまでてきました。初期目標はある程度達成。とりあえず、ツイートまではやってみたいと思います。

 

 つづく

 

 

bwgift.hatenadiary.jp