本文章来源于对李沐动手深度学习
代码以及原理的理解,并且由于李沐老师的代码能力很强,以及视频中讲解代码的部分较少,所以这里将代码进行尽量逐行详细解释
并且由于pytorch的语法有些小伙伴可能并不熟悉,所以我们会采用逐行解释+小实验的方式来给大家解释代码
在这一块,李沐老师的代码里面其实有很多的测试例子,而这些测试例子往往是劝退初学者的一个很大的因素,为了快速理解并且上手卷积神经网络,我并不会很强调所有的例子,而是根据李沐老师的顺序,将主要框架进行搭建,重要的小例子我会带大家进行浮现,但是具体的一些小例子就让大家自己去试试
本文的动图来自:https://blog.youkuaiyun.com/Together_CZ/article/details/115494176
以及一些网络的资料
卷积
相信工科专业的同学对这个词应该不会陌生,尤其是通信专业,我们经常会做信号卷积的操作,但是在其他的使用上面,我们常常使用的是一维卷积,但是在卷积神经网络中,我们用到的是二维卷积,我们可以用下面这张动图来描述二维卷积:
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
我们使用这一段代码来描述这样的一个卷积的过程,这个代码实际上没有很大的难度,但是我们需要弄清楚的是卷积前和卷积后,二维图像尺寸的变化
我认为大家只需要记住一个公式,就可以弄清楚卷积和其他操作之后,我们图像的尺寸了(这里默认二维图像的高和宽是一样的,这里算出的是边长):
O u p u t = ( I n p u t + 2 ∗ p a d d i n g − k e r n e l ) / s t r i d e + 1 结果向下取整 Ouput = (Input+2*padding-kernel)/stride+1\\结果向下取整 Ouput=(Input+2∗padding−kernel)/stride+1结果向下取整
这个公式的具体推导我们可以看Pytorch官网的推导,这里我也可以把链接放在这里尺寸公式推导
或许初学者小伙伴们就会有疑惑,Output和Input我们都知道,是输入和输出;但是padding,kernel,stride是什么呢?没关系,我们后面会进行解释
卷积层
在上面的代码里面,我们已经实现了一个卷积操作,卷积层实际上就是将这个卷积操作做成一个类
# 实现二维卷积层
class Conv2d(nn.Module):
def __init__(self,kernel_size):
super().__init__()
self.weight = nn.Parameter(torch.rand(kernel_size))
self.bias = nn.Parameter(nn.zeros(1))
def forward(self,x):
return corr2d(x,self.weight)+self.bias
如果对类这个概念不是特别了解的同学,可以去看看我之前的文章,有讲解python的类的文章
需要注意的是,由于我们继承了父类nn.Module,所以__call__
方法在这里写成forward
方法,两者是等价的,我们先来讲解一下卷积层比较重要的一个参数kernel_size
Kernel_size
这个参数表示卷积核的大小,我们根据上面的动图来看,卷积核的大小是3×3,因为映射到图片上的影子是3×3的
或许你会认为这样的实现方式过于麻烦,我们当然也有更简单的实现方法,就是调用torch.nn
模型中的Conv2d的函数,我们下面就对这个重要的函数进行讲解
torch.nn.Conv2d
conv2d = nn.Conv2d(1,1,kernel_size=(1,2)