【问题标题】:@tf.function( input_signature ) on an object's method defined outside of a class scope@tf.function( input_signature ) 在类范围之外定义的对象方法上
【发布时间】:2021-07-25 20:36:09
【问题描述】:

假设我有一个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 需要很长时间才能开始第一个 epoch,我不知道这个自定义层是否可以做类似的事情,但花费的时间更少。但最终我相信缓慢的初始化时间是因为 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])

然后我跑了.experimental_get_tracing_count() count is 300 这真的不应该超过 10,这就是为什么我想把这个方法拿出来def Mimic_RNN(self, step_input, step_state)remove it from the class 并尝试给它一个 input_signature。请看下面:

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

【问题讨论】:

  • 为什么A_method 不在类中时使用self 关键字?
  • 您好,谢谢您的回复!我在 tensorflow 的网站上看到它说 If you need to force retracing, create a new Function. Separate Function objects are guaranteed not to share traces. 我多次重复使用这个自定义层类,所以我将 A_Method 从自定义层类中移到外面,不知道这是否有意义。 n 我必须使用self 将可训练变量传递给方法
  • 您能否澄清A_method 是否属于某个课程?
  • 您好,非常感谢您的回复!抱歉没解释清楚,A_methodnot类的一部分,只是个人def

标签: python tensorflow keras


【解决方案1】:

如果您指定输入签名,python 函数的所有输入都必须可转换为Tensorself 在这种情况下,持有对调用该方法的实例的引用,并且不能转换为张量。 您不能在 A_method 函数上指定 input_signature

但是,仍然可以从类中装饰方法,因为 TensorFlow 会检测要装饰的函数是否是方法,如果是这样,则会自动删除 self 参数。你可以查看source code

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:]

值得注意的是,如果一个方法是在类之外定义的,那么这个检查将会失败。 (检查依赖于标准库inspect 模块中的ismethod 函数)。由于self 不能转换为张量,因此被装饰的方法在调用时会抛出错误。

在类定义之外定义方法并不是最佳实践:它会使代码更难阅读,也更难使用。您可以查看该问题以了解更多详细信息:Define a method outside of class definition?。 python 在类之间重用逻辑的方法是使用继承,或者定义一个不依赖于对象属性的函数(或者这些属性作为参数传递给函数)。

【讨论】:

  • 嗨,非常感谢您的回答,这肯定让我对 input_signature 有了更好的了解和理解。我可以进一步详细说明我的情况,比如A_methodclass 中被多次使用,那么input_signature 只会跟踪一次。但是,如果我有多个 same class 实例,我知道它们具有完全相同的 input_shape,我如何才能节省一些时间让他们知道不要重新跟踪。我更新了我的问题应该更清楚一点,请您有空时再看看。非常感谢
  • 最好不要更新问题,而是问一个新问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-27
  • 2020-08-07
  • 1970-01-01
  • 2022-07-06
  • 1970-01-01
相关资源
最近更新 更多