ONNX 版本控制¶
本文檔說明 ONNX 版本控制的規則。MUST、SHOULD 等用法均與 RFC2119 一致。
版本控制原則¶
ONNX 定義三類實體的版本控制原則和機制
中介表示法 (IR) 規格,即圖表和運算子的抽象模型,以及表示它們的具體格式。這些版本始終以原子方式控制,並稱為IR 版本。
給定 ONNX 圖表可能會參照的運算子規格。我們將其稱為運算子版本。
定義特定圖表(以特定運算子表示)的已定義/訓練模型。我們將其稱為模型版本。
這三種實體類型的版本控制是各自獨立的。IR 規格的演變速度與運算子規格不同(通常較慢)。模型版本完全獨立於其他兩個版本。
版本管理特定政策僅適用於 IR 版本和運算子版本。對於模型版本控制,這些僅僅是建議。對於模型版本控制,ONNX 使用者和系統可以遵循任何適用的當地慣例;但是,為方便輕鬆管理 ONNX 模型共享集合,它們應該遵循模型版本控制中描述的政策。
新的 IR 和運算子版本是作為 ONNX 版本發佈的一部分發行的,這些版本有自己的版本控制方案。版本發佈版本控制方案本身並未在標準中描述。這會在ONNX 版本發佈管理文件中討論。
語義版本控制或簡單數字?¶
ONNX 版本控制系統允許使用簡單的單調遞增數字或 語義版本控制 (SemVer)。對於 IR 和運算子集,版本控制基於簡單的數字。對於模型,ONNX 不要求任何方案,但建議使用一組共用慣例。
模型使用的版本控制方案可透過檢查最重要的四個位元組來釐清,使用語義版本控制時,這四個位元組必須為非零,而使用簡單數字時,必須為零。換句話說,使用 SemVer 時,MAJOR 或 MINOR 號碼中至少一個必須為非零。
SemVer、檔案和消費者¶
對於模型和版本發佈版本控制,ONNX 建基於 SemVer 2.0.0 定義的原則和語法。在本文檔中,我們使用重大變更、非重大變更和修補程式等詞彙,與 SemVer 2.0.0 一致。
由於 ONNX 模型是序列化檔案(而非 API),因此值得釐清序列化模型和使用該模型的軟體之間的關係。粗略而言,序列化模型扮演 API 被呼叫者的角色,而序列化模型的使用者則扮演 API 呼叫者的角色。
ONNX 版本控制原則基於穩健性原則:「對於自己執行的動作保持保守,對於從其他地方接受的事物保持寬容」。
給定 ONNX 模型的產生者(以及 ONNX 規格本身)必須嚴格遵守本規格中定義的重大變更與非重大變更規則。
給定 ONNX 模型的使用者在新的 ONNX 檔案的 IR 版本、參照的運算子版本或模型版本沒有重大變更的情況下(表示兩個 ONNX 檔案之間的 MAJOR 版本號碼沒有變更),應該使用更新的 ONNX 檔案。
如果新的 ONNX 檔案的 IR 版本、參照的運算子版本或模型版本存在一個或多個重大變更,給定 ONNX 模型的使用者可以使用更新的 ONNX 檔案。
在 protobuf 中序列化 SemVer 版本號碼¶
為提高效率,ONNX 將 MAJOR、MINOR 和 PATCH 值序列化為位元組壓縮的 64 位元整數;兩個最重要的位元組是 MAJOR 元件、下兩個最重要的位元組是 MINOR 元件,而最不重要的四個位元組是 PATCH 元件。
例如,1.2.345 表示為 0x0001000200000159。
預發佈和組建中繼資料並未儲存在模型中。
IR 版本控制¶
IR 格式使用簡單的數字進行版本控制,這些數字必須單調遞增。對 ONNX 規格的格式或語義進行重大變更時,需要增加版本。對 IR 格式進行非重大變更時,不需要變更版本號碼。
注意:重大變更包括那些不會變更序列化二進位格式,但仍然會中斷使用寫入或讀取該格式的程式庫的軟體。例如,變更訊息屬性的拼寫會導致存取該屬性的程式碼中斷。
IR 格式遵循 proto3 規格的更新訊息類型部分中定義的版本控制準則。
作為一般原則,實作應該在面對遺失的欄位時保持穩健性。但是,為確保基本互通性,訊息欄位的子集會標示為給定 IR 版本的要求,且所有產生者必須正確設定這些欄位。必要欄位必須始終標示註解
// This field MUST be present for this version of the IR.
例如,每個模型中都必須存在 ModelProto.ir_version
屬性。ONNX 檢查器 (onnx/checker.py
) 會強制執行這些規則。
由於預期獨立開發人員會使用協定緩衝訊息定義 (.proto / .proto3 檔案),因此對這些定義的變更不應該中斷依賴產生語言繫結的程式碼(例如,變更現有欄位的類型)。
運算子版本控制¶
IR 可以獨立於運算符集合發展。運算符代表給定操作的簽名和語義。運算符是抽象介面,因為它們不暗示特定的實作;相反地,它們只是模型作者與模型可能在其上執行的實作之間的合約。
給定的運算符由一個三元組識別:(domain, op_type, since_version)
,在文章中寫成 domain.op_type:since_version
(例如,com.acme.FastConv:3
)。since_version
是引入該運算符的運算符集合的版本。破壞性運算符變更包括
新增/移除/重新命名屬性。這甚至包括新增一個新的可選屬性的情況,其中省略該屬性將暗示一個預設值,產生與先前運算符版本相同的語義。
新增/移除/重新排序輸入或輸出。
新增/移除輸入和輸出所支援的類型,以及變更屬性所使用的類型。
支援新的行為,即使現有的參數簽名在其他方面相同 (例如,隱含地在 Mean 運算符中支援張量廣播)。
以下是不破壞性的
釐清規格中的模糊之處,以符合現行的實作慣例。
運算符或函數語義的變更必須在新運算符中引入,而該運算符必須在新的運算符集合中引入。
在實務上,這表示 ONNX 儲存庫中的 BC 破壞性變更需要貢獻者遵循以下步驟
增加
DomainToVersionRange
中的最大版本。將舊的運算符模式複製到
old.cc
檔案。將
SinceVersion
標示符更新為步驟 (1) 中的新最大版本。在相應的
operator_sets
標頭檔中註冊新的運算符。在
convert.h
中新增版本轉接器,以便版本轉換器可以將舊版本的運算符升級到新的版本。如果遵循舊模式的運算符在新模式下仍然有效 (通常是這種情況),則可以使用CompatibleAdapter
。也可以在
convert.h
中新增一個將新運算符降級到舊版本的版本轉接器,但這不是強制性的。
節點如何繫結到運算符宣告是嚴格定義的,並且旨在根據穩健性原則的保守條款,提高 ONNX 實作之間的模型相容性。
ONNX 實作如何將運算符宣告繫結到特定的實作,不在本規格的範圍內。根據穩健性原則的自由條款,ONNX 的實作可以選擇引入更複雜的運算符宣告/實作繫結模式。
運算符集合¶
ONNX 使用運算符集合將不可變的運算符規格分組在一起。運算符集合代表一個特定版本的域,由一對 (domain, version) 表示。這代表屬於指定域和指定版本的所有運算符集合 (稱為 opset_version
)。當給定運算符集合的庫存透過新增、移除或變更所包含運算符的語義而變更時,其版本必須增加。
模型在其 ModelProto.opset_import
中以 (domain, opset_version)
配對的清單宣告它們所需的運算符集合。空字串 (「」) 域表示定義為 ONNX 規格一部分的運算符;其他域對應於其他供應商的運算符集合 (表示它們可以用於提供特定於供應商的 ONNX 擴充功能)。給定模型指定的運算符集合的聯集必須為模型圖中的每個節點提供相容的運算符宣告。
範例¶
本節不具規範性,僅供參考。
假設有以下運算符集合
OpSet |
運算符 |
註解 |
---|---|---|
1 |
{A} |
引入 A |
2 |
{A, B} |
引入 B |
3 |
{A’, B, C} |
更新 A (至 A’),引入 C |
4 |
{B, C’} |
移除 A,更新 C (至 C’) |
給定運算符集合的運算符將具有以下 since_version
值
運算符 |
OpSet 1 |
OpSet 2 |
OpSet 3 |
OpSet 4 |
---|---|---|---|---|
A |
1 |
1 |
3 |
- |
B |
- |
2 |
2 |
2 |
C |
- |
- |
3 |
4 |
註解
從先前的 OpSet 版本新增或更新的值以 粗體 顯示。
模型版本控制¶
本規格的這一節不具規範性。它僅概述一組建議的做法。
模型作者和應用程式/系統可以選擇忽略模型版本控制機制和原則規則。對於將在開發人員、團隊或組織之間共用的模型,模型作者和應用程式/系統應該遵守以下版本原則
簽名變更¶
對 ModelProto.graph.GraphProto.input 或 .output 的破壞性變更必須增加
ModelProto.model_version
的 MAJOR 版本。破壞性變更包括對輸入或輸出的語義進行破壞性變更 (例如,將輸入張量的必要內容從彩色影像變更為黑白影像)。
將輸入或輸出的宣告類型變更為不相容的類型 (例如,
tensor(int)->tensor(string)
)。新增一個沒有有意義或指定預設值的新輸入。回想一下,輸入的預設值在初始化程式清單中指定。
移除一個沒有有意義或指定預設值的現有輸出。
對 ModelProto.graph.GraphProto.input 或 .output 的非破壞性變更必須增加
ModelProto.model_version
的 MINOR 版本。非破壞性變更包括將輸入或輸出的宣告類型變更為相容/擴充的類型 (例如,
tensor(int32)->tensor(int64)
、tensor(float16)->tensor(float32)
)。新增一個有有意義或指定預設值的新輸入。
新增僅在圖形先前版本中不可能的輸入存在時才會觸發的新行為 (通常是透過新增輸入或允許先前無效的輸入值)。
準確性或效能變更¶
顯著影響準確性或效能,但不變更模型輸入或輸出的變更,應該增加 ModelProto.model_version
的 PATCH 版本。
發佈的版本¶
ONNX 版本 |
IR 版本 |
Opset 版本 ai.onnx |
Opset 版本 ai.onnx.ml |
Opset 版本 ai.onnx.training |
---|---|---|---|---|
1.0 |
3 |
1 |
1 |
- |
1.1 |
3 |
5 |
1 |
- |
1.1.2 |
3 |
6 |
1 |
- |
1.2 |
3 |
7 |
1 |
- |
1.3 |
3 |
8 |
1 |
- |
1.4.1 |
4 |
9 |
1 |
- |
1.5.0 |
5 |
10 |
1 |
- |
1.6.0 |
6 |
11 |
2 |
- |
1.7.0 |
7 |
12 |
2 |
1 |
1.8.0 |
7 |
13 |
2 |
1 |
1.8.1 |
7 |
13 |
2 |
1 |
1.9.0 |
7 |
14 |
2 |
1 |
1.10.0 |
8 |
15 |
2 |
1 |
1.10.1 |
8 |
15 |
2 |
1 |
1.10.2 |
8 |
15 |
2 |
1 |
1.11.0 |
8 |
16 |
3 |
1 |
1.12.0 |
8 |
17 |
3 |
1 |
1.13.0 |
8 |
18 |
3 |
1 |
1.13.1 |
8 |
18 |
3 |
1 |
1.14.0 |
9 |
19 |
3 |
1 |
1.14.1 |
9 |
19 |
3 |
1 |
1.15.0 |
9 |
20 |
4 |
1 |
1.16.0 |
10 |
21 |
5 |
1 |
1.17.0 |
10 |
22 |
5 |
1 |
上表的程式化存取版本可在這裡取得。有限的版本號碼資訊也維護在 version.h 和 schema.h 中。請在發佈新版本的 ONNX 時更新所有這些。