Caffe源码阅读(1) 全连接层

发表于 2014-09-15   |  

今天看全连接层的实现。
主要看的是https://github.com/BVLC/caffe/blob/master/src/caffe/layers/inner_product_layer.cpp

主要是三个方法,setup,forward,backward

  • setup 初始化网络参数,包括了w和b
  • forward 前向传播的实现
  • backward 后向传播的实现

setup

主体的思路,作者的注释给的很清晰。
主要是要弄清楚一些变量对应的含义

1
2
3
M_ 表示的样本数
K_ 表示单个样本的特征长度
N_ 表示输出神经元的个数

为了打字方便,以下省略下划线,缩写为M,K,N

forward

实现的功能就是 y=wx+b

1
2
3
4
x为输入,维度 MxK
y为输出,维度 Nx1
w为权重,维度 NxK
b为偏置,维度 Nx1

具体到代码实现,用的是这个函数caffe_cpu_gemm,具体的函数头为

1
2
3
4
void caffe_cpu_gemm<float>(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←αA×B+βC

1
2
3
4
5
6
7
8
9
10
11
12
13
14
const CBLAS_TRANSPOSE TransA  # A是否转置
const CBLAS_TRANSPOSE TransB # B是否转置 # 这部分都比较直观不用解释了
const int M
const int N
const int K
const float alpha
const float* A
const float* B
const float beta,
float* C # 其中A维度是MxK,B维度是KxN,C维度为MxN

从实际代码来算,全连接层的forward包括了两步:

1
2
3
4
5
6
7
8
# 这一步表示 y←wx,或者说是y←xw'
caffe_cpu_gemm<Dtype>(CblasNoTrans, CblasTrans, M_, N_, K_, (Dtype)1.,
bottom_data, weight, (Dtype)0., top_data);
# 这一步表示 y←y+b
caffe_cpu_gemm<Dtype>(CblasNoTrans, CblasNoTrans, M_, N_, 1, (Dtype)1.,
bias_multiplier_.cpu_data(),
this->blobs_[1]->cpu_data(), (Dtype)1., top_data);
# 所以两步连起来就等价于y=wx+b

backward

分成三步:

  • 更新w
  • 更新b
  • 计算delta

用公式来说是下面三条:

一步步来,先来第一步,更新w,对应代码是:

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

对照公式,有

1
2
3
需要更新的w的梯度的维度是NxK
公式中的a^(l)_j对应的是bottom_data,维度是KxM
公式中的\delta_(l+1)_i对应的是top_diff,维度是NxM

然后是第二步,更新b,对应代码是:

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

这里用到了caffe_cpu_gemv,简单来说跟上面的caffe_cpu_gemm类似,不过前者是计算矩阵和向量之间的乘法的(从英文命名可以分辨,v for vector, m for matrix)。函数头:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
void caffe_cpu_gemv<float>(const CBLAS_TRANSPOSE TransA, const int M,
const int N, const float alpha, const float* A, const float* x,
const float beta, float* y) # 实现的功能类似 Y←αAX + βY
# 其中A的维度为 MxN
# X是一个向量,维度为 Nx1
# Y是结果 ,也是一个向量,维度为Mx1 const CBLAS_TRANSPOSE TransA # 是否对A进行转置 # 下面的参数很直观,不描述了
const int M
const int N
const float alpha
const float* A
const float* x
const float beta
float* y

绕回到具体的代码实现。。如何更新b?根据公式b的梯度直接就是delta

1
2
3
4
# 所以对应的代码其实就是将top_diff转置后就可以了(忽略乘上bias_multiplier这步)
caffe_cpu_gemv<Dtype>(CblasTrans, M_, N_, (Dtype)1., top_diff,
bias_multiplier_.cpu_data(), (Dtype)0.,
this->blobs_[1]->mutable_cpu_diff());

第三步是计算delta,对应公式

这里面可以忽略掉最后一项f’,因为在caffe实现中,这是由Relu layer来实现的,这里只需要实现括号里面的累加就好了,这个累加其实可以等价于矩阵乘法

1
2
3
4
5
6
7
caffe_cpu_gemm<Dtype>(CblasNoTrans, CblasNoTrans, M_, K_, N_, (Dtype)1.,
top_diff, this->blobs_[0]->cpu_data(), (Dtype)0.,
(*bottom)[0]->mutable_cpu_diff()); # top_diff为\delta^(l+1)_j 维度 MxN
# this->blobs_[0]->cpu_data()为W^(l)_ji 维度 NxK
# (*bottom)[0]->mutable_cpu_diff()是要计算的结果,也就是\delta^(l)_i 维度是MxK

附录

又及,这里具体计算矩阵相乘用的是blas的功能,描述页面我参考的是:https://developer.apple.com/library/mac/documentation/Accelerate/Reference/BLAS_Ref/Reference/reference.html#//apple_ref/c/func/cblas_sgemm

Caffe源码阅读(1) 全连接层的更多相关文章

  1. caffe源码阅读

    参考网址:https://www.cnblogs.com/louyihang-loves-baiyan/p/5149628.html 1.caffe代码层次熟悉blob,layer,net,solve ...

  2. caffe源码阅读(1)_整体框架和简介(摘录)

    原文链接:https://www.zhihu.com/question/27982282 1.Caffe代码层次.回答里面有人说熟悉Blob,Layer,Net,Solver这样的几大类,我比较赞同. ...

  3. caffe源码阅读(1)-数据流Blob

    Blob是Caffe中层之间数据流通的单位,各个layer之间的数据通过Blob传递.在看Blob源码之前,先看一下CPU和GPU内存之间的数据同步类SyncedMemory:使用GPU运算时,数据要 ...

  4. caffe源码阅读(3)-Datalayer

    DataLayer是把数据从文件导入到网络的层,从网络定义prototxt文件可以看一下数据层定义 layer { name: "data" type: "Data&qu ...

  5. caffe源码阅读(2)-Layer

    神经网络是由层组成的,深度神经网络就是层数多了.layer对应神经网络的层.数据以Blob的形式,在不同的layer之间流动.caffe定义的神经网络已protobuf形式定义.例如: layer { ...

  6. caffe源码阅读(一)convert_imageset.cpp注释

    PS:本系列为本人初步学习caffe所记,由于理解尚浅,其中多有不足之处和错误之处,有待改正. 一.实现方法 首先,将文件名与它对应的标签用 std::pair 存储起来,其中first存储文件名,s ...

  7. caffe 源码阅读

    bvlc:Berkeley Vision and Learning Center. 1. 目录结构 models(四个文件夹均有四个文件构成,deploy.prototxt, readme.md, s ...

  8. caffe源码 全连接层

    图示全连接层 如上图所示,该全链接层输入n * 4,输出为n * 2,n为batch 该层有两个参数W和B,W为系数,B为偏置项 该层的函数为F(x) = W*x + B,则W为4 * 2的矩阵,B ...

  9. 源码阅读经验谈-slim,darknet,labelimg,caffe(1)

    本文首先谈自己的源码阅读体验,然后给几个案例解读,选的例子都是比较简单.重在说明我琢磨的点线面源码阅读方法.我不是专业架构师,是从一个深度学习算法工程师的角度来谈的,不专业的地方请大家轻拍. 经常看别 ...

随机推荐

  1. 微软爱开源:向Linux社区开放60000多项专利

    10月10日,微软在博客中宣布正式加入开放创新网络(Open Invention Network, 简称“OIN”),向所有开源专利联盟的成员开放其专利组合. 微软的加入意味着,旗下60000多项专利 ...

  2. BZOJ3453 XLkxc(拉格朗日插值)

    显然f(i)是一个k+2项式,g(x)是f(i)的前缀和,则显然其是k+3项式,插值即可.最后要求的东西大胆猜想是个k+4项式继续插值就做完了.注意2p>maxint…… #include< ...

  3. UVA11987 Almost Union-Find

    题目描述 PDF 输入输出格式 输入格式: 输出格式: 输入输出样例 输入样例#1: 5 7 1 1 2 2 3 4 1 3 5 3 4 2 4 1 3 4 3 3 输出样例#1: 3 12 3 7 ...

  4. [luogu3834]静态区间第k小【主席树】

    传送门:https://www.luogu.org/problemnew/show/P3834 题目描述 如题,给定N个整数构成的序列,将对于指定的闭区间查询其区间内的第K小值. 分析 很多人都说是用 ...

  5. 配置远程jupyter notebook

    在远程服务器上启动jupyter notebook,然后在本地进行访问.本文使用最简单的一种方法,无需设置密码,所以这种方法也是最不安全的方法,慎用. 1. 在远程服务器上生成jupyter note ...

  6. UVALive - 6442 (思维题)

    题目链接:https://vjudge.net/contest/241341#problem/I 题目大意:给你一个有N个点等距的环,编号[0,N-1],然后有些点上有一个或多个硬币,通过移动这些硬币 ...

  7. [luogu2822][组合数问题]

    题目链接 题解: 对于上面和下面的式子进行分解质因数,然后看看上面的质因数个数减去下面的质因数个数能不能达到k的质因数的要求即可. 分解质因数的时候用对于阶乘分解质因数的常用方法:比如要求1999!中 ...

  8. c基础:函数参数是 struct(结构),传的是引用,还是值?

    比如函数形式:void func(struct a data1, struct b data2); 答案: 只要不是指针或者数组都是传值,其实指针也是传递的地址值. 追问但是如果这个结构体里面有数组这 ...

  9. 如何删除launchpad里的空文件夹

    方法1: 重启后将任意一个应用拖入再移出 方法2: 在终端(应用工具>实用工具>终端)执行:defaults write com.apple.dock ResetLaunchPad -bo ...

  10. linu查看当前目录下文件大小

    查看当前目录下文件大小 [root@izm5e33l0ge76tvdj3qtnfz var]# du -sh * .0K adm 190M cache .0K crash 24K db .0K emp ...