開放神經網路交換中繼表示法 (ONNX IR) 規格¶
目的
此文件包含 ONNX 語意的規範性規格。
在 onnx 資料夾 下找到的 .proto
和 .proto3
檔案,以 Protocol Buffers 定義語言撰寫的語法規範性規格。 .proto
和 .proto3
檔案中的註解旨在提高這些檔案的可讀性,但如果與本文件衝突,則不具規範性。此類衝突應回報為文件錯誤。
關於模型驗證的注意事項
有一個 工具 可用於執行模型針對此規格的一般驗證。它以 C++ 實作,並帶有 Python 命令列包裝器。
關於本文件和所有相關文件中使用的語言的注意事項:
在本文件中使用 SHOULD、MUST、MAY 等詞彙與 RFC 2119 一致。
使用「list」應表示項目之排序的集合,「set」應表示唯一元素的非排序集合,而「bag」則表示可能包含非唯一元素的非排序集合。
元件¶
ONNX 是一個開放規格,由以下元件組成
可擴展計算圖模型的定義。
標準資料類型的定義。
內建運算符的定義。
#1 和 #2 一起構成 ONNX 中繼表示法,或稱為「IR」規格,本文將涵蓋該規格;內建運算符涵蓋在末尾列出的文件中。具體來說,內建運算符分為一組原始運算符和函式。函式是一種運算符,其語意透過使用其他運算符 (和函式) 擴展到子圖 (稱為函式主體) 中正式表示。在功能方面,如果 ONNX 相容的框架或執行階段沒有函式對應的實作,則可以內嵌函式主體來執行函式。
有兩個官方 ONNX 變體;兩者之間的主要區別在於預設運算符集。ONNX-ML 使用非基於神經網路的 ML 演算法擴展 ONNX 運算符集。
在 IR 版本 6 之前,ONNX 規格和模型格式僅處理推論 (也稱為評分)。從 IR 版本 7 開始,ONNX 規格和模型格式也支援訓練。ONNX 訓練模型是推論模型的擴展。僅限推論的執行階段可以取用訓練模型,並忽略與訓練相關的擴展。但是,與訓練模型相比,僅限推論的模型可以啟用更適合推論目的的表示法。
與執行階段無關¶
ONNX 不預先假設或暗示任何特定的執行階段實作方法。
例如,實作可能包含解釋模型的豐富執行階段;它可能是將模型整體轉換為用於某些目標程式語言的可執行程式碼的程式碼產生器;它可能是硬體實作;它可能是其中兩三者的組合。
本規格中的任何內容都不應被解釋為提倡任何實作方法優於其他方法;關於具體實作內部運作的任何評論都應被解釋為範例。
ONNX 版本控制¶
IR 規格、個別模型和運算符集都具有版本控制。此外,每個個別運算符都會指出它是在其包含的運算符集的哪個版本中引入或穩定化的。
版本號碼可以用作簡單數字,也可以用來編碼語意版本 (又名 SemVer)。如果使用語意版本,則慣例是使用最高有效位元組中的兩個位元組表示主要數字,使用下兩個位元組表示次要數字,以及使用最低有效位元組中的四個位元組表示修補/組建/錯誤修正數字。當使用語意版本控制時,主要/次要數字中至少必須有一個是非零數字。
IR 規格使用簡單的單調遞增數字作為其版本。onnx.proto 中 onnx.Version
列舉定義了有效的 IR 版本。
運算符集使用簡單的版本號碼。每個運算符集版本都表示運算符集合的快照,以及它們在特定時間點的語意。
本規格未提供有關模型產生器應使用何種版本控制方案的指導。
關於 IR、運算符集和模型的版本控制慣例和最佳實務的更多詳細資訊,請參閱版本控制。
可擴展計算圖模型¶
ONNX 指定計算圖的可移植序列化格式。它不必是框架選擇在內部使用的形式。例如,如果實作在最佳化過程中進行操作更有效,則可能會以不同的方式在記憶體中表示模型。
實作可以透過新增表達超出所有實作都必須支援的標準運算符集合的語意的運算符來擴展 ONNX。此機制是在模型中依賴擴展運算符的 opset_import
屬性中新增運算符集。
模型¶
頂層的 ONNX 結構是一個「模型 (Model)」,在協定緩衝區中以 onnx.ModelProto
類型表示。
模型結構的主要目的是將元數據與包含所有可執行元素的圖形關聯起來。元數據在首次讀取模型檔案時使用,為實作提供所需資訊,以判斷是否能夠執行模型、產生日誌訊息、錯誤報告等。此外,元數據對於 IDE 和模型庫等工具也很有用,這些工具需要元數據來讓人們了解給定模型的用途和特性。
每個模型都有以下組件
名稱 (Name) |
類型 (Type) |
描述 (Description) |
---|---|---|
ir_version |
int64 |
模型假設的 ONNX 版本。 |
opset_import |
OperatorSetId |
模型可用的運算符集識別符集合。實作必須支援集合中的所有運算符,否則拒絕模型。 |
producer_name |
string |
用於產生模型的工具名稱。 |
producer_version |
string |
產生工具的版本。 |
domain |
string |
反向 DNS 名稱,用於指示模型命名空間或域,例如「org.onnx」。 |
model_version |
int64 |
模型本身的版本,以整數編碼。 |
doc_string |
string |
此模型的人類可讀文檔。允許使用 Markdown。 |
graph |
Graph |
評估以執行模型之參數化的圖形。 |
metadata_props |
map<string,string> |
具名元數據值;鍵應不同。 |
training_info |
TrainingInfoProto[] |
一個包含訓練資訊的可選擴展。 |
functions |
FunctionProto[] |
模型本地函數的可選列表。 |
模型必須指定一個域,並根據負責組織的身分使用反向域名,這與 命名 Java 套件 使用的約定相同。
注意:探索 ONNX 檔案
您可以使用 Protocol Buffers 發行版中包含的 protoc
工具來檢查 ONNX 檔案的內容,您可以這樣做:
$ protoc --decode=onnx.ModelProto onnx.proto < yourfile.onnx
其中 onnx.proto 是此儲存庫中的檔案。
或者,您可以使用像 Netron 這樣的工具來探索 ONNX 檔案。
模型語意¶
推論模型的語意是一個*無狀態函數*(可能用於隨機數產生所使用的狀態除外)。因此,每當使用推論模型(沒有隨機產生器操作)對相同輸入執行推論時,預期會產生相同的輸出。
訓練模型的語意是*有狀態物件*,其狀態由訓練權重的當前值(以及所需的任何其他輔助狀態,例如學習演算法使用的動量)組成。具體來說,它的語意透過三種方法捕獲:初始化方法(用於初始化或重置狀態變數的值)、訓練步驟方法(用於使用批次的輸入輸出對進行訓練)和推論方法(用於使用學習權重的當前值執行推論)。前兩種方法更新物件的狀態,而第三種方法是無副作用的。
可選元數據¶
模型中的「metadata_props」欄位可用於工具或模型開發人員選擇放置的任何種類的可選元數據。以下是已定義的模型的「標準」可選元數據屬性。
名稱 (Name) |
類型 (Type) |
格式 (Format) |
描述 (Description) |
---|---|---|---|
model_author |
string |
以逗號分隔的名稱列表。 |
模型的作者的個人姓名,以及/或是他們的組織。 |
model_license |
string |
名稱或 URL。 |
模型可用的許可證的知名名稱或 URL。 |
運算符集識別符¶
每個運算符集都由(域,版本)對唯一識別。
名稱 (Name) |
類型 (Type) |
描述 (Description) |
---|---|---|
domain |
string |
正在識別的運算符集的域。 |
version |
int64 |
正在識別的運算符集的版本。與運算符集中的「opset_version」相同。 |
運算符集版本是一個簡單的整數值,隨著新版本的運算符集發布而單調遞增。
預設運算符集以外的運算符集必須指定域,並且應根據負責組織的身分使用反向域名,這與 命名 Java 套件 使用的約定相同。
運算符集¶
每個模型都必須明確命名其功能所依賴的運算符集。運算符集定義了可用的運算符及其版本。每個模型都會通過它們的域來定義導入的運算符集。所有模型都隱式導入預設的 ONNX 運算符集。
每個運算符集應在單獨的文件中定義,也使用 protobuf 作為序列化格式。如何在執行時找到運算符集文件是與實作相關的。
注意:截至本文件發布之日,已知沒有 ONNX 實作會處理運算符集文件。
運算符集的屬性為
名稱 (Name) |
類型 (Type) |
描述 (Description) |
---|---|---|
magic |
string |
值為「ONNXOPSET」 |
ir_version |
int32 |
與運算符對應的 ONNX 版本。 |
ir_version_prerelease |
string |
IR 的 SemVer 的預發布元件。 |
ir_build_metadata |
string |
此版本的運算符集的建置元數據。 |
domain |
string |
運算符集的域。在所有集合中必須唯一。 |
opset_version |
int64 |
運算符集的版本。 |
doc_string |
string |
此運算符集的人類可讀文檔。允許使用 Markdown。 |
operator |
Operator[] |
此運算符集中包含的運算符。 |
運算符集版本是一個簡單的整數值,隨著新版本的運算符集發布而單調遞增。
預設運算符集以外的運算符集必須指定域,並且應根據負責組織的身分使用反向域名,這與 命名 Java 套件 使用的約定相同。
運算符¶
圖形中使用的每個運算符都必須由模型導入的運算符集之一明確聲明。
運算符定義的屬性為
名稱 (Name) |
類型 (Type) |
描述 (Description) |
---|---|---|
op_type |
string |
運算符的名稱(區分大小寫),如圖形節點中所使用。在運算符集的域中必須唯一。 |
since_version |
int64 |
首次引入此運算符時的運算符集版本。 |
status |
OperatorStatus |
「EXPERIMENTAL」或「STABLE」之一。 |
doc_string |
string |
此運算符的人類可讀文檔字串。允許使用 Markdown。 |
版本值必須與首次發布運算符時的運算符集版本的值相同。一旦發布為 STABLE,後續版本的運算符集不得更改運算符的簽名或語意。
「status」屬性指示運算符的語法、語意或存在是否處於實驗性或穩定階段。一旦運算符發布為 STABLE,其語法和語意在後續版本的運算符集中不得更改。
有兩種不同的方式將資訊傳遞給運算符 — 輸入和屬性。輸入表示圖形輸入或在圖形其他位置計算的值,而屬性用於圖形中為常數的值。這種區別可能對於某些實作實現良好的效能至關重要,而對於其他實作則完全不相關。
函數¶
一個*函數*可以被認為是一個運算符與使用其他更基本的操作 (op) 實現的運算符的組合,這些操作稱為*函數體*。函數體由形成圖形的拓撲排序節點列表組成。因此,函數結合了運算符和圖形(如下所述)的各個方面。
模型中包含的每個函數(也稱為模型本地函數)都作為相應運算符的預設或回退實作。但是,執行時可以選擇使用運算符的替代實作(通常作為最佳化的核心)。因此,函數的唯一名稱很重要,因為它隱式地與語意規範相關聯。
序列化的函數 (FunctionProto) 具有以下屬性
名稱 (Name) |
類型 (Type) |
描述 (Description) |
---|---|---|
name |
string |
函數的名稱 |
domain |
string |
此函數所屬的域 |
overload |
string |
函數唯一 ID 的一部分(在 IR 版本 10 中添加) |
doc_string |
string |
此函數的人類可讀文檔。允許使用 Markdown。 |
attribute |
string[] |
函數的屬性參數 |
attribute_proto |
Attribute[] |
(IR 版本 9+)具有函數預設值的屬性參數。函數屬性應表示為字串屬性或 Attribute,兩者不能同時表示。 |
input |
string[] |
函數的輸入參數 |
output |
string[] |
函數的輸出參數。 |
node |
Node[] |
形成部分排序計算圖的節點列表。它必須按拓撲順序排列。 |
opset_import |
OperatorSetId |
函數實作所使用的運算符集識別符集合。 |
value_info |
ValueInfo[] |
(IR 版本 >= 10)用於儲存函數中使用值的類型和形狀資訊。 |
metadata_props |
map<string,string> |
(IR 版本 >= 10)具名元數據值;鍵應不同。 |
在 IR 版本 9 及更早版本中,名稱和域用於唯一標識運算符。IR 版本 10 添加了欄位 overload,並且三元組 (name, domain, overload) 充當儲存在模型中的函數的唯一 ID。這是為了支援在模型中對函數的不同呼叫需要不同函數體的情況。opset 版本在 FunctionProto 中沒有明確標識,而是由模型中包含的域的 opset 版本隱式確定。
輸入(input)、輸出(output)、屬性(attribute)以及屬性原型(attribute_proto,在 IR 版本 9 中新增)構成了運算子的簽名部分。簽名中沒有明確包含類型資訊。attribute_proto 欄位描述了函數的屬性參數及其預設值(當調用站點節點未指定時),而 attribute 欄位列出了沒有預設值的屬性參數。這兩個列表中的名稱必須不同。當函數的屬性參數在函數內的節點中使用時,如果該屬性有指定,則會被調用站點節點(函數的)針對該屬性指定的實際參數值所取代;如果該屬性有指定預設值,則會被預設值取代;否則會被省略。
opset_import 和 node 欄位描述了函數的實作。
value_info 欄位(在 IR 版本 10 中新增)允許模型儲存函數中使用值的類型和形狀資訊,包括其輸入和輸出。請注意,這是可選的,且 ONNX 允許函數具有多型性。
圖 (Graphs)¶
圖被用來描述無副作用的計算(函數)。序列化的圖由一組中繼資料欄位、一個模型參數列表和一個計算節點列表組成。
每個計算資料流圖都構建為節點的拓撲排序列表,這些節點形成一個圖,該圖必須沒有迴圈。每個節點代表對運算子或模型本地函數的調用。每個節點有零個或多個輸入以及一個或多個輸出。
圖具有以下屬性:
名稱 (Name) |
類型 (Type) |
描述 (Description) |
---|---|---|
name |
string |
模型圖的名稱。 |
node |
Node[] |
一個節點列表,根據輸入/輸出資料相依性形成一個部分排序的計算圖。它是拓撲排序的。 |
initializer (初始化器) |
Tensor[] |
一個具名張量值的列表。當初始化器的名稱與圖的輸入名稱相同時,它會指定該輸入的預設值。當初始化器的名稱與所有圖的輸入名稱不同時,它會指定一個常數值。列表的順序未指定。 |
doc_string |
string |
此模型的人類可讀文檔。允許使用 Markdown。 |
input |
ValueInfo[] |
圖的輸入參數,可能會由「初始化器」中的預設值初始化。 |
output |
ValueInfo[] |
圖的輸出參數。一旦圖的執行已寫入所有輸出參數,執行即完成。 |
value_info |
ValueInfo[] |
用於儲存非輸入或輸出的值的類型和形狀資訊。 |
metadata_props |
map<string,string> |
(IR 版本 >= 10)具名元數據值;鍵應不同。 |
ValueInfo 具有以下屬性:
名稱 (Name) |
類型 (Type) |
描述 (Description) |
---|---|---|
name |
string |
值/參數的名稱。 |
type (類型) |
類型 (Type) |
值的類型,包括形狀資訊。 |
doc_string |
string |
此值的人工可讀文件。允許使用 Markdown。 |
每個主(頂級)圖都必須定義其輸入和輸出的名稱、類型和形狀,這些資訊會指定為「值資訊」結構。主圖的輸入和輸出都需要具有形狀,表明其秩,即使不需要指定確切的維度。
巢狀子圖(指定為屬性值)必須定義其輸入和輸出的名稱,並且可以定義其輸入和輸出的類型。
每個圖都必須指定一個名稱。
對於所有節點輸出,圖必須遵守單一靜態賦值(SSA);這表示所有節點輸出名稱在一個圖中必須是唯一的。
圖應填入文件字串,這些字串可以使用 GitHub 風格的 Markdown 語法進行解讀。HTML 和其他文字標記語言不得在文件字串中使用。
圖中的名稱 (Names Within a Graph)¶
所有名稱都必須遵守 C90 識別符號語法規則。
節點、輸入、輸出、初始化器和屬性的名稱會組織到多個命名空間中。在一個命名空間中,每個名稱對於每個給定的圖必須是唯一的。如果圖包含巢狀子圖(作為屬性值),請參閱下文以獲得進一步的說明。
命名空間為:
命名空間 (Namespace) |
描述 (Description) |
---|---|
屬性 (Attribute) |
運算子的屬性名稱。對於每個運算子都是唯一的。 |
值 (Value) |
值的名稱 – 節點輸入和輸出、張量值(如果已命名)、圖輸入、輸出。 |
節點 (Node) |
圖節點的名稱。 |
Graph |
域中圖的名稱,在模型域中是唯一的。 |
運算子 (Operator) |
域中運算子的名稱。 |
Shape |
張量形狀變數的名稱 – 作用域限定為圖的值資訊記錄,這是形狀變數出現的地方。 |
節點 (Nodes)¶
計算節點由名稱、它調用的運算子的名稱、一個具名輸入列表、一個具名輸出列表和一個屬性列表組成。
輸入和輸出與運算子的輸入和輸出按位置關聯。屬性按名稱與運算子屬性關聯。
它們具有以下屬性:
名稱 (Name) |
類型 (Type) |
描述 (Description) |
---|---|---|
name |
string |
節點的可選名稱,僅用於診斷目的。 |
input |
string[] |
節點用來將輸入值傳播到節點運算子的值的名稱。它必須參考圖的輸入、圖的初始化器或節點的輸出。 |
output |
string[] |
節點用來從節點調用的運算子擷取資料的輸出的名稱。它會在圖中引入一個值,或參考圖的輸出。 |
op_type |
string |
要調用的運算子的符號識別符號。 |
domain |
string |
包含由 op_type 命名的運算子的運算子集合的域。 |
attribute |
Attribute[] |
具名屬性,另一種形式的運算子參數化,用於常數值,而不是傳播的值。 |
doc_string |
string |
此值的人工可讀文件。允許使用 Markdown。 |
overload |
string |
函數唯一 ID 的一部分(在 IR 版本 10 中添加) |
metadata_props |
map<string,string> |
(IR 版本 >= 10)具名元數據值;鍵應不同。 |
屬於值命名空間的名稱可能會出現在多個地方,即作為圖的輸入、圖的初始化器、圖的輸出、節點的輸入或節點的輸出。名稱作為圖的輸入、圖的初始化器或節點的輸出的出現被稱為定義,而名稱作為節點的輸入或圖的輸出的出現被稱為使用。
在一個圖中使用的值名稱必須具有唯一的定義,但相同的名稱可能同時出現在圖輸入列表和圖初始化器列表中(在存在巢狀子圖的情況下,會有進一步的例外,如下所述)。
當一個名稱同時出現在初始化器列表和圖輸入列表中時,執行階段可能允許調用者為此(輸入)名稱指定一個值,以覆寫初始化器中指定的值,並且執行階段可能允許使用者省略為此(輸入)名稱指定值,而選擇初始化器中指定的值。不打算被調用者覆寫的常數名稱,應僅出現在初始化器列表中,而不應出現在圖輸入列表中。在 IR 版本 >= 4 的模型中,在作為屬性值使用的巢狀子圖中,除非對應的運算子規格明確允許,否則使用者不得使用與子圖初始化器和子圖輸入相同的名稱。在 IR 版本 <= 3 的模型中,使用者可以使用與子圖初始化器和子圖輸入相同的名稱,但這僅限於通過初始化器支援常數,這些常數不打算對應於從節點傳遞到子圖的任何實際輸入。特別是,控制流程運算子語義會決定提供給子圖執行的輸入集合,並且這些輸入名稱不得作為子圖初始化器出現。子圖初始化器名稱必須出現在圖輸入列表中,在實際輸入之後。這樣可以讓實際輸入和形式輸入按位置匹配。
計算圖中的邊緣是通過一個節點的輸出,在後續節點的輸入中按名稱被引用來建立的。
給定節點的輸出會將新的名稱引入到圖中。節點輸出的值由節點的運算子計算。節點輸入可以參考節點輸出、圖輸入和圖初始化器。當節點輸出的名稱與圖輸出的名稱一致時,圖輸出的值是該節點計算的相應輸出值。巢狀子圖中的節點輸入可以參考在外部圖中引入的名稱(作為節點輸出、圖輸入或圖初始化器)。
對於所有節點輸出,圖必須使用單一靜態賦值,這表示所有節點輸出名稱在一個圖中必須是唯一的。在巢狀子圖的情況下,節點輸出名稱必須與巢狀子圖中可見的外部作用域中的名稱不同。
節點相依性不得在計算圖中建立迴圈。
節點中輸入和輸出的數量、它們的類型、節點中指定的屬性集合及其類型,必須滿足節點運算子的簽名所施加的約束。
定義頂級計算圖的節點列表必須以拓撲方式排序;也就是說,如果節點 K 在圖中跟隨節點 N,則 N 的任何資料輸入都不能參考 K 的輸出。
節點屬性用於將字面(靜態)值傳遞給運算子。
輸入和輸出值 (Input and Output Values)¶
該表示法區分了兩種值:屬性值(靜態已知)和輸入/輸出值。這兩種情況中允許的值類型不同。
輸入和輸出值會以圖輸入、輸出和初始化器的形式,以及節點輸入和輸出的形式出現。它們的值是在執行階段確定的,由啟動模型執行的程式碼確定,或由計算輸出值的運算子確定。
屬性 (Attributes)¶
屬性值僅在節點中找到,通過名稱關聯傳遞給運算子。屬性值是執行階段常數,因為它們的值是在建構模型圖時確定的,因此不是在執行階段計算的。屬性的常見用途是表示在模型訓練期間建立的係數。
屬性具有以下特性:
名稱 (Name) |
類型 (Type) |
描述 (Description) |
---|---|---|
name |
string |
屬性的名稱。在任何給定的運算子和節點中,屬性、輸入和輸出之間必須是唯一的。 |
doc_string |
string |
此值的人工可讀文件。允許使用 Markdown。 |
type (類型) |
AttributeType |
屬性的類型,決定使用哪個剩餘欄位來保存屬性的值。 |
f |
float |
一個 32 位元的浮點數值。 |
i |
int64 |
一個 64 位元的整數值。 |
s |
byte[] |
UTF-8 字串。 |
t |
Tensor |
一個張量值。 |
g |
Graph |
一個圖形。 |
floats |
float[] |
一個 32 位元浮點數值的列表。 |
ints |
int64[] |
一個 64 位元整數值的列表。 |
strings |
byte[][] |
一個 UTF-8 字串的列表。 |
tensors |
Tensor[] |
一個張量值的列表。 |
graphs |
Graph[] |
一個圖形的列表。 |
ref_attr_name |
string |
父函數屬性的名稱。 |
所有屬性都必須有 'name' 和 'type' 屬性,並且所有屬性都「應該」使用 'doc_string' 屬性。一個屬性「必須」只有一個攜帶值的屬性。
如果設置了 'ref_attr_name',則此屬性不包含資料,而是參考父函數中給定名稱的屬性。只能在函數體內使用。
可變輸入和輸出¶
運算子的最後一個輸入或輸出「可能」被標記為可變的。例如,運算子 'Max()' 可以用於計算可變數量的輸入值的最大值。可變運算子具有最小元數,它指定必須指定的最小運算元數量。
對於每個可變運算子輸入,必須指定 N 個或更多的節點輸入,其中 N 是運算子的最小元數。對於每個可變運算子輸出,必須指定 N 個或更多的節點輸出,其中 N 是運算子的最小元數。
可選輸入和輸出¶
靜態可選¶
某些運算子具有標記為可選的輸入,這表示參考的節點「可能」會省略為這些輸入提供值。
某些運算子具有可選的輸出。當未指定運算子的實際輸出參數時,運算子實作「可能」會省略計算這些輸出的值。
有兩種方法可以不指定可選的輸入或輸出:第一種方法僅適用於尾隨輸入和輸出,即簡單地不提供該輸入或輸出;第二種方法是使用空字串來代替輸入或輸出名稱。
每個引用具有可選輸出的運算子的節點「必須」為每個計算的輸出提供名稱,並且「不得」為未計算的輸出提供名稱。
上述類型的可選輸入和輸出稱為*靜態可選*。
動態可選(自 IR-8 起)¶
IR-8 版本引入了一種新的類型建構子來表示*動態可選*的輸入和輸出,除了上面描述的早期靜態可選版本之外。動態可選的 INT64 張量是與 INT64 張量類型不同的類型。相反,靜態可選的 INT64 張量沒有不同的類型,它與 INT64 張量具有相同的類型。運算子 Optional
和 OptionalGetElement
「必須」明確地用於在動態可選類型和底層非可選類型之間進行轉換。動態可選比靜態可選具有更大的表達能力。
外部張量資料¶
大型常數張量(例如初始值設定項)的原始資料「可能」會序列化在單獨的檔案中。在這種情況下,張量「必須」提供相對於模型檔案的檔案名稱,並且「不得」使用值欄位。它可以提供該檔案中的位元組偏移量和長度。它也可以指定該檔案的 SHA1 摘要。一個檔案「可能」包含多個張量的資料。
更多詳細資訊可以在 外部資料 中找到。
標準資料類型¶
有兩種官方 ONNX 變體;兩者之間的主要區別在於支援的類型和支援的運算子。
關於支援的類型,ONNX 和 ONNX-ML 定義都將張量、稀疏張量、序列、映射和可選視為輸入和輸出類型。從 IR 版本 6(ONNX 1.6.0 版本)開始支援序列和映射。從 IR 版本 8(ONNX 1.10.0 版本)開始支援可選類型。
以下資料類型受 ONNX 支援,用於圖形和節點的輸入和輸出,以及圖形的初始值設定項。
原始數值、字串和布林類型「必須」用作張量的元素。
張量定義¶
張量是向量和矩陣的泛化;向量具有一個維度,矩陣具有兩個維度,而張量可以具有任意數量的維度,包括零。零維張量在邏輯上等同於純量值。
從數學上講,張量可以定義為序列/列表對 (V, S),其中 S 是張量的形狀(非負整數列表),V 是一個值列表,其長度等於 S 中維度的乘積。當且僅當 V = V' 且 S = S' 時,兩個張量 (V, S) 和 (V', S') 相等。S 的長度稱為階數。
如果 S 的長度為 0,則 V 的長度必須為 1,因為空乘積定義為 1。在這種情況下,張量表示純量。
S 可以包含值為 0 的維度。如果任何維度為 0,則 V 的長度必須為 0。
如果 S 的長度為 1,則 V 的長度等於 S 中的單個維度。在這種情況下,張量表示向量。
表示長度為 1 的向量的張量具有形狀 [1],而表示純量的張量具有形狀 []。它們都只有一個元素,但純量「不是」長度為 1 的向量。
張量的形狀 S 是一個列表,但可以用值為 S 且形狀為 [R] 的張量表示,其中 R 是張量的階數。
對於張量 (V, S),表示其形狀的張量是 (S, [R])。
純量的形狀為 []。表示為張量時,[] 的形狀為 [0]。
表示法¶
通常將張量表示為巢狀列表。這通常運作良好,但在涉及零維度時會出現問題。形狀為 (5, 0) 的張量可以表示為 [[], [], [], [], []],但 (0, 5) 表示為 [],這會遺失第二個維度為 5 的資訊。
巢狀列表不是具有零值維度的張量的完整表示法。
張量元素類型¶
群組 |
類型 |
描述 (Description) |
---|---|---|
浮點類型 |
float16、float32、float64、bfloat16、float8e4m3fn、float8e5m2、float8e4m3fnuz、float8e5m2fnuz、float4e2m1 |
符合 IEEE 754-2008 標準的浮點資料表示形式,或在論文 用於深度學習的 FP8 格式、用於深度神經網路的 8 位元數值格式 和 開放運算專案 中定義的數值。 |
有號整數類型 |
int4、int8、int16、int32、int64 |
支援 4-64 位元寬度的有號整數。 |
無號整數類型 |
uint4、uint8、uint16、uint32、uint64 |
支援 4-64 位元寬度的無號整數。 |
複數類型 |
complex64、complex128 |
具有 32 位元或 64 位元實部和虛部的複數。 |
其他 |
string |
字串表示文字資料。所有字串都使用 UTF-8 編碼。 |
其他 |
bool |
布林值表示僅具有兩個值的資料,通常為 true 和 false。 |
輸入/輸出資料類型¶
以下類型用於定義圖形和節點輸入和輸出的類型。
變體 |
類型 (Type) |
描述 (Description) |
---|---|---|
ONNX |
密集張量 |
表示一個張量。請參閱上面的定義。 |
ONNX |
序列 |
序列是同類型元素的密集、有序集合。 |
ONNX |
映射 |
映射是由鍵類型和值類型定義的關聯表。 |
ONNX |
可選 |
可選是包裝器,其中可能包含張量、序列或映射類型的元素,或可能是空的(不包含任何元素)。 詳細資訊 |
靜態張量形狀¶
除了元素類型之外,張量類型還具有靜態形狀。張量變數的靜態形狀與張量值的執行階段(動態)形狀相關,但不同。靜態張量形狀是一個記錄列表,指示張量是向量、矩陣還是更高維度的值。例如,100x100 矩陣的形狀為 [100,100]。
靜態形狀由 'TensorShapeProto' 定義
message TensorShapeProto {
message Dimension {
oneof value {
int64 dim_value = 1;
string dim_param = 2;
};
};
repeated Dimension dim = 1;
}
張量類型訊息引用了該訊息
message Tensor {
optional TensorProto.DataType elem_type = 1;
optional TensorShapeProto shape = 2;
}
維度大小的空列表 `[]` 是一個有效的張量形狀,表示零維(純量)值。零維張量與未知維度的張量不同,後者在 Tensor 訊息中是以缺少 ‘shape’ 屬性來表示。當數值的型別(包括節點輸入)缺少 shape 屬性時,表示對應的運行時數值可能具有任何形狀。本小節將描述如何解讀缺失形狀或具有缺失維度的形狀等情況。然而,特定的使用情境可能會對型別和形狀施加進一步的約束。例如,模型(頂層圖)的輸入和輸出必須*具有*形狀,表示輸入和輸出的秩,即使不需要指定確切的維度。
列表中的每個大小可以表示為整數值,或是表示為「維度變數」,一個字串表示該維度的實際大小並非靜態地約束為特定數字。這對於宣告關心維度數量但不關心每個維度確切大小的介面非常有用。一個維度可以既沒有設定 `dim_value` 也沒有設定 `dim_param`。這樣的維度表示與其他未知維度無關的未知維度。
例如,一個 NxM 的矩陣會具有形狀列表 `[N,M]`。
每個維度變數的名稱必須符合 C90 識別符號語法規則。
目前,維度變數沒有作用域。維度變數「N」在模型中的整個圖中都代表相同的值。例如,如果圖有兩個輸入 X 和 Y,每個輸入的形狀都是 `["N"]`,那麼在運行時傳遞給 X 和 Y 的值必須是秩為 1 且具有相同維度的張量。巢狀子圖目前與主圖共享維度變數的相同作用域。這允許模型將子圖內張量的維度與外部圖中張量的維度聯繫起來。
ONNX 支援諸如張量序列之類的型別。維度變數的全局作用域表示型別為「Sequence<Tensor<float, [M,N]>」的變數表示*所有都具有相同形狀*的張量序列。如果該維度在序列中的所有張量之間沒有固定的大小,則必須從上述型別中省略維度變數 M 或 N。如果序列中不同的張量可能具有不同的秩,則必須從型別中省略整個形狀。
例如,執行矩陣交叉乘積的圖可以定義為接收形狀為 `[K,M]` 和 `[M,N]` 的兩個輸入,並產生形狀為 `[K,N]` 的輸出。
形狀可以使用整數和變數的組合來定義。
歷史注意事項:早期曾考慮過以下擴展,但從未實施或支持。
使用空字串(作為維度變數)來表示與任何其他維度無關的未知維度。為了使用既未設定 `dim_value` 也未設定 `dim_param` 的維度,這個做法被捨棄了。
使用字串「*」(作為維度變數)表示零個或多個未知基數的維度序列。這是不支援的。在目前的實作中,形狀中的維度數量必須表示張量的秩。未知秩的張量使用沒有形狀的 TypeProto::Tensor 物件表示,這是合法的。
允許子圖(例如迴圈的主體)的局部維度變數的作用域機制可能很有用,但目前不支援。
ONNX 支援諸如張量序列之類的型別。對於型別的局部維度變數的作用域機制,可能有利於區分以下兩種型別:不同大小的方陣序列 vs 所有大小相同的方陣序列。目前不支援此功能。
屬性類型¶
用於屬性的型別系統與用於輸入和輸出的型別系統相關,但略有不同。屬性值可以是密集張量、稀疏張量、純量數值、字串、圖或上述型別之一的重複值。
其他中繼資料¶
ModelProto 結構,以及在 IR 版本 >= 10 中,各種其他結構 (GraphProto、FunctionProto、NodeProto) 包含一個 `metadata_props` 欄位,允許使用者以鍵值對的形式儲存其他中繼資料。建議使用者使用以反向 DNS 名稱作為前綴的鍵名稱(例如 "ai.onnxruntime.key1"),以避免不同用途之間的衝突。ONNX 標準未來可能會使用未限定的名稱。
其他規格文件¶
ONNX 規格包含本文檔(定義 IR 和標準資料型別的語義)以及定義標準運算子語義和 IR 語法的以下文件。後者指定為 Protobuf v2 和 v3 架構檔案。
請參閱 中繼資料類別文件 以了解更多詳細資訊。