卷积基础知识 课后习题和代码代码实践

1. 理论习题

【中英】【吴恩达课后测验】Course 4 -卷积神经网络 - 第一周测验

本周的题多是一些尺寸和参数量的计算,只要对公式和层级结构足够熟练,就没什么大问题。

来看看这道可能容易混淆的题:

把下面这个过滤器应用到灰度图像会怎么样?

答案:检测竖直边缘。

这道题乍一看可能会有些迷惑,但是观察就会发现,左右数字对称,符号相反。

也就是说,如果应用这个过滤器,当对应区域左右像素接近时,结果就几乎为0。但当左右像素出现较大差别时,结果的绝对值就会较大。

这就是竖直边缘的逻辑,如果把整个矩阵旋转 90 度,检测的就是水平边缘,只是二者的效果可能都没有我们常用的边缘检测过滤器好。

2. 代码实践

吴恩达卷积神经网络实战

同样,这位博主还是手工构建了卷积网络中的各个组件,有兴趣可以链接前往。

我们还是用 PyTorch 来进行演示,终于正式引入了卷积网络,还是用猫狗二分类来看看卷积网络在图学习中的效果。

首先来看看 PyTorch 中如何定义卷积层:

self.conv1 = nn.Conv2d(3, 16, kernel_size=3, padding=0, stride=1)

# Conv2d 是指二维卷积,虽然图片可以有多个通道,但它实际上还是二维的”纸片人“。

# Conv3d 便适用于视频和 3D 图片这样的三维数据。

# 3,16 是指输入和输入的通道数,必须显式指定。

# kernel_size=3 是卷积核尺寸,必须显式指定。

# padding=0 ,0 就是padding 的默认值。

# stride 就是步长,1 就是步长的默认值。

再看看池化层:

self.max_pool1 = nn.MaxPool2d(kernel_size=2, stride=2)

# MaxPool2d 即为最大池化。

# 在池化层中,stride 默认和 kernel_size 相同。

# 池化层会自适应输入通道数,因此不用显示指定。

self.avg_pool2 = nn.AvgPool2d(kernel_size=2, stride=2)

# 同理,AvgPool2d 就是平均池化。

现在,我们就来看看卷积网络的使用效果。

2.1 卷积网络 1.0

我们现在设计卷积网络如下:

class SimpleCNN(nn.Module):

def __init__(self):

super().__init__()

# 卷积层

self.conv1 = nn.Conv2d(3, 16, kernel_size=3, padding=1)

self.conv2 = nn.Conv2d(16, 32, kernel_size=3, padding=1)

self.conv3 = nn.Conv2d(32, 64, kernel_size=3, padding=1)

self.pool = nn.MaxPool2d(2, 2)

# 全连接层

self.fc1 = nn.Linear(64 * 16 * 16, 128)

self.fc2 = nn.Linear(128, 1)

def forward(self, x):

x = self.conv1(x)

x = F.relu(x) # 另一种调用激活函数的方式

x = self.pool(x)

x = self.conv2(x)

x = F.relu(x)

x = self.pool(x)

x = self.conv3(x)

x = F.relu(x)

x = self.pool(x)

x = torch.flatten(x, 1) # 进入全连接层前要先展平

x = self.fc1(x)

x = self.fc2(x)

x = torch.sigmoid(x)

return x

来看看运行结果如何:

image.png

可以看到,仅仅经过 20 轮训练,训练准确率就几乎达到 100% ,但是验证准确率却仍在70%左右徘徊。

这是典型的过拟合现象:模型的学习能力很强,但是泛化能力不好。

经过前面的内容,我们已经了解了很多可以缓解过拟合现象的方法。现在,我们就开始一步步调试,缓解过拟合现象,增强模型的泛化能力。

2.2 卷积网络 2.0:加入 Dropout

我们在正则化部分了解了可以通过应用 dropout 来缓解过拟合,现在就来看看效果。

如果你有些忘了什么是dropout,它的第一次出现在这里:dropout正则化

应用 dropout 后,我们更新网络结构如下:

class SimpleCNN(nn.Module):

def __init__(self):

super().__init__()

# 卷积层

self.conv1 = nn.Conv2d(3, 16, kernel_size=3, padding=1)

self.conv2 = nn.Conv2d(16, 32, kernel_size=3, padding=1)

self.conv3 = nn.Conv2d(32, 64, kernel_size=3, padding=1)

self.pool = nn.MaxPool2d(2, 2)

# 全连接层

self.fc1 = nn.Linear(64 * 16 * 16, 128)

self.fc2 = nn.Linear(128, 1)

# dropout

self.dropout = nn.Dropout(p=0.3)

def forward(self, x):

x = self.conv1(x)

x = F.relu(x)

x = self.pool(x)

x = self.dropout(x) # dropout

x = self.conv2(x)

x = F.relu(x)

x = self.pool(x)

x = self.dropout(x) # dropout

x = self.conv3(x)

x = F.relu(x)

x = self.pool(x)

x = self.dropout(x) # dropout

x = torch.flatten(x, 1)

x = self.fc1(x)

x = self.dropout(x) # dropout

x = self.fc2(x)

x = torch.sigmoid(x)

return x

现在再来看看结果:

image.png

你会发现,dropout 确实有作用,增加训练轮次为 30 轮,训练集上的准确率上升的没有那么快了,确实和验证准确率的差距更小了。

但问题是验证准确率也没上去啊! 原本的过拟合问题,现在变成了欠拟合问题:模型对数据的拟合能力不足,而且通过趋势,会发现如果继续训练,仍存在过拟合风险。

那该怎么办呢?

我们知道,无论是过拟合还是欠拟合,我们希望提高模型性能,最直接的方法就是增加数据量。

我们先不急着上网找图片,不如就先试试我们之前经常提到的数据增强,看看效果如何。

2.3 卷积网络 3.0:进行数据增强

现在,我们要进行数据增强,那么要修改的代码内容就换到了预处理部分。

同样,数据增强第一次出现在这里:其他缓解过拟合的方法

现在,我们仍然保留上一步的 dropout 内容,修改预处理代码如下:

transform = transforms.Compose([

transforms.Resize((128, 128)),

transforms.RandomHorizontalFlip(),# 图片有 50% 可能水平翻转

transforms.RandomRotation(10), # 在 角度 -10° 到 10° 之间随机旋转图像。

transforms.ToTensor(),

transforms.Normalize((0.5,), (0.5,))

])

再再来看看效果如何:

image.png

不是,好像变化不大啊!

别着急,之前我们一直在关注准确率,但是你会发现,在相同的训练轮次下,损失仍在平稳下降,但是下降的更慢了,并没有达到最开始过拟合的损失水平,比刚加入 dropout 时的损失还要高。

这说明:我们还没有达到模型的上限。

现在,继续维持其他内容不变,只增加训练轮次,我们再来运行看看。

image

现在,把训练轮次增加到100轮,就可以发现:验证准确率有了一定的提升,但好像还是有过拟合风险,如果要继续修改,可以选择提高 dropout 的比率,也可以尝试其他正则化。

简单了解卷积层的性能后,我们就不在继续调试了。

实际上,通过继续修改网络结构或者继续增强数据,还可以让模型有更多的提升,但就不在这里演示了。

下一周的内容就是对现有的一些经典网络结构的介绍,到时候,我们再来看看出色的网络结构是什么效果。

3.附录

3.1 卷积网络 3.0 pytorch代码

import torch

import torch.nn as nn

import torch.nn.functional as F

import torch.optim as optim

from torchvision import datasets, transforms

from torch.utils.data import DataLoader, random_split

import matplotlib.pyplot as plt

transform = transforms.Compose([

transforms.Resize((128, 128)),

transforms.RandomHorizontalFlip(),

transforms.RandomRotation(10),

transforms.ToTensor(),

transforms.Normalize((0.5,), (0.5,))

])

dataset = datasets.ImageFolder(root='./cat_dog', transform=transform)

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_size=32, shuffle=True)

val_loader = DataLoader(val_dataset, batch_size=32, shuffle=False)

test_loader = DataLoader(test_dataset, batch_size=32, shuffle=False)

class SimpleCNN(nn.Module):

def __init__(self):

super().__init__()

# 卷积层

self.conv1 = nn.Conv2d(3, 16, kernel_size=3, padding=1)

self.conv2 = nn.Conv2d(16, 32, kernel_size=3, padding=1)

self.conv3 = nn.Conv2d(32, 64, kernel_size=3, padding=1)

self.pool = nn.MaxPool2d(2, 2)

# 全连接层

self.fc1 = nn.Linear(64 * 16 * 16, 128)

self.fc2 = nn.Linear(128, 1)

self.dropout = nn.Dropout(p=0.3)

def forward(self, x):

x = self.conv1(x)

x = F.relu(x)

x = self.pool(x)

x = self.dropout(x)

x = self.conv2(x)

x = F.relu(x)

x = self.pool(x)

x = self.dropout(x)

x = self.conv3(x)

x = F.relu(x)

x = self.pool(x)

x = self.dropout(x)

x = torch.flatten(x, 1)

x = self.fc1(x)

x = self.dropout(x)

x = self.fc2(x)

x = torch.sigmoid(x)

return x

device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

model = SimpleCNN().to(device)

criterion = nn.BCELoss()

optimizer = optim.Adam(model.parameters(), lr=1e-3)

epochs = 100

train_losses = []

train_accuracies = []

val_accuracies = []

for epoch in range(epochs):

model.train()

epoch_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_loss += loss.item()

preds = (outputs > 0.5).int()

correct_train += (preds == labels.int()).sum().item()

total_train += labels.size(0)

avg_loss = epoch_loss / len(train_loader)

train_acc = correct_train / total_train

train_losses.append(avg_loss)

train_accuracies.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.5).int()

correct_val += (preds == labels.int()).sum().item()

total_val += labels.size(0)

val_acc = correct_val / total_val

val_accuracies.append(val_acc)

print(f"轮次: [{epoch+1}/{epochs}], 训练损失: {avg_loss:.4f}, 训练准确率: {train_acc:.4f}, 验证准确率: {val_acc:.4f}")

# 可视化

plt.rcParams['font.sans-serif'] = ['SimHei']

plt.rcParams['axes.unicode_minus'] = False

plt.plot(train_losses, label='训练损失')

plt.plot(train_accuracies, label='训练准确率')

plt.plot(val_accuracies, label='验证准确率')

plt.title("训练损失、训练准确率、验证准确率变化曲线")

plt.xlabel("训练轮次(Epoch)")

plt.ylabel("数值")

plt.legend()

plt.grid(True)

plt.show()

# 最终测试,可忽略

model.eval()

correct_test = 0

total_test = 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.5).int()

correct_test += (preds == labels.int()).sum().item()

total_test += labels.size(0)

test_acc = correct_test / total_test

print(f"测试准确率: {test_acc:.4f}")

3.2 卷积网络 3.0 TF版代码

import tensorflow as tf

from tensorflow.keras import layers, models

import matplotlib.pyplot as plt

img_size = (128, 128)

batch_size = 32

train_ds = tf.keras.preprocessing.image_dataset_from_directory(

'./cat_dog',

validation_split=0.2,

subset="training",

seed=42,

image_size=img_size,

batch_size=batch_size

)

val_test_ds = tf.keras.preprocessing.image_dataset_from_directory(

'./cat_dog',

validation_split=0.2,

subset="validation",

seed=42,

image_size=img_size,

batch_size=batch_size

)

val_size = int(0.5 * len(val_test_ds))

val_ds = val_test_ds.take(val_size)

test_ds = val_test_ds.skip(val_size)

data_augmentation = tf.keras.Sequential([

layers.RandomFlip("horizontal"),

layers.RandomRotation(0.1)

])

normalization = layers.Rescaling(1/0.5, offset=-1)

AUTOTUNE = tf.data.AUTOTUNE

train_ds = train_ds.map(lambda x, y: (normalization(data_augmentation(x)), y)).prefetch(AUTOTUNE)

val_ds = val_ds.map(lambda x, y: (normalization(x), y)).prefetch(AUTOTUNE)

test_ds = test_ds.map(lambda x, y: (normalization(x), y)).prefetch(AUTOTUNE)

train_ds = train_ds.cache().shuffle(1000).prefetch(tf.data.AUTOTUNE)

val_ds = val_ds.cache().prefetch(tf.data.AUTOTUNE)

model = models.Sequential([

layers.Conv2D(16, (3, 3), padding='same', activation='relu', input_shape=img_size + (3,)),

layers.MaxPooling2D(2, 2),

layers.Dropout(0.3),

layers.Conv2D(32, (3, 3), padding='same', activation='relu'),

layers.MaxPooling2D(2, 2),

layers.Dropout(0.3),

layers.Conv2D(64, (3, 3), padding='same', activation='relu'),

layers.MaxPooling2D(2, 2),

layers.Dropout(0.3),

layers.Flatten(),

layers.Dense(128, activation='relu'),

layers.Dense(1, activation='sigmoid')

])

model.summary()

model.compile(

optimizer=tf.keras.optimizers.Adam(1e-3),

loss='binary_crossentropy',

metrics=['accuracy']

)

epochs = 100

history = model.fit(

train_ds,

validation_data=val_ds,

epochs=epochs

)

plt.rcParams['font.sans-serif'] = ['SimHei']

plt.rcParams['axes.unicode_minus'] = False

plt.plot(history.history['loss'], label='训练损失')

plt.plot(history.history['accuracy'], label='训练准确率')

plt.plot(history.history['val_accuracy'], label='验证准确率')

plt.title("训练损失、训练准确率、验证准确率变化曲线")

plt.xlabel("训练轮次(Epoch)")

plt.ylabel("数值")

plt.legend()

plt.grid(True)

plt.show()

test_loss, test_acc = model.evaluate(test_ds)

print(f"测试准确率: {test_acc:.4f}")

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/1018760.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

《狙击蝴蝶》是现代版的《杨过与小龙女》

本文比较了《狙击蝴蝶》与《神雕侠侣》的救赎主题,讨论了剧中角色关系和观众的不同反应,并分享了作者的个人观看体验。剧情当然没有杨过与小龙女天残地缺那么惨,但同样是男女主相互救赎。在《神雕侠侣》中,孙婆婆将…

Shell脚本字符串操作功能总结

以下是在Shell脚本中常见的字符串操作功能总结,涵盖了各种处理字符串的场景:1. 基本定义和赋值str"Hello World" # 双引号(允许变量扩展) strHello World # 单引号(原样输出) …

27、Linux内核安装、配置与测试全解析

Linux内核安装、配置与测试全解析 1. 引导加载程序与内核安装基础 引导加载程序的主要作用是将内核镜像加载到内存中,并把CPU的控制权交给新加载的内核。要让新内核正常工作,就必须让引导加载程序知晓内核的相关信息。 在了解Linux系统的引导加载程序之前,先看看普通基于…

Test-NetConnection 138.05.02.9595 -Port 7070

Microsoft Windows [版本 10.0.19045.6216] (c) Microsoft Corporation。保留所有权利。C:\Users\Administrator>ping 138.05.02.9595正在 Ping 138.05.02.9595 具有 32 字节的数据: 来自 138.05.02.9595 的回复: 字节32 时间37ms TTL117 来自 138.05.02.9595 的回复: 字节3…

DM8数据库与MySQL语法兼容性解析与实践指南

本文旨在系统性地整合与验证DM8在数据类型、SQL语法、内置函数及存储程序语言等多个层面与MySQL的兼容性,并提供清晰的迁移转换策略与实践指南。一、 兼容性总体策略与核心机制DM8实现MySQL兼容性的核心设计哲学是“语义等价,形式适配”。其并非完全照搬…

37、深入了解gawk:浮点运算、任意精度整数运算及扩展编写

深入了解gawk:浮点运算、任意精度整数运算及扩展编写 1. 浮点运算中的舍入模式 在进行浮点运算时,舍入模式是一个关键因素。如果系统的C库在使用 printf 处理中间值时未采用IEEE 754的偶数舍入规则,输出结果可能会截然不同。 ROUNDMODE 变量可对程序的舍入模式进行控制…

基于SpringBoot的家教信息匹配与预约系统_28jk27g9_

目录具体实现截图项目介绍论文大纲核心代码部分展示项目运行指导结论源码获取详细视频演示 :文章底部获取博主联系方式!同行可合作具体实现截图 本系统(程序源码数据库调试部署讲解)同时还支持java、ThinkPHP、Node.js、Spring B…

S32 Design Studio for Power Architecture + 风河编译器 生成库文件

本文描述了使用powerpc版本的S32DS和风河编译器生成静态链接库。库文件可在新工程中加载调用,详见参考1。对于其他版本的S32DS和编译器也有参考价值。 1. 新建工程 点击运行S32DS,在Workspace框填写新工作空间的路径。然后点击 “OK” 按钮。 点击菜单…

2025 年 12 月恒温恒湿试验箱厂家权威推荐榜:涵盖小型、步入式、可程式、低温等全系列,精准控温与耐久品质深度解析 - 品牌企业推荐师(官方)

2025 年 12 月恒温恒湿试验箱厂家权威推荐榜:涵盖小型、步入式、可程式、低温等全系列,精准控温与耐久品质深度解析 在工业制造、科研开发与质量检测领域,环境可靠性测试是验证产品性能与寿命的关键环节。恒温恒湿试…

23、深入Linux开发:工具、脚本与源码编译全解析

深入Linux开发:工具、脚本与源码编译全解析 在Linux系统的开发与管理中,掌握各种开发工具、脚本语言以及源码编译的方法至关重要。下面将详细介绍这些内容。 调试器gdb 在Linux系统中,标准的调试器是gdb,DDD则作为其图形用户前端。若要在程序中启用完整的调试功能,需在…

【码同学】2025VIP性能测试课程+资料

在当前快速发展的科技背景下,人工智能(AI)正以前所未有的速度渗透到各行各业。尤其是在教育领域,AI 被广泛应用于个性化学习、智能评估、课程推荐等方面,提高了学习的效率与效果。面对这样的变革,我们如何抵…

效率、合规、可追溯:一个成熟背景调查系统的三重价值

在人才竞争日益激烈的市场环境中,招聘决策的准确性直接关系到企业的运营安全与发展稳定。一个成熟的背景调查系统,已不再是简单的信息核验工具,而是集效率合规可追溯三重价值于一体的人才风险管理基石。效率:从数周到实时的决策加…

年底忙到飞起?用AI每天偷回1小时,老板的命也是命

应酬、复盘、规划、团建、催款…… 年底这五件套,专治各种不服。你是不是也这样?早上9点陪客户喝早茶,中午12点改年终PPT,下午3点开战略会,晚上8点还在回微信:“王总,发票明天一定开&#xff01…

通过企业微信ipad协议接口查询群成员信息

请求方式POSTContentType:”application/json”参数参数名必选类型说明uuid是String每个实例的唯一标识,根据uuid操作具体企业微信请求示例{"uuid":"3240fde0-45e2-48c0-90e8-cb098d0ebe43","roomid":1069XXXX5016166}返回示例{"…

嵌入式项目之温湿度闹钟

在个人职业发展的经济模型中,薪资水平本质上是对个人“不可替代性”和“价值创造范围”的定价。许多人长期困在低薪的“基础项目”中,并非不努力,而是因为他们始终停留在“螺丝钉”的角色——精通单一技能,但对整个系统的商业价值…

离子污染测试

什么是离子污染物离子污染物是指产品表面未被清洗掉的残留物质,这些物质在潮湿环境中会电离为导电离子, 例如电镀药水、助焊剂、清洗剂、人工汗液等,很容易在产品上形成离子残留。一旦这些物质在产品表面残留并形成离子,便可能对电子产品的性…

基于SpringBoot的智能旅游行程规划系统的设计与实现_f3t4o913

目录具体实现截图项目介绍论文大纲核心代码部分展示项目运行指导结论源码获取详细视频演示 :文章底部获取博主联系方式!同行可合作具体实现截图 本系统(程序源码数据库调试部署讲解)同时还支持java、ThinkPHP、Node.js、Spring B…

2026年,你希望公司更离不开你,还是你更离不开公司?

上个月底,在南山科技园一家咖啡馆,我碰见老周—— 他做工业传感器的,厂在龙华观澜,二十来号人,年营收3000万左右。 他眼圈发黑,手抖着搅咖啡: “昨晚又通宵改PPT,给投资人看明年规划…

任务5-1 单表查询

文章目录1. 实战概述2. 实战步骤3. 实战总结1. 实战概述 本次实战围绕 MySQL 单表查询展开,基于 bookstore 数据库的图书、会员和销售三张表,系统演练了 SELECT 子句的核心功能,包括列选择、别名定义、CASE 表达式分类、计算列、去重查询&am…

【Redis-day01】

《Redis-day01》 0. 今日总结 了解了NoSQL以及Redis的优势复习了Redis的基础命令了解了SpringDataRedis的配置和使用分别实现了自动和手动序列化及反序列化 1. 初识Redis 1.1 认识NoSQL1.2 认识Redis Redis诞生于2009年全称是Remote Dictionaryserver,远程词典服务器…