2017-03-03 75 views
0

所以我想破译here一些代码。下面我复制并粘贴了我不太了解的相关代码。了解这块Python代码与装饰

def layer(op): 
    '''Decorator for composable network layers.''' 

    def layer_decorated(self, *args, **kwargs): 
     # Automatically set a name if not provided. 
     name = kwargs.setdefault('name', self.get_unique_name(op.__name__)) 
     # Figure out the layer inputs. 
     if len(self.terminals) == 0: 
      raise RuntimeError('No input variables found for layer %s.' % name) 
     elif len(self.terminals) == 1: 
      layer_input = self.terminals[0] 
     else: 
      layer_input = list(self.terminals) 
     # Perform the operation and get the output. 
     layer_output = op(self, layer_input, *args, **kwargs) 
     # Add to layer LUT. 
     self.layers[name] = layer_output 
     # This output is now the input for the next layer. 
     self.feed(layer_output) 
     # Return self for chained calls. 
     return self 

    return layer_decorated 

class Network(object): 

    def __init__(self, inputs, trainable=True): 
     # The input nodes for this network 
     self.inputs = inputs 
     print(self.inputs) 
     # The current list of terminal nodes 
     self.terminals = [] 
     # Mapping from layer names to layers 
     self.layers = dict(inputs) 
     print(self.layers) 
     # If true, the resulting variables are set as trainable 
     self.trainable = trainable 

    … 

    def feed(self, *args): 
     '''Set the input(s) for the next operation by replacing the terminal nodes. 
     The arguments can be either layer names or the actual layers. 
     ''' 
     assert len(args) != 0 
     self.terminals = [] 
     for fed_layer in args: 
      if isinstance(fed_layer, string_types): 
       try: 
        fed_layer = self.layers[fed_layer] 
       except KeyError: 
        raise KeyError('Unknown layer name fed: %s' % fed_layer) 
      self.terminals.append(fed_layer) 
     return self 

.... 

# equivalent to max_pool = layer(max_pool) 
    @layer 
    def max_pool(self, inp, k_h, k_w, s_h, s_w, name, padding='SAME'): 
     self.validate_padding(padding) 
     return tf.nn.max_pool(inp, 
           ksize=[1, k_h, k_w, 1], 
           strides=[1, s_h, s_w, 1], 
           padding=padding, 
           name=name) 

我明白了上面的代码,虽然我有一点麻烦试图理解下面的代码:

class PNet(Network): 
    def setup(self): 
     (self.feed('data') 
      .conv(3, 3, 10, 1, 1, padding='VALID', relu=False, name='conv1') 
      .prelu(name='PReLU1') 
      .max_pool(2, 2, 2, 2, name='pool1') 
      .conv(3, 3, 16, 1, 1, padding='VALID', relu=False, name='conv2') 
      .prelu(name='PReLU2') 
      .conv(3, 3, 32, 1, 1, padding='VALID', relu=False, name='conv3') 
      .prelu(name='PReLU3') 
      .conv(1, 1, 2, 1, 1, relu=False, name='conv4-1') 
      .softmax(3,name='prob1')) 

     (self.feed('PReLU3') #pylint: disable=no-value-for-parameter 
      .conv(1, 1, 4, 1, 1, relu=False, name='conv4-2')) 

特别,我在代码的这部分困惑工作原理:

self.feed('data') 
      .conv(3, 3, 10, 1, 1, padding='VALID', relu=False, name='conv1') 
      .prelu(name='PReLU1') 
      .max_pool(2, 2, 2, 2, name='pool1') 
      .conv(3, 3, 16, 1, 1, padding='VALID', relu=False, name='conv2') 
      .prelu(name='PReLU2') 
      .conv(3, 3, 32, 1, 1, padding='VALID', relu=False, name='conv3') 
      .prelu(name='PReLU3') 
      .conv(1, 1, 2, 1, 1, relu=False, name='conv4-1') 
      .softmax(3,name='prob1')) 

它也可以写为: self.feed('data').conv(3, 3, 10, 1, 1, padding='VALID', relu=False, name='conv1').prelu(name='PReLU1')...

这是什么,我不明白,feed本身是Network类的方法,但我怎么能够访问feed的方法等

+0

这与装饰者无关。 'feed()'中有一个'return self',对于其他方法来说可能是一样的。 'self'只是对当前实例的另一个引用,所以链中的下一个方法再次调用'self',所以你可以调用另一个方法等。修饰器也返回'self'。 –

回答

1

这与装饰者无关。

feed方法 - 以及大概convprelu方法 - 返回self。这意味着您可以继续调用调用该方法结果的方法。

这就是所谓的“方法链”;在Ruby等语言中更常见,但您也可以在Python中完成。

0

这很简单真的。

所以当你启动这个链时你有对象self,你可以将它称为方法feed()方法执行,如果你查看源代码,它返回self。但它是修改后的自我。所以在这一点上feed()是'消耗',你留下了像(modified)self.prelu()....。这与另一种方法重复。它重复,直到没有电话离开。