旧项目新学习-天池-零基础入门NLP_-_新闻文本分类_-_BERT算法处理

当时代码使用了机器学习的方法进行处理,结果仅有80%多的准确率,最近整理代码发现这个项目已经有了更好的处理方式,记录一下代码的训练过程,

bert算法,可以用于nlp任务,由Google AI于2018年推出。在多种语言理解任务中取得了显著的性能提升,包括问答系统、语言推断、情感分析等。核心创新在于利用双向Transformer网络预训练深度双向表征,这些表征随后可以被微调用来改善各种特定的NLP任务。

1、bert理论(待补充)(已经补充至萱仔大模型学习记录)

bert算法是自然语言处理(NLP)领域的一项重要技术。这种算法帮助计算机理解和使用人类语言。这个算法特色是其“双向”处理能力。不同于传统语言模型只从一个方向读取文本,bert能同时从左到右和从右到左考虑上下文,这样能更全面地理解每个词的含义。Transformers结构适合处理大量数据。通过在大量文本上的训练,例如书籍、文章和网页。

bert训练方式

bert有两种训练方式在实际应用中,BERT能显著提升翻译、问题回答、内容总结等任务的表现。总的来说,bert算法通过模仿阅读和理解的过程,提高计算机处理语言任务的能力。

1. 掩码语言模型(MLM)

在这个训练任务中,算法从输入的文本中随机选择并隐藏一定比例的词汇。例如,句子“我喜欢吃苹果”可能被转换为“我喜欢吃 [MASK]”。然后,BERT需要预测出被掩盖的词是什么。这种方法迫使模型不仅考虑掩码词前的语境,也考虑后面的语境,从而实现双向理解。

2. 下一句预测(NSP)

在这个任务中,模型接收一对句子,并需要预测第二个句子是否是第一个句子的逻辑后续。这种类型的训练帮助模型学习理解句子之间的关系,问答系统和自然语言推理可以使用到这个模型。

bert微调

微调(Fine-tuning)是将预训练的模型应用到特定任务的过程。这一步骤是在预训练完成后进行的,目的是调整模型以适应具体的应用场景,如情感分析、文本分类、问答系统等。下面是进行微调的典型步骤:

1. 选择适当的预训练模型

首先,需要选取一个已经在大规模文本数据上进行预训练的模型。

2. 准备任务特定的数据集

根据需要解决的问题,准备相应的数据集。这个数据集应包含任务相关的输入文本以及对应的标签或答案。例如,对于情感分析任务,数据集会包含文本和其对应的情感标签(如正面、负面)。还有我这个任务中的文本数据数据集包括了14个类别的标签。

3. 设置任务特定的模型结构

一般来说bert的核心架构不变,为了完成我具体的任务,我得在其顶部添加特定的层来适应具体的任务。例如,对于分类任务,可以在BERT的输出上添加一个全连接层,这个层负责将BERT的输出映射到类别标签上。

4. 微调超参数调参

要调整一些超参数,如学习率lr,轮数epoch,批量batch size。这些参数会影响训练的速度和最终的模型效果。

5. 训练模型

使用特定任务的数据集来训练模型。这个过程中,模型参数会根据任务数据进行调整。通常,微调不需要像预训练那样的大量迭代,因为模型已经具备了一定的语言处理能力。

6. 评估模型性能

在独立的验证数据集上评估模型的表现,确保模型没有过拟合。可能需要反复调整模型结构和超参数,以达到最佳效果。

7. 应用模型

一旦模型在验证集上表现良好,就可以在实际的应用场景中部署使用了。需要持续监控模型的表现,并根据实际使用中遇到的问题进行调整。

这个微调过程使得模型可以从通用的语言理解转变为针对特定任务的优化,提高了模型在特定领域的应用效果和准确度。

2、bert算法微调实践demo

由于本地内存实在有限,选择先调试通代码然后去服务器运行,以下是具体步骤。

将bert用于本新闻文本分类算法的数据集,本代码的结构是一个tool.py,train.py,test.py,eva.py:

首先是tool的代码,其中包括了数据集的处理,和bert模型的引入,后面补充加了一个全连接层进行训练。主要是为了适应我这个工作输出新闻文本类型有14个类型。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

#xuan_tools.py

import torch
from torch.utils.data import Dataset
from transformers import BertTokenizer, BertModel
import pandas as pd
import torch.nn as nn

class XuanDataset(Dataset):
def __init__(self, sentences, labels, max_length=128):
self.tokenizer = BertTokenizer.from_pretrained('D:/pytorch/nlp_new')#这里放模型架构文件地址
self.sentences = sentences
self.labels = torch.tensor(labels, dtype=torch.long)
self.max_length = max_length

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

def __getitem__(self, index):
sent = self.sentences[index]
label = self.labels[index]
encoded_pair = self.tokenizer(sent, padding='max_length', truncation=True, max_length=self.max_length, return_tensors='pt')
token_ids = encoded_pair['input_ids'].squeeze(0)
attn_masks = encoded_pair['attention_mask'].squeeze(0)
token_type_ids = encoded_pair['token_type_ids'].squeeze(0)
return token_ids, attn_masks, token_type_ids, label

class Bert_c(nn.Module):
def __init__(self, num_classes=14):#这里是需要分类的类别
super(Bert_c, self).__init__()
self.bert = BertModel.from_pretrained('D:/pytorch/nlp_new')
#这里放模型架构文件https://huggingface.co/models这里下载
self.linear = nn.Linear(768, num_classes)
self.dropout = nn.Dropout(0.5)

def forward(self, token_ids, attn_masks, token_type_ids):
outputs = self.bert(input_ids=token_ids, attention_mask=attn_masks, token_type_ids=token_type_ids)
logits = self.linear(self.dropout(outputs.pooler_output))
return logits

然后是训练的过程如下:

可以看出来训练还是选择读入了以前那个新闻文本分类的数据集,然后对bert的算法进行微调

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49

# train.py

import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader
from sklearn.model_selection import train_test_split
import pandas as pd
import matplotlib.pyplot as plt
from xuan_tools import XuanDataset, Bert_c

def main():
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
df = pd.read_csv('D:/pytorch/nlp_new/train.csv', sep='\t')
X_train, X_test, y_train, y_test = train_test_split(df['text'], df['label'], test_size=0.2, random_state=42)

train_dataset = XuanDataset(X_train.tolist(), y_train.tolist())
train_loader = DataLoader(dataset=train_dataset, batch_size=2, shuffle=True)

model = Bert_c(num_classes=14).to(device)
optimizer = optim.Adam(model.parameters(), lr=1e-3)
loss_fn = nn.CrossEntropyLoss()

losses = []
model.train()
for epoch in range(100):#这里是训练轮数
total_loss = 0
for token_ids, attn_masks, token_type_ids, labels in train_loader:
token_ids, attn_masks, token_type_ids, labels = token_ids.to(device), attn_masks.to(device), token_type_ids.to(device), labels.to(device)
optimizer.zero_grad()
outputs = model(token_ids, attn_masks, token_type_ids)
loss = loss_fn(outputs, labels)
loss.backward()
optimizer.step()
total_loss += loss.item()
losses.append(total_loss)
print(f'Epoch {epoch + 1}, Loss: {total_loss}')

torch.save(model.state_dict(), 'bert_model.pth')
plt.plot(losses)
plt.title('Training Loss')
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.savefig('training_loss.png')

if __name__ == '__main__':
main()

验证的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader
from sklearn.model_selection import train_test_split
import pandas as pd
import matplotlib.pyplot as plt
from xuan_tools import XuanDataset, Bert_c

def main():
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
model = BertClassify().to(device)
model.load_state_dict(torch.load('bert_model.pth'))
model.eval()

df = pd.read_csv('D:/pytorch/nlp_new/eva.csv', delimiter='\t')
X_val, y_val = df['text'].tolist(), df['label'].tolist()

validate_dataset = MyDataset(X_val, y_val)
validate_loader = Data.DataLoader(dataset=validate_dataset, batch_size=2, shuffle=False)

correct = 0
total = 0
with torch.no_grad():
for token_ids, attn_masks, token_type_ids, labels in validate_loader:
token_ids, attn_masks, token_type_ids, labels = token_ids.to(device), attn_masks.to(device), token_type_ids.to(device), labels.to(device)
outputs = model(token_ids, attn_masks, token_type_ids)
_, predicted = torch.max(outputs.data, 1)
total += labels.size(0)
correct += (predicted == labels).sum().item()

print(f'Accuracy of the network on the validation texts: {100 * correct / total}%')
if __name__ == '__main__':
main()