slimとkerasの計算グラフ
CPPXのXです。
tensorflowをぬるぬる書くためのライブラリであるslimとkerasをちょこっと比較しようかなと思います。
tensorboardを使いつつ、どのようなグラフが出来上がるのかを見たいと思います。
どっち使っても簡単に記述出来るし、どっちがいいの!?みたいなことです。
今回は、使用頻度が高い畳み込み層、プーリング層、全結合層を見ていこうかと思います。
slim, kerasのついでに生TF, tf.contrib.layersも見てみます。
では目次です。
環境
- python 3.5.3
- tensorflow 1.9.0
imports
import tensorflow as tf import numpy as np
使うモデル
input: 28x28@3ch
↓
conv
↓
max pool
↓
fully connected
こんな感じの適当ぶっこいたモデルを作っています。
入力はこれで統一しています。
inp = tf.placeholder(tf.float32, (None, 28, 28, 3), name="input")
生TF
slimもkerasも使わないで生のtensorflowで書いて見ます。
with tf.variable_scope("tensorflow"): with tf.name_scope("conv"): w = tf.Variable(tf.random_normal((3, 3, 3, 32))) b = tf.Variable(tf.random_normal((32,))) x = tf.nn.conv2d(inp, w, strides=[1, 2, 2, 1], padding="SAME") x = tf.nn.relu(tf.nn.bias_add(x, b)) with tf.name_scope("pool"): x = tf.nn.max_pool(x, [1, 2, 2, 1], strides=[1, 2, 2, 1], padding="VALID") with tf.name_scope("flatten"): x = tf.reshape(x, (-1, np.prod(x.shape[1:]))) with tf.name_scope("fc"): w = tf.Variable(tf.random_normal((x.shape[-1].value, 10))) b = tf.Variable(tf.random_normal((10,))) logits = tf.nn.bias_add(tf.matmul(x, w), b)
んひゃあ
初めて書きました。
グラフは以下のようになりました。
全体像です。
畳み込み層です。
プーリング層です。
全結合層です。
variableとかの中身は畳み込み層のものと変わらないので、展開しません。
コードは複雑ですが、出来上がるグラフは簡素でいいですね。
keras
Sequential使って書くのがkerasっぽいのですが、今回は使わずに書いています。
実際に中身は見ていないのであんまり言えないですが、おそらく出来上がるグラフに大きい影響は無いと思います。
with tf.variable_scope("keras"): x = tf.keras.layers.Conv2D(32, 3, strides=2, padding="SAME")(inp) x = tf.keras.layers.MaxPool2D(2)(x) x = tf.keras.layers.Flatten()(x) logits = tf.keras.layers.Dense(10)(x)
いい感じですね。
グラフは以下のようになりました。
全体像です。
畳み込み層です。
isinitializedみたいなのがありますね。
なんでしょうこれ、調べてもよくわかりませんでした。
プーリング層です。
まあ、変わりようが無いですよね。
全結合層です。
見やすいですね、keras。
ただ、中身を開いて見るとほんの少しだけごっちゃりしています。
slim
name_scopeを使うと、畳み込みとか全結合の重みがスコープの外にはみ出しちゃうので注意が必要です。
with tf.variable_scope("slim"): x = tf.contrib.slim.conv2d(inp, 32, 3, stride=2) x = tf.contrib.slim.max_pool2d(x, 2) x = tf.contrib.slim.flatten(x) logits = tf.contrib.slim.fully_connected(x, 10)
スリムですね。
グラフは以下のようになりました。
全体像です。
畳み込み層です。
プーリング層は、他と同様なので省きます。
全結合層です。
initializerとか開いて無いですが、kerasと同じようになっていました。
kerasよりもスッキリしてると思うのですが、どうでしょう。
ちなみに、variable_scopeを使わないとこのように中身がはみ出します。
個人的にはちょっとこの仕様がつらいです。
雑にループ回したい時など、name_scopeだと勝手に数値を後ろにくっつけてよしなにしてくれますが、variable_scopeだと名前を変える必要が出てきて、面倒臭っとなります。
誤差みたいな手間ですが、ループから出したり入れたりして試してると面倒臭くなりました。
tf.contrib.layers
これ、slimと全く同じものが出来上がりました。
一応載せますが、全体像です。
中身開いても全く同じものが出てきます。
slimとkerasの共存
今回話に上げたslimとkerasですが、機能的にはkerasの方が色々あります。
ただ、slimの書き方が自分好みだったので、kerasに移るかどうか迷っていました。
kerasを軽く触って見たところ、あっこれslimと共存出来るじゃんと気がつきました。
足りない機能は借りてくればいいのです。
例えばこんな感じです。
with tf.variable_scope("keraslim"): x = tf.contrib.slim.conv2d(inp, 32, 3, stride=2, activation_fn=tf.keras.layers.PReLU()) x = tf.contrib.slim.max_pool2d(x, 2) x = tf.keras.layers.GlobalAvgPool2D()(x) x = tf.contrib.slim.flatten(x) logits = tf.contrib.slim.fully_connected(x, 10)
PReLU使いて。とか
GAP使いて。とか
雰囲気で添えてあげてください。
おわり
slimとkerasで軽くベンチーマークとか取ったらよかったかもしれません。
またの機会にやろうかと思います。
slimとkerasですが、結局のところどっちがいいとか無い気がします。
グラフに関してはslimの方が見やすいかな って思いましたが、このぐらいの差なら人によって違うと思います。
好きな方使って、どうしても ってところを借りてくると良さそうです。
今回はslimベースでkerasを借りるのをちょろっとだけ紹介しましたが、kerasからslimを借りるのもきっと簡単に出来るはずです。