我们定义一个函数,实现图像的卷积操作。
这里X[i:i+h,j:j+w]的用法是把X这个大矩阵中,行数从i到i+h-1,列数从j到j+w-1的一小块给拿出来了,例子如下:
A = torch.tensor([ [1,1,1,1], [2,2,2,2], [3,3,3,3], [4,4,4,4] ]) print(A[0:3,1:4])
输出结果:
1.卷积层
卷积层对输入和卷积核权重进行互相关运算,并在添加标量偏置之后产生输出。 所以,卷积层中的两个被训练的参数是卷积核权重和标量偏置。 就像我们之前随机初始化全连接层一样,在训练基于卷积层的模型时,我们也随机初始化卷积核权重。
基于上面定义的corr2d
函数实现二维卷积层。在__init__
构造函数中,将weight
和bias
声明为两个模型参数。前向传播函数调用corr2d
函数并添加偏置。
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
2.学习卷积核
就像torch.nn中有全连接层nn.Linear()一样,torch.nn也有卷积层nn.Conv2d()。nn.Conv2d()有四个参数,分别是输入通道数、输出通道数、卷积核尺寸kernel_size,以及偏置bias。
我们学习一个横向的边缘检测卷积核。首先定义一个矩阵X:
再定义我们希望的输出矩阵Y,Y的值是X经过1*2卷积核[1,-1]得到的:
我们简单实现一个训练代码,来训练卷积核参数:
# 使用nn的内置卷积层,前两个参数分别表示输入、输出通道数 conv2d = nn.Conv2d(1,1, kernel_size=(1, 2), bias=False) # 四个参数分别是(批量大小、通道、高度、宽度) 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: print(f'epoch {i+1}, loss {l.sum():.3f}')
这里面,梯度清零使用了conv2d.zero_grad(),conv2d是Conv2d类的对象,是nn.Module的子类的一个对象,应该是nn.Module都有这个.zero_grad()方法。
在3.2节,线性回归的从零开始实现中我们自己实现了sgd优化算法,如下:
def sgd(params, lr, batch_size): #@save """小批量随机梯度下降""" with torch.no_grad(): for param in params: param -= lr * param.grad / batch_size param.grad.zero_()
这里参数梯度的更新是使用参数本身的.grad.zero_()更新的。
标签:nn,卷积,torch,6.2,图像,grad,conv2d,size From: https://www.cnblogs.com/pkuqcy/p/17584944.html