HDF5는 대용량 과학 데이터 및 복잡한 데이터 구조를 효율적으로 저장하고 관리할 수 있는 포맷입니다. 기존의 CSV, JSON, XML 등의 포맷과 비교하여 HDF5는 대량의 이진 데이터를 고성능으로 읽고 쓸 수 있으며, 데이터 압축과 병렬 I/O 기능을 지원합니다.
과학, 공학, AI, 기상학, 생물학 등 다양한 분야에서 HDF5는 데이터 저장 및 공유 표준으로 활용됩니다. 특히, 실험 데이터, 시뮬레이션 결과, 이미지 및 시간 기반 데이터 등을 효과적으로 저장할 수 있어, 고성능 컴퓨팅(HPC) 환경에서 필수적인 데이터 포맷입니다.
본 기사에서는 C 프로그래밍에서 HDF5 라이브러리를 사용하여 데이터를 저장하고 불러오는 방법을 설명합니다. HDF5의 기본 개념부터 실제 사용법까지 단계별로 살펴보며, 대용량 데이터 관리의 효율성을 높이는 다양한 기법도 소개합니다.
HDF5란 무엇인가?
HDF5(Hierarchical Data Format version 5)는 대용량 과학 데이터를 저장하고 관리하기 위한 고성능 파일 포맷입니다. HDF5는 다양한 데이터 타입을 효율적으로 저장하고 검색할 수 있도록 설계되었으며, 특히 구조화된 데이터를 계층적으로 관리하는 데 적합합니다.
HDF5의 주요 특징
- 계층적 구조: 데이터셋을 그룹으로 조직화할 수 있어 복잡한 데이터를 논리적으로 정리할 수 있습니다.
- 고성능 I/O: 이진 데이터 포맷을 사용하여 빠른 읽기/쓰기 속도를 제공합니다.
- 데이터 압축 지원: 내부적으로 Gzip, Szip 등의 압축 방식을 지원하여 저장 공간을 절약할 수 있습니다.
- 병렬 I/O 지원: MPI 기반 병렬 I/O를 통해 대규모 데이터 처리 성능을 향상시킬 수 있습니다.
- 다양한 프로그래밍 언어 지원: C, C++, Fortran, Python 등 다양한 언어에서 사용할 수 있습니다.
HDF5와 기존 파일 포맷 비교
특징 | CSV | JSON/XML | HDF5 |
---|---|---|---|
데이터 저장 방식 | 텍스트 | 텍스트 | 이진 |
대용량 데이터 처리 | 낮음 | 중간 | 높음 |
구조화 데이터 지원 | 없음 | 있음 | 있음 |
데이터 압축 | 없음 | 없음 | 지원 |
병렬 I/O | 불가능 | 불가능 | 가능 |
HDF5는 단순한 데이터 포맷이 아니라 강력한 데이터 관리 시스템으로서, 특히 대용량 데이터를 다루는 과학 및 공학 분야에서 널리 사용됩니다. 이를 활용하면 복잡한 데이터 구조를 체계적으로 관리하고, 저장 공간을 효율적으로 사용할 수 있으며, 고속 데이터 처리까지 가능하게 됩니다.
HDF5 파일 구조와 주요 개념
HDF5 파일은 단순한 이진 파일이 아니라, 데이터를 계층적으로 저장할 수 있는 데이터 컨테이너입니다. 내부적으로 데이터셋, 그룹, 속성 등의 개념을 사용하여 데이터를 조직적으로 관리할 수 있도록 설계되었습니다.
HDF5 파일의 주요 개념
1. 그룹(Group)
그룹은 파일 시스템의 디렉터리와 유사한 개념으로, 여러 데이터셋과 하위 그룹을 포함할 수 있습니다.
hid_t group_id = H5Gcreate(file_id, "/experiment1", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
위 코드는 /experiment1
이라는 그룹을 생성하는 예제입니다.
2. 데이터셋(Dataset)
데이터셋은 HDF5에서 실제 데이터를 저장하는 단위입니다. 배열과 같은 형태로 저장되며, 데이터 타입과 차원을 정의할 수 있습니다.
hid_t dataspace_id = H5Screate_simple(2, dims, NULL);
hid_t dataset_id = H5Dcreate(file_id, "/experiment1/data", H5T_NATIVE_INT, dataspace_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
위 코드는 /experiment1/data
라는 2차원 데이터셋을 생성하는 예제입니다.
3. 속성(Attribute)
속성은 그룹이나 데이터셋에 부가 정보를 저장하는 작은 데이터 단위입니다.
hid_t attr_id = H5Acreate(dataset_id, "units", H5T_NATIVE_CHAR, dataspace_id, H5P_DEFAULT, H5P_DEFAULT);
위 코드는 units
라는 속성을 생성하는 예제입니다.
HDF5 파일 구조 예제
아래는 HDF5 파일의 내부 구조 예제입니다.
/ (Root Group)
├── experiment1 (Group)
│ ├── data (Dataset)
│ ├── metadata (Dataset)
│ └── attributes (Attribute)
└── experiment2 (Group)
├── results (Dataset)
├── parameters (Dataset)
HDF5의 그룹, 데이터셋, 속성을 활용하면 다양한 형태의 데이터를 체계적으로 저장하고 관리할 수 있습니다. 이를 통해 대용량 데이터의 접근성과 처리 속도를 크게 향상시킬 수 있습니다.
HDF5 라이브러리 설치 및 설정
C 언어에서 HDF5 라이브러리를 사용하려면 먼저 HDF5 라이브러리를 설치하고, 프로젝트에서 적절히 설정해야 합니다. HDF5는 Windows, Linux, macOS에서 모두 사용할 수 있으며, C 및 C++ 개발 환경에서 활용할 수 있습니다.
HDF5 라이브러리 설치
1. Linux 및 macOS에서 설치
대부분의 Linux 배포판에서는 패키지 매니저를 사용하여 간단히 HDF5를 설치할 수 있습니다.
Ubuntu 및 Debian 계열:
sudo apt update
sudo apt install libhdf5-dev
CentOS 및 RHEL 계열:
sudo yum install hdf5-devel
macOS (Homebrew 사용):
brew install hdf5
2. Windows에서 설치
Windows에서는 HDF5 공식 웹사이트에서 바이너리를 다운로드하거나, vcpkg
또는 MSYS2
를 통해 설치할 수 있습니다.
MSYS2에서 설치:
pacman -S mingw-w64-x86_64-hdf5
Vcpkg에서 설치:
vcpkg install hdf5
HDF5 설치 파일 다운로드:
HDF5 라이브러리 설정
HDF5를 C 프로그램에서 사용하려면 컴파일러가 HDF5 헤더 파일과 라이브러리를 찾을 수 있도록 설정해야 합니다.
1. 컴파일 및 링크 옵션
HDF5를 사용하는 C 프로그램을 컴파일할 때는 h5cc
(HDF5 전용 컴파일러)를 사용하는 것이 가장 간편한 방법입니다.
h5cc -o my_program my_program.c
만약 gcc
또는 clang
을 사용할 경우, h5cc -show
명령어를 실행하면 필요한 컴파일 옵션을 확인할 수 있습니다.
예제:
gcc -o my_program my_program.c -I/usr/include/hdf5/serial -L/usr/lib/x86_64-linux-gnu/hdf5/serial -lhdf5
2. CMake를 이용한 HDF5 설정
CMake를 사용하여 HDF5를 포함하려면 다음과 같이 find_package(HDF5)
를 활용할 수 있습니다.
CMakeLists.txt 예제:
find_package(HDF5 REQUIRED)
add_executable(my_program my_program.c)
target_include_directories(my_program PRIVATE ${HDF5_INCLUDE_DIRS})
target_link_libraries(my_program PRIVATE ${HDF5_LIBRARIES})
설치 확인
HDF5가 올바르게 설치되었는지 확인하려면 다음 명령어를 실행합니다.
h5cc -showconfig
또한, 간단한 프로그램을 작성하여 H5open()
과 H5Fcreate()
함수를 호출해보는 것도 좋은 방법입니다.
이제 HDF5 라이브러리가 준비되었으므로, C에서 HDF5 파일을 생성하고 데이터를 저장하는 방법을 알아보겠습니다.
C에서 HDF5 파일 생성 및 데이터 저장
C 언어에서 HDF5 파일을 생성하고 데이터를 저장하려면 HDF5 라이브러리에서 제공하는 API를 사용해야 합니다. 기본적으로 파일을 생성한 후, 데이터셋을 정의하고 데이터를 저장하는 과정이 필요합니다.
HDF5 파일 생성
HDF5 파일을 생성하려면 H5Fcreate()
함수를 사용합니다.
#include "hdf5.h"
int main() {
hid_t file_id; // HDF5 파일 식별자
// HDF5 파일 생성 (기존 파일이 있을 경우 덮어쓰기)
file_id = H5Fcreate("example.h5", H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT);
// 파일 닫기
H5Fclose(file_id);
return 0;
}
위 코드는 example.h5
파일을 생성하고, 파일을 닫는 기본적인 코드입니다.
데이터셋 생성 및 데이터 저장
데이터를 저장하려면 먼저 데이터셋을 생성하고 데이터를 입력해야 합니다.
1. 1차원 배열 저장
다음 코드는 1차원 정수 배열을 HDF5 파일에 저장하는 방법을 보여줍니다.
#include "hdf5.h"
#define DATASET_NAME "int_array"
#define SIZE 5
int main() {
hid_t file_id, dataset_id, dataspace_id;
hsize_t dims[1] = {SIZE}; // 데이터셋 차원 (1차원 배열)
int data[SIZE] = {10, 20, 30, 40, 50};
// HDF5 파일 생성
file_id = H5Fcreate("data.h5", H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT);
// 데이터 공간 생성
dataspace_id = H5Screate_simple(1, dims, NULL);
// 데이터셋 생성
dataset_id = H5Dcreate(file_id, DATASET_NAME, H5T_NATIVE_INT, dataspace_id,
H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
// 데이터 쓰기
H5Dwrite(dataset_id, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, data);
// 자원 해제
H5Dclose(dataset_id);
H5Sclose(dataspace_id);
H5Fclose(file_id);
return 0;
}
위 코드에서는 H5Dcreate()
를 사용하여 /int_array
라는 데이터셋을 생성하고, H5Dwrite()
로 데이터를 저장합니다.
2. 2차원 배열 저장
HDF5는 다차원 데이터를 저장할 수도 있습니다.
#define ROWS 3
#define COLS 3
int main() {
hid_t file_id, dataset_id, dataspace_id;
hsize_t dims[2] = {ROWS, COLS}; // 2차원 데이터 차원
int data[ROWS][COLS] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
file_id = H5Fcreate("matrix.h5", H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT);
dataspace_id = H5Screate_simple(2, dims, NULL);
dataset_id = H5Dcreate(file_id, "/matrix", H5T_NATIVE_INT, dataspace_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
H5Dwrite(dataset_id, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, data);
H5Dclose(dataset_id);
H5Sclose(dataspace_id);
H5Fclose(file_id);
return 0;
}
위 코드는 matrix.h5
파일에 3×3 행렬을 저장하는 예제입니다.
HDF5 파일 구조 확인
HDF5 파일이 올바르게 생성되었는지 확인하려면 h5ls
명령어를 사용할 수 있습니다.
h5ls data.h5
출력 예시:
int_array Dataset {5}
matrix Dataset {3, 3}
이를 통해 파일 내 데이터셋이 올바르게 저장되었는지 확인할 수 있습니다.
다음 단계에서는 저장된 데이터를 다시 불러오는 방법을 살펴보겠습니다.
HDF5에서 데이터 불러오기
HDF5에 저장된 데이터를 C 프로그램에서 읽어오는 방법을 알아봅니다. 기본적으로 HDF5 파일을 열고, 데이터셋을 접근한 후 데이터를 읽어와야 합니다.
1. HDF5 파일 열기
기존 HDF5 파일을 열려면 H5Fopen()
함수를 사용합니다.
#include "hdf5.h"
int main() {
hid_t file_id;
// HDF5 파일 열기 (읽기 전용)
file_id = H5Fopen("data.h5", H5F_ACC_RDONLY, H5P_DEFAULT);
// 파일 닫기
H5Fclose(file_id);
return 0;
}
이 코드는 data.h5
파일을 읽기 전용 모드로 열고 닫는 간단한 예제입니다.
2. 1차원 배열 데이터 읽기
저장된 1차원 배열 데이터를 읽어오는 방법을 살펴보겠습니다.
#include "hdf5.h"
#include <stdio.h>
#define DATASET_NAME "int_array"
#define SIZE 5
int main() {
hid_t file_id, dataset_id;
int data[SIZE]; // 데이터를 저장할 배열
// HDF5 파일 열기
file_id = H5Fopen("data.h5", H5F_ACC_RDONLY, H5P_DEFAULT);
// 데이터셋 열기
dataset_id = H5Dopen(file_id, DATASET_NAME, H5P_DEFAULT);
// 데이터 읽기
H5Dread(dataset_id, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, data);
// 읽은 데이터 출력
for (int i = 0; i < SIZE; i++) {
printf("%d ", data[i]);
}
printf("\n");
// 자원 해제
H5Dclose(dataset_id);
H5Fclose(file_id);
return 0;
}
위 코드는 data.h5
파일에서 /int_array
데이터셋을 불러와 정수 배열을 읽고 출력합니다.
3. 2차원 배열 데이터 읽기
이제 2차원 배열을 읽어보겠습니다.
#define ROWS 3
#define COLS 3
int main() {
hid_t file_id, dataset_id;
int data[ROWS][COLS];
// HDF5 파일 열기
file_id = H5Fopen("matrix.h5", H5F_ACC_RDONLY, H5P_DEFAULT);
// 데이터셋 열기
dataset_id = H5Dopen(file_id, "/matrix", H5P_DEFAULT);
// 데이터 읽기
H5Dread(dataset_id, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, data);
// 읽은 데이터 출력
for (int i = 0; i < ROWS; i++) {
for (int j = 0; j < COLS; j++) {
printf("%d ", data[i][j]);
}
printf("\n");
}
// 자원 해제
H5Dclose(dataset_id);
H5Fclose(file_id);
return 0;
}
위 코드는 matrix.h5
파일에서 /matrix
데이터셋을 불러와 3×3 행렬 데이터를 출력합니다.
4. 특정 부분 데이터 읽기 (부분 읽기)
HDF5는 전체 데이터셋을 읽는 것이 아니라 특정 부분만 읽는 것도 가능합니다.
hsize_t offset[2] = {1, 1}; // 시작 위치 (1행 1열)
hsize_t count[2] = {2, 2}; // 읽을 크기 (2×2)
hid_t memspace_id = H5Screate_simple(2, count, NULL);
hid_t dataspace_id = H5Dget_space(dataset_id);
H5Sselect_hyperslab(dataspace_id, H5S_SELECT_SET, offset, NULL, count, NULL);
H5Dread(dataset_id, H5T_NATIVE_INT, memspace_id, dataspace_id, H5P_DEFAULT, data);
이 방법을 사용하면 큰 데이터셋 중 필요한 부분만 빠르게 불러올 수 있습니다.
5. 데이터 읽기 확인
HDF5 파일에 저장된 데이터가 올바르게 읽혀졌는지 확인하려면 h5dump
명령어를 사용할 수 있습니다.
h5dump data.h5
출력 예시:
HDF5 "data.h5" {
GROUP "/" {
DATASET "int_array" {
DATATYPE H5T_STD_I32LE
DATASPACE SIMPLE { (5) / (5) }
DATA {
(0): 10, 20, 30, 40, 50
}
}
}
}
이제 C에서 HDF5 파일에 저장된 데이터를 불러오는 방법을 이해했으며, 다음 단계에서는 병렬 I/O를 활용하는 방법을 살펴보겠습니다.
HDF5와 병렬 I/O 활용하기
대용량 데이터를 처리할 때 단일 프로세스의 입출력(I/O) 속도는 병목이 될 수 있습니다. 이를 해결하기 위해 HDF5는 MPI(Message Passing Interface) 를 활용한 병렬 I/O 를 지원합니다. 이를 통해 여러 프로세스가 동시에 같은 HDF5 파일을 읽고 쓸 수 있어 성능을 크게 향상시킬 수 있습니다.
1. 병렬 HDF5 개념
병렬 HDF5는 MPI와 연계하여 동작하며, 다음과 같은 주요 특징을 가집니다.
- 병렬 파일 접근(PHDF5): 여러 프로세스가 동시에 같은 HDF5 파일에 접근 가능
- 집합 I/O(Collective I/O)와 개별 I/O(Independent I/O) 지원
- MPI-IO를 기반으로 한 고성능 입출력 지원
- HDF5의 투명한 데이터 구조 유지
MPI와 HDF5의 병렬 기능을 활용하려면, HDF5 라이브러리를 병렬 지원 옵션으로 빌드해야 합니다.
2. 병렬 HDF5 라이브러리 설치
Linux/macOS:
sudo apt install libhdf5-mpi-dev
혹은 HDF5를 소스에서 빌드할 때 다음 옵션을 사용합니다.
CC=mpicc ./configure --enable-parallel
make
sudo make install
Windows(MSYS2 사용)
pacman -S mingw-w64-x86_64-hdf5
3. 병렬 HDF5 파일 생성 및 쓰기
다음은 MPI를 사용하여 여러 프로세스가 동시에 HDF5 파일에 데이터를 저장하는 예제입니다.
#include "hdf5.h"
#include "mpi.h"
#include <stdio.h>
#define FILE_NAME "parallel.h5"
#define DATASET_NAME "parallel_data"
#define ROWS 4
#define COLS 4
int main(int argc, char **argv) {
MPI_Init(&argc, &argv); // MPI 초기화
int rank, size;
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &size);
hid_t plist_id = H5Pcreate(H5P_FILE_ACCESS);
H5Pset_fapl_mpio(plist_id, MPI_COMM_WORLD, MPI_INFO_NULL);
// HDF5 파일 생성
hid_t file_id = H5Fcreate(FILE_NAME, H5F_ACC_TRUNC, H5P_DEFAULT, plist_id);
H5Pclose(plist_id);
// 데이터 저장을 위한 2D 공간 생성
hsize_t dims[2] = {ROWS, COLS};
hid_t dataspace_id = H5Screate_simple(2, dims, NULL);
// 데이터셋 생성
hid_t dataset_id = H5Dcreate(file_id, DATASET_NAME, H5T_NATIVE_INT, dataspace_id,
H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
// 각 프로세스가 쓸 데이터 생성
int data[ROWS][COLS];
for (int i = 0; i < ROWS; i++) {
for (int j = 0; j < COLS; j++) {
data[i][j] = rank * 10 + (i * COLS + j);
}
}
// 병렬 I/O를 위한 전송 속성 설정
plist_id = H5Pcreate(H5P_DATASET_XFER);
H5Pset_dxpl_mpio(plist_id, H5FD_MPIO_COLLECTIVE);
// 데이터 쓰기
H5Dwrite(dataset_id, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, plist_id, data);
// 자원 해제
H5Pclose(plist_id);
H5Dclose(dataset_id);
H5Sclose(dataspace_id);
H5Fclose(file_id);
MPI_Finalize(); // MPI 종료
return 0;
}
실행 방법:
mpicc -o parallel_hdf5 parallel_hdf5.c -lhdf5 -lhdf5_mpi
mpirun -np 4 ./parallel_hdf5
위 코드를 실행하면 4개의 MPI 프로세스가 각기 다른 데이터를 생성하고, 동일한 HDF5 파일 내 같은 데이터셋에 병렬로 저장하게 됩니다.
4. 병렬 HDF5 데이터 읽기
저장된 데이터를 병렬로 읽어올 수도 있습니다.
#include "hdf5.h"
#include "mpi.h"
#include <stdio.h>
#define FILE_NAME "parallel.h5"
#define DATASET_NAME "parallel_data"
#define ROWS 4
#define COLS 4
int main(int argc, char **argv) {
MPI_Init(&argc, &argv);
int rank;
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
// HDF5 병렬 접근 설정
hid_t plist_id = H5Pcreate(H5P_FILE_ACCESS);
H5Pset_fapl_mpio(plist_id, MPI_COMM_WORLD, MPI_INFO_NULL);
// 파일 열기
hid_t file_id = H5Fopen(FILE_NAME, H5F_ACC_RDONLY, plist_id);
H5Pclose(plist_id);
// 데이터셋 열기
hid_t dataset_id = H5Dopen(file_id, DATASET_NAME, H5P_DEFAULT);
// 데이터 읽기
int data[ROWS][COLS];
H5Dread(dataset_id, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, data);
// 데이터 출력
printf("Process %d reads:\n", rank);
for (int i = 0; i < ROWS; i++) {
for (int j = 0; j < COLS; j++) {
printf("%d ", data[i][j]);
}
printf("\n");
}
// 자원 해제
H5Dclose(dataset_id);
H5Fclose(file_id);
MPI_Finalize();
return 0;
}
실행 방법:
mpirun -np 4 ./parallel_hdf5
각 프로세스는 동일한 parallel.h5
파일에서 데이터를 병렬로 읽어오게 됩니다.
5. 병렬 HDF5 성능 최적화
병렬 HDF5의 성능을 극대화하려면 다음 전략을 고려해야 합니다.
- 집합 I/O (Collective I/O) 를 활용하여 동기화된 데이터 전송 수행
- 대용량 데이터 블록 읽기 를 통해 I/O 횟수를 줄이기
- 파일 시스템 및 MPI-IO 튜닝 을 통해 성능 향상
HDF5의 병렬 I/O 기능을 활용하면 대용량 데이터의 입출력 속도를 향상시킬 수 있으며, 특히 슈퍼컴퓨터 환경에서 효과적입니다. 다음 섹션에서는 HDF5의 데이터 압축 및 최적화 기법을 알아보겠습니다.
HDF5 데이터 압축 및 최적화
HDF5는 대용량 데이터를 효율적으로 저장하기 위해 다양한 압축 및 최적화 기법을 제공합니다. 이를 활용하면 파일 크기를 줄이고 I/O 성능을 향상시킬 수 있습니다.
1. HDF5 데이터 압축 개요
HDF5에서는 기본적으로 이진(Binary) 형식을 사용하여 데이터를 저장하므로, 일반적인 CSV, JSON 파일보다 저장 공간을 덜 차지합니다. 그러나 추가적으로 데이터 압축 기능을 활용하면 더욱 효율적인 저장이 가능합니다.
HDF5는 다음과 같은 압축 방식을 지원합니다.
- Gzip(ZLIB) 압축: 기본적인 무손실 압축, 높은 압축률 제공
- Szip(Shuffling Zip) 압축: NASA에서 개발한 압축 알고리즘, 과학 데이터에 최적화
- Shuffle 필터: 바이트 순서를 재조정하여 압축률 향상
- Fletcher32 체크섬: 데이터 무결성 검증
2. Gzip 압축 적용하기
HDF5에서 Gzip 압축을 적용하려면 속성(Property List) 을 설정해야 합니다.
#include "hdf5.h"
#include <stdio.h>
#define FILE_NAME "compressed.h5"
#define DATASET_NAME "gzip_data"
#define SIZE 100
int main() {
hid_t file_id, dataset_id, dataspace_id, plist_id;
hsize_t dims[1] = {SIZE};
int data[SIZE];
// 데이터 초기화
for (int i = 0; i < SIZE; i++) {
data[i] = i * 2;
}
// HDF5 파일 생성
file_id = H5Fcreate(FILE_NAME, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT);
// 데이터 공간 생성
dataspace_id = H5Screate_simple(1, dims, NULL);
// 압축을 위한 속성(Property List) 생성
plist_id = H5Pcreate(H5P_DATASET_CREATE);
H5Pset_deflate(plist_id, 9); // Gzip 압축 레벨 (0~9)
// 압축된 데이터셋 생성
dataset_id = H5Dcreate(file_id, DATASET_NAME, H5T_NATIVE_INT, dataspace_id,
H5P_DEFAULT, plist_id, H5P_DEFAULT);
// 데이터 쓰기
H5Dwrite(dataset_id, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, data);
// 자원 해제
H5Pclose(plist_id);
H5Dclose(dataset_id);
H5Sclose(dataspace_id);
H5Fclose(file_id);
printf("Gzip 압축 적용 완료.\n");
return 0;
}
이 코드는 Gzip 압축을 적용하여 compressed.h5
파일을 생성합니다.
압축률 확인:
h5ls -vl compressed.h5
출력 예시:
/gzip_data Dataset {100} {COMPRESSION: GZIP(9)}
3. Szip 압축 적용
Szip 압축은 과학 데이터에 특화된 압축 방식으로, NASA에서 개발되었습니다.
H5Pset_szip(plist_id, H5_SZIP_NN_OPTION_MASK, 8);
이렇게 하면 Szip 압축이 적용됩니다.
4. Shuffle 필터 적용
Shuffle 필터는 데이터를 압축하기 전에 바이트 순서를 재배열하여 압축률을 향상시키는 기술입니다.
H5Pset_shuffle(plist_id);
H5Pset_deflate(plist_id, 9); // Gzip 압축과 함께 사용 가능
이렇게 설정하면 Shuffle과 Gzip 압축이 함께 적용됩니다.
5. Chunking을 활용한 최적화
HDF5에서 데이터를 읽고 쓸 때 Chunking(청크 단위 저장) 을 적용하면 성능이 향상됩니다. 특히 압축과 함께 사용하면 효율적입니다.
hsize_t chunk_dims[1] = {10}; // 청크 크기 지정
H5Pset_chunk(plist_id, 1, chunk_dims);
6. 데이터 압축 비교
압축 방식 | 압축률 | 속도 | 특징 |
---|---|---|---|
Gzip | 높음 | 보통 | 범용적인 압축 방식 |
Szip | 중간 | 빠름 | 과학 데이터에 최적화 |
Shuffle+Gzip | 최고 | 보통 | Shuffle이 압축률을 향상 |
7. 압축된 데이터 읽기
압축된 데이터를 읽을 때는 일반적인 HDF5 데이터셋 읽기와 동일합니다.
H5Dread(dataset_id, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, data);
HDF5 라이브러리는 압축 해제를 자동으로 수행하므로, 별도의 코드 변경 없이 압축된 데이터를 불러올 수 있습니다.
8. 압축 및 최적화된 HDF5 파일 확인
파일 크기를 비교하여 압축이 적용되었는지 확인할 수 있습니다.
ls -lh compressed.h5
h5ls -vl compressed.h5
이제 HDF5에서 데이터를 압축 및 최적화 하는 방법을 이해했으며, 다음 섹션에서는 HDF5를 활용한 과학 데이터 응용 사례를 살펴보겠습니다.
HDF5를 활용한 과학 데이터 응용 사례
HDF5는 과학, 공학, AI, 기상학, 천문학 등 다양한 분야에서 대용량 데이터 관리를 위한 표준 포맷으로 사용됩니다. 특히, 고속 데이터 입출력(I/O) 및 병렬 처리를 지원하여 실험 데이터, 시뮬레이션 결과, 머신러닝 모델 저장 등에 최적화되어 있습니다.
1. 기후 및 기상 데이터 저장
기후 및 기상 데이터는 일반적으로 고해상도 격자 데이터(grid data) 로 표현됩니다. HDF5는 이러한 대규모 데이터를 저장하고 분석하는 데 최적화되어 있습니다.
예제: 기온 데이터를 HDF5 파일에 저장
#include "hdf5.h"
#include <stdio.h>
#define FILE_NAME "climate.h5"
#define DATASET_NAME "temperature"
#define ROWS 1000
#define COLS 1000
int main() {
hid_t file_id, dataset_id, dataspace_id;
hsize_t dims[2] = {ROWS, COLS};
float data[ROWS][COLS];
// 임의의 기온 데이터 생성
for (int i = 0; i < ROWS; i++) {
for (int j = 0; j < COLS; j++) {
data[i][j] = 15.0 + (i * 0.01) + (j * 0.01);
}
}
// HDF5 파일 생성
file_id = H5Fcreate(FILE_NAME, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT);
// 데이터 공간 생성
dataspace_id = H5Screate_simple(2, dims, NULL);
// 데이터셋 생성 및 데이터 저장
dataset_id = H5Dcreate(file_id, DATASET_NAME, H5T_NATIVE_FLOAT, dataspace_id,
H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
H5Dwrite(dataset_id, H5T_NATIVE_FLOAT, H5S_ALL, H5S_ALL, H5P_DEFAULT, data);
// 자원 해제
H5Dclose(dataset_id);
H5Sclose(dataspace_id);
H5Fclose(file_id);
printf("기후 데이터 저장 완료: %s\n", FILE_NAME);
return 0;
}
이 코드는 1000×1000 해상도의 기온 데이터를 저장하는 예제입니다.
2. 머신러닝 모델 및 딥러닝 데이터 저장
HDF5는 텐서(Tensor) 데이터 를 저장하는 데 매우 적합하며, Keras 및 TensorFlow에서도 모델과 데이터를 저장할 때 HDF5를 사용합니다.
예제: 신경망 가중치(weight) 저장
#define WEIGHTS_SIZE 1024
hid_t file_id, dataset_id, dataspace_id;
hsize_t dims[1] = {WEIGHTS_SIZE};
float weights[WEIGHTS_SIZE];
// 가중치 초기화
for (int i = 0; i < WEIGHTS_SIZE; i++) {
weights[i] = (float)i / WEIGHTS_SIZE;
}
// HDF5 파일 생성 및 가중치 저장
file_id = H5Fcreate("ml_model.h5", H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT);
dataspace_id = H5Screate_simple(1, dims, NULL);
dataset_id = H5Dcreate(file_id, "weights", H5T_NATIVE_FLOAT, dataspace_id,
H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
H5Dwrite(dataset_id, H5T_NATIVE_FLOAT, H5S_ALL, H5S_ALL, H5P_DEFAULT, weights);
// 자원 해제
H5Dclose(dataset_id);
H5Sclose(dataspace_id);
H5Fclose(file_id);
이 코드는 신경망 가중치(weights) 를 저장하는 예제입니다.
3. 천문학 및 우주 연구
천문학 데이터는 수십 기가바이트에서 수 테라바이트 크기의 데이터가 포함될 수 있습니다. HDF5는 천체 망원경 데이터 를 저장하는 데 널리 사용됩니다.
예제: 별(Star) 좌표 데이터 저장
#define NUM_STARS 1000000
hid_t file_id, dataset_id, dataspace_id;
hsize_t dims[2] = {NUM_STARS, 3}; // (x, y, z) 좌표
float star_positions[NUM_STARS][3];
// 데이터 초기화
for (int i = 0; i < NUM_STARS; i++) {
star_positions[i][0] = i * 0.001f; // x 좌표
star_positions[i][1] = i * 0.002f; // y 좌표
star_positions[i][2] = i * 0.003f; // z 좌표
}
// HDF5 파일 생성
file_id = H5Fcreate("stars.h5", H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT);
dataspace_id = H5Screate_simple(2, dims, NULL);
dataset_id = H5Dcreate(file_id, "positions", H5T_NATIVE_FLOAT, dataspace_id,
H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
H5Dwrite(dataset_id, H5T_NATIVE_FLOAT, H5S_ALL, H5S_ALL, H5P_DEFAULT, star_positions);
// 자원 해제
H5Dclose(dataset_id);
H5Sclose(dataspace_id);
H5Fclose(file_id);
이 코드는 별 100만 개의 3D 좌표를 HDF5 파일에 저장하는 예제입니다.
4. 유전체학 및 생물정보학
유전체 데이터는 수억 개의 DNA 시퀀스 를 포함하기 때문에 HDF5의 압축 기능과 빠른 I/O 성능 이 매우 중요합니다.
예제: 유전자 염기서열 저장
#define SEQUENCE_LENGTH 1000000
hid_t file_id, dataset_id, dataspace_id;
hsize_t dims[1] = {SEQUENCE_LENGTH};
char dna_sequence[SEQUENCE_LENGTH];
// A, T, G, C 무작위 염기서열 생성
for (int i = 0; i < SEQUENCE_LENGTH; i++) {
char bases[] = {'A', 'T', 'G', 'C'};
dna_sequence[i] = bases[i % 4];
}
// HDF5 파일 생성 및 저장
file_id = H5Fcreate("genome.h5", H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT);
dataspace_id = H5Screate_simple(1, dims, NULL);
dataset_id = H5Dcreate(file_id, "DNA_sequence", H5T_NATIVE_CHAR, dataspace_id,
H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
H5Dwrite(dataset_id, H5T_NATIVE_CHAR, H5S_ALL, H5S_ALL, H5P_DEFAULT, dna_sequence);
// 자원 해제
H5Dclose(dataset_id);
H5Sclose(dataspace_id);
H5Fclose(file_id);
이 코드는 100만 개의 DNA 염기서열을 HDF5 파일에 저장하는 예제입니다.
5. HDF5가 과학 데이터에서 중요한 이유
- 고속 I/O 성능: 바이너리 포맷으로 데이터 입출력 속도 향상
- 대용량 데이터 저장 가능: 테라바이트(TB)급 데이터 저장 지원
- 병렬 I/O 지원: MPI와 함께 사용 가능
- 데이터 압축 및 최적화: Gzip, Szip, Shuffle 필터 활용 가능
- 다양한 데이터 타입 지원: 정수, 부동소수점, 문자열, 구조체 등
HDF5는 과학 연구와 데이터 분석에서 필수적인 데이터 관리 도구 로 활용됩니다. 다음 섹션에서는 전체 내용을 정리하겠습니다.
요약
본 기사에서는 C 언어에서 HDF5 라이브러리를 활용하여 대용량 과학 데이터 관리 방법을 다뤘습니다. HDF5는 고속 입출력(I/O), 병렬 처리, 데이터 압축 및 최적화 기능을 지원하여 과학 및 공학 데이터 처리에 적합한 파일 포맷입니다.
- HDF5 기본 개념: 계층적 구조(그룹, 데이터셋, 속성)로 데이터를 체계적으로 저장 가능
- 파일 생성 및 데이터 저장: HDF5 파일 생성, 1차원/다차원 데이터 저장 방법 소개
- 데이터 불러오기: HDF5에 저장된 데이터를 효율적으로 읽는 방법 설명
- 병렬 I/O 활용: MPI 기반 병렬 HDF5 입출력을 통해 성능 최적화
- 데이터 압축 및 최적화: Gzip, Szip, Shuffle 필터를 활용한 데이터 저장 공간 절약 및 속도 향상
- 과학 데이터 응용 사례: 기후 모델링, 머신러닝 모델 저장, 천문학 연구, 유전체 데이터 분석 등 다양한 활용 사례
HDF5는 효율적인 데이터 관리 가 필요한 모든 분야에서 강력한 도구로 활용됩니다. 본 기사를 통해 C 언어 환경에서 HDF5를 효과적으로 사용하여 대용량 데이터 처리 성능을 향상 시킬 수 있습니다.