Caffe Notes | Cheney Shen

Technology blog

Caffe Notes

Tags: ,

Caffe 文件结构:

 
 

http://blog.csdn.net/thystar/article/details/50052707


 
 

这里,最重要的三个文件夹就是include, tools, src。在源码解读中会对里面的文件代码一一介绍,这里给出src文件的结构:

 
 


src中的每个.cpp文件对应include文件中的头文件。

 
 

在编译完成后,会生成build文件夹。这个文件的目标文件指向一个debug或者release文件夹。这里建议用debug编译,这样在调试代码时可以跟到caffe的内部。只要在Makefile.config中改一下就好。

 
 

 
 

 
 

caffe的三级结构:Blobs,Layers,Nets

 
 

http://blog.csdn.net/thystar/article/details/50675076

 
 


 
 

深度网络是一个复杂的模型,caffe定义了一个层与层之间连接的网络模型。这个网络定义了从输入层到损失的所有模型。caffe使用blobs结构存储,交换和处理网络中正向和反向迭代时的数据和导数信息,blob是Caffe的标准数组结构,它提供了一个统一的内存接口。Layer是Caffe模型和计算的基本单元。Net是一系列的Layer和其连接的集合,Blob详细描述了信息是如何在Layer和net中存储和交换的。

 
 

solving:是求解方法,分别配置解耦模型和优化方法

 
 

1. Blob存储与交换

 
 

Blob是caffe中负责数据传递和处理的包,并且提供了在CPU与GPU之间同步处理的功能。从数学角度看,Blob是C语言风格的一个连续存数的N维数组。

 
 

Caffe利用Blobs存储和交换数据,Blobs提供了统一的内存接口存储某种类型的数据,如批处理的图像数据,模型参数和用与优化算法的导数。

 
 

Blobs可以根据CPU主机和GPU设备的需要,屏蔽CPU/GPU计算和混合操作中的开销,主机和设备的内存按需求分配(lazily),以提高内存利用率。

 
 

对于批处理的图片来说,Blobs常规的维度为:图像数据的个数N * 通道数K * 图像高度H * 图像宽度W。Blob按行存储, 这使得它最后/最右面的维度更新的最快。比如,在一个4维的blob中,位置为(n,k,h,w)的值的物理位置为((n * K + k) * H + h) * W + w.

 
 

Number/N是每批处理数据的规模,批量处理数据有利于提高设备处理和交换数据的吞吐率。在Imagenet上训练数据每批有256张图像,则N=256.

 
 

Channel/K是特征维度,对于RGB图像K=3.

 
 

虽然在Caffe在用于图像数据过程中,Blob都是4维的,但是它完全可以用于非图像数据。例如,如果你仅需要类似于传统多层感知机那样的全连接网络,使用2维的blobs(形式为(N,D)) , 然后调用InnerProdectLayer(全连接层)即可。

 
 

Blob的维度参数根据层的类型和配置而变化,对于由96个规模为11*11,输入为3通道的滤波器构成的卷积层,blob的维度为96*3×11*11,对于一个输入是1024维,输出是1000维的内几层和全连接层,blob的维度是1000*1024.

 
 

对于一些特定的数据,自己设计输入工具或数据层是有必要的,但是,一旦数据准备完毕,各种层模块会帮你完成剩下的工作。

 
 

 
 

实现细节:

 
 

对于blob中的数据,我们通常会关心它的值和梯度,因此,blob存储了两块数据内容:data和diff。前者是通过网络的普通数据,后者是网络反向计算得到的梯度。

 
 

而且,因为数据既可以存储在CPU上,又可以存储在GPU上,因而有两种不同的访问方式:静态方式,不改变数值,动态方式,改变数值。

 
 


const Dtype* cpu_data() const;

Dtype* mutable_cpu_data();

 
 

这么设计是为了用SyncedMem类来同步CPU与GPU上的数值,以隐藏同步细节,最小化传送数据。一个准则是,如果你不想改变数值,就一直用常数调用,不要在你的项目中存储指针,每层操作blob时,调用相应的函数获取它的指针,因为SyncedMem需要用这种方式确定何时需要复制数据。

 
 

实际上,使用GPU时,Caffe中的CPU 代码先从磁盘加载到blob,调用一个(GPU)设备核使GPU进行计算, 再将算好的blob数据送入下一层,忽略了底层的细节,同时又能维持高效的运算。一旦所有的层都有GPU实现,那么所有中间数据和梯度都会保存在GPU上。

 
 

下面的例子解释blub何时复制数据:

 
 


// Assuming that data are on the CPU initially, and we have a blob.假定数据在CPU上进行初始化,我们有一个blob

const Dtype* foo;

Dtype* bar;

foo = blob.gpu_data(); // data copied cpu->gpu.数据从cpu复制到gpu

foo = blob.cpu_data(); // no data copied since both have up-to-date contents.没有数据复制,两者都有最新的内容

bar = blob.mutable_gpu_data(); // no data copied.没有数据复制

// … some operations …一些操作

bar = blob.mutable_gpu_data(); // no data copied when we are still on GPU. 没有数据拷贝,依旧在gpu

foo = blob.cpu_data(); // data copied gpu->cpu, since the gpu side has modified the data 数据从gpu复制到cpu,因为gpu端已经修改了数据

foo = blob.gpu_data(); // no data copied since both have up-to-date contents没有数据拷贝,两边都是最新内容

bar = blob.mutable_cpu_data(); // still no data copied.没有数据拷贝

bar = blob.mutable_gpu_data(); // data copied cpu->gpu.数据从cpu到gpu

bar = blob.mutable_cpu_data(); // data copied gpu->cpu.数据从gpu到cpu

 
 

 
 

 
 

 
 

2. Layer : 计算和连接

 
 

这一层是非常重要的模型,是执行计算的基本单元, Layers可以进行的计算有:convolve filters(卷积滤波), pool(池化),inner products(内积), 及一些非线性运算如rectified-linear(限制线性运算),sigmoid及元素级的数据转换,normalize(归一化),数据加载,计算损失,如softmax和hinge。

 
 


 
 

这一层通过bottom(底部)连接层接收数据,通过top(顶部)连接层输出数据

 
 

每个类型的层都定义了三种重要运算:setup, forward, 和backward.

 
 

Setup: 在模型初始化时,初始化层和它的连接

Forward: 从bottom给定的输入计算输出,传到top层中

Backward: 给定输出层的梯度,计算相对于输入层的梯度,并传到bottom层,一个有参的layer需要计算相对于各个参数的梯度并存储。

 
 

特别的,Forward和Backward函数有CPU和GPU两种执行方式。如果你没有执行GPU版本,layer会转为作为备选的CPU方式,这会增加额外的数据传送成本,但是对于一些快速实验还是很方便的(尽管输入数据要由gpu到cpu,之后输出数据从gpu回到cpu)。

 
 

Layers承担了整个网络的两个核心操作: 前向传播,接收输入计算输出;反向传播,接收关于输出的梯度,计算参数的梯度并反向传播给前面的层,由此组成了每个layer的前向和反向通道。

 
 

由于caffe网络的组合性和其代码的模块化,定义layer是很容易的,只要定义好setup,forward,backward,就可以将layer接入到网络中。

 
 

 
 

 
 

  1. Net的定义和操作:

 
 

net通过组合和自动微分,定义了一个函数和其对应的梯度。通过各个层的输出计算这个函数,执行给定的任务。并通过组合各个层的反向传播过程计算学习任务中损失函数的梯度,caffe模型是一种端到端的机器学习引擎。

 
 

net是由一系列层组成的有向无环图,Caffe保留了图中所有层的中间值以确保前向和反向迭代的正确性。一个典型的net开始于数据(data)层,从磁盘中加载数据,结束于损失(loss)层,计算目标任务,如分类和重构。

 
 

net模型定义在一个纯文本模型语言中,有一系列的层和它们的连接构成。一个简单的逻辑回归定义如下:

 
 


 
 

其网络结构定义为:

 
 


 
 

模型通过Net::Init()初始化,初始化主要做两件事情:通过创建blobs和layers搭建整个网络的DAG图; 调用layers的Setup()函数。初始化时会有一系列的记录,例如整个网络的结构是否正确构建。同时,Net在初始化阶段会将其日志答应在INFO中:

 
 


 
 

注意:caffe中网络的构件与设备无关,回想之前解释过的blobs和layers是为了从模型定义中隐藏实现细节的,网络构建完成之后,通过设置Caffe::mode()和Caffe::set_mode(),网络将在CPU或GPU中运行。CPU和GPU的实现结果相同,CPU和GPU可以无缝切换并且独立于模型定义

 
 

 
 

 
 

Model格式

 
 

Caffe的模型定义在纯文本的协议上(prototxt),学习好的模型被序列化到二进制protocol buffer(binaryproto).caffemodel文件中。

 
 

模型格式用protobuf语言定义在caffe.proto文件中。这部分也会在笔记中解释。

 
 

 
 

 
 

 
 

前向传播和反向传播

 
 

http://blog.csdn.net/thystar/article/details/51244234

 
 

 
 

前向传播和反向传播是计算神经网络非常重要的部分。

 
 


 
 

考虑一个简单的逻辑回归分类问题

 
 

前向传播:通过网络的输入计算输出结果的过程,在前向传播中,caffe整合每一层的计算得到整个模型的计算函数,这个过程是个自底向上的过程,如图:

 
 


 
 

数据x通过通过内积层得到g(x),然后通过softmax得到h(g(x))和损失函数(softmax loss)fw(x).

 
 

反向传播网络:根据损失计算梯度,在反向传播过程中,Caffe通过自动求导计算逆向组合每一层的梯度得到整个模型的梯度,在反向传播中,这个过程是自顶向下的。如图:

 
 


反向过程由loss开始,根据输出计算梯度dfw/dh (fw对h求导), 模型中其余各层的梯度根据链式法则计算。每层的参数:如INNER_PRODUCT层,在反馈过程中对参数计算梯度dfw/dWip.

 
 

你只需要定义好模型,这些计算就可以立即执行,caffe已经定义好的前向传播和反向传播的执行方法。

 
 

Net::Forward()和Net::Backward()实现整个网络的前向与后向的传播,Layer::Forward和Layer::Backward()计算每一层的前后向的传播

 
 

每一层都有backward_{cpu,gpu}和backward{cpu,gpu}方法适应不同的计算模式。但是,一个层仅能使用其中的一种模式

 
 

Solver优化一个模型,首先通过forward计算输出和损失,然后通过backward生成模型的梯度,让后根据梯度和权值更新最小话损失函数,Solver,Net和Layer间的分离保证了caffe的模块化设计和开源。

 
 

 
 

 
 

loss function

 
 

http://blog.csdn.net/thystar/article/details/51248272

 
 

与大多数的机器学习算法一样,caffe的学习也是由loss function驱动的(或者叫error,cost,objective function)。损失函数的目标是,将参数(就是网络中的权值和偏置)映射到一个能够度量参数”不好程度”的标量中,因此,其目标就是让这个标量最小化(其实就是调整参数,是的损失函数的值最小)。

 
 

在caffe中,通过前向传播计算损失,每一层由一系列的输入(bottom)blobs产生一系列的输出(top),某些层的输出可以用于损失函数,一类典型的多分类任务的损失函数是SoftmaxWithLoss函数,其定义如下:

 
 


 
 

在SoftmaxWithLoss函数中,top blob是一个标量值,它是整个mni-batch损失的平均值(由预测标签和真实标签计算得到)

 
 

 
 

Loss weights

 
 

如果一个网络由多个层可以产生损失(比如,一个网络使用SoftmaxWithLoss对输入数据分类,同时也使用EuclideanLoss层重构网络), loss weights可以用来给定两个损失的重要性.

 
 

按惯例 , caffe中后缀为loss的层均用于损失函数, 其他层单纯的用于中间计算。但是,可以通过添加一个loss_weight: <float>字段将任意层定义为一个loss。对于后缀为loss的层,该层的第一个top blob的loss_weight默认为1,其余层默认为0。因此上面的SoftmaxWithLoss层的定义等价于:

 
 


 
 

但是,对于能反向传播的层,可以给定一个非0的loss_weight,例如,如果需要,正则化网络中某些层的中间值。对于有关联损失的非孤立的输出,其损失可以简单通过所有blob的求和计算的出

 
 

caffe中整个网络的损失可以通过对整个权值损失求和得到,其伪代码如下:

 
 


 
 

 
 

 
 

mnist数据集的训练

 
 

http://blog.csdn.net/thystar/article/details/50470325

 
 

怎么运行在此不讲,主要看代码。

 
 

1. 准备数据

 
 

get_mnist.sh

 
 

用于获取数据,主要是靠wget的使用。

 
 


 
 

/examples/mnist/create_mnist.sh

 
 

#生成数据,这个脚本的作用是将数据转换成lmdb格式或leveldb格式,具体如下:

 
 


 
 

convert_mnist_data.bin是由convert_minst_data.cpp编译生成的可执行文件,这个编译过程就是在caffe安装的时候完成的,这个函数接受四个参数:

 
 

$DATA/train-images-idx3-ubyte: 手写数字源文件

$DATA/train-labels-idx1-ubyte: 手写数字标签文件

$EXAMPLE/mnist_train_${BACKEND} : 转换后数据的存储位置

–backend=${BACKEND} : 宏定义,转换数据的格式lmdb或leveldb

 
 

注:convert_mnist_data.cpp及用到的其他文件在下一篇中介绍

 
 

 
 

2. 网络模型

 
 

这个实验中使用的模型是LeNet,其模型结构如下:

 
 


 
 

这个网络包含两个卷积层,两个池化层,两个全连接层,最后一层用于分类

 
 

其结构定义在:$CAFFE_ROOT/examples/mnist/lenet_train_test.prototxt中,图示如下

 
 


 
 

 
 

对于这个文档的了解,需要查看caffe.proto相关的内容

 
 

首先,给出网络名称

 
 


 
 

数据层

 
 

接着,是数据层的写入

 
 

这里,我们从之前创建的lmdb文件夹中读入数据

 
 


 
 

文档中还有另一个数据层,用于测试阶段

 
 

卷积层

 
 


 
 

池化层

 
 


 
 

全连接层

 
 


 
 

非线性层

 
 


 
 

准确率层

 
 


 
 

损失估计层

 
 


 
 

 
 

3.模型优化文件

 
 

这个文件在$CAFFE_ROOT/examples/mnist/lenet_solver.prototxt,配置一些参数信息等

 
 


 
 

 
 

接下来就是执行训练

 
 

在caffe根目录下输入:


 
 

执行过程

首先,程序读取lenet_solver.prototxt和lenet_train_test.prototxt这两个配置文件。

之后,紧跟着创建每层网络。

接下来,开始计算反馈网络。

之后,输出测试网络和创建过程。

这一步完成后,开始优化参数

当代码运行到这里时,进入迭代优化过程

待运行结束,输出结果:


其中,#0:为准确度, #1:为损失

 
 

 
 

 
 

CIFAR-10 tutorial

 
 

 
 

这是caffe官网中Examples中的第三个例子,链接地址:

http://caffe.berkeleyvision.org/gathered/examples/cifar10.html

 
 

这个例子重现了Alex Krizhevsky的cuda-convnet中的结果,具体的模型定义、参数、训练步骤等都是按照cuda-convnet中的进行设置的。

 
 

数据集描述:CIFAR-10数据集包含60000张32*32的彩色图像,包含10类,每类6000张图片,50000张训练样本图片,10000张测试样本图片。 图片类型:airplane, bird, car, cat, deer, dog, horse, monkey, ship, truck.

 
 

下面进入训练阶段

 
 

1. 获取数据:

 
 

./data/cifar10/get_cifar10.sh

./examples/cifar10/create_cifar10.sh

 
 

还是要根据本地环境改一下内容,就能跑起来。

 
 

2. 使用模型:

 
 

网络结构模型





 
 

对于学习率的影响,在Simon Haykin的《神经网络与及其学习》中说道(中文版p86):反向传播算法提供使用最速下降方法在权值空间计算得到的轨迹的一种近似,使用的参数越小,从一次迭代到下一次迭代的网络突触权值的变化量就越小,轨迹在权值空间就越光滑,然而,这种改进是以减慢学习速度为代价的。另一方面,如果学习率的值太大,学习速度加快,就可能使网络的权值变化量不稳定。

 
 

 
 

3. 训练

 
 

执行

 
 

./examples/cifar10/train_quick.sh

训练数据,输出形式类似与mnist训练的形式,这里不重复。

 
 

训练结果的正确率大约在75%

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 


One Comment

Post a Comment

Your email address will not be published. Required fields are marked *

  • Categories

  • Tags