文章目录

  • 引入
  • 1 二维互相关运算
  • 2 二维卷积层
  • 3 图像中物体边缘检测
  • 4 通过数据学习核矩阵
  • 5 互相关运算和卷积运算
  • 完整代码


引入

神经网络二维卷积 二维 卷积_深度学习

1 二维互相关运算

  虽然卷积层得名于卷积 (convalution)计算,但通常在卷积层中使用更为直观的互相关 (cross-correlation)运算。

  在二维卷积层中,一个二维输入数组和一个二维核通过互相关运算,输出一个二维数组。例如下图 (图片源自原书):

  输入一个神经网络二维卷积 二维 卷积_FanSmale_02的矩阵、神经网络二维卷积 二维 卷积_深度学习_03的核矩阵。核矩阵在卷积计算中又称为卷积核过滤器 (filter)。卷积核窗口 (或称卷积窗口)的形状取决于卷积核的大小。

神经网络二维卷积 二维 卷积_深度学习_04


  在二维互相关运算中,卷积窗口从输入矩阵的最左上方开始,按照←、→、↑、↓的顺序依次在输入矩阵中扫描。在某一位置时,计算该位置的两个矩阵的点乘并求和。例如上图所示窗口中,有:

神经网络二维卷积 二维 卷积_深度学习_05

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 图像中物体边缘检测

  以下介绍一个卷积层的简单应用:检测图像中物体的边缘,即找到像素变化的位置。
  首先构造一张神经网络二维卷积 二维 卷积_互相关_06的图像,且神经网络二维卷积 二维 卷积_二维卷积层_07神经网络二维卷积 二维 卷积_二维卷积层_08白然后构建一个神经网络二维卷积 二维 卷积_神经网络二维卷积_09的核矩阵:

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))

神经网络二维卷积 二维 卷积_二维卷积层_07;否则非神经网络二维卷积 二维 卷积_二维卷积层_07

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 通过数据学习核矩阵

神经网络二维卷积 二维 卷积_互相关_12和输出数据神经网络二维卷积 二维 卷积_二维卷积层_13来构建核矩阵:
  1)构建一个卷积层,卷积核则被随机初始化;
  2)每一次迭代中,使用平方误差来比较神经网络二维卷积 二维 卷积_二维卷积层_13和卷积层的输出,并计算梯度用于更新权重。

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等老师的这本《动手学深度学习》一书。