模型容器与AlexNet构建
之前介绍了在模型构建过程中有两个非常重要的步骤:构建子模块和拼接子模块,在搭建模型过程中还有一个比较重要的概念——模型容器,这次就主要介绍一下模型容器和AlexNet的构建。
- 模型容器(Containers)
- AlexNet构建
在pytorch提供的模型容器中有三个常用的子模块:
第一个是nn.Sequential,它的作用是将多个网络层按顺序包装起来;第二个是nn.ModuleList,它会像python的list一样包装多个网络层,可以像python的list一样进行迭代;第三个是nn.ModuleDict,它像python的dict(字典)一样包装多个网络层。
nn.Sequential
nn.Sequential是nn.Module的容器,用于按顺序包装一组网络层。在传统机器学习中有一个部分是特征工程,比如对图像进行特征提取然后将特征输入到分类器当中。在深度学习时代已经弱化了特征工程这个概念,尤其是卷积神经网络,对图像的特征不需要人为地设计,卷积神经网络的卷积层可以去自动地学习特征,然后在最后会添加若干个全连接层用于分类输出。在早期的神经网络当中,用于分类的分类器正是全连接构成的,所以在深度学习时代也有习惯以全连接层为界限将网络模型划分为特征提取模块和分类模块。比如上面的LeNet模型,我们可以将conv1、pool1、conv2、pool2进行封装,把它称为特征提取器;之后把全连接层的部分进行包装,把它称为分类器。
可以看到在LeNetSequential这个类中,使用nn.Sequential对卷积层、池化层和**函数层进行包装,再把nn.Sequential赋给features;之后再用nn.Sequential对三个全连接层进行包装,并赋给类属性classifier。
和之前一样,我们stepinto来查看一下nn.Sequential这个模块的实现细节:此外,Sequential也是继承自Module这个类的,因为是继承自Module,所以它还是会有那8个有序字典去管理它的属性。可以看到,Sequential已经有了这8个有序字典:
首先程序会判断传进来的参数是否为有序字典OrderedDict,这里不是所以程序会执行else分支,将我们传入的参数循环地取出每一个网络层,然后采用module的类方法add_module()将网络层添加到Sequential中。通过stepover循环添加网络层至Sequential中,我们可以看到modules中不断地有新网络层添加进来:接着会以同样的方式进行三个全连接层的封装,这里就不再赘述。
其中在LeNetSequential里的forward函数中每个Sequential层的调用都会自动调用nn.Sequential模块的forward函数。这样就实现了使用Sequential构建LeNet以及进行前向传播forward。以这种方式构建Sequential层每个子网络层的索引都是数字,这对于成百上千个数量的网络层构成的Sequential来说性能不高,所以下面介绍另一种构建LeNet的方式——使用OrderDict,继续使用单步调试来观察Sequential是怎样给网络层命名的:再stepover至nn.MaxPool2d处,stepinto stepout再stepinto之后,可以看到:
程序对参数进行判断,由于是OrderDict所以add_module()函数会按key,value键值对的形式对参数进行存储,这里的key就是网络层的命名。
可以看到第一个key是’conv1’,就这样不断地添加,网络层即可得到它的命名。可以看到,modules里的各个网络层现在都是已经有名称的了,之后即可根据名称去索引每一个网络层。
总结
nn.Sequential是nn.Module的容器,用于按顺序包装一组网络层:
- 顺序性:各网络层之间严格按顺序构建
- 自带forward():自带的forward里,通过for循环依次执行前向传播运算
nn.ModuleList
nn.ModuleList是nn.Module的容器,用于包装一组网络层,以迭代方式调用网络层 :
主要方法:
- append():在ModuleList后面添加网络层
- extend():拼接两个ModuleList
- insert():指定在ModuleList中位置插入网络层
我们依然stepinto,一探究竟…
可以看到,这里是使用for循环20次创建ModuleList列表。
循环20次结束之后我们stepinto,之后程序会进入到一个__init__()函数中,可以看到,这里判断传入的modules是否为空,若不为空则进行list添加。借助nn.ModuleList我们可以仅通过一行代码就可以构建一个20层的全连接网络模型。
nn.ModuleDict
nn.ModuleDict是nn.Module的容器,用于包装一组网络层,以索引方式调用网络层。
主要方法:
- clear():清空ModuleDict
- items():返回可迭代的键值对(key-value pairs)
- keys():返回字典的键(key)
- values():返回字典的值(value)
- pop():返回一对键值,并从字典中删除
这里的学习方式和前两个其实是一样的,不再进行说明介绍。接下来对上述三种nn.Module的容器进行简要总结:
- nn.Sequential:顺序性,各网络层之间严格按顺序执行,常用于block构建
- nn.ModuleList:迭代性,常用于大量重复网络构建,通过for循环实现重复构建
- nn.ModuleDict:索引性,常用于可选择的网络层
AlexNet的网络构建
AlexNet是2012年以高出第二名10多个百分点的准确率获得ImageNet分类任务冠军,开创了卷积神经网络的新时代。
AlexNet特点如下:
- 采用ReLU:替换饱和**函数,减轻梯度消失
- 采用LRN(Local Response Normalization):对数据归一化,减轻梯度消失
- Dropout:提高全连接层的鲁棒性,增加网络的泛化能力
- Data Augmentation:TenCrop,色彩修改
AlexNet结构:
同样,AlexNet模型也可被分为特征提取模块和分类器模块。AlexNet模型的代码实现:它同样采用了一个Sequential将卷积层池化层等网络层进行顺序连接,构成一个特征提取器;之后构建一个池化层;最后再根据Sequential构建一个分类器。可以看到,AlexNet模型的构建还是十分简单的。
参考资料
深度之眼训练营——Pytorch课程