目录标题
- 一、运算过程
- 二、再次尝试理解一下
- 三、不知所云
- 四、卷积层api和代码实现
一、运算过程
图像是 3 维数据,除了长、宽外还需要处理通道方向。在 3 维数据的卷积运算中,输入数据的通道数和卷积核的通道数须设为相同的值。当有多个通道时,会按通道进行输入数据和卷积核的卷积运算,并将结果相加得到输出数据。
使用 1 个形状为( C , F H , F W ) (C, FH, FW)(C,FH,FW)的卷积核,对一个形状为( C , H , W ) (C, H, W)(C,H,W)的输入数据进行卷积运算,输出 1 张形状为( O H , O W ) (OH, OW)(OH,OW)特征图,即输出的通道数为 1。
若想在通道方向获取多个卷积运算的输出,需要使用多个卷积核
使用FN个卷积核,输出特征图也变成FN个
使用 FN 个形状为( C , F H , F W ) (C, FH, FW)(C,FH,FW)的卷积核,对一个形状为( C , H , W ) (C, H, W)(C,H,W)的输入数据进行卷积运算,输出 FN 张形状为( O H , O W ) (OH, OW)(OH,OW)特征图,即输出的通道数为 FN。
如可虑偏置,则:
如果输入数据是N个呢
使用 FN 个形状为( C , F H , F W ) (C, FH, FW)(C,FH,FW)的卷积核,对N个形状为( C , H , W ) (C, H, W)(C,H,W)的输入数据进行卷积运算,输出 N个 FN 张形状为( O H , O W ) (OH, OW)(OH,OW)特征图,即输出的通道数为 FN,输出的个数是N
二、再次尝试理解一下
1. 认清卷积核的真面目:它不是一张纸,是一摞纸
假设输入画布是7x7x3(RGB三通道)。
此时,你的一个卷积核不能是3x3的,它必须也是3x3x3的立体方块。
这3x3x3的立方体里,包含了 27 个固定的数字(参数):
- 最上面一层(
3x3),是专门给红通道准备的。 - 中间一层(
3x3),是专门给绿通道准备的。 - 最下面一层(
3x3),是专门给蓝通道准备的。
这些数字是初始化时随机生成,然后通过训练学出来的。在整个滑动过程中,这 27 个数字死死钉在这个立方体里,绝不会改变。
2. 它是怎么滑动的?(像盖印章一样)
想象你拿着这个3x3x3的立体方块(像个透明玻璃盒),重重地“盖”在7x7x3的画布上。
这时候,对应关系是天然发生的,不需要卷积核自己去变:
- 卷积核的红层(
3x3),严丝合缝地盖住画布的红色局部(3x3); - 卷积核的绿层(
3x3),严丝合缝地盖住画布的绿色局部(3x3); - 卷积核的蓝层(
3x3),严丝合缝地盖住画布的蓝色局部(3x3)。
3. 怎么计算出一个结果?(融为一炉)
此时,这 3 个通道各自独立做二维的“相乘再相加”,你会得到 3 个数字:
- 红层计算得出:a aa
- 绿层计算得出:b bb
- 蓝层计算得出:c cc
注意!关键来了:
卷积神经网络会把这 3 个数字直接加起来(a + b + c a + b + ca+b+c) ,得出一个唯一的最终数字。
这个最终数字,就填在输出特征图(比如5 × 5 5 \times 55×5)对应的那个格子里。
这个数字代表了:在这个特定的空间位置( x , y ) (x, y)(x,y),红绿蓝三个通道组合起来的整体特征,跟这个立体卷积核有多匹配。
**4. **
卷积核的厚度 = 画布的厚度。
红通道的数据只能碰红层的卷积核,绿碰绿,蓝碰蓝,各找各妈,绝不串线。一个卷积核只有一个立体形状。它滑遍全图,用的都是同一套参数,所以才叫“权值共享”。
卷积核为什么能提取特征?因为它的 27 个数字是训练出来的。比如它学成了“红层找竖线,绿层找横线,蓝层找圆圈”,那么它滑到哪里,就能把这三个通道里同时满足这些条件的地方找出来,融合成一张特征图。
三、不知所云
1. 什么是“特征图”?
那个5 × 5 5 \times 55×5的矩阵(厚度为1),整体叫做“这一层特征图”。
2. 什么是“特征值”?
5 × 5 5 \times 55×5这个矩阵里,每一个单独的格子(比如左上角那个格子,或者右下角那个格子)里面的数字,才叫“特征值”。这个特征值,代表了原图对应位置有多像这个卷积核。
- 5 × 5 5 \times 55×5的图里一共有25个格子,所以算出了25个特征值。
想象你有一张7 × 7 7 \times 77×7的图片,你的卷积核是3 × 3 3 \times 33×3。当你把卷积核放在左上角(比如坐标1,1到3,3)时,你算出了一个数字,比如 9.8。
这个 9.8 是怎么来的?是这 9 个像素点乘以卷积核的 9 个权重,强行加在一起得出来的。
- 如果这 9 个像素组成的图案,跟卷积核想找的图案高度一致,乘积相加就会得到一个大数字(比如 9.8)。
- 如果这 9 个像素跟卷积核完全相反或毫无关系,乘积相加就会得到一个小数字,甚至是负数。
重点来了:
当你把窗口向右滑动一格(坐标1,2到3,4),算出了一个新数字,比如 0.5。
你发现了吗?每一个数字,都对应着图片上的一个特定的小方块区域(空间位置)。特征图上的[1,1]位置是 9.8,就是在大声告诉你:“原图左上角那一片,极其强烈地拥有这个特征!” “特征图上的[1,2]位置是 0.5,就是告诉你:“原图稍微靠右一点的地方,只有一点点这个特征。”
特征图,其实就是一张“热力图(Heatmap)”(或者“寻宝地图”),上面每一个格子的数值,记录了那个特定位置有多像你要找的特征。
“这 9 个数字加在一起,凭什么就能代表那3 × 3 3 \times 33×3区域的特征?”
这就涉及到一个极其重要的数学概念:点积(内积)。
在高中数学里,两个向量的点积越大,说明这两个向量方向越一致。
- 把图片上的3 × 3 3 \times 33×3区域拉平成 9 个数字(向量 A)。
- 把卷积核拉平成 9 个数字(向量 B)。
- 卷积运算,本质上就是 A 和 B 在做点积。
四、卷积层api和代码实现
torch.nn.Conv2d(in_channels,out_channels,kernel_size,stride,padding)# in_channels:输入通道数# out_channels:输出通道数# kernel_size:卷积核大小# stride:步幅# padding:填充幅度算出卷积后的形状:
代码
importtorchimportmatplotlib.pyplotasplt#卷积层的定义和应用测试#1.读取图片img=plt.imread("../../data/duck.jpg")print(img.shape)# (1080, 1080, 3)# 2.将图片数据调整为卷积层输入特征图对应的形状input=torch.tensor(img).permute(2,0,1).float()print(f"输入特征图的形状:{input.shape}")# 输入特征图的形状:torch.Size([3, 1080, 1080])# 3.定义卷积层conv=torch.nn.Conv2d(in_channels=3,out_channels=3,kernel_size=9,stride=3,padding=0,bias=False)# 4. 前向传播,将卷积层应用到输入特征图上output=conv(input)print(f"输出特征图的形状:{output.shape}")# 输出特征图的形状:torch.Size([3, 358, 358])# 5.将输出特征图转为图片数据# 防止数据超过图片范围,要夹断output=torch.clamp(output.int(),min=0,max=255)output=output.permute(1,2,0).detach().numpy()print(output.shape)# (358, 358, 3)# 显示图片,进行对比fig,ax=plt.subplots(1,2,figsize=(10,5))ax[0].imshow(img)ax[1].imshow(output)# plt.show()plt.savefig('testcnn_result.png')效果