Skip to content

Instantly share code, notes, and snippets.

@vincentzhang
Forked from rafaspadilha/customLayerTutorial.md
Created August 18, 2017 01:48
Show Gist options
  • Save vincentzhang/80bc49bc007532fef3cacadab9e26ced to your computer and use it in GitHub Desktop.
Save vincentzhang/80bc49bc007532fef3cacadab9e26ced to your computer and use it in GitHub Desktop.

Revisions

  1. @rafaspadilha rafaspadilha revised this gist Jun 13, 2017. 1 changed file with 10 additions and 10 deletions.
    20 changes: 10 additions & 10 deletions customLayerTutorial.md
    Original file line number Diff line number Diff line change
    @@ -38,16 +38,16 @@ So important things to remember:
    ### - Setup method
    The Setup method is called once during the lifetime of the execution, when Caffe is instantiating all layers. This is where you will read parameters, instantiate fixed-size buffers.

    ###- Reshape method
    ### - Reshape method
    Use the reshape method for initialization/setup that depends on the bottom blob (layer input) size. It is called once when the network is instantiated.

    ###- Forward method
    ### - Forward method
    The Forward method is called for each input batch and is where most of your logic will be.

    ###- Backward method
    ### - Backward method
    The Backward method is called during the backward pass of the network. For example, in a convolution-like layer, this would be where you would calculate the gradients. This is optional (a layer can be forward-only).

    ##Prototxt Template
    ## Prototxt Template
    Ok, so now you have your layer designed! This is how you define it in your *.prototxt* file:

    ```
    @@ -75,7 +75,7 @@ Important remarks:
    - You can pass parameters to the layer using **param_str** (more on accessing them bellow);
    - Just like any other layer, you can define in which phase you want it to be active (see the examples to see how you can check the current phase);

    ##Passing parameters to the layer
    ## Passing parameters to the layer
    You can define the layer parameters in the prototxt by using *param_str*. Once you've done it, here is an example on how you access these paremeters inside the layer class:

    ```python
    @@ -89,17 +89,17 @@ def setup(self, bottom, top):
    # ...
    ```

    ##Where should I save the class file?
    ## Where should I save the class file?
    You have two options (at least that I know of). Either you can save the custom layer file in the same folder as you are going to run the *caffe* command (probably where your prototxt files would be).
    Another way, also my favorite one, is to save all your custom layers in a folder and adding this folder to your PYTHONPATH.


    ##Examples
    ## Examples
    Bellow are two examples of layers. One of them is a "measure" layer, that outputs the accuracy and a confusion matrix for a binary problem during training and the accuracy, false positive rate and false negative rate during test/validation. Although Caffe already has a Accuracy layer, sometimes you want something more, like a F-measure.

    The other is a custom data layer, that receives a text file with image paths, loads a batch of images and preprocesses them. Just a quick tip, Caffe already has a big range of data layers and probably a custom layer is not the most efficient way if you just want something simple.

    ###Measure Layer
    ### Measure Layer
    This is my *measureLayer.py* with my class definition:

    ```python
    @@ -233,7 +233,7 @@ layer {
    }
    ```

    ###Data Layer
    ### Data Layer
    My *dataLayer.py* could be something like:
    ```python
    import caffe
    @@ -324,7 +324,7 @@ layer {
    }
    ```

    ##References
    ## References
    1. [Christopher Bourez's blog](http://christopher5106.github.io/deep/learning/2015/09/04/Deep-learning-tutorial-on-Caffe-Technology.html)
    2. [Caffe Github](https://github.com/BVLC/caffe/issues/684)
    3. [StackOverflow](https://github.com/BVLC/caffe/issues/684)
  2. @rafaspadilha rafaspadilha revised this gist Jun 13, 2017. 1 changed file with 5 additions and 5 deletions.
    10 changes: 5 additions & 5 deletions customLayerTutorial.md
    Original file line number Diff line number Diff line change
    @@ -1,16 +1,16 @@
    # How to create a custom Caffe layer in Python?
    This tutorial will guide through the steps to create a simple custom layer for Caffe using python. By the end of it, there are some examples of custom layers.

    ###- Why would I want to do that?
    ### - Why would I want to do that?
    Usually you would create a custom layer to implement a funcionality that isn't available in Caffe, tuning it for your requirements.

    ###- What will I need?
    ### - What will I need?
    Probably just Python and Caffe instaled.

    ###- Is there any downside?
    ### - Is there any downside?
    Creating a python custom layer adds some overhead to your network and probably isn't as efficient as a C++ custom layer. However, this way, you won't have to compile the whole caffe with your new layer.

    ##Layer Template
    ## Layer Template

    ```python
    import caffe
    @@ -35,7 +35,7 @@ So important things to remember:
    - All methods have a *top* and a *bottom* parameters, which are the blobs that store the input and the output passed to your layer. You can access it using *top[i].data* or *bottom[i].data*, where *i* is the index of the blob in case you have more than one upper or lower blob.


    ###- Setup method
    ### - Setup method
    The Setup method is called once during the lifetime of the execution, when Caffe is instantiating all layers. This is where you will read parameters, instantiate fixed-size buffers.

    ###- Reshape method
  3. @rafaspadilha rafaspadilha revised this gist Dec 19, 2016. 1 changed file with 6 additions and 1 deletion.
    7 changes: 6 additions & 1 deletion customLayerTutorial.md
    Original file line number Diff line number Diff line change
    @@ -39,7 +39,7 @@ So important things to remember:
    The Setup method is called once during the lifetime of the execution, when Caffe is instantiating all layers. This is where you will read parameters, instantiate fixed-size buffers.

    ###- Reshape method
    Use the reshape method for initialization/setup that depends on the bottom blob (layer input) size. It is called once for each batch.
    Use the reshape method for initialization/setup that depends on the bottom blob (layer input) size. It is called once when the network is instantiated.

    ###- Forward method
    The Forward method is called for each input batch and is where most of your logic will be.
    @@ -323,3 +323,8 @@ layer {
    }
    }
    ```

    ##References
    1. [Christopher Bourez's blog](http://christopher5106.github.io/deep/learning/2015/09/04/Deep-learning-tutorial-on-Caffe-Technology.html)
    2. [Caffe Github](https://github.com/BVLC/caffe/issues/684)
    3. [StackOverflow](https://github.com/BVLC/caffe/issues/684)
  4. @rafaspadilha rafaspadilha revised this gist Dec 17, 2016. 1 changed file with 0 additions and 3 deletions.
    3 changes: 0 additions & 3 deletions customLayerTutorial.md
    Original file line number Diff line number Diff line change
    @@ -321,8 +321,5 @@ layer {
    layer: "Custom_Data_Layer"
    param_str: '{"batch_size": 126,"im_shape":256, "crop_size":224, "src_file": "path_to_TRAIN_file.txt"}'
    }
    include{
    phase: TRAIN
    }
    }
    ```
  5. @rafaspadilha rafaspadilha revised this gist Dec 17, 2016. 1 changed file with 67 additions and 19 deletions.
    86 changes: 67 additions & 19 deletions customLayerTutorial.md
    Original file line number Diff line number Diff line change
    @@ -95,7 +95,8 @@ Another way, also my favorite one, is to save all your custom layers in a folder


    ##Examples
    Bellow are two examples of layers I use during my work. One of them is a "measure" layer, that outputs a confusion matrix for a binary problem. Although Caffe already has a Accuracy layer, sometimes you want something more, like a F-measure.
    Bellow are two examples of layers. One of them is a "measure" layer, that outputs the accuracy and a confusion matrix for a binary problem during training and the accuracy, false positive rate and false negative rate during test/validation. Although Caffe already has a Accuracy layer, sometimes you want something more, like a F-measure.

    The other is a custom data layer, that receives a text file with image paths, loads a batch of images and preprocesses them. Just a quick tip, Caffe already has a big range of data layers and probably a custom layer is not the most efficient way if you just want something simple.

    ###Measure Layer
    @@ -106,6 +107,8 @@ This is my *measureLayer.py* with my class definition:
    # and the second class would be 'positive'

    import caffe
    TRAIN = 0
    TEST = 1

    class Measure_Layer(caffe.Layer):
    #Setup method
    @@ -114,10 +117,12 @@ class Measure_Layer(caffe.Layer):
    if len(bottom) != 2:
    raise Exception("Wrong number of bottom blobs (prediction and label)")

    #And five top blobs
    if len(top) != 5:
               raise Exception("Wrong number of top blobs (acc, tp, tn, fp and fn)")

    #And some top blobs, depending on the phase
    if self.phase = TEST and len(top) != 3:
               raise Exception("Wrong number of top blobs (acc, FPR, FNR)")
          if self.phase = TRAIN and len(top) != 5:
    raise Exception("Wrong number of top blobs (acc, tp, tn, fp and fn)")

    #Initialize some attributes
           self.TPs = 0.0
    self.TNs = 0.0
    @@ -150,7 +155,7 @@ class Measure_Layer(caffe.Layer):
    self.FPs += 1.0

    acc = (self.TPs + self.TNs) / self.totalImgs

          try: #just assuring we don't divide by 0
                   fpr = self.FPs / (self.FPs + self.TNs)
    except:
    @@ -160,14 +165,18 @@ class Measure_Layer(caffe.Layer):
    fnr = self.FNs / (self.FNs + self.TPs)
    except:
    fnr = -1.0

    #output data to top blob
    top[0].data = acc
    top[1].data = self.TPs
    top[2].data = self.TNs
    top[3].data = self.FPs
    top[4].data = self.FNs

    if self.phase == TRAIN:
    top[1].data = self.TPs
    top[2].data = self.TNs
    top[3].data = self.FPs
    top[4].data = self.FNs
    elif self.phase == TEST:
    top[1].data = fpr
    top[2].data = fnr

    def reshape(self, bottom, top):
    """
           We don't need to reshape or instantiate anything that is input-size sensitive
    @@ -199,22 +208,41 @@ layer {
    module: "measureLayer"
    layer: "Measure_Layer"
    }
    include {
    phase: TRAIN
    }
    }
    layer {
    name: "metrics"
    type: "Python"
    top: "Acc"
     top: "FPR"
     top: "FNR"
     bottom: "prediction"   #let's supose we have these two bottom blobs
     bottom: "label"
     python_param {
    module: "measureLayer"
    layer: "Measure_Layer"
    }
    include {
    phase: TEST
    }
    }
    ```

    ###Data Layer
    My *dataLayer.py* could be something like:
    ```python
    import caffe
    TRAIN = 0
    TEST = 1

    class Custom_Data_Layer(caffe.Layer):
    def setup(self, bottom, top):
    # Check top shape (depending on the phase)
    if self.phase == TRAIN and len(top) != 2:
    # Check top shape
    if len(top) != 2:
               raise Exception("Need to define tops (data and label)")
    elif self.phase == TEST and len(top) != 1:
    raise Exception("Need to define top (data)")

    #Check bottom shape
           if len(bottom) != 0:
    @@ -255,6 +283,8 @@ class Custom_Data_Layer(caffe.Layer):
    top[1].data[itt, ...] = label

    def load_next_img(self):
    #If we have finished forwarding all images, then an epoch has finished
    #and it is time to start a new one
    if self._cur == len(self.imgTuples):
    self._cur = 0
    shuffle(self.imgTuples)
    @@ -276,5 +306,23 @@ class Custom_Data_Layer(caffe.Layer):
    This layer does not back propagate
    """
    pass
    ```

    ```
    And the *prototxt* would be like:
    ```
    layer {
    name: "Data"
    type: "Python"
     top: "data"
     top: "label"
     python_param {
    module: "dataLayer"
    layer: "Custom_Data_Layer"
    param_str: '{"batch_size": 126,"im_shape":256, "crop_size":224, "src_file": "path_to_TRAIN_file.txt"}'
    }
    include{
    phase: TRAIN
    }
    }
    ```
  6. @rafaspadilha rafaspadilha revised this gist Dec 17, 2016. 1 changed file with 76 additions and 1 deletion.
    77 changes: 76 additions & 1 deletion customLayerTutorial.md
    Original file line number Diff line number Diff line change
    @@ -202,4 +202,79 @@ layer {
    }
    ```

    ###Data Layer
    ###Data Layer
    ```python
    import caffe
    TRAIN = 0
    TEST = 1

    class Custom_Data_Layer(caffe.Layer):
    def setup(self, bottom, top):
    # Check top shape (depending on the phase)
    if self.phase == TRAIN and len(top) != 2:
               raise Exception("Need to define tops (data and label)")
    elif self.phase == TEST and len(top) != 1:
    raise Exception("Need to define top (data)")

    #Check bottom shape
           if len(bottom) != 0:
    raise Exception("Do not define a bottom.")

    #Read parameters
    params = eval(self.param_str)
           src_file = params["src_file"]
           self.batch_size = params["batch_size"]
           self.im_shape = params["im_shape"]
           self.crop_size = params.get("crop_size", False)

    #Reshape top
    if self.crop_size:
    top[0].reshape(self.batch_size, 3, self.crop_size, self.crop_size)
    else:
    top[0].reshape(self.batch_size, 3, self.im_shape, self.im_shape)

    top[1].reshape(self.batch_size)

    #Read source file
           #I'm just assuming we have this method that reads the source file
    #and returns a list of tuples in the form of (img, label)
    self.imgTuples = readSrcFile(src_file)

    self._cur = 0 #use this to check if we need to restart the list of imgs

    def forward(self, bottom, top):
    for itt in range(self.batch_size):
    # Use the batch loader to load the next image.
    im, label = self.load_next_image()

               #Here we could preprocess the image
               # ...

    # Add directly to the top blob
    top[0].data[itt, ...] = im
    top[1].data[itt, ...] = label

    def load_next_img(self):
    if self._cur == len(self.imgTuples):
    self._cur = 0
    shuffle(self.imgTuples)

    im, label = self.imgTuples[self._cur]
    self._cur += 1

    return im, label

    def reshape(self, bottom, top):
    """
    There is no need to reshape the data, since the input is of fixed size
    (img shape and batch size)
    """
    pass

    def backward(self, bottom, top):
    """
    This layer does not back propagate
    """
    pass

    ```
  7. @rafaspadilha rafaspadilha revised this gist Dec 17, 2016. 1 changed file with 7 additions and 1 deletion.
    8 changes: 7 additions & 1 deletion customLayerTutorial.md
    Original file line number Diff line number Diff line change
    @@ -75,7 +75,7 @@ Important remarks:
    - You can pass parameters to the layer using **param_str** (more on accessing them bellow);
    - Just like any other layer, you can define in which phase you want it to be active (see the examples to see how you can check the current phase);

    ##Passing Parameters to the layer
    ##Passing parameters to the layer
    You can define the layer parameters in the prototxt by using *param_str*. Once you've done it, here is an example on how you access these paremeters inside the layer class:

    ```python
    @@ -89,6 +89,11 @@ def setup(self, bottom, top):
    # ...
    ```

    ##Where should I save the class file?
    You have two options (at least that I know of). Either you can save the custom layer file in the same folder as you are going to run the *caffe* command (probably where your prototxt files would be).
    Another way, also my favorite one, is to save all your custom layers in a folder and adding this folder to your PYTHONPATH.


    ##Examples
    Bellow are two examples of layers I use during my work. One of them is a "measure" layer, that outputs a confusion matrix for a binary problem. Although Caffe already has a Accuracy layer, sometimes you want something more, like a F-measure.
    The other is a custom data layer, that receives a text file with image paths, loads a batch of images and preprocesses them. Just a quick tip, Caffe already has a big range of data layers and probably a custom layer is not the most efficient way if you just want something simple.
    @@ -196,4 +201,5 @@ layer {
    }
    }
    ```

    ###Data Layer
  8. @rafaspadilha rafaspadilha revised this gist Dec 17, 2016. 1 changed file with 5 additions and 4 deletions.
    9 changes: 5 additions & 4 deletions customLayerTutorial.md
    Original file line number Diff line number Diff line change
    @@ -105,14 +105,15 @@ import caffe
    class Measure_Layer(caffe.Layer):
    #Setup method
    def setup(self, bottom, top):

    #We want two bottom blobs, the labels and the predictions
    if len(bottom) != 2:
    raise Exception("Wrong number of bottom blobs (prediction and label)")


    #And five top blobs
    if len(top) != 5:
               raise Exception("Wrong number of top blobs (acc, tp, tn, fp and fn)")
           #Initialize some attributes

    #Initialize some attributes
           self.TPs = 0.0
    self.TNs = 0.0
    self.FPs = 0.0
    @@ -170,7 +171,7 @@ class Measure_Layer(caffe.Layer):

    def backward(self, bottom, top):
    """
    These layers does not back propagate
    This layer does not back propagate
    """
    pass
    ```
  9. @rafaspadilha rafaspadilha revised this gist Dec 17, 2016. 1 changed file with 25 additions and 3 deletions.
    28 changes: 25 additions & 3 deletions customLayerTutorial.md
    Original file line number Diff line number Diff line change
    @@ -94,13 +94,15 @@ Bellow are two examples of layers I use during my work. One of them is a "measur
    The other is a custom data layer, that receives a text file with image paths, loads a batch of images and preprocesses them. Just a quick tip, Caffe already has a big range of data layers and probably a custom layer is not the most efficient way if you just want something simple.

    ###Measure Layer
    ```python
    import caffe
    This is my *measureLayer.py* with my class definition:

    ```python
    #Remark: This class is designed for a binary problem, where the first class would be the 'negative'
    # and the second class would be 'positive'

    class measureLayer(caffe.Layer):
    import caffe

    class Measure_Layer(caffe.Layer):
    #Setup method
    def setup(self, bottom, top):

    @@ -173,4 +175,24 @@ class measureLayer(caffe.Layer):
    pass
    ```

    And this is an example of a *prototxt* with it:
    ```
    layer {
    name: "metrics"
    type: "Python"
    top: "Acc"
     top: "TPs"
     top: "TNs"
     top: "FPs"
     top: "FNs"
     bottom: "prediction"   #let's supose we have these two bottom blobs
     bottom: "label"
     python_param {
    module: "measureLayer"
    layer: "Measure_Layer"
    }
    }
    ```
    ###Data Layer
  10. @rafaspadilha rafaspadilha revised this gist Dec 17, 2016. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion customLayerTutorial.md
    Original file line number Diff line number Diff line change
    @@ -160,7 +160,7 @@ class measureLayer(caffe.Layer):
    top[3].data = self.FPs
    top[4].data = self.FNs

    def reshape(self, bottom, top):
    def reshape(self, bottom, top):
    """
           We don't need to reshape or instantiate anything that is input-size sensitive
           """
  11. @rafaspadilha rafaspadilha revised this gist Dec 17, 2016. 1 changed file with 2 additions and 4 deletions.
    6 changes: 2 additions & 4 deletions customLayerTutorial.md
    Original file line number Diff line number Diff line change
    @@ -95,10 +95,7 @@ The other is a custom data layer, that receives a text file with image paths, lo

    ###Measure Layer
    ```python
    import numpy as np
    import scipy
    import caffe
    from random import shuffle

    #Remark: This class is designed for a binary problem, where the first class would be the 'negative'
    # and the second class would be 'positive'
    @@ -129,7 +126,8 @@ class measureLayer(caffe.Layer):
    self.totalImgs += len(labels)

    for i in range(len(labels)): #len(labels) is equal to the batch size
    pred = predictions[i] #pred is a tuple with the normalized probability of a sample i.r.t. two classes
    pred = predictions[i] #pred is a tuple with the normalized probability
    #of a sample i.r.t. two classes
    lab = labels[i]

    if pred[0] > pred[1]:
  12. @rafaspadilha rafaspadilha revised this gist Dec 17, 2016. 1 changed file with 85 additions and 0 deletions.
    85 changes: 85 additions & 0 deletions customLayerTutorial.md
    Original file line number Diff line number Diff line change
    @@ -7,6 +7,9 @@ Usually you would create a custom layer to implement a funcionality that isn't a
    ###- What will I need?
    Probably just Python and Caffe instaled.

    ###- Is there any downside?
    Creating a python custom layer adds some overhead to your network and probably isn't as efficient as a C++ custom layer. However, this way, you won't have to compile the whole caffe with your new layer.

    ##Layer Template

    ```python
    @@ -87,7 +90,89 @@ def setup(self, bottom, top):
    ```

    ##Examples
    Bellow are two examples of layers I use during my work. One of them is a "measure" layer, that outputs a confusion matrix for a binary problem. Although Caffe already has a Accuracy layer, sometimes you want something more, like a F-measure.
    The other is a custom data layer, that receives a text file with image paths, loads a batch of images and preprocesses them. Just a quick tip, Caffe already has a big range of data layers and probably a custom layer is not the most efficient way if you just want something simple.

    ###Measure Layer
    ```python
    import numpy as np
    import scipy
    import caffe
    from random import shuffle

    #Remark: This class is designed for a binary problem, where the first class would be the 'negative'
    # and the second class would be 'positive'

    class measureLayer(caffe.Layer):
    #Setup method
    def setup(self, bottom, top):

    #We want two bottom blobs, the labels and the predictions
    if len(bottom) != 2:
    raise Exception("Wrong number of bottom blobs (prediction and label)")

    if len(top) != 5:
               raise Exception("Wrong number of top blobs (acc, tp, tn, fp and fn)")
           #Initialize some attributes
           self.TPs = 0.0
    self.TNs = 0.0
    self.FPs = 0.0
    self.FNs = 0.0
    self.totalImgs = 0

    #Forward method
    def forward(self, bottom, top):
    #The order of these depends on the prototxt definition
    predictions = bottom[0].data
    labels = bottom[1].data

    self.totalImgs += len(labels)

    for i in range(len(labels)): #len(labels) is equal to the batch size
    pred = predictions[i] #pred is a tuple with the normalized probability of a sample i.r.t. two classes
    lab = labels[i]

    if pred[0] > pred[1]:
    if lab == 1.0:
    self.FNs += 1.0
    else:
    self.TNs += 1.0
    else:
    if lab == 1.0:
    self.TPs += 1.0
    else:
    self.FPs += 1.0

    acc = (self.TPs + self.TNs) / self.totalImgs

          try: #just assuring we don't divide by 0
                   fpr = self.FPs / (self.FPs + self.TNs)
    except:
    fpr = -1.0

    try: #just assuring we don't divide by 0
    fnr = self.FNs / (self.FNs + self.TPs)
    except:
    fnr = -1.0

    #output data to top blob
    top[0].data = acc
    top[1].data = self.TPs
    top[2].data = self.TNs
    top[3].data = self.FPs
    top[4].data = self.FNs

    def reshape(self, bottom, top):
    """
           We don't need to reshape or instantiate anything that is input-size sensitive
           """
    pass

    def backward(self, bottom, top):
    """
    These layers does not back propagate
    """
    pass
    ```

    ###Data Layer
  13. @rafaspadilha rafaspadilha revised this gist Dec 17, 2016. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions customLayerTutorial.md
    Original file line number Diff line number Diff line change
    @@ -5,7 +5,7 @@ This tutorial will guide through the steps to create a simple custom layer for C
    Usually you would create a custom layer to implement a funcionality that isn't available in Caffe, tuning it for your requirements.

    ###- What will I need?
    Python and Caffe instaled and a sample layer template (provided bellow) so you can customize it.
    Probably just Python and Caffe instaled.

    ##Layer Template

    @@ -67,7 +67,7 @@ layer {
    Important remarks:
    - **type** must be **Python**;
    - You must have a **python_param** dictionary with at least the **module** and **layer** parameters;
    - **module** refers to the file where you implemented your layer;
    - **module** refers to the file where you implemented your layer (without the *.py*);
    - **layer** refers to the name of your class;
    - You can pass parameters to the layer using **param_str** (more on accessing them bellow);
    - Just like any other layer, you can define in which phase you want it to be active (see the examples to see how you can check the current phase);
  14. @rafaspadilha rafaspadilha revised this gist Dec 17, 2016. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions customLayerTutorial.md
    Original file line number Diff line number Diff line change
    @@ -88,6 +88,6 @@ def setup(self, bottom, top):

    ##Examples

    #Measure Layer
    ###Measure Layer

    #Data Layer
    ###Data Layer
  15. @rafaspadilha rafaspadilha revised this gist Dec 17, 2016. 1 changed file with 5 additions and 1 deletion.
    6 changes: 5 additions & 1 deletion customLayerTutorial.md
    Original file line number Diff line number Diff line change
    @@ -86,4 +86,8 @@ def setup(self, bottom, top):
    # ...
    ```

    ##Examples
    ##Examples

    #Measure Layer

    #Data Layer
  16. @rafaspadilha rafaspadilha renamed this gist Dec 17, 2016. 1 changed file with 3 additions and 1 deletion.
    4 changes: 3 additions & 1 deletion gistfile1.md → customLayerTutorial.md
    Original file line number Diff line number Diff line change
    @@ -84,4 +84,6 @@ def setup(self, bottom, top):

    #Continue with the setup
    # ...
    ```
    ```

    ##Examples
  17. @rafaspadilha rafaspadilha revised this gist Dec 17, 2016. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion gistfile1.md
    Original file line number Diff line number Diff line change
    @@ -72,7 +72,7 @@ Important remarks:
    - You can pass parameters to the layer using **param_str** (more on accessing them bellow);
    - Just like any other layer, you can define in which phase you want it to be active (see the examples to see how you can check the current phase);

    ###Passing Parameters to the layer
    ##Passing Parameters to the layer
    You can define the layer parameters in the prototxt by using *param_str*. Once you've done it, here is an example on how you access these paremeters inside the layer class:

    ```python
  18. @rafaspadilha rafaspadilha revised this gist Dec 17, 2016. 1 changed file with 16 additions and 4 deletions.
    20 changes: 16 additions & 4 deletions gistfile1.md
    Original file line number Diff line number Diff line change
    @@ -65,11 +65,23 @@ layer {
    ```

    Important remarks:
    - **type** must be *"Python"*;
    - **type** must be **Python**;
    - You must have a **python_param** dictionary with at least the **module** and **layer** parameters;
    - **module** refers to the file where you implemented your layer
    - **layer** refers to the name of your class
    - You can pass parameters to the layer using *param_str* (more on accessing it bellow);
    - **module** refers to the file where you implemented your layer;
    - **layer** refers to the name of your class;
    - You can pass parameters to the layer using **param_str** (more on accessing them bellow);
    - Just like any other layer, you can define in which phase you want it to be active (see the examples to see how you can check the current phase);

    ###Passing Parameters to the layer
    You can define the layer parameters in the prototxt by using *param_str*. Once you've done it, here is an example on how you access these paremeters inside the layer class:

    ```python
    def setup(self, bottom, top):
    params = eval(self.param_str)
       param1 = params["param1"]
    param2 = params.get('param2', False) #I usually use this when fetching a bool
    param3 = params["param3"]

    #Continue with the setup
    # ...
    ```
  19. @rafaspadilha rafaspadilha revised this gist Dec 17, 2016. 1 changed file with 27 additions and 11 deletions.
    38 changes: 27 additions & 11 deletions gistfile1.md
    Original file line number Diff line number Diff line change
    @@ -1,5 +1,5 @@
    # How to create a custom Caffe layer in Python?
    This tutorial will guide through the steps to create a simple custom layer for Caffe using python.
    This tutorial will guide through the steps to create a simple custom layer for Caffe using python. By the end of it, there are some examples of custom layers.

    ###- Why would I want to do that?
    Usually you would create a custom layer to implement a funcionality that isn't available in Caffe, tuning it for your requirements.
    @@ -29,7 +29,7 @@ class My_Custom_Layer(caffe.Layer):
    So important things to remember:
    - Your custom layer has to inherit from **caffe.Layer** (so don't forget to *import caffe*);
    - You must define the four following methods: **setup**, **forward**, **reshape** and **backward**;
    - All methods have a *top* and a *bottom* parameters, that store the input and the output passed to your layer;
    - All methods have a *top* and a *bottom* parameters, which are the blobs that store the input and the output passed to your layer. You can access it using *top[i].data* or *bottom[i].data*, where *i* is the index of the blob in case you have more than one upper or lower blob.


    ###- Setup method
    @@ -44,16 +44,32 @@ The Forward method is called for each input batch and is where most of your logi
    ###- Backward method
    The Backward method is called during the backward pass of the network. For example, in a convolution-like layer, this would be where you would calculate the gradients. This is optional (a layer can be forward-only).

    ##Prototxt Template
    Ok, so now you have your layer designed! This is how you define it in your *.prototxt* file:

    ```
    layer {
    name: "LayerName"
    type: "Python"
    top: "TopBlobName"
     bottom: "BottomBlobName"
     python_param {
    module: "My_Custom_Layer_File"
    layer: "My_Custom_Layer_Class"
       param_str: '{"param1": 1,"param2":True, "param3":"some string"}'
    }
    include{
    phase: TRAIN
    }
    }
    ```

    Important remarks:
    - **type** must be *"Python"*;
    - You must have a **python_param** dictionary with at least the **module** and **layer** parameters;
    - **module** refers to the file where you implemented your layer
    - **layer** refers to the name of your class
    - You can pass parameters to the layer using *param_str* (more on accessing it bellow);
    - Just like any other layer, you can define in which phase you want it to be active (see the examples to see how you can check the current phase);









    ###Prototxt
    ###Passing Parameters to the layer
  20. @rafaspadilha rafaspadilha revised this gist Dec 17, 2016. 1 changed file with 15 additions and 1 deletion.
    16 changes: 15 additions & 1 deletion gistfile1.md
    Original file line number Diff line number Diff line change
    @@ -28,7 +28,7 @@ class My_Custom_Layer(caffe.Layer):

    So important things to remember:
    - Your custom layer has to inherit from **caffe.Layer** (so don't forget to *import caffe*);
    - You must define the four following methods: **setup**, **forward**, **reshape**, **backward**;
    - You must define the four following methods: **setup**, **forward**, **reshape** and **backward**;
    - All methods have a *top* and a *bottom* parameters, that store the input and the output passed to your layer;


    @@ -43,3 +43,17 @@ The Forward method is called for each input batch and is where most of your logi

    ###- Backward method
    The Backward method is called during the backward pass of the network. For example, in a convolution-like layer, this would be where you would calculate the gradients. This is optional (a layer can be forward-only).












    ###Prototxt
    ###Passing Parameters to the layer
  21. @rafaspadilha rafaspadilha revised this gist Dec 16, 2016. 1 changed file with 5 additions and 1 deletion.
    6 changes: 5 additions & 1 deletion gistfile1.md
    Original file line number Diff line number Diff line change
    @@ -29,13 +29,17 @@ class My_Custom_Layer(caffe.Layer):
    So important things to remember:
    - Your custom layer has to inherit from **caffe.Layer** (so don't forget to *import caffe*);
    - You must define the four following methods: **setup**, **forward**, **reshape**, **backward**;
    - All methods have a *top* and a *bottom* parameters, that store the input and the output passed to your layer;


    ###- Setup method
    The Setup method is called once during the lifetime of the execution, when Caffe is instantiating all layers. This is where you will read parameters, instantiate fixed-size buffers.

    ###- Reshape method
    Use the reshape method for initialization/setup that depends on the bottom blob (layer input) size. It is called once for each batch.

    ###- Forward method
    The Forward method is called for each input batch and is where most of your logic will be.

    ###- Backward method

    The Backward method is called during the backward pass of the network. For example, in a convolution-like layer, this would be where you would calculate the gradients. This is optional (a layer can be forward-only).
  22. @rafaspadilha rafaspadilha revised this gist Dec 16, 2016. 1 changed file with 6 additions and 6 deletions.
    12 changes: 6 additions & 6 deletions gistfile1.md
    Original file line number Diff line number Diff line change
    @@ -1,10 +1,10 @@
    # How to create a custom Caffe layer in Python?
    This tutorial will guide through the steps to create a simple custom layer for Caffe using python.

    ###Why would I want to do that?
    ###- Why would I want to do that?
    Usually you would create a custom layer to implement a funcionality that isn't available in Caffe, tuning it for your requirements.

    ###What will I need?
    ###- What will I need?
    Python and Caffe instaled and a sample layer template (provided bellow) so you can customize it.

    ##Layer Template
    @@ -31,11 +31,11 @@ So important things to remember:
    - You must define the four following methods: **setup**, **forward**, **reshape**, **backward**;


    ###Setup method
    ###- Setup method

    ###Reshape method
    ###- Reshape method

    ###Forward method
    ###- Forward method

    ###Backward method
    ###- Backward method

  23. @rafaspadilha rafaspadilha revised this gist Dec 16, 2016. 1 changed file with 12 additions and 2 deletions.
    14 changes: 12 additions & 2 deletions gistfile1.md
    Original file line number Diff line number Diff line change
    @@ -27,5 +27,15 @@ class My_Custom_Layer(caffe.Layer):
    ```

    So important things to remember:
    - Your custom layer has to herit from *caffe.Layer* (so don't forget to *import caffe*);
    - You must define the four following methods: *setup*, *forward*, *reshape*, *backward*;
    - Your custom layer has to inherit from **caffe.Layer** (so don't forget to *import caffe*);
    - You must define the four following methods: **setup**, **forward**, **reshape**, **backward**;


    ###Setup method

    ###Reshape method

    ###Forward method

    ###Backward method

  24. @rafaspadilha rafaspadilha revised this gist Dec 16, 2016. 1 changed file with 7 additions and 2 deletions.
    9 changes: 7 additions & 2 deletions gistfile1.md
    Original file line number Diff line number Diff line change
    @@ -8,7 +8,7 @@ Usually you would create a custom layer to implement a funcionality that isn't a
    Python and Caffe instaled and a sample layer template (provided bellow) so you can customize it.

    ##Layer Template

    ```python
    import caffe

    @@ -18,9 +18,14 @@ class My_Custom_Layer(caffe.Layer):

    def forward(self, bottom, top):
    pass

    def reshape(self, bottom, top):
    pass

    def backward(self, bottom, top):
    pass
    ```
    ```

    So important things to remember:
    - Your custom layer has to herit from *caffe.Layer* (so don't forget to *import caffe*);
    - You must define the four following methods: *setup*, *forward*, *reshape*, *backward*;
  25. @rafaspadilha rafaspadilha revised this gist Dec 16, 2016. 1 changed file with 5 additions and 36 deletions.
    41 changes: 5 additions & 36 deletions gistfile1.md
    Original file line number Diff line number Diff line change
    @@ -11,47 +11,16 @@ Python and Caffe instaled and a sample layer template (provided bellow) so you c

    ```python
    import caffe
    import numpy as np

    class FPR_FNR_Layer(caffe.Layer):
    class My_Custom_Layer(caffe.Layer):
    def setup(self, bottom, top):
    top[0].reshape(1)
    top[1].reshape(1)

    def forward(self, bottom, top):
    """
    Load Data
    """
    predictions = bottom[0].data
    labels = bottom[1].data

    FPs = 0.0
    FNs = 0.0

    for i in range(len(labels)):
    pred = predictions[i]
    lab = labels[i]

    if pred[0] > pred[1]:
    if lab == 1.0:
    FNs += 1.0
    else:
    if lab == 0.0:
    FPs += 1.0

    top[0].data[0] = FPs/float(len(labels))
    top[1].data[0] = FNs/float(len(labels))
    pass

    def reshape(self, bottom, top):
    """
    There is no need to reshape the data, since the input is of fixed size
    (rows and columns)
    """
    def forward(self, bottom, top):
    pass
    def reshape(self, bottom, top):
    pass

    def backward(self, bottom, top):
    """
    These layers does not back propagate
    """
    pass
    ```
  26. @rafaspadilha rafaspadilha revised this gist Dec 16, 2016. 1 changed file with 45 additions and 2 deletions.
    47 changes: 45 additions & 2 deletions gistfile1.md
    Original file line number Diff line number Diff line change
    @@ -9,6 +9,49 @@ Python and Caffe instaled and a sample layer template (provided bellow) so you c

    ##Layer Template

    ```
    WWW
    ```python
    import caffe
    import numpy as np

    class FPR_FNR_Layer(caffe.Layer):
    def setup(self, bottom, top):
    top[0].reshape(1)
    top[1].reshape(1)

    def forward(self, bottom, top):
    """
    Load Data
    """
    predictions = bottom[0].data
    labels = bottom[1].data

    FPs = 0.0
    FNs = 0.0

    for i in range(len(labels)):
    pred = predictions[i]
    lab = labels[i]

    if pred[0] > pred[1]:
    if lab == 1.0:
    FNs += 1.0
    else:
    if lab == 0.0:
    FPs += 1.0

    top[0].data[0] = FPs/float(len(labels))
    top[1].data[0] = FNs/float(len(labels))

    def reshape(self, bottom, top):
    """
    There is no need to reshape the data, since the input is of fixed size
    (rows and columns)
    """
    pass

    def backward(self, bottom, top):
    """
    These layers does not back propagate
    """
    pass
    ```
  27. @rafaspadilha rafaspadilha revised this gist Dec 16, 2016. 1 changed file with 6 additions and 1 deletion.
    7 changes: 6 additions & 1 deletion gistfile1.md
    Original file line number Diff line number Diff line change
    @@ -5,5 +5,10 @@ This tutorial will guide through the steps to create a simple custom layer for C
    Usually you would create a custom layer to implement a funcionality that isn't available in Caffe, tuning it for your requirements.

    ###What will I need?
    Probably just Python and Caffe instaled and a sample layer template (provided bellow) so you can customize it.
    Python and Caffe instaled and a sample layer template (provided bellow) so you can customize it.

    ##Layer Template

    ```
    WWW
    ```
  28. @rafaspadilha rafaspadilha revised this gist Dec 16, 2016. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions gistfile1.md
    Original file line number Diff line number Diff line change
    @@ -1,9 +1,9 @@
    # How to create a custom Caffe layer in Python?
    This tutorial will guide through the steps to create a simple custom layer for Caffe using python.

    ##Why would I want to do that?
    ###Why would I want to do that?
    Usually you would create a custom layer to implement a funcionality that isn't available in Caffe, tuning it for your requirements.

    ##What will I need?
    ###What will I need?
    Probably just Python and Caffe instaled and a sample layer template (provided bellow) so you can customize it.

  29. @rafaspadilha rafaspadilha revised this gist Dec 16, 2016. 1 changed file with 8 additions and 2 deletions.
    10 changes: 8 additions & 2 deletions gistfile1.md
    Original file line number Diff line number Diff line change
    @@ -1,3 +1,9 @@
    # How to create a Caffe Layer in Python?
    # How to create a custom Caffe layer in Python?
    This tutorial will guide through the steps to create a simple custom layer for Caffe using python.

    ##Why would I want to do that?
    Usually you would create a custom layer to implement a funcionality that isn't available in Caffe, tuning it for your requirements.

    ##What will I need?
    Probably just Python and Caffe instaled and a sample layer template (provided bellow) so you can customize it.

    ##Why would you want to do that?
  30. @rafaspadilha rafaspadilha renamed this gist Dec 16, 2016. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.