Bert代码详解(二)

这是bert的pytorch版本(与tensorflow一样的,这个更简单些,这个看懂了,tf也能看懂),地址:https://github.com/huggingface/pytorch-pretrained-BERT   主要内容在pytorch_pretrained_bert/modeling文件中。

由于这几天要参见计算所复试,超级紧张,所以先把草稿贴在这里,复试过了再加以完善!!!嘤嘤嘤~保佑通过!
--------------------- 
作者:c-minus 
来源:CSDN 
原文:https://blog.csdn.net/cpluss/article/details/88418176 
版权声明:本文为博主原创文章,转载请附上博文链接!

讲解之前,有必要先了解一下torch.nn.CrossEntropyLoss函数

#这是一个交叉熵损失函数,但又和传统的交叉熵函数不是太一样。由于在源码中出现的次数较多,因此先讲解一下。
#以下全是我的个人理解!!!!(真的不一定是正确的,欢迎指正)
#我只讲可能用到的参数。
class torch.nn.CrossEntropyLoss(weight=None, size_average=None, ignore_index=-100, reduce=None, reduction='mean')
#weight:权重。这个参数是针对训练文件不平衡设置的。例如,训练一个C分类问题,但是训练数据中C中各种类别所占的比例不一样,这是就需要一个weight参数,也因此weight也必须是C维度的
#ignore_index:忽略的值。如果target中出现和ignore_index一样的值,则此值的损失不参与计算
#input_size : [(batch_size*seq_length), vocab_size]
#对于输入,我的理解是,每个单词对应一个vocab_size向量,此向量上的每个值就是对该词的预测。例如 x = [23,45,...,65],x[0]=23就是预测x单词是0号单词的评分为23
#target,为一个[batch_size*seq_length]的一维向量,此向量的值,必须在0-vocab_size中选择(因为每个词都属于词表)
#output:一个标量(reduce默认为true的情况下)
#损失函数如下,class代表target中真实的标签

BertForMaskedLM

BERT Transformer with the pre-trained masked language modeling head on top

#masked language model(参考论文)
#相当于针对一个C分类问题做损失函数。对于masked的单词,预测他是什么,相当于预测这个单词属于每个单词的概率(总共有vocab_size个单词),所以是一个
#vocab_size分类问题
#下面详细讲解如何构造这个损失函数
    def forward(self, input_ids, token_type_ids=None, attention_mask=None, masked_lm_labels=None):
        #我们只要最后一层的输出,其形状为[batch_size, seq_length, hidden_size]
        sequence_output, _ = self.bert(input_ids, token_type_ids, attention_mask,
                                       output_all_encoded_layers=False)
        #计算预测分数,形状为[batch_size, seq_length, vocab_size],每一个值都是对该词语是否是某个词语的打分(好绕……)
        #具体的我不详细解释,其实很简单,经过一个全连接层,激活层,layer_norm层,一个decoder层(改变形状),就得到结果
        #代码很简单,自己去看
        prediction_scores = self.cls(sequence_output)
        
        #如果mask_lm_label不等于None,则返回预测与真实的loss。
        #否则,直接返回预测
        if masked_lm_labels is not None:
            #交叉熵损失函数,上面讲过,其中需要注意的是ignore_index为-1,意味着target中值为-1的不需要参与loss计算
            #什么时候值为-1,其实就是那些没有被masked的单词,无需预测,也就无需参与loss计算
            #(to be completed)
            loss_fct = CrossEntropyLoss(ignore_index=-1)
            #预测值更改为[(batch_size*seq_length), vocab_size],target为[(batch_size*seq_length)]
            masked_lm_loss = loss_fct(prediction_scores.view(-1, self.config.vocab_size), masked_lm_labels.view(-1))
            return masked_lm_loss
        else:
            return prediction_scores

BertForNextSentencePrediction

BERT model with next sentence prediction head

#看懂了上面的那个model,下面的这些就很简单了,无非就是将输出结果更更改改换成所需要的格式
#下一句预测,实则是一个二分类问题,是下一句 or 不是下一句
    def forward(self, input_ids, token_type_ids=None, attention_mask=None, next_sentence_label=None):
        #注意这里用的是所有层的输出[12,batch_size,seq_length,hidden_size](假设总共有12层)
        _, pooled_output = self.bert(input_ids, token_type_ids, attention_mask,
                                     output_all_encoded_layers=False)
        #将形状改变为[12,batch_size,seq_length,2]:更改了形状
        seq_relationship_score = self.cls( pooled_output)
        #下面这些就和上面的一样了,不详细讲解
        if next_sentence_label is not None:
            loss_fct = CrossEntropyLoss(ignore_index=-1)
            next_sentence_loss = loss_fct(seq_relationship_score.view(-1, 2), next_sentence_label.view(-1))
            return next_sentence_loss
        else:
            return seq_relationship_score

BertForSequenceClassification

BERT model for classification

#和BertForNextSentencePrediction一样,只不过BertForNextSentencePrediction是一个二分类问题,而这个model是一个num_labels的分类问题
#不解释

剩下的模块如果没有需求,暂时不讲(我懒~)

你可能感兴趣的:(NLP)