上一篇文章中,我详细讲解了 BertModel
。
在今天这篇文章,我会使用 BertForSequenceClassification
,在自己的训练集上训练情感分类模型。
数据集来源于 https://github.com/bojone/bert4keras/tree/master/examples/datasets
是一个中文的情感二分类数据集。
而词汇表 vocab.txt
来自于哈工大的中文预训练语言模型 BERT-wwm, Chinese
。
地址:https://github.com/ymcui/Chinese-BERT-wwm#%E4%B8%AD%E6%96%87%E6%A8%A1%E5%9E%8B%E4%B8%8B%E8%BD%BD
以 PyTorch 版BERT-wwm, Chinese
为例,下载完毕后对zip文件进行解压得到:
1 |
chinese-bert_chinese_wwm_pytorch.zip |
我们前面提到,BertForSequenceClassification
是在 BertModel
的基础上,添加了一个线性层 + 激活函数,用于分类。而 Huggingface 提供的预训练模型 bert-base-uncased
只包含 BertModel
的权重,不包括线性层 + 激活函数的权重。在下面,我们会使用model = BertForSequenceClassification.from_pretrained("bert-base-uncased", config=config)
来加载模型,那么线性层 + 激活函数的权重就会随机初始化。我们的目的,就是通过微调,学习到线性层 + 激活函数的权重。
我们这里预训练模型使用 Huggingface 的 bert-base-uncased
,不使用哈工大模型的权重,因为我们是想要在 bert-base-uncased
的基础上进行微调。因此只使用其中的 vocab.txt
。
我把数据、词汇表(vocab.txt)以及代码,放到了 github 上:https://github.com/zhangxiann/BertPractice。
下面开始讲解代码。
导入库
1 |
import torch.nn as nn |
1 |
# 超参数 |
在 Dataset
的 __getitem__()
函数里,根据 idx 分别找到 text 和 label,最后返回一个 dict。
DataLoader
的 batch_size
设置为 16。
1 |
class SentimentDataset(Dataset): |
这里定义了 BertConfig
,使用了上面定义的一些超参数:如类别数量,hidden_dropout_prob
等。
预训练模型选择 bert-base-uncased
。
1 |
# 定义 tokenizer,传入词汇表 |
其中bias
和 LayerNorm
的权重不使用 weight_decay
。这是根据 https://huggingface.co/transformers/training.html 来设置的,暂未查到这么做的原因。如果你知道原因,欢迎留言告诉我。
1 |
# 定义优化器和损失函数 |
首先从 dataloader
获取到 text 和 label。
然后通过
1 |
tokenized_text = tokenizer(text, max_length=100, add_special_tokens=True, truncation=True, padding=True, return_tensors="pt") |
获得 tokenized_text
,包括 input_ids
, token_type_ids
, attention_mask
。
max_length=100
表示最大长度为 100,配合 truncation=True
,表示超过 100 则截断。
padding=True
表示长度小于 100,则补全到 100。
1 |
|
1 |
# 开始训练和验证 |
参考