• CNN(八):Inception V1算法实战与解析


     🍨 本文为🔗365天深度学习训练营 中的学习记录博客
    🍖 原作者:K同学啊|接辅导、项目定制 

    1 Inception V1

    Inception v1论文

    1.1 理论知识

            GoogLeNet首次出现在2014年ILSVRC比赛中获得冠军。这次的版本通常称其为Inception V1。Inception V1有22层深,参数量为5M。同一时期的VGGNet性能和InceptionV1差不多,但是参数量远大于Inception V1.

            Inception Module是Inception V1的核心组成单元,提出了卷积层的并行结构,实现了在同一层就可以提取不同的特征,如下图(a)所示。

            按照这样的结构来增加网络的深度,虽然可以提升性能,但是还面临计算量大(参数多)的问题。为改善这种现象,Inception Module借鉴Network-in-Network的思想,使用1x1的卷积核实现降维操作(也间接增加了网络的深度),以此来减少网络的参数量与计算量,如上图b所示。

            备注举例:假如前一层的输出为100x100x128,经过具有256个5x5卷积核的卷积层之后(stride=1, pad=2), 输出数据为100x100x256.其中,卷积层的参数为5x5x128x256+256。例如上一层输出先经过具有32个1x1卷积核的卷积层(1x1卷积降低了通道数,且特征图尺寸不变),经过具有256个5x5卷积核的卷积层,最终的输出数据仍为100x100x256,但卷积参数量以及减少为(128x1x1x32+32)+(32x5x5x256+256),参数数量减少为原来的约四分之一。其计算量由原先的8.191x10e9,降低至2.048x10e9。

            1x1卷积核的作用:1x1卷积核的最大作用是降低输入特征图的通道数,减少 网络的参数量与计算量。

            最后Inception Module基本由1x1卷积,3x3卷积,5x5卷积,3x3最大池化四个基本单元组成,对四个基本单元运算结果进行通道上组合,不同大小的卷积核赋予不同大小的感受野,从而提取到图像不同尺度的信息,进行融合,得到图像更好的表征,就是Inception Module的核心思想。

    1.2 算法结构

            实现的Inception v1网络结构图如下所示:

            注: 另外增加了两个辅助分支,作用有两点:

    (1)避免梯度消失,用于前向传导梯度。反向传播时,如果有一层求导为0,链式求导结果则为0。

    (2)将中间某一层输出用作分类,起到模型融合作用,实际测试时,这两个辅助softmax分支会被去掉。 在后续模型的发展中,该方法采用较少。

           详细网络结构图如下所示:

     2 代码实现

    2.1 开发环境

    电脑系统:ubuntu16.04

    编译器:Jupter Lab

    语言环境:Python 3.7

    深度学习环境:Pytorch

    2.2 前期准备

    2.2.1 设置GPU

    1. import torch
    2. import torch.nn as nn
    3. import torchvision.transforms as transforms
    4. import torchvision
    5. from torchvision import transforms, datasets
    6. import os, PIL, pathlib, warnings
    7. warnings.filterwarnings("ignore")
    8. device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
    9. print(device)

      2.2.2 导入数据

    1. import os,PIL,random,pathlib
    2. data_dir = '../data/4-data/'
    3. data_dir = pathlib.Path(data_dir)
    4. data_dir
    5. data_paths = list(data_dir.glob('*'))
    6. classNames = [str(path).split('\\')[-1] for path in data_paths]
    7. print('classNames:', classNames , '\n')
    8. total_dir = '../data/4-data/'
    9. train_transforms = transforms.Compose([
    10. transforms.Resize([224, 224]), # resize输入图片
    11. transforms.ToTensor(), # 将PIL Image或numpy.ndarray转换成tensor
    12. transforms.Normalize(
    13. mean=[0.485, 0.456, 0.406],
    14. std=[0.229, 0.224, 0.225]) # 从数据集中随机抽样计算得到
    15. ])
    16. total_data = datasets.ImageFolder(total_dir, transform=train_transforms)
    17. print(total_data, '\n')
    18. print(total_data.class_to_idx)

            结果如下所示:

    2.2.3 划分数据集

    1. train_size = int(0.8 * len(total_data))
    2. test_size = len(total_data) - train_size
    3. train_dataset, test_dataset = torch.utils.data.random_split(total_data, [train_size, test_size])
    4. print(train_dataset, test_dataset)
    5. batch_size = 4
    6. train_dl = torch.utils.data.DataLoader(train_dataset,
    7. batch_size=batch_size,
    8. shuffle=True,
    9. num_workers=1,
    10. pin_memory=False)
    11. test_dl = torch.utils.data.DataLoader(test_dataset,
    12. batch_size=batch_size,
    13. shuffle=True,
    14. num_workers=1,
    15. pin_memory=False)
    16. for X, y in test_dl:
    17. print("Shape of X [N, C, H, W]:", X.shape)
    18. print("Shape of y:", y.shape, y.dtype)
    19. break

            结果如下所示:

    2.3  Inception的实现

            这里去掉了两个辅助分支,直接复现主支。

    2.3.1 inception_block

            定义一个名为Inception的类,继承自nn.Module。inception_block类包含了Inception V1模型的所有层和参数。

    1. import torch
    2. import torch.nn as nn
    3. import torch.nn.functional as F
    4. class inception_block(nn.Module):
    5. def __init__(self, in_channels, ch1x1, ch3x3red, ch3x3, ch5x5red, ch5x5, pool_proj):
    6. super(inception_block, self).__init__()
    7. # 1x1 conv branch
    8. self.branch1 = nn.Sequential(
    9. nn.Conv2d(in_channels, ch1x1, kernel_size=1),
    10. nn.BatchNorm2d(ch1x1),
    11. nn.ReLU(inplace=True)
    12. )
    13. # 1x1 conv -> 3x3 conv branch
    14. self.branch2 = nn.Sequential(
    15. nn.Conv2d(in_channels, ch3x3red, kernel_size=1),
    16. nn.BatchNorm2d(ch3x3red),
    17. nn.ReLU(inplace=True),
    18. nn.Conv2d(ch3x3red, ch3x3, kernel_size=3, padding=1),
    19. nn.BatchNorm2d(ch3x3),
    20. nn.ReLU(inplace=True)
    21. )
    22. # 1x1 conv -> 5x5 conv branch
    23. self.branch3 = nn.Sequential(
    24. nn.Conv2d(in_channels, ch5x5red, kernel_size=1),
    25. nn.BatchNorm2d(ch5x5red),
    26. nn.ReLU(inplace=True),
    27. nn.Conv2d(ch5x5red, ch5x5, kernel_size=5, padding=2),
    28. nn.BatchNorm2d(ch5x5),
    29. nn.ReLU(inplace=True)
    30. )
    31. # 3x3 max pooling -> 1x1 conv branch
    32. self.branch4 = nn.Sequential(
    33. nn.MaxPool2d(kernel_size=3, stride=1, padding=1),
    34. nn.Conv2d(in_channels, pool_proj, kernel_size=1),
    35. nn.BatchNorm2d(pool_proj),
    36. nn.ReLU(inplace=True)
    37. )
    38. def forward(self, x):
    39. # compute forward pass through all branches
    40. # and concatenate the outout feature maps
    41. branch1_output = self.branch1(x)
    42. branch2_output = self.branch2(x)
    43. branch3_output = self.branch3(x)
    44. branch4_output = self.branch4(x)
    45. outputs = [branch1_output, branch2_output, branch3_output, branch4_output]
    46. return torch.cat(outputs, 1)

             在__init__方法中,我们定义了四个分支,分别是:

    (1) branch1:一个1x1卷积层;

    (2) branch2:一个1x1卷积层+一个3x3卷积层;

    (3) branch3:一个1x1卷积层+5x5卷积层;

    (4) branch4:一个3x3最大池化层+一个1x1卷积层;

            每个分支都包含了一些卷积层、批归一化层和激活函数。这些层都是PyTorch中的标准层,我们可以使用nn.Conv2d、nn.BatchNorm2d和nn.ReLU分别定义卷积层、批归一化层和ReLU激活函数。

            在forward方法中,我们计算从输入到所有分支的前向传递,并将所有分支的特征图拼接在一起。最后,我们返回拼接后的特征图。

    2.3.2 Inception v1

            下面定义Inception v1模型,使用nn.ModuleList和nn.Sequential组合多个Inception模块和其他层。

    1. class InceptionV1(nn.Module):
    2. def __init__(self, num_classes=4):
    3. super(InceptionV1, self).__init__()
    4. self.conv1 = nn.Conv2d(3, 64, kernel_size=7, stride=2, padding=3)
    5. self.maxpool1 = nn.MaxPool2d(kernel_size=3, stride=2, padding=1)
    6. self.conv2 = nn.Conv2d(64, 64, kernel_size=1, stride=1, padding=0)
    7. self.conv3 = nn.Conv2d(64, 192, kernel_size=3, stride=1, padding=1)
    8. self.maxpool2 = nn.MaxPool2d(kernel_size=3, stride=2, padding=1)
    9. self.inception3a = inception_block(192, 64, 96, 128, 16, 32, 32)
    10. self.inception3b = inception_block(256, 128, 128, 192, 32, 96, 64)
    11. self.maxpool3 = nn.MaxPool2d(kernel_size=3, stride=2, padding=1)
    12. self.inception4a = inception_block(480, 192, 96, 208, 16, 48, 64)
    13. self.inception4b = inception_block(512, 160, 112, 224, 24, 64, 64)
    14. self.inception4c = inception_block(512, 128, 128, 256, 24, 64, 64)
    15. self.inception4d = inception_block(512, 112, 144, 288, 32, 64, 64)
    16. self.inception4e = inception_block(528, 256, 160, 320, 32, 128, 128)
    17. self.maxpool4 = nn.MaxPool2d(kernel_size=3, stride=2, padding=1)
    18. self.inception5a = inception_block(832, 256, 160, 320, 32, 128, 128)
    19. self.inception5b = nn.Sequential(
    20. inception_block(832, 384, 192, 384, 48, 128, 128),
    21. nn.AvgPool2d(kernel_size=7, stride=1, padding=0),
    22. nn.Dropout(0.4)
    23. )
    24. # 全连接网络层,用于分类
    25. self.classifier = nn.Sequential(
    26. nn.Linear(in_features=1024, out_features=1024),
    27. nn.ReLU(),
    28. nn.Linear(in_features=1024, out_features=num_classes),
    29. nn.Softmax(dim=1)
    30. )
    31. def forward(self, x):
    32. x = self.conv1(x)
    33. x = F.relu(x)
    34. x = self.maxpool1(x)
    35. x = self.conv2(x)
    36. x = F.relu(x)
    37. x = self.conv3(x)
    38. x = F.relu(x)
    39. x = self.maxpool2(x)
    40. x = self.inception3a(x)
    41. x = self.inception3b(x)
    42. x = self.maxpool3(x)
    43. x = self.inception4a(x)
    44. x = self.inception4b(x)
    45. x = self.inception4c(x)
    46. x = self.inception4d(x)
    47. x = self.inception4e(x)
    48. x = self.maxpool4(x)
    49. x = self.inception5a(x)
    50. x = self.inception5b(x)
    51. x = torch.flatten(x, start_dim=1)
    52. x = self.classifier(x)
    53. return x

    2.3.3 输出模型结构

    1. # 统计模型参数量以及其他指标
    2. import torchsummary
    3. # 调用并将模型转移到GPU中
    4. model = InceptionV1().to(device)
    5. # 显示网络结构
    6. torchsummary.summary(model, (3, 224, 224))
    7. print(model)

            输出如下所示

    1. ----------------------------------------------------------------
    2. Layer (type) Output Shape Param #
    3. ================================================================
    4. Conv2d-1 [-1, 64, 112, 112] 9,472
    5. MaxPool2d-2 [-1, 64, 56, 56] 0
    6. Conv2d-3 [-1, 64, 56, 56] 4,160
    7. Conv2d-4 [-1, 192, 56, 56] 110,784
    8. MaxPool2d-5 [-1, 192, 28, 28] 0
    9. Conv2d-6 [-1, 64, 28, 28] 12,352
    10. BatchNorm2d-7 [-1, 64, 28, 28] 128
    11. ReLU-8 [-1, 64, 28, 28] 0
    12. Conv2d-9 [-1, 96, 28, 28] 18,528
    13. BatchNorm2d-10 [-1, 96, 28, 28] 192
    14. ReLU-11 [-1, 96, 28, 28] 0
    15. Conv2d-12 [-1, 128, 28, 28] 110,720
    16. BatchNorm2d-13 [-1, 128, 28, 28] 256
    17. ReLU-14 [-1, 128, 28, 28] 0
    18. Conv2d-15 [-1, 16, 28, 28] 3,088
    19. BatchNorm2d-16 [-1, 16, 28, 28] 32
    20. ReLU-17 [-1, 16, 28, 28] 0
    21. Conv2d-18 [-1, 32, 28, 28] 12,832
    22. BatchNorm2d-19 [-1, 32, 28, 28] 64
    23. ReLU-20 [-1, 32, 28, 28] 0
    24. MaxPool2d-21 [-1, 192, 28, 28] 0
    25. Conv2d-22 [-1, 32, 28, 28] 6,176
    26. BatchNorm2d-23 [-1, 32, 28, 28] 64
    27. ReLU-24 [-1, 32, 28, 28] 0
    28. inception_block-25 [-1, 256, 28, 28] 0
    29. Conv2d-26 [-1, 128, 28, 28] 32,896
    30. BatchNorm2d-27 [-1, 128, 28, 28] 256
    31. ReLU-28 [-1, 128, 28, 28] 0
    32. Conv2d-29 [-1, 128, 28, 28] 32,896
    33. BatchNorm2d-30 [-1, 128, 28, 28] 256
    34. ReLU-31 [-1, 128, 28, 28] 0
    35. Conv2d-32 [-1, 192, 28, 28] 221,376
    36. BatchNorm2d-33 [-1, 192, 28, 28] 384
    37. ReLU-34 [-1, 192, 28, 28] 0
    38. Conv2d-35 [-1, 32, 28, 28] 8,224
    39. BatchNorm2d-36 [-1, 32, 28, 28] 64
    40. ReLU-37 [-1, 32, 28, 28] 0
    41. Conv2d-38 [-1, 96, 28, 28] 76,896
    42. BatchNorm2d-39 [-1, 96, 28, 28] 192
    43. ReLU-40 [-1, 96, 28, 28] 0
    44. MaxPool2d-41 [-1, 256, 28, 28] 0
    45. Conv2d-42 [-1, 64, 28, 28] 16,448
    46. BatchNorm2d-43 [-1, 64, 28, 28] 128
    47. ReLU-44 [-1, 64, 28, 28] 0
    48. inception_block-45 [-1, 480, 28, 28] 0
    49. MaxPool2d-46 [-1, 480, 14, 14] 0
    50. Conv2d-47 [-1, 192, 14, 14] 92,352
    51. BatchNorm2d-48 [-1, 192, 14, 14] 384
    52. ReLU-49 [-1, 192, 14, 14] 0
    53. Conv2d-50 [-1, 96, 14, 14] 46,176
    54. BatchNorm2d-51 [-1, 96, 14, 14] 192
    55. ReLU-52 [-1, 96, 14, 14] 0
    56. Conv2d-53 [-1, 208, 14, 14] 179,920
    57. BatchNorm2d-54 [-1, 208, 14, 14] 416
    58. ReLU-55 [-1, 208, 14, 14] 0
    59. Conv2d-56 [-1, 16, 14, 14] 7,696
    60. BatchNorm2d-57 [-1, 16, 14, 14] 32
    61. ReLU-58 [-1, 16, 14, 14] 0
    62. Conv2d-59 [-1, 48, 14, 14] 19,248
    63. BatchNorm2d-60 [-1, 48, 14, 14] 96
    64. ReLU-61 [-1, 48, 14, 14] 0
    65. MaxPool2d-62 [-1, 480, 14, 14] 0
    66. Conv2d-63 [-1, 64, 14, 14] 30,784
    67. BatchNorm2d-64 [-1, 64, 14, 14] 128
    68. ReLU-65 [-1, 64, 14, 14] 0
    69. inception_block-66 [-1, 512, 14, 14] 0
    70. Conv2d-67 [-1, 160, 14, 14] 82,080
    71. BatchNorm2d-68 [-1, 160, 14, 14] 320
    72. ReLU-69 [-1, 160, 14, 14] 0
    73. Conv2d-70 [-1, 112, 14, 14] 57,456
    74. BatchNorm2d-71 [-1, 112, 14, 14] 224
    75. ReLU-72 [-1, 112, 14, 14] 0
    76. Conv2d-73 [-1, 224, 14, 14] 226,016
    77. BatchNorm2d-74 [-1, 224, 14, 14] 448
    78. ReLU-75 [-1, 224, 14, 14] 0
    79. Conv2d-76 [-1, 24, 14, 14] 12,312
    80. BatchNorm2d-77 [-1, 24, 14, 14] 48
    81. ReLU-78 [-1, 24, 14, 14] 0
    82. Conv2d-79 [-1, 64, 14, 14] 38,464
    83. BatchNorm2d-80 [-1, 64, 14, 14] 128
    84. ReLU-81 [-1, 64, 14, 14] 0
    85. MaxPool2d-82 [-1, 512, 14, 14] 0
    86. Conv2d-83 [-1, 64, 14, 14] 32,832
    87. BatchNorm2d-84 [-1, 64, 14, 14] 128
    88. ReLU-85 [-1, 64, 14, 14] 0
    89. inception_block-86 [-1, 512, 14, 14] 0
    90. Conv2d-87 [-1, 128, 14, 14] 65,664
    91. BatchNorm2d-88 [-1, 128, 14, 14] 256
    92. ReLU-89 [-1, 128, 14, 14] 0
    93. Conv2d-90 [-1, 128, 14, 14] 65,664
    94. BatchNorm2d-91 [-1, 128, 14, 14] 256
    95. ReLU-92 [-1, 128, 14, 14] 0
    96. Conv2d-93 [-1, 256, 14, 14] 295,168
    97. BatchNorm2d-94 [-1, 256, 14, 14] 512
    98. ReLU-95 [-1, 256, 14, 14] 0
    99. Conv2d-96 [-1, 24, 14, 14] 12,312
    100. BatchNorm2d-97 [-1, 24, 14, 14] 48
    101. ReLU-98 [-1, 24, 14, 14] 0
    102. Conv2d-99 [-1, 64, 14, 14] 38,464
    103. BatchNorm2d-100 [-1, 64, 14, 14] 128
    104. ReLU-101 [-1, 64, 14, 14] 0
    105. MaxPool2d-102 [-1, 512, 14, 14] 0
    106. Conv2d-103 [-1, 64, 14, 14] 32,832
    107. BatchNorm2d-104 [-1, 64, 14, 14] 128
    108. ReLU-105 [-1, 64, 14, 14] 0
    109. inception_block-106 [-1, 512, 14, 14] 0
    110. Conv2d-107 [-1, 112, 14, 14] 57,456
    111. BatchNorm2d-108 [-1, 112, 14, 14] 224
    112. ReLU-109 [-1, 112, 14, 14] 0
    113. Conv2d-110 [-1, 144, 14, 14] 73,872
    114. BatchNorm2d-111 [-1, 144, 14, 14] 288
    115. ReLU-112 [-1, 144, 14, 14] 0
    116. Conv2d-113 [-1, 288, 14, 14] 373,536
    117. BatchNorm2d-114 [-1, 288, 14, 14] 576
    118. ReLU-115 [-1, 288, 14, 14] 0
    119. Conv2d-116 [-1, 32, 14, 14] 16,416
    120. BatchNorm2d-117 [-1, 32, 14, 14] 64
    121. ReLU-118 [-1, 32, 14, 14] 0
    122. Conv2d-119 [-1, 64, 14, 14] 51,264
    123. BatchNorm2d-120 [-1, 64, 14, 14] 128
    124. ReLU-121 [-1, 64, 14, 14] 0
    125. MaxPool2d-122 [-1, 512, 14, 14] 0
    126. Conv2d-123 [-1, 64, 14, 14] 32,832
    127. BatchNorm2d-124 [-1, 64, 14, 14] 128
    128. ReLU-125 [-1, 64, 14, 14] 0
    129. inception_block-126 [-1, 528, 14, 14] 0
    130. Conv2d-127 [-1, 256, 14, 14] 135,424
    131. BatchNorm2d-128 [-1, 256, 14, 14] 512
    132. ReLU-129 [-1, 256, 14, 14] 0
    133. Conv2d-130 [-1, 160, 14, 14] 84,640
    134. BatchNorm2d-131 [-1, 160, 14, 14] 320
    135. ReLU-132 [-1, 160, 14, 14] 0
    136. Conv2d-133 [-1, 320, 14, 14] 461,120
    137. BatchNorm2d-134 [-1, 320, 14, 14] 640
    138. ReLU-135 [-1, 320, 14, 14] 0
    139. Conv2d-136 [-1, 32, 14, 14] 16,928
    140. BatchNorm2d-137 [-1, 32, 14, 14] 64
    141. ReLU-138 [-1, 32, 14, 14] 0
    142. Conv2d-139 [-1, 128, 14, 14] 102,528
    143. BatchNorm2d-140 [-1, 128, 14, 14] 256
    144. ReLU-141 [-1, 128, 14, 14] 0
    145. MaxPool2d-142 [-1, 528, 14, 14] 0
    146. Conv2d-143 [-1, 128, 14, 14] 67,712
    147. BatchNorm2d-144 [-1, 128, 14, 14] 256
    148. ReLU-145 [-1, 128, 14, 14] 0
    149. inception_block-146 [-1, 832, 14, 14] 0
    150. MaxPool2d-147 [-1, 832, 7, 7] 0
    151. Conv2d-148 [-1, 256, 7, 7] 213,248
    152. BatchNorm2d-149 [-1, 256, 7, 7] 512
    153. ReLU-150 [-1, 256, 7, 7] 0
    154. Conv2d-151 [-1, 160, 7, 7] 133,280
    155. BatchNorm2d-152 [-1, 160, 7, 7] 320
    156. ReLU-153 [-1, 160, 7, 7] 0
    157. Conv2d-154 [-1, 320, 7, 7] 461,120
    158. BatchNorm2d-155 [-1, 320, 7, 7] 640
    159. ReLU-156 [-1, 320, 7, 7] 0
    160. Conv2d-157 [-1, 32, 7, 7] 26,656
    161. BatchNorm2d-158 [-1, 32, 7, 7] 64
    162. ReLU-159 [-1, 32, 7, 7] 0
    163. Conv2d-160 [-1, 128, 7, 7] 102,528
    164. BatchNorm2d-161 [-1, 128, 7, 7] 256
    165. ReLU-162 [-1, 128, 7, 7] 0
    166. MaxPool2d-163 [-1, 832, 7, 7] 0
    167. Conv2d-164 [-1, 128, 7, 7] 106,624
    168. BatchNorm2d-165 [-1, 128, 7, 7] 256
    169. ReLU-166 [-1, 128, 7, 7] 0
    170. inception_block-167 [-1, 832, 7, 7] 0
    171. Conv2d-168 [-1, 384, 7, 7] 319,872
    172. BatchNorm2d-169 [-1, 384, 7, 7] 768
    173. ReLU-170 [-1, 384, 7, 7] 0
    174. Conv2d-171 [-1, 192, 7, 7] 159,936
    175. BatchNorm2d-172 [-1, 192, 7, 7] 384
    176. ReLU-173 [-1, 192, 7, 7] 0
    177. Conv2d-174 [-1, 384, 7, 7] 663,936
    178. BatchNorm2d-175 [-1, 384, 7, 7] 768
    179. ReLU-176 [-1, 384, 7, 7] 0
    180. Conv2d-177 [-1, 48, 7, 7] 39,984
    181. BatchNorm2d-178 [-1, 48, 7, 7] 96
    182. ReLU-179 [-1, 48, 7, 7] 0
    183. Conv2d-180 [-1, 128, 7, 7] 153,728
    184. BatchNorm2d-181 [-1, 128, 7, 7] 256
    185. ReLU-182 [-1, 128, 7, 7] 0
    186. MaxPool2d-183 [-1, 832, 7, 7] 0
    187. Conv2d-184 [-1, 128, 7, 7] 106,624
    188. BatchNorm2d-185 [-1, 128, 7, 7] 256
    189. ReLU-186 [-1, 128, 7, 7] 0
    190. inception_block-187 [-1, 1024, 7, 7] 0
    191. AvgPool2d-188 [-1, 1024, 1, 1] 0
    192. Dropout-189 [-1, 1024, 1, 1] 0
    193. Linear-190 [-1, 1024] 1,049,600
    194. ReLU-191 [-1, 1024] 0
    195. Linear-192 [-1, 4] 4,100
    196. Softmax-193 [-1, 4] 0
    197. ================================================================
    198. Total params: 7,041,172
    199. Trainable params: 7,041,172
    200. Non-trainable params: 0
    201. ----------------------------------------------------------------
    202. Input size (MB): 0.57
    203. Forward/backward pass size (MB): 69.61
    204. Params size (MB): 26.86
    205. Estimated Total Size (MB): 97.05
    206. ----------------------------------------------------------------
    207. InceptionV1(
    208. (conv1): Conv2d(3, 64, kernel_size=(7, 7), stride=(2, 2), padding=(3, 3))
    209. (maxpool1): MaxPool2d(kernel_size=3, stride=2, padding=1, dilation=1, ceil_mode=False)
    210. (conv2): Conv2d(64, 64, kernel_size=(1, 1), stride=(1, 1))
    211. (conv3): Conv2d(64, 192, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    212. (maxpool2): MaxPool2d(kernel_size=3, stride=2, padding=1, dilation=1, ceil_mode=False)
    213. (inception3a): inception_block(
    214. (branch1): Sequential(
    215. (0): Conv2d(192, 64, kernel_size=(1, 1), stride=(1, 1))
    216. (1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    217. (2): ReLU(inplace=True)
    218. )
    219. (branch2): Sequential(
    220. (0): Conv2d(192, 96, kernel_size=(1, 1), stride=(1, 1))
    221. (1): BatchNorm2d(96, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    222. (2): ReLU(inplace=True)
    223. (3): Conv2d(96, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    224. (4): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    225. (5): ReLU(inplace=True)
    226. )
    227. (branch3): Sequential(
    228. (0): Conv2d(192, 16, kernel_size=(1, 1), stride=(1, 1))
    229. (1): BatchNorm2d(16, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    230. (2): ReLU(inplace=True)
    231. (3): Conv2d(16, 32, kernel_size=(5, 5), stride=(1, 1), padding=(2, 2))
    232. (4): BatchNorm2d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    233. (5): ReLU(inplace=True)
    234. )
    235. (branch4): Sequential(
    236. (0): MaxPool2d(kernel_size=3, stride=1, padding=1, dilation=1, ceil_mode=False)
    237. (1): Conv2d(192, 32, kernel_size=(1, 1), stride=(1, 1))
    238. (2): BatchNorm2d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    239. (3): ReLU(inplace=True)
    240. )
    241. )
    242. (inception3b): inception_block(
    243. (branch1): Sequential(
    244. (0): Conv2d(256, 128, kernel_size=(1, 1), stride=(1, 1))
    245. (1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    246. (2): ReLU(inplace=True)
    247. )
    248. (branch2): Sequential(
    249. (0): Conv2d(256, 128, kernel_size=(1, 1), stride=(1, 1))
    250. (1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    251. (2): ReLU(inplace=True)
    252. (3): Conv2d(128, 192, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    253. (4): BatchNorm2d(192, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    254. (5): ReLU(inplace=True)
    255. )
    256. (branch3): Sequential(
    257. (0): Conv2d(256, 32, kernel_size=(1, 1), stride=(1, 1))
    258. (1): BatchNorm2d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    259. (2): ReLU(inplace=True)
    260. (3): Conv2d(32, 96, kernel_size=(5, 5), stride=(1, 1), padding=(2, 2))
    261. (4): BatchNorm2d(96, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    262. (5): ReLU(inplace=True)
    263. )
    264. (branch4): Sequential(
    265. (0): MaxPool2d(kernel_size=3, stride=1, padding=1, dilation=1, ceil_mode=False)
    266. (1): Conv2d(256, 64, kernel_size=(1, 1), stride=(1, 1))
    267. (2): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    268. (3): ReLU(inplace=True)
    269. )
    270. )
    271. (maxpool3): MaxPool2d(kernel_size=3, stride=2, padding=1, dilation=1, ceil_mode=False)
    272. (inception4a): inception_block(
    273. (branch1): Sequential(
    274. (0): Conv2d(480, 192, kernel_size=(1, 1), stride=(1, 1))
    275. (1): BatchNorm2d(192, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    276. (2): ReLU(inplace=True)
    277. )
    278. (branch2): Sequential(
    279. (0): Conv2d(480, 96, kernel_size=(1, 1), stride=(1, 1))
    280. (1): BatchNorm2d(96, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    281. (2): ReLU(inplace=True)
    282. (3): Conv2d(96, 208, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    283. (4): BatchNorm2d(208, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    284. (5): ReLU(inplace=True)
    285. )
    286. (branch3): Sequential(
    287. (0): Conv2d(480, 16, kernel_size=(1, 1), stride=(1, 1))
    288. (1): BatchNorm2d(16, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    289. (2): ReLU(inplace=True)
    290. (3): Conv2d(16, 48, kernel_size=(5, 5), stride=(1, 1), padding=(2, 2))
    291. (4): BatchNorm2d(48, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    292. (5): ReLU(inplace=True)
    293. )
    294. (branch4): Sequential(
    295. (0): MaxPool2d(kernel_size=3, stride=1, padding=1, dilation=1, ceil_mode=False)
    296. (1): Conv2d(480, 64, kernel_size=(1, 1), stride=(1, 1))
    297. (2): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    298. (3): ReLU(inplace=True)
    299. )
    300. )
    301. (inception4b): inception_block(
    302. (branch1): Sequential(
    303. (0): Conv2d(512, 160, kernel_size=(1, 1), stride=(1, 1))
    304. (1): BatchNorm2d(160, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    305. (2): ReLU(inplace=True)
    306. )
    307. (branch2): Sequential(
    308. (0): Conv2d(512, 112, kernel_size=(1, 1), stride=(1, 1))
    309. (1): BatchNorm2d(112, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    310. (2): ReLU(inplace=True)
    311. (3): Conv2d(112, 224, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    312. (4): BatchNorm2d(224, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    313. (5): ReLU(inplace=True)
    314. )
    315. (branch3): Sequential(
    316. (0): Conv2d(512, 24, kernel_size=(1, 1), stride=(1, 1))
    317. (1): BatchNorm2d(24, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    318. (2): ReLU(inplace=True)
    319. (3): Conv2d(24, 64, kernel_size=(5, 5), stride=(1, 1), padding=(2, 2))
    320. (4): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    321. (5): ReLU(inplace=True)
    322. )
    323. (branch4): Sequential(
    324. (0): MaxPool2d(kernel_size=3, stride=1, padding=1, dilation=1, ceil_mode=False)
    325. (1): Conv2d(512, 64, kernel_size=(1, 1), stride=(1, 1))
    326. (2): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    327. (3): ReLU(inplace=True)
    328. )
    329. )
    330. (inception4c): inception_block(
    331. (branch1): Sequential(
    332. (0): Conv2d(512, 128, kernel_size=(1, 1), stride=(1, 1))
    333. (1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    334. (2): ReLU(inplace=True)
    335. )
    336. (branch2): Sequential(
    337. (0): Conv2d(512, 128, kernel_size=(1, 1), stride=(1, 1))
    338. (1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    339. (2): ReLU(inplace=True)
    340. (3): Conv2d(128, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    341. (4): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    342. (5): ReLU(inplace=True)
    343. )
    344. (branch3): Sequential(
    345. (0): Conv2d(512, 24, kernel_size=(1, 1), stride=(1, 1))
    346. (1): BatchNorm2d(24, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    347. (2): ReLU(inplace=True)
    348. (3): Conv2d(24, 64, kernel_size=(5, 5), stride=(1, 1), padding=(2, 2))
    349. (4): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    350. (5): ReLU(inplace=True)
    351. )
    352. (branch4): Sequential(
    353. (0): MaxPool2d(kernel_size=3, stride=1, padding=1, dilation=1, ceil_mode=False)
    354. (1): Conv2d(512, 64, kernel_size=(1, 1), stride=(1, 1))
    355. (2): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    356. (3): ReLU(inplace=True)
    357. )
    358. )
    359. (inception4d): inception_block(
    360. (branch1): Sequential(
    361. (0): Conv2d(512, 112, kernel_size=(1, 1), stride=(1, 1))
    362. (1): BatchNorm2d(112, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    363. (2): ReLU(inplace=True)
    364. )
    365. (branch2): Sequential(
    366. (0): Conv2d(512, 144, kernel_size=(1, 1), stride=(1, 1))
    367. (1): BatchNorm2d(144, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    368. (2): ReLU(inplace=True)
    369. (3): Conv2d(144, 288, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    370. (4): BatchNorm2d(288, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    371. (5): ReLU(inplace=True)
    372. )
    373. (branch3): Sequential(
    374. (0): Conv2d(512, 32, kernel_size=(1, 1), stride=(1, 1))
    375. (1): BatchNorm2d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    376. (2): ReLU(inplace=True)
    377. (3): Conv2d(32, 64, kernel_size=(5, 5), stride=(1, 1), padding=(2, 2))
    378. (4): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    379. (5): ReLU(inplace=True)
    380. )
    381. (branch4): Sequential(
    382. (0): MaxPool2d(kernel_size=3, stride=1, padding=1, dilation=1, ceil_mode=False)
    383. (1): Conv2d(512, 64, kernel_size=(1, 1), stride=(1, 1))
    384. (2): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    385. (3): ReLU(inplace=True)
    386. )
    387. )
    388. (inception4e): inception_block(
    389. (branch1): Sequential(
    390. (0): Conv2d(528, 256, kernel_size=(1, 1), stride=(1, 1))
    391. (1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    392. (2): ReLU(inplace=True)
    393. )
    394. (branch2): Sequential(
    395. (0): Conv2d(528, 160, kernel_size=(1, 1), stride=(1, 1))
    396. (1): BatchNorm2d(160, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    397. (2): ReLU(inplace=True)
    398. (3): Conv2d(160, 320, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    399. (4): BatchNorm2d(320, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    400. (5): ReLU(inplace=True)
    401. )
    402. (branch3): Sequential(
    403. (0): Conv2d(528, 32, kernel_size=(1, 1), stride=(1, 1))
    404. (1): BatchNorm2d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    405. (2): ReLU(inplace=True)
    406. (3): Conv2d(32, 128, kernel_size=(5, 5), stride=(1, 1), padding=(2, 2))
    407. (4): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    408. (5): ReLU(inplace=True)
    409. )
    410. (branch4): Sequential(
    411. (0): MaxPool2d(kernel_size=3, stride=1, padding=1, dilation=1, ceil_mode=False)
    412. (1): Conv2d(528, 128, kernel_size=(1, 1), stride=(1, 1))
    413. (2): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    414. (3): ReLU(inplace=True)
    415. )
    416. )
    417. (maxpool4): MaxPool2d(kernel_size=3, stride=2, padding=1, dilation=1, ceil_mode=False)
    418. (inception5a): inception_block(
    419. (branch1): Sequential(
    420. (0): Conv2d(832, 256, kernel_size=(1, 1), stride=(1, 1))
    421. (1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    422. (2): ReLU(inplace=True)
    423. )
    424. (branch2): Sequential(
    425. (0): Conv2d(832, 160, kernel_size=(1, 1), stride=(1, 1))
    426. (1): BatchNorm2d(160, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    427. (2): ReLU(inplace=True)
    428. (3): Conv2d(160, 320, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    429. (4): BatchNorm2d(320, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    430. (5): ReLU(inplace=True)
    431. )
    432. (branch3): Sequential(
    433. (0): Conv2d(832, 32, kernel_size=(1, 1), stride=(1, 1))
    434. (1): BatchNorm2d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    435. (2): ReLU(inplace=True)
    436. (3): Conv2d(32, 128, kernel_size=(5, 5), stride=(1, 1), padding=(2, 2))
    437. (4): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    438. (5): ReLU(inplace=True)
    439. )
    440. (branch4): Sequential(
    441. (0): MaxPool2d(kernel_size=3, stride=1, padding=1, dilation=1, ceil_mode=False)
    442. (1): Conv2d(832, 128, kernel_size=(1, 1), stride=(1, 1))
    443. (2): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    444. (3): ReLU(inplace=True)
    445. )
    446. )
    447. (inception5b): Sequential(
    448. (0): inception_block(
    449. (branch1): Sequential(
    450. (0): Conv2d(832, 384, kernel_size=(1, 1), stride=(1, 1))
    451. (1): BatchNorm2d(384, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    452. (2): ReLU(inplace=True)
    453. )
    454. (branch2): Sequential(
    455. (0): Conv2d(832, 192, kernel_size=(1, 1), stride=(1, 1))
    456. (1): BatchNorm2d(192, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    457. (2): ReLU(inplace=True)
    458. (3): Conv2d(192, 384, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    459. (4): BatchNorm2d(384, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    460. (5): ReLU(inplace=True)
    461. )
    462. (branch3): Sequential(
    463. (0): Conv2d(832, 48, kernel_size=(1, 1), stride=(1, 1))
    464. (1): BatchNorm2d(48, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    465. (2): ReLU(inplace=True)
    466. (3): Conv2d(48, 128, kernel_size=(5, 5), stride=(1, 1), padding=(2, 2))
    467. (4): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    468. (5): ReLU(inplace=True)
    469. )
    470. (branch4): Sequential(
    471. (0): MaxPool2d(kernel_size=3, stride=1, padding=1, dilation=1, ceil_mode=False)
    472. (1): Conv2d(832, 128, kernel_size=(1, 1), stride=(1, 1))
    473. (2): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    474. (3): ReLU(inplace=True)
    475. )
    476. )
    477. (1): AvgPool2d(kernel_size=7, stride=1, padding=0)
    478. (2): Dropout(p=0.4, inplace=False)
    479. )
    480. (classifier): Sequential(
    481. (0): Linear(in_features=1024, out_features=1024, bias=True)
    482. (1): ReLU()
    483. (2): Linear(in_features=1024, out_features=4, bias=True)
    484. (3): Softmax(dim=1)
    485. )
    486. )

    2.4 训练模型

    2.4.1 编写训练函数

    1. # 训练循环
    2. def train(dataloader, model, loss_fn, optimizer):
    3. size = len(dataloader.dataset) # 训练集的大小
    4. num_batches = len(dataloader) # 批次数目, (size/batch_size,向上取整)
    5. train_loss, train_acc = 0, 0 # 初始化训练损失和正确率
    6. for X, y in dataloader: # 获取图片及其标签
    7. X, y = X.to(device), y.to(device)
    8. # 计算预测误差
    9. pred = model(X) # 网络输出
    10. loss = loss_fn(pred, y) # 计算网络输出pred和真实值y之间的差距,y为真实值,计算二者差值即为损失
    11. # 反向传播
    12. optimizer.zero_grad() # grad属性归零
    13. loss.backward() # 反向传播
    14. optimizer.step() # 每一步自动更新
    15. # 记录acc与loss
    16. train_acc += (pred.argmax(1) == y).type(torch.float).sum().item()
    17. train_loss += loss.item()
    18. train_acc /= size
    19. train_loss /= num_batches
    20. return train_acc, train_loss

     2.4.2 编写测试函数

    1. def test(dataloader, model, loss_fn):
    2. size = len(dataloader.dataset) # 训练集的大小
    3. num_batches = len(dataloader) # 批次数目, (size/batch_size,向上取整)
    4. test_loss, test_acc = 0, 0 # 初始化测试损失和正确率
    5. # 当不进行训练时,停止梯度更新,节省计算内存消耗
    6. # with torch.no_grad():
    7. for imgs, target in dataloader: # 获取图片及其标签
    8. with torch.no_grad():
    9. imgs, target = imgs.to(device), target.to(device)
    10. # 计算误差
    11. tartget_pred = model(imgs) # 网络输出
    12. loss = loss_fn(tartget_pred, target) # 计算网络输出和真实值之间的差距,targets为真实值,计算二者差值即为损失
    13. # 记录acc与loss
    14. test_loss += loss.item()
    15. test_acc += (tartget_pred.argmax(1) == target).type(torch.float).sum().item()
    16. test_acc /= size
    17. test_loss /= num_batches
    18. return test_acc, test_loss

     2.4.3 正式训练

    1. import copy
    2. optimizer = torch.optim.Adam(model.parameters(), lr = 1e-4)
    3. loss_fn = nn.CrossEntropyLoss() #创建损失函数
    4. epochs = 40
    5. train_loss = []
    6. train_acc = []
    7. test_loss = []
    8. test_acc = []
    9. best_acc = 0 #设置一个最佳准确率,作为最佳模型的判别指标
    10. if hasattr(torch.cuda, 'empty_cache'):
    11. torch.cuda.empty_cache()
    12. for epoch in range(epochs):
    13. model.train()
    14. epoch_train_acc, epoch_train_loss = train(train_dl, model, loss_fn, optimizer)
    15. #scheduler.step() #更新学习率(调用官方动态学习率接口时使用)
    16. model.eval()
    17. epoch_test_acc, epoch_test_loss = test(test_dl, model, loss_fn)
    18. #保存最佳模型到best_model
    19. if epoch_test_acc > best_acc:
    20. best_acc = epoch_test_acc
    21. best_model = copy.deepcopy(model)
    22. train_acc.append(epoch_train_acc)
    23. train_loss.append(epoch_train_loss)
    24. test_acc.append(epoch_test_acc)
    25. test_loss.append(epoch_test_loss)
    26. #获取当前的学习率
    27. lr = optimizer.state_dict()['param_groups'][0]['lr']
    28. template = ('Epoch: {:2d}. Train_acc: {:.1f}%, Train_loss: {:.3f}, Test_acc:{:.1f}%, Test_loss:{:.3f}, Lr: {:.2E}')
    29. print(template.format(epoch+1, epoch_train_acc*100, epoch_train_loss, epoch_test_acc*100, epoch_test_loss, lr))
    30. PATH = './J7_best_model.pth'
    31. torch.save(model.state_dict(), PATH)
    32. print('Done')

            输出结果如下所示:

    2.5 结果可视化

    1. import matplotlib.pyplot as plt
    2. #隐藏警告
    3. import warnings
    4. warnings.filterwarnings("ignore") #忽略警告信息
    5. plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文标签
    6. plt.rcParams['axes.unicode_minus'] = False # 用来正常显示负号
    7. plt.rcParams['figure.dpi'] = 100 #分辨率
    8. epochs_range = range(epochs)
    9. plt.figure(figsize=(12, 3))
    10. plt.subplot(1, 2, 1)
    11. plt.plot(epochs_range, train_acc, label='Training Accuracy')
    12. plt.plot(epochs_range, test_acc, label='Test Accuracy')
    13. plt.legend(loc='lower right')
    14. plt.title('Training and Validation Accuracy')
    15. plt.subplot(1, 2, 2)
    16. plt.plot(epochs_range, train_loss, label='Training Loss')
    17. plt.plot(epochs_range, test_loss, label='Test Loss')
    18. plt.legend(loc='upper right')
    19. plt.title('Training and Validation Loss')
    20. plt.show()

         输出结果显示如下:

    3 总结

            大部分流行的CNN是将网络的卷积层堆叠的越来越多,网络越来越深,同时channel越来越宽,网络越来越宽,以此来希望提取更高层的特征,从而得到更好的性能。但单纯的网络堆叠和加宽会带来副作用,包括梯度爆炸和数据量剧增而导致的训练困难的问题等。而Inception的提出,改善了此种现象。

            Inception是用多路分支来并行采用不同的卷积核大小,来提取不同大小感受野所代表的特征。这种分支结构,将单路改变为多路,并行计算,使得网络运行速度更快。而不同大小的卷积核,则代表在不同大小感受野的范围内提取的特征,使得网络可以同时“看到”该位置不同范围的特征,通过后续的concate操作,将不同大小感受野的特征融合起来,综合该位置不同范围的特征。其解读思想更接近于人类的解读方式。

            同时,为减少参数量,在分支中,使用1x1卷积将channel维度进行降维,提取特征后再次使用1x1卷积进行channel维度的回升,看似繁琐,却将参数量大大降低。而且,这样的操作,也在无形中增加了网络的深度,提取了更高维的特征。这种降维操作类似于将一个大矩阵转化为一个小矩阵,转化的过程中会提取大矩阵的“精华”,去除冗余信息。而升维操作则类似于将小矩阵又转化为原始大小的大矩阵,方便不同分支的特征融合。

  • 相关阅读:
    独立站定制开发,如何做Google广告引流
    Leetcoder Day32| 贪心算法part05
    自学C++ day01
    Linux nohup命令
    spring的学习【3】
    angular中使用 ngModel 自定义组件
    蓝桥杯每日一题2023.10.18
    Vue项目
    嵌入式养成计划-53----ARM--串口通信
    Orin + Marvell 88q4364调试
  • 原文地址:https://blog.csdn.net/ali1174/article/details/132899834