pytorch中的2D卷积的函数是:
class torch.nn.Conv2d(in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, groups=1, bias=True)
Parameters:
- in_channels(int) – 输入信号的通道
- out_channels(int) – 卷积产生的通道
- kerner_size(int or tuple) - 卷积核的尺寸
- stride(int or tuple, optional) - 卷积步长
- padding(int or tuple, optional) - 输入的每一条边补充0的层数
- dilation(int or tuple, optional) – 卷积核元素之间的间距
- groups(int, optional) – 从输入通道到输出通道的阻塞连接数
- bias(bool, optional) - 如果bias=True,添加偏置
输出和权值的计算公式为:
1. 最基础的情况下:
# 定义一个输入,为了看起来方便,我们定义一个全为1的张量
input = autograd.Variable(torch.ones(1, 1, 5, 5))
>> tensor([[[[ 1., 1., 1., 1., 1.],
[ 1., 1., 1., 1., 1.],
[ 1., 1., 1., 1., 1.],
[ 1., 1., 1., 1., 1.],
[ 1., 1., 1., 1., 1.]]]])
>> torch.Size([1, 1, 5, 5])
# 定义一个最基础的2D卷积,卷积核为3 * 3
CNN= nn.Conv2d(in_channels=1, out_channels=1, kernel_size=3, stride=1, padding=0, bias=False)
# 为了直观,我们直接先设置卷积和,在实际使用时它是先随机初始化,然后再通过反向来得到
CNN_W = np.array([[1, 1, 1], [1, 1, 1], [1, 1, 1]], dtype='float32')
# CNN的权值也是张量形式
CNN_W = CNN_W.reshape((1, 1, 3, 3))
CNN.weight.data = torch.from_numpy(CNN_W)
# 卷积计算
print(CNN.weight.data)
print(CNN(input))
np.shape(CNN(input))
>> tensor([[[[ 1., 1., 1.],
[ 1., 1., 1.],
[ 1., 1., 1.]]]])
>> tensor([[[[ 9., 9., 9.],
[ 9., 9., 9.],
[ 9., 9., 9.]]]])
>> torch.Size([1, 1, 3, 3])
2. stride使得卷积核无法走遍整个图时:
# 修改上面的卷积的步数为3,此时,卷积核不能走遍整个图,所以,通过不使用padding时,会舍弃掉部分值
CNN= nn.Conv2d(in_channels=1, out_channels=1, kernel_size=3, stride=3, padding=0, bias=False)
print(CNN.weight.data)
print(CNN(input))
np.shape(CNN(input))
>> tensor([[[[ 1., 1., 1.],
[ 1., 1., 1.],
[ 1., 1., 1.]]]])
>> tensor([[[[ 9.]]]])
>> torch.Size([1, 1, 1, 1])
3. 使用padding时:
# 使用padding=1时,此时输入会在周围包上一层0,也就是原来5 * 5的矩阵变成7 * 7
CNN= nn.Conv2d(in_channels=1, out_channels=1, kernel_size=3, stride=3, padding=1, bias=False)
print(CNN.weight.data)
print(CNN(input))
np.shape(CNN(input))
>> tensor([[[[ 1., 1., 1.],
[ 1., 1., 1.],
[ 1., 1., 1.]]]])
>> tensor([[[[ 4., 6.],
[ 6., 9.]]]])
>> torch.Size([1, 1, 2, 2])
4. 输出通道数不设为1时:
# 使用out_channels =2时,此时其实就是初始化两个卷积核,这里我们不给它设值,直接让其随机初始化
CNN= nn.Conv2d(in_channels=1, out_channels=2, kernel_size=3, stride=3, padding=1, bias=False)
print(CNN.weight.data)
print(CNN(input))
np.shape(CNN(input))
>> tensor([[[[-0.1465, 0.3027, 0.2025],
[-0.0289, -0.0376, 0.2881],
[-0.1316, 0.1987, 0.2249]]],
[[[ 0.0905, -0.1791, 0.3059],
[ 0.1897, 0.1662, 0.2220],
[ 0.1330, -0.2048, 0.1505]]]])
>> tensor([[[[ 0.6741, 0.5137],
[ 1.1793, 0.8724]],
[[ 0.3340, 0.6567],
[ 0.4608, 0.8740]]]])
>> torch.Size([1, 2, 2, 2])
5. 输入通道数不为1时:
input = autograd.Variable(torch.ones(1, 2, 5, 5))
print(input)
np.shape(input)
>> tensor([[[[ 1., 1., 1., 1., 1.],
[ 1., 1., 1., 1., 1.],
[ 1., 1., 1., 1., 1.],
[ 1., 1., 1., 1., 1.],
[ 1., 1., 1., 1., 1.]],
[[ 1., 1., 1., 1., 1.],
[ 1., 1., 1., 1., 1.],
[ 1., 1., 1., 1., 1.],
[ 1., 1., 1., 1., 1.],
[ 1., 1., 1., 1., 1.]]]])
>> torch.Size([1, 2, 5, 5])
# 使用in_channels =2时,其实此时也是随机初始化了两个卷积核对应两个通道,最后将结果相加
CNN= nn.Conv2d(in_channels=2, out_channels=1, kernel_size=3, stride=1, padding=0, bias=False)
# 为了直观,这里我们同样使用自己设的卷积核参数
CNN_W = np.array([[[1, 1, 1], [1, 1, 1], [1, 1, 1]],[[1, 1, 1], [1, 1, 1], [1, 1, 1]]], dtype='float32')
# CNN的权值也是张量形式
CNN_W = CNN_W.reshape((1, 2, 3, 3))
CNN.weight.data = torch.from_numpy(CNN_W)
# 卷积计算过程
print(CNN.weight.data)
print(CNN(input))
np.shape(CNN(input))
>> tensor([[[[ 1., 1., 1.],
[ 1., 1., 1.],
[ 1., 1., 1.]],
[[ 1., 1., 1.],
[ 1., 1., 1.],
[ 1., 1., 1.]]]])
>> tensor([[[[ 18., 18., 18.],
[ 18., 18., 18.],
[ 18., 18., 18.]]]])
>> torch.Size([1, 1, 3, 3])
6. 输入个数不为1时:
input = autograd.Variable(torch.ones(2, 1, 5, 5))
print(input)
np.shape(input)
>> tensor([[[[ 1., 1., 1., 1., 1.],
[ 1., 1., 1., 1., 1.],
[ 1., 1., 1., 1., 1.],
[ 1., 1., 1., 1., 1.],
[ 1., 1., 1., 1., 1.]]],
[[[ 1., 1., 1., 1., 1.],
[ 1., 1., 1., 1., 1.],
[ 1., 1., 1., 1., 1.],
[ 1., 1., 1., 1., 1.],
[ 1., 1., 1., 1., 1.]]]])
>> torch.Size([2, 1, 5, 5])
# 此时卷积还是对应通道数,其实就是生成一个卷积核,去分别作用在两个对象上
CNN= nn.Conv2d(in_channels=1, out_channels=2, kernel_size=3, stride=1, padding=0, bias=False)
# 卷积计算过程
print(CNN.weight.data)
print(CNN(input))
np.shape(CNN(input))
tensor([[[[ 0.4774, 0.4774, 0.4774],
[ 0.4774, 0.4774, 0.4774],
[ 0.4774, 0.4774, 0.4774]]],
[[[ 0.4774, 0.4774, 0.4774],
[ 0.4774, 0.4774, 0.4774],
[ 0.4774, 0.4774, 0.4774]]]])
>> torch.Size([2, 1, 3, 3])
至于dilation
就是在卷积核里加0,解释上是说可以扩大感知:
可以参考:https://blog.csdn.net/cai13160674275/article/details/71155295