文章目录
前言
笔者从人工智能小白的角度,力求能够从原文中解析出最高效率的知识。
之前看了很多博客去学习AI,但发现虽然有时候会感觉很省时间,但到了复现的时候就会傻眼,因为太多实现的细节没有提及。而且博客具有很强的主观性,因此我建议还是搭配原文来看。
请下载原文《ImageNet Classification with Deep Convolutional Neural Networks》搭配阅读本文,会更高效哦!
一、论文精读
0 摘要标题和结论
《ImageNet Classification with Deep Convolutional Neural Networks》首先,看完标题,摘要和结论,我了解到了以下信息:
- 把ImageNet数据集用监督学习的方法去训练,并利用GPU 加速,与当时前沿的技术结果进行了对比,取得了不错的分类效果。
- 把图片上倒数第二层的向量取出,然后找到给定图片在向量上比较相似的那些图片,最后发现向量值相似度高的种类图片相似度也高。即训练出来的最后的向量在语义空间的表示特别好。这点让我想到了机器学习当中的简单分离器,就可以很好的根据特征去进行分类的原因。
1.Introduction
训练数据集的方法也是先用小的数据集再过渡到ImageNet。打算用CNN,然后想办法把CNN网络做大。但是没有提到前人所做过的工作,也就是Related work。Section3会讨论文章所采用的新的网络架构。因为文章采用CNN网络架构很大,就很容易出现overfitting,于是section4会提及防止过拟合方法(我推测当时应该是讨论dropout等)。然后讨论了深度网络的必要性。
2.The Dataset
创新性的点在于端到端(End-to-End)。
3.The Architecture
- 提出了非饱和型非线性层ReLu比饱和型线性层sigmoid,tanh快很多。(这个观点在现在看来其实是不那么正确的,现在我们还在用ReLu层,可能是因为ReLu比较简单。)
- 多个GPU做训练,如何分开网络。
- 正则归一化。用Normalization避免饱和。(存疑)
- 对传统Pooling进行了改动,效果不错。
- 整个架构由5个卷积层,3个全连接层,最后用了一个softmax。输入的是原始的图片,2242243。用两个GPU 训练,在第三个卷积层进行了输出通道合并。随着层数增多,卷积层大小在减小,意味着空间信息在压缩,但增加了通道数,提高了对特定模式的识别。最后一张图片会表示成4096维度的向量,这个向量有很好的语义信息,再用线性分类去做链接。(让我想到深度学习的精髓就在于,把人能看到的信息进行压缩,最后变成机器能够识别的一种模式,再利用这种模式去进行应用操作。)
(我认为这个架构没有很好的通用性,实现比较复杂,架构限制了就是使用两个GPU去切片,而与实际上出入可能比较多。除非真的遇到非常大的模型比如BERT)
4.Reducing Overfitting
- 数据增强:两种方法。第一种是人工抠出图片的一部分,然后再放大抠出来的图片。第二种是改变颜色通道,用的是主成分分析(PCA)(我想起,这个方法在遥感影像里面用的也比较多。)
- Dropout:随机把一些隐藏层变成50%概率设为0。更像是一个正则的效果。(把Dropout放在了前两个全连接上面,所以训练速度会别其他模型慢两倍。而且这么大的全连接,导致GPU放不进去,这个地方其实我认为是一种设计缺陷。)
5.Details of learning
- 优化器:选择的是SGD,其噪声能够很好地提高模型的泛化能力。并采用momentum,防止在local minima时,model就走不动了。
- 采用了权重衰减L2正则项(weight decay)
- 权重初始化:0+0.01高斯分布。
- 动态调整learning rate:走不动就降低十倍。(现在主流做法可能是先从小值开始,然后先变大,再变小,因为前期太小的话可能会出现比较明显的震荡,后期太大又会卡住。)
二、代码阅读
1.卷积层
class AlexNet(nn.Module):
def __init__(self,num_classes=2):
super(AlexNet, self).__init__()
self.features=nn.Sequential(
nn.Conv2d(3,48, kernel_size=11),
nn.ReLU(inplace=True),
nn.MaxPool2d(kernel_size=3,stride=2),
nn.Conv2d(48,128, kernel_size=5, padding=2),
nn.ReLU(inplace=True),
nn.MaxPool2d(kernel_size=3,stride=2),
nn.Conv2d(128,192,kernel_size=3,stride=1,padding=1),
nn.ReLU(inplace=True),
nn.Conv2d(192,192,kernel_size=3,stride=1,padding=1),
nn.ReLU(inplace=True),
nn.Conv2d(192,128,kernel_size=3,stride=1,padding=1),
nn.ReLU(inplace=True),
nn.MaxPool2d(kernel_size=3,stride=2),
)
2.全连接层
self.classifier=nn.Sequential(
nn.Linear(6*6*128,2048),
nn.ReLU(inplace=True),
nn.Dropout(0.5),
nn.Linear(2048,2048),
nn.ReLU(inplace=True),
nn.Dropout(),
nn.Linear(2048,num_classes),
)
3.数据增强
def DataEnhance(sourth_path,aim_dir,size):
name=0
#得到源文件的文件夹
file_list=os.listdir(sourth_path)
#创建目标文件的文件夹
if not os.path.exists(aim_dir):
os.mkdir(aim_dir)
for i in file_list:
img=Image.open('%s\%s'%(sourth_path,i))
name+=1
transform1=transforms.Compose([
transforms.ToTensor(),
transforms.ToPILImage(),
transforms.Resize(size),
])
img1=transform1(img)
img1.save('%s/%s'%(aim_dir,name))
代码整体架构算是比较简单,通过PyTorch搭建的代码,整体比较典型。