TensorFlowを扱う上ではテンソルの形状(shape)についての基礎知識は必須になります。
TensorFlowでは変数を作成するときも、変換するときにもshape
を使用するので、shapeの概念を知っておくことでTensorFlowを理解しやすくなり、デバッグも容易になります。
本記事では
- TensorFlowでのshapeの意味について
- 動的shapeと静的shapeにつて
- tf.shapeの使い方
- tf.get_shapeとの違い
について解説します。この記事を通して、shapeについて完璧に理解していきましょう。
テンソルのshapeとはなにか
以前、NumPyについて解説しているときに、ndarrayにshapeという概念があることを以下の記事で紹介しました。
NumPyのndarrayのインスタンス変数shapeの意味 /features/numpy-shape.html
基本的には、TensorFlowはndarrayのshapeと同様の意味を持ちます。仮に、以下のようにTensorをtf.contantを使用して呼び出してみましょう。
In [1]: import tensorflow as tf
In [2]: a = tf.constant(1, shape=[2, 3, 1])
In [3]: sess = tf.Session()
In [4]: sess.run(a)
Out[4]:
array([[[1],
[1],
[1]],
[[1],
[1],
[1]]], dtype=int32)
In [5]: b = tf.constant([[1, 2], [3, 4]])
In [6]: b.shape
Out[6]: TensorShape([Dimension(2), Dimension(2)])
最初のa
では、shape
を2 × 3 × 1の要素が1であるTensorを作成しています。次のb
では2つの要素が入った2つのテンソルなので、2 × 2になります。
計算グラフ内の動的shapeについて
これまで見てきたshape
計算グラフ外からみても計算グラフ内から見ても、明確に同一な値のshapeを持つNodeを作成しました。計算グラフの構築時にも実行時にも、作成したNodeのshapeは必ず指定したshape
になります。
しかしながら、shapeを指定したくない場合はどうすればいいのでしょうか。例えば、機械学習の文脈でバッチ学習するサイズを任意にしておきたい場合などが考えられます。推論時には、入力したいバッチサイズを動的に変更して、1枚でも1000枚でも画像認識をすることができるようにしたいはずです。
NumPyでは、一つ任意の値でshapeを整形したい場合、-1
を利用する方法がありました。例えば、以下のように形状変換することができます。
In [1]: import numpy as np
In [2]: a = np.arange(15)
In [3]: b = np.reshape(a, [-1, 3])
In [4]: b
Out[4]:
array([[ 0, 1, 2],
[ 3, 4, 5],
[ 6, 7, 8],
[ 9, 10, 11],
[12, 13, 14]])
n × 3のshapeを作成したい場合には、nに-1を指定するとNumPyが自動で5 × 3と計算してくれます。
同様にTensorFlowでは、以下のようにNone
を指定すると、具体的な数値を指定しないようにすることができます。
In [1]: import tensorflow as tf
In [2]: x = tf.placeholder(tf.int32, shape=[None, 3])
In [3]: sess = tf.Session()
In [4]: sess.run(x, feed_dict={x: [[1, 2, 3]]})
Out[4]: array([[1, 2, 3]], dtype=int32)
In [5]: sess.run(x, feed_dict={x: [[1, 2, 3], [2, 3, 4]]})
Out[5]:
array([[1, 2, 3],
[2, 3, 4]], dtype=int32)
1度目の評価と2度目の評価ではバッチサイズが1と2で違った入力値を入れる。といった使用方法になります。
tf.shapeとget_shapeの違い
TensorFlowにはtf.shape
と.get_shape
という2つの似たような名前の関数が存在しています。
この2つは同じようで、少し異なります。違いは以下のようになります。
-
tf.shape
tf.shape
は前述した動的に変更されうるshape
に使用しましょう。バッチサイズや画像のサイズなどを計算する場合に使用します。 -
.get_shape
.get_shape
は変更されないshape
に使用します。
具体的には以下のようになります。
In [1]: import tensorflow as tf
In [2]: x = tf.placeholder(tf.int32, shape=[None, 3])
In [3]: batch_size = tf.shape(x)[0]
In [4]: sess = tf.Session()
In [5]: sess.run(batch_size, feed_dict={x: [[1, 2, 3], [1, 2, 3]]})
Out[5]: 2
In [6]: batch_size2 = x.get_shape()[0]
TypeError: Fetch argument Dimension(None) has invalid type...
一方で、決まったshapeであれば、get_shape
も使用することもできます。
In [1]: import tensorflow as tf
In [2]: y = tf.constant(1, shape=[2, 3, 4])
In [3]: y.get_shape()[0]
Out[3]: Dimension(2)
まとめ
本記事では、TensorFlowを扱う上では必須のshapeについて解説しました。
この記事を通して、shape
の使い方と、tf.shape
の使用方法についてマスターしてください。