[LSTM文章生成]ml5jsを使う

[Javascript Advent Calendar 2019](https://qiita.com/advent-calendar/2019/javascript) の24日目

## LSTMってなんぞや

文章データを学習したmodelに対して、始まりの文字を与え、次に来る文字を推測させるというものです。

## 利用したライブラリー

### ml5js
[ml5](http://ml5js.org)
tensorflowのモデルを使用しjsで扱いやすくしてくれる。

### tensorflow
モデル生成に利用します。
[tensorflow](https://www.tensorflow.org/) 

## 事前準備

### インストールするもの

- [Python](https://www.python.org/)
    - tensorflowを動かすために必要
- [Anaconda](https://www.anaconda.com/)
    - Pythonのディストリビューション。機械学習・科学計算で使うライブラリがまとまっている。Python本体もインストールされます。
- [pip](https://pip.pypa.io/en/stable/)
    - Pythonパッケージのインストールに利用する(TensorFlowはpipで入れます)
- [nodejs](https://nodejs.org/ja/)
    - ml5ライブラリーフロントエンド側を動かす為に利用する

私はAnacondaでPythonをインストールして、pipでTensorFlowをインストールしました。

### 環境
OS:windows 10
（ゲーミングPCです。負荷がそれなりにかかりそうと思いあえて。）

## トレーニング用セット
こちらをダウンロードします
[training-charRNN](https://github.com/ml5js/training-charRNN)

```
git clone https://github.com/ml5js/training-charRNN.git
```


## データを用意
後にも先にもここが一番大変な所なんですが、とりあえず動かせるようにする為、適当な文章データを用意しておきます。

日本語データを用意するのは文節等分ける作業が大変なので英語データにしましょう。日本語については後日まとめてみようと思っています。

ファイル名：input.txt
配置場所：training-lstm-master/[any_holder_name]/

input.txtに文章を入力し保存します。

### 参考データ
フリーで使える英文の小説や物語が公開されています。試しに利用するのであれば、こちらから元となるデータを用意してみるだけでも良いかと思います。
[Project Gutenberg](https://www.gutenberg.org/)


## トレーニングさせる

- AnacondaPromptを起動
- トレーニング用セットの、ディレクトリ配下に移動します。

```
cd training-lstm-master
```
- 作成したデータをトレーニングさせる

```
python train.py --data_path=./[any_holder_name]/input.txt
```

この後トレーニングが始まり、終わるとmodels/input/にファイルが生成されています。

### 生成されるファイル群

- embedding
- manifest.json
- rnnlm_multi_rnn_cell_cell_0_basic_lstm_cell_bias
- rnnlm_multi_rnn_cell_cell_0_basic_lstm_cell_kernel
- rnnlm_multi_rnn_cell_cell_1_basic_lstm_cell_bias
- rnnlm_multi_rnn_cell_cell_1_basic_lstm_cell_kernel
- rnnlm_softmax_b
- rnnlm_softmax_w
- Variable
- vocab.json

このファイル群を後で説明する[ml5-examples](https://github.com/ml5js/ml5-examples)で利用します。


### エラーが起きたら
私は、tensorflow最新バージョンを入れていたのですが、怒られたんですよね。
（その時のエラー内容はすみませんが千の風になってしまいました。）

仕方なく　**tensorflow　1.15.0**　を入れました。

1系の関数に書き換えないといけず、train.pyの下記を修正しています。

```
# hide logs
tf.logging.set_verbosity(tf.logging.ERROR)
```

↓

```
# hide logs
tf.compat.v1.logging.set_verbosity(tf.compat.v1.logging.ERROR)
```

まだフロントエンドの話になっていないので、アドベント的にこれいいのかなと不安に襲われる・・


## フロントエンド
やっとjavascriptの話にたどりつきました。
では先ほど作成したmodelを使ってみようと思います。

### ファイル群を移動

こちらをダウンロードします
[ml5-examples](https://github.com/ml5js/ml5-examples)

```
git clone https://github.com/ml5js/ml5-examples.git
```


nodejsのpackageを利用しているのでいつものやつ

```
npm install
```

### ファイル群を移動

先ほど生成したmodels/input/配下のファイル群を移動させる。

移動先
https://github.com/ml5js/ml5-examples/tree/release/p5js/CharRNN/CharRNN_Text/models/woolf

※inputフォルダは文章に合わせたフォルダ名にすることをお勧めします。

例）
猫についての文章
ml5-examples-master/p5js/CharRNN/CharRNN_Text/models/cat

占いについての文章
ml5-examples-master/p5js/CharRNN/CharRNN_Text/models/horoscope


### modelを指定する

sketch.jsにmodelsの指定があるので、「woolf」の所を先程models配下に作成したフォルダ名にする。

```
charRNN = ml5.charRNN('./models/woolf/', modelReady);
```

https://github.com/ml5js/ml5-examples/blob/release/p5js/CharRNN/CharRNN_Text/sketch.js#L24


### local serverを立ち上げる

python 3系

```
python -m http.server
```

python 2系

```
python -m SimpleHTTPServer
```

http://localhost:8000/ を開くとディレクトリが見えると思います。


### CharRNN Textを使う

pl5jsをクリック

![FireShot Capture 017 - Directory listing for _ - localhost.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28662/fb81a423-2f05-913d-f2ff-005ce99c25eb.png)

CharRNNをクリック
![FireShot Capture 018 - Directory listing for _p5js_ - localhost.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28662/895eb266-0a01-9b0f-1144-3081f4164e7f.png)

CharRNN_Textをクリック
![FireShot Capture 019 - Directory listing for _p5js_CharRNN_ - localhost.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28662/40a462f4-3c95-0d7d-f09b-03ad6c606c0d.png)

Generaterの画面にたどり着きます。

seed text: 最初に与える文字
length: 生成したい文字数
temperature: 重さ・深さ

![FireShot Capture 022 - LSTM Text Generation Example - localhost.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28662/b63c47ba-e4f1-8ecd-9a89-b03f2f023af9.png)

seed text:happy
length：100
temperature：0.5で生成した文章

```
happy and the other grown herself, 'I was than the bottle my to little sing how the poor comly up and gut
```
![FireShot Capture 023 - 翻訳 - Google 検索 - www.google.com.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28662/a5ffe0d3-7cf7-4ff0-5f27-24d0522f4e4f.png)



seed text:happy
length：100
temperature：1で生成した文章

```
happys! All spomes wife a 'How finE it?' said 'Hares" should neven backed as much had right gaim--'
```

![FireShot Capture 026 - 翻訳 - Google 検索 - www.google.com.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28662/a0d17959-f642-5a17-3804-7a85f32b7c5b.png)


文章としては支離滅裂です。

さて私は何の文章をデータとしたでしょうか。
後者の生成した文章にヒントが載っています。

ヒント「うさぎ」。

答え：[Alice's Adventures in Wonderland](https://www.gutenberg.org/files/11/11.txt)

後者の文章はtemperatureを1にしたので、前者(temperature:0.5)に比べて、よりAlice's Adventures in Wonderlandっぽい文章となっているはずです。

確かに「うさぎ」とか「権利」とかの部分にそれっぽさが出ているような気がします。


ml5.CharRNNについてもっと調べていきたくなりました。

[mecab](https://taku910.github.io/mecab/)を使い日本語の文章データを用意させれば日本語文章もいけるかも！という話をきいたので時間をみて、やってみようと思います。完全にjavascriptの話ではなくなる笑


## 参考記事
- [4_1_2：LSTMの訓練(「不思議の国のアリス」モデルの作成) ml5.js JavaScript](https://himco.jp/2018/12/31/4_1_2%EF%BC%9Alstm%E3%81%AE%E8%A8%93%E7%B7%B4%E3%80%8C%E4%B8%8D%E6%80%9D%E8%AD%B0%E3%81%AE%E5%9B%BD%E3%81%AE%E3%82%A2%E3%83%AA%E3%82%B9%E3%80%8D%E3%83%A2%E3%83%87%E3%83%AB%E3%81%AE%E4%BD%9C%E6%88%90/)
- [4_1_1：LSTM 文章生成サンプル ml5.js JavaScript](https://himco.jp/2018/12/30/4_1_1%EF%BC%9Alstm-%E6%96%87%E7%AB%A0%E7%94%9F%E6%88%90%E3%82%B5%E3%83%B3%E3%83%97%E3%83%AB/)