2016-11-01 5 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

このコードで複数の問題がありますが、例えばtrainmodelaccuracyおよびpredictの方法を参照されたい。私はこれがその自然の生息地からコードをカットすることによると仮定します。

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 

引数を使用しない場合でも、この場合は必須です。 (_real_weightsメソッドがするよう)selfweights

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

を使用して、関数のテンプレートを作成するときにこのように、あなたは基本的に、あなたが作成_weightsテンプレートは、2つの位置引数を取るべきであると述べています。あなたは

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

ように、テンプレートから作成された関数を呼び出すときしたがって、あなたは未指定(必須)shape引数を残し、self引数に配列を渡します。

あなたはここに2つのオプションがあるだろうようにそれが見えるものから:ことを考えると、あなたが望むものはおそらくされていない

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クラスの外で_real_weights通常の関数を作ることができるのいずれかあなたはすでにモデルのクラスを作成した - またはあなたが明示的に、それを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の参照が省略されています。

その後、明示的に静的メソッドの名前スコープとしてクラスMLPを指定して、後者の場合には

tf.make_template('_weights', _real_weights) 
最初のケースで

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

としてテンプレートを作成します。どちらの方法でも、_real_weightsファンクション/メソッドと_weightsテンプレートの両方に、1つの引数、作成する変数の形があります。

+0

"自己引数に配列を渡します" なぜですか? 'self._weights([in、out]) 'というメソッドとして呼び出すので、selfの最初の引数はPythonによって自動的にインクルードされるべきです –

+0

' _weights'は 'tf.make_template'によって作成される自由な関数なので、クラスメソッド。元のクラスへの参照が失われるので、Pythonは 'self'について知りません。 – sunside

+0

しかし、make_templateによって生成された関数はクラスメンバに割り当てられているので、実際にはメソッドであり、1つのように呼び出されます –

関連する問題