HDF5文件学习笔记
1. HDF5简介
1.1 什么是HDF5?
HDF5 (Hierarchical Data Format version 5) 是一种用于存储和组织大量数据的文件格式和库。它特别适合处理大规模科学数据、机器学习模型和数据集。
主要特点:
- 支持超大文件和超大数据集
- 层次化组织结构(类似文件系统)
- 高效的I/O性能
- 跨平台兼容
- 支持压缩
- 广泛应用于深度学习(Keras、PyTorch等)
1.2 基本概念
- File: HDF5文件本身
- Group: 类似文件夹,可以包含其他Group或Dataset
- Dataset: 实际存储数据的多维数组
- Attribute: 附加到Group或Dataset的元数据
文件结构类似于:
my_file.h5 ├── group1/ │ ├── dataset1 │ └── dataset2 └── group2/ └── subgroup/ └── dataset32. 查看HDF5文件结构
2.1 方法一:使用h5py库(推荐)
2.1.1 基本查看
importh5pyimportnumpyasnp# 打开文件(只读模式)withh5py.File('data.h5','r')asf:# 查看所有顶层keysprint("顶层keys:",list(f.keys()))# 递归打印所有结构defprint_structure(name,obj):print(name)f.visititems(print_structure)2.1.2 详细查看函数
defexplore_h5_structure(filename):""" 详细探索HDF5文件结构 """defprint_attrs(name,obj):"""打印对象的属性"""print(f"\n{'='*60}")print(f"路径:{name}")print(f"类型:{type(obj).__name__}")# 如果是Dataset,打印详细信息ifisinstance(obj,h5py.Dataset):print(f"形状:{obj.shape}")print(f"数据类型:{obj.dtype}")print(f"大小:{obj.size}个元素")# 打印所有属性iflen(obj.attrs)>0:print("属性:")forkey,valinobj.attrs.items():print(f"{key}:{val}")withh5py.File(filename,'r')asf:print(f"文件:{filename}")print(f"顶层组/数据集:{list(f.keys())}")f.visititems(print_attrs)# 使用示例explore_h5_structure('model.h5')2.1.3 可视化树状结构
defprint_h5_tree(filename,indent=""):""" 以树状结构打印HDF5文件 """defprint_tree(name,obj):# 计算缩进level=name.count('/')indent="│ "*levelifisinstance(obj,h5py.Group):print(f"{indent}├── 📁{name.split('/')[-1]}/")elifisinstance(obj,h5py.Dataset):shape_str=f"{obj.shape}"ifobj.shapeelse"scalar"print(f"{indent}├── 📄{name.split('/')[-1]}{shape_str}{obj.dtype}")withh5py.File(filename,'r')asf:print(f"📦{filename}")f.visititems(print_tree)# 使用示例print_h5_tree('data.h5')2.2 方法二:使用HDFView(GUI工具)
HDFView是官方提供的图形化工具,可以可视化浏览HDF5文件。
安装:
# 从官网下载# https://www.hdfgroup.org/downloads/hdfview/2.3 方法三:使用命令行工具
2.3.1 h5ls命令
# 安装HDF5命令行工具# Ubuntu/Debian:sudoapt-getinstallhdf5-tools# macOS:brewinstallhdf5# 基本使用h5ls file.h5# 列出顶层内容h5ls -r file.h5# 递归列出所有内容h5ls -d file.h5/dataset_name# 查看数据集详细信息h5ls -v file.h5# 详细模式2.3.2 h5dump命令
h5dump file.h5# 导出完整文件内容h5dump -H file.h5# 只显示头部信息(不显示数据)h5dump -d /dataset_name file.h5# 导出特定数据集3. HDF5基本操作
3.1 创建HDF5文件
importh5pyimportnumpyasnp# 创建新文件withh5py.File('example.h5','w')asf:# 创建数据集data=np.random.randn(100,50)f.create_dataset('my_dataset',data=data)# 创建组group=f.create_group('my_group')group.create_dataset('nested_data',data=np.arange(10))# 添加属性f.attrs['author']='Josh'f.attrs['version']=1.0group.attrs['description']='Example group'3.2 读取数据
withh5py.File('example.h5','r')asf:# 方法1:直接读取整个数据集data=f['my_dataset'][:]# 方法2:切片读取(节省内存)subset=f['my_dataset'][0:10,:]# 方法3:访问嵌套数据nested=f['my_group/nested_data'][:]# 读取属性author=f.attrs['author']description=f['my_group'].attrs['description']3.3 修改现有文件
# 追加模式withh5py.File('example.h5','a')asf:# 添加新数据集f.create_dataset('new_dataset',data=np.ones((5,5)))# 修改属性f.attrs['modified']=True# 注意:不能直接修改dataset的形状或类型# 需要删除后重新创建3.4 删除数据
withh5py.File('example.h5','a')asf:# 删除数据集或组delf['my_dataset']# 删除属性delf.attrs['version']4. 高级用法
4.1 处理大型数据集(分块读写)
# 创建大型数据集,使用分块存储withh5py.File('large_data.h5','w')asf:# chunks参数指定分块大小dset=f.create_dataset('large_array',shape=(10000,10000),dtype='float32',chunks=(1000,1000),compression='gzip')# 启用压缩# 分块写入数据foriinrange(10):data_chunk=np.random.randn(1000,10000).astype('float32')dset[i*1000:(i+1)*1000,:]=data_chunk# 分块读取withh5py.File('large_data.h5','r')asf:dset=f['large_array']# 只读取需要的部分chunk=dset[0:100,0:100]# 迭代读取foriinrange(0,dset.shape[0],1000):data_chunk=dset[i:i+1000,:]# 处理数据块...4.2 压缩选项
withh5py.File('compressed.h5','w')asf:data=np.random.randn(1000,1000)# GZIP压缩(0-9级别)f.create_dataset('gzip_data',data=data,compression='gzip',compression_opts=9)# LZF压缩(速度快)f.create_dataset('lzf_data',data=data,compression='lzf')# 不压缩f.create_dataset('raw_data',data=data)4.3 数据类型和形状调整
withh5py.File('flexible.h5','w')asf:# 可扩展数据集dset=f.create_dataset('expandable',shape=(100,),maxshape=(None,),# 可无限扩展dtype='float32')# 扩展数据集dset.resize((200,))dset[100:200]=np.random.randn(100)# 复合数据类型dt=np.dtype([('name','S50'),('age','i4'),('score','f8')])dset_struct=f.create_dataset('structured',shape=(10,),dtype=dt)5. 实用示例
5.1 保存和加载机器学习模型权重
importh5pyimportnumpyasnp# 保存模型权重defsave_model_weights(filename,weights_dict):""" 保存模型权重字典到HDF5 weights_dict: {'layer_name': {'weights': array, 'biases': array}} """withh5py.File(filename,'w')asf:forlayer_name,paramsinweights_dict.items():group=f.create_group(layer_name)forparam_name,param_valueinparams.items():group.create_dataset(param_name,data=param_value)# 加载模型权重defload_model_weights(filename):""" 从HDF5加载模型权重 """weights_dict={}withh5py.File(filename,'r')asf:forlayer_nameinf.keys():weights_dict[layer_name]={}forparam_nameinf[layer_name].keys():weights_dict[layer_name][param_name]=f[layer_name][param_name][:]returnweights_dict# 使用示例weights={'layer1':{'weights':np.random.randn(784,128),'biases':np.zeros(128)},'layer2':{'weights':np.random.randn(128,10),'biases':np.zeros(10)}}save_model_weights('model_weights.h5',weights)loaded_weights=load_model_weights('model_weights.h5')5.2 保存训练数据和标签
defsave_training_data(filename,X_train,y_train,X_val,y_val):""" 保存训练数据到HDF5 """withh5py.File(filename,'w')asf:# 创建训练集组train_group=f.create_group('train')train_group.create_dataset('X',data=X_train,compression='gzip')train_group.create_dataset('y',data=y_train,compression='gzip')# 创建验证集组val_group=f.create_group('validation')val_group.create_dataset('X',data=X_val,compression='gzip')val_group.create_dataset('y',data=y_val,compression='gzip')# 添加元数据f.attrs['num_train_samples']=len(X_train)f.attrs['num_val_samples']=len(X_val)f.attrs['input_shape']=X_train.shape[1:]defload_training_data(filename):""" 加载训练数据 """withh5py.File(filename,'r')asf:X_train=f['train/X'][:]y_train=f['train/y'][:]X_val=f['validation/X'][:]y_val=f['validation/y'][:]metadata={'num_train':f.attrs['num_train_samples'],'num_val':f.attrs['num_val_samples'],'input_shape':f.attrs['input_shape']}returnX_train,y_train,X_val,y_val,metadata5.3 查看Keras模型文件
definspect_keras_model(model_path):""" 检查Keras模型的HDF5文件结构 """withh5py.File(model_path,'r')asf:# Keras模型通常有这些顶层键print("顶层键:",list(f.keys()))# 查看模型配置if'model_config'inf.attrs:importjson config=json.loads(f.attrs['model_config'])print("\n模型配置:")print(json.dumps(config,indent=2))# 查看层权重if'model_weights'inf:print("\n模型层:")forlayer_nameinf['model_weights'].keys():print(f"\n层:{layer_name}")layer_group=f['model_weights'][layer_name]forweight_nameinlayer_group.keys():weight=layer_group[weight_name]print(f"{weight_name}: shape={weight.shape}, dtype={weight.dtype}")# 使用示例inspect_keras_model('my_model.h5')6. 常见问题和技巧
6.1 内存管理
# ❌ 错误:一次性加载大文件到内存withh5py.File('large.h5','r')asf:data=f['big_dataset'][:]# 可能导致内存溢出# ✅ 正确:分批处理withh5py.File('large.h5','r')asf:dset=f['big_dataset']batch_size=1000foriinrange(0,len(dset),batch_size):batch=dset[i:i+batch_size]# 处理batch...6.2 检查文件是否存在某个键
withh5py.File('data.h5','r')asf:if'my_dataset'inf:data=f['my_dataset'][:]# 检查嵌套路径if'group1/subgroup/dataset'inf:data=f['group1/subgroup/dataset'][:]6.3 复制数据集
# 从一个文件复制到另一个文件withh5py.File('source.h5','r')asf_src:withh5py.File('dest.h5','w')asf_dst:# 复制整个组f_src.copy('group_name',f_dst)# 复制特定数据集f_src.copy('dataset_name',f_dst,name='new_name')6.4 性能优化
# 使用合适的chunk大小# 经验法则:chunk大小应该在10KB-1MB之间optimal_chunk=(100,100)# 根据访问模式调整dset=f.create_dataset('data',shape=(10000,10000),chunks=optimal_chunk,compression='gzip',compression_opts=4,# 平衡压缩率和速度shuffle=True)# 提高压缩效果7. 快速参考
7.1 常用打开模式
| 模式 | 说明 |
|---|---|
| ‘r’ | 只读(文件必须存在) |
| ‘r+’ | 读写(文件必须存在) |
| ‘w’ | 创建文件,覆盖已存在的文件 |
| ‘w-’ 或 ‘x’ | 创建文件,文件存在则失败 |
| ‘a’ | 读写,文件不存在则创建 |
7.2 常用压缩方法
| 压缩方法 | 特点 | 压缩比 | 速度 |
|---|---|---|---|
| ‘gzip’ | 标准压缩 | 高 | 慢 |
| ‘lzf’ | 快速压缩 | 中等 | 快 |
| None | 无压缩 | 1:1 | 最快 |
7.3 有用的属性和方法
# Dataset属性dset.shape# 形状dset.dtype# 数据类型dset.size# 元素总数dset.chunks# 分块大小dset.compression# 压缩方法# File/Group方法f.keys()# 列出键f.values()# 列出值f.items()# 列出键值对f.visit(func)# 遍历所有对象f.visititems(func)# 遍历所有对象(带名称)8. 总结
HDF5是处理大规模科学数据和机器学习数据的强大工具。关键要点:
- 层次化结构:使用Group组织数据,类似文件系统
- 高效I/O:支持分块读写,避免内存溢出
- 压缩支持:节省存储空间
- 元数据:使用attributes存储描述信息
- 跨平台:Python、MATLAB、R等都支持
最佳实践:
- 使用压缩节省空间
- 合理设置chunk大小
- 为大数据集启用分块读写
- 添加有意义的attributes
- 使用上下文管理器(with语句)确保文件正确关闭