ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

WSL下CPU版Caffe与Faster R-CNN编译配置实战指南

WSL下CPU版Caffe与Faster R-CNN编译配置实战指南

1. 为什么要在WSL里折腾Caffe版Faster R-CNN

先说清楚一件事:现在都2025年了,为什么还有人要在WSL里装Caffe版本的Faster R-CNN?答案很直接——复现老论文、跑通遗留项目、维护祖传代码。很多经典的目标检测论文(比如Faster R-CNN原始实现)都是基于Caffe写的,而Caffe这个框架在Windows原生环境下编译简直是噩梦。WSL的出现让这件事变得可行:你既能在Windows上享受图形界面和日常办公,又能在WSL里用Linux工具链编译Caffe。

但问题来了——大多数人手头只有CPU,没有GPU。网上能找到的教程要么默认你有CUDA,要么在编译Caffe时各种报错。我自己前前后后装了不下五次,踩过的坑包括但不限于:protobuf版本冲突、hdf5路径找不到、boost库链接失败、OpenCV版本不兼容、conda环境里Python版本和Caffe不匹配……每一次都是血泪史。

这篇文章就是把这些经验全部摊开来讲。我会从WSL环境准备开始,一步步带你装好conda、编译Caffe的CPU版本、配置Faster R-CNN的Python接口,最后跑通一个demo验证。整个过程不需要GPU,不需要CUDA,纯CPU就能跑。适合谁看?适合那些需要在WSL里复现Caffe项目、手头只有CPU、又不想被各种编译错误折磨的开发者。如果你正好在这个场景里,那这篇内容能帮你省下至少两天的排查时间。

2. WSL环境与conda的准备工作

2.1 WSL版本选择与系统更新

WSL现在有两个主要版本:WSL1和WSL2。装Caffe必须用WSL2,因为WSL1的文件系统性能太差,编译Caffe这种大型项目会慢到让你怀疑人生。检查当前版本用这个命令:

wsl --list --verbose

如果显示VERSION是1,需要升级到2:

wsl --set-version <发行版名称> 2

发行版我推荐Ubuntu 20.04或者22.04。20.04的好处是很多老项目的依赖包版本正好匹配,22.04则更新一些但可能需要手动降级某些库。我自己用的是20.04,因为Caffe对较新的GCC和glibc兼容性不太好。

进入WSL后第一件事是更新系统:

sudo apt update && sudo apt upgrade -y

这一步别跳过。我有一次偷懒没更新,结果后面装依赖时各种版本冲突,最后还是回来重新更新了一遍。

2.2 安装编译Caffe所需的系统依赖

Caffe的CPU版本编译需要一大堆系统库。这些依赖缺一个都会导致编译失败,而且报错信息往往不直接指向缺失的库,排查起来很痛苦。所以建议一次性全部装齐:

sudo apt install -y build-essential cmake git pkg-config \ libprotobuf-dev libleveldb-dev libsnappy-dev libopencv-dev \ libhdf5-serial-dev protobuf-compiler libgflags-dev \ libgoogle-glog-dev liblmdb-dev libboost-all-dev \ libatlas-base-dev libopenblas-dev \ python3-dev python3-pip python3-numpy

这里有几个关键点需要解释:

  • libatlas-base-dev和libopenblas-dev:这两个是线性代数库,Caffe的CPU模式需要它们来做矩阵运算。ATLAS是默认选项,但OpenBLAS在多核CPU上性能更好。两个都装上,编译时可以通过Makefile.config选择。
  • libboost-all-dev:Boost库,Caffe的C++代码大量使用了Boost的智能指针和线程库。这个包很大,装的时候耐心等。
  • libhdf5-serial-dev:HDF5数据格式支持。注意要装serial版本而不是mpi版本,否则编译时会报链接错误。
  • protobuf-compiler和libprotobuf-dev:Protocol Buffers,Caffe用protobuf来定义网络结构。版本很关键,后面会详细说。

装完之后验证一下protobuf版本:

protoc --version

Ubuntu 20.04默认给的是3.6.1,这个版本和Caffe兼容性最好。如果你用的是22.04,可能会给到3.12或更高,那就需要手动降级,否则Caffe编译会报一堆protobuf相关的错误。

2.3 conda环境创建与Python版本选择

接下来装conda。我推荐用Miniconda而不是Anaconda,因为Anaconda太臃肿了,装了一堆用不到的东西。下载安装:

wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh bash Miniconda3-latest-Linux-x86_64.sh

安装过程中会问你是否初始化conda到bashrc,选yes。然后重新加载shell配置:

source ~/.bashrc

现在创建专门用于Caffe的conda环境。Python版本必须选3.6或3.7,这是最关键的一点。Caffe的Python接口对Python 3.8+支持很差,很多老代码用了3.8里已经移除的API。我试过用3.9,结果import caffe直接报错,折腾了半天最后还是退回3.7。

conda create -n caffe-cpu python=3.7 -y conda activate caffe-cpu

在环境里装必要的Python包:

pip install numpy==1.19.5 protobuf==3.6.1 six scikit-image matplotlib

注意numpy的版本。1.19.5是最后一个对Python 3.7友好且和Caffe兼容的版本。如果你装了numpy 1.20+,Caffe的Python接口会因为numpy的API变化而报错。protobuf的Python包版本也要和系统里的protoc版本一致,否则序列化/反序列化时会出问题。

3. Caffe源码编译中的关键配置与踩坑

3.1 获取Caffe源码与Makefile.config定制

Caffe的官方仓库已经很久不更新了,但编译CPU版本仍然用它最稳妥:

cd ~ git clone https://github.com/BVLC/caffe.git cd caffe cp Makefile.config.example Makefile.config

接下来编辑Makefile.config,这是整个编译过程中最核心的一步。用你习惯的编辑器打开:

nano Makefile.config

需要修改的地方我逐条说明:

第一处:启用CPU-only模式

CPU_ONLY := 1

把这一行前面的注释去掉。这是CPU版本编译的前提,不设置的话Caffe会去找CUDA,然后报错说找不到cuda.h。

第二处:Python路径配置

PYTHON_INCLUDE := $(HOME)/miniconda3/envs/caffe-cpu/include/python3.7m \ $(HOME)/miniconda3/envs/caffe-cpu/lib/python3.7/site-packages/numpy/core/include PYTHON_LIB := $(HOME)/miniconda3/envs/caffe-cpu/lib

这里的路径要根据你的实际conda安装位置调整。用conda info --base可以查看conda的根目录。注意Python 3.7的include目录名是python3.7m,那个m不能漏掉。

第三处:HDF5路径

INCLUDE_DIRS := $(PYTHON_INCLUDE) /usr/local/include /usr/include/hdf5/serial LIBRARY_DIRS := $(PYTHON_LIB) /usr/local/lib /usr/lib /usr/lib/x86_64-linux-gnu /usr/lib/x86_64-linux-gnu/hdf5/serial

Ubuntu下HDF5的头文件在/usr/include/hdf5/serial,库文件在/usr/lib/x86_64-linux-gnu/hdf5/serial。如果不加这两行,编译时会报fatal error: hdf5.h: No such file or directory。

第四处:BLAS选择

BLAS := open

如果你装了OpenBLAS就用open,否则用atlas。OpenBLAS在多核CPU上性能明显更好,建议用它。

3.2 protobuf版本冲突的完整排查过程

这是最容易踩的坑,我单独拿出来讲。症状是这样的:编译Caffe时一切正常,但运行Python接口时import caffe报错:

ImportError: libprotobuf.so.XX: cannot open shared object file

或者更隐蔽的:

[libprotobuf FATAL google/protobuf/stubs/common.cc:83] This program was compiled against version 3.6.1 of the Protocol Buffer runtime library, which is not compatible with the installed version (3.12.4).

根因分析:系统里存在多个protobuf版本。conda环境里pip装的protobuf是一个版本,系统apt装的protobuf-compiler是另一个版本,Caffe编译时链接的又是其中一个。三者版本不一致就会出问题。

排查步骤:

  1. 查看系统protoc版本:protoc --version
  2. 查看conda环境里Python protobuf版本:python -c "import google.protobuf; print(google.protobuf.__version__)"
  3. 查看Caffe链接的protobuf库:ldd build/lib/libcaffe.so | grep protobuf

解决方案:统一到3.6.1版本。系统层面如果apt给的不是3.6.1,需要手动编译安装:

wget https://github.com/protocolbuffers/protobuf/releases/download/v3.6.1/protobuf-all-3.6.1.tar.gz tar -xzf protobuf-all-3.6.1.tar.gz cd protobuf-3.6.1 ./configure --prefix=/usr/local make -j$(nproc) sudo make install sudo ldconfig

然后conda环境里也装对应版本:

pip install protobuf==3.6.1

最后重新编译Caffe。这一步做完,protobuf的问题基本就解决了。

3.3 编译过程中的其他常见错误与修复

除了protobuf,还有几个高频错误:

错误一:fatal error: boost/... : No such file or directory

虽然装了libboost-all-dev,但有时候头文件路径没被正确识别。检查/usr/include/boost是否存在。如果存在还报错,在Makefile.config的INCLUDE_DIRS里加上/usr/include。

错误二:undefined reference to cv::imread

OpenCV链接问题。Ubuntu 20.04默认装的是OpenCV 4.x,而Caffe的代码是按OpenCV 2.x/3.x写的。需要在Makefile里加:

LIBRARIES += opencv_core opencv_highgui opencv_imgproc opencv_imgcodecs

同时把opencv_imgcodecs加进去,因为OpenCV 4把imread从highgui移到了imgcodecs。

错误三:error: ‘CV_LOAD_IMAGE_COLOR’ was not declared

同样是OpenCV 4的API变化。CV_LOAD_IMAGE_COLOR被改成了cv::IMREAD_COLOR。需要手动修改源码:

grep -rl "CV_LOAD_IMAGE" --include="*.cpp" --include="*.hpp" . | xargs sed -i 's/CV_LOAD_IMAGE_COLOR/cv::IMREAD_COLOR/g' grep -rl "CV_LOAD_IMAGE" --include="*.cpp" --include="*.hpp" . | xargs sed -i 's/CV_LOAD_IMAGE_GRAYSCALE/cv::IMREAD_GRAYSCALE/g'

错误四:cannot find -lboost_python3

Boost Python库的命名问题。Ubuntu下可能是libboost_python37.so而不是libboost_python3.so。找到实际的文件名:

ls /usr/lib/x86_64-linux-gnu/ | grep boost_python

然后在Makefile.config里把PYTHON_LIBRARIES改成实际的名字。

4. Faster R-CNN的Python接口配置与验证

4.1 编译pycaffe与环境变量设置

Caffe编译完成后,需要单独编译Python接口:

make pycaffe -j$(nproc)

编译成功后,把pycaffe的路径加到Python的搜索路径里:

echo 'export PYTHONPATH=$HOME/caffe/python:$PYTHONPATH' >> ~/.bashrc source ~/.bashrc

验证一下:

python -c "import caffe; print(caffe.__version__)"

如果输出了版本号,说明pycaffe装好了。如果报错,大概率还是protobuf或者numpy版本的问题,回到3.2节排查。

4.2 Faster R-CNN代码获取与依赖安装

Caffe版的Faster R-CNN有几个流行的实现,我选的是比较经典的那个py-faster-rcnn结构。代码结构大概是这样的:

py-faster-rcnn/ ├── caffe-fast-rcnn/ # 修改过的Caffe ├── lib/ # Python工具库 ├── data/ # 数据目录 ├── experiments/ # 训练配置 ├── tools/ # 训练和测试脚本 └── output/ # 输出目录

注意:这个项目自带了一个修改版的Caffe(caffe-fast-rcnn),里面增加了ROI Pooling层等Faster R-CNN特有的层。你不能用之前编译的原始Caffe,必须编译这个修改版。编译步骤和前面一样,但Makefile.config需要重新配置。

Python端的依赖:

cd py-faster-rcnn/lib pip install -r requirements.txt

主要需要Cython、easydict、pyyaml、scikit-image等。如果requirements.txt里的版本太老装不上,可以手动装兼容版本:

pip install Cython easydict pyyaml scikit-image==0.17.2

scikit-image的版本要注意,0.18+移除了一些老API,会导致faster rcnn的代码报错。0.17.2是最后一个兼容的版本。

4.3 编译Cython扩展与跑通demo

faster rcnn的lib目录下有几个Cython文件需要编译:

cd py-faster-rcnn/lib make

这一步会生成cython_bbox.so和cython_nms.so。如果报错说找不到numpy头文件,检查一下:

python -c "import numpy; print(numpy.get_include())"

然后在setup.py里确认include路径正确。

编译完成后,把lib目录加到PYTHONPATH:

export PYTHONPATH=$HOME/py-faster-rcnn/lib:$PYTHONPATH

现在可以跑demo了。faster rcnn的demo需要下载预训练模型,但CPU版本跑预训练模型会非常慢(一张图可能要几十秒)。为了快速验证环境是否配好,我建议先用一个简单的测试脚本:

import caffe import numpy as np # 测试Caffe基本功能 net = caffe.Net( 'models/test.prototxt', caffe.TEST ) print("Caffe加载网络成功") print("网络层数:", len(net.layers))

如果这个能跑通,说明Caffe和Python接口都没问题。然后再跑完整的demo:

cd py-faster-rcnn ./tools/demo.py --cpu

注意加--cpu参数,否则会尝试用GPU。CPU模式下跑一张图大概需要20-40秒(取决于你的CPU性能),耐心等。

5. CPU模式下的性能调优与实用技巧

5.1 利用OpenBLAS多线程加速

CPU模式下最大的性能瓶颈是矩阵运算。Caffe默认用ATLAS,但OpenBLAS在多核CPU上能快2-3倍。确保Makefile.config里设置了:

BLAS := open

然后设置OpenBLAS的线程数:

export OPENBLAS_NUM_THREADS=$(nproc)

我实测在8核CPU上,设置线程数后单张图片的推理时间从40秒降到了15秒左右。虽然还是慢,但至少能用了。

另外,Caffe的prototxt里可以设置engine: CAFFE来强制使用CPU引擎。在Faster R-CNN的test.prototxt里,把ROI Pooling层的engine改成CAFFE:

layer { name: 'roi_pool' type: 'ROIPooling' bottom: 'conv5' bottom: 'rois' top: 'pool5' roi_pooling_param { pooled_w: 7 pooled_h: 7 spatial_scale: 0.0625 } }

5.2 减少不必要的内存拷贝

CPU模式下内存带宽是另一个瓶颈。有几个地方可以优化:

  • 使用LMDB而不是HDF5:LMDB的读取效率比HDF5高,尤其是在小批量数据时。在数据层配置里用Data类型而不是HDF5Data。
  • 设置合理的batch size:CPU模式下batch size不宜过大,通常设为1-2。太大的batch会导致内存交换,反而更慢。
  • 关闭不必要的日志:Caffe的GLOG会输出大量日志,设置GLOG_minloglevel=2只输出错误信息。
export GLOG_minloglevel=2

5.3 常见运行时错误速查

即使编译通过了,运行时还是可能遇到各种问题。这里整理一个速查表:

错误信息根因解决方案
ImportError: No module named caffePYTHONPATH没设置把caffe/python加到PYTHONPATH
ImportError: libcaffe.so: cannot open动态库路径不对把caffe/build/lib加到LD_LIBRARY_PATH
Check failed: error == cudaSuccess代码里硬编码了GPU确认所有层都支持CPU,或修改源码
F0510 ... Check failed: top_shape[j] == bottom_shape[j]网络结构配置错误检查prototxt里的输入尺寸
numpy.dtype size changednumpy版本不兼容降级到1.19.5
AttributeError: 'module' object has no attribute 'imread'OpenCV版本问题确认python-opencv版本,或改用cv2.imread

这个表里的每一行都是我实际遇到过的。特别是最后那个OpenCV的问题,因为conda环境里可能装了opencv-python,而系统里又有python3-opencv,两个版本冲突时就会出各种奇怪的错误。建议在conda环境里统一用pip装的opencv-python:

pip install opencv-python==4.5.5.64

6. 从安装到跑通:我的完整操作时间线

最后分享一下我最近一次完整安装的实际时间线,供你参考:

  • 第1-2小时:WSL更新、系统依赖安装。大部分时间花在下载和安装libboost-all-dev上,这个包解压后有好几个G。
  • 第3小时:conda环境创建、Python包安装。protobuf和numpy的版本选择花了些时间试错。
  • 第4-5小时:Caffe编译。第一次编译因为OpenCV 4的API问题失败,修改源码后重新编译通过。
  • 第6小时:pycaffe编译和测试。遇到protobuf运行时版本冲突,降级系统protobuf后解决。
  • 第7-8小时:Faster R-CNN代码配置、Cython编译、demo测试。Cython编译时numpy头文件路径问题卡了一会儿。

总共大约8小时。但这是在我已经踩过所有坑的前提下。如果你是第一次装,可能要花两到三天。所以我的建议是:严格按照本文的版本号来,不要随意升级或降级任何组件。Python 3.7 + protobuf 3.6.1 + numpy 1.19.5 + OpenCV 4.5.5这个组合是我验证过最稳定的。

还有一个实用技巧:整个安装过程建议在WSL的home目录下操作,不要放在/mnt/c/下面。WSL2访问Windows文件系统的性能很差,编译Caffe这种IO密集的操作放在/mnt/c/下会慢好几倍。我一开始把代码放在Windows桌面,编译了40分钟还没完,移到home目录后15分钟就搞定了。

另外,如果你只是需要跑通Faster R-CNN的推理,不需要训练,那其实可以考虑用PyTorch版本的实现,安装配置简单得多。但如果你必须用Caffe版本(比如要复现论文的原始结果,或者维护遗留项目),那本文的流程就是最可靠的路径。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进