Transformers 介紹(下)

Transformers是TensorFlow 2.0和PyTorch的最新自然語言處理庫

Transformers(以前稱為pytorch-transformers和pytorch-pretrained-bert)提供用於自然語言理解(NLU)和自然語言生成(NLG)的最先進的模型(BERT,GPT-2,RoBERTa,XLM,DistilBert,XLNet,CTRL ...) ,擁有超過32種預訓練模型,支持100多種語言,並且在TensorFlow 2.0和PyTorch之間具有深厚的互操作性。

微調和使用腳本

在運行微調腳本之前,設置你的環境來運行示例。

這個庫包含了幾個SOTA執行NLU和NLG任務的例子腳本:

  • run_glue.py:對Bert、XLNet和XLM在9個不同的GLUE任務上進行微調的示例(序列級分類)
  • run_squad.py:對Bert、XLNet和XLM在問題回答數據集集SQuAD 2.0上進行微調的示例(詞語級別分類)
  • run_generation.py:一個使用GPT、GPT-2、CTRL、Transformer-XL和XLNet生成語言的例子
  • 其他特定於模型的示例(參見文檔)。

以下是這三個腳本的快速使用示例:

run_glue.py: 微調GLUE任務的序列級分類

通用語言理解評估(GLUE)基準測試是一個包含九個句子或句子對的語言理解任務的集合,用於評估和分析自然語言理解系統。

在運行這些GLUE任務之前,你應該下載

GLUE數據 https://gluebenchmark.com/tasks

這個腳本 https://gist.github.com/W4ngatang/60c2bdb54d156a41194446737ce03e2e

解壓到某個目錄$GLUE_DIR。

你應該安裝例子所需的額外軟件包:

<code>pip install -r ./examples/requirements.txt/<code>
<code>export GLUE_DIR=/path/to/glue
export TASK_NAME=MRPC

python ./examples/run_glue.py \\
--model_type bert \\
--model_name_or_path bert-base-uncased \\
--task_name $TASK_NAME \\
--do_train \\
--do_eval \\
--do_lower_case \\
--data_dir $GLUE_DIR/$TASK_NAME \\
--max_seq_length 128 \\
--per_gpu_eval_batch_size=8 \\
--per_gpu_train_batch_size=8 \\
--learning_rate 2e-5 \\
--num_train_epochs 3.0 \\
--output_dir /tmp/$TASK_NAME//<code>

其中任務名可以是CoLA, SST-2, MRPC, STS-B, QQP, MNLI, QNLI, RTE, WNLI。

dev集結果將出現在指定的output_dir中的文本文件'eval_results.txt'。對於MNLI,由於有兩個獨立的開發集,匹配的和不匹配的,除了“/tmp/MNLI/”之外,還有一個單獨的輸出文件夾,稱為“/tmp/MNLI-MM/”。

在STS-B迴歸任務上微調XLNet模型

這個示例代碼使用一個具有4個V100 gpu的服務器上的並行訓練對STS-B語料庫上的XLNet進行微調。 並行訓練是一種使用多個gpu的簡單方法(但是比分佈式訓練更慢,靈活性更差,見下文)。

<code>export GLUE_DIR=/path/to/glue

python ./examples/run_glue.py \\
--model_type xlnet \\
--model_name_or_path xlnet-large-cased \\
--do_train \\
--do_eval \\
--task_name=sts-b \\
--data_dir=${GLUE_DIR}/STS-B \\
--output_dir=./proc_data/sts-b-110 \\
--max_seq_length=128 \\
--per_gpu_eval_batch_size=8 \\
--per_gpu_train_batch_size=8 \\
--gradient_accumulation_steps=1 \\
--max_steps=1200 \\
--model_name=xlnet-large-cased \\
--overwrite_output_dir \\
--overwrite_cache \\
--warmup_steps=120/<code>

因此,在這臺機器上,我們的batch大小為32,如果你有一臺更小的機器,請增加gradient_accumulation_steps以達到相同的batch大小。這些超參數將導致開發集的Pearson相關係數+0.917 。

對MRPC分類任務的Bert模型進行微調

此示例代碼使用8個V100 gpu上的分佈式訓練,對Microsoft Research的釋義語料庫(MRPC)上的Bert詞屏蔽模型進行微調,以達到F1 > 92。

<code>python -m torch.distributed.launch --nproc_per_node 8 ./examples/run_glue.py   \\
--model_type bert \\
--model_name_or_path bert-large-uncased-whole-word-masking \\
--task_name MRPC \\
--do_train \\
--do_eval \\
--do_lower_case \\
--data_dir $GLUE_DIR/MRPC/ \\
--max_seq_length 128 \\
--per_gpu_eval_batch_size=8 \\
--per_gpu_train_batch_size=8 \\
--learning_rate 2e-5 \\
--num_train_epochs 3.0 \\
--output_dir /tmp/mrpc_output/ \\

--overwrite_output_dir \\
--overwrite_cache \\/<code>

利用這些超參數進行訓練,得到以下結果:

<code>  acc = 0.8823529411764706
acc_and_f1 = 0.901702786377709
eval_loss = 0.3418912578906332
f1 = 0.9210526315789473
global_step = 174
loss = 0.07231863956341798/<code>

run_squad.py:對在SQuAD進行fine-tuning

這個示例代碼使用8個V100 gpu上的分佈式訓練和BERT全字屏蔽無大小寫模型對班組數據集上的BERT進行微調,以達到F1 > 93:

<code>python -m torch.distributed.launch --nproc_per_node=8 ./examples/run_squad.py \\
--model_type bert \\
--model_name_or_path bert-large-uncased-whole-word-masking \\
--do_train \\
--do_eval \\
--do_lower_case \\
--train_file $SQUAD_DIR/train-v1.1.json \\
--predict_file $SQUAD_DIR/dev-v1.1.json \\
--learning_rate 3e-5 \\
--num_train_epochs 2 \\
--max_seq_length 384 \\
--doc_stride 128 \\
--output_dir ../models/wwm_uncased_finetuned_squad/ \\
--per_gpu_eval_batch_size=3 \\
--per_gpu_train_batch_size=3 \\/<code>

利用這些超參數進行訓練,得到以下結果:

<code>python $SQUAD_DIR/evaluate-v1.1.py $SQUAD_DIR/dev-v1.1.json ../models/wwm_uncased_finetuned_squad/predictions.json
{"exact_match": 86.91579943235573, "f1": 93.1532499015869}/<code>

這個模型以bert-large-uncased-whole-word-masking-finetuned-squad提供。

run_generation.py 使用GPT、GPT-2、CTRL、Transformer-XL和XLNet生成文本

其中還包括一個條件生成腳本,用於從提示符生成文本。 生成腳本包括由Aman Rusia提出的技巧,以獲得使用Transformer-XL和XLNet等高質量生成模型(包括使短輸入變長的預定義文本)。

下面是運行腳本與小版本的OpenAI GPT-2模型:

<code>python ./examples/run_generation.py \\
--model_type=gpt2 \\
--length=20 \\
--model_name_or_path=gpt2 \\/<code>

從Salesforce的CTRL模型:

<code>python ./examples/run_generation.py \\
--model_type=ctrl \\
--length=20 \\
--model_name_or_path=ctrl \\
--temperature=0 \\
--repetition_penalty=1.2 \\/<code>

快速瀏覽模型共享

從v2.2.2開始,你現在可以使用庫中內置的CLI,向社區上傳和共享經過調優的模型。

首先,在https://huggingface.co/join上創建一個帳戶。然後:

<code>transformers-cli login
# 使用與huggingface.co上相同的憑據登錄/<code>

上傳模型

<code>transformers-cli upload ./path/to/pretrained_model/

#上傳包含權重/分詞/配置的文件夾

# 通過.save_pretrained()`保存

transformers-cli upload ./config.json [--filename folder/foobar.json]

# 上傳單個文件
# 你可以選擇覆蓋其文件名,該文件名可以嵌套在文件夾中/<code>

你的模型將通過它的標識符來訪問,你的用戶名和上面的文件夾名的連接:

<code>"username/pretrained_model"/<code>

在model_cards/下請添加README.md model card用於的repo,包括:模型描述、訓練參數(數據集、預處理、超參數)、評估結果、預期用途和限制等。

你的模型現在有了一個關於huggingface的頁面。

任何人都可以從代碼加載:

<code>tokenizer = AutoTokenizer.from_pretrained("username/pretrained_model")
model = AutoModel.from_pretrained("username/pretrained_model")/<code>

列出所有S3上的文件:

<code>transformers-cli s3 ls/<code>

你也可以刪除不需要的文件:

<code>transformers-cli s3 rm …/<code>

快速瀏覽管道

新版本“v2.3”:Pipeline是高級對象,它自動處理標記化,通過轉換器模型運行數據並將結果輸出到一個結構化對象中。

你可以為下列下游任務創建“管道”對象:

  • feature-extraction:為輸入序列生成一個張量表示
  • ner:為輸入序列中的每個單詞生成命名實體映射。
  • sentiment-analysis:給出整個輸入序列的情感分析(正/負)。
  • text-classification:直接初始化一個TextClassificationPipeline,或者查看sentiment-analysis。
  • question-answer:提供一些上下文和一個與上下文相關的問題,它將提取上下文中的問題的答案。
  • fill-mask:接受包含掩碼標記(例如)的輸入序列,並返回最可能填充序列的列表及其概率。
<code>from transformers import pipeline

# 為情感分析分配一個管道
nlp = pipeline('sentiment-analysis')
nlp('We are very happy to include pipeline into the transformers repository.')
>>> {'label': 'POSITIVE', 'score': 0.99893874}

# 分配一個用於回答問題的管道
nlp = pipeline('question-answering')
nlp({
'question': 'What is the name of the repository ?',
'context': 'Pipeline have been included in the huggingface/transformers repository'
})
>>> {'score': 0.28756016668193496, 'start': 35, 'end': 59, 'answer': 'huggingface/transformers'}/<code>

從pytorch-transformer遷移到transformer

以下是從pytorch-transformer遷移到transformer時應該注意的事項的快速摘要。

一些模型的關鍵輸入參數(attention_mask,token_type_ids …)改變了

為了能夠使用Torchscript(參見#1010,#1204和#1195),某些模型的特定順序關鍵輸入 (attention_mask, token_type_ids…)已經改變。

如果你曾經使用關鍵字參數的關鍵字名稱來調用模型,例如。model(inputs_ids, attention_mask=attention_mask, token_type_ids=token_type_ids),這應該不會導致任何更改。

如果你使用關鍵字參數的位置輸入來調用模型,例如model(inputs_ids, attention_mask, token_type_ids),你可能需要仔細檢查輸入參數的確切順序。

從pytorch-pretrained-bert到transformers

下面是一個簡短的總結,告訴你從pytorch-pretrained-bert到transformers時應該注意什麼。

模型總是輸出tuples

從pytorch-pretrained-bert遷移到transformers時,主要的中斷變化是每個模型的forward方法總是輸出一個“tuple”,其中包含依賴於模型和配置參數的各種元素。

每個模型的元組的確切內容在模型的文檔字符串和文檔中有詳細說明

在幾乎所有的情況下,只要將輸出的第一個元素作為之前在pytorch-pretrained-bert中使用的輸出就可以了。

這裡有一個pytorch-pretrained-bert轉換為transformers的例子,用於BertForSequenceClassification分類模型:

<code># 加載模型
model = BertForSequenceClassification.from_pretrained('bert-base-uncased')

# 如果你以前在pytorch-pretrained-bert中使用此行:
loss = model(input_ids, labels=labels)

# 現在,只需在transformers中使用此即可從輸出元組中提取損失:
outputs = model(input_ids, labels=labels)
loss = outputs[0]

# 在transformers中,你還可以訪問logits:
loss, logits = outputs[:2]

# 甚至是注意力權重,如果你將模型配置為輸出它們(以及其他輸出,也請參閱文檔字符串和文檔)
model = BertForSequenceClassification.from_pretrained('bert-base-uncased', output_attentions=True)
outputs = model(input_ids, labels=labels)
loss, logits, attentions = outputs/<code>

用隱藏狀態

通過啟用配置選項output_hidden_​​states,可以檢索編碼器的最後隱藏狀態。在pytorch-transformers和transformers中,返回值略有變化:all_hidden_​​states現在還包括嵌入的隱藏狀態,以及編碼層的隱藏狀態。這使用戶可以輕鬆訪問嵌入的最終狀態。

序列化

from_pretrained()方法的重大更改:

  1. 現在,在使用from_pretrained()方法實例化時,默認情況下將模型設置為評估模式。要訓​​練它們,不要忘記將它們重新設置為訓練模式(model.train())以激活退出模塊。
  2. 提供給from_pretrained()方法的附加* input和** kwargs參數曾經被直接傳遞給基類init __()方法。現在,它們被用來更新模型配置屬性,這可以破壞基於先前的BertForSequenceClassification示例構建的派生模型類。我們正在努力通過轉發模型的init __()方法來減輕重大變化

同樣,雖然沒有什麼大的變化,但是序列化方法已經標準化,如果以前使用過任何其他序列化方法,則可能應該切換到新方法save_pretrained(save_directory)。這是一個例子:

<code>### 加載一個模型和分詞器
model = BertForSequenceClassification.from_pretrained('bert-base-uncased')
tokenizer = BertTokenizer.from_pretrained('bert-base-uncased')

### 對我們的模型和分詞進行一些處理
tokenizer.add_tokens(['[SPECIAL_TOKEN_1]', '[SPECIAL_TOKEN_2]'])
model.resize_token_embeddings(len(tokenizer))
# 訓練模型
train(model)

### 現在讓我們將模型和分詞器保存到目錄中
model.save_pretrained('./my_saved_model_directory/')
tokenizer.save_pretrained('./my_saved_model_directory/')

### 重新加載模型和分詞器

model = BertForSequenceClassification.from_pretrained('./my_saved_model_directory/')
tokenizer = BertTokenizer.from_pretrained('./my_saved_model_directory/')/<code>

優化器:BertAdam和OpenAIAdam現在改成AdamW,schedules是標準的PyTorch schedules

以前包括的兩個優化器,BertAdam和OpenAIAdam,已由單個的AdamW優化器代替,但有一些區別:

  • 僅實現權重衰減校正,
  • schedules現在是外部的(請參閱下文),
  • 梯度裁剪現在也是外部的(請參閱下文)。

新的優化器AdamW與PyTorchAdam優化器API匹配,可讓你使用標準的PyTorch或apex方法進行計劃和裁剪。

現在,這些schedules已成為標準的PyTorch學習率調度程序,現在不再是優化程序的一部分。

以下是轉換示例:

<code># 參數:
lr = 1e-3
max_grad_norm = 1.0
num_training_steps = 1000
num_warmup_steps = 100
warmup_proportion = float(num_warmup_steps) / float(num_training_steps) # 0.1

### 以前,BertAdam優化器是這樣實例化的:
optimizer = BertAdam(model.parameters(), lr=lr, schedule='warmup_linear', warmup=warmup_proportion, t_total=num_training_steps)
### 並像這樣使用:
for batch in train_data:
loss = model(batch)

loss.backward()
optimizer.step()

### 在“Transformer”中,優化器和schedules按如下方式拆分和實例化:
optimizer = AdamW(model.parameters(), lr=lr, correct_bias=False) # 要重現BertAdam特定的行為,請設置correct_bias = False
scheduler = get_linear_schedule_with_warmup(optimizer, num_warmup_steps=num_warmup_steps, num_training_steps=num_training_steps) # PyTorch調度程序用法如下:

for batch in train_data:
model.train()
loss = model(batch)
loss.backward()
torch.nn.utils.clip_grad_norm_(model.parameters(), max_grad_norm) # 梯度裁剪不再在AdamW中了(因此你可以毫無問題地使用放大器)
optimizer.step()
scheduler.step()
optimizer.zero_grad()/<code>


分享到:


相關文章: