1

https://github.com/davidsandberg/facenet/blob/master/src/align/detect_face.py

Please refer to this python code above.

I found the prototype of class Network function conv can NOT match with its calling part as

@layer
def conv(self,
         inp,
         k_h,
         k_w,
         c_o,
         s_h,
         s_w,
         name,
         relu=True,
         padding='SAME',
         group=1,
         biased=True):

& calling conv by

class PNet(Network):
def setup(self):
    (self.feed('data') #pylint: disable=no-value-for-parameter, no-member
         .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'))

Notice that

  1. self
  2. inp --> where it comes from?
  3. ....

I know that self can be ignored; inp, k_h, k_w, c_o, s_h, s_w, can match with position by, ex: 3, 3, 10, 1, 1 and the other parameters are assigned by name.

However, I cannot figure out the way inp comes from?

It contradicts with my familiar programming language C & C++ a a lot..

Does any one can help on explaining it?

Thanks in advance.

1
  • 1
    Inp is input from previous layer. Commented Jun 27, 2018 at 11:35

2 Answers 2

1

You are indeed right to note that although the function signature takes as its first argument an input layer inp, it is not passed when the function is called.

This trick is achieved with the function decorator @layer that is placed right before the function definition. Here is the definition of the layer decorator:

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.
        # [!] Here it passes the `inp` parameter, and all the other ones
        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

It takes as input a function/method via the op parameter and it returns another one, layer_decorated which will replace the original definition of op. So PNet.conv = layer(Pnet.conv). If you look at the definition of layer_decorated, you see that it essentially sets up the first argument of the op function, namely layer_input (line with [!]). It also does some book-keeping to know which layer to use as input based on its name.

To simplify things, this allows the programmer to use chained method calls without repeating themselves. It transforms this:

 x = self.feed('data') #pylint: disable=no-value-for-parameter, no-member
 x = self.conv(x, 3, 3, 10, 1, 1, padding='VALID', relu=False, name='conv1')
 x = self.prelu(x, name='PReLU1')
 x = self.max_pool(x, 2, 2, 2, 2, name='pool1')

into this:

x = (self.feed('data') #pylint: disable=no-value-for-parameter, no-member
     .conv(3, 3, 10, 1, 1, padding='VALID', relu=False, name='conv1')
     .prelu(name='PReLU1')
     .max_pool(2, 2, 2, 2, name='pool1')
 )
Sign up to request clarification or add additional context in comments.

1 Comment

@changjc On stackOverflow questions are considered solved when they have an accepted answer. This shows other people all is well with the question and allows them to move to unaswered ones. So consider marking this as an accepted answer if it solved your problem (tick the green mark). Also consider doing this for your previous questions
1

Pnet is a network which performs many convolutions. You can pass an image to the input layer and it performs many convolutions on it. Name of input layer is 'data'. Input layer is a tensor which accepts an image.

data = tf.placeholder(tf.float32, (None,None,None,3), 'input')
pnet = PNet({'data':data})

Consider

out = pnet(img_y)

img_y is placed on 'data' layer of Pnet,

which is fed to a convolution layer.

.conv(3, 3, 10, 1, 1, padding='VALID', relu=False, name='conv1')

k_h (kernel height) = 3

k_w (kernel width) = 3

c_o (number of filters) = 10

s_h (stride height) = 1

s_w (stride width) = 1

inp is output of previous layer i.e data layer which is our image.

prelu and max pool are applied, then the output is fed as input of next convolution layer.

.conv(3, 3, 16, 1, 1, padding='VALID', relu=False, name='conv2')

and so on.

To understand convolutional neural networks better, refer CNN

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.