ホーム » Keras » TensorFlow : Tutorials : Eager : カスタム層

TensorFlow : Tutorials : Eager : カスタム層

TensorFlow : Tutorials : Eager : カスタム層 (翻訳/解説)

翻訳 : (株)クラスキャット セールスインフォメーション
作成日時 : 07/18/2018

* TensorFlow 1.9 でドキュメント構成が変わり新規にチュートリアル・ページも追加されました。
* 本ページは、TensorFlow 本家サイトの Tutorials – Research and Experimentation – Custom layers を
翻訳した上で適宜、補足説明したものです:

* サンプルコードの動作確認はしておりますが、適宜、追加改変している場合もあります。
* ご自由にリンクを張って頂いてかまいませんが、sales-info@classcat.com までご一報いただけると嬉しいです。

 

ニューラルネットワークを構築するための高位レベル API として tf.keras の使用を推奨します。とは言え、殆どの TensorFlow API は eager execution とともに利用可能です。

import tensorflow as tf
tfe = tf.contrib.eager

tf.enable_eager_execution()

 

層: 有用な演算の一般的なセット

大抵の場合、機械学習モデルのためのコードを書くとき個々の演算や個々の変数の操作よりも抽象化のより高いレベルで演算することを望むでしょう。多くの機械学習モデルは比較的単純な層の組み立てやスタックとして表現できます、そして TensorFlow は多くの一般的な層のセットとともに、スクラッチからあるいは既存の層の組み立てとして貴方自身のアプリケーション固有の層を書く簡単な方法の両者を提供します。

TensorFlow は tf.keras パッケージにフル Keras API を含み、そして Keras 層は貴方自身のモデルを構築するとき非常に有用です。

# In the tf.keras.layers package, layers are objects. To construct a layer,# In th 
# 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]))

Out:

<tf.Tensor: id=30, 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 by calling layer.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.21914625,  0.0990991 ,  0.18261564,  0.40257913,  0.34072709,
         -0.0625487 , -0.24020803, -0.12010807,  0.40558523, -0.03303367],
        [ 0.08877724, -0.40127528, -0.57334077,  0.10226113, -0.27305049,
         -0.29159862, -0.58058709, -0.60042459, -0.36712468, -0.22455806],
        [-0.2126697 , -0.15910214,  0.12656337,  0.44269663,  0.57688957,
          0.18262208, -0.41651565, -0.33097616,  0.51486522,  0.57214183],
        [ 0.21742707,  0.23269236,  0.56807464, -0.6096639 ,  0.25128335,
         -0.12213349,  0.21207756, -0.05127466,  0.02161229,  0.42359179],
        [-0.53448963,  0.55796593,  0.20331413, -0.5741179 , -0.10637027,
         -0.05225825, -0.4186154 , -0.51762027, -0.24687892, -0.08826667]], 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.21914625,  0.0990991 ,  0.18261564,  0.40257913,  0.34072709,
         -0.0625487 , -0.24020803, -0.12010807,  0.40558523, -0.03303367],
        [ 0.08877724, -0.40127528, -0.57334077,  0.10226113, -0.27305049,
         -0.29159862, -0.58058709, -0.60042459, -0.36712468, -0.22455806],
        [-0.2126697 , -0.15910214,  0.12656337,  0.44269663,  0.57688957,
          0.18262208, -0.41651565, -0.33097616,  0.51486522,  0.57214183],
        [ 0.21742707,  0.23269236,  0.56807464, -0.6096639 ,  0.25128335,
         -0.12213349,  0.21207756, -0.05127466,  0.02161229,  0.42359179],
        [-0.53448963,  0.55796593,  0.20331413, -0.5741179 , -0.10637027,
         -0.05225825, -0.4186154 , -0.51762027, -0.24687892, -0.08826667]], 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 に基づいて遅延 (= late) variable 作成を可能にすることです。その一方で、variable を __init__ で作成することは variable を作成するために必要な 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=[input_shape[-1].value, 
                                           self.num_outputs])
    
  def call(self, input):
    return tf.matmul(input, self.kernel)
  
layer = MyDenseLayer(10)
print(layer(tf.zeros([10, 5])))
print(layer.variables)
tf.Tensor(
[[ 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.]], shape=(10, 10), dtype=float32)
[<tf.Variable 'my_dense_layer/kernel:0' shape=(5, 10) dtype=float32, numpy=
array([[-0.24975419, -0.33780435,  0.17131561,  0.28679961, -0.27856019,
        -0.38586116, -0.19720221,  0.25158852, -0.61064029, -0.35856512],
       [ 0.52740663,  0.26937109, -0.61597472,  0.53265864, -0.05881637,
        -0.02134347,  0.59274155, -0.11058015, -0.22670561,  0.34645844],
       [ 0.41161889, -0.40521431, -0.49620956,  0.62973171, -0.20672497,
         0.55795223, -0.29845288,  0.30644548,  0.26540279,  0.27750438],
       [ 0.54720205, -0.14807495, -0.18610999, -0.00718719,  0.23697406,
        -0.30066797,  0.34169638,  0.43261009, -0.08473277, -0.30719322],
       [-0.45203799, -0.57771409, -0.06893957,  0.62330216,  0.43259674,
        -0.15227216, -0.15664744, -0.32023922,  0.32174361,  0.3802709 ]], dtype=float32)>]

コード全体はそれが (可能なときはいつでも) 標準的な層を使用すれば読みやすく維持しやすいです、何故ならば他の読者は標準的な層の挙動に精通しているからです。

 

モデル: 層を構成する

機械学習モデルの多くの興味深い層ライクなものは既存の層を組み立てることにより実装されます。例えば、resnet の各残差ブロックは畳み込み、バッチ正規化、そしてショートカットの合成です。

他の層を含む層ライクなものを作成するとき使用される主要なクラスは tf.keras.Model です。一つの実装は tf.keras.Model から継承することで成されます。

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])
print(block(tf.zeros([1, 2, 3, 3])))
print([x.name for x in block.variables])

Out:

tf.Tensor(
[[[[ 0.  0.  0.]
   [ 0.  0.  0.]
   [ 0.  0.  0.]]

  [[ 0.  0.  0.]
   [ 0.  0.  0.]
   [ 0.  0.  0.]]]], shape=(1, 2, 3, 3), dtype=float32)
[
'resnet_identity_block/conv2d/kernel:0', 'resnet_identity_block/conv2d/bias:0', 
'resnet_identity_block/batch_normalization/gamma:0', 
'resnet_identity_block/batch_normalization/beta:0', 'resnet_identity_block/conv2d_1/kernel:0', 
'resnet_identity_block/conv2d_1/bias:0', 'resnet_identity_block/batch_normalization_1/gamma:0',
'resnet_identity_block/batch_normalization_1/beta:0', 'resnet_identity_block/conv2d_2/kernel:0',
'resnet_identity_block/conv2d_2/bias:0', 'resnet_identity_block/batch_normalization_2/gamma:0',
'resnet_identity_block/batch_normalization_2/beta:0', 
'resnet_identity_block/batch_normalization/moving_mean:0', 'resnet_identity_block/batch_normalization/moving_variance:0',
'resnet_identity_block/batch_normalization_1/moving_mean:0',
'resnet_identity_block/batch_normalization_1/moving_variance:0',
'resnet_identity_block/batch_normalization_2/moving_mean:0',
'resnet_identity_block/batch_normalization_2/moving_variance:0'
]

けれでも大抵の場合、多くの層を構成するモデルは単に一つの層を他の層に続いて呼び出すだけです。これは tf.keras.Sequential を使用して非常に小さいコードで成されます。

my_seq = tf.keras.Sequential([tf.keras.layers.Conv2D(1, (1, 1)),
                               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=503, 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)>

 
以上






AI導入支援 #2 ウェビナー

スモールスタートを可能としたAI導入支援   Vol.2
[無料 WEB セミナー] [詳細]
「画像認識 AI PoC スターターパック」の紹介
既に AI 技術を実ビジネスで活用し、成果を上げている日本企業も多く存在しており、競争優位なビジネスを展開しております。
しかしながら AI を導入したくとも PoC (概念実証) だけでも高額な費用がかかり取組めていない企業も少なくないようです。A I導入時には欠かせない PoC を手軽にしかも短期間で認知度を確認可能とするサービの紹介と共に、AI 技術の特性と具体的な導入プロセスに加え運用時のポイントについても解説いたします。
日時:2021年10月13日(水)
会場:WEBセミナー
共催:クラスキャット、日本FLOW(株)
後援:働き方改革推進コンソーシアム
参加費: 無料 (事前登録制)
人工知能開発支援
◆ クラスキャットは 人工知能研究開発支援 サービスを提供しています :
  • テクニカルコンサルティングサービス
  • 実証実験 (プロトタイプ構築)
  • アプリケーションへの実装
  • 人工知能研修サービス
◆ お問合せ先 ◆
(株)クラスキャット
セールス・インフォメーション
E-Mail:sales-info@classcat.com