【问题标题】:What should I worry about if I compress float64 array to float32 in numpy?如果我在numpy中将float64数组压缩为float32我应该担心什么?
【发布时间】:2012-06-13 01:42:19
【问题描述】:

这是一种特殊的有损压缩,在 numpy 中很容易实现。

我原则上可以直接比较原始 (float64) 和重构 (float64(float32(original)) 并了解最大误差等信息。

除了查看我的实际数据的最大误差之外,是否有人知道这会产生什么类型的失真,例如作为原始值大小的函数?

我最好先将所有值(64 位)映射到 [-1,1] 上(作为极值的一部分,可以保留在 64 位中)以利用更大的密度浮动在零附近?

我正在添加一个我想到的特定案例。假设我有 500k 到 1e6 的值,范围从 -20 到 20,大约是 IID ~ Normal(mu=0,sigma=4) 所以它们已经非常集中在零附近,“20”是 ~5-sigma 罕见.假设它们是科学测量,其中真正的精度远低于 64 位浮点数,但很难真正准确地知道。我有大量单独的实例(可能是 TB 的价值),因此压缩具有很多实用价值,而 float32 是获得 50% 的快速方法(如果有的话,使用 gzip 等额外一轮无损压缩效果更好)。因此,“-20 到 20”消除了很多对非常大的值的担忧。

【问题讨论】:

    标签: python numpy floating-point compression


    【解决方案1】:

    以下假设您使用的是标准 IEEE-754 浮点运算,这些运算很常见(有一些例外),在通常的舍入到最近模式下。

    如果双精度值在浮点值的正常范围内,那么当双精度值舍入为浮点时发生的唯一变化是有效数字(值的小数部分)从 53 位舍入到 24 位。这将导致最多 1/2 ULP(最小精度单位)的误差。浮点数的 ULP 是不大于浮点数的 2 的最大幂的 2-23 倍。例如,如果一个浮点数是7.25,不大于它的2的最大幂是4,所以它的ULP是4*2-23 = 2-21,大约是4.77 e-7。所以区间[4, 8)中的double转换为float时的误差最多为2-22,约为2.38e-7。再举个例子,如果一个浮点数大约是 0.03,不大于它的 2 的最大幂是 2-6,所以 ULP 是 2-29,而转换为双精度时的最大误差为 2-30

    这些都是绝对错误。相对误差小于 2-24,即 1/2 ULP 除以可能的最小值(特定 ULP 区间中的最小值,因此限制为 2 的幂它)。例如,对于 [4, 8) 中的每个数字 x,我们知道该数字至少为 4,误差最多为 2-22,因此相对误差最多为 2-22 /4 = 2-24。 (错误不能正好是 2-24 因为将 2 的精确幂从 float 转换为 double 时没有错误,所以只有当 x 大于 4 时才会有错误,所以相对错误小于,不等于 2-24。)当您对要转换的值有更多了解时,例如,它比 4 更接近 8,您可以更紧密地限制错误。

    如果数字超出浮点数的正常范围,错误可能会更大。最大有限浮点值为2128-2104,约为3.40e38。当您将 1/2 ULP(float 的;double 具有更精细的 ULP)的 double 转换为 float 时,将返回无穷大,这当然是无限的绝对误差和无限的相对误差。 (大于最大有限浮点数但小于 1/2 ULP 的 double 将转换为最大有限浮点数,并具有与上一段中讨论的相同的错误。)

    最小正向正常浮点数为2-126,约为1.18e-38。此(含)1/2 ULP 内的数字将转换为它,但小于此的数字将转换为特殊的非规范化格式,其中 ULP 固定为 2-149。绝对误差最多为 1/2 ULP,2-150。相对误差很大程度上取决于被转换的值。

    上面讨论的是正数。负数的误差是对称的。

    如果 double 的值可以精确地表示为 float,则转换没有错误。

    将输入数字映射到新的区间可以减少特定情况下的错误。作为一个人为的例子,假设你所有的数字都是区间 [248, 248+224) 中的整数。然后将它们转换为浮点数会丢失所有区分值的信息;它们都将转换为 248。但是将它们映射到 [0, 224) 会保留所有信息;每个不同的输入都会被转换成不同的结果。

    哪种地图最适合您的目的取决于您的具体情况。

    【讨论】:

    • 回复:“取决于您的具体情况”是否有数字最佳实践?鉴于接近零的值具有较小的 ULP(根据上述,取决于大于值的 2 的第一次幂),压缩错误减少了,但映射和反转映射(64 位土地)以及一些错误/成本存在额外的存储空间。在简单的 [-1,1] 情况下(存储极端符号,通过除以映射,通过向上转换后乘以反转)存储需求很小(假设长数组)和 CPU 时间略微空闲(与 IO 相比)所以问题是 64 位 div 和 mult 丢失了什么?
    • 如果你描述你的具体情况而不是我们试图完全描述所有可能的情况会更容易。通常,乘法和除法不太可能有太大帮助。浮点的全部意义在于提供一个动态范围。也就是说,已经内置了一个很好的缩放比例。除非你在非正规范围内,否则相对误差只会变化两倍,缩放只能稍微减少误差。翻译可以更多地减少错误,但前提是您的数字域不包含零或您增加了某些域中的错误。
    • 不要分割。在现代处理器上,除法通常很昂贵(需要很长时间才能执行)。计算一次倒数,然后乘以它。在对双精度数进行算术运算时,您不太可能需要担心舍入错误;该算术中的舍入误差远小于转换为浮点数时的舍入误差。一个例外是,如果您的值可以精确表示,并且您按不是 2 的幂的值进行缩放,则可能会在以前没有舍入错误的情况下产生舍入错误。
    • 我在原帖中添加了一个例子。
    【解决方案2】:

    简单的转换不太可能显着减少错误,因为您的分布以零为中心。

    缩放只能通过两种方式产生影响:第一,它将值移离单精度值的非正规区间,(-2-126, 2-126)。 (例如,如果你乘以 [2-249, 2-126 中的 2123 值)映射到 [ 2-126, 2-3),它在非正规区间之外。)第二,它改变了每个“binade”中值的位置(从 2 的一个幂的区间到下一个)。例如,您的最大值是 20,其中相对误差可能是 1/2 ULP / 20,其中该 binade 的 ULP 是 16*2-23 = 2-19,所以相对误差可能是1/2 * 2-19 / 20,约4.77e-8。假设您按 32/20 缩放,因此 20 以下的值将变为 32 以下的值。然后,当您转换为浮点数时,相对误差最多为 1/2 * 2-19 / 32 (或略低于 32),大约 2.98e-8。所以你可以稍微减少错误。

    关于前者,如果你的值几乎是正态分布的,那么很少会在 (-2-126, 2-126) 中,只是因为那个区间这么小。 (您的正态分布的一万亿个样本几乎可以肯定在该区间内没有值。)您说这些是科学测量,所以也许它们是用某种仪器产生的。可能是机器测量或计算不够精细,无法返回 2-126 到 20 范围内的值,因此如果您在非正规区间中根本没有值,我不会感到惊讶。如果您在单精度非正规范围内没有值,则缩放以避免该范围是没有用的。

    关于后者,我们发现在您的范围末端有一个小的改进。但是,在您的范围内的其他地方,一些值也会移动到 binade 的高端,但有些值会跨越 binade 边界移动到新 binade 的小端,从而导致它们的相对误差增加。不太可能有显着的净改善。

    另一方面,我们不知道什么对您的申请很重要。您的应用程序可以容忍多少错误?如果在每个数字上添加 1% 的随机噪声,最终结果的变化是否会不明显?或者,如果几个数字变化小到 2-200,结果会不会完全无法接受?

    您对产生这些数字的机器了解多少?它真的产生比单精度浮点数更精确的数字吗?也许,尽管它产生 64 位浮点值,但实际值仅限于可以用 32 位浮点表示的总体。您是否执行了从 double 到 float 的转换并测量了错误?

    仍然没有足够的信息来排除这些或其他可能性,但我最好的猜测是任何转换都没有什么好处。转换为浮点数要么会引入太多错误,要么不会,而且首先转换数字不太可能改变这一点。

    【讨论】:

    • 标记为已接受。这解释了与缩放相关的权衡(以及上面解释绝对和相对误差作为幅度函数的答案)。似乎对于我关心的值(参见有问题的示例),我最好在没有任何特殊映射的情况下转换为 float32。
    【解决方案3】:

    float32 的指数要小得多(或在负指数的情况下更大),但假设所有数字都小于该值,您只需要担心精度损失。 float32 只适用于大约 7 或 8 位有效十进制数字

    【讨论】:

    • 我认为您是在暗示作为幅度函数的误差为〜(幅度 * 1e-7),直到指数达到其最大值然后变为(幅度 - max_float32)?如果是这种情况并且您的值相对于 max_float32 很小,那么尝试任何花哨的东西似乎没有任何收获(例如将值映射到 [-1,1]),但我只是想确保我的解释正确?我一直听说 [-1,1] 附近的值更密集,所以我认为那里的误差会小得多。谢谢!
    • @JosephHastings,没错。这些值更密集,但仍然只有相同的精度
    猜你喜欢
    • 2016-05-15
    • 1970-01-01
    • 2016-11-16
    • 1970-01-01
    • 1970-01-01
    • 2011-09-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多