cs336笔记1

前言

最近开始学习这门新课,本人之前已经学习过了一些深度学习的知识,想来尝试学习一下这门课,这个系列是去做一些知识笔记。

计算机浮点数表示

上次学习浮点数知识还是在CSAPP中进行学习的,现在再来重新学习一下有关浮点数的知识。计算机中的所有数都是通过二进制来表示的,不同的是,由于浮点数引入的小数点,所以为了统一表示,科学家发明了一个统一的标准,即IEEE 754。一般的分为双精度浮点数和单精度浮点数,也就是32位和64位,我们来看看浮点数的表示,先从熟悉的十进制和科学计数法来看:

image-20260719184653352

对于一个32位浮点数来说存储如上图所示,分为:

  • S:符号位
  • K:指数位
  • M:小数位

符号位

符号位比较好理解,这里,如果这个数是正数,那么符号位就是0,如果是负数,那么符号位就是1

指数位

指数位需要结合科学计数法去进行理解,对于一个数,比如说15.75,我们把它拆成二进制小数的样子: $$ 15.75 = 1111.11_{(2)} $$ 类比十进制,小数点后每一位是$10^{-1}, 10^{-2}$,所以对于二进制来说就是$2^{-1}, 2^{-2}$,所以我们可以使用计数法来表示这个数,也就是 $$ 1111.11 = 1.11111 \times 2 ^{3} $$ 我们得到了指数位,也就是3,同时,因为二进制科学计数法开头的数字一定是1,所以我们可以省略这个1,也就是 $$ .11111 \times 2 ^{3} $$ 这样我们就得到了小数部分。

此时又有一个问题,怎么表述指数为负数的情况呢?这里我们知道,因为32位浮点数中指数部分是8位,所以可以表示的范围是0~255,于是就做了一个映射,把0~255映射为-127~128,也就是说,浮点数的指数位需要减去127得到的才是实际的指数为,所以,我们的指数位就是127+3=130,也就是1000 0010,小数位就是11111,填充一下得到15.75的表示

1
2
0    	1000 0010	11111000000000000
符号位(1位)     指数位(8位)		 	小数部分(23位)

这样,我们就搞懂了一个浮点数是怎么表示的,下面来看一看不同的浮点数吧。

fp16

很多情况下需要降低显存的压力,于是乎就发明了许多新的存储格式。

image-20260719212708155

fp16没有解决的问题是当数值过小时容易溢出,即无法表示,为了解决这个问题而发明了bf16

bf16

BF16(BFloat16)是Google Brain团队专为深度学习场景设计的16位浮点数据格式

BF16(16位脑浮点):1位符号+8位指数+7位尾数,仅占用2字节。核心优势是完全继承FP32的超大数值范围,仅牺牲少量小数精度,同时硬件可零成本与FP32互相转换,无需复杂运算逻辑。

image-20260719214058900

混合精度

在训练中,如果需要fp32去进行训练,那么就会需要占用许多显存,如果全程采用半精度去进行训练(fp16或者bp16),那么训练结果不稳定。所以采用的一个办法就是使用混合精度去进行训练。

混合精度训练:

  • 使用bf16存储参数、激活值和梯度
  • 使用fp32存储优化器状态

Pytorch有一个自动混合精度的API库,叫做 automatic mixed precision (AMP),除此之外,还有fp8fp4等精度。

计算能力

常见的浮点数操作有加减乘除这些,而A floating-point operation (FLOP) 。这里有两个长得比较像,容易搞混的内容:

  • FLOPs:指的是浮点数运算数,可以理解为计算量。
  • FLOPS或者FLOP/s指的是每秒浮点数运算能力,可以理解为计算速度。

MFU模型FLOPs利用率

我们把MFU定义为:实际的计算速度/理论的计算速度。

实际上的计算速度我们可以这样去进行计算,让总的计算次数除以总的计算时间。实际中,MFU>0.5已经算好的了!

为什么这个数值不是接近于1的?我们需要看看是怎么计算的?计算一个数值的过程是这样的:

  1. 把来自内存的输入发送到计算器中
  2. 执行计算
  3. 把结果写回内存

这个过程的总时间取决于两个内容:

  1. 计算器的计算能力,FLOPS
  2. 内存的带宽,也就是发送能力(bytes/s)

所以,在计算的总时间可以分为两个部分:

  • 内存通信时间,即将数据发送到运算单元的时间
  • 计算时间,执行计算的时间

这两部分理想情况下是可以独立进行的,实际中会发生重合,这样,执行整个计算的时间就可以确定,就是两者之间的最大值。所以,对性能瓶颈进行分析:

  • 内存瓶颈:当通信时间大于计算时间
  • 计算瓶颈:计算时间大于通信时间

算数强度(Accelerator Intensity)

  • 计算公式:算术强度 =$(\frac{\text{加速器计算吞吐量}(FLOPs/sec)}{\text{内存带宽}(Bytes/sec)})$

  • 物理意义:代表数据在硬件中传输与处理的比例。数值越高,说明硬件利用率越高,计算能力越强大。

  • 单位:FLOP/Byte(每字节的浮点操作次数)

每搬运1 Byte数据,GPU最多能做多少FLOPs

算法强度(Arithmetic Intensity)

$(\text{Arithmetic Intensity} = \frac{\text{总计算量 (FLOPs)}}{\text{总访存量 (Bytes)}})$

每搬运1 Byte数据,实际做了多少FLOPs,这里指的是算法。

例如,对于ReLU这个算法,如下面:

1
y = relu(x)

其流程是这样的:

  • 读一次x(2 Byte)
  • 做一次比较(1 FLOP)
  • 写一次y(2 Byte)

所以,搬运了4次数据,只做了1次计算,可以通过比较这两个值来确定是内存受限还是计算受限:

  • 当Accelerator Intensity > Arithmetic Intensity时,也就是说该算法的搬运速度小于计算速度,所以是内存受限的
  • 反之,搬运速度大于计算速度,则是计算受限

总结

这次笔记搞清楚了一些基本的概念知识,下次见!

Licensed under CC BY-NC-SA 4.0
花有重开日,人无再少年
使用 Hugo 构建
主题 StackJimmy 设计