TensorFlowは「テンサーフロー」か「テンソルフロー」か？TensorFlow自身に聞いてみる。

この記事は、 [TensorFlow Advent Calendar](http://qiita.com/advent-calendar/2016/tensorflow) 2016 25日目の記事です。

今年の10/7、TensorFlow UserGroup (TFUG) が発足しました。
「TensorFlow User Group立ち上げの儀」 に私も参加させていただいたのですが、そこで議題となったのが 「TensorFlowの読み方(カタカナ表記)」 でした。その場で多数決をとって、TFUGとしては 「テンソルフロー」 にすることに決定したのですが、思い通りに進まないのが世の常。

- TFUG コアメンバの多数決の結果、 TFUGでは 「テンソルフロー」 に統一することに決定
- TFUG #1 で、 NHKの取材が入り、 「テンサーフロー」 と書かれる
- Googleの中の人に聞くと 「テンサーフロー」 だと言われる

と、混乱を極めております。そこで、 TensorFlow Advent Calender の締めくくりとして、TensorFlow 自身に呼び方を決めてもらおうと思います。

## 全体方針

さて、TensorFlowのカタカナ表記を決めるにはどうしたらよいでしょうか。

英語の「TensorFlow」をカタカナに翻訳できれば良いでしょう。幸いにも、翻訳は深層学習の典型的な応用例の1つです。TensorFlowでの翻訳事例もたくさんあります。TensorFlowに興味のある方であれば下のような図を見たことがあると思います。

![image](https://qiita-image-store.s3.amazonaws.com/0/24770/41d08db3-769c-69a7-9bf2-e25ed72809bf.png)

これは、「sequence to sequence」 と呼ばれるモデルで、深層学習を使って翻訳や要約する定番のモデルです。最近高精度化した Google 翻訳でも用いられている手法ですし、この記事でも、このモデルの派生系を使ってカタカナへの翻訳を試みます。


### Sequence to Sequence モデル

sequence to sequence モデル自体については、いろいろな記事で紹介されているので、詳しい解説はそちらにおまかせして、ここでは概要だけ説明します。

深層学習にかぎらず、機械学習には最適なパラメーターを探す「学習」フェーズと、見つけたパラメータで予測をする「推定」フェーズがありますが、イメージのつきやすい「推定」フェーズからみてみます。

#### 推定フェーズ

まず、上記のネットワークは入力データを固定長の長さに圧縮する「エンコーダー」部分と圧縮された情報から出力を生成する「デコーダー」部分にわかれます。

![image](https://qiita-image-store.s3.amazonaws.com/0/24770/687ba15f-dad3-4e79-b5cb-111e6fe0be6e.png)

エンコーダーでは、入力文字列を1文字づつ読み込んで、都度状態を更新していきます。上記の例ですと、

1. t を読み込んで状態(初期値)を更新
2. e を読み込んで、 1. の状態をさらに更新
3. n を読み込んで、 2. の状態をさらに更新
4. ...

という流れになります。状態の初期値は適当(ゼロ配列など)に決め、最後の文字まで更新された最後の状態がエンコーダーの出力となります。「更新」ってなんやねん、となりそうですが、そこは学習フェーズで適切な更新方法を探すことになります。
一方、デコーダーでは、エンコーダーの出力をもとに、一文字づつ文字を出力を生成していきます。上記の例ですと、

1. BOS を読み込み、エンコーダーの出力(状態)を更新。ついでに次に来るべき1文字を推定する (テ)
2. 1.で推定した文字(テ)を読み込んで、1.の状態をさらに更新。ついでに次に来るべき1文字を推定する (ン)
3. 2.で推定した文字(ン)を読み込んで、2.の状態を更に更新。ついでに次に来るべき1文字を推定する (ソ)
4. ...

となります。

#### 学習フェーズ

さて、次は学習フェーズです。

![image](https://qiita-image-store.s3.amazonaws.com/0/24770/fd8a9199-078a-1b98-48d7-cca9699a4f3b.png)

sequence to sequence では、エンコーダーとデコーダーをまとめて学習します。
入力は翻訳元の文字列と翻訳先の文字列を BOS(※ 翻訳先の文字列に含まれない文字であればなんでもよい)でくっつけたものです。
出力はデコーダーに対応する部分の出力がちょうど翻訳先の文字列となるように、「更新方法」を学習していきます。
入力に翻訳先の文字列(テン...)も含まれますが、 BOS のお陰で出力とは1文字づつずれていて、「次の文字を予測する」形となっているのがポイントですね。


## データ準備

さて、今回の例に sequence to swquence を利用するには、エンコーダーに英語表記、デコーダーにカタカナ表記を入力すれば良さそうです。要するに英語表記とカタカナ表記のペアが必要になるのですが、そういったデータセットを手に入れることはできるでしょうか?
きれいなデータセットがあるに越したことはないのですが、さっと調べた限りでは使えそうなものはありませんでした。そこで今回は無料の英和辞書から日本語表記カタカナのものを抽出することで代替します。パっと思いつくデータソースは以下の２つです


|データソース|概要 |
|:---:|:--- |
|[EJDICT](http://kujirahand.com/web-tools/EJDictFreeDL.php)|無料の英和辞書|
|[Wikipedia](https://ja.wikipedia.org/wiki/Wikipedia:%E3%83%87%E3%83%BC%E3%82%BF%E3%83%99%E3%83%BC%E3%82%B9%E3%83%80%E3%82%A6%E3%83%B3%E3%83%AD%E3%83%BC%E3%83%89)|日本語ページと英語ページの両方がある記事のタイトルを辞書とみなす|

それぞれダウンロードして中身を見てみましたが、EJDICTは前処理が大変そうだったのと、データ量がWikipediaのほうが多かったので、今回は Wikipedia を利用することとしました。

### Wikipedia データ加工

Wikipdeia では、クローリング/スクレイピングしなくてよいように、データの[ダンプ](https://ja.wikipedia.org/wiki/Wikipedia:%E3%83%87%E3%83%BC%E3%82%BF%E3%83%99%E3%83%BC%E3%82%B9%E3%83%80%E3%82%A6%E3%83%B3%E3%83%AD%E3%83%BC%E3%83%89)を用意してくれています。Wikipediaのダンプにはいろいろな種類がありますが、今回は以下の２つをダウンロードすれば十分です。

|ファイル名|内容|用途|
|:--:|:--:|:--|
| jawiki-latest-page.sql.gz | ページ情報 | タイトルを取得する |
| jawiki-latest-langlinks.sql.gz | 別言語ページへのリンク情報 | 英語ページのタイトルを取得する |

以下の処理をして約66,000個の 英語・カタカナ の対を得ることができました。

1. 適当なMySQLに２つのテーブルをリストア
2. 日本語のページと英語のページを JOIN して、 csv ファイルにダンプ
3. 正規表現を用いて、日本語側がカタカナ(と数字)のみの行を抽出
4. 大文字を小文字に変換

できたファイルは[こちら](https://gist.github.com/ohtaman/0a466ae6f93a07efa8e78ba87527db8b)にあります。
見ていただけるとわかると思うのですが、まだまだ汚いので、翻訳の精度を上げるには、もっと抽出条件条件を詰めたほうが良さそうです。

## TensorFlowでの実装

データが準備できたので、あとは実装するだけです。
sequence to sequence モデルは、TensorFlowの[チュートリアル](https://www.tensorflow.org/versions/master/tutorials/seq2seq/#sequence-to-sequence-models)にもなっているので、そこをベースに実装するのが賢いやり方です。私が過去に対話ボットを作った際にも、チュートリアルを参考に実装し~~て発狂しそうになり~~ました。

生のTensorFlowで書いても良いのですが、最近は [Keras](https://keras.io/ja/) や [TFLearn](http://tflearn.org/)、 [TF-slim](https://github.com/tensorflow/tensorflow/tree/master/tensorflow/contrib/slim) など、TensorFlowを容易に使えるライブラリが増えてきています。
今回は、最近 TensorFlow本家のリポジトリに取り込まれた skflow (tensorflow.contrib.learn) を使~~います。~~おうと思っていたのですが、諸事情により断念しました。とは言え、結構苦労しながら手を動かしたので、断念した経緯やskflowの使い方・ベストプラクティスなどについて別記事にまとめようと思います。

というわけで、今回の実装は生のTensorFlowで書いたものとなります。[第5回 TensorFlow 勉強会](https://connpass.com/event/38073/)での[発表](https://docs.google.com/presentation/d/1Qk1wq5IhY-VhUdrjkDH3N7J8E1y3YHWC3HJTvE5FXmY/pub?start=false&loop=false&delayms=3000&slide=id.p)に使った VAE(Variational Auto Encoder)という sequence to sequence の派生系のネットワークをそのまま利用しました。
VAEのネットワーク構造は以下のとおりです。

![image](https://qiita-image-store.s3.amazonaws.com/0/24770/930d55c8-29eb-88f2-276c-1311ce4436a8.png)
<cite>[Generating Sentences from a Continuous Space](https://arxiv.org/pdf/1511.06349.pdf)</cite>

エンコーダーとデコーダーの間に見慣れないものが入っていますが、基本的に普通の sequence to sequence と同じことができます。このネットワークの詳細については、[発表資料](https://docs.google.com/presentation/d/1Qk1wq5IhY-VhUdrjkDH3N7J8E1y3YHWC3HJTvE5FXmY/pub?start=false&loop=false&delayms=3000&slide=id.p)を御覧ください。

## 学習経過

100000ステップ学習してみた結果は以下のとおりです。最近のGPUを積んでいるマシンであれば1-2時間程度だと思います。
言語生成系のモデルは、学習過程が面白いですね。

|ステップ数|tensorflowのカタカナ表記の推定値|
|--:|:--|
|0|ヱ|
|100||
|500|ー ト ラ ー ル|
|1000|ン ト ラ ン|
|2000|ン ト ラ ン|
|5000|ト ラ ト ラ イ ン|
|10000|テ ン ロ フ ィ ア|
|20000|ン ド|
|30000|テ ン コ ラ ブ|
|40000|テ ン コ ル フ|
|50000|ン ス ホ ル フ ル|
|60000|テ ン コ ル フ ォ|
|70000|テ ン ル フ ォ ー|
|80000|テ ン ス ル フ|
|90000|テ ン ス ル フ|
|100000|テ ン ス ル フ ォ ル|

徐々に学習されているのが見て取れますね。
パラメーターのチューニングや学習ステップの増加など、やるべきことはたくさんありますが、この記事としてはここで終わりではないぞよ、もうちっとだけ続くんじゃ、と言いたいところですが、ここで終わります。m(_ _)m

## 結論

TensorFlow さんに聞いたところ、 TensorFlowは 「テンスルフォル」 でした。「テンソルフロー」か「テンサーフロー」といってほしかったのですが、新たな候補がでてきてさらに混沌としてきました。

## 感想

- tf.contrib.learn 鬼門すぎる

## おまけ

Google さんに聞いてみました。

[<img width="812" alt="スクリーンショット 2016-12-05 10.16.40.png" src="https://qiita-image-store.s3.amazonaws.com/0/24770/6f0151ca-3fdb-b514-0222-c811714312aa.png">](https://translate.google.co.jp/?ie=UTF-8&hl=ja&client=tw-ob#en/ja/tensorflow)

間違っていると思われる方はフィードバックするとかえてもらえるかもしれません!