首页 > 其他分享 >使用预训练语言模型作帖子分类

使用预训练语言模型作帖子分类

时间:2023-12-07 09:22:05浏览次数:35  
标签:训练 模型 torch 帖子 print import model

​ 预训练语言模型PLMs或PTMs应用广泛且效果良好。有的文章中把自然语言处理中的预训练语言模型的发展划分为4个时代:词入时代,上下文嵌入(Context Word Embedding)时代、预训练语言模型时代、改进型和领域定制型时代。

为什么需要预训练

​ 模型通常需要非常大的参数量,但并不是所有任务都有足够多的有标记的数据去训练这样复杂的模型,训练数据少可能导致模型出现过拟合,就是模型误以为少量数据特有的某些不重要的特征是关键的通用的特征。过拟合会导致模型在实际使用中表现不佳。

​ 可以先使用一些通用的数据对模型进行预训练,让模型学习一些这个领域通用的东西,然后使用较少量最终要解决的问题的数据做最终的训练。

​ 先在海量语料上对模型进行预训练,常用的语料有维基百科、新闻文章等,而且常常使用无监督学习的方法。因为很多自然语言处理任务的语料人工标注成本很高,但是有大量不带标注的语料可以用于无监督学习。

在海量语料上进行模型预训练的好处有:

(1)可以让模型学习到这个语言中的通用的知识。
(2)避免训练数据量过少造成的过拟合
(3)使用预训练参数是一种初始化模型参数的方法。

预训练模型的工作方式

​ 预训练模型有两个步骤,第一是使用海量的带有标记的通用数据训练模型,称为预训练:第二则是使用具体任务的数据,在预训练得到的模型结构和参数的基础上对模型做进一步的训练,这个过程中模型可能会学到一些新的参数,也可能会对预训阶段中的参数做一些修改,使模型更适应当前的任务,称为Fine-tuning。

​ 对于预训练模型来说,预训练阶段完成的任务被称为预训练任务,而 Fine-tuning 阶段完成的任务和实际要做的具体任务被称为下游任务(downstream tasks)。

​ Fine-tuning阶段往往会采用较小的学习率

ELMo 模型,ELMo 不仅是能提供 D 到词向量的词表的模型,而且是由 Embedding 层和个双向LSTM构成的语言模型。

​ 下游任务使用ELMo模型的时候,不仅会使用Embedding层的预训练参数,还会使用LSTM道型的结构和参数,这样当词序列通过 Embedding 层时得到词向量,再经过LSTM 模型则能够结合上下文信息。

ELMo

​ ELMo模型是一个双向的语言模型,而且ELMo模型通过双向LSTM模型输出包含上下文信息的词向量,可以根据语境自动调整具体词对应的向量。

特点

​ ELMo是来自语言模型的、结合上下文信息的词嵌入

GPT

​ GPT即Generative Pre-Training,意为生成式预训练

特点

​ GPT采用Transformer结构取代LSTM,有更高的效率。可以在更大的数据集进行更多训练。GPT 采用半监督学习的训练方案,即先进行无监督的预训练,然后在有标记的数据上进行有监督的Fine-tuningo

下游任务

​ 对于分类任务可以直接在 Transformer 结构后面添加线性层。推理任务可以在前提文本和楼断文本中间添加分隔符,再按顺序输入模型。文本相似度任务可以在要比较的两个文本中间添加分隔符,并按不同顺序输入模型。多选任务则把题目和多个回答分别用分隔符分开,分多次输入模型。

预训练过程

​ 预训练使用BooksCorpus语料,包含从互联网上获取的7000多本书籍数据,这些书涉及多个不同主题。这个数据集已经无法公开获取,但是可以通过代码自动下载和处理。预训练过程训练100个轮次。

GPT-2和GPT-3

​ GPT-2采用无监督学习,用于训练的数据集是 WebText,该数据集包含几百万网页数据。GPT-2的参数量也很大最大规模的GPT-2有超过15亿个参数。

​ GPT-3参数量高达1750亿个。

BERT

​ 使用 Transformer结的双向编码器表示

​ BERT模型与GPT模型一样都使用Transformer 结构,但BERT使用的是双向Transformer结构,可以同时结合上下文的信息,另外,GPT是Transformer Decoder模型,BERT则是Transformer Encoder。

Hugging Face Transformers

​ Hugging Face Transformers是 Hugging Face 开发的自然语言处理算法库,包含多种先进的使用Transformer 结构的自然语言处理模型,并提供预训练权重

​ Hugging Face Transformers 把它包含的模型分为自回归模型(autoregressive modelARmodel)、自编码模型(Autoencoding model)、Seq2seq 模型、多模态模型(Multimodalmodel)和 Retrieval-based model。

​ 自回归模型包括前面介绍的GPT和GPT-2模型等。自回归模型通过上文预测下一个单词,所以它是单向的语言模型。

​ 自编码模型包括前面介绍的BERT、ALBERT、ROBERTa等模型。自编码器模型的训练目标是忽略输入的噪声从而还原原始输入。自编码模型把输入的一个序列转化为另一个序列。

​ Seq2seq模型

​ 多模态模型指融合多种信息形式的模型, MMBT

使用Transformers

使用HuggingFaceTransformers解决自然语言处理问题主要分为以下几个步骤:预处理数据、定义模型、加载预训练模型、模型调优。模型调优有时可以省略。

下载预训练模型

调用 Tokenizer 或者模型的 from_pretrained 方法时可以自动下载模型。代码如下。采用from_pretrained 方法也可以通过指定本地路径从文件加载模型

from transformers import AutoTokenizer
tokenizer =AutoTokenizer.from_pretrained('bert-base-uncased')#bert-base-chinese

Tokenizer

Tokenizer用于把输入的句子分解为模型词表中的token。

result=tokenizer("并广泛动员社会各方面的力量")
print(result)

-----
{'input_ids': [101, 100, 1842, 100, 100, 100, 1924, 1763, 100, 1863, 1976, 1916, 1778, 100, 102], 
 'token_type_ids': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 'attention_mask': [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]}

原输入有13个字,但得到的 input ids有15个ID,这是因为tokenizer 默认自动添加了特殊符号。不同预训练模型的特殊字符的ID可能不同

可通过allspecialids 方法查看特殊字符ID。

print(tokenizer.all_special_ids)

----
[100, 102, 0, 101, 103]

通过allspecial tokens方法查看所有特殊字符

print(tokenizer.all_special_tokens)

----
['[UNK]', '[SEP]', '[PAD]', '[CLS]', '[MASK]']

BERT的使用

一般可以根据不同的任务选择具体的模型,如文本分类、下一句预测、文本序列标注等都有对应的类,它们都继承于同一个基类,并可以使用相同的预训练参数,但是输入和输出由于#务不同而有所不同。

Hugging Face Transformers 提供针对不同任务的多种模型使构建模型解决具体问题变得很带单。很多情况下甚至无须自定义模型类,而可以直接使用 Hugging Face Transformers 提供的类创建对象。

BertForMaskedLM

BertForMaskedLM 是 BERT 的预训练任务之一,实现了 Masked Language Model.

from transformers import BertTokenizer, BertForMaskedLM
import torch
tokenizer =BertTokenizer.from_pretrained('bert-base-uncased')#bert-base-chinese
model =BertForMaskedLM.from_pretrained('bert-base-uncased')#bert-base-chinese
inputs=tokenizer(["并广泛动员社会[MASK]方面的力量"],return_tensors="pt")
labels= tokenizer(["并广泛动员社会各方面的力量"],return_tensors="pt")["input_ids"]

outputs=model(**inputs,labels=labels)
loss = outputs.loss
logits =outputs.logits
print(loss,logits.shape)
print(inputs['input_ids'])
print(labels)


-----
tensor(3.4853, grad_fn=<NllLossBackward0>) torch.Size([1, 15, 30522])
tensor([[ 101,  100, 1842,  100,  100,  100, 1924, 1763,  103, 1863, 1976, 1916,1778,  100,  102]])
tensor([[ 101,  100, 1842,  100,  100,  100, 1924, 1763,  100, 1863, 1976, 1916,1778,  100,  102]])
BertForNextSentencePrediction

用于预测下一个句子的 BERT,预测下一个句子也是BERT的预训练任务之一。

from transformers import BertTokenizer, BertForNextSentencePrediction
import torch
tokenizer =BertTokenizer.from_pretrained('bert-base-uncased')#bert-base-chinese
model = BertForNextSentencePrediction.from_pretrained('bert-base-uncased')
prompt="在我的后园,可以看见墙外有两株树,"
next_sentence_1="一株是枣树,还有一株也是枣树"
next_sentence_2="一九二四年九月十五日"
encoding = tokenizer(prompt, next_sentence_1, return_tensors='pt')
outputs = model(**{k: v.unsqueeze(0) for k,v in encoding.items()}, labels=labels)
loss =outputs.loss
logits= outputs.logits
print(logits)

BertForTokenClassification

BertForTokenClassification 是用于标记序列中的元素的BERT模型,会给序列中每个元素输出一个标签。

from transformers import BertTokenizer, BertForTokenClassification
import torch
tokenizer =BertTokenizer.from_pretrained('bert-base-uncased')#bert-base-chinese
model = BertForTokenClassification.from_pretrained('bert-base-uncased')

inputs=tokenizer("一九二四年九月十五日",return_tensors="pt")
labels = torch.tensor([0,1,1,1,1,0,1,0,1,1,0,0]).unsqueeze(0)

outputs=model(**inputs,labels=labels)
loss = outputs.loss
logits =outputs.logits
print(logits)

-----
tensor([[[-0.4444,  0.2574],
         [ 0.6357,  0.1568],
         [ 0.5538, -0.1078],
         [ 0.6453, -0.0598],
         [ 0.6642,  0.0519],
         [ 0.7227, -0.0997],
         [ 0.6060, -0.0166],
         [ 0.7038,  0.1973],
         [ 0.6122,  0.0787],
         [ 0.6021,  0.2544],
         [ 0.6061, -0.1438],
         [ 0.1394, -0.7285]]], grad_fn=<ViewBackward0>)

BertForQuestionAnswering

BertForQuestionAnswering是用于完成问答问题的BERT模型

from transformers import BertTokenizer, BertForQuestionAnswering
import torch
tokenizer =BertTokenizer.from_pretrained('bert-base-uncased')#bert-base-chinese
model = BertForQuestionAnswering.from_pretrained('bert-base-uncased')
question,text = "在我的后园,可以看见墙外有两株树,一株是枣树,另一株是什么树?","也是枣树。"
inputs = tokenizer(question, text,return_tensors='pt')
outputs = model(**inputs)
loss = outputs.loss
start_scores = outputs.start_logits
end_scores = outputs.end_logits

其他开源中文预训练模型

目前 Hugging Face Transformers 只提供 BERT的中文版本,但该模型只有 base规模。

TAL-EduBERT

Albert


实践 使用 Hugging Face Transformers 中的 BERT 做帖子标题分类

# 定义两个列表分别存储两个板块的帖子数据
# academy_titles 考研考博 job_titles 招聘信息

# 定义两个list分别存放两个板块的帖子数据
academy_titles = []
job_titles = []
with open('E:/nlp/dataSet/academy_titles.txt', encoding='utf8') as f:
    for l in f:  # 按行读取文件
        academy_titles.append(l.strip( ))  # strip 方法用于去掉行尾空格
with open('E:/nlp/dataSet/job_titles.txt', encoding='utf8') as f:
    for l in f:  # 按行读取文件
        job_titles.append(l.strip())  # strip 方法用于去掉行尾空格
# 合并两个列表的label
data_list = []
for title in academy_titles:
    data_list.append([title, 0])

for title in job_titles:
    data_list.append([title, 1])
# 计算标题的最大长度
max_length = 0
for case in data_list:
    max_length = max(max_length, len(case[0])+2)
print(max_length)
# 切分训练集和评估集
from sklearn.model_selection import train_test_split
train_list, dev_list = train_test_split(data_list,test_size=0.3,random_state=15,shuffle=True)
# 导入包和设置参数
import os
import time
import random
import torch
import torch.nn.functional as F
from torch import nn
from tqdm import tqdm
import random

from transformers import get_linear_schedule_with_warmup, AdamW
from transformers import BertTokenizer, BertForSequenceClassification

if torch.cuda.is_available():
    device = torch.device("cuda")
else:
    device = torch.device("cpu")
max_train_epochs = 6
warmup_proportion = 0.05
gradient_accumulation_steps = 2
train_batch_size = 16
valid_batch_size = train_batch_size
test_batch_size = train_batch_size
data_workers= 2

learning_rate=1e-6
weight_decay=0.01
max_grad_norm=1.0
cur_time = time.strftime("%Y-%m-%d_%H:%M:%S") # 当前日期时间字符串
# 定义dataset和dataloader
tokenizer = BertTokenizer.from_pretrained('bert-base-uncased')
class MyDataSet(torch.utils.data.Dataset):
    def __init__(self, examples):
        self.examples = examples

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

    def __getitem__(self, index):
        example = self.examples[index]
        title = example[0]
        label = example[1]
        r = tokenizer.encode_plus(title, max_length=max_length, padding="max_length")
        return title, label, index#, r['token_type_ids'], label, index

def the_collate_fn(batch):
    r = tokenizer([b[0] for b in batch], padding=True)
    input_ids = torch.LongTensor(r['input_ids'])
    attention_mask = torch.LongTensor(r['attention_mask'])
    label = torch.LongTensor([b[1] for b in batch])
    indexs = [b[2] for b in batch]
    return input_ids, attention_mask, label, indexs #, token_type_ids

train_dataset = MyDataSet(train_list)
train_data_loader = torch.utils.data.DataLoader(
    train_dataset,
    batch_size=train_batch_size,
    shuffle = True,
    num_workers=data_workers,
    collate_fn=the_collate_fn,
)

dev_dataset = MyDataSet(dev_list)
dev_data_loader = torch.utils.data.DataLoader(
    dev_dataset,
    batch_size=train_batch_size,
    shuffle = False,
    num_workers=data_workers,
    collate_fn=the_collate_fn,
)
# 定义评估函数 
def get_score():
    y_true = []
    y_pred = []
    for step, batch in enumerate(tqdm(dev_data_loader)):
        model.eval()
        with torch.no_grad():
            input_ids, attention_mask = (b.to(device) for b in batch[:2])
        y_true += batch[2].numpy().tolist()
        logist = model(input_ids, attention_mask)[0]
        result = torch.argmax(logist, 1).cpu().numpy().tolist()
        y_pred += result
    correct = 0
    for i in range(len(y_true)):
        if y_true[i] == y_pred[i]:
            correct += 1
    accuracy = correct / len(y_pred)
    
    return accuracy
# 定义模型
# 可以直接使用BertForSequenceClassification而无需重新定义模型,并使用adamw优化器
model = BertForSequenceClassification.from_pretrained('bert-base-uncased')
model.to(device)

t_total = len(train_data_loader) // gradient_accumulation_steps * max_train_epochs + 1
num_warmup_steps = int(warmup_proportion * t_total)
print('warmup steps : %d' % num_warmup_steps)
no_decay = ['bias', 'LayerNorm.weight'] # no_decay = ['bias', 'LayerNorm.bias', 'LayerNorm.weight']
param_optimizer = list(model.named_parameters())
optimizer_grouped_parameters = [
    {'params':[p for n, p in param_optimizer if not any(nd in n for nd in no_decay)],'weight_decay': weight_decay},
    {'params':[p for n, p in param_optimizer if any(nd in n for nd in no_decay)],'weight_decay': 0.0}
]
optimizer = AdamW(optimizer_grouped_parameters, lr=learning_rate, correct_bias=False)
scheduler = get_linear_schedule_with_warmup(optimizer, num_warmup_steps=num_warmup_steps, num_training_steps=t_total)

------
Some weights of BertForSequenceClassification were not initialized from the model checkpoint at bert-base-uncased and are newly initialized: ['classifier.bias', 'classifier.weight']
You should probably TRAIN this model on a down-stream task to be able to use it for predictions and inference.
warmup steps : 46
def print_test(title):
    r = tokenizer([title])
    input_ids = torch.LongTensor(r['input_ids']).to(device)
    attention_mask = torch.LongTensor(r['attention_mask']).to(device)
    logist = model(input_ids, attention_mask)[0]
    result = torch.argmax(logist, 1).cpu().numpy().tolist()[0]
    result = ['考研考博', '招聘信息'][result]
    print(title, result)
def print_cases():
    print_test('考研心得')
    print_test('北大实验室博士')
    print_test('考外校博士')
    print_test('北大实验室招博士')
    print_test('工作or考研?')
    print_test('急求自然语言处理工程师')
    print_test('校招offer比较')
# 训练模型
import time
time.clock =time.perf_counter
for epoch in range(max_train_epochs):
    b_time = time.time()
    model.train()
    for step, batch in enumerate(tqdm(train_data_loader)):
        input_ids, attention_mask, label = (b.to(device) for b in batch[:-1])
        loss = model(input_ids, attention_mask, labels=label)
        loss = loss[0]
        loss.backward()
        if (step + 1) % gradient_accumulation_steps == 0:
            optimizer.step()
            scheduler.step() 
            optimizer.zero_grad()
    print('Epoch = %d Epoch Mean Loss %.4f Time %.2f min' % (epoch+1, loss.item(), (time.time() - b_time)/60))
    print(get_score())
    print_cases()

标签:训练,模型,torch,帖子,print,import,model
From: https://www.cnblogs.com/idazhi/p/17880967.html

相关文章

  • 数据分享|AARRR模型淘宝用户行为分析、电商销售分析
    全文链接:https://tecdat.cn/?p=34482原文出处:拓端数据部落公众号分析师:YeYuan随着互联网、5G时代到来,大数据横空出世,数据变得越来越重要,如何针对业务问题和需求,提取有效特征数据并对问题进行深入分析,最终得到可靠的结论是数据分析最核心的环节,只有得出正确的结论才能对症下药......
  • R语言SIR模型网络结构扩散过程模拟SIR模型(Susceptible Infected Recovered )代码实例|
    全文链接:http://tecdat.cn/?p=14593最近我们被客户要求撰写关于SIR模型的研究报告,包括一些图形和统计输出。与普通的扩散研究不同,网络扩散开始考虑网络结构对于扩散过程的影响。这里介绍一个使用R模拟网络扩散的例子基本的算法非常简单:生成一个网络:g(V,E)。随机选择一个或几......
  • 代码随想录算法训练营第七天| 344.反转字符串 541. 反转字符串II
    LeetCode344.反转字符串题目链接: LeetCode344思路: 定义left、right指针,将两指针对应的值反转即可 classSolution{public:voidreverseString(vector<char>&s){intn=s.size();for(intleft=0,right=n-1;left<right;++left,--right){......
  • 俄罗斯AI突破:Kandinsky-3模型的创新与性能解析
    引言俄罗斯AI研究团队AIForever在开源领域再次取得显著成就,推出了Kandinsky-3模型。这一模型以其11.9B的庞大参数量,不仅刷新了开源文生图模型的规模纪录,也代表了俄罗斯在AI技术方面的重要突破。Kandinsky2.2与Kandinsky-3的演进Kandinsky-3的前身Kandinsky2.2结合了DALL-E2和La......
  • 大模型词表构建
    1.引言在文本输入embedding层之前,以中文文本为例,首先对文本进行分词并进行one-hot编码,分词肯定是根据词表来进行分词,那构建一个合适的词表就显得至关重要,过大或者过小都会对后续模型的训练效果产生影响。所以这里介绍当前各个大模型的词表构建方法。2.技术基础在介绍具体的词......
  • 史文钊谈数字技术在医学创新中的应用:大模型不求大,贵在精
    近日,国际性学术会议“北京论坛2023”隆重召开,迄今已举办20届。本届论坛以“文明的和谐与共同繁荣——传承与互鉴”为主题,下设16个分论坛和4个专题论坛,来自国内外各领域的600余位顶级专家学者聚焦后疫情时代的全球可持续发展,通过对话与交流为解决新时代课题贡献智慧。作为北......
  • 在科技行业的热门趋势中,你必定无法忽视日益增长的人工智能大模型的影响力。无论是你热
    在科技行业的热门趋势中,你必定无法忽视日益增长的人工智能大模型的影响力。无论是你热衷浏览的短视频还是见不得的“AI绘画”,或者是你的朋友圈中充斥的“虚拟试衣”和智能聊天软件ChatGPT,这些都在告诉你,AI大模型正在为日常生活带来革命性的改变。今天,我们就来探讨如何使用AI大模型......
  • 第四单元 视图与模型
    createdatabaseMvcUnit4;gouseMvcUnit4;gocreatetableProduct(Idbigintprimarykey,ProductNamevarchar(30),CategoryNamevarchar(30),Pricedecimal(10,2),Remarkvarchar(200),CreatedUserIdbigint,UpdatedUserIdbigint......
  • three.js 使用 sortObjects 和 renderOrder 处理网格修改后覆盖模型的问题
    问题效果:目标效果处理此问题首先需要了解three的渲染机制:渲染机制threejs的渲染器是基于webGL的。它的渲染机制是根据物体离照相机的距离来控制和进行渲染的。也就是说,它根据物体的空间位置进行排序,然后根据这个顺序来渲染物体。对于透明的物体,是按照从最远到最近的顺序进行......
  • 【自己搭建一个:端到端的语音+大模型聊天机器人】
    概要发篇文章记录一下最近搞的语音+大模型聊天机器人的搭建过程,供交流学习。有正反馈的话会继续优化。整体架构流程注意:借传统的基于RASA的对话机器人的图一用,本博会把NLU(NaturalLanguageUnderstanding)和DialogueManagement这两个组件,用大模型来替代。组件及模型说明:用......