简单cnn

news2025/6/2 15:07:54

数据增强

在图像数据预处理环节,为提升数据多样性,可采用数据增强(数据增广)策略。该策略通常不改变单次训练的样本总数,而是通过对现有图像进行多样化变换,使每次训练输入的样本呈现更丰富的形态差异,从而有效扩展模型训练的样本空间多样性。

常见的修改策略包括以下几类

1. 几何变换:如旋转、缩放、平移、剪裁、裁剪、翻转

2. 像素变换:如修改颜色、亮度、对比度、饱和度、色相、高斯模糊(模拟对焦失败)、增加噪声、马赛克

3. 语义增强(暂时不用):mixup,对图像进行结构性改造、cutout随机遮挡等

此外,在数据极少的场景长,常常用生成模型来扩充数据集,如GAN、VAE等。

# 1. 数据预处理
# 训练集:使用多种数据增强方法提高模型泛化能力
train_transform = transforms.Compose([
    # 随机裁剪图像,从原图中随机截取32x32大小的区域
    transforms.RandomCrop(32, padding=4),
    # 随机水平翻转图像(概率0.5)
    transforms.RandomHorizontalFlip(),
    # 随机颜色抖动:亮度、对比度、饱和度和色调随机变化
    transforms.ColorJitter(brightness=0.2, contrast=0.2, saturation=0.2, hue=0.1),
    # 随机旋转图像(最大角度15度)
    transforms.RandomRotation(15),
    # 将PIL图像或numpy数组转换为张量
    transforms.ToTensor(),
    # 标准化处理:每个通道的均值和标准差,使数据分布更合理
    transforms.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010))
])

CNN模型

卷积的本质:通过卷积核在输入通道上的滑动乘积,提取跨通道的空间特征。所以只需要定义几个参数即可

1. 卷积核大小:卷积核的大小,如3x3、5x5、7x7等。

2. 输入通道数:输入图片的通道数,如1(单通道图片)、3(RGB图片)、4(RGBA图片)等。

3. 输出通道数:卷积核的个数,即输出的通道数。如本模型中通过 32→64→128 逐步增加特征复杂度

4. 步长(stride):卷积核的滑动步长,默认为1。

#定义CNN模型的定义(替代原MLP)
class CNN(nn.Module):
    def __init__(self):
        super(CNN, self).__init__()  # 继承父类初始化
        
        # ---------------------- 第一个卷积块 ----------------------
        # 卷积层1:输入3通道(RGB),输出32个特征图,卷积核3x3,边缘填充1像素
        self.conv1 = nn.Conv2d(
            in_channels=3,       # 输入通道数(图像的RGB通道)
            out_channels=32,     # 输出通道数(生成32个新特征图)
            kernel_size=3,       # 卷积核尺寸(3x3像素)
            padding=1            # 边缘填充1像素,保持输出尺寸与输入相同
        )
        # 批量归一化层:对32个输出通道进行归一化,加速训练
        self.bn1 = nn.BatchNorm2d(num_features=32)
        # ReLU激活函数:引入非线性,公式:max(0, x)
        self.relu1 = nn.ReLU()
        # 最大池化层:窗口2x2,步长2,特征图尺寸减半(32x32→16x16)
        self.pool1 = nn.MaxPool2d(kernel_size=2, stride=2)  # stride默认等于kernel_size
        
        # ---------------------- 第二个卷积块 ----------------------
        # 卷积层2:输入32通道(来自conv1的输出),输出64通道
        self.conv2 = nn.Conv2d(
            in_channels=32,      # 输入通道数(前一层的输出通道数)
            out_channels=64,     # 输出通道数(特征图数量翻倍)
            kernel_size=3,       # 卷积核尺寸不变
            padding=1            # 保持尺寸:16x16→16x16(卷积后)→8x8(池化后)
        )
        self.bn2 = nn.BatchNorm2d(num_features=64)
        self.relu2 = nn.ReLU()
        self.pool2 = nn.MaxPool2d(kernel_size=2)  # 尺寸减半:16x16→8x8
        
        # ---------------------- 第三个卷积块 ----------------------
        # 卷积层3:输入64通道,输出128通道
        self.conv3 = nn.Conv2d(
            in_channels=64,      # 输入通道数(前一层的输出通道数)
            out_channels=128,    # 输出通道数(特征图数量再次翻倍)
            kernel_size=3,
            padding=1            # 保持尺寸:8x8→8x8(卷积后)→4x4(池化后)
        )
        self.bn3 = nn.BatchNorm2d(num_features=128)
        self.relu3 = nn.ReLU()  # 复用激活函数对象(节省内存)
        self.pool3 = nn.MaxPool2d(kernel_size=2)  # 尺寸减半:8x8→4x4
        
        # ---------------------- 全连接层(分类器) ----------------------
        # 计算展平后的特征维度:128通道 × 4x4尺寸 = 128×16=2048维
        self.fc1 = nn.Linear(
            in_features=128 * 4 * 4,  # 输入维度(卷积层输出的特征数)
            out_features=512          # 输出维度(隐藏层神经元数)
        )
        # Dropout层:训练时随机丢弃50%神经元,防止过拟合
        self.dropout = nn.Dropout(p=0.5)
        # 输出层:将512维特征映射到10个类别(CIFAR-10的类别数)
        self.fc2 = nn.Linear(in_features=512, out_features=10)

    def forward(self, x):
        # 输入尺寸:[batch_size, 3, 32, 32](batch_size=批量大小,3=通道数,32x32=图像尺寸)
        
        # ---------- 卷积块1处理 ----------
        x = self.conv1(x)       # 卷积后尺寸:[batch_size, 32, 32, 32](padding=1保持尺寸)
        x = self.bn1(x)         # 批量归一化,不改变尺寸
        x = self.relu1(x)       # 激活函数,不改变尺寸
        x = self.pool1(x)       # 池化后尺寸:[batch_size, 32, 16, 16](32→16是因为池化窗口2x2)
        
        # ---------- 卷积块2处理 ----------
        x = self.conv2(x)       # 卷积后尺寸:[batch_size, 64, 16, 16](padding=1保持尺寸)
        x = self.bn2(x)
        x = self.relu2(x)
        x = self.pool2(x)       # 池化后尺寸:[batch_size, 64, 8, 8]
        
        # ---------- 卷积块3处理 ----------
        x = self.conv3(x)       # 卷积后尺寸:[batch_size, 128, 8, 8](padding=1保持尺寸)
        x = self.bn3(x)
        x = self.relu3(x)
        x = self.pool3(x)       # 池化后尺寸:[batch_size, 128, 4, 4]
        
        # ---------- 展平与全连接层 ----------
        # 将多维特征图展平为一维向量:[batch_size, 128*4*4] = [batch_size, 2048]
        x = x.view(-1, 128 * 4 * 4)  # -1自动计算批量维度,保持批量大小不变
        
        x = self.fc1(x)           # 全连接层:2048→512,尺寸变为[batch_size, 512]
        x = self.relu3(x)         # 激活函数(复用relu3,与卷积块3共用)
        x = self.dropout(x)       # Dropout随机丢弃神经元,不改变尺寸
        x = self.fc2(x)           # 全连接层:512→10,尺寸变为[batch_size, 10](未激活,直接输出logits)
        
        return x  # 输出未经过Softmax的logits,适用于交叉熵损失函数



# 初始化模型
model = CNN()
model = model.to(device)  # 将模型移至GPU(如果可用)

batch归一化

Batch 归一化是深度学习中常用的一种归一化技术,加速模型收敛并提升泛化能力。通常位于卷积层后。

卷积操作常见流程如下:

1. 输入 → 卷积层 → Batch归一化层(可选) → 池化层 → 激活函数 → 下一层

2. Flatten -> Dense (with Dropout,可选) -> Dense (Output)

其中,BatchNorm 应在池化前对空间维度的特征完成归一化,以确保归一化统计量基于足够多的样本(空间位置),避免池化导致的统计量偏差

旨在解决深度神经网络训练中的内部协变量偏移问题:深层网络中,随着前层参数更新,后层输入分布会发生变化,导致模型需要不断适应新分布,训练难度增加。就好比你在学新知识,知识体系的基础一直在变,你就得不断重新适应,模型训练也是如此,这就导致训练变得困难,这就是内部协变量偏移问题。

通过对每个批次的输入数据进行标准化(均值为 0、方差为 1),想象把一堆杂乱无章、分布不同的数据规整到一个标准的样子。

1. 使各层输入分布稳定,让数据处于激活函数比较合适的区域,缓解梯度消失 / 爆炸问题;

2. 因为数据分布稳定了,所以允许使用更大的学习率,提升训练效率。

特征图

卷积层输出的叫做特征图,通过输入尺寸和卷积核的尺寸、步长可以计算出输出尺寸。可以通过可视化中间层的特征图,理解 CNN 如何从底层特征(如边缘)逐步提取高层语义特征(如物体部件、整体结构)。MLP是不输出特征图的,因为他输出的一维向量,无法保留空间维度

特征图就代表着在之前特征提取器上提取到的特征,可以通过 Grad-CAM方法来查看模型在识别图像时,特征图所对应的权重是多少。

调度器

ReduceLROnPlateau调度器适用于当监测的指标(如验证损失)停滞时降低学习率。是大多数任务的首选调度器,尤其适合验证集波动较大的情况

这种学习率调度器的方法相较于之前只有单纯的优化器,是一种超参数的优化方法,它通过调整学习率来优化模型。

常见的优化器有 adam、SGD、RMSprop 等,而除此之外学习率调度器有 lr_scheduler.StepLR、lr_scheduler.ExponentialLR、lr_scheduler.CosineAnnealingLR 等。

criterion = nn.CrossEntropyLoss()  # 交叉熵损失函数
optimizer = optim.Adam(model.parameters(), lr=0.001)  # Adam优化器

# 引入学习率调度器,在训练过程中动态调整学习率--训练初期使用较大的 LR 快速降低损失,训练后期使用较小的 LR 更精细地逼近全局最优解。
# 在每个 epoch 结束后,需要手动调用调度器来更新学习率,可以在训练过程中调用 scheduler.step()
scheduler = optim.lr_scheduler.ReduceLROnPlateau(
    optimizer,        # 指定要控制的优化器(这里是Adam)
    mode='min',       # 监测的指标是"最小化"(如损失函数)
    patience=3,       # 如果连续3个epoch指标没有改善,才降低LR
    factor=0.5        # 降低LR的比例(新LR = 旧LR × 0.5)

@浙大疏锦行

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

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

相关文章

C#集合循环删除某些行

你想要在遍历集合(例如List)的同时删除某些元素时,直接在循环中删除元素可能会导致问题,因为这可能会改变集合的大小和导致索引问题; 可以用for循环的倒序来删除; 如果要删除满足特定条件的所有元素&…

【Linux 学习计划】-- 进程地址空间

目录 进程地址的引入 进程地址空间基础原理 区域划分的本质 如何理解进程地址空间 越界访问的本质 进一步理解写时拷贝 重谈 fork 返回值 结语 进程地址的引入 我们先来看一段代码: 首先我们可以看到,父进程和子进程是可以同时可以看到一个变量…

CTFHub-RCE 命令注入-过滤空格

观察源代码 代码里面可以发现过滤了空格 判断是Windows还是Linux 源代码中有 ping -c 4 说明是Linux 查看有哪些文件 127.0.0.1|ls 打开flag文件 我们尝试将空格转义打开这个文件 利用 ${IFS} 127.0.0.1|cat${IFS}flag_195671031713417.php 可是发现 文本内容显示不出来&…

Express教程【002】:Express监听GET和POST请求

文章目录 2、监听post和get请求2.1 监听GET请求2.2 监听POST请求 2、监听post和get请求 创建02-app.js文件。 2.1 监听GET请求 1️⃣通过app.get()方法,可以监听客户端的GET请求,具体的语法格式如下: // 1、导入express const express req…

【PostgreSQL 03】PostGIS空间数据深度实战:从地图服务到智慧城市

PostGIS空间数据深度实战:从地图服务到智慧城市 关键词 PostGIS, 空间数据库, 地理信息系统, GIS, 空间查询, 地理分析, 位置服务, 智慧城市, 空间索引, 坐标系统 摘要 PostGIS是PostgreSQL的空间数据扩展,它将普通的关系数据库转变为强大的地理信息系统…

HIT-csapp大作业:程序人生-HELLO‘s P2P

计算机系统 大作业 题 目 程序人生-Hello’s P2P 专 业 计算学部 学  号 2023111813 班 级 23L0518 学 生 鲁永哲 指 导 教 师 史先俊 计…

深入探讨redis:主从复制

前言 如果某个服务器程序,只部署在一个物理服务器上就可能会面临一下问题(单点问题) 可用性问题,如果这个机器挂了,那么对应的客户端服务也相继断开性能/支持的并发量有限 所以为了解决这些问题,就要引入分布式系统&#xff0c…

帕金森常见情况解读

一、身体出现的异常节奏​ 帕金森会让身体原本协调的 “舞步” 出现错乱。它是一种影响身体行动能力的状况,随着时间推进,就像老旧的时钟,齿轮转动不再顺畅,使得身体各个部位的配合逐渐失衡,打乱日常行动的节奏。​ …

清华大学发Nature!光学工程+神经网络创新结合

2025深度学习发论文&模型涨点之——光学工程神经网络 清华大学的一项开创性研究成果在《Nature》上发表,为光学神经网络的发展注入了强劲动力。该研究团队巧妙地提出了一种全前向模式(Fully Forward Mode,FFM)的训练方法&…

【android bluetooth 案例分析 04】【Carplay 详解 3】【Carplay 连接之车机主动连手机】

1. 背景 在前面的文章中,我们已经介绍了 carplay 在车机中的角色划分, 并实际分析了 手机主动连接车机的案例。 感兴趣可以 查看如下文章介绍。 【android bluetooth 案例分析 04】【Carplay 详解 1】【CarPlay 在车机侧的蓝牙通信原理与角色划分详解】…

C++学习-入门到精通【11】输入/输出流的深入剖析

C学习-入门到精通【11】输入/输出流的深入剖析 目录 C学习-入门到精通【11】输入/输出流的深入剖析一、流1.传统流和标准流2.iostream库的头文件3.输入/输出流的类的对象 二、输出流1.char* 变量的输出2.使用成员函数put进行字符输出 三、输入流1.get和getline成员函数2.istrea…

NW969NW978美光闪存颗粒NW980NW984

NW969NW978美光闪存颗粒NW980NW984 技术解析:NW969、NW978、NW980与NW984的架构创新 美光(Micron)的闪存颗粒系列,尤其是NW969、NW978、NW980和NW984,代表了存储技术的前沿突破。这些产品均采用第九代3D TLC&#xf…

使用 ssld 提取CMS 签名并重签名

拿SpringBoard的cms签名和entitlements.xml,对tihook.dylib进行重签名 工具来源:https://github.com/eksenior/ssld

大厂前端研发岗位PWA面试题及解析

文章目录 一、基础概念二、Service Worker 深度三、缓存策略实战四、高级能力五、性能与优化六、调试与部署七、安全与更新八、跨平台兼容九、架构设计十、综合场景十一、前沿扩展一、基础概念 什么是PWA?列举3个核心特性 解析:渐进式网页应用。核心特性:离线可用、类原生体…

第十四章 MQTT订阅

系列文章目录 系列文章目录 第一章 总体概述 第二章 在实体机上安装ubuntu 第三章 Windows远程连接ubuntu 第四章 使用Docker安装和运行EMQX 第五章 Docker卸载EMQX 第六章 EMQX客户端MQTTX Desktop的安装与使用 第七章 EMQX客户端MQTTX CLI的安装与使用 第八章 Wireshark工具…

腾讯云推出云开发AI Toolkit,国内首个面向智能编程的后端服务

5月28日,腾讯云开发 CloudBase 宣布推出 AI Toolkit(CloudBase AI Toolkit),这是国内首个面向智能编程的后端服务,适配 Cursor 等主流 AI 编程工具。 云开发 AI Toolkit旨在解决 AI 辅助编程的“最后一公里”问题&…

前端-不对用户显示

这是steam的商店偏好设置界面,在没有被锁在国区的steam账号会有5个选项,而被锁在国区的账号只有3个选项,这里使用的技术手段仅仅在前端隐藏了这个其他两个按钮。 单击F12打开开发者模式 单击1处,找到这一行代码,可以看…

WPF【10_2】数据库与WPF实战-示例

客户预约关联示例图 MainWindow.xaml 代码 <Window x:Class"WPF_CMS.MainWindow" xmlns"http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x"http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d"ht…

Cursor奇技淫巧篇(经常更新ing)

Dot files protection &#xff1a;Cursor当开启了Agent模式之后可以自动帮我们写文件&#xff0c;但是一般项目中的一些配置文件&#xff08;通常以.开头的&#xff09;都是非常重要性&#xff0c;为了防止Cursor在运行的过程中自己修改这些文件&#xff0c;导致风险&#xff…

Unity3D仿星露谷物语开发58之保存时钟信息到文件

1、目标 保存当前的时钟信息到文件中。 2、修改TimeManager对象 TimeManager对象添加组件&#xff1a;Generate GUID 3、修改SceneSave.cs脚本 添加1行代码&#xff1a; 4、修改TimeManager.cs脚本 添加&#xff1a; using System; 修改TimeManager类&#xff1a; 添加属…