数据预处理¶
在本教程中,我们将指导您准备train数据集。
为了预处理数据集,有两种可用的方法:
*原生MindSpore Dataset API
*修改 BaseMapFunction api in mindnlp
虽然原生MindSpore方法可以使您更加灵活,但 BaseMapFunction 方法有助于包装代码以获得更好的可读性。
此外,在上升或GPU环境中工作会带来处理过程的细微差异,这主要是由于动态形状的不同处理。 我们会在进行时看到它。
加载并拆分数据集¶
首先,从HuggingFace存储库中加载数据集:
from mindnlp import load_dataset
imdb_ds = load_dataset('imdb', split=['train', 'test'])
imdb_train = imdb_ds['train']
imdb_test = imdb_ds['test']
load_dataset 接受一个数据集名称,用于从拥抱面积存储库中远程获取,以及指向存储在磁盘上的数据集的本地路径。
这 split 参数告知 load_dataset 获取数据集的哪个分配。 在这里,它将获取train数据集(“火车”)和测试数据集(“测试”)。
要进一步将train数据集分为train和验证数据集,请使用 .split() 方法。 数字列表指定了每个拆分的数据条目的比例。
imdb_train, imdb_val = imdb_train.split([0.7, 0.3])
要查看数据集的外观,请从数据集的迭代器中获取第一个元素:
print(next(imdb_train.create_dict_iterator()))
加载令牌¶
令牌器将原始文本转换为相应模型可以处理的格式,这对于自然语言处理任务至关重要。
我们利用 AutoTokenizer 从MindNLP到获取并实例化适当的令牌以作为预先训练的模型:
from mindnlp.transformers import AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained('bert-base-cased')
要获取相应的令牌,您可以提供模型名称,在这种情况下 'bert-base-cased',到 AutoTokenizer.from_pretrained 方法。 然后,它将下载您的模型所需的令牌。
与原生MindSpore的预处理¶
为了用本机思维孔预处理数据集,我们编写一个函数 process_dataset 这包括关键步骤:
import mindspore
import numpy as np
from mindspore.dataset import GeneratorDataset, transforms
def process_dataset(dataset: GeneratorDataset, tokenizer, max_seq_len=256, batch_size=32, shuffle=False, take_len=None):
is_ascend = mindspore.get_context('device_target') == 'Ascend'
# The tokenize function
def tokenize(text):
if is_ascend:
tokenized = tokenizer(text, padding='max_length', truncation=True, max_length=max_seq_len)
else:
tokenized = tokenizer(text, truncation=True, max_length=max_seq_len)
return tokenized['input_ids'], tokenized['token_type_ids'], tokenized['attention_mask']
# Shuffle the order of the dataset
if shuffle:
dataset = dataset.shuffle(buffer_size=batch_size)
# Select the first several entries of the dataset
if take_len:
dataset = dataset.take(take_len)
# Apply the tokenize function, transforming the 'text' column into the three output columns generated by the tokenizer.
dataset = dataset.map(operations=[tokenize], input_columns="text", output_columns=['input_ids', 'token_type_ids', 'attention_mask'])
# Cast the datatype of the 'label' column to int32 and rename the column to 'labels'
dataset = dataset.map(operations=transforms.TypeCast(mindspore.int32), input_columns="label", output_columns="labels")
# Batch the dataset with padding.
if is_ascend:
dataset = dataset.batch(batch_size)
else:
dataset = dataset.padded_batch(batch_size, pad_info={'input_ids': (None, tokenizer.pad_token_id),
'token_type_ids': (None, 0),
'attention_mask': (None, 0)})
return dataset
这是每个步骤的分解: *####Tokenization 第一步是Tokenization。 Tokenization将原始文本转换为可以馈入机器学习模型的格式。
定义令牌函数以处理数据集的每一行中的文本。
def tokenize(text):
tokenized = tokenizer(text, truncation=True, max_length=max_seq_len)
return tokenized['input_ids'], tokenized['token_type_ids'], tokenized['attention_mask']
然后利用 GeneratorDataset.map 来自Mindspore的API将Tokenization操作映射到数据集中的所有行。 这将采用 "text" 列作为输入,将其引起并返回 "input_ids","token_type_ids" 和 "attention_mask" 列作为输出。
dataset = dataset.map(operations=[tokenize], input_columns="text", output_columns=['input_ids', 'token_type_ids', 'attention_mask'])
*####类型铸造
在某些情况下,需要将列的数据类型投放到另一个。 在这里,"label" 我们数据集中的列最初是类型的 Int64。 我们使用 mindspore.dataset.transform 将数据类型投入到 Int32。 然后将此操作映射到 "label" 柱子。
注意 output_columns 与名称 "labels",而不是 "label" 因此,在映射后,我们将专栏重命名为新名称。
from mindspore.dataset import transforms
dataset = dataset.map(operations=transforms.TypeCast(mindspore.int32), input_columns="label", output_columns="labels")
*####改组
改组数据集条目的顺序对于确保模型不学习数据的顺序很重要,这可能导致过度拟合。 用 shuffle 方法:
dataset = dataset.shuffle(buffer_size=batch_size)
*####用填充物进行批处理
为了促进模型中的批处理处理,我们将分组每个 batch_size 排成一批。 批处理自然语言数据集的特殊要求是确保批次中的所有序列的长度相同。 这是通过填充来实现的,其中包括 padded_batch 方法。
dataset = dataset.padded_batch(batch_size, pad_info={'input_ids': (None, tokenizer.pad_token_id),
'token_type_ids': (None, 0),
'attention_mask': (None, 0)})
padded_batch 仅在支持张量的动态形状的GPU平台上工作。 如果您正在与Ascend合作,则需要使用 batch 方法:
is_ascend = mindspore.get_context('device_target') == 'Ascend' # Check whether the platform is Ascend
if is_ascend:
dataset = dataset.batch(batch_size)
*####取子集
有时,您可能需要在较小的数据子集上进行训练或测试,例如调试train过程。 为此,请使用 take 方法,选择指定的编号( take_len 数据集的条目:
dataset = dataset.take(take_len)
现在,将预处理功能应用于数据集:
batch_size = 4 # Size of each batch
processed_dataset_train = process_dataset(imdb_train, tokenizer, batch_size=batch_size, shuffle=True)
检查处理后的数据集:
print(next(processed_dataset_train.create_dict_iterator()))
与 BaseMapFunction¶
预处理数据集进行train的另一种方法是通过 BaseMapFunction 来自Mindnlp。 您可以修改 BaseMapFunction 创建您的映射功能:
import mindspore as ms
from mindnlp.dataset import BaseMapFunction
class ModifiedMapFunction(BaseMapFunction):
def __call__(self, text, label):
tokenized = tokenizer(text, max_length=512, padding='max_length', truncation=True)
labels = label.astype(ms.int32)
return tokenized['input_ids'], tokenized['token_type_ids'], tokenize['attention_mask'], labels
map_fn = ModifiedMapFunction(['text', 'label'], ['input_ids', 'token_type_ids', 'attention_mask', 'labels'])
修改的地图功能将从每个条目中获取文本和标签 Int32 并输出input_ids,token_type_ids,activation_mask和标签。
请注意,仅当映射函数实例化时,仅定义输入和输出列的名称。
您可能会注意到地图功能不涉及批处理操作。 这是因为 Trainer 类提供内部批处理功能,可以通过设置 per_device_train_batch_size 参数 TrainingArgument 目的。
现在让我们通过 map_fn 进入 Trainer 以及其他论点:
from mindnlp.engine import Trainer, TrainingArguments
from mindnlp.transformers import AutoModelForSequenceClassification
model = AutoModelForSequenceClassification.from_pretrained('bert-base-cased', num_labels=2)
training_args = TrainingArguments(
output_dir='../../output',
per_device_train_batch_size=16
)
trainer = Trainer(
model=model,
args=training_args,
train_dataset=imdb_train,
map_fn=map_fn,
)