mcpField
C
cupynumeric-hdf5

cupynumeric-hdf5

github.com/promptingcompany数据与数据库039 次安装17 周前更新
代码仓库

关于 cupynumeric-hdf5

cupynumeric-hdf5 是使用 `legate.io.hdf5` 在 cuPyNumeric 与 HDF5 文件间读写数组的技能,面向处理分布式数组和 HPC 数据流程的用户。它支持按块读取,并说明异步写入、GPU 读取及数据转换的注意事项。

主要功能

  1. 01并行写入单个 HDF5 文件
  2. 02读取 HDF5 数据集为分布式数组
  3. 03按块读取大型数据集
  4. 04LogicalArray 与 cuPyNumeric 数组转换
  5. 05说明 GPU 读取的 GDS 设置

适用场景

  1. 01将 cuPyNumeric 数组保存为 HDF5
  2. 02将 HDF5 数据集载入分布式数组
  3. 03分块读取大型 HDF5 文件
  4. 04为 GPU HDF5 读取配置 GDS

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/promptingcompany/nv-skills --skill cupynumeric-hdf5

安装后在 Claude Code 中输入/cupynumeric-hdf5确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

BENCHMARK.md
skill-card.md
skill.oms.sig
assets/
hdf5_batched_read.py
hdf5_roundtrip.py
evals/
evals.json

详细介绍

cuPyNumeric HDF5 I/O

用途

使用 legate.io.hdf5 将 cuPyNumeric 数组读写为 HDF5 文件。只要需要将 cuPyNumeric 数组写入 .h5/.hdf5 文件,或从中读取数组,就使用它:每个 rank 都会并行读取和写入自己的数据块,因此不要通过单个进程传输大型数组。

直接回答。 将以下代码片段和规则视为完整且经过验证的内容——对于保存/加载/分块读取/同步/桥接相关问题,直接作答,无需打开 assets/ 脚本或阅读已安装的 legate 源码。只有在运行验证时才使用这些资源。

适用场景

当用户询问以下内容时使用:将 cuPyNumeric 数组保存到 .h5/.hdf5 文件、将 HDF5 数据集加载到 cuPyNumeric 数组、分块读取大型 HDF5 数据集、为 HPC 后处理工作流生成单个文件,或使用 GPUDirect Storage 加速 HDF5 磁盘 I/O。

不适用场景

对于以下请求,请转而使用其他方案,而非 legate.io.hdf5:

  • 将 Parquet/Arrow/cuDF、原始二进制或分片/自定义磁盘布局相关请求交给 cupynumeric-parallel-data-load 技能——它负责处理 cuPyNumeric 没有内置加载器的路径;legate.io.hdf5 仅支持单文件 HDF5。
  • 使用 cuPyNumeric 运算处理纯数组计算(FFT、矩阵乘法、归约、切片、线性代数)——本技能仅涉及磁盘 I/O。
  • 将分块或对象存储(S3)输出写入 Zarr 等分块格式——不要使用单文件 HDF5。
  • 使用 NumPy(np.load)加载 .npz 或 pickle 归档,然后通过 cn.asarray(...) 转换——legate.io.hdf5 仅读取 HDF5,而 cupynumeric.load 仅读取单个 .npy 文件。
  • 对于不涉及 cuPyNumeric/Legate 的普通 HDF5 读取,直接使用 h5py——with h5py.File(path, "r") as f: arr = f["dataset"][:]。

前提条件

在从 legate.io.hdf5 导入任何内容之前安装 h5py:

conda install -c conda-forge h5py        # required; legate/io/hdf5.py imports it at load

在安装之前,执行 from legate.io.hdf5 import ... 会触发 ModuleNotFoundError——该模块会在加载时导入 h5py。(h5py · conda-forge 构建)

API

函数签名用途
to_fileto_file(array, path, dataset_name)将 cuPyNumeric 数组/LogicalArray 写入一个 HDF5 文件,作为虚拟数据集(VDS)——每个 rank 写入自己的数据块。
from_filefrom_file(path, dataset_name) -> LogicalArray将一个 HDF5 数据集读入分布式数组。
from_file_batchedfrom_file_batched(path, dataset_name, chunk_size) -> Iterator[(LogicalArray, offsets)]分块读取数据集——分块的是文件读取,而不是组装后的数组。

从 legate.io.hdf5 导入以上三个函数。始终将 dataset_name 设为文件中单个数组的完整路径(例如 "/data" 或 "/group/x"),而不是群组。

示例

往返读写
import cupynumeric as cn
from legate.core import get_legate_runtime
from legate.io.hdf5 import from_file, to_file

a = cn.arange(64, dtype=cn.float32).reshape(8, 8)

# Write: pass the cuPyNumeric ndarray straight in - no manual conversion.
to_file(array=a, path="out.h5", dataset_name="/data")
get_legate_runtime().issue_execution_fence(block=True)   # needed before any external reader

# Read: from_file returns a legate LogicalArray; cn.asarray bridges it back.
b = cn.asarray(from_file("out.h5", dataset_name="/data"))
assert cn.array_equal(a, b)

运行 assets/hdf5_roundtrip.py 进行验证(可选——回答问题不需要运行)。

分块读取大型文件

使用 from_file_batched 分块读取源文件,避免一次性将整个文件读入主机内存。它会针对每个数据块返回一个 LogicalArray,以及该数据块在全局形状中的偏移量。边界数据块可能会被截短(长度为 5 的轴在 chunk_size=2 时会产生 2、2、1 三个数据块),因此应根据数据块的实际形状放置,而不是使用请求的 chunk_size。注意,这里分块的是文件读取,而非结果——组装后的数组(out)仍必须能放入分布式内存:

import h5py
import cupynumeric as cn
from legate.core import get_legate_runtime
from legate.io.hdf5 import from_file_batched

with h5py.File("big.h5", "r") as f:          # read shape/dtype without loading data
    shape, dtype = f["data"].shape, f["data"].dtype

out = cn.empty(shape, dtype=dtype)
for chunk, (r0, c0) in from_file_batched("big.h5", "data", chunk_size=(4096, 4096)):
    out[r0:r0 + chunk.shape[0], c0:c0 + chunk.shape[1]] = cn.asarray(chunk)
get_legate_runtime().issue_execution_fence(block=True)

确保每个 chunk_size 值都为正数,且其长度与数据集的秩相同,否则 from_file_batched 会引发 ValueError。运行 assets/hdf5_batched_read.py 进行验证(可选)。

使用说明

  • 直接将 cuPyNumeric ndarray 传给 to_file——它实现了 __legate_data_interface__,可作为 LogicalArrayLike 传给 to_file。请跳过任何 np.array(...) 往返转换。
  • 使用 cn.asarray(...) 将结果转换回来。 from_file 和每个 from_file_batched 分块都会返回 Legate LogicalArray;将其包装为 cn.asarray(la),即可得到 cuPyNumeric ndarray(零拷贝,不经过主机)。
  • 在任何外部读取器打开文件前设置栅栏。 Legate I/O 是异步的:to_file 只会将写入操作加入队列。在 h5py、子进程或其他工具打开文件前,插入 get_legate_runtime().issue_execution_fence(block=True)。对于同一 Legate 程序中稍后发出的 from_file,无需设置栅栏——运行时会保留操作顺序。
  • 从 cuPyNumeric 源代码树之外运行(例如,执行 cd /tmp)。Python 会将当前工作目录放在 sys.path 的首位,因此树内的 cupynumeric/ 目录会遮蔽已安装的包(ModuleNotFoundError: cupynumeric.install_info)。
  • 为所有 rank 指定相同的 path。 程序会在每个 rank 上运行(SPMD),因此传给 to_file/from_file 的 path 必须在每个 rank 上完全相同——每个 rank 使用各自的 tempfile.mkstemp() 文件名会破坏集体 I/O。如果程序自行创建文件,请使用集体 to_file 写入,而不要使用每个 rank 各自的 h5py 写入。

to_file 的行为注意事项

  • 预期会生成 HDF5 虚拟数据集(VDS):每个 rank 写入自己的数据块,文件会将它们呈现为一个逻辑数据集。
  • 将 to_file 视为破坏性操作——如果 path 已存在,它会覆盖该文件,因此请保护好任何不得覆盖的文件。
  • 让 to_file 创建缺失的父目录;不要预先创建这些目录。
  • 为 path 指定文件名(/path/to/file.h5),不能指定目录——否则会引发 ValueError。传入有界数组(即形状已知的数组);对于无界数组,to_file 会引发 ValueError。无界数组是指创建时未指定形状、由生产任务稍后填入范围的 Legate 数组(例如 create_array(dtype, ndim=n))。cuPyNumeric ndarray 始终是有界的——即使是惰性/延迟数组也如此,因此这只影响原始 LogicalArray。

GPUDirect Storage(GDS)

读取 HDF5 并将数据载入 GPU 内存的运行,始终设置 LEGATE_IO_USE_VFD_GDS=1——无论集群是否具有支持 GPUDirect 的存储:

export LEGATE_IO_USE_VFD_GDS=1          # set before launching
# or, with the legate driver:
legate --io-use-vfd-gds my_script.py
  • 通过 GDS VFD 将数据读入 GPU,而不要使用默认路径。 默认的(POSIX)VFD 会通过零拷贝内存(ZCMEM)暂存每次 GPU 读取,而 Legate 仅预留 128 MB——因此,读取大于约 128 MB 的数组时会中止。GDS VFD 会移除该暂存缓冲区。
  • 读入主机(CPU)内存时不要设置该变量——此时不需要 GDS VFD 插件,设置它只会增加开销。
  • 即使没有支持 GPUDirect 的存储,也要保留 =1——cuFile 会自动回退到兼容模式(如果尚未启用,请设置 export CUFILE_ALLOW_COMPAT_MODE=true),而 =1 仍可避免 ZCMEM 中止。
  • **正确说明其归属:**GDS VFD 是基于 NVIDIA cuFile 的 nv-legate/vfd-gds 插件,不是 KvikIO(KvikIO 支持 Legate 的 Zarr/分块 I/O,而非 HDF5)。可在运行日志中搜索 H5FD__gds_open: Successfully opened file w/GDS VFD,确认其已启用。

故障排除

症状原因和修复方法
导入时出现 ModuleNotFoundError: No module named 'h5py'缺少 h5py — 执行 conda install -c conda-forge h5py。
to_file 后,文件对 h5py 来说看起来是空的或被截断异步写入尚未完成 — 在外部读取之前添加 get_legate_runtime().issue_execution_fence(block=True)。
to_file 返回 ValueErrorpath 是一个目录 — 传入文件路径,例如 results/data.h5。
出现 ModuleNotFoundError: No module named 'cupynumeric.install_info'在源代码树中运行 — cd /tmp(切换到仓库以外的任意目录)。
读取 ≳128 MB 的 GPU 数组时中止或崩溃默认的 128 MB ZCMEM 暂存缓冲区 — 对 GPU 读取设置 LEGATE_IO_USE_VFD_GDS=1。
from_file 返回了 LogicalArray(...)这是预期行为 — 用 cn.asarray(...) 包装它。

限制和版本说明

  • 从 legate.io.hdf5 导入(Legate 26.01+);将 25.03 系列遗留的任何 legate.core.io.hdf5 导入路径改写为新路径(例如,25.03 发布博文仍显示旧路径)。
  • 显式安装 h5py — cuPyNumeric 的默认环境中不包含它。
  • 将 dataset_name 指向单个数组,绝不能指向组;先用 h5py 遍历组,以查找数据集路径。
  • 在 GPU 上,始终使用 LEGATE_IO_USE_VFD_GDS=1 读取(参见 GPUDirect Storage(GDS))— 默认路径在 GPU 数组大于 128 MB ZCMEM 缓冲区时会中止。CPU 读取时不要设置该变量。

验证

cd /tmp                                  # outside the cupynumeric source tree
conda install -c conda-forge h5py        # one-time, if not already present
LEGATE_CONFIG="--cpus 4" LEGATE_AUTO_CONFIG=0 python <skill>/assets/hdf5_roundtrip.py
LEGATE_CONFIG="--cpus 4" LEGATE_AUTO_CONFIG=0 python <skill>/assets/hdf5_batched_read.py

预期会显示 HDF5 ROUND TRIP OK 和 HDF5 BATCHED READ OK。添加 --gpus 1(以及 LEGATE_IO_USE_VFD_GDS=1)以测试 GPU / GDS 路径。

评论

支持 Markdown