CUDA-MODE课程笔记 第6课: 如何优化PyTorch中的优化器

news2024/9/19 10:46:22

我的课程笔记,欢迎关注:https://github.com/BBuf/how-to-optim-algorithm-in-cuda/tree/master/cuda-mode

CUDA-MODE课程笔记 第6课: 如何优化PyTorch中的优化器

课程内容

上面三张Slides讲述了运行时间(runtime)和内存使用(memory usage)之间的权衡关系。

第一张Slides:

  • 介绍了运行时间和内存使用通常是相互矛盾的。
  • 展示了两种运输车辆:一辆小卡车(代表低内存使用但速度慢)和一辆大卡车(代表高内存使用但速度快)。
  • 提出了一个问题:如果要运送512辆车,应该选择哪种卡车?

第二张Slides:

  • 在第一张图的基础上增加了一个新的限制条件:途中有一座低通桥。
  • 这代表了在某些情况下,我们可能无法简单地选择高内存使用的方案(大卡车),因为存在硬件或系统限制。

第三张Slides:

  • 明确表示"今天我们专注于速度!"
  • 显示了小卡车被划掉,表明选择了大卡车(高内存使用但速度快的方案)。
  • 同时提醒"这确实意味着内存会受到影响,免责声明"。

这张Slides展示了一个naive的优化器实现,核心要点是假设有M个参数,对于每个参数有N个操作,那么遍历所有参数并处理完共需要M * N个操作。

这张Slides介绍了一种称为"horizontally fused optimizer"(水平融合优化器)的优化方法,可以把naive的优化器实现中的for循环fuse掉。

这张Slides介绍了实际上我们可以把整个优化器的操作fuse成一个cuda kernel。

这张Slides传达的核心信息是:在CUDA编程中,通过减少kernel启动的次数可以提高程序的执行效率。这是因为每次启动CUDAkernel都会有一定的开销,如果能够将多个操作合并到更少的kernel中,就可以减少这些开销,从而提高整体性能。水平融合和垂直融合是实现这一目标的两种主要策略:水平融合合并了相似的并行操作;垂直融合则进一步合并了不同的计算步骤。

上面倒数第二张Slides类比了线粒体是细胞的能量工厂,而multi_tensor_apply是高速优化器的"动力卡车"。展示了一辆装载多辆小汽车的大卡车,暗示multi_tensor_apply可以同时处理多个张量。说明multi_tensor_apply允许我们对张量列表进行操作,而不是单个张量。

上面最后一张Slides,对比了普通的torch.add操作(左侧小车+小卡车)和_foreach_add操作(右侧大卡车装载多辆小车)。

上面的一系列Slides在讨论如何在CUDA中实现一个用于多个张量的add操作(_foreach_add)时输入应该怎么如何传递。

上面第一张Slides展示了普通的add操作和_foreach_add操作的函数签名。提供了一个普通add操作的CUDA kernel签名,假设使用float类型的Tensors,引出问题:应该怎么给_foreach_add操作的CUDA kernel写签名?

第二张和第三张Slides尝试使用std::vector<float*>来实现_foreach_add_kernel,这种方法不行,因为CUDA不识别std::vector

第四张和第五张Slides尝试使用C风格的数组(float**)来实现_foreach_add_kernel,结论:这种方法也不行,会导致非法内存访问(IMA),因为外层指针*是CPU地址。

Slides里面还画了一些示意图用于解释这个问题。

这两张Slides讲解了在CUDA中实现多张量操作(specifically _foreach_add)的第三种尝试方法,称为"pass by chonky boi"(通过大块数据传递)。

  • 方法描述:
    • 创建一个名为TensorListMetadata的结构体,用于存储多个张量的地址信息。
    • 结构体包含一个二维数组addresses[3][NUM_TENSORS],用于存储三组张量(可能是输入、输出和中间结果)的地址。
  • 内存布局说明:
    • 紫色框代表CPU内存,绿色框代表GPU/CUDA内存。
    • 在GPU内存中,张量数据和kernel参数空间被分开存储。
    • 张量的数据指针(data_ptr())和张量列表的地址都存储在GPU内存中。
  • 结果:
    • 这种方法成功通过了编译(“It passes CI! Yay!”)。
    • 它解决了之前尝试中遇到的问题,如std::vector不被CUDA支持,以及直接使用指针数组导致的非法内存访问。

这里说明的是尝试上面的大块数据传递方式之后作者碰到了CUDA中的非法内存访问。问题似乎与张量列表的大小(N)有关。在N=423和N=424之间存在一个临界点,可能与CUDA的内存管理或某些硬件限制有关。

这里继续说明了当尝试传递大量数据(在这里是张量地址)作为kernel参数时,可能会超出CUDAkernel参数空间的4KB限制,导致程序失败。这就解释了为什么只有当NUM_TENSORS小于某个特定值(这里提到424)时,代码才能正常工作。

这里的第一张Slides期望是能够一次性将所有数据(用小汽车表示)装载到一辆大卡车上。现实是由于CUDAkernel参数空间的4KB限制,无法一次性装载所有数据,导致部分数据"掉落"。第二张Slides提出了"Attempt 4"(第四次尝试)的解决方案,建议通过多次启动kernel来解决问题,即"make more trips"(多次运输)。第三张Slides展示了当前的方法是进行水平融合(Horizontal Fusion),将多个操作合并到一个kernel中,但实际上常常会产生多个水平融合的kernel和垂直融合的kernel。

这里的第一张Slides展示了"尝试2"的回顾,目标是将CPU内存(紫色)中的数据转移到CUDA/GPU内存(绿色)中。最后提出了将紫色的指针(*)转变为绿色的想法,即将数据从CPU移到GPU。第二张Slides进一步详细说明了解决方案,即使用memcpy将地址列表复制到CUDA内存中。通过这种方法,可以避开CUDAkernel参数空间的4KB限制,从而能够启动单个kernel处理所有数据,注意,memcpy操作是昂贵的($$$)。

第三张Slides总结了最终的解决方案,提出了结构体(struct)和memcpy的混合使用策略。左侧:如果数据量较小,符合kernel参数空间限制,就直接使用结构体传递。右侧:如果数据量超过限制,则使用memcpy将数据复制到GPU内存,然后传递指针。

这里的第一张Slides展示了水平融合(Horizontal Fusion)和垂直融合(Vertical Fusion),多个独立的操作(灰色块)首先进行水平融合,变成蓝色的块,然后这些蓝色的块可能进一步进行垂直融合,形成一个更大的绿色块。这种看起来比较麻烦的实现依赖multi_tensor_apply函数。

第二张Slides解释了 _foreach_add 和 _fused_adamw 两种操作的实现差异。_foreach_add 调用 multi_tensor_apply 时使用一个执行加法的 Callable。_fused_adamw 调用 multi_tensor_apply 时使用一个更大的 Callable。还展示了 multi_tensor_apply_kernel 的代码片段,其中包含 callable 参数。

第三张Slides继续解释了 _foreach_add 和 _fused_adamw 的实现差异并展示了 _fused_adamw 的具体实现代码。可以粗略浏览到以下内容,使用AT_DISPATCH_FLOATING_TYPES_AND2 宏来处理不同的浮点类型。调用 multi_tensor_apply_for_fused_optimizer 函数,传入 FusedAdamMathFunctor 作为参数。

这里UP主展示了FusedAdamMathFunctor的代码实现,包括两个主要部分:

  • 左侧是FusedAdamMathFunctor结构体的定义,包含operator()函数的实现。
  • 右侧是adam_math函数的实现,这是Adam优化器的核心计算逻辑。实现了Adam优化器的各个步骤,包括梯度计算、一阶和二阶动量更新等

这里的第三张Slides显示了"…that was very manual."的文字,暗示这种实现方式是非常手动和复杂的。

这几张Slides讲了PyTorch中的torch.compile()功能及其在优化器中的应用,主要内容如下:

  • 第一张Slides介绍了torch.compile()函数。
  • 第二张Slides解释了torch.compile()的主要优势是垂直融合(vertical fusion)。图示展示了如何将多个水平融合(horizontal fusion)的操作进一步垂直融合成一个更大的操作。
  • 第三张Slides展示了如何在优化器中使用torch.compile():
    • 首先创建一个AdamW优化器
    • 然后使用@torch.compile装饰器定义一个compiled_step函数
    • 在训练循环中,使用compiled_step替代原来的optimizer.step()
  • 最后一张Slides展示了torch.compile()生成的Triton kernel的一部分代码。这是一个大型的、高度优化的kernel,包含了许多临时变量(tmp0, tmp1等)和复杂的数学运算。这说明torch.compile()确实可以生成非常复杂和高效的fuse kernel。

最后这张Slides展示了了 PyTorch 中编译优化器(compiled optimizers)的工作条件和使用情况。

  • 需要 CUDA 功能版本 7.0 或更高以支持 Triton
  • PyTorch 中所有具有 foreach 实现的优化器现在都可以编译。
  • 除了 L-BFGS 和 SparseAdam 外,其他所有优化器都支持编译。
  • 任何支持的 foreach* 操作序列都应该能够进行垂直融合。
  • 鼓励用户尝试自己的实验性优化器。如果发现不能工作的情况,建议提交issue。

个人总结

这节课实际上就是宏观介绍了一下PyTorch的Optimizer是怎么通过CUDA kernel fuse优化的。我这里使用Claude-3-Opus-200k来总结一下这节课涉及到的要点。

下面的内容由Claude-3-Opus-200k总结而成

这堂课程的主要内容是介绍如何在PyTorch中优化优化器的性能。重点包括以下几个方面:

  • 1.运行时间和内存使用之间的权衡。一般来说,提高速度往往需要更多的内存。但有时也会受到硬件或系统的限制。
  • 2.优化器实现的不同方式:
    • Naive实现:简单地遍历所有参数,执行所有操作,总共需要M*N次操作。
    • 水平融合(Horizontally fused):将循环融合,减少总操作数。
    • 垂直融合(Vertically fused):将整个优化器操作融合成一个CUDA kernel。
  • 3.在CUDA编程中,减少kernel启动次数可以提高效率。这可以通过水平融合(合并相似的并行操作)和垂直融合(合并不同的计算步骤)来实现。
  • 4.PyTorch中的multi_tensor_apply函数允许同时对张量列表进行操作,类似于vectorized的"_foreach"操作。但需要注意CUDA kernel参数空间的4KB限制。
  • 5.针对超出4KB限制的情况,可以采取的解决方案:
    • 分多次启动kernel(make more trips)
    • 使用memcpy将数据从CPU复制到GPU内存
    • 结合使用struct和memcpy:小数据量直接用struct传递,大数据量先memcpy再传递指针
  • 6.手动实现水平和垂直融合的优化器(如FusedAdamW)的过程比较复杂。
  • 7.PyTorch的torch.compile()功能可以自动生成高度优化的vertical fusion kernel,大大简化了编译优化器的实现。
  • 8.目前PyTorch中大部分优化器都支持编译优化(compiled optimizers),但对CUDA版本有要求(>=7.0)。用户也可以尝试自己的实验性优化器。

总的来说,这门课深入讲解了如何从多个方面优化PyTorch中的优化器实现,包括算法层面的水平/垂直融合,工程实现层面的参数传递和内存管理,以及新功能torch.compile()带来的便利。

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

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

相关文章

ChatGPT 3.5/4.0 新手使用手册(详细版)

1. 什么是 ChatGPT&#xff1f; ChatGPT是由 OpenAI 开发的先进人工智能语言模型&#xff0c;能够理解并生成自然语言文本。它可以帮助你进行写作、回答问题、提供建议&#xff0c;甚至参与对话。ChatGPT 3.5 和 4.0 是两个不同版本&#xff0c;它们都拥有强大的语言处理能力&…

sublime text 4 安装(含激活码)安装破解汉化 Sublime Text 4 的操作指南

sublime text 4 安装&#xff08;含激活码&#xff09; 一、下载步骤 官网地址&#xff1a;Sublime Text - the sophisticated text editor for code, markup and prosehttps://link.zhihu.com/?targethttps://www.sublimetext.com/ windows下载链接&#xff1a;Thank You -…

【数据结构算法经典题目刨析(c语言)】使用数组实现循环队列(图文详解)

&#x1f493; 博客主页&#xff1a;C-SDN花园GGbond ⏩ 文章专栏&#xff1a;数据结构经典题目刨析(c语言) 目录 一.题目描述 二.解题思路 1.循环队列的结构定义 2.队列初始化 3.判空 4.判满 5.入队列 6.出队列 7.取队首元素 8.取队尾元素 三.完整代码实…

【Datawhale AI夏令营第四期】魔搭-AIGC方向 Task03笔记 原神风格Lora尝试 ComfyUI Lora微调 补充选学内容

【Datawhale AI夏令营第四期】魔搭-AIGC方向 Task03笔记 原神风格Lora尝试 ComfyUI Lora微调 首先我们继续推进网课进度。 https://space.bilibili.com/1069874770 传送门 WorldArt锦书产品介绍&#xff1a; 我属实是没想到这个产品居然还可以用作遗迹鉴定和名家笔记仿写这样…

2.2算法的时间复杂度与空间复杂度——经典OJ

本博客的OJ标题均已插入超链接&#xff0c;点击可直接跳转~ 一、消失的数字 1、题目描述 数组nums包含从0到n的所有整数&#xff0c;但其中缺了一个。请编写代码找出那个缺失的整数。你有办法在O(n)时间内完成吗&#xff1f; 2、题目分析 &#xff08;1&#xff09;numsS…

Java流程控制之循环结构(附案例说明)超详细

循环结构&#xff1a;根据循环条件&#xff0c;重复性执行某段代码 for循环 while 循环 do-while 循环 凡是循环 就有4个要素&#xff1a; 1、初始化要素2、循环条件&#xff08;一定是boolean类型的变量或表达式&#xff09; 3、循环体 4、迭代部分 for 循环格式 for(1;2;…

阿里声音项目Qwen2-Audio的部署安装,在服务器Ubuntu22.04系统——点动科技

阿里声音项目Qwen2-Audio的部署安装&#xff0c;在服务器Ubuntu22.04系统——点动科技 一、ubuntu22.04基本环境配置1.1 更换清华Ubuntu镜像源1.2 更新包列表&#xff1a;2. 安装英伟达显卡驱动2.1 使用wget在命令行下载驱动包2.2 更新软件列表和安装必要软件、依赖2.2 卸载原有…

JAVA学习之知识补充(下)

六&#xff1a;File类与IO流&#xff1a; 这里给出三种常见的初始化方法&#xff1a; 通过文件路径初始化: File file new File("C:/example/test.txt");这种方法用于创建一个文件对象&#xff0c;该文件对象表示指定路径的文件或目录。例如&#xff1a;File fil…

Zookeeper服务注册及心跳机制详解

ZooKeeper提供了一种类似于文件目录的结构来保存key值&#xff0c;其提供了四种key类型&#xff0c;分别是持久节点&#xff0c;临时节点&#xff0c;持久有序节点&#xff0c;临时有序节点。其中临时节点的特性是当创建此节点的会话断开时&#xff0c;节点也会被删除。这一特性…

xss.function靶场(easy)

文章目录 第一关Ma Spaghet!第二关Jefff第三关Ugandan Knuckles第四关Ricardo Milos第五关Ah Thats Hawt第六关Ligma第七关Mafia第八关Ok, Boomer 网址&#xff1a;https://xss.pwnfunction.com/ 第一关Ma Spaghet! 源码 <!-- Challenge --> <h2 id"spaghet&qu…

一文掌握 Web 测试:功能、界面、兼容与安全的综合测试指南!

随着Web技术的不断演进&#xff0c;测试除了对应用的功能性、界面美观性、跨平台兼容性的基本要求外、安全性和性能的要求也逐步增高。因此&#xff0c;全面、系统的测试思维和策略成为了保证Web应用高质量的关键因素。本篇文章将从功能测试、界面测试、兼容性测试和安全测试四…

AI歌手-五月天(声音转换)

重磅推荐专栏: 《大模型AIGC》 《课程大纲》 《知识星球》 本专栏致力于探索和讨论当今最前沿的技术趋势和应用领域,包括但不限于ChatGPT和Stable Diffusion等。我们将深入研究大型模型的开发和应用,以及与之相关的人工智能生成内容(AIGC)技术。通过深入的技术解析和实践经…

JavaScript - 数组对象中实用好玩的reduce方法

JavaScript中reduce() 方法对数组中的每个元素执行一个由您提供的reducer函数(升序执行)&#xff0c;将其结果汇总为单个返回值。 语法&#xff1a; arr.reduce(callback(accumulator, currentValue[, index[, array]])[, initialValue]) 参数配置&#xff1a; 参数名描述cal…

系列:水果甜度个人手持设备检测-github等开源库和方案

系列:水果甜度个人手持设备检测 -- github等开源库和方案 概述 通常来说&#xff0c;年纪轻轻的我们一般都喜欢走捷径&#xff0c;对于智能设备和算法软件领域来说&#xff0c;GitHub应该算为数不多的的捷径之一。就算因为效果不好/知识产权/方向不同等原因不用&#xff0c;…

XML外部实体注入

1.DTD实体及引用 DTD(文档类型定义)是一种用于定义XML文档结构和元素约束的方法。它可以描述一个XML文档的元素、属性、实体、注释等&#xff0c;从而规定了文档的结构和语法规则。DTD 通常是一个单独的文件&#xff0c;可以被多个XML文档所共享。 而在DTD中&#xff0c;实体…

日志分析-Windows

目录 Windows事件日志场景 1&#xff08;问题 1&#xff09;&#xff1a;服务器管理员向管理层提出了大量关于 PowerShell 在环境中被阻止的投诉。管理层最终批准在环境中使用 PowerShell。查看哪些日志、监控哪些事件 ID 等。场景 2&#xff08;问题 2&#xff09;&#xff1a…

Ubuntu 24.04系统部署Zabbix7.0

1、Ubuntu 24.04系统 阿里云镜像下载地址&#xff1a; https://mirrors.aliyun.com/ubuntu-releases/noble/ubuntu-24.04-live-server-amd64.iso 如果不使用Ubuntu系统&#xff0c;自己可以在下图选择对应版本。安装操作差不多&#xff0c;就命令有差异。 2、Zabbix版本 &am…

AVL树的学习

1.1 AVL树的概念 二叉搜索树虽可以缩短查找的效率&#xff0c;但如果数据有序或接近有序二叉搜索树将退化为单支树&#xff0c;查 找元素相当于在顺序表中搜索元素&#xff0c;效率低下。因此&#xff0c;两位俄罗斯的数学家G.M.Adelson-Velskii 和E.M.Landis在1962年 发明了…

微前端架构:使用不同框架构建可扩展的大型应用

​ 大家好&#xff0c;我是程序员小羊&#xff01; 前言 在现代前端开发中&#xff0c;随着应用规模的扩大和团队分工的复杂化&#xff0c;传统的单体前端架构逐渐暴露出维护困难、部署周期长、技术栈更新不便等问题。为了应对这些挑战&#xff0c;微前端架构应运而生。这种架构…

每日OJ_牛客_树根(简单模拟)

目录 牛客_树根&#xff08;简单模拟&#xff09; 解析代码 牛客_树根&#xff08;简单模拟&#xff09; 数根__牛客网 解析代码 这个题目很容易理解&#xff0c;对于数字的每一位进行相加直到不大于9为止即可。 接收字符串得到各个数字&#xff0c;并且每位求和&#xff…