Kerasモデル(.h5)をTensorFlowモデル(.pb)に変換して使用する方法

# KerasモデルをTensroFlowモデルに変換したい
 Keras（今回は、TensorFlow内蔵のKerasを使用する前提です）で学習したモデル(.h5）をTensorFlowモデル（.pb）に変換して使いたくなったときに色々ハマったのでメモです。

　バージョンは以下の前提です。

- TensorFlow==1.15.0
- Mac OS 10.13.6（変換時）
- Keras==2.3.1（変換時）

　モデルの学習時と変換時でTensorFlowのバージョンは合わせておくのが良いでしょう。単体のKerasは変換のときのみ使用します（学習時は、TensorFlow内蔵のKerasのみでOKです）。私の環境では、Kerasのバージョンが、新し過ぎてもエラーになったので注意しましょう。

## 学習
　この記事の本題ではないので省略します。TensorFlow内蔵のKerasで学習して下さい。今回はGoogle Colaboratoryを使用しました。学習に関して詳しく知りたい方は、Keraのチュートリアルや以下参考記事を参照下さい。

[ラズパイマガジン2020年2月号にAI特集記事を寄稿しました](https://karaage.hatenadiary.jp/entry/2020/01/15/073000)

[「Google Colaboratory」を使って簡単にディープラーニングで画像認識ができるチュートリアル](https://note.com/karaage0703/n/n7bc5dd2d8e51)

## KerasモデルとTensorFlowモデルの変換
　以下リポジトリのkeras_to_tensorflow.pyというスクリプトで変換できます。
[GitHub:amir-abdi/keras_to_tensorflow](https://github.com/amir-abdi/keras_to_tensorflow)

　ただ、そのままだと私の環境では不都合だったので、forkして修正したリポジトリを用意しました。

[GitHub:karaage0703/keras_to_tensorflow](https://github.com/karaage0703/keras_to_tensorflow)

　変更点は以下です。

- TensorFlow内臓のKerasで学習したモデルが読み込めなかったので修正
- pbデータを確認するスクリプトを追加

　使用する場合は、以下でcloneして変更したブランチをcheckoutして下さい。

```sh
$ git clone https://github.com/karaage0703/keras_to_tensorflow
$ git checkout develop
```

　変換するコマンドはREADMEに書いてありますが、スクリプトと同じディレクトリに`mode.h5`というKerasモデルを置いた場合は以下となります。

```sh
$ python keras_to_tensorflow.py --input_model="model.h5" --output_model="model.pb"
```

　TensorFlow内蔵のKerasで学習した場合、最初`ValueError: Unknown initializer: GlorotUniform`というエラーが出たので、以下のようにスクリプトをTensorFlow内蔵のKerasを使用するように書き換えて対応しています。

```python
-        model = keras.models.load_model(input_model_path)
+        model = tf.keras.models.load_model(input_model_path)
```

　他、Kerasのバージョンによっては、以下のようなエラーが出たので、冒頭のKerasのバージョンに変えることで対処しました。

```
Error while reading resource variable dense/bias from Container: localhost. This could mean that the variable was uninitialized. Not found: Container localhost does not exist h5 pb
```


## TensorFlowモデルの中身確認
　TensorFlowモデル（.pb）に変換できましたが、どう使えばよいのかわかりませんね。

　そのためにpbファイルの中身を確認するスクリプトを用意しました。以下コマンドで、先ほど作成したpbファイルの中身をチェックできます。

```sh
$ python check_pb.py -m='model.pb' --logdir='LOGDIR'
```

　ずらずらと、モデルのレイヤーの情報がテキストで表示されます。

　TensorBoardを使えば、きれいに可視化された情報が見れます。TensorBoardは、以下コマンドを実行して下さい。

```sh
$ tensorboard --logdir='LOGDIR'
```

　あとは、ブラウザ（Google Chromeを使いました）で以下アドレスにアクセスします。

```
http://localhost:6006/
```

　最初画面に`import`というテキストが表示されているので、ダブルクリックすると以下のようにモデルの中身が表示されます。

<img width="760" alt="tf_pb.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/81919/fad9a8c1-068f-61de-c3c6-59718b129479.png">

　これでpbファイルの中身が見えましたね。

## 変換したpbファイルの使い方
　入力のレイヤーが`import/conv2d_input:0`で出力のレイヤーが`import/activation_3/Softmax:0`と分かったので、例えば入力に対してモデルの出力を得たい場合は、モデルを読み込んだ後に以下のように書きます。

```python
output_tensor = sess.graph.get_tensor_by_name('import/activation_3/Softmax:0')
output = sess.run(output_tensor, feed_dict = {'import/conv2d_input:0': X})
print(output)
```

　画像の推論をする場合の簡単な例を、リポジトリに`load_pb.py`という名前で保存してあります。


# まとめ
　KerasモデルをTensorFlowモデルに変換して使用するまでをまとめてみました。変換するまでしか書いてなくて、どう使ってよいかちょっと手間取ったのでまとめてみました。しかし、やはり生TensorFlowはできれば触りたくないですね。

# 参考リンク
- https://toxweblog.toxbe.com/2018/06/07/tensorboard-open-pb-file/
- https://docs.microsoft.com/ja-jp/azure/cognitive-services/custom-vision-service/export-model-python
- https://leimao.github.io/blog/Save-Load-Inference-From-TF-Frozen-Graph/