機械と小説
これは小説ではないです。エッセイとしていますが、別にエッセイでもないです。なので、興味ないよという方はブラウザバックしてください。
あと素人なので、解説とかは割と適当なところがあるので、あまり鵜呑みにしないでください。
最近、「幽霊でも役に立てますか?」の続編を書いているんですが、なかなか思ったように筆が進まないので、気晴らしに文章生成をやってみることにしました(あわよくば機械に書いてもらいたいという気持ちも…(笑))。
本来ならここにエッセイとしてあげることではないと思いますが、僕はブログもやってないし、かといってtwitterでは長すぎるし、割烹だと画像があげられないので、それと一応なろうの小説をデータとして使用しているので、まあ結局ここにあげておくのが良いかとなって、こうして書いているという次第です。
最近何かと話題のいわゆるAIやら深層学習やら言われる方法でやってみましたが、今回は本当に軽く触ってみたというだけなので、そんなに大それたことはしていません。今は便利なもので、個人で簡単に実装できるようにライブラリが充実していますし、そもそも簡単な文章生成のコードだったらネット上で公開されているのがあるので、それをちょちょっと拝借して、なろうの小説データで学習してみたというだけのことです。
なろうのデータといっても、内容ばかりは許可取りとかしないといけないのかなと考えたら非常に面倒になったので、自分の書いた末田くんシリーズの長編三作を使いました。
以下、その結果です。最初の四十字は初期値として固定(小説中からランダムに抽出)しているので、実際に機械が書いてくれたのはそのあとです。延々続かないように、四百字くらいで打ち止めしています。
まずはエポック数が1での結果です。エポック数は学習の回数で、これが大きくなればなるほどよく学習して、結果が良くなるんですが、かといって大きくしすぎると過学習を起こして汎用性がなくなってしまいます。まあ、過去問を何週も勉強したけど、実際の試験では新傾向の問題が出てきて全然できなかった、みたいな感じです。
背景黒の文字緑なのは、某ゲームの影響です(笑)。見づらかったらごめんなさい。
エポック数が10での結果です。
エポック数が50での結果です。
なんか全然うまくいってませんね(笑)。
一つの原因としては、使ったソースコードが文字ベースのモデルを実装しているので、そのせいかもしれません。つまり今回は40字をひとまとめに入力して、その40字の次に来るであろう一文字を予想して出力、入力に使った40字のうち、後ろ39字に出力の1文字を加えた40字をまた入力して、さらに次の一文字を予想して出力……。といった感じでやっています。もともとが英語のデータに使われていたコードなので、文字といってもアルファベットとカンマやピリオドくらいと種類が少ないので、多分それなりの精度が出るんだと思いますが、今回は日本語の小説なので、ひらがなカタカナのみならず漢字にアルファベットに数字…と文字種類がたくさんになってしまっているため、正しい予測が出にくくなってしまっているようです。
そこで、一旦文章をカタカナに直して、文字種類を減らしてからやってみました。
手作業で全部仮名に直すのは地獄の作業なので、MeCabという形態素解析エンジンを使用しました。
形態素解析というのはまあ、こういうことをするやつです。
これだけ見ててもなんか面白い感じがしますが、今回はこれの読み仮名の部分を使って、文章を仮名に直します。とはいえ、魔法のツールではないので、辞書にない単語は正しく変換できません。僕の小説の場合、特に名字や名前がヘンテコなので、全然ちゃんと変換できませんでした。本来なら辞書にそうした単語を加えてやるべきなんですが、なんかうまくいかなかったので、あきらめてそのままにします。
これで文字種類が大体10分の1くらいには小さくなりました。
で、以下がエポック数1、10、50での結果です。出力が全部仮名で読みづらいので、Googleの文字変換使って変換してみた結果を出しています。
う~ん、やっぱり全然うまくいってませんね。なんかところどころそれっぽいような部分もあるんですが、ちゃんとした単語ができていない部分もあります。これはまあ、文字ベースでやっているので仕方がないですね。単語ベースで、つまり40単語を入力して次の一単語を出力する形にしてやってみるのも手かもしれません。
今回の結果としては、機械に小説なんてまだまだ無理といった結果になってしまいました。結局自分で書くしかないですね(当たり前)。
まあ、一番単純なモデルを使っているので、深層学習というよりも浅層学習とでもいったほうが正しい気がするくらいなので、もっとモデルの構造を深くしたり、パラメータを調整したりすることで、もうちょっと良い結果が得られるんじゃないかなあとも思います。また、入力する時には文章をベクトルに直す必要があるんですが、今回は単純に出現する文字一つ一つに番号を割り振って、その番号の羅列を入力としています。
例えば、こんにちは。とかいう文があって、
こ:10,は:37,ん:20,ち:25,に:42,'。':50
こんな感じの対応表があったら、
こんにちは。の文は[10,20,42,25,37,50]の6次元のベクトルで表せます。
ただ今回のこの方法だと、ちょっとシンプルすぎるので、word2vec(char2vec)と呼ばれる手法を使って文字ごとにベクトルにする方法を使ってやってみるのもありかと思います。この方法を使うと、文字と文字との間の関係性とか、例えば、’俺’と’私’という二文字は意味的に似ているとかいうのを捉えられたりするので、もうちょっとよくなるのかなあとざっくりそんな考えでいます。
あと他には、seq2seqと呼ばれる、対話システムとかGoogle翻訳とかにも使われているモデルがあるんですが、それを使うと、文と次の文との間にちゃんとした関係が生まれて、もっとよくなるんじゃないかと思います。
暇とやる気と結果が得られたら、またこうしてあげようかなとも思ってますので何卒よろしくお願いします。