文章目录
- 引入
- 1 二维互相关运算
- 2 二维卷积层
- 3 图像中物体边缘检测
- 4 通过数据学习核矩阵
- 5 互相关运算和卷积运算
- 完整代码
引入
。
1 二维互相关运算
虽然卷积层得名于卷积 (convalution)计算,但通常在卷积层中使用更为直观的互相关 (cross-correlation)运算。
在二维卷积层中,一个二维输入数组和一个二维核通过互相关运算,输出一个二维数组。例如下图 (图片源自原书):
输入一个的矩阵、的核矩阵。核矩阵在卷积计算中又称为卷积核或过滤器 (filter)。卷积核窗口 (或称卷积窗口)的形状取决于卷积核的大小。
在二维互相关运算中,卷积窗口从输入矩阵的最左上方开始,按照←、→、↑、↓的顺序依次在输入矩阵中扫描。在某一位置时,计算该位置的两个矩阵的点乘并求和。例如上图所示窗口中,有:
import torch
import warnings
warnings.filterwarnings('ignore')
def corr2d(x, k):
"""
Correlation compute with 2-dimensional matrix.
"""
m, n = k.shape
ret_mat = torch.zeros((x.shape[0] - m + 1, x.shape[1] - n + 1))
for i in range(ret_mat.shape[0]):
for j in range(ret_mat.shape[1]):
ret_mat[i, j] = torch.sum(x[i: i + m, j: j + n] * k)
return ret_mat
if __name__ == '__main__':
# Main
temp_x = torch.reshape(torch.range(0, 8, dtype=torch.float), (3, 3))
temp_k = torch.tensor([[0, 1], [2, 3]])
print(corr2d(temp_x, temp_k))
输出如下:
tensor([[19., 25.],
[37., 43.]])
2 二维卷积层
二维卷积层将输入和卷积核做互相关运算,并加上一个变量偏差来得到输出。
卷积层的模型参数包括了卷积核和标准偏差。在模型训练时,通常先对卷积核随机初始化,然后不断迭代卷积核和偏差:
class Conv2D(nn.Module):
def __init__(self, kernel_size):
super(Conv2D, self).__init__()
self.weight = nn.Parameter(torch.randn(kernel_size))
self.bias = nn.Parameter(torch.randn(1))
def forward(self, x):
"""
The forward function.
"""
return corr2d(x, self.weight) + self.bias
3 图像中物体边缘检测
以下介绍一个卷积层的简单应用:检测图像中物体的边缘,即找到像素变化的位置。
首先构造一张的图像,且黑白然后构建一个的核矩阵:
if __name__ == '__main__':
# Main
temp_x = torch.ones(6, 8)
temp_x[:, 2:6] = 0
temp_k = torch.tensor([[1, -1]])
print(temp_x)
print(corr2d(temp_x, temp_k))
;否则非:
tensor([[1., 1., 0., 0., 0., 0., 1., 1.],
[1., 1., 0., 0., 0., 0., 1., 1.],
[1., 1., 0., 0., 0., 0., 1., 1.],
[1., 1., 0., 0., 0., 0., 1., 1.],
[1., 1., 0., 0., 0., 0., 1., 1.],
[1., 1., 0., 0., 0., 0., 1., 1.]])
tensor([[ 0., 1., 0., 0., 0., -1., 0.],
[ 0., 1., 0., 0., 0., -1., 0.],
[ 0., 1., 0., 0., 0., -1., 0.],
[ 0., 1., 0., 0., 0., -1., 0.],
[ 0., 1., 0., 0., 0., -1., 0.],
[ 0., 1., 0., 0., 0., -1., 0.]])
4 通过数据学习核矩阵
和输出数据来构建核矩阵:
1)构建一个卷积层,卷积核则被随机初始化;
2)每一次迭代中,使用平方误差来比较和卷积层的输出,并计算梯度用于更新权重。
if __name__ == '__main__':
# Main
temp_x = torch.ones(6, 8)
temp_x[:, 2:6] = 0
temp_y = corr2d(temp_x, torch.tensor([[1, -1]]))
test = Conv2D(kernel_size=(1, 2))
step = 20
lr = 0.01
for i in range(step):
temp_hat_y = test(temp_x)
temp_loss = torch.sum((temp_hat_y - temp_y)**2)
temp_loss.backward()
test.weight.data -= lr * test.weight.grad
test.bias.data -= lr * test.bias.grad
test.weight.grad.fill_(0)
test.bias.grad.fill_(0)
print("Step %d, loss %.3f" % (i + 1, temp_loss.item()))
输出如下:
Step 1, loss 161.404
Step 2, loss 37.544
Step 3, loss 23.270
Step 4, loss 17.266
Step 5, loss 13.061
Step 6, loss 9.925
Step 7, loss 7.565
Step 8, loss 5.780
Step 9, loss 4.425
Step 10, loss 3.394
Step 11, loss 2.608
Step 12, loss 2.006
Step 13, loss 1.545
Step 14, loss 1.190
Step 15, loss 0.918
Step 16, loss 0.709
Step 17, loss 0.547
Step 18, loss 0.423
Step 19, loss 0.327
Step 20, loss 0.253
Process finished with exit code 0
5 互相关运算和卷积运算
卷运算与互相关运算类型,为了获得卷积运算的输出,只需将核数组左右翻转并上下翻转,再与输入数组做互相关运算。
完整代码
import torch
import warnings
import torch.nn as nn
warnings.filterwarnings('ignore')
def corr2d(x, k):
"""
Correlation compute with 2-dimensional matrix.
"""
m, n = k.shape
ret_mat = torch.zeros((x.shape[0] - m + 1, x.shape[1] - n + 1))
for i in range(ret_mat.shape[0]):
for j in range(ret_mat.shape[1]):
ret_mat[i, j] = torch.sum(x[i: i + m, j: j + n] * k)
return ret_mat
class Conv2D(nn.Module):
def __init__(self, kernel_size):
super(Conv2D, self).__init__()
self.weight = nn.Parameter(torch.randn(kernel_size))
self.bias = nn.Parameter(torch.randn(1))
def forward(self, x):
"""
The forward function.
"""
return corr2d(x, self.weight) + self.bias
if __name__ == '__main__':
# Main
temp_x = torch.ones(6, 8)
temp_x[:, 2:6] = 0
temp_y = corr2d(temp_x, torch.tensor([[1, -1]]))
test = Conv2D(kernel_size=(1, 2))
step = 20
lr = 0.01
for i in range(step):
temp_hat_y = test(temp_x)
temp_loss = torch.sum((temp_hat_y - temp_y)**2)
temp_loss.backward()
test.weight.data -= lr * test.weight.grad
test.bias.data -= lr * test.bias.grad
test.weight.grad.fill_(0)
test.bias.grad.fill_(0)
print("Step %d, loss %.3f" % (i + 1, temp_loss.item()))
参考文献
[1] 李沐、Aston Zhang等老师的这本《动手学深度学习》一书。