基于HF transformers的AI建模和训练实战

我们经常使用 scikit-learn 对监督学习和无监督学习任务的数据进行建模。 我们熟悉面向对象的设计,例如启动类并从类中调用子函数。 然而,当我个人使用 PyTorch 时,我发现与 scikit-learn 类似但又不一样的设计模式。
基于HF transformers的AI建模和训练实战_第1张图片

在线工具推荐: Three.js AI纹理开发包 - YOLO合成数据生成器 - GLTF/GLB在线编辑 - 3D模型格式在线转换 - 可编程3D场景编辑器

1、PyTorch和transformers

要使用 PyTorch 训练模型,你必须为数据集和模型创建一个类,并添加每个类的继承。 例如,你需要创建一个名为 TextDataset(Dataset) 的类,并且该 Dataset 是 torch.utils.Dataset 中的一个类。 要创建模型,也必须创建一个类例如 Classifier(nn.Module) ,与scikit-learn 相比,PyTorch 允许你构建自己的类并在类中执行一些操作。

我们来谈谈Hugging Face开发的 transformers。 当我看到一位在LinkedIn上和我有联系的研究科学家发布的有关添加的新功能的帖子时,我注意到了这个库。 但是,当时我并没有考虑立即尝试。 然后,就到了我对 BERT 架构感到好奇并想要实现它的时候。

如果你是 PyTorch 的新手。 尝试使用它构建一些模型,例如构建用于文本分类或图像分类的模型以开始。 PyTorch 有一个很棒的文档。 在你熟悉使用 PyTorch 来训练和评估模型后。 可以轻松使用 transformers。

我开始仅从 Transformers 的文档中探索它们。 我关注 Hugging Face 推特帐户,该帐户经常发布有关库和开发的最新更新的推文。 这让我更容易了解他们的更新。 查看 Transformers 文档中的使用页面。 它解释了如何在自然语言处理中使用各种应用程序,从序列分类到神经机器翻译。

在深度学习社区中,我们经常强调预训练模型。 一个经过预先训练的模型,可以将其用于另一个类似的任务,也称为迁移学习。 Hugging Face 托管来自各个开发人员的预训练模型。 他们创建了一个共享预训练模型的平台,你也可以将其用于自己的任务。

之后,我想知道,如果我想使用 BERT 架构训练自己的模型而不使用预训练模型(这意味着从头开始训练模型)怎么办? 因为大多数人从博客文章或研究论文中以 BERT-base-uncased 为例讨论预训练模型。 然后我想起来,PyTorch 与 Keras 相比有很大不同,Keras 具有 fit 和 Predict 函数。
基于HF transformers的AI建模和训练实战_第2张图片

2、使用transformers训练文本分类BERT模型

我开始使用 PyTorch 从 Kaggle 竞赛数据集训练文本分类, Real or Not? NLP with Disaster Tweets 是一个不错的开始选择。 我使用了 XGBoost 和 CatBoost,并在数据清理和特征提取方面做了一些神奇的事情,但分数上不去。 然后,我认为 BERT 会将分数添加到排行榜中。 事实证明,使用 bert-base-uncased 后,平均 F 分数提高到了 83%,并进入排行榜前 12%!

为了从头开始训练模型,我创建了一个函数来生成管线:

def generate_model(args, num_labels):
    
    config = AutoConfig.from_pretrained(
        args.model_name_or_path,
        num_labels=num_labels,
        finetuning_task=args.task_name,
        )
    tokenizer = AutoTokenizer.from_pretrained(
        args.model_name_or_path,
        do_lower_case=args.do_lower_case
    )
    model = AutoModelForSequenceClassification.from_config(
        config
    )
    
    return config, tokenizer, model

如你所知, Transformers 需要三个组件来推断或训练你的模型。 AutoConfig 用于设置模型和分词器配置。 可以将 AutoConfig 更改为 BertConfig 或 Transformers 中可用的任何其他架构。 AutoTokenizer 的应用与配置相同。 但这里的分词器使用预先训练的,这意味着我使用来自 bert-base-uncased 的分词器。 它已经加载了自己的词汇表,你可以查看 vocab.txt 中的每个token, 所以我没有建立自己的词汇表。 最后一个组件 AutoModelForSequenceClassification 是从配置加载的,因为我想从头开始训练。 AutoModel 可以更改为 BertForSequenceClassification 。

第二步,我创建 DisasterDataset 类来加载数据集:

class DisasterDataset():
    def __init__(self, data_path, eval_path, tokenizer):
        d_data = pd.read_table(data_path, sep=',')
        d_eval = pd.read_table(eval_path, sep=',')
        
        row, col = d_data.shape
        d_train = d_data[:int(row * 0.8)]
        d_test = d_data[int(row*0.8):]

        d_train.reset_index(drop=True, inplace=True)
        d_test.reset_index(drop=True, inplace=True)
        
        self.tokenizer = tokenizer
        self.dataset = {'train': (d_train, len(d_train)),
                       'test': (d_test, len(d_test)),
                       'eval': (d_eval, len(d_eval))}
        self.num_labels = len(d_train.target.unique().tolist())
        self.set_split('train')
    
    def get_vocab(self):
        text = " ".join(self.data.text.tolist())
        text = text.lower()
        vocab = text.split(" ")
        with open('vocab.txt', 'w') as file:
            for word in vocab:
                file.write(word)
                file.write('\n')
        file.close()
        return 'vocab.txt'
        
    
    def set_split(self, split = 'train'):
        self.split = split
        self.data, self.length = self.dataset[split]
    
    def __getitem__(self, idx):
        x = self.data.loc[idx, "text"].lower()
        x = self.tokenizer.encode(x, return_tensors="pt")[0]
    
        if self.split != 'eval':
            y = self.data.loc[idx, "target"]
            return {'id': idx, 'x': x, 'y': y}
        else:
            id_ = self.data.loc[idx, "id"]
            return {'id': id_, 'x': x}
    
    def __len__(self):
        return self.length

上面的脚本用于构建类数据集。 我没有使用任何预处理,任何清洁。 只需使用纯文本并使用 Tokenizers 库中的 BertWordPiece 进行标记化:

for epoch in range(1, 101):
    running_loss = 0
    running_accuracy = 0
    running_loss_val = 0
    running_accuracy_val = 0
    
    start_time = time.time()
    # dataset class is assigned to dd variable
    dd.set_split('train')
    dataset = DataLoader(dd, batch_size=64, shuffle=True, collate_fn=padded)
    model.train()
    for batch_index, batch_dict in enumerate(dataset, 1):
        optimizer.zero_grad()

        x = batch_dict['x'].permute(1, 0)
        x = x.to(device)
        y = batch_dict['y'].to(device)

        output = model(x)[0]
        output = torch.softmax(output.squeeze(), dim=1)
        loss = criterion(output, y.type(torch.LongTensor).to(device))

        running_loss += (loss.item() - running_loss) / batch_index

        accuracy = compute_accuracy(y, output)
        running_accuracy += (accuracy - running_accuracy) / batch_index

        loss.backward()

        optimizer.step()
        
    dd.set_split('test')
    dataset = DataLoader(dd, batch_size=64, shuffle=True, collate_fn=padded)
    model.eval()        
    for batch_index, batch_dict in enumerate(dataset, 1):

        x = batch_dict['x'].permute(1, 0)
        x = x.to(device)
        y = batch_dict['y'].to(device)

        output = model(x)[0]
        output = torch.softmax(output.squeeze(), dim=1)
        loss = criterion(output, y.type(torch.LongTensor).to(device))

        running_loss_val += (loss.item() - running_loss_val) / batch_index

        accuracy = compute_accuracy(y, output)
        running_accuracy_val += (accuracy - running_accuracy_val) / batch_index

最后,上面的脚本是训练模型的。 我使用 Adam 优化器,学习率为 0.0001,并使用 PyTorch 的调度程序 StepLR(), step_size 为 20, gamma 为 0.01。 对于标准,我使用 CrossEntropyLoss() 。 即使任务是二进制的,假设使用二进制交叉熵。 但模型返回类别的概率,使用softmax 作为激活函数。

我使用 GPU Nvidia K-80 在计算引擎上运行脚本,得到结果的速度相当快,因为我设置 running_accuracy > 90 并且 running_accuracy_val > 90 将被停止。 该脚本不会运行 100 个周期才能完成。

3、结束语

最后,BERT 架构比 Transformers 库更加有用且易于使用。 在雅加达人工智能研究中心,一个位于雅加达的人工智能研究社区,主要使用 PyTorch 和 Transformers 来开发和运行项目实验。 我们还尝试构建自己的编码器来超越现有的编码器,例如 GPT 和 BERT 架构。


原文链接:HF transformers建模 — BimAnt

你可能感兴趣的:(人工智能)