课程打卡凭证
迁移学习
迁移学习是机器学习中一个重要的技术,通过在一个任务上训练的模型来改善在另一个相关任务上的表现。在深度学习中,迁移学习通常涉及在一个大型数据集(如ImageNet)上预训练的模型上进行微调,以便它可以应用于目标数据集。这里将使用迁移学习对ImageNet数据集的狼和狗进行分类。
数据集准备与加载
下载数据集。
定义初始值。
导入必要的库和模块。
定义数据集的目录路径,分别用于训练和验证数据集。
使用ImageFolderDataset方法加载图像数据集,并指定并行工作线程数和是否打乱数据。
定义图像的均值和标准差,用于归一化操作。scale用于调整图像大小。
对于训练数据集,进行随机裁剪、随机水平翻转、归一化和格式转换的操作。对于验证数据集,进行解码、调整大小、中心裁剪、归一化和格式转换的操作。
使用定义的预处理操作对图像数据进行映射,再将数据集进行批量处理,并返回处理好的数据集。最后调用函数创建训练和验证数据集,并获取每个数据集的大小。
从数据集中加载一个批次的图像和标签,并打印它们的形状和标签信息。
对上述数据和标签进行可视化,结果如下图所示。
构建ResNet50网络
导入必要的库和模块,设置参数初始值。
初始化残差块,接受输入通道数、输出通道数、步长、归一化层和下采样层作为参数。其中归一化层默认为nn.BatchNorm2d。
定义两个卷积层,卷积核大小为 3x3,使用ReLU激活函数。定义下采样层,用于在输入和输出维度不同时调整输入维度。
主分支第一层将输入通过第一个卷积层和归一化层,然后应用ReLU激活函数。主分支第二层则将输出通过第二个卷积层和归一化层。将主分支的输出和identity相加,形成残差连接。最后,再次应用ReLU激活函数。
始化了残差块,接受输入通道数、输出通道数、步长和下采样层作为参数。
- self.conv1定义了一个1x1卷积层,用于减少通道数。
- self.norm1对应第一个卷积层的批归一化层。
- self.conv2定义了一个3x3卷积层,用于特征提取,步长由 stride 参数决定。
- self.norm2对应第二个卷积层的批归一化层。
- self.conv3定义了一个1x1卷积层,用于恢复通道数,通道数为 out_channel 的4倍。
- self.norm3对应第三个卷积层的批归一化层。
- self.relu定义了ReLU激活函数。
- self.down_sample定义了下采样层,用于在输入和输出维度不同时调整输入维度。
主分支第一层将输入通过第一个1x1卷积层和归一化层,然后应用ReLU激活函数。主分支第二层将输出通过第二个3x3卷积层和归一化层,然后应用ReLU激活函数。主分支第三层将输出通过第三个1x1卷积层和归一化层。再将主分支的输出和identity相加,形成残差连接。最后,再次应用ReLU激活函数。
定义函数用于构建ResNet网络中的一个层,该层由多个残差块堆叠而成。通过判断是否需要下采样来调整输入维度,并通过循环堆叠指定数量的残差块。
定义一个ResNet类,用于构建ResNet50模型。
定义ResNet网络的前向传播过程。
函数 _resnet 用于实例化ResNet并加载预训练模型。
resnet50函数用于构建和返回一个ResNet50模型。
固定特征进行训练
导入必要的库和模块,加载预训练的ResNet50模型。
获取并修改全连接层的输入通道数,再将ResNet50的全连接层输出通道数改为2,用于狼和狗的二分类。最后修改平均池化层的kernel size为7。
冻结模型中除最后一层外的所有参数,以避免这些层在训练过程中更新。
使用动量优化器,并设定学习率和动量。定义交叉熵损失函数。
定义前向传播函数 forward_fn,计算预测值和损失。使用 ms.value_and_grad 获取前向传播和梯度计算的函数 grad_fn。定义训练步骤函数 train_step,计算损失和梯度,并更新模型参数。最后实例化训练模型。
加载数据集并设置训练和验证数据迭代器,设置训练参数。
导入必要的库和模块,初始化训练循环。
定义训练循环。
在每个训练轮次结束后,使用验证数据集评估模型的准确率。记录训练轮次结束时间,并计算本轮训练的总时间以及每步的平均时间。打印当前训练轮次的平均训练损失和准确率,以及训练时间统计。
保存最佳模型,打印结束信息。
训练结果如图所示。
可视化模型预测
可视化模型的预测结果,展示图像及其预测类别,结果如下图所示。