跳至主要內容

H5DF | H5py 文档小整理

Kevin 吴嘉文大约 3 分钟知识笔记大数据NLP

H5DF 简介

HDF5 官方文档链接open in new window,以下对 H5PY 基础操作进行总结。安装:

conda install h5py

File

f = h5py.File('myfile.hdf5','w')

文件模式 w/a/r等于 python io 类似。同时 H5PY 还提供了 SWMR 接口,可以实现但进程写入的同时多进程读取。此外,文件还提供不同的 driver 形式,已针对不同的数据场景:

f = h5py.File('myfile.hdf5', driver=<driver name>, <driver_kwds>)

使用结束后需要关闭:f.close()。对于一次性读取的可以使用 with h5py.File() as fp:

Group

group 的功能类似于菜单,Group 下面可以储存 Group 和 dataset 类型数据。

创建组对象:

grp = f.create_group("bar")
grp.name  # '/bar'
subgrp = grp.create_group("baz")
subgrp.name  # '/bar/baz'

引用组对象:

grp3 = f['/some/long']
grp3.name  # '/some/long'

可以采用 keys(), values() 遍历对象。但是更推荐使用 group.visit()group.visititems()

group.get() 类似于字典的 get。判断某个 group 是否存在可以尝试使用:if f['group_name'],但部分 H5PY 版本不支持。

Datasets

h5py dataset 中的数据 API 与 numpy 类似。

创建 DATASET,必须指定 dataset 的 name, shape, dtype。默认的dtypef。(除非创建 Empty dataset)

dset = f.create_dataset("ints", (100,), dtype='i8')
dataset 导入数据

创建时候导入

arr = np.arange(100)
dset = f.create_dataset("init", data=arr)

对以有 dataset 导入:

dset[0, 1] = 3.0  # print(dset[0, 1])
dset[0,:] = other_data
dataset 引用数据

注意:不能使用 numpy 中的双层索引,如dset[0][3]

dset = f.create_dataset("MyDataset", (10,10,10), 'f')
dset[0,0,0]
dset[0,2:10,1:9:3]
dset[:,::2,5]
dset[0]
dset[1,5]
dset[0,...]
dset[...,6]
dset[()]

如果要遍历 dataset 的话,采用 dataset.len() 代替 len(dataset)

chunked

默认 h5df dataset 采用连续空间存储。但可以采用 chunks 来指定数据存储的连续性。如下:

dset = f.create_dataset("chunked", (1000, 1000), chunks=(100, 100))

案例中表示 dset[0:100,0:100], dset[200:300, 400:500] 将被储存再连续空间。官方建议设置 chunk 块大小为 10kb - 1MB。chunked 的特点就是,当 chunked 中的一个数据被读取的时候,整个 chunked 的数据都会被读取。可以让 h5df 自动设置 chunk 的大小。

dset = f.create_dataset("autochunk", (1000, 1000), chunks=True)

如对于深度学习,你可能希望将 chunks 手动设置为每个 samples 的大小,这样会比让系统自动设置快很多。(个人测试最快时候可以差 10 倍读取速度)

resizable dataset

dset = f.create_dataset("unlimited", (10, 10), maxshape=(None, 10))

需要注意的是 resize 不是像 numpy 的 reshape,缩小维度上的数据会被直接丢弃掉

compression

compression 压缩有时候甚至可以提高读取的速度!压缩可以选择不同的方式,以及不同的等级。

df.create_dataset(dset_name, data=data, maxshape=tuple(shape_list), dtype='int64',
                          chunks=tuple(data_shapes[dset_name]), compression="gzip")

Attibute

向 group 或者 dataset 添加 attibute。通常为 64kb 以下的小数据

dset.attrs["myAttr1"] = [100, 200]
dset.attrs.get("myAttr1")

其他

对于字符串内容,需要定义特殊类型

f = h5py.File('foo.hdf5')
>>> dt = h5py.string_dtype(encoding='utf-8')
>>> ds = f.create_dataset('VLDS', (100,100), dtype=dt)
>>> ds.dtype.kind
'O'
>>> h5py.check_string_dtype(ds.dtype)
string_info(encoding='utf-8', length=None)
  • 顺序读取 h5df 数据库的速度会比随机读取快很多!快将近 40%

  • 使用 H5DF 配合 dataloader 的时候,建议添加 dataloader num_workers > 0,个人测试可以提升最高 5%的训练速度。

  • 如果需要 shuffle 的话,建议同时使用 batchsampler,因为 h5df 的随机访问效率能够被提高。

  • 似乎 h5df 1.10 的多线程处理效率更好?h5df dataloader 相关open in new window

  • group 的访问也是需要时间的(命名空间上的搜索需要花费大量时间),因此如果要遍历 dataset 的话,最好直接采用变量引用到 dataset,而非在 group 基础上使用 group['dset'] 来遍历。如:

    # 建议这样写,节省命名空间搜索
    self.feature_dataset = h5py.File(self.h5df_path, 'r', swmr=True)[feature_group_name]
    features = self.feature_dataset[self.sample_ids[index]]
    data = {
        'input_ids': features[0],
        'input_mask': features[1],
        'segment_ids': features[2],
    }
    

    上面方式会比下面方式速度快很多:

    self.dataset = h5py.File(self.h5df_path, 'r', swmr=True)
    features = self.dataset[feature_group_name][self.sample_ids[index]]
    data = {
        'input_ids': features[0],
        'input_mask': features[1],
        'segment_ids': features[2],
    } 
    
上次编辑于:
贡献者: kevinng77