Pytorch深度学习【十四】

news2025/7/3 20:30:01

批量归一化

  • 归一化
    • 损失出现在最后,后面的层(高级语义层)训练较快
    • 数据输入在最底部
      • 底部的层训练慢
      • 底部层一变化,所有高级语义层都得跟着变
      • 最后的那些层需要重新学习多次—收敛速度变慢
    • 问题—是否可以在学习底部层的时候避免变化顶部层
  • 批量归一化
    • 固定小批量里面每一层的均值和方差
      μ B = 1 | B | ∑ i ∈ B x i a n d σ B 2 = 1 | B | ∑ i ∈ B ( x i − μ B ) 2 + ϵ \mu_B = \frac{1}{|B|}\sum_{i\in{B}}x_i \quad and \quad \sigma_B^2=\frac{1}{|B|}\sum_{i\in{B}}(x_i-\mu_B)^2+\epsilon μB=B1iBxiandσB2=B1iB(xiμB)2+ϵ
    • 进行可学习参数的归一化
      x i + 1 = γ x i − μ B σ B + β x_{i+1}=\gamma\frac{x_i-\mu_B}{\sigma_B}+\beta xi+1=γσBxiμB+β
    • 意思是先进行小批量的均值方差计算,而后对每个输入数据进行处理
  • 批量归一化层
    • 可以学习的参数为 γ β \gamma \quad \beta γβ
    • 批量归一化层作用位置
      • 全连接层和卷积层输出上,激活层之前
      • 全连接和卷积层输入上
    • 对全连接层,作用在特征维度上
    • 对于卷积层,作用在通道维上
  • 批量归一化的作用
    • 加入噪音来控制模型复杂度
      x i + 1 = γ x i − μ B σ B + β x_{i+1}=\gamma\frac{x_i-\mu_B}{\sigma_B}+\beta xi+1=γσBxiμB+β
    • 没必要跟丢弃法混合使用
  • 总结
    • 批量归一化固定小批量中的均值和方差,然后学习出适合的偏移和缩放
    • 可以加速收敛速度,因此学习率可以比较大,但一般不改变模型精确度
  • 代码实现
    • 从零实现
      def batch_norm(X, gamma, beta, moving_mean, moving_var, eps, momentum):
        if not torch.is_grad_enabled():
            X_hat = (X - moving_mean) / torch.sqrt(moving_var + eps)
        else:
            assert len(X.shape) in (2, 4)
            if len(X.shape) == 2:
                mean = X.mean(dim=0)
                var = ((X - mean)**2).mean(dim=0)
            else:
                mean = X.mean(dim=(0, 2, 3), keepdim=True)
                var = ((X - mean)**2).mean(dim=(0, 2, 3), keepdim=True)
            X_hat = (X - mean) / torch.sqrt(var + eps)
            moving_mean = momentum * moving_mean + (1.0 - momentum) * mean
            moving_var = momentum * moving_var + (1.0 - momentum) * var
        Y = gamma * X_hat + beta
        return Y, moving_mean.data, moving_var.data
      class BatchNorm(nn.Module):
          def __init__(self, num_features, num_dims):
              super().__init__()
              if num_dims == 2:
                  shape = (1, num_features)
              else:
                  shape = (1, num_features, 1, 1)
              self.gamma = nn.Parameter(torch.ones(shape))
              self.beta = nn.Parameter(torch.zeros(shape))
              self.moving_mean = torch.zeros(shape)
              self.moving_var = torch.ones(shape)
      
          def forward(self, X):
              if self.moving_mean.device != X.device:
                  self.moving_mean = self.moving_mean.to(X.device)
                  self.moving_var = self.moving_var.to(X.device)
              Y, self.moving_mean, self.moving_var = batch_norm(
                  X, self.gamma, self.beta, self.moving_mean, self.moving_var,
                  eps=1e-5, momentum=0.9)
              return Y
      
    • 快速实现
      net = nn.Sequential(
        nn.Conv2d(1, 6, kernel_size=5), nn.BatchNorm2d(6), # 6就是上一层的输出通道个数
        nn.Sigmoid(), nn.MaxPool2d(kernel_size=2, stride=2)
      )
      

残差神经网络

  • 加深神经网络一直会带来好处么

    • 如果模型的训练方向有问题—模型反而变差
    • 因此,我们要保证后续的模型包含前向模型,要保证学到本该学到的东西
  • 残差块

    • 串联一个层改变函数类,我们希望能扩大函数类
    • 残差块加入快速通道(右边)来得到 f ( x ) = x + g ( x ) f(x)=x+g(x) f(x)=x+g(x)
    • 解读—即使不通过g(x),我依然能直接跳过本层获得上层特征结果
  • 残差网络解决的问题—梯度消失

    • 每层梯度都是本层梯度加上层梯度,保证梯度不会太小导致模型参数更新出现问题
  • 结构图
    在这里插入图片描述

  • 细节实现—引入1*1的目的—修改通道数
    在这里插入图片描述

  • 总结

    • 残差块使得很深的网络更加容易训练
      • 因为其包含了前向模型,可以逐步训练保证稳定性
    • 残差网络对随后的深层神经网络设计产生了深远影响
  • 代码实现

import torch
from torch import nn
from torch.nn import functional as F
from d2l import torch as d2l

class Residual(nn.Module):  
    def __init__(self, input_channels, num_channels, use_1x1conv=False,
                 strides=1):
        super().__init__()
        self.conv1 = nn.Conv2d(input_channels, num_channels, kernel_size=3,
                               padding=1, stride=strides)
        self.conv2 = nn.Conv2d(num_channels, num_channels, kernel_size=3,
                               padding=1)
        if use_1x1conv:
            self.conv3 = nn.Conv2d(input_channels, num_channels,
                                   kernel_size=1, stride=strides)
        else:
            self.conv3 = None
        self.bn1 = nn.BatchNorm2d(num_channels)
        self.bn2 = nn.BatchNorm2d(num_channels)
        self.relu = nn.ReLU(inplace=True)

    def forward(self, X):
        Y = F.relu(self.bn1(self.conv1(X)))
        Y = self.bn2(self.conv2(Y))
        if self.conv3:
          X = self.conv3(X)
        Y += X
        return F.relu(Y)
b1 = nn.Sequential(nn.Conv2d(1, 64, kernel_size=7, stride=2, padding=3),
                   nn.BatchNorm2d(64), nn.ReLU(),
                   nn.MaxPool2d(kernel_size=3, stride=2, padding=1))

def resnet_block(input_channels, num_channels, num_residuals,
                 first_block=False):
    blk = []
    for i in range(num_residuals):
        if i == 0 and not first_block:
            blk.append(
                Residual(input_channels, num_channels, use_1x1conv=True,
                         strides=2))
        else:
            blk.append(Residual(num_channels, num_channels))
    return blk

b2 = nn.Sequential(*resnet_block(64, 64, 2, first_block=True))
b3 = nn.Sequential(*resnet_block(64, 128, 2))
b4 = nn.Sequential(*resnet_block(128, 256, 2))
b5 = nn.Sequential(*resnet_block(256, 512, 2))

net = nn.Sequential(b1, b2, b3, b4, b5, nn.AdaptiveAvgPool2d((1, 1)),
                    nn.Flatten(), nn.Linear(512, 10))
X = torch.rand(size=(1, 1, 224, 224))
for layer in net:
    X = layer(X)
    print(layer.__class__.__name__, 'output shape:\t', X.shape)

数据增广

  • 增加一个已有数据集,使得有更多的多样性
    • 在语言里面加入各种不同的背景噪声
    • 改变图片颜色和形状
  • 流程
    • 读取数据—随机读取—数据增强
  • 可以认为是一个正则项
  • 常见办法
    • 翻转
      • 左右翻转
      • 上下翻转
    • 切割
      • 从图片中切割一块而后变形到固定形状
        • 随机高宽比
        • 随机大小
        • 随机位置
    • 颜色
      • 改变色调,饱和度,明亮度
  • 总结
    • 数据增广通过变形数据来获得多样性从而使得模型泛化性能更好
    • 常见图片增广包括翻转、切割、变色
  • 代码实现
#===============================基础操作部分===============================#
!pip install d2l
!pip install matplotlib_inline
%matplotlib inline
import torch
import torchvision
from torch import nn
from d2l import torch as d2l
d2l.set_figsize() # 设置后续画图的大小
!wget -O ./pic/test.jpg "https://cdn.pixabay.com/photo/2017/02/20/18/03/cat-2083492__480.jpg" # 下载照片
img = d2l.Image.open('./pic/test.jpg') # 读取照片
d2l.plt.imshow(img) # 查看当前照片
def apply(img, aug, num_rows=2, num_cols=4, scale=1.5):
  """对img进行2*4张图的aug方法的增广"""
  Y = [aug(img) for _ in range(num_rows*num_cols)]
  d2l.show_images(Y, num_rows, num_cols, scale=scale)
# 图像左右翻转
apply(img, torchvision.transforms.RandomHorizontalFlip())
# 图像上下翻转
apply(img, torchvision.transforms.RandomVerticalFlip())
# 随机裁剪
shape_aug = torchvision.transforms.RandomResizedCrop(
    (200, 200), scale=(0.3, 0.8), ratio=(0.5, 2)
)
# (200, 200)---不论裁剪多大最后都要放大到200200
# scale---裁剪的范围比例
# 拉伸比例
apply(img, shape_aug)
# 随机修改亮度
apply(img, torchvision.transforms.ColorJitter(brightness=0.5, contrast=0.2, saturation=0.6, hue=0.4))
# 增广方式的混合使用
color_aug = torchvision.transforms.ColorJitter(brightness=0.5, contrast=0.2, saturation=0.6, hue=0.4)
augs = torchvision.transforms.Compose([torchvision.transforms.RandomHorizontalFlip(), shape_aug, color_aug])
apply(img, augs)
  • 完整数据增强训练案例
all_images = torchvision.datasets.CIFAR10(
    train=True, root="./data", download=True
)
d2l.show_images([
    all_images[i][0] for i in range(32)], 4, 8, scale=0.8);
train_augs = torchvision.transforms.Compose([
    torchvision.transforms.RandomHorizontalFlip(),
    torchvision.transforms.ToTensor()])
test_augs = torchvision.transforms.Compose([
    torchvision.transforms.ToTensor()
])
# torchvision.transforms.ToTensor()转换增广使得其可以训练
# 测试不需要增广
# 定义辅助函数,便于读取图像和应用图像增广
def load_cifar10(is_train, augs, batch_size):
  dataset = torchvision.datasets.CIFAR10(
      root='./data', train=is_train, transform=augs, download=True
  )
  dataloader = torch.utils.data.DataLoader(
      dataset, batch_size=batch_size, shuffle=is_train, num_workers=4
  )
  return dataloader
# 定义一个函数,使用多GPU对模型进行训练和评估
def train_batch_ch13(net, X, y, loss, trainer, devices):
    if isinstance(X, list):
        X = [x.to(devices[0]) for x in X]
    else:
        X = X.to(devices[0])
    y = y.to(devices[0])
    net.train()
    trainer.zero_grad()
    pred = net(X)
    l = loss(pred, y)
    l.sum().backward()
    trainer.step()
    train_loss_sum = l.sum()
    train_acc_sum = d2l.accuracy(pred, y)
    return train_loss_sum, train_acc_sum

def train_ch13(net, train_iter, test_iter, loss, trainer, num_epochs,
               devices=d2l.try_all_gpus()):
    timer, num_batches = d2l.Timer(), len(train_iter)
    animator = d2l.Animator(xlabel='epoch', xlim=[1, num_epochs], ylim=[0, 1],
                            legend=['train loss', 'train acc', 'test acc'])
    net = nn.DataParallel(net, device_ids=devices).to(devices[0]) # 多GPU训练
    for epoch in range(num_epochs):
        metric = d2l.Accumulator(4)
        for i, (features, labels) in enumerate(train_iter):
            timer.start()
            l, acc = train_batch_ch13(net, features, labels, loss, trainer,
                                      devices)
            metric.add(l, acc, labels.shape[0], labels.numel())
# 定义 train_with_data_aug 函数,使用图像增广来训练模型
batch_size, devices, net = 256, d2l.try_all_gpus(), d2l.resnet18(10, 3)

def init_weights(m):
    if type(m) in [nn.Linear, nn.Conv2d]:
        nn.init.xavier_uniform_(m.weight)

net.apply(init_weights)

def train_with_data_aug(train_augs, test_augs, net, lr=0.001):
    train_iter = load_cifar10(True, train_augs, batch_size)
    test_iter = load_cifar10(False, test_augs, batch_size)
    loss = nn.CrossEntropyLoss(reduction="none")
    trainer = torch.optim.Adam(net.parameters(), lr=lr)
    train_ch13(net, train_iter, test_iter, loss, trainer, 10, devices)
# 训练模型
train_with_data_aug(train_augs, test_augs, net)

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

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

相关文章

8 个精彩的免费 G​​IS 软件资源分享

有人说:一个人从1岁活到80岁很平凡,但如果从80岁倒着活,那么一半以上的人都可能不凡。 生活没有捷径,我们踩过的坑都成为了生活的经验,这些经验越早知道,你要走的弯路就会越少。 GIS 软件有两种通用格式&a…

【面试题】2023年前端最新面试题-性能优化篇

原文见:语雀(https://www.yuque.com/deepstates/interview/xtt59x) ● 性能指标 ● 分析工具 ● 优化方式 ○ 加载 ○ 渲染 ● 专题优化 ○ 技术栈:react ○ 浏览器 ○ 打包工具:webpack ● 项目 ⭐️⭐️⭐️ 相关知…

如何隐藏电脑硬盘分区?

无论是个人还是公司的电脑我们都会储存一些重要的数据,有些甚至还是涉及个人隐私或公司的商业机密。为了更好地保护电脑磁盘中的重要资料,部分用户希望能将硬盘分区隐藏起来。那么怎么隐藏硬盘分区呢?方法一:使用磁盘管理隐藏硬盘…

将vscode打造为你的开发工具的首选

文章目录前言vscode主要配置vscode的两个主要快捷键Java配置JDK和Gradle环境主要插件常见的配置launch.json配置运行测试用例常见问题Python主要插件settings.json配置Javascript/typescript常用插件settings.json样例Golang参考前言 什么是IDE? IDE 文本编辑 搜索 代码导…

Matlab矩阵和数组的操作

一、矩阵的建立 1、直接输入法 将矩阵的元素用方括号括起来,按矩阵行的顺序输入各元素,同一行的各元素之间用空格或逗号分隔,不同行的元素之间用分号分隔。 A [16 3 2 13; 5 10 11 8; … 9 6 7 12; 4 15 14 1] A 16 3 2 13 5 10 11 8 9 6…

如何有效的增加 shopee 的流量?

很多卖家选择在跨境电商平台开店。说到跨境电商,大家首先想到的应该是亚马逊、易趣等电商平台,边肖会在shopee平台上给大家带来店铺。新店如何获得流量?有哪些方式?米贸搜为你整理如下:shopee店铺如何获取流量&#xf…

Python学习笔记——函数

函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段。能提高应用的模块性,和代码的重复利用率。定义函数定义函数使用关键字def,后接函数名,再后接放在圆括号()中的可选…

P1036 [NOIP2002 普及组] 选数————C++

题目 [NOIP2002 普及组] 选数 题目描述 已知 nnn 个整数 x1,x2,⋯,xnx_1,x_2,\cdots,x_nx1​,x2​,⋯,xn​&#xff0c;以及 111 个整数 kkk&#xff08;k<nk<nk<n&#xff09;。从 nnn 个整数中任选 kkk 个整数相加&#xff0c;可分别得到一系列的和。例如当 n4n4…

支持ITIL的IT帮助台

什么是ITIL 信息技术基础架构库 &#xff08;ITIL&#xff09; 是一套集成的最佳实践&#xff0c;旨在帮助企业向客户提供 IT 服务。ITIL是由中央设计的广泛采用的框架 计算机和电信局&#xff08;CCTA&#xff09;&#xff0c;英国的政府机构;它目前由AXELOS Ltd拥有。 ITIL…

【微信小程序】实用教程03-自定义底部导航(含自定义tabBar导航高亮需点击两次的解决方案)

开始前&#xff0c;请先完成底部导航的开发&#xff0c;详见 【微信小程序】实用教程01-注册登录账号&#xff0c;获取 AppID、下载安装开发工具、创建项目、上传体验 显然&#xff0c;纯文字的底部导航有点low&#xff0c;还是需要有图标的才酷&#xff0c;下面我们一起来实…

python的numpy的用法总结

本文总结Numpy的用法&#xff0c;建议先学习python的container 基础。numpy可以理解列表或数组。一个numpy数组是一个由不同数值组成的网格。网格中的数据都是同一种数据类型&#xff0c;可以通过非负整型数的元组来访问。维度的数量被称为数组的阶&#xff0c;数组的大小是一个…

五个了解自己天赋优势的分析工具(五)PDP性格测试

PDP性格测试 PDP的全称是Professional Dyna-Metric Programs⾏为特质动态衡量系统&#xff0c;它是⼀个⽤来衡量个⼈的⾏为特质、活⼒、动能、压⼒、精⼒及能量变动情况的系统。 PDP根据⼈的天⽣特质&#xff0c;将⼈群分为五种类型&#xff0c;包括&#xff1a;⽀配型、外向型…

项目部署 koa项目 (后端)

当你用node koa写好项目后&#xff0c;把它部署到服务器上使用 首先&#xff0c;你要买台服务器&#xff0c;链接到你的服务器上&#xff08;我前面部署前端项目有写&#xff0c;你可以参考&#xff09; 安装node 因为我们是node项目&#xff0c;所以先安装node dnf instal…

学习记录662@项目管理之项目整体管理

什么是项目整体管理 整体管理就是要决定在什么时间把工作量分配到相应的资源上&#xff0c;有哪些潜在的问题并在其出现问题之前积极处理&#xff0c;以及协调各项工作使项目整体上取得一个好的结果。项目整体管理包括选择资源分配方案、平衡相互竞争的目标和方案&#xff0c;…

LiveGBS流媒体平台GB/T28181功能-支持GB35114接入海康大华华为设备通过GB35114国标流媒体平台

LiveGBS流媒体平台GB/T28181功能-支持GB35114接入国标流媒体平台接入说明1、LiveNVR通过GB35114接入LiveGBS1.1、开启LiveGBS 35114功能1.2、 获取设备端证书给平台1.3、LiveGBS白名单中添加需要接入的国密设备1.4、导出LiveGBS平台端证书给设备&#xff08;双向认证需要&#…

嵌入式Linux-进程中常用的函数调用

1. execve()函数 系统调用 execve()可以将新程序加载到某一进程的内存空间&#xff0c;通过调用 execve()函数将一个外部的可执行文件加载到进程的内存空间运行&#xff0c;使用新的程序替换旧的程序&#xff0c;而进程的栈、数据、以及堆数据会被新程序的相应部件所替换&…

W13Scan 漏洞扫描器之XSS插件模块编写示例

一、背景 上周将W13Scan目录结构整理了一番&#xff0c;觉得要深入研究还得从代码层&#xff0c;于是尝试编写一下插件&#xff1b;框架本身已经集成了XSS扫描插件&#xff1b; 本篇文章的XSS插件的编写单纯是为了学习这个框架&#xff0c;所以只支持GET型&#xff0c;了解插…

一文解析企业网盘 带你寻找数据协作的“满分答案”

数据量急剧增长&#xff0c;线上办公逐渐成为常态。许多企业都会选择部署企业网盘来满足日益增长的数据管理与数据协作的需求。网盘市场乱花渐欲迷人眼&#xff0c;企业又该如何从中甄别最适合自己的企业网盘&#xff1f; 网盘&#xff0c;企业的数字基建 飞速发展的科技让企业…

[GIT] GIT拆分仓库--不丢git提交历史记录

背景 如果你的代码仓库里有多个目录&#xff0c;你想把其中一个目录拆分出去变成一个独立的代码仓库。重要的一点是拆分的过程中要保留git提交历史记录。 拆分步骤 1. 检查一下你的 repo 的根目录中。 进入根目录后&#xff0c;快速运行 ls 终端命令以确保列出所有子目录。…

ruoyi-vue版本框架(二)源码目录结构的讲解,与底层子项目的讲解

目录1 目录介绍2 ruoyi-common 子项目3 ruoyi-system 子项目4 配置文件5 ruoyi-framework6 数据库表7 druid 监控1 目录介绍 下载下来源码&#xff0c;后端一共有6个模块 其中 rouyi-admin这个子项目是整个若依框架的web项目&#xff0c;也就是我们要启动的后台就是这个子项目…