Datasets documentation
Stream
Stream
Dataset streaming cho phép bạn làm việc với một dataset mà không cần tải nó xuống. Dữ liệu được stream khi bạn lặp qua dataset. Điều này đặc biệt hữu ích khi:
- Bạn không muốn chờ đợi quá lâu để tải xuống một bộ dữ liệu cực kỳ lớn.
- Kích thước bộ dữ liệu vượt quá dung lượng ổ đĩa khả dụng trên máy tính của bạn.
- Bạn muốn nhanh chóng khám phá một vài mẫu của tập dữ liệu.

Ví dụ, phần chia tiếng Anh của bộ dữ liệu HuggingFaceFW/fineweb có dung lượng 45 terabyte, nhưng bạn có thể sử dụng nó ngay lập tức với streaming. Để stream một bộ dữ liệu, hãy đặt streaming=True trong load_dataset() như minh họa bên dưới:
>>> from datasets import load_dataset
>>> dataset = load_dataset('HuggingFaceFW/fineweb', split='train', streaming=True)
>>> print(next(iter(dataset)))
{'text': 'How AP reported in all formats from tornado-stricken regionsMarch 8, 2012\nWhen the first serious bout of tornadoes of 2012 blew through middle America in the middle of the night, they touched down in places hours from any AP bureau...', ...,
'language_score': 0.9721424579620361, 'token_count': 717}Dataset streaming cũng cho phép bạn làm việc với một dataset được tạo từ các tệp cục bộ mà không cần thực hiện bất kỳ bước chuyển đổi nào. Trong trường hợp này, dữ liệu sẽ được stream từ các tệp cục bộ khi bạn lặp qua dataset. Điều này đặc biệt hữu ích khi:
- Bạn không muốn chờ đợi một bộ dữ liệu cục bộ cực kỳ lớn được chuyển đổi sang định dạng Arrow.
- Kích thước của các tệp đã chuyển đổi sẽ vượt quá dung lượng ổ đĩa khả dụng trên máy tính của bạn.
- Bạn muốn nhanh chóng khám phá một vài mẫu của tập dữ liệu.
- Bạn muốn chỉ tải một số cột nhất định hoặc lọc hiệu quả một tập dữ liệu Parquet.
Ví dụ, bạn có thể stream một dataset cục bộ gồm hàng trăm tệp JSONL nén như oscar-corpus/OSCAR-2201 để sử dụng ngay lập tức:
>>> from datasets import load_dataset
>>> data_files = {'train': 'path/to/OSCAR-2201/compressed/en_meta/*.jsonl.gz'}
>>> dataset = load_dataset('json', data_files=data_files, split='train', streaming=True)
>>> print(next(iter(dataset)))
{'id': 0, 'text': 'Founded in 2015, Golden Bees is a leading programmatic recruitment platform dedicated to employers, HR agencies and job boards. The company has developed unique HR-custom technologies and predictive algorithms to identify and attract the best candidates for a job opportunity.', ...Parquet là định dạng cột cho phép bạn stream và nạp chỉ một tập con các cột, bỏ qua các cột không cần thiết. Parquet cũng lưu trữ metadata như thống kê cột (ở cấp độ tệp và nhóm hàng), cho phép lọc hiệu quả. Sử dụng các đối số columns và filters của datasets.packaged_modules.parquet.ParquetConfig để stream các dataset Parquet, chọn cột và áp dụng bộ lọc:
>>> from datasets import load_dataset
>>> dataset = load_dataset('HuggingFaceFW/fineweb', split='train', streaming=True, columns=["url", "date"])
>>> print(next(iter(dataset)))
{'url': 'http://%20jwashington@ap.org/Content/Press-Release/2012/How-AP-reported-in-all-formats-from-tornado-stricken-regions', 'date': '2013-05-18T05:48:54Z'}
>>> dataset = load_dataset('HuggingFaceFW/fineweb', split='train', streaming=True, filters=[("language_score", ">=", 0.99)])
>>> print(next(iter(dataset)))
{'text': 'Everyone wishes for something. And lots of people believe they know how to make their wishes come true with magical thinking.\nWhat is it? "Magical thinking is a belief in forms of causation, with no known physical basis," said Professor Emily Pronin of Princeton...', ...,
'language_score': 0.9900368452072144, 'token_count': 716}Việc tải một tập dữ liệu ở chế độ streaming tạo ra một instance của kiểu tập dữ liệu mới (thay vì đối tượng Dataset cổ điển), được gọi là IterableDataset. Kiểu tập dữ liệu đặc biệt này có bộ phương pháp xử lý riêng được hiển thị bên dưới.
Một IterableDataset hữu ích cho các tác vụ lặp lại như huấn luyện mô hình. Bạn không nên dùng IterableDataset cho các tác vụ yêu cầu truy cập ngẫu nhiên vào các ví dụ, vì bạn phải lặp qua toàn bộ tập dữ liệu bằng vòng lặp for. Để lấy ví dụ cuối cùng trong một tập dữ liệu dạng lặp, bạn sẽ phải lặp qua tất cả các ví dụ trước đó. Bạn có thể tìm thêm chi tiết trong hướng dẫn so sánh Dataset và IterableDataset.
Chỉ mục cột
Đôi khi, việc lặp qua các giá trị của một cột cụ thể là rất tiện lợi. May mắn thay, IterableDataset hỗ trợ chỉ mục cột:
>>> from datasets import load_dataset
>>> dataset = load_dataset("allenai/c4", "en", streaming=True, split="train")
>>> print(next(iter(dataset["text"])))
Beginners BBQ Class Taking Place in Missoula!...Chuyển đổi từ một Dataset
Nếu bạn đã có một đối tượng Dataset, bạn có thể chuyển đổi nó thành IterableDataset bằng hàm to_iterable_dataset(). Thực tế, cách này nhanh hơn việc đặt tham số streaming=True trong load_dataset() vì dữ liệu được stream từ các tệp cục bộ.
>>> from datasets import load_dataset
# faster 🐇
>>> dataset = load_dataset("ethz/food101")
>>> iterable_dataset = dataset.to_iterable_dataset()
# slower 🐢
>>> iterable_dataset = load_dataset("ethz/food101", streaming=True)Hàm to_iterable_dataset() hỗ trợ chia shard khi IterableDataset được khởi tạo. Điều này hữu ích khi làm việc với các bộ dữ liệu lớn, và bạn muốn xáo trộn bộ dữ liệu hoặc cho phép tải song song nhanh với PyTorch DataLoader.
>>> import torch
>>> from datasets import load_dataset
>>> dataset = load_dataset("ethz/food101")
>>> iterable_dataset = dataset.to_iterable_dataset(num_shards=64) # shard the dataset
>>> iterable_dataset = iterable_dataset.shuffle(buffer_size=10_000) # shuffles the shards order and use a shuffle buffer when you start iterating
dataloader = torch.utils.data.DataLoader(iterable_dataset, num_workers=4) # assigns 64 / 4 = 16 shards from the shuffled list of shards to each worker when you start iteratingXáo trộn
Giống như một đối tượng Dataset thông thường, bạn cũng có thể xáo trộn một IterableDataset bằng IterableDataset.shuffle().
Tham số buffer_size kiểm soát kích thước của bộ đệm để lấy mẫu ngẫu nhiên các ví dụ. Giả sử tập dữ liệu của bạn có một triệu ví dụ và bạn đặt buffer_size là mười nghìn. IterableDataset.shuffle() sẽ chọn ngẫu nhiên các ví dụ từ mười nghìn ví dụ đầu tiên trong bộ đệm. Các ví dụ đã được chọn trong bộ đệm sẽ được thay thế bằng các ví dụ mới. Mặc định, kích thước bộ đệm là 1.000.
>>> from datasets import load_dataset
>>> dataset = load_dataset('HuggingFaceFW/fineweb', split='train', streaming=True)
>>> shuffled_dataset = dataset.shuffle(seed=42, buffer_size=10_000)IterableDataset.shuffle() lấp đầy bộ đệm bằng cách sử dụng tối đa
max_buffer_input_shardsshard mỗi lần (mặc định là 10), điều này cải thiện đáng kể chất lượng của việc xáo trộn. Nó cũng xáo trộn thứ tự của các shard nếu tập dữ liệu được chia thành nhiều tệp.
Nếu bạn đang stream một dataset Parquet chỉ có một hoặc vài file, hãy dùng reshard() trước khi shuffle. Điều này hữu ích để chia dataset theo row group thay vì theo file, cải thiện chất lượng shuffle.
Xáo trộn
Đôi khi bạn có thể muốn xáo trộn lại bộ dữ liệu sau mỗi epoch. Điều này yêu cầu bạn đặt một seed khác nhau cho mỗi epoch. Hãy sử dụng IterableDataset.set_epoch() giữa các epoch để thông báo cho bộ dữ liệu bạn đang ở epoch nào.
Seed của bạn thực chất sẽ trở thành: initial seed + current epoch.
>>> for epoch in range(epochs):
... shuffled_dataset.set_epoch(epoch)
... for example in shuffled_dataset:
... ...Tách bộ dữ liệu
Bạn có thể chia bộ dữ liệu của mình theo một trong hai cách:
- IterableDataset.take() trả về
nví dụ đầu tiên trong một tập dữ liệu:
>>> dataset = load_dataset('HuggingFaceFW/fineweb', split='train', streaming=True)
>>> dataset_head = dataset.take(2)
>>> list(dataset_head)
[{'text': "How AP reported in all formats from tor...},
{'text': 'Did you know you have two little yellow...}]- IterableDataset.skip() bỏ qua
nví dụ đầu tiên trong một tập dữ liệu và trả về các ví dụ còn lại:
>>> train_dataset = shuffled_dataset.skip(1000)
takevàskipngăn các lần gọishuffletiếp theo vì chúng cố định thứ tự của các shard. Bạn nênshufflebộ dữ liệu trước khi chia nhỏ nó.
Shard
🤗 Datasets hỗ trợ sharding để chia một dataset rất lớn thành một số lượng chunk đã định trước. Chỉ định tham số num_shards trong shard() để xác định số shard cần chia dataset thành. Bạn cũng cần cung cấp shard muốn trả về bằng tham số index.
Ví dụ, bộ dữ liệu amazon_polarity có 4 shard (trong trường hợp này là 4 tệp Parquet):
>>> from datasets import load_dataset
>>> dataset = load_dataset("fancyzhx/amazon_polarity", split="train", streaming=True)
>>> print(dataset)
IterableDataset({
features: ['label', 'title', 'content'],
num_shards: 4
})Sau khi chia bộ dữ liệu thành hai phần, phần đầu tiên sẽ chỉ có 2 shard:
>>> dataset.shard(num_shards=2, index=0)
IterableDataset({
features: ['label', 'title', 'content'],
num_shards: 2
})Để tăng số lượng shard của một dataset, bạn có thể sử dụng IterableDataset.reshard():
>>> dataset.reshard()
IterableDataset({
features: ['label', 'title', 'content'],
num_shards: 3600
})Cơ chế resharding phụ thuộc vào định dạng tệp của dataset. Ví dụ, với Parquet, nó thực hiện resharding bằng cách sử dụng các nhóm hàng (row groups) thay vì tạo một tệp cho mỗi shard. Xem cách hoạt động cho mọi định dạng trong tài liệu của IterableDataset.reshard().
Nếu tập dữ liệu của bạn có dataset.num_shards==1 ngay cả sau khi resharding, bạn nên chia nhỏ nó bằng cách sử dụng IterableDataset.skip() và IterableDataset.take() thay vì cách khác.
Nối
Các tập dữ liệu riêng biệt có thể được nối với nhau nếu chúng có cùng kiểu cột. Nối các tập dữ liệu bằng concatenate_datasets():
>>> from datasets import concatenate_datasets, load_dataset
>>> stories = load_dataset("ajibawa-2023/General-Stories-Collection", split="train", streaming=True)
>>> stories = stories.select_columns(["text"]) # only keep the 'text' column
IterableDataset({
features: Unknown,
num_shards: 10
})
>>> wiki = load_dataset("wikimedia/wikipedia", "20231101.en", split="train", streaming=True)
>>> wiki = wiki.select_columns(["text"]) # only keep the 'text' column
IterableDataset({
features: ['text'],
num_shards: 41
})
>>> bert_dataset = concatenate_datasets([stories, wiki])
IterableDataset({
features: ['text'],
num_shards: 51
})Các shard của dataset được nối lại chính là các shard của các dataset đầu vào.
Bạn cũng có thể nối hai dataset theo chiều ngang bằng cách đặt axis=1 miễn là các dataset có cùng số dòng:
>>> from datasets import IterableDataset
>>> stories_ids = IterableDataset.from_dict({"ids": list(range(num_stories))})
>>> stories_with_ids = concatenate_datasets([stories, stories_ids], axis=1)Trong trường hợp này, bộ dữ liệu đã ghép chỉ có 1 shard, nhằm tránh việc kết thúc bằng các shard không căn đều từ các bộ dữ liệu đầu vào.
Xen kẽ
interleave_datasets() có thể kết hợp một IterableDataset với các dataset khác nếu chúng có cùng kiểu cột. Dataset kết hợp sẽ trả về các ví dụ xen kẽ từ mỗi dataset gốc.
>>> from datasets import interleave_datasets
>>> es_dataset = load_dataset('allenai/c4', 'es', split='train', streaming=True)
IterableDataset({
features: Unknown,
num_shards: 2048
})
>>> fr_dataset = load_dataset('allenai/c4', 'fr', split='train', streaming=True)
IterableDataset({
features: Unknown,
num_shards: 2048
})
>>> multilingual_dataset = interleave_datasets([es_dataset, fr_dataset])
IterableDataset({
features: ['text', 'timestamp', 'url'],
num_shards: 2048
})
>>> list(multilingual_dataset.take(2))
[{'text': 'Comprar Zapatillas para niña en chancla con goma por...'},
{'text': 'Le sacre de philippe ier, 23 mai 1059 - Compte Rendu...'}]Định nghĩa xác suất lấy mẫu từ mỗi tập dữ liệu gốc để kiểm soát tốt hơn cách lấy mẫu và kết hợp chúng. Đặt đối số probabilities với các xác suất lấy mẫu mong muốn của bạn:
>>> multilingual_dataset_with_oversampling = interleave_datasets([es_dataset, fr_dataset], probabilities=[0.8, 0.2], seed=42)
>>> list(multilingual_dataset_with_oversampling.take(2))
[{'text': 'Comprar Zapatillas para niña en chancla con goma por...'},
{'text': 'Chevrolet Cavalier Usados en Bogota - Carros en Vent...'}]Khoảng 80% bộ dữ liệu cuối cùng được tạo từ es_dataset, và 20% từ fr_dataset.
Bạn cũng có thể chỉ định stopping_strategy. Chiến lược mặc định, first_exhausted, là chiến lược lấy mẫu con, tức là việc xây dựng tập dữ liệu sẽ dừng lại ngay khi một trong các tập dữ liệu hết mẫu.
Bạn có thể chỉ định stopping_strategy=all_exhausted để thực thi chiến lược lấy mẫu quá mức. Trong trường hợp này, việc xây dựng tập dữ liệu sẽ dừng lại ngay khi mọi mẫu trong mọi tập dữ liệu đã được thêm vào ít nhất một lần. Trên thực tế, điều này có nghĩa là nếu một tập dữ liệu bị cạn, nó sẽ quay lại đầu tập dữ liệu đó cho đến khi đạt được tiêu chí dừng.
Lưu ý rằng nếu không chỉ định xác suất lấy mẫu, tập dữ liệu mới sẽ có max_length_datasets*nb_dataset samples.
Cũng có stopping_strategy=all_exhausted_without_replacement để đảm bảo rằng mỗi mẫu được xem đúng một lần.
Để đảm bảo song song hóa đúng cách bằng cách chia mảnh, các mảnh của tập dữ liệu xen kẽ chứa ít nhất 1 mảnh của mỗi tập dữ liệu đầu vào. Do đó, mức chia mảnh của tập dữ liệu xen kẽ là mức chia mảnh tối thiểu của các tập dữ liệu đầu vào.
Ví dụ, nếu các tập dữ liệu đầu vào lần lượt có 32, 48 và 128 shard, thì tập dữ liệu xen kẽ sẽ có 32 = min(32, 48, 128) shard, và mỗi shard mới sẽ có 1 shard từ tập dữ liệu đầu tiên, 1-2 shard từ tập dữ liệu thứ hai và 4 shard từ tập dữ liệu thứ ba.
Đổi tên, xóa và chuyển kiểu
Các phương thức sau cho phép bạn sửa đổi các cột của một dataset. Những phương thức này hữu ích để đổi tên hoặc xóa các cột và thay đổi các cột thành một tập hợp các đặc trưng mới.
Đổi tên
Sử dụng IterableDataset.rename_column() khi bạn cần đổi tên một cột trong dataset của mình. Các đặc trưng (features) liên quan đến cột gốc thực chất được chuyển sang dưới tên cột mới, thay vì chỉ thay thế cột gốc tại chỗ.
Cung cấp cho IterableDataset.rename_column() tên của cột gốc và tên cột mới:
>>> from datasets import load_dataset
>>> dataset = load_dataset('allenai/c4', 'en', streaming=True, split='train')
>>> dataset = dataset.rename_column("text", "content")Xóa
Khi cần xóa một hoặc nhiều cột, hãy truyền tên cột cần xóa cho IterableDataset.remove_columns(). Để xóa nhiều cột, hãy cung cấp một danh sách các tên cột:
>>> from datasets import load_dataset
>>> dataset = load_dataset('allenai/c4', 'en', streaming=True, split='train')
>>> dataset = dataset.remove_columns('timestamp')Cast
IterableDataset.cast() thay đổi kiểu đặc trưng của một hoặc nhiều cột. Phương thức này nhận Features mới của bạn làm đối số. Mã mẫu sau đây cho thấy cách thay đổi kiểu đặc trưng của ClassLabel và Value:
>>> from datasets import load_dataset
>>> dataset = load_dataset('nyu-mll/glue', 'mrpc', split='train', streaming=True)
>>> dataset.features
{'sentence1': Value('string'),
'sentence2': Value('string'),
'label': ClassLabel(names=['not_equivalent', 'equivalent']),
'idx': Value('int32')}
>>> from datasets import ClassLabel, Value
>>> new_features = dataset.features.copy()
>>> new_features["label"] = ClassLabel(names=['negative', 'positive'])
>>> new_features["idx"] = Value('int64')
>>> dataset = dataset.cast(new_features)
>>> dataset.features
{'sentence1': Value('string'),
'sentence2': Value('string'),
'label': ClassLabel(names=['negative', 'positive']),
'idx': Value('int64')}Casting chỉ hoạt động nếu kiểu đặc trưng gốc và kiểu đặc trưng mới tương thích. Ví dụ, bạn có thể cast một cột có kiểu đặc trưng
Value('int32')thànhValue('bool')nếu cột gốc chỉ chứa các giá trị một và không.
Sử dụng IterableDataset.cast_column() để thay đổi kiểu đặc trưng của chỉ một cột. Truyền tên cột và kiểu đặc trưng mới của nó dưới dạng các đối số:
>>> dataset.features
{'audio': Audio(sampling_rate=44100, mono=True)}
>>> dataset = dataset.cast_column("audio", Audio(sampling_rate=16000))
>>> dataset.features
{'audio': Audio(sampling_rate=16000, mono=True)}Bản đồ
Tương tự như hàm Dataset.map() cho một Dataset thông thường, 🤗 Datasets có IterableDataset.map() để xử lý một IterableDataset. IterableDataset.map() áp dụng xử lý theo thời gian thực khi các ví dụ được truyền trực tiếp.
Nó cho phép bạn áp dụng một hàm xử lý cho từng ví dụ trong một tập dữ liệu, độc lập hoặc theo lô. Hàm này thậm chí có thể tạo ra các hàng và cột mới.
Ví dụ sau minh họa cách thực hiện tokenize một IterableDataset. Hàm cần nhận và xuất ra một dict:
>>> def add_prefix(example):
... example['text'] = 'My text: ' + example['text']
... return exampleTiếp theo, áp dụng hàm này lên bộ dữ liệu bằng IterableDataset.map():
>>> from datasets import load_dataset
>>> dataset = load_dataset('allenai/c4', 'en', streaming=True, split='train')
>>> updated_dataset = dataset.map(add_prefix)
>>> list(updated_dataset.take(3))
[{'text': 'My text: Beginners BBQ Class Taking Place in Missoula!\nDo you want to get better at making...',
'timestamp': '2019-04-25 12:57:54',
'url': 'https://klyq.com/beginners-bbq-class-taking-place-in-missoula/'},
{'text': 'My text: Discussion in \'Mac OS X Lion (10.7)\' started by axboi87, Jan 20, 2012.\nI\'ve go...',
'timestamp': '2019-04-21 10:07:13',
'url': 'https://forums.macrumors.com/threads/restore-from-larger-disk-to-smaller-disk.1311329/'},
{'text': 'My text: Foil plaid lycra and spandex shortall with metallic slinky insets. Attached metall...',
'timestamp': '2019-04-25 10:40:23',
'url': 'https://awishcometrue.com/Catalogs/Clearance/Tweens/V1960-Find-A-Way'}]Hãy xem một ví dụ khác, lần này bạn sẽ xóa các cột bằng IterableDataset.map(). Khi bạn xóa một cột, nó chỉ bị xóa sau khi ví dụ đã được cung cấp cho hàm được map. Điều này cho phép hàm được map sử dụng nội dung của các cột trước khi chúng bị xóa.
Chỉ định cột cần xóa bằng đối số remove_columns trong IterableDataset.map():
>>> updated_dataset = dataset.map(add_prefix, remove_columns=["timestamp", "url"])
>>> list(updated_dataset.take(3))
[{'text': 'My text: Beginners BBQ Class Taking Place in Missoula!\nDo you want to get better at making...'},
{'text': 'My text: Discussion in \'Mac OS X Lion (10.7)\' started by axboi87, Jan 20, 2012.\nI\'ve go...'},
{'text': 'My text: Foil plaid lycra and spandex shortall with metallic slinky insets. Attached metall...'}]Xử lý theo lô
IterableDataset.map() cũng hỗ trợ làm việc với các lô (batch) ví dụ. Để thao tác trên các lô, hãy đặt batched=True. Kích thước lô mặc định là 1000, nhưng bạn có thể điều chỉnh bằng tham số batch_size. Điều này mở ra nhiều ứng dụng thú vị như tokenization, chia các câu dài thành các đoạn ngắn hơn và tăng cường dữ liệu.
Tokenization
>>> from datasets import load_dataset
>>> from transformers import AutoTokenizer
>>> dataset = load_dataset("allenai/c4", "en", streaming=True, split="train")
>>> tokenizer = AutoTokenizer.from_pretrained('distilbert-base-uncased')
>>> def encode(examples):
... return tokenizer(examples['text'], truncation=True, padding='max_length')
>>> dataset = dataset.map(encode, batched=True, remove_columns=["text", "timestamp", "url"])
>>> next(iter(dataset))
{'input_ids': [101, 4088, 16912, 22861, 4160, 2465, 2635, 2173, 1999, 3335, ..., 0, 0, 0],
'attention_mask': [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ..., 0, 0]}Xem các ví dụ khác về xử lý theo lô trong tài liệu xử lý map theo lô. Chúng hoạt động tương tự với các tập dữ liệu dạng lặp.
Bộ lọc
Bạn có thể lọc các dòng trong bộ dữ liệu dựa trên một hàm điều kiện bằng cách sử dụng Dataset.filter(). Hàm này trả về các dòng khớp với điều kiện được chỉ định:
>>> from datasets import load_dataset
>>> dataset = load_dataset('HuggingFaceFW/fineweb', streaming=True, split='train')
>>> start_with_ar = dataset.filter(lambda example: example['text'].startswith('San Francisco'))
>>> next(iter(start_with_ar))
{'text': 'San Francisco 49ers cornerback Shawntae Spencer will miss the rest of the sea...}Dataset.filter() cũng có thể lọc theo chỉ mục nếu bạn đặt with_indices=True:
>>> even_dataset = dataset.filter(lambda example, idx: idx % 2 == 0, with_indices=True)
>>> list(even_dataset.take(3))
[{'text': 'How AP reported in all formats from tornado-stricken regionsMarch 8, 2012 Whe...},
{'text': 'Car Wash For Clara! Now is your chance to help! 2 year old Clara Woodward has...},
{'text': 'Log In Please enter your ECode to log in. Forgotten your eCode? If you create...}]Batch
Phương thức batch biến đổi IterableDataset của bạn thành một đối tượng lặp được chứa các lô (batch). Điều này đặc biệt hữu ích khi bạn muốn làm việc với các lô trong vòng lặp huấn luyện hoặc khi sử dụng các framework yêu cầu đầu vào dạng lô.
Ngoài ra, còn có tùy chọn “Batch Processing” khi sử dụng hàm
mapđể áp dụng một hàm lên các lô dữ liệu, được thảo luận trong phần Map ở trên. Phương thứcbatchđược mô tả ở đây khác biệt và cung cấp cách trực tiếp hơn để tạo các lô từ tập dữ liệu của bạn.
Bạn có thể sử dụng phương thức batch như sau:
from datasets import load_dataset
# Load a dataset in streaming mode
dataset = load_dataset("some_dataset", split="train", streaming=True)
# Create batches of 32 samples
batched_dataset = dataset.batch(batch_size=32)
# Iterate over the batched dataset
for batch in batched_dataset:
print(batch)
breakTrong ví dụ này, batched_dataset vẫn là một IterableDataset, nhưng mỗi phần tử được trả về giờ đây là một batch gồm 32 mẫu thay vì một mẫu đơn lẻ. Việc phân batch này được thực hiện theo thời gian thực khi bạn lặp qua dataset, giữ nguyên đặc tính tiết kiệm bộ nhớ của IterableDataset.
Phương thức batch cũng cung cấp tham số drop_last_batch. Khi được đặt thành True, nó sẽ loại bỏ batch cuối cùng nếu kích thước của nó nhỏ hơn batch_size được chỉ định. Điều này có thể hữu ích trong các kịch bản mà xử lý phía sau của bạn yêu cầu tất cả các batch phải có cùng kích thước:
batched_dataset = dataset.batch(batch_size=32, drop_last_batch=True)Dòng chảy trong vòng lặp huấn luyện
IterableDataset có thể được tích hợp vào vòng lặp huấn luyện. Trước tiên, hãy xáo trộn bộ dữ liệu:
>>> seed, buffer_size = 42, 10_000
>>> dataset = dataset.shuffle(seed, buffer_size=buffer_size)Cuối cùng, tạo một vòng lặp huấn luyện đơn giản và bắt đầu huấn luyện:
>>> import torch
>>> from torch.utils.data import DataLoader
>>> from transformers import AutoModelForMaskedLM, DataCollatorForLanguageModeling
>>> from tqdm import tqdm
>>> dataset = dataset.with_format("torch")
>>> dataloader = DataLoader(dataset, collate_fn=DataCollatorForLanguageModeling(tokenizer))
>>> device = 'cuda' if torch.cuda.is_available() else 'cpu'
>>> model = AutoModelForMaskedLM.from_pretrained("distilbert-base-uncased")
>>> model.train().to(device)
>>> optimizer = torch.optim.AdamW(params=model.parameters(), lr=1e-5)
>>> for epoch in range(3):
... dataset.set_epoch(epoch)
... for i, batch in enumerate(tqdm(dataloader, total=5)):
... if i == 5:
... break
... batch = {k: v.to(device) for k, v in batch.items()}
... outputs = model(**batch)
... loss = outputs[0]
... loss.backward()
... optimizer.step()
... optimizer.zero_grad()
... if i % 10 == 0:
... print(f"loss: {loss}")Lưu điểm kiểm tra của bộ dữ liệu và tiếp tục lặp
Nếu vòng lặp huấn luyện của bạn bị dừng, bạn có thể muốn khởi động lại quá trình huấn luyện từ vị trí đã dừng. Để làm điều này, bạn có thể lưu một checkpoint của mô hình và các optimizer, cũng như data loader của bạn.
Các tập dữ liệu dạng lặp (iterable) không cung cấp khả năng truy cập ngẫu nhiên vào một chỉ mục ví dụ cụ thể để tiếp tục từ đó, nhưng bạn có thể sử dụng IterableDataset.state_dict() và IterableDataset.load_state_dict() để tiếp tục từ một checkpoint, tương tự như cách bạn có thể làm với các mô hình và bộ tối ưu hóa:
>>> iterable_dataset = Dataset.from_dict({"a": range(6)}).to_iterable_dataset(num_shards=3)
>>> for idx, example in enumerate(iterable_dataset):
... print(example)
... if idx == 2:
... state_dict = iterable_dataset.state_dict()
... print("checkpoint")
... break
>>> iterable_dataset.load_state_dict(state_dict)
>>> print(f"restart from checkpoint")
>>> for example in iterable_dataset:
... print(example)Trả về:
{'a': 0}
{'a': 1}
{'a': 2}
checkpoint
restart from checkpoint
{'a': 3}
{'a': 4}
{'a': 5}Bên trong, tập dữ liệu dạng lặp (iterable dataset) theo dõi shard hiện đang được đọc và chỉ mục của ví dụ trong shard hiện tại, sau đó lưu trữ thông tin này trong state_dict.
Để khôi phục từ một checkpoint, dataset sẽ bỏ qua tất cả các shard đã được đọc trước đó để bắt đầu lại từ shard hiện tại. Sau đó, nó đọc shard và bỏ qua các ví dụ cho đến khi đạt đến đúng ví dụ từ checkpoint.
Do đó, việc khởi động lại một dataset khá nhanh, vì nó sẽ không đọc lại các shard đã được lặp qua. Tuy nhiên, việc tiếp tục một dataset thường không diễn ra tức thì, vì nó phải bắt đầu đọc lại từ đầu shard hiện tại và bỏ qua các ví dụ cho đến khi đạt đến vị trí checkpoint.
Điều này có thể được sử dụng cùng với StatefulDataLoader từ torchdata:
>>> from torchdata.stateful_dataloader import StatefulDataLoader
>>> iterable_dataset = load_dataset("deepmind/code_contests", streaming=True, split="train")
>>> dataloader = StatefulDataLoader(iterable_dataset, batch_size=32, num_workers=4)
>>> # checkpoint
>>> state_dict = dataloader.state_dict() # uses iterable_dataset.state_dict() under the hood
>>> # resume from checkpoint
>>> dataloader.load_state_dict(state_dict) # uses iterable_dataset.load_state_dict() under the hoodViệc tiếp tục sẽ quay lại đúng vị trí mà checkpoint đã được lưu, ngoại trừ khi sử dụng
.shuffle(): các mẫu trong bộ đệm shuffle sẽ bị mất khi tiếp tục và các bộ đệm sẽ được nạp lại bằng dữ liệu mới.
Lưu
Khi bộ dữ liệu lặp (iterable dataset) của bạn đã sẵn sàng, bạn có thể lưu nó dưới dạng Hugging Face Dataset ở định dạng Parquet và sử dụng lại sau này với load_dataset().
Lưu dataset của bạn bằng cách cung cấp tên kho dataset trên Hugging Face mà bạn muốn lưu vào dưới dạng đối số cho push_to_hub(). Thao tác này sẽ lặp qua dataset và tải dần dữ liệu lên Hugging Face:
dataset.push_to_hub("username/my_dataset")Mặc định, IterableDataset.push_to_hub() ghi dataset.num_shards tệp. Đặt num_shards để chọn một số lượng khác. Với nhiều shard đầu ra hơn dataset.num_shards, mỗi shard đầu vào được phân bố trên nhóm shard đầu ra riêng của nó bằng cách ghi các ví dụ của nó vào chúng theo kiểu round-robin, trong một lần quét duy nhất trên dữ liệu. Nếu có ít ví dụ hơn số shard được yêu cầu, các shard còn lại sẽ là các tệp Parquet rỗng.
Nếu tập dữ liệu gồm nhiều shard (dataset.num_shards > 1), bạn có thể sử dụng nhiều tiến trình để tải lên song song. Điều này đặc biệt hữu ích nếu bạn đã áp dụng các bước map() hoặc filter() vì chúng sẽ chạy nhanh hơn khi chạy song song:
dataset.push_to_hub("username/my_dataset", num_proc=8)Sử dụng hàm load_dataset() để tải lại bộ dữ liệu:
from datasets import load_dataset
reloaded_dataset = load_dataset("username/my_dataset")Xuất
🤗 Datasets hỗ trợ xuất dữ liệu để bạn có thể làm việc với bộ dữ liệu của mình trong các ứng dụng khác. Bảng dưới đây liệt kê các định dạng tệp hiện được hỗ trợ để xuất:
| Loại tệp | Phương thức xuất |
|---|---|
| CSV | IterableDataset.to_csv() |
| JSON | IterableDataset.to_json() |
| Parquet | IterableDataset.to_parquet() |
| SQL | IterableDataset.to_sql() |
| Đối tượng Python trong bộ nhớ | IterableDataset.to_pandas(), IterableDataset.to_polars() or IterableDataset.to_dict() |
Ví dụ, xuất bộ dữ liệu của bạn ra tệp CSV như sau:
>>> dataset.to_csv("path/of/my/dataset.csv")Nếu bạn có một bộ dữ liệu lớn, bạn có thể lưu một tệp cho mỗi shard, ví dụ
>>> num_shards = dataset.num_shards
>>> for index in range(num_shards):
... shard = dataset.shard(index, num_shards)
... shard.to_parquet(f"path/of/my/dataset/data-{index:05d}.parquet")