深度学习框架 Caffe 的安装与基本使用
2015-07-21Caffe 简介
Caffe 是一个 C++ 编写的深度学习框架,原来是 UC Berkeley 博士毕业的贾扬清的个人项目,后来被他开源。由于其清晰与高效而被广泛使用,用户逐渐地也形成了一个开放的社区,各方的一些重要的研究成果(主要是各种模型)都被分享到社区中,这是非常棒的一点。
Caffe 的清晰表现在网络结构与参数都独立于代码,用户只要以普通文本(但需遵循一定的简单格式)就可以定义好自己的神经网络,并按自己的需要进行调整。而其高效体现在对 CUDA 的支持,GPU 运算能极大地提高运算速度,同时提供了在 CPU 模式和 GPU 模式之间切换的简便方法。
另外,代码也写得很漂亮!
Caffe 的安装
Caffe 依赖以下外部的库或者工具:
CUDA: NVIDIA 公司发布的并行计算框架,通过利用 GPU 的处理能力来大幅提升计算性能。由于需要数据的量很大以及 DNN 本身的结构复杂性,DNN 的训练过程通常会非常非常慢,如果能够利用 CUDA 能极大地提高效率。
来块 TITAN 吧少年!
- BLAS: 被广泛使用的线性代数库
- Boost(>=1.55): 著名的 C++ 第三方库
- OpenCV(>=2.4): 著名的计算机视觉库
- Google 开源的一套东西:
- protobuf: 数据序列化框架
- gflags: 命令行参数解析库
- glog: 日志记录框架
- IO 相关的库
- hdf5
- leveldb
- snappy
- lmdb
以上依赖中可以从系统软件源安装的有 2, 5 中除 glog 外的其他两个, 6。在 Debian 上使用以下命令进行安装:
sudo apt-get install libatlas-dev libblas-dev libatlas-base-dev libatlas3-base # BLAS sudo apt-get install libprotobuf-dev protobuf-compiler libgflags-dev sudo apt-get install libhdf5-dev libleveldb-dev libsnappy-dev liblmdb-dev
Boost 虽然也能从软件源安装,但需要注意版本,如果版本过低还是需要进行编译安装。
glog 会在 Caffe 安装的时候自动安装,所以需要手动安装的就剩下:
- CUDA
- Boost
- OpenCV
CUDA 的安装笔者没有经验,就不作展开了,另外两个通过源代码编译安装即可。OpenCV 建议选择稳定版本 2.4.10。
解决上述依赖问题后进行编译安装即可。
cd caffe && mkdir build cd build cmake .. make && make install
上述命令将会把 Caffe 安装到 caffe/build/install 目录下,如果需要安装在其他位置,可以在执行 cmake 时附加参数 "CMAKE_INSTALL_PREFIX":
cmake -DCMAKE_INSTALL_PREFIX=/opt/caffe ../
注意 cmake 输出中的 "Install path" 以确认是否生效。
如果权限允许,比较方便的方法是安装到 /usr/local 下面,这样相应的头文件、库文件都是在系统的查找路径中,在使用 Caffe 的 API 时就无需再另外指定头文件位置和链接参数。
此外 Caffe 还提供了 Python 的接口,在安装目录中有一个 python 目录,将其加入到环境变量中即可在 Python 项目中使用:
export PYTHONPATH=/opt/caffe/python:$PYTHONPATH
当然了,这个 python 接口也有一些依赖需要安装,这些依赖在 python 目录下的 requirements.txt 中设置,使用 pip 即可进行安装:
sudo pip install -r requirements.txt
其中一个依赖 scipy 需要 fortran 编译器:
sudo apt-get install gfortran
至此安装结束,此时可用的资源有:
- C++ 库,包括头文件、动态链接库(或静态链接库)
- Python 接口
- 命令行工具,位于安装目录的 bin/ 目录下面
相关概念
Blob
Blob 是用于存储数据的对象,在 Caffe 中各种数据(图像输入、模型参数)都是以 Blob 的形式在网络中传输的。同时 Blob 还能在 CPU 和 GPU 之间进行同步以支持 CPU/GPU 的混合运算。
Layer
Layer 是网络的次级单元,也是 Caffe 中能在外部进行调整的最小网络结构单元 —— 一般来说,都让同一层的神经元具备相同的性质,因此也就没有必要提供对单个神经元的操作。
每个 Layer 都会有输入的 Blob 和输出的 Blob。
Net
即一个完整的包含输入层、隐藏层、输出层的深度网络,在 Caffe 中一般是一个卷积神经网络(Convolution Neural Networ, CNN)。
通过定义不同类型的 Layer,并用 Blob 将不同的 Layer 连接起来,就能产生一个 Net 。
使用 Caffe 进行训练
这里以 MNIST 的例子来进行说明。
训练参数设置
训练参数通常记录到一个统一的文件中,关键参数有:
训练(及测试)使用的网络
网络结构要在另外一个文件中定义,在配置文件中用 "net" 指定其位置,如:
net: "examples/mnist/lenet_train_test.prototxt"
学习率等网络迭代参数
Caffe 中的权值更新通过学习率和动量项来进行计算
base_lr: 0.01 # 初始学习率 momentum: 0.9 # 动量项
同时还有 "lr_policy" 等参数用于学习率的自适应优化:
lr_policy: "inv" gamma: 0.0001 power: 0.75
此外还可以通过 "weight_decay" 来设置权重衰减
weight_decay: 0.0005
训练迭代次数
设置最大迭代次数:
max_iter: 10000
训练模式(CPU/GPU)
如果系统安装了 CUDA 支持 GPU 运算,那么 GPU 模式是更好的选择,否则应当选择 CPU 模式:
solver_mode: CPU
除以上参数外,还有用于测试的一些参数:
- test_iter: 测试次数
- test_interval: 两次测试之间的间隔
在 MNIST 例子中,配置文件为 examples/mnist/lenet_solver.prototxt,其内容为:
# The train/test net protocol buffer definition net: "examples/mnist/lenet_train_test.prototxt" # test_iter specifies how many forward passes the test should carry out. # In the case of MNIST, we have test batch size 100 and 100 test iterations, # covering the full 10,000 testing images. test_iter: 100 # Carry out testing every 500 training iterations. test_interval: 500 # The base learning rate, momentum and the weight decay of the network. base_lr: 0.01 momentum: 0.9 weight_decay: 0.0005 # The learning rate policy lr_policy: "inv" gamma: 0.0001 power: 0.75 # Display every 100 iterations display: 100 # The maximum number of iterations max_iter: 10000 # snapshot intermediate results snapshot: 5000 snapshot_prefix: "examples/mnist/lenet" # solver mode: CPU or GPU solver_mode: GPU
网络结构定义
如前所述,Net 由 Layer 组成,每个 Layer 的定义都是以下形式:
layer { name: "<name>" type: "<type>" bottom: "<input blob>" top: "<output blob>" transform_param { ... } <prefix>_param { ... } }
可用的 Layer 类型及其参数见 Caffe|Layer catalogue 。
层与层通过输入和输出联系在一起,比如说定义一个两层的前馈网络,可以这样:
layer { name: "input" type: "Data" top: "data" } layer { name: "output" type: "SoftmaxWithLoss" bottom: "data" top: "loss" }
"input" 层的输出 Blob 是 "data" ,同时 "data" 这个 Blob 又是 "output" 层的输出,这两个层就这样被连接起来了。
在 MNIST 例子中,网络结构定于于 examples/mnist/lenet_train_test.prototxt 中,由于其内容较长,这里就不详细写出来了,仅以图示之。
TODO: 图
数据准备
在 MNIST 的例子中,需要将 MNIST 数据集转换为 lmdb 格式。先来看看 MNIST 数据集的处理再谈一下普通的数据如何转换成可用于训练的数据。
首先要获取数据,这都已经在 Caffe 的源代码包中提供了相应的工具:
- data/mnist/get_mnist.sh
- examples/mnist/create_mnist.sh
第一个脚本用于下载 MNIST 数据集,阅读一下脚本内容,发现不过就是几条 wget 命令而已:
wget http://yann.lecun.com/exdb/mnist/train-images-idx3-ubyte.gz wget --no-check-certificate http://yann.lecun.com/exdb/mnist/train-labels-idx1-ubyte.gz wget --no-check-certificate http://yann.lecun.com/exdb/mnist/t10k-images-idx3-ubyte.gz wget --no-check-certificate http://yann.lecun.com/exdb/mnist/t10k-labels-idx1-ubyte.gz
第二个脚本用于将下载的 MNIST 数据集转换为 lmdb 文件,脚本内容如下,也是比较简单。
EXAMPLE=examples/mnist DATA=data/mnist BUILD=build/examples/mnist BACKEND="lmdb" echo "Creating ${BACKEND}..." rm -rf $EXAMPLE/mnist_train_${BACKEND} rm -rf $EXAMPLE/mnist_test_${BACKEND} $BUILD/convert_mnist_data.bin $DATA/train-images-idx3-ubyte \ $DATA/train-labels-idx1-ubyte $EXAMPLE/mnist_train_${BACKEND} --backend=${BACKEND} $BUILD/convert_mnist_data.bin $DATA/t10k-images-idx3-ubyte \ $DATA/t10k-labels-idx1-ubyte $EXAMPLE/mnist_test_${BACKEND} --backend=${BACKEND} echo "Done."
对于我们自己的数据,一般来说是一堆图片,Caffe 也提供了 convert_imageset 这个工具,这是安装 Caffe 后提供的命令行工具之一。该命令的使用方式为:
convert_imageset [FLAGS] ROOTFOLDER/ LISTFILE DB_NAME
其中 LISTFILE 每行记录一张图片的(相对)路径及类别,如:
pics/0_1.png 0
需要注意的是,这里的 "类别" 必须是一个整数 。ROOTFOLDER 和 LISTFILE 中图片的路径构成图片的真实路径,DB_NAME 是要创建的 lmdb 文件的名称。
如果图片集中存在图片大小不一致的情况,可以用 -resize_height 和 -resize_width 来将所有图片规整成统一的尺寸。
convert_imageset -resize_height 64 -resize_width 64 ./ pic_label.list mydb
训练与测试
在以上步骤都完成后即可开始进行训练与测试,使用命令行工具中的 caffe 命令即可:
caffe train --solver=lenet_train_test.prototxt
在训练过程中会观察到类似下面这样的输出:
I1203 solver.cpp:204] Iteration 100, lr = 0.00992565 I1203 solver.cpp:66] Iteration 100, loss = 0.26044 ... I1203 solver.cpp:84] Testing net I1203 solver.cpp:111] Test score #0: 0.9785 I1203 solver.cpp:111] Test score #1: 0.0606671
这些输出表明了学习率、loss 和测试数据在当前网络上的表现,这些输出都是需要注意的。举个栗子
如果在开始时学习率设置过大,导致训练过程不收敛了,是能够通过观察 loss 和 测试数据在当前网络上的表现判断出来的。
在 MNIST 的例子中,最后训练生成的模型是: examples/mnist/lenet_iter_10000.caffemodel。这个模型可以在之后的分类中使用。