Transformer实战——datasets库核心功能解析

0. 前言

在自然语言处理 (Natural Language Processing, NLP) 任务中,高效管理和处理数据是模型成功的关键。然而,面对海量的数据集、复杂的格式转换以及跨语言任务的挑战,传统的数据处理流程往往效率低下且难以扩展。Hugging Facedatasets 库简化了数据加载与缓存,还支持灵活的数据操作(如拆分、过滤、映射)以及与预训练模型的深度集成。无论是从社区共享的经典数据集(如 GLUEXTREME )中快速获取数据,还是对本地文件进行动态处理,datasets 库都能显著提升开发效率。

1. 使用 datasets 库加载数据集

datasets 库提供了一个非常高效的工具,能够加载、处理和通过 Hugging Face Hub 与社区共享数据集。与 TensorFlow datasets 类似,datasets 库使得用户能够轻松地下载、缓存和动态加载数据集。该库还提供了与数据相关的评估指标。实际上,Hugging Face Hub 并不持有或分发数据集,而是保留有关数据集的所有信息,包括所有者、预处理脚本、描述和下载链接。

(1) 首先,安装 datasets

$ pip install datasets

(2) 使用 Hugging Face Hub 自动加载 CoLA 数据集,datasets.load_dataset() 函数会在数据集未缓存时,从实际路径下载加载脚本:

from datasets import load_dataset
cola = load_dataset('glue', 'cola')
cola['train'][18:22]

使用以上代码,我们从 GLUE 基准中下载了 cola 数据集,并从其训练集中打印了几个示例样本如下:

{'sentence': ['They drank the pub.',
  'The professor talked us into a stupor.',
  'The professor talked us.',
  'We yelled ourselves hoarse.'],
 'label': [0, 1, 0, 1],
 'idx': [18, 19, 20, 21]}

需要注意的是,每次重新运行代码时,datasets 库会缓存加载和操作请求。它首先存储数据集,并开始缓存对数据集的操作,例如拆分、选择和排序,可能会看到类似 “reusing dataset xtreme (/home/.cache/huggingface/dataset...)” 或 “loading cached sorted...” 的警告消息。

(2) Hugging Face Hub上包含 19,298 个数据集和 116 个评估指标,并且仍在不断扩充:

from pprint import pprint
from huggingface_hub import list_datasets, list_metrics
all_d = list_datasets()
metrics = list_metrics()
print(f"{len(all_d)} datasets and {len(metrics)} metrics exist in the hub\n")
pprint(list(all)[:20], compact=True)
pprint(metrics, compact=True)

输出如下所示:

输出结果

一个数据集可能有多个配置。例如,GLUE 作为一个综合基准,包含许多子集,如 CoLASST-2MRPC 等。要访问某个 GLUE 基准数据集,需要传递两个参数,第一个是 “glue”,第二个是某个具体数据集的名称(例如 colasst2)。
数据集通常包含一个 DatasetDict 对象,其中包含多个 Dataset 实例。当使用 split='...' 参数时,可以获得具体的 Dataset 实例。例如,CoLA 数据集包含一个 DatasetDict,其拆分为 3 部分:train (训练集)、validation (验证集)和test(测试集)。其中,训练集和验证集包含两个标签(1表示可接受,0表示不可接受),而测试集的标签值为-1,表示没有标签。

(3) 接下来,查看 CoLA 数据集对象的结构:

cola = load_dataset('glue', 'cola')
print(cola)
cola['train'][12]
cola['validation'][68]
cola['test'][20]

输出如下所示:

输出结果

(4) 数据集对象还包含一些额外的元数据,包括拆分 (split)、描述 (description)、引用 (citation)、主页 (homepage)、许可 (license) 和信息 (info) 等:

print(cola["train"].description)
print(cola["train"].citation)
print(cola["train"].homepage)

(5) GLUE 基准提供了多个数据集,接下来,下载 MRPC 数据集:

mrpc = load_dataset('glue', 'mrpc')

(6) 要访问其他 GLUE 任务,可以修改第二个参数:

load_dataset('glue', 'XYZ')

(7) 为了进行数据可用性的初步检查,可以运行以下代码:

glue=['cola', 'sst2', 'mrpc', 'qqp', 'stsb', 'mnli', 'mnli_mismatched', 'mnli_matched', 'qnli', 'rte', 'wnli', 'ax']
for g in glue:
    _ = load_dataset('glue', g)

(8) XTREME 是另一个常用的跨语言数据集,接下来,从 XTREME 集合中选取 MLQA 示例。MLQAXTREME 基准的一个子集,旨在评估跨语言问答模型的性能。它包含约 5,000 个基于 SQuAD 格式的提取式问答实例,涵盖七种语言:英语、德语、阿拉伯语、印地语、越南语、西班牙语和简体中文。例如,MLQA.en.de 是一个英语-德语问答示例数据集:

en_de = load_dataset('xtreme', 'MLQA.en.de')
print(en_de)

加载后查看数据结构,输出结果如下:

输出结果

为了更方便地查看数据,可以将其转换为 pandas DataFrame 格式:

import pandas as pd
pd.DataFrame(en_de['test'][0:4])

输出结果如下:

输出结果

2. 使用 datasets 库处理数据

2.1 加载指定部分数据

数据集通常包含多个子集的字典,其中 split 参数用于决定加载哪个子集或子集的哪个部分。如果默认没有指定该参数(默认情况下为 None),它将返回一个包含所有子集(训练集、测试集、验证集或其他任意组合)的数据集字典。

(1) 如果指定了 split 参数,它将返回一个单个数据集而不是字典。例如,只获取 cola 数据集的训练集部分:

cola_train = load_dataset('glue', 'cola', split='train')

(2) 还可以获取训练集和验证集的混合部分:

cola_sel = load_dataset('glue', 'cola', split='train[:300]+validation[-30:]')

其中,split 表达式表示,从训练集中获取前300个样本,从验证集中获取最后30个样本,结果保存在 cola_sel 中。

(3) 还可以应用不同的组合方式:

  • 从训练集和验证集各获取前 100 个样本:
    split='train[:100]+validation[:100]'
    
  • 从训练集中获取前 50%,从验证集中获取后 30%
    split='train[:50%]+validation[-30%:]'
    
  • 从训练集中获取前 20%,从验证集中获取 [30:50] 范围内的样本:
    split='train[:20%]+validation[30:50]'
    

2.2 排序、索引和打乱数据

(2) 调用 cola_sel 对象的 sort() 函数,查看前 15 个和最后 15 个标签:

cola_sel.sort('label')['label'][:15]
cola_sel.sort('label')['label'][-15:]
# [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
# [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]

(2) 也可以使用切片表示法或通过索引列表来访问多行数据:

cola_sel[6, 19, 44]

输出结果如下:

{'sentence': ['Fred watered the plants flat.',
  'The professor talked us into a stupor.',
  'The trolley rumbled through the tunnel.'],
 'label': [1, 1, 1],
 'idx': [6, 19, 44]}

(3) 使用 shuffle() 方法打乱数据集:

cola_sel.shuffle()[2:5]

输出结果如下:

{'sentence': ['The chocolate melted onto the carpet.',
  'Herman hammered the metal flat.',
  'John made Bill master of himself.'],
 'label': [1, 1, 1],
 'idx': [94, 9, 1035]}

2.3 缓存与可重用性

使用缓存文件可以通过内存映射加载大规模数据集(如果数据集可以存放在磁盘中),并使用快速的后端进行操作。这种智能缓存有助于保存和重用已在硬盘上执行的操作结果。

(1) 查看与数据集相关的缓存日志,可以使用以下代码:

cola_sel.cache_files

输出结果如下,表明数据已经被缓存:

[{'filename': '/home/br/.cache/huggingface/datasets/glue/cola/0.0.0/bcdcba79d07bc864c1c254ccfcedcce55bcc9a8c/glue-train.arrow'},
 {'filename': '/home/br/.cache/huggingface/datasets/glue/cola/0.0.0/bcdcba79d07bc864c1c254ccfcedcce55bcc9a8c/glue-validation.arrow'}]

2.4 datasets 的 filter 和 map 函数

(1) 有时,我们需要对数据集进行特定选择。比如,可以从 cola 数据集中仅提取包含单词 “kick” 的句子。使用 datasets.Dataset.filter() 函数返回包含 “kick” 的句子,其中应用了匿名函数和 lambda 关键字:

cola_sel = load_dataset('glue', 'cola', split='train[:100%]+validation[-30%:]')
cola_sel.filter(lambda s: "kick" in s['sentence'])["sentence"][:3]

输出结果如下:

['Jill kicked the ball from home plate to third base.',
 'Fred kicked the ball under the porch.',
 'Fred kicked the ball behind the tree.']

(2) 通过 filter() 来获取正样本:

cola_sel.filter(lambda s: s['label'] == 1)["sentence"][:3]

输出结果如下:

["Our friends won't buy this analysis, let alone the next one we propose.",
 "One more pseudo generalization and I'm giving up.",
 "One more pseudo generalization or I'm giving up."]

(3) 在某些情况下,我们可能不知道类别标签的数值编码。假设有多个类别,可以通过 str2int() 函数来传递标签(如 acceptable),而不是直接使用数值编码:

cola_sel.filter(lambda s: s['label']== cola_sel.features['label'].str2int('acceptable'))["sentence"][:3]

输出结果如下所示:

["Our friends won't buy this analysis, let alone the next one we propose.",
 "One more pseudo generalization and I'm giving up.",
 "One more pseudo generalization or I'm giving up."]

(4) datasets.Dataset.map() 函数能够遍历数据集,将一个处理函数应用于数据集中的每个样本,并修改样本内容。例如,添加一个新的 ‘len’ 特征,用来表示句子的长度:

cola_new=cola_sel.map(lambda e:{'len': len(e['sentence'])})
pd.DataFrame(cola_new[0:3])

输出结果如下所示:

输出结果

(5) 或者,将句子截断至 20 个字符,这并不会创建一个新特征,而是直接更新 sentence 特征的内容:

cola_cut=cola_new.map(lambda e: {'sentence': e['sentence'][:20]+ '_'})
pd.DataFrame(cola_cut[:3])

输出结果如下所示:

输出结果

2.5 处理本地文件

为了从本地文件加载数据集(如 CSVTXTJSON 格式),我们将文件类型 (csvtextjson) 传递给通用的 load_dataset() 加载脚本,如下代码所示。在 ../data/ 文件夹下,有三个 CSV 文件 (a.csvb.csvc.csv),这些文件是从 SST-2 数据集中随机选择的简单样本。也可以加载单个文件,如数据对象 data1 所示,或者合并多个文件,如数据对象 data2,甚至可以对数据集进行拆分,如 data3 所示:

from datasets import load_dataset
data1 = load_dataset('csv', data_files='./data/a.csv', delimiter="\t")
data2 = load_dataset('csv', data_files=['./data/a.csv', './data/b.csv', './data/c.csv'], delimiter="\t")
data3 = load_dataset('csv', data_files={'train':['./data/a.csv', './data/b.csv'], 'test':['./data/c.csv']}, delimiter="\t")

为了加载其他格式的文件,可以将 csv 替换为 jsontext 等所需格式:

data_json = load_dataset('json', data_files='a.json')
data_text = load_dataset('text', data_files='a.txt')

我们已经讨论了如何加载、处理和操作托管在数据中心或存储在本地磁盘上的数据集。接下来,我们将学习如何准备数据集以进行 Transformer 模型的训练。

3. 为模型训练准备数据集

首先,从分词过程开始。每个模型都有自己独特的分词器,分词器会在实际语言模型训练之前进行训练。以下代码加载了来自预训练 distilBERT-base-uncased 模型的分词器,使用 map 和匿名函数 (lambda) 将分词器应用于 data3。如果 map 函数中的 batched 参数设置为 True,则会将一个批次的样本传递给分词器函数,默认情况下,batch_size 值为 1000,即每批次传递给函数的样本数。如果没有设置 batched 参数(默认情况下为 False),则整个数据集会作为一个批次传递给函数:

from transformers import AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained("distilbert-base-uncased")
encoded_data3 = data3.map(lambda e: tokenizer(e['sentence'], padding=True, truncation=True, max_length=12), batched=True, batch_size=1000)
print(data3)
print(encoded_data3)

输出结果如下所示,可以看到 data3encoded_data3 之间的区别,encoded_data3 中新增了两个特征——attention_maskinput_ids,并将其相应地添加到数据集中。简而言之,input_ids 是句子中每个 token 对应的索引,是 TransformerTrainer 类所需的特征:

输出结果

我们通常会一次传递多个句子(称为一个批次)给分词器,并将分词后的批数据进一步传递给模型。为此,将每个句子填充到该批次中最大句子的长度,或者填充到由 max_length 参数指定的特定最大长度,在本节中为 12。同时,将较长的句子截断以适应最大长度:

print(encoded_data3['test'][12])
# {'sentence': 'an extremely unpleasant film . ', 'label': 0, 'input_ids': [101, 2019, 5186, 16010, 2143, 1012, 102, 0, 0, 0, 0, 0], 'attention_mask': [1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0]}

小结

本文深入探讨了 Hugging Face datasets 库在 NLP 数据处理中的核心功能与应用场景,包括:

  • 快速访问数据集:从 Hugging Face Hub 加载 GLUEXTREME 等基准数据集,并通过缓存机制优化重复加载效率
  • 灵活操作数据:利用 split 参数实现复杂拆分逻辑,结合 shufflesortfiltermap 函数完成数据的动态调整与特征增强
  • 本地与多格式支持:处理本地 CSVJSON 等类型文件,并支持多文件合并与自定义拆分策略
  • 适配模型训练:通过集成 AutoTokenizer,将原始文本高效转换为模型输入,为下游任务提供标准化数据流

系列链接

Transformer实战——词嵌入技术详解
Transformer实战——循环神经网络详解
Transformer实战——从词袋模型到Transformer:NLP技术演进
Transformer实战——Hugging Face环境配置与应用详解
Transformer实战——Transformer模型性能评估

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

盼小辉丶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值