在 ONNX 中新增運算子或函式¶
或將現有運算子更新至新的 Opset 版本。
目錄¶
在 ONNX 中提議及提交新的運算子或函式¶
運算子是用來定義 ONNX 模型的基本建構區塊。透過豐富的運算子集,ONNX 可以描述來自各種框架的大部分 DNN 和 ML 模型。函式可以利用更基本運算子表達複雜的運算子。ONNX 規格包含一組可啟用許多模型的核心運算子。新增所有可能的運算子並非目標,但是會視需要新增更多運算子,以涵蓋不斷發展的需求。
在這份文件中,我們說明接受新提議運算子的流程,以及如何正確提交新的運算子做為 ONNX 標準的一部分。目標是根據我們從社群收集的經驗、學習和意見反應來改進我們目前所擁有的。
新增運算子的 4 個步驟¶
決定要提議的項目
為新的運算子/函式提交 PR
由運算子 SIG 審查 PR
合併 PR 並納入下一個 ONNX 版本
步驟 1:提議新的運算子/函式¶
為了提議新的運算子/函式,需要以下項目
如果運算子可以用其他 ONNX 運算子表示,則應為函式而非運算子 (我們在 ONNX 中有一個函式:MeanVarianceNormalization)。
如果運算子可以拆分為新的基本運算,則應提議這些基本運算,並將運算子做為函式。
根據模型。這會幫助我們了解其用途,以及其是否可以解決實際問題。如果模型是私有或 IP 且無法共用,則運算子不屬於標準,應實作為自訂 OP。
運算子必須至少由一個 (知名的) 框架實作。這有助於我們了解運算子的實際行為及其用法。
運算子簽章和行為
如果運算子在 numpy 中可用,請優先使用 numpy 語意。
如果運算子在多個框架中可用,請確保您的設計是通用的,並且涵蓋這些框架。
優先使用屬性而非輸入。
運算子不應比使用案例所需更複雜。然而,運算子應盡可能通用,只要不會使實作更複雜。這需要仔細平衡通用性和複雜性。例如,對於某些運算子來說,從 3 維張量泛化到 N 維張量是簡單的 (就實作而言),但對於其他運算子來說則很複雜。在這種情況下,將根據這種泛化的複雜性來做出選擇。
步驟 2:提交 PR¶
一旦滿足提議新的運算子/函式的條件,您就需要為新的運算子/函式提交 PR。以下是 PR 應包含的內容的預期。審查者應在簽核前驗證 PR 的完整性。
描述
撰寫關於運算子及其預期行為的詳細描述。幾乎描述應清楚到足以避免實作者之間的混淆。
在描述中新增範例,以說明用法。
在描述中新增對應框架中運算子來源的參考 (如果可能的話)。
在描述中撰寫數學公式或虛擬碼。核心演算法需要非常清楚。
以 Python 撰寫參考實作,此參考實作應涵蓋運算子的所有預期行為。只有在極其罕見的情況下,我們才會免除此要求。
運算子版本:請參閱我們的 版本控制文件
撰寫涵蓋主要用法和邊緣案例的單元測試。
測試範例將會擷取至文件中。
我們也會為其產生二進位資料。
撰寫升級和降級測試
請在 onnx/test/automatic_upgrade_test.py 中使用
_test_op_upgrade
為您的運算子新增至少一個自動升級測試。這些測試會在指定的 opset 版本 (通常是運算子引入的版本) 建立給定的運算子,並測試版本轉換器是否能夠將其轉換為最高可用版本。因此,對於新的運算子_test_op_upgrade
不會測試任何內容,但是一旦運算子在未來的 opset 中更新,測試將會自動變得不簡單。同樣地,請在 onnx/test/automatic_downgrade_test.py 中使用
_test_op_downgrade
為您的運算子新增至少一個自動降級測試。指定目前的版本,以便在運算子於較高的 opset 版本更新後,測試會確保向下轉換已驗證。
更新文件並產生測試資料。
執行 指令碼。如果您的檔案位於
onnx/backend/test/data/node
下,且無法由onnx/backend/test/case/node
中的指令碼產生,請進一步使用python onnx/backend/test/cmd_tools.py generate-data --clean
來清除目錄並僅保留所需的測試資料。以更新文件並產生測試資料。
形狀推斷函式
如果形狀推斷有意義且適用,請提供形狀推斷函式。
如果無法進行形狀推斷,則至少必須具有執行等級推斷的邏輯 (在輸出形狀中新增正確的維度數量)
形狀推斷函式必須隨附單元測試 (onnx/test/shape_inference_test.py)。
在實作您自己的函式時,您可以參考
TopK
運算子的形狀推斷函式(onnx/defs/math/defs.cc)。
範例參考¶
PR 1959 是一個很好的參考範例。
步驟 3:由運算子 SIG 進行 PR 審查¶
運算子 SIG 負責 ONNX 規格中的運算子/函式。SIG 會定期舉行會議並審查 PR。
簽核¶
至少需要兩位運算子 SIG 貢獻者的簽核。
步驟 4:ONNX 發佈¶
一旦 PR 通過審查並獲得運算子 SIG 的簽核,它將會被合併。您新的運算子/函式將會成為主分支的一部分,並可供任何從原始碼建置的人使用。這些並非正式發佈版本。ONNX 會定期發佈正式的新版本,這些版本是主分支的快照。您新的運算子/函式將會包含在該發佈版本中。
更新現有運算子¶
當需要支援新的情境或輸入類型時,可能需要更新現有運算子的定義。此過程與建立新運算子的過程大致相似。
檢查清單¶
更新現有運算子時,請使用此檢查清單:https://github.com/onnx/onnx/wiki/Checklist-for-updating-an-existing-operator
移除運算子或函式¶
移除現有 ONNX 運算子或函式的原因有很多,例如被不同的運算子取代,或者可以由一組其他運算子分解。本文檔描述從標準中移除現有 ONNX 運算子的標準。
移除運算子¶
ONNX 中的任何運算子都是因為模型和/或框架需要而添加的。為了棄用這樣的運算子,我們需要執行以下操作。
除非有替代方案,否則運算子不能被棄用。
替代方案可以是取代舊運算子的更通用的運算子。
或者是一組原始運算子,它們共同可以實現已棄用運算子(函式)的相同功能和行為。
如果已棄用的運算子可以由現有運算子分解,則必須將其轉換為函式。
如果替代方案尚未在 ONNX 標準中,則先添加替代運算子或一組運算子。
新增一個版本轉換器,將運算子轉換為版本轉換器的替代方案。範例:onnx/version_converter/adapters/upsample_9_10.h
棄用的運算子不需要寬限期。
移除函式¶
根據定義,函式是由 ONNX 原始運算組成;但是,函式可能會被支援 ONNX 的框架或執行時加速。因此,不建議移除函式,除非添加另一個取代其功能的單一函式。
記錄移除運算子或函式¶
為了確保每個人都了解棄用,需要執行以下操作
從 ONNX 中移除的任何運算子或函式都需要在發佈說明中提及。
它們的舊文件需要更新,以顯示新的替代方案以及從舊到新的對應關係。
只需要移除
def.cc
,old.cc
將保留。old.cc
需要更新為與替代方案的對應關係。
需要更新 ONNX 檢查器,以產生帶有適當訊息的錯誤。
所有移除的運算子都需要附加在
operator.md
檔案的末尾。