TensorFlow 2.0 : 上級 Tutorials : カスタマイズ :- カスタム層 (翻訳/解説)
翻訳 : (株)クラスキャット セールスインフォメーション
作成日時 : 10/28/2019
* 本ページは、TensorFlow org サイトの TF 2.0 – Advanced Tutorials – Customization の以下のページを翻訳した上で適宜、補足説明したものです:
* サンプルコードの動作確認はしておりますが、必要な場合には適宜、追加改変しています。
* ご自由にリンクを張って頂いてかまいませんが、sales-info@classcat.com までご一報いただけると嬉しいです。
- お住まいの地域に関係なく Web ブラウザからご参加頂けます。事前登録 が必要ですのでご注意ください。
- Windows PC のブラウザからご参加が可能です。スマートデバイスもご利用可能です。
◆ お問合せ : 本件に関するお問い合わせ先は下記までお願いいたします。
株式会社クラスキャット セールス・マーケティング本部 セールス・インフォメーション |
E-Mail:sales-info@classcat.com ; WebSite: https://www.classcat.com/ |
Facebook: https://www.facebook.com/ClassCatJP/ |
カスタマイズ :- カスタム層
ニューラルネットワークを構築するために tf.keras を高位 API として使用することを推奨します。とは言うものの、殆どの TensorFlow API は eagar execution とともに利用可能です。
from __future__ import absolute_import, division, print_function, unicode_literals
import tensorflow as tf
層: 有用な演算の一般的なセット
機械学習モデルのためのコードを書く際の時間の殆どで個々の演算と個々の変数の操作よりも抽象度の高いレベルで操作することを望むでしょう。
多くの機械学習モデルは比較的単純な層の組み合わせとスタックとして表現可能で、そして TensorFlow は多くの一般的な層のセットに加えて貴方自身のアプリケーション固有の層をスクラッチからあるいは既存の層の組み合わせとして書くための容易な方法の両者を提供します。
TensorFlow は tf.keras パッケージで完全な Keras API を含み、そして Keras 層は貴方自身のモデルを構築するとき非常に有用です。
# In the tf.keras.layers package, layers are objects. To construct a layer, # simply construct the object. Most layers take as a first argument the number # of output dimensions / channels. layer = tf.keras.layers.Dense(100) # The number of input dimensions is often unnecessary, as it can be inferred # the first time the layer is used, but it can be provided if you want to # specify it manually, which is useful in some complex models. layer = tf.keras.layers.Dense(10, input_shape=(None, 5))
事前の既存の層の完全なリストは ドキュメント で見ることができます。それは Dense (完全結合層), Conv2D, LSTM, BatchNormalization, Dropout そして多くのその他を含みます。
# To use a layer, simply call it. layer(tf.zeros([10, 5]))
<tf.Tensor: id=29, shape=(10, 10), dtype=float32, numpy= array([[0., 0., 0., 0., 0., 0., 0., 0., 0., 0.], [0., 0., 0., 0., 0., 0., 0., 0., 0., 0.], [0., 0., 0., 0., 0., 0., 0., 0., 0., 0.], [0., 0., 0., 0., 0., 0., 0., 0., 0., 0.], [0., 0., 0., 0., 0., 0., 0., 0., 0., 0.], [0., 0., 0., 0., 0., 0., 0., 0., 0., 0.], [0., 0., 0., 0., 0., 0., 0., 0., 0., 0.], [0., 0., 0., 0., 0., 0., 0., 0., 0., 0.], [0., 0., 0., 0., 0., 0., 0., 0., 0., 0.], [0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]], dtype=float32)>
# Layers have many useful methods. For example, you can inspect all variables # in a layer using `layer.variables` and trainable variables using # `layer.trainable_variables`. In this case a fully-connected layer # will have variables for weights and biases. layer.variables
[<tf.Variable 'dense_1/kernel:0' shape=(5, 10) dtype=float32, numpy= array([[ 0.51294535, 0.39046746, 0.5169707 , -0.50724113, 0.20505047, 0.3687951 , 0.31146628, 0.14512777, 0.17081863, 0.46950692], [-0.41236007, -0.44020796, -0.18911147, 0.4183591 , 0.16210389, 0.02787369, -0.3171257 , 0.04602218, -0.33665502, -0.31346938], [ 0.18812859, 0.19958586, 0.13240266, -0.34834057, 0.22317702, -0.4768321 , -0.3115183 , 0.31428623, -0.25364092, -0.21017173], [ 0.16382337, -0.6286906 , 0.18086797, -0.08836156, 0.2523052 , -0.41885728, 0.26864457, 0.44391626, -0.07597739, -0.5618839 ], [-0.33893436, 0.31044286, -0.10406214, 0.04485041, 0.1952014 , 0.38055784, -0.45492256, 0.3415655 , 0.39259988, -0.42731035]], dtype=float32)>, <tf.Variable 'dense_1/bias:0' shape=(10,) dtype=float32, numpy=array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0.], dtype=float32)>]
# The variables are also accessible through nice accessors layer.kernel, layer.bias
(<tf.Variable 'dense_1/kernel:0' shape=(5, 10) dtype=float32, numpy= array([[ 0.51294535, 0.39046746, 0.5169707 , -0.50724113, 0.20505047, 0.3687951 , 0.31146628, 0.14512777, 0.17081863, 0.46950692], [-0.41236007, -0.44020796, -0.18911147, 0.4183591 , 0.16210389, 0.02787369, -0.3171257 , 0.04602218, -0.33665502, -0.31346938], [ 0.18812859, 0.19958586, 0.13240266, -0.34834057, 0.22317702, -0.4768321 , -0.3115183 , 0.31428623, -0.25364092, -0.21017173], [ 0.16382337, -0.6286906 , 0.18086797, -0.08836156, 0.2523052 , -0.41885728, 0.26864457, 0.44391626, -0.07597739, -0.5618839 ], [-0.33893436, 0.31044286, -0.10406214, 0.04485041, 0.1952014 , 0.38055784, -0.45492256, 0.3415655 , 0.39259988, -0.42731035]], dtype=float32)>, <tf.Variable 'dense_1/bias:0' shape=(10,) dtype=float32, numpy=array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0.], dtype=float32)>)
カスタム層を実装する
貴方自身の層を実装する最善の方法は tf.keras.Layer クラスを拡張して以下を実装することです : * __init__ , そこでは総ての入力独立な初期化を行なうことができます * build, そこでは入力 tensor の shape を知って初期化の残りを行なうことができます * call, そこでは forward 計算を行ないます。
貴方の変数を作成するために build が呼び出されるまで待たなくても構わないことに注意してください、それらを __init__ で作成することもできます。けれども、それらを build で作成する優位点は (層がその上で操作する) 入力の shape を基にそれが遅延変数作成を可能にすることです。他方、__init__ で変数を作成することは変数を作成するために必要な shape が明示的に指定される必要があることを意味します。
class MyDenseLayer(tf.keras.layers.Layer): def __init__(self, num_outputs): super(MyDenseLayer, self).__init__() self.num_outputs = num_outputs def build(self, input_shape): self.kernel = self.add_variable("kernel", shape=[int(input_shape[-1]), self.num_outputs]) def call(self, input): return tf.matmul(input, self.kernel) layer = MyDenseLayer(10)
_ = layer(tf.zeros([10, 5])) # Calling the layer `.builds` it.
WARNING:tensorflow:From:9: Layer.add_variable (from tensorflow.python.keras.engine.base_layer) is deprecated and will be removed in a future version. Instructions for updating: Please use `layer.add_weight` method instead.
print([var.name for var in layer.trainable_variables])
['my_dense_layer/kernel:0']
全体的なコードが可能なときには標準的な層を使用すれば、他の読み手は標準的な層の動作に馴染みがありますので、読みやすく維持しやすくなります。tf.keras.layers にない層を使用することを望む場合には、github issue を提出することを考えるか、更に良いことは pull リクエストを送ることです!
モデル: 層を構成する
機械学習モデルの多くの興味深い層-like なものは既存の層を組み合わせることにより実装されます。例えば、resnet の各残差ブロックは畳み込み、バッチ正規化とショートカットの組み合わせです。層は他の層の内部にネストできます。
次のようなモデル・メソッド : Model.fit, Model.evaluate と Model.save を必要とするとき典型的には tf.keras.Model から継承します (詳細については Custom Keras layers and models 参照)。
(keras.layers.Layer の代わりに) keras.Model により提供される一つの他の特徴は変数を追跡することに加えて、keras.Model はまたその内部層を追跡し、それを調査することを容易にします。
例えばここに ResNet ブロックがあります :
class ResnetIdentityBlock(tf.keras.Model): def __init__(self, kernel_size, filters): super(ResnetIdentityBlock, self).__init__(name='') filters1, filters2, filters3 = filters self.conv2a = tf.keras.layers.Conv2D(filters1, (1, 1)) self.bn2a = tf.keras.layers.BatchNormalization() self.conv2b = tf.keras.layers.Conv2D(filters2, kernel_size, padding='same') self.bn2b = tf.keras.layers.BatchNormalization() self.conv2c = tf.keras.layers.Conv2D(filters3, (1, 1)) self.bn2c = tf.keras.layers.BatchNormalization() def call(self, input_tensor, training=False): x = self.conv2a(input_tensor) x = self.bn2a(x, training=training) x = tf.nn.relu(x) x = self.conv2b(x) x = self.bn2b(x, training=training) x = tf.nn.relu(x) x = self.conv2c(x) x = self.bn2c(x, training=training) x += input_tensor return tf.nn.relu(x) block = ResnetIdentityBlock(1, [1, 2, 3])
_ = block(tf.zeros([1, 2, 3, 3]))
block.layers
[<tensorflow.python.keras.layers.convolutional.Conv2D at 0x7fd04c20a780>, <tensorflow.python.keras.layers.normalization_v2.BatchNormalization at 0x7fd04c20ac18>, <tensorflow.python.keras.layers.convolutional.Conv2D at 0x7fd04c20af60>, <tensorflow.python.keras.layers.normalization_v2.BatchNormalization at 0x7fd04c20e470>, <tensorflow.python.keras.layers.convolutional.Conv2D at 0x7fd04c20e7b8>, <tensorflow.python.keras.layers.normalization_v2.BatchNormalization at 0x7fd04c20ec88>]
len(block.variables)
18
block.summary()
Model: "resnet_identity_block" _________________________________________________________________ Layer (type) Output Shape Param # ================================================================= conv2d (Conv2D) multiple 4 _________________________________________________________________ batch_normalization (BatchNo multiple 4 _________________________________________________________________ conv2d_1 (Conv2D) multiple 4 _________________________________________________________________ batch_normalization_1 (Batch multiple 8 _________________________________________________________________ conv2d_2 (Conv2D) multiple 9 _________________________________________________________________ batch_normalization_2 (Batch multiple 12 ================================================================= Total params: 41 Trainable params: 29 Non-trainable params: 12 _________________________________________________________________
けれども大抵の時は、多くの層を構成するモデルは単純に他の (層の) 後に一つの層を呼び出します。これは tf.keras.Sequential を使用して非常に小さいなコードから成されます。
my_seq = tf.keras.Sequential([tf.keras.layers.Conv2D(1, (1, 1), input_shape=( None, None, 3)), tf.keras.layers.BatchNormalization(), tf.keras.layers.Conv2D(2, 1, padding='same'), tf.keras.layers.BatchNormalization(), tf.keras.layers.Conv2D(3, (1, 1)), tf.keras.layers.BatchNormalization()]) my_seq(tf.zeros([1, 2, 3, 3]))
<tf.Tensor: id=744, shape=(1, 2, 3, 3), dtype=float32, numpy= array([[[[0., 0., 0.], [0., 0., 0.], [0., 0., 0.]], [[0., 0., 0.], [0., 0., 0.], [0., 0., 0.]]]], dtype=float32)>
my_seq.summary()
Model: "sequential" _________________________________________________________________ Layer (type) Output Shape Param # ================================================================= conv2d_3 (Conv2D) (None, None, None, 1) 4 _________________________________________________________________ batch_normalization_3 (Batch (None, None, None, 1) 4 _________________________________________________________________ conv2d_4 (Conv2D) (None, None, None, 2) 4 _________________________________________________________________ batch_normalization_4 (Batch (None, None, None, 2) 8 _________________________________________________________________ conv2d_5 (Conv2D) (None, None, None, 3) 9 _________________________________________________________________ batch_normalization_5 (Batch (None, None, None, 3) 12 ================================================================= Total params: 41 Trainable params: 29 Non-trainable params: 12 _________________________________________________________________
以上