小白的经典CNN复现(三):AlexNet (4)

这个图就看起来很舒服了,不仅告诉你每一个卷积层的卷积核大小以及通道数,而且连输出的图片尺寸是咋算出来的都告诉了,阅读体验极佳,当然这个图的出处我会放在最后,大家可以去原博客里面去看一下。

网络的大致结构已经放在这里了,那接下来我们就对每一个模块进行一个简单的介绍吧。由于原论文中并没有对每一个层进行命名,因此我们按照下面的方式对模型的每一层进行命名:

所有的卷积层以C开头,后面的数字表示第几个卷积层,比如C3是第三个卷积层,并且不代表这是网络的第三层

所有的池化层以S开头,数字的含义同上

所有的全连接层以F开头,数字含义同上

所有的LRN标准化层以N开头,数字含义同上

命名方式搞定,下面我们来看一下每一个层的具体结构吧

C1层

之前我们提到过,输入图片的实际尺寸是[3, 224, 224]。并且在论文中提到,在作卷积的时候使用的卷积核的尺寸是11,虽然没有说明使用这个尺寸的目的,但是大致来看目的是在于让C1层能够尽可能地提取到足够的信息,从而让之后的卷积层能够提取到足够的组合信息。并且论文中提到,使用的移动步长stride为4,这一步长恰好使得感受野之间的距离也恰好是4。这样选取的目的在论文中并没有提及,在我看来有两个目的:首先是采用较大的步长,这样在卷积核较大的条件下依然可以保持一个较小的计算量,并且尽量降低输出特征图的尺寸;其次,采取较大的步长,使得卷积核取得的特征之间重叠较少,更有利于之后的处理获得更加多样的特征。

关于C1层的输出特征图的尺寸,从论文中给出的图解来看应该是55×55,结合卷积核的尺寸和步长,卷积使用的padding = 2,输出的特征图的channel数应该是96。

因此综合来看,在C1层使用的参数应如下:

in_channels: 3

out_channels: 96

kernel_size: 11

stride: 4

padding: 2

卷积层由于Pytorch已经提供了类供我们调用,因此在这里就不附代码了。但是在这里需要注意的是,论文里提到在C1层会进行初始化处理,初始化的方法为:

权重:使用均值为0,标准差为0.01的正态分布进行随机采样

偏置:全部设置为0

关于权重的初始化问题,由于论文中指定的参数初始化方法是需要满足N(0, 0.01^2),而之前我们使用的randn是满足的N(0, 1)的标准正态分布,为了能够让初始化的参数满足我们的要求,我们需要使用另一个初始化的函数:

torch.normal(mean, std)

这个函数的mean和std最好是tensor,随机生成的tensor的维度和mean以及std的维度一致,并且每一个元素都是满足对应位置的N(mean, std^2)的分布。

举个例子:

a=torch.normal(torch.tensor([0,1,2], torch.tensor([1,1,1])))

那么a[0] ~ N(0, 1),a[1] ~ N(1, 1),a[2] ~ N(2, 1)

论文提到,所有的权重都是一样的设置,所以我们可以之后整体用一个函数遍历,但是偏置的问题,好几个层是0,好几个层是1(作者是真的事多┓(\'∀\')┏),所以我们将偏置的设置放在C1层的定义之后:

self.C1.bias.data = torch.zeros(self.C1.bias.data.size())

关于这样的定义方式其实我们早就接触过很多了,只不过之前我们的写的时候使用一个循环,而且设置的不是偏置(bias)而是权重(weight),所以相关的内容建议大家看一下我的LeNet-1989这篇博客,里面对这个代码的含义有简单的介绍。

论文里说明,在C1层之后使用ReLU作为激活函数,关于这个激活函数的特点,将在后面的章节中简单解释,在这里就不啰嗦啦。

顺便提一下,经过C1层之后,特征图的尺寸为[96, 55, 55]

N1层(LRN)

由于激活函数使用的是ReLU函数,这个函数是没有上界的,这很有可能导致最后通过激活函数输出的数据分布过于极端。与此同时,论文的作者发现,对数据进行Normalize处理将有利于提高模型的泛化性能,降低过拟合的风险。所以在论文中作者提出了一个标准化方法,就是这里的LRN了。标准化使用的计算方法如下所示:

\[b^i_{x,y}=a^i_{x,y}/(k+{\alpha}\sum^{min(N-1,i+n/2)}_{j=max(0,i-n/2)}(a^j_{x,y})^2)^{\beta} \]

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zzxyjy.html