【问题标题】:Compressing floating point data压缩浮点数据
【发布时间】:2012-01-27 16:08:34
【问题描述】:

是否有任何无损压缩方法可以应用于浮点时间序列数据,并且会显着优于将数据以二进制形式写入文件并通过 gzip 运行?

降低精度可能是可以接受的,但必须以可控的方式发生(即我必须能够设置必须保留多少位数的界限)

我正在处理一些大型数据文件,这些文件是一系列相关的doubles,描述了时间的函数(即值是相关的)。我通常不需要完整的 double 精度,但我可能需要更多 float

由于图像/音频有专门的无损方法,我想知道是否有专门针对这种情况的方法。

澄清:我正在寻找现有的实用工具,而不是描述如何实现这样的东西的论文。在速度上可以与 gzip 相媲美的东西会非常好。

【问题讨论】:

  • 你打算如何处理这些数据?你是在转移吗?使用前存放一段时间?只是想使用更少的内存?或者您是否专门寻找一种紧凑的方式来存储时间序列数据?
  • 您说“无损”,但您也说“降低精度是可以接受的”。但是,降低精度损失。
  • 以受控方式降低精度“有损压缩”。 “无损”意味着压缩然后解压缩会产生与原始数据完全相同的数据,逐位。如果结果只是一个近似值(通常以某种受控/有界的方式降级),那么这就是“有损压缩”。
  • 你能抛开头发分裂@jameslarge 吗?它没有增加讨论。这种类型的“我必须是正确的”强迫性争论并没有使 StackOverflow 成为一个更好的地方。让我们专注于解决问题,好吗?
  • 我看到你在 scicomp 上问了一个类似的问题并得到了一些很好的答案,所以我想确保这里有参考:scicomp.stackexchange.com/questions/1671/…

标签: compression floating-point time-series


【解决方案1】:

如果您想创建自己的简单算法,这里有一些想法:

  • 使用当前值与前一个值的异或来获得一组描述差异的位。
  • 将此差异分为两部分:一部分是“尾数位”,另一部分是“指数位”。
  • 使用可变长度编码(每个值的位数/字节数不同)或您选择的任何压缩方法来保存这些差异。您可以为尾数和指数使用单独的流,因为尾数需要压缩的位数更多。
  • 如果您在两个不同的时间价值流源之间交替,这可能无法正常工作。因此,您可能必须将每个源压缩到单独的流或块中。
  • 要降低精度,您可以从尾数中删除最低有效位或字节,同时保持指数不变。

【讨论】:

    【解决方案2】:
    【解决方案3】:

    由于您声明您需要介于“浮点”和“双精度”之间的精度:您可以将单精度和双精度浮点数中的任意数量的最低有效位归零。 IEEE-754 浮点数用二进制表示,大致类似于seeefffffffff,表示值

    sign*1.fffffff*2^(eee).

    您可以将最低有效小数 (f) 位清零。对于单精度(32 位)浮点数,有 23 个小数位,您最多可以将其归零到 22。对于双精度(64 位),它是 52 和最多 51。(如果您将所有位归零,则特殊值 NaN 和 +/-inf 将丢失)。

    特别是如果数据表示十进制值,例如 1.2345,这将有助于数据压缩。那是因为 1.2345 不能完全表示为二进制浮点值,而是表示为0x3ff3c083126e978d,对数据压缩不友好。去掉最低有效的 24 位将得到0x3ff3c08312000000,它仍然精确到大约 9 位十进制数字(在此示例中,差异为 1.6e-9)。

    如果您对原始数据执行此操作,然后存储后续数字之间的差异,那么如果原始数据变化缓慢,它将更加便于压缩(通过 gzip)。

    这是一个 C 语言示例:

    #include <inttypes.h>
    
    double double_trunc(double x, int zerobits)
    {
      // mask is e.g. 0xffffffffffff0000 for zerobits==16
      uint64_t mask = -(1LL << zerobits);  
      uint64_t floatbits = (*((uint64_t*)(&x)));
      floatbits &= mask;
      x = * ((double*) (&floatbits));
      return x;
    }
    

    还有一个在 python/numpy 中:

    import numpy as np
    
    def float_trunc(a, zerobits):
        """Set the least significant <zerobits> bits to zero in a numpy float32 or float64 array.
        Do this in-place. Also return the updated array.
        Maximum values of 'nzero': 51 for float64; 22 for float32.
        """
    
    at = a.dtype
    assert at == np.float64 or at == np.float32 or at == np.complex128 or at == np.complex64
    if at == np.float64 or at == np.complex128:
        assert nzero <= 51
        mask = 0xffffffffffffffff - (1 << nzero) + 1
        bits = a.view(np.uint64)
        bits &= mask
    elif at == np.float32 or at == np.complex64:
        assert nzero <= 22
        mask = 0xffffffff - (1 << nzero) + 1
        bits = a.view(np.uint32)
        bits &= mask
    
    return a
    

    【讨论】:

      【解决方案4】:

      HDF5 人们使用的一种技术是“洗牌”,您可以将 N 个浮点值的每个字节组合在一起。这更有可能为您提供重复的字节序列,这些字节序列将使用 gzip 更好地压缩,for example

      我发现的第二种大大减小压缩 gzip 数据大小的方法是首先将数据转换为 float16 (half-precision) format,然后再转换回 float32。这会在输出流中产生很多零,压缩后可以将文件大小缩小约 40-60%。一个微妙之处是最大 float16 值相当低,因此您可能希望首先缩放数据,例如在python中

      import numpy as np
      import math
      
      input = np.array(...)
      
      # format can only hold 65504 maximum, so we scale input data
      log2max = int(math.log(np.nanmax(input), 2))
      scale = 2**(log2max - 14)
      scaled = input * (1./scale)
      
      # do the conversion to float16
      temp_float16 = np.array(scaled, dtype=np.float16)
      # convert back again and rescale
      output = np.array(temp_float16, dtype=np.float32) * scale
      

      一些测试表明,某些数据的输入和输出之间的平均绝对分数差异约为 0.00019,最大值为 0.00048。这符合尾数的 2**11 精度。

      【讨论】:

      【解决方案5】:

      既然您要的是现有工具,也许zfp 可以解决问题。

      【讨论】:

        【解决方案6】:

        可用于浮点压缩的可能方法:

        您可以使用适用于 linux 和 windows 的 icapp 工具,使用您的数据测试所有这些方法。

        【讨论】:

          【解决方案7】:

          您可以使用 Holt 的指数平滑算法(基于预测的压缩算法)。最初为数据分配一些权重并预测下一个值。如果两个数据相同,则通过 XOR 操作在 MSB 中产生许多零

          【讨论】:

            猜你喜欢
            • 2013-09-19
            • 1970-01-01
            • 1970-01-01
            • 2011-08-06
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-01-13
            • 1970-01-01
            相关资源
            最近更新 更多