From 7003d1b8e24416cb5bdb5537a7805cb5a9de2ca1 Mon Sep 17 00:00:00 2001 From: Evan Shelhamer Date: Tue, 30 Jun 2015 15:35:21 -0700 Subject: [PATCH] [examples] add Euclidean loss PythonLayer --- examples/pycaffe/layers/pyloss.py | 37 ++++++++++++++++++++++++ examples/pycaffe/linreg.prototxt | 60 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 97 insertions(+) create mode 100644 examples/pycaffe/layers/pyloss.py create mode 100644 examples/pycaffe/linreg.prototxt diff --git a/examples/pycaffe/layers/pyloss.py b/examples/pycaffe/layers/pyloss.py new file mode 100644 index 0000000..6200e6b --- /dev/null +++ b/examples/pycaffe/layers/pyloss.py @@ -0,0 +1,37 @@ +import caffe +import numpy as np + + +class EuclideanLossLayer(caffe.Layer): + """ + Compute the Euclidean Loss in the same manner as the C++ EuclideanLossLayer + to demonstrate the class interface for developing layers in Python. + """ + + def setup(self, bottom, top): + # check input pair + if len(bottom) != 2: + raise Exception("Need two inputs to compute distance.") + + def reshape(self, bottom, top): + # check input dimensions match + if bottom[0].count != bottom[1].count: + raise Exception("Inputs must have the same dimension.") + # difference is shape of inputs + self.diff = np.zeros_like(bottom[0].data, dtype=np.float32) + # loss output is scalar + top[0].reshape(1) + + def forward(self, bottom, top): + self.diff[...] = bottom[0].data - bottom[1].data + top[0].data[...] = np.sum(self.diff**2) / bottom[0].num / 2. + + def backward(self, top, propagate_down, bottom): + for i in range(2): + if not propagate_down[i]: + continue + if i == 0: + sign = 1 + else: + sign = -1 + bottom[i].diff[...] = sign * self.diff / bottom[i].num diff --git a/examples/pycaffe/linreg.prototxt b/examples/pycaffe/linreg.prototxt new file mode 100644 index 0000000..c0fb077 --- /dev/null +++ b/examples/pycaffe/linreg.prototxt @@ -0,0 +1,60 @@ +name: 'LinearRegressionExample' +# define a simple network for linear regression on dummy data +# that computes the loss by a PythonLayer. +layer { + type: 'DummyData' + name: 'x' + top: 'x' + dummy_data_param { + shape: { dim: 10 dim: 3 dim: 2 } + data_filler: { type: 'gaussian' } + } +} +layer { + type: 'DummyData' + name: 'y' + top: 'y' + dummy_data_param { + shape: { dim: 10 dim: 3 dim: 2 } + data_filler: { type: 'gaussian' } + } +} +# include InnerProduct layers for parameters +# so the net will need backward +layer { + type: 'InnerProduct' + name: 'ipx' + top: 'ipx' + bottom: 'x' + inner_product_param { + num_output: 10 + weight_filler { type: 'xavier' } + } +} +layer { + type: 'InnerProduct' + name: 'ipy' + top: 'ipy' + bottom: 'y' + inner_product_param { + num_output: 10 + weight_filler { type: 'xavier' } + } +} +layer { + type: 'Python' + name: 'loss' + top: 'loss' + bottom: 'ipx' + bottom: 'ipy' + python_param { + # the module name -- usually the filename -- that needs to be in $PYTHONPATH + module: 'pyloss' + # the layer name -- the class name in the module + layer: 'EuclideanLossLayer' + } + # set loss weight so Caffe knows this is a loss layer. + # since PythonLayer inherits directly from Layer, this isn't automatically + # known to Caffe + loss_weight: 1 +} -- 2.7.4