目录一、项目流程1.1 加载预训练模型Bert1.2 数据预处理1.3 模型定义1.4 模型训练1.5 模型预测二、总结BERT 是谷歌于 2018 年提出的基于 Transformer 编码器结构的预训练语言模型。本文基于 BERT 架构完成从预处理、微调训练到效果评估的全流程实验经过多轮迭代优化模型在情感分析任务上精确率达到98.7%相比 LSTM 模型精确率提高108%。github项目地址zhanghong203/bert_based_emotion_analysis at masterLSTM项目地址zhanghong203/emotion_analyse_lm: 基于LSTM的情感分析模型一、项目流程实验配置显卡 NVIDIA GeForce RTX 3050 LAPTOP GP模型google-bert/bert-base-chinese · Hugging Face数据评论情感分析数据集1.1 加载预训练模型BertBert模型 通过官方链接或者代码方式下载from transformers import AutoTokenizer, AutoModelForMaskedLM tokenizer AutoTokenizer.from_pretrained(bert-base-chinese) model AutoModelForMaskedLM.from_pretrained(bert-base-chinese)默认huggingface安装目录 ~/.cache/huggingface/hub可以通过配置环境变量修改完成Bert模型加载后通过from_pretrained方法可以从huggingface缓存中读取同时也可以把模型放置在项目目录下通过读取绝对路径方式加载。关于from_pretrained方法详细介绍参考链接from_pretrained 做了啥_from pretrained-CSDN博客1.2 数据预处理该过程主要完成数据清洗、对接Bert输入的任务。数据清洗过滤无用列去除不符合的行。# 过滤数据 dataset dataset.remove_columns([cat]) dataset dataset.filter(lambda x: x[review] is not None) dataset dataset.cast_column(label, ClassLabel(names[negative, positive]))Bert一般接收参数(input_ids token_type_idsattention_maskOptional [labels])def batch_encode(batch): inputs tokenizer(batch[review], truncationTrue, paddingmax_length, max_lengthconfig.MAX_LENGTH) inputs[labels] batch[label] return inputs dataset_dict dataset_dict.map(batch_encode, batchedTrue, remove_columns[review, label])调用tokenizer()获取前三个字段为了保证批处理需要做填充和截断操作。针对带句子分类任务头的Bert还需要labels字段。在后续过程中为了方便解构提前将label字段转化成labels后续添加任务头不需要再做预处理。tokenizer方法参考链接1.3 模型定义首先明确设计的任务是对评论进行情感分析属于二分类任务。通过Bert前向传播即通过12层隐藏层只需要将最后一层last_hidden_state(batch_size, sequence_length, hidden_size)Bert模型第一个token蕴含的向量信息是整个句子信息接一个线性层。默认hidden_size是768线性层输出维度设为1。def forward(self, input_ids, attention_mask, token_type_ids): output self.bert(input_ids, attention_mask, token_type_ids) last_hidden_state output.last_hidden_state cls_hidden_state last_hidden_state[:, 0, :] output self.linear(cls_hidden_state).squeeze(-1) return outputBert输出结构参考链接1.4 模型训练对于不带任务头的Bert传入参数不需要携带labels并且在进行训练时需要再多一步计算损失然而针对句子分类任务的Bert输出包含loss字段。# 含任务头 model AutoModelForSequenceClassification.from_pretrained(google-bert/bert-base-chinese).to(device)训练代码如下def train_one_epoch(model, dataloader, loss_fn, optimizer, device): total_loss 0 model.train() for batch in tqdm(dataloader, desc训练): inputs {k: v.to(device) for k, v in batch.items()} labels inputs.pop(labels).to(dtypetorch.float) outputs model(**inputs) loss loss_fn(outputs, labels) loss.backward() optimizer.step() optimizer.zero_grad() total_loss loss.item() return total_loss / len(dataloader) def train(): # 1.设备 device torch.device(cuda if torch.cuda.is_available() else cpu) print(device) # 2.数据 dataloader get_loader() # 3.分词器 tokenizer AutoTokenizer.from_pretrained(google-bert/bert-base-chinese) # 4.模型 model ReviewAnalyzeModel().to(device) # 5.损失函数 loss_fn torch.nn.BCEWithLogitsLoss() # 6.优化器 optimizer torch.optim.Adam(model.parameters(), lrconfig.LEARNING_RATE) # train best_loss float(inf) for epoch in range(config.EPOCHS): print(fEpoch: {epoch 1}) loss train_one_epoch(model, dataloader, loss_fn, optimizer, device) print(fLoss: {loss:.4f}) # 保存模型 if loss best_loss: best_loss loss torch.save(model.state_dict(), config.MODELS_DIR / best.pt) print(保存模型)BertForSequenceClassification模型介绍1.5 模型预测1.3小节中的模型是通过一个线性层得到一个结果通过sigmoid映射到[0,1]含任务头的Bert模型输出包含一个logit字段(batch_size, config.num_labels)在预测阶段logit的形状是(1, 2)可以使用argmax完成标签映射。# 含任务头 def predict_batch(model, inputs): model.eval() with torch.no_grad(): output model(**inputs) logits output.logits # (batch_size, config.num_labels) result torch.argmax(logits, dim1) return result.tolist() ------------------------------------------- # 不含任务头 def predict_batch(model, inputs): model.eval() with torch.no_grad(): output model(**inputs) # output.shape (batch_size) batch_result torch.sigmoid(output) return batch_result.tolist()二、总结本文基于Bert完成从数据预处理到模型预测的全流程在项目过程中免不了Bert文档的查看笔者在每个小节都添加了相关API便于读者理解。此外下载Bert以及训练有一些小问题没有列举出来比如访问huggingface超时、GPU显存利用率过高训练效率很低等问题。上述内容如果有错误的地方希望大佬们可以指正。我一直在学习的路上您的帮助使我收获更大觉得对您有帮助的话还请点赞支持我也会不断更新文章