当前位置: 首页 > news >正文

NLP | 基于LLMs的文本分类任务

比赛链接:讯飞开放平台

来源:DataWhale AI夏令营3(NLP)

Roberta-base(BERT的改进)

①Roberta在预训练的阶段中没有对下一句话进行预测(NSP

②采用了动态掩码 ③使用字符级词级别表征的混合文本编码

论文:https://arxiv.org/pdf/1907.11692.pdf

DataWhale Topline的改进:

  特征1:平均池化MeanPooling(768维) -> 全连接层fc(128维)

  特征2:末隐藏层Last_hidden (768维) -> 全连接层fc(128维)

运行方式:阿里云机器学习平台PAI-交互式建模DSW

镜像选择pytorch:1.12-gpu-py39-cu113-ubuntu20.04

上传代码,解压指令:

unzip [filename]

运行py脚本指令(遇到网络错误重新运行即可):
 

python [python_filename]

① 数据处理模块

导入需要的模块:

from transformers import AutoTokenizer  #文本分词
import pandas as pd
import numpy as np
from tqdm import tqdm  #显示进度条
import torch
from torch.nn.utils.rnn import pad_sequence
#填充序列,保证向量中各序列维度的大小一样MAX_LENGTH = 128  #定义最大序列长度为128

训练集制作:

def get_train(model_name, model_dict):model_index = model_dict[model_name]  # 获取模型索引train = pd.read_csv('./dataset/train.csv') #读取训练数据为DataFrametrain['content'] = train['title'] + train['author'] + train['abstract']  #将标题、作者和摘要拼接为训练内容tokenizer = AutoTokenizer.from_pretrained(model_name, max_length=MAX_LENGTH, cache_dir=f'./premodels/{model_name}_saved')  # 实例化分词器对象# 通过分词器对训练数据进行分词,并获取输入ID、注意力掩码和标记类型ID(这个可有可无)input_ids_list, attention_mask_list, token_type_ids_list = [], [], []y_train = []  # 存储训练数据的标签for i in tqdm(range(len(train['content']))):  # 遍历训练数据sample = train['content'][i]  # 获取样本内容tokenized = tokenizer(sample, truncation='longest_first') #分词处理,【最长优先方式】截断input_ids, attention_mask = tokenized['input_ids'], tokenized['attention_mask']  # 获取输入ID和注意力掩码input_ids, attention_mask = torch.tensor(input_ids), torch.tensor(attention_mask)  # 转换为PyTorch张量try:token_type_ids = tokenized['token_type_ids']  # 获取标记类型IDtoken_type_ids = torch.tensor(token_type_ids) # 转换为PyTorch张量except:token_type_ids = input_ids #异常处理input_ids_list.append(input_ids)  # 将输入ID添加到列表中attention_mask_list.append(attention_mask)  # 将注意力掩码添加到列表中token_type_ids_list.append(token_type_ids)  # 将标记类型ID添加到列表中y_train.append(train['label'][i])  # 将训练数据的标签添加到列表中# 保存 对下述对象进行填充,保证向量中各序列维度的大小一样,生成张量# 输入      ID input_ids_tensor、# 注意力掩码 attention_mask_tensor# 标记类型ID token_type_ids_tensorinput_ids_tensor = pad_sequence(input_ids_list, batch_first=True, padding_value=0)attention_mask_tensor = pad_sequence(attention_mask_list, batch_first=True, padding_value=0)token_type_ids_tensor = pad_sequence(token_type_ids_list, batch_first=True, padding_value=0) x_train = torch.stack([input_ids_tensor, attention_mask_tensor, token_type_ids_tensor], dim=1)  # 将输入张量堆叠为一个张量x_train = x_train.numpy()   # 转换为NumPy数组(ndarray)np.save(f'./models_input_files/x_train{model_index}.npy', x_train) #保存训练数据y_train = np.array(y_train) # 转换为NumPy数组(ndarray)np.save(f'./models_input_files/y_train{model_index}.npy', y_train) #保存标签数据

测试集制作:

def get_test(model_name, model_dict):model_index = model_dict[model_name]  # 获取模型索引test = pd.read_csv('./dataset/testB.csv')  # 从CSV文件中读取测试数据为DataFrametest['content'] = test['title'] + ' ' + test['author'] + ' ' + test['abstract']  # 将标题、作者和摘要拼接为测试内容tokenizer = AutoTokenizer.from_pretrained(model_name, max_length=MAX_LENGTH,cache_dir=f'./premodels/{model_name}_saved')  # 实例化分词器对象# 通过分词器对测试数据进行分词,创建输入ID、注意力掩码和标记类型ID列表进行记录(可有可无)input_ids_list, attention_mask_list, token_type_ids_list = [], [], []for i in tqdm(range(len(test['content']))):  # 遍历测试数据sample = test['content'][i]  # 获取样本内容tokenized = tokenizer(sample, truncation='longest_first')  # 分词处理,使用最长优先方式截断input_ids, attention_mask = tokenized['input_ids'], tokenized['attention_mask']  # 获取输入ID和注意力掩码input_ids, attention_mask = torch.tensor(input_ids), torch.tensor(attention_mask)  # 转换为PyTorch张量try:token_type_ids = tokenized['token_type_ids']  # 获取标记类型IDtoken_type_ids = torch.tensor(token_type_ids)  # 转换为PyTorch张量except:token_type_ids = input_ids #异常处理input_ids_list.append(input_ids)  # 将输入ID添加到列表中attention_mask_list.append(attention_mask)  # 将注意力掩码添加到列表中token_type_ids_list.append(token_type_ids)  # 将标记类型ID添加到列表中# 保存,对输入ID、注意力掩码、标记类型ID进行填充,保证向量中各序列维度的大小一样,生成张量input_ids_tensor = pad_sequence(input_ids_list, batch_first=True, padding_value=0) attention_mask_tensor = pad_sequence(attention_mask_list, batch_first=True, padding_value=0)token_type_ids_tensor = pad_sequence(token_type_ids_list, batch_first=True, padding_value=0) x_test = torch.stack([input_ids_tensor, attention_mask_tensor, token_type_ids_tensor], dim=1)  # 将输入张量堆叠为一个张量x_test = x_test.numpy()  # 转换为NumPy数组np.save(f'./models_input_files/x_test{model_index}.npy', x_test)  # 保存测试数据

划分训练集和验证集:

def split_train(model_name, model_dict):# 训练集:验证集 = 9 : 1split_rate = 0.90# 处理样本内容model_index = model_dict[model_name]  # 获取模型索引train = np.load(f'./models_input_files/x_train{model_index}.npy')  # 加载训练数据state = np.random.get_state()  # 获取随机数状态,保证样本间的随机是可重复的# 或者也可以设置经典随机种子random_seed=42np.random.shuffle(train)  # 随机打乱训练数据,数据洗牌val = train[int(train.shape[0] * split_rate):]  # 划分验证集 validationtrain = train[:int(train.shape[0] * split_rate)]  # 划分训练集 train setnp.save(f'./models_input_files/x_train{model_index}.npy', train)  # 保存训练集np.save(f'./models_input_files/x_val{model_index}.npy', val)  # 保存验证集train = np.load(f'./models_input_files/y_train{model_index}.npy')  # 加载标签数据# 处理样本标签np.random.set_state(state)  # 恢复随机数状态,让样本标签的随机可重复np.random.shuffle(train)  # 随机打乱标签数据val = train[int(train.shape[0] * split_rate):]  # 划分验证集 validationtrain = train[:int(train.shape[0] * split_rate)]  # 划分训练集 train setnp.save(f'./models_input_files/y_train{model_index}.npy', train)  # 保存训练集标签np.save(f'./models_input_files/y_val{model_index}.npy', val)  # 保存验证集标签print('split done.')

数据处理主函数:

if __name__ == '__main__':model_dict = {'xlm-roberta-base':1,'roberta-base':2, 'bert-base-uncased':3, 'microsoft/BiomedNLP-PubMedBERT-base-uncased-abstract-fulltext':4, 'dmis-lab/biobert-base-cased-v1.2':5, 'marieke93/MiniLM-evidence-types':6,'microsoft/MiniLM-L12-H384-uncased':7, 'cambridgeltl/SapBERT-from-PubMedBERT-fulltext':8,'microsoft/BiomedNLP-PubMedBERT-base-uncased-abstract':9,'microsoft/BiomedNLP-PubMedBERT-large-uncased-abstract':10}model_name = 'roberta-base'get_train(model_name, model_dict) #读取训练集get_test(model_name, model_dict)  #读取测试集split_train(model_name, model_dict) #划分训练集和测试集

② 模型训练

导入需要的模块:

import numpy as np
import torch
import torch.nn as nn
from sklearn import metrics
import os
import time
from transformers import AutoModel, AutoConfig
# 导入AutoModel和AutoConfig类,用于加载预训练模型
from tqdm import tqdm  #显示进度条

超参数类(可修改的所有超参数):

class opt:seed               = 42 # 随机种子batch_size         = 16 # 批处理大小set_epoch          = 5  # 训练轮数 early_stop         = 5  # 提前停止epoch数learning_rate      = 1e-5 # 学习率weight_decay       = 2e-6 # 权重衰减,L2正则化device             = torch.device("cuda" if torch.cuda.is_available() else "cpu") # 选择设备,GPU或CPUgpu_num            = 1 # GPU个数use_BCE            = False # 是否使用BCE损失函数models             = ['xlm-roberta-base', 'roberta-base', 'bert-base-uncased',  'microsoft/BiomedNLP-PubMedBERT-base-uncased-abstract-fulltext', 'dmis-lab/biobert-base-cased-v1.2', 'marieke93/MiniLM-evidence-types',  'microsoft/MiniLM-L12-H384-uncased','cambridgeltl/SapBERT-from-PubMedBERT-fulltext', 'microsoft/BiomedNLP-PubMedBERT-base-uncased-abstract','microsoft/BiomedNLP-PubMedBERT-large-uncased-abstract'] # 模型名称列表model_index        = 2 # 根据上面选择使用的模型,这里填对应的模型索引model_name         = models[model_index-1] # 使用的模型名称continue_train     = False # 是否继续训练show_val           = False # 是否显示验证过程

定义模型类:

# 定义模型
class MODEL(nn.Module):def __init__(self, model_index):super(MODEL, self).__init__()# 若是第一次下载权重,则下载至同级目录的./premodels/内,以防占主目录的存储空间self.model = AutoModel.from_pretrained(opt.models[model_index-1], cache_dir='./premodels/'+opt.models[model_index-1]+'_saved', from_tf=False) # 加载预训练语言模型# 加载模型配置,可以直接获得模型最后一层的维度,而不需要手动修改config = AutoConfig.from_pretrained(opt.models[model_index-1], cache_dir='./premodels/'+opt.models[model_index-1]+'_saved') # 获取配置last_dim = config.hidden_size # 最后一层的维度if opt.use_BCE:out_size = 1 # 损失函数如果使用BCE,则输出大小为1else          :out_size = 2 # 否则则使用CE,输出大小为2feature_size = 128 # 设置特征的维度大小self.fc1 = nn.Linear(last_dim, feature_size) # 全连接层1self.fc2 = nn.Linear(last_dim, feature_size) # 全连接层2self.classifier = nn.Linear(feature_size, out_size) # 分类器self.dropout = nn.Dropout(0.3) # Dropout层def forward(self, x): #BPinput_ids, attention_mask, token_type_ids = x[:,0],x[:,1],x[:,2] # 获取输入x = self.model(input_ids, attention_mask) # 通过模型all_token     = x[0] # 全部序列分词的表征向量pooled_output = x[1] # [CLS]的表征向量+一个全连接层+Tanh激活函数feature1 = all_token.mean(dim=1) # 对全部序列分词的表征向量取均值feature1 = self.fc1(feature1)    # 再输入进全连接层,得到feature1feature2 = pooled_output      # [CLS]的表征向量+一个全连接层+Tanh激活函数feature2 = self.fc2(feature2) # 再输入进全连接层,得到feature2feature  = 0.5*feature1 + 0.5*feature2 # 加权融合特征feature  = self.dropout(feature) # Dropoutx  = self.classifier(feature) # 分类return x

数据加载:

def load_data():#数据集路径train_data_path     = f'models_input_files/x_train{model_index}.npy'train_label_path    = f'models_input_files/y_train{model_index}.npy'val_data_path       = f'models_input_files/x_val{model_index}.npy'# 验证集val_label_path      = f'models_input_files/y_val{model_index}.npy'# 验证集标签test_data_path      = f'models_input_files/x_test{model_index}.npy'# 测试集输入#数据集读取#data=torch.tensor([path],allow_pickle=True).tolist())train_data          = torch.tensor(np.load(train_data_path  , allow_pickle=True).tolist())train_label         = torch.tensor(np.load(train_label_path  , allow_pickle=True).tolist()).long() val_data            = torch.tensor(np.load(val_data_path  , allow_pickle=True).tolist()) val_label           = torch.tensor(np.load(val_label_path  , allow_pickle=True).tolist()).long()test_data           = torch.tensor(np.load(test_data_path  , allow_pickle=True).tolist()) #构造训练集、验证集、测试集train_dataset       = torch.utils.data.TensorDataset(train_data  , train_label) val_dataset         = torch.utils.data.TensorDataset(val_data  , val_label) test_dataset        = torch.utils.data.TensorDataset(test_data) return train_dataset, val_dataset, test_dataset # 返回数据集

模型预训练:

def model_pretrain(model_index, train_loader, val_loader):# 超参数设置set_epoch          = opt.set_epoch  # 训练轮数early_stop         = opt.early_stop # 提前停止epoch数learning_rate      = opt.learning_rate # 学习率weight_decay       = opt.weight_decay  # 权重衰减device             = opt.device  # 设备 gpu_num            = opt.gpu_num # GPU个数continue_train     = opt.continue_train # 是否继续训练model_save_dir     = 'checkpoints' # 模型保存路径# 是否要继续训练,若是,则加载模型进行训练;若否,则跳过训练,直接对测试集进行推理if not continue_train:# 判断最佳模型是否已经存在,若存在则直接读取,若不存在则进行训练if os.path.exists(f'checkpoints/best_model{model_index}.pth'): best_model = MODEL(model_index)best_model.load_state_dict(torch.load(f'checkpoints/best_model{model_index}.pth')) # 加载模型return best_modelelse:pass# 模型初始化model = MODEL(model_index).to(device) if continue_train:model.load_state_dict(torch.load(f'checkpoints/best_model{model_index}.pth')) # 继续训练加载模型# 优化器初始化if device    != 'cpu' and gpu_num > 1:  # 多张显卡optimizer = torch.optim.AdamW(model.module.parameters(), lr=learning_rate, weight_decay=weight_decay)optimizer = torch.nn.DataParallel(optimizer, device_ids=list(range(gpu_num))) # 多GPUelse: # 单张显卡optimizer = torch.optim.AdamW(model.parameters(), lr=learning_rate, weight_decay=weight_decay) # 单GPU# 损失函数初始化if opt.use_BCE:loss_func = nn.BCEWithLogitsLoss() # BCE损失else:loss_func = nn.CrossEntropyLoss() # 交叉熵损失(CE)# 模型训练best_epoch         = 0 # 最佳epochbest_train_loss    = 100000 # 最佳训练损失train_acc_list     = [] # 训练准确率列表train_loss_list    = [] # 训练损失列表val_acc_list       = [] # 验证准确率列表 val_loss_list      = [] # 验证损失列表start_time         = time.time() # 训练开始时间for epoch in range(set_epoch): # 轮数model.train() # 模型切换到训练模式train_loss = 0 # 训练损失train_acc = 0 # 训练准确率for x, y in tqdm(train_loader): # 遍历训练集# 训练前先将数据放到GPU上x        = x.to(device)y        = y.to(device)outputs  = model(x) # 前向传播if opt.use_BCE: # BCE损失loss = loss_func(outputs, y.float().unsqueeze(1)) else: # 交叉熵损失loss = loss_func(outputs, y)train_loss += loss.item() # 累加训练损失optimizer.zero_grad() # 清空梯度loss.backward() # 反向传播if device != 'cpu' and gpu_num > 1: # 多GPU更新optimizer.module.step()  else:optimizer.step() # 单GPU更新if not opt.use_BCE: # 非BCE损失_, predicted = torch.max(outputs.data, 1) # 预测结果else:predicted = (outputs > 0.5).int() # 预测结果predicted = predicted.squeeze(1) train_acc   += (predicted == y).sum().item() # 计算训练准确率average_mode = 'binary'# 计算F1、Precision、Recalltrain_f1     = metrics.f1_score(y.cpu(), predicted.cpu(), average=average_mode)train_pre    = metrics.precision_score(y.cpu(), predicted.cpu(), average=average_mode)train_recall = metrics.recall_score(y.cpu(), predicted.cpu(), average=average_mode)train_loss /= len(train_loader) # 平均所有步数的训练损失作为一个epoch的训练损失train_acc  /= len(train_loader.dataset) # 平均所有步数训练准确率作为一个epoch的准确率train_acc_list.append(train_acc)   # 添加训练准确率train_loss_list.append(train_loss) # 添加训练损失print('-'*50)print('Epoch [{}/{}]\n Train Loss: {:.4f}, Train Acc: {:.4f}'.format(epoch + 1, set_epoch, train_loss, train_acc))print('Train-f1: {:.4f}, Train-precision: {:.4f} Train-recall: {:.4f}'.format(train_f1, train_pre, train_recall))if opt.show_val: # 显示验证过程# 验证model.eval() # 模型切换到评估模式val_loss = 0 # 验证损失val_acc = 0 # 验证准确率for x, y in tqdm(val_loader): # 遍历验证集# 训练前先将数据放到GPU上x = x.to(device) y = y.to(device)outputs = model(x) # 前向传播if opt.use_BCE: # BCE损失loss = loss_func(outputs, y.float().unsqueeze(1))else: # 交叉熵损失  loss = loss_func(outputs, y)val_loss += loss.item() # 累加验证损失if not opt.use_BCE: # 非BCE损失_, predicted = torch.max(outputs.data, 1) else:predicted = (outputs > 0.5).int() # 预测结果predicted = predicted.squeeze(1)val_acc += (predicted == y).sum().item() # 计算验证准确率#计算F1、Precision、Recallval_f1     = metrics.f1_score(y.cpu(), predicted.cpu(), average=average_mode)val_pre    = metrics.precision_score(y.cpu(), predicted.cpu(), average=average_mode)val_recall = metrics.recall_score(y.cpu(), predicted.cpu(), average=average_mode)val_loss /= len(val_loader) # 平均验证损失val_acc /= len(val_loader.dataset) # 平均验证准确率val_acc_list.append(val_acc)   # 添加验证准确率val_loss_list.append(val_loss) # 添加验证损失print('\nVal Loss: {:.4f}, Val Acc: {:.4f}'.format(val_loss, val_acc))print('Val-f1: {:.4f}, Val-precision: {:.4f} Val-recall: {:.4f}'.format(val_f1, val_pre, val_recall))if train_loss < best_train_loss: # 更新最佳训练损失best_train_loss = train_lossbest_epoch = epoch + 1if device == 'cuda' and gpu_num > 1: # 多GPU保存模型torch.save(model.module.state_dict(), f'{model_save_dir}/best_model{model_index}.pth')else:torch.save(model.state_dict(), f'{model_save_dir}/best_model{model_index}.pth') # 单GPU保存模型# 提前停止判断if epoch+1 - best_epoch == early_stop:  print(f'{early_stop} epochs later, the loss of the validation set no longer continues to decrease, so the training is stopped early.')end_time = time.time()print(f'Total time is {end_time - start_time}s.')breakbest_model = MODEL(model_index) # 初始化最佳模型best_model.load_state_dict(torch.load(f'checkpoints/best_model{model_index}.pth')) # 加载模型参数return best_model # 返回最佳模型

模型推理:

def model_predict(model, model_index, test_loader):device = 'cuda'model.to(device) # 模型到GPUmodel.eval()  # 切换到评估模式test_outputs = Nonewith torch.no_grad():  # 禁用梯度计算for i, data in enumerate(tqdm(test_loader)):data = data[0].to(device) # 测试数据到GPUoutputs = model(data) # 前向传播if i == 0: test_outputs = outputs # 第一个batch直接赋值else:test_outputs = torch.cat([test_outputs, outputs], dim=0) # 其余batch拼接del data, outputs  # 释放不再需要的Tensor# 保存预测结果    if not opt.use_BCE: test_outputs = torch.softmax(test_outputs, dim=1) # 转换为概率torch.save(test_outputs, f'./models_prediction/{model_index}_prob.pth') # 保存概率

模型训练主函数:

def run(model_index):# 固定随机种子seed = opt.seed  torch.seed = seednp.random.seed(seed)torch.manual_seed(seed)torch.cuda.manual_seed(seed)torch.cuda.manual_seed_all(seed)torch.backends.cudnn.deterministic = Truetrain_dataset, val_dataset, test_dataset = load_data() # 加载数据集# 打印数据集信息print('-数据集信息:')print(f'-训练集样本数:{len(train_dataset)},测试集样本数:{len(test_dataset)}')train_labels = len(set(train_dataset.tensors[1].numpy()))# 查看训练样本类别均衡状况print(f'-训练集的标签种类个数为:{train_labels}') numbers = [0] * train_labelsfor i in train_dataset.tensors[1].numpy():numbers[i] += 1print(f'-训练集各种类样本的个数:')for i in range(train_labels):print(f'-{i}的样本个数为:{numbers[i]}')batch_size   = opt.batch_size # 批处理大小# 构建DataLoadertrain_loader = torch.utils.data.DataLoader(dataset=train_dataset, batch_size=batch_size, shuffle=True) val_loader   = torch.utils.data.DataLoader(dataset=val_dataset,   batch_size=batch_size, shuffle=True)test_loader  = torch.utils.data.DataLoader(dataset=test_dataset,  batch_size=batch_size, shuffle=False)best_model   = model_pretrain(model_index, train_loader, val_loader)# 使用验证集评估模型model_predict(best_model, model_index, test_loader) # 模型推理if __name__ == '__main__':model_index = opt.model_index # 获取模型索引run(model_index) # 运行程序

③ 模型评估

import torch
import pandas as pd
from models_training import MODEL  # 从本地文件models_training.py中导入MODEL类
from tqdm import tqdm
from sklearn.metrics import classification_report
import numpy as np# 推理
def inference(model_indexs, use_BCE):device = 'cuda'  # 设备选择为cudafor model_index in model_indexs:# 加载模型model = MODEL(model_index).to(device)  # 创建MODEL类的实例,并将模型移至设备(device)model.load_state_dict(torch.load(f'checkpoints/best_model{model_index}.pth'))  # 加载模型的权重参数model.eval()  # 切换到评估模式# 加载val数据val_data_path = f'models_input_files/x_val{model_index}.npy'  # val数据的路径val_data = torch.tensor(np.load(val_data_path, allow_pickle=True).tolist())  # 加载val数据,并转换为Tensor格式val_dataset = torch.utils.data.TensorDataset(val_data)  # 创建val数据集val_loader  = torch.utils.data.DataLoader(dataset=val_dataset, batch_size=32, shuffle=False)  # 创建val数据的数据加载器val_outputs = None  # 初始化val_outputs变量with torch.no_grad():  # 禁用梯度计算for i, data in enumerate(tqdm(val_loader)):  # 遍历val_loader,显示进度条data = data[0].to(device)  # 将数据移至GPUoutputs = model(data)  # 模型推理,获取输出if i == 0:val_outputs = outputs  # 若为第一次迭代,直接赋值给val_outputselse:val_outputs = torch.cat([val_outputs, outputs], dim=0)  # 否则在dim=0上拼接val_outputs和outputsdel data, outputs  # 释放不再需要的Tensor对象# 输出预测概率if not use_BCE:val_outputs = torch.softmax(val_outputs, dim=1)  # 对val_outputs进行softmax操作torch.save(val_outputs, f'evaluate_prediction/{model_index}_prob.pth')  # 保存预测概率结果def run(model_indexs, use_BCE):# 读取所有的model_prob.pth,并全加在一起avg_pred = None  # 初始化avg_pred变量for i in model_indexs:pred = torch.load(f'evaluate_prediction/{i}_prob.pth').data  # 加载预测概率结果if use_BCE:# 选取大于0.5的作为预测结果pred = (pred > 0.5).int()  # 将大于0.5的值转换为整数(0或1)pred = pred.reshape(-1)  # 将预测结果进行形状重塑else:# 选取最大的概率作为预测结果pred = torch.argmax(pred, dim=1)  # 获取最大概率的索引作为预测结果pred = pred.cpu().numpy()  # 将预测结果转移到CPU上,并转换为NumPy数组# to_evaluate# 读取真实标签val_label_path = f'models_input_files/y_val{i}.npy'  # 真实标签的路径y_true = np.load(val_label_path)  # 加载真实标签# 分类报告print(f'model_index = {i}:')print(classification_report(y_true, pred, digits=4))  # 打印分类报告,包括精确度、召回率等指标zero_acc = 0; one_acc = 0 # 初始化0类和1类的准确率zero_num = 0; one_num= 0  # 初始化0类和1类的样本数量for i in range(pred.shape[0]):if y_true[i] == 0:zero_num += 1  # 统计0类的样本数量elif y_true[i] == 1:one_num += 1  # 统计1类的样本数量if pred[i] == y_true[i]:if pred[i] == 0:zero_acc += 1  # 统计0类的正确预测数量elif pred[i] == 1:one_acc += 1  # 统计1类的正确预测数量zero = np.sum(pred == 0) / pred.shape[0]  # 计算预测为0类的样本占比zero_acc /= zero_num  # 计算0类的正确率print(f'预测0类占比:{zero}  0类正确率:{zero_acc}')one = np.sum(pred == 1) / pred.shape[0]  # 计算预测为1类的样本占比one_acc /= one_num  # 计算1类的正确率print(f'预测1类占比:{one}  1类正确率:{one_acc}')print('-' * 80)if __name__ == '__main__':use_BCE = False  # 是否使用BCE损失函数的标志,这里我只用交叉熵CE,所以是Falseinference([2], use_BCE=use_BCE)  # 进行推理,传入模型索引和use_BCE标志model_indexs = [2]  # 模型索引列表run(model_indexs, use_BCE=use_BCE)  # 进行运行,传入模型索引和use_BCE标志

④ 测试集推理

import torch
import pandas as pd
import warnings # 过滤警告
warnings.filterwarnings('ignore')def run(model_indexs, use_BCE):# 记录模型数量model_num = len(model_indexs)# 读取所有的model_prob.pth,并全加在一起for i in model_indexs:# 加载模型在训练完成后对测试集推理所得的预测文件pred = torch.load(f'./models_prediction/{i}_prob.pth', map_location='cpu').data# 这里的操作是将每个模型对测试集推理的概率全加在一起if i == model_indexs[0]:avg_pred = predelse:avg_pred += pred# 取平均avg_pred /= model_num # 使用全加在一起的预测概率除以模型数量if use_BCE:# 选取概率大于0.5的作为预测结果pred = (avg_pred > 0.5).int()pred = pred.reshape(-1)else:# 后处理 - 根据标签数目的反馈,对预测阈值进行调整pred[:, 0][pred[:, 0]>0.001] = 1pred[:, 1][pred[:, 1]>0.999] = 1.2# 选取最大的概率作为预测结果pred = torch.argmax(avg_pred, dim=1)pred = pred.cpu().numpy()# to_submit# 读取test.csv文件test = pd.read_csv('./dataset/testB_submit_exsample.csv')# 开始写入预测结果for i in range(len(pred)):test['label'][i] = pred[i]print(test['label'].value_counts())# 保存为提交文件test.to_csv(f'submit.csv',index=False)if __name__ == '__main__':run([2], use_BCE=False)# run([1,2,3,4,5,6,7,8,9,10], use_BCE=False)

模型优化的思路:

超参数调整、最大序列长度调整、损失函数更改、模型参数冻结

特征工程、模型集成、对比学习、提示学习サ

ChatGML2-6B

LLMs:自回归模型

Pretrained => prompt、finetune => RLHF 强化对齐学习

LoRA低秩适应:冻结预训练好的模型权重参数,在冻结原模型参数的情况下,通过往模型中加入额外的网络层,并只训练这些新增的网络层参数。

「instruction --> 」「input: X」「output: Y」

P-tuning v2:在原有的大型语言模型上添加一些新的参数,这些新的参数可以帮助模型更好地理解和处理特定的任务。

微调应用:垂直领域、个性化

在阿里云Pytorch环境中,克隆代码、下载chatglm2-6b模型,

安装依赖,并且运行训练脚本。

xfg_train.sh

CUDA_VISIBLE_DEVICES=0 python src/train_bash.py \--model_name_or_path chatglm2-6b \ 本地模型的目录--stage sft \ 微调方法--use_v2 \ 使用glm2模型微调,默认值true--do_train \ 是否训练,默认值true--dataset paper_label \ 数据集名字--finetuning_type lora \ --lora_rank 8 \  LoRA 微调中的秩大小--output_dir ./output/label_xfg \ 输出lora权重存放目录--per_device_train_batch_size 4 \ 用于训练的批处理大小--gradient_accumulation_steps 4 \ 梯度累加次数--lr_scheduler_type cosine \--logging_steps 10 \ 日志输出间隔--save_steps 1000 \ 断点保存间隔--learning_rate 5e-5 \ 学习率--num_train_epochs 4.0 \ 训练轮数--fp16 是否使用 fp16 半精度 默认值:False

导入数据

import pandas as pd
train_df = pd.read_csv('./csv_data/train.csv')
testB_df = pd.read_csv('./csv_data/testB.csv')

制作数据集

res = [] #存储数据样本for i in range(len(train_df)):# 遍历训练数据的每一行paper_item = train_df.loc[i] # 获取当前行的数据# 创建一个字典,包含LoRA的指令、输入和输出信息tmp = {"instruction": "Please judge whether it is a medical field paper according to the given paper title and abstract, output 1 or 0, the following is the paper title and abstract -->","input": f"title:{paper_item[1]},abstract:{paper_item[3]}","output": str(paper_item[5])}res.append(tmp) # 将字典添加到结果列表中import json #用于保存数据集# 将制作好的数据集保存到data目录下
with open('./data/paper_label.json', mode='w', encoding='utf-8') as f:json.dump(res, f, ensure_ascii=False, indent=4)

修改data/data_info.json

{"paper_label": {"file_name": "paper_label.json"}
}

加载训练好的LoRA权重,进行预测

from peft import PeftModel
from transformers import AutoTokenizer, AutoModel, GenerationConfig, AutoModelForCausalLM# 定义预训练模型的路径
model_path = "../chatglm2-6b"
model = AutoModel.from_pretrained(model_path, trust_remote_code=True).half().cuda()
tokenizer = AutoTokenizer.from_pretrained(model_path, trust_remote_code=True)# 加载 label lora权重
model = PeftModel.from_pretrained(model, './output/label_xfg').half()
model = model.eval()# 使用加载的模型和分词器进行聊天,生成回复
response, history = model.chat(tokenizer, "你好", history=[])
response

预测函数:

def predict(text):# 使用加载的模型和分词器进行聊天,生成回复response, history = model.chat(tokenizer, f"Please judge whether it is a medical field paper according to the given paper title and abstract, output 1 or 0, the following is the paper title and abstract -->{text}", history=[],temperature=0.01)return response

预测,导出csv

from tqdm import tqdm #预测过程的进度条label = [] #存储预测结果for i in tqdm(range(len(testB_df))): # 遍历测试集中的每一条样本test_item = testB_df.loc[i]      # 测试集中的每一条样本# 构建预测函数的输入:prompttest_input = f"title:{test_item[1]},author:{test_item[2]},abstract:{test_item[3]}"label.append(int(predict(test_input)))# 预测结果存入lable列表testB_df['label'] = label # 把label列表存入testB_df# task1虽然只需要label,但需要有一个keywords列,用个随意的字符串代替
testB_df['Keywords'] = ['tmp' for _ in range(2000)]# 制作submit,提交submit
submit = testB_df[['uuid', 'Keywords', 'label']]
submit.to_csv('submit.csv', index=False)

提交结果:

 ライト

相关文章:

NLP | 基于LLMs的文本分类任务

比赛链接&#xff1a;讯飞开放平台 来源&#xff1a;DataWhale AI夏令营3&#xff08;NLP&#xff09; Roberta-base&#xff08;BERT的改进&#xff09; ①Roberta在预训练的阶段中没有对下一句话进行预测&#xff08;NSP&#xff09; ②采用了动态掩码 ③使用字符级和词级…...

攻防世界-base÷4

原题 解题思路 base644&#xff0c;莫不是base16&#xff0c;base16解码网站&#xff1a; 千千秀字...

【Java转Go】快速上手学习笔记(三)之基础篇二

【Java转Go】快速上手学习笔记&#xff08;二&#xff09;之基础篇一 了解了基本语法、基本数据类型这些使用&#xff0c;接下来我们来讲数组、切片、值传递、引用传递、指针类型、函数、map、结构体。 目录 数组和切片值传递、引用传递指针类型defer延迟执行函数map结构体匿名…...

【vue 引入pinia与pinia的详细使用】

vue引入pinia与使用 安装引入使用定义 store在组件中使用 store在插件中使用 store配置 store 总结 Pinia 是一个用于 Vue 3 的状态管理库&#xff0c;其设计目标是提供一个简单、一致的 API 和强类型支持。下面介绍如何引入 Pinia 并使用它。 安装 npm install pinia引入 在…...

USACO18DEC Fine Dining G

P5122 [USACO18DEC] Fine Dining G 题目大意 有一个由 n n n个点 m m m条边构成的无向连通图&#xff0c;这 n n n个点的编号为 1 1 1到 n n n。前 n − 1 n-1 n−1个点上都有一头奶牛&#xff0c;这些奶牛都要前往 n n n号点。第 i i i条边连接 a i a_i ai​和 b i b_i bi​…...

fckeditor编辑器的两种使用方法

需要的资源包我放我资源里了&#xff0c;不要积分 https://download.csdn.net/download/wybshyy/88245895 首先把FredCK.FCKeditorV2.dll添加到引用 具体方法如下&#xff0c;一个是客户端版本&#xff0c;一个是服务器端版本 客户端版本&#xff1a; <% Page Language…...

数据结构,查找算法(二分,分块,哈希)

一、查找算法 1、二分查找:(前提条件: 必须有序的序列) #include <stdio.h> //二分查找 value代表的是被查找的值 int findByHalf(int *p, int n, int value) {int low = 0;//low低int high = n-1;//high高int middle;//用来保存中间位置的下标while(low <= high…...

C++(Qt)软件调试---gdb调试入门用法(12)

gdb调试—入门用法&#xff08;1&#xff09; 文章目录 gdb调试---入门用法&#xff08;1&#xff09;1、前言1.1 什么是GDB1.2 为什么要学习GDB1.3 主要内容1.4 GDB资料 2、C/C开发调试环境准备3、gdb启动调试1.1 启动调试并传入参数1.2 附加到进程1.3 过程执行1.4 退出调试 4…...

shell和Python 两种方法分别画 iostat的监控图

在服务器存储的测试中,经常需要看performance的性能曲线&#xff0c;这样最能直接观察HDD或者SSD的性能曲线。 如下这是一个针对HDD跑Fio读写的iostat监控log,下面介绍一下分别用shell 和Python3 写画iostat图的方法 1 shell脚本 环境:linux OS gnuplot工具 第一步 :解析iosta…...

设计模式(9)建造者模式

一、 1、概念&#xff1a;将一个复杂对象的构造与它的表示分离&#xff0c;使得同样的构造过程可以创建不同的表示。建造者模式主要用于创建一些复杂的对象&#xff0c;这些对象内部构建间的顺序通常是稳定的&#xff0c;但对象内部的构建通常面临着复杂的变化&#xff1b;建造…...

PHP 创业感悟交流平台系统mysql数据库web结构apache计算机软件工程网页wamp

一、源码特点 PHP 创业感悟交流平台系统&#xff08;含论坛&#xff09;是一套完善的web设计系统&#xff0c;对理解php编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。 源码下载&#xff1a; https://download.csdn.…...

工作流程引擎之flowable(集成springboot)

0、背景 现状&#xff1a;公司各部门业务系统有各自的工作流引擎&#xff0c;也有cross function的业务在不同系统或OA系统流转&#xff0c;没有统一的去规划布局统一的BPM解决方案&#xff0c;近期由于一个项目引发朝着整合统一的BPM方案&#xff0c;特了解一下市面上比较主流…...

leetcode54. 螺旋矩阵(java)

螺旋矩阵 题目描述解题 收缩法 上期经典算法 题目描述 难度 - 中等 原题链接 - leecode 54 螺旋矩阵 给你一个 m 行 n 列的矩阵 matrix &#xff0c;请按照 顺时针螺旋顺序 &#xff0c;返回矩阵中的所有元素。 示例1&#xff1a; 输入&#xff1a;matrix [[1,2,3],[4,5,6],[7…...

go gorm 查询

定义model package mysqltestimport ("errors""fmt""gorm.io/gorm" )type Product struct {gorm.ModelID uint gorm:"primarykey"Name string gorm:"column:name"Price float64 gorm:"column:price_value&quo…...

Flutter GetXController 动态Tabbar 报错问题

场景&#xff1a; 1.Tabbar的内容是接口获取的 2. TabController? tabController;&#xff1b; 在onInit 方法中初始化tabbarController tabController TabController(initialIndex: 0, length: titleDataList.length, vsync: this); 这时候会报一个错误 Controllers l…...

Redis(缓存预热,缓存雪崩,缓存击穿,缓存穿透)

目录 一、缓存预热 二、缓存雪崩 三、缓存击穿 四、缓存穿透 一、缓存预热 开过车的都知道&#xff0c;冬天的时候启动我们的小汽车之后不要直接驾驶&#xff0c;先让车子发动机预热一段时间再启动。缓存预热是一样的道理。 缓存预热就是系统启动前&#xff0c;提前将相关的…...

UE4/5Niagara粒子特效学习(使用UE5.1,适合新手)

目录 创建空模板 创建粒子 粒子的基础属性 粒子的生命周期 颜色 大小设置 生成的位置 Skeletal Mesh Location的效果&#xff1a; Shape Location 添加速度 添加Noise力场 在生成中添加&#xff1a; 效果&#xff1a; ​编辑 在更新中添加&#xff1a; 效果&…...

from moduleA import * 语句 和import moduleA 的区别

from moduleA import * 语句和import moduleA 的区别是&#xff1a; from moduleA import * 语句会将moduleA模块中的所有内容&#xff08;函数、变量、类等&#xff09;直接导入到当前模块的命名空间中&#xff0c;这样就可以直接使用它们&#xff0c;而不需要加上模块名的限…...

【leetcode 力扣刷题】交换链表中的节点

24. 两两交换链表中的节点 24. 两两交换链表中的节点两两节点分组&#xff0c;反转两个节点连接递归求解 24. 两两交换链表中的节点 题目链接&#xff1a;24. 两两交换链表中的节点 题目内容&#xff1a; 题目中强调不能修改节点内部值&#xff0c;是因为如果不加这个限制的话…...

学会Mybatis框架:让你的代码更具灵活性、可维护性、安全性和高效性【二.动态SQL】

&#x1f973;&#x1f973;Welcome Huihuis Code World ! !&#x1f973;&#x1f973; 接下来看看由辉辉所写的关于Mybatis的相关操作吧 目录 &#x1f973;&#x1f973;Welcome Huihuis Code World ! !&#x1f973;&#x1f973; 一.Mybatis动态SQL如何应用 1.需求 2.…...

Oracle 中 ROWNUM 使用问题记录

ROWNUM 使用问题记录(2023-08-17) Oracle 版本&#xff1a; 19.0.0.0.0 Enterprise现象&#xff1a;今天在项目遇到一个问题&#xff0c;测试人员反馈前一天能看到的数据今天看不到了 用表格举例&#xff0c;这是前一天看到的数据&#xff0c;有9、7、1 这几个数量信息 日期…...

MySQL数据库:内置函数

日期函数 规定&#xff1a;日期&#xff1a;年月日 时间&#xff1a;时分秒 函数名称作用描述current_date()当前日期current_time()当前时间current_timestamp()当前时间戳date(datetime)返回datetime参数的日期部分date_add(date,interval d_value_type)在date中添加…...

【C++杂货铺】探索string的底层实现

文章目录 一、成员变量二、成员函数2.1 默认构造函数2.2 拷贝构造函数2.3 operator2.4 c_str()2.5 size()2.6 operator[ ]2.7 iterator2.8 reserve2.9 resize2.10 push_back2.11 append2.12 operator2.13 insert2.14 erase2.15 find2.16 substr2.17 operator<<2.18 opera…...

c++ day1

定义一个命名空间Myspace&#xff0c;包含以下函数&#xff1a;将一个字符串中的所有单词进行反转&#xff0c;并输出反转后的结果。例如&#xff0c;输入字符串为"Hello World"&#xff0c;输出结果为"olleH dlroW"&#xff0c;并在主函数内测试该函数。 …...

变动的Python爬虫实现

在电商时代&#xff0c;了解商品价格的变动对于购物者和卖家来说都非常重要。本文将分享一种基于Python的实时监控电商平台商品价格变动的爬虫实现方法。通过本文的解决方案和代码示例&#xff0c;您将能够轻松监控商品价格&#xff0c;并及时做出决策。 一、了解需求和目标 在…...

mybatis-plus--配置-(sql)日志输出-自动填充-分页-多数据源-逻辑删除

写在前面&#xff1a; 本文主要介绍mybatis-plus的配置&#xff0c;以后在有的时候在补充。欢迎交流。 文章目录 日志输出自动填充分页全局字段配置多数据源 日志输出 调试的时候需要看执行的sql&#xff0c;这时候就很需要日志来记录查看了。 mybatis-plus的日志配置在yml…...

数据API服务管理功能:解放数据潜力,提升业务效率

数据API服务的重要性 在数字化时代&#xff0c;数据被认为是企业的重要资产。数据API服务的管理功能能够有效帮助企业实现数据的整合和利用。通过合理的数据API服务管理&#xff0c;企业可以更好地解放数据潜力&#xff0c;提升业务效率。 ​ 解放数据潜力 数据API服务管理功…...

云南森林火灾vr消防模拟安全演练系统训练消防员火灾和事故的适应和应对能力

据统计,每一场破坏性地震发生后,会引发次生的灾害,而火灾是其中之一。导致火灾的原因,推测是地震时使供电线路短路,引燃易燃物,火灾就随即发生。所以,在日常生活中,定期的消防演练还是非常必要的, VR消防&#xff0c;是VR公司深圳华锐视点利用VR虚拟现实技术&#xff0c;将VR和…...

(6)(6.2) 任务命令

文章目录 前言 6.2.1 概述 6.2.2 导航命令 6.2.3 条件命令 6.2.4 DO命令 前言 本文介绍了 Copter、Plane 和 Rover 切换到自动模式时支持的任务指令。 &#xff01;Warning 这是一项正在进行中的工作&#xff0c;尚未经过全面审核。有关 Copter 的更佳列表&#xff0c;请…...

【consul】

consul 一、什么是服务注册与发现1.11.2 二、 什么是consul2.1定义2.2特性2.2.1服务注册与发现&#xff1a;2.2.2健康检查&#xff1a;2.2.3Key/Value存储&#xff1a; 三、consul部署-datacenter &#xff1a;指定数据中心名称&#xff0c;默认是dc1。consul &#xff1a;指定…...

aspcms网站地图/百度知道问答首页

骁龙780G&#xff1a;搭载全新的5nm制作工艺&#xff0c;为用户提供很好的手机旗舰功耗管理 我用的手机就是活动时8折抢购的 点击开抢http://shouji.adiannao.cn/7 骁龙778G&#xff1a;搭载6nm制作工艺&#xff0c;这是目前性价比很好的芯片制作工艺 骁龙780G&#xff1a;在芯…...

找人做效果图去什么网站/百度收录批量提交入口

1、问题描述 在新安装的PyCharm 2017.3(Community Edition)中&#xff0c;调试Python代码的时候&#xff0c;只启动Debugger&#xff0c;不启动Console&#xff0c;无法看打印出来的日志。 图1 debug代码结果页面只有Debugger 2、原因分析 根据以往调试经验&#xff0c;一定是…...

哪个网站做黄金交易最好/南京seo代理

本文主要内容是如何从0到1基于vue搭建一个后台管理项目的前端工程。示例的代码地址&#xff1a;https://github.com/tyuqing/vue-admin 1 创建项目 使用vue-cli3快速创建项目&#xff0c;具体的创建方法vue-cli官网上有说明。创建时大家可根据自己项目的需求选择合适的模块&a…...

自己做网站免费/网站推广步骤

精装房真的好么&#xff1f;是不是墙面可以直接贴墙纸&#xff0c;很多人都不了解嗨喽大家好&#xff0c;今天继续为大家分享家居中的那些小常识&#xff0c;今天我们要说的&#xff0c;和很多人都关注的新房有管&#xff0c;相对于毛胚房来说&#xff0c;不少人都更喜欢多花一…...

做网站 怎么赚钱吗/百度指数电脑版

2019独角兽企业重金招聘Python工程师标准>>> 原因&#xff1a;开发的jdk 为1.8 64位 生产的是1.7 32位 结论&#xff1a;开发与生产环境要保持一致 转载于:https://my.oschina.net/springMVCAndspring/blog/1600882...

广西网站/2022真实新闻作文400字

前些天&#xff0c;测试人员向我反映有一家企业的通讯录同步接口不返回数据&#xff0c;我查日志nginx的相应access.log状态码是499&#xff0c;请求超时&#xff0c;从网上查找资料分析有两种可能&#xff1a;1.客户端主动断开连接2.服务端响应超时造成客户端连接中断问了客户…...