重新预训练BERT

本文介绍了如何使用BERT进行预训练,重点讲解了数据预处理的个性化挑战、仅使用MLM的方法,并分享了一个GitHub项目链接,展示了从头开始训练BERT模型的过程,包括设置随机种子、加载数据、模型配置和训练参数等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在面试时经常有面试官问有没有做过Bert的预训练,今天特地记录一下。
参考链接:
https://blog.youkuaiyun.com/weixin_43476533/article/details/107512497
https://blog.youkuaiyun.com/qq_22472047/article/details/115528031

"""
transformers:version-4.5.1
个人感觉:数据预处理是比较麻烦的一个步骤,因为每个人的数据格式是不同的;而运行代码则大同小异。
本次预训练仅使用了MLM,未使用NSP(需要额外处理NSP标签,比较费劲)

github链接
https://github.com/tyistyler/some_little_program/tree/main/pretrain_new_bert
"""
# coding: utf-8
# Name:     do_pretrain
# Author:   dell
# Data:     2021/11/8

import os
import torch
import random
import warnings
import numpy as np
from argparse import ArgumentParser

from transformers import TrainingArguments, Trainer, DataCollatorForLanguageModeling
from transformers import BertTokenizer, BertConfig, BertForMaskedLM
from transformers.trainer_utils import get_last_checkpoint
from transformers import TextDataset


# 设置随机种子
def setup_seed(seed):
    torch.manual_seed(seed)  # 为cpu分配随机种子
    if torch.cuda.is_available():
        torch.cuda.manual_seed(seed)  # 为gpu分配随机种子
        torch.cuda.manual_seed_all(seed)  # 若使用多块gpu,使用该命令设置随机种子
    random.seed(seed)
    np.random.seed(seed)
    torch.backends.cudnn.deterministic = True
    torch.backends.cudnn.benchmard = False


def main():
    parser = ArgumentParser()

    parser.add_argument("--pretrain_data_path", type=str, default="./pretrain_data/preprocessed_data.txt")
    parser.add_argument("--pretrain_model_path", type=str, default="./ckpt/bert-base-chinese")
    parser.add_argument("--data_caches", type=str, default="./caches")
    parser.add_argument("--vocab_path", type=str, default="./pretrain_data/vocab.txt")
    parser.add_argument("--config_path", type=str, default="./pretrain_data/config.json")
    parser.add_argument("--checkpoint_save_path", type=str, default="./ckpt/checkpoint")
    parser.add_argument("--save_path", type=str, default="./ckpt/bert-base-patent")
    parser.add_argument("--num_train_epochs", type=int, default=50)
    parser.add_argument("--max_seq_len", type=int, default=300)
    parser.add_argument("--batch_size", type=int, default=16)
    parser.add_argument("--learning_rate", type=float, default=1e-5)
    parser.add_argument("--seed", type=int, default=1234)
    parser.add_argument("--save_steps", type=int, default=5000)
    parser.add_argument("--logging_steps", type=int, default=500)
    parser.add_argument("--save_total_limit", type=int, default=5)          # 限制checkpoints的数量,最多5个

    # python通过调用warnings模块中定义的warn()函数来发出警告,我们可以通过警告过滤器进行控制是否发出警告消息。
    warnings.filterwarnings("ignore")
    args = parser.parse_args()

    setup_seed(args.seed)

    device = "cuda" if torch.cuda.is_available() else "cpu"

    if not os.path.exists(os.path.dirname(args.save_path)):
        os.makedirs(os.path.dirname(args.save_path))

    tokenizer = BertTokenizer.from_pretrained(args.vocab_path, model_max_length=args.max_seq_len)
    bert_config = BertConfig.from_pretrained(args.config_path)
    model = BertForMaskedLM(config=bert_config)
    model = model.to(device)

    data_collator = DataCollatorForLanguageModeling(tokenizer, mlm=True, mlm_probability=0.15)

    training_args = TrainingArguments(
        seed=args.seed,
        save_steps=args.save_steps,
        logging_steps=args.logging_steps,
        output_dir=args.checkpoint_save_path,
        learning_rate=args.learning_rate,
        save_total_limit=args.save_total_limit,
        num_train_epochs=args.num_train_epochs,
        per_device_train_batch_size=args.batch_size
    )

    print("=========loading TextDateset=========")
    dataset = TextDataset(tokenizer=tokenizer, block_size=args.max_seq_len, file_path=args.pretrain_data_path)
    print("=========TextDateset loaded =========")

    trainer = Trainer(model, args=training_args, train_dataset=dataset, data_collator=data_collator)

    last_checkpoint = get_last_checkpoint(training_args.output_dir)
    if last_checkpoint is not None:
        train_result = trainer.train(resume_from_checkpoint=last_checkpoint)
    else:
        print("=========training=========")
        train_result = trainer.train()
    print(train_result)
    trainer.save_model(args.save_path)
    tokenizer.save_vocabulary(args.save_path)



if __name__ == "__main__":
    main()




### 使用预训练 BERT 模型进行细粒度 NLP 任务的最佳实践 #### 微调方法的优势与适用场景 对于大多数细粒度的自然语言处理 (NLP) 任务,如情感分析、命名实体识别 (NER) 或关系抽取,微调方法通常是首选方案。这种方法通过在预训练模型的基础上添加一个简单的分类层,并对整个网络的所有参数进行联合优化来适应具体任务的需求[^1]。 #### 特征提取方法的应用场合 尽管如此,在某些特殊情况下,基于特征的方法可能更为合适。例如,当目标任务无法被简单地映射到 Transformer 编码器结构时,或者为了节省计算资源而希望重用已有的预计算表示时,可以从预训练模型中提取固定特征并附加特定于任务的架构。 #### AMBERT 的引入及其特点 针对传统 BERT 可能存在的局限性,研究者提出了 AMBERT 算法作为一种改进版的语言建模框架。AMBert 不仅继承了原始版本的优点,还进一步融入了多粒度 token 和共享参数机制,从而增强了其灵活性以及泛化能力[^2]。 #### CNN 层叠设计技巧 当考虑将卷积神经网络(CNNs)堆砌至Bert之上执行诸如短文本匹配之类的子句级别操作时,则需要注意输入数据格式转换的重要性。如果发现初始馈送进去的数据维度不兼容目标运算符(比如F.max_pool1d),那么应当借助像`torch.unsqueeze()`这样的工具去扩充必要的轴数;或者是运用`torch.transpose()`实现不同方向间的互换以便达成最终适配目的[^3]。 ```python import torch.nn as nn class BertWithCNN(nn.Module): def __init__(self, bert_model, num_classes): super(BertWithCNN, self).__init__() self.bert = bert_model self.conv = nn.Conv1d(in_channels=768, out_channels=100, kernel_size=3) self.pool = nn.MaxPool1d(kernel_size=2) self.fc = nn.Linear(100 * ((max_len - 2)//2), num_classes) def forward(self, input_ids, attention_mask=None): outputs = self.bert(input_ids=input_ids, attention_mask=attention_mask)[0].transpose(1, 2).contiguous() conv_out = self.conv(outputs) pooled_out = self.pool(conv_out).view(conv_out.size()[0], -1) logits = self.fc(pooled_out) return logits ``` 上述代码片段展示了一个结合BERT和一维卷积的操作实例,其中包含了如何正确调整张量尺寸以确保后续最大池化的顺利实施过程。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值