Caffa 源码学习系列一----全连接层
来源:互联网 发布:舆情软件 编辑:程序博客网 时间:2024/05/20 09:21
前段时间学习了caffe的python接口的使用,为了提高速度,现在想直接使用C++接口,下面的系列是我的学习笔记!
原作者:在路上 原文链接:http://zhangliliang.com/2014/09/15/about-caffe-code-full-connected-layer/
今天看全连接层的实现。
主要看的是https://github.com/BVLC/caffe/blob/master/src/caffe/layers/inner_product_layer.cpp
主要是三个方法,setup,forward,backward
- setup 初始化网络参数,包括了w和b
- forward 前向传播的实现
- backward 后向传播的实现
setup
主体的思路,作者的注释给的很清晰。
主要是要弄清楚一些变量对应的含义
123
M_ 表示的样本数K_ 表示单个样本的特征长度N_ 表示输出神经元的个数
为了打字方便,以下省略下划线,缩写为M,K,N
forward
实现的功能就是 y=wx+b
1234
x为输入,维度 MxKy为输出,维度 Nx1w为权重,维度 NxKb为偏置,维度 Nx1
具体到代码实现,用的是这个函数caffe_cpu_gemm
,具体的函数头为
1234
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(此处个人感觉有问题,最后一个C应该是B???)
1234567891011121314
const CBLAS_TRANSPOSE TransA # A是否转置const CBLAS_TRANSPOSE TransB # B是否转置# 这部分都比较直观不用解释了const int M const int Nconst int Kconst float alphaconst float* Aconst float* Bconst float beta,float* C# 其中A维度是MxK,B维度是KxN,C维度为MxN
从实际代码来算,全连接层的forward包括了两步:
12345678
# 这一步表示 y←wx,或者说是y←xw‘caffe_cpu_gemm<Dtype>(CblasNoTrans, CblasTrans, M_, N_, K_, (Dtype)1., bottom_data, weight, (Dtype)0., top_data);# 这一步表示 y←y+bcaffe_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,对应代码是:
12
caffe_cpu_gemm<Dtype>(CblasTrans, CblasNoTrans, N_, K_, M_, (Dtype)1., top_diff, bottom_data, (Dtype)0., this->blobs_[0]->mutable_cpu_diff());
对照公式,有
123
需要更新的w的梯度的维度是NxK公式中的a^(l)_j对应的是bottom_data,维度是KxM公式中的\delta_(l+1)_i对应的是top_diff,维度是NxM
然后是第二步,更新b,对应代码是:
123
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)。函数头:
12345678910111213141516171819
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是结果 ,也是一个向量,维度为Mx1const CBLAS_TRANSPOSE TransA # 是否对A进行转置# 下面的参数很直观,不描述了const int Mconst int Nconst float alphaconst float* Aconst float* xconst float betafloat* y
绕回到具体的代码实现。。如何更新b?根据公式b的梯度直接就是delta
1234
# 所以对应的代码其实就是将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来实现的,这里只需要实现括号里面的累加就好了,这个累加其实可以等价于矩阵乘法
1234567
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
- Caffa 源码学习系列一----全连接层
- caffe源码 全连接层
- mxnet系列 全连接层代码阅读
- Caffe源码阅读(1) 全连接层
- Caffe源码阅读(1) 全连接层
- 全连接层解析(一)
- 深度学习: Full Connection (全连接层)
- caffe全连接层(INNER_PRODUCT)源码注释与分析
- 全连接层解析(二)——源码解析
- Caffe框架源码剖析(7)—全连接层InnerProductLayer
- 全连接层解析——源码解析
- Caffe框架源码剖析(7)—全连接层InnerProductLayer
- Caffe源码学习系列二----卷积层
- 神经网络-全连接层
- 全连接层
- 全连接层(FullconnectLayer)
- 全连接层FC
- 全连接层
- CoreOS安装到VMware
- DOM/jQuery的submit() 方法失效的解决方案
- jQuery AJAX 详解
- 《剑指offer》——二叉树中和为某一值的路径
- Unix终端的概念
- Caffa 源码学习系列一----全连接层
- ajax请求参数乱码问题
- 支付宝快速集成
- Computer 101
- Android的DrawText详解
- HTTP协议头部与Keep-Alive模式详解
- 通过自绘背景图改变按钮颜色
- [MFC] 控件大小跟随对话框大小比例变化 [转]
- iOS UITextField