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/
└── dataset3
2. 查看HDF5文件结构
2.1 方法一:使用h5py库(推荐)
2.1.1 基本查看
python
import h5py
import numpy as np
# 打开文件(只读模式)
with h5py.File('data.h5', 'r') as f:
# 查看所有顶层keys
print("顶层keys:", list(f.keys()))
# 递归打印所有结构
def print_structure(name, obj):
print(name)
f.visititems(print_structure)
2.1.2 详细查看函数
python
def explore_h5_structure(filename):
"""
详细探索HDF5文件结构
"""
def print_attrs(name, obj):
"""打印对象的属性"""
print(f"\n{'='*60}")
print(f"路径: {name}")
print(f"类型: {type(obj).__name__}")
# 如果是Dataset,打印详细信息
if isinstance(obj, h5py.Dataset):
print(f"形状: {obj.shape}")
print(f"数据类型: {obj.dtype}")
print(f"大小: {obj.size} 个元素")
# 打印所有属性
if len(obj.attrs) > 0:
print("属性:")
for key, val in obj.attrs.items():
print(f" {key}: {val}")
with h5py.File(filename, 'r') as f:
print(f"文件: {filename}")
print(f"顶层组/数据集: {list(f.keys())}")
f.visititems(print_attrs)
# 使用示例
explore_h5_structure('model.h5')
2.1.3 可视化树状结构
python
def print_h5_tree(filename, indent=""):
"""
以树状结构打印HDF5文件
"""
def print_tree(name, obj):
# 计算缩进
level = name.count('/')
indent = "│ " * level
if isinstance(obj, h5py.Group):
print(f"{indent}├── 📁 {name.split('/')[-1]}/")
elif isinstance(obj, h5py.Dataset):
shape_str = f"{obj.shape}" if obj.shape else "scalar"
print(f"{indent}├── 📄 {name.split('/')[-1]} {shape_str} {obj.dtype}")
with h5py.File(filename, 'r') as f:
print(f"📦 {filename}")
f.visititems(print_tree)
# 使用示例
print_h5_tree('data.h5')
2.2 方法二:使用HDFView(GUI工具)
HDFView是官方提供的图形化工具,可以可视化浏览HDF5文件。
安装:
bash
# 从官网下载
# https://www.hdfgroup.org/downloads/hdfview/
2.3 方法三:使用命令行工具
2.3.1 h5ls命令
bash
# 安装HDF5命令行工具
# Ubuntu/Debian:
sudo apt-get install hdf5-tools
# macOS:
brew install hdf5
# 基本使用
h5ls file.h5 # 列出顶层内容
h5ls -r file.h5 # 递归列出所有内容
h5ls -d file.h5/dataset_name # 查看数据集详细信息
h5ls -v file.h5 # 详细模式
2.3.2 h5dump命令
bash
h5dump file.h5 # 导出完整文件内容
h5dump -H file.h5 # 只显示头部信息(不显示数据)
h5dump -d /dataset_name file.h5 # 导出特定数据集
3. HDF5基本操作
3.1 创建HDF5文件
python
import h5py
import numpy as np
# 创建新文件
with h5py.File('example.h5', 'w') as f:
# 创建数据集
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.0
group.attrs['description'] = 'Example group'
3.2 读取数据
python
with h5py.File('example.h5', 'r') as f:
# 方法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 修改现有文件
python
# 追加模式
with h5py.File('example.h5', 'a') as f:
# 添加新数据集
f.create_dataset('new_dataset', data=np.ones((5, 5)))
# 修改属性
f.attrs['modified'] = True
# 注意:不能直接修改dataset的形状或类型
# 需要删除后重新创建
3.4 删除数据
python
with h5py.File('example.h5', 'a') as f:
# 删除数据集或组
del f['my_dataset']
# 删除属性
del f.attrs['version']
4. 高级用法
4.1 处理大型数据集(分块读写)
python
# 创建大型数据集,使用分块存储
with h5py.File('large_data.h5', 'w') as f:
# chunks参数指定分块大小
dset = f.create_dataset('large_array',
shape=(10000, 10000),
dtype='float32',
chunks=(1000, 1000),
compression='gzip') # 启用压缩
# 分块写入数据
for i in range(10):
data_chunk = np.random.randn(1000, 10000).astype('float32')
dset[i*1000:(i+1)*1000, :] = data_chunk
# 分块读取
with h5py.File('large_data.h5', 'r') as f:
dset = f['large_array']
# 只读取需要的部分
chunk = dset[0:100, 0:100]
# 迭代读取
for i in range(0, dset.shape[0], 1000):
data_chunk = dset[i:i+1000, :]
# 处理数据块...
4.2 压缩选项
python
with h5py.File('compressed.h5', 'w') as f:
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 数据类型和形状调整
python
with h5py.File('flexible.h5', 'w') as f:
# 可扩展数据集
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 保存和加载机器学习模型权重
python
import h5py
import numpy as np
# 保存模型权重
def save_model_weights(filename, weights_dict):
"""
保存模型权重字典到HDF5
weights_dict: {'layer_name': {'weights': array, 'biases': array}}
"""
with h5py.File(filename, 'w') as f:
for layer_name, params in weights_dict.items():
group = f.create_group(layer_name)
for param_name, param_value in params.items():
group.create_dataset(param_name, data=param_value)
# 加载模型权重
def load_model_weights(filename):
"""
从HDF5加载模型权重
"""
weights_dict = {}
with h5py.File(filename, 'r') as f:
for layer_name in f.keys():
weights_dict[layer_name] = {}
for param_name in f[layer_name].keys():
weights_dict[layer_name][param_name] = f[layer_name][param_name][:]
return weights_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 保存训练数据和标签
python
def save_training_data(filename, X_train, y_train, X_val, y_val):
"""
保存训练数据到HDF5
"""
with h5py.File(filename, 'w') as f:
# 创建训练集组
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:]
def load_training_data(filename):
"""
加载训练数据
"""
with h5py.File(filename, 'r') as f:
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']
}
return X_train, y_train, X_val, y_val, metadata
5.3 查看Keras模型文件
python
def inspect_keras_model(model_path):
"""
检查Keras模型的HDF5文件结构
"""
with h5py.File(model_path, 'r') as f:
# Keras模型通常有这些顶层键
print("顶层键:", list(f.keys()))
# 查看模型配置
if 'model_config' in f.attrs:
import json
config = json.loads(f.attrs['model_config'])
print("\n模型配置:")
print(json.dumps(config, indent=2))
# 查看层权重
if 'model_weights' in f:
print("\n模型层:")
for layer_name in f['model_weights'].keys():
print(f"\n层: {layer_name}")
layer_group = f['model_weights'][layer_name]
for weight_name in layer_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 内存管理
python
# ❌ 错误:一次性加载大文件到内存
with h5py.File('large.h5', 'r') as f:
data = f['big_dataset'][:] # 可能导致内存溢出
# ✅ 正确:分批处理
with h5py.File('large.h5', 'r') as f:
dset = f['big_dataset']
batch_size = 1000
for i in range(0, len(dset), batch_size):
batch = dset[i:i+batch_size]
# 处理batch...
6.2 检查文件是否存在某个键
python
with h5py.File('data.h5', 'r') as f:
if 'my_dataset' in f:
data = f['my_dataset'][:]
# 检查嵌套路径
if 'group1/subgroup/dataset' in f:
data = f['group1/subgroup/dataset'][:]
6.3 复制数据集
python
# 从一个文件复制到另一个文件
with h5py.File('source.h5', 'r') as f_src:
with h5py.File('dest.h5', 'w') as f_dst:
# 复制整个组
f_src.copy('group_name', f_dst)
# 复制特定数据集
f_src.copy('dataset_name', f_dst, name='new_name')
6.4 性能优化
python
# 使用合适的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 有用的属性和方法
python
# 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语句)确保文件正确关闭