Python 现代开发学习笔记

(二十)图像窗口与卷积计算

8×8 图形的相邻像素有位置关系。卷积层让同一个小窗口在图像上移动,在每个位置用同一组权重读取局部内容。

# 项目文件:demos/convolution_patch.py
import torch
from torch import nn

x = torch.tensor(
    [[1, 2, 0, 1], [0, 1, 3, 2], [2, 1, 0, 1], [1, 0, 2, 3]], dtype=torch.float32
)
layer = nn.Conv2d(1, 1, kernel_size=2, bias=False)
with torch.no_grad():
    # 每个窗口用左上角减去右下角;PyTorch 按给定次序对应相乘。
    layer.weight.copy_(torch.tensor([[[[1.0, 0.0], [0.0, -1.0]]]]))
output = layer(x.unsqueeze(0).unsqueeze(0))
print("卷积结果", output[0, 0].detach().tolist())
pool_input = torch.tensor(
    [[[[1, 5, 2, 3], [4, 0, 7, 1], [2, 6, 0, 8], [1, 3, 9, 4]]]], dtype=torch.float32
)
print("池化结果", nn.MaxPool2d(2)(pool_input)[0, 0].tolist())

先看左上角的 2×2 窗口 [[1,2],[0,1]],与权重 [[1,0],[0,-1]] 对应相乘再相加,得到 1-1=0。窗口右移一格变成 [[2,0],[1,3]],得到 2-3=-1。继续向右、换下一行,最终输出:

 0 -1 -2
-1  1  2
 2 -1 -3
二乘二权重先覆盖左上窗口计算零,右移一格计算负一,再按行移动填入三乘三输出,明确权重与像素的对应项

Conv2d 的这一计算采用给定权重次序对应相乘,不先翻转窗口权重,数学上常称为互相关。深度学习中仍沿用卷积层这个名称。

kernel_size 是窗口大小,stride 是每次移动距离,padding 是四周补的像素宽度,这里的卷积层使用补零。方形窗口的单侧输出长度可按下面计算:

Hout=⌊H+2p−ks⌋+1. H_{out}=\left\lfloor\frac{H+2p-k}{s}\right\rfloor+1.

其中输入高为 HH,补边宽为 pp,窗口宽为 kk,步长为 ss。本例 4、0、2、1 得到 3;8×8 图用 3×3 窗口、补一圈、步长一,得到 (8+2-3)/1+1=8。带膨胀间隔的窗口与更多参数可继续查 Conv2d。

笔记正文与全部题解 · Ctrl / ⌘ K