Transformers 快速入門 | 一


作者|huggingface
編譯|VK
來源|Github

理念

Transformers是一個為NLP的研究人員尋求使用/研究/擴展大型Transformers模型的庫。

該庫的設計有兩個強烈的目標:

  • 盡可能簡單和快速使用:
    • 我們盡可能限制了要學習的面向對象抽象的類的數量,實際上幾乎沒有抽象,每個模型只需要使用三個標准類:配置、模型和tokenizer,
    • 所有這些類都可以通過使用公共的from_pretrained()實例化方法從預訓練實例以簡單統一的方式初始化,該方法將負責從庫中下載,緩存和加載相關類提供的預訓練模型或你自己保存的模型。
    • 因此,這個庫不是構建神經網絡模塊的工具箱。如果您想擴展/構建這個庫,只需使用常規的Python/PyTorch模塊,並從這個庫的基類繼承,以重用諸如模型加載/保存等功能。
  • 提供最先進的模型與性能盡可能接近的原始模型:
    • 我們為每個架構提供了至少一個例子,該例子再現了上述架構的官方作者提供的結果
    • 代碼通常盡可能地接近原始代碼,這意味着一些PyTorch代碼可能不那么pytorch化,因為這是轉換TensorFlow代碼后的結果。

其他幾個目標:

  • 盡可能一致地暴露模型的內部:
    • 我們使用一個API來訪問所有的隱藏狀態和注意力權重,
    • 對tokenizer和基本模型的API進行了標准化,以方便在模型之間進行切換。
  • 結合一個主觀選擇的有前途的工具微調/調查這些模型:
    • 向詞匯表和嵌入項添加新標記以進行微調的簡單/一致的方法,
    • 簡單的方法面具和修剪變壓器頭。

主要概念

該庫是建立在三個類型的類為每個模型:

  • model類是目前在庫中提供的8個模型架構的PyTorch模型(torch.nn.Modules),例如BertModel
  • configuration類,它存儲構建模型所需的所有參數,例如BertConfig。您不必總是自己實例化這些配置,特別是如果您使用的是未經任何修改的預訓練的模型,創建模型將自動負責實例化配置(它是模型的一部分)
  • tokenizer類,它存儲每個模型的詞匯表,並在要輸送到模型的詞匯嵌入索引列表中提供用於編碼/解碼字符串的方法,例如BertTokenizer

所有這些類都可以從預訓練模型來實例化,並使用兩種方法在本地保存:

  • from_pretraining()允許您從一個預訓練版本實例化一個模型/配置/tokenizer,這個預訓練版本可以由庫本身提供(目前這里列出了27個模型),也可以由用戶在本地(或服務器上)存儲,
  • save_pretraining()允許您在本地保存模型/配置/tokenizer,以便可以使用from_pretraining()重新加載它。

我們將通過一些簡單的快速啟動示例來完成這個快速啟動之旅,看看如何實例化和使用這些類。其余的文件分為兩部分:

  • 主要的類詳細介紹了三種主要類(配置、模型、tokenizer)的公共功能/方法/屬性,以及一些作為訓練工具提供的優化類,
  • 包引用部分詳細描述了每個模型體系結構的每個類的所有變體,特別是調用它們時它們期望的輸入和輸出。

快速入門:使用

這里有兩個例子展示了一些Bert和GPT2類以及預訓練模型。

有關每個模型類的示例,請參閱完整的API參考。

BERT示例

讓我們首先使用BertTokenizer從文本字符串准備一個標記化的輸入(要輸入給BERT的標記嵌入索引列表)

import torch
from transformers import BertTokenizer, BertModel, BertForMaskedLM

# 可選:如果您想了解發生的信息,請按以下步驟logger
import logging
logging.basicConfig(level=logging.INFO)

# 加載預訓練的模型標記器(詞匯表)
tokenizer = BertTokenizer.from_pretrained('bert-base-uncased')

# 標記輸入
text = "[CLS] Who was Jim Henson ? [SEP] Jim Henson was a puppeteer [SEP]"
tokenized_text = tokenizer.tokenize(text)

# 用“BertForMaskedLM”掩蓋我們試圖預測的標記`
masked_index = 8
tokenized_text[masked_index] = '[MASK]'
assert tokenized_text == ['[CLS]', 'who', 'was', 'jim', 'henson', '?', '[SEP]', 'jim', '[MASK]', 'was', 'a', 'puppet', '##eer', '[SEP]']

# 將標記轉換為詞匯索引
indexed_tokens = tokenizer.convert_tokens_to_ids(tokenized_text)
# 定義與第一句和第二句相關的句子A和B索引(見論文)
segments_ids = [0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1]

# 將輸入轉換為PyTorch張量
tokens_tensor = torch.tensor([indexed_tokens])
segments_tensors = torch.tensor([segments_ids])

讓我們看看如何使用BertModel在隱藏狀態下對輸入進行編碼:

# 加載預訓練模型(權重)
model = BertModel.from_pretrained('bert-base-uncased')

# 將模型設置為評估模式
# 在評估期間有可再現的結果這是很重要的!
model.eval()

# 如果你有GPU,把所有東西都放在cuda上
tokens_tensor = tokens_tensor.to('cuda')
segments_tensors = segments_tensors.to('cuda')
model.to('cuda')

#預測每個層的隱藏狀態特征
with torch.no_grad():
    # 有關輸入的詳細信息,請參見models文檔字符串
    outputs = model(tokens_tensor, token_type_ids=segments_tensors)
    # Transformer模型總是輸出元組。
    # 有關所有輸出的詳細信息,請參見模型文檔字符串。在我們的例子中,第一個元素是Bert模型最后一層的隱藏狀態
    encoded_layers = outputs[0]
# 我們已將輸入序列編碼為形狀(批量大小、序列長度、模型隱藏維度)的FloatTensor
assert tuple(encoded_layers.shape) == (1, len(indexed_tokens), model.config.hidden_size)

以及如何使用BertForMaskedLM預測屏蔽的標記:

# 加載預訓練模型(權重)
model = BertForMaskedLM.from_pretrained('bert-base-uncased')
model.eval()

# 如果你有GPU,把所有東西都放在cuda上
tokens_tensor = tokens_tensor.to('cuda')
segments_tensors = segments_tensors.to('cuda')
model.to('cuda')

# 預測所有標記
with torch.no_grad():
    outputs = model(tokens_tensor, token_type_ids=segments_tensors)
    predictions = outputs[0]

# 確認我們能預測“henson”
predicted_index = torch.argmax(predictions[0, masked_index]).item()
predicted_token = tokenizer.convert_ids_to_tokens([predicted_index])[0]
assert predicted_token == 'henson'

OpenAI GPT-2

下面是一個快速開始的例子,使用GPT2TokenizerGPT2LMHeadModel類以及OpenAI的預訓練模型來預測文本提示中的下一個標記。

首先,讓我們使用GPT2Tokenizer

import torch
from transformers import GPT2Tokenizer, GPT2LMHeadModel

# 可選:如果您想了解發生的信息,請按以下步驟logger
import logging
logging.basicConfig(level=logging.INFO)

# 加載預訓練模型(權重)
tokenizer = GPT2Tokenizer.from_pretrained('gpt2')

# 編碼輸入
text = "Who was Jim Henson ? Jim Henson was a"
indexed_tokens = tokenizer.encode(text)

# 轉換為PyTorch tensor
tokens_tensor = torch.tensor([indexed_tokens])

讓我們看看如何使用GPT2LMHeadModel生成下一個跟在我們的文本后面的token:

# 加載預訓練模型(權重)
model = GPT2LMHeadModel.from_pretrained('gpt2')

# 將模型設置為評估模式
# 在評估期間有可再現的結果這是很重要的!
model.eval()

# 如果你有GPU,把所有東西都放在cuda上
tokens_tensor = tokens_tensor.to('cuda')
model.to('cuda')

# 預測所有標記
with torch.no_grad():
    outputs = model(tokens_tensor)
    predictions = outputs[0]

# 得到預測的下一個子詞(在我們的例子中,是“man”這個詞)
predicted_index = torch.argmax(predictions[0, -1, :]).item()
predicted_text = tokenizer.decode(indexed_tokens + [predicted_index])
assert predicted_text == 'Who was Jim Henson? Jim Henson was a man'

每個模型架構(Bert、GPT、GPT-2、Transformer XL、XLNet和XLM)的每個模型類的示例,可以在文檔中找到。

使用過去的GPT-2

以及其他一些模型(GPT、XLNet、Transfo XL、CTRL),使用pastmems屬性,這些屬性可用於防止在使用順序解碼時重新計算鍵/值對。它在生成序列時很有用,因為注意力機制的很大一部分得益於以前的計算。

下面是一個使用帶pastGPT2LMHeadModel和argmax解碼的完整工作示例(只能作為示例,因為argmax decoding引入了大量重復):

from transformers import GPT2LMHeadModel, GPT2Tokenizer
import torch

tokenizer = GPT2Tokenizer.from_pretrained("gpt2")
model = GPT2LMHeadModel.from_pretrained('gpt2')

generated = tokenizer.encode("The Manhattan bridge")
context = torch.tensor([generated])
past = None

for i in range(100):
    print(i)
    output, past = model(context, past=past)
    token = torch.argmax(output[..., -1, :])

    generated += [token.tolist()]
    context = token.unsqueeze(0)

sequence = tokenizer.decode(generated)

print(sequence)

由於以前所有標記的鍵/值對都包含在past,因此模型只需要一個標記作為輸入。

Model2Model示例

編碼器-解碼器架構需要兩個標記化輸入:一個用於編碼器,另一個用於解碼器。假設我們想使用Model2Model進行生成性問答,從標記將輸入模型的問答開始。

import torch
from transformers import BertTokenizer, Model2Model

# 可選:如果您想了解發生的信息,請按以下步驟logger
import logging
logging.basicConfig(level=logging.INFO)

# 加載預訓練模型(權重)
tokenizer = BertTokenizer.from_pretrained('bert-base-uncased')

# 編碼輸入(問題)
question = "Who was Jim Henson?"
encoded_question = tokenizer.encode(question)

# 編碼輸入(答案)
answer = "Jim Henson was a puppeteer"
encoded_answer = tokenizer.encode(answer)

# 將輸入轉換為PyTorch張量
question_tensor = torch.tensor([encoded_question])
answer_tensor = torch.tensor([encoded_answer])

讓我們看看如何使用Model2Model獲取與此(問題,答案)對相關聯的loss值:

#為了計算損失,我們需要向解碼器提供語言模型標簽(模型生成的標記id)。
lm_labels =  encoded_answer
labels_tensor = torch.tensor([lm_labels])

# 加載預訓練模型(權重)
model = Model2Model.from_pretrained('bert-base-uncased')

# 將模型設置為評估模式
# 在評估期間有可再現的結果這是很重要的!
model.eval()

# 如果你有GPU,把所有東西都放在cuda上
question_tensor = question_tensor.to('cuda')
answer_tensor = answer_tensor.to('cuda')
labels_tensor = labels_tensor.to('cuda')
model.to('cuda')

# 預測每個層的隱藏狀態特征
with torch.no_grad():
    # 有關輸入的詳細信息,請參見models文檔字符串
    outputs = model(question_tensor, answer_tensor, decoder_lm_labels=labels_tensor)
    # Transformers模型總是輸出元組。
    # 有關所有輸出的詳細信息,請參見models文檔字符串
    # 在我們的例子中,第一個元素是LM損失的值
    lm_loss = outputs[0]

此損失可用於對Model2Model的問答任務進行微調。假設我們對模型進行了微調,現在讓我們看看如何生成答案:

# 讓我們重復前面的問題
question = "Who was Jim Henson?"
encoded_question = tokenizer.encode(question)
question_tensor = torch.tensor([encoded_question])

# 這次我們試圖生成答案,所以我們從一個空序列開始
answer = "[CLS]"
encoded_answer = tokenizer.encode(answer, add_special_tokens=False)
answer_tensor = torch.tensor([encoded_answer])

# 加載預訓練模型(權重)
model = Model2Model.from_pretrained('fine-tuned-weights')
model.eval()

# 如果你有GPU,把所有東西都放在cuda上
question_tensor = question_tensor.to('cuda')
answer_tensor = answer_tensor.to('cuda')
model.to('cuda')

# 預測所有標記
with torch.no_grad():
    outputs = model(question_tensor, answer_tensor)
    predictions = outputs[0]

# 確認我們能預測“jim”
predicted_index = torch.argmax(predictions[0, -1]).item()
predicted_token = tokenizer.convert_ids_to_tokens([predicted_index])[0]
assert predicted_token == 'jim'

歡迎關注磐創博客資源匯總站:
http://docs.panchuang.net/

歡迎關注PyTorch官方中文教程站:
http://pytorch.panchuang.net/

OpenCV中文官方文檔:
http://woshicver.com/


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM