Skip to content
Snippets Groups Projects
Commit cf140068 authored by 김종명's avatar 김종명
Browse files

Merge branch '201920759_jong' into 'main'

201920759 jong

See merge request !2
parents 96a200ae 4332ab1e
No related branches found
No related tags found
1 merge request!2201920759 jong
[.text-right]
## 신경망 교환 형식
### 크로노스 NNEF 실무단
[.text-right]
#### 버전 1.0.5, 개정 1판, 2022-02-16
\ No newline at end of file
평면적인 설명에서도 복합 연산은 여전히 유효하다고 간주되지만, 이러한 연산들은 원자적인 기본 요소로도 취급됩니다.
아래는 더 큰 하위 그래프가 어떻게 구축되고, 전체 그래프가 정의될 때까지 점점 확장되는지를 그래픽으로 나타낸 것입니다:
image::image/10_figure2.png[]
_그림 2. 복합 프래그먼트(fragment)와 그래프의 계층적 구축_
조합적 설명은 그래프에서 고차 구조를 전달하여 빈번히 발생하는 하위 그래프들을 그룹화합니다. 이는 간결한 설명을 용이하게 하며, 평면적인 설명보다 더 많은 정보를 전달하며, 실행 엔진은 이러한 구조적 정보를 활용할 수 있습니다. 그러나 조합적 설명은 더 복잡하며, 컴파일이 어렵습니다. 따라서 평면적인 설명으로 충분한 경우에는 NNEF 구문의 적절한 하위 집합만 사용하는 것이 가능합니다.
연산을 설명할 때, 기본 연산은 입력과 출력 매핑을 명시해야 합니다. 이는 그들이 수행하는 계산, 입력에 따른 결과의 형태와 데이터 유형을 포함합니다. 이러한 기본 연산들의 의미는 수학적인 공식으로 표현됩니다. 반면에, 복합 연산은 기본 연산들로부터 구축되며, 이들이 구성되는 방식은 기본 연산들로부터 파생된 의미를 제공합니다. 이를 통해 전체 계산 그래프는 명확한 의미를 가지게 됩니다.
다른 연산들(기본 또는 복합)을 이용해 복합 연산을 설명하기 위해 _절차적(procedural)_ 표기법을 사용합니다. 대부분의 딥 러닝 프레임워크는 일반적인 목적의 스크립팅 언어(예: Python)를 사용합니다. 현재의 그래프 구조 설명은 이러한 스크립팅 언어의 단순한 하위 집합을 따르며, 그래프 _프래그먼트(fragment)_ 구성을 중심으로 구축되어 파라미터화된 연산을 다른 하위 연산들로 명시할 수 있게 합니다. 이 방법론은 전체 신경망의 그래프를 간결하게 설명하는 데 적용될 수 있습니다.
## *2.4. 그래프 설명 및 사용 개요*
이 형식의 목적은 실행될 수 있는 계산 그래프를 설명하는 것입니다. 그러나 형식 자체는 실행 모델을 정의하지 않고 그래프의 구조와 데이터 매개변수만을 제공합니다. 이를 위해 간단한 텍스트 형식이 계산 그래프의 구조적 측면을 설명합니다. 이 텍스트 형식과 함께 계산 그래프의 외부 텐서 매개변수를 설명하는 데이터 저장 형식이 제공됩니다.
이 문서의 구조는 다음과 같습니다. 형식적 설명 장(3. Formal Description)에서는 텍스트 형식의 구문(3.2. Syntax)과 의미론(3.3. Sementics)을 상세하게 다룹니다. 연산 장(4. Operations)에서는 기본 및 복합 연산의 집합을 설명하며, 이를 통해 계산 그래프를 구축할 수 있으며, 이들의 매개화와 의미론도 다룹니다. 네트워크 데이터 저장(5. Storing Network Data)장에서는 네트워크 가중치를 저장하는 이진 형식에 대해 설명합니다.
형식이 어떻게 사용될 수 있는지 보다 명확한 설명을 제공하기 위해, 이러한 부분들이 어떻게 조합되어 계산 그래프를 컴파일하고 실행하는지를 설명합니다.
\ No newline at end of file
### *2.4.1. 그래프 컴파일 및 실행*
계산 그래프의 컴파일은 다음으로부터 시작됩니다: ::
- 연산들의 순차적인 시퀀스로서의 계산 그래프를 설명하는 바이트 스트림(텍스트 형식).
- 계산 그래프의 외부 텐서 매개변수를 직렬화한 데이터를 포함하는 선택적인 바이트 스트림(이진 형식)
개념적 수준에서 컴파일 과정은 다음 단계를 포함할 수 있습니다: ::
- 구조적 설명을 구문 분석하고, 형식적 설명 규칙에 따라 유효성을 확인합니다.
- 만약 설명이 조합적이라면, 컴파일 시간 표현식을 평가하여 속성을 기반으로 연산들의 계층을 기본 요소들로 확장시켜서 평면화된 구조를 얻습니다.
- 텐서 형태를 전파하고, 연산에 대한 인수 확인을 수행하며, 연산에서 설명된대로 작업합니다.
구현은 연산(4. Operations 참조)에 나열된 기본 연산들의 그래프를 컴파일하는 것에 제한되지 않습니다. 대신, 복합 연산(4.9. Compound Operations)에 나열된 연산과 같은 것들을 개별적으로 원자적으로 구현하여 효율성을 높일 수 있습니다. 실행 가능한 그래프를 구축한 후에, 구현은 중간 버퍼나 불필요한 연산을 제거하거나 연산의 시퀀스를 병합하여 최적화할 수 있습니다.
컴파일 과정 이후, 그래프 실행은 다음과 같은 단계를 가질 수 있습니다: ::
- 이전에 직렬화된 데이터를 불러오거나 변수로 선언된 텐서에 초기 값을 주입합니다.
- 각 주기마다 외부 입력으로 선언된 텐서에 값을 주입하고 필요한 연산을 실행하며 출력을 읽어냅니다.
- 필요시 업데이트된 변수를 저장합니다.
다시 한 번 강조하자면, 교환 형식은 설명되는 계산 그래프의 실행 모델을 정의하지 않습니다. 위에서 설명한 것은 단순히 그것이 사용될 수 있는 예시에 불과합니다.
## *2.5. 용어 사전*
사양에서 빈번하게 사용되는 다음 용어들을 명시적으로 여기에 나열합니다:
*속성* ::
연산에 대한 추가적인 세부 정보를 정의하는 비텐서 매개변수입니다. 속성은 그래프 컴파일 시간에 알려진 원시 타입의 값들로 구성되며, 따라서 속성의 표현식은 그래프 컴파일 시간에 평가될 수 있습니다.
*복합 연산* ::
다른 연산들을 기반으로 정의된 연산입니다. 그 연산이 정의된 연산들의 합성을 통해 의미론적으로 결정됩니다.
\ No newline at end of file
*계산 그래프* ::
연산 또는 텐서(tensor)로 된 노드가 있는 그래프입니다. 연산 노드는 텐서 노드에만 연결되며, 그 반대의 경우도 마찬가지입니다.
*사용자 지정 연산* ::
NNEF 문서에 본문 없이 정의된 기본 연산입니다.
이 연산의 의미론(수학적 공식 및 형상 정보)은 사용자에게 달려 있습니다.
이러한 내용들은 명세서나 NNEF 문서 자체에서 정의되지 않습니다.
*그래프 프래그먼트* ::
전체 그래프(네트워크)의 하위 그래프입니다. 프래그먼트는 텐서들에 의해 상호 연결된 연산들의 집합에 의해 설명될 수 있습니다.
*그래프 컴파일 시간* ::
그래프가 실행되기 전에 구성되는 시간을 의미합니다. 프로그래밍 언어의 컴파일 시간과 유사한 의미를 갖고 있습니다.
*그래프 실행 시간* ::
그래프가 구성된 후에 실행되는 시간으로, 때로는 여러 번 실행될 수 있습니다. 이는 프로그래밍 언어에서의 런타임(run-time)과 유사합니다.
*연산* ::
입력 텐서들을 출력 텐서들로 매핑(mapping)하는 것을 의미합니다.
*원시 연산* ::
다른 작업에 의해 정의되지 않은 연산입니다. 그 의미론은 수학적 공식을 통해 정의됩니다.
*(차원의) 랭크* ::
형상에 명시적으로 지정된 차원의 수이거나 형상 전파에 의해 암시적으로 정의된 텐서의 차원 수입니다. (5,1)로 명시적으로 정의된 형상은 마지막 차원이 1차원이지만, 그 랭크는 2입니다.
*행 주요 순서* ::
행렬의 행 주요 데이터 레이아웃을 다차원 배열에 일반화한 것입니다. 데이터는 다차원 배열에서 다중 인덱스가 가장 빠르게 변하는 마지막 차원을 따라 배치되며, 가장 느리게 변하는 차원은 0번째 차원입니다. 후행 싱글톤(singleton) 차원은 개념적으로 무한한 다중 지수에서 후행 0 지수만 도입하므로 개념적으로 무한한 차원 데이터에도 이 정의가 유효합니다.
*(텐서의) 형상* ::
텐서의 각 관련 차원에서의 크기를 정의하는 정수들의 목록입니다.
*텐서(tensor)* ::
그래프 내에서 데이터 흐름을 나타내는 스칼라들의 다차원 배열입니다. 개념적으로 차원이 무한하지만, 구현에서 실제로 지원되는 최소 차원은 2이며, 차원의 끝에 있는 무의미한 싱글톤(singleton) 차원은 1입니다.
\ No newline at end of file
*가변 텐서* ::
지정된 연산에 의해 값이 업데이트될 수 있는 텐서(tensor)입니다. 다른 모든 텐서는 개념적으로 불변이며, 각 연산은 새로운 텐서를 생성합니다.
*(텐서의) 부피* ::
형상의 범위들의 곱으로 이루어진 정수 값입니다.
# *제 3장. 형식 설명*
본 챕터는 계산 그래프의 구조적 측면에 대한 교환 형식에 대한 형식적인 설명을 제공합니다. 이는 낮은 수준의 구성 요소에서부터 계산 그래프 프래그먼트를 설명하는 것을 목표로 한 간단한 표기법입니다. 이를 통해 전체 네트워크 그래프의 설명까지 이르게 됩니다.
Backus-Naur Form (BNF) 그래머를 사용하여 이 표기법의 구문을 설명합니다. 먼저 문법의 어휘 요소를 정의하고 유효한 계산 그래프에 대한 제약 조건도 열거합니다.
## *3.1. 어휘 요소*
설명 형식은 다음과 같은 렉시컬(lexical) 엔티티들로 이루어져 있습니다:
`<식별자(identifier)>`::
식별자는 알파벳과 숫자로 이루어진 ASCII 문자열로, 밑줄 문자도 포함될 수 있습니다. 더 구체적으로는 식별자는 *반드시* 다음과 같은 ASCII 문자로 이루어져야 합니다: `_`, `[a-z]`, `[A-Z]`, `[0-9]`. 식별자는 *반드시* 숫자로 시작해서는 *안 됩니다*.
`<숫자-리터럴(numeric-literal)>`::
숫자 리터럴은 정수 부분, 선택적 소수점 (`.`), 소수 부분, `e` 또는 `E` 그리고 선택적으로 부호가 있는 정수 지수로 구성됩니다. 정수, 소수 및 지수 부분은 *반드시* 각각 십진수 (10진수) 숫자(`[0-9]`)의 시퀀스여야 합니다. 리터럴은 선택적으로 - (마이너스) 기호로 시작될 수 있습니다. 평탄한 문법의 경우, 마이너스 기호는 리터럴 값의 일부로 해석됩니다. 조합적 문법의 경우, 마이너스 기호는 단항 마이너스 연산자로 해석되어 숫자 리터럴 앞에 옵니다. 그러나 최종 결과는 어느 경우에나 동일합니다.
`<문자열-리터럴(string-literal)>`::
문자열 리터럴은 `'` 또는 `"` 문자로 묶인 문자의 시퀀스입니다. 시작과 끝의 따옴표는 *반드시* 일치해야 합니다. 인쇄 가능한 ASCII 문자는 문자열 내에 나타날 수 있습니다. 단, 시작 따옴표 문자를 제외하고는 *반드시* `\` 문자로 빠져나와야 합니다. `\` 문자도 *반드시* `\` 문자와 함께 빠져나와야 합니다.
`<논리-리터럴(logical-literal)>`::
논리 리터럴은 `true` 와 `false` 의 값을 가집니다.
`<키워드(keyword)>`::
주어진 설명 구문에서 다음 알파벳 문자 시퀀스는 특별한 의미를 갖기 때문에 *반드시* 식별자로 사용해서는 *안 됩니다*: `version`, `extension`, `graph`, `fragment`, `tensor`, `integer`, `scalar`, `logical`, `string`, `shape_of`, `length_of`, `range_of`, `for`, `in`, `yield`, `if`, `else`.
`<연산자(operator)>`::
수학 표현식에서 다음 문자 시퀀스는 연산자로 특별한 의미를 가집니다: `+`, `-`, `*`, `/`, `^`, `<`, `<=`, `>`, `>=`, `==`, `!=`, `&&`, `||`, `!`.
\ No newline at end of file
*구문 문자* ::
구문적 의미를 가진 특수 문자: `(`, `)`, `[`, `]`, `{`, `}`, `:`, `=`, `,`, `;`, `->`.
*공백* ::
임의의 어휘 엔티티 사이에 공백 문자가 삽입될 수 있습니다. 여기에는 공백 문자, 가로 탭, 세로 탭, 폼 피드 및 새 라인을 나타내는 컨트롤 문자가 포함됩니다.
*주석* ::
주석은 `#` 기호로 시작하여 해당 줄의 끝까지 계속됩니다(폼 피드(form feed) 또는 새 줄 문자가 나올 때까지).
## *3.2 구문*
계산 그래프에서 중요한 개념은 입력 텐서를 출력 텐서로 매핑하는 연산입니다. 연산은 선언되어야 하며, 계산 그래프 설명은 선언된 연산으로 구축됩니다. 따라서 우리는 설명을 두 가지 주요 부분으로 구분합니다: ::
- 그래프 작성을 위한 가능한 연산을 선언합니다. 연산은 이름과 매개변수 및 결과 목록을 갖습니다. 형식 매개변수는 어떤 종류의 표현식이 그 자리에 대체될 수 있는지를 식별하는 타입이 지정됩니다.
- 실제 그래프 설명은 선언에 대해 유효성을 검사하는 연산 호출 목록으로 구성됩니다. 연산은 이름을 참조하고 형식 매개변수에 대한 인자를 제공하여 호출됩니다.
더 나아가, 구문 설명은 _평면(flat)_ 설명에 필요한 구성 요소와 _구성적(compositional)_ 설명에 필요한 확장으로 구분됩니다.
다음 BNF 표기법은 보다 형식적인 방식으로 설명 구문을 소개합니다. 아래 `::=` 로 정의된 모든 것은 BNF 설명의 일부이며 유효한 구문을 구성합니다. 이러한 BNF 규칙에서 정의된 내용 외에는 유효하지 않은 구문으로 간주됩니다
### *3.2.1 그래프 정의*
그래프 정의는 그래프 선언과 그 본문으로 구성됩니다. 그래프 선언에는 매개변수와 결과의 목록이 있습니다.
----
<graph-definition> ::= <graph-declaration> <body>
<graph-declaration> ::= "graph" <identifier> "(" <identifier-list> ")"
"->" "(" <identifier-list> ")"
<identifier-list> ::= <identifier> ("," <identifier>)*
----
그래프 정의 자체는 할당 목록으로 구성되며, 할당의 좌변은 식별자 표현식(단일 식별자, 튜플 또는 배열)이고, 우변은 연산 호출입니다.
\ No newline at end of file
----
<body> ::= "{" <assignment>+ "}"
<assignment> ::= <lvalue-expr> "=" <invocation> ";"
----
호출은 식별자와 인자 목록으로 구성됩니다:
----
<invocation> ::= <identifier> ["<" <type-name> ">"] "(" <argument-list> ")"
<argument-list> ::= <argument> ("," <argument>)*
<argument> ::= <rvalue-expr> | <identifier> "=" <rvalue-expr>
----
표현식은 리터럴(literal), 식별자, 배열 및 튜플(tuple)일 수 있습니다. 좌측 값(left-value) 표현식과 우측 값(right-value) 표현식을 구분하는 것이 필요합니다.
좌측 값 표현식은 할당문의 좌변에 허용됩니다.
----
<array-lvalue-expr> ::= "[" [<lvalue-expr> ("," <lvalue-expr>)* ] "]"
<tuple-lvalue-expr> ::= "(" <lvalue-expr> ("," <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>
<literal> ::= <numeric-literal> | <string-literal> | <logical-literal>
----
호출은 여러 개의 결과를 가질 수 있습니다 (작업이 여러 결과를 정의하는 경우). 이 경우 반환된 표현식은 튜플(tuple)이며, 좌측 값 표현식도 튜플이어야 합니다.
예시로, 위의 선언을 사용하여 그래프의 일부를 다음과 같이 정의할 수 있습니다.
----
graph barfoo( input ) -> ( output )
{
input = external(shape = [1,10]);
intermediate, extra = bar(input, alpha = 2);
output = foo(intermediate, size = [3,5]);
}
----
위의 예시에서, `external` 은 외부 소스로부터 데이터를 수신하는 텐서를 도입하는 데 사용되는 연산이며 (pass:[<span style="color:turquoise;">4.1. Tensor Indroducing Operations</span>] 참조), `bar` 와 `foo` 와 같은 연산의 예시는 아래에 정의되어 있습니다.
\ No newline at end of file
## *3.2.2. 프래그먼트 정의*
다음 구문 요소는 *반드시* 확장 기능인 `KHR_enable_fragment_definitions` 에 의해 활성화되어야 합니다.
프래그먼트는 할당 목록에 의해 본문이 정의된다는 점에서 그래프와 유사하지만, 프래그먼트의 선언은 입력된 형식의 매개변수 및 결과를 허용합니다.
----
<fragment-definition> ::= <fragment-declaration> (<body> | ";")
----
프래그먼트 선언은 `fragment` 키워드에 의해 도입되고, 이름, 매개변수 목록 및 결과 목록을 갖습니다. 매개변수는 명시적으로 입력되며 기본값을 가질 수 있습니다. 또한, 결과는 `->` 기호 뒤에 도입됩니다.
----
<fragment-declaration> ::= "fragment" <identifier> [<generic-declaration>]
"(" <parameter-list> ")" "->" "(" <result-list> ")"
<generic-declaration> ::= "<" "?" ["=" <type-name>] ">"
<parameter-list> ::= <parameter> ("," <parameter>)*
<parameter> ::= <identifier> ":" <type-spec> ["=" <literal-expr>]
<result-list> ::= <result> ("," <result>)*
<result> ::= <identifier> ":" <type-spec>
----
기본값은 리터럴(literal)로만 작성된 리터럴 표현식입니다:
----
<array-literal-expr> ::= "[" [<literal-expr> ("," <literal-expr>)* ] "]"
<tuple-literal-expr> ::= "(" <literal-expr> ("," <literal-expr>)+ ")"
<literal-expr> ::= <literal> | <array-literal-expr> | <tuple-literal-expr>
----
유형 지정은 원시 타입, 배열 타입 또는 튜플(tuple) 타입을 나타낼 수 있습니다.
----
<type-name> ::= "integer" | "scalar" | "logical" | "string" | "?"
<tensor-type-spec> ::= "tensor" "<" [<type-name>] ">"
<array-type-spec> ::= <type-spec> "[]"
<tuple-type-spec> ::= "(" <type-spec> ("," <type-spec>)+ ")"
<type-spec> ::= <type-name> | <tensor-type-spec> |
<array-type-spec> | <tuple-type-spec>
----
예를 들어, 다음 줄에는 일부 연산에 대한 선언을 보여줍니다:
----
fragment foo( input: tensor<scalar>, size: integer[] = [1] )
-> ( output: tensor<scalar> )
fragment bar( input: tensor<scalar>, alpha: scalar = 0.5 )
-> ( output: tensor<scalar>, extra: tensor<scalar>[] )
----
프래그먼트의 결과 타입은 *반드시* 모두 텐서(tensor)이어야 합니다.
\ No newline at end of file
## *3.2.3. 연산자 표현식*
다음 구문 요소는 *반드시* 확장 기능인 `KHR_enable_operator_expressions` 에 의해 활성화되어야 합니다.
이 구문은 더 복잡한 표현식을 우측 값(right-value) 표현식으로 사용될 수 있도록 합니다. 이러한 표현식을 사용하면 컴파일 시간 산술 및 인자 조합이 가능합니다.
다양한 산술, 비교 및 논리 연산자를 사용하여 이진 표현식을 작성할 수 있습니다:
----
<comparison-operator> ::= "<" | "<=" | ">" | ">=" | "==" | "!=" | "in"
<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> ")"
----
if-else 표현식은 조건에 따라 두 개의 표현식 중 하나를 선택함으로써 분기를 구현합니다.
----
<if-else-expr> ::= <rvalue-expr> "if" <rvalue-expr> "else" <rvalue-expr>
----
배열 내포 표현식은 루핑(looping)의 형태를 구현합니다. 하나 이상의 배열을 반복하며 선택적으로 결과 항목을 필터링하여 배열을 생성합니다.
----
<loop-iter> ::= <identifier> "in" <rvalue-expr>
<loop-iter-list> ::= <loop-iter> ("," <loop-iter>)*
<comprehension-expr> ::= "[" "for" <loop-iter-list> ["if" <rvalue-expr>]
"yield" <rvalue-expr> "]"
----
NOTE: 내포 표현식에 `if` 조건이 포함된 경우, `if` 는
내포 표현식 내의 `in` 키워드를 따르는 if-else 표현식의 일부로 해석되는 것이 아니라 내포 표현식의 일부로 해석된다.
아래첨자(subscripting) 표현식은 배열 내의 단일 항목을 참조하거나 범위의 항목을 참조할 수 있습니다. 이 경우 범위의 시작(포함)과 끝(제외)은 `:` 으로 구분됩니다. 시작과 끝 모두 선택 사항이며, 선택하지 않은 경우 각각 0 또는 배열의 길이가 사용됩니다.
----
<subscript-expr> ::= <rvalue-expr> "[" (<rvalue-expr> |
[<rvalue-expr>] ":" [<rvalue-expr>]) "]"
----
몇 가지 특별 키워드를 내장 함수에 사용할 수 있습니다.
----
<builtin-name> ::= "shape_of" | "length_of" | "range_of"
| "integer" | "scalar" | "logical" | "string"
<builtin-expr> ::= <builtin-name> "(" <rvalue-expr> ")"
----
마지막으로, 확장된 오른쪽 값 표현식은 위의 모든 구성(기본 오른쪽 값 표현식 및 호출의 정의에 있는 구성 포함)의 결합입니다. 할당에는 호출뿐만 아니라 모든 오른쪽 값 표현식이 포함될 수 있습니다:
----
<rvalue-expr> ::= <identifier>
| <literal>
| <binary-expr>
| <unary-expr>
| <paren-expr>
| <array-rvalue-expr>
| <tuple-rvalue-expr>
| <subscript-expr>
| <if-else-expr>
| <comprehension-expr>
| <builtin-expr>
| <invocation>
<assignment> ::= <lvalue-expr> "=" <rvalue-expr> ";"
----
### *3.2.4. 전체 문서*
NNEF 구조 설명은 버전 정보, 사용되는 확장명 목록 (선택사항), 작업 정의 목록(선택사항) 및 최상위 그래프 정의로 구성됩니다. 연산 정의 및 확장 표현식이 포함되지 않은 NNEF 문서는 _flat_ 이라고 합니다. 그래프의 정의는 항상 존재해야 합니다.
----
<document> ::= <version> <extension>* <fragment-definition>* <graph-definition>
----
\ No newline at end of file
# *목차*
:hardbreaks:
*1. 개요*::
1.1. NNEF란:::
1.1.1. NNEF에 대한 수출자의 관점
1.1.2. NNEF에 대한 수입자의 관점
1.1.3. NNEF에 대한 응용 프로그래머의 관점
1.1.4. NNEF가 아닌 것
1.2. 사양 용어:::
*2. 기초*::
2.1. 계산 그래프
2.2. 데이터 설명
2.3. 연산 설명
2.4. 그래프 설명 및 사용 개요:::
2.4.1 그래프 컴파일 및 실행
2.5. 용어 사전
*3. 형식 설명*::
3.1. 어휘 요소
3.2. 구문:::
3.2.1. 그래프 정의
3.2.2. 프래그먼트 정의
3.2.3. 연산자 표현식
3.2.4. 전체 문서
3.3. 의미론:::
3.3.1. 타입 시스템 및 타입 확인
3.3.2. 그래프와 프래그먼트 정의
3.3.3. 표현식 작성
3.3.4. 내보낸 식별자
*4. 연산*::
4.1. 텐서 도입 연산:::
4.1.1. 외부 데이터 소스
4.1.2. 상수
4.1.3. 변수
4.2. 원소별 연산:::
4.2.1. 단항 연산
4.2.2. 이진 연산
4.2.3. 선택 연산
4.2.4. 단순화 연산
4.3. 슬라이딩-윈도우 연산:::
4.3.1. 합성곱과 역합성곱
4.3.2. 박스 필터
4.3.3. 인덱스 기반 샘플링
4.3.4. 업 & 다운 샘플링
\ No newline at end of file
버전 정보는 `version` 키워드에 의해 소개되며, 점으로 구분된 major 및 minor 버전으로, 실수 형태의 숫자 리터럴(literal)에 의해 정의됩니다:
----
<version> ::= "version" <numeric-literal> ";"
----
`extension` 키워드 뒤에 확장명을 지정할 수 있습니다:
----
<extension> ::= "extension" <identifier>+ ";"
----
NOTE: 세 가지 유형의 확장이 구별되며, 이는 명명 규칙에 반영됩니다: ::
- 크로노스(Khronos) 확장은 다음과 같은 형식을 사용합니다: `KHR_extension_name`. +
- 공급업체 간(Cross-vendor) 확장은 다음과 같은 형식을 사용합니다: `KHR_extension_name`. +
- 벤더-지정(Vendor-specific) 확장은 `VENDOR_extension_name` 형식을 사용하며, 여기서 VENDOR는 공급업체의 실제 이름입니다.
아래는 설명을 위한 간단한 예제입니다.
----
version 1.0;
extension KHR_enable_fragment_definitions;
fragment foo( input: tensor<scalar>, flag: logical ) -> ( output: tensor<scalar> )
{
output = ...
}
fragment bar( input: tensor<scalar>, param: scalar ) -> ( output: tensor<scalar> )
{
output = ...
}
graph foobar( input ) -> ( output )
{
input = external(shape = [4,10]);
hidden = foo(input, flag = true);
output = bar(hidden, param = 3.14);
}
----
네트워크는 실제 문서 설명에서 정의할 필요 없이, 미리 정의된 작업(pass:[<span style="color:turquoise;">4. Operations</span>] 참조)만으로도 구축할 수 있다는 것을 알아두시길 바랍니다. 따라서 일반적으로 프래그먼트 정의는 불필요합니다. 더 나아가, 그래프 정의 본문은 일반적으로 연산자 표현식(복합 연산을 정의하는데 가장 유용합니다.)을 사용하지 않고 작성할 수 있습니다. 따라서 사용자 정의 작업이 없는 네트워크는 일반적으로 단순한 구문만을 사용하여 작성할 수 있습니다.
\ No newline at end of file
## *3.3. 의미론*
다음 하위 섹션에서는 조각 정의로 구성된 구문론적으로(3.2 Syntax 참조) 유효한 문서가 의미론적으로도 잘 정의된 경우를 정의합니다. 의미론적 유효성 규칙은 적절한 명명 및 참조, 인자 번호, 인자 유형, 인자 범위, 선언된 매개 변수 및 로컬 식별자의 적절한 사용을 포함하여 프래그먼트의 적절한 정의 및 호출을 설명합니다.
### *3.3.1. 타입 시스템 및 타입 확인*
구문에 정의된 문법에서 연산의 형식적 매개변수는 명시적으로 유형(type)이 지정됩니다. 게다가, 리터럴(literal) 상수도 암시적으로 정의된 유형이 있습니다. 표현식의 유형은 그들의 인자들의 유형에서 유도됩니다.
타입은 원시 또는 복합 타입일 수 있습니다. 복합 타입은 원시 타입에서나 다른 복합 타입에서 구성됩니다.
*원시 타입*
다음과 같은 기본 유형들이 정의되어 있습니다: ::
- 정수 `integer`: 텐서 모양, 차원 및 텐서 내부의 인덱스(index)를 설명하는 데 사용되는 부호 있는 정수 값
- 스칼라 `scalar`: 연산 내의 데이터 및 매개변수를 설명하는 데 사용되는 실수 값
- 논리형 `logical`: 일반적으로 플래그(flag) 및 분기 조건을 설명하는 데 사용되는 논리값
- 문자열 `string`: 열거 및 이름을 나타내는 데 사용되는 일반적인 문자 시퀀스
원시 타입은 컴파일 시간에 알려진 매개변수를 나타내는 데 사용됩니다.
*복합 타입*
복합 타입은 몇 가지 구성 템플릿을 따릅니다: ::
- _텐서 타입_ 은 *반드시* 원시 타입인, 단일 데이터 타입으로 구성됩니다. 예를 들어, `tensor<scalar>` 는 스칼라들의 텐서입니다. 텐서는 런타임에서 계산되는 데이터를 나타냅니다. 텐서 타입은 `tensor<>` 구문을 사용하여 데이터 유형 없이 제한되지 않을 수 있습니다.(Unbound)
- _배열 타입_ 은 단일 아이템 유형에서 구성됩니다. 배열 내 각 항목은 동일한 타입을 갖습니다. 예를 들어, `integer[]` 는 정수들의 배열입니다.
- _튜플 타입_ 은 여러 항목 유형에서 구성되며 항상 고정된 수의 항목을 갖습니다. 예를 들어, `(integer, scalar)` 는 정수와 스칼라로 이루어진 튜플입니다.
텐서 타입을 포함하지 않으면 _속성_ 타입으로 정의됩니다. 런타임 데이터 매개변수와 컴파일 타임 속성 값들을 분리하기 위해 튜플은 *반드시* 동시에 텐서와 텐서가 아닌 아이템 타입을 포함해서는 안 됩니다.
합성 유형의 아이템 유형은 또 다른 합성 유형일 수 있습니다(텐서 제외). 이를 통해 배열의 배열, 튜플의 배열 또는 배열을 포함하는 튜플 등이 가능합니다. 예를들어, `scalar[][]` 는 2차원 스칼라 배열입니다(각 하위 배열의 길이가 다를 수 있음), `(integer, scalar)[]` 는 튜플의 배열이며, `(integer[], scalar)` 는 배열과 스칼라(scalar)를 포함하는 튜플(tuple)입니다.
\ No newline at end of file
결속되지 않은 텐서들은 연산의 결과가 될 수 없으며, 다른 텐서와의 데이터 유형을 확인하거나 일치시킬 필요가 없는 입력을 선언하는 데에만 사용될 수 있습니다.
NOTE: 텐서(tensor) 데이터 유형이 어떻게 표현되는지는 추론 엔진의 구현에 달려 있습니다.
*제네릭(Generic) 타입*
구문은 원시 유형의 자리에 `?` 기호를 사용하여 제네릭 타입을 구성할 수 있는 제한적인 방법을 제공합니다. 이는 예를 들어 `tensor<?>` 와 같이 제네릭 텐서 또는 `?[]` 와 같이 제네릭 배열을 나타내는 복합 유형에서 사용될 수 있습니다. 제네릭 심볼은 프래그먼트 선언에서 사용될 수 있어서 해당 연산이 모든 데이터 유형의 텐서에 적용될 수 있음을 선언할 수 있습니다. 예를 들어:
----
fragment buzz<?>( input: tensor<?>, param: ? ) -> ( output: tensor<?> )
----
이 선언은 어떤 데이터 유형의 텐서에 대해서도 적용 가능한 `buzz` 작업을 선언합니다. 또한 정의는 `input` 매개변수의 데이터 타입이 `param` 매개변수의 유형과 동일해야 하며, 결과인 `output` 의 데이터 타입은 입력값 에서 상속될 것이라는 것을 의미합니다.
호출될 때, 제네릭 데이터 타입 `?` 은 실제 인자에서 추론될 수 있습니다. 그러나 입력이 제네릭 유형이 아닌 출력만이 제네릭인 경우도 있을 수 있습니다. 이 경우 제네릭 타입에 선택적 기본값을 지정할 수 있습니다.
----
fragment fizz<? = scalar>( shape: integer[] ) -> ( output: tensor<?> )
----
이 경우에는 제네릭 매개변수를 명시적으로 제공해야 하며, 그렇지 않으면 기본값이 사용됩니다.
----
a = fizz<integer>(shape = [...]) # 명시적 정수 데이터 타입
b = fizz(shape = [...]) # 기본 스칼라 데이터 타입
----
제네릭(generic) 매개변수를 복합 연산에서 전파해야 하는 경우, 작업 이름 뒤에 `<?>` 를 사용하여 수행할 수 있습니다:
----
fragment fizz<? = scalar>( shape: integer[] ) -> ( output: tensor<?> )
{
output = buzz<?>(...);
}
----
*리터럴 상수의 유형*
리터럴(literal) 상수의 유형은 다음과 같습니다:
- `<numeric-literal>` 의 유형은 각각 정수를 나타내는지 실제 값을 나타내는지에 따라 `integer` 또는 `scalar` 중 하나입니다.
- `<string-literal>` 의 유형은 `string` 입니다.
- 상수 `true` 와 `false` 의 타입은 `logical` 입니다.
- 리터럴 `[]` 의 타입은 특수 유형인 빈 배열 형식입니다. 이 형식은 명시적으로 선언할 수 없습니다
\ No newline at end of file
*타입 변환*
명시된 암시적 형 변환만 허용됩니다(다른 형 변환은 허용되지 않습니다): ::
- 원시 타입은 해당 데이터 타입의 텐서 타입으로 변환(cast)될 수 있습니다.
- 어떤 원시 타입이든지 제네릭(generic) 타입인 `?` 으로 캐스팅할 수 있으며, 어떤 제한된(bound) 텐서 타입이든지 제네릭 타입인 `tensor<?>` 으로 캐스팅할 수 있습니다.
- 어떤 텐서 유형이든 제한되지 않은 텐서 유형인 `tensor<>` 로 변환될 수 있습니다
- 아이템 타입이 변환될 수 있는 경우 배열 유형은 다른 배열 유형으로 변환될 수 있습니다. 빈 배열 유형은 다른 어떤 배열 유형으로도 캐스트될 수 있지만, 다른 어떤 배열 유형도 빈 배열 유형으로 캐스트될 수 없습니다.
- 튜플(tuple) 유형은 같은 수의 항목을 갖고 있고 해당 항목 유형이 다른 튜플의 유형으로 변환될 수 있는 경우에만 변환이 가능합니다.
두 유형 중 하나가 다른 하나로 변환될 수 있다면, 두 유형에는 공통 유형이 있습니다.
원시 타입의 매개변수가 텐서 매개변수 자리에 대체되면, 그들은 싱글톤(singleton) 형태의 상수 텐서처럼 동작합니다.
표현식이 연산의 매개변수 자리에 대체되거나 프개르먼트의 결과에 할당될 때, 그 표현식의 타입은 *반드시* 해당 매개변수나 결과 타입과 동일하거나 변환 가능해야 합니다. 그렇지 않으면 호출은 유효하지 않습니다.
필요한 경우, 기본 내장 함수를 사용하여 원하는 대로 원시 타입 간의 명시적 타입 변환을 할 수 있습니다.(29p. built-in functions 참조)
## *3.3.2 그래프 및 프래그먼트(fragment) 정의*
*선언*
각각의 프래그먼트 선언은 *반드시* 고유한 이름을 가져야 합니다. 프래그먼트들은 오직 그들의 이름에 기반하여 식별됩니다. 유효한 선언은 *반드시* 다음과 같은 조건을 만족해야 합니다: ::
- 형식 매개변수 이름과 결과 이름은 선언 내에서 *반드시* 고유해야 합니다. 즉, 유효한 선언에는 *반드시* 동일한 이름의 여러 형식 매개변수나 결과가 포함되어서는 *안 됩니다*. (물론 다른 선언에서는 같은 형식 매개변수 이름을 사용할 수 있습니다.)
- 텐서 형식의 매개변수는 *반드시* 속성 이전에 위치해야 합니다.
- 프래그먼트 결과는 *반드시* 모두 텐서여야 합니다.
- 기본값 표현식의 유형은 *반드시* 형식 매개변수의 유형과 일치해야 합니다.
제네릭 프래그먼트는 프래그먼트 이름 뒤에 `<?>` 를 추가하여 정의될 수 있습니다. 기호 `?` 는 프래그먼트 선언 및 본문 내에서 제네릭 유형 매개변수를 참조하는 데 사용됩니다. 제네릭 유형 매개변수는 `<? = ...>` 구문을 사용하여 선택적으로 기본값을 가질 수 있습니다. 자세한 내용은 (22p. Generic Types)를 참조하세요.
\ No newline at end of file
만약 프래그먼트(fragment)에 최소 하나 이상의 제네릭(generic) 매개변수 또는 결과 유형이 있다면, 이는 *반드시* 제네릭으로 선언되어야 합니다. 반대로, 프래그먼트가 제네릭으로 선언되었다면, *반드시* 최소 하나 이상의 제네릭 매개변수 또는 결과 유형을 가지고 있어야 합니다.
*호출*
호출은 *반드시* 각각 기본값이 없는 형식 매개변수에 대해 고유한 인수 값을 할당해야 합니다. 기본값이 있는 형식 매개변수에도 다른 값을 할당할 수 있습니다.
형식 매개변수에 값을 할당하는 방법은 두 가지가 있습니다: 위치 기반(_위치 인자_)과 이름 기반(_명명된 인자_). 위치 인자는 형식 매개변수를 선언된 순서대로 대응합니다. 명명된 인자는 형식 매개변수의 선언 순서와 무관하게 어떤 순서로든 나타날 수 있습니다. 텐서 인자만 위치 기반이 될 수 있으며, 속성 값은 이름으로 지정된 인자여야 합니다(3.3.1. Type System and Type Checking 참조).
NOTE: 텐서 매개변수에 이름 기반 인자를 사용하는 것은 *폐지(deprecated)* 되었습니다. 텐서 인자와 텐서가 아닌 속성을 명확히 구분하기 위해 텐서는 위치 기반 인자여야 하며, 속성은 이름으로 지정된 인자여야 합니다.
유효한 호출은 *반드시* 다음 기준을 충족해야 합니다: ::
- 호출된 연산 이름은 *반드시* 선언된 연산과 일치해야 합니다.
- 호출에 전달되는 인자의 수는 *반드시* 선언된 매개변수의 수를 초과해서는 *안 됩니다*.
- 기본값이 없는 각 형식 매개변수는 인자 값을 *반드시* 할당받아야 합니다.
- 위치에 따른 인자는 명명된 인자보다 앞에 위치해야 합니다.
- 각 명명된 인자는 *반드시* 연산에 선언된 매개변수의 이름과 일치해야 합니다.
- 명명된 인자는 *반드시* 고유해야 하며, 다시 말해 호출 내에서 각 매개변수 이름은 한 번만 사용되어야 합니다.
- 명명된 인자는 *반드시* 위치에 따른 인자로 할당된 매개변수를 참조해서는 안 됩니다.
- 제네릭 프래그먼트(fragment)는 `name<type>` 구문을 사용하여 명시적 타입 지정자로 호출될 수 있습니다. 또한 `name<?>` 구문은 제네릭 매개변수 타입이 제네릭 프래그먼트 내에서 전파되어야 할 때 사용될 수 있습니다. 만약 제네릭 프래그먼트가 기본 값으로 타입을 가지고 있고 명시적인 제네릭 인자 없이 호출되면, 해당 제네릭 타입의 기본 값이 대체됩니다.
호출에서 매개변수에 기본값이 있는데 어떠한 값도 할당되지 않으면 해당 매개변수에는 기본값이 대입됩니다.
만약 프래그먼트가 제네릭(generic)하고 명시적으로 제네릭 파라미터 유형이 지정되지 않고, 제네릭 타입에 대한 기본값이 없다면, 제네릭 파라미터의 값은 호출 인수에서 추론됩니다. 추론은 *반드시* 고유한 값으로 결정되어야 합니다. 여러 개의 후보 값이 나오거나 후보 값이 없으면 호출은 유효하지 않습니다.
\ No newline at end of file
*할당*
할당의 오른쪽은 어떤 종류의 표현일 수 있지만, 왼쪽은 *반드시* 결과가 풀리는 식별자 또는 배열 또는 튜플(또는 그러한 조합)이어야 합니다. 즉, 튜플의 배열은 허용되지만, 호출 및 상수 표현은 왼쪽에서 허용되지 않습니다
우변이 호출일 경우, 좌변 표현식은 *반드시* 호출된 연산의 결과 유형과 구조적으로 동일해야 하거나, 결과의 하위 구조가 좌변의 단일 식별자로 덮일 수 있어야 합니다. 예를 들어, 연산에서 텐서(tensor)의 배열이 나온 경우, 좌변은 *반드시* 식별자의 배열이거나 전체 배열을 단일 식별자로 덮어야 합니다. 그러나 후자의 호출은 결과 배열의 길이가 호출로부터 결정될 수 있는 경우에만 유효합니다. 더 구체적으로, 배열이 원시 연산의 결과라면 정확한 의미론(그리고 형상 추론)을 이해하지 않고서는 결과 배열 길이를 알 수 없으므로 그러한 호출은 유효하지 않습니다. 반면에, 배열이 복합 연산의 결과라면 분해 후 결과 배열은 원시 연산자에 의해 할당되거나 화합물 내부의 배열 표현식에 의해 할당됩니다. 만약 배열 표현식에 의해 할당된다면, 배열의 길이를 결정할 수 있으므로 호출이 유효하지만, 원시 작업에 의해 할당된 경우에는 결정할 수 없으므로 호출이 유효하지 않습니다.
*그래프 및 프래그먼트 본문에서의 식별자 사용법*
유효한 형식 식별자 사용 규칙은 다음과 같습니다: ::
- 프래그먼트의 매개변수는 *반드시* 프래그먼트 본문 내에서 할당의 왼쪽에 표시되어서는 *안 되며*, 할당의 오른쪽에서만 표현식 인수로 사용할 수 있습니다.
- _그래프_ 의 매개변수(암시적으로 텐서 타입을 갖습니다)는 *반드시* `external` 연산의 결과로 정의되어야 합니다. `external` 연산은 *반드시* 프래그먼트 내에서 사용해서는 *안 되며*, `external` 연산의 결과인 모든 텐서는 *반드시* 그래프 매개변수로 정의되어야 합니다 (그래프 매개변수와 외부에서 정의된 텐서 사이의 일대일 매핑)
- 프래그먼트의 결과는 *반드시* 프래그먼트 본문 내에서 정확히 한 번만 할당되어야 합니다.
- 프래그먼트 내부 또는 주요 그래프 내의 로컬(local) 식별자는 *반드시* 후속 할당의 오른쪽 표현식에서 인자로 사용되기 전에 먼저 할당문의 좌변에 나타나야 합니다.
- 동일한 식별자는 *반드시* 할당문의 좌변에 여러 번 사용해서는 *안 됩니다*(프래그먼트 내 또는 주요 그래프 내에서).
- _그래프_ 본문의 모든 개별 식별자는 *반드시* 텐서 유형이어야 합니다. 즉, 텐서 배열, 텐서 튜플 및 원시 유형의 식별자는 허용되지 않습니다. 텐서 배열이나 튜플이 할당문의 좌변에 사용될 때 개별 텐서 식별자를 배열이나 튜플 표현식을 통해 명시적으로 구성해야 합니다.
- `variable` 및 `update` 연산은 *반드시* 프래그먼트 내부에서 사용해서는 *안 됩니다*. 이는 오로지 그래프 본문 안에서만 사용되어야 하며(복합 작업의 결과는 입력에 의해 정의되어야 하며 부작용이 없어야 합니다), 그 외에는 사용되어서는 안 됩니다.
\ No newline at end of file
*Copyright 2017 The Khronos Group Inc.*
이 사양은 저작권법으로 보호되며 Khronos에게 소유권이 있는 자료를 포함하고 있습니다. 이 조건에 따르지 않은 경우 Khronos의 명시적 사전 서면 허가 없이는 해당 내용이나 구성 요소를 재생산, 출판, 배포, 전송, 표시, 방송하거나 그 밖의 방법으로 어떠한 형태로든 이용할 수 없습니다.
이 사양은 Khronos 지적재산권 정책 하에 작성되었으며, 이는 www.khronos.org/files/member_agreement.pdf에서 확인할 수 있는 Khronos 그룹 회원 계약의 부록 A입니다. Khronos는 수정되지 않은 사양을 수수료나 로열티 없이 어떠한 목적으로도 사용하고 재생산할 수 있는 조건부 저작권 라이선스를 부여하지만, 이 조건에 따라 어떠한 특허, 상표 또는 기타 지적재산권에 대한 라이선스는 부여되지 않습니다. 이 사양을 구현하고 해당 구현에 Khronos 상표를 사용하고 Khronos IP 정책에 따른 상호 특허 라이선스 보호를 받기를 원하는 당사자는 해당 사양에 대한 구현을 Khronos에서 정의한 프로세스에 따라 적합하다고 확인하고 구현하기 위해 채택자(Adopter)가 되어야 합니다. 자세한 정보는 https://www.khronos.org/adopters를 참조하세요.
Khronos는 이 사양과 관련하여, 명시적이든 묵시적이든, 상품성, 특정 목적에의 적합성, 지적 재산권의 비침해, 정확성, 완전성, 적시성 및 신뢰성을 포함하여 어떠한 표현이나 보증도 하지 않으며 명시적으로 부인합니다. 어떠한 경우에도 Khronos, 그러니까 Khronos의 프로모터, 기여자, 회원, 그리고 그들의 파트너, 임원, 이사, 직원, 대리인 또는 대표자들은 이 자료와 관련하여 또는 이와 연관하여 상실된 수익, 이익 손실 또는 기타 어떠한 직간접적인 특별 또는 결과적인 손해로 인한 어떠한 손해에 대해서도 책임을 지지 않습니다.
Vulkan은 등록 상표이며, Khronos, OpenXR, SPIR, SPIR-V, SYCL, WebGL, WebCL, OpenVX, OpenVG, EGL, COLLADA, glTF, NNEF, OpenKODE, OpenKCAM, StreamInput, OpenWF, OpenSL ES, OpenMAX, OpenMAX AL, OpenMAX IL, OpenMAX DL, OpenML, 및 DevU는 The Khronos Group Inc.의 상표입니다. ASTC는 ARM Holdings PLC의 상표이며, OpenCL은 Apple Inc.의 상표입니다. OpenGL 및 OpenML은 등록 상표이며, OpenGL ES 및 OpenGL SC 로고는 Silicon Graphics International이 라이선스로 사용하는 Khronos의 상표입니다. 모든 다른 제품 이름, 상표, 그리고/또는 회사 이름들은 식별용으로만 사용되며 해당 소유자들의 소유입니다.
\ No newline at end of file
# *제 1장. 서론*
이 장은 용어를 제외한 전반적인 정보를 제공합니다.
본 문서는 "NNEF 사양" 또는 이후에는 "사양"로 언급되며, 신경망 교환 형식(Neural Network Exchange Format)에 대해 무엇인지, 어떻게 사용되어야 하는지, 생산하거나 사용하기 위해 필요한 것은 무엇인지에 대해 설명합니다. 독자가 최소한의 신경망과 딥 러닝에 대한 기본적인 이해를 가지고 있다고 가정합니다. 이는 신경망 작업과 용어의 기본적인 이해를 의미합니다.
## *1.1. NNEF란*
NNEF는 (훈련된) 신경망에 대한 정보를 교환하기 위한 데이터 형식입니다. 딥러닝이 학술 연구에서 실제 산업 응용 분야로 발전함에 따라 이러한 정보를 표준화된 형식으로 교환하는 것이 불가피해졌습니다. 오픈 소스 딥러닝 프레임워크가 증가하고 신경망 가속화를 위한 하드웨어 지원이 나타나면서, 서로 다른 가속기가 서로 다른 프레임워크와 호환되는 문제로 분열 현상이 발생하고 있습니다. NNEF의 목표는 가속된 신경망 실행 엔진과 사용 가능한 딥러닝 도구를 연결하기 위한 표준 플랫폼을 제공하는 것입니다. 이상적인 상황에서는 딥러닝 프레임워크에서 훈련된 신경망을 NNEF로 내보내고, 신경망 가속기 라이브러리가 모든 딥러닝 프레임워크와의 호환성에 대한 걱정 없이 소비할 수 있을 것입니다.
NNEF는 신경망의 두 가지 핵심 측면인 네트워크 구조와 네트워크 데이터를 캡슐화하는 것을 목표로 합니다. 유연한 방식으로 네트워크 구조를 설명하기 위해 NNEF는 일반적인 신경망 구조를 표현하기 위한 일련의 표준화된 연산과 함께 기존 스크립팅 언어와 유사한 간단한 구문을 도입합니다. 구문은 사람이 읽기 쉽고 편집하기 쉽도록 설계되었으며, 동시에 소비자 라이브러리에서 쉽게 구문 분석될 수 있도록 고안되었습니다. 또한, 구조의 매개변수를 형성하는 네트워크 데이터는 유연한 네트워크의 생성과 사용을 지원하는 간단한 형식으로 저장됩니다. NNEF는 네트워크에 데이터가 공급되는 방식이나 기본 하드웨어의 데이터 표현 및 알고리즘과 같이 훈련 및 추론 과정의 많은 세부 사항에 독립적이면서 신경망 가속기를 프로그래밍할 수 있는 간단한 언어로 생각할 수 있습니다.
NNEF의 주요 초점은 딥 러닝 프레임워크에서 신경망 가속기 라이브러리에 이르는 파이프라인의 중심적인 역할이 되는 것이지만, 우리는 이 형식이 향후 훈련과 실행 과정에서 독립적인 방법으로 신경망을 변환하기 위한 중간 도구로서 사용되어 신경망을 변형할 수 있을 것으로 예상합니다. 따라서 NNEF의 생산자와 소비자는
다양할 수 있지만, 아래에 설명된 두 가지 중요한 하위 범주는 수출자(exporter)와 수입자(importer)입니다.
### *1.1.1. NNEF에 대한 수출자의 관점*
딥러닝 프레임워크와 같은 NNEF의 수출자에게 NNEF는 해당 내부 네트워크 표현을 변환할 수 있는 형식이며, 이후 NNEF를 사용할 수 있는 모든 가속기 라이브러리가 훈련된 네트워크를 실행할 수 있게 됩니다(네트워크가 해당 라이브러리 기능과 일치하는 경우). 이 매핑이 가능한 경우 수출자의 임무는 연산 및 데이터 표현을 NNEF의 작업 및 데이터 표현에 매핑하는 것입니다.
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment