Reference:https://github.com/649453932/Bert-Chinese-Text-Classification-Pytorch
模型代码学习-CLS文本分类-Bert-Chinese-Text-Classification-Pytorch代码学习-模型结构
baseDir: Bert-Chinese-Text-Classification-Pytorch/models/
目录
./models/bert.py学习
这里的文本分类模型结构比较简单,基本上就是一个bert(可以理解为encoder?)加一个fc layer做分类器。一些额外补充内容的说明如下:
- 这里class_list采用了读文件的统计方法,只要把各个label写在文件里一行一行的,这里就能自动strip(去掉首位空格)进行构建class list
- 模型训练结果后缀是.ckpt,后续.ckpt如何使用?->在test中应该多了一行的引用过程
- device采用torch.cuda.is_availalbe()的判断方法,但是在后续可能需要设置到是cuda几,或者说第几个gpu上
- self.pad_size表明每句话处理成的长度,这时候要依据所需要目标处理的数据集而定,可以先统计目标数据集的文本长度分布,然后选一个几乎最长的,或者说再进行一些其他选择调整(或许一般来说,对于同一个数据集,提供的文本长度应该是差不多的?)
- self.tokenizer采用BertTokenizer.from_pretrained()的方式,这个是指使用预训练的?怎么理解这里预训练和常说的fine-tune的关系?->fine-tune用简单的理解来说就是把这个模型用在自己的数据集上,然后来更新pretrain模型的参数
- hidden_size = 768 这个是bert的一些惯用设置吗,因为在不止一段代码中看到了768这个数值,或许bert输出的最后一层是768dim的?->一般来说如果用到pretrain的话,从模型结构定死来说一般最后一层就是x×768,这样基本就可以说是不能变的。
- self.bert = BertModel.from_pretrained(config.bert_path) for param in self.bert.parameters(): param.requires_grad = True 这几句话是指不frozen bert的层内参数?因为requires_grad=True,关于requires_grad=True的说明,对于需要求导的tensor,其requires_grad属性必须为True,于是如果都需要求导,那是否就意味着在原有基础上进一步训练? 而似乎不是forzen后的fine-tune?->是
- self.fc是一个简单的linear函数,做dim转换
- 对于过程中输入的x,需要看传入参数,再进行补充。
- attention mask的作用是对pad的区域进行mask,在输入时难免遇到句子长度不一而需要pad的情况,这种情况下在计算attention的时候就不需要计算pad部分的attention,所以需要mask掉。这样理解是否正确?看传入参数x的具体内容,再进行补充。
- self.bert的返回参数是怎样的,为什么除了pooled以外还需要一个_来进行占位->返回最后一层的输出,还有cls向量,其中用来分类的是cls向量,而不需要最后一层的输出。
- output_all_encoded_layers=False的作用是只输出并使用最后一层的参数?->是
- out的dim是怎么样的,是多少维×class label个数的?
# coding: UTF-8
import torch
import torch.nn as nn
# from pytorch_pretrained_bert import BertModel, BertTokenizer
from pytorch_pretrained import BertModel, BertTokenizer
class Config(object):
"""配置参数"""
def __init__(self, dataset):
self.model_name = 'bert'
self.train_path = dataset + '/data/train.txt' # 训练集
self.dev_path = dataset + '/data/dev.txt' # 验证集
self.test_path = dataset + '/data/test.txt' # 测试集
self.class_list = [x.strip() for x in open(
dataset + '/data/class.txt').readlines()] # 类别名单
self.save_path = dataset + '/saved_dict/' + self.model_name + '.ckpt' # 模型训练结果
self.device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') # 设备
self.require_improvement = 1000 # 若超过1000batch效果还没提升,则提前结束训练
self.num_classes = len(self.class_list) # 类别数
self.num_epochs = 3 # epoch数
self.batch_size = 128 # mini-batch大小
self.pad_size = 32 # 每句话处理成的长度(短填长切)
self.learning_rate = 5e-5 # 学习率
self.bert_path = './bert_pretrain'
self.tokenizer = BertTokenizer.from_pretrained(self.bert_path)
self.hidden_size = 768
class Model(nn.Module):
def __init__(self, config):
super(Model, self).__init__()
self.bert = BertModel.from_pretrained(config.bert_path)
for param in self.bert.parameters():
param.requires_grad = True
self.fc = nn.Linear(config.hidden_size, config.num_classes)
def forward(self, x):
context = x[0] # 输入的句子
mask = x[2] # 对padding部分进行mask,和句子一个size,padding部分用0表示,如:[1, 1, 1, 1, 0, 0]
_, pooled = self.bert(context, attention_mask=mask, output_all_encoded_layers=False)
out = self.fc(pooled)
return out