caffe框架分析

一、总体流程

caffe主要有四个功能模块。

a)  Blob 主要用来表示网络中的数据,包括训练数据,网络各层自身的参数(包括权值、偏置以及它们的梯度),网络之间传递的数据都是通过 Blob 来实现的,同时 Blob 数据也支持在 CPU 与 GPU 上存储,能够在两者之间做同步。

b)  Layer 是对神经网络中各种层的一个抽象,包括我们熟知的卷积层和下采样层,还有全连接层和各种激活函数层等等。同时每种 Layer 都实现了前向传播和反向传播,并通过 Blob 来传递数据。

c) Net 是对整个网络的表示,由各种 Layer 前后连接组合而成,也是我们所构建的网络模型。

d) Solver 定义了针对 Net 网络模型的求解方法,记录网络的训练过程,保存网络模型参数,中断并恢复网络的训练过程。自定义 Solver 能够实现不同的网络求解方式。

整体的框架是以layer为主,不同的layer完成不同的功能,如卷积,反卷积等。net是管理layer的,solver是做训练用的,而核心的创新就是blob数据了,以一个四元组完成了各种数据的传输,同时解决了cpu和gpu共享数据的问题。


二. 卷积操作

对图像(不同的数据窗口数据)和滤波矩阵(一组固定的权重:因为每个神经元的多个权重固定,所以又可以看做一个恒定的滤波器filter)做内积(逐个元素相乘再求和)的操作就是所谓的『卷积』操作,也是卷积神经网络的名字来源。


                                                           (上图可以看作一个滤波器filter,多个filter构成一个卷积层)


上图中有两个卷积核(filter w0和w1),每个卷积核有三个通道(channels),每个filter的值就是权重值,我们要求的就是改变里面的值使损失函数最小。


3. caffe中的数学函数

A)  caffe_cpu_gemm 函数:

void caffe_cpu_gemm(const CBLAS_TRANSPOSE TransA, const CBLAS_TRANSPOSE TransB, const int M, const int N, const int K, const float alpha, const float* A, const float* B, const float beta, float* C)

功能: C=alpha*A*B+beta*C

A,B,C 是输入矩阵(一维数组格式)

CblasRowMajor :数据是行主序的(二维数据也是用一维数组储存的)

TransA, TransB:是否要对A和B做转置操作(CblasTrans CblasNoTrans)

M: A、C 的行数

N: B、C 的列数

K: A 的列数, B 的行数

lda : A的列数(不做转置)行数(做转置)

ldb: B的列数(不做转置)行数(做转置)

这个函数主要是用了库函数的运算公式进行矩阵相乘,那接下来就是怎么将卷积运算转化为矩阵相乘的问题了,这就需要用到image2col的函数了。

B) image2col 函数:




                                         最终:Filter Matrix乘以Feature Matrix,得到输出矩阵Cout x (H x W)。




再说的详细点:




如上图

(1)在矩阵A中

M为卷积核个数,K=k*k,等于卷积核大小,即第一个矩阵每行为一个卷积核向量(是将二维的卷积核转化为一维),总共有M行,表示有M个卷积核。

(2)在矩阵B中

因此,N为输出图像大小的长宽乘积,也是卷积核在输入图像上滑动可截取的最大特征数。

K=k*k,表示利用卷积核大小的框在输入图像上滑动所截取的数据大小,与卷积核大小一样大。

(3)在矩阵C中

矩阵C为矩阵A和矩阵B相乘的结果,得到一个M*N的矩阵,其中每行表示一个输出图像即feature map,共有M个输出图像(输出图像数目等于卷积核数目)

Caffe中的卷积计算是将卷积核矩阵和输入图像矩阵变换为两个大的矩阵A与B,然后A与B进行矩阵相乘得到结果C。


C)im2col_cpu分析

1.结合代码分析以下公式的由来

int output_h = (height + 2 * pad_h -  (dilation_h * (kernel_h - 1) + 1)) / stride_h + 1;

int output_w = (width + 2 * pad_w -(dilation_w * (kernel_w - 1) + 1)) / stride_w +1;

2.先不要dilation_h 和dilation_w ,如下:

N=((image_h + 2*pad_h – kernel_h)/stride_h+ 1)*((image_w +2*pad_w – kernel_w)/stride_w + 1)

这里要结合动态stride滑动卷积图

原理: N = H*W

H:  在image高度方向上滑动的总次数。W:在image宽度方向上滑动的次数


D)Dilation分析

1.由于池化层的存在,响应张量的大小(长和宽)越来越小。

2.池化层去掉随之带来的是网络各层的感受野(receptive field)变小,这样会降低整个模型的预测精度。

3. Dilated convolution 的主要贡献就是,如何在去掉池化下采样操作的同时,而不降低网络的感受野。


结合这个图再推倒一下output_h 和output_w的公式

Dilation :表示每个元素的相隔距离,如果相邻,dilation=1

运算公式: (除去原点的长度)×dilation(扩张系数)+ 1(原点)

即: kernel_h_new = (kernel_h-1)*dilation_h +1

kernel_w_new = (kernel_w-1)*dilation_w +1


E)im2col_cpu整体分析



F)Forward_cpu的整体分析

1. forward_cpu_gemm:

这个主要是处理处理Wx 的函数,里面分为两个步骤:

a)conv_im2col_cpu:将image转为矩阵

 b) caffe_cpu_gemm: 将A中的矩阵和卷积核的矩阵相乘,得到特征图像的矩阵。

2. forward_cpu_bias:

这个主要是处理偏置数据。

G)Conv_layer的整体分析

1. Forward_cpu

2. Backward_cpu

F)BP流程

Backward_cpu函数的代码,整个更新过程大概可以分成三步

1. caffe_cpu_gemm(CblasTrans, CblasNoTrans, N_, K_, M_, (Dtype)1., top_diff, bottom_data, (Dtype)1., this->blobs_[0]->mutable_cpu_diff());


其中的bottom_data对应的是a,即输入的神经元激活值,维数为K_×N_,top_diff对应的是delta,维数是M_×N_,而caffe_cpu_gemm函数是对blas中的函数进行封装,实现了一个N_×M_的矩阵与一个M_×K_的矩阵相乘(注意此处乘之前对top_diff进行了转置)。相乘得到的结果保存于blobs_[0]->mutable_cpu_diff(),对应dW。

2. caffe_cpu_gemv(CblasTrans, M_, N_, (Dtype)1., top_diff, bias_multiplier_.cpu_data(), (Dtype)1., this->blobs_[1]->mutable_cpu_diff());


caffe_cpu_gemv函数实现了一个M_×N_的矩阵与N_×1的向量进行乘积,其实主要实现的是对delta进行了一下转置,就得到了db的值,保存于blobs_[1]->mutable_cpu_diff()中。此处的与bias_multiplier_.cpu_data()相乘是实现对M_个样本求和,bias_multiplier_.cpu_data()是全1向量,从公式上看应该是取平均的,但是从loss传过来时已经取过平均了,此处直接求和即可。

3.3 . caffe_cpu_gemm(CblasNoTrans, CblasNoTrans, M_, K_, N_, (Dtype)1., top_diff, this->blobs_[0]->cpu_data(), (Dtype)1., bottom[0]->mutable_cpu_diff());



主要Inner_product层里面并没有激活函数,因此没有乘f’,与f’的相乘写在ReLU层的Backward函数里了,因此这一句里只有W和delta_l+1相乘。blobs_[0]->cpu_data()对应W,维度是N_×K_,bottom[0]->mutable_cpu_diff()是本层的delta_l,维度是M_×K_。

caffe里的反向传播过程只是计算每层的梯度的导,把所有层都计算完之后,在solver.cpp里面统一对整个网络进行更新。


                                        先写到这里吧,学无止境,且学且记录。

                                                              END

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容