簡體   English   中英

@tf.function( input_signature ) 在 class scope 之外定義的對象方法

[英]@tf.function( input_signature ) on an object's method defined outside of a class scope

假設我有一個Custom Layer

class Custom_Layer(keras.layers.Layer):
    def __init__(self, **kwargs):
        self.w_0 = tf.Variable(tf.random_uniform_initializer(),trainable=True)
        self.b_0 = tf.Variable(tf.zeros_initializer(),trainable=True)    
        ....
    def call(self, inputs):
        output = A_Method(self, inputs)
        return output
def A_Method(self, TensorA):
    ....
    return something

如果我想將@tf.function(with input_signature)裝飾為A_Method以控制跟蹤

@tf.function(input_signature=[???,  tf.TensorSpec(shape=None)])
def A_Method(self, TensorA):
    ....
    return something

我應該為self設定什么規格? 我嘗試放置tf.TensorSpec但出現錯誤

___Updated the question___:

我對 tensorflow 很陌生,如果代碼很奇怪或沒有意義,我深表歉意。 我這樣做的原因是我發現 RNN 花了很長時間才開始第一個紀元,我不知道這個自定義層是否可以做類似的事情但花費的時間更少。 但最終我相信緩慢的初始化時間是因為 tensorflow retracing repeatedly even on same input_spec - input_shape 我反復使用這一層,

input_layer = Input(shape=( X_.shape[1],X_.shape[2]),  name='input')
for loop :
Hard_Code_RNN_Layer(input_layer[:,:, slicing])

remove it from the class.experimental_get_tracing_count() def Mimic_RNN(self, step_input, step_state) 請看下面:

def Initialize_Variable(input_dim, units):
    w_init = tf.random_normal_initializer()
    b_init = tf.zeros_initializer()
    w_0 = tf.Variable(initial_value=w_init(shape=(input_dim, units))) 
    b_0 = tf.Variable(initial_value=b_init(shape=(units)))
    return w_0, b_0
def Initialize_One_Variable(input_dim, units):
    w_init = tf.random_uniform_initializer()
    R_kernal = tf.Variable(initial_value=w_init(shape=(input_dim, units))) 
    return R_kernal
class Hard_Code_RNN_Layer(keras.layers.Layer):
    def __init__(self, input_tuple, Sequencee=True, **kwargs):
        super(Hard_Code_RNN_Layer, self).__init__()
        input_shape, units = input_tuple       
        self.Hidden_Size = (int)(input_shape * 0.85)
        self.inputshape = input_shape
        self.units = units
        self.thiseq = Sequencee
        self.Uz = Initialize_One_Variable(self.Hidden_Size, self.Hidden_Size)
        self.Ur = Initialize_One_Variable(self.Hidden_Size, self.Hidden_Size)
        self.w_hz, self.b_hz    = Initialize_Variable(self.units, self.Hidden_Size)
        self.w_out, self.b_out  = Initialize_Variable(self.Hidden_Size,self.units)
        self.w_0, self.b_0  = Initialize_Variable(self.inputshape,self.units)

    def get_config(self):
        cfg = super().get_config()
        return cfg 

    def Layer_Method(inputs, w_h, b_h):
        return tf.matmul(inputs, w_h) + b_h
    
    def Mimic_RNN(self, step_input, step_state):  <-----------input_signature_this
        x__j = self.Layer_Method(step_input, self.w_0, self.b_0)
        r = tf.sigmoid(tf.matmul(step_state, self.Ur))
        z = tf.sigmoid(tf.matmul(step_state, self.Uz))
        h__ = tf.nn.relu(tf.matmul(x__j, self.w_hz) +  tf.multiply(r, step_state) + self.b_hz) 
        h = (1-z) * h__ + z * step_state
        output__ = tf.nn.relu(tf.matmul(h, self.w_out) + self.b_out)
        
        return output__, h
    
    def call(self, inputs):
        unstack = tf.unstack(inputs, axis=1)
        out1, hiddd = self.Mimic_RNN(step_input=unstack[0], step_state=tf.zeros_like(unstack[0][:,0:self.Hidden_Size]))
        out2, hiddd = self.Mimic_RNN(step_input=unstack[1], step_state=hiddd)
        out3, hiddd = self.Mimic_RNN(step_input=unstack[2], step_state=hiddd)
        
        if(self.thiseq):
            return tf.stack([out1, out2, out3], axis =1 )  
        else:
            return out3

您實際上可以input_signature與 class 方法一起使用。 在輸入簽名規范中只需忽略初始self參數,因此您只需為其他參數提供tf.TensorSpec

例如:

import tensorflow as tf

class MyClass:
    @tf.function(input_signature=(tf.TensorSpec([None], tf.float32),
                                  tf.TensorSpec([None], tf.float32)))
    def my_method(self, a, b):
        return a + b

tf.print(MyClass().my_method([1, 2, 3], [4]))
# 5, 6, 7

如果您指定輸入簽名,則 python function 的所有輸入都必須可轉換為Tensor 在這種情況下, self持有對調用該方法的實例的引用,並且不能轉換為張量。 您只是不能在A_method input_signature上指定 input_signature。

但是,仍然可以從 class 裝飾方法,因為 TensorFlow 將檢測 function 是否是一種方法,如果是這種情況,將自動刪除self參數。 您可以查看源代碼

if self._is_method:
  # Remove `self`: default arguments shouldn't be matched to it.
  # TODO(b/127938157): Should this error out if there is no arg to
  # be removed?
  args = fullargspec.args[1:]

值得注意的是,如果在 class 之外定義了方法,則此檢查將失敗。 (檢查依賴於標准庫inspect模塊中的ismethod )。 由於self不能轉換為 Tensor,因此被修飾的方法在調用時會拋出錯誤。

在 class 定義之外定義方法並不是最佳實踐:它使代碼更難閱讀,也更難使用。 您可以查看該問題以獲取更多詳細信息: 在 class 定義之外定義方法? . The python way of reusing logic between classes is either to use inheritance, or to define a function that does not depend on the attributes of the object (or where those attributes are passed as argument to the function).

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM