# caffe Custom Python Layers Measure Layer

## Example

In this example we will design 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.

This is my measureLayer.py with my class definition:

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

import caffe
TRAIN = 0
TEST = 1

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 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
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
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
"""
pass

def backward(self, bottom, top):
"""
This layer does not back propagate
"""
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"
}
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
}
}
``````