日本語T5を使って文章生成　〜ヒロアカのキャラ名予測〜

## 概略
- 今回、「 [僕のヒーローアカデミア](https://heroaca.com/) 」のキャラの個性名と個性の説明から名前を生成するタスクを行いました。
- モデルは日本語で事前学習された [T5](https://arxiv.org/abs/1910.10683) (Text-to-Text Transfer Transformer)を使用しています。
- キャラは136人程度で学習データがかなり少なくても比較的良さげな名前を生成できました。
- 任意のデータを用意すれば転移学習を行い、文章生成を試せる [コード](https://github.com/toshi835/t5-generation) をあげています。

## はじめに
自然言語処理についてあまり触れたことがない方もこんなことができるんだなぁと知っていただきたいので記事を書かせていただくことにしました。

今回、アニメで放送中の「 [僕のヒーローアカデミア](https://heroaca.com/) 」（ヒロアカ）のキャラの個性名と個性の説明から名前を生成するタスクを行いました。
ヒロアカのキャラは個性と名前に関連があります。なのでその関係を学習して名前を生成してみようということです。

最終的には、自分が生成を試してみたいと思うデータを集めたcsvファイルを用意するだけで転移学習を行い、文章生成するコードを紹介します。
プログラムについてもよくわからないという方もExcelでデータを集め、指示に従いGoogle Colaboratoryで実行すれば文章生成にトライできます。

## 使うモデルについて
近年、自然言語処理のあらゆるタスクにおいて、大量のコーパス（言語データ）で事前学習を行ったモデルが素晴らしいスコアを記録しています。
その中でも今回使用するのはGoogleが2019年後半に発表した [T5](https://arxiv.org/abs/1910.10683) (Text-to-Text Transfer Transformer)というモデルです。
利用するには大量のデータで事前学習した後に、特定のタスクに用いるデータで転移学習を行う必要があります。
モデルの機構や事前学習に関しては詳しい [解説記事](https://www.ogis-ri.co.jp/otc/hiroba/technical/similar-document-search/part7.html) があるので参考にしてください。

今回は [日本語で学習されたT5](https://qiita.com/sonoisa/items/a9af64ff641f0bbfed44) を使用させていただきました。モデルだけではなく、転移学習の [サンプルコード](https://github.com/sonoisa/t5-japanese) も提供してくださり、ありがとうございます。
今回はサンプルコードを元にし、任意のデータで転移学習を試せるようにしました。

## ヒロアカの名前予測
### データ集め
実験に用いるデータを集めるところから始めます。
[こちらのサイト](https://milacle39.com/2021/03/08/%E3%83%92%E3%83%AD%E3%82%A2%E3%82%AB%E5%80%8B%E6%80%A7%EF%BC%86%E7%95%B0%E8%83%BD%E4%B8%80%E8%A6%A7%E8%A1%A8%E3%82%92%E4%BD%9C%E3%81%A3%E3%81%A6%E3%81%BF%E3%81%9F%EF%BD%9C%E3%83%92%E3%83%BC%E3%83%AD/) と [wiki](https://ja.wikipedia.org/wiki/%E5%83%95%E3%81%AE%E3%83%92%E3%83%BC%E3%83%AD%E3%83%BC%E3%82%A2%E3%82%AB%E3%83%87%E3%83%9F%E3%82%A2) を参考にさせていただいてデータを作成しました。


モデルの入力は「個性名: 説明」で統一しました。
データのサイズは136人分、時々個性の説明がないキャラクターもいます。
それにしても136キャラもいるんですね、驚きました。

データはこのようになりました。

|名前|個性|
|:---:|:---:|
|緑谷出久|ワンフォーオール: 個性を譲渡する個性。先人が培った力を内包しており、それを発揮することができる。|
|爆豪勝己|爆破: 掌の汗腺からニトロのような物質を出して爆発させる。爆風をりようして移動や加速もできる。|
|轟焦凍|半冷半燃: 右半身で凍らせ、左半身で燃やす。その範囲・威力共にビルを丸ごと凍らせる程、規格外！|
|...|...|

ここで悩ましいのが本名とヒーロー名やヴィラン名の扱い方です。 エンデヴァーは轟炎司という本名がありますよね。
今回は個性により関連性があるのはヒーロー名より本名の方だと考えたので極力本名で統一することにしました。
ヒーロー名やヴィラン名しかないキャラはそのまま使用しています。

### データの分割
それでは集まったデータを訓練データ、開発データ、テストデータに分割していきます。
簡単に言うと、開発データで調整しながら訓練データを使ってモデルの学習を行い、結果をテストデータで確認するという流れです。

訓練：開発：テスト = 8 : 1 : 1 としています。内容としてはtrain_test_splitで分割するだけです。

```python:preprocess.py
df = pd.read_csv("data.csv", index_col=0)
df_train, df_devtest = train_test_split(df, random_state=0)
df_dev, df_test = train_test_split(df_devtest, test_size=0.5, random_state=0)

df_train.to_csv("./train.tsv", sep="\t")
df_dev.to_csv("./dev.tsv", sep="\t")
df_test.to_csv("./test.tsv", sep="\t")
```

しかし、今回、テストデータがうろ覚えのキャラばっかりだと面白くありません。
なので、緑谷出久、切島鋭児郎、上鳴電気あたりを手作業でテストデータに持ってくることにしました。その際に、緑谷出久と八木俊典(オールマイト)は同じ個性を持っているので、八木俊典は開発データに移動してもらいました。

### 学習
データを使って学習していきます。
とは言っても、T5を読み込んで学習データを元に、モデルの重みを更新していくだけです。
ここでは詳しい内容は省略させていただきます。詳しい内容を知りたい方は、先程記載した解説記事やコードを参照してください。

今回のデータはGoogle ColaboratoryのGPUを使って1epoch1分くらい、合計10分以内で終わりました。

### テスト
それでは学習ができたのでテストデータを使って生成してみます。
結果は以下のようになりました。

|生成結果|名前|個性|
|:---:|:---:|:---|
|ワン・フォー・オール|緑谷出久|ワン・フォー・オール: 個性を譲渡する個性。先人が培った力を内包しており、それを発揮することができる。|
|足蹴飛龍|飯田天哉|エンジン: ふくらはぎにあるエンジン器官により超瞬足が可能。そのかそくを利用して強力な攻撃を放てる。|
|ガットガット|切島鋭児郎|硬化: 全身をガチガチに硬化。効果部位は鋭利な形状で防御だけでなく刃物のような斬撃効果を持つ。|
|帯電可憐|上鳴電気|帯電: 体に電気を纏い、自身を中心に放出。出力数を調整する事で携帯電話の充電などもできる。|
|猿田彦太|尾白猿夫|尻尾: 頑丈で力強い尻尾が生えている。敵を叩きつけたり、柱に巻き付けて猿のように移動もできる。|
|無重力空間|麗日お茶子|無重力: 指先の肉球で触れた3tまでの物体を無重力状態にできる。自分に発動すれば宙も浮ける。|
|風間勇人|夜嵐イナサ|旋風: 微細なコントロールで無数の風を操る。自身を宙に浮かし飛ぶ事や対象物を動かす事も容易い。|
|護身拳|拳藤一佳|大拳: 人が覆えるサイズまで両拳を巨大化できる。パワーアップした拳は金属製の盾をも破壊する。|
|超硬質硬質|真壁漆喰|硬質化: 生物以外の物体を、こすったりこねたりして超硬質の武器を生成。|
|浮島浮遊|志村菜奈|浮遊: 体を宙に留める個性。|

いかがでしょうか。個人的にはよく出来ている名前が多いと感じました。

### 考察
結果からいくつか考察をしたいと思います。

デク(緑谷出久)に関しては、個性と名前に関連性はないので新しい名前を命名しようくらいのつもりで考えていたのですが、「ワン・フォー・オール」とそのまま出てしまいました。
そう、気づいた方はいるかもしれませんが、原因は「オール・フォー・ワン」が訓練データにいたことです。彼は個性も名前も「オール・フォー・ワン」です。それを学習して個性と名前が同じになったようです。

切島くんは学習データにいたヒーロー名のデータを踏襲してガットガットと出たようです。

上鳴くんは帯電可憐と女性っぽい名前になりました。確かに性別はデータとして与えていないので、もし上鳴くんが女性だったらこんな名前だったかもしれません。

お茶子ちゃんの結果はあまり良くないものとなりました。無重力空間という単語を出力してしまっているのでもう少し改善の余地がありそうです。

それ以外はあり得そうな名前ですね。面白いです。(飯田くんが足蹴飛龍というのはかなり強そうですね。)

これらより、今回かなり少ないデータ量でも改善の余地はありますが、生成が比較的行えることがわかりました。

以上でヒロアカのキャラ名生成は終了です。

## 任意データでの生成
これから自分で用意したデータを使ってT5で生成を行う方法を説明していきます。
まず、どのようなときにT5を使うといいのか言及したいと思います。  
- **新しいタスクがどれくらいできそうなのかさっと試す**
  自然言語に携わっている方がこんなタスクって実際にできるのかなって気になるときにまずはT5で試してみることが考えられます。
- **アイデアが思いつかない時**
  文章にタイトルをつけたいけどいいのが思いつかないとか、今回のヒロアカのような、答えが明確にあるわけではないアイデア重視の生成をしたいときに試してみると色んな種類を出して提案してくれると思います。
- **純粋な興味**
  とりあえずなにか生成してみたいという創作意欲の高い方におすすめです。
  
なにかを生成しようと決めたら、以下の順番に沿って行ってください。

**使い方**  

1.生成したい文章とその入力となるデータを用意します。
2.そのデータを用いて、以下のようなcsvファイルを作成し、*data.csv*と名前をつけて保存します。

``` csv:data.csv
生成したい文章, 入力  
..., ...  
..., ...  
```

3.[こちらのコード](https://colab.research.google.com/drive/1eFtsJ2UgD0hvYU2ROsS2FaSm8QY9PlEv?usp=sharing) を開く
4.ランタイムから「ランタイムのタイプの変更」を行い、GPUを選択する
5.左のファイルマークを選択し、*data.csv*をアップロードする
6.ランタイムから「すべてのセルを実行」を選択
7.結果を確認する  


### 補足
- 現状、長文から短文を生成することは比較的できますが、短文から長文を生成するのは難易度が高いと思われます。
- 一般にデータは多いほうが良い結果が得られますが、今回は学習データが約100文対でも生成は行えました。参考にしてください。
- [Github](https://github.com/toshi835/t5-generation) に生のテキストを入力したら生成結果を複数種類出力するコード(test_raw.py)も作成したので元からPythonや自然言語処理の知識がある方は試してみてください。
- 本コードの利用はあくまでも趣味での利用を想定していますので、万一利用者に何らかの不都合があった場合も作者が責任を負うものではありませんのでご了承ください。

## おわりに
この記事を通して、どなたでもデータさえ準備できれば数ステップで文章生成に取り組めるということが伝われば幸いです。   
今回使用したソースコードは [Github](https://github.com/toshi835/t5-generation) で公開していますので、 もし面白いと思っていただいた方は、LGTMやGithubのスターをよろしくお願い致します。

## 参考
- [Exploring the Limits of Transfer Learning with a Unified Text-to-Text Transformer](https://arxiv.org/abs/1910.10683)
- [【日本語モデル付き】2021年に自然言語処理をする人にお勧めしたい事前学習済みモデル](https://qiita.com/sonoisa/items/a9af64ff641f0bbfed44)
- [https://github.com/sonoisa/t5-japanese](https://github.com/sonoisa/t5-japanese)  
- [T5 によるテキスト生成の検証](https://www.ogis-ri.co.jp/otc/hiroba/technical/similar-document-search/part7.html)