マサムネの部屋

RNNによる文章自動生成

自然言語処理(NLP)の分野に、文章生成があります。与えられた文字列から、文章を作るというものです。原理などについての詳しい説明は別の記事でする事にして、RNNで遊んでみる事が目標です。
太宰治風の文章を生成してみます。

スポンサーリンク

word2vec

人間は文字を認識できますが、コンピューターはそのままでは認識できません。文字や単語を数字からなるベクトルに置き換えてやる必要があります。この変換の事をword2vecと書く事が多いです。例えば、以下のように変換します。
I love Masamune. Masamune is cute. →0 1 2 3 2 4 5 3
出てきた単語に固有の番号 1 を与えて、ベクトルとしています。例えばI=0 , Masamune = 2です。
英語の場合は単語の区切りに必ず半角スペースがあるので、単語毎で見ても扱いやすい 2 です。しかし、日本語はそうはなっていません。文を単語レベルに分割してベクトルに変換することは一応出来ますが、それはそれで大変なので、今回は文字一つ一つに固有の数字を与える事にします。例えば
$$\begin{eqnarray}
masamune→0 1 2 1 0 3 4 5 \\
マサムネ→0 1 2 3
\end{eqnarray}$$
のように変換されます。日本語では1文字それ自体が意味を成すことは殆どないので、適当な数の文字の集まりを1つのデータとして扱います。次の文から、入力データと出力データを作ってみましょう。
マサムネはトゲトゲしていて可愛い。
数字に直すと、
0 1 2 3 4 5 6 5 6 7 8 9 8 9 10 11 9 12
となります。例えば、4文字を1つのデータとすると入力と出力は以下のようになります。
$$\begin{eqnarray}
((0,1,2,3) , 4) \\
((1,2,3,4), 5 ) \\
((2,3,4,5),6 )\\
((3,4,5,6),5)\\
\vdots\\
((10,11,9),12)
\end{eqnarray}$$

RNNによる文章生成

RNNについての解説記事は以下を読んでみてください。

リカレントニューラルネットワーク(RNN)
ニューラルネットワークモデルの一つに、リカレントニューラルネットワーク(RNN)と呼ばれるものがあります。自己相関の高いデータに対して有用なモデルです。RNN, LSTM, GRUの解説をして、映画レビューの分類問題で3つのモデルの特徴を掴みます。

RNNのモデルの特徴は、過去の情報の出力も教師データとして使う事です。RNN層は以下の図のようになっています。

RNN層

8文字からなる文字列が\( x_t \)にあたり、 \(h_t \)が \(x_t \)の後に来る文字の予測値です。
文章に対してRNNモデルを適用することで、著者独特の文章の流れや言葉選びも学習してくれるはずです。従って、1人の著者を教師データとして使う事で、その著者風の文章を生成することが出来るはずで す。

データの準備

今回は 青空文庫で公開されている太宰治の人間失格を教師データとして太宰治っぽい文章生成器を作ります。

人間失格 (太宰 治)
はしがき 私は、その男の写真を三葉、見たことがある。 一葉は、その男の、幼年時代、とでも言うべきであろうか、十歳前後かと推定される頃の写真であって、その子供が大勢の女のひとに取りかこまれ、(それは、そ…

テキストファイルが公開されているので、ダウンロードして何種類の単語から出来ているか3調べます。

text = open('ningen_shikkaku.txt', 'rb').read().decode(encoding='utf-8')
vocab = sorted(set(text))
print ('{} unique characters'.format(len(vocab)))
1763 unique characters

1763種類の単語から1つの作品が出来ていることが分かりました。単純な文字の数は約40万個です。
単語に数字を割り振り、文字をベクトルに直します。 8文字を1つのデータとしてモデルを学習させます。 モデルはGRUを使います。
遊ぶのが目的なのでコードは全部は載せません。tesnorflow の文章生成のチュートリアルのプログラムを少し弄っただけですので。

print ('{} ---- characters mapped to int ---- > {}'.format(repr(text[5:10]), text_as_int[5:10]))
#'私は、その' ---- characters mapped to int ---- > [1212   73   25   55   72]
def build_model(vocab_size, embedding_dim, rnn_units, batch_size):
    model = tf.keras.Sequential([
    tf.keras.layers.Embedding(vocab_size, embedding_dim,
                              batch_input_shape=[batch_size, None]),
    tf.keras.layers.GRU(rnn_units,
                        return_sequences=True,
                        stateful=True,
                        recurrent_initializer='glorot_uniform'),
    tf.keras.layers.Dense(vocab_size)
  ])
    return model
RNNを使用したテキスト生成  |  Text  |  TensorFlow

人間失格→走れメロス

人間失格を学習したモデルで、走れメロスから続けて140字生成してみます。

メロスは、自分の心情は、いまに具合いがって来た、という言葉がは、それ以来、シゲ子の本性を見つからなければならないのです。 それをこでも、まことに奇妙な、そうして、いう自分に対して、お巡りの生活に、自分は、正面切っての議論の、世間という化を演じさせるに、アパートの屋上に駈けるほどだ、た。 

激怒してくれませんでした。句読点の多さには太宰っぽさ 4 を感じます。
シゲ子の本性を見つからなければらないのです。が
シゲ子の本性を見つめなければならないのです。
だったらかなりそれっぽい感じでした。
次は、メロスには から続けて140字生成させてみます。

メロスには知っている)それを読まれて自分がわいて来て、狂人という事になりました。けれども、自分はそのお金を使ってしまうのでした)その一言が、奇妙に自分の、震えおの貧した一つ、真人間あつかいにしていました。演説がすんで、そのお金で、思い切ってひとりで南伊豆の温泉に行ってみたりなどしていたとし

政治が分からぬ、とは言ってもらえませんでした。「狂人という事になりました。」からの「お金を使ってしまうのでした。」には太宰治というより人間失格を感じます。メロスは、から始めた文章よりもそれっぽい文章が仕上がっています。特に、お金を使ってしまうという文の後に、お金で南伊豆の温泉に行くという文が来るのは凄いです。お金の用途をなんとなくモデルが学習していることが分かります。
もっと大量に教師データを使えば激怒したり政治が分からんと言ってもらえるのかもしれませんが、今回はお遊びという事で終わっておきます。

まとめ

  1. 普通は大文字小文字は区別しません。
  2. プログラムを書くのが楽という事です。
  3. 前処理の過程は載せていませんが、改行やルビ、注を削除しています。
  4. 村上春樹でやったら絶対面白いですね。Twitterのbotに既にありそうですが。