# 비디오 데이터 로드

> [!WARNING]
> Video 지원은 실험적이며 변경될 수 있습니다.

Video 데이터셋에는 `torchcodec` 객체를 포함하는 [Video](/docs/datasets/main/ko/package_reference/main_classes#datasets.Video) 타입의 컬럼이 있습니다.

> [!TIP]
> 비디오 데이터셋을 다루려면 `torchcodec` 및 `ffmpeg` 패키지가 설치되어 있어야 합니다. 설치 방법은 [설치](https://github.com/meta-pytorch/torchcodec#installing-torchcodec) 가이드를 참고하세요.

비디오 데이터셋을 로드하고 비디오 컬럼을 호출하면 비디오는 `torchcodec` Videos로 디코딩됩니다:

```py
>>> from datasets import load_dataset, Video

>>> dataset = load_dataset("path/to/video/folder", split="train")
>>> dataset[0]["video"]
<torchcodec.decoders._video_decoder.VideoDecoder object at 0x14a61d5a0>
```

> [!WARNING]
> `dataset[0]["video"]`와 같이 행 인덱스를 먼저 사용하고 `video` 열을 인덱싱하여 비디오 데이터셋에 접근하세요. 이렇게 하면 데이터셋의 모든 비디오 객체를 생성하지 않아도 됩니다. 그렇지 않으면 데이터셋이 크면 느리고 시간이 많이 걸리는 과정이 될 수 있습니다.

모든 유형의 데이터를 로드하는 방법에 대한 가이드는 일반적인 로드 가이드를 참고하세요.

## 프레임 읽기

`VideoReader`의 `next()`를 사용하여 비디오에서 프레임을 직접 액세스합니다:

```python
>>> video = dataset[0]["video"]
>>> first_frame = video.get_frame_at(0)
>>> first_frame.data.shape
(3, 240, 320)
>>> first_frame.pts_seconds  # timestamp
0.0
```

여러 프레임을 한 번에 가져오려면 `.get_frames_in_range(start: int, stop: int, step: int)`을 호출할 수 있습니다. 이 메서드는 프레임 배치(frame batch)를 반환합니다. 긴 프레임 목록을 효율적으로 가져오는 방법이며, 데이터를 효율적으로 접근하기 위한 추가 함수는 [torchcodec 문서](https://meta-pytorch.org/torchcodec/stable/generated/torchcodec.decoders.VideoDecoder.html)를 참고하세요:

```python
>>> import torch
>>> frames = video.get_frames_in_range(0, 6, 1)
>>> frames.data.shape
torch.Size([5, 3, 240, 320])
```

특정 시간 범위에 재생된 모든 프레임에 액세스하기 위해 `.get_frames_played_in_range(start_seconds: float, stop_seconds: float)`도 있습니다.

```python
>>> frames = video.get_frames_played_in_range(.5, 1.2)
>>> frames.data.shape
torch.Size([42, 3, 240, 320])
```

## 로컬 파일

비디오 경로에서 데이터셋을 로드할 수 있습니다. [cast_column()](/docs/datasets/main/ko/package_reference/main_classes#datasets.Dataset.cast_column) 함수를 사용하여 비디오 파일 경로 컬럼을 받아 [Video](/docs/datasets/main/ko/package_reference/main_classes#datasets.Video) 기능으로 `torchcodec` 비디오로 디코딩합니다:

```py
>>> from datasets import Dataset, Video

>>> dataset = Dataset.from_dict({"video": ["path/to/video_1", "path/to/video_2", ..., "path/to/video_n"]}).cast_column("video", Video())
>>> dataset[0]["video"]
<torchcodec.decoders._video_decoder.VideoDecoder object at 0x14a61e080>
```

비디오 객체를 디코딩하지 않고 비디오 데이터셋의 기본 경로만 로드하려면 [Video](/docs/datasets/main/ko/package_reference/main_classes#datasets.Video) 기능에서 `decode=False`를 설정하세요:

```py
>>> dataset = dataset.cast_column("video", Video(decode=False))
>>> dataset[0]["video"]
{'bytes': None,
 'path': 'path/to/video/folder/video0.mp4'}
```

## VideoFolder

`VideoFolder` dataset builder를 사용하여 커스텀 dataloader를 작성하지 않고도 dataset을 로드할 수 있습니다. 이를 통해 `VideoFolder`은 다양한 vision task에 대해 수천 개의 비디오로 구성된 video dataset을 빠르게 생성하고 로드하는 데 이상적입니다. 비디오 dataset 구조는 다음과 같아야 합니다:

```
folder/train/dog/golden_retriever.mp4
folder/train/dog/german_shepherd.mp4
folder/train/dog/chihuahua.mp4

folder/train/cat/maine_coon.mp4
folder/train/cat/bengal.mp4
folder/train/cat/birman.mp4
```

데이터셋이 `VideoFolder` 구조를 따르는 경우, [load_dataset()](/docs/datasets/main/ko/package_reference/loading_methods#datasets.load_dataset)를 사용하여 직접 로드할 수 있습니다:

```py
>>> from datasets import load_dataset

>>> dataset = load_dataset("username/dataset_name")
>>> # OR locally:
>>> dataset = load_dataset("/path/to/folder")
```

로컬 데이터셋의 경우, 이는 [load_dataset()](/docs/datasets/main/ko/package_reference/loading_methods#datasets.load_dataset)에서 `videofolder`를 수동으로 전달하고 `data_dir`에 해당 디렉터리를 지정하는 것과 동일합니다:

```py
>>> dataset = load_dataset("videofolder", data_dir="/path/to/folder")
```

이후 `torchcodec.decoders._video_decoder.VideoDecoder` 객체로 비디오에 액세스할 수 있습니다:

```
>>> dataset["train"][0]
{"video": <torchcodec.decoders._video_decoder.VideoDecoder object at 0x14a61e080>, "label": 0}

>>> dataset["train"][-1]
{"video": <torchcodec.decoders._video_decoder.VideoDecoder object at 0x14a61e090>, "label": 1}
```

메타데이터 파일의 정보를 무시하려면 [load_dataset()](/docs/datasets/main/ko/package_reference/loading_methods#datasets.load_dataset)에서 `drop_metadata=True`를 설정하세요:

```py
>>> from datasets import load_dataset

>>> dataset = load_dataset("username/dataset_with_metadata", drop_metadata=True)
```

메타데이터 파일이 없는 경우 `VideoFolder`는 디렉터리 이름에서 라벨 이름을 자동으로 추론합니다. 자동으로 생성된 라벨을 제거하려면 `drop_labels=True`를 설정하세요. 이 경우 데이터셋에는 비디오 컬럼만 포함됩니다:

```py
>>> from datasets import load_dataset

>>> dataset = load_dataset("username/dataset_without_metadata", drop_labels=True)
```

마지막으로 `filters` 인수를 사용하면 라벨 또는 메타데이터에 대한 조건을 기반으로 데이터셋의 부분 집합만 로드할 수 있습니다. 이는 메타데이터가 Parquet 형식으로 저장된 경우 특히 유용하며, 이 형식은 빠른 필터링을 지원하기 때문입니다. 기본적으로 필터링 전에 데이터셋이 완전히 다운로드되므로, 이 인수를 사용할 때 `streaming=True`를 함께 사용하는 것이 권장됩니다.

```python
>>> filters = [("label", "=", 0)]
>>> dataset = load_dataset("username/dataset_name", streaming=True, filters=filters)
```

> [!TIP]
> `VideoFolder` 데이터셋을 직접 만드는 방법에 대한 자세한 내용은 [비디오 데이터셋 만들기](./video_dataset) 가이드를 참고하세요.

## WebDataset

[WebDataset](https://github.com/webdataset/webdataset) 형식은 TAR 아카이브 폴더를 기반으로 하며, 대규모 비디오 데이터셋에 적합합니다. 크기가 크기 때문에 WebDataset은 일반적으로 스트리밍 모드( `streaming=True` 사용)로 로드됩니다.

WebDataset를 다음과 같이 로드할 수 있습니다:

```python
>>> from datasets import load_dataset

>>> dataset = load_dataset("webdataset", data_dir="/path/to/folder", streaming=True)
```

## Lance

[Lance](https://lance.org)는 오픈 멀티모달 레이크하우스 테이블 형식입니다. Lance 테이블은 텍스트와 스칼라 값뿐만 아니라 이미지, 오디오, 비디오와 같은 대형 바이너리 객체(blobs)도 테이블 데이터와 함께 네이티브로 저장할 수 있습니다. Lance 테이블 내부에서 비디오와 같은 대형 blobs는 오프셋을 가진 바이트로 저장됩니다([blob 가이드](https://lance.org/guide/blob/)에서 자세한 내용을 확인하세요). 이를 통해 무거운 비디오 blobs를 로드하지 않고도 메타데이터를 스캔하고 필터링할 수 있으며, 필요할 때에만 특정 비디오 blobs만 온디맨드로 가져올 수 있습니다.

또한 Lance는 컬럼형(columnar) 형식이기 때문에, 관심 있는 메타데이터 컬럼만 투영(projection)하고 필터링할 수 있습니다(대용량 비디오 파일을 가져오지 않고도). 준비가 되면 비디오를 포함한 소수의 행만 가져오면 됩니다. 이를 통해 별도의 파일 저장소나 외부 인덱스 없이 메타데이터와 비디오를 한 곳에 유지할 수 있습니다.

```python
import lance

ds = lance.dataset("hf://datasets/lance-format/openvid-lance/data/train.lance")

# 1. Browse metadata without loading video blobs.
metadata = ds.scanner(
    columns=["caption", "aesthetic_score"],
    filter="aesthetic_score >= 4.5",
    limit=2,
).to_table().to_pylist()

# 2. Fetch a single video blob by row index.
selected_index = 0
blob_file = ds.take_blobs("video_blob", ids=[selected_index])[0]
with open("video_0.mp4", "wb") as f:
    f.write(blob_file.read())
```

이 예제에서는 비디오가 인코딩된 바이트 형태로 Lance 테이블에 네이티브로 저장되므로, 추가 변환 단계 없이 로컬 파일 시스템의 `mp4` 파일에 직접 쓸 수 있습니다.

Lance 데이터셋을 다루는 방법에 대한 자세한 내용은 [Lance 문서](https://lance.org)를 참고하세요.

## 비디오 디코딩

기본적으로 데이터셋을 반복할 때 비디오는 `VideoDecoders`로 순차적으로 디코딩됩니다. 비디오의 메타데이터를 순차적으로 디코딩하며, 비디오 프레임을 직접 접근하기 전까지는 프레임을 읽지 않습니다.

그러나 멀티스레드 디코딩을 사용하면 데이터셋을 상당히 빠르게 처리할 수 있습니다:

```python
>>> import os
>>> num_threads = num_threads = min(32, (os.cpu_count() or 1) + 4)
>>> dataset = dataset.decode(num_threads=num_threads)
>>> for example in dataset:  # up to 20 times faster !
...     ...
```

`num_threads`를 사용하여 멀티스레딩을 활성화할 수 있습니다. 이는 원격 데이터 스트리밍을 가속하는 데 특히 유용합니다. 그러나 빠른 디스크의 로컬 데이터의 경우 `num_threads=0`보다 느릴 수 있습니다.

torchcodec `VideoDecoders`로 디코딩된 비디오에 관심이 없고 대신 경로/바이트에 액세스하려면 디코딩을 비활성화할 수 있습니다:

```python
>>> dataset = dataset.decode(False)
```

참고: [IterableDataset.decode()](/docs/datasets/main/ko/package_reference/main_classes#datasets.IterableDataset.decode)는 현재 스트리밍 데이터셋에서만 사용할 수 있습니다.

