Reformerによる文章生成を日本語で行う

# 概要
2020年1月16日にGoogleによって公開された**Reformer**のcolab環境を使用して、手動入力した**日本語**の続きを自動的に生成してみます。

# 背景
2020年3月現在、言語翻訳やチャットボット、自動作曲などのサービスが当たり前のように社会に組み込まれています。これらの実現のために使用されているディープラーニング技術は、2016年頃までは**RNN**や**LSTM**が主流でしたが、2017年の7月に発表された**Transfomer**で高い精度を得られることが分かると、研究分野を中心に次第にTransfomerに切り替わっていきました。

そして、2020年1月16日にGoogleから「[Reformer: The Efficient Transformer] (https://ai.googleblog.com/2020/01/reformer-efficient-transformer.html)」というタイトルの記事が発表されました。Reformerは、タイトル通り「効率的なTransfomer」ということで、処理速度と使用リソース面でTransfomerから改善が行われています。

ディープラーニングの世界では、大量のデータを使って高い精度を追い求めると、どうしてもメモリ等のリソースが不足しがちです。ところが、今回の改善では仮にキーワードが100万個あったとしても16GBのメモリサイズで処理が可能になったそうです。

改善内容の詳細は、公式記事を見ていただければと思いますが、個人的には以下2つの工夫点によって処理が効率化されたと理解しています。

##### Reformer効率化の要点
1. LSH(locality-sensitive-hashing)による処理速度向上
これまでのTransformerでは、長いシーケンスのデータを取り込むとAttention処理で計算量が増えてしまいました。
Reformerでは、ハッシュ関数を使用して各キーワードをチャンクと呼ばれるグループに振り分けて、分散表現の近い単語同士を同じチャンク（あるいは隣のチャンク）に集めることで計算量を減らしています。また、チャンク毎の並列処理によっても処理速度を向上させています。

2. reversible residual layersによる使用メモリ量削減
Transformerでは、大規模なデータを取り込んで数千もの層で処理を行うと、テラバイト級のメモリが必要になることもあります。Reformerでは、reversible layersを使用して、ディープラーニングの各層の情報をメモリに保存せずに逆伝播時に再計算することによって、使用するメモリサイズを少なくしています。

# 前提
難しいことはさておき、今回、試したことを整理します。 
####試したこと
Googleが公開した英語の自動生成のサンプルコードを使って、日本語も同じように自動生成できるかを試しました。日本語の質を追求している訳ではなく、それらしい文章を生成するところまでです。
精度、処理時間、使用メモリ量などに関して、Transformerとの比較は行っていません。

####実行環境
実行環境は、オリジナルと同じGoogle colab環境です。ipynb形式をchrome上で実行しています。
オリジナルのサンプルコードは、TPUを使用するように定義されており、colab環境での実行に最適化されているようです。
（補足ですが、ローカルのCPU環境でも学習までは処理が進んだことは確認しました。）

なお、今回の試行では、日本語を生成するためにデータを変えながら何度も試行を重ねています。
その過程をご覧になりたいかたは、「[こちら](https://qiita.com/artisanbaggio/items/389df4e42762022d4e37
)」を参照してください。

# 試行結果
### オリジナルを実行
何はなくとも、まずは公開されているオリジナルをそのまま実行してみます。

- [オリジナルcolab実行環境(Google Colaboratory)]
(https://colab.research.google.com/github/google/trax/blob/master/trax/models/reformer/text_generation.ipynb)

オリジナルの処理で何をやっているかというと、ドストエフスキーの小説「罪と罰」を学習してモデルを作成後、任意に入力した「There was a time when」に続く文章を自動生成しています。

1. 学習データの読み込み
読み込むファイルのパスは、「gs://」となっており、Cloud Storage内に公開ファイルとして置かれていますので、気にせずにそのまま実行します。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276223/69720f2b-bde4-287a-7346-e4261d10daf3.png" width=80%>

2. 学習(1step)
学習は「train_epoch」にて行っていますが、1stepしか学習していないため、精度や損失は非常に悪いです。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276223/19efb7cd-6b03-1474-7e24-98a8a29218d6.png" width=80%>

3. 文章生成1
最後に「There was a time when」に続く文章を8パターン自動生成しています。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276223/aafe4fb2-d8d0-ab3b-83ad-311d5316844c.png" width=90%>
パッと見て単語の並び順は合っていそうですが、よく読むと、「There was a time when the door , 」のように変な位置にカンマが登場していて、理解できない文章も多いです。


4. 学習(600step)
学習量を600stepに増やしてみると、精度が72%にまで向上しています。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276223/f38f6e4c-098f-7a30-3d11-f758b39e856a.png" width=80%>

5. 文章生成2
この状態で再度文章を生成してみると、まだ理解に苦しむ部分は残っていますが、先ほどよりは改善しているようです。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276223/359e9645-280a-d2f9-e346-3768df2c9f99.png" width=90%>


### 日本語を生成
日本語のWikipediaを学習してみます。

- 学習成果
600stepまで学習すると精度44%まで到達しました。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276223/6211ed9a-a6b3-dd15-eec8-880b0d40ec8a.png" width=85%>

- 文生成
文章はまだ改善の余地はありますが「映画とは、」に続く文章を生成させてみると、何となく日本語らしい文章が出力できています。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276223/a5f07f08-73f3-dfa2-7d03-9f1b56c4f61f.png" width=85%>

英語と同様に日本語も割と簡単に生成できましたので、今後、学習を重ねることでより自然な日本語を生成できそうです。

以上

# 参考資料


- [Reformer発表資料(Google AI Blog)]
(https://ai.googleblog.com/2020/01/reformer-efficient-transformer.html)
- [colab実行環境(Google Colaboratory)]
(https://colab.research.google.com/github/google/trax/blob/master/trax/models/reformer/text_generation.ipynb)
- [論文2020年2月18日版(arxiv) （初版は2020年1月13日登録）]
(https://arxiv.org/abs/2001.04451v2)
- [ソース(github)]
(https://github.com/google/trax/tree/master/trax/models/reformer)
- [質問コミュニティ(gitter)]
(https://gitter.im/trax-ml/community)