1、要求
2、导入了一些必要的库和模块
以便在使用MindSpore和MindNLP进行深度学习任务时能使用各种功能,比如数据集处理、模型训练、评估和回调功能。
import os # 导入操作系统相关功能的模块,如文件和目录操作
import mindspore # 导入MindSpore库,这是一个深度学习框架
from mindspore.dataset import text, GeneratorDataset, transforms # 从MindSpore的数据集模块导入处理文本、生成数据集和变换功能
from mindspore import nn # 从MindSpore库导入神经网络模块
from mindnlp.dataset import load_dataset # 从MindNLP库导入加载数据集的功能
from mindnlp._legacy.engine import Trainer, Evaluator # 从MindNLP库的旧版本引擎模块导入训练器和评估器
from mindnlp._legacy.engine.callbacks import CheckpointCallback, BestModelCallback # 导入旧版本引擎模块的回调功能,用于检查点保存和最佳模型保存
from mindnlp._legacy.metrics import Accuracy # 从MindNLP库的旧版本指标模块导入准确率指标
3、加载IMDB数据集
并将其分为训练集和测试集。load_dataset
函数会返回一个包含数据集各个部分的字典,然后你可以通过键 'train'
和 'test'
来访问相应的数据。
imdb_ds = load_dataset('imdb', split=['train', 'test']) # 加载IMDB数据集,并将数据集分为训练集和测试集,返回一个包含两个部分的字典
imdb_train = imdb_ds['train'] # 从字典中提取训练集数据
imdb_test = imdb_ds['test'] # 从字典中提取测试集数据
4、获取训练集数据集大小
get_dataset_size()
用于返回数据集中包含的样本数量。这个方法的返回值通常是一个整数,表示训练集中有多少个样本。
imdb_train.get_dataset_size() # 获取训练集数据集中样本的数量
5、定义一个用于处理数据集的函数 process_dataset
。
将输入文本数据进行tokenization,并根据设备类型选择不同的批处理方式。如果需要,还可以对数据集进行打乱和批处理。
import numpy as np # 导入NumPy库,用于数值计算和数组操作
def process_dataset(dataset, tokenizer, max_seq_len=512, batch_size=4, shuffle=False):
# 定义处理数据集的函数,接受数据集、tokenizer、最大序列长度、批量大小和是否打乱数据集作为参数
is_ascend = mindspore.get_context('device_target') == 'Ascend'
# 检查当前设备是否为Ascend(华为的深度学习处理器),根据设备类型选择不同的tokenizer处理方式
def tokenize(text):
# 定义tokenize函数,用于对文本进行tokenization
if is_ascend:
# 如果在Ascend设备上,使用'padding'和'truncation'进行tokenization
tokenized = tokenizer(text, padding='max_length', truncation=True, max_length=max_seq_len)
else:
# 否则只进行'truncation'和设置最大长度
tokenized = tokenizer(text, truncation=True, max_length=max_seq_len)
return tokenized['input_ids'], tokenized['attention_mask']
# 返回tokenized的'input_ids'和'attention_mask'字段
if shuffle:
dataset = dataset.shuffle(batch_size)
# 如果设置了shuffle参数为True,则对数据集进行打乱
# 对数据集应用map操作
dataset = dataset.map(operations=[tokenize], input_columns="text", output_columns=['input_ids', 'attention_mask'])
# 使用tokenize函数处理数据集中的"text"列,并生成新的列'input_ids'和'attention_mask'
dataset = dataset.map(operations=transforms.TypeCast(mindspore.int32), input_columns="label", output_columns="labels")
# 将数据集中的"label"列转换为mindspore.int32类型,并生成新的列"labels"
# 根据设备类型选择批处理方式
if is_ascend:
dataset = dataset.batch(batch_size)
# 如果在Ascend设备上,直接进行批处理
else:
dataset = dataset.padded_batch(batch_size, pad_info={'input_ids': (None, tokenizer.pad_token_id),
'attention_mask': (None, 0)})
# 否则使用padded_batch进行批处理,设置填充信息(input_ids和attention_mask的填充值)
return dataset # 返回处理后的数据集
6、初始化一个GPT模型的tokenizer
加载预训练的GPT模型,然后添加了一些特殊标记,如句子开始标记、句子结束标记和填充标记。
from mindnlp.transformers import GPTTokenizer
# 从MindNLP库中导入GPTTokenizer,用于加载和处理GPT模型的tokenizer
gpt_tokenizer = GPTTokenizer.from_pretrained('openai-gpt')
# 使用预训练的GPT tokenizer进行初始化,指定预训练模型名称为'openai-gpt'
# add special token: <PAD>
special_tokens_dict = {
"bos_token": "<bos>", # 句子开始标记
"eos_token": "<eos>", # 句子结束标记
"pad_token": "<pad>", # 填充标记
}
# 定义一个字典,用于添加特定的特殊标记到tokenizer中
num_added_toks = gpt_tokenizer.add_special_tokens(special_tokens_dict)
# 将定义的特殊标记添加到tokenizer中,并返回添加的标记数量
7、划分训练集、验证集
将一个训练数据集 imdb_train
按照 70% 和 30% 的比例分割成两个数据集:一个用于训练 (imdb_train
),另一个用于验证 (imdb_val
)。
# split train dataset into train and valid datasets
# 将训练数据集拆分成训练集和验证集
imdb_train, imdb_val = imdb_train.split([0.7, 0.3])
# 将 imdb_train 数据集按 70% 和 30% 的比例分割成两个数据集
# imdb_train 包含 70% 的数据,用于继续训练
# imdb_val 包含 30% 的数据,用于验证模型
8、处理三个数据集:训练集、验证集和测试集。
process_dataset
函数的作用是对数据集进行预处理,包括标记化、清洗或其他转换操作。gpt_tokenizer
是用于将文本数据转换为模型可以理解的格式的标记化工具。数据集的打乱(shuffle=True
)有助于防止模型训练中的过拟合和提升泛化能力。
dataset_train = process_dataset(imdb_train, gpt_tokenizer, shuffle=True)
# 使用 process_dataset 函数处理 imdb_train 数据集
# gpt_tokenizer 用于对数据进行标记化处理
# shuffle=True 表示对数据进行随机打乱,以提高训练效果
# 处理后的数据集存储在 dataset_train 中
dataset_val = process_dataset(imdb_val, gpt_tokenizer)
# 使用 process_dataset 函数处理 imdb_val 数据集
# gpt_tokenizer 用于对数据进行标记化处理
# 处理后的数据集存储在 dataset_val 中
# 这里没有指定 shuffle 参数,默认情况下数据不会被打乱
dataset_test = process_dataset(imdb_test, gpt_tokenizer)
# 使用 process_dataset 函数处理 imdb_test 数据集
# gpt_tokenizer 用于对数据进行标记化处理
# 处理后的数据集存储在 dataset_test 中
# 这里也没有指定 shuffle 参数,默认情况下数据不会被打乱
9、从 dataset_train
中获取下一个数据样本
dataset_train.create_tuple_iterator()
:将dataset_train
数据集转换为一个迭代器,这个迭代器返回的每一项都是一个元组(通常包含输入数据和对应的标签)。next()
:从迭代器中获取下一个数据项。如果迭代器中没有更多的数据项,它将引发StopIteration
异常。
next(dataset_train.create_tuple_iterator())
# 创建一个迭代器,用于遍历 dataset_train 数据集中的数据
# 使用 create_tuple_iterator() 方法将 dataset_train 转换为一个元组迭代器
# 然后调用 next() 函数从迭代器中获取下一个数据样本
# 这将返回数据集中的第一个数据项(通常是一个包含特征和标签的元组)
10、配置模型
配置一个 GPT 模型进行序列分类任务,并设置了训练过程中的优化器、评估指标、回调函数等。
-
模型定义和配置:
GPTForSequenceClassification.from_pretrained('openai-gpt', num_labels=2)
:从预训练的 GPT 模型加载,并配置为二分类任务。model.config.pad_token_id = gpt_tokenizer.pad_token_id
:设置模型的填充标记 ID。model.resize_token_embeddings(model.config.vocab_size + 3)
:扩展模型的词汇表以适应新增的词汇。
-
优化器和学习率:
optimizer = nn.Adam(model.trainable_params(), learning_rate=2e-5)
:使用 Adam 优化器,学习率设置为 0.00002。
-
评估指标:
metric = Accuracy()
:使用准确率作为模型性能评估指标。
-
回调函数:
CheckpointCallback
:用于保存训练过程中的模型检查点。BestModelCallback
:用于保存和自动加载最佳模型检查点。
-
训练配置:
Trainer
:用于模型的训练,指定了模型、数据集、优化器、回调函数等参数。
from mindnlp.transformers import GPTForSequenceClassification
from mindspore.experimental.optim import Adam
# set bert config and define parameters for training
# 设置模型配置和训练参数
# 创建一个 GPT 模型用于序列分类任务,num_labels=2 表示有两个分类标签
model = GPTForSequenceClassification.from_pretrained('openai-gpt', num_labels=2)
# 配置模型的填充标记 ID 为 tokenzier 中的 pad_token_id
model.config.pad_token_id = gpt_tokenizer.pad_token_id
# 调整模型的词汇表大小,为模型词汇表增加 3 个新的词汇
model.resize_token_embeddings(model.config.vocab_size + 3)
# 使用 Adam 优化器,并设置学习率为 2e-5
optimizer = nn.Adam(model.trainable_params(), learning_rate=2e-5)
# 定义准确率作为评估指标
metric = Accuracy()
# 定义回调函数以保存检查点
# ckpoint_cb 用于保存模型检查点
ckpoint_cb = CheckpointCallback(save_path='checkpoint', ckpt_name='gpt_imdb_finetune', epochs=1, keep_checkpoint_max=2)
# best_model_cb 用于保存最佳模型检查点,并自动加载最佳模型
best_model_cb = BestModelCallback(save_path='checkpoint', ckpt_name='gpt_imdb_finetune_best', auto_load=True)
# 创建一个 Trainer 对象用于训练模型
trainer = Trainer(
network=model, # 训练的模型
train_dataset=dataset_train, # 训练数据集
eval_dataset=dataset_train, # 验证数据集(这里使用了训练集进行验证)
metrics=metric, # 评估指标
epochs=1, # 训练轮次
optimizer=optimizer, # 优化器
callbacks=[ckpoint_cb, best_model_cb], # 回调函数
jit=False # 是否使用 JIT 编译
)
11、trainer.run(tgt_columns="labels")
启动了模型的训练过程,并指定了目标列。
-
trainer.run()
: 这个方法启动了模型的训练过程。它会根据之前配置的训练参数(如模型、优化器、数据集、回调函数等)开始训练。 -
tgt_columns="labels"
: 这是一个参数,指定了数据集中哪个列作为模型的目标列(即标签列)。在这里,"labels"
表示数据集中用于训练和验证的目标列是labels
。这个列的值用于计算损失函数并进行模型的优化。
这种设置通常用于数据集中包含多个列的情况,其中一个列是模型训练的目标输出。在这个例子中,labels
列包含了分类任务中的标签。
trainer.run(tgt_columns="labels")
# 启动训练过程
# tgt_columns="labels" 指定了训练数据集中包含的目标列(标签列)
# 训练过程将使用这些目标列来计算损失和进行梯度更新
12、 设置并运行了模型的评估过程
-
创建
Evaluator
对象:network=model
:指定要评估的模型。eval_dataset=dataset_test
:指定用于评估的数据集。这里使用了dataset_test
数据集进行评估。metrics=metric
:指定评估时使用的指标。在这里是准确率(Accuracy()
)。
-
运行评估:
evaluator.run(tgt_columns="labels")
:启动模型的评估过程。tgt_columns="labels"
:指定目标列(即数据集中用于计算评估指标的列)。在这里,"labels"
表示模型将使用这个列中的标签来计算准确率。
通过这种设置,Evaluator
对象会遍历 dataset_test
数据集,计算模型在测试集上的表现,并根据指定的评估指标(准确率)输出结果。
evaluator = Evaluator(network=model, eval_dataset=dataset_test, metrics=metric)
# 创建一个 Evaluator 对象,用于评估模型
# 参数解释:
# network=model: 要评估的模型
# eval_dataset=dataset_test: 用于评估的数据集
# metrics=metric: 评估过程中使用的指标(这里是准确率)
evaluator.run(tgt_columns="labels")
# 启动评估过程
# tgt_columns="labels" 指定了数据集中包含的目标列(标签列)
# 评估过程中使用这些目标列来计算评估指标(如准确率)
打卡