caffe中卷积转换为矩阵时im2col的详细过程
来源:互联网 发布:小程序 js 加空格 编辑:程序博客网 时间:2024/06/17 17:22
转载自;http://blog.csdn.net/jiongnima/article/details/69736844
推荐该博主的解析代码笔记详细易理解。
卷积层输出 = 权值矩阵 * 输入特征图转化得到的矩阵
权值矩阵尺度 = (卷积组输出通道数) * (卷积组输入通道数*卷积核高*卷积核宽)
输入特征图转化得到的矩阵尺度 = (卷积组输入通道数*卷积核高*卷积核宽) * (卷积层输出单通道特征图高 * 卷积层输出单通道特征图宽)
因此,卷积层输出尺度可以表示为
卷积层输出尺度 = (卷积层输出通道数) * (卷积层输出单通道特征图高 * 卷积层输出单通道特征图宽)
到此是不是可以看到,卷积层输出尺度正好是理论上的卷积输出尺度。那么,在这个卷积乘法中,权值矩阵与输入特征图转化得到的矩阵是怎么得来的呢?这就是im2col.cpp中定义的了,也是本篇博客笔者解析的重点,下面笔者将以一张卷积层输入的单通道特征图为例,解析一下是通过怎样的操作生成相应的矩阵的。
首先给出is_a_ge_zero_and_a_lt_b函数的定义及注释:
该函数定义是:若a大于0且严格小于b,则返回真,否则返回假,该函数的作用是判断矩阵上某元的输出是否为pad的0。然后给出im2col_cpu函数定义及注释:
im2col_cpu函数将卷积层输入转化为矩阵相乘的右元,核心是5个for循环,首先第一个for循环表示按照输入的通道数逐个处理卷积层输入的特征图,下面笔者将用图示表示剩余的四个for循环操作,向读者朋友们展示卷积层输入的单通道特征图是通过怎样的方式转化为一个矩阵。在这里我们假设,卷积层输入单通道特征图原大小为5*5,高和宽方向的pad为1,高和宽方向步长为2,卷积核不进行扩展。
我们先计算一下,卷积层输入单通道特征图转化得到的矩阵的尺度,矩阵的行数应该为卷积核高*卷积核宽,即为9,列数应该为卷积层输出特征图高(output_h)*卷积层输出特征图宽(output_w),也为9,那么,im2col算法起始由下图开始:
首先kernel_row为0,kernel_col也为0。按照input_row = -pad_h + kernel_row * dilation_h计算input_row的值,在这里,pad_h为1,kernel_row为0,dilation_h为1,计算出input_row为-1,此时output_row为3,满足函数中的第一个if条件,那么在输出图像上先置output_w个零,因为output_w为3,因此得到下图:
然后input_row加上步长2,由-1变成1,此时output_rows为2,计算input_col等于-1,此时执行input_col定义下面的for循环,得到3个值:依次往目标矩阵中填入0,data_im[1*5+1]和data_im[1*5+3],即填入0,7和9。得到下图:
再接着执行,此时input_row再加上2变为3,此时output_rows变为1,计算input_col等于-1,执行input_col定义下面的for循环,得到3个值,分别为0,data_im[3*5+1]和data_im[3*5+3],即填入0,17和19。得到下图:
接着,kernel_col变成1,此时kernel_row为0,kernel_col为1。计算input_row又变成-1,第一个if条件成立,那么,再在输出矩阵上输出3个0。然后,input_row变成1,input_col分别为0(-1+1),2(-1+1+2)和4(-1+1+2+2)时,输出矩阵上分别输出data_im[1*5+0],data[1*5+2],data[1*5+4],即分别填入6,8,10。然后,input_row变成3,input_col分别为0,2,4时,输出矩阵上分别输出data_im[3*5+0],data[3*5+2],data[3*5+4],即分别输出16,18,20。
然后,kernel_col变成2,此时kernel_row为0,kernel_col为2。计算input_row又变成-1,第一个if条件成立,那么,再在输出矩阵上输出3个0。然后,input_row变成1,input_col分别为1(-1+2),3(-1+2+2)和5(-1+2+2+2)时,输出矩阵上分别输出data_im[1*5+1],data[1*5+3],0,即分别填入7,9,0。然后,input_row变成3,input_col分别为1,3,5时,输出矩阵上分别输出data_im[3*5+0],data[3*5+2],0,即分别输出17,19,0。见下图:
接着,kernel_row变成1,kernel_col变成0。计算input_row又变成0,input_col分别为-1(-1+0),1(-1+0+2)和3(-1+0+2+2),输出矩阵上分别输出0,data[0*5+1],data[0*5+3],即分别填入0,2,4。然后,input_row变成2,input_col分别为-1,1和3时,输出矩阵上分别输出0,data[2*5+1],data[2*5+3],即分别填入0,12,14。然后,input_row变成4,input_col分别为-1,1,3时,输出矩阵上分别输出0,data[4*5+1],data[4*5+3],即分别输出0,22,24。见下图:
然后,kernel_row为1,kernel_col变成1。计算input_row为0,input_col分别为0(-1+1),2(-1+1+2)和4(-1+1+2+2),输出矩阵上分别输出data[0*5+0],data[0*5+2],data[0*5+4],即分别填入1,3,5。然后,input_row变成2,input_col分别为0,2和4时,输出矩阵上分别输出data[2*5+0],data[2*5+2],data[2*5+4],即分别填入11,13,15。然后,input_row变成4,input_col分别为0,2,4时,输出矩阵上分别输出data[4*5+0],data[4*5+2],data[4*5+4],即分别输出21,23,25。见下图:
然后,kernel_row为1,kernel_col变成2。计算input_row为0,input_col分别为1(-1+2),3(-1+2+2)和5(-1+2+2+2),输出矩阵上分别输出data[0*5+1],data[0*5+3],0,即分别填入2,4,0。然后,input_row变成2,input_col分别为1,3和5时,输出矩阵上分别输出data[2*5+1],data[2*5+3],0,即分别填入12,14,0。然后,input_row变成4,input_col分别为1,3,5时,输出矩阵上分别输出data[4*5+1],data[4*5+3],0,即分别输出22,24,0。见下图:
接着,kernel_row变成2,kernel_col变成0。计算input_row为1,input_col分别为-1(-1+0),1(-1+0+2)和3(-1+0+2+2),输出矩阵上分别输出0,data[1*5+1],data[1*5+3],即分别填入0,7,9。然后,input_row变成3,input_col分别为-1,1和3时,输出矩阵上分别输出0,data[3*5+1],data[3*5+3],即分别填入0,17,19。然后,input_row变成5,满足第一个if条件,直接输出三个0。见下图:
然后,kernel_row为2,kernel_col变成1。计算input_row为1,input_col分别为0(-1+1),2(-1+1+2)和4(-1+1+2+2),输出矩阵上分别输出data[1*5+0],data[1*5+2],data[1*5+4],即分别填入6,8,10。然后,input_row变成3,input_col分别为0,2和4时,输出矩阵上分别输出data[3*5+0],data[3*5+2],data[3*5+4],即分别填入16,18,20。然后,input_row变成5,满足第一个if条件,直接输出三个0。见下图:
最后,kernel_row为2,kernel_col变成2。计算input_row为1,input_col分别为1(-1+2),3(-1+2+2)和5(-1+2+2+2),输出矩阵上分别输出data[1*5+1],data[1*5+3],0,即分别填入7,9,0。然后,input_row变成3,input_col分别为1,3和5时,输出矩阵上分别输出data[3*5+1],data[3*5+3],0,即分别填入17,19,0。然后,input_row变成5,满足第一个if条件,直接输出三个0。见下图:
到此卷积层单通道输入特征图就转化成了一个矩阵,请读者朋友们仔细看看,矩阵的各列是不是卷积核操作的各小窗口呢?
笔者还想提醒大家的是,注意卷积中的zero-pad操作的实现,并不是真正在原始输入特征图周围添加0,而是在特征图转化得到的矩阵上的对应位置添加0。
而im2col_cpu函数功能的相反方向的实现则有由col2im_cpu函数完成,笔者依旧把该函数的代码注释放在下面:
到此,im2col.cpp中的核心函数就已经解析完毕了,笔者在最开始阅读这个源码的时候,也没有弄得太明白,可是经过仔细画图推敲,明白了其中的含义。从这件小事可以看出,光看不练假把式,在阅读源码时,遇到功能实现中比较抽象的部分,应该再仔细思考分析的同时,多动笔杆,切勿偷懒!
- caffe中卷积转换为矩阵时im2col的详细过程
- caffe源码深入学习6:超级详细的im2col绘图解析,分析caffe卷积操作的底层实现
- Caffe中卷积的实现细节(涉及到BaseConvolutionLayer、ConvolutionLayer、im2col等)
- Caffe中卷积的实现细节(涉及到BaseConvolutionLayer、ConvolutionLayer、im2col等)
- caffe代码阅读10:Caffe中卷积的实现细节(涉及到BaseConvolutionLayer、ConvolutionLayer、im2col等)-2016.4.3
- 参看caffe中三通道彩色图像的卷积过程
- 卷积运算转换为矩阵乘法
- Caffe中卷积的实现
- caffe 中的卷积的计算过程
- caffe源码解析-im2col
- caffe im2col 详解
- caffe im2col详解
- Caffe中卷积层的实现
- caffe中卷积层的实现
- Caffe中实现卷积的计算
- caffe中卷积层的权重初始化
- caffe中RGB图像三通道卷积过程学习推导
- caffe代码阅读7:Caffe中卷积的实现
- PADS 软件基础知识整理
- JVM参数优化(基础篇)
- TypeScript 学习笔记4: Type Fundamentals
- 激活win 10正式专业版
- DAS、SAN、NAS三种存储方式的概念及应用
- caffe中卷积转换为矩阵时im2col的详细过程
- Java 线程 50个Java多线程面试题
- java集合中那些知识
- 比较前面板中输入的三个数,并输出其中最大值
- jenkins配置springboot svn maven自动构建+启动
- mysql彻底卸载
- centos7 + nginx
- js中函数的返回值return
- Oracle中查询该表中的主键被哪些表引用,该表中的外键来源于哪些表