web-dev-qa-db-ja.com

浮動小数点データの圧縮

浮動小数点時系列データに適用できるロスレス圧縮方法はありますか。たとえば、データをバイナリとしてファイルに書き込んでgzipで実行すると、パフォーマンスが大幅に向上しますか?

精度の低下は許容できるかもしれませんが、制御された方法で発生する必要があります(つまり、保持する必要がある桁数に限界を設定できる必要があります)

時間の関数を記述する一連の相関doublesであるいくつかの大きなデータファイルで作業しています(つまり、値は相関しています)。通常、完全なdouble精度は必要ありませんが、floatより多くの精度が必要になる場合があります。

画像/音声にはロスレスの特殊な方法があるため、この状況に特化したものが存在するのではないかと思っていました。

説明:このようなものを実装する方法を説明する論文ではなく、既存の実用的なツールを探しています。速度のgzipに匹敵するものは素晴らしいでしょう。

43
Szabolcs
22
Bobrovsky

独自の単純なアルゴリズムを作成する場合のアイデアをいくつか次に示します。

  • 現在の値と前の値のxorを使用して、違いを表すビットのセットを取得します。
  • この違いを2つの部分に分けます。1つは「仮数ビット」で、もう1つは「指数ビット」です。
  • 可変長エンコーディング(値ごとに異なるビット/バイト数)、または選択した圧縮方法を使用して、これらの違いを保存します。仮数には圧縮するビットが多いため、仮数と指数に別々のストリームを使用する場合があります。
  • 2つの異なる時間値ストリームソースを交互に使用している場合、これはうまく機能しない可能性があります。そのため、各ソースを個別のストリームまたはブロックに圧縮する必要がある場合があります。
  • 精度を落とすには、指数をそのままにして、仮数から最下位ビットまたはバイトを削除できます。
18
Frank Hileman

「float」と「double」の間のどこかに精度が必要であると述べたので、単精度および倍精度の浮動小数点の最下位ビットをいくつでもゼロにできます。 IEEE-754浮動小数点数は、おおよそseeefffffffffのようにバイナリで表され、値を表します

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

最下位(f)ビットをゼロにできます。単精度(32ビット)浮動小数点数の場合、23の小数ビットがあり、最大で22までゼロ化できます。倍精度(64ビット)の場合は、52から最大51です。(すべてのビットをゼロ化する場合、その後、特別な値NaNおよび+/- infは失われます)。

特に、データが1.2345などの10進数値を表す場合、これはデータ圧縮に役立ちます。これは、1.2345を2進浮動小数点値として正確に表すことができないため、データ圧縮に適さない0x3ff3c083126e978dとして表すことができるためです。最下位の24ビットを切り落とすと、0x3ff3c08312000000が生成されますが、これは10桁の約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の1つ:

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
6

既存のツールを求めているので、多分 zfp でうまくいくでしょう。

4
primfaktor

浮動小数点圧縮に使用できる可能な方法:

  • Floatの場合は4xN、double + lz77の場合は8xNを転置します
    実装: TurboTransposeでの浮動小数点圧縮
    エラー制限付き不可逆圧縮も参照

  • 予測子(例:有限コンテキストメソッド)+エンコード(例: "整数圧縮")。
    実装: TurboPForの浮動小数点圧縮

  • 可能であれば、すべての浮動小数点数を整数に変換します(例:1.63-> 163)、
    その後、整数圧縮を使用します
    実装: 整数圧縮

LinuxおよびWindows用の icapp ツールを使用して、これらのすべてのメソッドをデータでテストできます。

3
powturbo

HDF5の人々が使用する1つの手法は「シャッフル」で、N個の浮動小数点値の各バイトをグループ化します。これは、gzipでよりよく圧縮される反復的なバイトシーケンスを提供する可能性が高くなります たとえば

圧縮されたgzip圧縮されたデータのサイズを大幅に削減する2つ目の方法は、最初にデータを float16(半精度)形式 に変換し、再びfloat32に戻すことです。これにより、出力ストリームに多くのゼロが生成され、圧縮後にファイルサイズを約40〜60%縮小できます。微妙な点の1つは、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精度と一致しています。

3
xioxox

Holtの指数平滑化アルゴリズム(予測ベースの圧縮アルゴリズム)を使用できます。最初にデータにいくつかの重みを割り当て、次の値を予測します。両方のデータが同じ場合、XOR演算を実行することにより、MSBに多くのゼロが生成されます

1
Giriraj