pytorch中关于BF16、FP16的一些操作

文章目录

  • 前提
  • 创建BF16和FP16的数据
  • BF16和FP16的二进制存储格式
  • 如何根据十进制数得到对应的二进制存储
  • 如何根据二进制存储计算对应的十进制数?
    • 第一种方法
    • 第二种方法
  • 二进制乘法
  • 如果是负数怎么办?
  • 如何手动计算BF16对应的的二进制存储格式
  • 参考链接

前提

好久没更新博客了,最近在学习过程中遇到了如何生成一个float16的数或者生成一个bfloat16的数,并对其二进制的存储格式进行一些操作的问题,这里做一个简单的记录。

创建BF16和FP16的数据

经过查阅资料发现,python的numpy库可以创建一个FP16的数,但是无法创建BF16的数。pytorch的话,可以创建数据类型为FP16,也可以创建数据类型为BF16的数。所以我们使用pytorch来创建这两种数据格式。

import torch
torch.set_printoptions(precision=32) # print的显示位数

A = torch.rand(1, dtype=torch.bfloat16)
B = torch.rand(1, dtype=torch.float16)

print(f"A: {A}") # A: tensor([0.07031250000000000000000000000000], dtype=torch.bfloat16)
print(f"B: {B}")  # B: tensor([0.03320312500000000000000000000000], dtype=torch.float16)

BF16和FP16的二进制存储格式

参考FP32,TF32,FP16,BF16介绍这篇文章可知。类型为BF16的数据有16bit,1bit为符号位,8bit为指数位,7bit为尾数位;类型为FP16的数据也有16bit,1bit为符号位,5bit为指数位,10bit为尾数位。
同一个十进制数,例如0.75,在数据类型分别为BF16和FP16的情况下,对应的二进制存储肯定是不相同的。那么如何得到BF16和FP16十进制数对应的二进制存储呢?

如何根据十进制数得到对应的二进制存储

代码如下:

import torch
torch.set_printoptions(precision=32)

A = torch.tensor(0.785, dtype=torch.bfloat16)
B = torch.tensor(0.785, dtype=torch.float16)
print(f"A: {A}")   # A: 0.78515625
print(f"B: {B}")   # B: 0.78515625

int16_A = A.view(torch.int16)
int16_B = B.view(torch.int16)


print(bin(int16_A))  # 0b11111101001001
print(bin(int16_B))  # 0b11101001001000

首先说明,虽然我们创建tensor时输入的数据为0.785,但是实际数据是0.78515625,这里不做多余解释,只当我们创建的tensor大小为0.78515625。
先对int16_A = A.view(torch.int16)这行代码做个解析,如果我们直接使用bin(A)代码是会报错的,报错信息是:only integer tensors of a single element can be converted to an index。这是因为只有整型tensor才可以使用bin,我们使用view函数将类型位BF16的数据A所拥有的16个bit位看作是一个int16的整数,FP16同理。如下图所示。
在这里插入图片描述

这样的话我们就可以使用bin查看其二进制存储。在这里我们多说一句:负数在计算机中以补码存储,而正数以原码存储。而符号位0/1代表了这个数是整数还是负数,稍后我们会使用bin查看一个负数得出的二进制存储。

接下来我们对bin(int16_A)的结果进行说明。我们可以看到结果是0b11111101001001,其中0b代表了这个数是二进制,除过0b外,剩下14bit的0/1,那这不对呀,BF16要有16bit的二进制呢。原因在于,bin输出的结果会将前面多余的0省略,我们补上两个0就是16bit了。FP16同理。
在这里插入图片描述
所以0011111101001001就是BF16(0.78515625)所对应的二进制存储。

如何根据二进制存储计算对应的十进制数?

这里我们还是使用上面的0.78515625进行解释。符号位为:0,指数位位:01111110,尾数位为:1001001。

第一种方法

( − 1 ) sign × 2 exp − 127 × ( 2 0 + frac ) 2 (-1)^{\text{sign}} \times 2^{\text{exp}-127}\times (2^0+\text{frac})_{2} (1)sign×2exp127×(20+frac)2
frac代表尾数,exp代表指数,sign代表符号,127是bias(偏置,FP16的中bias为15),1.0代表了隐藏数(隐藏位)。将指数01111110变为十进制的数为126。这个公式中的乘法以及frac都是二进制的。如果这里你不太明白,下面还有一种十进制的方法,你可以进行对比。

将公式套用进去得到
( − 1 ) 0 × ( 1.0 + 0.1001001 ) × 2 126 − 127 = 1 × 1.1001001 × 2 − 1 (-1)^0\times (1.0+0.1001001)\times 2^{126-127} = 1\times 1.1001001 \times 2^{-1} (1)0×(1.0+0.1001001)×2126127=1×1.1001001×21

1.1001001 × 2 − 1 1.1001001 \times 2^{-1} 1.1001001×21 的意思是将小数点向左移动一位,2的指数是负几,就向左移动几位。如果是正数的话,就向右移动。因此我们得到0.11001001,这是一个二进制数,我们现在要将他转为整数。如下:
2 − 1 + 2 − 2 + 2 − 5 + 2 − 8 = 0.78515625 2^{-1}+2^{-2}+2^{-5}+2^{-8}=0.78515625 21+22+25+28=0.78515625
如果这里不明白如何将二进制数转为十进制数,可以自行百度。

第二种方法

公式如下:
( − 1 ) sign × 2 exp − 127 × ( 2 0 + frac ) 10 (-1)^{\text{sign}} \times 2^{\text{exp}-127}\times (2^0+\text{frac})_{10} (1)sign×2exp127×(20+frac)10

乍一看,这个公式和上面的没有区别。是的,的确没有区别,只不过这里我们计算frac时是十进制的。
我们先将frac转为十进制,也就是将0.1001001转为十进制,计算如下:
2 − 1 + 2 − 4 + 2 − 7 = 0.5703125 2^{-1}+2^{-4}+2^{-7} = 0.5703125 21+24+27=0.5703125
然后将其带入公式中如下:
( − 1 ) 0 × ( 2 0 + 0.5703125 ) × 2 126 − 127 = 1 × 1.5703125 × 2 − 1 = 0.78515625 (-1)^0\times (2^{0}+0.5703125)\times 2^{126-127} = 1\times 1.5703125 \times 2^{-1} = 0.78515625 (1)0×(20+0.5703125)×2126127=1×1.5703125×21=0.78515625

可以看到两种计算方式的结果是一样的。第一种方式是使用二进制进行运算,最后将结果转为十进制;第二种方式是直接使用十进制进行计算,结果就直接是十进制的。

二进制乘法

有两个二进制,比如说一个是11011,另一个是01001,那么两个二进制做乘法的结果是多少呢?这里当时犯了一个比较愚蠢的错误,二进制的乘法的结果就是其对应十进制的乘法再转为二进制结果。
11011对应的十进制数是27,01001对应的十进制数是9,所以如下:
( 11011 ) 2 × ( 01001 ) 2 = ( ( 27 ) 10 × ( 9 ) 10 ) 2 = 11110011 (11011)_2\times(01001)_2 = ((27)_{10}\times(9)_{10})_2=11110011 (11011)2×(01001)2=((27)10×(9)10)2=11110011
我们手算一下看结果是否正确。
在这里插入图片描述
可以看到结果完全正确,二进制的乘法就是遇2进一。

如果是负数怎么办?

相同的代码,只不过我们这里是负数,然后使用bin来得到其二进制存储。

import torch
torch.set_printoptions(precision=32)

A = torch.tensor(-0.785, dtype=torch.bfloat16)
print(f"A: {A}")   # A: -0.78515625


int16_A = A.view(torch.int16)
print(int16_A)
print(bin(int16_A))  # -0b100000010110111

在解释这段代码及结果之前,我们先看看windows自带的计算其中,一个负数对应的二进制为多少。
在这里插入图片描述
那么5呢,5是多少?
在这里插入图片描述
可以看到,并不是我们说的负数和正数只不过符号位一个是1,一个是0而已。这句话至关重要:负数在计算机中以补码存储,而正数以原码存储
在这里插入图片描述
按理来说,这样才是正确的,其中绿色的框代表了符号位。但是负数在计算机中是按照补码存储的,求补码的方式就是反码+1,如下图所示:
在这里插入图片描述
这下应该可以明白为什么计算器得出的结果不是我们想要的了。因为它输出的是-5的补码,同理当我们对一个负数使用bin()函数时,输出的也是它的补码。

我们将这个结论应用大到BF16的负数中,看是否成立。
在这里插入图片描述
bin输出的结果是-0b100000010110111,这个-符号就代表了这个数是负数,我们将它转为1即可,同时如果有空缺的bit位置补0即可,所以bin输出的结果就是:1100000010110111,可以看到和我们手动推导的一样。

这里要指出,如果你使用bin(-5)的话,会得到一个-0b101的结果,和我们上面解释的并不一样,这里博主也不太清楚原因,如有了解的,欢迎告知。

如何手动计算BF16对应的的二进制存储格式

上面我们是编程得到BF16的二进制存储格式,那么如何手算呢?这里给出方法。如何计算BF16类型的数据0.78515625对应的二进制存储格式。

  1. 将0.78515625分为整数和小数两部分求二进制
    0.78515325 = 0.11001001 0.78515325 = 0.11001001 0.78515325=0.11001001
  2. 移动小数点,使其位于第一个非0位和其后一位中间。
    0.11001001 = 1.1001001 × 2 − 1 0.11001001 = 1.1001001\times 2^{-1} 0.11001001=1.1001001×21
  3. 计算指数和尾数
    e x p = − 1 + 127 = 126 = ( 1111110 ) 2 f r a c = ( 1001001 ) 2 exp = -1+127=126=(1111110)_2 \\ frac = (1001001)_2 exp=1+127=126=(1111110)2frac=(1001001)2
  4. 将符号位,指数位,尾数位拼起来,注意指数位要补0
    ( 0.78515325 ) 10 = [ 0 ] [ 01111110 ] [ 1001001 ] (0.78515325)_{10} = [0] [01111110] [1001001] (0.78515325)10=[0][01111110][1001001]

参考链接

  1. https://blog.csdn.net/qq_41298763/article/details/135705243
  2. https://www.jianshu.com/p/7affd951b3e4

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

湖北汽车工业学院 实验一 关系数据库标准语言SQL

头歌 实验一 关系数据库标准语言SQL 制作不易!点个关注呗!为大家创造更多的价值! 目录 头歌 实验一 关系数据库标准语言SQL**制作不易!点个关注呗!为大家创造更多的价值!** 第一关:创建数据库第…

Chrome/Edge 使用 Markdown Viewer 查看 Markdown 格式文件

Chrome/Edge 使用 Markdown Viewer 查看 Markdown 格式文件 0. 引言1. 安装 Markdown Viewer 插件2. 使用 Markdown Viewer 阅读 Markdown 格式文件 0. 引言 大部分程序员都喜欢 Markdown 格式的文件,这时给一些没有在电脑上安装 Markdown 编辑器的同事分享资料时&…

脏牛提权(靶机复现)

目录 一、脏牛漏洞概述 二、漏洞复现 1.nmap信息收集 1.1.查看当前IP地址 1.2.扫描当前网段,找出目标机器 1.3.快速扫描目标机全端口 三、访问收集到的资产 192.168.40.134:80 192.168.40.134:1898 四、msf攻击 1.查找对应exp 2.选择对应exp并配置相关设…

基于nodejs+vue健美操评分系统python-flask-django-php

本系统采用的数据库是MySQL,使用nodejs技术开发。在设计过程中,很好地发挥了该开发方式的优势,让实现代码有了良好的可读性,而且使代码的更新和维护更加的方便,操作方便,对以后的维护减少了很多麻烦。系统的…

wpf程序调用macad的c++编写的dll

1.把macad里的build,source文件夹复制到一个文件夹里 2.创建一个wpf项目,在解决方案里添加macad.occt项目 3.把macad.occt设为dll文件,修改平台工具集,在macadtest里引用macad.occt 4.运行,应该会报错,说找…

「09」媒体源:播放本地或在线的音视频GIF文件

「09」媒体源播放本地或在线的音视频GIF文件 通过媒体源功能,您可以添加自己想要展示的各种视频内容,例如自己的视频课程、电影或客户见证视频、以及GIF动画等。 (图层叠加效果) (绿幕抠像叠加效果) 缺点…

Covalent Network(CQT)的以太坊时光机:在 Rollup 时代确保长期数据可用性

以太坊正在经历一场向 “Rollup 时代” 的转型之旅,这一转型由以太坊改进提案 EIP-4844 推动。这标志着区块链技术的一个关键转折,采用了一种被称为“数据块(blobs)”的新型数据结构。为了与以太坊的扩容努力保持一致,…

解析汽车充电桩主板的常见故障表现、原因及应对方法

充电桩主板作为充电桩的核心组件,直接影响着充电桩运行的安全性与稳定性。然而,在使用过程中,充电桩主板难免会因各种原因而出现一些故障情况,因此,了解这些原因并采取相应的应对方法对维护充电桩的正常运行起着至关重…

c语言应该怎么系统的学习?

c语言应该怎么系统的学习? 系统性学习C语言,这个描述首先是给人目标不明确,概念不清晰的映像。在开始前我有一些资料,是我根据网友给的问题精心整理了一份「c语言的资料从专业入门到高级教程」, 点个关注在评论区回复“888”之后…

centos7 安装influxdb+telegraf+grafana 监控服务器

influxdb influxdb是一个时间序列数据库, 所有数据记录都会打上时间戳, 适合存储数字类型的内容 telegraf telegraf 可以用于收集系统和服务的统计数据并发送到influxdb grafana grafana 是一个界面非常漂亮, 可直接读取influxdb数据展示成各种图表的开源可视化web软件 安…

探索 JDK 11 的新特性:迈向 Java 平台的下一个里程碑

随着时间的推移,Java 平台一直在不断演进和改进,为开发人员提供更好的工具和功能。JDK 11 是 Java 平台的一个重要版本,引入了许多新的特性和改进,为开发人员带来了全新的体验和可能性。本文将介绍 JDK 11 中一些重要的新特性&…

python基础语法--快速入门

目录 一、字面量1.1定义 二、关键字三、注释四、引号五、输入输出六、缩进七、数据类型转换八、标识符九、运算符 一、字面量 1.1定义 字面量:在代码中,被写下来的固定的值。 python中哪些值可以被写下来,如何在代码中写他们呢?…

JavaWeb开发-前端HTML基础

1.HTML的基本语法 HTML是什么?:HTML是一种超文本标记语言,负责网页的结构,设计页面的元素内容等 超文本:超越文本限制,除了文本信息,还可以定义图片,音频,视频等标记语言…

2024 年广西职业院校技能大赛高职组《云计算应用》赛项赛题第 5 套

#需要资源或有问题的,可私博主!!! #需要资源或有问题的,可私博主!!! #需要资源或有问题的,可私博主!!! 某企业根据自身业务需求&…

中科数安 || 公司办公文件资料加密、防泄密管理软件系统

#文件防泄密软件# 中科数安提供专业的公司文件资料加密与防泄密管理系统,这套软件主要服务于企业用户,以强化内部信息安全、防止重要数据泄露为核心目标。 中科数安 | 电脑文件防泄密软件 PC地址: www.weaem.com 该系统具备以下功能特性&a…

如何解决kafka rebalance导致的暂时性不能消费数据问题

文章目录 背景思考答案排它故障转移共享 背景 之前在review同组其它业务的时候,发现竟然把kafka去掉了,问了下原因,有一个单独的服务,我们可以把它称为agent,就是这个服务是动态扩缩容的,会采集一些指标&a…

格瑞纳电子邀您参观2024杭州快递物流展

2024长三角快递物流供应链与技术装备展览会 2024.7.8-10 杭州国际博览中心 参展企业介绍 北京格瑞纳电子产品有限公司是一家立足于专业科学技术领域集产品代理、培训咨询和个性化增值服务的高科技公司,于2009年成立于北京,立足于复杂系统仿真领域&…

水电站泄洪预警广播系统方案

一、行业背景 近年来由于危险河道管理措施不到位,调峰电站泄水风险长期存在,信息通报制度缺失以及民众安全警觉性不高等因素导致的水电站在泄洪时冲走下游河道游客以及人民财产的事故频发。 我司通过物联网、云计算、大数据、人工智能等技术手段&#x…

随机链表的深拷贝

目录 一、何为深拷贝? 二、题目 三、思路 1.拷贝节点插入到原节点后面 2.控制拷贝节点的random 3.脱离原链表 : 尾插的思想 四、代码 五、附加 一、何为深拷贝? 一个引用对象一般来说由两个部分组成:一个具名的Handle,也就…

一键跳过开屏广告,这下舒服了

现在的app开屏广告越来越过分了,不小心摇一摇翻转就点开广告了。 今天分享个强大的自动跳过广告https://github.com/gkd-kit/gkd,李跳跳替代品,下载地址在公众号后台对话框回复 广告 玩转互联网达人 苏生不惑备用号,分享各种黑科…