日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 人文社科 > 生活经验 >内容正文

生活经验

Bert源码阅读

發布時間:2023/11/28 生活经验 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Bert源码阅读 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

前言

對Google開源出來的bert代碼,來閱讀下。不糾結于代碼組織形式,而只是梳理下其訓練集的生成,訓練的self-attention和multi-head的具體實現。

訓練集的生成

主要實現在create_pretraining_data.py和tokenization.py兩個腳本里。
輸入文本格式舉例,下面是兩篇文章外加一篇空文章。兩篇文章之間用空格作間隔。

This is a blog about bert code reading.
It is writed using markdown, which is a markup language that can be written using a plain text editor.
Hopefuly it will give the reader a deep understanding of bert.

本文是篇關于bert源碼閱讀的博客。
它是用markdown寫的,markdown是種可以使用普通文本編輯器編寫的標記語言。
希望本文能夠給讀者以對bert更深層次的理解。


1
2
3
4
5
6
7
8
9
第一步,讀取raw文本,按行分詞處理后存儲all_documents[doc_0, doc_1, …]里面,doc_i=[line_0, line_1, …], line_i = [token_0, token_1, …],然后shuffle文章。
第二步,重復dupe_factor=10次,每篇文章生成樣本,[CLS +A+SEP +B+SEP]作一條樣本。
注意:上述樣本既用于MLM,又用于next-Sentence預測訓練。

for _ in range(dupe_factor):
for document_index in range(len(all_documents)):
instances.extend(
create_instances_from_document(
all_documents, document_index, max_seq_length, short_seq_prob,
masked_lm_prob, max_predictions_per_seq, vocab_words, rng))
1
2
3
4
5
6
create_instances_from_document函數對每篇文章都生成一個訓練樣本實例。
從第一條句子循環到最后一條句子i ii,收集segment到current_chunk列表中,當收集到的總句子長度>=單條樣本最長值時,構造A+B。

if i == len(document) - 1 or current_length >= target_seq_length:
1
隨機截取 current_chunk的某個位置a_end,[0, a_end]作為子句A=token_a。
B句隨機概率選擇是Next or Not next,如果是next,則current_chunk的剩余[a_end, :]作為子句B=token_b。如果Not next,則隨機挑一篇文章,選擇某個長度的子句作為B=token_b。注意,Not next時,循環經過的B句子對應的步幅,要回去(因為這部分句子并沒有被真正使用,所以退回去以免浪費)。

num_unused_segments = len(current_chunk) - a_end
i -= num_unused_segments
1
2
兩個句子加和長度超過最大長度怎么辦?使用truncate_seq_pair在A和B中隨機選擇一個,隨機丟掉首/尾的詞,每次丟一個token,直到加和長度<=最大長度。

truncate_seq_pair(tokens_a, tokens_b, max_num_tokens, rng)
1
之后根據token_a和token_b生成tokens和segment_ids
tokens=[CLS,A0,A1,A2,SEP,B0,B1,B2,SEP] tokens = [CLS, A_0, A_1, A_2, SEP, B_0, B_1, B_2, SEP]tokens=[CLS,A
0
?
,A
1
?
,A
2
?
,SEP,B
0
?
,B
1
?
,B
2
?
,SEP]
segment_ids=[0a,0a,0a,0a,0a,1b,1b,1b,1b] segment\_ids =[0_a, 0_a, 0_a, 0_a, 0_a, 1_b, 1_b, 1_b, 1_b]segment_ids=[0
a
?
,0
a
?
,0
a
?
,0
a
?
,0
a
?
,1
b
?
,1
b
?
,1
b
?
,1
b
?
]
再之后,根據tokens生成遮擋替換之后的tokens、遮擋位置masked_lm_positions、遮擋位置的真實詞masked_lm_labels。

(tokens, masked_lm_positions,
masked_lm_labels) = create_masked_lm_predictions(
tokens, masked_lm_prob, max_predictions_per_seq, vocab_words, rng)
1
2
3
15%采樣遮擋,對遮擋的處理情況如下:
a) 80%的概率,遮擋詞被替換為[mask]。? \longrightarrow?別人看不到我。
b) 10%的概率,遮擋詞被替換為隨機詞。? \longrightarrow?別人看走眼我。
c) 10%的概率,遮擋詞被替換為原來詞。? \longrightarrow?別人能看到我。

masked_token = None
# 80% of the time, replace with [MASK]
if rng.random() < 0.8:
masked_token = "[MASK]"
else:
# 10% of the time, keep original
if rng.random() < 0.5:
masked_token = tokens[index]
# 10% of the time, replace with random word
else:
masked_token = vocab_words[rng.randint(0, len(vocab_words) - 1)]
1
2
3
4
5
6
7
8
9
10
11
輸入和返回結果舉例:

input tokens ="The man went to the store . He bought a gallon of milk "
ouput tokens ="The man went to the [mask] . He [mask] a gallon of ice"
output masked_lm_positions = [5, 8, 10, 11]
output masked_lm_labels = [store, bought, gallon, milk]
1
2
3
4
位置#5,#8被遮擋,#10被替換為原token,#11被替換為隨機詞。注意CLS和SEP不會被遮擋。
然后保存成TrainingInstance類,同時保留了is_next標記.

instance = TrainingInstance(
tokens=tokens,
segment_ids=segment_ids,
is_random_next=is_random_next,
masked_lm_positions=masked_lm_positions,
masked_lm_labels=masked_lm_labels)
1
2
3
4
5
6
tokenization.FullTokenizer類用來處理分詞,標點符號,unknown詞,Unicode轉換等操作。注意:中文只有單個字的切分,沒有詞。

數據存儲及讀取

存儲為TF-Record
輸入sentence變量的處理

input_ids = tokenizer.convert_tokens_to_ids(instance.tokens) ## ID化 ##
input_mask = [1] * len(input_ids)
segment_ids = segment_ids
padding 0 --> max_seq_length
1. 對iput_ids 補0到句子最大長度
2. 對input_mask 補0到句子最大長度
3. 對segment_ids 補0到句子最大長度
1
2
3
4
5
6
7
注意:input_mask是樣本中有效詞句的標識,后面需要用作作attention視野的約束。
遮擋變量的處理

masked_lm_positions = list(instance.masked_lm_positions)
masked_lm_ids = tokenizer.convert_tokens_to_ids(instance.masked_lm_labels)
masked_lm_weights = [1.0] * len(masked_lm_ids)
## padding 0 --> max_seq_length
1
2
3
4
注意:

masked_lm_ids是有mask的詞對應的ID,比如[120, 911, 234, 0, 0, 0, 0];
masked_lm_positions是有mask的詞對應的句子中位置,比如[15, 23, 11, 0, 0, 0, 0];
masked_lm_weights記錄遮擋詞的有效位置,計算masked-loss時使用,比如[1, 1, 1, 0, 0, 0, 0]。
next_sentense 的標記處理

next_sentence_label = 1 if instance.is_random_next else 0
1
save format 處理

features = collections.OrderedDict()
features["input_ids"] = create_int_feature(input_ids)
features["input_mask"] = create_int_feature(input_mask)
features["segment_ids"] = create_int_feature(segment_ids)
features["masked_lm_positions"] = create_int_feature(masked_lm_positions)
features["masked_lm_ids"] = create_int_feature(masked_lm_ids)
features["masked_lm_weights"] = create_float_feature(masked_lm_weights)
features["next_sentence_labels"] = create_int_feature([next_sentence_label])

tf_example = tf.train.Example(features=tf.train.Features(feature=features))
1
2
3
4
5
6
7
8
9
10
讀取使用dataset。

input_ids = features["input_ids"]
''' tf.data.TFRecordDataset '''
1
2
BertModel

模型實例化 ,注意這里的變量對應。

model = modeling.BertModel(
config=bert_config,
is_training=is_training,
input_ids=input_ids,
input_mask=input_mask,
token_type_ids=segment_ids, ## token_type是句子標記 ##
use_one_hot_embeddings=use_one_hot_embeddings)
1
2
3
4
5
6
7
輸入token_ids–>向量化處理, embeding_lookup返回token_emb 和查詢的table表。

(self.embedding_output, self.embedding_table) = embedding_lookup(
input_ids=input_ids,
vocab_size=config.vocab_size,
embedding_size=config.hidden_size,
word_embedding_name="word_embeddings", #and so on#)
1
2
3
4
5
加入pos_emb和type_emb處理, embedding_postprocessor
注意:pos_emb并不是用sin/cos函數生成的,而是隨機生成的。

self.embedding_output = embedding_postprocessor(
input_tensor=self.embedding_output,
use_token_type=True, ## type_emb的處理設置 ##
token_type_ids=token_type_ids,
token_type_vocab_size=config.type_vocab_size,
use_position_embeddings=True, ## pos_emb的處理設置 ##
dropout_prob=config.hidden_dropout_prob, # and so on #)
1
2
3
4
5
6
7
重要:構造attention可視域的attention_mask,因為每個樣本都經過padding了,視野必須要約束到有效范圍詞句內。

# This converts a 2D mask of shape [batch_size, seq_length] to a 3D
# mask of shape [batch_size, seq_length, seq_length] which is used for the attention scores.
attention_mask = create_attention_mask_from_input_mask(input_ids, input_mask)
## 注意:
## input_ids 是經過padding后的 [32,108, 99, 0, 0]; ##
## input_mask 是有效詞標志 [1, 1, 1, 0, 0] ##
def create_attention_mask_from_input_mask(from_tensor, to_mask):
"""Create 3D attention mask from a 2D tensor mask.
from_tensor: 2D or 3D Tensor of shape [batch_size, from_seq_length, ...].
to_mask: int32 Tensor of shape [batch_size, to_seq_length].
returns: [batch_size, from_seq_length, to_seq_length].
"""
1
2
3
4
5
6
7
8
9
10
11
12
Bert.Transformer

# Run the stacked transformer.
# `sequence_output` shape = [batch_size, seq_length, hidden_size].
self.all_encoder_layers = transformer_model(
input_tensor=self.embedding_output, ## 輸入token_ids經過 emb + pos_emb + seg_emb之后的結果 ##
attention_mask=attention_mask, ## 根據input_mask得到的可視域3D表示 ##
num_attention_heads=config.num_attention_heads, ## 多頭數量 ##
do_return_all_layers=True, # and so on #)
1
2
3
4
5
6
7
對Transformer內部,逐層attention
1)先搞self-attention,注意有效位置的計算attention_mask。
2)再對每個位置做前向網絡,加個drop層,加個layer-norm層,殘差連接2)的輸入。
3)再對每個位置做前向網絡,加個drop層,加個layer-norm層,殘差連接3)的輸入。
4)輸出作下層的輸入,直到N層。
重要:這里根據輸入query=[batch_size * seq_length, emb_size]來梳理下計算單層self-attenion過程中的維度變化。


注意:輸入詞的emb_size必須跟Transformer 的輸出dim=-1的size一樣么,必須的,因為有殘差連接,必須保持維度一致。但是,head_nums_size × \times× size_per_head = emb_size=hidden_size不用必須成立【notice,bert代碼實現上是將其設為相等的】,query_layer的最后維度只需是head_nums × \times× 任意數。靠近輸出的dense包括了drop/layer-norm操作。
self-attention的矩陣計算示例


再說明下,query–>query_layer的變換,并不是echo token獨享一個轉換矩陣,也不是每個位置獨享一個矩陣,而是query的emb_size空間–> query_layer的hidden_size空間上的維度變換。
重要:attention的計算示例
1)先看下單條樣本時,self-attention的計算示例SelfAttentionSingle.py 鏈接
2)再看下batch樣本時,self-attention的計算示例SelfAttentionBatch.py 鏈接
3)最后再看下batch+heads時,self-attention的計算示例SelfAttentionBatchMultiHeads.py 鏈接

attention_mask的作用在于,softmax時,對非視野內的做負向大加權,使得attention-score只計算注意在可視域范圍內【非補0的地方】的數值。

if attention_mask is not None:
# `attention_mask` = [B, 1, F, T]
attention_mask = tf.expand_dims(attention_mask, axis=[1])
# Since attention_mask is 1.0 for positions we want to attend and 0.0 for
# masked positions, this operation will create a tensor which is 0.0 for
# positions we want to attend and -10000.0 for masked positions.
adder = (1.0 - tf.cast(attention_mask, tf.float32)) * -10000.0
# Since we are adding it to the raw scores before the softmax, this is
# effectively the same as removing these entirely.
attention_scores += adder
# Normalize the attention scores to probabilities.
# `attention_probs` = [B, N, F, T]
attention_probs = tf.nn.softmax(attention_scores)
1
2
3
4
5
6
7
8
9
10
11
12
13
注意,計算完上下文信息后,要轉換成[batch, seq_length, num_heads, size_per_head],再作其他處理。

BertModel.sequence_output 是取最后attenion層的輸出。
BertModel.pooled_output 取sequence_output的第一個token“CLS”的emb,然后加個連接層。

Loss Compute

Masked Language Model的loss計算

(masked_lm_loss,
masked_lm_example_loss, masked_lm_log_probs) = get_masked_lm_output(
bert_config, model.get_sequence_output(), model.get_embedding_table(),
masked_lm_positions, masked_lm_ids, masked_lm_weights)
def get_masked_lm_output(bert_config, input_tensor, output_weights, positions,
label_ids, label_weights):
## input_tensor = model.get_sequence_output(), model的最后層輸出 ## [B, seq_len, emb_size]
## output_weights = model.get_embedding_table(), vocab_table ## [vocab_size, emb_size]
## positions = msked_lm_positions 遮擋詞的在句子中的位置 ## [B, seq_len] ## 前幾個是位置 ## 舉例 [#pos1, #pos3, #pos10, 0, 0, 0]
## label_ids = masked_lm_ids ## 遮擋詞的ID ## [B, seq_len] ## 前幾個是ID ## 舉例 [119, 301, 911, 0, 0, 0]
## label_weights = masked_lm_weights ## 遮擋詞權重=1,非遮擋詞權重=0 ## [B, seq_len] ## 舉例 [1, 1, 1, 0, 0, 0]
## = pdding([1.0] * len(masked_lm_ids))
"""Get loss and log probs for the masked LM."""
input_tensor = gather_indexes(input_tensor, positions)
## gather_indexes也會將補0取出來,所以總tensor_size是不變的, [B*seq_len, emb_size]
## 注意后續的計算,都是在這個尺寸上進行的 ##
## 又單獨加了層輸出dense,并增加了vocab_emb_table的乘積 + bias ##

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
注意: label_weight在最后計算總loss時,乘上,只計算有遮擋的位置的loss。

Next Sentence Predict的loss計算
注意:此處使用模型最后輸出層的第一個token-"CLS"的emb作為輸入。

(next_sentence_loss, next_sentence_example_loss,
next_sentence_log_probs) = get_next_sentence_output(
bert_config, model.get_pooled_output(), next_sentence_labels)
def get_next_sentence_output(bert_config, input_tensor, labels):
## input_tensor = model.get_pooled_output() ## 模型最后輸出層的第一個token-"CLS"的emb ##
## labels = next_sentence_labels ##
"""Get loss and log probs for the next sentence prediction."""
## 剩下的就是添加個dense層,二元分類 計算loss ##
1
2
3
4
5
6
7
8
兩個loss加和作總的損失,聯合訓練。

total_loss = masked_lm_loss + next_sentence_loss
1
參考

https://github.com/google-research/bert
---------------------
作者:于建民
來源:CSDN
原文:https://blog.csdn.net/yujianmin1990/article/details/85175905
版權聲明:本文為博主原創文章,轉載請附上博文鏈接!

總結

以上是生活随笔為你收集整理的Bert源码阅读的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 成人免费视频国产在线观看 | 国产91影院 | 久久无毛 | 亚洲av无码一区二区乱孑伦as | 久久久久久久久99精品 | 亚洲福利社 | 国产在线成人精品午夜 | 精品+无码+在线观看 | 久久婷婷一区二区 | 雨宫琴音一区二区三区 | 狠狠躁日日躁 | 激情六月丁香 | 亚洲AV无码久久精品色三人行 | 国产1区在线观看 | 久久久久一区二区 | 激情的网站| 91成人精品一区在线播放 | 一区二区av | 高清一区二区三区四区 | 午夜精品美女久久久久av福利 | 欧美成人激情在线 | 国产亚洲欧美在线视频 | 欧美亚洲另类在线 | av一二三区| 不许穿内裤随时挨c调教h苏绵 | 精品国产乱码久久久久久浪潮 | 杨幂毛片| 国产精品女教师 | 蜜臀久久99精品久久一区二区 | 久久综合日本 | 视频一区二区中文字幕 | 裸体美女免费视频网站 | 日韩av一区二区在线播放 | 欧美视频二区 | 亚洲狠狠婷婷综合久久久久图片 | 色翁荡息又大又硬又粗又爽 | 亚洲国产视频在线观看 | 亚洲粉嫩| 岳奶大又白下面又肥又黑水多 | 亚洲天堂av网站 | 538国产精品一区二区 | 国产毛片毛片毛片毛片毛片 | 久久免费视频2 | 国内外免费激情视频 | 国产美女在线免费观看 | 国产aⅴ精品一区二区果冻 台湾性生生活1 | 国产精品jizz在线观看美国 | av日韩在线免费观看 | 超碰按摩 | 在线97| 成人国产毛片 | 超碰av在线免费观看 | av无遮挡| 色综合中文 | 国产第一福利 | 久久伊人久久 | 深夜的私人秘书 | 九月婷婷| 国产精品视频久久久久久 | 精品久久久无码中文字幕 | 日韩免费播放 | 18岁禁黄网站 | 操人视频在线观看 | 国产成人福利视频 | av不卡在线看 | 国产 中文 字幕 日韩 在线 | 成a人v| 在线成人福利 | 欧美激情h | 青草av在线| 91亚色视频 | 狠狠撸狠狠干 | 亚洲中午字幕 | 日韩xxx视频 | 99成人国产精品视频 | 亚洲激情午夜 | 波多野结衣在线视频免费观看 | 美女搞黄视频网站 | 国产又粗又长 | 亚洲欲色| 国产精品美女高潮无套 | 国产真实偷伦视频 | 天天操夜夜操夜夜操 | 日本不卡视频一区二区 | aaa影院| av国产一区 | 日本高清xxx| 亚洲操片 | 精品国产乱码久久 | 欧美精品一区二区视频 | 巨胸喷奶水www久久久免费动漫 | 天堂va欧美ⅴa亚洲va一国产 | 神马久久久久 | 婷婷狠狠爱 | 国产va亚洲va在线va | 95在线视频 | 又粗又猛又爽又黄少妇视频网站 | 日韩一区二区高清 | 啄木乌欧美一区二区三区 |