基于深度学习caffe的图像分类-安装及使用

深度学习在计算机视觉领域四大基本任务中的应用,包括分类、定位检测、语义分割、和实例分割。首先从图像分类开始学习,利用Caffe搭建深度学习网络,在实际数据集上进行测试。

CNN模型

补充:为什引入非线性激励函数?为什么Relu比sigmoid和tanh效果要好?

第一个问题:为什么引入非线性激励函数?
如果不用激励函数(其实相当于激励函数是f(x) = x),在这种情况下你每一层输出都是上层输入的线性函数,很容易验证,无论你神经网络有多少层,输出都是输入的线性组合,与没有隐藏层效果相当,这种情况就是最原始的感知机(Perceptron)了。
正因为上面的原因,我们决定引入非线性函数作为激励函数,这样深层神经网络就有意义了(不再是输入的线性组合,可以逼近任意函数)。最早的想法是sigmoid函数或者tanh函数,输出有界,很容易充当下一层输入(以及一些人的生物解释balabala)。
第二个问题:为什么引入Relu呢?
第一,采用sigmoid等函数,算激活函数时(指数运算),计算量大,反向传播求误差梯度时,求导涉及除法,计算量相对大,而采用Relu激活函数,整个过程的计算量节省很多。
第二,对于深层网络,sigmoid函数反向传播时,很容易就会出现梯度消失的情况(在sigmoid接近饱和区时,变换太缓慢,导数趋于0,这种情况会造成信息丢失,参见 @Haofeng Li 答案的第三点),从而无法完成深层网络的训练。
第三,Relu会使一部分神经元的输出为0,这样就造成了网络的稀疏性,并且减少了参数的相互依存关系,缓解了过拟合问题的发生(以及一些人的生物解释balabala)。

当然现在也有一些对relu的改进,比如prelu,random relu等,在不同的数据集上会有一些训练速度上或者准确率上的改进,具体的大家可以找相关的paper看。
多加一句,现在主流的做法,会在做完relu之后,加一步batch normalization,尽可能保证每一层网络的输入具有相同的分布[1]。而最新的paper[2],他们在加入bypass connection之后,发现改变batch normalization的位置会有更好的效果。大家有兴趣可以看下。

常用网络结构

lenet

alexnet

vgg

resnet

caffe安装及使用

安装平台是mac os x10.13.3 利用anaconda带的python环境,此外,mac安装需要Homebrew,安装Homebrew,会自动创建目录 /usr/local/Cellar,我们可以把所有相关的安装依赖包都保存到此路径下,便于管理和使用。

1
2
3
4
5
6
# Homebrew 安装
ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)”
# 卸载
ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/uninstall)”
# 测试是否成功
brew --version

下载Anaconda2-4.2.0-MacOSX-x86_64.pkg并安装在/usr/local/Cellar/anaconda目录下,安装依赖包

1
2
3
4
brew install -vd snappy leveled flags glow szip lmdb
# need the home-brew science source for openCV and hdf5
brew tap home-brew/science
brew install hdf5 opencv

如果使用Anaconda python,openCV需要做如下的修改

1
2
3
brew edit opencv
-DPYTHON2_LIBRARY=/usr/local/Cellar/anaconda/lib/libpython2.7.dylib
-DPYTHON2_INCLUDE_DIR=/usr/local/Cellar/anaconda/include/python2.7

继续安装依赖

1
2
3
brew install --build-from-source --with-python -vd protobuf
brew install --build-from-source -vd boost boost-python
brew install openblas

修改环境变量

1
2
3
4
# added by Anaconda2 4.2.0 installer
export PATH="/usr/local/Cellar/anaconda/bin:$PATH"
export DYLD_FALLBACK_LIBRARY_PATH=/usr/local/cuda/lib:/usr/local/Cellar/anaconda/lib:/usr/local/lib:/usr/lib:/usr/local/Cellar/hdf5/:/usr/local/Cellar/:
export CPLUS_INCLUDE_PATH=/usr/local/Cellar/anaconda/include/python2.7/

下载caffe并生成配置文件

1
2
3
4
git clone https://github.com/BVLC/caffe.git  
# 复制到/usr/local/Cellar路径下面
cd /usr/local/Cellar/caffe
cp Makefile.config.example Makefile.config

修改配置文件中的内容,下面的配置文件是基于我自己电脑的参数进行的修改

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
## Refer to http://caffe.berkeleyvision.org/installation.html
# Contributions simplifying and improving our build system are welcome!

# cuDNN acceleration switch (uncomment to build with cuDNN).
# USE_CUDNN := 1

# CPU-only switch (uncomment to build without GPU support).
CPU_ONLY := 1

# uncomment to disable IO dependencies and corresponding data layers
# USE_OPENCV := 0
# USE_LEVELDB := 0
# USE_LMDB := 0

# uncomment to allow MDB_NOLOCK when reading LMDB files (only if necessary)
# You should not set this flag if you will be reading LMDBs with any
# possibility of simultaneous read and write
# ALLOW_LMDB_NOLOCK := 1

# Uncomment if you're using OpenCV 3
OPENCV_VERSION := 3

# To customize your choice of compiler, uncomment and set the following.
# N.B. the default for Linux is g++ and the default for OSX is clang++
# CUSTOM_CXX := g++

# CUDA directory contains bin/ and lib/ directories that we need.
CUDA_DIR := /usr/local/cuda
# On Ubuntu 14.04, if cuda tools are installed via
# "sudo apt-get install nvidia-cuda-toolkit" then use this instead:
# CUDA_DIR := /usr

# CUDA architecture setting: going with all of them.
# For CUDA < 6.0, comment the *_50 through *_61 lines for compatibility.
# For CUDA < 8.0, comment the *_60 and *_61 lines for compatibility.
# For CUDA >= 9.0, comment the *_20 and *_21 lines for compatibility.
CUDA_ARCH := -gencode arch=compute_20,code=sm_20 \
-gencode arch=compute_20,code=sm_21 \
-gencode arch=compute_30,code=sm_30 \
-gencode arch=compute_35,code=sm_35 \
-gencode arch=compute_50,code=sm_50 \
-gencode arch=compute_52,code=sm_52 \
-gencode arch=compute_60,code=sm_60 \
-gencode arch=compute_61,code=sm_61 \
-gencode arch=compute_61,code=compute_61

# BLAS choice:
# atlas for ATLAS (default)
# mkl for MKL
# open for OpenBlas
BLAS := OPenBlas
# Custom (MKL/ATLAS/OpenBLAS) include and lib directories.
# Leave commented to accept the defaults for your choice of BLAS
# (which should work)!
BLAS_INCLUDE := /usr/local/opt/openblas/include
BLAS_LIB := /usr/local/opt/openblas/lib

# Homebrew puts openblas in a directory that is not on the standard search path
# BLAS_INCLUDE := $(shell brew --prefix openblas)/include
# BLAS_LIB := $(shell brew --prefix openblas)/lib

# This is required only if you will compile the matlab interface.
# MATLAB directory should contain the mex binary in /bin.
# MATLAB_DIR := /usr/local
# MATLAB_DIR := /Applications/MATLAB_R2012b.app

# NOTE: this is required only if you will compile the python interface.
# We need to be able to find Python.h and numpy/arrayobject.h.
# PYTHON_INCLUDE := /usr/include/python2.7 \
# /usr/lib/python2.7/dist-packages/numpy/core/include
# Anaconda Python distribution is quite popular. Include path:
# Verify anaconda location, sometimes it's in root.
ANACONDA_HOME := /usr/local/Cellar/anaconda
PYTHON_INCLUDE := $(ANACONDA_HOME)/include \
$(ANACONDA_HOME)/include/python2.7 \
$(ANACONDA_HOME)/lib/python2.7/site-packages/numpy/core/include

# Uncomment to use Python 3 (default is Python 2)
# PYTHON_LIBRARIES := boost_python3 python3.5m
# PYTHON_INCLUDE := /usr/include/python3.5m \
# /usr/lib/python3.5/dist-packages/numpy/core/include

# We need to be able to find libpythonX.X.so or .dylib.
# PYTHON_LIB := /usr/lib
PYTHON_LIB := $(ANACONDA_HOME)/lib

# Homebrew installs numpy in a non standard path (keg only)
# PYTHON_INCLUDE += $(dir $(shell python -c 'import numpy.core; print(numpy.core.__file__)'))/include
# PYTHON_LIB += $(shell brew --prefix numpy)/lib

# Uncomment to support layers written in Python (will link against Python libs)
# WITH_PYTHON_LAYER := 1

# Whatever else you find you need goes here.
INCLUDE_DIRS := $(PYTHON_INCLUDE) /usr/local/include
LIBRARY_DIRS := $(PYTHON_LIB) /usr/local/lib /usr/lib

# If Homebrew is installed at a non standard location (for example your home directory) and you use it for general dependencies
# INCLUDE_DIRS += $(shell brew --prefix)/include
# LIBRARY_DIRS += $(shell brew --prefix)/lib

# NCCL acceleration switch (uncomment to build with NCCL)
# https://github.com/NVIDIA/nccl (last tested version: v1.2.3-1+cuda8.0)
# USE_NCCL := 1

# Uncomment to use `pkg-config` to specify OpenCV library paths.
# (Usually not necessary -- OpenCV libraries are normally installed in one of the above $LIBRARY_DIRS.)
# USE_PKG_CONFIG := 1

# N.B. both build and distribute dirs are cleared on `make clean`
BUILD_DIR := build
DISTRIBUTE_DIR := distribute

# Uncomment for debugging. Does not work on OSX due to https://github.com/BVLC/caffe/issues/171
# DEBUG := 1

# The ID of the GPU that 'make runtest' will use to run unit tests.
TEST_GPUID := 0

# enable pretty build (comment to see full commands)
Q ?= @

进行编译

1
2
3
4
5
6
make all
make test
install_name_tool -add_rpath '/usr/local/Cellar/anaconda/lib' /usr/local/Cellar/caffe/.build_release/tools/caffe
install_name_tool -add_rpath '/usr/local/Cellar/anaconda/lib’ /usr/local/Cellar/caffe/.build_release/test/test_all.testbin
make runtest
Make pycaffe

在jupyter notebook中使用

1
2
3
import caffe
caffe_root = '/usr/local/Cellar/caffe'
sys.path.insert(0, caffe_root + 'python')

import caffe如果出现问题,一般是protobuf安装有问题,原因不明确。
解决办法:将anaconda里面默认的先 pip uninstall protobuf 然后打开Anaconda Navigator控制器 在root里面 安装protobuf(利用默认的channel,清华镜像的channel只有3.2版本),新的版本为3.4.1,随后import成功。

使用自带模型

训练cifar训练集,进入到caffe根目录获取训练数据

1
2
./data/cifar10/get_cifar10.sh
./examples/cifar10/create_cifar10.sh

开始训练

1
./examples/cifar10/train_quick.sh

在运行之前需要在./examples/cifar10/目录中修改cifar10_quick_solver_lr1.prototxt和cifar10_quick_solver.prototxt这两个文件中solver_mode为CPU(根据实际配置),训练后会得到:

1
2
cifar10_quick_iter_5000.caffemodel.h5
cifar10_quick_iter_5000.solverstate.h5

此时,我们就训练得到了模型,用于后面的分类。下面我们使用模型来分类数据(注意examples前面两个空格):

1
python python/classify.py --model_def examples/cifar10/cifar10_quick.prototxt --pretrained_model examples/cifar10/cifar10_quick_iter_5000.caffemodel.h5 --center_only  examples/images/cat.jpg foo

默认的classify脚本不会直接输出结果,而是会把结果输入到foo文件里,不太直观,这里我在网上找了一个修改版,添加了一些参数,可以输出概率最高的分类。替换python/classify.py,下载地址:http://download.csdn.net/detail/caisenchuan/9513196 ,但是原始程序有一点点问题以及dataframe升级后排序函数有些变化,因此里面的代码做如下改变:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
if args.print_results:
scores = predictions.flatten()
with open(args.labels_file) as f:
labels_df = pd.DataFrame([
{
'name': l.strip().split(' ')[0],
'synset_id': ' '.join(l.strip().split(' ')[1:]).split(',')[0]
}
for l in f.readlines()
])
labels = labels_df.sort_values('synset_id')['name']
indices = (-scores).argsort()[:5]
ps = labels[indices]

meta = [
(p, '%.5f' % scores[i])
for i, p in zip(indices, ps)
]
print meta

这个脚本添加了两个参数,可以指定labels_file,然后可以直接把分类结果输出来:

1
python python/classify.py --print_results --model_def examples/cifar10/cifar10_quick.prototxt --pretrained_model examples/cifar10/cifar10_quick_iter_5000.caffemodel.h5 --labels_file data/cifar10/cifar10_words.txt --center_only  examples/images/cat.jpg foo

可以根据自己的需求进行修改分类函数。