05_卷积、填充、步幅、池化

对于B站课程19_P3

'''卷积层'''
import torch
from torch import nn
from d2l import torch as d2l


# 互相关运算
def corr2d(X, K):
    """计算二维互相关运算"""
    h, w = K.shape
    Y = torch.zeros((X.shape[0] - h + 1, X.shape[1] - w + 1))
    for i in range(Y.shape[0]):
        for j in range(Y.shape[1]):
            Y[i, j] = (X[i:i + h, j:j + w] * K).sum()
    return Y


# 自定义二维卷积层
class Conv2D(nn.Module):
    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


if __name__ == '__main__':
    '''
    X = torch.tensor([[0.0, 1.0, 2.0], [3.0, 4.0, 5.0], [6.0, 7.0, 8.0]])
    K = torch.tensor([[0.0, 1.0], [2.0, 3.0]])
    print(corr2d(X, K))
    '''

    X = torch.ones((6, 8))
    X[:, 2:6] = 0
    K = torch.tensor([[1.0, -1.0]])  # 1*2的卷积核
    Y = corr2d(X, K)
    print(Y)

    # 构造一个二维卷积层,它具有1个输入通道1个输出通道  卷积核形状为(1,2)
    conv2d = nn.Conv2d(1, 1, kernel_size=(1, 2), bias=False)
    # 这个二维卷积层使用四维输入和输出格式(批量大小、通道、高度、宽度),其中批量大小和通道数都为1
    X = X.reshape((1, 1, 6, 8))
    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
        if (i + 1) % 2 == 0:     # 每两个batch输出l.sum
            print(f'epoch {i + 1}, loss {l.sum():.3f}')
    print(conv2d.weight.data.reshape((1, 2)))

笔记

对于B站课程20_P2

'''填充和步幅'''
import torch
from torch import nn


# 为了方便起见,我们定义了一个计算卷积层的函数。
# 此函数初始化卷积层权重,并对输入和输出提高和缩减相应的维数
def comp_conv2d(conv2d, X):
    # 这里的(1,1)表示批量大小和通道数都是1
    X = X.reshape((1, 1) + X.shape)
    Y = conv2d(X)
    # 省略前两个维度:批量大小和通道
    return Y.reshape(Y.shape[2:])
    # return Y    # torch.Size([1, 1, 8, 8])

if __name__ == '__main__':

    X = torch.rand(size=(8, 8))
    '''
    # 步幅
    conv2d = nn.Conv2d(1, 1, kernel_size=(3,3), padding=1)  # 上下左右各填充一行
    print(comp_conv2d(conv2d, X).shape)
  
    conv2d = nn.Conv2d(1, 1, kernel_size=(5, 3), padding=(2, 1))  # 上下各加2行,左右各加1行。
    print(comp_conv2d(conv2d, X).shape)
    '''

    '''
    # 填充
    conv2d = nn.Conv2d(1, 1, kernel_size=(3,3), padding=1, stride=(2,2))
    print(comp_conv2d(conv2d, X).shape)
    '''
    conv2d = nn.Conv2d(1, 1, kernel_size=(3, 5), padding=(0, 1), stride=(3, 4))
    print(comp_conv2d(conv2d, X).shape)

对于B站课程21_P2

'''多输入多输出'''
import torch
from d2l import torch as d2l


# 多输入通道,单输出通道
def corr2d_multi_in(X, K):
    # 先遍历“X”和“K”的第0个维度(通道维度),再把它们加在一起
    return sum(d2l.corr2d(x, k) for x, k in zip(X, K))  # zip 依次返回X单个通道及其对应的kernal

# 多输入,多输出通道
def corr2d_multi_in_out(X, K):
    # 迭代“K”的第0个维度,每次都对输入“X”执行互相关运算。
    # 最后将所有结果都叠加在一起
    return torch.stack([corr2d_multi_in(X, k) for k in K], 0)

# 1*1的卷积(等价于全连接)
def corr2d_multi_in_out_1x1(X, K):
    c_i, h, w = X.shape  # c_i,h, w=3,
    c_o = K.shape[0]  # c_o=2
    X = X.reshape((c_i, h * w))  # 3*9
    K = K.reshape((c_o, c_i))   # 2*3
    # 全连接层中的矩阵乘法
    Y = torch.matmul(K, X)
    return Y.reshape((c_o, h, w))

if __name__ == '__main__':

    '''
    # 多输入单\多输出
    X = torch.tensor([[[0.0, 1.0, 2.0], [3.0, 4.0, 5.0], [6.0, 7.0, 8.0]],
                   [[1.0, 2.0, 3.0], [4.0, 5.0, 6.0], [7.0, 8.0, 9.0]]])
    K = torch.tensor([[[0.0, 1.0], [2.0, 3.0]], [[1.0, 2.0], [3.0, 4.0]]])
    # K + 1:对K的每个元素+1,把K,K + 1, K + 2 按dim=0即按行堆叠起来
    K = torch.stack((K, K + 1, K + 2), 0)
    # K.shape torch.Size([3, 2, 2, 2]) 3表示个输出,第一个2对应输入有2个通道,即原来的K.shape为[2,2,2]
    #print(corr2d_multi_in(X, K))  # 多输入单输出
    print(corr2d_multi_in_out(X, K))  # 多输入多输出
    '''

    # 1*1的卷积(3输入2输出)
    X = torch.normal(0, 1, (3, 3, 3))
    K = torch.normal(0, 1, (2, 3, 1, 1))

    Y1 = corr2d_multi_in_out_1x1(X, K)
    Y2 = corr2d_multi_in_out(X, K)
    assert float(torch.abs(Y1 - Y2).sum()) < 1e-6

对于B站课程22_P2

'''池化'''

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


def pool2d(X, pool_size, mode='max'):   # 该函数第三个参数有默认值可不传
    p_h, p_w = pool_size
    Y = torch.zeros((X.shape[0] - p_h + 1, X.shape[1] - p_w + 1))
    for i in range(Y.shape[0]):
        for j in range(Y.shape[1]):
            if mode == 'max':
                Y[i, j] = X[i: i + p_h, j: j + p_w].max()
            elif mode == 'avg':
                Y[i, j] = X[i: i + p_h, j: j + p_w].mean()
    return Y


'''
# 池化
X = torch.tensor([[0.0, 1.0, 2.0], [3.0, 4.0, 5.0], [6.0, 7.0, 8.0]])
print(pool2d(X, (2, 2)))
print(pool2d(X, (2, 2), 'avg'))
'''

X = torch.arange(16, dtype=torch.float32).reshape((1, 1, 4, 4))  # 第1个1批量大小 第2个1通道个数
print(X)
'''
# 单通道池化+步幅、填充
pool2d = nn.MaxPool2d(2)  # torch中默认步幅和池化层大小相同
print(pool2d(X))
pool2d = nn.MaxPool2d(3, padding=1, stride=2)  # 大小3*3 填充上下左右各1,步幅为2
print(pool2d(X))
pool2d = nn.MaxPool2d((2, 3), stride=(2, 3), padding=(1, 1))
print(pool2d(X))
'''

# 多通道输入池化
X = torch.cat((X, X + 1), 1)  # cat不增加维度
print(X)
pool2d = nn.MaxPool2d(3, padding=1, stride=2)
print(pool2d(X))

对于21_P2中.stack与22_P2.cat的理解

 

 .cat不增加维度

 

 

.stack会增加维度 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

CPU疼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值