[examples] add Euclidean loss PythonLayer
authorEvan Shelhamer <shelhamer@imaginarynumber.net>
Tue, 30 Jun 2015 22:35:21 +0000 (15:35 -0700)
committerEvan Shelhamer <shelhamer@imaginarynumber.net>
Tue, 30 Jun 2015 22:35:21 +0000 (15:35 -0700)
examples/pycaffe/layers/pyloss.py [new file with mode: 0644]
examples/pycaffe/linreg.prototxt [new file with mode: 0644]

diff --git a/examples/pycaffe/layers/pyloss.py b/examples/pycaffe/layers/pyloss.py
new file mode 100644 (file)
index 0000000..6200e6b
--- /dev/null
@@ -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 (file)
index 0000000..c0fb077
--- /dev/null
@@ -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
+}