深度学习实验二 简单神经网络模型构建
一、实验目的
1.掌握 PyTorch 包的安装方法,熟悉 PyTorch 深度学习框架的基本使用,能完成环境验证与基础张量操作。
2.学会使用 PyTorch 构建 AlexNet、VGG、ResNet 和 MobileNet 等经典卷积神经网络模型,理解各模型的网络结构特点与设计逻辑。
3.掌握模型构建后的测试方法,能通过代码验证模型输出维度、参数数量等关键信息,分析不同模型的复杂度差异。
4.培养基于深度学习框架实现经典模型的工程实践能力,为后续模型训练、调优及实际应用奠定基础。
二、实验内容
1、安装Pytorch包
(1)激活现有虚拟环境
打开 Anaconda Prompt,输入命令conda activate py39(“py39” 为实验一创建的虚拟环境,若环境名不同需替换),激活后命令提示符前会显示 “(py39)”。
(2)安装 PyTorch
打开 PyTorch 官网(https://pytorch.org/),根据官网提供命令下载安装pytorch。
复制命令,在虚拟环境中粘贴并回车执行。
输入命令后,系统会提示确认依赖包,输入 “y” 并回车,等待安装完成,由于是国外的网站下载,因此速度可能较慢,需要耐心等待。
如上图所示,pytorch安装完成。
(3)验证 PyTorch 安装
在 Anaconda Prompt 中输入python启动 Python 解释器,依次输入以下代码:
import torch # 导入PyTorch库
# 测试张量创建与运算
x = torch.tensor([[1, 2], [3, 4]])
y = torch.tensor([[5, 6], [7, 8]])
print("张量x:\n", x)
print("张量y:\n", y)
print("x + y:\n", x + y)
# 测试CUDA可用性(有GPU会显示True,无则显示False)
print("CUDA是否可用:", torch.cuda.is_available())
如下图所示,运行结果表示pytorch安装成功,CUDA也确实可用。
2、用Pytorch构建AlexNet网络模型
步骤 1:定义 AlexNet 类并继承 nn.Module
初始化函数__init__中,先调用父类初始化方法
划分网络为 “特征提取部分” 和 “分类部分”,均用nn.Sequential封装(于按顺序执行层操作)
步骤 2:搭建特征提取部分(5 卷积 + 3 池化)
第一组:1 个卷积层(设置输入通道 3、输出通道 96、卷积核 11×11、步长 4、适当 padding)→ ReLU 激活函数 → 1 个最大池化层(池化核 3×3、步长 2)
第二组:1 个卷积层(输入通道 96、输出通道 256、卷积核 5×5、适当 padding)→ ReLU → 1 个最大池化层(同第一组池化参数)
第三组:1 个卷积层(输入通道 256、输出通道 384、卷积核 3×3、适当 padding)→ ReLU(无池化)
第四组:1 个卷积层(输入通道 384、输出通道 384、卷积核 3×3、适当 padding)→ ReLU(无池化)
第五组:1 个卷积层(输入通道 384、输出通道 256、卷积核 3×3、适当 padding)→ ReLU → 1 个最大池化层(同前)
步骤 3:搭建分类部分(3 全连接 + 2 dropout)
第一全连接组:dropout 层(失活概率 0.5)→ 全连接层(输入维度 = 256×6×6,输出维度 4096)→ ReLU
第二全连接组:dropout 层(失活概率 0.5)→ 全连接层(输入维度 4096,输出维度 4096)→ ReLU
第三全连接层:输入维度 4096,输出维度 = 分类数(默认 1000,可自定义)
步骤 4:定义前向传播函数
输入数据通过特征提取部分将特征提取输出展平(保持 batch_size 不变,合并其余维度)展平后数据通过分类部分,返回最终输出
步骤 5:模型测试验证
实例化 AlexNet 模型(指定分类数)
打印模型结构,确认层顺序与参数设置正确
创建随机测试张量(维度:1×3×224×224,模拟单张 RGB 图像)
将测试张量输入模型,输出并验证输出维度是否为(1× 分类数)
统计模型总参数数量(遍历模型参数,累加每个参数的元素个数)
2.1 代码实现
首先,基于之前创建的虚拟环境py39创建一个新工程,并新建python文件编写代码,如下图所示
如何,按照上述构建步骤实现代码,参考代码如下
import torch
import torch.nn as nn# 步骤 1:定义 AlexNet 类
class AlexNet(nn.Module):def __init__(self, num_classes=1000):super(AlexNet, self).__init__()# 步骤 2:特征提取部分self.features = nn.Sequential(# 第一组卷积 + 池化nn.Conv2d(in_channels=3, out_channels=96, kernel_size=11, stride=4, padding=2),nn.ReLU(inplace=True),nn.MaxPool2d(kernel_size=3, stride=2),# 第二组卷积 + 池化nn.Conv2d(96, 256, kernel_size=5, padding=2),nn.ReLU(inplace=True),nn.MaxPool2d(kernel_size=3, stride=2),# 第三组卷积nn.Conv2d(256, 384, kernel_size=3, padding=1),nn.ReLU(inplace=True),# 第四组卷积nn.Conv2d(384, 384, kernel_size=3, padding=1),nn.ReLU(inplace=True),# 第五组卷积 + 池化nn.Conv2d(384, 256, kernel_size=3, padding=1),nn.ReLU(inplace=True),nn.MaxPool2d(kernel_size=3, stride=2))# 步骤 3:分类部分self.classifier = nn.Sequential(nn.Dropout(p=0.5),nn.Linear(256 * 6 * 6, 4096),nn.ReLU(inplace=True),nn.Dropout(p=0.5),nn.Linear(4096, 4096),nn.ReLU(inplace=True),nn.Linear(4096, num_classes))# 步骤 4:前向传播def forward(self, x):x = self.features(x)x = torch.flatten(x, 1) # 展平,保持 batch_size 不变x = self.classifier(x)return x# 步骤 5:模型测试验证
if __name__ == "__main__":num_classes = 1000model = AlexNet(num_classes=num_classes)# 打印模型结构print(model)# 创建随机测试张量 (1x3x224x224)test_input = torch.randn(1, 3, 224, 224)output = model(test_input)print(f"输出维度: {output.shape}") # 应该是 (1, num_classes)# 统计总参数量total_params = sum(p.numel() for p in model.parameters())print(f"模型总参数量: {total_params}")
运行代码后可得如下图所示的运行结果。
2.2 简单分析
接下来,我们分析一下:
首先,在代码中定义了一个 AlexNet
类,并继承自 nn.Module
,这是 PyTorch 中构建神经网络模型的标准做法。初始化函数 __init__
中将整个网络划分为特征提取部分和分类部分,并使用 nn.Sequential
封装,这样可以按顺序依次执行各个层。特征提取部分通过五个卷积层和三个最大池化层逐步提取图像特征,卷积层的通道数逐渐增加,空间尺寸逐渐减小,同时 ReLU 激活函数增加非线性,保证网络能够学习复杂特征。分类部分由三层全连接层和两个 Dropout 层组成,将卷积提取到的高维特征展平后映射到最终的分类输出,Dropout 用于减轻过拟合风险。前向传播函数中,输入数据先通过特征提取部分,然后展平,再送入分类部分得到最终输出,实现了完整的前向计算流程。
在运行测试阶段,实例化模型并打印结构可以直观看到各层的排列顺序和参数设置,确认卷积核大小、步长、padding 和全连接层输入输出维度都符合 AlexNet 的设计要求。通过创建一个随机输入张量 (1×3×224×224)
,将其送入模型前向传播,输出维度为 (1,1000)
,说明特征提取和分类映射过程正确,模型能够接受标准尺寸图像并输出对应类别的预测。统计总参数量约为 62M,与 AlexNet 原论文中的模型容量相符,其中大部分参数集中在全连接层,反映出模型具有足够的表达能力用于复杂图像分类任务。整个代码运行正常,进程退出代码为 0,说明逻辑正确、无报错,模型可以直接用于进一步训练或迁移学习。
总体来看,代码逻辑清晰,特征提取和分类部分设计合理,前向传播实现正确;实验结果验证了模型结构、输出维度和参数量都符合预期,实验过程完整地展示了从模型定义到前向测试的整个流程,充分体现了 AlexNet 在 PyTorch 中的实现与功能。
3、用Pytorch构建VGG网络模型
步骤 1:定义 VGG16 类并继承 nn.Module
初始化函数中调用父类方法,划分 “特征提取部分” 和 “分类部分”
步骤 2:搭建特征提取部分(13 卷积 + 5 池化,分 5 个卷积块)
第一卷积块:2 个卷积层(输入 3→64→64,卷积核 3×3、padding=1)→ ReLU → 最大池化层(2×2,步长 2)
第二卷积块:2 个卷积层(64→128→128,卷积核 3×3、padding=1)→ ReLU → 最大池化层(同前)
第三卷积块:3 个卷积层(128→256→256→256,卷积核 3×3、padding=1)→ ReLU → 最大池化层(同前)
第四卷积块:3 个卷积层(256→512→512→512,卷积核 3×3、padding=1)→ ReLU → 最大池化层(同前)
第五卷积块:3 个卷积层(512→512→512→512,卷积核 3×3、padding=1)→ ReLU → 最大池化层(同前)
步骤 3:搭建分类部分(3 全连接 + 2 dropout)
第一全连接层:输入维度 = 512×7×7(池化后特征展平),输出维度 4096 → ReLU → dropout(0.5)
第二全连接层:输入 4096,输出 4096 → ReLU → dropout(0.5)
第三全连接层:输入 4096,输出 = 分类数(默认 1000)
步骤 4:定义前向传播函数
输入→特征提取部分→展平特征→分类部分→返回输出
步骤 5:模型测试验证
同 AlexNet 测试步骤:实例化模型→打印结构→输入随机张量→验证输出维度→统计参数数量
3.1 代码实现
同理,创建新工程,新建python文件实现代码。
参考代码如下
import torch
import torch.nn as nn# 步骤 1:定义 VGG16 类并继承 nn.Module
class VGG16(nn.Module):def __init__(self, num_classes=1000):super(VGG16, self).__init__() # 调用父类初始化# 步骤 2:特征提取部分(13卷积+5池化,5个卷积块)self.features = nn.Sequential(# Block 1nn.Conv2d(3, 64, kernel_size=3, padding=1),nn.ReLU(inplace=True),nn.Conv2d(64, 64, kernel_size=3, padding=1),nn.ReLU(inplace=True),nn.MaxPool2d(kernel_size=2, stride=2),# Block 2nn.Conv2d(64, 128, kernel_size=3, padding=1),nn.ReLU(inplace=True),nn.Conv2d(128, 128, kernel_size=3, padding=1),nn.ReLU(inplace=True),nn.MaxPool2d(kernel_size=2, stride=2),# Block 3nn.Conv2d(128, 256, kernel_size=3, padding=1),nn.ReLU(inplace=True),nn.Conv2d(256, 256, kernel_size=3, padding=1),nn.ReLU(inplace=True),nn.Conv2d(256, 256, kernel_size=3, padding=1),nn.ReLU(inplace=True),nn.MaxPool2d(kernel_size=2, stride=2),# Block 4nn.Conv2d(256, 512, kernel_size=3, padding=1),nn.ReLU(inplace=True),nn.Conv2d(512, 512, kernel_size=3, padding=1),nn.ReLU(inplace=True),nn.Conv2d(512, 512, kernel_size=3, padding=1),nn.ReLU(inplace=True),nn.MaxPool2d(kernel_size=2, stride=2),# Block 5nn.Conv2d(512, 512, kernel_size=3, padding=1),nn.ReLU(inplace=True),nn.Conv2d(512, 512, kernel_size=3, padding=1),nn.ReLU(inplace=True),nn.Conv2d(512, 512, kernel_size=3, padding=1),nn.ReLU(inplace=True),nn.MaxPool2d(kernel_size=2, stride=2))# 步骤 3:分类部分(3全连接+2 Dropout)self.classifier = nn.Sequential(nn.Linear(512 * 7 * 7, 4096),nn.ReLU(inplace=True),nn.Dropout(0.5),nn.Linear(4096, 4096),nn.ReLU(inplace=True),nn.Dropout(0.5),nn.Linear(4096, num_classes))# 步骤 4:前向传播函数def forward(self, x):x = self.features(x) # 特征提取部分x = torch.flatten(x, 1) # 展平x = self.classifier(x) # 分类部分return x# 步骤 5:模型测试验证
if __name__ == "__main__":model = VGG16(num_classes=1000) # 实例化模型print(model) # 打印模型结构test_input = torch.randn(1, 3, 224, 224) # 随机测试张量output = model(test_input) # 前向传播print(f"输出维度: {output.shape}") # 验证输出维度total_params = sum(p.numel() for p in model.parameters()) # 总参数print(f"模型总参数量: {total_params}")
运行代码可得结果,如下图所示。
3.2 简单分析
接下来,我们简单分析一下:
VGG16 模型通过继承 nn.Module 定义,网络划分为特征提取部分和分类部分。特征提取部分由 5 个卷积块组成,每块包含 2~3 个卷积层和一个最大池化层,卷积通道逐步增加(3→64→128→256→512→512),空间尺寸逐步减小,ReLU 激活函数引入非线性,使网络能够提取丰富的高维特征。分类部分由三层全连接和两个 Dropout 层组成,将卷积输出展平(25088 = 512×7×7)后映射到最终类别,Dropout 层用于减轻过拟合,全连接层完成从特征到分类的映射。
前向传播中,输入数据先经过特征提取部分生成高维特征,再展平送入分类部分得到输出。实验测试显示,随机输入 (1×3×224×224) 输出维度 [1,1000],符合 VGG16 设计的分类要求;打印模型结构确认卷积、池化、ReLU 和全连接层顺序正确;总参数量约 138M,主要集中在全连接层,说明模型容量充足,能够学习复杂图像特征。
4、用Pytorch构建ResNet网络模型
步骤 1:定义瓶颈残差块(Bottleneck)类
继承 nn.Module,设置expansion=4(输出通道是中间通道的 4 倍)
初始化函数:
定义 3 个卷积层:1×1 卷积(降维)→ 3×3 卷积(特征提取)→ 1×1 卷积(升维),每层后接批量归一化(BN)和 ReLU
定义下采样模块(当输入输出维度不匹配时,用 1×1 卷积 + BN 调整残差维度)
前向传播函数:
保存原始输入作为 “残差”
输入通过 3 个卷积层 + BN+ReLU 的组合
若有下采样,对残差进行维度调整
残差与卷积输出相加,再通过 ReLU,返回结果
步骤 2:定义 ResNet50 类并继承 nn.Module
初始化函数:
初始卷积层:3→64(7×7 卷积,步长 2,padding=3)→ BN → ReLU → 最大池化(3×3,步长 2)
定义残差块生成函数_make_layer:
输入:残差块类、中间通道数、块数量、步长
逻辑:先创建 1 个带下采样的残差块(若步长≠1 或维度不匹配),再创建剩余无下采样的残差块,组成残差块组
构建 4 个残差块组:layer1(3 个块,步长 1)、layer2(4 个块,步长 2)、layer3(6 个块,步长 2)、layer4(3 个块,步长 2)
分类部分:自适应全局平均池化(输出 1×1)→ 全连接层(输入 512×4,输出分类数)
步骤 3:定义前向传播函数
输入→初始卷积 + 池化→4 个残差块组→全局平均池化→展平→全连接层→返回输出
步骤 4:模型测试验证
实例化 ResNet50→打印结构(重点确认残差块组与瓶颈块数量)→输入随机张量→验证输出维度(1× 分类数)→统计参数数量
4.1 代码实现
创建好工程以及相应的空白python文件,如下图所示。
接着按照前面的步骤编写代码。参考代码如下
import torch
import torch.nn as nn# 步骤 1:定义瓶颈残差块(Bottleneck)
class Bottleneck(nn.Module):expansion = 4 # 输出通道 = 中间通道 * 4def __init__(self, in_channels, mid_channels, stride=1, downsample=None):super(Bottleneck, self).__init__()# 1x1 卷积(降维)self.conv1 = nn.Conv2d(in_channels, mid_channels, kernel_size=1, stride=1, bias=False)self.bn1 = nn.BatchNorm2d(mid_channels)# 3x3 卷积(特征提取)self.conv2 = nn.Conv2d(mid_channels, mid_channels, kernel_size=3, stride=stride, padding=1, bias=False)self.bn2 = nn.BatchNorm2d(mid_channels)# 1x1 卷积(升维)self.conv3 = nn.Conv2d(mid_channels, mid_channels * self.expansion, kernel_size=1, stride=1, bias=False)self.bn3 = nn.BatchNorm2d(mid_channels * self.expansion)self.relu = nn.ReLU(inplace=True)# 下采样模块(调整残差维度)self.downsample = downsampledef forward(self, x):residual = x # 保存原始输入作为残差out = self.conv1(x)out = self.bn1(out)out = self.relu(out)out = self.conv2(out)out = self.bn2(out)out = self.relu(out)out = self.conv3(out)out = self.bn3(out)if self.downsample is not None:residual = self.downsample(x)out += residualout = self.relu(out)return out# 步骤 2:定义 ResNet50 类
class ResNet50(nn.Module):def __init__(self, num_classes=1000):super(ResNet50, self).__init__()# 初始卷积层self.in_channels = 64self.conv1 = nn.Conv2d(3, 64, kernel_size=7, stride=2, padding=3, bias=False)self.bn1 = nn.BatchNorm2d(64)self.relu = nn.ReLU(inplace=True)self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1)# 4 个残差块组self.layer1 = self._make_layer(Bottleneck, 64, 3, stride=1)self.layer2 = self._make_layer(Bottleneck, 128, 4, stride=2)self.layer3 = self._make_layer(Bottleneck, 256, 6, stride=2)self.layer4 = self._make_layer(Bottleneck, 512, 3, stride=2)# 分类部分:全局平均池化 + 全连接self.avgpool = nn.AdaptiveAvgPool2d((1, 1))self.fc = nn.Linear(512 * Bottleneck.expansion, num_classes)# 残差块生成函数def _make_layer(self, block, mid_channels, blocks, stride=1):downsample = Noneif stride != 1 or self.in_channels != mid_channels * block.expansion:# 下采样:1x1 卷积 + BNdownsample = nn.Sequential(nn.Conv2d(self.in_channels, mid_channels * block.expansion, kernel_size=1, stride=stride, bias=False),nn.BatchNorm2d(mid_channels * block.expansion))layers = []# 第一个残差块可能带下采样layers.append(block(self.in_channels, mid_channels, stride, downsample))self.in_channels = mid_channels * block.expansion# 剩余残差块for _ in range(1, blocks):layers.append(block(self.in_channels, mid_channels))return nn.Sequential(*layers)# 步骤 3:前向传播def forward(self, x):x = self.conv1(x)x = self.bn1(x)x = self.relu(x)x = self.maxpool(x)x = self.layer1(x)x = self.layer2(x)x = self.layer3(x)x = self.layer4(x)x = self.avgpool(x)x = torch.flatten(x, 1)x = self.fc(x)return x# 步骤 4:模型测试验证
if __name__ == "__main__":model = ResNet50(num_classes=1000)print(model) # 打印模型结构,重点查看残差块组数量test_input = torch.randn(1, 3, 224, 224)output = model(test_input)print(f"输出维度: {output.shape}") # 应为 (1, 1000)total_params = sum(p.numel() for p in model.parameters())print(f"模型总参数量: {total_params}")
运行结果如下
4.2 简单分析
接下来,我们分析一下:
ResNet50 的实现严格遵循了经典 ResNet50 架构。首先,网络使用了一个 7×7 卷积 + BN + ReLU + 3×3 最大池化 的初始层,将输入图像从 3 通道映射到 64 通道,并进行初步下采样,为后续残差块处理提供高维特征。网络主体由 四个残差块组(layer1~layer4) 组成,每个残差块组由多个 Bottleneck 残差块 构成,其中第一个块可能带下采样(通过 1×1 卷积调整残差维度),其余块保持输入输出通道一致。Bottleneck 块采用 1×1 降维 → 3×3 特征提取 → 1×1 升维 的结构,每个卷积层后都跟 BN 和 ReLU,确保训练稳定性和非线性表达能力。残差连接通过将原始输入与卷积输出相加再经过 ReLU,实现梯度直接传递,解决了深层网络训练的梯度消失问题。
从输出结果看,网络在输入维度为 1×3×224×224 的随机张量时,输出维度为 1×1000,符合 ImageNet 分类默认 1000 类的输出要求。模型总参数量约 25,557,032,接近标准 ResNet50 参数规模,说明残差块数量和通道设计正确无误。逐层打印的结构也显示每个残差块的输入输出通道、下采样设置及 Bottleneck 的层次关系均符合设计,layer1~layer4 的块数量为 3、4、6、3,也与经典 ResNet50 架构一致。
5、用Pytorch构建MobileNet网络模型
步骤 1:定义深度可分离卷积块类
继承 nn.Module,初始化函数:
深度卷积:输入通道 = 输出通道,卷积核 3×3,分组数 = 输入通道(单通道独立卷积)→ BN → ReLU
逐点卷积:1×1 卷积(调整输出通道数)→ BN → ReLU
前向传播:输入→深度卷积→逐点卷积→返回输出
步骤 2:定义 MobileNetV1 类并继承 nn.Module
初始化函数:
特征提取部分:
初始卷积:3→32(3×3,步长 2,padding=1)→ BN → ReLU
13 个深度可分离卷积块:按 “32→64(步 1)→128(步 2)→128(步 1)→256(步 2)→256(步 1)→512(步 2)→512×5(步 1)→1024(步 2)→1024(步 1)” 的通道与步长顺序排列
全局平均池化(7×7,步长 1)
分类部分:全连接层(输入 1024,输出分类数)
步骤 3:定义前向传播函数
输入→特征提取部分→展平→全连接层→返回输出
步骤 4:模型测试验证
实例化模型→打印结构(确认深度可分离卷积块数量与顺序)→输入随机张量→验证输出维度→统计参数数量(重点对比其他模型,观察轻量化效果)
5.1 代码实现
创建好工程以及相应的空白python文件,如下图所示。
按照上述步骤,编写代码。参考代码如下:
import torch
import torch.nn as nn# 步骤 1:定义深度可分离卷积块
class DepthwiseSeparableConv(nn.Module):def __init__(self, in_channels, out_channels, stride=1):super(DepthwiseSeparableConv, self).__init__()self.depthwise = nn.Conv2d(in_channels, in_channels, kernel_size=3, stride=stride, padding=1, groups=in_channels, bias=False)self.bn1 = nn.BatchNorm2d(in_channels)self.relu1 = nn.ReLU(inplace=True)self.pointwise = nn.Conv2d(in_channels, out_channels, kernel_size=1, stride=1, padding=0, bias=False)self.bn2 = nn.BatchNorm2d(out_channels)self.relu2 = nn.ReLU(inplace=True)def forward(self, x):x = self.depthwise(x)x = self.bn1(x)x = self.relu1(x)x = self.pointwise(x)x = self.bn2(x)x = self.relu2(x)return x# 步骤 2:定义 MobileNetV1 网络
class MobileNetV1(nn.Module):def __init__(self, num_classes=1000):super(MobileNetV1, self).__init__()# 初始卷积self.features = nn.Sequential(nn.Conv2d(3, 32, kernel_size=3, stride=2, padding=1, bias=False),nn.BatchNorm2d(32),nn.ReLU(inplace=True),# 13 个深度可分离卷积块DepthwiseSeparableConv(32, 64, stride=1),DepthwiseSeparableConv(64, 128, stride=2),DepthwiseSeparableConv(128, 128, stride=1),DepthwiseSeparableConv(128, 256, stride=2),DepthwiseSeparableConv(256, 256, stride=1),DepthwiseSeparableConv(256, 512, stride=2),DepthwiseSeparableConv(512, 512, stride=1),DepthwiseSeparableConv(512, 512, stride=1),DepthwiseSeparableConv(512, 512, stride=1),DepthwiseSeparableConv(512, 512, stride=1),DepthwiseSeparableConv(512, 512, stride=1),DepthwiseSeparableConv(512, 1024, stride=2),DepthwiseSeparableConv(1024, 1024, stride=1),nn.AdaptiveAvgPool2d(1))# 分类层self.classifier = nn.Linear(1024, num_classes)def forward(self, x):x = self.features(x)x = x.view(x.size(0), -1) # 展平x = self.classifier(x)return x# 步骤 4:模型测试验证
if __name__ == "__main__":model = MobileNetV1(num_classes=1000)print(model)# 随机测试张量x = torch.randn(1, 3, 224, 224)out = model(x)print("输出维度:", out.shape)# 统计模型总参数量total_params = sum(p.numel() for p in model.parameters())print("模型总参数量:", total_params)
运行代码,结果如下图所示。
5.2 简单分析
接着简单分析一下:
使用 PyTorch 构建 MobileNetV1 网络模型,重点采用深度可分离卷积(Depthwise Separable Convolution)实现轻量化卷积神经网络。网络首先通过一个标准卷积层将输入 RGB 图像通道从 3 映射到 32,并进行批量归一化(BN)和 ReLU 激活。随后依次通过 13 个深度可分离卷积块,每个块包含一个 3×3 深度卷积(每个通道独立卷积)和一个 1×1 逐点卷积(用于通道扩展),并在每层卷积后配合 BN 与 ReLU 激活函数,实现高效特征提取。深度可分离卷积块的通道数和步长按照 MobileNetV1 原始设计规范排列,实现空间下采样和通道逐步增大,特征维度随着网络深度逐渐扩展至 1024。
在特征提取结束后,模型使用自适应平均池化将空间特征压缩为 1×1,再通过全连接层输出最终分类结果。运行结果显示,模型在输入大小为 1×3×224×224 的张量时输出维度为 [1, 1000]
,符合 1000 类分类任务的要求。模型总参数量为 4,231,976,相比 AlexNet(约 61M)、VGG16(约 138M)、ResNet50(约 25M)显著减少,体现了 MobileNetV1 的轻量化特性,尤其适合在计算资源受限的嵌入式或移动设备上部署。
从网络结构上可以看出,深度可分离卷积通过将标准卷积拆分为空间卷积与通道卷积,有效降低了计算量和参数数量,同时保持较强的特征表达能力。