-
Notifications
You must be signed in to change notification settings - Fork 18.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Reform the boost::python wrapper, including layers implemented in Python #1703
Conversation
641dce3
to
84bafa5
Compare
This new style of python wrappers are really hard to read and doesn't actually simplify the existing code. The boost.python call policies are very confusing. The old code has no call policies, and instead handles the lifetime explicitly with
|
@netheril96, I can certainly see the argument that boost::python may be a bit too willing to embrace template metaprogramming, but consider the advantages of the new style:
So, in my view, explicitness is improved, and don't forget
and
|
84bafa5
to
e04a467
Compare
@longjon I rebased on dev and archived your branch to
TODO
|
e04a467
to
6106e73
Compare
A note for a possible future PR: With V2 protobufs, a new, nicer(?) way to implement Python layers becomes possible. Instead of explicitly declaring each Python layer to have type |
45095b7
to
5ef63e0
Compare
Rebased with layer factory using |
PythonLayer (rightfully) refuses to be instantiated when a module and class aren't given. It's still covered by tests however through pytest.
5ef63e0
to
9b38744
Compare
Reform the boost::python wrapper, including layers implemented in Python
Postscript: the "shortcomings" noted above were addressed as follows:
|
The pyreformation BVLC#1703 aligned pycaffe Net with the real Caffe Net. This broke the pre-processing helpers that had been bolted on to `caffe.Net`. These responsibilities are gathered in `caffe.io.Transformer` instead. This is only an intermediate step in a real solution to pycaffe IO that should make use of the same data pipeline as the rest of the framework. See BVLC#1245 for further thoughts on input processing.
I was just trying out PythonLayer for the first time today/yesterday -- I'm using it to input data, replacing a combination of synchronized Using a Python |
At some point there'll be a proper PythonLayer example but until then anyone interested can check out this Python loss layer gist that ports |
Seems there is no way to pass parameters to PythonLayer. How about adding a string field into the PythonParameter as a parameter of the PythonLayer? The layer can interpret this parameter as whatever it want such as a path to a file that holds the true parameters or a json string that hold true parameters. |
Please see my PR #2001, but this is still not merged. I would appreciate any comments or suggestions. |
@tnarihi exactly what I want. I should search PRs first. Thanks. |
Is there a way to define the blob shape or number of output of python layer? |
Hi @jeffdonahue, Could you share your python_layers for HDF5 and ImageData in a gist or something similar? |
Hey @escorciav, I found very useful examples here https://github.com/tnarihi/tnarihi-caffe-helper/blob/master/python/caffe_helper/layers/data_layers.py |
Thank you. It looks very interesting and it's more pythonic+clean than my current attempt. |
This is great functionality, but is there any way to access memory on the gpu instead? It'd be nice to write gpu layers in pycuda (I've been itching for a top-k argmax/accuracy layer for multidimensional outputs so that testing is more feasible) and not have to copy the memory from the gpu to the cpu and back. |
I encounter 2 kinds of error when I use the custom python layer:
|
After #1473 and #1686. Replaces #1020.
The current boost::python code uses custom wrapper classes (
Py*
) to handle conversion, memory management, and extra checks. This is one more layer of abstraction then necessary to use boost::python, which is really intended to directly wrap C++ interfaces.This PR gets rid of all the custom wrapper classes, and uses boost::python as it was intended. Special memory management logic is handled with boost::python's call policies, and a few thin wrapper functions are used where necessary.
This leads to a better way to implement Python layers (formerly #1020). In Python, one simply subclasses
caffe.Layer
to define a layer, and uses it as in #1020.To improve readability of the changes, the commits go like this: first one commit removes most of the existing code, then support for each class is added one-at-a-time, culminating with Python layer.
Thanks to Philipp Krähenbühl for sharing his implementation of some of the functionality of the PR, which I referred to while (re)constructing this.
Improvements
caffe.get_solver
.Caffe::
functions are exposed as top-level functions of thecaffe
module rather than attached toNet
. This probably breaks some existing Python code, and of course the per-Net
functions will come back soon enough when they make sense, but for now this is more sensible.Shortcomings [see below for resolution]
Net.set_{mode/phase/device}
functions currently don't work.GetPythonLayer
needs to transfer ownership of the C++ object from itself toNet
in such a way that the Python object will be cleaned up when Net is done with the C++ object. I implemented something really hacky that I think doesn't leak memory, but won't work if you try to construct a layer object outside of a net definition (but you wouldn't do that, right?). A better solution might be to make the factory deal inshared_ptr
s.Makefile
to optionally include the Python layer. This works fine if used through pycaffe, but not through thecaffe
tool binary, due to double linking of the layer registration (and possibly other registration). I have a fix through dynamic linking, but it causes a crash on exit for some protobuf-related reason (distinct from the previous issues in Python layer for rapidly writing nets in Python #1020). More on this in the upcoming PR, "Linking Nightmare Part II". (Note, however, that enablingWITH_PYTHON_LAYER
shouldn't cause any problems with the tool binary if no Python layers are actually used.)Should be usable as is, but not well tested, and (might?) break existing Python code.