Tensorflow 2カスタムLayersの_init__,buildとcallの詳細


Tensorflow 2カスタムLayersの_init__,buildとcallの詳細
  • 世間話:
  • --init--buildとcall
  • まとめ

  • 公式リンクを参照:https://tensorflow.google.cn/tutorials/customization/custom_layers
    雑談:
    自分のLayerをカスタマイズするにはtfを使用します.keras.Layerが自分のクラスを作成するには欠かせない.
    しかし、筆者は最近、自分の毕設をしている間に、カスタム層とtfに出会った.functionのError:Value Error:tf.function-decorated function tried to create variables on non-first call. 初歩的な判断:add_それは...function競合.この衝突を解決しようとするとdef build()関数の理解がまだ不十分であることが分かった.だからこの記録をします.
    -init-,buildとcall
  • -init-関数:この関数は、すべての独立した入力を初期化するために使用されます.(独立した入力:特に訓練データに関係のない入力を指す)(この関数は1回のみ実行される)
  • build関数:この関数は、Tensorのshapeを入力したことを知ってから、残りの初期化を完了するために使用されます.(すなわち、データのshapeを知る必要があるが、データの具体的な値を知る必要はない)(注意:この関数はCallが最初に呼び出されたときにのみ実行される)
  • .
  • call関数:この関数は順方向計算に使用される関数です.

  • 注意:build関数は必須ではありません.Tensorのshape、すなわちデータが明示的であることを事前に知っていれば、build関数を定義する必要がなく、-init-でbuild内の初期化された内容を完全に実行することができます.もちろんbuildにもメリットがあります.データのshapeを事前に知らないと、buildの役割が明らかになります.例えば、入力画像のsizeが224 x 224なのか512 x 512なのか分からない場合は、自分のLayerをどのように初期化しますか.buildは、このようなソリューションを提供します.もう一つ、筆者は上記の筆者が直面した問題を解決する可能性があると考えているが、まだ検証されていない.文末で検証されるはずです.
    上記の関数の特徴をよりよく理解するために、簡単な例を挙げます.
    import tensorflow as tf
    class MyDenseLayer(tf.keras.layers.Layer):
      def __init__(self, num_outputs):
        super(MyDenseLayer, self).__init__()
        print('init    ')
        self.num_outputs = num_outputs
        self.i = 0
        print('Init:This is i',self.i)
        self.i = self.i +1
      def build(self,input_shape):
        print('build    ')
        print('input_shape',input_shape)
        print('Build:This is i',self.i)
        self.kernel = self.add_weight("kernel",
                                      shape=[int(input_shape[-1]),
                                             self.num_outputs])
      
      def call(self, input):
        print('call    ')
        return tf.matmul(input, self.kernel)
    
    layer = MyDenseLayer(10)
    _ = layer(tf.zeros([10, 5])) # Calling the layer `.builds` it.
    print([var.name for var in layer.trainable_variables])
    _ = layer(tf.ones([10, 5]))
    print([var.name for var in layer.trainable_variables])
    

    出力結果は次のとおりです.
    init    
    Init:This is i 0
    build    
    input_shape (10, 5)
    Build:This is i 1
    call    
    ['my_dense_layer/kernel:0']
    call    
    ['my_dense_layer/kernel:0']
    

    上記のコードに合わせて見ると、わかりやすいのではないでしょうか.Initは先に実行され、一度だけ実行されます.buildも、Call関数実行を初めて呼び出します.callは呼び出されるたびに実行されます.
    まとめ
    以上の説明から,筆者の問題はBuildには現れないことが分かった.しかし、この日の検索を経て、最終的に問題の所在地を特定することに成功した.
    こんなにたくさんやって、道を迷った(このblogの誕生も含めて).しかし、最終的には問題に位置づけられました.Nice!
    早く寝なさい.
    (補足:この問題は解決されました.
  • で発生した問題:私のモデルはCNNとGCNのネストであり、CNNのcall関数内でGCNを呼び出すと、CNNのcallが呼び出されたときにGCN modelが実行することに相当し、GCN内のcallはtfを含む.variable関数は、tfをループ呼び出したことに相当する.variable関数のため、問題が発生しました.
  • ソリューション:GCNのtf.variableは–init–関数内に入れ、GCNNとCNNの–init–関数を同時に呼び出し、tfを回避する.variable被循環問題)