Tensorflow v2とTensorflowHub KerasLayerを使った最小の労力で自然言語処理

`Tensorflow v2` から利用できる[TensorflowHub KerasLayer](https://www.tensorflow.org/hub/api_docs/python/hub/KerasLayer)がすごい便利なので紹介。

データが少なくても簡単に自然言語系のタスクを実装できるようになり、Keras利用者にとって `KerasLayer` のおかげで `TensorflowHub` がもっと組み込みやすくなってます。

## そもそもTensorflowHubとは

https://tfhub.dev/

- 学習済みモデルを利用/公開できるサービス
- [https://tfhub.dev/](https://tfhub.dev/)で利用したいモデルを探す
- `pip install tensorflow-hub` とサンプルコードですぐ試せる
- 画像関連はもちろん、自然言語で日本語に対応したモデルもある
- 転移学習に利用できる

## 環境

私はpyenvを使っているので `pyenv` で `3.7.1` をインストール。

`tensorflow` と `tensorflow-hub` もインストールします。

`tensorflow` に組み込まれた `keras` を利用します。

```
$ pyenv install 3.7.1
$ pip install tensorflow==2.0.0 tensorflow-hub==0.7.0
```

## 簡単なnnlmを使ってみる

`TensorflowHub` からモデルをロードして文章をベクトル化できます。(これは以前と同じ)

このベクトルを自作のモデルなどに転移学習する事もできます。

```python
import tensorflow_hub as hub

embed = hub.load('https://tfhub.dev/google/nnlm-ja-dim128-with-normalization/2')
embed(['ネコ'])
```

```
<tf.Tensor: id=182, shape=(1, 128), dtype=float32, numpy=
array([[-0.10296704,  0.01587082,  0.0573468 ,  0.059175  , -0.03958198,
        -0.08217786, -0.14779228, -0.24691384, -0.07068112, -0.11670566,
        -0.08285586, -0.01857655, -0.04645912, -0.05692579,  0.0815312 ,
        -0.07908769, -0.05466406, -0.02179208,  0.10979927, -0.05734158,
        -0.06557054,  0.07709339,  0.12023042,  0.00258559, -0.07060173,
         0.10960913, -0.08923677,  0.06238426,  0.08451481,  0.14662118,
        -0.03688983,  0.10679894,  0.01809704, -0.08754648,  0.0429281 ,
         0.11621989,  0.11202757,  0.05788481,  0.00816733,  0.009843  ,
         0.05847297, -0.0869061 , -0.12621959,  0.04002178,  0.12822641,
         0.07994641, -0.00221055, -0.19458152, -0.02742083,  0.14718114,
         0.0555301 ,  0.11112078,  0.10370145,  0.08804794,  0.09565531,
         0.16998029,  0.05571814, -0.03676133,  0.08836656, -0.02724845,
         0.07221054, -0.04380354, -0.09449258,  0.01015431, -0.0904016 ,
         0.10437841,  0.0442632 , -0.06275094, -0.00733054, -0.0532412 ,
         0.05747321,  0.08354431,  0.14614691, -0.03355311, -0.04487225,
         0.018634  , -0.16693713,  0.01418052, -0.1447136 , -0.02863057,
         0.11374816, -0.02529281, -0.15476134,  0.00983464,  0.11917529,
         0.08267409,  0.01913127,  0.07049622, -0.08751827,  0.00729084,
        -0.03081291,  0.03002417, -0.03669447, -0.10596528,  0.045755  ,
        -0.07780168,  0.03002104,  0.12458465,  0.01451691,  0.01804689,
         0.03775274, -0.05732382,  0.06064591,  0.07148866, -0.16499299,
         0.21076469,  0.0302352 ,  0.08122093, -0.15884502,  0.06737471,
         0.0686043 ,  0.02858042, -0.067475  , -0.08131913,  0.03652628,
         0.0554016 , -0.13050069, -0.01471644,  0.13639897, -0.1885046 ,
        -0.16372472, -0.03479837,  0.02419067,  0.02371116,  0.02106602,
         0.10979195,  0.01713384, -0.01521267]], dtype=float32)>
```

## KerasLayerを使ってkerasに組み込んでみる

`KerasLayer` に対応したモデルだと `hub.KerasLayer` でkerasに組み込めるレイヤとしてロードできます。

[オリジナルのKerasレイヤーを作成する](https://keras.io/ja/layers/writing-your-own-keras-layers/)を見て実装する必要がなくなりました。

```python
import tensorflow as tf
from tensorflow import keras

hub_layer = hub.KerasLayer(
    'https://tfhub.dev/google/nnlm-ja-dim128-with-normalization/2',
    output_shape=[128],
    input_shape=[],
    dtype=tf.string,
)

model = keras.Sequential()
model.add(hub_layer)
model.add(keras.layers.Dense(64, activation='relu'))
model.add(keras.layers.Dense(16, activation='relu'))
model.add(keras.layers.Dense(1, activation='sigmoid'))

model.summary()
```

```
Model: "sequential"
_________________________________________________________________
Layer (type)                 Output Shape              Param #
=================================================================
keras_layer (KerasLayer)     (None, 128)               117568128
_________________________________________________________________
dense (Dense)                (None, 64)                8256
_________________________________________________________________
dense_1 (Dense)              (None, 16)                1040
_________________________________________________________________
dense_2 (Dense)              (None, 1)                 17
=================================================================
Total params: 117,577,441
Trainable params: 9,313
Non-trainable params: 117,568,128
_________________________________________________________________
```

## 雑に2値分類で学習してみる

10個とかなり少ないデータセットを用意しました。食べ物と動物を2値分類するタスクです。

雑に50エポック回してみます。

```python
model.compile(
    optimizer=keras.optimizers.RMSprop(),
    loss='binary_crossentropy',
    metrics=['acc'],
)

model.fit(
    [
        'ピザ', '寿司', 'ステーキ', 'パスタ', 'コーラ',
        'イヌ', 'ネコ', 'トラ', 'ゾウ', 'キリン',
    ],
    [
        0, 0, 0, 0, 0,
        1, 1, 1, 1, 1,
    ],
    epochs=50,
)
```

## 試してみる

```python
import numpy as np

model.predict(np.array(['ラザニア', 'チキン', '牛', 'ワニ', 'サル']))
```

```
array([[0.06712804],
       [0.10662787],
       [0.6637654 ],
       [0.8527697 ],
       [0.9033404 ]], dtype=float32)
```

ラザニアは94%、チキンは90%で食べ物と判定し、

ワニは85%、サルは90%で動物だと判定しています。

動物であり、割と食べ物な牛は66%で動物と、的を得ています。

`TensorflowHub` から転移学習しなければこんな少ないデータセットで学習する事など無理ですが、

簡単かつ強力なモデルを作る事ができました。

## さいごに

簡単に自然言語系のタスクを実装できる `TensorflowHub KerasLayer` を紹介しました。

[universal-sentence-encoder-xling-many](https://tfhub.dev/google/universal-sentence-encoder-xling-many/1)を転移学習させて質疑応答できるシステムを作ってますが、それ専用にカスタムモデル作ったり、[tensorflow/serving](https://github.com/tensorflow/serving)に載せる際にハマった事などいろいろあるのでまた今度紹介しようと思います。