Transformers 文件
向 Transformers 新增新模型
並獲得增強的文件體驗
開始使用
向 Transformers 新增新模型
請先嚐試以更模組化的方式新增新模型。這能顯著簡化向 Transformers 貢獻模型的過程!
Transformers 中的許多模型都是由開發者和研究人員貢獻的。作為一個開源優先專案,我們致力於賦能社群積極獨立地新增更多模型。
當你向 Transformers 新增模型時,你將學到:
這是一個充滿挑戰但回報豐厚的過程。
本指南將引導你向 Transformers 新增一個示例 BrandNewLlama PyTorch 模型。開始之前,最好先熟悉一下這個庫。
Transformers 概述
Transformers 是一個有獨特理念和設計選擇的庫。這些選擇有助於我們持續擴充套件和維護 Transformers。
請在理念文件中瞭解更多關於我們的設計原則。
其中一些設計選擇包括:
- 組合優於過度抽象
- 如果能大大提高可讀性和可訪問性,重複程式碼也並非總是壞事
- 模型檔案是自包含的,所有必要的模型程式碼都可在
modeling_mymodel.py
檔案中找到
這些設計選擇對與模型互動的*所有人*都很重要。它們能使程式碼更易讀、易懂、易修改。
本節描述了模型和配置類如何互動以及 Transformers 的程式碼風格。
模型和配置
所有 Transformers 模型都繼承自基類 PreTrainedModel 和 PretrainedConfig。配置是模型的藍圖。
為了保持程式碼可讀性,任何模型都不能超過兩層抽象。這裡的示例模型 BrandNewLlama 繼承自 BrandNewLlamaPreTrainedModel
和 PreTrainedModel。新模型只依賴於 PreTrainedModel 很重要,這樣它就可以使用 from_pretrained() 和 save_pretrained() 方法。
其他重要函式(如 forward 方法)在 modeling.py
檔案中定義。
特定的模型頭(例如,序列分類或語言建模)應該在 forward 傳遞中呼叫基模型,而不是繼承它,以保持低抽象度。
新模型需要一個配置,例如 BrandNewLlamaConfig
,它作為 PreTrainedModel 的一個屬性儲存。
model = BrandNewLlamaModel.from_pretrained("username/brand_new_llama")
model.config
PretrainedConfig 提供了 from_pretrained() 和 save_pretrained() 方法。
當你使用 PreTrainedModel.save_pretrained() 時,它會自動呼叫 PretrainedConfig.save_pretrained(),這樣模型和配置就會一起儲存。
模型儲存為 model.safetensors
檔案,配置儲存為 config.json
檔案。
程式碼風格
Transformers 傾向於清晰可讀的程式碼風格,而非更抽象的程式碼風格。一些程式碼風格選擇包括:
程式碼應易於非英語使用者理解。選擇描述性變數名,避免縮寫。例如,偏好“activation”而非“act”。除非是 for 迴圈中的索引,否則強烈不建議使用單字母變數名。
即使程式碼較長,也偏好顯式程式碼,而非較短的程式碼。
避免子類化 nn.Sequential。改為子類化 nn.Module,以便可以使用 print 語句或斷點快速除錯程式碼。
函式簽名應進行型別註解。否則,使用良好的變數名以使其更易於理解。
新模型新增問題
開啟新模型新增問題,以新增特定模型。
在 GitHub 上按新模型標籤篩選,以檢視和新增任何現有模型請求。
現在是熟悉 BrandNewLlama 的好時機。閱讀模型研究論文以瞭解其技術設計和實現會有所幫助。你不必過多擔心理論細節,而是專注於實踐細節。使用下面的問題來指導你的閱讀。
- BrandNewLlama 是哪種型別的模型?它是編碼器、解碼器還是編碼器-解碼器模型?
- BrandNewLlama 可用於哪些任務?
- BrandNewLlama 與其他模型有何不同?
- Transformers 中哪些模型與 BrandNewLlama 最相似?
- BrandNewLlama 使用哪種分詞器?
除了更多地瞭解你的模型,還可以使用以下提示來幫助你更快地新增模型。
每個貢獻者都有自己獨特的風格和工作流程來向 Transformers 新增模型。例如,可以看看Gemma是如何新增的。
- 不要重複造輪子!花時間探索現有模型和分詞器,看看哪些可以複製和重用。Grep 和 ripgrep 是很好的工具。
- 這更像是一個工程挑戰,而非科學挑戰。專注於模型的實際方面(例如,建立高效的除錯環境),而不是理論方面。
- 不要害羞,儘管尋求幫助!我們在這裡支援你。🤗
開發環境
點選 Transformers 倉庫上的 Fork 按鈕,建立你自己的副本進行工作。將倉庫克隆到本地磁碟,並將基礎倉庫新增為遠端倉庫。
git clone https://github.com/[your Github handle]/transformers.git
cd transformers
git remote add upstream https://github.com/huggingface/transformers.git
建立一個虛擬環境,並使用“dev”或開發依賴項對庫進行可編輯安裝。
python -m venv .env
source .env/bin/activate
pip install -e ".[dev]"
由於 Transformers 發展壯大,可選依賴項的數量可能會導致此命令失敗。在這種情況下,請安裝“quality”依賴項。還要確保你已安裝深度學習框架。
pip install -e ".[quality]"
返回父目錄並克隆並安裝原始 BrandNewLlama 倉庫。
git clone https://github.com/org_that_created_brand_new_llama_org/brand_new_llama.git
cd brand_new_bert
pip install -e .
返回你的 Transformers 克隆以開始移植 BrandNewLlama。
cd transformers
執行原始模型有兩種可能的除錯環境:筆記本(Google Colab 或 Jupyter)或本地 Python 指令碼。
我們不建議設定 GPU 環境來執行原始模型,因為這會很昂貴。相反,請先在 CPU 環境中工作,以驗證模型在 Transformers 中是否有效。一旦有效,你就可以在 GPU 上驗證它。
Notebook 非常適合逐個單元格執行程式碼,這有助於將邏輯元件彼此分離。它還可以加速調試周期,因為可以儲存中間結果。你還可以在與其他貢獻者協作時共享 Notebook。
缺點是如果你不習慣它們,可能需要一些時間來適應。
如果模型架構與現有模型相同,請跳過此步驟,直接新增轉換指令碼,因為你可以重用現有模型的架構。
執行以下命令,開始並完成問卷,填寫有關新模型的一些基本資訊。此命令透過自動生成一些你將需要修改的模型程式碼來啟動此過程。
transformers add-new-model-like
建立拉取請求
在開始修改程式碼之前,請建立一個拉取請求以跟蹤你的進度並從 Transformers 團隊獲取反饋。將你的拉取請求標題命名為 [WIP] Add BrandNewLlama,這樣就能清楚地表明這是一個正在進行中的工作。
從你的主分支建立一個具有描述性名稱的分支。
git checkout -b add_brand_new_bert
提交程式碼,然後拉取並 rebase 到主分支。
git add . git commit git fetch upstream git rebase upstream/main
將所有更改推送到你的分支,然後點選 Compare & pull request 在 GitHub 上開啟一個拉取請求。以*草稿*形式開啟拉取請求,表示其正在進行中。
git push -u origin a-descriptive-name-for-my-changes
透過在拉取請求中新增 Hugging Face 團隊成員的 GitHub 使用者名稱,以便他們回答問題、提供反饋、評論和審查。點選 Files changed 選項卡,然後點選行號左側的 + 以新增評論,將團隊成員引導到你想要關注的程式碼特定部分。當問題或故障解決後,點選 Resolve 表示問題已解決。這能保持對話有條理且清晰。
請記住定期提交併推送你的工作,並用當前主分支更新你的工作。
git fetch upstream git merge upstream/main
原始檢查點
花一些時間先研究原始模型的實現,以瞭解其工作原理。
如果原始模型倉庫缺少文件或程式碼庫複雜,這可能會很困難。但你應該以此作為在 Transformers 中實現模型的動力。你的貢獻能使其對每個人都更易於訪問和使用!
透過以下步驟熟悉原始倉庫:
- 找到預訓練權重。
- 弄清楚如何將預訓練權重載入到模型中。
- 弄清楚如何獨立於模型執行分詞器。
- 跟蹤一次前向傳播,瞭解需要哪些類和函式。這些可能是你唯一需要實現的類和函式。
- 定位模型的所有重要元件(模型類、模型子類、自注意力層等)。
- 弄清楚如何在原始倉庫中除錯模型。新增列印語句,使用互動式偵錯程式(如 ipdb),或使用高效的整合開發環境(IDE),如 PyCharm。
最後一點尤為重要,因為在將原始模型重新實現到 Transformers 中之前,你需要對原始模型內部發生的事情有透徹的理解。如果你遇到任何問題,請隨時在原始倉庫中開啟問題和拉取請求。
一個好的第一步是載入一個*小型*預訓練檢查點,並嘗試使用一個示例整數輸入向量重現單次前向傳播。例如,在虛擬碼中,這可能看起來像以下內容。
model = BrandNewLlamaModel.load_pretrained_checkpoint("/path/to/checkpoint/")
input_ids = [0, 4, 5, 2, 3, 7, 9] # vector of input ids
original_output = model.generate(input_ids)
除錯
如果你遇到問題,你需要根據原始模型的程式碼庫選擇以下除錯策略之一。
此策略依賴於將原始模型分解為更小的子元件,例如當代碼可以輕鬆在 Eager 模式下執行時。雖然更困難,但這種方法有一些優點。
- 稍後比較原始模型與你的實現會更容易。你可以自動驗證每個單獨的元件是否與其在 Transformers 實現中的相應元件匹配。這比依賴基於列印語句的視覺比較更好。
- 移植單個元件比移植整個模型更容易。
- 將模型分解成更小的部分有助於理解其工作原理。
- 透過元件到元件的測試,當你更改程式碼時,可以更容易地防止後續出現迴歸。
有關如何將模型分解為更小元件的良好示例,請參閱 ELECTRA 整合檢查。
無論你選擇哪種策略,都建議先除錯初始層,最後除錯最終層。按以下順序檢索這些層的輸出(透過列印語句或子元件函式):
- 傳遞給模型的輸入 ID
- 詞嵌入
- 第一個 Transformer 層的輸入
- 第一個 Transformer 層的輸出
- 後續 n-1 個 Transformer 層的輸出
- 整個模型的輸出
輸入 ID 應該只是一個整數陣列,例如 input_ids = [0, 4, 4, 3, 2, 4, 1, 7, 19]
。
層輸出通常由多維浮點陣列組成。
[[
[-0.1465, -0.6501, 0.1993, ..., 0.1451, 0.3430, 0.6024],
[-0.4417, -0.5920, 0.3450, ..., -0.3062, 0.6182, 0.7132],
[-0.5009, -0.7122, 0.4548, ..., -0.3662, 0.6091, 0.7648],
...,
[-0.5613, -0.6332, 0.4324, ..., -0.3792, 0.7372, 0.9288],
[-0.5416, -0.6345, 0.4180, ..., -0.3564, 0.6992, 0.9191],
[-0.5334, -0.6403, 0.4271, ..., -0.3339, 0.6533, 0.8694]]],
每個 Transformers 模型輸出的精度或誤差容限應為*1e-3*。這考慮了使用不同庫框架時出現的任何輸出差異。比較原始模型與 Transformers 實現的中間輸出,以確保它們幾乎相同。擁有一個*高效*的除錯環境對於此步驟至關重要。
以下是一些高效除錯環境的提示。
要除錯中間結果,取決於原始模型倉庫使用的機器學習框架。對於 PyTorch,你應該編寫一個指令碼將原始模型分解為更小的子元件以檢索中間值。對於 TensorFlow,你可能需要使用 tf.print。對於 Flax,確保模型在向前傳播期間*沒有被 JIT 編譯*(有關更多詳細資訊,請參閱此 GitHub 問題)。
使用較小的預訓練檢查點進行除錯比使用較大的檢查點(前向傳播需要 10 秒以上)更快。如果只有大型檢查點可用,則建立一個帶有隨機初始化權重的虛擬模型,並儲存這些權重以與 Transformers 實現進行比較。
找到呼叫模型前向傳播的最簡單方法。理想情況下,此函式(可能稱為
predict
、evaluate
、forward
或__call__
)應該只調用前向傳播*一次*。除錯多次呼叫前向傳播的函式會更困難。將分詞與前向傳播分開。找到字串輸入在前向傳播中如何變為輸入 ID 的位置,並從這裡開始。你可能需要建立一個小指令碼或修改原始程式碼以直接輸入輸入 ID,而不是輸入字串。
確保模型*不處於*訓練模式。這可能由於模型中的多個 dropout 層而產生隨機輸出。除錯環境中的前向傳播應該是*確定性*的,這樣 dropout 層就不會被使用。
一旦你能夠執行原始檢查點,你就可以開始為 Transformers 調整模型程式碼了。
調整模型程式碼
transformers add-new-model-like
命令應該已經生成了一個模型和配置檔案。
src/transformers/models/brand_new_llama/modeling_brand_new_llama.py
src/transformers/models/brand_new_llama/configuration_brand_new_llama.py
如果你回答它是一個僅解碼器模型,那麼 modeling.py
檔案中自動生成的程式碼將具有與 Llama 相同的架構;如果你回答它是一個編碼器-解碼器模型,則它將具有與 BART 相同的架構。生成的程式碼只是一個起點。根據你對新模型的研究,你需要透過調整生成的程式碼來實現那些特定的更改。這可能涉及對自注意力層、歸一化層順序等的更改。
模型初始化
此時,你的程式碼不必乾淨,甚至不必完全正確。更高效的做法是快速建立一個初稿,然後迭代改進它。最重要的是你的模型可以從 Transformers 例項化。下面的命令從配置中建立一個具有隨機權重的模型,驗證 __init__
方法是否有效。
from transformers import BrandNewLlama, BrandNewLlamaConfig
model = BrandNewLlama(BrandNewLlamaConfig())
隨機初始化發生在 BrandNewLlamaPreTrainedModel
的 _init_weights
方法中。所有葉模組都根據配置的變數進行初始化。
def _init_weights(self, module):
"""Initialize the weights"""
if isinstance(module, nn.Linear):
module.weight.data.normal_(mean=0.0, std=self.config.initializer_range)
if module.bias is not None:
module.bias.data.zero_()
elif isinstance(module, nn.Embedding):
module.weight.data.normal_(mean=0.0, std=self.config.initializer_range)
if module.padding_idx is not None:
module.weight.data[module.padding_idx].zero_()
elif isinstance(module, nn.LayerNorm):
module.bias.data.zero_()
module.weight.data.fill_(1.0)
如果你需要根據模型調整初始化方案,它可能看起來不同。例如,Wav2Vec2ForPreTraining 在其最後兩個線性層中初始化 nn.Linear。
_is_hf_initialized
標誌確保子模組只被初始化一次。將 module.project_q
和 module.project_hid
設定為 True
確保自定義初始化不會在以後被覆蓋。_init_weights
函式將不會應用於這些模組。
def _init_weights(self, module):
"""Initialize the weights"""
if isinstance(module, Wav2Vec2ForPreTraining):
module.project_hid.reset_parameters()
module.project_q.reset_parameters()
module.project_hid._is_hf_initialized = True
module.project_q._is_hf_initialized = True
elif isinstance(module, nn.Linear):
module.weight.data.normal_(mean=0.0, std=self.config.initializer_range)
if module.bias is not None:
module.bias.data.zero_()
將檢查點轉換為 Transformers
原始檢查點必須轉換為 Transformers 相容的檢查點。
嘗試尋找現有轉換指令碼,複製、調整並重新用於你的模型!
確保**所有**必需的權重都已初始化,並打印出所有未用於初始化的檢查點權重,以確保模型已正確轉換。
在轉換過程中,你可能會遇到錯誤的形狀語句或名稱分配。這很可能是由於 BrandNewLlamaConfig
中引數不正確、架構錯誤、你的實現中 init
方法存在錯誤,或者你需要轉置其中一個檢查點權重。
繼續迭代調整模型程式碼部分,直到所有檢查點權重都正確載入。一旦你能在模型中載入檢查點,將其儲存到一個資料夾中。該資料夾應包含一個 model.safetensors
檔案和一個 config.json
檔案。
model.save_pretrained("/path/to/converted/checkpoint/folder")
為了幫助轉換,下一節簡要介紹了 PyTorch 模型如何儲存和定義層權重和名稱。
PyTorch 層權重和名稱
建立一個基本的 PyTorch 模型以瞭解層名稱的定義方式和權重的初始化方式會很有幫助。
from torch import nn
class SimpleModel(nn.Module):
def __init__(self):
super().__init__()
self.dense = nn.Linear(10, 10)
self.intermediate = nn.Linear(10, 10)
self.layer_norm = nn.LayerNorm(10)
PyTorch 層名稱由層的類屬性名稱定義(dense
、intermediate
、layer_norm
)。建立一個 SimpleModel
例項以用隨機權重填充所有層。
model = SimpleModel()
print(model)
SimpleModel(
(dense): Linear(in_features=10, out_features=10, bias=True)
(intermediate): Linear(in_features=10, out_features=10, bias=True)
(layer_norm): LayerNorm((10,), eps=1e-05, elementwise_affine=True)
)
特定層的權重值是隨機初始化的。
print(model.dense.weight.data)
tensor([[-0.0818, 0.2207, -0.0749, -0.0030, 0.0045, -0.1569, -0.1598, 0.0212,
-0.2077, 0.2157],
[ 0.1044, 0.0201, 0.0990, 0.2482, 0.3116, 0.2509, 0.2866, -0.2190,
0.2166, -0.0212],
[-0.2000, 0.1107, -0.1999, -0.3119, 0.1559, 0.0993, 0.1776, -0.1950,
-0.1023, -0.0447],
[-0.0888, -0.1092, 0.2281, 0.0336, 0.1817, -0.0115, 0.2096, 0.1415,
-0.1876, -0.2467],
[ 0.2208, -0.2352, -0.1426, -0.2636, -0.2889, -0.2061, -0.2849, -0.0465,
0.2577, 0.0402],
[ 0.1502, 0.2465, 0.2566, 0.0693, 0.2352, -0.0530, 0.1859, -0.0604,
0.2132, 0.1680],
[ 0.1733, -0.2407, -0.1721, 0.1484, 0.0358, -0.0633, -0.0721, -0.0090,
0.2707, -0.2509],
[-0.1173, 0.1561, 0.2945, 0.0595, -0.1996, 0.2988, -0.0802, 0.0407,
0.1829, -0.1568],
[-0.1164, -0.2228, -0.0403, 0.0428, 0.1339, 0.0047, 0.1967, 0.2923,
0.0333, -0.0536],
[-0.1492, -0.1616, 0.1057, 0.1950, -0.2807, -0.2710, -0.1586, 0.0739,
0.2220, 0.2358]]).
在轉換指令碼中,隨機權重應替換為原始檢查點中相應層的精確權重。
# retrieve matching layer weights with recursive algorithm
layer_name = "dense"
pretrained_weight = array_of_dense_layer
model_pointer = getattr(model, "dense")
model_pointer.weight.data = torch.from_numpy(pretrained_weight)
驗證隨機初始化的權重及其對應的預訓練檢查點權重是否具有相同的**形狀**和**名稱**。為形狀新增斷言語句,並打印出檢查點權重名稱。
assert (
model_pointer.weight.shape == pretrained_weight.shape
), f"Pointer shape of random weight {model_pointer.shape} and array shape of checkpoint weight {pretrained_weight.shape} mismatched"
logger.info(f"Initialize PyTorch weight {layer_name} from {pretrained_weight.name}")
當形狀或名稱不匹配時,你可能已將不正確的檢查點權重分配給隨機初始化層。不正確的形狀可能是因為 BrandNewLlama
引數與原始模型引數不完全匹配。但它也可能是因為 PyTorch 層實現要求權重首先進行轉置。
實現前向傳播
如果模型載入正確,接下來應該實現前向傳播。它接受一些輸入並返回模型輸出。
model = BrandNewLlamaModel.from_pretrained("/path/to/converted/checkpoint/folder")
input_ids = [0, 4, 4, 3, 2, 4, 1, 7, 19]
output = model.generate(input_ids).last_hidden_states
如果你的前向傳播與原始模型輸出不一致或返回錯誤,不要氣餒。檢查前向傳播是否丟擲任何錯誤。這通常是因為維度錯誤或使用了錯誤的資料型別(torch.long 而不是 torch.float32)。
你的輸出精度應為*1e-3*。確保輸出形狀和輸出值相同。輸出不相同常見原因包括:
- 未新增某些層(啟用層或殘差連線)。
- 詞嵌入矩陣未繫結。
- 使用了錯誤的 positional embeddings,因為原始實現包含偏移量。
- 在前向傳播期間應用了 Dropout。透過確保
model.training
為False
並將self.training
傳遞給 torch.nn.functional.dropout 來修復此錯誤。
比較原始模型和你的實現的前向傳播,以檢查是否存在任何差異。理想情況下,除錯並打印出前向傳播的兩種實現的中間輸出,以精確找出原始實現與你的實現之間的差異。
- 確保兩種實現中硬編碼的
input_ids
相同。 - 驗證
input_ids
第一次變換的輸出(通常是詞嵌入)是否相同,然後逐步檢查到最後一層。
兩種實現之間的任何差異都應該指出你實現中的錯誤。
最好的策略之一是在兩種實現的相同位置新增許多列印語句,然後在它們對中間輸出產生相同值時逐步刪除它們。
當兩種實現產生相同的輸出時,驗證輸出精度在*1e-3*以內。
torch.allclose(original_output, output, atol=1e-3)
這通常是整個過程中最困難的部分。如果你已經走到這一步,恭喜你!
如果你在這個步驟中卡住或遇到困難,請隨時在你的拉取請求中尋求幫助。
新增模型測試
雖然模型有效,但你仍需要新增測試以確保其與 Transformers 相容。測試很重要,因為它們透過特定測試幫助使用者理解你的工作,並防止你的模型在未來進行任何更改時崩潰。
Cookiecutter 應該已經為你的模型添加了一個測試檔案。執行以下測試檔案以確保所有常見測試都透過。
pytest tests/models/brand_new_llama/test_modeling_brand_new_llama.py
整合測試應首先新增,因為它們的目的與你之前用於在 Transformers 中實現新模型的除錯指令碼相同。這些模型測試的模板 BrandNewLlamaModelIntegrationTests
已由 Cookiecutter 新增,並應填寫完整。為了確保其透過,請執行以下命令。
RUN_SLOW=1 pytest -sv tests/models/brand_new_llama/test_modeling_brand_new_llama.py::BrandNewLlamaModelIntegrationTests
BrandNewLlama 獨有的所有特性都應在 BrandNewLlamaModelTester/BrandNewLlamaModelTest
下的單獨測試中進行測試。此測試經常被忽視,但它極其重要,因為
- 它透過展示模型的新穎功能如何工作,幫助將你在過程中獲得的知識傳遞給社群
- 未來的貢獻者可以透過執行這些特殊測試快速測試對模型的更改
實現分詞器
我們建議新增一個快速分詞器(PreTrainedTokenizerFast),以提供最佳效能。歡迎在你的 PR 中標記 @ArthurZucker 或 @itazap,以獲取有關如何新增 PreTrainedTokenizerFast 的幫助。
模型已完成,現在是時候關注分詞器了。分詞器應該與 Transformers 中現有分詞器相同或非常相似。
找到並載入原始分詞器檔案到你的實現中。在原始倉庫中建立一個指令碼,輸入字串並返回 input_ids
。虛擬碼應該類似於以下程式碼。
input_str = "This is a long example input string containing special characters .$?-, numbers 2872 234 12 and words."
model = BrandNewLlamaModel.load_pretrained_checkpoint("/path/to/checkpoint/")
input_ids = model.tokenize(input_str)
你可能需要搜尋原始倉庫以找到正確的分詞器函式,或者修改你克隆的原始倉庫中的現有分詞器,使其只返回 input_ids
。你的分詞器的指令碼應該類似於以下內容。
from transformers import BrandNewLlamaTokenizer
input_str = "This is a long example input string containing special characters .$?-, numbers 2872 234 12 and words."
tokenizer = BrandNewLlamaTokenizer.from_pretrained("/path/to/tokenizer/folder/")
input_ids = tokenizer(input_str).input_ids
當兩種實現具有相同的 input_ids
時,新增一個分詞器測試檔案。此檔案與建模測試檔案類似。分詞器測試檔案應包含幾個硬編碼的整合測試。
實現影像處理器
快速影像處理器使用 torchvision 庫,可以在 GPU 上執行影像處理,顯著提高處理速度。我們建議除了“慢速”影像處理器(BaseImageProcessor)之外,還新增一個快速影像處理器(BaseImageProcessorFast),以向用戶提供最佳效能。歡迎標記 @yonigozlan 以獲取新增 BaseImageProcessorFast 的幫助。
雖然本示例不包含影像處理器,但如果你的模型需要影像輸入,你可能需要實現一個。影像處理器負責將影像轉換為適合你的模型的格式。在實現新處理器之前,請檢查 Transformers 庫中是否存在可重用的影像處理器,因為許多模型共享相似的影像處理技術。請注意,你也可以使用模組化來重用現有元件的影像處理器。
如果確實需要實現新的影像處理器,請參考現有影像處理器以瞭解預期的結構。慢速影像處理器(BaseImageProcessor)和快速影像處理器(BaseImageProcessorFast)的設計方式不同,因此請確保根據你正在實現的處理器型別遵循正確的結構。
執行以下命令(僅當你尚未透過 transformers add-new-model-like
命令建立快速影像處理器時)以生成必要的匯入併為快速影像處理器建立預填充模板。修改模板以適應你的模型。
transformers add-fast-image-processor --model-name your_model_name
此命令將生成必要的匯入並提供快速影像處理器的預填充模板。然後你可以對其進行修改以適應你的模型需求。
在 tests/models/your_model_name/test_image_processing_your_model_name.py
中新增影像處理器的測試。這些測試應類似於其他影像處理器的測試,並應驗證影像處理器是否正確處理影像輸入。如果你的影像處理器包含獨特的功能或處理方法,請確保也為其新增特定的測試。
實現處理器
如果你的模型接受多種模態,例如文字和影像,則需要新增一個處理器。處理器在將不同的模態傳遞給模型之前,集中處理它們的預處理。
處理器應在其 __call__
函式中呼叫適當的模態特定處理器,以正確處理每種型別的輸入。請務必檢查庫中現有的處理器,以瞭解其預期結構。Transformers 在 __call__
函式簽名中使用以下約定。
def __call__(
self,
images: ImageInput = None,
text: Union[TextInput, PreTokenizedInput, list[TextInput], list[PreTokenizedInput]] = None,
audio=None,
videos=None,
**kwargs: Unpack[YourModelProcessorKwargs],
) -> BatchFeature:
...
YourModelProcessorKwargs
是一個 TypedDict
,包含所有典型的處理引數和特定處理器可能需要的任何額外引數。
在 tests/models/your_model_name/test_processor_your_model_name.py
中新增處理器的測試。這些測試應類似於其他處理器的測試,並應驗證處理器是否正確處理不同的模態。
整合測試
現在你有了模型和分詞器,請將模型和分詞器的端到端整合測試新增到 tests/models/brand_new_llama/test_modeling_brand_new_llama.py
中。
測試應提供一個有意義的文字到文字示例,以展示模型按預期工作。例如,你可以包含一個源到目標翻譯對、一篇文章到摘要對,或一個問題到答案對。
如果檢查點尚未在下游任務上進行微調,則模型測試就足夠了。
最後,嘗試確保你的測試可以在 GPU 上執行,方法是將 .to(self.device)
語句新增到模型的內部張量中。如果你無法訪問 GPU,我們可以為你處理。
新增文件
你的模型只有在使用者知道如何使用時才有用。這就是為什麼新增文件和文件字串很重要的原因。Cookiecutter 添加了一個模板檔案 docs/source/model_doc/brand_new_llama.md
,你可以用它來填寫有關模型的資訊。
這通常是使用者與模型的第一次互動,因此文件應該清晰簡潔。新增模型使用示例通常非常有幫助。
確保將文件字串新增到 src/transformers/models/brand_new_llama/modeling_brand_new_llama.py
,幷包含所有必需的輸入和輸出。查閱我們的文件編寫和文件字串指南。
重構
是時候整理一下,確保程式碼風格與庫的其餘部分保持一致了。執行以下命令以自動修復不正確的風格。
make style
要驗證程式碼風格是否透過質量檢查,請執行以下命令。
make quality
由於 Transformers 嚴格的設計測試,你的拉取請求上可能還有其他失敗的測試或檢查(缺少文件字串或命名不正確)。如果你遇到困難,我們可以幫助你解決這些問題。
在確保程式碼執行正確後,你可能希望重構程式碼,使其更具可讀性或更簡潔。
上傳到 Hub
將所有檢查點轉換為並上傳到 Hub。新增模型卡片,以提供有關模型的更多透明度和上下文。模型卡片應突出檢查點的特定特徵、模型的訓練方式以及使用程式碼示例。
在許多情況下,新增一個使用者可以執行的互動式筆記本是展示如何使用模型進行推理或在下游任務上對其進行微調的好方法。雖然不是必需的,但包含筆記本可以促進模型更廣泛的採用。
您還應諮詢 Transformers 團隊,以確定模型的適當名稱,並獲取上傳模型所需的訪問許可權。
使用 push_to_hub() 方法上傳模型。
brand_new_bert.push_to_hub("brand_new_llama")
有關上傳模型到 Hub 的更多資訊,請參閱共享指南。
合併你的模型
你終於準備好合併你的拉取請求,並正式將模型新增到 Transformers 中了!確保所有測試都透過,並且所有評論和反饋都已解決。
恭喜你將新模型新增到 Transformers!🥳
這是一項非常重要的貢獻。你的工作使世界各地的開發者和研究人員更容易使用 Transformers。你應該為你的貢獻感到自豪,並與社群分享你的成就!
模型新增時間線
模型新增有四種時間線,具體取決於模型貢獻者和社群對架構的需求。
0 日整合:如果你計劃釋出 Transformers-first 版本,這是一個很好的選擇,因為我們可以確保文件清晰並儘可能最佳化你的模型(量化、FlashAttention、KV-cache 等)。我們還可以幫助你新增模型,提供早期審查並確保其按預期工作。
請提前幾天(最好是幾周)聯絡 transformers@huggingface.co,特別是如果架構特別新穎,以確保模型整合。我們將在 Transformers 的私人分支上合作,直到你的檢查點和釋出準備就緒。
同周整合:如果模型作者沒有主動聯絡,通常會在同一周內新增具有顯著請求/需求量的模型。
使用問題追蹤器請求新增特定模型。問題上的活動越多,我們整合的速度就越快,可能性也越大。
釋出後集成:對於沒有普遍需求或我們沒有足夠頻寬整合的模型,將在釋出後進行新增。
如果你有興趣向 Transformers 貢獻模型,這是一個好機會。檢視標有“新模型”的開放問題。隨意嘗試最受歡迎的模型,以增加你的貢獻影響力。我們將全程為你提供幫助!
Hub 優先發布:Transformers 遠端程式碼功能允許直接在 Hub 上共享基於 Transformers 的專案。如果你沒有足夠的精力直接將模型新增到 Transformers 中,這是一個不錯的選擇。
如果一個模型最終非常受歡迎,那麼我們很可能會自行將其整合到 Transformers 中,以便為其提供更好的支援(文件、維護、最佳化等)。Hub 優先發布是新增模型最無障礙的方式。