[深度学习][LLM]:浮点数怎么表示,什么是混合精度训练?

混合精度训练

  • 混合精度训练
    • 1. 浮点表示法:[IEEE](https://zh.wikipedia.org/wiki/电气电子工程师协会)二进制浮点数算术标准(IEEE 754)
      • 1.1 浮点数剖析
      • 1.2 举例说明
          • 例子 1:
          • 例子 2:
      • 1.3 浮点数比较
      • 1.4 浮点数的舍入
    • 2. 混合精度训练
      • 2.1 为什么需要半精度
      • 2.2 FP16带来的问题:[量化误差](https://zhida.zhihu.com/search?q=量化误差&zhida_source=entity&is_preview=1)
      • 2.3 FP32 权重备份
      • 2.4 Loss Scale
      • 2.5 提高算数精度

在日常深度学习训练中,一般使用单精度浮点数(float:FP32) 来表示参数并进行相关训练任务。那么浮点数在内存中是如何存储的呢?

在正式开始介绍混合精度训练之前,让我们先对半精度(FP16)单精度(FP32)双精度(FP64) 相关基础知识进行介绍。

1. 浮点表示法:IEEE二进制浮点数算术标准(IEEE 754)

IEEE二进制浮点数算术标准(IEEE 754)是20世纪80年代以来最广泛使用的浮点数运算标准,为许多CPU与浮点运算器所采用。这个标准定义了表示浮点数的格式(包括负零-0)与反常值(denormal number),一些特殊数值((无穷(Inf)与非数值(NaN)),以及这些数值的“浮点数运算符”;它也指明了四种数值舍入规则和五种例外状况(包括例外发生的时机与处理方式)。

1.1 浮点数剖析

一个浮点数 (Value) 的表示其实可以这样表示:
Value=sign × exponent × fraction 1. M . . . × 2 E , E = exponent ; M = fraction \text{Value=sign} \times \text{exponent} \times \text{fraction} \\ 1.M... \times2^E,E=\text{exponent};M=\text{fraction} Value=sign×exponent×fraction1.M...×2E,E=exponent;M=fraction
也就是浮点数的实际值,等于符号位(sign bit)乘以指数偏移值(exponent bias)再乘以分数值(fraction)。

二进制浮点数是以符号数值表示法的格式存储——最高有效位被指定为符号位(sign bit);“指数部分”,即次高有效的e个比特,存储指数部分;最后剩下的f个低有效位的比特,存储“有效数”(significand)的小数部分。

img

指数部分,也称为指数偏移值(exponent bias),即浮点数表示法中指数域的编码值,等于指数的实际值加上某个固定的值,IEEE 754标准规定该固定值为 2 e − 1 − 1 2^{e−1}−1 2e11其中的 e e e 为存储指数的比特的长度。

以单精度浮点数为例,它的指数域是8个比特,固定偏移值是 2 8 − 1 − 1 = 128 − 1 = 127 2^{8−1}−1=128−1=127 2811=1281=127,单精度浮点数的指数部分 E E E,实际取值是从-126到127(-127和128被用作特殊值处理)

采用指数的实际值加上固定的偏移值的办法表示浮点数的指数,好处是可以用长度为 e e e 个比特的无符号整数来表示所有的指数取值,这使得两个浮点数的指数大小的比较更为容易,实际上可以按照字典次序比较两个浮点表示的大小。

这种移码表示的指数部分,中文称作阶码

特殊值

这里有三个特殊值需要指出:

  1. 如果指数是0并且尾数的小数部分是0,这个数±0(和符号位相关): s i g n × 0.0 × 2 − 127 sign \times0.0\times2^-{127} sign×0.0×2127
  2. 如果指数 = 2 e − 1 = 2^{e−1} =2e1 并且尾数的小数部分是0,这个数是±∞(同样和符号位相关): s i g n × 0.0 × 2 128 sign\times0.0\times2^{128} sign×0.0×2128
  3. 如果指数 = 2e−1并且尾数的小数部分非0,这个数表示为非数(NaN): s i g n × 0. x x . . . × 2 128 sign\times0.xx...\times2^{128} sign×0.xx...×2128
image-20240904170054620

img

img

  1. 浮点数如何在计算机中储存,即**符号位,指数位,小数位(通常翻译为尾数)**取值范围取决于指数位,计算精度取决于小数位(尾数)。
  2. 小数位越多(比如双精度是52位),则能表示的数越大,那么计算精度则越高。单精度的小数位在计算机中只有23位(二进制),换算到十进制只能百分百保证6位十进制数字的精确度。不能百分百保证7位的精度运算。超过该精度(二进制23位,十进制6位)的小数运算将会被截取,造成精度损失和计算结果的不准确。同理,双精度,小数位是52位(二进制),换算为十进制则只能百分百能保证15位。
  • float16的精度是3-4位有效数字,取值范围为 [ − 65504 , 65504 ] [-65504,65504] [65504,65504],占用2字节(8位)

  • float32的精度是6位有效数字,取值范围是 1 0 − 38 10^{-38} 1038 1 0 38 10^{38} 1038次方,float占用4字节空间(32位)

  • double的精度是15位有效数字,取值范围是 1 0 − 308 10^{-308} 10308 1 0 308 10^{308} 10308次方,double占用8字节空间(64位)。

1.2 举例说明

那一个小数到底要怎么换算成二进制呢?我们得拿实际例子来解释。

例子 1:

比如:把十进制小数0.875转换成二进制,具体怎么操作?

可以分几大步走:

1、以小数点为界,拆分

2、整数部分转换

整数转二进制我想大家应该都熟悉,使用:除2取余法 即可。而这里的0.875整数部分为0,无需操作。

3、小数部分转换

小数部分的转换不同于整数部分,采用的是 “乘2取整法” ,图示一下就明白了:

image-20240904175645817

4、合并结果

整数部分 + 小数部分,最终得到二进制结果为0.111

所以该结果按照上一节所述的尾数 + 阶码的计算机计数方式和上述公式对齐,小数点右移一位,则可以表示为:
1.11 × 2 − 1 1.11\times 2^{-1} 1.11×21
所以对应可得:

  • 符号位0正数
  • 阶码(E)部分:若以float为例,固定偏移值为127,应为 127 +(-1)= 126或者直接二进制相加,因此二进制表示为:01111110
  • 尾数部分(M):若以float为例,应为23位,因此尾部补齐后为11000000000000000000000

因此最终的总结果为(以32位精度float表示):

00111111011000000000000000000000
例子 2:

再比如:把十进制小数6.36转换成二进制,具体怎么操作?

但凡能用图示,我就不想写文字,所以用一张图就可以解释得明明白白:

image-20240904175708167

整数部分 + 小数部分,因此最终得到的结果二进制结果为110.01011100...

还是按照上一节所述的尾数 + 阶码的计算机计数方式,小数点左移两位,则可以表示为:
1.1001011100... × 2 2 1.1001011100...\times2^{2} 1.1001011100...×22

所以对应可得:

  • 符号位0
  • 阶码(E)部分:若以float为例,应为 127 +(2)= 129,因此二进制表示为:10000001
  • 尾数部分(M)1001011100...,其实它本身无限不循环,但若以float型精度来截取23位,则可以表示为10010111000010100011111

因此最终的总结果为(以32位精度float表示):

01000000110010111000010100011111

所以像这种无限位数的尾数情况,用计算机存储产生截取是必然的,必定会有一定的精度损失!所以这也从根本上解释了为什么float或者double这种类型数据使用时的风险性,因此必须要结合实际业务理性考量。

1.3 浮点数比较

浮点数基本上可以按照符号位、指数域、尾数域的顺序作字典比较。显然,所有正数大于负数;正负号相同时,指数的二进制表示法更大的其浮点数值更大。

1.4 浮点数的舍入

任何有效数上的运算结果,通常都存放在较长的寄存器中,当结果被放回浮点格式时,必须将多出来的比特丢弃。 有多种方法可以用来执行舍入作业,实际上IEEE标准列出4种不同的方法:

  • 舍入到最接近:舍入到最接近,在一样接近的情况下偶数优先(Ties To Even,这是默认的舍入方式):会将结果舍入为最接近且可以表示的值,但是当存在两个数一样接近的时候,则取其中的偶数(在二进制中是以0结尾的)。
  • 朝+∞方向舍入:会将结果朝正无限大的方向舍入。
  • 朝-∞方向舍入:会将结果朝负无限大的方向舍入。
  • 朝0方向舍入:会将结果朝0的方向舍入。

2. 混合精度训练

该篇内容摘自:https://zhuanlan.zhihu.com/p/103685761

在这里的混合精度训练,指代的是单精度 float和半精度 float16 混合。比较经典的就是这篇ICLR2018,百度和Nvidia联合推出的论文 MIXED PRECISION TRAINING。 因此,这里也以这篇论文作为引子,对混合精度进行讲解。

2.1 为什么需要半精度

float16和float的优势,总结下来就是两个方面:内存占用更少,计算更快。

  • 内存占用更少: 这个是显然可见的,通用的模型 fp16 占用的内存只需原来的一半。memory-bandwidth 减半所带来的好处:

    • 模型占用的内存更小,训练的时候可以用更大的batchsize。
    • 模型训练时,通信量(特别是多卡,或者多机多卡)大幅减少,大幅减少等待时间,加快数据的流通。
  • 计算更快:

    • 目前的不少GPU都有针对 fp16 的计算进行优化。论文指出:在近期的GPU中,半精度的计算吞吐量可以是单精度的 2-8 倍;

2.2 FP16带来的问题:量化误差

那么使用FP16的时候有没有什么问题呢?当然有。FP16带来的问题主要有两个:

  • 溢出错误;
  • 舍入误差。
  1. 溢出错误(Grad Overflow / Underflow) 由于FP16的动态范围( 6×10−8∼65504 )比FP32的动态范围( 1.4×10−45∼1.7×1038 )要狭窄很多,因此在计算过程中很容易出现上溢出(Overflow, g>65504 )和下溢出(Underflow, g<6×10−8 )的错误,溢出之后就会出现“Nan”的问题。在深度学习中,由于激活函数的的梯度往往要比权重梯度小,更易出现下溢出的情况。
img

2. 舍入误差(Rounding Error) 舍入误差指的是当梯度过小,小于当前区间内的最小间隔时,该次梯度更新可能会失败,用一张图清晰地表示:

img

这是因为FP16的最小间隔是一个比较玄乎的事,在wikipedia的引用上有这么一张图: 描述了 fp16 各个区间的最小gap。

img

2.3 FP32 权重备份

这种方法主要是用于解决舍入误差的问题。其主要思路,可以概括为:weights, activations, gradients 等数据在训练中都利用FP16来存储,同时拷贝一份FP32的weights,用于更新。 在这里,我直接贴一张论文[1]的图片来阐述:

image-20240904174056317

可以看到,其他所有值(weights,activations, gradients)均使用 fp16 来存储,而唯独权重weights需要用 fp32 的格式额外备份一次。 这主要是因为,在更新权重的时候,往往公式: 权重 = 旧权重 + lr * 梯度,而在深度模型中,lr * 梯度 这个值往往是非常小的,如果利用 fp16 来进行相加的话, 则很可能会出现上面所说的『舍入误差』的这个问题,导致更新无效。因此上图中,通过将weights拷贝成 fp32 格式,并且确保整个更新(update)过程是在 fp32 格式下进行的。

看到这里,可能有人提出这种 fp32 拷贝weight的方式,那岂不是使得内存占用反而更高了呢?是的, fp32 额外拷贝一份 weight 的确新增加了训练时候存储的占用。 但是实际上,在训练过程中,内存中占据大部分的基本都是 activations 的值。特别是在batchsize 很大的情况下, activations 更是特别占据空间。 保存 activiations 主要是为了在 back-propogation 的时候进行计算。因此,只要 activation 的值基本都是使用 fp16 来进行存储的话,则最终模型与 fp32 相比起来,内存占用也基本能够减半。

此时所存储的参数为;

FP16: weights,activations,gradients

FP32: weights,gradients

2.4 Loss Scale

Loss Scale 主要是为了解决 fp16 underflow 的问题。刚才提到,训练到了后期,梯度(特别是激活函数平滑段的梯度)会特别小,fp16 表示容易产生 underflow 现象。 下图展示了 SSD 模型在训练过程中,激活函数梯度的分布情况:可以看到,有67%的梯度小于 2−24 ,如果用 fp16 来表示,则这些梯度都会变成0。

image-20240904174316549

为了解决梯度过小的问题,论文中对计算出来的loss值进行scale,由于链式法则的存在,loss上的scale会作用也会作用在梯度上。这样比起对每个梯度进行scale更加划算。 scaled 过后的梯度,就会平移到 fp16 有效的展示范围内。

这样,scaled-gradient 就可以一直使用 fp16 进行存储了。只有在进行更新的时候,才会将 scaled-gradient 转化为 fp32,同时将scale抹去。论文指出, scale 并非对于所有网络而言都是必须的。而scale的取值为也会特别大,论文给出在 8 - 32k 之间皆可。

2.5 提高算数精度

在论文中还提到一个『计算精度』的问题:在某些模型中,fp16矩阵乘法的过程中,需要利用 fp32 来进行矩阵乘法中间的累加(accumulated),然后再将 fp32 的值转化为 fp16 进行存储。 换句不太严谨的话来说,也就是利用 利用fp16进行乘法和存储,利用fp32来进行加法计算。 这么做的原因主要是为了减少加法过程中的舍入误差,保证精度不损失。

在这里也就引出了,为什么网上大家都说,只有 Nvidia Volta 结构的 拥有 TensorCore 的CPU(例如V100),才能利用 fp16 混合精度来进行加速。 那是因为 TensorCore 能够保证 fp16 的矩阵相乘,利用 fp16 or fp32 来进行累加。在累加阶段能够使用 FP32 大幅减少混合精度训练的精度损失。而其他的GPU 只能支持 fp16 的 multiply-add operation。这里直接贴出原文句子:

Whereas previous GPUs supported only FP16 multiply-add operation, NVIDIA Volta GPUs introduce Tensor Cores that multiply FP16 input matrices andaccumulate products into either FP16 or FP32 outputs

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

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

相关文章

【数据结果-二维前缀和】力扣221. 最大正方形

在一个由 ‘0’ 和 ‘1’ 组成的二维矩阵内&#xff0c;找到只包含 ‘1’ 的最大正方形&#xff0c;并返回其面积。 示例 1&#xff1a; 输入&#xff1a;matrix [[“1”,“0”,“1”,“0”,“0”],[“1”,“0”,“1”,“1”,“1”],[“1”,“1”,“1”,“1”,“1”],[“1”…

Java 入门指南:Java 并发编程 —— 并发容器 TransferQueue、LinkedTransferQueue、SynchronousQueue

BlockingQueue BlockingQueue 是Java并发包&#xff08;java.util.concurrent&#xff09;中提供的一个阻塞队列接口&#xff0c;它继承自 Queue 接口。 BlockingQueue 中的元素采用 FIFO 的原则&#xff0c;支持多线程环境并发访问&#xff0c;提供了阻塞读取和写入的操作&a…

机器学习的入门笔记(第十六周)

本周观看了B站up主霹雳吧啦Wz的图像处理的课程&#xff0c; 课程链接&#xff1a;霹雳吧啦Wz的个人空间-霹雳吧啦Wz个人主页-哔哩哔哩视频 下面是本周的所看的课程总结。 MobileNet V2的代码实现 1、定义ConvBNReLU类&#xff0c;将卷积操作&#xff0c;批量归一化操作&…

有三层交换机就不用路由器了?真的假的

号主&#xff1a;老杨丨11年资深网络工程师&#xff0c;更多网工提升干货&#xff0c;请关注公众号&#xff1a;网络工程师俱乐部 晚上好&#xff0c;我的网工朋友。 在现代企业网络环境中&#xff0c;三层交换机因其高效的数据包处理能力和较低的延迟而受到广泛欢迎。 然而&…

【TheMisto.AI】Flux最强线稿模型实际效果测评(附安装方法)

原文链接&#xff1a;【TheMisto.AI】Flux最强线稿模型实际效果测评&#xff08;附安装方法&#xff09; (chinaz.com) 不知道有没有小伙伴去测试一下哈&#xff0c;上一篇文章用的都是官方提供的参考图&#xff0c;经常关注Flux的小伙伴也知道那些ControlNet买家秀和卖家秀基…

TDesign 微信小程序组件库配置

文章目录 1.安装 npm 包2. 构建 npm3. 构建完成后即可使用 npm 包。4.修改 app.json5.修改 tsconfig.json6.使用组件 1.安装 npm 包 在小程序 package.json 所在的目录中执行命令安装 npm 包&#xff1a; npm install结果报错 PS C:\WeChatProjects\miniprogram-1> npm i…

ARM32开发——(二十三)存储器介绍

1. 存储器分类 存储器按其存储介质特性主要分为“易失性存储器”和“非易失性存储器”两大类。 “易失/非易失”是指存储器断电后&#xff0c; 它存储的数据内容是否会丢失的特性。 在计算机中易失性存储器最典型的代表是内存&#xff0c;非易失性存储器的代表则是硬盘。 2.…

2024年最新版Ajax+Axios 学习【包含原理、Promise、报文、接口等...】

基础知识 AJAX概念 AJAX概念&#xff1a;是浏览器与服务器进行数据通信的技术。 认识URL 定义&#xff1a;统一资源定位符&#xff0c;简称网址&#xff0c;用于访问网络上的资源。 组成&#xff1a; http协议&#xff1a;超文本传输协议&#xff0c;规定浏览器和服务器之…

程序设计—基于JavaWeb的流浪动物救助网站(案例分析)

摘 要 21世纪的今天&#xff0c;随着社会的不断发展与进步&#xff0c;人们对于信息科学化的认识&#xff0c;已由低层次向高层次发展&#xff0c;由原来的感性认识向理性认识提高&#xff0c;管理工作的重要性已逐渐被人们所认识&#xff0c;科学化的管理&#xff0c;使信息…

OpenAI API in node gives basic Await error. How do I fix?

题意&#xff1a;OpenAI API 在 Node 中出现基本的 Await 错误。我该如何修复&#xff1f; 问题背景&#xff1a; I literally copied the code from the openAI example and it gives me a remedial Await JS error but I am unsure what it expects me to do. I just want t…

【开源风云】从若依系列脚手架汲取编程之道(三)

&#x1f4d5;开源风云系列 &#x1f34a;本系列将从开源名将若依出发&#xff0c;探究优质开源项目脚手架汲取编程之道。 &#x1f349;从不分离版本开写到前后端分离版&#xff0c;再到微服务版本&#xff0c;乃至其中好玩的一系列增强Plus操作。 &#x1f348;希望你具备如下…

基于zigbee的蔬菜大棚温湿度监测系统(论文+源码)

1 系统的功能及方案设计 本次基于zigbee的蔬菜大棚温湿度监测系统主要包括传感器节点、协调器节点和监控中心三个功能模块。 其中协调器节点&#xff1a;由cc2530作为主控芯片&#xff0c;负责接收终端一和终端二发送过来的温湿度数据&#xff0c;并将其通过ch340串行转USB输…

【王树森】RNN模型与NLP应用(8/9):Attention(个人向笔记)

前言 基于RNN的Seq2Seq模型无法记住长序列Attentnion机制可以大幅度提升Seq2Seq模型 Seq2Seq Model with Attention Attention可以让句子在逐步变长的时候不忘记前面的输入信息Attention还可以告诉Decoder应该关注哪一个状态优点&#xff1a;Attention可以大幅度提高准确率缺…

【Java】实体类Javabean

文章目录 前言一、实体类Javabean是什么&#xff1f;二、代码总结 前言 记录实体类的基本语法 一、实体类Javabean是什么&#xff1f; 其实就是一种特殊形式的类&#xff0c;这种类特殊点在于&#xff1a; 1、这个类中的成员变量都要私有&#xff0c;并且要对外提供相应的ge…

Dubbo ZooKeeper Spring Boot整合

依赖配置 1. Dubbo 起步依赖 Dubbo 是一款高性能的 Java RPC 框架&#xff0c;用于快速开发高性能的服务。 <dependency><groupId>org.apache.dubbo</groupId><artifactId>dubbo-spring-boot-starter</artifactId><version>${dubbo.ver…

【功能自动化】使用HTMLTestRunner生成测试报告

配置环境&#xff1a; 部署webtours网站 准备数据 user.txt 在软件开发过程中&#xff0c;测试是非常重要的环节&#xff0c;通过测试可以验证代码的正确性和稳定性。而生成测试报告则是测试的一个重要环节&#xff0c;通过测试报告可以清晰地了解测试的结果、覆盖率等信息。…

第九届世界渲染大赛国内参赛者作品在哪里可以看?

第九届世界渲染大赛汇聚了全球顶尖的CG艺术家&#xff0c;其中国内选手的表现尤为引人注目。他们凭借独特的创意视角和精湛的技术&#xff0c;将浓郁的国风元素融入作品之中&#xff0c;为大赛增添了一抹独特的东方色彩。接下来&#xff0c;就让我们一探究竟&#xff0c;看看这…

datagrip链接sql server2005报错

错误信息 第一次报 DBMS: Microsoft SQL Server (no ver.) Case sensitivity: plainmixed, delimitedexact [08S01] 驱动程序无法通过使用安全套接字层(SSL)加密与 SQL Server 建立安全连接。错误:“The server selected protocol version TLS10 is not accepted by client pr…

C++学习笔记----6、内存管理(一)---- 使用动态内存(4)

3.6、多维自由内存空间上的数组 如果需要在运行时决定多维数组的维度&#xff0c;可以使用在自由内存空间上的数组。与一维动态分配的数组通过指针访问一样&#xff0c;多维动态分配的数组也可以通过指针访问。不同的地方在于在二维数组中&#xff0c;需要用一个指向指针的指针…

基于精益六西格玛管理方法进行生产线综合改善

生产线精益六西格玛改善是一个系统工程&#xff0c;只有对其进行系统的策划与组织&#xff0c;才能收到良好的改善效果。一般来说&#xff0c;需要成立一个专门的精益六西格玛推进组织&#xff0c;由其完成一系列的组织、准备工作。具体如下&#xff1a; &#xff08;1&#xf…