C에서 HDF5 라이브러리로 대용량 과학 데이터 관리하기

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와 기존 파일 포맷 비교

특징CSVJSON/XMLHDF5
데이터 저장 방식텍스트텍스트이진
대용량 데이터 처리낮음중간높음
구조화 데이터 지원없음있음있음
데이터 압축없음없음지원
병렬 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를 효과적으로 사용하여 대용량 데이터 처리 성능을 향상 시킬 수 있습니다.