add lab5/Experiment Guide.md
chenjh919
1 year, 16 days ago
| 0 | # 深度学习模型实验指导:MLP与CNN模型对比分析 | |
| 1 | ||
| 2 | ## 实验概述 | |
| 3 | ||
| 4 | 本实验旨在通过对多层感知机(MLP)和卷积神经网络(CNN)的实现、训练和评估,帮助学生深入理解两种模型的结构特点、性能差异以及适用场景。学生将从基础模型开始,逐步探索更复杂的网络架构,最终通过对比分析,掌握深度学习模型设计与评估的关键技能。 | |
| 5 | ||
| 6 | 本实验的代码已经可以稳定运行。作业内容包括补全两个模型定义代码(MLP与CNN)以及回答一系列问题。两个补全任务的代码仅需在实验报告中体现即可。 | |
| 7 | ||
| 8 | ||
| 9 | ||
| 10 | ## 实验目的 | |
| 11 | ||
| 12 | 1. 掌握MLP和CNN的基本原理和实现方法 | |
| 13 | 2. 了解不同网络结构对模型性能的影响 | |
| 14 | 3. 学习深度学习模型训练、评估和可视化的方法 | |
| 15 | 4. 通过对比实验,理解不同模型在图像分类任务中的优缺点 | |
| 16 | 5. 培养深度学习模型调优和问题解决的能力 | |
| 17 | ||
| 18 | ## 实验准备 | |
| 19 | ||
| 20 | ### 环境要求 | |
| 21 | ||
| 22 | - Python 3.6+ | |
| 23 | - PyTorch 1.7+ | |
| 24 | - NumPy, Matplotlib | |
| 25 | - scikit-learn (用于评估) | |
| 26 | - 建议使用GPU环境(可选) | |
| 27 | ||
| 28 | 实验环境已经在mo平台中搭建好了,同学们无需自行配置 | |
| 29 | ||
| 30 | ### 实验数据集 | |
| 31 | ||
| 32 | 本实验使用CIFAR-10数据集,包含10个类别的彩色图像,每类6000张,共60000张32×32的图像。 | |
| 33 | ||
| 34 | ### 项目结构 | |
| 35 | ||
| 36 | ``` | |
| 37 | 项目根目录/ | |
| 38 | ├── models/ | |
| 39 | │ ├── __init__.py | |
| 40 | │ ├── mlp.py # MLP模型定义 | |
| 41 | │ └── cnn.py # CNN模型定义 | |
| 42 | ├── utils/ | |
| 43 | │ ├── __init__.py | |
| 44 | │ ├── data_loader.py # 数据加载函数 | |
| 45 | │ └── train_utils.py # 训练和评估函数 | |
| 46 | ├── train_all_notebook.py # 统一训练脚本 | |
| 47 | └── compare_models.py # 模型比较脚本 | |
| 48 | ``` | |
| 49 | ||
| 50 | ## 实验原理 | |
| 51 | ||
| 52 | ### 多层感知机(MLP) | |
| 53 | ||
| 54 | 多层感知机是一种前馈神经网络,由输入层、一个或多个隐藏层和输出层组成。MLP的主要特点是: | |
| 55 | ||
| 56 | 1. 每层神经元与下一层全连接 | |
| 57 | 2. 使用非线性激活函数(如ReLU、Sigmoid等) | |
| 58 | 3. 通过反向传播算法进行训练 | |
| 59 | ||
| 60 | **思考问题1**: MLP在处理图像数据时面临哪些挑战?请从数据结构、参数量和特征提取能力三个角度分析。 | |
| 61 | ||
| 62 | ||
| 63 | ### 卷积神经网络(CNN) | |
| 64 | ||
| 65 | 卷积神经网络是为处理具有网格状拓扑结构的数据而设计的神经网络,主要包含卷积层、池化层和全连接层。CNN的主要特点是: | |
| 66 | ||
| 67 | 1. 局部连接:每个神经元只与输入数据的一个局部区域连接 | |
| 68 | 2. 权重共享:同一特征图的所有神经元共享相同的权重 | |
| 69 | 3. 多层次特征提取:低层检测边缘等简单特征,高层组合这些特征形成更复杂的表示 | |
| 70 | ||
| 71 | **思考问题2**: CNN相比MLP在处理图像时具有哪些优势?解释卷积操作如何保留图像的空间信息。 | |
| 72 | ||
| 73 | ||
| 74 | ## 实验内容 | |
| 75 | ||
| 76 | ### 第一部分:基础MLP模型 | |
| 77 | ||
| 78 | #### 1.1 了解MLP模型结构 | |
| 79 | ||
| 80 | 查看`models/mlp.py`文件,理解三种MLP模型的结构: | |
| 81 | - `SimpleMLP`: 单隐层MLP | |
| 82 | - `DeepMLP`: 多隐层MLP,带有BatchNorm和Dropout | |
| 83 | - `ResidualMLP`: 带有残差连接的MLP | |
| 84 | ||
| 85 | **任务1**: 在下面的代码块中,实现一个具有两个隐藏层的MLP模型。第一隐藏层有128个神经元,第二隐藏层有64个神经元,输出层对应10个类别。使用ReLU激活函数,并添加BatchNorm和Dropout(0.3)。 | |
| 86 | ||
| 87 | ```python | |
| 88 | import torch.nn as nn | |
| 89 | ||
| 90 | class TwoLayerMLP(nn.Module): | |
| 91 | def __init__(self, input_dim=3*32*32): | |
| 92 | super(TwoLayerMLP, self).__init__() | |
| 93 | self.flatten = nn.Flatten() | |
| 94 | # 使用nn.Linear, nn.BatchNorm1d, nn.ReLU和nn.Dropout实现两个隐藏层 | |
| 95 | ||
| 96 | def forward(self, x): | |
| 97 | x = self.flatten(x) | |
| 98 | # 实现前向传播 | |
| 99 | return x | |
| 100 | ``` | |
| 101 | ||
| 102 | #### 1.2 训练和评估MLP模型 | |
| 103 | ||
| 104 | 1. 在 `train.ipynb` 中训练SimpleMLP模型,确保将`model_type`设置为`'simple_mlp'`。 | |
| 105 | ||
| 106 | 2. 观察训练过程中的损失和准确率变化,以及最终在测试集上的性能。 | |
| 107 | ||
| 108 | **分析问题1**: 训练过程中,损失和准确率曲线表现如何?是否出现过拟合或欠拟合?简要分析可能的原因。 | |
| 109 | ||
| 110 | ||
| 111 | 3. 修改参数尝试训练DeepMLP模型,将`model_type`设置为`'deep_mlp'`。 | |
| 112 | ||
| 113 | **分析问题2**: 对比SimpleMLP和DeepMLP的性能,增加网络深度对性能有何影响? | |
| 114 | ||
| 115 | ||
| 116 | ### 第二部分:基础CNN模型 | |
| 117 | ||
| 118 | #### 2.1 了解CNN模型结构 | |
| 119 | ||
| 120 | 查看`models/cnn.py`文件,理解不同CNN模型的结构: | |
| 121 | - `SimpleCNN`: 简单的CNN,包含两个卷积层 | |
| 122 | - `MediumCNN`: 中等复杂度的CNN,带有BatchNorm和Dropout | |
| 123 | - `VGGStyleNet`: VGG风格的CNN,使用连续的3x3卷积 | |
| 124 | - `SimpleResNet`: 简化的ResNet,包含残差连接 | |
| 125 | ||
| 126 | **任务2**: 修改下面的`SimpleCNN`代码,添加一个额外的卷积层和BatchNorm。新的卷积层应该在第二个池化层之后,卷积核数量为64,卷积核大小为3x3。 | |
| 127 | ||
| 128 | ```python | |
| 129 | class EnhancedCNN(nn.Module): | |
| 130 | def __init__(self): | |
| 131 | super(EnhancedCNN, self).__init__() | |
| 132 | self.conv1 = nn.Conv2d(3, 16, kernel_size=3, padding=1) | |
| 133 | self.conv2 = nn.Conv2d(16, 32, kernel_size=3, padding=1) | |
| 134 | # 在这里添加一个新的卷积层、BatchNorm和相应的池化层 | |
| 135 | self.pool = nn.MaxPool2d(2, 2) | |
| 136 | self.flatten = nn.Flatten() | |
| 137 | # 修改全连接层以适应新的特征图尺寸 | |
| 138 | self.relu = nn.ReLU() | |
| 139 | def forward(self, x): | |
| 140 | # 实现包含新卷积层的前向传播 | |
| 141 | return x | |
| 142 | ``` | |
| 143 | ||
| 144 | #### 2.2 训练和评估CNN模型 | |
| 145 | ||
| 146 | 1. 在 `train.ipynb` 中训练SimpleMLP模型,确保将`model_type`设置为`'simple_cnn'`,并将`use_data_augmentation`设置为`True`。 | |
| 147 | ||
| 148 | 2. 观察训练过程和卷积核可视化结果。 | |
| 149 | ||
| 150 | **分析问题3**: 卷积核可视化显示了什么模式?这些模式与图像中的哪些特征可能对应? | |
| 151 | ||
| 152 | ||
| 153 | 3. 继续训练MediumCNN模型,将`model_type`设置为`'medium_cnn'`。 | |
| 154 | ||
| 155 | **分析问题4**: CNN模型相比MLP在CIFAR-10上的性能有何不同?为什么会有这样的差异? | |
| 156 | ||
| 157 | ||
| 158 | ||
| 159 | ### 第三部分:高级CNN架构探索 | |
| 160 | ||
| 161 | #### 3.1 VGG风格和ResNet风格网络架构 | |
| 162 | ||
| 163 | 在本部分中,我们将探索两种影响深远的CNN架构:VGG和ResNet。通过理解这些经典架构的设计理念和特点,可以帮助我们设计更高效的神经网络。 | |
| 164 | ||
| 165 | ##### 3.1.1 VGG架构特点 | |
| 166 | VGG网络(由Visual Geometry Group开发)是一种非常简洁而有效的CNN架构,在2014年ImageNet挑战赛中取得了优异成绩。其主要特点包括: | |
| 167 | ||
| 168 | 1. **简单统一的设计**:使用小尺寸(3×3)卷积核和2×2最大池化层 | |
| 169 | 2. **深度堆叠**:通过堆叠多个相同配置的卷积层增加网络深度 | |
| 170 | 3. **结构规整**:遵循"卷积层组-池化层"的模式,随着网络深入,特征图尺寸减小而通道数增加 | |
| 171 | ||
| 172 | 在我们的实现中,`VGGStyleNet`采用了简化版的VGG设计理念,包含三个卷积块,每个块包含两个卷积层和一个池化层。 | |
| 173 | ||
| 174 | 1. 在 `train.ipynb` 中训练SimpleMLP模型,确保将`model_type`设置为`'vgg_style'`,并将`use_data_augmentation`设置为`True`。 | |
| 175 | ||
| 176 | 2. 观察网络的训练过程和性能。特别注意其收敛速度和最终准确率。 | |
| 177 | ||
| 178 | ##### 3.1.2 ResNet架构及残差连接 | |
| 179 | ||
| 180 | ResNet(残差网络)由微软研究院的He等人在2015年提出,是解决"深度退化问题"的突破性架构。其核心创新是引入了残差连接(skip connection): | |
| 181 | ||
| 182 | 1. **残差连接**:通过快捷连接(shortcut connection)将输入直接加到输出上,形成恒等映射路径 | |
| 183 | 2. **残差学习**:网络不再直接学习输入到输出的映射F(x),而是学习残差F(x)-x | |
| 184 | 3. **深度扩展**:残差连接有效缓解了梯度消失问题,使得训练非常深的网络成为可能 | |
| 185 | ||
| 186 | 在我们的实现中,`SimpleResNet`使用了基本的残差块,每个残差块包含两个3×3的卷积层和一个跳跃连接。 | |
| 187 | ||
| 188 | 1. 在 `train.ipynb` 中训练SimpleMLP模型,确保将`model_type`设置为`'resnet'`,并将`use_data_augmentation`设置为`True`。 | |
| 189 | ||
| 190 | 2. 观察网络的训练过程和性能,特别是深度对训练稳定性的影响。 | |
| 191 | ||
| 192 | ##### 3.1.3 Bottleneck结构 | |
| 193 | ||
| 194 | 在更深的ResNet变体中,常使用"瓶颈"(Bottleneck)结构来降低计算复杂度: | |
| 195 | ||
| 196 | - 使用1×1卷积降低通道数(降维) | |
| 197 | - 使用3×3卷积进行特征提取 | |
| 198 | - 再使用1×1卷积恢复通道数(升维) | |
| 199 | ||
| 200 | 这种设计大幅减少参数量和计算量,同时保持或提高性能。 | |
| 201 | ||
| 202 | **思考问题3**: 分析Bottleneck结构的优势。为什么1×1卷积在深度CNN中如此重要?它如何帮助控制网络的参数量和计算复杂度? | |
| 203 | ||
| 204 | ||
| 205 | **探索问题1**: 查看`models/cnn.py`中的`SimpleResNet`实现,分析残差连接是如何实现的。如果输入和输出通道数不匹配,代码是如何处理的? | |
| 206 | ||
| 207 | ||
| 208 | ||
| 209 | #### 3.2 模型复杂度分析 | |
| 210 | ||
| 211 | 不同CNN架构在性能和效率之间存在权衡。现在我们将通过分析不同模型的参数量和推理时间来理解这种权衡。 | |
| 212 | ||
| 213 | 1. 运行以下代码来分析各个模型的复杂度: | |
| 214 | ```python | |
| 215 | from models import SimpleMLP, DeepMLP, ResidualMLP, SimpleCNN, MediumCNN, VGGStyleNet, SimpleResNet | |
| 216 | from utils import model_complexity | |
| 217 | import torch | |
| 218 | ||
| 219 | device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu') | |
| 220 | ||
| 221 | models = { | |
| 222 | 'SimpleMLP': SimpleMLP(), | |
| 223 | 'DeepMLP': DeepMLP(), | |
| 224 | 'SimpleCNN': SimpleCNN(), | |
| 225 | 'MediumCNN': MediumCNN(), | |
| 226 | 'VGGStyleNet': VGGStyleNet(), | |
| 227 | 'SimpleResNet': SimpleResNet() | |
| 228 | } | |
| 229 | ||
| 230 | results = {} | |
| 231 | for name, model in models.items(): | |
| 232 | print(f"\n分析{name}复杂度:") | |
| 233 | params, time = model_complexity(model, device=device) | |
| 234 | results[name] = {'params': params, 'time': time} | |
| 235 | ``` | |
| 236 | ||
| 237 | 2. 记录并比较各个模型的参数量和推理时间。 | |
| 238 | ||
| 239 | **分析问题5**: VGG风格和ResNet风格网络的性能比较。残差连接带来了哪些优势? | |
| 240 | ||
| 241 | **分析问题6**: 参数量和推理时间如何影响模型的实用性?如何在性能和效率之间找到平衡? | |
| 242 | ||
| 243 | ||
| 244 | #### 3.3 理解高级CNN设计理念 | |
| 245 | ||
| 246 | 随着深度学习的发展,CNN架构设计也变得更加精细和高效。以下是一些重要的设计理念: | |
| 247 | ||
| 248 | 1. **网络深度与宽度平衡**:更深的网络能学习更抽象的特征,但也更难训练;更宽的网络(更多通道)能捕获更多特征,但参数量增加 | |
| 249 | 2. **跳跃连接**:除了ResNet的残差连接,还有DenseNet的密集连接、U-Net的跨层连接等 | |
| 250 | 3. **特征增强**:注意力机制(如SENet的通道注意力)、特征融合等 | |
| 251 | 4. **高效卷积设计**:深度可分离卷积(MobileNet)、组卷积(ShuffleNet)等 | |
| 252 | ||
| 253 | **探索问题2**: 如果你要为移动设备设计一个CNN模型,应该考虑哪些因素来权衡性能和效率?请提出至少三条具体的设计原则。 | |
| 254 | ||
| 255 | ||
| 256 | ### 第四部分:模型比较与分析 | |
| 257 | ||
| 258 | 运行 `compare.py` 来对比不同模型的性能: | |
| 259 | ||
| 260 | **综合分析**: 根据比较结果,分析不同类型模型(MLP和CNN)以及不同复杂度模型的性能差异。考虑以下几点: | |
| 261 | 1. 测试准确率 | |
| 262 | 2. 参数量 | |
| 263 | 3. 推理时间 | |
| 264 | 4. 训练收敛速度 | |
| 265 | 5. 过拟合/欠拟合情况 | |
| 266 | ||
| 267 | ||
| 268 | ## 创新探索任务(选做) | |
| 269 | ||
| 270 | 选择下列一项或多项任务完成: | |
| 271 | ||
| 272 | 1. **模型改进**:对任一模型进行修改和改进,提高其在CIFAR-10上的性能。 | |
| 273 | 2. **可视化分析**:设计更好的可视化方法来解释模型的决策过程。 | |
| 274 | 3. **迁移学习**:探索如何利用预训练模型提高CIFAR-10的分类性能。 | |
| 275 | 4. **对抗性样本**:生成对抗性样本,并研究不同模型对对抗性样本的鲁棒性。 | |
| 276 | 5. **自监督学习**:实现一个简单的自监督学习方法,并评估其效果。 | |
| 277 | ||
| 278 | ## 实验报告要求 | |
| 279 | ||
| 280 | 实验报告应包含以下内容: | |
| 281 | ||
| 282 | 1. 实验目的和背景介绍 | |
| 283 | 2. 实验原理简述 | |
| 284 | 3. 实验过程描述 | |
| 285 | 4. 实现的代码(关键部分,包含详细注释) | |
| 286 | 5. 实验结果和分析(包括填写的所有分析问题和任务) | |
| 287 | 6. 创新探索任务的设计、实现和结果(如果选做) | |
| 288 | 7. 结论和思考 | |
| 289 | 8. 参考文献 | |
| 290 | ||
| 291 | ## 评分标准 | |
| 292 | ||
| 293 | - 基础任务完成度:60% | |
| 294 | - 分析问题深度和准确性:35% | |
| 295 | - 创新探索任务:15% (bonus) | |
| 296 | - 报告质量和表达清晰度:5% | |
| 297 | ||
| 298 | ## 参考资料 | |
| 299 | ||
| 300 | 1. LeCun, Y., Bengio, Y., & Hinton, G. (2015). Deep learning. Nature, 521(7553), 436-444. | |
| 301 | 2. He, K., Zhang, X., Ren, S., & Sun, J. (2016). Deep residual learning for image recognition. CVPR. | |
| 302 | 3. Simonyan, K., & Zisserman, A. (2014). Very deep convolutional networks for large-scale image recognition. arXiv preprint arXiv:1409.1556. | |
| 303 | 4. PyTorch文档:https://pytorch.org/docs/stable/index.html | |
| 304 | 5. CS231n: Convolutional Neural Networks for Visual Recognition:https://cs231n.github.io/⏎ |