BasicModule
程序实现的时候所有模型继承自定义的basicmoudle,主要重写了模型加载和保存等方法
1 import torch 2 from config import opt 3 class BasicModule(torch.nn.Module): 4 def __init__(self): 5 super(BasicModule,self).__init__() 6 #self.model_name = str(type(self)) 7 8 def save(self,path=None): 9 if path is None: 10 path = 'checkpoints/'+opt.model+'_'+'model.pth' 11 torch.save(self.state_dict(),path) 12 def load(self,path): 13 self.load_state_dict(torch.load(path),strict = False)
Lenet5
这个是n多年前就有的一个CNN的经典结构,主要是用于手写字体的识别,也是刚入门需要学习熟悉的一个网络,引入cnn做图像处理,使用全连接做分类。
- 输入尺寸:32*32
- 卷积层:2个
- 降采样层:2个
- 全连接层:3个
- 输出:10个类别(数字0-9的概率
- 总参数:122304
1 class LeNet5(nn.Module): 2 def __init__(self): 3 super(LeNet5,self).__init__() 4 self.conv1 = nn.Sequential(nn.Conv2d(3,6,5,1,0),nn.ReLU(),nn.MaxPool2d(2,2)) 5 self.conv2 = nn.Sequential(nn.Conv2d(6,16,5,1,0),nn.ReLU(),nn.MaxPool2d(2,2)) 6 self.fc1 = nn.Sequential(nn.Linear(400,120),nn.BatchNorm1d(120),nn.ReLU()) 7 self.fc2 = nn.Sequential(nn.Linear(120,84),nn.BatchNorm1d(84),nn.ReLU()) 8 self.fc3 = nn.Sequential(nn.Linear(84,10),nn.BatchNorm1d(10),nn.ReLU()) 9 10 def forward(self,x): 11 x = self.conv1(x) 12 x = self.conv2(x) 13 x = x.view(x.size(0),-1) 14 #print(x.size()) 15 x = self.fc1(x) 16 x = self.fc2(x) 17 x = self.fc3(x) 18 return x
AlexNet
AlexNet可以说是LeNet的继承和发展,AlexNet具有6000万个参数和65万个神经元的神经网络由五个卷积层和三个全连接层,以及最后的1000维的softmax层组成. ImageNet上测试的结果表明,AlexNet比(论文发表时的)以前所有的网络的性能都要高,而且需要的训练时间更少。下面简单分析AlexNet的创新点,并探讨它们是如何影响性能的: 1)将ReLU代替sigmoid作为CNN的激活函数,并验证了ReLU在较深的网络里性能优于sigmoid,有效解决了sigmoid引起的梯度弥散的问题。而且ReLU比sigmoid的学习速度更快,节省训练时间。 2)多GPU训练,由于以前的GPU内存(GTX580内存为3G)较小,这限制了可以在其上训练的网络的最大尺寸。AlexNet将网络分布在两个GPU上,而在训练时GPU仅在特定的层间进行通信,从而减少性能消耗。
与在单个GPU上训练且每个卷积层的内核数量少一半的网络相比,这个方案分别将top-1和top-5的错误率分别降低了1.7%和1.2%。双GPU网络的训练时间比单GPU网络的训练时间少一点。 3)提出LRN局部响应归一化(用于ReLU后),不同的内核计算的神经元输出之间产生对大激活度的竞争,使得局部较大的响应值更大,而小的会变得更小,从而抑制了小的神经元,增强模型的泛化能力。
响应归一化将top-1和top-5的错误率分别降低了1.4%和1.2%。 4)使用重叠的最大池化代替平均池化,避免平均池化造成的模糊化效果。而且Alexnet中的步长比池化核的尺寸要小,池化层的输出间会有重叠,这样使特征能表现更多的内容,提高识别性能。
这个方案将top-1和top-5的错误率分别降低了0.4%和0.3%。通常在训练期间观察到重叠池模型稍微难以过度拟合。
5)Dropout即以0.5的概率把每个隐藏的神经元的输出设置为零。以这种方式“dropout”的神经元不参与正向传递,也不参与反向传递。所以每次提交输入时,神经网络都采样不同的体系结构,但是所有这些体系结构共享权重。
这种技术减少了神经元的复杂的共同适应,因为神经元不能依赖于特定的其他神经元的存在。注意dropout大致使收敛所需的迭代次数翻倍。 6)数据增强。因为Alexnet的参数量巨多,容易造成过拟合,通过截取,平移,翻转还有RGB像素值集上做PCA(对于每个训练图像,成倍增加已有的主成分)等方法使得数据集更丰富,从而提高泛化能力。
从原始图像生成变换的图像是在CPU上的Python代码中生成的,而GPU正在训练上一批图像,这节约了时间。
- 输入尺寸:224*224
- 卷积层:5个
- 降采样层:3个
- 全连接层:3个
- 输出:10个类别(数字0-9的概率
-
1 #coding:utf8 2 from torch import nn 3 from .BasicModule import BasicModule 4 5 class AlexNet(BasicModule): 6 ''' 7 code from torchvision/models/alexnet.py 8 结构参考 <https://arxiv.org/abs/1404.5997> 9 ''' 10 def __init__(self, num_classes=2): 11 12 super(AlexNet, self).__init__() 13 14 self.model_name = 'alexnet' 15 16 self.features = nn.Sequential( 17 nn.Conv2d(3, 64, kernel_size=11, stride=4, padding=2), 18 nn.ReLU(inplace=True), 19 nn.MaxPool2d(kernel_size=3, stride=2), 20 nn.Conv2d(64, 192, kernel_size=5, padding=2), 21 nn.ReLU(inplace=True), 22 nn.MaxPool2d(kernel_size=3, stride=2), 23 nn.Conv2d(192, 384, kernel_size=3, padding=1), 24 nn.ReLU(inplace=True), 25 nn.Conv2d(384, 256, kernel_size=3, padding=1), 26 nn.ReLU(inplace=True), 27 nn.Conv2d(256, 256, kernel_size=3, padding=1), 28 nn.ReLU(inplace=True), 29 nn.MaxPool2d(kernel_size=3, stride=2), 30 ) 31 self.classifier = nn.Sequential( 32 nn.Dropout(), 33 nn.Linear(256 * 6 * 6, 4096), 34 nn.ReLU(inplace=True), 35 nn.Dropout(), 36 nn.Linear(4096, 4096), 37 nn.ReLU(inplace=True), 38 nn.Linear(4096, num_classes), 39 ) 40 41 def forward(self, x): 42 x = self.features(x) 43 x = x.view(x.size(0), 256 * 6 * 6) 44 x = self.classifier(x) 45 return x
VGG16
一、简述
VGG卷积神经网络是牛津大学计算机视觉实验室参加2014年ILSVRC(ImageNet Large Scale Visual Recognition Challenge)比赛的网络结构,为了解决ImageNet中的1000类图像分类和定位问题。实验结果是VGGNet斩获了2014年ILSVRC分类第二,定位第一,分类第一是GoogleNet模型。
想要更好的理解和掌握VGG系列的模型,建议阅读原论文:VGG论文链接
二、模型结构
下图是VGGNet系列的结构说明,其中最著名的是VGG16模型,下图就是VGGNet系列,从11层到19层
VGG16总参数为总计:138357544个
上图是VGGNet系列的结构说明,其中最著名的是VGG16模型,也就是上图中的D结构。
VGG16输入尺寸变化具体如下图所示:
从上述两个图可以得到,VGG16共有16个层,这也是VGG16名称的由来,是一个相当深的卷积神经网络。VGG各种级别的结构都采用了5段卷积,每一段有一个或多个卷积层。同时每一段的尾部都接着一个最大池化层来缩小图片尺寸。每一段内的卷积核数量一致,越靠后的卷积核数量越多 64-128-256-512-512。经常出现多个完全一样的卷积层堆叠在一起的情况。
三、深入理解VGG16模型 作者在学习VGG16模型的时候,上网查找了很多关于VGG16模型的文章,但是感觉大家都只是在介绍VGG16模型本身的结构而已,至于为什么要这样设计似乎很少有人提及,所以作者一直都是一知半解的,对于想要更好的理解和掌握VGG16,甚至去改进它,
就需要深入理解隐藏在模型结构背后的直觉和原理,后来在不经意间,看到一篇不错的文章,感觉很有帮助~,在这里分享给大家:卷积神经网络VGG 论文细读 要理解VGG16模型的设计原理,首先要理解卷积神经网络两大特点: 1:局部连接 2:权值共享 在这里作者就不再详细的介绍这两大特点了,如果对这两个特点还不了解的或者了解地不透彻可以移步到:CNN初步认识(局部感知、权值共享) 深度:对于局部连接来说,每个神经元的输出就只和该神经元上一层周围的局部神经元有关,这样就可以使得网络的参数大大降低,可以设计更深的网络模型,这样做肯定有坏处,可能会丢失一些全局信息,但如果我们设计的网络结构很深,
那么可以在高层对网络低层的局部特征进行组合,最终得到全局特征。所以这似乎是一个很巧妙的特点,一方面局部连接可能会丢失全局特征,但另一方面它又可以设计出更深的网络模型,从而得到全局特征。深度对网络的性能极其重要,
一般来说越深的深度网络性能也就越好,深度网络自然集成了低、中、高层特征,可以表达出更丰富的特征和含义。在VGG系列模型中,网络深度达到16-19层,是当时在论文发表前最深的深度网络,所以它表现出了极佳的性能。 宽度:对于权值共享来说,这里的权值指的是卷积核的权值,所谓共享指的是从一个局部区域学习到的信息,应用到图像的其它地方去,即用一个相同的卷积核去卷积整幅图像。通过权值共享,使得网络中训练的参数大大减少,
可以帮助我们训练更深的模型。其次,也由于权值共享,一个卷积核也就只能学到相应的某个特征,所以我们需要设计多个不同的卷积核来提取图像中不同的特征,卷积核的数量也成为卷积神经网络的宽度,在VGG16模型中,最开始是64个卷积核,
随着网络的加深,卷积核数量一直增加到512,是一个很宽的网络,所以它最后的性能如此之强大也不足为奇了。 卷积核:同时我们可以发现,VGG模型中所有的卷积核大小均为3×3,使用3×3的小卷积核堆叠代替大卷积核,主要有以下几个原因: (1)3x3是最小的能够捕获像素八邻域信息的尺寸。
(2)两个3x3的堆叠卷基层的有限感受野是5x5;三个3x3的堆叠卷基层的感受野是7x7,故可以通过小尺寸卷积层的堆叠替代大尺寸卷积层,并且感受野大小不变。所以可以把三个3x3的filter看成是一个7x7filter的分解中间层有非线性的分解,
并且起到隐式正则化的作用。 (3)多个3x3的卷基层比一个大尺寸filter卷基层有更多的非线性(更多层的非线性函数,使用了3个非线性激活函数),使得判决函数更加具有判决性。 (4)多个3x3的卷积层比一个大尺寸的filter有更少的参数,假设卷积层的输入和输出的特征图大小相同为C,那么三个3x3的卷积层参数个数3x((3x3xC)xC)=27C²;一个(7x7xC)xC的卷积层参数为49C²。前者可以表达出输入数据中更多个强力特征,使用的参数也更少。 唯一的不足是,在进行反向传播时,中间的卷积层可能会导致占用更多的内存。 池化核:相比AlexNet的3x3的池化核,VGG全部采用2x2的池化核,可以保留更多的图像信息。 全连接转卷积(测试阶段):这也是VGG的一个特点,在网络测试阶段将训练阶段的三个全连接层替换为三个卷积层,使得测试得到的全卷积网络因为没有全连接的限制,因而可以接收任意宽或高为的输入,这在测试阶段很重要。 卷积层和全连接层的唯一区别在于卷积层的神经元对输入是局部连接的,并且同一个通道(channel)内不同神经元共享权值(weights). 卷积层和全连接层都是进行了一个点乘操作, 它们的函数形式相同. 因此卷积层可以转化为对应的全连接层,
全连接层也可以转化为对应的卷积层。 比如VGGNet[1]中, 第一个全连接层的输入是7*7*512, 输出是4096. 这可以用一个卷积核大小7*7, 步长(stride)为1, 没有填补(padding), 输出通道数4096的卷积层等效表示, 其输出为11*4096, 和全连接层等价.
后续的全连接层可以用1x1卷积等效替代。 简而言之, 全连接层转化为卷积层的规则是: 将卷积核大小设置为输入的空间大小.这样做的好处在于卷 积层对输入大小没有限制, 因此可以高效地对测试图像做滑动窗式的预测. 总结: 1、通过增加深度和宽度能有效地提升性能; 2、最佳模型:VGG16,从头到尾只有3x3卷积与2x2池化,简洁优美; 3、卷积可代替全连接,测试阶段可适应各种尺寸的图片。
import torch import torch.nn as nn import torch.nn.functional as F class VGG16(nn.Module): def __init__(self): super(VGG16, self).__init__() # 3 * 224 * 224 self.conv1_1 = nn.Conv2d(3, 64, 3) # 64 * 222 * 222 self.conv1_2 = nn.Conv2d(64, 64, 3, padding=(1, 1)) # 64 * 222* 222 self.maxpool1 = nn.MaxPool2d((2, 2), padding=(1, 1)) # pooling 64 * 112 * 112 self.conv2_1 = nn.Conv2d(64, 128, 3) # 128 * 110 * 110 self.conv2_2 = nn.Conv2d(128, 128, 3, padding=(1, 1)) # 128 * 110 * 110 self.maxpool2 = nn.MaxPool2d((2, 2), padding=(1, 1)) # pooling 128 * 56 * 56 self.conv3_1 = nn.Conv2d(128, 256, 3) # 256 * 54 * 54 self.conv3_2 = nn.Conv2d(256, 256, 3, padding=(1, 1)) # 256 * 54 * 54 self.conv3_3 = nn.Conv2d(256, 256, 3, padding=(1, 1)) # 256 * 54 * 54 self.maxpool3 = nn.MaxPool2d((2, 2), padding=(1, 1)) # pooling 256 * 28 * 28 self.conv4_1 = nn.Conv2d(256, 512, 3) # 512 * 26 * 26 self.conv4_2 = nn.Conv2d(512, 512, 3, padding=(1, 1)) # 512 * 26 * 26 self.conv4_3 = nn.Conv2d(512, 512, 3, padding=(1, 1)) # 512 * 26 * 26 self.maxpool4 = nn.MaxPool2d((2, 2), padding=(1, 1)) # pooling 512 * 14 * 14 self.conv5_1 = nn.Conv2d(512, 512, 3) # 512 * 12 * 12 self.conv5_2 = nn.Conv2d(512, 512, 3, padding=(1, 1)) # 512 * 12 * 12 self.conv5_3 = nn.Conv2d(512, 512, 3, padding=(1, 1)) # 512 * 12 * 12 self.maxpool5 = nn.MaxPool2d((2, 2), padding=(1, 1)) # pooling 512 * 7 * 7 # view self.fc1 = nn.Linear(512 * 7 * 7, 4096) self.fc2 = nn.Linear(4096, 4096) self.fc3 = nn.Linear(4096, 1000) # softmax 1 * 1 * 1000 def forward(self, x): # x.size(0)即为batch_size in_size = x.size(0) out = self.conv1_1(x) # 222 out = F.relu(out) out = self.conv1_2(out) # 222 out = F.relu(out) out = self.maxpool1(out) # 112 out = self.conv2_1(out) # 110 out = F.relu(out) out = self.conv2_2(out) # 110 out = F.relu(out) out = self.maxpool2(out) # 56 out = self.conv3_1(out) # 54 out = F.relu(out) out = self.conv3_2(out) # 54 out = F.relu(out) out = self.conv3_3(out) # 54 out = F.relu(out) out = self.maxpool3(out) # 28 out = self.conv4_1(out) # 26 out = F.relu(out) out = self.conv4_2(out) # 26 out = F.relu(out) out = self.conv4_3(out) # 26 out = F.relu(out) out = self.maxpool4(out) # 14 out = self.conv5_1(out) # 12 out = F.relu(out) out = self.conv5_2(out) # 12 out = F.relu(out) out = self.conv5_3(out) # 12 out = F.relu(out) out = self.maxpool5(out) # 7 # 展平 out = out.view(in_size, -1) out = self.fc1(out) out = F.relu(out) out = self.fc2(out) out = F.relu(out) out = self.fc3(out) out = F.log_softmax(out, dim=1) return out
Inception V1
1 版本主要思想详述
1.1 Inception v1
Inception V1 在ILSVRC 2014的比赛中,以较大优势取得了第一名,top-5错误率6.67%。Inception V1降低参数量的目的有两点,第一,参数越多模型越庞大,需要供模型学习的数据量就越大,而目前高质量的数据非常昂贵;第二,参数越多,耗费的计算资源也会更大。Inception V1参数少但效果好的原因除了模型层数更深、表达能力更强外,还有两点:一是去除了最后的全连接层,用全局平均池化层(即将图片尺寸变为1*1)来取代它(用全局平均池化层取代全连接层的做法借鉴了NetworkI n Network(以下简称NIN)论文)。在相同尺寸的感受野中叠加更多的卷积,能提取到更加丰富的特征,也采用了 NIN 中的观点。
这里对传统的卷积层结构做个介绍,原理如下所示:
左侧是是传统的卷积层结构(线性卷积),在一个尺度上只有一次卷积;右图是Network in Network结构(NIN结构),先进行一次普通的卷积(比如3x3),紧跟再进行一次1x1的卷积,对于某个像素点来说1x1卷积等效于该像素点在所有特征上进行一次全连接的计算,所以右侧图的1x1卷积画成了全连接层的形式,需要注意的是NIN结构中无论是第一个3x3卷积还是新增的1x1卷积,后面都紧跟着激活函数(比如relu)。将两个卷积串联,就能组合出更多的非线性特征。举个例子,假设第1个3x3卷积+激活函数近似于f1(x)=ax2+bx+c,第二个1x1卷积+激活函数近似于f2(x)=mx2+nx+q,那f1(x)和f2(f1(x))比哪个非线性更强,更能模拟非线性的特征?答案是显而易见的。参数量只有Alexnet的12分之一约500w.
1.1.1 结构原理
Inception架构的主要想法是考虑怎样近似卷积视觉网络的最优稀疏结构并用容易获得的密集组件进行覆盖。注意假设转换不变性,这意味着我们的网络将以卷积构建块为基础。我们所需要做的是找到最优的局部构造并在空间上重复它。
为了避免块校正的问题,目前Inception架构形式的滤波器的尺寸仅限于1×1、3×3、5×5,这个决定更多的是基于便易性而不是必要性。另外,由于池化操作对于目前卷积网络的成功至关重要,因此建议在每个这样的阶段添加一个替代的并行池化路径应该也应该具有额外的有益效果。其原理如下图所示:
第一个分支对输入进行1*1的卷积,它可以进行跨通道的特征变换,提高网络的表达能力,同时可以对输出通道升维和降维;
第二个分支先使用了1*1卷积,然后连接3*3卷积,相当于进行了两次特征变换;
第三个分支先是1*1的卷积,然后连接5*5卷积;
第四个分支则是3*3最大池化后直接使用1*1卷积;
Inception Module的4个分支在最后通过一个聚合操作合并(在输出通道数这个维度上聚合)。
其中:
在图片数据中,天然的就是临近区域的数据相关性高,因此相邻的像素点被卷积操作连接在一起。而我们可能有多个卷积核,在同一空间位置但在不同通道的卷积核的输出结果相关性极高。
1*1的卷积作用:
- 可以进行跨通道的特征变换,把这些相关性很高的、在同一个空间位置但是不同通道的特征连接在一起,提高网络的表达能力;
- 同时可以对输出通道升维(拉伸)和降维(压缩),计算量小。
多尺度卷积再聚合的作用:
- 直观感觉上在多个尺度上同时进行卷积,能提取到不同尺度的特征。
- 利用稀疏矩阵分解成密集矩阵计算的原理来加快收敛速度。
- Hebbin赫布原理。用在inception结构中就是要把相关性强的特征汇聚到一起。有点像上面提到的这点。
总的来说,Inception Module中包含了3种不同尺寸的卷积和1个最大池化,增加了网络对不同尺度的适应性,让网络的深度和宽度高效率地扩充,提升准确率且不致于过拟合。
1.1.2 网络结构
Inception Net有22层深,除了最后一层的输出,其中间节点的分类效果也很好。因此在Inception Net中,还使用到了辅助分类节点(auxiliary classifiers),即将中间某一层的输出用作分类,并按一个较小的权重(0.3)加到最终分类结果中。这样相当于做了模型融合,同时给网络增加了反向传播的梯度信号,也提供了额外的正则化(实际上这在低级的层级上处理用处不大),对于整个Inception Net的训练很有裨益。其完整结构如下所示:
在较低的层(靠近输入的层)中,相关单元更侧重提取局部区域的信息。因此使用1x1的特征可以保存这些特征,从而与其他支路提取的特征进行融合。
3x3和5x5的卷积是想要提取不同尺度的特征,3x3卷积和5x5卷积之前的1x1的卷积作用是减少channel,从而降低参数量。
论文中说到之所以使用pooling,是因为pooling操作在目前最好的卷积网络中是必要的,个人理解是pooling操作可以增强网络的平移不变性。
GoogLeNet结构(Inception V1)
输入为224x224的RGB图像,‘#3x3 reduce’和‘#5x5 reduce’表示3x3和5x5卷积之前1x1的卷积核的个数。
为了阻止该网络中间部分梯度消失,作者引入了两个辅助分类器。它们对其中两个 Inception 模块的输出执行 softmax 操作,然后在同样的标签上计算辅助损失。总损失即辅助损失和真实损失的加权和。辅助损失只是用于训练,在推断过程中并不使用。
1 import torch 2 import torch.nn as nn 3 4 # Inception模块 5 class Block(nn.Module): 6 def __init__(self, in_channels, out_chanel_1, out_channel_3_reduce, out_channel_3, 7 out_channel_5_reduce, out_channel_5, out_channel_pool): 8 super(Block, self).__init__() 9 10 block = [] 11 self.block1 = nn.Conv2d(in_channels=in_channels, out_channels=out_chanel_1, kernel_size=1) 12 block.append(self.block1) 13 self.block2_1 = nn.Conv2d(in_channels=in_channels, out_channels=out_channel_3_reduce, kernel_size=1) 14 self.block2 = nn.Conv2d(in_channels=out_channel_3_reduce, out_channels=out_channel_3, kernel_size=3, padding=1) 15 block.append(self.block2) 16 self.block3_1 = nn.Conv2d(in_channels=in_channels, out_channels=out_channel_5_reduce, kernel_size=1) 17 self.block3 = nn.Conv2d(in_channels=out_channel_5_reduce, out_channels=out_channel_5, kernel_size=3, padding=1) 18 block.append(self.block3) 19 self.block4_1 = nn.MaxPool2d(kernel_size=3,stride=1,padding=1) 20 self.block4 = nn.Conv2d(in_channels=in_channels, out_channels=out_channel_pool, kernel_size=1) 21 block.append(self.block4) 22 23 # self.incep = nn.Sequential(*block) 24 25 def forward(self, x): 26 out1 = self.block1(x) 27 out2 = self.block2(self.block2_1(x)) 28 out3 = self.block3(self.block3_1(x)) 29 out4 = self.block4(self.block4_1(x)) 30 out = torch.cat([out1, out2, out3, out4], dim=1) 31 print(out.shape) 32 return out 33 34 # 在完整网络中间某层输出结果以一定的比例添加到最终结果分类 35 class InceptionClassifiction(nn.Module): 36 def __init__(self, in_channels,out_channels): 37 super(InceptionClassifiction, self).__init__() 38 39 self.avgpool = nn.AvgPool2d(kernel_size=5, stride=3) 40 self.conv1 = nn.Conv2d(in_channels=in_channels, out_channels=128, kernel_size=1) 41 self.linear1 = nn.Linear(in_features=128 * 4 * 4, out_features=1024) 42 self.relu = nn.ReLU(inplace=True) 43 self.dropout = nn.Dropout(p=0.7) 44 self.linear2 = nn.Linear(in_features=1024, out_features=out_channels) 45 46 def forward(self, x): 47 x = self.conv1(self.avgpool(x)) 48 x = x.view(x.size(0), -1) 49 x= self.relu(self.linear1(x)) 50 out = self.linear2(self.dropout(x)) 51 return out 52 53 class InceptionV1(nn.Module): 54 def __init__(self, num_classes=1000, stage='train'): 55 super(InceptionV1, self).__init__() 56 self.stage = stage 57 58 self.blockA = nn.Sequential( 59 nn.Conv2d(in_channels=3,out_channels=64,kernel_size=7,stride=2,padding=3), 60 nn.MaxPool2d(kernel_size=3,stride=2, padding=1), 61 nn.LocalResponseNorm(64), 62 63 ) 64 self.blockB = nn.Sequential( 65 nn.Conv2d(in_channels=64, out_channels=64, kernel_size=1, stride=1), 66 nn.Conv2d(in_channels=64, out_channels=192, kernel_size=3, stride=1, padding=1), 67 nn.LocalResponseNorm(192), 68 nn.MaxPool2d(kernel_size=3, stride=2, padding=1), 69 ) 70 71 self.blockC = nn.Sequential( 72 Block(in_channels=192,out_chanel_1=64, out_channel_3_reduce=96, out_channel_3=128, 73 out_channel_5_reduce = 16, out_channel_5=32, out_channel_pool=32), 74 Block(in_channels=256, out_chanel_1=128, out_channel_3_reduce=128, out_channel_3=192, 75 out_channel_5_reduce=32, out_channel_5=96, out_channel_pool=64), 76 nn.MaxPool2d(kernel_size=3, stride=2, padding=1), 77 ) 78 79 self.blockD_1 = Block(in_channels=480, out_chanel_1=192, out_channel_3_reduce=96, out_channel_3=208, 80 out_channel_5_reduce=16, out_channel_5=48, out_channel_pool=64) 81 82 if self.stage == 'train': 83 self.Classifiction_logits1 = InceptionClassifiction(in_channels=512,out_channels=num_classes) 84 85 self.blockD_2 = nn.Sequential( 86 Block(in_channels=512, out_chanel_1=160, out_channel_3_reduce=112, out_channel_3=224, 87 out_channel_5_reduce=24, out_channel_5=64, out_channel_pool=64), 88 Block(in_channels=512, out_chanel_1=128, out_channel_3_reduce=128, out_channel_3=256, 89 out_channel_5_reduce=24, out_channel_5=64, out_channel_pool=64), 90 Block(in_channels=512, out_chanel_1=112, out_channel_3_reduce=144, out_channel_3=288, 91 out_channel_5_reduce=32, out_channel_5=64, out_channel_pool=64), 92 ) 93 94 if self.stage == 'train': 95 self.Classifiction_logits2 = InceptionClassifiction(in_channels=528,out_channels=num_classes) 96 97 self.blockD_3 = nn.Sequential( 98 Block(in_channels=528, out_chanel_1=256, out_channel_3_reduce=160, out_channel_3=320, 99 out_channel_5_reduce=32, out_channel_5=128, out_channel_pool=128), 100 nn.MaxPool2d(kernel_size=3, stride=2, padding=1), 101 ) 102 103 self.blockE = nn.Sequential( 104 Block(in_channels=832, out_chanel_1=256, out_channel_3_reduce=160, out_channel_3=320, 105 out_channel_5_reduce=32, out_channel_5=128, out_channel_pool=128), 106 Block(in_channels=832, out_chanel_1=384, out_channel_3_reduce=192, out_channel_3=384, 107 out_channel_5_reduce=48, out_channel_5=128, out_channel_pool=128), 108 ) 109 110 self.avgpool = nn.AvgPool2d(kernel_size=7,stride=1) 111 self.dropout = nn.Dropout(p=0.4) 112 self.linear = nn.Linear(in_features=1024,out_features=num_classes) 113 114 def forward(self, x): 115 x = self.blockA(x) 116 x = self.blockB(x) 117 x = self.blockC(x) 118 Classifiction1 = x = self.blockD_1(x) 119 Classifiction2 = x = self.blockD_2(x) 120 x = self.blockD_3(x) 121 out = self.blockE(x) 122 out = self.avgpool(out) 123 out = self.dropout(out) 124 out = out.view(out.size(0), -1) 125 out = self.linear(out) 126 if self.stage == 'train': 127 Classifiction1 = self.Classifiction_logits1(Classifiction1) 128 Classifiction2 = self.Classifiction_logits2(Classifiction2) 129 return Classifiction1, Classifiction2, out 130 else: 131 return out 132 133 134 model = InceptionV1() 135 print(model) 136 137 input = torch.randn(8, 3, 224, 224) 138 Classifiction1, Classifiction2, out = model(input)