【深度学习】既然英伟达A100/H100 太贵,为什么不用 4090?

您所在的位置:网站首页 ipadmini256太贵了 【深度学习】既然英伟达A100/H100 太贵,为什么不用 4090?

【深度学习】既然英伟达A100/H100 太贵,为什么不用 4090?

2024-07-11 07:24| 来源: 网络整理| 查看: 265

作者丨李博杰@知乎(已授权)

来源丨https://zhuanlan.zhihu.com/p/655402388

编辑丨极市平台

导读

 

大模型的训练用 4090 是不行的,但推理(inference/serving)用 4090 不仅可行,在性价比上还能比 H100 稍高。4090 如果极致优化,性价比甚至可以达到 H100 的 2 倍。

(长文预警:本文按 Word 计数法 16000 字,按知乎计数法 24000 字)

这是一个好问题。先说结论,大模型的训练用 4090 是不行的,但推理(inference/serving)用 4090 不仅可行,在性价比上还能比 H100 稍高。4090 如果极致优化,性价比甚至可以达到 H100 的 2 倍。

事实上,H100/A100 和 4090 最大的区别就在通信和内存上,算力差距不大。

H100A1004090Tensor FP16 算力989 Tflops312 Tflops330 TflopsTensor FP32 算力495 Tflops156 Tflops83 Tflops内存容量80 GB80 GB24 GB内存带宽3.35 TB/s2 TB/s1 TB/s通信带宽900 GB/s900 GB/s64 GB/s通信时延~1 us~1 us~10 us售价$30000~$40000$15000$1600

NVIDIA 的算力表里面油水很多,比如 H100 TF16 算力写的是 1979 Tflops,但那是加了 sparsity(稀疏)的,稠密的算力只有一半;4090 官方宣传 Tensor Core 算力高达 1321 Tflops,但那是 int8 的,FP16 直只有 330 Tflops。这篇文章的第一版就是用了错的数据,H100 和 4090 的数据都用错了,得到的结论非常离谱。

H100 这个售价其实是有 10 倍以上油水的。

2016 年我在 MSRA 的时候,见证了微软给每块服务器部署了 FPGA,把 FPGA 打到了沙子的价格,甚至成为了供应商 Altera 被 Intel 收购的重要推手。2017 年我还自己挖过矿,知道什么显卡最划算。后来在华为,我也是鲲鹏、昇腾生态软件研发的核心参与者。因此,一个芯片成本多少,我心里大概是有数的。

鲲鹏的首席架构师夏 Core 有一篇知名文章《谈一下英伟达帝国的破腚》,很好的分析了 H100 的成本:

把他的成本打开,SXM 的成本不会高于 300$,封装的 Substrate 及 CoWoS 大约也需要 $300,中间的 Logic Die 最大颗,看上去最高贵 :) 那是 4nm 的一颗 814mm2 的 Die,TSMC 一张 12 英寸 Wafer 大致上可以制造大约 60 颗这个尺寸的 Die,Nvidia 在 Partial Good 上一向做得很好(他几乎不卖 Full Good),所以这 60 颗大致能有 50 颗可用,Nvidia 是大客户,从 TSMC 手上拿到的价格大约是 $15000,所以这个高贵的 Die 大约只需要 $300。哦,只剩下 HBM 了,当前 DRAM 市场疲软得都快要死掉一家的鬼样了,即使是 HBM3 大抵都是亏本在卖,差不多只需要 $15/GB,嗯,80GB 的容量成本是 $1200。TSMC 曾经讲过一个故事。台湾同胞辛辛苦苦攒钱建厂,一张 4nm 那么先进的工艺哦,才能卖到 $15000,但是那某个客户拿去噢,能卖出 $1500000($30000*50)的货啦,机车,那样很讨厌耶。你懂我意思吗?就如最开始说的,在这个世界的商业规则下,$2000 成本的东西卖 $30000,只有一家,销售量还很大,这是不符合逻辑的,这种金母鸡得有航母才守得住。

据说微软和 OpenAI 包下了 H100 2024 年产能的一半,猜猜他们会不会发挥当年跟 Altera 砍价的传统艺能?会真的花 $40,000 * 500,000 = 200 亿美金去买卡?

咱们再分析下 4090 的成本,5nm 的 609mm2 Die,大约成本是 $250。GDDR6X,24 GB,按照 1 GB $10 算,$240。PCIe Gen4 这种便宜东西就算 $100 吧。封装和风扇这些东西,算它 $300。总成本最多 $900,这样的东西卖 $1600,算是良心价了,因为研发成本也是钱啊,更何况 NVIDIA 的大部分研发人员可是在世界上程序员平均薪酬最高的硅谷。

可以说,H100 就像是中国一线城市的房子,本身钢筋水泥不值多少钱,房价完全是被供求关系吹起来的。我在 LA 已经住了两周,公司租的房子使用面积是我北京房子的 4 倍,但售价只贵了 30%,还带个小院,相当于单位面积的房价是北京的 1/3。我跟本地的老外聊天,他们都很吃惊,你们的平均收入水平比 LA 低这么多,怎么买得起北京的房子的?

问题来了,如果 4090 这么香的话,为啥大家还要争着买 H100,搞得 H100 都断货了?甚至 H100 都要对华禁售,搞出个 H800 的阉割版?

大模型训练为什么不能用 4090 GPU 训练性能和成本对比

LambdaLabs 有个很好的 GPU 单机训练性能和成本对比,在此摘录如下。

首先看吞吐量,看起来没有什么违和的,在单卡能放下模型的情况下,确实是 H100 的吞吐量最高,达到 4090 的两倍。看算力和内存也能看出来,H100 的 FP16 算力大约是 4090 的 3 倍,内存带宽是 3.35 倍,训练过程中由于 batch size 比较大,大多数算子是 compute bound(计算密集型),少数算子是 memory bound(内存密集型),这个结果是不意外的。

eaa5e5bbb3b4cbc0cd6bac166b6f8048.jpeg LambdaLabs PyTorch 单卡训练吞吐量对比图 1914b28ea12a881e1ffb57672322eec9.jpeg LambdaLabs PyTorch 单卡训练吞吐量对比表

然后看性价比,就有意思了,原来排在榜首的 H100 现在几乎垫底了,而且 4090 和 H100 的差距高达接近 10 倍。这就是因为 H100 比 4090 贵太多了。

由于 H100 货源紧张,云厂商的 H100 租用价格就更黑了,按照标价大约 7 个月就可以回本。就算大客户价能便宜一半,一年半也足够回本了。

在价格战中过惯了苦日子的 IaaS 云服务商看到这样的 H100 回本速度,估计要感叹,这真是比区块链挖矿回本还快呐。

aca5012e5c852ae93f29981ea25824d4.jpeg LambdaLabs PyTorch 单卡训练单位成本吞吐量对比图 785eee9e0df61f6f4cbf51d9c909acaa.jpeg LambdaLabs PyTorch 单卡训练单位成本吞吐量对比表 大模型训练的算力需求

既然 4090 单卡训练的性价比这么高,为啥不能用来做大模型训练呢?抛开不允许游戏显卡用于数据中心这样的许可证约束不谈,从技术上讲,根本原因是大模型训练需要高性能的通信,但 4090 的通信效率太低。

大模型训练需要多少算力?训练总算力(Flops)= 6 * 模型的参数量 * 训练数据的 token 数。

我今年初第一次看到有人煞有介事地讲这个公式的时候,觉得这不是显然的吗?又看到 OpenAI 的高级工程师能拿 90 多万美金的年薪,顿时整个人都不好了,还是 AI 香呀。之前我也面试过一些做 AI 的工程师,包括一些做 AI 系统优化的专家,连 Q、K、V 是啥都说不清楚,LLaMA 每个 tensor 的大小也算不出来,就这样还能拿到 offer。

APNet 2023 panel 的主题是 Network, AI, and Foundational Models: Opportunties and Challenges。前面几个问题都中规中矩的,panelists 有点放不开,我就提了一个问题,网络历史上的重要成就基本上都基于对应用场景深刻的理解,但我们现在做网络的很多都不了解 AI,甚至连每个 tensor 的大小和每个 step 传输的数据量都不知道,如何让 network community 更了解 AI 呢?

这下热闹了,台下的谭博首先发言,说我在华为肯定能知道所有这些东西;然后传雄老师也跟了一句,要是做网络的懂了太多 AI,那可能他就变成一个 AI guy 了。接着主持人陈凯教授问,你们有谁真的训练过大模型?沉默了一会儿,阿里的兄弟先说,我算是半个训练过大模型的,我们做的东西是支撑阿里大模型 infra 的。后面又有 panelist 说,做 AI 系统的网络优化是否有必要自己懂 AI 呢,是不是只要会做 profiling 就行了?

我个人观点仍然是,AI 并不难学,要想做好 AI 系统优化,可以不懂 attention 的 softmax 里面为什么要除以 sqrt(d_k),但不能不会计算模型所需的算力、内存带宽、内存容量和通信数据量。Jeff Dean 就有个很有名的 Numbers Every Programmer Should Know,数量级的估算对任何系统优化来说都很关键,不然根本不知道瓶颈在哪里。

回到大模型训练所需的总算力,其实很简单,6 * 模型的参数量 * 训练数据的 token 数就是所有训练数据过一遍所需的算力。这里的 6 就是每个 token 在模型正向传播和反向传播的时候所需的乘法、加法计算次数。

一堆矩阵相乘,简单来想就是左边若干个神经元,右边若干个神经元,组成一个完全二分图。选出其中任意一个左边的神经元 l 和右边的神经元 r,正向传播的时候:

l 把它的输出乘上 l 和 r 之间的权重 w,发给 r;

r 不可能只连一个神经元吧,总要把多个 l 的加到一起,这就是 reduce,需要一次加法。

反向传播的时候:

r 把它收到的梯度乘上 l 和 r 之间的权重 w,发给 l;

l 也不可能只连一个 r,需要把梯度 reduce 一下,做个加法;

别忘了权重 w 需要更新,那就要计算 w 的梯度,把 r 收到的梯度乘上 l 正向传播的输出(activation);

一个 batch 一般有多个 sample,权重 w 的更新需要把这些 sample 的梯度加到一起。

一共 3 次乘法,3 次加法,不管 Transformer 多复杂,矩阵计算就是这么简单,其他的向量计算、softmax 之类的都不是占算力的主要因素,估算的时候可以忽略。

想起来我 2019 年刚加入 MindSpore 团队的时候,领导让我开发一个正向算子的反向版本,我求导给求错了,搞得算子的计算结果总是不对,还以为是我们的编译器出 bug 了。当发现求导求错的时候,领导像以为我没学过微积分一样看着我,确实我的微积分学的不好,这也是我从数学专业转到计算机专业的原因之一。

在 MindSpore 的时候,自动微分一共就不到 1000 行代码,按照微分公式递归计算下去就行了,但自动微分作为一个重要特性被吹了半天,我都感觉不好意思了。

模型的参数量和训练数据的 token 数之间也有个比例关系,这也很容易理解,只要把模型想象成数据的压缩版本就行了,压缩比总是有极限的。模型的参数量太小,就吃不下训练数据里面所有的知识;模型的参数量如果大于训练数据的 token 数,那又浪费,还容易导致 over-fitting。

训练 LLaMA-2 70B 需要多少张卡

有了模型训练所需的总算力,除以每个 GPU 的理论算力,再除以 GPU 的有效算力利用比例,就得到了所需的 GPU-hours,这块已经有很多开源数据。LLaMA 2 70B 训练需要 1.7M GPU hours(A100),要是用 1 个 GPU,那得算 200 年。要在一个月这种比较能接受的时间周期内训练出来,就得至少有 2400 块 A100。

如果用 4090,单卡 FP16 算力是跟 A100 差不多(330 vs 312 Tflops),但是内存带宽比 A100 低一半(1 vs 2 TB/s),内存容量更是差好几倍(24 vs 80 GB),计算梯度时需要使用的 TF32 算力也低一半(83 vs 156 Tflops),综合起来 4090 单卡的训练速度还比 A100 稍低(参考前面 LambdaLabs 的评测)。

就按照 2048 块 4090 算吧,这 2048 块 4090 之间的通信就成了最大的问题。

为什么?一般有 tensor parallelism、pipeline parallelism、data parallelism 几种并行方式,分别在模型的层内、模型的层间、训练数据三个维度上对 GPU 进行划分。三个并行度乘起来,就是这个训练任务总的 GPU 数量。

10de999a1a1809c378c4e88dc6fc07fe.jpeg 三种并行方式从三个维度划分计算空间的示意图,来源:DeepSpeed Data parallelism(数据并行)

数据并行是最容易想到的并行方式。每个 GPU 分别计算不同的输入数据,计算各自的梯度(也就是模型参数的改变量),再把梯度汇总起来,取个平均值,广播给各个 GPU 分别更新。

ac2a8110cd63d2cd4b1033d75300b811.jpeg Data Parallelism 示意图,来源:Colossal AI

但只用数据并行是肯定不行的,因为一块 GPU 放不下整个 LLaMA 70B 模型。

就模型训练需要多少 GPU 内存,我发现能算清楚的人就不多。有的人甚至以为只需要把模型的参数和反向传播的梯度存下来就够了。事实上,训练需要的内存包括模型参数、反向传播的梯度、优化器所用的内存、正向传播的中间状态(activation)。

优化器所用的内存其实也很简单,如果用最经典的 Adam 优化器,它需要用 32 位浮点来计算,否则单纯使用 16 位浮点来计算的误差太大,模型容易不收敛。因此,每个参数需要存 4 字节的 32 位版本(正向传播时用 16 位版本,优化时用 32 位版本,这叫做 mixed-precision),还需要存 4 字节的 momentum 和 4 字节的 variance,一共 12 字节。如果是用类似 SGD 的优化器,可以不存 variance,只需要 8 字节。

正向传播的中间状态(activation)是反向传播时计算梯度必需的,而且跟 batch size 成正比。Batch size 越大,每次读取模型参数内存能做的计算就越多,这样对 GPU 内存带宽的压力就越小。可是不要忘了,正向传播的中间状态数量是跟 batch size 成正比的,GPU 内存容量又会成为瓶颈。

大家也发现正向传播中间状态占的内存太多了,可以玩一个用算力换内存的把戏,就是不要存储那么多梯度和每一层的正向传播的中间状态,而是在计算到某一层的时候再临时从头开始重算正向传播的中间状态,这样这层的正向传播中间状态就不用保存了。如果每一层都这么干,那么就只要 2 个字节来存这一层的梯度。但是计算中间状态的算力开销会很大。因此实际中一般是把整个 Transformer 分成若干组,一组有若干层,只保存每组第一层的中间状态,后面的层就从该组第一层开始重新计算,这样就平衡了算力和内存的开销。

如果还是算不清楚,可以读读这篇论文:Reducing Activation Recomputation in Large Transformer Models。

当然有人说,GPU 内存放不下可以换出到 CPU 内存,但是就目前的 PCIe 速度,换出到 CPU 内存的代价有时候还不如在 GPU 内存里重算。如果是像 Grace Hopper 那种极高带宽的统一内存,那么换入换出倒是一个不错的主意,不管训练的正向传播中间状态还是 KV Cache,都有很多优化的空间。

Pipeline parallelism(流水线并行)

既然一块 GPU 放不下,用多块 GPU 总行了吧?这就是 model parallelism(模型并行),可以大致分为 pipeline parallelism 和 tensor parallelism。

大家最容易想到的并行方式就是 pipeline parallelism,模型不是有很多层吗,那就分成几组,每组算连续的几层,穿成一条链。

7b38c1a3c8680a5e949c1195bd7a2de3.jpeg Pipeline Parallelism 示意图,来源:Colossal AI

这样就有个问题,一条链上只有一个 GPU 在干活,剩下的都在干等。当然聪明的你一定也想到了,既然叫 pipeline,那就可以流水线处理,可以把一个 batch 分为若干个 mini-batch,每个 mini-batch 分别计算。

043eec0da9f1a02be1eb4bb2142bf630.jpeg Pipeline Parallelism 示意图,来源:GPipe

这可好,是不是把 pipeline 搞的越深越好,每个 GPU 只算一层?

首先,正向传播中间状态(activation)的存储容量会成倍增加,加剧内存容量不足的问题。比如流水线的第一级算出了正向传播的中间状态,如果有 N 个流水级,那就要正向流过后面的 N - 1 个流水级,再等反向传播 N - 1 个流水级,也就是 2N - 2 轮之后才能用到这个正向传播的中间状态。不要忘了每一轮都会产生这么多中间状态,因此一共是保存了 2N - 1 个中间状态。如果 N 比较大,这个存储容量是非常恐怖的。

其次,pipeline 的相邻流水级(pipeline stage)之间是要通信的,级数越多,通信的总数据量和总时延就越高。

最后,要让这样的 pipeline 流起来,batch size 需要等于 Transformer 里面的层数,一般是几十,再乘以 data parallelism 的并行数,batch size 会很大,影响模型收敛的速度或模型收敛后的精度。

因此,在内存容量足够的情况下,最好还是少划分一些流水级。

对于 LLaMA-2 70B 模型,模型参数需要 140 GB,反向传播的梯度需要 140 GB,优化器的状态(如果用 Adam)需要 840 GB。

正向传播的中间状态跟 batch size 和选择性重新计算的配置有关,我们在算力和内存之间取一个折中,那么正向传播的中间状态需要 token 长度 * batch size * hidden layer 的神经元数量 * 层数 * (10 + 24/张量并行度) 字节。假设 batch size = 8,不用张量并行,那么 LLaMA-2 70B 模型的正向传播中间状态需要 4096 * 8 * 8192 * 80 * (10 + 24) byte = 730 GB,是不是很大?

总共需要 140 + 140 + 840 + 730 = 1850 GB,这可比单放模型参数的 140 GB 大多了。一张 A100/H100 卡也只有 80 GB 内存,这就至少要 24 张卡;如果用 4090,一张卡 24 GB 内存,就至少需要 78 张卡。

LLaMA-2 模型一共就只有 80 层,一张卡放一层,是不是正好?这样就有 80 个流水级,单是流水线并行就有 80 个并行的 batch 才能填满流水线。

这样,正向传播的中间状态存储就会大到无法忍受,这可是 80 * 2 = 160 轮的中间状态,翻了 160 倍。就算是使用选择性重新计算,比如把 80 层分成 8 组,每组 10 层,中间状态存储仍然是翻了 16 倍。

除非是用最极端的完全重新计算,反向传播到每一层都重新从头开始计算正向传播的中间结果,但这样计算开销可是随模型层数平方级别的增长,第 1 层算 1 层,第 2 层算 2 层,一直到第 80 层算 80 层,一共算了 3240 层,计算开销可是比正常算一次 80 层翻了 40 倍,这还能忍?

中间状态存储的问题就已经够大了,再看这 2048 张卡之间的通信开销。按照一张卡放一层,并且用不同的输入数据让它完全流水起来的做法,这 2048 张卡分别在计算自己的 mini-batch,可以认为是独立参与到 data parallelism 里面了。前面讲过,在数据并行中,每一轮需要传输的是它计算出的梯度和全局平均后的梯度,梯度的数据量就等于模型的参数数量。

把 70B 模型分成 80 层,每一层大约有 1B 参数,由于优化器用的是 32 bit 浮点数,这就需要传输 4 GB 数据。那么一轮计算需要多久呢?总的计算量 = batch size * token 数量 * 6 * 参数量 = 8 * 4096 * 6 * 1B = 196 Tflops,在 4090 上如果假定算力利用率 100%,只需要 0.6 秒。而通过 PCIe Gen4 传输这 4 GB 数据就已经至少需要 0.12 秒了,还需要传两遍,也就是先传梯度,再把平均梯度传过来,这 0.24 秒的时间相比 0.6 秒来说,是占了比较大的比例。

当然我们也可以做个优化,让每个 GPU 在 pipeline parallelism 中处理的 80 组梯度数据首先在内部做个聚合,这样理论上一个 training step 就需要 48 秒,通信占用的时间不到 1 秒,通信开销就可以接受了。当然,通信占用时间不到 1 秒的前提是机器上插了足够多的网卡,能够把 PCIe Gen4 的带宽都通过网络吐出去,否则网卡就成了瓶颈。假如一台机器上插了 8 块 GPU,这基本上需要 8 块 ConnectX-6 200 Gbps RDMA 网卡才能满足我们的需求。

最后再看 batch size,整个 2048 张卡的集群跑起来,每个 GPU 的 mini-batch 我们刚才设置为 8,那可真是 batch size = 16384,已经是大规模训练中比较大的 batch size 了,如果再大,可能就影响模型的收敛速度或收敛后的精度了。

因此,单纯使用流水线并行和数据并行训练大模型的最大问题在于流水线并行级数过多,导致正向传播中间状态(activation)存储容量不足。

Tensor parallelism(张量并行)

那就没办法了吗?我们还有最后一招,就是 Tensor parallelism(张量并行)。它也是模型并行的一种,但不像流水线并行那样是在模型的层间划分,而是在模型的层内划分,也就是把一层内的 attention 计算和 Feed Forward Network 划分到多个 GPU 上处理。

有了张量并行,就可以缓解 GPU 放不下模型导致的流水级太多的问题。分到 80 个 GPU 才能放下的模型,如果用单机 8 卡张量并行,就只需要划分 10 个流水级。同时,张量并行还可以降低 batch size,因为张量并行的几个 GPU 是在算同一个输入数据。

48767fc5cea36f1548957a487a7972ed.jpeg Tensor、Pipeline、Data 三种并行方式从模型层内、模型层间、训练数据三个维度上划分计算空间,来源:DeepSpeed

Attention 的计算过程是比较容易并行的,因为有多个 head,用来关注输入序列中的不同位置的,那么把这些 head 分别拆开就行了。

2756c08e8cd96fc70259203f485bb61f.jpeg Attention 的计算过程,来源:The Illustrated Transformer

但是我们做任何并行计算的时候都不要忘记通信开销。

每个 head 里面的 Q、K 两个矩阵的大小是 batch size * token 长度 * key 的大小,V 矩阵的大小是 batch size * token 长度 * value 的大小。key/value 的大小一般等于 embedding size / heads 数量,例如在 LLaMA-2 70B 中就是 8192 / 64 = 128,矩阵大小是 batch size * 4096 * 8192 / 64(注意,这只是一个 head 的)。而 Q、K、V 参数矩阵在每个 head 上的大小是 embedding size * embedding size / heads num = 8192 * 8192 / 64。

我们前面推导过,正向的计算量基本上就是每个 token 过一遍所有参数的计算量,2 * 3 (Q, K, V) * batch size * token 长度 * 参数个数 = 2 * 3 * batch size * 4096 * 8192 * 8192 / 64。可以跟矩阵的大小对一下,看看有没有算错。

那么通信量是多少呢?输出矩阵 Z 是由每个 head 拼起来的,每个 head 的大小是 batch size * token 长度 * embedding size / heads num = batch size * 4096 * 8192 / 64。输入矩阵 X 的大小是 batch size * token 长度 * embedding size = batch size * 4096 * 8192。注意这里的 X 大小跟所有 heads 合并在一起后的 Z 大小是一致的,而我们在这里算的是每个 head 的 Z 大小。这里的单位是参数数量,如果按照字节算,还要乘以每个参数的大小。

如果我们采用最极端的方式,每个 head 交给一个 GPU 去算,那么计算量和通信量的比例是多少?大概是 2 * 3 * embedding size / heads num / bytes per param = 2 * 3 * 8192 / 64 / 2 = 384。代入 4090 的 330 Tflops,如果想让通信不成为瓶颈,那么通信带宽至少需要是 330T / 384 = 859 GB/s,发送接收双向还得乘以 2,就是 1.7 TB/s。太大了,远远超过 PCIe Gen4 x16 的 64 GB/s,就算 NVLink 的 900 GB/s 都撑不住。

所以,tensor parallelism 不能切得太细,每个 GPU 需要多算几个 heads。如果每个 GPU 多算几个 attention heads,输入矩阵 X 就是这些 heads 共享的了,因此输入矩阵的通信开销就被多个 heads 平摊了,计算量和通信量的比例就可以提高。

还是按照 4090 的算力 / 单向通信带宽 = 330T / (64GB/s / 2) 来算,计算量和通信量的比例最少需要是 10000,也就是 2 * 3 * (embedding size / 张量并行 GPU 数量) / bytes per param = 2 * 3 * 8192 / 张量并行 GPU 数量 / 2 >= 10000,解得:张量并行 GPU 数量 = 1100,解得:张量并行 GPU 数量



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3