《ImageNet Classification with Deep Convolutional Neural Networks》
–《基于深度卷积神经网络的ImageNet分类》(中文名 )
目录
《ImageNet Classification with Deep Convolutional Neural Networks》
一、论文阅读方法
1.翻译工具
2.阅读方法
二、论文的主要内容及框架概述:
1.摘要 (Abstract)
2.引言 (Introduction)
3. 研究背景(Background)
4.数据集 (The Dataset)
5.架构 (The Architecture)
6.减少过拟合 (Reducing Overfitting)
7.学习细节 (Details of learning)
8.结果 (Results)
9.定性评估 (Qualitative Evaluations)
10.总结(summary)
参考文献 (References)
三、论文复现(Colab+Keras)
基本信息:
标题:ImageNet Classification with Deep Convolutional Neural Networks
时间:2012
出版源:Neural Information Processing Systems (NIPS)
论文领域:深度学习,计算机视觉
引用格式:Krizhevsky A, Sutskever I, Hinton G E. Imagenet classification with deep convolutional neural networks[C]//Advances in neural information processing systems. 2012: 1097-1105.
链接: https://dl.acm.org/doi/10.5555/2999134.2999257
这篇论文的标题是《ImageNet Classification with Deep Convolutional Neural Networks》,作者是 Alex Krizhevsky、Ilya Sutskever 和 Geoffrey E. Hinton,来自多伦多大学。这篇论文在深度学习和计算机视觉领域具有里程碑意义,因为它介绍了一种深度卷积神经网络(CNN),该网络在 ImageNet LSVRC-2010 大规模图像识别竞赛中取得了突破性的成绩。
一、 论文阅读方法
由于目前翻译工具在专业领域翻译中存在的局限性主要包括以下几个方面:
- 专业术语理解不准确:翻译工具在处理专业领域的术语时,往往无法准确理解其含义,导致翻译结果不准确或不通顺。
- 文化背景差异:翻译工具无法完全理解不同文化背景下的语言表达方式,容易导致翻译结果与原文意思不符。
- 语法结构不准确:翻译工具在处理复杂的句子结构或语法规则时,往往无法准确理解其逻辑关系,导致翻译结果不通顺或不连贯。
我们综合运用一下几个翻译工具,同时结合人工校对等方法来更加完善对此篇论文报告阅读
1.翻译工具
1.kimi.ai
2.沉浸式网页翻译插件
3.网易有道翻译
- 沙拉查词-聚合词典划词翻译
2.阅读方法
二、论文的主要内容及框架概述:
1.摘要 (Abstract)
论文描述了他们训练的深度卷积神经网络,该网络能够对 ImageNet 数据集中的 1.2 百万高分辨率图像进行分类,这些图像被分为 1000 个不同的类别,是一个典型的有监督学习多分类问题。
论文中神经网络由卷积层、最大池化层和全连接层组成,激活函数采用了当时全新的Relu,最后使用1000路的softmax作为分类输出,并且使用了“dropout”正则化方法来避免过拟合。
他们在测试数据上取得了 top-1 和 top-5 的错误率分别为 37.5% 和 17.0%,这显著优于之前的最佳水平。
论文还提到了他们使用的技术和方法,包括非饱和神经元、高效的 GPU 实现、以及一种称为“dropout”的正则化方法。
2.引言 (Introduction)
首先,介绍了训练大量图片数据集的挑战性,自身实验需要用到大量图片数据,以及使用卷积神经网络的优势(CNN):与标准的前馈神经网络相比,拥有更少的参数和连接层,并且在二维上更好的保留图片的特征信息,也会更好训练(其实我并不是很理解卷积网络在深度上的优势,感觉这里没解释清楚,只能说明此结构的CNN在这个任务中表现良好)。
其次,作者介绍了本论文使用的网络以及提出的新计算特性。文中使用的方法用到了专门研究的为GPU计算使用的算法,提高了图像卷积计算的效率,并且降低了功耗和训练时间。由于网络的规模,作者采用了专门的方法解决过拟合问题。最终网络结构由5个卷积层和3个全连接层组成,并且作者提出:网络的规模和能力被GPU内存所限制,如果有更大内存的GPU和更多可用的数据集,可以在更复杂的网络上实现更加强大的功能。
3. 研究背景(Background)
传统的物体识别方法依赖于机器学习技术,但受限于数据集的大小和多样性。为了提高识别性能,研究者们转向了更大规模的数据集,如 ImageNet,它包含了超过 1500 万张标记图像。
4.数据集 (The Dataset)
论文描述了 ImageNet 数据集的构成,包括其图像来源、类别数量以及如何为 ILSVRC 准备数据集。
ImageNet:120万张训练图像,50000张验证图像和150000张测试图像,共约1000个类别的高分辨率图片。
ILSVRC:ILSVRC竞赛中唯一可以获得测试集标签的版本,文中模型报告了top-1和top-5(正解不在前五种最认可的标签里)两种rate。
对于ImageNet数据集,需要对分辨率不确定的图片进行预处理,文中统一缩放成了256*256的图片。另外对图像进行的唯一预处理就是在每个像素上减去训练集的均值。(像素去均值化是图像标准化的一种手段,可以移除掉图像中的平均亮度值,因为我们不关心图像本身的亮度。此外,研究表明去均值处理可以更加突出主要目标的轮廓等特征,如下图所示,天空纹理被去除了,汽车的轮廓则更明显。但是请注意,无论何种预处理,都只能用于训练集数据,绝不能用于测试集数据。)
5.架构 (The Architecture)
5.1 ReLU Nonlinearity(线性整流激活函数Relu)
这是作者认为网络中最重要的一环,使用的Relu激活函数。文中通过实验证明在同样的模型训练中,非饱和线性Relu的效率要高于饱和线性tanh函数(效率指达到相同准确率需要的epoch数量)。文中还强调更快的训练对于大的数据集和模型都是很大的积极作用的。
图表 1Relus-实线,tanh-虚线 实验网络-四层卷积网络
网络体系架构:共计8个学习层:5个卷积层和3个全连接层
• 该网络层包括8层权重,有五个卷积层和三个全连接层,最后通过 1000 路 softmax 输出分类概率。
• 引入了局部响应归一化(LRN)和重叠池化技术,增强了网络的泛化能力。
首先输入的是一张2242243(因为是彩色RGB三通道的图)
第一层用的卷积核的大小是 11∗11∗3 ,卷积核的个数是48+48=96,从这一层开始两个GPU开始分开运行,现在定义处理上半层特征图的叫GPU_A,处理下半层特征图的叫GPU_B,每个GPU负责48个卷积核的运算,上半层GPU_A生成48张特征图,下半层GPU_B生成48张特征图。这一层卷积结束之后,还需要LRN(Local Response Normalization 局部响应归一化)和Max_Pooling(最大池化)
第二层和第一层同理,两个GPU分别处理自己上一层传来的output(那48张特征图),卷积核的大小是 5∗5∗48 ,然后一共有128+128=256个卷积核,所以两个GPU各自利用自己上一层的output生成128张特征图。这一层的卷积结束之后还需要LRN(Local Response Normalization 局部响应归一化)和Max_Pooling(最大池化)
第三层和前两层不同,这一层两个GPU都要是将两个GPU的上一层的全部输出output作为输入input,所以这一层的卷积核大小是 3∗3∗ (128[来自GPU_A]+128[来自GPU_B]),也就是这层的卷积核是 3∗3∗256 ,而不是像前两层那样只是把自己上一层的输出当成输入,这层一共有192+192=384个卷积核,GPU_A负责前192个卷积核的生成的特征图,GPU_B负责后192个卷积核生成的特征图。
第四层和第五层同第二层。
关键来了,这里看图是接了一个全连接层(FC),首先将128[来自GPU_A]和128[来自GPU_B]的一共256张特征图拉直成一个超长的向量,连接到一个大小为4096的全连接层中,其中4096个神经元的前2048个神经元由GPU_A运算,后2048个神经元由GPU_B来运算。
第七层和第六层同理。
第八层是再连接到一个大小为1000的全连接层中,用softmax,来算1000种分类的分布。
5.2多GPU部署
双GPU主要原因是当时受到硬件技术所限,所使用的GTX580只有3G内存,一块不足以支撑训练足够大的网络。但是好在显卡支持不同GPU之间直接访问内存,这就提供了并行训练的可能性。作者使用了两块GPU进行训练,每一块分别占有网络一半的kernel,且GPU之间只在特定的层进行通信,如特定层之间发送输入或输出数据才会进行通信。实践表明这样做不仅缩短了训练时间,而且小幅提升了最终的识别准确率(降低了错误率)
5.3 局部响应归一化
Relu无需规范化输入,但是规范化有助于泛化,也有助于提升准确率。
其中, 𝑎𝑥,𝑦𝑗 ,是第j个通道上 x,y 位置上的ReLU激活值。n,k,α,β都是超参数,根据一组validation set得到n=5,k=2,α=10−4,β=0.75,N是这个feature map总的通道个数。这里就是之前提到的“亮度去均值标准化”的过程。并且在实际数据集和额外测试数据集上,都证明这种局部响应规范化能带来更低的错误率。
加入这个机制的最初目的是,模仿真实神经元的侧抑制机制(lateral inhibition),提高网络的泛化能力。实际上,此机制能使top 1/5错误率下降了1.4/1.2%。经过此机制修正后,ReLU的正数部分也有类似于饱和非线性函数的曲线。ReLU+Local Response Normalization的输出,类似于真实神经元的电位发放的表现。
图表 2Relu+Local Response NOrmalization输出类似饱和非线性函数曲线
5.4重叠 pooling
在最大池化的基础上进行重叠池化, 这样和传统池化做法比信息压缩量小,信息丢失也就少,而且实验证明可以更好的避免过拟合。在文中也提到降低了错误率。
5.5 总体结构
介绍了网络中具体的层结构和层之间的规范化、数据传递的信息,具体可见结构图。
6.减少过拟合 (Reducing Overfitting)
6.1数据增强
大规模网络过拟合是正常现象,数据增强是常用的解决手段。
1、图像平移和水平翻转,从256256图像随机裁出224224图像,数据集扩展2048倍(但是扩展出来的图像都是高度依赖的)。
2、加全局调整,对整个训练集做PCA来取得RGB值的主要特征(改变RGB通道的强度),然后对输入进行主要特征的σ=0.1的高斯扰动。实际上相当于对图片的强度进行小范围调整。
每张图片的像素通道通过以下公式重新计算,并且每当再次用到这张图片时会重新计算。
该方案近似地捕捉了自然图像的一个重要特性,即物体的特性不因光照强度和颜色的变化而改变。
6.2Dropout
(a)标准神经网络 (b)运用后dropout后的神经网络
每个隐藏神经元输出时有一定的概率被赋值为0,在网络中就不在有贡献,也不会参与误差反向传播过程。本文中该概率选择的是0.5。神经元在随机被dropout的情况下学习的数据也是随机的,但是共享weights。因此网络的学习结果更具健壮性,也就解决了过分学习图像特征造成过拟合的现象。
forward/前向过程:可以看到神经元失活是先随机初始化一个与当前层规模一样的mask,然后根据mask中每个元素的随机值(介于0到1之间),将小于dropoutFraction的元素设置为0,其余为1,得到dropOutMask。再将该层的所有激活值与dropOutMask进行点乘,得到结果。
backward/反向过程:backprop回来的所在层的derivatives乘以对应层的dropOutMask。
test过程:所有神经元参与计算,但是每个元素值乘以(1-dropOutFraction),作为没有被dropout的比率被留下的值(这个过程我不理解什么意思,应该是为了让test的测试数据和训练时的forward保持一致)。
7.学习细节 (Details of learning)
• 权重初始化:每层权重根据均值为0标准差为0.01的高斯分布初始化,第二、第四、第五层卷积和全连接层的bias初始化为常数1,剩下所有层的bias初始化为0。这种初始化有助于早期阶段正样本的学习的加速;
• 优化算法:小批量梯度下降;
• 权重优化:
i是迭代次数,v是动量, 𝜖 是learning rate,后者是目标函数关于权重的偏导数,基于第i个batch的平均值。
• learning rate:0.01,所有层使用一样的初始学习率。训练过程中如果val-error不降低,那么就会对learning rate除以10。训练总共跑了90个epochs,3次因为val-error不降低调整学习率。
• epoch:90。(两块GTX580跑了5、6天)。
8.结果 (Results)
• 在 ILSVRC-2010 上取得了 top-1 错误率 37.5% 和 top-5 错误率 17.0% 的优异成绩。
• 在 ILSVRC-2012 比赛中,通过模型集成进一步降低了错误率,达到了 15.3%。
9.定性评估 (Qualitative Evaluations)
其实训练好的网络本身就可以当做特征提取器,比方下面图右侧,就是跑了网络得出 softmax 前的feature map,然后对其他所有图与给定的图计算欧氏距离,得到最近的 6 张图(这一方法在人证比对之类的场景用的比较多)。每一行第一个是给出的图,这一行剩下的6个是其他feature map与第一张图最近的6张。
10.总结(summary)
作者最后提出了观望,表示在自己的成果种网络的结构至关重要,多一层或少一层都不行。但实际上,尽管卷积神经网络的深度确实重要,也需要权衡算力和深度之间的关系。整篇论文偏工程方向,但是在当时能写出这个网络就是划时代意义的,有很多值得我学习和借鉴的地方。
另外,结合他人博客学习,发现这个网络在最终softmax的输出前,实际上可以做一个可视化物品比对的分析器,或相似物品比对之类的可视化展示。
论文总结了大型深度卷积神经网络在纯监督学习下取得的成果,并讨论了网络深度对于性能的重要性以及未来的研究方向。
本论文展示了深度卷积神经网络在大规模图像分类任务中的潜力,为未来的研究和应用奠定了基础。通过创新的训练技术和网络架构设计,作者们不仅推动了图像识别领域的发展,也为深度学习的其他应用提供了宝贵的经验。
三、论文复现(Colab+Keras)
Colab(全称:Colaboratory)可以理解为是一款搭载在Google云端硬盘上的网页版软件,主要用于python的机器学习。它的优点主要在于可以向用户免费提供GPU,以便程序编写、模型和网络训练及测试。Colab所在环境与Linux系统下的环境基本相同(在编程方面Linux稳定性比Windows要好)
3.1.1几个注意点
第一:最好在Google浏览器上进行Colab操作,其他浏览器我没试过。
第二:,GPU在30分钟内不操作时容易掉线,所以要经常查看自己的程序是否在工作。
第三:每天好像只能用12小时,这个我没亲身实践过,因为我还没有训练过超过12小时的模型
3.2 部署教程
从Google云端硬盘到Colab——简便入门教程 - 知乎 (zhihu.com)
3.2.1 部署前准备
云端硬盘向新用户提供15G的存储空间。一般而言15G存储空间已经可以满足日常使用,如需更大空间需要进行购买。
在使用Colab过程中,GPU是随机分配的,RAM大概能分到12G,磁盘能分配到30G以上。这对有兴趣做机器学习而又经费不足的研究人员而言,无疑是一个巨大的帮助。
Colab是在Google浏览器网页上进行操作的,在操作之前需要一款能够“科学上网”的浏览器插件或者电脑软件,帮助你顺利实现接下来的操作。
在一切装备妥当之后,我们就顺利的正式开始第2个环节。
3.2.2Google云端硬盘如何关联Colab
完成以上步骤,现在Colab能够享用Google云端硬盘的空间了。
现在已经建立好了一个Colab文件
红色圈,可以改变python的名称,绿色圈,点击连接,就可以连接到云端进行计算,不过此时的连接并不是在GPU环境下工作。
GPU环境修改:
注:这里也有谷歌去年新出的TPU谷歌的张量处理器(Tensor Processing Unit),感兴趣的同学可以试试
CPU即中央处理器(Central Processing Unit)
GPU即图形处理器(Graphics Processing Unit)
TPU即谷歌的张量处理器(Tensor Processing Unit)
NPU即神经网络处理器(Neural network Processing Unit)
….详细的自己可以去了解一下
点击连接,就就能进入GPU环境下,如下图
3.2.3正式部署开始
改变Colab的工作路径
1.首先在你的Google云盘上新建一个文件夹用来存放你的代码
- 然后在文件夹内新建一个colab的 Jupyter notebook
- 之后我们打开它,开始我们的代码之旅
3.3代码复现
1.新建一个代码块,输入下面的代码
!apt-get install -y -qq software-properties-common python-software-properties module-init-tools
!add-apt-repository -y ppa:alessandro-strada/ppa 2>&1 > /dev/null
!apt-get update -qq 2>&1 > /dev/null
!apt-get -y install -qq google-drive-ocamlfuse fuse
from google.colab import auth
auth.authenticate_user()
from oauth2client.client import GoogleCredentials
creds = GoogleCredentials.get_application_default()
import getpass
!google-drive-ocamlfuse -headless -id={creds.client_id} -secret={creds.client_secret} < /dev/null 2>&1 | grep URL
vcode = getpass.getpass()
!echo {vcode} | google-drive-ocamlfuse -headless -id={creds.client_id} -secret={creds.client_secret}
- 两次验证,输入指定的密码,完成验证。 然后新建一个代码块,改变工作路径
!mkdir -p drive
!google-drive-ocamlfuse drive
import os
import sys
os.chdir('gdrive/AlexNet_keras')
- 如果你完全严格按照我的步骤os.chdir(‘ghdrive/AlexNet_keras’),就和我输一样的代码,如果你的文件名不是起的AlexNet_keras,这里改成你自己起的文件名。
Keras AlexNet 代码
- import 用到的包,设置超参数
import keras
from keras.datasets import cifar10
from keras import backend as K
from keras.layers import Input, Conv2D, GlobalAveragePooling2D, Dense, BatchNormalization, Activation, MaxPooling2D
from keras.models import Model
from keras.layers import concatenate,Dropout,Flatten
from keras import optimizers,regularizers
from keras.preprocessing.image import ImageDataGenerator
from keras.initializers import he_normal
from keras.callbacks import LearningRateScheduler, TensorBoard, ModelCheckpoint
num_classes = 10 #分成多少类
batch_size = 64 # 一个batch用64张图
iterations = 782 #一个epoch用782个batch
epochs = 300 #一共循环300个epoch
DROPOUT=0.5 # 每个神经元以50%的概率失效
CONCAT_AXIS=3
weight_decay=1e-4
DATA_FORMAT='channels_last' # Theano:'channels_first' Tensorflow:'channels_last'
log_filepath = './alexnet' #tensorbroad的文件储存的路径
- 数据预处理并设置学习率的变换规律
def color_preprocessing(x_train,x_test):
x_train = x_train.astype('float32')
x_test = x_test.astype('float32')
mean = [125.307, 122.95, 113.865]
std = [62.9932, 62.0887, 66.7048]
for i in range(3):
x_train[:,:,:,i] = (x_train[:,:,:,i] - mean[i]) / std[i]
x_test[:,:,:,i] = (x_test[:,:,:,i] - mean[i]) / std[i]
return x_train, x_test
def scheduler(epoch):
if epoch < 100:
return 0.01
if epoch < 200:
return 0.001
return 0.0001
# load data
(x_train, y_train), (x_test, y_test) = cifar10.load_data()
y_train = keras.utils.to_categorical(y_train, num_classes)
y_test = keras.utils.to_categorical(y_test, num_classes)
x_train, x_test = color_preprocessing(x_train, x_test)
- 搭建网络
按照上面这张图来设置我们的网络
def alexnet(img_input,classes=10):
x = Conv2D(96,(11,11),strides=(4,4),padding='same',
activation='relu',kernel_initializer='uniform')(img_input)# valid
x = MaxPooling2D(pool_size=(3,3),strides=(2,2),padding='same',data_format=DATA_FORMAT)(x)
x = Conv2D(256,(5,5),strides=(1,1),padding='same',
activation='relu',kernel_initializer='uniform')(x)
x = MaxPooling2D(pool_size=(3,3),strides=(2,2),padding='same',data_format=DATA_FORMAT)(x)
x = Conv2D(384,(3,3),strides=(1,1),padding='same',
activation='relu',kernel_initializer='uniform')(x)
x = Conv2D(384,(3,3),strides=(1,1),padding='same',
activation='relu',kernel_initializer='uniform')(x)
x = Conv2D(256,(3,3),strides=(1,1),padding='same',
activation='relu',kernel_initializer='uniform')(x)
x = MaxPooling2D(pool_size=(3,3),strides=(2,2),padding='same',data_format=DATA_FORMAT)(x)
x = Flatten()(x)
x = Dense(4096,activation='relu')(x)
x = Dropout(0.5)(x)
x = Dense(4096,activation='relu')(x)
x = Dropout(0.5)(x)
out = Dense(classes, activation='softmax')(x)
return out
- 生成模型
img_input=Input(shape=(32,32,3))
output = alexnet(img_input)
model=Model(img_input,output)
model.summary()
再次看下网络结构和参数量
5. 训练模型
梯度下降的方法用了SGD随机梯度下降,并且用了momentum。 数据增强用了注释里的方法
# set optimizer
sgd = optimizers.SGD(lr=.1, momentum=0.9, nesterov=True)
model.compile(loss='categorical_crossentropy', optimizer=sgd, metrics=['accuracy'])
# set callback
tb_cb = TensorBoard(log_dir=log_filepath, histogram_freq=0)
change_lr = LearningRateScheduler(scheduler)
cbks = [change_lr,tb_cb]
# set data augmentation
datagen = ImageDataGenerator(horizontal_flip=True,
width_shift_range=0.125,
height_shift_range=0.125,
fill_mode='constant',cval=0.)
#horizontal_flip=True Randomly flip inputs horizontally. 随机翻转
# width_shift_range=0.125 水平平移,相对总宽度的比例
#height_shift_range=0.125 垂直平移,相对总高度的比例
#fill_mode='constant',cval=0 'constant': kkkkkkkk|abcd|kkkkkkkk (cval=k) 平移完用0来填充
datagen.fit(x_train)
# start training
model.fit_generator(datagen.flow(x_train, y_train,batch_size=batch_size),
steps_per_epoch=iterations,
epochs=epochs,
callbacks=cbks,
validation_data=(x_test, y_test))
model.save('alexnet.h5')
根据我的实战,如果用Colab会出现以下这种情况
先给出结论,这个报错并不会影响实验的结果,它只是不能在这个页面上显示接下来轮次的loss,acc,val_loss,val_acc,如果想避免这个报错
这个verbose,是model.fit_generator()中的参数,加上应该就可以了,但是我没实操过,大家可以试试。
6.实验结果
下载里面对应的文件
假设我们将文件放到桌面一个log的文件夹
在Chrome上输入上面的网址,我这里是http://127.0.0.1:6006
然后就能看到我们的可视化训练过程了
我们可以看到120个epoch的时候就开始过拟合了,我们模型的准确率维持在75.5%左右。