h5py で圧縮

h5py で既存の HDF5 ファイルを圧縮した。現状の HDF5 は、既存のデータセットを削除できない(論理的には削除できるが、その領域を再利用できないし、ファイルサイズが縮むこともない)ので、新たにファイルを作って、圧縮フィルタを通しながら書き込んでいくしかない。

以下では、data という名前のデータセットのみ圧縮している。

import h5py
import sys

if len(sys.argv) != 3:
    print "Usage: %s inp.h5 out.h5" % sys.argv[0]
    sys.exit(-1)

inp = h5py.File(sys.argv[1], "r")
out = h5py.File(sys.argv[2], "w-")

def rec(dinp, dout):
    for k in dinp:
        print k
        if dinp[k].__class__ is h5py._hl.group.Group:
            dout.create_group(k)
            rec(dinp[k], dout[k])
        else:
            source = dinp[k]
            compression = None
            compression_opts = None
            if k == "data":
                compression = "gzip"
                compression_opts = 9
            dout.create_dataset(k, shape=source.shape, dtype=source.dtype,\
                                   data=source, compression=compression, compression_opts=compression_opts)

rec(inp, out)

とある回折画像を圧縮したところ、サイズは以下のようになった。

設定 サイズ (byte)
元のファイル 41955504
gzip opt2 20686982
gzip opt4 20404798
gzip opt9 20174447
lzf 30444781

速度的には、gzip opt9 <約10倍< opt4 〜 opt2 〜 lzf < 無圧縮 という感じ。

このうち、lzf は h5py 附属なので、hdf5lib だけでは使えない。gzip は hdf5lib 標準添付なのでどの環境でも使えはずだが、実際には Anaconda でインストールされる h5py はビルド方法が不適切で、gzip フィルタが使えない(Anaconda 1.7 h5py does not have gzip/deflate filter)。

と、ここまで書いたところで、h5repack ユーティリティで圧縮できることが判明したorz

h5repack の場合、

h5repack -f GZIP=4 input.h5 output.h5

のようになる。

設定 サイズ (byte) 所要時間 (sec)
元のファイル 1804225760 -
gzip opt2 738225990 40.3
gzip opt4 707160027 52.4

という感じ。