Last Updated on 2022-04-28 by Clay
基本介紹
T5 ,全名是 Transfer Learning with a Unified Text-to-Text Transformer,在 2019 年底提出、隔年 2020 年則在 GLUE 上成為榜首,成功擠下了自家的 ALBERT。
這是一個很有名的預訓練模型(pre-trained model),早幾年我曾經接觸過,不過說真的一直到最近才在工作中親眼見識到它的威力。效果比之前試過的幾個預訓練模型來得更好,真是名不虛傳啊老大哥。
也正是因為這樣,我才覺得寫下這篇筆記,算是我對 T5 模型的一些初步了解。
備註
為了科普,還是簡單地講一下什麼是 NLP 任務的預訓練模型吧!簡單來說,應用預訓練模型(pre-trained model)於自己的任務領域進行微調(fine-tune),是近年來處理 NLP 任務時的主流方法。
其做法是,先使用大量不同領域的未標記資料在非監督式學習中訓練出一個預訓練模型(而這個模型通常由大公司開源提供... 小公司根本沒那麼資金燒出這樣的一個模型),再於下游任務調整權重。
這樣做的好處,通常我們的下游任務(目標領域)資料量其實是不足以訓練出好的模型參數的,然而再使用了大量其他領域的資料訓練後,就便能讓我們的預訓練模型有一定程度的推理能力。
將預訓練模型調整成適合我們的任務領域,比方說將這個泛用模型應用在法律、醫學、古文等等特定領域中,我們就能期待這強大的預訓練模型遷移學習到我們的領域後展現出的強大適應性,從而解決我們需要解決的問題。
簡單來說,我們可以把 T5 視為一個完整的 Transformer 模型結構。什麼是 Transformer 模型呢?就是分別由編碼器(Encoder)和解碼器(Decoder)兩部份所組成。
之所以這樣強調,是因為在之前主流的預訓練模型中,通常這兩者是分開的;比方說講到 Encoder 架構,我們就會想到經典的 BERT 等系列模型;而說到 Decoder 架構,則難免想起 GPT-2 之類的模型。
前者是把輸入進行編碼,取得良好的 token vector、後者是把編碼後的資訊進行解碼,產生出我們要的文字。
而 T5 模型作為一個完整的 Transformer 模型,自然是把這些能做的事情通通都做完了。
T5 能將所有的 NLP 任務,都轉換成 Text-to-Text 的形式(以往都稱為 Seq-to-Seq,將文字輸入通過 Encoder 進行編碼、再由 Decoder 進行解碼得到最終文字輸出)。
詳細的輸入輸出格式,可以直接參考下方的範例;就連分類任務,T5 模型都能直接用產生的字詞告訴我們分類的標簽。比方說二分類,T5 甚至會直接產出字串形式的 "True" 和 "False",夠神了吧?
對了,值得一提的是,在原始論文中,針對 T5 一共做了近 70 組實驗。70 組啊!以前我都會用『錢彷彿從螢幕上噴出來』來形容 3A 級別大作的遊戲,但在今天仔細看了下這組表格後,我實在是很想對這篇論文講出一樣的評語。
資料集
講完了 T5 模型的基本介紹後,接著來記錄一下 T5 模型所使用的資料集。若說模型的架構是一個好的模型的骨幹,那麼資料集大概就是重要的營養來源。兩者都缺一不可,才能鍛鍊出好的權重,擁有強壯的解決問題能力。
而這份資料集,被稱為 C4。
C4 (crawl from Common Crawl,每月爬 20TB,清理成 750GB 訓練資料),是 Colossal Clean Crawled Corpus(大型乾淨爬蟲語料庫)的簡稱。也有一說是影射鑽石評級的 4C 規格。
也就是很厲害的意思。
有趣的是,其實所謂的 T5 模型,也隱隱約約有在影射 Google 的 T5 級別工程師。
總之,關於這份 C4 資料集的清理規則基本如下:
- 以一行(line)為單位
- 僅保留結尾是正常符號的資料
- 刪除包含不好詞彙的頁面(參考 List-of-Dirty-Naughty-Obscene-and-Otherwise-Bad-Words)
- 刪除包含 Javascript 語法的資料
- 刪除包含程式語言中大括號的頁面(不想爬取程式碼)
- 刪除包含 “lorem ipsum”(排版測試)的資料
- 連續三筆資料重複,僅保留唯一一筆資料
其中我個人覺得有些感慨的是,之前我個人有在研究深度學習應用於編譯器優化的問題;然而這份看起來很不錯的資料集卻完全刪除了包含有程式語言的頁面,我想詞庫或許也少了許多程式語言的詞彙,這樣很難讓 Encoder 的部分做出不錯的編碼。
看來,或許 T5 是比較難應用在編譯器優化的項目上的。
模型架構
Step 1: 測試以下三種模型架構
- Encoder-Decoder
Seq-to-Seq 常用模型,即分為 Encoder 和 Decoder 兩階段。
Encoder 可以看到前一層全部的資料;
Decoder 僅能看到前一層自己神經元位置前的資料。
如大家耳熟能詳的 BERT 就是 Encoder 的部份。 - Language Model
可以想像成 Decoder 結構,當前時間步僅能看到當前時間步之前的資訊。
如大家耳熟能詳的 GPT-2 就是 Decoder。 - Prefix LM (Language Model)
Encoder 和 Decoder 的融合,一部分 Encoder 能看見所有資訊、一部分 Decoder 只能看到當前時間步前的資訊。
如 UniLM 便是此架構。
最後實驗結果得出使用 Encoder-Decoder 是最適當的模型架構。
Step 2: 預訓練任務
- High-level approaches
- Language modeling: 從左到右預測詞彙,如 GPT-2
- BERT-style: Masked Language Model 和 Next Sentence Prediction 隨機將詞彙遮蔽,然後還原、以及預測句 A 和句 B 是否為先後關係的二分類
- Deshuffling: 將文本中的詞彙順序打亂,再將其順序還原
其中 BERT-style 的效果最好。
- Corruption strategies
- Mask: 遮蔽 token,或許將其轉換成 “[M]” 之類的遮蔽符號
- Replace Span: 遮蔽 span,將 Mask 方法中相鄰的 “[M]” 遮蔽符號都置換成特殊符號,提高計算效率
- Drop: 並非替換,而是隨機丟棄 token
效果最好的是 Replace Span,如 SpanBERT 也是使用這種方式。
- Corruption rate
- 10%
- 15%
- 25%
- 50%
此為破壞掉文本資料的比例。最後選定了跟 BERT 同樣 15% 的破壞比例。
- Corrupted span length
- 2
- 3
- 5
- 10
由於 replace span 需要決定該何種長度的 span,於是測試了不同長度的破壞;最後發現長度 3 的效果最好。
使用方法
資料輸入
一個任務目的的 prompt(可以理解為任務項目的提示詞),加上特徵輸入(文本)與標籤輸出(文本)。
以下分別為『機器翻譯』、『分類任務』、『句子相似度』等不同任務的資料輸入輸出。
Example 1:
Input: [“translate English to German”, “This is good.”]
Output: [“Das ist gut.”]
Example 2:
Input: [“cola sentence”, “The course is jumping well.”]
Output: [“not acceptable”]
Example 3:
Input: [“stsb sentence1: The rhino grazed on the grass.”, “stsb sentence2: A rhino is grazing in a field”]
Output: [“3.8”]
預訓練模型
Model | Parameter |
---|---|
t5-small | 60M |
t5-base | 220M |
t5-large | 770M |
t5-3b | 3B |
t5-11b | 11B |
T5 模型也有多變體,可以衡量自己的任務需求與硬體配置來選擇。
Sample Code
以下是一段範例程式碼,想要做減法的任務。
不過,效果很難稱得上好。大概是因為訓練資料不足吧。
但最重要的是,我們可以通過這份簡單的範例程式碼,確認程式可以正常執行。這樣一來使用者就可以簡單地抽換成自己想要做的任務了。
# coding: utf-8
"""
It is a simple script for test different T5 model arguments.
"""
import pandas as pd
from simpletransformers.t5 import T5Model, T5Args
def main() -> None:
"""Entry point"""
# Train data
train_data = [
["sub", "13-7", "6"],
["sub", "7-5", "2"],
["sub", "6-2", "4"], ["sub", "19-7", "12"],
]
train_df = pd.DataFrame(train_data)
train_df.columns = ["prefix", "input_text", "target_text"]
# Valid data
eval_data = [
["sub", "11-3", "8"],
["sub", "55-53", "2"],
]
eval_df = pd.DataFrame(eval_data)
eval_df.columns = ["prefix", "input_text", "target_text"]
# Configurations
model_args = T5Args()
model_args.num_train_epochs = 100
model_args.no_save = True
model_args.evaluate_generated_text = True
model_args.evaluate_during_training = True
model_args.evaluate_during_training_verbose = True
model_args.overwrite_output_dir = True
# Build the model
model = T5Model("t5", "t5-small", args=model_args, use_cuda=False)
# Train the model
print(f"train: {train_df}")
print(f"eval: {eval_df}")
model.train_model(train_df, eval_data=eval_df)
# Evaluate the model
result = model.eval_model(eval_df)
print(f"result: {result}")
# Prediction
to_predict = [
["sub", "15-13"],
["sub", "32-30"],
]
preds = model.predict(to_predict)
print(f"preds: {preds}")
if __name__ == "__main__":
main()
延伸問題(追記)
問題一:如何計算信賴區間/信賴分數(confidence score)
Huggingface 所開源之 transformer 預訓練模型與套件,有 num_beams 參數可以建立候選預測答案。或許可以拿來做一些計算。
先備註在這裡,避免自己忘記。
References
- 原始論文: https://arxiv.org/pdf/1910.10683.pdf
- Seq-to-Seq introduction: https://blog.paperspace.com/introduction-to-seq2seq-models/
- Hugging Faceh 提供的 T5 預訓練模型: https://huggingface.co/sentence-transformers/sentence-t5-base
- 提出 Transformer 架構的論文: https://arxiv.org/pdf/1706.03762.pdf
- Tranformer 架構的科普文章: 淺談神經機器翻譯 & 用 Transformer 與 TensorFlow 2 英翻中
想詢問一下,最後的結果是 preds: [’12’, ‘2’],這是合理的結果嗎?
是的,這種文字生成模型對於數字極度不敏感,所以生成的數字是隨機的是相當合理了,不如說產生的是數字已經夠厲害了。
真的希望 T5 模型做到回答計算題這件事,還需要更多的資料跟更多的訓練才行呢。