데이터셋 불러오기

데이터셋 불러오기 (Load)

데이터는 정말 다양한 곳에 저장될 수 있어요. 내 컴퓨터 디스크에 있을 수도 있고, Github 저장소에 있을 수도 있고, 파이썬 딕셔너리나 Pandas DataFrame 같은 메모리(in-memory) 데이터 구조에 들어 있을 수도 있죠. 데이터셋이 어디에 있든 🤗 Datasets이 불러오는 걸 도와줍니다.

이 가이드에서는 다음 위치에서 데이터셋을 불러오는 법을 보여줄게요:

  • Hugging Face Hub
  • 로컬 파일
  • 메모리 안의 데이터
  • 오프라인
  • split의 특정 슬라이스

다른 모달리티(형태)의 데이터셋 로딩이 궁금하다면 오디오 데이터셋 로드, 이미지 데이터셋 로드, 비디오 데이터셋 로드, 텍스트 데이터셋 로드 가이드를 참고해요.

Hugging Face Hub

Hub에 있는 어떤 데이터셋 저장소에서든 데이터셋을 불러올 수 있어요! 먼저 데이터셋 저장소를 만들고 데이터 파일을 업로드하세요. 이제 load_dataset() 함수로 데이터셋을 불러올 수 있어요.

예를 들어 이 demo 저장소의 파일을 저장소 네임스페이스와 데이터셋 이름을 제공해서 불러와 볼게요. 이 저장소에는 CSV 파일이 있고, 아래 코드가 CSV 파일에서 데이터셋을 불러옵니다.

>>> from datasets import load_dataset
>>> dataset = load_dataset("lhoestq/demo1")

일부 데이터셋은 Git 태그, 브랜치, 커밋에 따라 여러 버전이 있을 수 있어요. 불러오고 싶은 데이터셋 버전을 지정하려면 revision 파라미터를 사용해요.

>>> dataset = load_dataset(
...   "lhoestq/custom_squad",
...   revision="main"  # 태그 이름, 브랜치 이름, 또는 커밋 해시
... )

Hub에 데이터셋 저장소를 만들고 데이터 파일을 업로드하는 더 자세한 방법은 데이터셋을 Hub에 업로드 튜토리얼을 참고하세요.

데이터셋은 기본적으로 모든 데이터를 train split으로 불러오거나, 데이터 파일 이름에서 split 이름(예: "train", "test", "validation")을 찾아내요. data_files 파라미터로 데이터 파일을 train, validation, test 같은 split에 매핑할 수 있어요.

>>> data_files = {"train": "train.csv", "test": "test.csv"}
>>> dataset = load_dataset("namespace/your_dataset_name", data_files=data_files)

어떤 데이터 파일을 쓸지 지정하지 않으면 load_dataset()이 모든 데이터 파일을 반환해요. C4처럼 약 13TB에 달하는 큰 데이터셋이라면 시간이 오래 걸릴 수 있으니 주의하세요.

data_filesdata_dir 파라미터로 파일의 특정 하위 집합만 불러올 수도 있어요. 이 파라미터들은 데이터셋이 불러와지는 기본 경로에 상대 경로로 결정되는 경로를 받을 수 있어요.

>>> from datasets import load_dataset

# grep 패턴에 맞는 파일만 불러오기
>>> c4_subset = load_dataset("allenai/c4", data_files="en/c4-train.0000*-of-01024.json.gz")

# Hub의 en 디렉토리에서 데이터셋 불러오기
>>> c4_subset = load_dataset("allenai/c4", data_dir="en")

split 파라미터로 데이터 파일을 특정 split에 매핑할 수도 있어요.

>>> data_files = {"validation": "en/c4-validation.*.json.gz"}
>>> c4_validation = load_dataset("allenai/c4", data_files=data_files, split="validation")

로컬 파일과 원격 파일

데이터셋은 내 컴퓨터에 저장된 로컬 파일과 원격 파일에서 불러올 수 있어요. 데이터셋은 대부분 csv, json, txt, parquet 파일로 저장되어 있어요. load_dataset() 함수가 이 파일 유형을 모두 불러올 수 있습니다.

CSV

🤗 Datasets은 하나 또는 여러 개의 CSV 파일로 이루어진 데이터셋을 읽을 수 있어요 (이 경우 CSV 파일들을 리스트로 넘기세요):

>>> from datasets import load_dataset
>>> dataset = load_dataset("csv", data_files="my_file.csv")

더 자세한 내용은 CSV 파일에서 표(tabular) 데이터셋 불러오기 가이드를 확인하세요.

JSON

JSON 파일은 아래처럼 load_dataset()으로 바로 불러와요.

>>> from datasets import load_dataset
>>> dataset = load_dataset("json", data_files="my_file.json")

JSON 파일은 다양한 형식을 가지는데, 가장 효율적인 형식은 여러 JSON 객체가 한 줄마다 하나의 데이터 행을 나타내는 방식이에요. 예를 들면:

{"a": 1, "b": 2.0, "c": "foo", "d": false}
{"a": 4, "b": -5.5, "c": null, "d": true}

만날 수 있는 또 다른 JSON 형식은 중첩 필드(nested field)인데, 이 경우 아래처럼 field 인자를 지정해야 해요.

{"version": "0.1.0",
 "data": [{"a": 1, "b": 2.0, "c": "foo", "d": false},
          {"a": 4, "b": -5.5, "c": null, "d": true}]
}

>>> from datasets import load_dataset
>>> dataset = load_dataset("json", data_files="my_file.json", field="data")

HTTP를 통해 원격 JSON 파일을 불러오려면 URL을 넘기면 돼요.

>>> base_url = "https://rajpurkar.github.io/SQuAD-explorer/dataset/"
>>> dataset = load_dataset("json", data_files={"train": base_url + "train-v1.1.json", "validation": base_url + "dev-v1.1.json"}, field="data")

이것들이 가장 흔한 JSON 형식이지만, 다른 형식으로 된 데이터셋도 만나게 될 거예요. 🤗 Datasets은 이런 형식도 알아서 파이썬의 JSON 로딩 메서드로 처리해 줍니다.

Parquet

Parquet 파일은 CSV 같은 행 기반 파일과 달리 칼럼형(columnar) 형식으로 저장돼요. 큰 데이터셋은 Parquet 파일로 저장하는 경우가 많은데, 쿼리 결과를 돌려주는 속도가 더 효율적이고 빠르기 때문이에요.

Parquet 파일을 불러오려면:

>>> from datasets import load_dataset
>>> dataset = load_dataset("parquet", data_files={'train': 'train.parquet', 'test': 'test.parquet'})

HTTP를 통해 원격 Parquet 파일을 불러오려면 URL을 넘기면 돼요.

>>> base_url = "https://huggingface.co/datasets/wikimedia/wikipedia/resolve/main/20231101.ab/"
>>> data_files = {"train": base_url + "train-00000-of-00001.parquet"}
>>> wiki = load_dataset("parquet", data_files=data_files, split="train")

Arrow

Arrow 파일은 CSV 같은 행 기반 형식이나 압축되지 않은 Parquet과 달리 메모리 내 칼럼형 형식으로 저장돼요.

Arrow 파일을 불러오려면:

>>> from datasets import load_dataset
>>> dataset = load_dataset("arrow", data_files={'train': 'train.arrow', 'test': 'test.arrow'})

HTTP를 통해 원격 Arrow 파일을 불러오려면 URL을 넘기면 돼요.

>>> base_url = "https://huggingface.co/datasets/croissantllm/croissant_dataset/resolve/main/english_660B_11/"
>>> data_files = {"train": base_url + "train/data-00000-of-00080.arrow"}
>>> wiki = load_dataset("arrow", data_files=data_files, split="train")

Arrow는 🤗 Datasets이 내부적으로 쓰는 파일 형식이에요. 그래서 로컬 Arrow 파일은 Dataset.from_file()로 직접 불러올 수 있어요.

>>> from datasets import Dataset
>>> dataset = Dataset.from_file("data.arrow")

load_dataset()과 달리 Dataset.from_file()은 캐시에서 데이터셋을 준비하지 않고 Arrow 파일을 메모리 맵(memory map) 하므로 디스크 공간을 아껴줘요. 이 경우 중간 처리 결과를 저장할 캐시 디렉토리는 Arrow 파일 디렉토리가 됩니다.

현재는 Arrow 스트리밍 형식만 지원돼요. Arrow IPC 파일 형식(Feather V2라고도 함)은 지원되지 않습니다.

Lance

Lance는 AI를 위한 오픈소스 멀티모달 레이크하우스 테이블 형식이에요. Lance 테이블은 텍스트와 스칼라 값뿐 아니라 이미지·오디오·비디오 같은 큰 바이너리 객체(blob)도 표 데이터와 함께 기본적으로 저장할 수 있어요.

>>> from datasets import load_dataset
>>> lance_base_url = "lance-format/laion-1m"

streaming=True 파라미터를 지정하면 로컬 머신에 복사하지 않고 데이터셋을 스트리밍할 수 있어요.

ds = load_dataset(lance_base_url, split="train", streaming=True)
# 처음 세 행 가져오기
for row in ds.take(3):
    print(row["caption"], row["image"])

이렇게 하면 이미지 캡션과 이미지 바이트를 단일 요청으로 반환해요.

HDF5 파일

HDF5 파일은 과학 컴퓨팅과 머신러닝에서 큰 수치 데이터를 저장할 때 흔히 사용돼요. 🤗 Datasets으로 HDF5 파일을 불러오는 건 CSV 파일을 불러오는 것과 비슷해요.

>>> from datasets import load_dataset
>>> dataset = load_dataset("hdf5", data_files="data.h5")

HDF5 로더는 파일이 "표(tabular)" 구조라고 가정한다는 점을 기억하세요. 즉 파일의 모든 데이터셋이 첫 번째 차원에 (같은 수의) 행을 가진다는 뜻이에요.

SQL

from_sql()에 데이터베이스에 연결할 URI를 지정하면 데이터베이스 내용을 읽을 수 있어요. 테이블 이름과 쿼리 모두 읽을 수 있습니다.

>>> from datasets import Dataset
# 전체 테이블 불러오기
>>> dataset = Dataset.from_sql("data_table_name", con="sqlite:///sqlite_file.db")
# 쿼리로 불러오기
>>> dataset = Dataset.from_sql("SELECT text FROM table WHERE length(text) > 100 LIMIT 10", con="sqlite:///sqlite_file.db")

더 자세한 내용은 SQL 데이터베이스에서 표 데이터셋 불러오기 가이드를 확인하세요.

WebDataset

WebDataset 형식은 TAR 아카이브 기반이라 큰 이미지 데이터셋에 적합해요. 크기 때문에 WebDataset은 일반적으로 스트리밍 모드(streaming=True 사용)로 불러옵니다.

WebDataset은 이렇게 불러올 수 있어요.

>>> from datasets import load_dataset
>>>
>>> path = "path/to/train/*.tar"
>>> dataset = load_dataset("webdataset", data_files={"train": path}, split="train", streaming=True)

HTTP를 통해 원격 WebDataset을 불러오려면 URL을 넘기면 돼요.

>>> from datasets import load_dataset
>>>
>>> base_url = "https://huggingface.co/datasets/lhoestq/small-publaynet-wds/resolve/main/publaynet-train-{i:06d}.tar"
>>> urls = [base_url.format(i=i) for i in range(4)]
>>> dataset = load_dataset("webdataset", data_files={"train": urls}, split="train", streaming=True)

원격 파일

csv, json, txt, parquet 또는 그 밖의 지원 형식으로 저장된 원격 파일이 있다면, load_dataset() 함수에 원격 경로를 지정해서 불러올 수 있어요.

  • 공개 온라인 파일의 https:// URL, 예: data_files=["https://rajpurkar.github.io/SQuAD-explorer/dataset/train-v2.0.json"]
  • Hugging Face의 데이터셋 저장소Storage Bucket에 있는 파일의 hf:// URL, 예: data_files=["hf://datasets/karpathy/tinystories-gpt4-clean/tinystories_gpt4_clean.parquet"] 또는 data_files=["hf://buckets/julien-c/my-training-bucket/julien/affluence.csv"]

멀티프로세싱

데이터셋이 여러 파일(우리가 "샤드(shard)"라고 부르는 것)로 이루어져 있다면 데이터셋 다운로드·준비 단계를 크게 가속화할 수 있어요.

num_proc를 사용해 데이터셋을 병렬로 준비할 프로세스 수를 정할 수 있어요. 이 경우 각 프로세스에 준비할 샤드의 일부가 주어집니다.

from datasets import load_dataset

imagenet = load_dataset("timm/imagenet-1k-wds", num_proc=8)
ml_librispeech_spanish = load_dataset("facebook/multilingual_librispeech", "spanish", num_proc=8)

메모리 안의 데이터

🤗 Datasets은 파이썬 딕셔너리나 Pandas DataFrame 같은 메모리 내 데이터 구조에서도 Dataset을 바로 만들 수 있게 해 줘요.

파이썬 딕셔너리

from_dict()로 파이썬 딕셔너리를 불러와요.

>>> from datasets import Dataset
>>> my_dict = {"a": [1, 2, 3]}
>>> dataset = Dataset.from_dict(my_dict)

파이썬 딕셔너리 리스트

from_list()로 파이썬 딕셔너리 리스트를 불러와요.

>>> from datasets import Dataset
>>> my_list = [{"a": 1}, {"a": 2}, {"a": 3}]
>>> dataset = Dataset.from_list(my_list)

파이썬 제너레이터

from_generator()로 파이썬 제너레이터에서 데이터셋을 만들어요.

>>> from datasets import Dataset
>>> def my_gen():
...     for i in range(1, 4):
...         yield {"a": i}
...
>>> dataset = Dataset.from_generator(my_gen)

이 방식은 사용 가능한 메모리보다 큰 데이터를 불러오는 것도 지원해요.

gen_kwargs에 리스트를 넘겨 샤드화된 데이터셋을 정의할 수도 있어요.

>>> def gen(shards):
...     for shard in shards:
...         with open(shard) as f:
...             for line in f:
...                 yield {"line": line}
...
>>> shards = [f"data{i}.txt" for i in range(32)]
>>> ds = IterableDataset.from_generator(gen, gen_kwargs={"shards": shards})
>>> ds = ds.shuffle(seed=42, buffer_size=10_000)  # 샤드 순서 셔플 + 셔플 버퍼 사용
>>> from torch.utils.data import DataLoader
>>> dataloader = DataLoader(ds.with_format("torch"), num_workers=4)  # 각 워커에 32/4=8개 샤드의 부분집합 제공

Pandas DataFrame

from_pandas()로 Pandas DataFrame을 불러와요.

>>> from datasets import Dataset
>>> import pandas as pd
>>> df = pd.DataFrame({"a": [1, 2, 3]})
>>> dataset = Dataset.from_pandas(df)

더 자세한 내용은 Pandas DataFrame에서 표 데이터셋 불러오기 가이드를 확인하세요.

오프라인

인터넷 연결이 없어도 데이터셋을 불러오는 게 가능해요. Hub 저장소에서 데이터셋을 한 번이라도 다운로드했다면 캐시에 있기 때문이에요. 즉 캐시에서 데이터셋을 다시 불러와 오프라인으로 쓸 수 있습니다.

인터넷에 접속하지 못할 걸 미리 안다면 🤗 Datasets을 완전 오프라인 모드로 실행할 수 있어요. 이렇게 하면 Dataset 빌더 다운로드가 타임아웃되길 기다리는 대신 바로 캐시를 살펴보기 때문에 시간을 아껴줘요. 환경 변수 HF_HUB_OFFLINE1로 설정하면 완전 오프라인 모드가 켜집니다.

Split 슬라이스

split의 특정 슬라이스만 골라 불러올 수도 있어요. split을 슬라이스하는 방법은 두 가지로, 문자열을 쓰거나 ReadInstruction API를 쓰는 거예요. 단순한 경우에는 문자열이 더 간결하고 읽기 쉬운 반면, ReadInstruction은 가변 슬라이싱 파라미터에 쓰기 좋아요.

traintest split을 이어붙이려면:

>>> train_test_ds = datasets.load_dataset("ajibawa-2023/General-Stories-Collection", split="train+test")

train split의 특정 행을 고르려면:

>>> train_10_20_ds = datasets.load_dataset("ajibawa-2023/General-Stories-Collection", split="train[10:20]")

split의 백분율을 고르려면:

>>> train_10pct_ds = datasets.load_dataset("ajibawa-2023/General-Stories-Collection", split="train[:10%]")

각 split의 백분율 조합을 고르려면:

>>> train_10_80pct_ds = datasets.load_dataset("ajibawa-2023/General-Stories-Collection", split="train[:10%]+train[-80%:]")

마지막으로 교차 검증(cross-validation) split까지 만들 수 있어요. 아래 예시는 10겹 교차 검증 split을 만드는데, 각 검증 데이터셋은 10% 청크이고 훈련 데이터셋은 나머지 상보적인 90% 청크를 이룹니다.

>>> val_ds = datasets.load_dataset("ajibawa-2023/General-Stories-Collection", split=[f"train[{k}%:{k+10}%]" for k in range(0, 100, 10)])
>>> train_ds = datasets.load_dataset("ajibawa-2023/General-Stories-Collection", split=[f"train[:{k}%]+train[{k+10}%:]" for k in range(0, 100, 10)])

백분율 슬라이싱과 반올림

요청한 슬라이스 경계가 100으로 나누어 떨어지지 않는 데이터셋에서는 기본 동작이 경계를 가장 가까운 정수로 반올림해요. 아래처럼 어떤 슬라이스는 다른 슬라이스보다 더 많은 예시를 포함할 수도 있어요. 예를 들어 다음 train split이 999개 레코드를 포함한다면:

# 19개 레코드, 500(포함)부터 519(미포함)까지.
>>> train_50_52_ds = datasets.load_dataset("ajibawa-2023/General-Stories-Collection", split="train[50%:52%]")
# 20개 레코드, 519(포함)부터 539(미포함)까지.
>>> train_52_54_ds = datasets.load_dataset("ajibawa-2023/General-Stories-Collection", split="train[52%:54%]")

균등한 크기의 split을 원한다면 pct1_dropremainder 반올림을 쓰면 돼요. 이 방식은 지정한 백분율 경계를 1%의 배수로 취급합니다.

# 18개 레코드, 450(포함)부터 468(미포함)까지.
>>> train_50_52pct1_ds = datasets.load_dataset("ajibawa-2023/General-Stories-Collection", split=datasets.ReadInstruction("train", from_=50, to=52, unit="%", rounding="pct1_dropremainder"))
# 18개 레코드, 468(포함)부터 486(미포함)까지.
>>> train_52_54pct1_ds = datasets.load_dataset("ajibawa-2023/General-Stories-Collection", split=datasets.ReadInstruction("train",from_=52, to=54, unit="%", rounding="pct1_dropremainder"))
# 또는 동등하게:
>>> train_50_52pct1_ds = datasets.load_dataset("ajibawa-2023/General-Stories-Collection", split="train[50%:52%](pct1_dropremainder)")
>>> train_52_54pct1_ds = datasets.load_dataset("ajibawa-2023/General-Stories-Collection", split="train[52%:54%](pct1_dropremainder)")

데이터셋의 예시 수가 100으로 나누어 떨어지지 않으면 pct1_dropremainder 반올림이 데이터셋의 마지막 예시들을 잘라낼 수 있어요.

문제 해결

데이터셋을 불러올 때 예상치 못한 결과를 얻는 경우가 있어요. 가장 흔한 두 가지는 데이터셋을 수동으로 다운로드한 경우와 데이터셋의 features를 지정하는 경우예요.

Features 지정

로컬 파일에서 데이터셋을 만들면 FeaturesApache Arrow에 의해 자동으로 추론돼요. 하지만 데이터셋의 features가 우리가 기대한 것과 항상 일치하는 건 아니라서, features를 직접 정의하고 싶을 수도 있어요. 아래 예시는 ClassLabel feature로 커스텀 레이블을 추가하는 방법을 보여줍니다.

Features 클래스로 직접 레이블을 정의하는 것부터 시작해요.

>>> class_names = ["sadness", "joy", "love", "anger", "fear", "surprise"]
>>> emotion_features = Features({'text': Value('string'), 'label': ClassLabel(names=class_names)})

다음으로 load_dataset()features 파라미터에 방금 만든 features를 지정해요.

>>> dataset = load_dataset('csv', data_files=file_dict, delimiter=';', column_names=['text', 'label'], features=emotion_features)

이제 데이터셋 features를 살펴보면 우리가 정의한 커스텀 레이블을 쓰는 걸 확인할 수 있어요.

>>> dataset['train'].features
{'text': Value('string'),
'label': ClassLabel(names=['sadness', 'joy', 'love', 'anger', 'fear', 'surprise'])}

출처: 공식문서