深度学习实践4:手撕卷积神经网络

思路:

本部分实现了一个简单的二维卷积神经网络(Conv2D),并进行了简单的实践,以下是代码流程。

代码流程:

import torch
from torch import nn
import torch.nn.functional as F

导入所需的 PyTorch 模块。

def corr2d(X, K, bias=None, stride=1, padding=0):
    h, w = K.shape
    # 计算输出矩阵的大小
    out_h = (X.shape[0] - h + 2 * padding) // stride + 1
    out_w = (X.shape[1] - w + 2 * padding) // stride + 1

    # 构建输出矩阵
    Y = torch.zeros(out_h, out_w)

    # 添加填充
    X_padded = F.pad(X, (padding, padding, padding, padding))

    # 滑动,并进行求值
    for i in range(0, X_padded.shape[0] - h + 1, stride):
        for j in range(0, X_padded.shape[1] - w + 1, stride):
            Y[i // stride, j // stride] = (X_padded[i:i + h, j:j + w] * K).sum()

    # 添加偏置项
    if bias is not None:
        Y += bias

    return Y

这是一个自定义的二维卷积函数 corr2d,用于计算输入 X 与卷积核 K 的卷积结果。它支持设置步长(stride)和填充(padding),并可以选择添加偏置项(bias)。

class Conv2D(nn.Module):
    # 对参数进行初始化,w设为随机值,b设为零值
    def __init__(self, kernel_size):
        super().__init__()
        self.weight = nn.Parameter(torch.rand(kernel_size))
        self.bias = nn.Parameter(torch.zeros(1))

    # 前向传播
    def forward(self, x):
        return corr2d(x, self.weight) + self.bias

这是一个继承自 nn.Module 的自定义卷积层类 Conv2D。在初始化函数 __init__ 中,它定义了卷积核的权重 self.weight 和偏置项 self.bias,并将它们都设置为可训练的参数。在前向传播函数 forward 中,它调用了之前定义的 corr2d 函数来计算卷积结果,并加上偏置项。

简单实践:

kernel_size = (1, 2)
conv_layer = Conv2D(kernel_size)

定义了卷积核的大小为 (1, 2),并创建了一个 Conv2D 的实例 conv_layer

X = torch.ones((6, 8))
X[:, 2:6] = 0

创建了一个大小为 (6, 8) 的张量 X,并将其中的一部分置为 0。

K = torch.tensor([[1.0, -1.0]])
Y = corr2d(X, K)

创建了一个大小为 (1, 2) 的卷积核张量 K,并通过调用 corr2d 函数计算了输入 X 与卷积核 K 的卷积结果,保存在张量 Y 中。

optimizer = torch.optim.SGD(conv_layer.parameters(), lr=0.1)

定义了一个随机梯度下降(SGD)优化器,用于更新卷积层的参数。优化器的参数是卷积层的可训练参数 conv_layer.parameters(),学习率为 0.1。

for i in range(100):
    optimizer.zero_grad()
    Y_hat = conv_layer(X)
    l = F.mse_loss(Y_hat, Y)  # 均方误差
    l.sum().backward()
    optimizer.step()
    if (i + 1) % 2 == 0:
        print(f'batch {i + 1}, loss {l.sum():.3f}')

进行训练循环,迭代 100 次。在每次迭代中,首先将优化器的梯度缓存清零 optimizer.zero_grad(),然后通过调用卷积层的前向传播函数 conv_layer(X) 得到预测结果 Y_hat,并计算预测结果与真实结果之间的均方误差损失 l。接着,通过调用 l.sum().backward() 计算损失相对于可训练参数的梯度,并通过调用 optimizer.step() 更新参数。最后,每隔 2 次迭代,打印当前迭代的批次号和损失值。

print(conv_layer.weight.data)

打印训练后的卷积层权重的数值。

结果:

batch 90, loss 0.002
batch 92, loss 0.001
batch 94, loss 0.001
batch 96, loss 0.001
batch 98, loss 0.001
batch 100, loss 0.001
tensor([[ 0.9462, -0.9426]])

可以看到预测的结果跟 [1,-1]还算接近,说明效果还算不错。

        

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值