pytorch学习笔记(8)

# 图像卷积代码

import torch
from torch import nn
from d2l import torch as d2l

def corr2d(X, K):  # X 是输入数据,通常是一个二维张量(例如,图像),K 是卷积核(滤波器)。
    """计算二维互相关运算"""
    h, w = K.shape  # 首先获取卷积核 K 的高度 h 和宽度 w
    Y = torch.zeros((X.shape[0] - h + 1, X.shape[1] - w + 1))  # 创建一个输出张量 Y,其形状由输入 X 的形状和卷积核的大小决定,但不包括边缘像素。
    for i in range(Y.shape[0]):  # 使用两个嵌套循环遍历输入 X 中的所有位置,计算互相关运算的结果并将结果存储在 Y 中。
        for j in range(Y.shape[1]):
            Y[i, j] = (X[i:i + h, j:j + w] * K).sum()
    return Y

# 简单来说Y就是输出矩阵
class Conv2D(nn.Module):
    def __init__(self, kernel_size):  # kernel_size 参数表示卷积核(滤波器)的大小。它是一个整数或元组,指定了卷积核的高度和宽度。
        super().__init__()
        self.weight = nn.Parameter(torch.rand(kernel_size))  # 这一行代码创建了卷积层的权重参数 self.weight。权重参数是一个可训练的 PyTorch 参数,它使用随机初始化的值(从均匀分布中随机抽样),其形状由 kernel_size 决定。
        self.bias = nn.Parameter(torch.zeros(1))  # 这一行代码创建了卷积层的偏置参数 self.bias,初始化为零。

    def forward(self, x):
        return corr2d(x, self.weight) + self.bias

学习卷积核

# 构造一个二维卷积层,它具有1个输出通道和形状为(1,2)的卷积核
conv2d = nn.Conv2d(1,1, kernel_size=(1, 2), bias=False)  # 1, 1:表示该卷积层有一个输入通道和一个输出通道。kernel_size=(1, 2):指定了卷积核的大小,为 1x2,这意味着卷积核的高度为1,宽度为2。bias=False:表示不使用偏置项。


X = X.reshape((1, 1, 6, 8))  #形状为(批量大小,通道数,高度,宽度)。在这里,X 和 Y 分别被调整为(1,1,6,8)和(1,1,6,7)的形状。
Y = Y.reshape((1, 1, 6, 7))
lr = 3e-2  # 定义学习率,用于控制梯度下降的步长。

for i in range(10):
    Y_hat = conv2d(X)  # 计算模型的输出。
    l = (Y_hat - Y) ** 2  # 计算平方损失。
    conv2d.zero_grad()  # 清零卷积核的梯度,以避免梯度累积
    l.sum().backward()  # 通过反向传播计算损失函数相对于卷积核权重的梯度。
    # 迭代卷积核
    conv2d.weight.data[:] -= lr * conv2d.weight.grad  # 更新卷积核的权重,使用梯度下降方法。学习率 lr 控制了每次更新的步长。
    if (i + 1) % 2 == 0:
        print(f'epoch {i+1}, loss {l.sum():.3f}')

# 填充和步幅


# 为了方便起见,我们定义了一个计算卷积层的函数。
# 此函数初始化卷积层权重,并对输入和输出提高和缩减相应的维数
def comp_conv2d(conv2d, X):
    # 这里的(1,1)表示批量大小和通道数都是1
    X = X.reshape((1, 1) + X.shape)  # X 是输入数据,这里将其形状调整为 (1, 1, 8, 8) 的四维张量,其中 (1, 1) 表示批量大小和通道数都为 1,(8, 8) 表示高度和宽度为 8 的图像。
    Y = conv2d(X)  # 计算了卷积层 conv2d 对输入 X 的卷积结果,并将结果存储在 Y 中。
    # 省略前两个维度:批量大小和通道
    return Y.reshape(Y.shape[2:])  # 为了简化结果,这行代码将 Y 的形状从 (1, 1, 8, 8) 调整为 (8, 8),省略了批量大小和通道维度。

# 请注意,这里每边都填充了1行或1列,因此总共添加了2行或2列
conv2d = nn.Conv2d(1, 1, kernel_size=3, padding=1)  # 1, 1 表示输入通道数和输出通道数都为 1。kernel_size=3 表示卷积核的大小为 3x3。表示在图像的每一侧都填充了一行或一列的零,总共添加了2行或2列的填充。
X = torch.rand(size=(8, 8))
comp_conv2d(conv2d, X).shape
conv2d = nn.Conv2d(1, 1, kernel_size=(3, 5), padding=(0, 1), stride=(3, 4))  # padding=(0, 1):在水平方向上不填充,而在垂直方向上填充了1行的零;stride=(3, 4):在水平方向上的步幅为3,而在垂直方向上的步幅为4。
comp_conv2d(conv2d, X).shape  # 输出的形状为 (2, 2)。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值