2016-11-01 55 views
1

我试图使用make_template()来避免在我的模型中传递重用标志。但似乎make_template()在python类中使用时无法正确工作。我粘贴]我的模型代码和我得到的错误。在MNIST数据集上训练是一个简单的MLP。在TensorFlow中使用make_template()

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

模型

 
class MLP(object): 
    def __init__(self, hidden=[], biases=False, activation=tf.nn.relu): 
     self.graph = tf.get_default_graph() 
     self.hidden = hidden 
     self.activation = activation 
     self.biases = biases 
     self.n_features = 784 
     self.n_classes = 10 
     self.bsize = 100 
     self.l2 = 0.1 

    def _real_weights(self, shape): 
     initializer=tf.truncated_normal_initializer(stddev=0.1) 
     weights = tf.get_variable('weights', shape, initializer=initializer) 
     return weights 
    # use make_template to make variable reuse transparent 
    _weights = tf.make_template('_weights', _real_weights) 

    def _real_biases(self, shape): 
     initializer=tf.constant_initializer(0.0) 
     return tf.get_variable('biases', shape, initializer=initializer) 
    # use make_template to make variable reuse transparent 
    _biases = tf.make_template('_biases', _real_biases) 

    def _create_dense_layer(self, name, inputs, n_in, n_out, activation=True): 
     with tf.variable_scope(name): 
      weights = self._weights([n_in, n_out]) 
      layer = tf.matmul(inputs, weights) 
      if self.biases: 
       biases = self._biases([n_out]) 
       layer = layer + biases 
      if activation: 
       layer = self.activation(layer) 
      return layer 

    def _create_model(self, inputs): 
     n_in = self.n_features 
     for i in range(len(self.hidden)): 
      n_out = self.hidden[i] 
      name = 'hidden%d' % (i) 
      inputs = self._create_dense_layer(name, inputs, n_in, n_out) 
      n_in = n_out 
     output = self._create_dense_layer('output', inputs, n_in, self.n_classes, activation=False)  
     return output 

    def _create_loss_op(self, logits, labels): 
     cent = tf.nn.softmax_cross_entropy_with_logits(logits, labels) 
     weights = self.graph.get_collection('weights') 
     l2 = (self.l2/self.bsize) * tf.reduce_sum([tf.reduce_sum(tf.square(w)) for w in weights]) 
     return tf.reduce_mean(cent, name='loss') + l2 

    def _create_train_op(self, loss): 
     optimizer = tf.train.AdamOptimizer() 
     return optimizer.minimize(loss) 

    def _create_accuracy_op(self, logits, labels): 
     predictions = tf.nn.softmax(logits) 
     errors = tf.equal(tf.argmax(predictions, 1), tf.argmax(labels, 1)) 
     return tf.reduce_mean(tf.cast(errors, tf.float32)) 

    def train(self, images, labels): 
     logits = model._create_model(images) 
     loss = model._create_loss_op(logits, labels) 
     return model._create_train_op(loss)  

    def accuracy(self, images, labels): 
     logits = model._create_model(images) 
     return model._create_accuracy_op(logits, labels) 

    def predict(self, images): 
     return model._create_model(images) 

错误:

 
--------------------------------------------------------------------------- 
TypeError         Traceback (most recent call last) 
in() 
    25  model = MLP(hidden=[128]) 
    26  # define ops 
---> 27  train = model.train(images, labels) 
    28  accuracy = model.accuracy(eval_images, eval_labels) 
    29  # load test data and create a prediction op 

in train(self, images, labels) 
    60 
    61  def train(self, images, labels): 
---> 62   logits = model._create_model(images) 
    63   loss = model._create_loss_op(logits, labels) 
    64   return model._create_train_op(loss) 

in _create_model(self, inputs) 
    39    n_out = self.hidden[i] 
    40    name = 'hidden%d' % (i) 
---> 41    inputs = self._create_dense_layer(name, inputs, n_in, n_out) 
    42    n_in = n_out 
    43   output = self._create_dense_layer('output', inputs, n_in, self.n_classes, activation=False) 

in _create_dense_layer(self, name, inputs, n_in, n_out, activation) 
    25  def _create_dense_layer(self, name, inputs, n_in, n_out, activation=True): 
    26   with tf.variable_scope(name): 
---> 27    weights = self._weights([n_in, n_out]) 
    28    layer = tf.matmul(inputs, weights) 
    29    if self.biases: 

/usr/local/lib/python3.5/site-packages/tensorflow/python/ops/template.py in __call__(self, *args, **kwargs) 
    265   self._unique_name, self._name) as vs: 
    266   self._var_scope = vs 
--> 267   return self._call_func(args, kwargs, check_for_new_variables=False) 
    268 
    269 @property 

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

TypeError: _real_weights() missing 1 required positional argument: 'shape' 

originally defined at: 
    File "", line 1, in 
    class MLP(object): 
    File "", line 17, in MLP 
    _weights = tf.make_template('_weights', _real_weights) 

回答

2

没有与此代码的多个问题,因为它是在这里,例如在train,accuracypredict方法中的model参考文献。我认为这是由于从自然栖息地切割代码。

原因你提到的TypeError

TypeError: _real_weights() missing 1 required positional argument: 'shape' 

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

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

请注意,即使您不使用参数,在这种情况下它仍然是必需的。使用

tf.make_template('_weights', self._real_weights) 

创建函数模板这样,当你基本上说出您所创建的_weights模板应取两个位置参数:selfweights(一样的_real_weights方法)。因此,当你调用从模板创建的功能

weights = self._weights([n_in, n_out]) 

你传递数组到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. 

这可能不是你想要的,因为你已经创建了一个类的模型 - 或者你可以明确地使其成为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 

自定义静态方法不上一个类实例进行操作,你可以(一d必须)省略self参考。

你会再创建模板作为

tf.make_template('_weights', _real_weights) 
在第一种情况下

tf.make_template('_weights', MLP._real_weights) 

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

+0

“你将数组传递给自变量” 为什么?我将它称为'self._weights([in,out])'',所以自我的第一个参数应该被python自动包含。 –

+0

因为'_weights'是'tf.make_template'创建的一个自由函数,不是类方法。原始类的引用丢失了,所以Python不知道“self”。 – sunside

+0

但是,由make_template生成的函数被分配给一个类成员,所以它实际上是一个方法,它被称为像一个 –

相关问题