基于MindSpore的GPT模型fine-tuning微调
收藏回复举报
基于MindSpore的GPT模型fine-tuning微调
发表于2024-01-31 15:54:35
0 查看

AGNews数据集汇集了100多万篇新闻文章。ComeToMyHead在一年多的活动中从2000多个新闻来源收集了新闻文章。ComeToMyHead是一个学术新闻搜索引擎,自2004年7月开始运行。该数据集由学术团体提供,用于数据挖掘(聚类、分类等)、信息检索(排名、搜索等)、xml、数据压缩、数据流和任何其他非商业活动的研究目的。

我们使用AGNews dataset数据集,通过fine-tuning GPT进行情感分类任务。

URL = {
    "train": "https://raw.githubusercontent.com/mhjabreel/CharCnn_Keras/master/data/ag_news_csv/train.csv",
    "test": "https://raw.githubusercontent.com/mhjabreel/CharCnn_Keras/master/data/ag_news_csv/test.csv",
}

如下分类:

  • World
  • Sports
  • Business
  • Sci/Tech
{
    "label": 3,
    "text": "New iPad released Just like every other September, this one is no different. Apple is planning to release a bigger, heavier, fatter iPad that..."
}

自定义数据集

mindspore.dataset提供了一些常见数据集和标准格式数据集的加载API。GeneratorDataset可以帮助基于这些类/函数内部的逻辑加载数据集

class RandomAccessDataset:
    def __init__(self, filepath):
        self._data, self._label = self._load_data(filepath)

    def _load_data(self, filepath):
        data, labels = [], []
        with open(filepath, encoding="utf-8") as csv_file:
            csv_reader = csv.reader(csv_file)
            next(csv_reader)  # Skip the header row if present
            for row in csv_reader:
                label, title, description = row
                label = int(label) - 1  # Adjust label to 0-indexed
                text = " ".join((title, description))  # Concatenate title and description
                labels.append(label)
                data.append(text)
        return data, labels

    def __getitem__(self, index):
        return self._data[index], self._label[index]

    def __len__(self):
        return len(self._data)

选取test.csv作为验证集,train.csv数据作为训练集

train_path = 'train.csv'
test_path = 'test.csv'
train_loader = RandomAccessDataset(train_path)
test_loader = RandomAccessDataset(test_path)
train_dataset = GeneratorDataset(source=train_loader, column_names=["text", "label"])
test_dataset = GeneratorDataset(source=test_loader, column_names=["text", "label"])
for data in train_dataset:
    print(data)
    break

加载GPT tokenizer,并添加上述使用到的<bos><eos><pad>占位符。

# tokenizer
from mindnlp.transforms import  GPTTokenizer
gpt_tokenizer = GPTTokenizer.from_pretrained('./openai-gpt', from_pt=True)

# add sepcial token: <PAD>
special_tokens_dict = {
    "bos_token": "<bos>",
    "eos_token": "<eos>",
    "pad_token": "<pad>",
}
num_added_toks = gpt_tokenizer.add_special_tokens(special_tokens_dict)

由于AGnews数据集本身不验证集, 我们手动将其分割为训练和验证两部分, 比例取0.8, 0.2

ds_train, ds_val = train_dataset.split([0.8, 0.2])

我们需要对数据进行如下处理:

  • 将文本内容进行分词, 并映射为对应的数字索引;
  • 统一序列长度:超过进行截断, 不足通过占位符进行补全;
  • 按照分类任务的输入要求, 在句首和句末分别添加Start与Extract占位符 (此处用与表示);
  • 批处理
def process_dataset(dataset, tokenizer, max_seq_len=512, batch_size=16, shuffle=False):
    def tokenize(text):
        tokenized = tokenizer(text, truncation=True, max_length=max_seq_len)
        return tokenized[0], tokenized[1]

    if shuffle:
        dataset = dataset.shuffle(batch_size)

    # map dataset
    dataset = dataset.map(operations=[tokenize], input_columns="text", output_columns=['input_ids', 'attention_mask'])
    dataset = dataset.map(operations=transforms.TypeCast(mindspore.int32), input_columns="label", output_columns="labels")
    # batch dataset
    dataset = dataset.padded_batch(batch_size, pad_info={'input_ids': (None, tokenizer.pad_token_id),
                                                         'attention_mask': (None, 0)})

    return dataset
dataset_train = process_dataset(ds_train, gpt_tokenizer, shuffle=True)
dataset_val = process_dataset(ds_val, gpt_tokenizer)
dataset_test = process_dataset(test_dataset, gpt_tokenizer)
next(dataset_train.create_tuple_iterator())

另外需要注意的一点是, 由于在前序数据处理中 我们添加了3个特殊占位符, 所以在token embedding中需要调整词典的大小(vocab_size + 3)。

# set bert config and define parameters for training
model = GPTForSequenceClassification.from_pretrained('openai-gpt', from_pt=True, num_labels=4)
model.config.pad_token_id = gpt_tokenizer.pad_token_id
model.resize_token_embeddings(model.config.vocab_size + 3)

optimizer = nn.Adam(model.trainable_params(), learning_rate=2e-5)

metric = Accuracy()

# define callbacks to save checkpoints
ckpoint_cb = CheckpointCallback(save_path='checkpoint', ckpt_name='gpt_agenews_finetune', epochs=1, keep_checkpoint_max=2)
best_model_cb = BestModelCallback(save_path='checkpoint', ckpt_name='gpt_agenews_finetune_best', auto_load=True)

trainer = Trainer(network=model, train_dataset=dataset_train,
                  eval_dataset=dataset_train, metrics=metric,
                  epochs=3, optimizer=optimizer, callbacks=[ckpoint_cb, best_model_cb],
                  jit=False)

trainer.run(tgt_columns="labels")

模型评估

evaluator = Evaluator(network=model, eval_dataset=dataset_test, metrics=metric)
evaluator.run(tgt_columns="labels")

本帖最后由 匿名用户2024/03/20 16:20:54 编辑

我要发帖子