BERT BERT

BERT

***** 2020年3月11日更新:更小的BERT模型 *****

這是在《深閱讀的學生學得更好:預訓練緊湊模型的重要性》(arXiv:1908.08962)中提到的24種較小規模的英文未分詞BERT模型的發布。

我們已經證明,標準的BERT架構和訓練目標在各種模型大小上都是有效的,不僅僅是BERT-Base和BERT-Large。這些小型BERT模型旨在用于計算資源有限的環境。它們可以像原始BERT模型一樣進行微調。然而,在知識蒸餾的背景下,它們最有效,此時微調標簽由更大、更準確的教師模型生成。

我們的目標是讓資源較少的機構能夠進行研究,并鼓勵社區尋求不同于增加模型容量的創新方向。

所有24個模型可以從這里下載,或者從下面的表格中單獨下載:

H=128H=256H=512H=768
L=22/128(BERT-Tiny)2/2562/5122/768
L=44/1284/256(BERT-Mini)4/512(BERT-Small)4/768
L=66/1286/2566/5126/768
L=88/1288/2568/512(BERT-Medium)8/768
L=1010/12810/25610/51210/768
L=1212/12812/25612/51212/768(BERT-Base)

注意,此次發布的BERT-Base模型只是為了完整性,它是在與原始模型相同的條件下重新訓練的。

以下是GLUE測試集上的相應分數:

模型得分CoLASST-2MRPCSTS-BQQPMNLI-mMNLI-mmQNLI(v2)RTEWNLIAX
BERT-Tiny64.20.083.281.1/71.174.3/73.662.2/83.470.270.381.557.262.321.0
BERT-Mini65.80.085.981.1/71.875.4/73.366.4/86.274.874.384.157.962.326.1
BERT-Small71.227.889.783.4/76.278.8/77.068.1/87.077.677.086.461.862.328.6
BERT-Medium73.538.089.686.6/81.680.4/78.469.6/87.980.079.187.762.262.330.5

對于每個任務,我們在以下列表中選擇了最佳微調超參數,并進行了4個周期的訓練:

  • 批次大小:8, 16, 32, 64, 128
  • 學習率:3e-4, 1e-4, 5e-5, 3e-5

如果您使用這些模型,請引用以下論文:

@article{turc2019,title={Well-Read Students Learn Better: On the Importance of Pre-training Compact Models},author={Turc, Iulia and Chang, Ming-Wei and Lee, Kenton and Toutanova, Kristina},journal={arXiv preprint arXiv:1908.08962v2 },year={2019}
}

***** 2019年5月31日新更新:整體單詞掩碼模型 *****

這是對預處理代碼改進后產生的多個新模型的發布。

在原來的預處理代碼中,我們隨機選擇WordPiece令牌進行掩碼。例如:

輸入文本:the man jumped up , put his basket on phil ##am ##mon ' s head
原掩碼輸入:[MASK] man [MASK] up , put his [MASK] on phil [MASK] ##mon ' s head

新的技術稱為整體單詞掩碼。在這種情況下,我們總是同時掩碼一個單詞的所有對應令牌。整體掩碼率保持不變。

整體單詞掩碼輸入:the man [MASK] up , put his basket on [MASK] [MASK] [MASK] ' s head

訓練仍然是相同的 - 我們仍然獨立預測每個被掩碼的WordPiece令牌。改進來自于原來的預測任務對于被拆分為多個WordPiece的單詞來說太“容易”。

這可以通過在create_pretraining_data.py中傳遞標志--do_whole_word_mask=True來啟用。

帶有整體單詞掩碼的預訓練模型鏈接如下。數據和訓練否則完全相同,模型具有與原始模型相同的結構和詞匯。我們只包含BERT-Large模型。當使用這些模型時,請在論文中明確說明您正在使用BERT-Large的整體單詞掩碼變體。

  • BERT-Large, 不區分大小寫(整體單詞掩碼): 24層,1024隱藏,16頭,3.4億參數

  • BERT-Large, 區分大小寫(整體單詞掩碼): 24層,1024隱藏,16頭,3.4億參數

模型名稱SQUAD 1.1 F1/EM多任務NLI準確性
BERT-Large, 不區分大小寫(原版)91.0/84.386.05
BERT-Large, 不區分大小寫(整體單詞掩碼)92.8/86.787.07
BERT-Large, 區分大小寫(原版)91.5/84.886.09
BERT-Large, 區分大小寫(整體單詞掩碼)92.9/86.786.46

***** 2019年2月7日新更新:TensorFlow Hub模塊 *****

BERT已上傳至TensorFlow Hub。請參閱run_classifier_with_tfhub.py以了解如何使用TF Hub模塊,或在Colab中運行瀏覽器中的示例。

***** 2018年11月23日新更新:未規范化多語言模型 + 泰語 + 蒙古語 *****

我們上傳了一個新的多語言模型,該模型在輸入時不進行任何規范化(不區分大小寫、不移除音標、不進行Unicode標準化),并額外包括泰語和蒙古語。

建議在開發多語言模型時使用此版本,特別是對于使用非拉丁字母的語言。

這不需要任何代碼更改,可以在以下位置下載:

  • BERT-Base, 多語言區分大小寫: 104種語言,12層,768隱藏,12頭,1.1億參數

***** 2018年11月15日新更新:SOTA SQuAD 2.0系統 *****

我們發布了代碼更改以重現我們的83%F1 SQuAD 2.0系統,目前在排行榜上領先3%。有關詳細信息,請參閱README的SQuAD 2.0部分。

***** 2018年11月5日新更新:第三方PyTorch和Chainer版本的BERT可用 *****

來自HuggingFace的NLP研究人員提供了與我們的預訓練檢查點兼容的PyTorch版本的BERT,并且能夠復制我們的結果。Sosuke Kobayashi也提供了Chainer版本的BERT(謝謝!)。我們沒有參與PyTorch實現的創建和維護,所以請直接向該存儲庫的作者提問。

***** 2018年11月3日新更新:多語言和中文模型可用 *****

我們提供了兩種新的BERT模型:

  • BERT-Base, 多語言(不推薦,改用多語言區分大小寫:102種語言,12層,768隱藏,12頭,1.1億參數
  • BERT-Base, 中文:簡體中文和繁體中文,12層,768隱藏,12頭,1.1億參數

我們為中文使用基于字符的分詞,而其他所有語言則使用WordPiece分詞。兩個模型都可以無縫使用,無需任何代碼更改。我們確實更新了tokenization.py中的BasicTokenizer的實現以支持中文字符分詞,因此如果分叉了它,請進行更新。但是,我們并未更改分詞API。

更多信息,請參閱多語言README。

***** 結束新信息 *****

引言

BERT,即雙向編碼器表示(Bidirectional Encoder Representations)從轉換器(Transformers),是一種新的語言表征預訓練方法,它在各種自然語言處理(NLP)任務中取得了最先進的結果。

詳細描述BERT并提供多個任務完整結果的學術論文可在此找到:[1810.04805] BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding。

舉幾個數字,在SQuAD v1.1問答任務中的成績如下:

SQuAD v1.1 領先榜(2018年10月8日)測試EM測試F1
第1名合集 - BERT87.493.2
第2名合集 - nlnet86.091.7
第1名單模型 - BERT85.191.8
第2名單模型 - nlnet83.590.1

還有多項自然語言推理任務的成績:

系統MultiNLIQuestion NLISWAG
BERT86.791.186.3
OpenAI GPT(先前最好)82.288.175.0

此外還包括許多其他任務。

重要的是,這些成果幾乎無需針對特定任務設計神經網絡架構。

如果你已經了解BERT,并希望立即開始操作,只需下載預先訓練好的模型,然后在幾分鐘內使用BERT進行先進的微調。

什么是BERT?

BERT是一種預訓練語言表示的方法,意味著我們在大型文本語料庫(如維基百科)上訓練一個通用的“語言理解”模型,然后用該模型來執行我們關心的下游NLP任務(例如,問答)。BERT超越了以前的方法,因為它是首個無監督、深度雙向的預訓練NLP系統。

無監督意味著BERT僅使用純文本語料庫進行訓練,這一點很重要,因為許多語言在網絡上有大量公開可用的純文本數據。

預訓練表示可以是上下文無關的或是上下文相關的,而上下文相關的表示則可以是單向的雙向的。例如,像word2vec或GloVe這樣的上下文無關模型為詞匯表中的每個詞生成一個單一的“詞嵌入”表示,所以“bank”在“bank deposit”和“river bank”中的表示相同。而上下文相關模型則根據句子中其他詞生成每個詞的表示。

BERT建立在最近關于預訓練上下文表示的工作之上——包括Semi-supervised Sequence Learning、Generative Pre-Training、ELMo以及ULMFit——但關鍵在于這些模型都是單向的淺度雙向的。這意味著每個詞僅根據其左側(或右側)的詞進行上下文化。例如,在句子“I made a bank deposit”中,“bank”的單向表示僅基于“I made a”,而不包括“deposit”。一些早期工作結合了分別來自左文境和右文境模型的表示,但只是以“淺”的方式。BERT利用左右文境——“I made a ... deposit”——從深度神經網絡的底層對“bank”進行表示,因此是深度雙向的

BERT為此采用了一種簡單的方法:我們將輸入中15%的單詞遮蓋,整個序列通過深雙向的Transformer編碼器運行,然后僅預測被遮蓋的單詞。例如:

輸入: the man went to the [MASK1] . he bought a [MASK2] of milk.
標簽: [MASK1] = store; [MASK2] = gallon

為了學習句子間的關系,我們也對一項簡單的任務進行訓練,這個任務可以從任何單語語料庫生成:給定兩個句子AB,“B”是否實際上是緊跟在A后面的句子,還是語料庫中的隨機句子?

句子A: the man went to the store .
句子B: he bought a gallon of milk .
標簽: IsNextSentence
句子A: the man went to the store .
句子B: penguins are flightless .
標簽: NotNextSentence

然后,我們在大型語料庫(維基百科+BookCorpus)上用一個大模型(12層到24層Transformer)進行長時間(1M步更新)訓練,這就是BERT。

使用BERT有兩個階段:預訓練微調

預訓練相對昂貴(在4到16個云TPU上花費四天時間),但對于每種語言來說都是一次性的過程(當前模型僅支持英文,但多語言模型將在不久后發布)。我們將發布論文中訓練的多個預訓練模型,它們是在Google上預先訓練的。大多數NLP研究者無需從頭開始訓練自己的模型。

微調成本較低。論文中所有的結果都可以在最多1小時的單個Cloud TPU上,或幾個小時的GPU上復現,從同一個預訓練模型開始。例如,SQuAD可以在單個Cloud TPU上大約30分鐘內完成訓練,達到Dev F1分數91.0%,這是單系統的最新狀態。

BERT的另一個重要方面是它可以非常容易地適應多種類型的NLP任務。在論文中,我們展示了幾乎沒有任務特定修改的情況下,在句子級(如SST-2)、句子對級(如MultiNLI)、詞級(如NER)和跨度級(如SQuAD)任務上的最佳結果。

此存儲庫已發布什么?

我們發布了以下內容:

  • 包含BERT模型架構(主要是標準的Transformer架構)的TensorFlow代碼。
  • 論文中BERT-BaseBERT-Large的小寫和全拼版本的預訓練檢查點。
  • TensorFlow代碼,用于一鍵復制論文中最重要微調實驗,包括SQuAD、MultiNLI和MRPC。

此存儲庫中的所有代碼均與CPU、GPU和Cloud TPU兼容并可直接使用。

預訓練模型

我們發布了論文中的BERT-BaseBERT-Large模型。Uncased表示在WordPiece分詞之前,文本已經轉換為小寫,例如,John Smith變為john smithUncased模型還會移除所有重音標記。Cased意味著保留真實的大小寫和重音標記。通常情況下,除非您知道對于您的任務(如命名實體識別或詞性標注),大小寫信息是重要的,否則Uncased模型表現會更好。

這些模型都根據源代碼相同的許可證(Apache 2.0)發布。

如果使用帶大小寫的模型,請確保在訓練腳本中傳遞--do_lower=False參數。(或者如果您使用自己的腳本,直接向FullTokenizer傳遞do_lower_case=False。)

模型鏈接如下(右鍵點擊,選擇“另存為...”):

  • BERT-Large, Uncased (Whole Word Masking): 24層,1024個隱藏單元,16個頭,340M參數
  • BERT-Large, Cased (Whole Word Masking): 24層,1024個隱藏單元,16個頭,340M參數
  • BERT-Base, Uncased: 12層,768個隱藏單元,12個頭,110M參數
  • BERT-Large, Uncased: 24層,1024個隱藏單元,16個頭,340M參數
  • BERT-Base, Cased: 12層,768個隱藏單元,12個頭,110M參數
  • BERT-Large, Cased: 24層,1024個隱藏單元,16個頭,340M參數
  • BERT-Base, Multilingual Cased (New, recommended): 支持104種語言,12層,768個隱藏單元,12個頭,110M參數
  • BERT-Base, Multilingual Uncased (Orig, not recommended)?(不推薦,建議使用Multilingual Cased替代):支持102種語言, 12層,768個隱藏單元,12個頭,110M參數
  • BERT-Base, Chinese: 中文簡體與繁體,12層,768個隱藏單元,12個頭,110M參數

每個.zip文件包含以下三個項目:

  • 一個TensorFlow檢查點文件(bert_model.ckpt),其中包含預訓練權重(實際上是3個文件)。
  • 詞匯文件(vocab.txt),用于映射WordPiece到單詞ID。
  • 配置文件(bert_config.json),指定模型的超參數。

使用BERT進行微調

重要提示:論文中所有結果是在具有64GB內存的單個Cloud TPU上進行微調得到的。目前,在只有12GB至16GB內存的GPU上無法重現大多數BERT-Large的結果,因為可以容納的最大批次大小太小。我們正在努力更新此存儲庫以允許在GPU上實現更大的有效批量大小。有關更多細節,請參閱內存溢出問題部分。

此代碼已測試過TensorFlow 1.11.0版本,同時支持Python2和Python3(盡管更全面地測試了Python2,因為這是Google內部使用的版本)。

使用BERT-Base的微調示例應該能夠在至少具有12GB內存的GPU上,按照給定的超參數運行。

在Cloud TPU上微調

以下大部分示例假設您將在本地機器上使用像Titan X或GTX 1080這樣的GPU運行訓練和評估。

但是,如果您有要訓練的Cloud TPU,請在run_classifier.pyrun_squad.py中添加以下標志:

  --use_tpu=True \--tpu_name=$TPU_NAME

請參考Google Cloud TPU教程,了解如何使用Cloud TPU。或者,您可以使用Google Colab筆記本 "BERT FineTuning with Cloud TPUs"。

在Cloud TPU上,預訓練模型和輸出目錄需要在Google Cloud Storage上。例如,如果您有一個名為some_bucket的存儲桶,您可能會使用以下標志:

  --output_dir=gs://some_bucket/my_output_dir/

預訓練模型的未壓縮文件也可以在Google Cloud Storage的gs://bert_models/2018_10_18文件夾中找到。例如:

export BERT_BASE_DIR=gs://bert_models/2018_10_18/uncased_L-12_H-768_A-12

句子(和句子對)分類任務

在運行這個例子之前,您需要通過運行這個腳本下載GLUE數據,然后將其解壓到目錄$GLUE_DIR。接下來,下載BERT-Base檢查點并將其解壓縮到目錄$BERT_BASE_DIR

這個示例代碼會在微軟研究的Paraphrase語料庫(MRPC)上微調BERT-Base,該語料庫僅包含3,600個示例,可以在大多數GPU上用幾分鐘的時間完成微調。

export BERT_BASE_DIR=/path/to/bert/uncased_L-12_H-768_A-12
export GLUE_DIR=/path/to/gluepython run_classifier.py \--task_name=MRPC \--do_train=true \--do_eval=true \--data_dir=$GLUE_DIR/MRPC \--vocab_file=$BERT_BASE_DIR/vocab.txt \--bert_config_file=$BERT_BASE_DIR/bert_config.json \--init_checkpoint=$BERT_BASE_DIR/bert_model.ckpt \--max_seq_length=128 \--train_batch_size=32 \--learning_rate=2e-5 \--num_train_epochs=3.0 \--output_dir=/tmp/mrpc_output/

您應看到如下輸出:

***** Eval results *****eval_accuracy = 0.845588eval_loss = 0.505248global_step = 343loss = 0.505248

這意味著開發集準確率為84.55%。像MRPC這樣的小型數據集即使從同一個預訓練檢查點開始,其開發集準確性也會有很大差異。如果多次重新運行(確保指向不同的output_dir),您應看到介于84%和88%之間的結果。

有幾個預訓練模型已在run_classifier.py中開箱即用,因此使用BERT進行任何單句或多句分類任務應該很容易遵循這些示例。

注意:您可能會看到一條消息Running train on CPU。這實際上只是指它不在Cloud TPU上運行,包括GPU。

分類器預測

一旦訓練了分類器,您就可以在推理模式下使用它,通過使用--do_predict=true命令。需要在輸入文件夾中有一個名為test.tsv的文件。輸出將在名為test_results.tsv的輸出文件夾中創建。每行將包含每個樣本的輸出,列是類別概率。

export BERT_BASE_DIR=/path/to/bert/uncased_L-12_H-768_A-12
export GLUE_DIR=/path/to/glue
export TRAINED_CLASSIFIER=/path/to/fine/tuned/classifierpython run_classifier.py \--task_name=MRPC \--do_predict=true \--data_dir=$GLUE_DIR/MRPC \--vocab_file=$BERT_BASE_DIR/vocab.txt \--bert_config_file=$BERT_BASE_DIR/bert_config.json \--init_checkpoint=$TRAINED_CLASSIFIER \--max_seq_length=128 \--output_dir=/tmp/mrpc_output/

SQuAD 1.1

斯坦福問答數據集(SQuAD)是一個流行的問題回答基準數據集。BERT(在發布時)幾乎無需針對任務特定的網絡架構修改或數據增強,就能在此數據集上取得最先進的結果。然而,它確實需要半復雜的預處理和后處理來應對:(a) 變長度的SQuAD上下文段落,以及 (b) 用于SQuAD訓練的字符級答案注釋。這些處理在run_squad.py中實現并文檔化。

首先,你需要下載該數據集。SQuAD網站似乎不再鏈接到v1.1版本的數據集,但所需的文件可以在這里找到:

  • train-v1.1.json
  • dev-v1.1.json
  • evaluate-v1.1.py

將這些文件下載到目錄?$SQUAD_DIR

由于內存限制,在12GB-16GB GPU上無法重現論文中的最新SQuAD結果(事實上,即使批處理大小設為1也不適用于12GB GPU上的BERT-Large)。然而,一個相當強大的BERT-Base模型可以在GPU上使用以下超參數進行訓練:

python run_squad.py \--vocab_file=$BERT_BASE_DIR/vocab.txt \--bert_config_file=$BERT_BASE_DIR/bert_config.json \--init_checkpoint=$BERT_BASE_DIR/bert_model.ckpt \--do_train=True \--train_file=$SQUAD_DIR/train-v1.1.json \--do_predict=True \--predict_file=$SQUAD_DIR/dev-v1.1.json \--train_batch_size=12 \--learning_rate=3e-5 \--num_train_epochs=2.0 \--max_seq_length=384 \--doc_stride=128 \--output_dir=/tmp/squad_base/

開發集的預測結果會被保存到output_dir中的名為predictions.json的文件里:

python $SQUAD_DIR/evaluate-v1.1.py $SQUAD_DIR/dev-v1.1.json ./squad/predictions.json

這應該會輸出類似如下結果:

{"f1": 88.41249612335034, "exact_match": 81.2488174077578}

你應該能看到與BERT-Base報道的88.5%相似的結果。

如果你有訪問Cloud TPU的權限,你可以用BERT-Large進行訓練。以下是獲得大約90.5%-91.0% F1單系統評分的一組(與論文略有不同)一致的超參數,僅基于SQuAD進行訓練:

python run_squad.py \--vocab_file=$BERT_LARGE_DIR/vocab.txt \--bert_config_file=$BERT_LARGE_DIR/bert_config.json \--init_checkpoint=$BERT_LARGE_DIR/bert_model.ckpt \--do_train=True \--train_file=$SQUAD_DIR/train-v1.1.json \--do_predict=True \--predict_file=$SQUAD_DIR/dev-v1.1.json \--train_batch_size=24 \--learning_rate=3e-5 \--num_train_epochs=2.0 \--max_seq_length=384 \--doc_stride=128 \--output_dir=gs://some_bucket/squad_large/ \--use_tpu=True \--tpu_name=$TPU_NAME

例如,用這些參數進行一次隨機運行,會產生如下開發集分數:

{"f1": 90.87081895814865, "exact_match": 84.38978240302744}

如果你在此次訓練之前先在一個epoch上對TriviaQA進行微調,結果會更好,但你需要將TriviaQA轉換為SQuAD JSON格式。

SQuAD 2.0

此模型也在run_squad.py中實現并記錄。

要運行SQuAD 2.0,首先需要下載數據集。所需文件如下所示:

  • train-v2.0.json
  • dev-v2.0.json
  • evaluate-v2.0.py

將這些文件下載到目錄?$SQUAD_DIR

在Cloud TPU上,你可以用以下方式運行BERT-Large

python run_squad.py \--vocab_file=$BERT_LARGE_DIR/vocab.txt \--bert_config_file=$BERT_LARGE_DIR/bert_config.json \--init_checkpoint=$BERT_LARGE_DIR/bert_model.ckpt \--do_train=True \--train_file=$SQUAD_DIR/train-v2.0.json \--do_predict=True \--predict_file=$SQUAD_DIR/dev-v2.0.json \--train_batch_size=24 \--learning_rate=3e-5 \--num_train_epochs=2.0 \--max_seq_length=384 \--doc_stride=128 \--output_dir=gs://some_bucket/squad_large/ \--use_tpu=True \--tpu_name=$TPU_NAME \--version_2_with_negative=True

假設你已將輸出目錄的所有內容復制到本地名為squad/的目錄下。最初的開發集預測將在squad/predictions.json中,每個問題的最佳非空答案與無答案(" ")之間的得分差異會在squad/null_odds.json文件中。

運行以下腳本來調整預測空值與非空值答案的閾值:

python $SQUAD_DIR/evaluate-v2.0.py $SQUAD_DIR/dev-v2.0.json ./squad/predictions.json --na-prob-file ./squad/null_odds.json

假設腳本輸出了“best_f1_thresh”THRESH。(典型值介于-1.0和-5.0之間)。現在,你可以重新運行模型以生成使用派生閾值的預測,或者從squad/nbest_predictions.json中提取相應的答案。

python run_squad.py \--vocab_file=$BERT_LARGE_DIR/vocab.txt \--bert_config_file=$BERT_LARGE_DIR/bert_config.json \--init_checkpoint=$BERT_LARGE_DIR/bert_model.ckpt \--do_train=False \--train_file=$SQUAD_DIR/train-v2.0.json \--do_predict=True \--predict_file=$SQUAD_DIR/dev-v2.0.json \--train_batch_size=24 \--learning_rate=3e-5 \--num_train_epochs=2.0 \--max_seq_length=384 \--doc_stride=128 \--output_dir=gs://some_bucket/squad_large/ \--use_tpu=True \--tpu_name=$TPU_NAME \--version_2_with_negative=True \--null_score_diff_threshold=$THRESH

內存溢出問題

論文中所有的實驗都是在擁有64GB設備RAM的Cloud TPU上進行微調的。因此,如果你使用只有12GB-16GB RAM的GPU,并且使用了論文中描述的相同超參數,很可能會遇到內存不足的問題。

影響內存使用的因素包括:

  • max_seq_length:發布的模型是用序列長度高達512進行訓練的,但可以通過縮短最大序列長度來節省大量內存。這在示例代碼中的max_seq_length標志處控制。

  • train_batch_size:內存使用量也直接與批處理大小成比例。

  • 模型類型,BERT-BaseBERT-LargeBERT-Large模型比BERT-Base需要更多的內存。

  • 優化器:BERT的默認優化器是Adam,它需要大量的額外內存來存儲mv向量。切換到更節省內存的優化器可以減少內存使用,但也可能影響結果。我們尚未嘗試過其他用于微調的優化器。

使用默認的訓練腳本(run_classifier.pyrun_squad.py),我們在配備了TensorFlow 1.11.0的單個Titan X GPU(12GB RAM)上進行了最大批處理大小的基準測試:

系統序列長度最大批處理大小
BERT-Base6464
...12832
...25616
...32014
...38412
...5126
BERT-Large6412
...1286
...2562
...3201
...3840
...5120

不幸的是,對于BERT-Large來說,這些最大批處理大小如此之小,以至于無論使用什么學習率,都會損害模型的準確性。我們正在努力向這個倉庫添加代碼,以便在GPU上使用更大的有效批處理大小。代碼將以以下一種(或兩種)技術為基礎:

  • 梯度積累:在微型批次中的樣本通常獨立于梯度計算(不包括這里未使用的批量歸一化)。這意味著在執行權重更新之前,可以累積多個較小微型批次的梯度,這與單次較大的更新完全等價。

  • 梯度檢查點:深度神經網絡訓練期間,GPU/TPU內存的主要用途是在前向傳遞中緩存用于反向傳遞高效計算的中間激活。"梯度檢查點"通過智能地重新計算激活來交換內存與計算時間。

但是,這在當前版本中并未實現。

利用BERT提取固定特征向量(類似ELMo)

在某些情況下,而不是對整個預訓練模型進行端到端的微調,獲取“預訓練上下文嵌入”是有益的。這些是通過預訓練模型隱藏層生成的每個輸入令牌的固定上下文表示,可以緩解大部分內存不足的問題。

我們提供了腳本extract_features.py,使用方法如下:

# 句子A和句子B以|||分隔符隔開,適用于像問答和蘊含這樣的句子對任務。
# 對于單句輸入,每行放一個句子,并不要使用分隔符。
echo 'Who was Jim Henson ? ||| Jim Henson was a puppeteer' > /tmp/input.txtpython extract_features.py \--input_file=/tmp/input.txt \--output_file=/tmp/output.jsonl \--vocab_file=$BERT_BASE_DIR/vocab.txt \--bert_config_file=$BERT_BASE_DIR/bert_config.json \--init_checkpoint=$BERT_BASE_DIR/bert_model.ckpt \--layers=-1,-2,-3,-4 \--max_seq_length=128 \--batch_size=8

這將在一個JSON文件中創建一行對應一行輸入的BERT激活值,其中layers參數指定的(-1是Transformer的最后一層隱含層等)。

請注意,此腳本會生成非常大的輸出文件(默認情況下,每個輸入令牌大約15kb)。

如果需要在原始單詞和分詞化后的單詞之間保持對齊(用于投影訓練標簽),請參閱下面的“分詞”部分。

**注意:**您可能會看到如Could not find trained model in model_dir: /tmp/tmpuB5g5c, running initialization to predict.的消息。這是預期中的,它意味著我們使用了init_from_checkpoint()?API而不是保存模型API。如果沒有指定檢查點或指定了無效的檢查點,這個腳本會報錯。

分詞

對于句子級別的任務(或句子對任務),分詞很簡單。只需遵循run_classifier.pyextract_features.py中的示例代碼。基本步驟是:

  1. 實例化一個tokenizer = tokenization.FullTokenizer對象。

  2. 使用tokens = tokenizer.tokenize(raw_text)對原始文本進行分詞。

  3. 將長度截斷至最大序列長度。(您可以使用最多512個,但為了內存和速度考慮,盡可能短一些)。

  4. 在正確位置添加[CLS][SEP]令牌。

詞級和跨度級任務(例如SQuAD和NER)更復雜,因為需要在輸入文本和輸出文本之間維護對齊,以便將訓練標簽投影回去。SQuAD是一個特別復雜的例子,因為其輸入標簽基于字符,并且SQuAD段落常常超過我們的最大序列長度。請查看run_squad.py的代碼,了解我們如何處理這個問題。

在描述處理詞級任務的一般方法之前,理解我們的分詞器到底在做什么是很重要的。它主要分為三個步驟:

  1. 文本規范化:將所有空白字符轉換為空格,(對于“Uncased”模型)將輸入小寫并去除重音標記。例如:John Johanson's, → john johanson's,

  2. 標點符號分割:在標點符號兩側都進行切割(即,在所有標點符號周圍添加空格)。標點符號定義為(a)具有“P*”Unicode類的任何字符,(b)非字母/數字/空間的ASCII字符(例如,實際上不是標點符號的字符如$) 。例如:john johanson's, → john johan ##son ' s ,

  3. 詞塊分詞:將上述過程的輸出應用空格分詞,并對每個單獨的單詞應用WordPiece分詞。(我們的實現直接基于tensor2tensor的版本,見鏈接)。例如:john johan ##son ' s , → john johan ##son ' s ,

這種方案的優點是與大多數現有的英語分詞器“兼容”。例如,假設你有一個部分-of-speech標注任務,如下所示:

輸入:  John Johanson 's   house
標簽:  NNP  NNP      POS NN

分詞后的輸出將是這樣:

分詞: john johan ##son ' s house

關鍵的是,這將與原始文本John Johanson's house(在's前沒有空格)的輸出相同。

如果你有預分詞的詞級注釋,你可以獨立地對每個輸入詞進行分詞,并確定性地維護從原始詞到分詞詞的映射:

### 輸入
orig_tokens = ["John", "Johanson", "'s",  "house"]
labels      = ["NNP",  "NNP",      "POS", "NN"]### 輸出
bert_tokens = []# 原始詞到分詞詞的映射將會是一個int -> int映射,分別對應`orig_tokens`索引和`bert_tokens`索引。
orig_to_tok_map = []tokenizer = tokenization.FullTokenizer(vocab_file=vocab_file, do_lower_case=True)bert_tokens.append("[CLS]")
for orig_token in orig_tokens:orig_to_tok_map.append(len(bert_tokens))bert_tokens.extend(tokenizer.tokenize(orig_token))
bert_tokens.append("[SEP]"]# bert_tokens == ["[CLS]", "john", "johan", "##son", "'", "s", "house", "[SEP]"]
# orig_to_tok_map == [1, 2, 4, 6]

現在,orig_to_tok_map可用于將labels投影到分詞表示中。

存在一些常見的英語分詞策略會導致與BERT的預訓練方式略有不匹配。例如,如果輸入分詞將像do n't這樣的縮寫分開,就會產生不匹配。如果可能,你應該先處理數據,將其恢復為原始樣式的文本。如果不方便,這種不匹配可能不會有太大影響。

使用BERT進行預訓練

我們發布了針對任意文本語料庫進行“掩碼語言模型”和“下一句預測”的代碼。請注意,這不是論文中所使用的精確代碼(原文本用C++編寫,有些額外的復雜性),但此代碼確實生成了論文中描述的預訓練數據。

運行數據生成的方法如下。輸入是一個純文本文件,每行一個句子。(對于“下一句預測”任務,確保這些都是實際的句子)。文檔由空行分隔。輸出是一組序列化的tf.train.Example,格式為TFRecord文件。

你可以使用現成的NLP工具包(如spaCy)來執行句子切分。create_pretraining_data.py腳本會將段落連接在一起,直到達到最大序列長度,以減少填充導致的計算浪費(有關更多細節,請參閱腳本)。然而,你可能想要有意在輸入數據中添加少量噪音(例如,隨機截斷2%的輸入段),使模型在微調時對非句子輸入更具魯棒性。

該腳本將所有例子存儲在內存中,所以對于大型數據文件,你應該將輸入文件劃分為多個部分,并多次調用該腳本。(可以在run_pretraining.py中傳遞文件通配符,例如tf_examples.tf_record*)。

max_predictions_per_seq是每個序列的最大掩碼語言模型預測數。你應該設置為大約max_seq_length乘以masked_lm_prob(腳本不會自動這樣做,因為這個值需要在兩個腳本中傳入)。

python create_pretraining_data.py \--input_file=./sample_text.txt \--output_file=/tmp/tf_examples.tfrecord \--vocab_file=$BERT_BASE_DIR/vocab.txt \--do_lower_case=True \--max_seq_length=128 \--max_predictions_per_seq=20 \--masked_lm_prob=0.15 \--random_seed=12345 \--dupe_factor=5

以下是進行預訓練的步驟。如果從頭開始預訓練,不要包含init_checkpoint。模型配置(包括詞匯表大小)在bert_config_file中指定。此演示代碼只預訓練幾個步驟(20步),但在實踐中,你可能希望將num_train_steps設為10000步以上。傳遞給run_pretraining.pymax_seq_lengthmax_predictions_per_seq參數必須與create_pretraining_data.py中相同。

python run_pretraining.py \--input_file=/tmp/tf_examples.tfrecord \--output_dir=/tmp/pretraining_output \--do_train=True \--do_eval=True \--bert_config_file=$BERT_BASE_DIR/bert_config.json \--init_checkpoint=$BERT_BASE_DIR/bert_model.ckpt \--train_batch_size=32 \--max_seq_length=128 \--max_predictions_per_seq=20 \--num_train_steps=20 \--num_warmup_steps=10 \--learning_rate=2e-5

這會產生如下的輸出:

***** Eval results *****global_step = 20loss = 0.0979674masked_lm_accuracy = 0.985479masked_lm_loss = 0.0979328next_sentence_accuracy = 1.0next_sentence_loss = 3.45724e-05

由于我們的sample_text.txt文件很小,這個示例訓練會在幾步內過度擬合該數據,產生不真實的高度準確度數字。

預訓練提示和注意事項

  • 如果使用自定義詞匯表,請確保在bert_config.json中更改vocab_size。如果不這樣做,當您在GPU或TPU上訓練時,可能會因為未檢查的越界訪問而出現NaN值。
  • 如果您的任務有一個大型特定領域的語料庫(如“電影評論”或“科學論文”),那么從BERT檢查點開始,在您的語料庫上額外進行幾步預訓練可能是有益的。
  • 我們在論文中使用的學習率是1e-4。但是,如果您從現有BERT檢查點開始進行附加預訓練步驟,應使用較小的學習率(例如,2e-5)。
  • 目前的BERT模型僅支持英文,但我們計劃在未來不久(希望是在2018年11月底之前)發布一個預訓練了多種語言的多語言模型。
  • 因為注意力計算與序列長度平方成正比,因此較長的序列會不成比例地昂貴。換句話說,64個序列長度為512的一批數據要比256個序列長度為128的一批數據成本高得多。全連接/卷積成本相同,但512長度序列的注意力成本要高得多。因此,一個好的策略是先用序列長度為128進行9萬步預訓練,然后再用序列長度為512進行額外的1萬步預訓練。非常長的序列主要用來學習位置嵌入,這些可以相對較快地學習到。請注意,這確實需要使用不同的max_seq_length值生成兩次數據。
  • 如果從零開始預訓練,要做好準備,預訓練在計算上是昂貴的,特別是在GPU上。如果從頭開始預訓練,我們推薦的方案是在單個可搶占Cloud TPU v2上預訓練一個BERT-Base,大約需要兩周時間,費用約為500美元(基于2018年10月的價格)。當只在一個Cloud TPU上訓練時,相比于論文中的設置,您需要降低批次大小。

預訓練數據

我們將無法發布論文中使用的預處理數據集。對于維基百科,建議的預處理方法是下載最新版的dump,使用WikiExtractor.py提取文本,然后進行必要的清理以將其轉換為純文本。

不幸的是,收集BookCorpus的研究人員不再提供公共下載。古騰堡項目數據集是一個稍小一些(約2億字)的舊公共領域書籍集合。

Common Crawl是另一個非常大的文本集合,但您可能需要進行大量的預處理和清理工作,才能從中提取出用于預訓練BERT的可用語料庫。

學習新的WordPiece詞匯表

此存儲庫不包含用于學習新WordPiece詞匯表的代碼。原因是論文中使用的代碼是用C++實現的,并依賴于谷歌內部的庫。對于英文,通常最好直接使用我們的詞匯表和預訓練模型。對于學習其他語言的詞匯表,有很多開源選項可供選擇。然而,請注意它們與我們的tokenization.py庫不兼容:

  • Google的SentencePiece庫

  • tensor2tensor的WordPiece生成腳本

  • Rico Sennrich的Byte Pair Encoding庫

在Colab中使用BERT

如果您想在Colab中使用BERT,可以從筆記本 "BERT FineTuning with Cloud TPUs" 開始。截至本文寫作時間(2018年10月31日),Colab用戶可以完全免費訪問Cloud TPU。?注意:每個用戶限一個,資源有限,需要Google云端平臺賬戶和存儲空間(盡管可以通過注冊GCP免費獲得存儲信用),并且這種功能將來可能不再可用。點擊鏈接的BERT Colab獲取更多信息。

常見問題解答(FAQ)

這個代碼與Cloud TPUs兼容嗎?關于GPU呢?

是的,此倉庫中的所有代碼都可以直接與CPU、GPU和Cloud TPU一起使用。但GPU訓練僅限單GPU。

我收到了內存不足錯誤,是怎么回事?

請參閱有關內存不足問題的部分以獲取更多信息。

有PyTorch版本可用嗎?

沒有官方的PyTorch實現。然而,來自HuggingFace的NLP研究人員提供了一個與BERT相兼容的PyTorch版本,可以匹配我們預訓練的檢查點并重現我們的結果。我們未參與PyTorch實現的創建或維護,所以請將任何相關問題指向該存儲庫的作者。

有Chainer版本可用嗎?

沒有官方的Chainer實現。但是,Sosuke Kobayashi提供了一個與BERT兼容的Chainer版本,可以匹配我們的預訓練檢查點并重現我們的結果。我們未參與Chainer實現的創建或維護,所以請將任何問題直接發送給該存儲庫的作者。

是否會發布其他語言的模型?

是的,我們計劃在未來不久發布一個多語言的BERT模型。我們不能保證具體會包括哪些語言,但它很可能是包含大多數有顯著規模維基百科的語言的單一模型。

是否會發布大于BERT-Large的模型?

至今我們還沒有嘗試訓練比BERT-Large更大的模型。如果我們能取得顯著的改進,可能會發布更大的模型。

此庫的許可證是什么?

所有的代碼模型都根據Apache 2.0許可發布。請參閱LICENSE文件以獲取更多信息。

如何引用BERT?

目前,請參考以下Arxiv論文:

@article{devlin2018bert,title={BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding},author={Devlin, Jacob and Chang, Ming-Wei and Lee, Kenton and Toutanova, Kristina},journal={arXiv preprint arXiv:1810.04805},year={2018}
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/903253.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/903253.shtml
英文地址,請注明出處:http://en.pswp.cn/news/903253.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

SpringBoot啟動警告:OpenJDK 64-Bit Server VM warning

問題描述 以Debug模式啟動Spring boot項目之后,日志打印:OpenJDK 64-Bit Server VM warning: Sharing is only supported for boot loader classes because bootstrap classpath has been appended, 警告信息 解決方案:配置VM opt…

“該虛擬機似乎正在使用中“

當某一天打開虛擬機突然彈出"該虛擬機似乎正在使用中"。 遇到這種問題的解決方法很簡單,出現這種問題是因為錯誤關閉虛擬機導致,當我們點擊獲取所有權時發現不能解決問題。這里分享一種簡單的解決方法。 打開虛擬機的文件目錄 找到lck文件夾下…

【CSS】層疊,優先級與繼承(三):超詳細繼承知識點

目錄 繼承一、什么是繼承?2.1 祖先元素2.2 默認繼承/默認不繼承 二、可繼承屬性2.1 字體相關屬性2.2 文本相關屬性2.3 列表相關屬性 三、不可繼承屬性3.1 盒模型相關屬性3.2 背景相關屬性 四、屬性初始值4.1 根元素4.2 屬性的初始值4.3 得出結論 五、強制繼承5.1 in…

Android LiveData關鍵代碼

1、observer方法 public void observe(NonNull LifecycleOwner owner, NonNull Observer<? super T> observer) {assertMainThread("observe");if (owner.getLifecycle().getCurrentState() DESTROYED) {// ignorereturn;}LifecycleBoundObserver wrapper …

Docker-高級使用

前言 書接上文Docker-初級安裝及使用_用docker安裝doccano-CSDN博客&#xff0c;我們講解了Docker的基本操作&#xff0c;下面我們講解的是高級使用&#xff0c;請大家做好準備&#xff01; 大家如果是從初級安裝使用過來的話&#xff0c;建議把之前鏡像和搭載的容器數據卷里面…

Spring Boot常用注解詳解:實例與核心概念

Spring Boot常用注解詳解&#xff1a;實例與核心概念 前言 Spring Boot作為Java領域最受歡迎的快速開發框架&#xff0c;其核心特性之一是通過注解&#xff08;Annotation&#xff09;簡化配置&#xff0c;提高開發效率。注解驅動開發模式讓開發者告別繁瑣的XML配置&#xff…

TRO再添新案 TME再拿下一熱門IP,涉及Paddington多個商標

4月2日和4月8日&#xff0c;TME律所代理Paddington & Company Ltd.對熱門IP Paddington Bear帕丁頓熊的多類商標發起維權&#xff0c;覆蓋文具、家居用品、毛絨玩具、紡織用品、游戲、電影、咖啡、填充玩具等領域。跨境賣家需立即排查店鋪內的相關產品&#xff01; 案件基…

經驗分享-上傳ios的ipa文件

.ipa格式的二進制文件&#xff0c;是打包后生成的文件&#xff0c;無論我們是放上去testflight測試還是正式上傳到app store&#xff0c;都需要先上傳到蘋果開發者中心的app store connect上的構建版本上。 在app store connect上&#xff0c;上傳構建版本的功能&#xff0c;它…

docker(3) -- 圖形界面

1. 前言 在wsl(8) – 圖形界面文章中介紹了wsl2默認是支持圖形界面的&#xff0c;現在我們嘗試下在docker中運行gui程序試試看。 2. x11-apps 啟動一個docker&#xff0c;安裝一些gui小程序&#xff0c;然后運行&#xff0c;發現會失敗。ubuntu_base詳見文章wsl(6) – 安裝d…

Docker容器跑定時任務腳本

最近搞了一個Docker容器跑腳本&#xff0c;想設置一個定時任務&#xff0c;每天8點運行一次&#xff0c;結果死活不成功。排查了一天&#xff0c;有一點當局者迷了&#xff0c;明明時間是對的&#xff0c;明明時區是對的&#xff0c;定時任務也是啟動的&#xff0c;它就是不執行…

【Linux】什么是完全限定域名

FQDN 是 “完全限定域名” (Fully Qualified Domain Name) 的縮寫。 FQDN 是一個互聯網上特定計算機或主機的完整且唯一的域名。它詳細說明了該主機在域名系統 (DNS) 層級結構中的確切位置。 一個 FQDN 通常由以下幾個部分組成&#xff0c;從左到右依次是&#xff1a; 主機名…

小結:BFD

*BFD&#xff08;雙向轉發檢測&#xff0c;Bidirectional Forwarding Detection&#xff09;是一種快速、輕量級的故障檢測機制&#xff0c;用于檢測網絡中兩點之間的連通性。它廣泛應用于各種場景 1. 檢測 IP 鏈路 應用場景&#xff1a; BFD 用于檢測兩臺設備之間的 IP 層連…

配置Spark歷史服務器,輕松查看任務記錄

在大數據處理中&#xff0c;Spark是一個強大的分布式計算框架。但當Spark服務重啟后&#xff0c;之前的運行記錄就會消失&#xff0c;給我們排查問題和分析任務執行情況帶來不便。這時&#xff0c;配置Spark歷史服務器就顯得尤為重要&#xff0c;它能幫助我們保存和查看歷史任務…

(六)RestAPI 毛子(外部導入打卡/游標分頁/Refit/Http resilience/批量提交/Quartz后臺任務/Hateoas Driven)

文章目錄 項目地址一、外部導入打卡功能1.1 創建實體1. Entry實體2. EntryImport實體3. 添加數據庫配置4. 創建表 1.2 創建DTOs1.3 創建GetEnties Controller 二、游標分頁2.1 創建所需要的DTOs1. 創建游標分頁的請求參數2. 創建CollectionResponse3. 添加游標編碼和解碼的DTO …

Node.js CSRF 保護指南:示例及啟用方法

解釋 CSRF 跨站請求偽造 (CSRF/XSRF) 是一種利用用戶權限劫持會話的攻擊。這種攻擊策略允許攻擊者通過誘騙用戶以攻擊者的名義提交惡意請求,從而繞過我們的安全措施。 CSRF 攻擊之所以可能發生,是因為兩個原因。首先,CSRF 攻擊利用了用戶無法辨別看似合法的 HTML 元素是否…

Flink介紹——實時計算核心論文之Dataflow論文總結

數據流處理的演變與 Dataflow 模型的革新 在大數據處理領域&#xff0c;流式數據處理系統的發展歷程充滿了創新與變革。從早期的 S4 到 Storm&#xff0c;再到 MillWheel&#xff0c;每一個系統都以其獨特的方式推動了技術的進步。S4 以其無中心架構和 PE&#xff08;Processi…

Arduino 入門學習筆記(五):KEY實驗

Arduino 入門學習筆記&#xff08;五&#xff09;&#xff1a;KEY實驗 開發板&#xff1a;正點原子ESP32S3 例程源碼在文章頂部可免費下載&#xff08;審核中…&#xff09; 1. GPIO 輸入功能使用 1.1 GPIO 輸入模式介紹 在上一文章中提及到 pinMode 函數&#xff0c; 要對…

Centos9安裝docker

1. 卸載docker 查看是否安裝了docker yum list | grep docker卸載老版本docker&#xff0c;拷貝自官網 sudo yum remove docker \docker-client \docker-client-latest \docker-common \docker-latest \docker-latest-logrotate \docker-logrotate \docker-engine卸載新版本…

Pgvector+R2R搭建RAG知識庫

背景 R2R是一個采用Python編寫的開源AI RAG框架項目&#xff0c;與PostgreSQL技術棧集成度高&#xff0c;運行需求資源少&#xff08;主要是本人的Macbook air m1內存只有8G&#xff09;的特點&#xff0c;對部署本地私有化化AI RAG應用友好。 Resource Recommendations Whe…

go中redis使用的簡單介紹

目錄 一、Redis 簡介 二、Go中Redis的使用 1. 安裝Go Redis包 2. 單機模式 連接示例 3. 哨兵模式 依賴 連接示例 三、Redis集群 1. 集群模式 集群部署 部署結構 使用redis-cli創建集群 連接示例 四、常用數據結構與操作 1. 字符串&#xff08;String&#xff0…