Mục lục
- Mục tiêu bài học
- Datasets library là gì
- Cài đặt
- Basic load
- Load 1 split cụ thể
- Inspect data
- Common datasets
- Dataset multilingual
- Streaming cho corpus TB
- Filter và Map
- Batched processing
- Train / val / test split
- Shuffle
- Select và slice
- Save và load local
- Push lên Hub
- Convert sang PyTorch DataLoader
- Custom dataset từ file local
- Dataset format
- Cache
- Combine datasets
- Use case AI Engineer
- Memory-efficient processing
- Pitfall thường gặp
- Tổng kết Module 3
- Code Python
- Bài tập
- Tóm tắt
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.
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.
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: pyarrow và pandas đã đi kèm datasets (không phải cài riêng).
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"].
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.
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.
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.
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: vitrênhuggingface.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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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
trltrainer. - 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ể.
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 khisave_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()và.filter()theo lazy fashion. - Batch processing:
map(batched=True)giảm overhead per-call; chỉ tăngbatch_sizetrong giới hạn RAM cho phép.
Pitfall thường gặp
- Quên
set_format("torch")trước khi feed vàoDataLoader→ 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_columnssau 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ảicasttrước.
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:
transformerslibrary —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):
datasetslibrary — 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.
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).
Bài tập
Bài 1 — Load IMDB, đếm positive / negative. Load imdb, in features, đếm số example mỗi class trong split train và test. 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 text và label (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).
Tóm tắt
datasetslà 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ềDatasetDicttheo split. - Có thể load 1 split bằng
split="train"hoặc slicesplit="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ềIterableDatasetkhông có random access. map/filterđể transform / lọc;batched=Truenhanh 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 quaHF_DATASETS_CACHE. concatenate_datasets,interleave_datasetsđể gộp nhiều nguồn.- Convert sang
DataLoader:set_format("torch", columns=...)rồi gói trongDataLoader. - 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.
- Hugging Face Datasets - Documentation
- Datasets - Loading
- Datasets - Process (map, filter, split)
- Datasets - Stream
- Datasets - Use with PyTorch
- Datasets - Share a dataset (push_to_hub)
- Datasets - Cache management
- Hugging Face Datasets Hub
- IMDB dataset trên Hub
- GLUE benchmark trên Hub
- SQuAD dataset trên Hub
- WikiText dataset trên Hub
- C4 dataset trên Hub
- mC4 (multilingual C4) trên Hub
- OSCAR corpus trên Hub
- Alpaca instruction dataset
- OpenOrca dataset
- HumanEval benchmark
- MMLU benchmark
- HellaSwag benchmark
- Apache Arrow Columnar Format
- PyTorch torch.utils.data
