首页 > 其他分享 >NLP 之四:双向预训练模型

NLP 之四:双向预训练模型

时间:2024-01-25 23:44:12浏览次数:24  
标签:NLP self torch ids test train 双向 之四 data

利用预训练好的模型进行微调(Fine-tune),可以获得比传统模型的巨大提升。

此时学习率一般是正常的十分之一(\(10^{-5}\) 左右)。也可以保持预训练的参数不变。

Transformer 架构

  • Encoder-only:擅长分类任务
  • Decoder-only:擅长生成任务
  • Encoder-only:混合情况(例如文本翻译、总结)

在无监督训练中,Encoder 和 Decoder 最大的区别是,前者可以从上下文同时学习,而后者则只能从上文学习。

前者也被称为双向预训练模型,BERT 便是其中的经典之作。

BERT:Encoder-only

为了同时从上下文学习,我们不能再使用直接使用注意力机制预测文本每一个词。因为这样当叠了两层 Attention 后,模型就可以从每个词自己提取出信息,直接预测出自己。取而代之的是以下的两种训练策略:

  • 掩码语言模型(MLM):随机一定规模(一般是15%)的词替换为【MASK】,用别的词预测它们。
  • 下一句预测 (NSP) :选两个句子,让模型判断其中一个是不是紧跟在另一个后面。

不过后者效果并不好,并且基本在一两轮训练后正确率就会接近100%。

IMDB 情感分类:BERT 微调实例

参考了网上的代码。

数据处理

正常下载下来是这样的,我们先处理成 [text,label] 的形式。(貌似这里 train 和 test 比例是1:1,正常来说会让它们变成大约9:1,不过我懒了)

import os
import random

def init(aim_set, data_dir, type):
    for i in os.listdir(data_dir):
        file_path = os.path.join(data_dir, i)
        with open(file_path, "r", encoding="utf-8") as file:
            aim_set.append([file.read(), type])

train_data = []
test_data = []
init(train_data, "aclImdb/train/pos/", 1)
init(train_data, "aclImdb/train/neg/", 0)
init(test_data, "aclImdb/test/pos/", 1)
init(test_data, "aclImdb/test/neg/", 0)
random.shuffle(train_data)
random.shuffle(test_data)

将数据转化成类 Dataset&Dataloader 的格式。

tokenizer = BertTokenizer.from_pretrained("./bert-base-uncased/", truncation=True, do_lower_case=True)

class My_Dataset(Dataset):
    def __init__(self, dataframe, tokenizer, max_len):
        self.tokenizer = tokenizer
        self.text = [row[0] for row in dataframe]
        self.targets = [row[1] for row in dataframe]
        self.max_len = max_len
    def __len__(self):
        return len(self.text)
    def __getitem__(self, index):
        text = str(self.text[index])
        text = " ".join(text.split())
        inputs = self.tokenizer.encode_plus(
            text,
            add_special_tokens = True,
            max_length = self.max_len,
            pad_to_max_length = True,
            return_token_type_ids = True
        )
        return {
            "ids": torch.tensor(inputs["input_ids"], dtype=torch.long),
            "mask": torch.tensor(inputs["attention_mask"], dtype=torch.long),
            "token_type_ids": torch.tensor(inputs["token_type_ids"], dtype=torch.long),
            "targets": torch.tensor(self.targets[index], dtype=torch.float)
        }

train_set = My_Dataset(train_data, tokenizer, MAX_LEN)
test_set = My_Dataset(test_data, tokenizer, MAX_LEN)

train_params = {"batch_size": TRAIN_BATCH_SIZE, "shuffle": True}
test_params = {"batch_size": VALID_BATCH_SIZE, "shuffle": True}
train_loader = DataLoader(train_set, **train_params)
test_loader = DataLoader(test_set, **test_params)

模型搭建

from transformers import BertModel

class BertClass(nn.Module):
    def __init__(self):
        super(BertClass, self).__init__()
        self.BERT = BertModel.from_pretrained("./bert-base-uncased/")
        self.l1 = torch.nn.Linear(768, 768)
        self.ReLU = torch.nn.ReLU()
        self.l2 = torch.nn.Linear(768, 2)

    def forward(self, input_ids, attention_mask, token_type_ids):
        output_BERT = self.BERT(input_ids=input_ids, attention_mask=attention_mask, token_type_ids=token_type_ids)
        hidden_state = output_BERT[0]
        x = hidden_state[:, 0]
        return self.l2(self.ReLU(self.l1(x)))

微调训练

model = BertClass()
model.to(device)
loss_function = torch.nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(params=model.parameters(), lr=LEARNING_RATE)

def calc(preds, targets):
    n_correct = (preds == targets).sum().item()
    return n_correct

def train(epoch, train_loader):
    tr_loss = 0
    n_correct = 0
    nb_tr_steps = 0
    nb_tr_examples = 0
    model.train()
    for _, data in tqdm(enumerate(train_loader, 0)):
        ids = data["ids"].to(device, dtype=torch.long)
        mask = data["mask"].to(device, dtype=torch.long)
        token_type_ids = data["token_type_ids"].to(device, dtype=torch.long)
        targets = data["targets"].to(device, dtype=torch.long)
        outputs = model(ids, mask, token_type_ids)
        loss = loss_function(outputs, targets)
        tr_loss += loss.item()
        big_val, big_idx = torch.max(outputs.data, dim=1)
        n_correct += calc(big_idx, targets)
        nb_tr_steps += 1
        nb_tr_examples += targets.size(0)
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
    epoch_loss = tr_loss / nb_tr_steps
    epoch_accu = (n_correct * 100) / nb_tr_examples
    print(f"The Total Accuracy for Epoch {epoch}: {(n_correct * 100) / nb_tr_examples}")
    print(f"Training Loss Epoch: {epoch_loss}")
    print(f"Training Accuracy Epoch: {epoch_accu}")
train(epoch, train_loader)
torch.save(model, model_dir)

结果

用 bert-base-uncased 微调可以在测试集上达到93%的正确率;如果权重初始随机,只靠 imdb 数据训练一轮,甚至只有50%左右;本地对 bert 简单预训练(mlm)则有85%。

为什么BERT不能识别出阴阳怪气啊

标签:NLP,self,torch,ids,test,train,双向,之四,data
From: https://www.cnblogs.com/xcyle/p/17975123

相关文章

  • 产品经理的四大核心要素之四:思考
    01思考!思考!思考!谁还不会思考呢,只是懒而已!思考很多时候都很痛苦和艰难,思来想去的,没有想到什么好方法,完全没有思路和线索,然后就不想了,顺其自然吧,不会就不会了。谁还不会躺平呢?思考肯定是基于某个目的,不然就是幻想、瞎想了。思考本身需要什么?思考需要你的基础认知能力、思考需要......
  • 路由策略(前缀列表,策略工具-filter-policy,策略工具-Router-policy,双点双向路由重发布)
    1.前缀列表默认是拒绝,如果没写允许,就都是拒绝Greater-equal26less-equal32从子网掩码26-32被匹配,其他的被拒绝2.策略工具1:filter-policy(过滤策略)Export只对引入的路由,,对引入的路由在过滤,是不是发给我的邻居使用,import对所有路由器都可用*ospf:import*R1传......
  • 工作中的网络知识之四_时延
    工作中的网络知识之四_时延时延的巨大影响高性能最大的杀手是时延.不管是CPU取指还是取操作数.还是内存读取和写入还是磁盘的读写.以及网络的收发包.高性能最大的屏障其实是时延.本机的很多时延可以通过增加cache,增加索引,利用程序的时间和空间局限性进行优化.......
  • AI_NLP以及DETR的理解-目标检测模型
    目标检测框架CNNbased以及Transformerbased。01.CNNbased通常又可以划分为以FasterRCNN和RetinaNet为代表 和以YOLO系列为代表阈值筛选(Confidencethreshold)和非极大值抑制(NMS)处理两个关键步骤02.Transformerbased目标检测:DETR......
  • 带你熟悉NLP预训练模型:BERT
    本文分享自华为云社区《【昇思技术公开课笔记-大模型】Bert理论知识》,作者:JeffDing。NLP中的预训练模型语言模型演变经历的几个阶段word2vec/Glove将离散的文本数据转换为固定长度的静态词向量,后根据下游任务训练不同的语言模型ELMo预训练模型将文本数据结合上下文信息,转换......
  • 【glibc】glib库双向链表GList介绍
    在上一篇文章里我介绍了glib库中单向链表的用法,这篇文章介绍glib库双向链表的用法,还是沿用上一篇文章的风格,采用在代码中加入注释来说明代码,最后贴出程序的运行结果,然后加以少量说明。双向链表与单向链表的区别是,从一个节点,不仅能访问到它的下一个节点,还能访问到它的上一个节点,其......
  • ICDM'23 BICE论文解读:基于双向LSTM和集成学习的模型框架
    本文分享自华为云社区《ICDM'23BICE论文解读》,作者:云数据库创新Lab。导读本文《EfficientCardinalityandCostEstimationwithBidirectionalCompressor-basedEnsembleLearning》是由华为云数据库创新Lab联合电子科技大学数据与智能实验室发表在顶会ICDM’23的长文。ICDM......
  • 用 CloudCanal 做跨互联网数据库双向同步
    简介CloudCanal推出跨互联网安全数据同步方案之后,有一些商业客户落地,效果良好,不过客户也反馈了一些改进和新需求,其中最大的一个需求即双向同步防循环。近期CloudCanal版本支持了这个特性,整体方案进一步升级,最大特点包括:两端数据库完全不开放公网端口两端数据库可双向同......
  • HanLP — 汉字转拼音 -- JAVA
    目录语料库训练加载语料库训练模型保存模型加载模型计算调用HanLP在汉字转拼音时,可以解决多音字问题,显示输出声调,声母、韵母,通过训练语料库,本文代码为《自然语言处理入门》配套版本HanLP-1.7.5对重载不是重任进行转拼音,效果如下:原文:重载不是重任拼音(数字音调):chong2,zai3,bu......
  • IGC的底层核心结构Transformer是如何彻底改变NLP游戏规则的?OJAC近屿智能带你一探究竟
    没有Transformer,就没有NLP的突破,听起来有些夸张,但事实确实如此。什么是Transformer?Transformer是一种基于注意力机制的神经网络架构。可以用于处理序列数据,被广泛应用于翻译、识别等任务。这种模型的主要特点是使用自注意力机制和位置Embedding来提升语言的表达能力。Transformer模......