switch from inheritance to directly overriding methods for caffe.Net
authorJonathan L Long <jonlong@cs.berkeley.edu>
Fri, 4 Apr 2014 05:21:13 +0000 (22:21 -0700)
committerJonathan L Long <jonlong@cs.berkeley.edu>
Sat, 5 Apr 2014 06:39:56 +0000 (23:39 -0700)
Also, internally drop the "Caffe" prefix for classes exported by the
internal _caffe module. This change means that SGDSolver will
automatically return a Net with the "nice" Python interface rather than
the internal one, (and avoids the extra layer of method wrapping that
results from switching to composition).

python/caffe/_caffe.cpp
python/caffe/pycaffe.py

index c3bd704..11813f6 100644 (file)
@@ -305,7 +305,7 @@ class CaffeSGDSolver {
 // The boost python module definition.
 BOOST_PYTHON_MODULE(_caffe) {
   boost::python::class_<CaffeNet>(
-      "CaffeNet", boost::python::init<string, string>())
+      "Net", boost::python::init<string, string>())
       .def("Forward",          &CaffeNet::Forward)
       .def("ForwardPrefilled", &CaffeNet::ForwardPrefilled)
       .def("Backward",         &CaffeNet::Backward)
@@ -314,11 +314,12 @@ BOOST_PYTHON_MODULE(_caffe) {
       .def("set_phase_train",  &CaffeNet::set_phase_train)
       .def("set_phase_test",   &CaffeNet::set_phase_test)
       .def("set_device",       &CaffeNet::set_device)
-      .add_property("blobs",   &CaffeNet::blobs)
+      // rename blobs here since the pycaffe.py wrapper will replace it
+      .add_property("_blobs",  &CaffeNet::blobs)
       .add_property("layers",  &CaffeNet::layers);
 
   boost::python::class_<CaffeBlob, CaffeBlobWrap>(
-      "CaffeBlob", boost::python::no_init)
+      "Blob", boost::python::no_init)
       .add_property("name",     &CaffeBlob::name)
       .add_property("num",      &CaffeBlob::num)
       .add_property("channels", &CaffeBlob::channels)
@@ -329,7 +330,7 @@ BOOST_PYTHON_MODULE(_caffe) {
       .add_property("diff",     &CaffeBlobWrap::get_diff);
 
   boost::python::class_<CaffeLayer>(
-      "CaffeLayer", boost::python::no_init)
+      "Layer", boost::python::no_init)
       .add_property("name",  &CaffeLayer::name)
       .add_property("blobs", &CaffeLayer::blobs);
 
index 367ad4f..863d315 100644 (file)
@@ -3,26 +3,31 @@ Wrap the internal caffe C++ module (_caffe.so) with a clean, Pythonic
 interface.
 """
 
-from ._caffe import CaffeNet, SGDSolver
+from ._caffe import Net, SGDSolver
 from collections import OrderedDict
 
-class Net(CaffeNet):
+# we directly update methods from Net here (rather than using composition or
+# inheritance) so that nets created by caffe (e.g., by SGDSolver) will
+# automatically have the improved interface
+
+@property
+def _Net_blobs(self):
+    """
+    An OrderedDict (bottom to top, i.e., input to output) of network
+    blobs indexed by name
+    """
+    return OrderedDict([(bl.name, bl) for bl in self._blobs])
+
+Net.blobs = _Net_blobs
+
+@property
+def _Net_params(self):
     """
-    The direct Python interface to caffe, exposing Forward and Backward
-    passes, data, gradients, and layer parameters
+    An OrderedDict (bottom to top, i.e., input to output) of network
+    parameters indexed by name; each is a list of multiple blobs (e.g.,
+    weights and biases)
     """
-    def __init__(self, param_file, pretrained_param_file):
-        super(Net, self).__init__(param_file, pretrained_param_file)
-        self._blobs = OrderedDict([(bl.name, bl)
-                                   for bl in super(Net, self).blobs])
-        self.params = OrderedDict([(lr.name, lr.blobs)
-                                   for lr in super(Net, self).layers
-                                   if len(lr.blobs) > 0])
+    return OrderedDict([(lr.name, lr.blobs) for lr in self.layers
+                                            if len(lr.blobs) > 0])
 
-    @property
-    def blobs(self):
-        """
-        An OrderedDict (bottom to top, i.e., input to output) of network
-        blobs indexed by name
-        """
-        return self._blobs
+Net.params = _Net_params