define caffe.Net input preprocessing members by boost::python
authorEvan Shelhamer <shelhamer@imaginarynumber.net>
Mon, 28 Jul 2014 21:55:13 +0000 (14:55 -0700)
committerEvan Shelhamer <shelhamer@imaginarynumber.net>
Tue, 5 Aug 2014 22:55:45 +0000 (15:55 -0700)
define `Net.{mean, input_scale, channel_swap}` on the boost::python side
so that the members always exist. drop ugly initialization logic.

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

index 10fc23b..30c86ae 100644 (file)
@@ -25,6 +25,7 @@
 
 
 using namespace caffe;  // NOLINT(build/namespaces)
+using boost::python::dict;
 using boost::python::extract;
 using boost::python::len;
 using boost::python::list;
@@ -274,6 +275,10 @@ struct CaffeNet {
 
   // The pointer to the internal caffe::Net instant.
   shared_ptr<Net<float> > net_;
+  // Input preprocessing configuration attributes.
+  dict mean_;
+  dict input_scale_;
+  dict channel_swap_;
   // if taking input from an ndarray, we need to hold references
   object input_data_;
   object input_labels_;
@@ -311,19 +316,22 @@ BOOST_PYTHON_MODULE(_caffe) {
   boost::python::class_<CaffeNet, shared_ptr<CaffeNet> >(
       "Net", boost::python::init<string, string>())
       .def(boost::python::init<string>())
-      .def("_forward",          &CaffeNet::Forward)
-      .def("_backward",         &CaffeNet::Backward)
-      .def("set_mode_cpu",      &CaffeNet::set_mode_cpu)
-      .def("set_mode_gpu",      &CaffeNet::set_mode_gpu)
-      .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)
-      .add_property("layers",   &CaffeNet::layers)
-      .add_property("inputs",   &CaffeNet::inputs)
-      .add_property("outputs",  &CaffeNet::outputs)
-      .def("_set_input_arrays", &CaffeNet::set_input_arrays)
-      .def("save",              &CaffeNet::save);
+      .def("_forward",              &CaffeNet::Forward)
+      .def("_backward",             &CaffeNet::Backward)
+      .def("set_mode_cpu",          &CaffeNet::set_mode_cpu)
+      .def("set_mode_gpu",          &CaffeNet::set_mode_gpu)
+      .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)
+      .add_property("layers",       &CaffeNet::layers)
+      .add_property("inputs",       &CaffeNet::inputs)
+      .add_property("outputs",      &CaffeNet::outputs)
+      .add_property("mean",         &CaffeNet::mean_)
+      .add_property("input_scale",  &CaffeNet::input_scale_)
+      .add_property("channel_swap", &CaffeNet::channel_swap_)
+      .def("_set_input_arrays",     &CaffeNet::set_input_arrays)
+      .def("save",                  &CaffeNet::save);
 
   boost::python::class_<CaffeBlob, CaffeBlobWrap>(
       "Blob", boost::python::no_init)
index 870dec4..64747f3 100644 (file)
@@ -211,8 +211,6 @@ def _Net_set_mean(self, input_, mean_f, mode='elementwise'):
     mode: elementwise = use the whole mean (and check dimensions)
           channel = channel constant (e.g. mean pixel instead of mean image)
     """
-    if not hasattr(self, 'mean'):
-        self.mean = {}
     if input_ not in self.inputs:
         raise Exception('Input not in {}'.format(self.inputs))
     in_shape = self.blobs[input_].data.shape
@@ -240,8 +238,6 @@ def _Net_set_input_scale(self, input_, scale):
     input_: which input to assign this scale factor
     scale: scale coefficient
     """
-    if not hasattr(self, 'input_scale'):
-        self.input_scale = {}
     if input_ not in self.inputs:
         raise Exception('Input not in {}'.format(self.inputs))
     self.input_scale[input_] = scale
@@ -257,8 +253,6 @@ def _Net_set_channel_swap(self, input_, order):
     order: the order to take the channels.
            (2,1,0) maps RGB to BGR for example.
     """
-    if not hasattr(self, 'channel_swap'):
-        self.channel_swap = {}
     if input_ not in self.inputs:
         raise Exception('Input not in {}'.format(self.inputs))
     self.channel_swap[input_] = order
@@ -282,6 +276,7 @@ def _Net_preprocess(self, input_name, input_):
     caffe_inputs: (K x H x W) ndarray
     """
     caffe_in = input_.astype(np.float32)
+    mean = self.mean.get(input_name)
     input_scale = self.input_scale.get(input_name)
     channel_order = self.channel_swap.get(input_name)
     in_size = self.blobs[input_name].data.shape[2:]
@@ -292,8 +287,8 @@ def _Net_preprocess(self, input_name, input_):
     if channel_order is not None:
         caffe_in = caffe_in[:, :, channel_order]
     caffe_in = caffe_in.transpose((2, 0, 1))
-    if hasattr(self, 'mean'):
-        caffe_in -= self.mean.get(input_name, 0)
+    if mean is not None:
+        caffe_in -= mean
     return caffe_in
 
 
@@ -302,10 +297,11 @@ def _Net_deprocess(self, input_name, input_):
     Invert Caffe formatting; see Net.preprocess().
     """
     decaf_in = input_.copy().squeeze()
+    mean = self.mean.get(input_name)
     input_scale = self.input_scale.get(input_name)
     channel_order = self.channel_swap.get(input_name)
-    if hasattr(self, 'mean'):
-        decaf_in += self.mean.get(input_name, 0)
+    if mean is not None:
+        decaf_in += mean
     decaf_in = decaf_in.transpose((1,2,0))
     if channel_order is not None:
         channel_order_inverse = [channel_order.index(i)