神經網絡的交換格式(1-2) http://www.lxweimin.com/p/aae219711c94
3.形式化描述
本章提供了計算圖結構方面的交換格式的正式描述。 這是一個簡單的符號,其目標是描述從較低級別構建塊構建計算圖形片段,最終到達整個網絡圖形的描述。
Backus-Naur Form(BNF)中的語法用于描述符號的語法。首先,定義語法的詞匯元素,并列舉與有效計算圖相關的約束條件。
3.1.詞法元素
描述格式由下列詞法元素構成:
<identifier>
一個identifier是ASCII字符序列,其中可能包含下劃線.特別的,<identifier>必須包含下列ASCII字符_
, [a-z]
, [A-Z]
, [0-9]
.<identifier>不能以數字開頭.
<numeric-literal>
一個numeric-literal包含一個整數部分,一個可選的小數點(.)和小數部分,還有一個可選的有符號指數.這些部分都必須由十進制數字組成.
<logical-literal>
值為true或false.
<keyword>
下列字符序列在語法中有特殊意義,因此不能用于identifier:
graph, fragment, tensor, extent, scalar, logical, string, shape_of, length_of, range_of, for, in, if, else.
<operator>
下列字符在數學表達式中有特殊意義:+, -, *, /, ^, <, <=, >, >=, ==, !=, &&, ||, !.
Syntactic characters
下列字符有特殊的語法意義:
(, ), [, ], {, }, :, =, ,, ;, ->.
White spaces
White spaces可能插入任意詞法元素之間,包括:
space字符,表示horizontal tab, vertical tab,格式補齊和新行的control字符.
Comments
用字符#
注釋某一行
3.2.語法
計算圖中的核心概念是將輸入張量映射為輸出張量的操作。 需要聲明操作,并根據聲明的操作構建計算圖描述。 因此,我們將描述分為兩個關鍵部分:
- 建立圖表的可能操作聲明。 操作有一個名稱和參數和結果的列表。 形式化的參數是鍵入的,確定什么樣的表達式可以代替它們的位置。
- 實際的圖形描述包含一系列針對聲明進行驗證的操作調用。 這些操作是通過引用它們的名字和提供參數來代替它們的形式參數來調用的。
此外,語法的描述被分成足夠的構造,以用于構成扁平的描述和根據需要擴展的成分描述。
以下BNF符號以更正式的方式介紹了描述語法。 由:: = below定義的所有內容都是BNF描述的一部分,并構成有效的語法。 這些BNF規則定義的語法之外的任何東西都被認為是無效的語法。
3.2.1.操作聲明
操作聲明由fragment關鍵字引入,具有名稱,參數列表和結果列表。 參數是明確鍵入的,可能有默認值。 結果在 - >符號之后引入。
<operation-declaration> ::= "fragment" <identifier> "(" <parameter-list> ")"
"->" "(" <result-list> ")"
<parameter-list> ::= <parameter> ("," <parameter>)*
<parameter> ::= <identifier> ":" <type-spec> ["=" <literal-expr>]
<result-list> ::= <result> ("," <result>)*
<result> ::= <identifier> ":" <type-spec>
類型規范可以表示一個基本類型,數組類型或元組類型。
<type-name> ::= "tensor" | "extent" | "scalar" | "logical" | "string"
<array-type-spec> ::= <type-spec> "[]"
<tuple-type-spec> ::= "(" <type-spec> ("," <type-spec>)+ ")"
<type-spec> ::= <type-name> | <array-type-spec> | <tuple-type-spec>
例如,以下幾行展示了一些操作聲明:
fragment foo( input: tensor, size: extent[] = [1] ) -> ( output: tensor )
fragment bar( input: tensor, alpha: scalar = 0.5 )
-> ( output: tensor, extra: tensor[] )
3.2.2.圖定義
圖形定義由一個圖形聲明及其正文組成。 圖聲明與操作聲明的語法類似,但由graph關鍵字引入,參數和結果列表不能包含類型規范和默認值。
<graph-definition> ::= <graph-declaration> <body>
<graph-declaration> ::= "graph" <identifier> "(" <identifier-list> ")"
"->" "(" <identifier-list> ")"
<identifier-list> ::= <identifier> ("," <identifier>)*
圖定義本身由一個賦值列表組成,其中賦值的左側是一個標識符表達式(單個標識符,元組或數組),右側是一個操作調用。
<body> ::= "{" <assignment>+ "}"
<assignment> ::= <lvalue-expr> "=" <invocation> [";"]
一個調用由一個標識符和一個參數列表組成:
<invocation> ::= <identifier> "(" <argument-list> ")"
<argument-list> ::= <argument> ("," <argument>)*
<argument> ::= <rvalue-expr> | <identifier> "=" <rvalue-expr>
表達式可以是文字,標識符,數組和元組。 有必要區分文字表達式,左值表達式和右值表達式。
在操作聲明中允許使用文字表達式作為默認值:
<literal> ::= <numeric-literal> | <string-literal> | <logical-literal>
<array-literal-expr> ::= "[" [<literal-expr> ("," <literal-expr>)* ] "]"
<tuple-literal-expr> ::= ["("] <literal-expr> ("," <literal-expr>)+ [")"]
<literal-expr> ::= <literal> | <array-literal-expr> | <tuple-literal-expr>
在賦值的左邊允許左值表達式:
<array-lvalue-expr> ::= "[" [<lvalue-expr> ("," <lvalue-expr>)* ] "]"
<tuple-lvalue-expr> ::= ["("] <lvalue-expr> ("," <lvalue-expr>)+ [")"]
<lvalue-expr> ::= <identifier> | <array-lvalue-expr> | <tuple-lvalue-expr>
在賦值的右側允許右值表達式(作為參數值):
<array-rvalue-expr> ::= "[" [<rvalue-expr> ("," <rvalue-expr>)* ] "]"
<tuple-rvalue-expr> ::= ["("] <rvalue-expr> ("," <rvalue-expr>)+ [")"]
<rvalue-expr> ::= <identifier> | <literal> | <array-rvalue-expr> | <tuple-rvalue-expr>
用可能有多個結果(如果操作定義了多個結果)。在這種情況下,返回的表達式是一個元組,左手大小的表達式也必須是一個元組。
作為一個例子,使用上面的聲明,我們可以將圖的一部分定義為:
graph barfoo( input ) -> ( output )
{
input = external(shape = [1,10])
intermediate, extra = bar(input, alpha = 2)
output = foo(intermediate, size = [3,5])
}
在上面的例子中,外部是一個操作,用于引入從外部源接收數據的張量(見張量引入操作)。
3.2.3.組成元素的描述
組合語法允許賦值列表定義一個新的操作,類似于整個圖的定義方式,但是使用fragment關鍵字。
<operation-definition> ::= <operation-declaration> <body>
而且,更復雜的表達式可以用作調用中的參數(右值表達式)。這些表達式允許編譯時算術和參數組合。
可以使用各種算術,比較和邏輯運算符來構建二進制表達式:
<comparison-operator> ::= "<" | "<=" | ">" | ">=" | "==" | "!="
<binary-arithmetic-operator> ::= "+" | "-" | "*" | "/" | "^"
<binary-logical-operator> ::= "&&" | "||"
<binary-operator> ::= <comparison-operator>
| <binary-arithmetic-operator>
| <binary-logical-operator>
一些一元運算符也可用于算術和邏輯表達式:
<unary-arithmetic-operator> ::= "+" | "-"
<unary-logical-operator> ::= "!"
<unary-operator> ::= <unary-arithmetic-operator>
| <unary-logical-operator>
運算符表達式可以使用一元和二元運算符和括號來構建:
<unary-expr> ::= <unary-operator> <rvalue-expr>
<binary-expr> ::= <rvalue-expr> <binary-operator> <rvalue-expr>
<paren-expr> ::= "(" <rvalue-expr> ")"
選擇表達式實現分支和數組理解表達式實現循環。數組理解表達式通過迭代另一個數組來生成數組,可以過濾結果項目。
<select-expr> ::= <rvalue-expr> "if" <rvalue-expr> "else" <rvalue-expr>
<comprehension-expr> :: "[" <rvalue-expr> "for" <identifier>
"in" <rvalue-expr> ["if" <rvalue-expr>] "]"
當理解表達式包含if條件時,if被解釋為理解表達式的一部分,而不是作為in關鍵字后的理解表達式內部的選擇表達式的一部分。
下標表達式可以引用數組中的單個條目或一系列條目,在這種情況下,范圍的開始(包含)和結束(排除)用下面的詞隔開:。 開始和結束都是可選的,在這種情況下,分別取0或數組的長度。
<subscript-expr> ::= <rvalue-expr> "[" (<rvalue-expr> |
<rvalue-expr> ":" <rvalue-expr>) "]"
一些特殊的關鍵字可以用于內置函數。
<builtin-name> ::= "shape_of" | "length_of" | "range_of"
| "extent" | "scalar" | "logical" | "string"
<builtin-expr> ::= <builtin-name> "(" <rvalue-expr> ")"
最后,擴展的右值表達式是上述所有結構(包括基本右值表達式和調用的定義中的結構)的聯合。
<rvalue-expr> ::= <indentifier>
| <literal>
| <binary-expr>
| <unary-expr>
| <paren-expr>
| <array-rvalue-expr>
| <tuple-rvalue-expr>
| <subscript-expr>
| <select-expr>
| <comprehension-expr>
| <builtin-expr>
| <invocation>
3.2.4.整個結構的描述
NNEF結構描述由版本信息,自定義操作定義的可選列表和頂層圖形定義組成。 據說不包含自定義操作定義的NNEF文檔是平坦的。 圖形定義必須始終存在。
<document> ::= <version> <operation-definition>* <graph-definition>
版本信息是由version關鍵字引入的,并且由實數數字文字定義為由點分隔的主版本和次版本:
<version> ::= "version" <numeric-literal>
下面是一個簡單的例子:
version 1.0
fragment foo( input: tensor, flag: logical ) -> ( output: tensor )
{
output = ...
}
fragment bar( input: tensor, param: scalar ) -> ( output: tensor )
{
output = ...
}
graph foobar( input ) -> ( output )
{
input = external(shape = [4,10])
hidden = foo(input, flag = true)
output = bar(hidden, param = 3.14)
}
請注意,可以僅從預定義操作(請參閱操作)構建網絡,而不需要在實際文檔描述中定義網絡。 因此,自定義操作定義通常是不必要的。 此外,圖形定義主體總是可以不使用擴展表達式來編寫; 它們只是定義復合操作所必需的。 因此,沒有自定義操作的網絡總是可以使用平面語法來編寫。
出于這個原因,圖形定義主體僅限于使用平面語法。這樣,沒有自定義操作的網絡總是可以依賴于平面語法來解釋。
3.3.語義
下面的小節定義了何時由片段定義構成的語法上有效的文檔在語義上也是明確定義的。 語義有效性規則描述了片段的正確定義和調用,包括適當的命名和引用,參數號,參數類型,參數范圍,正確使用聲明參數和本地標識符。
3.3.1片段定義
聲明
每個片段聲明必須具有唯一的名稱。片段僅基于其名稱來識別。
形式參數名稱和結果名稱在聲明中必須是唯一的,也就是說,有效聲明不能包含多個形式參數或名稱相同的結果。 但是,不同的聲明可能使用相同的形式參數名稱。
默認值表達式類型必須匹配形式參數的類型。
調用
調用必須為每個沒有默認值的形式參數分配一個唯一的參數值。具有默認值的形式參數也可以被賦予不同的值。
有兩種方法為形式參數賦值:基于位置(位置參數)和基于名稱(命名參數)。 位置參數按照其聲明的順序對應于形式參數。 命名的參數可以以任何順序出現,與形式參數聲明的順序無關。 只有張量參數(基元,數組或元組,請參閱類型系統和類型檢查)可能是位置型的,所有其他參數都必須命名。
有效的調用必須滿足以下條件:
- 調用中的操作名稱必須與已聲明的操作相對應。
- 一個調用的聲明不能超過聲明中正式參數的個數。
- 每個不具有默認值的形式參數都必須分配一個參數值。
- 位置參數必須在命名參數之前。
- 每個命名參數都必須具有與為該操作聲明的形式參數相對應的名稱。
- 命名參數必須是唯一的,即每個參數名稱在調用中只能出現一次。
- 命名參數不得引用也由位置參數分配的形式參數。
在調用中,沒有分配任何值但具有默認值的形式參數將取代它們的默認值。
分配
賦值的右邊可以是任何類型的表達式,但左邊必須是一個標識符或一個數組或元組(或任何這樣的組合)的結果被解壓縮的標識符。 也就是說,元組中的數組是允許的,但左側不允許調用和常量表達式。
圖表和片段主體中的標識符用法
有效的正式標識符使用規則如下:
- 片段的參數不能出現在片段體內賦值的左邊,它們只能被用作賦值右邊的表達式的參數。
- 圖形的參數(隱式類型張量)必須定義為外部操作的結果。外部操作不能用在片段中。
- 一個片段的結果必須在片段體內恰好分配一次。
- 片段或主圖形中的局部標識符必須首先出現在賦值的左側,然后在后續賦值的右側用作表達式中的參數。
- 在分配的左側不能多次使用相同的標識符(在一個片段內或在主圖表中)。
- 圖體中的所有單個標識符必須是張量類型。 也就是說,張量數組,張量元組和元參數類型的標識符是不允許的。 當張量數組或元組用于賦值的左側時,它們必須通過數組或元組表達式從單個張量標識符明確構造。
上述規則確保生成的圖形是非循環的,并且操作寫入主體的順序導致圖形的有效拓撲排序。 但是,并不是唯一有效的排序,只要滿足上述約束條件,就可以對操作進行重新排序或并行執行。
不允許在圖體中使用張量數組或張量元組的標識符的目的是讓每個張量都可以用一個單獨的名字來標識。
參數有效性
根據類型檢查,每個操作可以進一步限制所允許的參數集超出通常認為有效的范圍。 例如,操作可能會限制它們接受和作為結果返回的張量的數據類型,或者可能會限制參數在特定的范圍內。 具有多個張量參數的操作可以定義張量形狀一致性規則,并且還定義了它們的結果的形狀。 這些規則對于每個操作都是特定的,并且針對操作中的每個原語分別進行描述。
3.3.2類型系統和類型檢查
在語法中定義的語法中,操作的形式參數是明確鍵入的。此外,文字常量也有一個隱式定義的類型。表達式的類型是從它們的參數類型派生的。
類型可以是原始的也可以是復合的。化合物類型由基元或其他化合物類型組成。
此外,張量具有指定其內容類型的關聯數據類型。
原始類型
以下原始類型被定義:
- tensor(張量): 一個多維數組
- extent: 用來描述張量范圍和尺寸的(有符號的)整數值
- scalar(標量): 一個用于描述操作中的超參數的真實值
- logical: 通常用于描述標志和分支條件的邏輯值
- string: 一般字符序列,用來表示枚舉和名字
extent, scalar, logical and string構成原始類型,其值在編譯時已知。
復合類型
復合類型遵循一些構建模板:
- Array(數組)類型是從單個項目類型構建的。數組中的每個項目都具有相同的類型。例如,extent []是一個extent數組。
- Tuple(元組)類型由多個項目類型構建,并且始終具有固定數量的項目。例如,
(extent,tensor,tensor)
是一個extent和兩個tensor的元組。
復合類型的項目類型也可以是一個復合類型,從而啟用數組的數組,數組的數組或包含數組的元組。 例如,scalar[] []
是一個二維標量數組(每個子數組的長度可能不同),(extent,scalar)[]
是一個元組數組,而(extent [],tensor)
是一個 包含數組的元組。
張量數據類型
一般來說,張量持有標量數據。但是張量有兩種特殊的數據類型,不能與標量混合:
- logical(邏輯): 用于存儲比較操作的結果
- coordinate(坐標): 將位置信息存儲在另一個張量中
一般來說,操作接受標量張量。 一些操作導致或接受邏輯張量,而另一些操作則接受和返回坐標張量。 標量張量不能代替邏輯或坐標張量,反之亦然。 每個原始操作分別詳細描述了具體的要求。
文字常量的類型
文字常量的類型如下所示:
-
<numeric-literal>
的類型是extent
或scalar
,取決于它是分別表示整數還是實數。 -
<string-literal>
的類型是字符串。 - 常量true和false的類型是是
logical
。
類型轉換
以下隱式類型轉換是允許的:
- 如果tensor的期望數據類型是scalar,則可以使用
scalar
值代替tensor
參數。 - 如果
tensor
的期望數據類型是logical
,則可以使用logical
值代替tensor
參數。 - 如果一個數組元素的類型可以被轉換,那么它可以轉換為另一個數組類型。
- 如果元組的類型數量相同,則可以將元組類型轉換為另一個元組類型,并將相應的項類型轉換為另一個元組類型的元素類型。
當代替張量參數代替元參數時,它們表現為單一形狀的恒定張量。
當一個表達式在一個操作的調用中代替一個形式參數或者被分配給一個片段的結果時,表達式類型必須是相等的或者可以轉換成形式參數或結果類型; 否則調用無效。
此外,必要時可以使用內置函數強制顯式類型轉換。
3.3.3構建擴展表達式
這里描述的表達式主要使用組合語法(除了簡單的數組和元組構造)。算術,比較和邏輯表達式的目的是雙重的:
- 一個是作為某些操作的簡寫符號。例如,對于張量a和b,a + b相當于
add(a,b)
- 另一個是構建或計算元操作的元參數的值。例如,一個操作可能需要一個范圍數組,可以使用表達式來構建,例如
[1,2,3]
因此,表達式既可以是經常使用的算術運算符,比較運算符或邏輯運算符,也可以用于操作數據結構(如數組或元組)作為操作參數。 在操作數據結構時,所需的一組典型操作是從其組件或部件構建數據結構,并將數據結構解剖為其組件或部件。
以下小節描述了內置操作符和數據結構操作符符號。
內置操作
算術,比較和邏輯表達式可以由標識符和常量構建(請參閱語法)。 一個表達式可以是一個常量表達式,它只能由元參數類型構建,并且可以是非常量表達式,在這種情況下,它可以映射到基本片段(請參閱操作)。 下表總結了允許的參數類型和每個操作符的結果類型。 所有的操作符也適用于張量,因此這里沒有明確列出。 在這種情況下,結果也是一個張量(適當的數據類型)。 如果至少有一個參數是張量,則該操作將映射到適當的片段。 在這種情況下,參數類型必須以與顯式調用片段相同的方式進行檢查。
適用于標量的算術運算符也適用于范圍參數(但不是混合的),在這種情況下結果也是一個范圍。 適用于任何類型的比較運算符(為了方便起見用下面的字標記)必須具有相同類型的參數。
表1.內置運算符列表參數和結果類型,以及映射到片段
使用上述以外的參數類型的運算符會導致無效的表達式。
算術運算符+, - ,*,/,比較運算符<,<=,>,> =,==,!=和邏輯運算符&&,||,! 的語義,沿用他們的通常定義。
數組
在構建數組時,項目必須是相同的類型,或者必須可以將所有項目轉換為通用類型。
構建數組最簡單的方法是枚舉它的項目,如[a,b,c]。 或者,可以通過使用+運算符連接兩個數組來構建數組,例如[a,b] + [c,d],從而得到[a,b,c,d]或x + y,其中x和y是數組。 作為連接的泛化,可以使用*運算符多次復制數組。 例如,[a,b] * 2的結果是[a,b,a,b]。
要訪問數組中的項目或項目范圍,可以使用下標運算符[]
。 數組索引從0開始,直到數組的長度減1.有兩種類型的下標表達式,這取決于[]中的表達式:
- 如果下標表達式是extent類型的單個表達式,則結果是該數組的單個項目,下標表達式的類型是該數組元素的類型。例如,如果a = [1,2,3],那么a [1]等于2。
- 如果下標表達式是一個范圍(由:定界的extent類型的兩個表達式),則結果是數組的子序列,下標表達式的類型與數組類型相同。 范圍的開始是包容性的; 最后是排他性的。 范圍可以在兩端開放(通過省略:之前或之后的表達式)。 如果它在開始處是打開的,則它被定義為從0開始。如果在結尾處打開,則結束被定義為數組的長度。 如果開始小于或等于結束,結果是空數組。 例如,假設a = [1,2,3],則a [0:2]等于a [:2]并且等于[1,2],或者[1:3]等于a [1: ]和等于[2,3]。 而且,[2:2]等于[]。
元組
元組可以通過枚舉由運算符分隔的項來構造。例如,a,b是一個元組,或者可選地,為了更好的易讀性,可以像(a,b)中那樣將元組加括號。
如果表達式是元組類型的,則可以通過將其分配給包含元組項的標識符的元組來解壓縮它。 例如,如果t是三項的元組,則a,b,c = t將元組的項目解包到標識符a,b和c。 左邊的元組必須和右邊的元素數量相同。 具有多個結果的片段基本上返回一個元組。
下標也可以通過下標進行訪問:下標必須是整數文字,即范圍和索引變量或表達式是被禁止的。 a,b,c = t相當于a = t [0]; b = t [1]; c = t [2]。
字符串
雖然字符串是一種基本類型,但是字符串可以被認為是字符數組,并且一些操作可以像數組一樣被定義。字符串不能作為數組表達式來構建,然而:
- 字符串可以使用+運算符連接,并與*運算符重復使用。
- 可以使用范圍索引創建子字符串。當下標表達式是單個索引時,它也會導致一個單個字符的字符串。
內置函數
一些內置函數用于查詢來自張量,數組和字符串的信息。 為了描述這些函數的接口,為了方便起見,使用相同的符號。 但是,這些函數必須用一個位置參數來調用。 任何類型的說明符代表任何類型都可以代替。
-
shape_of(x:tensor) - >(shape:extent [])
返回張量x的形狀。 如果用非張量值代替張量x,則返回單體形狀。 得到的陣列的長度是張量的等級,或者至少2,取其大者 -
length_of(x:any []) - >(length:extent)
返回數組x的長度 -
length_of(x:string) - >(length:extent)
返回字符串x的長度 -
range_of(x:any []) - >(range:extent [])
返回范圍從0(包括)到數組x的長度(不包括) -
range_of(x:string) - >(range:extent [])
返回范圍從0(包括)到字符串x的長度(不包括)
此外,可以使用元參數類型的類型名稱作為一元函數(scalar,extent,logical,string)強制顯式類型轉換:
- 如果傳遞值為真,則
scalar(x:logical) - >(y:scalar)
將返回1.0,否則返回0.0 - 如果
scalar(x:string) - >(y:scalar)
描述一個有效的標量字面值(根據語法),則返回字符串的標量表示,否則調用無效 -
scalar(x:extent) - >(y:scalar)
返回與傳入相同的值,只更改類型 - 如果傳遞的值為真,
extent(x:logical) - >(y:extent)
將返回1,否則返回0 -
extent(x:string) - >(y:extent)
返回字符串的范圍表示,如果它描述了有效的范圍字面值(根據語法),否則調用無效 -
extent(x:scalar) - >(y:extent)
將傳遞的值截斷為最接近的較小整數值 - 如果傳遞值為0,
logical(x:extent) - >(y:logical)
將返回false,否則返回true - 如果傳遞的值是0.0,
logical(x:scalar) - >(y:logical)
將返回false,否則返回true - 如果傳入的字符串是空字符串(''),則
logical(x:string) - >(y:logical)
將返回false,否則返回true -
string(x:any) - >(y:string)
根據語法中的文字表示形式返回任何基本類型值的字符串表示形式
編譯時分支
編譯時分支是通過語法z = x if condition else y來實現的。 條件必須是邏輯類型的表達式(因此它的值在編譯時已知)。 此外,x或y的評估應該是懶惰的,也就是說,在評估條件之后,只應該評估x和y中適當的一個,這樣也可以使得未評估也是無效的(例如將一個數組索引 ),這在表達某些結構(如遞歸)時是必要的,如下所示:
fragment sum_of( items: scalar[] ) -> ( sum: scalar )
{
sum = items[0] + sum_of(items[1:]) if length_of(items) > 0 else 0.0
}
在上面遞歸求和數組中的項的例子中,當length_of(items)== 0時,表達式items [0]和items [1:]都將是無效的,但是由于懶惰評估而不被考慮。
編譯時循環
循環的一個顯而易見的方法是使用遞歸,如上例所示。但是,編寫和難以理解通常是非常麻煩的。
實現循環的一個更簡單的方法是數組理解,它通過迭代另一個數組并轉換它的項來生成一個數組。 一般來說,表達式b = [f(i)for i in a)
迭代數組a并通過將f應用于每個項目i來生成項目。 在許多情況下,我不是一個項目本身,而是一個索引運行通過一個范圍和下標多個數組,如在c = [a [i] * b [i]為我在range_of(a)]
,乘以相應的項目 數組a和b。 結果數組的長度等于迭代數組的長度。 可選地,可以提供條件來過濾所得到的項目:僅當條件c(i)的計算結果為真時,b = [f(i)for i in a c(i)]
才輸出項目。 在這種情況下,輸出的長度等于滿足條件的項目的數量。
調用鏈
操作調用可以像編程語言中的函數調用一樣鏈接,在這種情況下,操作的結果是另一個操作的輸入。 作為一個例子,鏈z = g(f(x),y)
等價于下面的調用序列
t = f(x)
z = g(t,y)
如果一個操作返回多個結果,被調用片段的相應參數必須是一個元組,以使鏈接有效。 如果目標是忽略某些結果,則必須首先明確地解壓縮結果,并且只有傳遞給第二個調用的相關參數或元組的相應項必須通過下標來選擇。
請注意,包含多個運算符的表達式也是隱式鏈接的。例如a = b + c * d
相當于a = add(b,mul(c,d))
。
3.3.4.張量形狀傳播
基本操作根據輸入的形狀和元參數來定義輸出的形狀。 從顯式提供形狀的輸入,變量和常量開始,形狀通過圖傳播,并且可以計算所有張量形狀。
但是,可以將某些尺寸的輸入張量的形狀信息保留為未指定的尺寸(請參見外部數據源),從而推遲依賴于輸入的操作的形狀傳播。 在這種情況下,當輸入的形狀信息變得可用時,形狀傳播和確認必須按照與輸入張量完全定義相同的方式執行。
但請注意,某些操作參數可能取決于張量形狀,即使某些輸入形狀未指定,這些參數也必須具有有效值。 例如,變量張量必須有明確定義的形狀(沒有未指定的維度),如果變量的形狀取決于未指定形狀的輸入,則認為無效(例如,匹配線性運算參數的形狀時)。 因此,變量形狀所依賴的輸入的這些維度不能保持不確定。
3.3.5導出標識符
某些張量需要從主要描述之外引用,以便能夠將更多的信息附加到圖上(如參數數據或量化信息)。 有兩種張量可供參考:變量和激活張量。
變量聲明為一個明確的字符串標簽(見變量),這個標簽必須是全局唯一的(共享權重除外),因此它可以用來引用一個變量。 此標簽用于將張量數據附加到序列化的變量。
圖表體中的激活張量也具有全局唯一標識符(分配的左側必須具有先前未使用的名稱),因此這些也可以用于參考激活張量,例如將量化信息附加到激活。
請注意,變量也可以是主要圖形描述的一部分,因此可以通過兩種機制(變量定義的字符串標簽和分配中使用的標識符名稱)引用它們。
variable42 = variable(label = 'block1/conv1/weights', ...)
在上面的例子中,盡管出于不同的目的,名稱'variable42'和'block1 / conv1 / weights'指的是相同的張量。