如何设计网站步骤,网站开发收获,推广页面,专业电商网站建设价格此分类用于记录吴恩达深度学习课程的学习笔记。
课程相关信息链接如下#xff1a;
原课程视频链接#xff1a;[双语字幕]吴恩达深度学习deeplearning.aigithub课程资料#xff0c;含课件与笔记:吴恩达深度学习教学资料课程配套练习#xff08;中英#xff09;与答案#…此分类用于记录吴恩达深度学习课程的学习笔记。课程相关信息链接如下原课程视频链接[双语字幕]吴恩达深度学习deeplearning.aigithub课程资料含课件与笔记:吴恩达深度学习教学资料课程配套练习中英与答案吴恩达深度学习课后习题与答案本篇为第四课第二周的课后习题和代码实践部分。1. 理论习题【中英】【吴恩达课后测验】Course 4 -卷积神经网络 - 第二周测验还是先上一下链接这周的理论习题涉及一些公式推导但是在这篇博客里已经给出了很详细的过程。所以就不再展开这一部分了。这周的代码演示内容较多我们就把精力主要放在下面的实践内容中。2. 代码实践要提前说明的是在吴恩达老师的课程中本周编程作业的题目是Keras 入门与残差网络的搭建。不过需要注意Keras 原本是一个独立的第三方库但在 TensorFlow 2.x 中它已被集成成为 TensorFlow 的高级 API。因此在这位博主的 Keras入门与残差网络的搭建 博客中部分导入语法在新版本中可能会报错这只是由于版本更新导致并不影响博客的核心内容且残差网络的手工搭建部分仍然是正确且值得学习的。我们在正文部分依旧还是用 PyTorch 来演示这周所学的内容。因为内容较多这里先简单列举一下使用 LeNet-5 进行手写数字图像识别使用 AlexNet 进行手写数字图像识别猫狗图像二分类使用 VGG-16 进行猫狗图像二分类使用 ResNet-18 进行猫狗图像二分类2.1 使用 LeNet-5 进行手写数字图像识别回看一下 LeNet-5 的网络结构我们在介绍它的时候就提到过LeNet-5 的提出应用就是单通道的文档识别。因此我们就来看看这个二十多年前的模型在手写数字图像识别上的效果如何。LeNet-5 的网络结构并不复杂我们用 ReLU 替换了原始的 sigmoid/tanh用CrossEntropyLoss 替代原始平方误差损失这样在 PyTorch 中更适合现代训练。最后代码如下/* by 01022.hk - online tools website : 01022.hk/zh/formatcss.html */ class LeNet5(nn.Module): def __init__(self, num_classes10): super(LeNet5, self).__init__() self.conv1 nn.Conv2d(1, 6, kernel_size5) # 输入: 1x32x32 - 输出: 6x28x28 self.pool nn.AvgPool2d(kernel_size2, stride2) # 6x28x28 - 6x14x14 self.conv2 nn.Conv2d(6, 16, kernel_size5) # 16x10x10 self.fc1 nn.Linear(16 * 5 * 5, 120) self.fc2 nn.Linear(120, 84) self.fc3 nn.Linear(84, num_classes) def forward(self, x): x F.relu(self.conv1(x)) # 6x28x28 x self.pool(x) # 6x14x14 x F.relu(self.conv2(x)) # 16x10x10 x self.pool(x) # 16x5x5 x torch.flatten(x, 1) # 16*5*5400 x F.relu(self.fc1(x)) # 120 x F.relu(self.fc2(x)) # 84 x self.fc3(x) # 10 return x # 参数设置 criterion nn.CrossEntropyLoss() #内置 softmax optimizer optim.Adam(model.parameters(), lr0.001) num_epochs 10现在来看看 LeNet-5 在手写数字图像识别上的效果如何可以看到及效果极佳仅仅 10 轮训练训练准确率几乎达到 100%测试准确率也接近 100%并且损失仍在平稳下降。原因一方面LeNet-5 的卷积-池化结构能够有效提取手写数字的局部到全局特征另一方面MNIST 数据集相对简单、规范使得小型模型也能快速收敛并取得高精度。2.2 AlexNet还是先回顾一下网络结构实际上AlexNet 被已经被PyTorch内置了我们可以比较方便的调用/* by 01022.hk - online tools website : 01022.hk/zh/formatcss.html */ # 使用内置 AlexNetmodel models.alexnet(pretrainedFalse)现在就来看看 AlexNet 在不同任务上的效果。1使用 AlexNet 进行手写数字图像识别这里先使用 AlexNet 跑 MNIST 并不是追求更高精度而是对比模型规模变大后训练效率和收敛行为的变化。因为 AlexNet 接受的输入为RGB图像因此在开始训练前还需要对 MNIST 数据集进行预处理transform transforms.Compose([ transforms.Resize((224, 224)), # AlexNet 需要 224x224 transforms.Grayscale(num_output_channels3), # MNIST 是单通道将其复制为 3 通道 transforms.ToTensor(), transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5)) ])运行结果是这样的这个结果不出意料AlexNet 在 LeNet-5 的基本逻辑上又通过网络深度增加了非线性表达能力但相应的也会增加每轮的平均训练时间。同时你会发现在相同训练轮次下AlexNet 的损失值相对 LeNet-5 略高这并不意味着模型性能更差而是由于其参数规模更大、优化难度更高在有限轮次下尚未充分收敛。从模型容量和表达能力上看AlexNet 具备更高的性能上限在更大数据规模或更充分训练条件下通常能取得更优结果。1使用 AlexNet 进行猫狗图像二分类我们先试试使用预训练的 AlexNet 来看看模型在这个任务上的上限。AlexNetmodel models.alexnet(pretrainedTrue)结果如下现在我们再试试从头开始训练AlexNetmodel models.alexnet(pretrainedFalse)结果如下仅仅不使用预训练参数训练过程就明显变得困难、损失下降缓慢前几层几乎学不到有意义的特征表现出典型的梯度消失现象。原因在于AlexNet 参数规模大但缺乏 BN 和残差等稳定训练的结构设计在小数据集上很难把梯度有效传回前层。因此我们由此进行一些调试进行数据增强变相“增加数据量”这一点在原论文也提到过。缩小学习率调试能否避免像这样一样“卡死”。transform transforms.Compose([ # 1尺度裁剪 transforms.RandomResizedCrop( 224, scale(0.8, 1.0), ratio(0.9, 1.1) ), # 2左右翻转 transforms.RandomHorizontalFlip(p0.5), # 3旋转 transforms.RandomRotation( degrees10, interpolationtransforms.InterpolationMode.BILINEAR ), # 4颜色抖动 transforms.ColorJitter( brightness0.2, contrast0.2, saturation0.2, hue0.05 ), transforms.ToTensor(), # 5标准化 transforms.Normalize( mean[0.485, 0.456, 0.406], std[0.229, 0.224, 0.225] ), ]) optimizer optim.Adam(model.parameters(), lr0.0001)现在再来看结果很明显有了好转损失稳步下降但是又出现了过拟合倾向。我们先不着急继续优化来看看别的模型的表现。2.3 VGG-16现在保持其他所有参数不变只改变模型为没有预训练的 VGG-16model models.vgg16(pretrainedFalse)再次运行看看结果你会发现在相同的参数设置下AlexNet的验证准确率最高只能达到80%而 VGG-16 却可以几乎稳定在80%以上。简单总结来看在相同训练设置下VGG-16 比 AlexNet 更容易从头训练训练过程也更稳定。原因在于 VGG-16 使用了统一的小卷积核结构特征是逐层、渐进式学习的梯度传播更顺畅。因此VGG-16 比 AlexNet 更好优化。继续最后登场的是 ResNet 。2.4 ResNet-18同样我们先回顾一下它的网络结构我们对它的使用也并不陌生model models.resnet18(pretrainedFalse) model.fc nn.Linear(model.fc.in_features, 1)同样保持其他参数不变来看看运行结果在这个实验规模下ResNet-18 的优势还未被完全放大但它的训练过程已经表现出明显的稳定性优势这正是残差结构的核心价值。2.5 对比总结模型结构特点训练难度实验表现核心结论LeNet-5浅层网络卷积 池化 全连接参数量小非常容易在 MNIST 上快速收敛准确率接近 100%结构简单但有效适合小图像、低复杂度任务AlexNet较深网络大卷积核 大量全连接层无 BN、无残差困难小数据集从头训练易梯度消失需预训练或强正则表达能力强但优化不稳定强依赖数据规模与初始化VGG-16统一小卷积核3×3堆叠结构规则中等从头训练稳定验证准确率明显高于 AlexNet结构“规整”比“更浅”更重要更易优化ResNet-18残差连接skip connection梯度直通最容易训练最稳定小数据集也能正常收敛残差结构本质上解决了深层网络难训练问题模型越往后发展提升的重点不是“更强的表达能力”而是“更容易被训练好”。当然这并不绝对同样有可以兼顾二者的强大技术我们之后就会了解到。回到现在LeNet-5 结构简单在低复杂度任务上非常好训AlexNet 虽然更深但缺乏良好的优化设计小数据集上反而容易卡住VGG-16 用规则的小卷积堆叠让网络更深却更稳定而 ResNet-18 通过残差连接给梯度开了“直通车”彻底缓解了深层网络难训练的问题。实际应用中我们也能发现在小规模数据集中预训练权重往往比模型深度更重要而在从头训练时结构是否好优化比参数量大小更关键。3.附录3.1 训练代码 PyTorch版import torch import torch.nn as nn import torch.optim as optim from torchvision import datasets, transforms, models from torch.utils.data import DataLoader, random_split import matplotlib.pyplot as plt # 数据预处理 transform transforms.Compose([ # 1尺度裁剪 transforms.RandomResizedCrop( 224, scale(0.8, 1.0), ratio(0.9, 1.1) ), # 2左右翻转 transforms.RandomHorizontalFlip(p0.5), # 3旋转 transforms.RandomRotation( degrees10, interpolationtransforms.InterpolationMode.BILINEAR ), # 4颜色抖动 transforms.ColorJitter( brightness0.2, contrast0.2, saturation0.2, hue0.05 ), # 5转 Tensor transforms.ToTensor(), # 6标准化 transforms.Normalize( mean[0.485, 0.456, 0.406], std[0.229, 0.224, 0.225] ), ]) dataset datasets.ImageFolder(root./cat_dog, transformtransform) train_size int(0.8 * len(dataset)) val_size int(0.1 * len(dataset)) test_size len(dataset) - train_size - val_size train_dataset, val_dataset, test_dataset random_split(dataset, [train_size, val_size, test_size]) train_loader DataLoader(train_dataset, batch_size32, shuffleTrue) val_loader DataLoader(val_dataset, batch_size32, shuffleFalse) test_loader DataLoader(test_dataset, batch_size32, shuffleFalse) device torch.device(cuda if torch.cuda.is_available() else cpu) # ---------------------------------- # 重点模型选择 # ---------------------------------- # model models.alexnet(pretrainedFalse) # 使用 AlexNet # model models.vgg16(pretrainedFalse) # 使用 VGG16 model models.resnet18(pretrainedFalse) # 使用 ResNet18 # 替换最后一层分类器 AlexNet、VGG16 使用这行 # model.classifier[6] nn.Linear(model.classifier[6].in_features, 1) # 替换最后一层分类器 ResNet18 使用这行 model.fc nn.Linear(model.fc.in_features, 1) model model.to(device) # 训练参数 criterion nn.BCEWithLogitsLoss() optimizer optim.Adam(model.parameters(), lr0.0001) epochs 80 train_losses [] train_accs [] val_accs [] for epoch in range(epochs): model.train() epoch_train_loss 0 correct_train 0 total_train 0 for images, labels in train_loader: images, labels images.to(device), labels.to(device).float().unsqueeze(1) outputs model(images) loss criterion(outputs, labels) optimizer.zero_grad() loss.backward() optimizer.step() epoch_train_loss loss.item() preds (outputs 0.5).int() correct_train (preds labels.int()).sum().item() total_train labels.size(0) avg_train_loss epoch_train_loss / len(train_loader) train_acc correct_train / total_train train_losses.append(avg_train_loss) train_accs.append(train_acc) # 验证集 model.eval() correct_val 0 total_val 0 with torch.no_grad(): for images, labels in val_loader: images, labels images.to(device), labels.to(device).float().unsqueeze(1) outputs model(images) preds (outputs 0).int() correct_val (preds labels.int()).sum().item() total_val labels.size(0) val_acc correct_val / total_val val_accs.append(val_acc) print(f轮次 [{epoch1}/{epochs}] f训练损失: {avg_train_loss:.4f} f训练准确率: {train_acc:.4f} f验证准确率: {val_acc:.4f}) # 可视化 plt.rcParams[font.sans-serif] [SimHei] plt.rcParams[axes.unicode_minus] False plt.figure(figsize(10,5)) plt.plot(train_losses, label训练损失) plt.plot(train_accs, label训练准确率) plt.plot(val_accs, label验证准确率) plt.legend() plt.grid(True) plt.show() # 测试集 model.eval() correct 0 total 0 with torch.no_grad(): for images, labels in test_loader: images, labels images.to(device), labels.to(device).float().unsqueeze(1) outputs model(images) preds (outputs 0).int() correct (preds labels.int()).sum().item() total labels.size(0) print(f测试准确率: {correct / total:.4f})3.2 训练代码 TF版由于官方模型库并未提供 AlexNet 与 ResNet-18我们分别采用手工实现AlexNet与结构等价模型ResNet50进行对比。import tensorflow as tf from tensorflow.keras import layers, models import matplotlib.pyplot as plt data_augmentation tf.keras.Sequential([ layers.Resizing(256, 256), layers.RandomCrop(224, 224), layers.RandomFlip(horizontal), layers.RandomRotation(0.05), layers.RandomContrast(0.2), ]) train_ds tf.keras.preprocessing.image_dataset_from_directory( ./cat_dog, validation_split0.2, subsettraining, seed42, image_size(224, 224), batch_size32 ) val_ds tf.keras.preprocessing.image_dataset_from_directory( ./cat_dog, validation_split0.2, subsetvalidation, seed42, image_size(224, 224), batch_size32 ) AUTOTUNE tf.data.AUTOTUNE train_ds train_ds.prefetch(AUTOTUNE) val_ds val_ds.prefetch(AUTOTUNE) # ------------------------------- # 模型选择 # ------------------------------- # ---------- AlexNet ---------- # def build_alexnet(): # return models.Sequential([ # layers.Input(shape(224, 224, 3)), # data_augmentation, # layers.Rescaling(1./255), # # layers.Conv2D(96, 11, strides4, activationrelu), # layers.MaxPooling2D(3, strides2), # # layers.Conv2D(256, 5, paddingsame, activationrelu), # layers.MaxPooling2D(3, strides2), # # layers.Conv2D(384, 3, paddingsame, activationrelu), # layers.Conv2D(384, 3, paddingsame, activationrelu), # layers.Conv2D(256, 3, paddingsame, activationrelu), # layers.MaxPooling2D(3, strides2), # # layers.Flatten(), # layers.Dense(4096, activationrelu), # layers.Dropout(0.5), # layers.Dense(4096, activationrelu), # layers.Dropout(0.5), # layers.Dense(1) # ]) # model build_alexnet() # ---------- VGG-16 ---------- # base_model tf.keras.applications.VGG16( # include_topFalse, # weightsNone, # input_shape(224, 224, 3) # ) # model models.Sequential([ # layers.Input(shape(224, 224, 3)), # data_augmentation, # layers.Rescaling(1./255), # base_model, # layers.Flatten(), # layers.Dense(4096, activationrelu), # layers.Dropout(0.5), # layers.Dense(4096, activationrelu), # layers.Dropout(0.5), # layers.Dense(1) # ]) # ---------- ResNet50 ---------- base_model tf.keras.applications.ResNet50( include_topFalse, weightsNone, input_shape(224, 224, 3) ) model models.Sequential([ layers.Input(shape(224, 224, 3)), data_augmentation, layers.Rescaling(1./255), base_model, layers.GlobalAveragePooling2D(), layers.Dense(1) ]) model.compile( optimizertf.keras.optimizers.Adam(learning_rate1e-4), losstf.keras.losses.BinaryCrossentropy(from_logitsTrue), metrics[accuracy] ) history model.fit( train_ds, validation_dataval_ds, epochs80 ) plt.figure(figsize(10, 5)) plt.plot(history.history[loss], label训练损失) plt.plot(history.history[accuracy], label训练准确率) plt.plot(history.history[val_accuracy], label验证准确率) plt.legend() plt.grid(True) plt.show()