前言
最近开始学习这门新课,本人之前已经学习过了一些深度学习的知识,想来尝试学习一下这门课,这个系列是去做一些知识笔记。
计算机浮点数表示
上次学习浮点数知识还是在CSAPP中进行学习的,现在再来重新学习一下有关浮点数的知识。计算机中的所有数都是通过二进制来表示的,不同的是,由于浮点数引入的小数点,所以为了统一表示,科学家发明了一个统一的标准,即IEEE 754。一般的分为双精度浮点数和单精度浮点数,也就是32位和64位,我们来看看浮点数的表示,先从熟悉的十进制和科学计数法来看:

对于一个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的表示
|
|
这样,我们就搞懂了一个浮点数是怎么表示的,下面来看一看不同的浮点数吧。
fp16
很多情况下需要降低显存的压力,于是乎就发明了许多新的存储格式。

而fp16没有解决的问题是当数值过小时容易溢出,即无法表示,为了解决这个问题而发明了bf16。
bf16
BF16(BFloat16)是Google Brain团队专为深度学习场景设计的16位浮点数据格式
BF16(16位脑浮点):1位符号+8位指数+7位尾数,仅占用2字节。核心优势是完全继承FP32的超大数值范围,仅牺牲少量小数精度,同时硬件可零成本与FP32互相转换,无需复杂运算逻辑。

混合精度
在训练中,如果需要fp32去进行训练,那么就会需要占用许多显存,如果全程采用半精度去进行训练(fp16或者bp16),那么训练结果不稳定。所以采用的一个办法就是使用混合精度去进行训练。
混合精度训练:
- 使用
bf16存储参数、激活值和梯度 - 使用
fp32存储优化器状态
Pytorch有一个自动混合精度的API库,叫做 automatic mixed precision (AMP),除此之外,还有fp8和fp4等精度。
计算能力
常见的浮点数操作有加减乘除这些,而A floating-point operation (FLOP) 。这里有两个长得比较像,容易搞混的内容:
FLOPs:指的是浮点数运算数,可以理解为计算量。FLOPS或者FLOP/s指的是每秒浮点数运算能力,可以理解为计算速度。
MFU模型FLOPs利用率
我们把MFU定义为:实际的计算速度/理论的计算速度。
实际上的计算速度我们可以这样去进行计算,让总的计算次数除以总的计算时间。实际中,MFU>0.5已经算好的了!
为什么这个数值不是接近于1的?我们需要看看是怎么计算的?计算一个数值的过程是这样的:
- 把来自内存的输入发送到计算器中
- 执行计算
- 把结果写回内存
这个过程的总时间取决于两个内容:
- 计算器的计算能力,FLOPS
- 内存的带宽,也就是发送能力(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这个算法,如下面:
|
|
其流程是这样的:
- 读一次
x(2 Byte) - 做一次比较(1 FLOP)
- 写一次
y(2 Byte)
所以,搬运了4次数据,只做了1次计算,可以通过比较这两个值来确定是内存受限还是计算受限:
- 当Accelerator Intensity > Arithmetic Intensity时,也就是说该算法的搬运速度小于计算速度,所以是内存受限的
- 反之,搬运速度大于计算速度,则是计算受限
总结
这次笔记搞清楚了一些基本的概念知识,下次见!