bert源码详解

BERT源码详解

共四部分:
1.生成预训练数据:create_pretraining_data.pytokenization.py’
2.bert模型预训练:run_pretraining.py
3.bert主模型:modeling.py
4.fine-tuning: run_squad.py


第一部分:
生成预训练数据:create_pretraining_data.py,tokenization.py

1.设置tokenizer为fulltokenizer,负责对文本进行预处理: tokenization.py

FullTokenizer():

1.load_vocab加载词典 ,建立词到id,id到词的映射关系
2.BasicTokenizer(): 对原始文本进行预处理,包括删除无效字符、转换空白字符为空格、将中文及部分韩文日文字符前后加空格、去除accent字符等,最后按空格分隔,返回tokens列表。
3.WordoieceTokenizer(): 把上面的结果再细粒度的切分为WordPiece,WordpieceTokenizer的目的是将合成词分解成类似词根一样的词片。例如,将"unwanted"分解成[“un”, “##want”, “##ed”]

2.构造训练样本:create_training_instances(), create_instances_from_document()

3.随机mask:返回mask后的样本,替换的index,替换的原始文本

4.假设原始两个句子为:”it is a good day”和”I want to go out”,那么处理后的TrainingInstance可能为:

1.tokens = ["[CLS], “it”, “is” “a”, “[MASK]”, “day”, “[SEP]”, “I”, “apple”, “to”, “go”, “out”, “[SEP]”]
2.segment_ids=[0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1]
3.is_random_next=False
4.masked_lm_positions=[4, 8, 9] 表示Mask后为["[CLS], “it”, “is” “a”, “[MASK]”, “day”, “[SEP]”, “I”, “[MASK]”, “to”, “go”, “out”, “[SEP]”]
5.masked_lm_labels=[“good”, “want”, “to”]


第二部分:
bert模型预训练:run_pretraining.py

1.模型构建器:model_fn_builder()

1.BertModel()部分在第三部分讲。
2.构建遮蔽词预测的损失函数:get_masked_lm_output()
3.构建Next Sentence Prediction的损失函数:get_next_sentences_output()
4.训练 :输入( 模型 ,loss ,优化器 )
5.验证: 计算损失和精确度

2.构造Estimator
3.训练数据集构建器,开始训练:input_fn_builder()
4.验证数据集构建器,开始验证:input_fn_builder()


第三部分:
bert主模型:modeling.py

  • 1.输入部分:

1.获得word embedding(one hot):embedding_lookup()
embedding_lookup函数用于实现Embedding,它有两种方式:使用tf.nn.embedding_lookup和矩阵乘法(one_hot_embedding=True)。
前者适合于CPU与GPU,后者适合于TPU。所谓的one-hot方法是把输入id表示成one-hot的向量,当然输入id序列就变成了one-hot的矩 阵,然后乘以Embedding矩阵。而tf.nn.embedding_lookup是直接用id当下标提Embedding矩阵对应的向量。
2.将positional embeddings,token_embedding,segment_embedding相加:embedding_postprocessor()

  • 2.encoder部分:

1.2D maskk转换为一个3D mask用于attention: `create_attention_mask_from_input_mask()

2.transformer部分: transformer_model()

1.构造multi-headed self-attention: attention_layer(from_tensor,to_tensor):

(1)self-attention的from_tensor, to_tensor是一样的,函数一开始对输入的shape进行校验,获取batch_size、from_seq_length 、to_seq_length 。输入如果是3D张量则转化成2D矩阵(以输入为word_embedding为例[batch_size, seq_lenth, hidden_size]->[batch_size*seq_lenth, hidden_size])

(2)通过全连接线性投影生成query_layer、key_layer 、value_layer,输出的第二个维度变成num_attention_heads *size_per_head整个模型默认hidden_size=num_attention_heads * size_per_head)。然后通过transpose_for_scores转换成多头。

(3)根据公式计算attention_probs(attention score):

1.attention_score = query_layer * key_layer (矩阵乘法) / sqrt(size_per_head) 。
2.attention_mask中为1的位置置为0,为0的位置置为-10000,然后直接加到attention_score中,进行softmax,提升计算效率。
3.attention_probs = tf.nn.softmax(attention_scores)
4.attention_probs = dropout(attention_probs, attention_probs_dropout_prob)

(4)最后再将value和attention_probs相乘,返回3D张量或者2D矩阵:
context_layer = tf.matmul(attention_probs, value_layer)

(5)dropout, layer_norm

2.inermediate(FFNN过程) : tf.layers.dense ( )
3.output : tf.layers.dense(),dropout, layer_norm

  • 3.pooler部分:

‘pooler’可根据实际业务需求进行调整,此处’pooler’是将第一个token作为input,增加一个dense layer, 即输入的第一个token为[CLS], 输出对应的第一个token(论文认为该token可以代表整个输入的集合)可用以对输入进行分类。


第四部分:
fine-tuning: run_squad.py

  • 1.Estimator:

1.model_fn_builder中调用create_model创建网络模型 : 读取checkpoint,并根据tf.estimator.ModeKeys=train/predict,进行具体的训练和预测操作;训练包括定义loss函数和优化函数;预测则直接得到预测结果.
2.estimator = tf.contrib.TPUEstimator(model_fn),创建时输入网络模型
3.训练,estimator.train(train_input_fn)
4.预测,estimator.predict(predict_input_fn)

  • 2.FLAGS.do_train:

1.train_examples = read_squad_examples() 读取样本数据,返回为SquadExample对象。
2.train_writer = FeatureWriter(),特征写入器: tf.train.Example()。
3.convert_examples_to_features(train_exampes,train_writer.process_feature)将SquadExample对象解析为InputFeatures对象使用回调函数train_writer.process_feature,将转换的InputFeatures特征写入文件。
4.train_input_fn = input_fn_builder(train_writer.filename),用于训练时特征读取器将特征写入文件,包括unique_ids,input_ids,input_mask,segment_ids以及tf.data.TFRecordDataset()的创建和读取。
5.estimator.train(train_input_fn),使用特征读取器训练。

  • 3.FLAGS.do_predict:

1.eval_examples = read_squad_examples()读取测试数据,返回为SquadExample对象
2.eval_writer = FeatureWriter(),特征写入器
3.convert_examples_to_features(eval_examples,tokenizer,append_feature)

1.eval_examples
2.tokenizer
3.append_feature,回调函数,保存到eval_features中(便于得到预测结果);eval_writer.process_feature写入文件

4.predict_input_fn = input_fn_builder(eval_writer.filename),用于预测时的特征读取器
5.estimator.predict(predict_input_fn),使用特征读取器预测
6.write_predictions(eval_examples, eval_features, all_result),得到预测结果解析并保存文件

你可能感兴趣的:(bert源码详解)