简体   繁体   English

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

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

Say I have a Custom Layer :假设我有一个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

if I want to decorate @tf.function(with input_signature) to A_Method to control tracing如果我想将@tf.function(with input_signature)装饰为A_Method以控制跟踪

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

what spec should i put for self ?我应该为self设定什么规格? I tried putting tf.TensorSpec but it raised an error我尝试放置tf.TensorSpec但出现错误

___Updated the question___:

Im quite new to tensorflow sorry if the code is weird or doesnt make sense.我对 tensorflow 很陌生,如果代码很奇怪或没有意义,我深表歉意。 the reason I do this is I found RNN took a long time for first epoch to get started, I dont know if this custom layer can do something alike but is taking less time.我这样做的原因是我发现 RNN 花了很长时间才开始第一个纪元,我不知道这个自定义层是否可以做类似的事情但花费的时间更少。 but ultimately I believe the slow initialize time is because of tensorflow retracing repeatedly even on same input_spec - input_shape .但最终我相信缓慢的初始化时间是因为 tensorflow retracing repeatedly even on same input_spec - input_shape I use this layer repeatedly as,我反复使用这一层,

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

then I ran .experimental_get_tracing_count() count is 300 which really shouldn't be above 10, thats why I wanted to take this method out def Mimic_RNN(self, step_input, step_state) remove it from the class and try giving it an input_signature. remove it from the class.experimental_get_tracing_count() def Mimic_RNN(self, step_input, step_state) Please see below:请看下面:

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

You actually can use input_signature with class methods.您实际上可以input_signature与 class 方法一起使用。 The initial self parameter simply needs to be ignored in the input signature specification, so you just provide the tf.TensorSpec for the other parameters.在输入签名规范中只需忽略初始self参数,因此您只需为其他参数提供tf.TensorSpec

For example:例如:

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

If you specify an input signature, all inputs to the python function must be convertible to Tensor .如果您指定输入签名,则 python function 的所有输入都必须可转换为Tensor self in that case, holds the reference to the instance on which the method is called on, and cannot be convertible as a Tensor.在这种情况下, self持有对调用该方法的实例的引用,并且不能转换为张量。 You just can't specify an input_signature on your A_method function.您只是不能在A_method input_signature上指定 input_signature。

However, it is still possible to decorate a method from a class, because TensorFlow will detect if the function to decorate is a method, and if that's the case, will automatically remove the self argument.但是,仍然可以从 class 装饰方法,因为 TensorFlow 将检测 function 是否是一种方法,如果是这种情况,将自动删除self参数。 You can check the 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:]

It's worth noting that if a method is defined outside of the class, then this check will fail.值得注意的是,如果在 class 之外定义了方法,则此检查将失败。 (The check relies on the ismethod function from the standard library inspect module). (检查依赖于标准库inspect模块中的ismethod )。 As self is not convertible to a Tensor, the decorated method will throw an error when called.由于self不能转换为 Tensor,因此被修饰的方法在调用时会抛出错误。

It's not best practice to define a method outside of the class definition: it makes the code harder to read, and harder to use.在 class 定义之外定义方法并不是最佳实践:它使代码更难阅读,也更难使用。 You can give a look to that question for more details: Define a method outside of class definition?您可以查看该问题以获取更多详细信息: 在 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). 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