卷积层是用一个固定大小的矩形区去席卷原始数据,将原始数据分成一个个和卷积核大小相同的小块,然后将这些小块和卷积核相乘输出一个卷积值(注意这里是一个单独的值,不再是矩阵了)。

卷积的本质就是用卷积核的参数来提取原始数据的特征,通过矩阵点乘的运算,提取出和卷积核特征一致的值,如果卷积层有多个卷积核,则神经网络会自动学习卷积核的参数值,使得每个卷积核代表一个特征。

这里我们拿最常用的conv1d举例说明卷积过程的计算。

conv1d是一维卷积,它和conv2d的区别在于只对宽度进行卷积,对高度不卷积。

函数定义:

torch.nn.functional.conv1d(input, weight, bias=None, stride=1, padding=0, dilation=1, groups=1)

参数说明:

 input:输入的Tensor数据,格式为(batch,channels,W),三维数组,第一维度是样本数量,第二维度是通道数或者记录数。三维度是宽度。

 weight:卷积核权重,也就是卷积核本身。是一个三维数组,(out_channels, in_channels/groups, kW)。out_channels是卷积核输出层的神经元个数,也就是这层有多少个卷积核;in_channels是输入通道数;kW是卷积核的宽度。

 bias:位移参数,可选项,一般也不用管。

 stride:滑动窗口,默认为1,指每次卷积对原数据滑动1个单元格。

 padding:是否对输入数据填充0。Padding可以将输入数据的区域改造成是卷积核大小的整数倍,这样对不满足卷积核大小的部分数据就不会忽略了。通过padding参数指定填充区域的高度和宽度,默认0(就是填充区域为0,不填充的意思)

 dilation:卷积核之间的空格,默认1。

 groups:将输入数据分组,通常不用管这个参数,没有太大意义。

测试代码

import torch

from torch.autograd import Variable

import torch.nn as nn

import torch.nn.functional as F

print("conv1d sample")

a=range(16)

x = Variable(torch.Tensor(a))

x=x.view(1,1,16)

print("x variable:", x)

b=torch.ones(3)

b[0]=0.1

b1=0.2

b2=0.3

weights = Variable(b)#torch.randn(1,1,2,2)) #out_channel*in_channel*H*W

weights=weights.view(1,1,3)

print ("weights:",weights)

y=F.conv1d(x, weights, padding=0)

print ("y:",y)

最终结果:

enter image description here

我们看看它是怎么计算的:

(1) 原始数据大小是0-15的一共16个数字,卷积核宽度是3,向量是[0.1,0.2,0.3]。 我们看第一个卷积是对x[0:3]共3个值[0,1,2]进行卷积,公式如下:

0*0.1+1*0.2+2*0.3=0.8

(2) 对第二个目标卷积,是x[1:4]共3个值[1,2,3]进行卷积,公式如下:

1*0.1+2*0.2+3*0.3=1.4

看到和计算结果完全一致!

enter image description here

该图就是conv1d的示意图,和conv2d的区别就是只对宽度卷积,不对高度卷积。最后的结果的宽度是原始数据的宽度减去卷积核的宽度再加上1,这里就是14。

所以最终卷积之后的结果一共是14个数值,显示如下:

enter image description here

我们再看看输入数据有多个通道的情况:

核心代码:

print("conv1d sample")

a=range(16)

x = Variable(torch.Tensor(a))

x=x.view(1,2,8)

print("x variable:", x)

b=torch.ones(6)

b[0]=0.1

b1=0.2

b2=0.3

weights = Variable(b)

weights=weights.view(1,2,3)

print ("weights:",weights)

y=F.conv1d(x, weights, padding=0)

print ("y:",y)

我们看看返回结果第一个元素27.8是怎么计算出来的,这时候卷积核有2个通道:

[0.1,0.2,0.3]和[1,1,1]

第1个卷积对象也有2个通道:

[0,1,2]和[8,9,10]

结果是2个卷积核分别对应2个输入通道进行卷积然后求和。

卷积核对第1个卷积对象的卷积值:(0.1*0+0.2*1+0.3*2)+(1*8+1*9+1*10)=27.8

第2个卷积对象也有2个通道:

[1,2,3]和[9,10,11]

卷积核对第2个卷积对象的卷积值:(0.1*1+0.2*2+0.3*3)+(1*9+1*10+1*11)=31.4

和pytorch计算结果相同。