Transformers 詞彙表

詞彙表每種模型都不同,但與其他模型相似。因此,大多數模型使用相同的輸入,此處將在用法示例中進行詳細說明。

輸入ID

輸入id通常是傳遞給模型作為輸入的唯一必需參數。它們是標記索引,標記的數字表示構建將被模型用作輸入的序列。

每個tokenizer的工作方式不同,但基本機制保持不變。這是一個使用BERTtokenizer(WordPiecetokenizer)的示例:

<code>from transformers import BertTokenizer
tokenizer = BertTokenizer.from_pretrained("bert-base-cased")

sequence = "A Titan RTX has 24GB of VRAM"/<code>

tokenizer負責將序列拆分為tokenizer詞彙表中可用的標記。

<code>#繼續上一個腳本
tokenized_sequence = tokenizer.tokenize(sequence)
assert tokenized_sequence == ['A', 'Titan', 'R', '##T', '##X', 'has', '24', '##GB', 'of', 'V', '##RA', '##M']/<code>

然後可以將這些標記轉換為模型可以理解的ID。有幾種方法可以使用,推薦使用的是encode或encode_plus,它們實現了最佳性能。

<code>#繼續上一個腳本
encode_sequence = tokenizer.encode(sequence)
assert encoded_sequence == [101, 138, 18696, 155, 1942, 3190, 1144, 1572, 13745, 1104, 159, 9664, 2107, 102]/<code>

encode和encode_plus方法自動添加“特殊標記”,這是模型使用的特殊ID。

注意力掩碼

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

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

<code>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.encode(sequence_a)
assert len(encoded_sequence_a) == 8

encoded_sequence_b = tokenizer.encode(sequence_b)
assert len(encoded_sequence_b) == 19/<code>

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

在第一種情況下,ID列表將通過填充索引擴展:

<code>#繼續上一個腳本
padded_sequence_a = tokenizer.encode(sequence_a, max_length=19, pad_to_max_length=True)

assert padded_sequence_a == [101, 1188, 1110, 170, 1603, 4954, 119, 102, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
assert encoded_sequence_b == [101, 1188, 1110, 170, 1897, 1263, 4954, 119, 1135, 1110, 1120, 1655, 2039, 1190, 1103, 4954, 138, 119, 102]/<code>

然後可以將它們轉換為PyTorch或TensorFlow中的張量。注意掩碼是一個二進制張量,指示填充索引的位置,以便模型不會注意它們。對於BertTokenizer,1表示應注意的值,而0表示填充值。

方法encode_plus()可用於直接獲取注意力掩碼:

<code>#繼續上一個腳本
sequence_a_dict = tokenizer.encode_plus(sequence_a, max_length=19, pad_to_max_length=True)


assert sequence_a_dict['input_ids'] == [101, 1188, 1110, 170, 1603, 4954, 119, 102, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
assert sequence_a_dict['attention_mask'] == [1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]/<code>

標記類型ID

一些模型的目的是進行序列分類或問題解答。這些要求將兩個不同的序列編碼在相同的輸入ID中。它們通常由特殊標記分隔,例如分類器標記和分隔符標記。例如,BERT模型按如下方式構建其兩個序列輸入:

<code>from transformers import BertTokenizer
tokenizer = BertTokenizer.from_pretrained("bert-base-cased")

# [CLS] SEQ_A [SEP] SEQ_B [SEP]

sequence_a = "HuggingFace is based in NYC"
sequence_b = "Where is HuggingFace based?"

encoded_sequence = tokenizer.encode(sequence_a, sequence_b)
assert tokenizer.decode(encoded_sequence) == "[CLS] HuggingFace is based in NYC [SEP] Where is HuggingFace based? [SEP]"/<code>

對於某些模型而言,這足以瞭解一個序列在何處終止以及另一序列在何處開始。但是,其他模型(例如BERT)具有附加機制,即段ID。標記類型ID是一個二進制掩碼,用於標識模型中的不同序列。

我們可以利用encode_plus()為我們輸出標記類型ID:

<code>#繼續上一個腳本
encoded_dict = tokenizer.encode_plus(sequence_a, sequence_b)

assert encoded_dict['input_ids'] == [101, 20164, 10932, 2271, 7954, 1110, 1359, 1107, 17520, 102, 2777, 1110, 20164, 10932, 2271, 7954, 1359, 136, 102]
assert encoded_dict['token_type_ids'] == [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1]/<code>

第一個序列,即用於問題的“上下文”,其所有標記均由0表示,而問題的所有標記均由1表示。某些模型(例如XLNetModel)使用由2表示的附加標記。

位置ID

模型使用位置ID來識別哪個標記在哪個位置。與將每個標記的位置嵌入其中的RNN相反,轉換器不知道每個標記的位置。為此創建了位置ID。

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

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


分享到:


相關文章: