本文更多资料来源于罗韵北京深度学习资料和Ian Goodfellow的书籍《Deep Learning》
链接: http://pan.baidu.com/s/1jIRJ6mU
提取密码:xehi
caffe:全称Convolutional Architecture for Fast Feature Embedding,是一个计算CNN 相关算法的框架,用C++和Python实现的。
Caffe的优点与局限性
优点:
• 1. 第一个主流的工业级深度学习工具。
• 2. 专精于图像处理
• 局限性:
• 1. 它有很多扩展,但是由于一些遗留的架构问题,不够灵活且对递归网络和语言建模的支持很差。
• 2. 基于层的网络结构,其扩展性不好,对于新增加的层,需要
自己实现(forward, backward and gradient update)
Caffe目录结构
• data/ 用于存放下载的训练数据
• docs/ 帮助文档
• examples/ 代码样例
• matlab/ MATLAB接文件
• python/ PYTHON接文件
• models/ 一些配置好的模型参数
• scripts/ 一些文档和数据会用到的脚本核心代码
• tools/ 保存的源码是用于生成二进制处理程序的,caffe在训练时实际是直接调用这些二进制文件
• include/ Caffe的实现代码的头文件
• src/ 实现Caffe的源文件
src/ 文件结构
gtest/ google test 一个用于测试的库,你make runtest时看见的很多绿⾊色RUN OK就是它,这个与caffe的学习无关,不过是个有用的库
caffe/ 关键代码
• test/ 用gtest测试caffe的代码
• util/ 数据转换时用的一些代码。caffe速度快,很大程度得益于内存设计上的优化(blob数据结构采用proto)和对卷积的优化(部分与im2col相
关)
• proto/ 即所谓的“Protobuf”,全称“Google Protocol Buffer”,是一种数据存储格式,帮助caffe提速
• layers/ 深度神经网络中的基本结构就是一层层互不相同的网络了,这个
文件夹下的源文件以及目前位置“src/caffe”中包含所有.cpp文件就是caffe的核心目录下的核心代码了。
Caffe核心代码
• blob[.cpp .h] 基本的数据结构Blob类
• common[.cpp .h] 定义Caffe类
• internal_thread[.cpp .h] 使用boost::thread线程库
• net[.cpp .h] 网络结构类Net
• solver[.cpp .h] 优化方法类Solver
• data_transformer[.cpp .h] 输入数据的基本操作类DataTransformer
• syncedmem[.cpp .h] 分配内存和释放内存类CaffeMallocHost,用于同步GPU,CPU数据
• layer[.cpp .h] 层类Layer
• layers/ 此文件夹下面的代码全部至少继承了类Layer, 从layer_factory中注册继承
1. Caffe三级结构(Blobs,Layers,Nets)
• Blob:用于数据的保存、交换和操作,Caffe基础存储结构
• Layer:用于模型和计算的基础
• Net:整合连接Layers
1.1 Blobs结构
• 在内存中表示4维数组,在caffe/blob.hpp中,维度包括
(width_,height_,channels_,num_)
• num_用于存储数据或权值(data)和权值增量(diff)
• Blob 在caffe源码 blob.hpp中是一个模板类。
• protected 的成员变量有:data_ , diff_ , shape_ , count_ , capacity_ ,其中data_ 和diff_ 是共享SyncedMemory 类(在syncedmem的源码中定义)的智能指针,shape_是int型的vector,count_ 和capacity_ 是整型变量。
• 其成员函数主要有:Reshape 、ReshapeLike、SharedData、 Updata 等等
• blob.hpp 包含了caffe.pb.h ,说明caffe protobuf 会向blob 传递参数。
“caffe/proto/caffe.pb.h”
• caffe.pb.h是google protocol buffer根据caffe.proto自动生成的,可以到src/caffe/proto/caffe.proto里看下caffe里面用到的各个数据的定义,比如BlobProto,Datum,NetParameter等。使用这个protocol buffer看起来确实方便,一方面可以用文本文件定义结构化的数据类型,另一方面可以生成查询效率更高、占空间更小的二进制文件。
“caffe/common.hpp”
• 主要singleton化Caffe类,并封装了boost和CUDA随机数生成的函数,提供了统一的接口。
“caffe/syncedmem.hpp”
• 定义了以下的接⼝口:
• inline void CaffeMallocHost(void** ptr, size_t size)
• inline void CaffeFreeHost(void* ptr)
• 主要是分配内存和释放内存的。而class SyncedMemory定义了内存分配管理和CPU与GPU之间同步的函数。
“caffe/util/math_functions.hpp”
• 封装了很多cblas矩阵运算
caffe.proto里面BlobProto的定义
message BlobProto {
optional BlobShape shape = 7;
repeated float data = 5 [packed = true];
repeated float diff = 6 [packed = true];
repeated double double_data = 8 [packed = true];
repeated double double_diff = 9 [packed = true];
// 4D dimensions -- deprecated. Use "shape" instead.
optional int32 num = 1 [default = 0];
optional int32 channels = 2 [default = 0];
optional int32 height = 3 [default = 0];
optional int32 width = 4 [default = 0];
}
• 对于BlobProto,可以看到定义了四个optional的int32类型的名字(name)num、channels、height和width,optional意味着Blob可以有一个或者没有这个参数,每个名字(name)后面都有一个数字,这个数字是其名字的一个标签。这个数字就是用来在生成的二进制文件中搜索查询的标签。关于这个数字,1到15会花费1byte的编码空间,16到2047花费2byte。所以⼀一般建议把那些频繁使用的名字的标签设为1到15之间的值。而后面的repeated意味着float类型的data和diff可以重复任意次,而加上[packed = true]是为了更高效的编码。
• 主要数据有两个data和diff,用num、channels、height和width这四个维度来确定数据的具体位置,做一些数据查询和Blob reshape的操作。
Blobs封装了运行时的数据信息,提供了CPU和GPU的同步。从数学上来说, Blob就是一个N维数组。它是caffe中的数据操作基本单位,就像matlab中以矩阵为基本操作对象一样。只是矩阵是二维的,而Blob是N维的。N可以是2,3,4等等。
对于图片数据来说,Blob可以表示为(N*C*H*W)这样一个4D数组。其中N表示图片的数量,C表示图片的通道数,H和W分别表示图片的高度和宽度。
当然,除了图片数据,Blob也可以用于非图片数据。比如传统的多层感知机,就是比较简单的全连接网络,用2D的Blob,调用innerProduct层来计算就可以了。
在模型中设定的参数,也是用Blob来表示和运算。它的维度会根据参数的类型不同而不同。比如:在一个卷积层中,输入一张3通道图片,有96个卷积核,每个核大小为11*11,因此这个Blob是96*3*11*11. 而在一个全连接层中,假设输入1024通道图片,输出1000个数据,则Blob为1000*1024。
1.2 Layer的五种类型
• Layer
• 所有的Pooling,Convolve,apply nonlinearities等操作都在这里实现。在Layer中input data用bottom表示,output data用top表示。每一层定义了三种操作setup(Layer初始化), forward(正向传导,根据input计算output), backward(反向传导计算,根据output计算input的梯度)。forward和backward有GPU和CPU两个版本的实现。
层是网络模型的组成要素和计算的基本单位。层的类型比较多,如Data,Convolution,Pooling,ReLU,Softmax-loss,Accuracy等,一个层的定义大至如下图:
从bottom进行数据的输入 ,计算后,通过top进行输出。图中的黄色多边形表示输入输出的数据,蓝色矩形表示层。
每一种类型的层都定义了三种关键的计算:setup,forward and backword
setup: 层的建立和初始化,以及在整个模型中的连接初始化。
forward: 从bottom得到输入数据,进行计算,并将计算结果送到top,进行输出。
backward: 从层的输出端top得到数据的梯度,计算当前层的梯度,并将计算结果送到bottom,向前传递。
正向传播的是数据,反向传播的是误差损失和梯度。
• 5种衍生Layers:
• data_layer
layer {
name: "cifar"
type: "Data"
top: "data"
top: "label"
include {
phase: TRAIN
}
transform_param {
mean_file: "examples/cifar10/mean.binaryproto"
}
data_param {
source: "examples/cifar10/cifar10_train_lmdb"
batch_size: 100
backend: LMDB
}
}
name: 表示该层的名称,可随意取
type: 层类型,如果是Data,表示数据来源于LevelDB或LMDB。根据数据的来源不同,数据层的类型也不同。一般都是采 用的LevelDB或LMDB数据,因此层类型设置为Data。
top或bottom: 每一层用bottom来输入数据,用top来输出数据。如果只有top没有bottom,则此层只有输出,没有输入。反之亦然。如果有多个 top或多个bottom,表示有多个blobs数据的输入和输出。
data 与 label: 在数据层中,至少有一个命名为data的top。如果有第二个top,一般命名为label。 这种(data,label)配对是分类模型所必需的。
include: 一般训练的时候和测试的时候,模型的层是不一样的。该层(layer)是属于训练阶段的层,还是属于测试阶段的层,需要用include来指定。如果没有include参数,则表示该层既在训练模型中,又在测试模型中。
Transformations: 数据的预处理,可以将数据变换到定义的范围内。如设置scale为0.00390625,实际上就是1/255, 即将输入数据由0-255归一化到0-1之间
mirror # 1表示开启镜像,0表示关闭,也可用ture和false来表示
crop_size: 227剪裁一个 227*227的图块,在训练阶段随机剪裁,在测试阶段从中间裁剪
data_layer主要包含与数据有关的文件。在官方文档中指出data是caffe数据的入口是网络的最低层,并且支持多种格式,在这之中又有5种LayerType
• DATA 用于LevelDB或LMDB数据格式的输入的类型,输入参数有source,batch_size, (rand_skip), (backend)。后两个是可选。
数据来自于数据库(如LevelDB和LMDB)
层类型(layer type):Data
必须设置的参数:
source: 包含数据库的目录名称,如examples/mnist/mnist_train_lmdb
batch_size: 每次处理的数据个数,如64
可选的参数:
rand_skip: 在开始的时候,路过某个数据的输入。通常对异步的SGD很有用。
backend: 选择是采用LevelDB还是LMDB, 默认是LevelDB.
• MEMORY_DATA 这种类型可以直接从内存读取数据使用时需要调用MemoryDataLayer::Reset,输入参数有batch_size, channels, height, width。
数据来自于内存层类型:MemoryData必须设置的参数:
batch_size:每一次处理的数据个数,比如2,channels:通道数
height:高度,width: 宽度
示例:
layer {
top: "data"
top: "label"
name: "memory_data"
type: "MemoryData"
memory_data_param{
batch_size: 2
height: 100
width: 100
channels: 1
}
transform_param {
scale: 0.0078125
mean_file: "mean.proto"
mirror: false
}
}
• HDF5_DATA HDF5数据格式输入的类型,输入参数有source, batch_size。
• HDF5_OUTPUT HDF5数据格式输出的类型,输入参数有file_name。
数据来自于HDF5
层类型:HDF5Data
必须设置的参数:
source: 读取的文件名称
batch_size: 每一次处理的数据个数
示例:
layer {
name: "data"
type: "HDF5Data"
top: "data"
top: "label"
hdf5_data_param {
source: "examples/hdf5_classification/data/train.txt"
batch_size: 10
}
}
• IMAGE_DATA 图像格式数据输入的类型,输入参数有source, batch_size,(rand_skip), (shuffle), (new_height), (new_width)。
数据来自于图片
层类型:ImageData
必须设置的参数:
source: 一个文本文件的名字,每一行给定一个图片文件的名称和标签(label)
batch_size: 每一次处理的数据个数,即图片数
可选参数:
rand_skip: 在开始的时候,路过某个数据的输入。通常对异步的SGD很有用。
shuffle: 随机打乱顺序,默认值为false
new_height,new_width: 如果设置,则将图片进行resize
示例:
layer {
name: "data"
type: "ImageData"
top: "data"
top: "label"
transform_param {
mirror: false
crop_size: 227
mean_file: "data/ilsvrc12/imagenet_mean.binaryproto"
}
image_data_param {
source: "examples/_temp/file_list.txt"
batch_size: 50
new_height: 256
new_width: 256
}
• 其实还有两种WINDOW_DATA, DUMMY_DATA⽤用于测试和预留的接⼝口,不重要。
数据来源于Windows
层类型:WindowData
必须设置的参数:
source: 一个文本文件的名字
batch_size: 每一次处理的数据个数,即图片数
示例:
layer {
name: "data"
type: "WindowData"
top: "data"
top: "label"
include {
phase: TRAIN
}
transform_param {
mirror: true
crop_size: 227
mean_file: "data/ilsvrc12/imagenet_mean.binaryproto"
}
window_data_param {
source: "examples/finetune_pascal_detection/window_file_2007_trainval.txt"
batch_size: 128
fg_threshold: 0.5
bg_threshold: 0.5
fg_fraction: 0.25
context_pad: 16
crop_mode: "warp"
}
}
• neuron_layer
同样是数据的操作层,neuron_layer实现里大量激活函数,主要是元素级别的操作,具有相同的bottom,top size。
• Caffe中实现了大量激活函数GPU和CPU的都有很多。它们的父类都是
NeuronLayer
• template <typename Dtype>
• class NeuronLayer : public Layer<Dtype>
1、Sigmoid
对每个输入数据,利用sigmoid函数执行操作。这种层设置比较简单,没有额外的参数。
层类型:Sigmoid
示例
layer {
name: "encode1neuron"
bottom: