diff --git a/CMakeLists.txt b/CMakeLists.txt index 2a48e062eca..54b044d347b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -17,6 +17,7 @@ caffe_option(CPU_ONLY "Build Caffe wihtout CUDA support" OFF) # TODO: rename to caffe_option(USE_CUDNN "Build Caffe with cuDNN libary support" ON IF NOT CPU_ONLY) caffe_option(BUILD_SHARED_LIBS "Build shared libraries" ON) caffe_option(BUILD_python "Build Python wrapper" ON) +set(python_version "2" CACHE STRING "Specify which python version to use") caffe_option(BUILD_matlab "Build Matlab wrapper" OFF IF UNIX OR APPLE) caffe_option(BUILD_docs "Build documentation" ON IF UNIX OR APPLE) diff --git a/cmake/Dependencies.cmake b/cmake/Dependencies.cmake index aa2dcbe1d0d..b1ac96c6777 100644 --- a/cmake/Dependencies.cmake +++ b/cmake/Dependencies.cmake @@ -92,12 +92,39 @@ endif() # ---[ Python if(BUILD_python) - # disable Python 3 search - find_package(PythonInterp 2.7) - find_package(PythonLibs 2.7) - find_package(NumPy 1.7.1) - find_package(Boost 1.46 COMPONENTS python) - + if(NOT "${python_version}" VERSION_LESS "3.0.0") + # use python3 + find_package(PythonInterp 3.0) + find_package(PythonLibs 3.0) + find_package(NumPy 1.7.1) + # Find the matching boost python implementation + set(version ${PYTHONLIBS_VERSION_STRING}) + + STRING( REPLACE "." "" boost_py_version ${version} ) + find_package(Boost 1.46 COMPONENTS "python-py${boost_py_version}") + set(Boost_PYTHON_FOUND ${Boost_PYTHON-PY${boost_py_version}_FOUND}) + + while(NOT "${version}" STREQUAL "" AND NOT Boost_PYTHON_FOUND) + STRING( REGEX REPLACE "([0-9.]+).[0-9]+" "\\1" version ${version} ) + STRING( REGEX MATCHALL "([0-9.]+).[0-9]+" has_more_version ${version} ) + if("${has_more_version}" STREQUAL "") + break() + endif() + + STRING( REPLACE "." "" boost_py_version ${version} ) + find_package(Boost 1.46 COMPONENTS "python-py${boost_py_version}") + set(Boost_PYTHON_FOUND ${Boost_PYTHON-PY${boost_py_version}_FOUND}) + endwhile() + if(NOT Boost_PYTHON_FOUND) + find_package(Boost 1.46 COMPONENTS python) + endif() + else() + # disable Python 3 search + find_package(PythonInterp 2.7) + find_package(PythonLibs 2.7) + find_package(NumPy 1.7.1) + find_package(Boost 1.46 COMPONENTS python) + endif() if(PYTHONLIBS_FOUND AND NUMPY_FOUND AND Boost_PYTHON_FOUND) set(HAVE_PYTHON TRUE) endif() diff --git a/docs/installation.md b/docs/installation.md index 16575b54029..144e6a34f67 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -30,7 +30,7 @@ Caffe has several dependencies. Pycaffe and Matcaffe interfaces have their own natural needs. -* For Python Caffe: `Python 2.7`, `numpy (>= 1.7)`, boost-provided `boost.python` +* For Python Caffe: `Python 2.7` or `Python 3.3+`, `numpy (>= 1.7)`, boost-provided `boost.python` * For MATLAB Caffe: MATLAB with the `mex` compiler. **cuDNN Caffe**: for fastest operation Caffe is accelerated by drop-in integration of [NVIDIA cuDNN](https://developer.nvidia.com/cudnn). To speed up your Caffe models, install cuDNN then uncomment the `USE_CUDNN := 1` flag in `Makefile.config` when installing Caffe. Acceleration is automatic. For now cuDNN v1 is integrated but see [PR #1731](https://github.com/BVLC/caffe/pull/1731) for v2. @@ -69,7 +69,7 @@ but we suggest first installing the [Anaconda](https://store.continuum.io/cshop/ To import the `caffe` Python module after completing the installation, add the module directory to your `$PYTHONPATH` by `export PYTHONPATH=/path/to/caffe/python:$PYTHONPATH` or the like. You should not import the module in the `caffe/python/caffe` directory! -*Caffe's Python interface works with Python 2.7. Python 3 or earlier Pythons are your own adventure.* +*Caffe's Python interface works with Python 2.7. Python 3.3+ should work out of the box without protobuf support. For protobuf support please install protobuf 3.0 alpha (https://developers.google.com/protocol-buffers/). Earlier Pythons are your own adventure.* #### MATLAB diff --git a/python/caffe/_caffe.cpp b/python/caffe/_caffe.cpp index a5d0e64605e..03967a21029 100644 --- a/python/caffe/_caffe.cpp +++ b/python/caffe/_caffe.cpp @@ -275,7 +275,9 @@ BOOST_PYTHON_MODULE(_caffe) { bp::class_ >("BoolVec") .def(bp::vector_indexing_suite >()); - import_array(); + // boost python expects a void (missing) return value, while import_array + // returns NULL for python3. import_array1() forces a void return value. + import_array1(); } } // namespace caffe diff --git a/python/caffe/io.py b/python/caffe/io.py index 0ce9ecfeeed..f51e3a64d36 100644 --- a/python/caffe/io.py +++ b/python/caffe/io.py @@ -3,7 +3,14 @@ from scipy.ndimage import zoom from skimage.transform import resize -from caffe.proto import caffe_pb2 +try: + # Python3 will most likely not be able to load protobuf + from caffe.proto import caffe_pb2 +except: + if sys.version_info >= (3,0): + print("Failed to include caffe_pb2, things might go wrong!") + else: + raise ## proto / datum / ndarray conversion diff --git a/python/caffe/pycaffe.py b/python/caffe/pycaffe.py index 31c145d77a5..d662d6cc282 100644 --- a/python/caffe/pycaffe.py +++ b/python/caffe/pycaffe.py @@ -4,7 +4,10 @@ """ from collections import OrderedDict -from itertools import izip_longest +try: + from itertools import izip_longest +except: + from itertools import zip_longest as izip_longest import numpy as np from ._caffe import Net, SGDSolver diff --git a/python/classify.py b/python/classify.py index d435a572266..81d06369341 100755 --- a/python/classify.py +++ b/python/classify.py @@ -103,7 +103,7 @@ def main(argv): channel_swap=channel_swap) if args.gpu: - print 'GPU mode' + print('GPU mode') # Load numpy array (.npy), directory glob (*.jpg), or image file. args.input_file = os.path.expanduser(args.input_file) @@ -115,12 +115,12 @@ def main(argv): else: inputs = [caffe.io.load_image(args.input_file)] - print "Classifying %d inputs." % len(inputs) + print("Classifying %d inputs." % len(inputs)) # Classify. start = time.time() predictions = classifier.predict(inputs, not args.center_only) - print "Done in %.2f s." % (time.time() - start) + print("Done in %.2f s." % (time.time() - start)) # Save np.save(args.output_file, predictions) diff --git a/python/detect.py b/python/detect.py index cb0c2645761..d395bd97abf 100755 --- a/python/detect.py +++ b/python/detect.py @@ -115,7 +115,7 @@ def main(argv): context_pad=args.context_pad) if args.gpu: - print 'GPU mode' + print('GPU mode') # Load input. t = time.time() diff --git a/python/draw_net.py b/python/draw_net.py index 4457b793e86..6320f775ef7 100755 --- a/python/draw_net.py +++ b/python/draw_net.py @@ -36,7 +36,7 @@ def main(): args = parse_args() net = caffe_pb2.NetParameter() text_format.Merge(open(args.input_net_proto_file).read(), net) - print 'Drawing net to %s' % args.output_image_file + print('Drawing net to %s' % args.output_image_file) caffe.draw.draw_net_to_file(net, args.output_image_file, args.rankdir)