Python自动人工智能训练数据增强工具 | DALI介绍(含代码)

news2024/11/24 23:10:20

Python自动人工智能训练数据增强工具 | DALI介绍(含代码)


文章目录

  • Python自动人工智能训练数据增强工具 | DALI介绍(含代码)
    • 自动数据增强方法
    • DALI 和条件执行
    • 使用 DALI 自动增强
    • 使用 DALI 的自动增强性能
    • 尝试使用 DALI 进行自动增强

深度学习模型需要数百 GB 的数据才能很好地概括未见过的样本。 数据扩充有助于增加数据集中示例的可变性。

当数据增强的选择依赖于设置模型训练的工程师的领域知识、技能和直觉时,传统的数据增强方法可以追溯到统计学习。

出现了自动增强以减少对手动数据预处理的依赖。 它结合了应用自动调整和根据概率分布随机选择增强的想法。

事实证明,使用自动数据增强方法(例如 AutoAugment 和 RandAugment)可以通过使模型在训练中看到的样本多样化来提高模型的准确性。 自动增强使数据预处理更加复杂,因为批次中的每个样本都可以使用不同的随机增强进行处理。

在这篇文章中,我们介绍了如何实现和使用 GPU 加速的 NVIDIA DALI自动增强工具来优化训练数据。

自动数据增强方法

自动增强基于标准图像变换,如旋转、剪切、模糊或亮度调整。 大多数操作接受一个称为幅度的控制参数。 量级越大,说明操作对图像的影响越大。

传统上,增强策略是由工程师手写的固定操作序列。 自动增强策略与传统策略的区别在于增强和参数的选择不是固定的,而是概率性的。

AutoAugment 使用强化学习从数据中学习最佳概率增强策略,将目标模型的泛化视为奖励信号。 使用 AutoAugment,我们发现了图像数据集的新策略,如 ImageNet、CIFAR-10 和 SVHN,超过了最先进的精度。

AutoAugment 策略是一组增强对。 每个增强都用应用或跳过操作的幅度和概率进行参数化。 运行策略时,随机选择并应用其中一对,独立于每个样本。

学习策略意味着寻找最好的增强对、它们的大小和概率。 目标模型必须在策略搜索过程中多次重新训练。 这使得策略搜索的计算成本变得巨大。

为避免计算成本高昂的搜索步骤,您可以重用在类似任务中找到的现有策略。 或者,您可以使用旨在使搜索步骤最少的其他自动数据扩充方法。

RandAugment 将策略搜索步骤减少到仅调整两个数字:N 和 M。N 是要在序列中应用的随机选择操作的数量,M 是所有操作共享的大小。 尽管 RandAugment 很简单,但我们发现这种数据增强方法在与相同的增强集一起使用时优于 AutoAugment 发现的策略。

TrivialAgument 通过删除两个超参数建立在 RandAugment 之上。 我们建议为每个样本应用一个随机选择的单一增强。 TrivialAugment 和 RandAugment 之间的区别在于幅度不是固定的,而是随机均匀采样的。

结果表明,在训练期间随机抽样增强对于模型泛化可能比广泛搜索仔细调整的策略更重要。

从 1.24 版开始,DALI 附带了 AutoAugment、RandAugment 和 TrivialAugment 的即用型实现。 在本文中,我们将向您展示如何使用所有这些最先进的实现,并讨论 DALI 中作为其实现支柱的新条件执行功能。

DALI 和条件执行

现代 GPU 架构显着加快了深度学习模型的训练速度。 然而,为了实现最大的端到端性能,模型使用的批量数据必须快速预处理以避免 CPU 瓶颈。

NVIDIA DALI 通过异步执行、预取、专用加载器、一组丰富的面向批处理的增强以及与 PyTorch、TensorFlow、PaddlePaddle 和 MXNet 等流行的 DL 框架的集成克服了这一预处理瓶颈。

为了创建数据处理管道,我们在 Python 函数中组合了所需的操作,并使用 @pipeline_def 修饰该函数。 出于性能原因,该函数仅定义 DALI 的执行计划,然后由 DALI 执行程序异步运行。

以下代码示例显示了一个管道定义,用于加载、解码图像并将随机噪声增强应用到图像。

from nvidia.dali import pipeline_def, fn, types 
  
@pipeline_def(batch_size=8, num_threads=4, device_id=0) 
def pipeline(): 
    encoded, _ = fn.readers.file(file_root=data_path, random_shuffle=True) 
    image = fn.decoders.image(encoded, device="mixed") 
    prob = fn.random.uniform(range=[0, 0.15]) 
    distorted = fn.noise.salt_and_pepper(image, prob=prob) 
    return distorted 

在这里插入图片描述

管道的代码是面向样本的,而输出是一批图像。 指定运算符时无需处理批处理,因为 DALI 在内部进行管理。

然而,直到现在,还无法表达对批次中的样本子集起作用的操作。 这阻止了 DALI 自动增强的实现,因为它会为每个样本随机选择不同的操作。

DALI 中引入的条件执行使您能够使用常规 Python 语义为批次中的每个样本选择单独的操作:if 语句。 以下代码示例随机应用两个扩充之一。

@pipeline_def(batch_size=4, num_threads=4, device_id=0,
              enable_conditionals=True)
def pipeline():
    encoded, _ = fn.readers.file(file_root=data_path, random_shuffle=True)
    image = fn.decoders.image(encoded, device="mixed")
    change_stauration = fn.random.coin_flip(dtype=types.BOOL)
    if change_stauration:
        distorted = fn.saturation(image, saturation=2)
    else:
        edges = fn.laplacian(image, window_size=5)
        distorted = fn.cast_like(0.5 * image + 0.5 * edges, image)
    return distorted

在下图中,我们根据 fn.random.coin_flip 结果增加了一些样本的饱和度,并在其他样本中使用拉普拉斯算子检测了边缘。 DALI 将 if-else 语句翻译成一个执行计划,根据 if 条件将批处理分成两个批处理。 这样,部分批次将分别并行处理,而落入同一 if-else 分支的样本仍然受益于批处理的 CUDA 内核。

您可以轻松地扩展该示例以使用从任意集合中随机选择的扩充。 在下面的代码示例中,我们定义了三个扩充并实现了一个选择运算符,它根据随机选择的整数选择正确的一个。

def edges(image):
    edges = fn.laplacian(image, window_size=5)
    return fn.cast_like(0.5 * image + 0.5 * edges, image)
 
def rotation(image):
    angle = fn.random.uniform(range=[-45, 45])
    return fn.rotate(image, angle=angle, fill_value=0)
 
def salt_and_pepper(image):
    return fn.noise.salt_and_pepper(image, prob=0.15)
 
 
def select(image, operation_idx, operations, i=0):
    if i >= len(operations):
        return image
    if operation_idx == i:
        return operations[i](image)
    return select(image, operation_idx, operations, i + 1)

在下面的代码示例中,我们选择了一个随机整数,并在 DALI 管道内使用 select 运算符运行了相应的操作。

@pipeline_def(batch_size=6, num_threads=4, device_id=0,
              enable_conditionals=True)
def pipeline():
    encoded, _ = fn.readers.file(file_root=data_path, random_shuffle=True)
    image = fn.decoders.image(encoded, device="mixed")
    operations = [edges, rotation, salt_and_pepper]
    operation_idx = fn.random.uniform(values=list(range(len(operations))))
    distorted = select(image, operation_idx, operations)
    return distorte

结果,我们得到了一批图像,其中每个图像都通过一个随机选择的操作进行了变换:边缘检测、旋转和椒盐噪声失真。

在上图中,管道对每个图像应用随机选择的增强:旋转、边缘检测或椒盐失真。

使用 DALI 自动增强

通过按样本选择运算符,您可以实现自动扩充。 为了便于使用,NVIDIA 在 DALI 中引入了 auto_aug 模块,其中包含流行自动增强的即用型实现:auto_aug.auto_augment、auto_aug.rand_augment 和 auto_aug.trivial_augment。 它们可以开箱即用,也可以通过调整增强幅度或构建用户定义的 DALI 原语增强来定制。

DALI 中的 auto_aug.augmentations 模块提供了一组由自动增强过程共享的默认操作:

  • auto_contrast
  • brightness
  • color
  • contrast
  • equalize
  • invert
  • posterize
  • rotate
  • sharpness
  • shear_x
  • shear_y
  • solarize
  • solarize_add
  • translate_x
  • translate_y

以下代码示例显示如何运行 RandAugment。

import nvidia.dali.auto_aug.rand_augment as ra
 
@pipeline_def(batch_size=6, num_threads=4, device_id=0,
              enable_conditionals=True)
def pipeline():
    encoded, _ = fn.readers.file(file_root=data_path, random_shuffle=True)
    shape = fn.peek_image_shape(encoded)
    image = fn.decoders.image(encoded, device="mixed")
    distorted = ra.rand_augment(image, n=3, m=15, shape=shape, fill_value=0)
    return distorted

rand_augment 运算符接受解码后的图像、图像的形状、要在序列中应用的随机增强数 (n=3) 以及这些操作应具有的幅度(m=15,超出可自定义的 [0, 30] 范围 ).

在这里插入图片描述

上图中的增强分为两类:几何和颜色变换。

在某些应用程序中,您可能必须限制使用的扩充集。 例如,如果数据集由数字图片组成,将数字“9”旋转 180 度会使关联标签无效。 以下代码示例使用一组有限的扩充运行 rand_augment。

from nvidia.dali.auto_aug import augmentations as a
 
augmentations = [
    a.shear_x.augmentation((0, 0.3), randomly_negate=True),
    a.shear_y.augmentation((0, 0.3), randomly_negate=True),
    a.translate_x.augmentation((0, 0.45), randomly_negate=True),
    a.translate_y.augmentation((0, 0.45), randomly_negate=True),
    a.rotate.augmentation((0, 30), randomly_negate=True),
]

每个增强都可以用幅度如何映射到转换强度来参数化。 例如,a.rotate.augmentation((0, 30)) 指定您要将图像旋转不超过 30 度的角度。 randomly_negate=True 指定角度应随机取反,以便您随机顺时针或逆时针旋转图像。

以下代码示例以类似于 RandAugment 的方式应用扩充。

@pipeline_def(batch_size=8, num_threads=4, device_id=0,
              enable_conditionals=True)
def pipeline():
    encoded, _ = fn.readers.file(file_root=data_path, random_shuffle=True)
    shape = fn.peek_image_shape(encoded)
    image = fn.decoders.image(encoded, device="mixed")
    distorted = ra.apply_rand_augment(augmentations, image, n=3, m=15, shape=shape, fill_value=0)
    return distorted

前两个管道定义之间的唯一区别是您使用了更通用的 apply_rand_augment 运算符,该运算符接受附加参数,即扩充列表。

接下来,将自定义扩充添加到集合中。 以抠图为例。 它使用 DALI fn.erase 函数用归零矩形随机覆盖图像的一部分。 用 @augmentation 装饰器包装 fn.erase ,它描述了如何将幅度映射到剪切矩形中。 cutout_size 是一个大小在 0.01 到 0.4 范围内的元组,而不是普通大小。

from nvidia.dali.auto_aug.core import augmentation
 
def cutout_shape(size):
    # returns the shape of the rectangle
    return [size, size]
 
@augmentation(mag_range=(0.01, 0.4), mag_to_param=cutout_shape)
def cutout(image, cutout_size, fill_value=None):
    anchor = fn.random.uniform(range=[0, 1], shape=(2,))
    return fn.erase(image, anchor=anchor, shape=cutout_size, normalized=True, centered_anchor=True, fill_value=fill_value)
 
augmentations += [cutout]

要进行更改,请运行自定义的几何增强集,例如 TrivialAugment,即使用随机大小。 对代码的改动很小; 您从 aut_aug 模块导入并调用 trivial_augment 而不是 rand_augment 。

import nvidia.dali.auto_aug.trivial_augment as ta
 
@pipeline_def(batch_size=8, num_threads=4, device_id=0,
              enable_conditionals=True)
def pipeline():
    encoded, _ = fn.readers.file(file_root=data_path, random_shuffle=True)
    shape = fn.peek_image_shape(encoded)
    image = fn.decoders.image(encoded, device="mixed")
    distorted = ta.apply_trivial_augment(augmentations, image, shape=shape, fill_value=0)
    return distorted

使用 DALI 的自动增强性能

现在,将 DALI 和 AutoAugment 插入模型训练并比较吞吐量,以 EfficientNet-b0 为例,改编自 NIVDIA 深度学习示例。 AutoAugment 是 EfficientNet 系列模型预处理阶段的标准部分。

在链接示例中,AutoAugment 策略使用 PyTorch 数据加载器实现并在 CPU 上运行,而模型训练在 GPU 上进行。 当 DALI 管道取代运行在 CPU 上的数据加载器时,吞吐量会增加。 DALI 示例中提供了 EfficientNet 和 DALI 的源代码。

该模型以自动混合精度模式 (AMP) 运行,批量大小:DGX-1 V100 为 128,DGX A100 为 256。

我们使用两种硬件设置运行实验:DGX-1 V100 16 GB 和 DGX A100。 我们测量了每秒处理的图像数量(越多越好)。 在这两种情况下,速度都提高了:DGX-1 V100 提高了 33%,DGX A100 提高了 12%。

图中虚线表示的理论吞吐量是仅通过改进数据预处理可以预期的训练速度的上限。 为了衡量理论极限,我们使用在每次迭代中重复的单批合成数据而不是真实数据来运行训练。 这让我们看看在不需要预处理的情况下模型处理批次的速度有多快。

综合案例和 CPU 数据加载器案例之间的显着性能差距表明存在预处理瓶颈。 要验证假设,请查看训练期间的 GPU 利用率。

这些图显示了我们在给定 GPU 利用率上花费了多少时间。 您可以看到,当使用在 CPU 上运行的数据加载器对数据进行预处理时,GPU 利用率会反复下降。 值得注意的是,在大约 5% 的时间里,利用率下降到 10% 以下。 这表明训练有规律地停止,等待下一批从数据加载器到达。

如果使用 DALI 将加载和自动增强步骤移至 GPU,则 [0, 10] 条消失并且整体 GPU 利用率增加。 图 6 中显示的使用 DALI 的训练吞吐量增加证实我们设法克服了之前的预处理瓶颈。

有关如何发现和解决数据加载瓶颈的更多信息,请参阅案例研究:带有 DALI 的 ResNet-50。

尝试使用 DALI 进行自动增强

您可以下载最新版本的预构建和测试 DALI pip 包。 您会发现 DALI 已集成为 NVIDIA NGC 容器的一部分,适用于 TensorFlow、PyTorch、PaddlePaddle 和由 Apache MXNet 提供支持的 NVIDIA 优化深度学习框架。 DALI Triton 后端是 NVIDIA Triton 推理服务器容器的一部分。

有关新 DALI 功能和增强功能的更多信息,请参阅 DALI 用户指南示例和最新的 DALI 发行说明。

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

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

相关文章

回归测试:优先级(Coverage 的适应度函数)

回归测试:优先级 介绍 在确定优先级时,我们的目标是为测试用例找到一个好的顺序。理想情况下,我们希望尽早发生任何故障。这可以加快整体开发过程,例如: 有时,一旦发现失败,我们就会停止测试。…

HashMap详细讲解-面试题大全

HashMap底层数据结构是什么?1.7和1.8有何不同 1.7是 数组 链表,1.8 是数组 (链表 或者 红黑树) 当链表的元素比较多的时候,链表就会转换成红黑树,红黑树的元素减少了,红黑树也会转换成链表 为…

前后分离的优势

1.可以实现真正的前后端解耦,前端服务器使用nginx。 前端/WEB服务器放的是css,js,图片等等一系列静态资源(甚至你还可以css,js,图片等资源放到特定的文件服务器,例如阿里云的oss,并使…

【计算机网络】前后端分离,HTTP协议,网络分层结构,TCP,强缓存/协商缓存

❤️ Author: 老九 ☕️ 个人博客:老九的CSDN博客 🙏 个人名言:不可控之事 乐观面对 😍 系列专栏: 文章目录 前后端分类HTTP协议HTTP组成HTTP的版本HTTP的请求方式HTTP请求头HTTP响应头强缓存和协商缓存 HT…

Linux ls -l输出文件信息详解

在linux中,我们知道一切皆为文件,经常我们会使用ls -l去查看文件的信息,今天会大家详细讲解一下ls -l输出的文件属性信息。 1.ls -l输出 命令: ls -l 通过ls -l命令输出,我们可以看到上图中的属性信息输出&#xff…

【珍藏版】生态系统NPP及碳源、碳汇模拟、土地利用变化、未来气候变化、空间动态模拟

由于全球变暖、大气中温室气体浓度逐年增加等问题的出现,“双碳”行动特别是碳中和已经在世界范围形成广泛影响。碳中和可以从碳排放(碳源)和碳固定(碳汇)这两个侧面来理解。陆地生态系统在全球碳循环过程中有着重要作…

五、JSP05 分页查询及文件上传

五、JSP 分页查询及文件上传 5.1 使用分页显示数据 通过网络搜索数据时最常用的操作,但当数据量很大时,页面就会变得冗长,用户必须拖动才能浏览更多的数据 分页是把数据库中需要展示的数据逐页分步展示给用户 以分页的形式显示数据&#xff…

Elasticsearch 8.X “图搜图”实战

1、什么是图搜图? "图搜图"指的是通过图像搜索的一种方法,用户可以通过上传一张图片,搜索引擎会返回类似或者相关的图片结果。这种搜索方式不需要用户输入文字,而是通过比较图片的视觉信息来找到相似或相关的图片。这项…

Tomcat服务器的安装即相关介绍

一、Tomcat的安装步骤 1、访问官网下载点击此处进入Tomcat官网; 2、在下图所示位置点击想要下载的版本下载,这边演示的是以Tomcat8为演示对象; 3、进入下载页面如下图所示,根据系统类型和版本选择合适的安装包; 4、下…

Wampsever升级增加php5.6的方法过程

1、下载wampserver2.5,文件包名:wampserver2.5-Apache-2.4.9-Mysql-5.6.17-php5.5.12-64b.exe https://sourceforge.net/projects/wampserver/files/WampServer%202/Wampserver%202.5/ 这个版本只有40M,包含: Apache-2.4.9&#x…

SpringCloud OpenFeign 学习

SpringCloud OpenFeign 文章目录 SpringCloud OpenFeign1 OpenFeign介绍2 OpenFeign-应用实例3 OpenFeign 测试 1 OpenFeign介绍 OpenFeign 是个声明式 WebService 客户端,使用 OpenFeign 让编写 Web Service 客户端 更简单 它的使用方法是定义一个服务接口然后在上…

【Java 抽象类抽象方法】什么是抽象类方法,如何定义,起什么作用?

博主:_LJaXi Or 東方幻想郷 专栏: Java | 从入门到入坟 Java 抽象类 & 抽象方法 抽象类的概念 👅抽象方法的概念 🐬抽象类和抽象方法结合使用 🦄 Java中的抽象类和抽象方法是面向对象编程中的重要概念,…

【系统学习】Java基础4之lamda表达式和函数式接口

lamda表达式与函数式接口 lamda表达式 语法格式一:无参,无返回值 Lambda 需要一个参数,但是没有返回值 语法格式三:数据类型可以省略,因为可由编译器推断得出,称为“类型推断” 语法格式四:…

MySQL和Redis之间的存储区别

概述 MySQL是一种关系型数据库,而Redis是一种键值对存储数据库。虽然它们都是用来存储和管理数据的,但是它们在很多方面都有不同,但是它们在存储策略、日志存储方式、硬盘存储、数据恢复等方面都有一定的区别。 数据类型 MySQL支持多种数据…

电脑怎么通过网络传输文件?

可以通过网络在电脑之间传输文件吗? “由于天气的原因,我的老板决定让所有员工在家工作。但是我很多工作文件都在公司的电脑中,怎么才能将公司的文件远程传输到我家里的电脑上?电脑可以通过网络远程传输文件吗?” …

计算机网络 | I/O模型、网络模型(OSI七层及TCP/IP四层)

欢迎关注博主 Mindtechnist 或加入【Linux C/C/Python社区】一起学习和分享Linux、C、C、Python、Matlab,机器人运动控制、多机器人协作,智能优化算法,滤波估计、多传感器信息融合,机器学习,人工智能等相关领域的知识和…

Python快速实现网页工具的利器

Python快速实现网页工具的利器 Streamlit是一个基于Python的Web应用程序开发框架,它具有快速开发、交互式、易于使用等特点。使用Streamlit,开发者可以很容易地将Python代码转换为漂亮的、交互式的Web应用程序,无需繁琐的前端开发经验。 如果…

什么是浪涌保护器SPD

浪涌保护器(SPD),也称为电涌保护器,是为各种电子设备,仪器和通信线路提供安全保护的电子设备。当由于外部干扰在电路或通信电路中突然产生尖峰电流或电压时,浪涌保护装置可以在很短的时间内传导和分流&…

设计模式之~策略模式

策略模式(Strategy): 它定义了算法家族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化,不会影响到使用算法的客户。 结构图: 实例: 优点: 策略模式…

MySQL行锁浅析

概述 MySQL是非常流行的关系型数据库,许多系统都使用它来存储和管理数据。在高并发环境下,为了保证数据的一致性和可靠性,数据库需要实现并发控制,其中包括锁机制。MySQL提供了两种锁类型,一种是表级锁,另…