­

huggingface transformers使用指南(更新and待續)

  • 2021 年 3 月 23 日
  • AI

ntransformers的前身是pytorch-transformers和pytorch-pretrained-bert,主要提供了自然語言理解(NLU)和自然語言生成(NLG)的通用體系結構(BERT,GPT-2,RoBERTa,XLM,DistilBert,XLNet等) )包含超過32種以100多種語言編寫的預訓練模型,以及TensorFlow 2.0和PyTorch之間的深度互操作性。

不過就上手而言,torch還是更順滑一些(因為很多非官方例子都是用torch來擼的),順便讓我熟悉一下torch的使用。

整體上調研了github上的多個相關的項目,包括huggingface transformer,谷歌開源的bert,bert4keras,tensorflow hub,以及其它的一些個人的keras-bert之類的實現,總的來說,huggingface的優點在於:

1、企業級維護,可靠性高,生產上用起來放心;

2、star多,issues多,網上能夠找到的各種各樣對應不同需求的demo代碼多;

3、適配tf.keras和torch,一次性可以擼兩個框架;

4、官方的tutorial是真的太特么全了

5、在PyTorch和TensorFlow 2.0之間輕鬆切換,從而允許使用一種框架進行訓練,而使用另一種框架進行推理。非常靈活,當然其實torch和tf之間框架互相轉換的功能的library挺多的;

整體架構:

  • 使用每個模型只需要三個標準類:configuration,models 和tokenizer 。model用於指定使用哪一種模型,例如model為bert,則相應的網絡結構為bert的網絡結構,configuration是模型具體的結構配置,例如可以配置多頭的數量等,這裡配置需要注意的地方就是,如果自定義配置不改變核心網絡結構的則仍舊可以使用預訓練模型權重,如果配置涉及到核心結構的修改,例如前饋網絡的隱層神經元的個數,則無法使用預訓練模型權重,這個時候transformers會默認你要重新自己預訓練一個模型從而隨機初始化整個模型的權重,這是是一種半靈活性的設計,
  • 所有這些類都可以使用通用的from_pretrained()實例化方法,以簡單統一的方式從受過訓練的實例中初始化,該方法將負責下載(如果需要),緩存和加載相關的類實例以及相關的數據(config的的超參數,再 Hugging Face Hub 上提供的預先訓練的檢查點或您自己保存的檢查點的tokenizer生成器的詞彙表和模型的權重)。
  • 在這三個基本類的基礎上,該庫提供了兩個API:pipeline()用於在給定任務上快速使用模型(及其關聯的tokenizer和configuration)和 Trainer或者TFtrainer 快速訓練或微調給定模型。
  • 因此,該庫不是神經網絡構建模塊的模塊化工具箱。如果要擴展/構建庫,只需使用常規的Python / PyTorch / TensorFlow / Keras模塊並從庫的基類繼承即可重用模型加載/保存之類的功能。

其他一些目標:

  • 儘可能一致地公開模型的內部:
  • 我們使用單個API授予全部隱藏狀態和注意力權重的訪問權限。
  • token生成器和基本模型的API已標準化,可輕鬆在模型之間切換。
  • 納入主觀選擇的有前途的工具,以對這些模型進行微調/研究:
  • 一種向詞彙表和嵌入物中添加新標記以進行微調的簡單/一致的方法。
  • 遮蓋和修剪transformer的任務曾的簡單方法。
  • 模型類例如Bert odel是30多個PyTorch模型(torch.nn.Module)或tf.keras模型(tf.keras.Model),它們可以使用庫中提供的預訓練權重。
  • 配置類(例如 Bert config,用於存儲構建模型所需的所有參數。您不必總是自己實例化這些。特別是,如果您使用未經任何修改的預訓練模型,則創建模型將自動實例化配置(這是模型的一部分)。
  • 諸如的Tokenizer類例如BertTokenizer,用於存儲每個模型的詞彙表,並提供用於編碼/解碼要饋送到模型的令牌嵌入索引列表中的字符串的方法。

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

  • from_pretrained()可以實例化一個型號/配置/標記者從庫本身要麼提供(在列表中提供支持的型號預訓練版本在這裡)或本地存儲(或服務器)用戶,
  • save_pretrained()使您可以在本地保存模型/配置/令牌,以便可以使用來重新加載模型/配置/令牌 from_pretrained()。

另外關於bert上模型的分類,huggingface的官方文檔也做了很詳細的歸類:

Summary of the modelshuggingface.co圖標

現有的預訓練模型整體上都屬於下面的5個類別之一:

1、自回歸模型:自回歸模型在經典語言建模任務上進行了預訓練:猜測下一個已讀完所有先前token的token。它們對應於transformer模型的解碼器部分,並且在整個句子的頂部使用了一個掩碼,以便注意頭只能看到文本中的之前內容,而不能看到其後的內容。儘管可以對這些模型進行微調並在許多任務上取得出色的結果,但其最自然的應用是文本生成。此類模型的典型例子是GPT;

2、自編碼模型:通過以某種方式破壞輸入token並嘗試重建原始句子來對自編碼模型進行預訓練。從某種意義上說,它們與transformer中的的編碼器相對應,因為它們無需任何掩碼即可訪問完整的輸入。這些模型通常建立整個句子的雙向表示。可以對它們進行微調並在許多任務(例如文本生成)上取得出色的結果,但是它們最自然的應用是文本分類或token分類(比如詞性標註)。此類模型的典型例子是BERT。

請注意,自動回歸模型和自動編碼模型之間的唯一區別在於模型的預訓練方式。因此,相同的體系結構既可以用於自動回歸模型,也可以用於自動編碼模型。當給定模型同時用於兩種類型的預訓練時,我們將其放在與首次引入該模型的文章相對應的類別中。

3、序列到序列模型:序列到序列模型將transformers的編碼器和解碼器同時用於翻譯任務或通過將其他任務轉換為序列到序列問題來訓練得到的。可以將它們微調來適應許多任務(這裡應該是說把sequence to sequence的預訓練模型的encoder或者decoder單獨抽取出來,然後用法就和上面兩種模型的用法一致),但最自然的應用是翻譯,摘要和問題解答。T5是一個典型的例子;

4、多模態模型將文本輸入與其他類型的輸入(例如圖像)混合在一起,並且更特定於給定任務。

這種模型沒有提供預訓練權重,只是定義了模型的結構;

5、基於檢索的模型

這個我實在不知道幹啥用的wtf。。。

針對於不同的使用目的,bert有不同的抽象等級的api實現:

應用目標1、直接調用預訓練模型不fine tune完成下游任務:

這種最簡單,不進行finetune,直接完成任務,bert提供了pipeline的功能:

from transformers import pipeline
classifier = pipeline('sentiment-analysis', model="nlptown/bert-base-multilingual-uncased-sentiment")
classifier('We are very happy to show you the   Transformers library.')

我們來看一下pipeline的參數:

pipeline(task: str, model: Optional = None, \
config: Union[str, transformers.configuration_utils.PretrainedConfig, NoneType] = None, \
 tokenizer: Union[str, transformers.tokenization_utils.PreTrainedTokenizer, NoneType] = None, \
 framework: Union[str, NoneType] = None, revision: Union[str, NoneType] = None,  \
use_fast: bool = True, model_kwargs: Dict[str, Any] = {}, **kwargs) \
 -> transformers.pipelines.base.Pipeline

task參數對應下游任務,根據下游要完成的任務來設置。

model參數對應使用的預訓練模型,比如可以是這樣:

classifier = pipeline('sentiment-analysis', model="nlptown/bert-base-multilingual-uncased-sentiment")

如果是本地已經下載好的模型,則model後面可以直接跟模型文件夾的絕對路徑。

config對應模型的具體配置,這個比較重要下面會詳細描述。

tokenizer 指定分詞器,這個也比較重要後面詳細描述。

framework:pt或者tf用於指定模型使用torch還是tensorflow版的

use_fast:是否使用優化後的分詞器,這個後面和分詞器一起講好了

個人不是很喜歡這裡的設計,封裝的過頭了,很多細節的地方把控起來不是很方便,所以pipeline功能就不詳細介紹了。

下面介紹一下第二種,通過autoXXX的功能來使用

當然pipeline本身封裝的代碼部分就是主要用autoXXX來實現的,這種方式可以較好的和現有的torch以及tf.keras的框架結合起來,本質上就是把這些預訓練模型當作一個大型的model,相對於pipeline來說,封裝的程度小一點,看一個例子:

基於huggingface/transforms(pytorch)框架實現Bert文本分類_Jay2coomzz的博客-CSDN博客_huggingface 文本分類blog.csdn.net圖標

可以看到,automodelXXX的功能實際上是默認直接幫你配完一個model,對於tf.keras來說就是直接得到一個compilr之後可以直接fit的model類,對於torch來說,就是一個已經用nn.module+class的方式構建完可以訓練的model。

例如上面的

self.model = BertForSequenceClassification.from_pretrained(pretrain_Model_path,config=config)

可以用

self.model = AutoModelForSequenceClassification.from_pretrained(pretrain_Model_path,config=config)

(這裡補充一下,automodelforXXX可以直接代替各類的bertforXXX,albertforXXX的用法,auto能夠根據你的from pretrained的model的字符串名字自動給你選擇對應的類,比如from_pretrained(‘bert-large-base’),那麼底層實際上就自動推斷給你返回一個bertforXXX的類。

看上述的代碼我們可以知道,automodelforXXX實際上默認是幫你把下游對應的任務層搭建好了,比如上面的文本分類任務,默認是幫你配了一個分類層在裏面。用torch或者keras的同學就不必再構建一個新對象或者add一個分類層了。

下面看一下官方給的幾個例子,可以比較好的對比pipeline和automodelXXX的使用上的差異:

Summary of the taskshuggingface.co

這裡介紹了文本分類、QA、語言建模任務、文本生成、命名識別和文本摘要等多個任務,為了方便這裡就介紹文本分類任務的例子:

from transformers import pipeline
nlp = pipeline("sentiment-analysis")
result = nlp("I hate you")[0]
print(f"label: {result['label']}, with score: {round(result['score'], 4)}")
result = nlp("I love you")[0]
print(f"label: {result['label']}, with score: {round(result['score'], 4)}")

上述的過程是這樣的:

  1. 從檢查點名稱實例化標記器和模型。該模型被識別為BERT模型,並使用存儲在檢查點中的權重加載該模型(從huggingface hub上下載和加載模型權重)。
  2. 使用正確的特定於模型的分隔符,標記類型ID和注意掩碼,從兩個句子構建一個序列(encode()__call__()注意這一點)。(自動使用下載的模型對應的分詞器對原始的輸入句子進行模型的適配性的轉換,講輸入的句子轉化為模型可以input的形式)
  3. 模型對輸入的tokenizer處理後的數據進行預測得到原始預測結果。
  4. 計算結果的softmax值以獲得不同類的概率。
  5. 輸出預測結果。

使用pipeline完成推斷非常的簡單,分詞以及分詞之後的張量轉換,模型的輸入和輸出的處理等等都根據你設置的task(上面是”sentiment-analysis”)直接完成了,如果要針對下游任務進行finetune,huggingface提供了trainer的功能,例子在這裡:

//github.com/huggingface/transformers/blob/master/examples/text-classification/run_glue.pygithub.com

比較麻煩,語法上和torch或者keras的訓練方式有一定差異。當然,如果純做推斷的話,會比較方便,但是如果tokenizer之類的需要自定義,或者模型的輸出層要做一些其它的特定的處理,則會比較麻煩。

相對而言,autoXXX的api用法會複雜一些,例如對於上面的任務,這個api要這麼用:

from transformers import AutoTokenizer, AutoModelForSequenceClassification
import torch
tokenizer = AutoTokenizer.from_pretrained("bert-base-cased-finetuned-mrpc")
model = AutoModelForSequenceClassification.from_pretrained("bert-base-cased-finetuned-mrpc")
classes = ["not paraphrase", "is paraphrase"]
sequence_0 = "The company HuggingFace is based in New York City"
sequence_1 = "Apples are especially bad for your health"
sequence_2 = "HuggingFace's headquarters are situated in Manhattan"
paraphrase = tokenizer(sequence_0, sequence_2, return_tensors="pt")
not_paraphrase = tokenizer(sequence_0, sequence_1, return_tensors="pt")
paraphrase_classification_logits = model(**paraphrase).logits
not_paraphrase_classification_logits = model(**not_paraphrase).logits
paraphrase_results = torch.softmax(paraphrase_classification_logits, dim=1).tolist()[0]
not_paraphrase_results = torch.softmax(not_paraphrase_classification_logits, dim=1).tolist()[0]
# Should be paraphrase
for i in range(len(classes)):
    print(f"{classes[i]}: {int(round(paraphrase_results[i] * 100))}%")
# Should not be paraphrase
for i in range(len(classes)):
    print(f"{classes[i]}: {int(round(not_paraphrase_results[i] * 100))}%")

相對來說會更加靈活一些,寫起來也更麻煩一點,分詞器部分我們可以直接用python語言來自定義處理,只要最終能夠轉化為模型能處理的input就可以了,然後要做finetune的話,其過程和torch的模型訓練過程是一樣的,通過

for i in range(epochs)的循環的寫法或者是skorch封裝之後直接fit都可以,這樣的話,顯存重計算,早停等功能都可以直接沿用torch的語法(雖然huggingface transformers其實也內置了這些功能,但是我真的懶得再去學一套api了。。。)

其它任務的差異基本上差不多。

應用目標2、直接調用預訓練模型不fine tune完成下游任務:

其實前面基本上已經把pipeline和autoXXX這兩個api的finetune的方法講完了。

Training and fine-tuninghuggingface.co

官方的文檔里這裡提供了更加詳細豐富的案例,這些例子使用automodelforXXX或者是特定的bertmodelforXXX都是可以跑的。


應用目標3、更加靈活的自定義以及torch的練手

涉及到自定義的話基本上就不會是直接predict的任務了,你接了分類層之後分類層的權重也是需要去訓練的

但是這種方法也不是很好,尤其是我這樣的初學菜鳥,因為我不知道bert的哪些輸出是直接接分類層的,練手的機會都沒有(逃)。除此之外,像torch lighting,skortch,torchkeras這類很好用的torch周邊不是很方便集成進來,如果搭建的時候盡量貼近原生的torch語法,那麼很多torch的周邊工具都會比較方便的集成進來一起使用。

(我始終覺得框架封裝的太過於完成不是很好的事情,比如lightgbm這類框架都寫死了,要做一些訓練層面的魔改無從下手,比如lgb的優化算法如果能結合tf中的optimizers一起用就好了)

所以我打算先接着這個框架把torch用熟悉,因此automodelXXX這部分和pipeline一樣跳過,等我擼熟了torch再專門總結一下這兩個部分


休息

Models部分:

transformers目前提供了非常海量的預訓練模型,這些預訓練模型使用的模型結構、語言任務、語料等等可能都不盡相同,實在太多了壓根研究不過來,先把常用的bert這類的弄清楚就好。

這些模型都可以通過相似的api來進行統一調用,常見的需求是直接使用預訓練模型來完成下游任務或者在下游任務數據上做finetune。

每個標記器的工作方式不同,但基本機制保持不變。這是一個使用BERT標記器的示例,該標記器是一個WordPiece標記器:

from transformers import BertTokenizer
tokenizer = BertTokenizer.from_pretrained("bert-base-cased")
sequence = "A Titan RTX has 24GB of VRAM"
 

這個和wordpiece的工作原理有關

然後可以將這些令牌轉換為模型可以理解的ID。這可以通過直接將句子提供給令牌生成器來完成,該令牌生成器利用Rust的擁抱面/令牌生成器實現最佳性能。

inputs = tokenizer(sequence)
encoded_sequence = inputs["input_ids"]
print(encoded_sequence)

請注意,令牌生成器會自動添加「特殊令牌」(如果關聯的模型依賴於它們),這些「特殊令牌」是模型有時使用的特殊ID。

如果我們解碼先前的ID序列,

decoded_sequence = tokenizer.decode(encoded_sequence)
>>> print(decoded_sequence)
[CLS] A Titan RTX has 24GB of VRAM [SEP]

注意麵膜

注意掩碼是將序列批處理在一起時使用的可選參數。此參數向模型指示應注意哪些令牌,不應該注意哪些令牌。

例如,考慮以下兩個序列:

from transformers import BertTokenizer
tokenizer = BertTokenizer.from_pretrained("bert-base-cased")
sequence_a = "This is a short sequence."
sequence_b = "This is a rather long sequence. It is at least longer than the sequence A."
encoded_sequence_a = tokenizer(sequence_a)["input_ids"]
encoded_sequence_b = tokenizer(sequence_b)["input_ids"]

編碼版本具有不同的長度:

len(encoded_sequence_a), len(encoded_sequence_b)
 

因此,我們不能將它們按原樣放在相同的張量中。需要將第一個序列填充到第二個序列的長度,或者將第二個序列截短到第一個序列的長度。

在第一種情況下,ID列表將通過填充索引進行擴展。我們可以將列表傳遞給令牌生成器,並要求其像這樣填充:

padded_sequences = tokenizer([sequence_a, sequence_b], padding=True)

我們可以看到,在第一句話的右邊添加了0,使其與第二句話的長度相同:

padded_sequences["input_ids"]
 [[101, 1188, 1110, 170, 1603, 4954, 119, 102, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [101, 1188, 1110, 170, 1897, 1263, 4954, 119, 1135, 1110, 1120, 1655, 2039, 1190, 1103, 4954, 138, 119, 102]]

然後可以將其轉換為PyTorch或TensorFlow中的張量。注意掩碼是一個二進制張量,指示填充索引的位置,以便模型不會注意它們。對於BertTokenizer1表示應注意的值,而0表示已填充的值。該注意掩碼在令牌生成器返回的字典中,在鍵「 attention_mask」下

padded_sequences["attention_mask"]
[[1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]]

令牌類型ID

一些模型的目的是進行序列分類或問題解答。這些要求將兩個不同的序列連接到單個「 input_ids」條目中,這通常是藉助特殊令牌(例如分類[CLS]符([SEP])和分隔符()令牌)執行的。例如,BERT模型按如下方式構建其兩個序列輸入:

>>> # [CLS] SEQUENCE_A [SEP] SEQUENCE_B [SEP]

我們可以使用令牌生成器通過將兩個序列tokenizer作為兩個參數(而不是像以前那樣的列表)傳遞給這樣的語句來自動生成這樣的句子:

from transformers import BertTokenizer
tokenizer = BertTokenizer.from_pretrained("bert-base-cased")
sequence_a = "HuggingFace is based in NYC"
sequence_b = "Where is HuggingFace based?"
encoded_dict = tokenizer(sequence_a, sequence_b)
decoded = tokenizer.decode(encoded_dict["input_ids"])

對於某些模型而言,這足以了解一個序列在何處結束以及另一序列在何處開始。但是,其他模型(例如BERT)也部署令牌類型ID(也稱為段ID)。它們被表示為二進制掩碼,標識了模型中的兩種序列。

令牌生成器將此掩碼作為「 token_type_ids」條目返回:

第一個序列,即用於問題的「上下文」,其所有標記均以a表示0,而第二個序列,對應於「 question」,其所有標記均以a表示1

某些模型(例如)XLNetModel使用以表示的附加令牌2

職位編號

與在其中嵌入每個令牌位置的RNN相反,轉換器不知道每個令牌的位置。因此,position_ids模型使用位置ID()來識別令牌列表中每個令牌的位置。

它們是可選參數。如果沒有position_ids傳遞給模型,則ID將自動創建為絕對位置嵌入。

在範圍內選擇絕對位置嵌入。一些模型使用其他類型的位置嵌入,例如正弦位置嵌入或相對位置嵌入。[0, config.max_position_embeddings - 1]

標籤

標籤是一個可選參數,可以傳遞該參數以便模型計算損耗本身。這些標籤應該是模型的預期預測:它將使用標準損失,以便計算其預測與預期值(標籤)之間的損失。

這些標籤根據模型頭而有所不同,例如:

  • 對於序列分類模型(例如BertForSequenceClassification),模型期望維度張量(batch_size),其中批次的每個值都對應於整個序列的預期標籤。
  • 對於令牌分類模型(例如BertForTokenClassification),模型期望維數張量,其中每個值對應於每個單獨令牌的預期標籤。(batch_size, seq_length)
  • 對於屏蔽語言建模(例如BertForMaskedLM),模型需要一個維數張量, 其中每個值對應於每個單獨令牌的預期標籤:標籤是屏蔽令牌的令牌ID,其餘值將被忽略(通常是-100)。(batch_size, seq_length)
  • 對於序列到序列的任務(例如,BartForConditionalGenerationMBartForConditionalGeneration),該模型預計尺寸的張量與對應於與每個輸入序列相關聯的靶序列的每個值。在訓練期間,BART和T5都將在內部製作適當的解碼器輸入ID和解碼器注意掩碼。通常不需要提供它們。這不適用於利用Encoder-Decoder框架的模型。有關每個特定模型標籤的更多信息,請參見每個模型的文檔。(batch_size, tgt_seq_length)

基本模型(例如BertModel不接受標籤,因為它們是基本變壓器模型,僅輸出要素features。

解碼器輸入ID
此輸入特定於編碼器-解碼器模型,並且包含將輸入到解碼器的輸入ID。這些輸入應用於按順序排序的任務,例如翻譯或摘要,並且通常以特定於每種模型的方式構建。
大多數編碼器/解碼器模型(BART,T5)都可以decoder_input_ids通過自己創建labels。在這樣的模型中,通過labels是處理培訓的首選方法。
請檢查每個模型的文檔,以了解它們如何處理這些輸入ID,以進行從序列到序列的訓練。

前饋分塊
在變壓器的每個剩餘注意力塊中,自我注意力層通常後面是2個前饋層。前饋層的中間嵌入大小通常大於模型的隱藏大小(例如 bert-base-uncased)。
對於size的輸入,存儲中間前饋嵌入所需的內存可能占內存使用的很大一部分。《Reformer:Efficient Transformer》的作者注意到,由於計算與尺寸無關,因此在數學上等效於分別計算兩個前饋層的輸出嵌入, 然後將它們嵌入到中,從而以增加的計算時間與減少的內存使用量進行了交換。 ,但得出數學上 相等的結果。[batch_size, sequence_length][batch_size, sequence_length, config.intermediate_size]sequence_length[batch_size, config.hidden_size]_0, ..., [batch_size, config.hidden_size]_n[batch_size, sequence_length, config.hidden_size]n = sequence_length
對於使用該函數的模型apply_chunking_to_forward()chunk_size定義並行計算的輸出嵌入的數量,從而定義內存和時間複雜度之間的權衡。如果chunk_size設置為0,則不執行前饋分塊。

這塊介紹了輸入輸出,還是非常不錯的。

任務摘要

此頁面顯示了使用庫時最常見的用例。可用的模型允許許多不同的配置,並在用例中具有極大的多功能性。這裡介紹了最簡單的方法,展示了諸如問題回答,序列分類,命名實體識別等任務的用法。

這些示例利用了自動模型,這些模型是將根據給定的檢查點實例化模型,自動選擇正確的模型體系結構的類。請檢查AutoModel文檔以獲取更多信息。隨意修改代碼使其更具體,並使其適應您的特定用例。

為了使模型在任務上表現良好,必須從與該任務相對應的檢查點加載模型。這些檢查點通常在大量數據集上進行預訓練,並在特定任務上進行微調。這意味着:

  • 並非所有模型都針對所有任務進行了微調。如果要針對特定​​任務微調模型,則可以利用示例目錄中的run_ $ TASK.py腳本之一。
  • 微調的模型在特定的數據集上微調。該數據集可能與您的用例和域重疊,也可能不重疊。如前所述,您可以利用示例腳本來微調模型,也可以創建自己的訓練腳本。

為了推斷任務,該庫提供了幾種機制:

  • 管道:非常易於使用的抽象,只需要兩行代碼即可。
  • 直接使用模型:通過直接訪問令牌生成器(PyTorch / TensorFlow)和完整的推理能力,可以減少抽象次數,但具有更大的靈活性和功能。

這兩種方法都在這裡展示。

此處介紹的所有任務都利用針對特定任務進行了微調的預訓練檢查點。加載未在特定任務上微調的檢查點將僅加載基礎變壓器層,而不加載用於該任務的附加磁頭,從而隨機初始化該磁頭的權重。

這將產生隨機輸出。

序列分類

序列分類是根據給定類數對序列進行分類的任務。序列分類的一個示例是GLUE數據集,它完全基於該任務。如果要微調GLUE序列分類任務上的模型,則可以利用run_glue.pyrun_tf_glue.pyrun_tf_text_classification.pyrun_xnli.py腳本。

這是使用管道進行情感分析的示例:識別序列是正數還是負數。它在sst2上利用了經過微調的模型,這是一個GLUE任務。

這將返回一個帶有分數的標籤(「正」或「負」),如下所示:

from transformers import pipeline
nlp = pipeline("sentiment-analysis")
result = nlp("I hate you")[0]
print(f"label: {result['label']}, with score: {round(result['score'], 4)}")
result = nlp("I love you")[0]
print(f"label: {result['label']}, with score: {round(result['score'], 4)}")
  

這是使用模型進行序列分類以確定兩個序列是否相互解釋的示例。該過程如下:

  1. 從檢查點名稱實例化標記器和模型。該模型被識別為BERT模型,並使用存儲在檢查點中的權重加載該模型。
  2. 使用正確的特定於模型的分隔符,標記類型ID和注意掩碼,從兩個句子構建一個序列(encode()__call__()注意這一點)。
  3. 將此序列傳遞給模型,以便將其分類為兩個可用類別之一:0(不是複述)和1(是複述)。
  4. 計算結果的softmax以獲得各類的概率。
  5. 打印結果。
from transformers import AutoTokenizer, AutoModelForSequenceClassification
import torch
tokenizer = AutoTokenizer.from_pretrained("bert-base-cased-finetuned-mrpc")
model = AutoModelForSequenceClassification.from_pretrained("bert-base-cased-finetuned-mrpc")
classes = ["not paraphrase", "is paraphrase"]
sequence_0 = "The company HuggingFace is based in New York City"
sequence_1 = "Apples are especially bad for your health"
sequence_2 = "HuggingFace's headquarters are situated in Manhattan"
paraphrase = tokenizer(sequence_0, sequence_2, return_tensors="pt")
not_paraphrase = tokenizer(sequence_0, sequence_1, return_tensors="pt")
paraphrase_classification_logits = model(**paraphrase).logits
not_paraphrase_classification_logits = model(**not_paraphrase).logits
paraphrase_results = torch.softmax(paraphrase_classification_logits, dim=1).tolist()[0]
not_paraphrase_results = torch.softmax(not_paraphrase_classification_logits, dim=1).tolist()[0]
# Should be paraphrase
for i in range(len(classes)):
    print(f"{classes[i]}: {int(round(paraphrase_results[i] * 100))}%")
# Should not be paraphrase
for i in range(len(classes)):
    print(f"{classes[i]}: {int(round(not_paraphrase_results[i] * 100))}%")

得到的就是一個nn module那個自定義的torch的網絡結構啊。。那使用的話和torch用起來不是差不多嗎。。。

提取式問答

提取問題答案是從給定問題的文本中提取答案的任務。SQuAD數據集是一個完全基於該任務的問題回答數據集。如果要微調SQuAD任務上的模型,則可以利用run_qa.pyrun_tf_squad.py腳本。

這是使用管道進行問題解答的示例:從給定問題的文本中提取答案。它在SQuAD上利用了經過微調的模型。

>>> from transformers import pipeline >>> nlp = pipeline(“question-answering”) >>> context = r””” Extractive Question Answering is the task of extracting an answer from a text given a question. An example of a question answering dataset is the SQuAD dataset, which is entirely based on that task. If you would like to fine-tune a model on a SQuAD task, you may leverage the examples/question-answering/run_squad.py script. “””

這將返回從文本中提取的答案,置信度得分以及「開始」和「結束」值,這些值是提取的答案在文本中的位置。

>>> result = nlp(question=”What is extractive question answering?”, context=context) >>> print(f”Answer: ‘{result[‘answer’]}‘, score: {round(result[‘score’], 4)}, start: {result[‘start’]}, end: {result[‘end’]}“) Answer: ‘the task of extracting an answer from a text given a question.’, score: 0.6226, start: 34, end: 96 >>> result = nlp(question=”What is a good example of a question answering dataset?”, context=context) >>> print(f”Answer: ‘{result[‘answer’]}‘, score: {round(result[‘score’], 4)}, start: {result[‘start’]}, end: {result[‘end’]}“) Answer: ‘SQuAD dataset,’, score: 0.5053, start: 147, end: 161

這是一個使用模型和標記器回答問題的示例。該過程如下:

  1. 從檢查點名稱實例化標記器和模型。該模型被識別為BERT模型,並使用存儲在檢查點中的權重加載該模型。
  2. 定義文本和一些問題。
  3. 遍歷問題,並根據文本和當前問題構建序列,並使用正確的特定於模型的分隔符標記類型ID和注意掩碼。
  4. 將此序列傳遞給模型。對於起點和終點位置,這將在整個序列標記(問題和文本)中輸出一定範圍的分數。
  5. 計算結果的softmax以獲得令牌上的概率。
  6. 從標識的起始值和終止值中獲取令牌,然後將這些令牌轉換為字符串。
  7. 打印結果。
>>> from transformers import AutoTokenizer, AutoModelForQuestionAnswering
>>> import torch

>>> tokenizer = AutoTokenizer.from_pretrained("bert-large-uncased-whole-word-masking-finetuned-squad")
>>> model = AutoModelForQuestionAnswering.from_pretrained("bert-large-uncased-whole-word-masking-finetuned-squad")

>>> text = r"""
...   Transformers (formerly known as pytorch-transformers and pytorch-pretrained-bert) provides general-purpose
... architectures (BERT, GPT-2, RoBERTa, XLM, DistilBert, XLNet…) for Natural Language Understanding (NLU) and Natural
... Language Generation (NLG) with over 32+ pretrained models in 100+ languages and deep interoperability between
... TensorFlow 2.0 and PyTorch.
... """

>>> questions = [
...     "How many pretrained models are available in   Transformers?",
...     "What does   Transformers provide?",
...     "  Transformers provides interoperability between which frameworks?",
... ]

>>> for question in questions:
...     inputs = tokenizer(question, text, add_special_tokens=True, return_tensors="pt")
...     input_ids = inputs["input_ids"].tolist()[0]
...
...     outputs = model(**inputs)
...     answer_start_scores = outputs.start_logits
...     answer_end_scores = outputs.end_logits
...
...     answer_start = torch.argmax(
...         answer_start_scores
...     )  # Get the most likely beginning of answer with the argmax of the score
...     answer_end = torch.argmax(answer_end_scores) + 1  # Get the most likely end of answer with the argmax of the score
...
...     answer = tokenizer.convert_tokens_to_string(tokenizer.convert_ids_to_tokens(input_ids[answer_start:answer_end]))
...
...     print(f"Question: {question}")
...     print(f"Answer: {answer}")
Question: How many pretrained models are available in   Transformers?
Answer: over 32 +
Question: What does   Transformers provide?
Answer: general - purpose architectures
Question:   Transformers provides interoperability between which frameworks?
Answer: tensorflow 2 . 0 and pytorch

語言建模

語言建模是使模型適合語料庫的任務,語料庫可以是特定於領域的。所有流行的基於變壓器的模型都使用語言建模的變體進行了訓練,例如具有掩蓋語言建模的BERT,具有因果語言建模的GPT-2。

語言建模在預訓練之外也很有用,例如,將模型分佈更改為特定領域:使用在非常大的語料庫上訓練的語言模型,然後將其微調到新聞數據集或科學論文上,例如LysandreJik / arxiv-nlp

掩蓋語言建模

掩碼語言建模的任務是用掩碼令牌對序列中的令牌進行掩碼,並提示模型用適當的令牌填充該掩碼。這允許模型同時關注右側上下文(蒙版右側的標記)和左側上下文(蒙版左側的標記)。這樣的培訓為需要雙向上下文的下游任務(例如SQuAD)提供了堅實的基礎(問題解答,請參見Lewis,Lui,Goyal等人,第4.2部分)。如果您想對掩蓋的語言建模任務進行模型微調,則可以利用run_mlm.py腳本。

這是使用管道替換序列中的掩碼的示例:

from transformers import pipeline

nlp = pipeline(“fill-mask”)

from pprint import pprint
pprint(nlp(f"HuggingFace is creating a {nlp.tokenizer.mask_token} that the community uses to solve NLP tasks."))

這是一個使用模型和標記器進行掩蓋語言建模的示例。該過程如下:

  1. 從檢查點名稱實例化標記器和模型。該模型被標識為DistilBERT模型,並使用存儲在檢查點中的權重加載該模型。
  2. 用帶掩碼的標記定義一個序列,放置tokenizer.mask_token而不是單詞。
  3. 將該序列編碼為ID列表,然後在該列表中找到被屏蔽令牌的位置。
  4. 在掩碼標記的索引處檢索預測:此張量與詞彙表具有相同的大小,並且值是歸屬於每個標記的分數。該模型為在這種情況下可能認為的代幣提供了更高的分數。
  5. 使用PyTorchtopk或TensorFlowtop_k方法檢索前5個令牌。
  6. 用標記替換掩碼標記並打印結果

Summary of the tasks 這裡全都是直接調用預訓練模型的用法,finetune的都是腳本感覺不好用。

基於Huggingface使用BERT進行文本分類的fine-tuning | 程序員燈塔www.wangt.cc

這裡是finetune的比較好的基於torch的例子,和之前寫的from scratch那個腳本差不多。


模型總結

這是 變壓器中可用模型的摘要。假定您熟悉原始的變壓器模型。為便於介紹,請檢查帶注釋的變壓器。在這裡,我們關注模型之間的高級差異。您可以在各自的文檔中更詳細地檢查它們。另外,請查看經過預訓練的模型頁面,以查看適用於每種類型的模型和所有社區模型的檢查點。

庫中的每個模型都屬於以下類別之一:

自回歸模型在經典語言建模任務上進行了預訓練:猜測下一個已讀完所有先前標記的標記。它們對應於原始轉換器模型的解碼器,並且在整個句子的頂部使用了一個掩碼,以便注意頭只能看到文本中的之前內容,而不能看到其後的內容。儘管可以對這些模型進行微調並在許多任務上取得很好的效果,但是最自然的應用是文本生成。此類模型的典型示例是GPT。

通過以某種方式破壞輸入令牌並嘗試重建原始句子來對自動編碼模型進行預訓練。從某種意義上說,它們與原始變壓器模型的編碼器相對應,因為它們無需任何掩碼即可訪問完整的輸入。這些模型通常建立整個句子的雙向表示。可以對它們進行微調並在許多任務(例如文本生成)上取得出色的結果,但是它們最自然的應用是句子分類或標記分類。此類模型的典型示例是BERT。

請注意,自動回歸模型和自動編碼模型之間的唯一區別在於模型的預訓練方式。因此,相同的體系結構既可以用於自動回歸模型,也可以用於自動編碼模型。當給定模型同時用於兩種類型的預訓練時,我們將其放在與首次引入該模型的文章相對應的類別中。

序列到序列模型將原始轉換器的編碼器和解碼器同時用於翻譯任務或通過將其他任務轉換為序列到序列問題。可以將它們微調成許多任務,但最自然的應用是翻譯,摘要和問題解答。原始的轉換器模型是此類模型的一個示例(僅用於翻譯),T5是可以在其他任務上進行微調的示例。

多模式模型將文本輸入與其他類型的輸入(例如圖像)混合在一起,並且更特定於給定任務。

Summary of the modelshuggingface.co圖標

都是各類模型的介紹

Preprocessing datahuggingface.co

這部分是關於tokenizer的問題,分詞器的各種設定,涉及到wordpiece和bpe算法wtf。

//huggingface.co/transformers/training.htmlhuggingface.co

訓練和微調

from transformers import BertForSequenceClassification
model = BertForSequenceClassification.from_pretrained('bert-base-uncased')
model.train()

這很有用,因為它使我們能夠使用預訓練的BERT編碼器,並輕鬆地在我們選擇的任何序列分類數據集上對其進行訓練。我們可以使用任何PyTorch優化器,但我們的庫也提供了AdamW()實現梯度偏差校正和權重衰減的 優化器。

from transformers import AdamW optimizer = AdamW(model.parameters(), lr=1e-5)

還有默認的優化器啊,wtf

no_decay = ['bias', 'LayerNorm.weight']
optimizer_grouped_parameters = [
    {'params': [p for n, p in model.named_parameters() if not any(nd in n for nd in no_decay)], 'weight_decay': 0.01},
    {'params': [p for n, p in model.named_parameters() if any(nd in n for nd in no_decay)], 'weight_decay': 0.0}
]
optimizer = AdamW(optimizer_grouped_parameters, lr=1e-5)

這部分就是torch高級一點的用法了

這個和torch的用法一樣,實際上就是用torch

torch的權重凍結方法

這幾個腳本應該不錯,都是用trainer來訓練啊,但是我想學torch啊啊啊啊啊

Training and fine-tuninghuggingface.co

Examples – transformers 4.4.2 documentationhuggingface.co

//huggingface.co/transformers/model_sharing.htmlhuggingface.co

模型的共享和

這幾個example應該也不錯

//huggingface.co/transformers/tokenizer_summary.html#huggingface.co

tokenizer的算法原理介紹

Multi-lingual modelshuggingface.co

多語種訓練;

Pretrained modelshuggingface.co

預訓練模型介紹


自定義數據集上做微調:

Fine-tuning with custom datasetshuggingface.co

這個上面的例子也都不錯可以Fine-tuning with custom datasets這個上面的例子也都不錯可以

Transformers Notebooks

Transformers Notebookshuggingface.co

這裡還有更多筆記本,很好。

Community – transformers 4.4.2 documentationhuggingface.co

這裡也是一堆的筆記本非常好:

Migrating from previous packageshuggingface.co

版本的變化和一些安裝的細節;

Exporting transformers modelshuggingface.co

模型的序列化和部署功能。

Exporting transformers modelshuggingface.co

模型的序列化和部署功能。

//huggingface.co/transformers/perplexity.htmlhuggingface.co

困惑度計算。

Callbacks – transformers 4.4.2 documentationhuggingface.co

trainer的callback功能,Callbacks – transformers 4.4.2 documentationtrainer的callback功能,

各種函數的用法。

Callbacks – transformers 4.4.2 documentationhuggingface.co

其它的一些使用小設計,不一定用上可能自己寫也行