从零开始的推荐系统学习之路(十三)---- 动手学深度学习系列 卷积神经网络 基础部分 CNN(卷积层 & 填充与步幅 & 多输入输出 & 池化层)
·
文章目录
前引
这个月还有两天了 可以多忙一会儿 希望这两天可以过大概30个视频 到50%左右的进度吧
头发有点长了 还有抽时间去剪头发。。。
从零开始的推荐系统学习之路(十三)---- 动手学深度学习系列 卷积神经网络 基础部分 CNN(卷积层 & 填充与步幅 & 多输入输出 & 池化层)
1、卷积层
这里卷积层 主要有两个特性吧 可以这样理解 一个是平移性 即 例如输入样本 相关纬度的数据 发生位置偏移 但是 对于训练好的模型 不同样本位置发生偏移 那结果肯定就不准了 所以有平移性 我是这样理解的。。 至于怎么实现后面再看
第二个就是 局部性 因为其实只需要关注 一张图片 也只需要关注局部性信息 其他区域的信息其实是可以相对而言不关心的
import torch
from torch import nn
import numpy as np
torch.rand((1, 2)) + 1
(1, 1) + (1, 1)
# K kernel
def corr2d(X, K):
kx, ky = K.shape
yx, yy = X.shape[0] - kx + 1, X.shape[1] - ky + 1
Y = torch.zeros((yx, yy))
for i, j in np.ndindex(yx, yy):
Y[i][j] = (X[i:i+kx, j:j+ky] * K).sum()
return Y
X = torch.ones((3, 3))
X[:, 2:5] = 0
K = torch.tensor([[1, 2], [3, 4]])
X, K, corr2d(X, K)
# for i, j in np.ndindex(1, 2):
# print(i, j)
class Conv2d(nn.Module):
def __init__(self, kernel_shape):
super().__init__()
self.weight = torch.rand(kernel_shape, requires_grad=True)
self.bias = torch.zeros(1, requires_grad=True)
def forward(self, X):
return corr2d(X, self.weight) + self.bias
Conv2d(K.shape)
X = torch.ones((7, 7))
X[:, 2:5] = 0
X
K = torch.tensor([[1.0, -1.0]])
Y = corr2d(X, K)
print(X, "\n", Y)
net = Conv2d(K.shape)
loss = nn.MSELoss()
trainer = torch.optim.Adam(params=[net.weight, net.bias], lr=5e-1)
for i in range(100):
l = loss(net(X), Y)
trainer.zero_grad()
net.zero_grad()
l.backward()
trainer.step()
print("epoch:{}, l:{:.4f}".format(i + 1, l.data))
print(net.weight)
net = nn.Conv2d(1, 1, kernel_size=K.shape, bias=False)
loss = nn.MSELoss()
# trainer = torch.optim.Adam(params=[net.weight, net.bias], lr=5e-1)
X = X.reshape((1, 1) + X.shape)
Y = Y.reshape((1, 1) + Y.shape)
for i in range(100):
l = loss(net(X), Y)
net.zero_grad()
l.sum().backward()
net.weight.data -= 3e-1 * net.weight.grad
print("epoch:{}, l:{:.4f}".format(i + 1, l.data))
print(net.weight)


2、填充和步幅
这个填充也是字面意思的 上下左右去填充
步幅指的是 去越多步幅去搞 这样可以更少的层数就可以收敛
输出高度 = floor((输入高度 + 2padding高度 - 卷积核高度) / 步幅高度 + 1)
输出宽度 = floor((输入宽度 + 2padding宽度 - 卷积核宽度) / 步幅宽度 + 1
def comp_conv2d(conv2d, X):
X = X.reshape((1, 1) + X.shape)
Y = conv2d(X)
return Y.reshape(Y.shape[2:])
net = nn.Conv2d(1, 1, kernel_size=(2, 1), bias=False, padding=1)
X = torch.ones((7, 7))
# (7, 7) - (2-1, 1-1) + (2, 2)
comp_conv2d(net, X).shape
net = nn.Conv2d(1, 1, kernel_size=(3, 3), bias=False, padding=2, stride=4)
X = torch.ones((7, 7))
# 输出高度 = floor((输入高度 + 2*padding高度 - 卷积核高度) / 步幅高度 + 1)
# 输出宽度 = floor((输入宽度 + 2*padding宽度 - 卷积核宽度) / 步幅宽度 + 1
comp_conv2d(net, X).shape

3、多输入输出通道
# 多一个通道纬度
def corr2d_multi_in(X, K):
print(X.shape, K.shape)
# return sum([d2l.corr2d(x, k) for x, k in zip(X, K)])
return sum(d2l.corr2d(x, k) for x, k in zip(X, K))
def corr2d_multi_in_for_test(X, K):
# return sum([d2l.corr2d(x, k) for x, k in zip(X, K)])
return [d2l.corr2d(x, k) for x, k in zip(X, K)]
# 多一个输出通道纬度
def corr2d_multi_in_out(X, K):
# return sum([d2l.corr2d(x, k) for x, k in zip(X, K)])
return torch.stack([corr2d_multi_in(X, k) for k in K], dim=0)
X = torch.tensor([[[0.0, 1.0, 2.0, 3.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, 10.0, 11.0, 12.0]]])
K = torch.tensor([[[0.0, 1.0],[1.0, 2.0]],
[[1.0, 2.0],[3.0, 4.0]]])
print(corr2d_multi_in(X, K))
print(corr2d_multi_in_for_test(X, K))
K = torch.tensor([[[0.0, 1.0],[1.0, 2.0]],
[[1.0, 2.0],[3.0, 4.0]]])
K = torch.stack([K, K + 1, K + 2], dim=0)
corr2d_multi_in_out(X, K)
X = torch.normal(0, 1, (3, 3, 3))
K = torch.normal(0, 1, (2, 3, 1, 1))
# X 为 3dim K 为 4dim 其中最外围为输出纬度
def corr_multi_in_out_1x1(X, K):
ci, h, w = X.shape
co, ci, kh, kw = K.shape
X = X.reshape((ci, h * w))
K = K.reshape((co, ci))
Y = torch.matmul(K, X)
return Y.reshape((co, h, w))
corr2d_multi_out(X, K), corr_multi_in_out_1x1(X, K)
Y1 = corr_multi_in_out_1x1(X, K)
Y2 = corr2d_multi_in_out(X, K)
assert (Y1 - Y2).abs().sum() <= 1e-6


4、池化层
中转层去单独处理
X = torch.normal(0, 1, (3, 3, 3))
K = torch.normal(0, 1, (2, 3, 1, 1))
# X 为 3dim K 为 4dim 其中最外围为输出纬度
def corr_multi_in_out_1x1(X, K):
ci, h, w = X.shape
co, ci, kh, kw = K.shape
X = X.reshape((ci, h * w))
K = K.reshape((co, ci))
Y = torch.matmul(K, X)
return Y.reshape((co, h, w))
corr2d_multi_out(X, K), corr_multi_in_out_1x1(X, K)
Y1 = corr_multi_in_out_1x1(X, K)
Y2 = corr2d_multi_in_out(X, K)
assert (Y1 - Y2).abs().sum() <= 1e-6
# 池化 2d输入
def pool2d(X, pool_size, mode='max'):
pool_h, pool_w = pool_size
h, w = X.shape
Y = torch.zeros((h - pool_h + 1, w - pool_w + 1))
yh, yw = Y.shape
for i, j in np.ndindex(yh, yw):
if mode == 'max':
Y[i][j] = X[i:i+pool_h, j:j+pool_w].max()
elif mode == 'avg':
Y[i][j] = X[i:i+pool_h, j:j+pool_w].mean()
return Y
X = torch.arange(9).reshape(3, -1).to(torch.float32)
X, pool2d(X, (2,2)), pool2d(X, (2,2), mode='avg')
X = torch.arange(9).reshape(1, 1, 3, -1).to(torch.float32)
# 步幅和窗口大小一样。。。 等于不会有重复格子
pool2d = nn.MaxPool2d(3)
print(pool2d(X))
pool2d = nn.MaxPool2d(2, padding=0, stride=1)
print(pool2d(X))
pool2d = nn.MaxPool2d(2, padding=1, stride=1)
print(pool2d(X))
X = torch.arange(9).reshape(1, 1, 3, -1).to(torch.float32)
X = torch.cat([X, X + 1], dim=0)
pool2d(X)



更多推荐
所有评论(0)