-
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
Python layer for rapidly writing nets in Python #1020
Conversation
Looks like a helpful addition. Once it's ready I'll be eager to help with CMake. |
This will be awesome whenever it's ready. I was just thinking this layer could be even more useful if a prefetch thread could call it as a data provider (in fact this is how all external data is provided in Alex Krizhevsky's cuda-convnet, which honestly makes it more flexible/extensible than our current set of data layers) -- it could be very useful if someone wanted to extend @longjon's python layer to work that way. Or maybe that would be better implemented in some other way? (It's getting a bit meta with a Python wrapper calling a C++ library which itself sometimes calls Python code...) I guess you can technically already write your data provider in Python, editing the input blobs, but for training you'd have to reimplement the solver logic, and it would be done serially between passes rather than in a separate thread...so maybe we're back to the idea of having a solver callback? Anyway, now I'm just rambling; hopefully someone else thinks this would be useful and has some more coherent thoughts on a good design. |
Rebasing @jeffdonahue having a prefetch hook to python / matlab / not C++ is a fine idea but I'm not sure what it should look like either. I do entirely agree it would be useful. While we have the solver callback now the data processing and solving are done in alternation instead of simultaneously by prefetching. Perhaps a PythonLayer and PythonData split is worthwhile since the layer interface is setup / forward / backward whereas for data it's really about setup / prefetch. I'm not certain a layer interface for prefetch is entirely right although that is part of the data / transformation layer conversation and more broadly a question of what to do about phases and stages. Should there be privileged stages like PREFETCH and DEPLOY that the Now I've done my rambling too. Should we meet up for a brew session on this? The cold brew returns tomorrow so there's occasion for Caffe conversation. |
I agree with @shelhamer that this will involve to think also on transformation augmentation (and generally synthetic generation). Finding a good design could be useful also in further for exploring transformation sampling space dynamically through monitoring loss or accuracy. |
This is necessary to allow Python to access Blobs from the layer interface, which takes raw pointers. (It does, however, mean that Python layers must not hold onto Blobs beyond their layer calls.)
This is needed for passing propagate_down to Python layers.
This option links the standard caffe binaries, not just pycaffe, against the Python libraries, making it possible to embed Python in caffe.
3205563
to
b46ede2
Compare
b46ede2
to
a48990d
Compare
Hey Jon, I was thinking of trying this out. I didn't actually test this, but is the
Should it not be something like:
|
Oh dear, @jeffdonahue, of course you're correct. I've fixed the example. |
I rebased and tried building this. I get a bunch of multiple definition errors when trying to compile pycaffe. Everything compiles correctly if I check out the second to last commit (before the PythonLayer is added) and comment out the Python object being added to
So I think the multiple definition errors come from the fact that Caffe builds with the PyCaffe object and PyCaffe builds with the Caffe object, leading to multiple definitions of things in the PyCaffe object? Not sure though... |
(Sorry, never mind -- it works when I compile from your non-rebased branch so I must have introduced a problem while rebasing.) |
@jeffdonahue, I suspect this is due to the addition of the Python layer doesn't really need to statically link against pycaffe; the problem is that dynamically loading In my local code, I link statically against So I think you've gathered by now that the linking situation is a confusing mess, and I don't have a straightforward answer right now. Actually my local version is very much in flux at the moment, so stay tuned, use the older branch if it suits your needs, and let me know if you run into more problems... or solutions. |
@Yangqing it'd be great to have your thoughts on the linking. The registry does keep the layer code neat, but the Python layer makes layer prototyping a breeze and gives a lot of flexibility. Lacking the C++ tool chain knowledge, it could take me a lot of cups of coffee to figure this out. |
Hmm, let me take a look tonight and see if I can find the problem... it seems that we may have mixed a few things in the source code (compiled and linked the same cc file twice, maybe?) and it's most likely not caused by the registry code. |
So I think I've found the problem. See my comments in the code prefixed with "[Compilation]" for details. Overall, my feeling is that we should really put all the PythonLayer related things into python_layer.hpp/cpp, and avoid the loop of having caffe depending on _caffe and _caffe depending again on caffe - I think this causes the double definition problem. |
@@ -103,6 +103,9 @@ OBJ_BUILD_DIR := $(BUILD_DIR)/src/$(PROJECT) | |||
LAYER_BUILD_DIR := $(OBJ_BUILD_DIR)/layers | |||
UTIL_BUILD_DIR := $(OBJ_BUILD_DIR)/util | |||
OBJS := $(PROTO_OBJS) $(CXX_OBJS) $(CU_OBJS) | |||
ifeq ($(USE_PYTHON_LAYER), 1) | |||
OBJS += python/$(PROJECT)/_$(PROJECT).o |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[Compilation] I think this causes the mutliple definition problem: python/caffe/_caffe.o is going to be linked into libcaffe.a because of this, and then when we make pycaffe, python/caffe/_caffe.cpp (which _caffe.o comes from) gets linked again - causing multiple definitions.
We should remove this line (together with other changes, see below).
OK I've finished my pass. @shelhamer @longjon please take another look. It does not seem to be the registration problem - mostly because we indeed linked the same cpp file twice. Should be relatively easy to fix. Happy to chip in if any further problems emerge. |
Great, thanks for the investigation @Yangqing. Note this isn't the latest
|
It's a little more subtle than that. Before I go into the agonizing details though, do note that this PR is now quite out-of-date, and was not intended as a final linking solution. The reason for linking against This could be done just by having Python layer The hack that I used to work around this was: link statically against Actually now I think the double protobuf loading was probably due to the fact that the In any case I've already made a lot of changes which include not needing to link against |
Upgraded and replaced by #1703. |
This PR depends on #1014, and shouldn't be merged before that one.Caffe is fast, but adding new layers is a multistep process (see #684), and is subject to all of the pitfalls of development in a low-level, compiled language. For quickly trying new ideas, speed of development may be more important than runtime speed.
This PR addresses this gap by allowing layers to be written in Python. One adds layers to the net prototxt that look like the following:
Then, one implements layers in Python with more or less the same interface as in C++, as below.
In order to make this work, the main caffe binaries need to be linked against the Python libraries. This is solved by adding a build option,
WITH_PYTHON_LAYER
, as well as a coupleifdef
s. These changes are probably not quite ready for merge; in particular, this should break the cmake build system, and the build option is not being tested in Travis yet. (@akosiorek or others, if you're eager to make this work with cmake, PRs against this branch are welcome.)Layers with learnable parameters are not supported yet.
In theory, this means you ought to be able to write layers in Theano (making use of Theano's symbolic differentiation), embed them in caffe nets, and solve using caffe. I haven't tried that yet, but it might be worth adding some Python-level helper code for that later on.
This hasn't really been tested at all (but does build and run).