# 대형 데이터셋을 LeRobot Dataset v3.0으로 이식하기

이 튜토리얼은 대규모 로봇 데이터셋을 LeRobot Dataset v3.0 형식으로 이식하는 방법을 설명합니다. 수천 개의 샤드가 SLURM 클러스터에 걸쳐 있는 테라바이트급 데이터셋을 처리하는 방법을 보여주는 **DROID 1.0.1** 데이터셋을 주요 예제로 사용합니다.

## 파일 구성: v2.1 vs v3.0

Dataset v3.0은 데이터의 조직 및 저장 방식을 근본적으로 변경합니다:

**v2.1 구조(에피소드 기반)**:

```
dataset/
├── data/chunk-000/episode_000000.parquet
├── data/chunk-000/episode_000001.parquet
├── videos/chunk-000/camera/episode_000000.mp4
└── meta/episodes.jsonl
```

**v3.0 구조(파일 기반)**:

```
dataset/
├── data/chunk-000/file-000.parquet        # Multiple episodes per file
├── videos/camera/chunk-000/file-000.mp4   # Consolidated video chunks
└── meta/episodes/chunk-000/file-000.parquet  # Structured metadata
```

개별 에피소드 파일에서 파일 기반 청크로의 전환은 성능을 크게 향상시키고 저장 오버헤드를 줄입니다.

## Dataset v3.0의 새로운 기능

Dataset v3.0은 대규모 데이터셋 처리를 위한 상당한 개선 사항을 도입합니다:

### 🏗️ **향상된 파일 구성**

- **파일 기반 구조**: 에피소드가 개별 에피소드 파일이 아닌 청크된 파일로 그룹화됩니다
- **구성 가능한 파일 크기**: 데이터 및 비디오 파일용
- **저장 효율 향상**: 더 나은 압축 및 오버헤드 감소

### 📊 **현대적인 메타데이터 관리**

- **Parquet 기반 메타데이터**: JSON Lines를 효율적인 parquet 형식으로 대체
- **구조화된 에피소드 접근**: `dataset.meta.episodes`를 통한 pandas DataFrame 직접 접근
- **에피소드별 통계**: 에피소드 수준의 통계 추적 기능 강화

### 🚀 **성능 향상**

- **메모리 매핑 액세스**: PyArrow 메모리 매핑을 통한 RAM 사용량 개선
- **더 빠른 로딩**: 데이터셋 초기화 시간 크게 단축
- **더 나은 확장성**: 수백만 개의 에피소드를 가진 데이터셋을 위해 설계

## 필수 조건

대용량 데이터셋을 이전하기 전에 다음을 갖추었는지 확인하세요:

- v3.0을 지원하는 **LeRobot**이 설치되었습니다. [설치 가이드](./installation)를 따르세요.
- **충분한 저장 공간**: 원본 데이터셋은 매우 클 수 있습니다(예: DROID는 2TB가 필요합니다)
- **클러스터 액세스** (대규모 데이터셋에 권장): SLURM 또는 유사한 작업 스케줄러
- **데이터셋별 종속성**: DROID의 경우 TensorFlow Dataset 유틸리티가 필요합니다

## DROID 데이터셋 이해하기

[DROID 1.0.1](https://droid-dataset.github.io/droid/the-droid-dataset)은 대규모 로봇 데이터셋의 훌륭한 예시입니다:

- **크기**: 1.7TB (RLDS 형식), 8.7TB (원시 데이터)
- **구조**: 2048개의 사전 정의된 TensorFlow 데이터셋 샤드
- **콘텐츠**: Franka Emika Panda 로봇의 76,000개 이상의 로봇 조작 궤적
- **범위**: 다양한 환경과 객체를 아우르는 실제 조작 작업
- **포맷**: 원래 TensorFlow Records/RLDS 포맷이며, LeRobot 포맷으로 변환이 필요합니다
- **호스팅**: `gsutil`을 통해 공개 액세스가 가능한 Google Cloud Storage

데이터셋에는 다음과 같은 다양한 조작 데모가 포함되어 있습니다:

- 여러 카메라 뷰(손목 카메라, 외부 카메라)
- 자연어 작업 설명
- 로봇의 고유수용성 상태와 동작
- 성공/실패 주석

### DROID 기능 스키마

```python
DROID_FEATURES = {
    # Episode markers
    "is_first": {"dtype": "bool", "shape": (1,)},
    "is_last": {"dtype": "bool", "shape": (1,)},
    "is_terminal": {"dtype": "bool", "shape": (1,)},

    # Language instructions
    "language_instruction": {"dtype": "string", "shape": (1,)},
    "language_instruction_2": {"dtype": "string", "shape": (1,)},
    "language_instruction_3": {"dtype": "string", "shape": (1,)},

    # Robot state
    "observation.state.gripper_position": {"dtype": "float32", "shape": (1,)},
    "observation.state.cartesian_position": {"dtype": "float32", "shape": (6,)},
    "observation.state.joint_position": {"dtype": "float32", "shape": (7,)},

    # Camera observations
    "observation.images.wrist_left": {"dtype": "video", "shape": (180, 320, 3), "names": ["height", "width", "channels"]},
    "observation.images.exterior_1_left": {"dtype": "video", "shape": (180, 320, 3), "names": ["height", "width", "channels"]},
    "observation.images.exterior_2_left": {"dtype": "video", "shape": (180, 320, 3), "names": ["height", "width", "channels"]},

    # Actions
    "action.gripper_position": {"dtype": "float32", "shape": (1,)},
    "action.cartesian_position": {"dtype": "float32", "shape": (6,)},
    "action.joint_position": {"dtype": "float32", "shape": (7,)},

    # Standard LeRobot format
    "observation.state": {"dtype": "float32", "shape": (8,)},  # joints + gripper
    "action": {"dtype": "float32", "shape": (8,)},  # joints + gripper
}
```

## 접근 방식 1: 단일 컴퓨터 이식

### 1단계: 종속성 설치

DROID의 경우:

```bash
pip install tensorflow
pip install tensorflow_datasets
```

다른 데이터셋의 경우, 소스 형식에 맞는 적절한 리더를 설치하세요.

### 2단계: 원시 데이터 다운로드

`gsutil`을 사용하여 Google Cloud Storage에서 DROID를 다운로드합니다:

```bash
# Install Google Cloud SDK if not already installed
# https://cloud.google.com/sdk/docs/install

# Download the full RLDS dataset (1.7TB)
gsutil -m cp -r gs://gresearch/robotics/droid/1.0.1 /your/data/

# Or download just the 100-episode sample (2GB) for testing
gsutil -m cp -r gs://gresearch/robotics/droid_100 /your/data/
```

> [!WARNING]
> 대규모 데이터셋에는 상당한 시간과 저장 공간이 필요합니다:
>
> - **Full DROID (1.7TB)**: 대역폭에 따라 다운로드에 며칠이 소요됩니다 - **처리 시간**: 전체 데이터셋의 로컬 포팅에 7일 이상 소요됩니다 - **업로드 시간**: Hugging Face Hub에 푸시하는 데 3일 이상 소요됩니다 - **로컬 저장소**: 처리된 LeRobot 형식에 대해 약 400GB

### 3단계: 데이터셋 이식

```bash
python examples/port_datasets/port_droid.py \
    --raw-dir /your/data/droid/1.0.1 \
    --repo-id your_id/droid_1.0.1 \
    --push-to-hub
```

### 개발 및 테스트

개발을 위해 단일 샤드를 이식할 수 있습니다:

```bash
python examples/port_datasets/port_droid.py \
    --raw-dir /your/data/droid/1.0.1 \
    --repo-id your_id/droid_1.0.1_test \
    --num-shards 2048 \
    --shard-index 0
```

이 접근법은 작은 데이터셋이나 테스트에는 적합하지만, 큰 데이터셋에는 클러스터 컴퓨팅이 필요합니다.

## 접근 방식 2: SLURM 클러스터 이식 (권장)

DROID와 같은 대규모 데이터셋의 경우, 여러 노드에 걸친 병렬 처리를 통해 처리 시간을 크게 줄일 수 있습니다.

### 1단계: 클러스터 종속성 설치

```bash
pip install datatrove  # Hugging Face's distributed processing library
```

### 2단계: SLURM 환경 구성

파티션 정보를 확인하세요:

```bash
sinfo --format="%R"  # List available partitions
sinfo -N -p your_partition -h -o "%N cpus=%c mem=%m"  # Check resources
```

GPU 없이 데이터셋 이식이 가능하므로 **CPU 파티션**을 선택합니다.

### 3단계: 병렬 포트링 작업 시작

```bash
python examples/port_datasets/slurm_port_shards.py \
    --raw-dir /your/data/droid/1.0.1 \
    --repo-id your_id/droid_1.0.1 \
    --logs-dir /your/logs \
    --job-name port_droid \
    --partition your_partition \
    --workers 2048 \
    --cpus-per-task 8 \
    --mem-per-cpu 1950M
```

#### 매개변수 가이드라인

- **`--workers`**: 병렬 작업 수 (DROID의 샤드 수 기준 최대 2048)
- **`--cpus-per-task`**: 프레임 인코딩 병렬화를 위해 8개의 CPU 권장
- **`--mem-per-cpu`**: 원시 프레임 로딩을 위한 총 ~16GB RAM (8×1950M)

> [!TIP]
> 수천 개의 작업을 시작하기 전에 클러스터 구성을 테스트하려면 워커 수를 적게(예: 100개) 설정하여 시작하세요.

### 4단계: 진행 상황 모니터링

실행 중인 작업 확인:

```bash
squeue -u $USER
```

전체 진행 상황 모니터링:

```bash
jobs_status /your/logs
```

개별 작업 로그를 확인합니다:

```bash
less /your/logs/port_droid/slurm_jobs/JOB_ID_WORKER_ID.out
```

Debug failed jobs:

```bash
failed_logs /your/logs/port_droid
```

### 5단계: 샤드 집계

모든 포트링 작업이 완료되면:

```bash
python examples/port_datasets/slurm_aggregate_shards.py \
    --repo-id your_id/droid_1.0.1 \
    --logs-dir /your/logs \
    --job-name aggr_droid \
    --partition your_partition \
    --workers 2048 \
    --cpus-per-task 8 \
    --mem-per-cpu 1950M
```

### 6단계: Hub에 업로드

```bash
python examples/port_datasets/slurm_upload.py \
    --repo-id your_id/droid_1.0.1 \
    --logs-dir /your/logs \
    --job-name upload_droid \
    --partition your_partition \
    --workers 50 \
    --cpus-per-task 4 \
    --mem-per-cpu 1950M
```

> [!NOTE]
> Upload은 계산이 아닌 네트워크에 의존적이므로 더 적은 워커(50)를 사용합니다.

## Dataset v3.0 파일 구조

완성된 데이터셋은 다음과 같은 현대적인 구조를 갖습니다:

```
dataset/
├── meta/
│   ├── episodes/
│   │   └── chunk-000/
│   │       └── file-000.parquet    # Episode metadata
│   ├── tasks.parquet               # Task definitions
│   ├── stats.json                  # Aggregated statistics
│   └── info.json                   # Dataset information
├── data/
│   └── chunk-000/
│       └── file-000.parquet        # Consolidated episode data
└── videos/
    └── camera_key/
        └── chunk-000/
            └── file-000.mp4        # Consolidated video files
```

…

## Dataset v2.1에서 마이그레이션

v2.1 형식의 기존 데이터셋이 있는 경우, 마이그레이션 도구를 사용하세요:

```bash
python src/lerobot/scripts/convert_dataset_v21_to_v30.py \
    --repo-id your_id/existing_dataset
```

이것은 자동으로 다음을 수행합니다:

- 파일 구조를 v3.0 형식으로 변환합니다
- JSON Lines에서 parquet로 메타데이터를 마이그레이션합니다
- 통계를 집계하고 에피소드별 통계를 생성합니다
- 버전 정보 업데이트

## 성능 이점

Dataset v3.0은 대규모 데이터셋에 대해 상당한 개선 사항을 제공합니다:

- **더 빠른 로딩**: 초기화 시간 3~5배 단축
- **메모리 효율성**: 메모리 매핑을 통한 더 나은 RAM 사용
- **확장 가능한 처리**: 수백만 개의 에피소드를 효율적으로 처리합니다
- **스토리지 최적화**: 파일 수 감소 및 압축률 향상

