在 TensorFlow 中使用 make_template()

Mad*_*bat 5 python tensorflow

我试图使用 make_template() 来避免在整个模型中传递重用标志。但在 python 类内部使用 make_template() 时,它似乎无法正常工作。我粘贴了]我的模型代码和下面出现的错误。这是一个在 MNIST 数据集上训练的简单 MLP。

由于代码有点长,这里的主要部分是 _weights() 函数。我尝试使用 make_template() 包装它,然后在其中使用 get_variables() 在整个模型中创建和重用权重。_weights() 由 _create_dense_layer() 使用,而 _create_model() 又使用它来创建图形。train() 函数接受我从数据读取器获得的张量。

模型

MLP 类(对象):
    def __init__(self, 隐藏=[], 偏差=False, 激活=tf.nn.relu):
        self.graph = tf.get_default_graph()
        self.hidden = 隐藏
        自我激活=激活
        自我偏见 = 偏见
        self.n_features = 784
        self.n_classes = 10
        self.bsize = 100
        自身.l2 = 0.1

    def _real_weights(自身,形状):
        初始化器=tf.truncated_normal_initializer(stddev=0.1)
        权重 = tf.get_variable('权重', 形状, 初始化器=初始化器)
        返回权重
    # 使用 make_template 使变量重用透明
    _weights = tf.make_template('_weights', _real_weights)

    def _real_biases(自我,形状):
        初始化器=tf.constant_initializer(0.0)
        返回 tf.get_variable('偏差', 形状, 初始化器 = 初始化器)
    # 使用 make_template 使变量重用透明
    _biases = tf.make_template('_biases', _real_biases)

    def _create_dense_layer(自身,名称,输入,n_in,n_out,激活= True):
        与 tf.variable_scope(name):
            权重 = self._weights([n_in, n_out])
            层= tf.matmul(输入,权重)
            如果自我偏见:
                偏差 = self._biases([n_out])
                层 = 层 + 偏差
            如果激活:
                层 = self.activation(层)
            返回层

    def _create_model(自我,输入):
        n_in = self.n_features
        对于范围内的 i(len(self.hidden)):
            n_out = self.hidden[i]
            名称 = '隐藏%d' % (i)
            输入= self._create_dense_layer(名称,输入,n_in,n_out)
            n_输入 = n_输出
        输出 = self._create_dense_layer('输出', 输入, n_in, self.n_classes, 激活=False)    
        返回输出

    def _create_loss_op(自我,logits,标签):
        cent = tf.nn.softmax_cross_entropy_with_logits(logits, 标签)
        权重 = self.graph.get_collection('权重')
        l2 = (self.l2 / self.bsize) * tf.reduce_sum([tf.reduce_sum(tf.square(w)) for w inweights])
        返回 tf.reduce_mean(cent, name='loss') + l2

    def _create_train_op(自我,损失):
        优化器 = tf.train.AdamOptimizer()
        返回优化器.最小化(损失)

    def _create_accuracy_op(自我,logits,标签):
        预测 = tf.nn.softmax(logits)
        错误 = tf.equal(tf.argmax(预测, 1), tf.argmax(标签, 1))
        返回 tf.reduce_mean(tf.cast(错误, tf.float32))

    def 火车(自身、图像、标签):
        logits = model._create_model(图像)
        损失 = model._create_loss_op(logits, labels)
        返回 model._create_train_op(loss)       

    def 准确率(自身、图像、标签):
        logits = model._create_model(图像)
        返回 model._create_accuracy_op(logits, labels)

    def 预测(自身,图像):
        返回 model._create_model(图像)

错误:

-------------------------------------------------- ------------------------
类型错误回溯(最近一次调用最后一次)
 在 ()
     25 模型 = MLP(隐藏=[128])
     26 # 定义操作
---> 27 train = model.train(图像, 标签)
     28 准确度 = model.accuracy(eval_images, eval_labels)
     29 # 加载测试数据并创建预测操作

 在火车上(自我、图像、标签)
     60
     61 def 训练(自身、图像、标签):
---> 62 logits = model._create_model(images)
     63 损失 = model._create_loss_op(logits, labels)
     64 返回 model._create_train_op(loss)

 在 _create_model(自我,输入)
     39 n_out = self.隐藏[i]
     40 名称 = '隐藏%d' % (i)
---> 41 个输入 = self._create_dense_layer(名称, 输入, n_in, n_out)
     42 n_输入=n_输出
     43 输出 = self._create_dense_layer('输出', 输入, n_in, self.n_classes, 激活=False)

 在 _create_dense_layer(自身、名称、输入、n_in、n_out、激活)
     25 def _create_dense_layer(自身,名称,输入,n_in,n_out,激活= True):
     26 与 tf.variable_scope(name):
---> 27 个权重 = self._weights([n_in, n_out])
     28层= tf.matmul(输入,权重)
     29如果自我偏见:

/usr/local/lib/python3.5/site-packages/tensorflow/python/ops/template.py 在 __call__(self, *args, **kwargs)
    [第 265 章]
    第266章
--> 267 返回 self._call_func(args, kwargs, check_for_new_variables=False)
    268
    第269章

/usr/local/lib/python3.5/site-packages/tensorflow/python/ops/template.py 在 _call_func(self, args, kwargs, check_for_new_variables)
    206 ops.get_collection(ops.GraphKeys.TRAINABLE_VARIABLES))
    207
--> 208 结果 = self._func(*args, **kwargs)
    209 if check_for_new_variables:
    第210章

类型错误:_real_weights() 缺少 1 个必需的位置参数:“形状”

最初定义于:
  文件“”,第 1 行,位于
    MLP 类(对象):
  MLP 中的文件“”,第 17 行
    _weights = tf.make_template('_weights', _real_weights)

sun*_*ide 3

此处的代码存在多个问题,例如、和方法model中的引用。我认为这是由于将代码从其自然栖息地中删除了。trainaccuracypredict

至于你提到的原因TypeError

TypeError: _real_weights() missing 1 required positional argument: 'shape'
Run Code Online (Sandbox Code Playgroud)

最有可能的原因是_real_weights它本身是类的实例方法MLP,而不是常规函数或静态方法。因此,函数的第一个参数始终是self调用时指向类实例的引用(this类 C 语言中指针的显式版本),如函数声明中所示:

def _real_weights(self, shape):
    initializer=tf.truncated_normal_initializer(stddev=0.1)
    weights = tf.get_variable('weights', shape, initializer=initializer)
    return weights
Run Code Online (Sandbox Code Playgroud)

请注意,即使您不使用该参数,在这种情况下仍然需要它。因此,当使用创建函数模板时

tf.make_template('_weights', self._real_weights)
Run Code Online (Sandbox Code Playgroud)

您基本上声明_weights您创建的模板应该采用两个位置参数:selfweights(与方法一样_real_weights)。因此,当您调用从模板创建的函数时

weights = self._weights([n_in, n_out])
Run Code Online (Sandbox Code Playgroud)

您将数组传递给self参数,shape而未指定(必需的)参数。

从看起来你在这里有两个选择:你可以_real_weightsMLP类之外创建一个常规函数,这样

def _real_weights(shape):
    initializer=tf.truncated_normal_initializer(stddev=0.1)
    weights = tf.get_variable('weights', shape, initializer=initializer)
    return weights

class MLP():
    # etc.
Run Code Online (Sandbox Code Playgroud)

这可能不是您想要的,因为您已经为模型创建了一个类 - 或者您可以显式地将其设为该类的静态方法MLP,这样

class MLP():
    @staticmethod
    def _real_weights(shape):
        initializer=tf.truncated_normal_initializer(stddev=0.1)
        weights = tf.get_variable('weights', shape, initializer=initializer)
        return weights
Run Code Online (Sandbox Code Playgroud)

由于根据定义,静态方法不对类实例进行操作,因此您可以(并且必须)省略引用self

然后您将创建模板为

tf.make_template('_weights', _real_weights)
Run Code Online (Sandbox Code Playgroud)

在第一种情况下和

tf.make_template('_weights', MLP._real_weights)
Run Code Online (Sandbox Code Playgroud)

在第二种情况下,显式指定类MLP作为静态方法的名称范围。无论哪种方式,_real_weights函数/方法和_weights模板现在都只有一个参数,即要创建的变量的形状。