Danh sách bài viết

Bài 20: Datasets library — load dataset chuẩn

Bài cuối của Module 3 đi qua thư viện datasets của Hugging Face — thành phần thứ hai (sau transformers) trong bộ công cụ tiêu chuẩn để load, xử lý và chia sẻ dataset ML. Bài giới thiệu cài đặt, load_dataset(), cách inspect dữ liệu, các dataset phổ biến (GLUE, SQuAD, IMDB, WikiText, C4, Alpaca, HumanEval, MMLU), corpus đa ngôn ngữ (mC4, OSCAR), chế độ streaming cho dataset terabyte, các operation map / filter / batched, train_test_split, shuffle, select, save_to_disk / load_from_disk / push_to_hub, load từ file local (CSV, JSON, Parquet), format Arrow / Parquet, cache, concatenate_datasets / interleave_datasets, convert sang PyTorch DataLoader, các pitfall thường gặp và tổng kết Module 3 trước khi mở Module 4 Prompt Engineering ở Bài 21.

25/05/2026
13 phút đọc
1 lượt xem
1

Mục tiêu bài học

Sau bài học, bạn sẽ:

  • Biết thư viện datasets đóng vai trò gì trong stack Hugging Face.
  • Dùng được load_dataset() để pull dataset từ Hub và inspect schema.
  • Biết tên một số dataset phổ biến cho NLU, QA, sentiment, LM, instruction tuning, code, benchmark.
  • Hiểu streaming mode và khi nào nên dùng để xử lý corpus terabyte.
  • Áp dụng map, filter, batched=True để preprocess dataset.
  • Split train/val, shuffle, save / load local, push lên Hub.
  • Load file local (CSV, JSON, Parquet) thành dataset object.
  • Convert sang torch.utils.data.DataLoader để feed vào training loop.
  • Tránh được các pitfall thường gặp: quên set_format("torch"), cache phình to, shuffle trên streaming.
2

Datasets library là gì

datasets là thư viện Python của Hugging Face cho phép load và xử lý dataset ML theo một API thống nhất. Mặc dù tên gắn với HF, thư viện này không chỉ phục vụ dataset trên Hub — nó còn load được file local (CSV, JSON, Parquet), URL, dataset Apache Arrow, v.v.

Bốn nhiệm vụ chính thư viện giải quyết:

  • Load: pull dataset từ Hub hoặc đọc file local thành object thống nhất.
  • Process: map / filter / shuffle / split — tất cả thực thi trên backend Arrow.
  • Share: save xuống disk hoặc push ngược lên Hub.
  • Stream: iterate dataset lớn hơn RAM mà không phải tải hết về.

Khi load model bằng transformers (Bài 16-18), thường bước tiếp theo là load dataset bằng datasets. Hai thư viện được thiết kế để dùng cùng nhau.

3

Cài đặt

pip install datasets

Cài kèm transformers cho hầu hết workflow:

pip install -U datasets transformers

Nếu cần audio / image: thêm pip install soundfile pillow. Nếu cần Parquet hoặc pandas interop: pyarrowpandas đã đi kèm datasets (không phải cài riêng).

4

Basic load

Cách đơn giản nhất là gọi load_dataset với tên dataset trên Hub:

from datasets import load_dataset

ds = load_dataset("imdb")
print(ds)
# DatasetDict({
#   'train': Dataset({features: ['text', 'label'], num_rows: 25000}),
#   'test':  Dataset({features: ['text', 'label'], num_rows: 25000}),
#   'unsupervised': Dataset({features: ['text', 'label'], num_rows: 50000}),
# })

Kết quả là một DatasetDict — dict các Dataset theo từng split. Truy cập theo key chuỗi: ds["train"], ds["test"].

5

Load 1 split cụ thể

Truyền tham số split= để bỏ qua các split không cần, tiết kiệm thời gian và disk:

train = load_dataset("imdb", split="train")
print(type(train))  # <class 'datasets.arrow_dataset.Dataset'>

Có thể slice ngay trong tham số: split="train[:1000]" hoặc split="train[80%:]". Cú pháp tiện cho thử nghiệm nhanh.

6

Inspect data

print(ds["train"][0])        # 1 example dạng dict
print(ds["train"].features)  # schema: {'text': Value('string'), 'label': ClassLabel(...)}
print(len(ds["train"]))      # số example
print(ds["train"].column_names)

Trước khi viết bất kỳ pipeline preprocess nào, luôn in features để biết tên trường và kiểu dữ liệu (string, int, ClassLabel, Sequence, Image, Audio…). Đây là bước người mới hay bỏ qua, sau đó sai khi viết hàm map.

7

Common datasets

Một số dataset hay gặp khi học hoặc benchmark:

  • GLUE — bộ benchmark NLU gồm nhiều task: SST-2 (sentiment), MNLI (NLI), QQP (paraphrase), QNLI, RTE… Load qua load_dataset("glue", "sst2").
  • SQuAD — Question Answering trên đoạn văn tiếng Anh (Stanford 2016, v2 năm 2018).
  • IMDB — phân loại sentiment review phim, 25K train + 25K test.
  • WikiText — corpus language modeling, bản 103 (~100M token) và 2.
  • CommonCrawl, C4 — pretrain corpus quy mô lớn (TB-scale).
  • Alpaca, ShareGPT, OpenOrca — dataset instruction tuning, dùng cho fine-tune chat (sẽ trở lại ở Bài 51).
  • HumanEval, MBPP — benchmark code generation Python.
  • MMLU, HellaSwag — benchmark đánh giá LLM (sẽ ở Bài 59).

Một số dataset (đặc biệt benchmark gated như MMLU bản đầy đủ) cần accept terms hoặc HF token tương tự gated model ở Bài 15.

8

Dataset multilingual

  • mC4 — phiên bản multilingual của C4, hỗ trợ trên 100 ngôn ngữ (gồm tiếng Việt). Pick subset theo language code: load_dataset("mc4", "vi").
  • OSCAR — corpus đa ngôn ngữ lọc từ CommonCrawl.
  • OpenSubtitles — phụ đề phim, hữu ích cho dialogue / translation parallel.
  • VietAI và các org Việt khác trên Hub publish dataset tiếng Việt: tóm tắt báo, sentiment, NER, translation. Tìm bằng filter language: vi trên huggingface.co/datasets.

Với tiếng Việt, kiểm tra kỹ chất lượng — corpus crawl thường có noise (HTML residue, tiếng nước ngoài lẫn, lặp). Trước khi train phải clean.

9

Streaming cho corpus TB

C4 hoặc mC4 nén còn vài TB. Tải toàn bộ là không thực tế cho phần lớn máy cá nhân. Giải pháp: streaming mode.

ds = load_dataset("c4", "en", streaming=True)

for example in ds["train"].take(5):
    print(example)

Khi streaming=True, kết quả là IterableDataset: không index theo position, không có len(), mỗi lần iterate sẽ kéo từng shard về và yield example. Có sẵn các operator .take(n), .skip(n), .map(fn), .filter(fn).

Tradeoff: không cần disk lớn, nhưng mất khả năng random access; shuffle chỉ shuffle theo buffer cố định.

10

Filter và Map

Filter giữ lại example thoả điều kiện:

filtered = ds["train"].filter(lambda x: len(x["text"]) > 100)
print(len(filtered))

Map transform mỗi example (hoặc batch example) thành record mới. Use case phổ biến là tokenize:

from transformers import AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained("bert-base-uncased")

def tokenize_fn(example):
    return tokenizer(example["text"], truncation=True, max_length=128)

ds_tokenized = ds["train"].map(tokenize_fn, batched=True)
print(ds_tokenized.column_names)
# ['text', 'label', 'input_ids', 'attention_mask', ...]

Hàm map trả về dict; key trùng tên sẽ ghi đè cột cũ, key mới sẽ thêm cột. Có thể remove_columns=["text"] nếu không cần raw text sau khi tokenize xong.

11

Batched processing

Khi gọi map(fn, batched=True), thư viện đưa nhiều example vào fn cùng lúc (mặc định 1000). Bên trong fn, mỗi cột là một list giá trị, không phải 1 giá trị đơn.

def batched_tokenize(examples):
    # examples["text"] là list[str]
    return tokenizer(examples["text"], truncation=True)

ds_tok = ds["train"].map(batched_tokenize, batched=True, batch_size=2000)

Lý do nên dùng batched=True: tokenizer fast (Rust backend) xử lý hàng nghìn câu trong một call nhanh hơn lặp từng câu nhiều lần. Tương tự cho mọi op có overhead per-call cao.

12

Train / val / test split

Dataset trên Hub có thể chỉ cho sẵn train + test. Khi cần thêm validation, dùng train_test_split:

split = ds["train"].train_test_split(test_size=0.1, seed=42)
train, val = split["train"], split["test"]
print(len(train), len(val))

Tham số seed giúp tái lập (reproducibility). stratify_by_column="label" giữ tỷ lệ class giữa train và val — hữu ích khi class imbalanced.

13

Shuffle

ds_shuffled = ds["train"].shuffle(seed=42)

Trên Dataset thường (Arrow), shuffle là full shuffle — toàn bộ index được hoán đổi. Trên IterableDataset (streaming), shuffle dùng buffer cố định:

ds_stream = load_dataset("c4", "en", streaming=True, split="train")
ds_stream = ds_stream.shuffle(seed=42, buffer_size=10_000)

Tăng buffer_size cho randomness tốt hơn, đổi lại tốn RAM thêm.

14

Select và slice

subset = ds["train"].select(range(100))   # 100 sample đầu, vẫn là Dataset
subset = ds["train"][:100]                # dict các cột, không phải Dataset

Phân biệt: select(indices) trả về một Dataset mới với chỉ các example được chọn, vẫn có thể tiếp tục map / filter / save. Slice [:100] trả về dict cột → list giá trị, dùng để inspect chứ không dùng để pipeline tiếp.

15

Save và load local

ds.save_to_disk("./my_dataset")

from datasets import load_from_disk
ds = load_from_disk("./my_dataset")

Sau khi đã preprocess xong (tokenize, filter, augment…), save_to_disk ghi ra Arrow format. Lần dùng sau chỉ cần load_from_disk — load gần như tức thì vì không phải chạy lại pipeline. Hữu ích cho training nhiều epoch hoặc nhiều thí nghiệm.

16

Push lên Hub

ds.push_to_hub("username/my-dataset")

Cần đã huggingface-cli login với token scope Write. Repo được tạo tự động nếu chưa tồn tại; mặc định public. Để private: push_to_hub("username/my-dataset", private=True).

Push xong nên vào web bổ sung dataset card (file README.md) mô tả: nguồn dữ liệu, license, schema cột, số lượng, cách sample, limitations.

17

Convert sang PyTorch DataLoader

from torch.utils.data import DataLoader

ds.set_format("torch", columns=["input_ids", "attention_mask", "label"])
loader = DataLoader(ds, batch_size=32, shuffle=True)

batch = next(iter(loader))
print(batch["input_ids"].shape)  # torch.Size([32, seq_len])

Sau khi set_format("torch", ...), mỗi lần index sẽ trả tensor PyTorch thay vì Python list. Tương tự có "numpy", "tensorflow", "jax", "pandas".

Có thể bỏ columns= để giữ tất cả; nhưng cột string (như raw text) không convert được sang tensor và sẽ gây lỗi khi DataLoader collate.

18

Custom dataset từ file local

ds = load_dataset("csv",     data_files="my.csv")
ds = load_dataset("json",    data_files="my.jsonl")
ds = load_dataset("parquet", data_files="my.parquet")

Có thể truyền dict để khai báo nhiều split:

ds = load_dataset(
    "csv",
    data_files={"train": "train.csv", "test": "test.csv"},
)

Cách này biến mọi nguồn dữ liệu local thành cùng API như dataset trên Hub — dùng được map / filter / save / push như nhau.

19

Dataset format

  • Arrow (default trong cache) — columnar in-memory format của Apache Arrow, memory-mapped, đọc nhanh, không phải parse mỗi lần.
  • Parquet — columnar on-disk, nén tốt, tương thích pandas / Spark / DuckDB. Hay dùng khi share dataset xuyên hệ thống.
  • JSON / JSONL — human-readable, dễ xem bằng editor, kích thước lớn, parse chậm hơn.
  • CSV — đơn giản, không có kiểu dữ liệu rõ, dễ lỗi khi có dấu phẩy / xuống dòng trong nội dung.

Với dataset internal có kích thước trung bình (vài GB), Parquet thường là lựa chọn cân bằng tốt giữa tốc độ và tính tương thích.

20

Cache

Khi gọi load_dataset("imdb") lần đầu, thư viện tải file gốc về và convert sang Arrow trong cache. Lần sau load tức thì từ cache, không gọi mạng.

Vị trí cache mặc định: ~/.cache/huggingface/datasets/. Có thể đổi qua biến môi trường HF_DATASETS_CACHE hoặc HF_HOME.

Pipeline map cũng có cache theo hash của hàm + input: nếu hàm không đổi, lần sau load sẽ dùng kết quả cũ. Khi sửa hàm map mà cache không invalidate đúng (vd closure capture biến ngoài), thêm load_from_cache_file=False để ép tính lại.

21

Combine datasets

from datasets import concatenate_datasets, interleave_datasets

combined = concatenate_datasets([ds1, ds2])
interleaved = interleave_datasets([ds1, ds2], probabilities=[0.7, 0.3])
  • concatenate_datasets: nối tuần tự — tất cả ds1, rồi tất cả ds2. Schema phải khớp.
  • interleave_datasets: trộn xen kẽ theo xác suất — hữu ích cho mixed pretrain (ví dụ 70% English + 30% Vietnamese) hoặc multi-task training.
22

Use case AI Engineer

  • Fine-tuning (Bài 51 trở đi): load dataset instruction (Alpaca, OpenOrca, dataset riêng) → tokenize bằng chat template → save_to_disk → đưa vào trl trainer.
  • Evaluation (Bài 59): load benchmark (MMLU, HellaSwag, HumanEval), iterate qua example, đẩy vào model, tính metric.
  • RAG (Bài 41): load corpus tài liệu (CSV / JSON / web crawl) → map qua chunker → embed → ghi vào vector DB.
  • Data labeling pipeline: load raw data từ file local → map qua LLM-as-labeler → push_to_hub bản đã có label.

Trong cả bốn case, API gần như giống nhau — chỉ khác hàm map cụ thể.

23

Memory-efficient processing

Cách giảm RAM khi data lớn:

  • Memory-mapped Arrow: Dataset đọc trực tiếp từ disk, chỉ load phần dùng tới. Tận dụng tự động khi save_to_disk / load_from_disk.
  • Streaming: dùng khi dataset lớn hơn disk hoặc chỉ muốn xem nhanh đầu/cuối.
  • Operator iter trên streaming: .take(n) lấy n đầu, .skip(n) bỏ n đầu, kết hợp được với .map().filter() theo lazy fashion.
  • Batch processing: map(batched=True) giảm overhead per-call; chỉ tăng batch_size trong giới hạn RAM cho phép.
24

Pitfall thường gặp

  • Quên set_format("torch") trước khi feed vào DataLoader → batch trả về dict các list Python, training loop sẽ lỗi khi gọi .to(device).
  • Cache phình to — load nhiều dataset / nhiều lần map khác nhau làm cache ngốn hàng chục GB. Định kỳ du -sh ~/.cache/huggingface/datasets/ kiểm tra; xoá manual nếu cần.
  • Shuffle trên streaming: chỉ là buffer shuffle, không phải full random. Với pretrain quy mô lớn, kết hợp tách shard ngẫu nhiên + buffer shuffle để xấp xỉ.
  • Map không batched trên tokenizer fast: chậm hơn batched 10-50 lần.
  • Forget remove_columns sau khi tokenize: cột text gốc vẫn còn, DataLoader collate fail vì list[str].
  • Schema mismatch khi concatenate_datasets: hai dataset phải cùng cột và cùng kiểu, nếu không phải cast trước.
25

Tổng kết Module 3

Module 3 gồm 6 bài, đi từ Hub đến code cụ thể:

  • Bài 15: Hugging Face Hub — repo model, dataset, Space.
  • Bài 16: transformers library — from_pretrained, kiến trúc thư viện.
  • Bài 17: Pipeline API — 1 dòng cho 1 task.
  • Bài 18: AutoModel / AutoTokenizer — control thấp hơn pipeline.
  • Bài 19: chạy SLM local — Phi-3, Llama-3.2-1B, Qwen 2.5 trên máy cá nhân.
  • Bài 20 (bài này): datasets library — load, preprocess, share dataset.

Sau Module 3, bạn có đủ công cụ để: load một model open + một dataset, tokenize và preprocess, chạy inference hoặc setup pipeline training cơ bản. Module 4 (Bài 21 trở đi) chuyển trọng tâm sang Prompt Engineering — cách giao tiếp với LLM (mở hoặc đóng) qua prompt có cấu trúc.

26

Code Python

Pipeline điển hình: load IMDB → inspect → tokenize → split → convert sang DataLoader.

from datasets import load_dataset
from transformers import AutoTokenizer
from torch.utils.data import DataLoader

# 1. Load và inspect
ds = load_dataset("imdb")
print(ds)
print(ds["train"][0])
print(ds["train"].features)

# 2. Tokenize (batched fast tokenizer)
tokenizer = AutoTokenizer.from_pretrained("bert-base-uncased")

def tokenize_fn(examples):
    return tokenizer(examples["text"], truncation=True, max_length=128)

ds_tok = ds["train"].map(
    tokenize_fn,
    batched=True,
    remove_columns=["text"],
)

# 3. Split train / val
split = ds_tok.train_test_split(test_size=0.1, seed=42)
train, val = split["train"], split["test"]

# 4. Convert sang DataLoader
train.set_format("torch", columns=["input_ids", "attention_mask", "label"])
val.set_format("torch",   columns=["input_ids", "attention_mask", "label"])

train_loader = DataLoader(train, batch_size=32, shuffle=True)
val_loader   = DataLoader(val,   batch_size=32)

batch = next(iter(train_loader))
print(batch["input_ids"].shape, batch["label"].shape)

Lưu ý: với batch chiều dài khác nhau, training thật cần DataCollatorWithPadding (xem docs Transformers). Đoạn trên giữ đơn giản, chỉ padding implicit khi truncation=True, max_length=128 chưa đủ — sẽ làm rõ ở Module 8 (fine-tuning).

27

Bài tập

Bài 1 — Load IMDB, đếm positive / negative. Load imdb, in features, đếm số example mỗi class trong split traintest. So sánh tỷ lệ — dataset có cân bằng không?

Bài 2 — Filter review dài. Trên split train, dùng filter giữ lại các review có len(text) > 200 ký tự. So sánh số lượng trước và sau filter. In 2 ví dụ minh hoạ.

Bài 3 — Tokenize và save. Tokenize train bằng bert-base-uncased với max_length=128, batched=True, remove_columns=["text"]. Save bằng save_to_disk("imdb_tokenized"). Load lại bằng load_from_disk và verify cùng số example.

Bài 4 — Load CSV của bạn. Tạo một file reviews.csv với 10 dòng, hai cột textlabel (0 hoặc 1). Load bằng load_dataset("csv", data_files="reviews.csv"). In features, num_rows, một example. Áp dụng cùng pipeline tokenize ở Bài 3.

Bài 5 (nâng cao) — Streaming C4. Load load_dataset("c4", "en", streaming=True, split="train"). Dùng .take(100) để lấy 100 example. Tính độ dài text trung bình. So sánh thời gian / RAM với cách load không streaming (nếu không có disk đủ, chỉ cần ghi nhận điều này).

28

Tóm tắt

  • datasets là thư viện chuẩn của Hugging Face để load, process, share dataset ML qua API thống nhất.
  • Cài đặt: pip install datasets. load_dataset(name) trả về DatasetDict theo split.
  • Có thể load 1 split bằng split="train" hoặc slice split="train[:1000]".
  • Inspect bằng features, column_names, len(); in luôn schema trước khi viết hàm map.
  • Dataset phổ biến: GLUE, SQuAD, IMDB, WikiText, C4, Alpaca, OpenOrca, HumanEval, MBPP, MMLU, HellaSwag.
  • Multilingual: mC4, OSCAR, OpenSubtitles, dataset tiếng Việt trên Hub.
  • Streaming (streaming=True) cho corpus TB; trả về IterableDataset không có random access.
  • map / filter để transform / lọc; batched=True nhanh hơn nhiều cho tokenizer fast.
  • train_test_split, shuffle, select để chia / xáo trộn / lấy subset.
  • save_to_disk + load_from_disk để cache pipeline đã preprocess; push_to_hub để chia sẻ.
  • Load file local: load_dataset("csv" | "json" | "parquet", data_files=...) — cùng API như dataset Hub.
  • Format on-disk: Arrow (default, memory-mapped), Parquet (compress + cross-tool), JSON / JSONL, CSV.
  • Cache mặc định ~/.cache/huggingface/datasets/; đổi qua HF_DATASETS_CACHE.
  • concatenate_datasets, interleave_datasets để gộp nhiều nguồn.
  • Convert sang DataLoader: set_format("torch", columns=...) rồi gói trong DataLoader.
  • Pitfall: quên set_format, cache phình, shuffle trên streaming, map không batched, schema mismatch khi concat.
  • Module 3 khép lại tại đây. Bài 21 mở Module 4 — Prompt Engineering: cách viết prompt có cấu trúc cho LLM.