“半精度”的16位浮点运算

只需要16位存储空间的浮点算术格式正变得越来越流行。也被称为半精密binary16,该格式在内存不足时非常有用。

目录

背景

IEEE 754标准,1985年出版,定义了浮动占据存储的32个或64位点编号格式。这些格式被称为二进制32二进制64,或更频繁双精度。多年来MATLAB只使用双精度,它仍然是我们的默认格式。单精度已经逐渐加入,在过去几年,现在也完全支持。万博1manbetx

IEEE 754在2008年发布的修订版定义了一种只占用16位的浮点格式。被称为binary16,它的主要目的是减少存储和内存带宽需求。由于它只提供了“半”精度,在实际计算中使用它是有问题的。下面提供了一个关于它作为一种增加动态范围的图像处理格式的实用程序的有趣讨论工业光魔。对半精度的硬件支持万博1manbetx现在可以在许多处理器上使用,包括GPU苹果iPhone 7。以下是有关在半精度上的文章的链接NVIDIA GeForce GPU

浮点解剖

浮点数的格式由两个参数表示,p,比特的分数的数量和,指数中的位数。我会考虑四个精度,季度一半双倍的。四分之一精度格式是我刚刚为这篇博文发明的;它不是标准的,实际上也不是很有用。

这四对特征参数是

p=[4,10,23,52];
Q = [3,5,8,11];

随着这些值p,再加上符号的一位,即这个单词的总位数,w,是二的幂。

w=p+q+1
W = 8 16 32 64

标准化数

大多数浮点数字标准化,表示为

$ x = (1+f)2^e $$

分数$f$在半开区间

$$ 0 \leq f < 1 $$

$f$的二进制表示最多需要p位。换句话说,$2^p f$是一个范围内的整数

$$0\leq 2^p f<2^p$$

指数$e$是一个范围内的整数

$$-b+1\leq e\leq b$$

量$b$是最大的指数偏见

$$ B = 2 ^ {Q-1} - 1 $$

b=2.^(q-1)-1
B = 3 15 127 1023

归一化的数的小数部分为$ 1 + F $,但只有$ F $需要被存储。这导致$ 1 $称为隐位

次正常

有两个指数$e$的值,对于这两个值,有偏指数$e+b$达到了中可能表示的最小值和最大值位。最小的是

$$ E + B = 0 $$

相应的浮点数没有隐藏的前导位。这些都是低于正常的denormal数字。

$$x=\pmf 2^{-b}$$

无穷,不是一个数字

最大可能的有偏指数是

$ e + b = 2^q-1 $。

这个指数场表示的量无穷大,或不是一个数字

由于低于正常值、无穷大或NaN而异常的浮点数百分比随着精度的降低而增加。异常指数只是$2^q$中的$2$值。对于双精度,这是$2/2^{11}$,小于百分之十,但是对于半精度,它是$2/2^5$,大于百分之六。在我的四分之一精度浮点数中,有四分之一是特别的。

对符号位进行编码s=0为负,并且s=1为阴性。并与抵消偏置编码指数,b。然后一个浮点数可以装在w有位

X = [S E + B 2 ^ P * F]

精度和范围

小量

如果一个实数不能与大多数二进制扩展需要表达p位,它必须近似为一个浮点数,确实有这样的二进制表示。这是舍入误差. 表征精度的重要量是机ε,或EPS. 在MATLAB中,每股收益(x)是从距离x到下一个较大的(绝对值)浮点数。毫无争议地,EPS简单地之间的差1和下一个较大的浮点数。

格式卖空每股收益= 2。^ (- p)
EPS = 0.0625 0.00097656 1.1921e-07 2.2204e-16

这就告诉我们,双精度有利于准确的约16位十进制数字,单约7十进制数字,一半约3,和季度勉强不止一个。

realmax

如果一个实数或一个算术运算的结果太大而无法表示,则它溢出并被替换。即不会溢出的最大浮点数

realmax = 2 ^ B。*(2-EPS)
Realmax = 15.5 65504 3.4028e+38 1.7977e+308

realmin

下溢而表示非常小的数就更复杂了。最小的规范化浮点数是

realmin=2.^(-b+1)
Realmin = 0.25 6.1035e-05 1.1755e-38 2.2251e-308

微小的

但也有比realmin。IEEE 754引入了逐渐下溢denormal数字。在2008年修订后的标准他们的名字改为低于正常的

考虑下涌流附近的整数舍入。在754之前,浮点数有一个令人不安的特性xy可能是不平等的,但他们的差异可能会因此而消失x - y变成0。754之间的差距0realmin填充有数字,其间距是相同的之间的间隔realmin2 *最小正浮点数. 我喜欢称这个间隔为最小的次正常数,微小的

小=最小正浮点数。*每股收益
Tiny = 0.015625 5.9605e-08 1.4013e-45 4.9407e-324

浮点整数

flintmax

用浮点数做整数运算是可能的。我喜欢打这样的电话燧石。当我们写的数字$ 3 $ $和$ 3.0,它们是相同的整数不同的描述,但我们认为作为一个固定点,另一个为浮点。最大的是火石flintmax

flintmax=2./eps
flintmax=32 2048 1.6777e+07 9.0072e+15

从技术上讲,所有浮点数都大于flintmax是整数,但它们之间的间距大于1,因此在整数算术中使用它们是不安全的。之间只有整数值浮点数0flintmax都可以被称为燧石。

桌子

让我们收集所有这些解剖学特征一起在一个新的MATLAB桌子

T=[w;p;q;b;每股收益;realmax;realmin;tiny;flintmax];T=表(T(:,1),T(:,2),T(:,3),T(:,4),...'variablenames',{“季”'一半''单身的'“双人”},...'rownames',{“w”“p”“问”“b”'EPS'“最大浮点数”“realmin”...“小”“flintmax”});disp (T)
季度半单个双________ __________ __________ ___________瓦特8 16 32 64第4页10 23 52 Q 3 5 8 11 b 3分配15 127 1023 0.0625 EPS 0.00097656 1.1921e-07 2.2204e-16 realmax 15.5 65504 3.4028e + 38 1.7977e + 308realmin 0.25 6.1035e-05 1.1755e-38 2.2251e-308微小0.015625 5.9605e-08 1.4013e-45 4.9407e-324 flintmax 32 2048 1.6777e + 07 9.0072e + 15

fp8和fp16

3.1版本的克利夫的实验室包括对象的代码@fp8@ FP16开始提供四分之一精度和半精度算法的完整实现。

目前提供的方法如下:

方法(fp16)
用于fp16类的方法:abs eps isfinite mrdivide rem subsref binary eq le mtimes round svd ctranspose fix lt ne sign tril diag fp16 lu norm single triu disp ge max plus size uminus display gt minus realmax subsgn double hex mldivide realmin subsindex

它们只提供部分实现,因为算术不会在紧凑表单上完成。我们欺骗。对于每个单独的标量操作,操作数从它们的短存储解压缩到老式的双精度浮点数。然后,该操作由现有的双精度代码执行,并将结果返回到较短格式。这模拟了降低的精度和限制的范围,但需要相对较少的新代码。

所有的工作都在构造函数中完成@fp8 / fp8.m@fp16/fp16.m我们可以称之为"解构者"@fp8/double.m@fp16 / double.m。构造函数将普通浮点数转换为更精确的表示,方法是尽可能多地将32或64位压缩到8或16位的字中。解构者则相反,他们把东西拆开。

一旦这些方法可用,其他的几乎都是微不足道的。大多数操作的代码与重载加法的代码类似。

类型@ FP16 / plus.m
函数z=plus(x,y)z=fp16(double(x)+double(y));终止

维基百科测试套件

维基百科页面大约半精度包括几个16位示例,其中符号、指数和分数字段分隔。我又加了几个。

0 01111 0000000000=1 0 00101 0000000000=2^-10=eps 0 01111 000000000 1=1+eps=1.0009765625(1之后的次最小浮动)1 10000 0000000000=-2 0 11110 1111111111111=65504(最大半精度)=2^15*(2-eps)0 000001 0000000000=2^-14=r~6.10352e-5(最小正法线)0 000001111111111111111=r*(1-eps)~6.09756e-5(最大次正常)0 000000000001=r*eps~5.96046e-8(最小正低于正常值)0 000000000000000~r*eps/2(底流为零)0 000000000000000=0 100000000000000=-0 01111000000000000=无穷大11111000000000000=-0 11111111111111111=NaN 0 01101 0101010101=0.333251953125~1/3

这提供了用于检查的测试套件fp16标量的操作。

清除0 = fp16(0);一个= fp16 (1);每股收益=每股收益(一);r =最小正浮点数(一);测试= {' 1 ''EPS'“1+eps”'-2'2 / r * (2-eps)”...“r”'R *(1-EPS)'“r *每股收益”的r * eps / 2...“零”'-零''1 /零''-1 /零'“零/零”'1/3'};

让我们运行测试。

T = test (:)' x = eval(T {:});y = fp16 (x);z =二进制(y);w =双(y);流('%18S%04S%19.10克%19.10克%S \ N'...Z,十六进制(Y),双(x)中,W,T {:})终止
0 01111 0000000000 3 c00 1 1 1 0 00101 0000000000 1400 0.0009765625 0.0009765625 eps 0 01111 0000000000 3 c01 1.000976563 1.000976563 1 +每股收益1 10000 0000000000 C000 2 2 2 0 11110 0000000000 7 bff 65504 65504 2 / r * (2-eps) 0 00001 0000000000 0400 6.103515625 6.103515625 e-05 e-05 r 0 6.097555161 6.097555161 00000 1111111111 03 ff e-05 e-05 r * (1-eps) 0 000000000000001 0001 5.960464478e-08 5.960464478e-08 r*eps 0 00000 0000000001 0001 5.960464478e-08 5.960464478e-08 r*eps/2 0 00000 0000000000 0000 0 0 zero 0 00000 0000000000 0000 0 0 -zero 0 11111 0000000000 7C00 Inf Inf 1/zero 1 11111 0000000000 FC00 -Inf -Inf -1/zero 1 11111 1111111111 FFFF NaN NaN zero/zero 0 01101 0101010101 3555 0.3333333333 0.3332519531 1/3

矩阵运算

大部分的方法@fp8@ FP16手柄矩阵。从丢勒的忧郁症II的4×4幻方提供了我的第一个例子。

清晰格式卖空ydF4y2BaM = fp16(魔法(4))
M=16233135110897641414151

让我们来看看封装的16位元素是如何看的二进制文件。

B=二进制(M)
B=4×4字符串数组列1到3“0 10011 0000000000”“0 100000000000000”“0 1000010000000000000”“0 100001 01000000000”“0 10010 01000000000”“0 10010 00100000000”“0 100001 110000000000”“0 100001 100000000”“0 100001000000000000”“0 10010 110000000000”“0 10010 11100000000”列4“0 10010 10100000000”“0 1001000000000000”"0 10010 1000000000" "0 01111 0000000000"

检查行和是否都相等。这个矩阵向量乘法可以用魔法方块中的燧石来完成。

e = fp16(ones(4,1))
e = 1 1 1 1 1 Me = 34 34 34 34

fp16反斜杠

我超载了mldivide,所以可以解决线性系统和计算逆。实际的计算是通过做lutx这是我多年前编写的一个“教科书”函数,远在这个半精确项目之前。但是现在MATLAB对象系统保证了每一个单独的算术操作都是在解压缩的情况下完成的fp16数字。

让我们生成一个包含随机两位数整数项的5乘5矩阵。

一个= fp16 (randi (100 5 5))
A = 76 71 83 44 49 75 4 70 39 45 40 28 32 77 65 66 5 96 80 71 18 10 4 19 76

我将使用fp16反斜线反转一个。所以我需要半精度的单位矩阵。

I = FP16(眼(5))
I=10 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 1

现在重载的反斜杠调用lutx求逆。

X = \我
X = -0.0044 0.0346 0.0125 -0.0254 -0.0046 0.0140 -0.0116 0.0026 -0.0046 -0.0002 0.0071 -0.0176 -0.0200 0.0238 0.0008 -0.0060 -0.0020 0.0200 0.0006 -0.0125 0.0003 -0.0052 -0.0072 0.0174

计算残留。

AX=A*xr=I-AX
AX = 1.0000 -0.0011 -0.0002 -0.0007 -0.0001 -0.0001 0.9990 -0.0001 -0.0007 -0.0001 -0.0001 -0.0005 1.0000 -0.0003 -0.0002 -0.0002 -0.0011 -0.0001 0.9995 -0.0002 -0.0000 -0.0001 0.0001 -0.0001 - 1.0000 0.0011 - 0.0002 R = 0 0 0.0007 0.0001 0.0001 0.0010 0.0001 0.0007 0.0001 0.0001 0.0005 0.0003 0.0002 0.0002 0.0011 0.0001 0.0005 0.0002 0.0000 0.0001-0.0001 - 0.0001 0

两个都斧头R是我从算术精确到只有三个十进制数的期望。

虽然我得到一个不同的随机一个每次我发表这篇博客文章的时候,我希望它有一个适度的条件数。

卡帕=秒(A)
k = 15.7828

一个没有条件不好,我可以颠倒计算逆,并期望得到接近原始整数矩阵。

Z = X \我
Z = 76.1250 71.0000 83.1250 44.1250 49.1250 75.1250 4.0234 70.1875 39.1250 45.1250 40.0625 28.0000 32.0625 77.0000 65.0625 66.1250 5.0234 96.1875 80.1250 71.1250 18.0156 10.0000 4.0156 19.0156 76.0000

fp16圣言

我只是漫不经心地算了一下COND(A)。但条件不在重载方法的列表上fp16。我惊喜地发现MATLAB \ matfun \ cond.m悄悄地在这个新的数据类型上工作。这是代码的核心。

数据库类型条件34:43, dbtype条件47
35 s = svd(A);处理奇异矩阵37 c = Inf(class(A));= max(s)./min(s);40 if is空(c) 41 c = 0 (class(A));42结束43结束47结束

所以它正确地使用了奇异值分解,我有圣言会过载。SVD计算由一个433行m文件处理,svdtx,,就像lutx,是以前写的fp16存在。

让我们再计算SVD。

[U, V] =圣言(A)
U = -0.5210 -0.4841 0.6802 -0.0315 0.1729 -0.4260 -0.2449 -0.3572 -0.4561 -0.6504 -0.4058 0.4683 0.1633 0.6284 -0.4409 -0.5786 0.0268 -0.5620 0.1532 0.5703 -0.2174 0.6968 0.2593 -0.6104 0.1658 267.5000 S = 0 0 0 0 0 71.1875 55.5000 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 16.9531 V = 37.3750 -0.4858 -0.3108 -0.0175 -0.3306 -0.7471 -0.2063 -0.2128 0.92380.2195 0.1039 -0.5332 -0.5205 -0.2920 -0.0591 0.5967 -0.4534 0.2891 -0.2050 0.7993 -0.1742 -0.4812 0.7095 0.1384 -0.4478 0.2126

重建一个从半精度SVD。这不是太寒酸。

USVT = U * * V '
USVT=75.9375 71.0000 83.0625 44.0313 49.0000 75.0000 4.0117 70.0625 38.9688 45.0000 40.0313 28.0469 32.0313 77.0625 65.0625 66.0000 4.9688 96.0625 80.0000 71.0000 18.0313 10.0234 4.0156 19.0313 76.0000

最后,确认我们一直在与fp16物体。

名称大小字节类属性A 5x5 226 fp16 AX 5x5 226 fp16 B 4x4 1576字符串I 5x5 226 fp16 M 4x4 208 fp16 Me 4x1 184 fp16 R 5x5 226 fp16 S 5x5 226 fp16 U 5x5 226 fp16 USVT 5x5 226 fp16 V 5x5 226 fp16 Z 5x5 226 fp16 e 4x184 fp16 kappa 1x8双精度

计算器

我介绍一个计算器在我的博客文章罗马数字. 第3.1版克利夫的实验室还包括一个更为奇特的计算器版本,它以四种不同的精度计算——四分之一、一半、单精度和双精度——并以四种不同的格式显示结果——十进制、十六进制、二进制和罗马。

我喜欢通过点击按键来演示计算器

1 0 0 0 1 = 1

因为小数展开是重复的.123456790

谢谢

感谢数学工作者Ben Tordoff, Steve Eddins和Kiran Kintali,他们为半精度工作提供了背景和指针。




与MATLAB®R2017a一起发布

|

评论

要留下评论,请点击这里登录到您的MathWorks帐户或创建一个新帐户。