웹 신경망 API

W3C 후보 권고안 초안,

이 문서에 대한 자세한 정보
이 버전:
https://www.w3.org/TR/2026/CRD-webnn-20260521/
최신 공개 버전:
https://www.w3.org/TR/webnn/
편집자 초안:
https://webmachinelearning.github.io/webnn/
이전 버전:
이력:
https://www.w3.org/standards/history/webnn/
구현 보고서:
https://wpt.fyi/results/webnn?label=master&label=experimental&aligned&q=webnn
테스트 스위트:
https://github.com/web-platform-tests/wpt/tree/master/webnn
피드백:
GitHub
명세 내 인라인
편집자:
Ningxin Hu (Intel Corporation)
Dwayne Robinson (Microsoft Corporation)
이전 편집자:
Chai Chaoweeraprasit (Microsoft Corporation)
기타:
구현 상태, 해설서, 샘플

초록

이 문서는 신경망 추론 하드웨어 가속을 위한 전용 저수준 API를 설명한다.

이 문서의 상태

이 절은 이 문서가 공개된 시점의 상태를 설명한다. 현재 W3C 공개 문서 목록과 이 기술 보고서의 최신 개정판은 W3C 표준 및 초안 색인에서 찾을 수 있다.

이 문서는 Web Machine Learning Working Group에 의해 권고안 트랙을 사용하여 후보 권고안 초안으로 공개되었다.

후보 권고안으로 공개되었다는 것이 W3C와 그 회원들의 지지를 의미하지는 않는다. 후보 권고안 초안은 워킹 그룹이 이후 후보 권고안 스냅샷에 포함하려는 이전 후보 권고안의 변경 사항을 통합한다.

이 문서는 초안 문서이며 언제든지 다른 문서로 갱신, 대체 또는 폐기될 수 있다. 진행 중인 작업 이외의 것으로 이 문서를 인용하는 것은 적절하지 않다.

Web Machine Learning Working Group은 그룹이 아직 처리하지 않은 모든 버그 보고서 목록을 유지한다. 미해결 이슈에 대한 제안된 명세 텍스트를 포함한 풀 리퀘스트를 강력히 권장한다.

이 문서는 W3C 특허 정책에 따라 운영되는 그룹에 의해 작성되었다. W3C는 그룹의 산출물과 관련하여 이루어진 모든 특허 공개의 공개 목록을 유지한다. 해당 페이지에는 특허 공개에 대한 지침도 포함되어 있다. 개인이 자신이 믿기에 필수 청구항을 포함하는 특허에 대해 실제로 알고 있는 경우, W3C 특허 정책 6절에 따라 그 정보를 공개해야 한다.

이 문서는 2025년 8월 18일 W3C 프로세스 문서의 적용을 받는다.

후보 권고안 스냅샷 2024년 4월 11일2026년 1월 22일 사이에 WebNN 명세는 100개가 넘는 중요한 변경과 함께 상당한 진화를 거쳤다. 가장 주목할 만한 추가 사항에는 향상된 트랜스포머 지원을 위한 세 번째 오퍼레이터 물결, 버퍼 공유를 위한 MLTensor API, 그리고 새로운 추상 장치 선택 메커니즘이 포함된다. API 표면은 현대화되었으며, 더 넓은 구현 경험과 개발자 피드백에 기반하여 상호 운용성 개선이 이루어졌다. 이 명세 버전은 핑거프린팅 완화를 포함한 보안 및 개인정보 보호 고려 사항을 강화하고, 새로운 접근성 고려 사항을 추가한다. 이러한 변경은 향상된 개발자 인체공학, 더 넓은 백엔드 호환성 및 표준 준수를 통해 제품 준비 상태를 향한 명세의 성숙을 반영한다. 자세한 내용은 § 14 변경 사항을 참조하라.

이 문서는 유지 관리되며 언제든지 갱신된다. 이 문서의 일부는 진행 중인 작업이며, 추가 개선 사항이 개정된 후보 권고안 초안 및 스냅샷에 반영될 것으로 예상된다.

제안 권고안으로 전환을 요청하기 전에, 워킹 그룹은 다음을 입증하고자 할 것이다.

1. 소개

Web Neural Network API는 플랫폼별 기능에 묶이지 않고 운영 체제와 기반 하드웨어 플랫폼의 기계 학습 기능을 활용하는 웹 친화적인 하드웨어 불가지론적 추상화 계층을 정의한다. 이 추상화 계층은 주요 기계 학습 JavaScript 프레임워크의 요구 사항을 다루며, ML 도메인에 익숙한 웹 개발자가 라이브러리의 도움 없이 사용자 지정 코드를 작성할 수도 있게 한다.

그림을 곁들인 소개는 해설서를 참조하라.

2. 사용 사례

2.1. 애플리케이션 사용 사례

이 절은 신경망 추론 하드웨어 가속을 위한 애플리케이션 수준의 사용 사례를 보여준다. 이러한 사용 사례의 모든 애플리케이션은 사전 훈련된 심층 신경망(DNN) [models] 위에 구축될 수 있다.

참고: 여기에 설명된 일부 사용 사례는 그 본질상 개인정보 침해적일 수 있다는 점을 유의하라. 이러한 사용 사례에 API를 사용하려는 개발자는 API가 사용자가 이해하고 승인한 목적을 위해, 사용자에게 이익이 되도록 사용되고 있음을 보장해야 한다. 개발자는 [webmachinelearning-ethics] Web Machine Learning 윤리 원칙을 적용하고, 투명성, 데이터 최소화, 사용자 제어와 같은 적절한 개인정보 위험 완화 조치를 구현해야 한다.

참고: § 3 접근성 고려 사항은 이러한 사용 사례의 접근성을 개선하는 방법에 대한 지침을 제공한다.

2.1.1. 사람 감지

사용자가 웹 기반 화상 회의 애플리케이션을 열었지만, 잠시 방을 비운다. 애플리케이션은 객체 감지(예를 들어, 단일 DNN을 사용하는 [SSD] 또는 [YOLO]와 같은 객체 감지 접근 방식)를 사용하여 사람이 포함된 카메라 입력 프레임의 영역을 감지함으로써, 그녀가 PC 앞에 있는지 감시한다.

그녀가 돌아오면, 애플리케이션은 자동으로 그녀를 감지하고 다른 온라인 사용자에게 그녀가 이제 활성 상태임을 알린다.

2.1.2. 의미론적 세그멘테이션

사용자는 사무실에 회의실이 없어 자신의 책상에서 웹 기반 화상 회의 애플리케이션을 통해 원격 회의에 참여한다. 원격 회의 중에 그녀는 자신의 방과 배경의 사람들이 보이지 않기를 원한다. 다른 사람들과 주변 환경의 개인정보를 보호하기 위해, 애플리케이션은 [DeepLabv3+], [MaskR-CNN] 또는 [SegAny]와 같은 기계 학습 모델을 실행하여 이미지를 의미론적으로 세그먼트로 나누고, 다른 사람과 배경을 나타내는 세그먼트를 다른 그림으로 대체한다.

2.1.3. 골격 감지

웹 기반 화상 회의 애플리케이션은 실시간 사람 자세 추정을 가능하게 하는 [PoseNet]과 같은 기계 학습 모델을 실행하여 사용자의 골격 자세를 추적하고, 그녀의 제스처와 몸짓 언어를 인식한다. 그녀가 손을 들면, 마이크 음소거가 자동으로 해제되고 원격 회의에서 말하기를 시작할 수 있다.

2.1.4. 얼굴 인식

회의실에 여러 사람이 있으며, 이들은 웹 기반 화상 회의 애플리케이션을 사용하여 온라인 회의에 참여한다. 애플리케이션은 객체 감지(예를 들어, [SSD]와 같은 객체 감지 접근 방식)를 사용하여 참가자의 얼굴을 감지하고, [FaceNet]과 같은 두 얼굴이 동일한지 여부를 검증하는 기계 학습 모델을 실행하여 각 얼굴이 이전 회의에 있었는지 여부를 확인한다.

2.1.5. 얼굴 랜드마크 감지

사용자는 온라인 안경 매장에서 자신에게 아름답게 어울리는 새 안경을 찾고 싶어 한다. 온라인 매장은 Face Alignment Network [FAN] 와 같은 기계 학습 모델을 실행하여 눈, 코, 입 등과 같은 얼굴 랜드마크를 감지하는 웹 기반 착용 시뮬레이터를 제공한다. 그녀가 안경을 선택하면, 시뮬레이터는 그녀의 얼굴 이미지에서 감지된 눈 위치에 선택된 안경을 적절히 렌더링한다.

2.1.6. 스타일 전이

사용자는 온라인 매장에서 화장품을 찾고 있으며 어떤 색상이 자신의 얼굴에 어울릴지 궁금해한다. 온라인 매장은 화장품의 샘플 얼굴 메이크업 이미지를 보여주고, [ContextualLoss] 또는 [PairedCycleGAN] 과 같은 기계 학습 모델을 실행하여 샘플 메이크업 이미지의 메이크업 스타일을 그녀의 얼굴 이미지로 전이하는 메이크업 시뮬레이터를 제공한다. 그녀는 시뮬레이터를 통해 선택한 메이크업이 자신의 얼굴에 어떻게 보이는지 확인할 수 있다.

2.1.7. 초해상도

웹 기반 화상 회의가 피어로부터 동영상 스트림을 수신하고 있지만, 네트워크 혼잡으로 인해 동영상의 해상도가 낮아진다. 지각되는 동영상 품질의 저하를 방지하기 위해, 애플리케이션은 [SRGAN] 과 같은 초해상도용 기계 학습 모델을 실행하여 더 높은 해상도의 동영상 프레임을 생성한다.

2.1.8. 이미지 캡션 생성

더 나은 접근성을 위해, 웹 기반 프레젠테이션 애플리케이션은 프레젠테이션 슬라이드의 설명 단어를 예측하는 [im2txt] 와 같은 기계 학습 모델을 실행하여 자동 이미지 캡션 생성을 제공한다.

2.1.9. 텍스트-이미지

이미지는 현대 웹 경험의 핵심 부분이다. 개인정보 보호 방식으로 텍스트 입력을 기반으로 이미지를 생성할 수 있는 능력은 웹 애플리케이션과 콘텐츠의 시각적 개인화와 적응을 가능하게 한다. 예를 들어, 웹 애플리케이션은 웹 페이지의 자연어 설명 또는 사용자가 텍스트 프롬프트 내에서 제공한 설명을 입력으로 사용하여 해당 텍스트 설명과 일치하는 이미지를 생성할 수 있다. 잠재 확산 모델 아키텍처 [LDM]에 의해 가능해지는 이 텍스트-이미지 사용 사례는 추가적인 텍스트-이미지 사용 사례의 기반을 형성한다. 예를 들어, 웹 페이지의 기존 이미지 일부를 새로 생성된 콘텐츠를 사용해 선택적으로 수정하는 인페인팅, 또는 그 반대인 아웃페인팅에서는 원본 이미지를 원래 크기 너머로 확장하고 빈 공간을 생성된 콘텐츠로 채운다.

2.1.10. 기계 번역

여러 나라의 여러 사람이 웹 기반 실시간 텍스트 채팅 애플리케이션을 통해 대화하고 있다. 애플리케이션은 모든 텍스트를 다른 언어로 번역하는 [GNMT] 또는 [OpenNMT]와 같은 기계 학습 모델을 사용하여 그들의 대화를 번역한다.

2.1.11. 감정 분석

사용자가 웹 기반 실시간 텍스트 채팅 애플리케이션을 통해 친구와 대화하고 있으며, 친구의 얼굴을 볼 수 없기 때문에 그 친구가 어떻게 느끼는지 궁금해한다. 애플리케이션은 입력 텍스트에서 감정을 추론하는 [DeepMoji] 와 같은 기계 학습 모델을 사용하여 친구의 감정을 분석하고, 추정된 감정을 나타내는 이모지를 표시한다.

2.1.12. 동영상 요약

웹 기반 화상 회의 애플리케이션은 수신된 동영상 스트림을 녹화하며, 저장할 녹화 동영상 데이터를 줄여야 한다. 애플리케이션은 [Video-Summarization-with-LSTM]과 같은 동영상 요약용 기계 학습 모델을 사용하여 녹화된 동영상의 짧은 버전을 생성한다.

2.1.13. 잡음 억제

웹 기반 화상 회의 애플리케이션은 수신된 오디오 스트림을 녹음하지만, 일반적으로 배경 잡음은 어디에나 있다. 애플리케이션은 화상 회의의 오디오 경험을 개선하기 위해, 아기 울음소리나 개 짖는 소리와 같은 배경 동적 잡음을 억제하는 데 [RNNoise]와 같은 순환 신경망을 사용하는 실시간 잡음 억제를 활용한다.

2.1.14. 음성 인식

speech to text라고도 알려진 음성 인식은 말해진 언어를 텍스트로 인식하고 변환할 수 있게 한다. 음성 인식의 예시 애플리케이션에는 전사, 자동 번역, 멀티모달 상호작용, 실시간 캡션 및 가상 비서가 포함된다. 음성 인식은 청각 콘텐츠의 접근성을 개선하고, 개인정보 보호 방식으로 이러한 콘텐츠와 텍스트 형식으로 상호작용할 수 있게 한다. 일반적인 사용 사례의 예로는 동영상 시청 또는 실시간 캡션을 사용한 온라인 회의 참여가 있다. [Whisper]와 같은 모델은 정확도와 견고성에서 인간에 가까워지고 있으며, 이러한 사용 사례의 접근성을 개선하기에 적합하다.

2.1.15. 텍스트 생성

다양한 텍스트 생성 사용 사례는 텍스트 시퀀스에서 다음 항목을 예측하는 일반적인 능력이 필요한 작업을 수행할 수 있는 대규모 언어 모델(LLM)에 의해 가능해진다. 이 모델 클래스는 텍스트를 번역하고, 텍스트 입력을 기반으로 질문에 답하고, 더 큰 본문을 요약하거나, 텍스트 입력을 기반으로 텍스트 출력을 생성할 수 있다. LLM은 RNN, CNN 또는 LSTM 아키텍처를 기반으로 한 이전 모델에 비해 더 나은 성능을 가능하게 하며, 이 절에서 논의된 많은 다른 사용 사례의 성능을 더욱 향상시킨다. LLM의 예에는 [t5-small], [m2m100_418M], [gpt2], 그리고 [llama-2-7b]가 포함된다.

2.1.16. 가짜 동영상 감지

사용자는 웹에서 ‘deepfake’로 생성된 사실적인 가짜 동영상에 노출된다. 가짜 동영상은 사용자를 정치적으로 선동하거나 사용자의 의견을 조작하기 위해 화자의 얼굴을 대통령의 얼굴로 바꿀 수 있다. [FaceForensics++]와 같은 deepfake 감지 애플리케이션은 동영상을 분석하고 사용자를 가짜 동영상이나 이미지로부터 보호한다. 사용자가 웹에서 가짜 동영상을 시청할 때, 감지 애플리케이션은 실시간으로 해당 사기 동영상을 사용자에게 경고한다.

2.2. 프레임워크 사용 사례

이 절은 신경망 추론 하드웨어 가속을 위한 전용 저수준 API에 대한 프레임워크 수준의 사용 사례를 모은다. 기계 학습 프레임워크가 Web Neural Network API(WebNN API)의 주요 소비자가 될 것으로 예상되며, WebNN API를 통해 노출되는 저수준 세부 사항은 일반적인 웹 개발자로부터 추상화된다. 그러나 기계 학습에 특정한 관심과 역량을 가진 웹 개발자는 더 높은 수준의 ML 프레임워크 대신 WebNN API와 직접 인터페이스하기를 원할 것으로도 예상된다.

2.2.1. 사용자 지정 계층

웹 애플리케이션 개발자는 WebNN API에서 DNN 모델을 실행하고 싶어 한다. 그러나 그녀는 [LeakyReLU], [ELU] 등과 같은 일부 활성화 함수가 WebNN API에 포함되어 있지 않다는 것을 발견했다. 이 문제를 해결하기 위해, 그녀는 추가 활성화 함수를 WebNN API 위에 사용자 지정 계층으로 구성한다. 사용자 지정 계층의 범위에는 활성화뿐만 아니라 컨볼루션, 정규화 등도 포함될 수 있음을 유의하라.

2.2.2. 네트워크 연결

웹 애플리케이션은 DNN 모델을 사용하며, 그 모델 데이터 중 상위 컨볼루션 계층과 하위 완전 연결 계층은 별도의 파일에 저장된다. 이는 완전 연결 계층의 모델 데이터가 서버 측의 미세 조정으로 인해 주기적으로 갱신되기 때문이다.

따라서 애플리케이션은 처음에 두 부분 모델 파일을 모두 다운로드하고 이를 단일 모델로 연결한다. 모델이 갱신되면, 애플리케이션은 모델의 미세 조정된 부분을 다운로드하고 완전 연결 계층만 그것으로 대체한다.

2.2.3. 성능 적응

웹 애플리케이션 개발자는 모바일 기기에서 자신의 DNN 모델의 성능에 대해 우려하고 있다. 그녀는 GPU 가속이 없는 모바일 기기에서는 모델이 너무 느리게 실행될 수 있음을 확인했다. 이 문제를 해결하기 위해, 그녀의 웹 애플리케이션은 WebNN API를 참조하여 가속이 사용 가능한지 여부를 확인하고, 가속이 없는 기기에 경고를 표시할 수 있게 한다.

몇 주 후, 그녀는 CPU에서도 실행될 수 있는 작은 DNN 모델을 개발했다. CPU 실행을 수용하기 위해, 그녀는 CPU 전용 기기의 경우 애플리케이션이 작은 모델을 로드하도록 애플리케이션을 수정한다.

2.2.4. 연산 수준 실행

JavaScript ML 프레임워크는 ML 모델을 로드하고, 해석하고, 실행하는 일을 담당한다. 모델 실행 단계에서, 프레임워크는 모델의 연산을 반복하고 각 연산을 CPU, GPU 또는 ML 가속기와 같은 하드웨어 기기에서 실행한다. 기기 간 불필요한 데이터 복사를 피하기 위해, 프레임워크는 연산을 실행할 동일한 기기를 선택한다. 컨볼루션 2D 또는 행렬 곱셈과 같은 계산 집약적 연산의 경우, 프레임워크는 선택된 기기에서 사용할 수 있는 ML 특화 가속으로 이를 실행하기 위해 WebNN API를 사용한다.

2.2.5. 실시간 동영상 처리와의 통합

WebRTC 기반 화상 회의의 사용자 경험은 실시간 동영상 처리를 사용하여 향상된다. 예를 들어, § 2.1.2 의미론적 세그멘테이션 모델을 사용하여 구현된 배경 흐림은 사용자의 실시간 카메라 피드에서 배경을 흐리게 한다. 이 사용 사례의 성능 요구 사항을 충족하기 위해, WebNN API는 WebNN API 기반 실시간 동영상 스트림 변환을 허용하도록 미디어 파이프라인을 구성하는 다른 Web API의 프리미티브와 통합된다.

3. 접근성 고려 사항

이 절은 신경망 추론 하드웨어 가속으로 가능해지는 § 2.1 애플리케이션 사용 사례의 접근성을 개선하는 방법에 대해 웹 작성자에게 지침을 제공한다. 이 지침은 이 명세에 개요로 제시된 특정 사용 사례를 넘어 일반화되며, 웹 작성자는 추가 접근성 지침을 위해 [wcag]를, 윤리적 원칙의 맥락에서 디지털 접근성을 위해 § 6 윤리적 고려 사항을 참조할 것이 권장된다.

§ 2.1.8 이미지 캡션 생성은 캡션이 스크린 리더 및 기타 보조 기술(AT) 사용자에게 제공되도록 보장함으로써 개선될 수 있다. 웹 작성자는 생성된 이미지 캡션이 각각의 이미지와 의미론적으로 연결되도록 보장할 것이 권장된다. 표준 alt 속성을 통해 연결하거나, 설명이 초기 페이지 로드 시 갱신되는지 또는 나중에 사용자 동작의 결과로 갱신되는지에 따라 달라질 수 있는 다른 방법을 사용할 수 있다.

§ 2.1.11 감정 분석은 사용자를 잘못 레이블링하고 따라서 잘못 분류하여 차별적인 경험으로 이어질 수 있다. 웹 작성자는 신뢰도 점수를 노출하고 사용자에게 해당 기능을 끌 수 있는 선택권을 제공할 것이 권장된다.

§ 2.1.13 잡음 억제는 공격적인 필터를 사용할 경우 구음 장애가 있는 사용자의 말을 제거하여 캡션과 인식이 실패하게 만들 수 있다. 웹 작성자는 우회 또는 민감도 제어를 노출하고, 실시간 캡션이 활성화된 경우 잡음 억제를 고정하지 않을 것이 권장된다.

§ 2.2.5 실시간 동영상 처리와의 통합에서 배경 흐림 기반 세그멘테이션은 방해 요소를 제거하는 데 도움이 되지만, 입술 읽기와 실시간 캡션을 방해할 만큼 지연을 너무 많이 추가할 수 있다. 웹 작성자는 사용자-facing 키보드 및 스크린 리더로 조작 가능한 “배경 흐림 켜기/끄기” 제어를 다른 접근성/미디어 설정 옆에 표시할 수 있는 기능을 제공할 것이 권장된다.

§ 7.2 장치 선택은 웹 작성자가 실행 속도와 전력 소비에 대한 선호를 나타낼 수 있게 한다. 구현자는 저사양 또는 배터리에 민감한 기기의 사람들이 특히 휴대용 AAC 또는 시선 추적 설정에서 캡션 및 기타 중요한 접근성 기능을 계속 반응성 있게 유지할 수 있도록, 브라우저 UI에서 사용자가 웹 작성자의 힌트를 재정의할 수 있게 할 것이 권장된다.

4. 보안 고려 사항

이 명세는 신경망 추론 하드웨어 가속을 위한 저수준 API를 정의한다. 이 API는 사용자의 컴퓨터에 대한 저수준 접근을 부여하기 때문에 강력한 기능 [POWERFUL-FEATURES]으로 간주된다. 강력한 기능의 인증 및 기밀성 기대 사항을 충족하고 중간자 공격을 방지하기 위해, 이 명세에서 정의하는 모든 인터페이스는 보안 컨텍스트에서만 사용할 수 있다.

이 API는 § 7.5 Permissions Policy 통합을 사용하여 모든 교차 출처 프레임에서 기본적으로 비활성화된다. 이는 임베딩 페이지가 권한을 부여하는 정책을 명시적으로 설정하지 않는 한 서드파티 콘텐츠가 이 API를 사용하는 것을 방지한다.

이 API는 WebGPU 명세에서 정의한 GPUDevice로부터 MLContext를 생성할 수 있게 한다. 이 컨텍스트의 보안 특성에 대한 자세한 내용은 WebGPU 보안 고려 사항을 참조하라.

이 API는 GPU, CPU 및 전용 ML 가속기 하드웨어 전반에 대한 추상화를 제공한다. GPU를 사용할 때는 WebGPU와 유사한 서비스 거부 고려 사항이 적용된다. CPU 또는 전용 ML 가속기를 사용할 때는 잠재적 리소스 경합의 유형이 다르며, 완화 조치는 구현 및 구성에 따라 달라진다. 구현은 사이트가 시스템 리소스를 불공정하게 많이 사용하는 것을 방지하기 위해 플랫폼에서 사용할 수 있는 어떤 메커니즘이든 사용해야 한다. 이러한 계산 유닛은 공유 리소스이며, 어떤 계산 API의 사용도 부하가 가득 찬 시스템의 전체 성능에 영향을 미친다.

그래프가 완전히 구성되고 컴파일되면, 그래프 내 각 연산으로 들어가는 입력 형태가 추론되고 확정된다. 실제 데이터에 대해 그래프를 실행하는 compute 메서드가 호출될 때 경계 검사가 발생한다. 이 단계 이전에는 실제 데이터가 컴파일된 그래프에 바인딩되지 않는다. 그 시점까지 이미 추론된 데이터의 형태에 대해 적절한 경계 검사가 이루어지도록 보장하는 것은 구현의 책임이다.

구현자에 대한 지침으로 범위 밖 접근에 취약한 연산을 문서화한다.

구현은 상수로 간주되는 데이터의 변경에 기반한 제어 흐름 공격을 방어해야 한다. 예를 들어, 기반 플랫폼의 최적화는 계산 전체에서 가중치가 변경되지 않는다고 가정할 수 있다. API가 계산 중에 가중치를 보관하는 버퍼의 내용을 변경할 수 있게 한다면, 이러한 최적화 가정은 무효화되어 기반 플랫폼에서 정의되지 않은 동작을 일으킬 수 있다. API는 항상 버퍼를 복사하거나 전송함으로써 스크립트로부터 발생하는 이 공격 범주를 완화하지만, 구현은 상수로 간주되는 데이터의 프로세스 격리와 같은 추가 방어를 고려해야 한다.

미래 대비 조치로, API 설계는 일반적으로 에뮬레이션될 수 있는 특정 연산이 보안, 성능 또는 기타 이유로 호환성을 깨뜨리지 않고 폐기될 수 있게 한다. 이는 이 명세에서 정의된 더 작은 프리미티브 연산으로 정의되는 고수준 함수에 의해 가능해진다. 이를 통해 고수준 함수의 네이티브 구현을 폴리필 구현으로 대체할 수 있다.

CPU가 렌더러를 실행하는 프로세스 간에 공유되는 현재 상태를 고려하여 사이드 채널 공격의 실현 가능성을 조사한다.

공격자가 결함을 포함할 수 있는 특정 구현을 표적으로 삼지 못하게 하기 위해, § 7.2 장치 선택 메커니즘은 힌트일 뿐이며, 구체적인 장치 선택은 구현에 맡겨진다. 예를 들어 사용자 에이전트는 알려진 취약점이 있는 장치에서 모델을 절대 실행하지 않도록 선택할 수 있다. 추가 완화 조치로, 장치 열거 메커니즘은 정의되지 않는다.

힌트 제공은 이 우려를 부분적으로 완화한다. 추가 완화 조치를 조사한다.

API 설계는 컴파일된 계산 그래프의 공격 표면을 최소화한다. 다양한 연산을 호스트하는 MLGraphBuilder 인터페이스는 데이터 정의 API이며, 따라서 아무것도 실행하지 않고 데이터만 구성한다. 그 결과 공격 가능성은 MLContext.dispatch() 메서드를 호출하여 실행하기 전에 데이터를 그래프에 바인딩할 때로 제한된다. 이를 통해 구현자는 MLContext.dispatch() 메서드를 강화하는 데 집중할 수 있다. 예를 들어, 데이터의 경계를 준수하고 경계가 지켜지지 않을 때 적절히 실패하도록 보장할 수 있다.

고해상도 시간을 측정하기 위한 목적 특화 Web API는 해상도 감소, 지터 추가, 남용 감지 및 API 호출 제한과 같은 기법을 사용하여 타이밍 공격을 완화한다 [hr-time-3]. WebNN 구현의 실제 배포는 타이밍 공격을 비현실적으로 만들기에 충분한 지터를 가져올 가능성이 높지만 (예: IPC를 사용하기 때문), 구현자는 자신의 구현을 타이밍 공격에 대해 고려하고 테스트할 것이 권고된다.

참고: Unicode 시퀀스와 관련된 보안 위험은 label USVString 정의의 맥락에서 논의된다.

4.1. 새 연산에 대한 지침

이 절은 비규범적이다.

이 명세에서 정의되는 연산이 안전하게 구현될 수 있는 방식으로 형성되도록 보장하기 위해, 이 절은 구현 문제의 가능성을 줄이도록 연산이 어떻게 정의될 것으로 예상되는지에 대한 지침을 포함한다. 이러한 지침은 업계 모범 사례와 맞추기 위해 시간이 지남에 따라 진화할 것으로 예상된다.

일반적으로 새 기능을 추가할 때는 Technical Architecture Group과 Privacy Interest Group이 [security-privacy-questionnaire]에 문서화한 보안 및 개인정보 보호 영향을 항상 고려한다.

5. 개인정보 보호 고려 사항

이 API는 민감한 사용자 데이터를 브라우저의 샌드박스 내에 유지함으로써 클라우드 기반 추론 대안에 비해 개인정보 보호 개선을 제공한다. 이미지, 오디오, 동영상 스트림 및 기타 개인정보와 같은 입력 데이터는 사용자의 장치를 떠나지 않으므로, 원격 서버로의 데이터 전송 및 서드파티 데이터 처리와 관련된 위험을 제거한다.

그러나 하드웨어 가속 기능과 밀접하게 상호작용하는 강력한 로컬 계산 API로서, WebNN API는 성능 최적화와 개인정보 보호 사이의 균형을 맞춰야 한다. 이 API는 효과적인 기계 학습 추론 기능을 가능하게 하면서도 핑거프린팅을 완화하기 위한 여러 개인정보 보호 조치를 포함한다.

5.1. 핑거프린팅

설계상, 이 API는 식별된 § 2 사용 사례를 최상의 성능과 결과의 신뢰성으로 다루기 위해 필요한 최소한의 정보만 노출하는 것을 목표로 한다. 첫째, API는 표준화를 통해 핑거프린팅을 완화한다. 즉, 다양한 플랫폼 API 전반에서 일관된 동작을 정의하고, 적합한 구현 전반에서 기반 하드웨어 변동에 관한 정보 누출을 최소화한다. 이는 다음을 통해 달성된다.

전체 설계는 구현이 서로 다른 플랫폼 전반에서 일관된 인터페이스를 유지하면서 필요한 기능을 제공하도록 보장한다. 플랫폼별 세부 사항을 추상화함으로써, API는 기반 가속이 CPU, GPU 또는 전용 ML 하드웨어에 의해 제공되는지 여부와 관계없이 개인정보 보호를 유지하는 예측 가능한 동작을 제공할 수 있다.

참고: MLContextOptions 는 활발히 개발 중이며, 더 많은 구현 경험과 더 넓은 웹 커뮤니티의 새로운 사용 사례를 바탕으로 설계가 변경될 것으로 예상된다.

MLGraph.devices API 확장이 그래프가 완전히 구성되고 컴파일된 후 실행을 위해 실제로 선택된 장치를 노출하도록 제안되었다. 이 API 확장의 개인정보 보호 영향은 조사 중이다. [Issue #836]

5.2. 실행 시간 분석

연산의 타이밍 특성은 기반 하드웨어 성능에 대한 일부 간접 정보를 제공할 수 있으며, 이는 모든 계산 API에 내재된 특징이다. 특정 상황에서 실행 시간 분석은 한 기반 플랫폼의 신경망 하드웨어 가속 기능 성능을 다른 기반 플랫폼에 비해 간접적으로 드러낼 수 있다. 타이밍 공격에 대한 추가 논의는 § 4 보안 고려 사항도 참조하라.

참고: 그룹은 제안된 실행 시간 분석 핑거프린팅 벡터와 완화 조치에 대한 추가 의견을 환영한다.

5.3. WebGPU 비교

WebGPU와 달리, 이 API는 본질적으로 사용자 지정 셰이더 작성을 지원하지 않는다. 따라서 셰이더 캐시 또는 기타 지속적 데이터에 의존하는 타이밍 공격에 취약하지 않다. 이 API는 브라우저 또는 기반 OS의 기존 셰이더와 저수준 프리미티브 위에 구축된다. GPUDevice 와 인터페이스하는 웹 개발자는 WebGPU 컴파일 캐시 고려 사항을 알고 있을 것으로 기대된다.

WebGPU API는 기계별 아티팩트를 개인정보 보호 고려 사항으로 식별한다. 마찬가지로, WebNN API의 계산 유닛 스케줄링은 특정 상황에서 핑거프린트를 도입할 수 있다. 그러나 WebGPU와 유사하게, 이러한 핑거프린트는 각 벤더의 대부분 또는 모든 장치에서 동일하므로 우려를 완화한다. 또한 소프트웨어 구현을 사용하여 이러한 아티팩트를 추가로 제거할 수 있다.

일반적으로 이 API의 구현자는 해당되는 경우 자신의 구현에 WebGPU 개인정보 보호 고려 사항을 적용할 것으로 기대된다.

6. 윤리적 고려 사항

워킹 그룹은 규범적 명세가 어떤 완화 조치를 고려해야 하는지 식별하는 데 도움을 주기 위해, 웹에서 기계 학습을 사용하는 것과 관련된 윤리적 문제를 문서화하기 시작했다. 워킹 그룹은 더 넓은 커뮤니티가 전용 GitHub 저장소를 통해 기여할 수 있는 Web Machine Learning 윤리 원칙 문서 [webmachinelearning-ethics]를 공개하고 유지한다.

7. 프로그래밍 모델

7.1. 개요

신경망의 핵심에는 수학적 연산의 계산 그래프가 있다. 이러한 연산은 컴퓨터 비전, 자연어 처리 및 로보틱스에서 현대 기계 학습 기술의 구성 요소이다. WebNN API는 신경망의 계산 그래프를 구성, 컴파일 및 실행하기 위한 명세이다.

MLGraph 인터페이스는 불변인 컴파일된 계산 그래프(즉, 모델)를 나타낸다.

MLGraphBuilder 인터페이스는 계산 그래프(그 그래프)를 구성하는 빌더(factory) 역할을 하며, 이후 컴파일되어 MLGraph를 생성한다.

WebNN에서 계산 그래프는 데이터에 작용하며 그래프의 노드인 오퍼레이터로 구성된다. MLOperand들은 계산 그래프 내에서 흐르는 데이터의 표현이며, 그래프의 간선이다. MLOperand들은 추론을 위한 계산 그래프입력 값, 추론에 사용되는 상수(훈련된 가중치 포함), 추론 중에 계산되는 중간 값(흔히 활성화라고 함), 그리고 추론의 출력 값을 포함한다. 오퍼레이터입력은 하나 이상의 MLOperand이다. 오퍼레이터출력은 하나 이상의 MLOperand이다. 오퍼레이터는 그 동작을 제어하는 오퍼레이터별 매개변수를 가지며, 여기에는 0개 이상의 활성화 함수가 포함될 수 있다.

MLGraphBuilder 인터페이스의 핵심 부분은 gemm()relu() 와 같은 메서드이다. 이 메서드들은 계산이 실행될 때 입력 데이터에 수행할 실제 연산을 나타내는 오퍼레이터를 생성하고, 해당 오퍼레이터를 보유하는 새 MLOperand를 반환한다. MLOperand를 생성하는 메서드는 모든 입력활성화를 오퍼레이터에 연결한다. 각 메서드 호출은 다른 어떤 MLOperand의 값도 변경하지 않고, 구별되는 새 값을 반환한다.

오퍼레이터레이블을 가지며, 이는 예외 메시지와 같은 진단에 포함될 수 있는 문자열이다. 오퍼레이터가 생성될 때 그 레이블구현 정의 방식으로 초기화되며, 전달된 label을 포함할 수 있다.

dispatch() 중 오류를 보고하기 위한 메커니즘 추가를 고려한다. [Issue #778]

추론 시, 모든 MLOperand는 본질적으로 다차원 배열인 텐서(실제 데이터)에 바인딩된다. 텐서의 표현은 구현에 따라 다르지만, 일반적으로 어떤 버퍼(메모리)에 저장된 배열 데이터와 배열 데이터(예: 그 형태)를 설명하는 일부 메타데이터를 포함한다.

계산 그래프 내 연산은 함수적 의미론을 가진다. 이를 통해 구현은 여러 텐서 간에 배열 데이터를 잠재적으로 공유할 수 있다. 예를 들어, reshape 또는 slice와 같은 연산의 구현은 입력 텐서와 동일한 버퍼를 공유하는 입력 텐서의 뷰를 반환할 수 있다. (reshape의 경우 전체 데이터가 공유되는 반면, slice의 경우 입력 데이터의 일부가 공유된다.) 구현은 위와 같은 뷰를 중간 값에 사용할 수 있다.

실행 전에, 하나 이상의 지정된 출력을 계산하는 데 사용되는 계산 그래프는 변환, 컴파일 및 최적화되어야 한다. 컴파일 단계의 핵심 목적은 연산 또는 루프 융합과 같이 둘 이상의 연산에 걸친 최적화를 가능하게 하는 것이다. 사용자 에이전트는 그래프 변환 중에도 이러한 최적화를 수행할 수 있다.

MLGraphBuilder.build() 메서드는 호출 스레드를 차단하지 않고 백그라운드에서 그래프를 컴파일하며, Promise를 반환한다. 이 Promise는 MLGraph로 resolve된다. 각 MLGraphBuilder는 최대 하나의 MLGraph만 빌드할 수 있다.

MLGraph 기반 구현은 MLGraphBuilder오퍼레이터MLOperand들에 대응하는 오퍼레이터와 피연산자의 플랫폼별 표현으로 구성되지만, 이는 스크립트에 보이지 않으며 스크립트가 구성한 그래프의 합성 또는 분해일 수 있다.

MLGraph가 구성되면, MLContext.dispatch() 메서드는 CPU 실행을 위한 별도의 워커 스레드의 병렬 타임라인 또는 GPU 명령 큐의 GPU 타임라인에서 비동기적으로 그래프 실행을 수행한다. 이 메서드는 실제 실행이 다른 타임라인으로 오프로딩되는 동안 호출 스레드를 차단하지 않고 즉시 반환한다. 호출자는 MLNamedTensors를 사용하여 입력 값을 제공하며, 입력 MLOperand들을 그 값에 바인딩한다. 호출자는 또한 출력 MLOperand를 위한 MLNamedTensors도 제공한다. 이는 그래프 실행이 성공할 경우 그 결과를 포함하며, 이 결과는 MLContext.readTensor(tensor) 메서드를 사용하여 스크립트로 다시 읽어 올 수 있다. 이러한 유형의 실행은 CPU, GPU 및 NPU 장치를 지원한다.

7.2. 장치 선택

MLContext 인터페이스는 신경망 실행의 전역 상태를 나타낸다. 중요한 컨텍스트 상태 중 하나는 리소스를 관리하고 신경망 그래프의 컴파일과 최종 실행을 용이하게 하는 기반 실행 장치이다. MLContextOptions를 사용하는 기본 생성 방법 외에도, MLContext는 애플리케이션에서 이미 사용 중인 특정 GPUDevice로부터 생성될 수도 있다.

GPU 컨텍스트가 시스템 메모리의 상수 또는 입력을 ArrayBufferView로 사용하여 그래프를 실행하는 상황에서, 입력 콘텐츠는 시스템 메모리에서 GPU 메모리로 자동 업로드되고, 그래프 실행이 끝날 때 ArrayBufferView 출력 버퍼의 시스템 메모리로 다시 다운로드된다. 이 데이터 업로드 및 다운로드 사이클은 GPU의 경우처럼 실행 장치가 데이터를 시스템 메모리 밖으로 복사하고 다시 시스템 메모리로 복사해야 할 때에만 발생한다. 장치가 CPU 장치인 경우에는 발생하지 않는다. 또한 그래프 실행의 결과는 알려진 레이아웃 형식이다. 실행은 그래프 내 중간 결과에서 네이티브 메모리 접근 패턴에 맞게 최적화될 수 있지만, 호출자의 관점에서 기대되는 동작을 유지하기 위해 그래프의 마지막 연산 출력은 그래프 끝에서 콘텐츠를 알려진 레이아웃 형식으로 다시 변환해야 한다.

MLContextMLContextOptions로 생성될 때, 사용자 에이전트는 이러한 옵션을 고려하여 기반 실행 장치를 선택하고 생성한다.

기반 플랫폼에 따라, 사용자 에이전트는 CPU, NPU 및 GPU 장치의 다양한 조합을 선택할 수 있다.

이 설계의 이력과 근거는 장치 선택 해설서를 참조하라.

7.3. 오퍼레이터

이 절은 비규범적이다.

WebNN API는 주요 § 2.1 애플리케이션 사용 사례를 다루는 잘 알려진 CNN 및 RNN, 트랜스포머와 생성 모델에 필요한 오퍼레이터 집합을 정의한다. 각 오퍼레이터의 세부 사항은 이 명세의 규범적 절에서 오퍼레이터 이름의 알파벳 순서로 정의된다. 이러한 오퍼레이터는 API 표면의 기능적 개요를 제공하기 위해 다음 비규범적 표에서 그 기능에 따라 범주로 그룹화된다.

참고: 일부 오퍼레이터는 여러 범주에 속한다. 예를 들어, clamp() 는 수학 함수이면서 활성화로도 사용된다.

범주별 오퍼레이터
범주 오퍼레이터​
텐서 생성 input(), constant()
텐서 조작 concat(), expand(), gather(), gatherElements(), scatterElements(), gatherND(), scatterND(), where(), pad(), reshape(), slice(), split(), transpose(), resample2d(), reverse(), tile(), triangular()
텐서 양자화 quantizeLinear(), dequantizeLinear()
텐서 캐스팅 cast()
수학 add(), sub(), mul(), div(), max(), min(), clamp(), pow(), abs(), ceil(), cos(), erf(), exp(), floor(), identity(), log(), neg(), reciprocal(), sin(), sqrt(), tan(), tanh(), sign(), clamp()
논리 equal(), notEqual(), greater(), greaterOrEqual(), lesser(), lesserOrEqual(), logicalNot(), logicalAnd(), logicalOr(), logicalXor()
행렬 곱셈 matmul(), gemm()
컨볼루션 conv2d(), convTranspose2d()
풀링 averagePool2d(), l2Pool2d(), maxPool2d()
활성화 clamp(), elu(), gelu(), hardSigmoid(), hardSwish(), leakyRelu(), linear(), prelu(), relu(), sigmoid(), softmax(), softplus(), softsign(), tanh()
정규화 batchNormalization(), instanceNormalization(), layerNormalization()
축소 argMin(), argMax(), reduceL1(), reduceL2(), reduceLogSum(), reduceLogSumExp(), reduceMax(), reduceMean(), reduceMin(), reduceProduct(), reduceSum(), reduceSumSquare(), cumulativeSum()
순환 신경망 gruCell(), gru(), lstmCell(), lstm()

7.4. 작업 소스

ML 작업 소스MLGraph들의 비동기 컴파일 및 실행과 MLContext들의 생성과 관련된 모든 작업에 사용될 작업 소스이다.

전역 객체 global과 일련의 단계 steps가 주어졌을 때, ML 작업을 큐에 넣는다는 것은 globalsteps와 함께 ML 작업 소스에서 전역 작업을 큐에 넣는 것이다.

7.5. Permissions Policy 통합

이 명세는 문자열 "webnn"으로 식별되는 정책 제어 기능을 정의한다. 그 기본 허용 목록'self'이다.

8. API

8.1. navigator.ml 인터페이스

ML 객체는 WindowWorkerGlobalScope 컨텍스트에서 각각 NavigatorWorkerNavigator 인터페이스를 통해 사용할 수 있으며, navigator.ml을 통해 노출된다.

interface mixin NavigatorML {
  [SecureContext, SameObject] readonly attribute ML ml;
};
Navigator includes NavigatorML;
WorkerNavigator includes NavigatorML;

8.2. ML 인터페이스

enum MLPowerPreference {
  "default",
  "high-performance",
  "low-power"
};

dictionary MLContextOptions {
  MLPowerPreference powerPreference = "default";
  boolean accelerated = true;
};

[SecureContext, Exposed=(Window, Worker)]
interface ML {
  Promise<MLContext> createContext(optional MLContextOptions options = {});
  Promise<MLContext> createContext(GPUDevice gpuDevice);
};

8.2.1. MLContextOptions

참고: MLContextOptions 는 활발히 개발 중이며, 더 많은 구현 경험과 더 넓은 웹 커뮤니티의 새로운 사용 사례를 바탕으로 설계가 변경될 것으로 예상된다. 워킹 그룹은 폴백 장치, 선호 순서의 여러 장치, 또는 특정 장치 제외를 정의할 수 있도록 추가 API 제어를 고려하고 있다. 논의 중인 다른 고려 사항에는 오류 처리, 최종 폴백 및 양자화된 오퍼레이터가 포함된다. 이러한 설계 고려 사항에 대한 피드백은 웹 개발자, 라이브러리 작성자, OS 및 하드웨어 벤더, 기타 이해관계자로부터 GitHub를 통해 환영한다. 핑거프린팅 고려 사항에 대한 추가 논의는 § 5 개인정보 보호 고려 사항을 참조하라.

powerPreference 옵션은 MLPowerPreference이며, 전력 소비와 관련된 애플리케이션의 선호를 나타낸다. 이는 다음 중 하나이다.

"default"
사용자 에이전트가 가장 적합한 동작을 선택하게 한다.
"high-performance"
전력 소비보다 실행 속도를 우선시한다.
"low-power"
실행 속도와 같은 다른 고려 사항보다 전력 소비를 우선시한다.

accelerated 옵션은 대규모 병렬 가속과 관련된 애플리케이션의 선호를 나타낸다. 이 옵션은 powerPreference보다 우선순위가 낮다. true(기본값)로 설정되면, 기반 플랫폼은 powerPreference에도 따라 GPU 또는 NPU와 같은 사용 가능한 대규모 병렬 가속기를 사용하려고 시도한다. false로 설정되면, 애플리케이션은 CPU 추론을 선호함을 나타낸다. 예를 들어 powerPreference"high-performance"이고 acceleratedfalse인 경우처럼 모순되는 입력이 있으면, 구현은 기반 플랫폼에서 사용 가능한 최상의 일치 항목을 선택한다(예를 들어 고성능 CPU 모드, 또는 acceleratedpowerPreference보다 우선순위가 낮으므로 이를 무시할 수 있다).

8.2.2. createContext()

인수: 반환: MLContext.
realm realmoptions(GPUDevice 또는 MLContextOptions)가 주어졌을 때 컨텍스트를 생성한다는 것은 다음 단계를 실행하는 것이다.
  1. contextrealm 내의 새 MLContext로 둔다.

  2. optionsGPUDevice 객체이면:

    1. context.[[contextType]]를 "webgpu"로 설정한다.

    2. context.[[powerPreference]]"default"로 설정한다.

    3. context.[[accelerated]]true로 설정한다.

  3. 그렇지 않으면:

    1. context.[[contextType]]를 "default"로 설정한다.

    2. context.[[lost]]realm 내의 새 promise로 설정한다.

    3. options["powerPreference"]가 존재하면, context.[[powerPreference]]options["powerPreference"]로 설정한다.

    4. 그렇지 않으면, context.[[powerPreference]]"default"로 설정한다.

    5. options["accelerated"]가 존재하면, context.[[accelerated]]options["accelerated"]로 설정한다.

    6. 그렇지 않으면, context.[[accelerated]]true로 설정한다.

  4. 사용자 에이전트가 context.[[contextType]]를 지원할 수 없다면, failure를 반환한다.

  5. context를 반환한다.

createContext(options) 단계는 다음과 같다.
  1. globalthis관련 전역 객체로 둔다.

  2. realmthis관련 realm으로 둔다.

  3. global연관된 Document사용이 허용된 webnn 기능이 아니라면, realm 내의 새 promise를 "SecurityError" DOMException으로 rejected하여 반환한다.

  4. promiserealm 내의 새 promise로 둔다.

  5. 다음 단계를 병렬로 실행한다.

    1. contextrealmoptions가 주어졌을 때 컨텍스트를 생성한 결과로 둔다. 그 결과가 failure이면, global과 함께 ML 작업을 큐에 넣어 promise를 "NotSupportedError" DOMException으로 reject하고, 이 단계를 중단한다.

    2. global과 함께 ML 작업을 큐에 넣어 promisecontextresolve한다.

  6. promise를 반환한다.

createContext(gpuDevice) 메서드 단계는 다음과 같다.
  1. globalthis관련 전역 객체로 둔다.

  2. realmthis관련 realm으로 둔다.

  3. global연관된 Document사용이 허용된 webnn 기능이 아니라면, realm 내의 새 promise를 "SecurityError" DOMException으로 rejected하여 반환한다.

  4. promiserealm 내의 새 promise로 둔다.

  5. 다음 단계를 병렬로 실행한다.

    1. contextrealmgpuDevice가 주어졌을 때 컨텍스트를 생성한 결과로 둔다. 그 결과가 failure이면, global과 함께 ML 작업을 큐에 넣어 promise를 "NotSupportedError" DOMException으로 reject하고, 이 단계를 중단한다.

    2. global과 함께 ML 작업을 큐에 넣어 promisecontextresolve한다.

  6. promise를 반환한다.

8.3. MLContext 인터페이스

MLContext 인터페이스는 신경망 계산 워크로드와 실행 프로세스의 전역 상태를 나타낸다. 각 MLContext 객체는 관련 컨텍스트 타입MLPowerPreference를 가진다.
typedef record<USVString, MLTensor> MLNamedTensors;

dictionary MLContextLostInfo {
  DOMString message;
};

[SecureContext, Exposed=(Window, Worker)]
interface MLContext {
  undefined dispatch(MLGraph graph, MLNamedTensors inputs, MLNamedTensors outputs);

  Promise<MLTensor> createTensor(MLTensorDescriptor descriptor);
  Promise<MLTensor> createConstantTensor(
    MLOperandDescriptor descriptor, AllowSharedBufferSource inputData);

  Promise<ArrayBuffer> readTensor(MLTensor tensor);
  Promise<undefined> readTensor(MLTensor tensor, AllowSharedBufferSource outputData);

  undefined writeTensor(MLTensor tensor, AllowSharedBufferSource inputData);

  MLOpSupportLimits opSupportLimits();

  undefined destroy();

  readonly attribute boolean accelerated;
  readonly attribute Promise<MLContextLostInfo> lost;
};
MLContext는 다음 내부 슬롯을 가진다.
[[contextType]], 타입은 컨텍스트 타입.

MLContext컨텍스트 타입.

[[powerPreference]], 타입은 MLPowerPreference.

MLContextMLPowerPreference.

[[accelerated]], 타입은 boolean.

MLContext의 처리 타입(CPU 또는 대규모 병렬 처리).

[[lost]], 타입은 Promise<MLContextLostInfo>.

MLContext의 기반 실행 장치를 더 이상 사용할 수 없을 때 resolve되는 Promise.

[[timeline]]

MLContext의 계산 유닛에서의 연산 실행과 관련된 타임라인. 이러한 연산에는 계산 그래프에 대한 추론과 [[data]] of MLTensor의 수정이 포함된다.

이 타임라인을 더 엄밀하게 정의한다. [Issue #529]

컨텍스트 타입은 리소스를 관리하고 신경망 그래프의 컴파일 및 실행을 용이하게 하는 실행 컨텍스트의 타입이다.

"default"
사용자 선호 옵션에 따라 생성된 컨텍스트.
"webgpu"
WebGPU 장치로부터 생성된 컨텍스트.
accelerated getter 단계는 this.[[accelerated]]를 반환하는 것이다.
AllowSharedBufferSource bufferSourceMLOperandDescriptor descriptor가 주어졌을 때 디스크립터로 버퍼를 검증한다는 것은 다음 단계를 실행하는 것이다.
  1. bufferSource바이트 길이descriptor바이트 길이와 같지 않으면 false를 반환한다.

  2. bufferSource의 타입에 대해 switch한다.

    ArrayBuffer

    true를 반환한다.

    SharedArrayBuffer

    true를 반환한다.

    ArrayBufferView
    1. bufferSourceUint8Array 객체이면 true를 반환한다.

    2. bufferSource이 표에 따라 descriptordataType과 일치하면 true를 반환한다.

    3. false를 반환한다.

참고: descriptordataType과 관계없이 Uint8Array를 사용하는 것은, 예를 들어 WebAssembly.Memory 인스턴스의 일부와 같이 ArrayBuffer의 slice를 표현하는 일반적인 방법으로 지원된다. 개발자는 가독성과 유지보수성을 위해 WebNN 코드를 작성할 때 더 구체적인 뷰 타입을 사용할 것이 권장된다.

MLNamedTensors namedTensorsrecord<USVString, MLOperandDescriptor> namedDescriptors가 주어졌을 때 디스크립터로 텐서를 검증한다는 것은 다음과 같다.
  1. namedTensors크기namedDescriptors크기와 같지 않으면 false를 반환한다.

  2. namedTensorsnametensor 각각에 대해 반복한다.

    1. tensor.[[isConstant]]가 true이면 false를 반환한다.

    2. namedDescriptors[name]이 존재하지 않으면 false를 반환한다.

    3. tensor.[[descriptor]]namedDescriptors[name]와 같지 않으면 false를 반환한다.

  3. true를 반환한다.

8.3.1. dispatch()

컴파일된 MLGraph의 계산 워크로드를 MLContext[[timeline]]에 스케줄한다.

인수:

반환: undefined.

참고: dispatch() 자체는 그래프 실행이 완료되었다는 신호를 제공하지 않는다. 대신, 호출자는 출력 텐서를 다시 읽은 결과를 await할 수 있다. 아래 § 8.3.1.1 예제를 참조하라.

dispatch(graph, inputs, outputs) 메서드 단계는 다음과 같다.
  1. graph.[[context]]this가 아니면, TypeErrorthrow한다.

  2. graph.[[isDestroyed]]가 true이면, "InvalidStateError" DOMExceptionthrow한다.

  3. allTensorsinputsoutputs으로 확장된 MLTensor들의 리스트로 둔다.

  4. allTensors가 중복 항목을 포함한다면, TypeErrorthrow한다.

  5. allTensors의 각 tensor에 대해 반복한다.

    1. tensor.[[context]]this가 아니면, TypeErrorthrow한다.

    2. tensor.[[isDestroyed]]가 true이면, TypeErrorthrow한다.

  6. inputsgraph.[[inputDescriptors]]가 주어졌을 때 디스크립터로 텐서를 검증한 결과가 false를 반환하면, TypeErrorthrow한다.

  7. outputsgraph.[[outputDescriptors]]가 주어졌을 때 디스크립터로 텐서를 검증한 결과가 false를 반환하면, TypeErrorthrow한다.

  8. 다음 단계를 graph.[[context]].[[timeline]]에 enqueue한다.

    1. 이 단계를 실행하되, thislost 상태이면 중단한다.

      1. inputsoutputs가 주어진 graph.[[implementation]]에 compute 요청을 발행한다.

        그래프 실행 중 오류를 보고하기 위한 메커니즘을 추가한다. [Issue #778]

tensor를 사용하여 상수 피연산자를 생성하는 경우, build가 완료된 후 해당 tensor를 destroy하는 것은 적법하다. 구현은 컴파일된 그래프가 그러한 destruction에도 유효하게 유지되고 영향을 받지 않도록 보장할 것으로 기대된다.

8.3.1.1. 예제
다음 코드는 MLGraphMLTensor들을 사용해 실행하는 것을 보여준다.
const descriptor = {
  dataType: 'float32',
  shape: [2, 2]
};
const context = await navigator.ml.createContext();
const builder = new MLGraphBuilder(context);

// 1. Create a computational graph 'C = 0.2 * A + B'.
const constant = builder.constant(descriptor, new Float32Array(4).fill(0.2));
const A = builder.input('A', descriptor);
const B = builder.input('B', descriptor);
const C = builder.add(builder.mul(A, constant), B);

// 2. Compile the graph.
const graph = await builder.build({'C': C});

// 3. Create reusable input and output tensors.
const [inputTensorA, inputTensorB, outputTensorC] = await Promise.all([
  context.createTensor({dataType: A.dataType, shape: A.shape, writable: true}),
  context.createTensor({dataType: B.dataType, shape: B.shape, writable: true}),
  context.createTensor({dataType: C.dataType, shape: C.shape, readable: true})
]);

// 4. Initialize the inputs.
context.writeTensor(inputTensorA, new Float32Array(4).fill(1.0));
context.writeTensor(inputTensorB, new Float32Array(4).fill(0.8));

// 5. Execute the graph.
const inputs = {
  'A': inputTensorA,
  'B': inputTensorB
};
const outputs = {
  'C': outputTensorC
};
context.dispatch(graph, inputs, outputs);

// 6. Read back the computed result.
const result = await context.readTensor(outputTensorC);
console.log('Output value:', new Float32Array(result));  // [1, 1, 1, 1]

8.3.2. createTensor()

MLContext와 연결된 MLTensor를 생성한다.

인수:

반환: Promise<MLTensor>.

createTensor(descriptor) 메서드 단계는 다음과 같다.
  1. globalthis관련 전역 객체로 둔다.

  2. realmthis관련 realm으로 둔다.

  3. thislost 상태이면, realm 내의 새 promise를 "InvalidStateError" DOMException으로 rejected하여 반환한다.

  4. tensorMLTensor 생성의 결과로 둔다. 이때 thisdescriptor가 주어진다.

  5. promiserealm 내의 새 promise로 둔다.

  6. 다음 단계를 this.[[timeline]]에 enqueue한다.

    1. 이 단계를 실행하되, thislost 상태이면 중단한다:

      1. descriptor가 주어졌을 때 tensor.[[data]]를 생성하고 모든 바이트를 0으로 초기화한다.

      2. 그것이 실패하면, global과 함께 ML 작업을 큐에 넣어 promise를 "UnknownError" DOMException으로 reject하고, 이 단계를 중단한다.

      3. 그렇지 않으면, global과 함께 ML 작업을 큐에 넣어 promisetensorresolve한다.

    2. 중단된 경우, global과 함께 ML 작업을 큐에 넣어 promise를 "InvalidStateError" DOMException으로 reject한다.

  7. promise를 반환한다.

8.3.3. createConstantTensor()

MLContext와 연결된 상수 MLTensor를 생성한다.

인수:

반환: Promise<MLTensor>.

createConstantTensor(descriptor, inputData) 메서드 단계는 다음과 같다.
  1. globalthis관련 전역 객체로 둔다.

  2. realmthis관련 realm으로 둔다.

  3. thislost 상태이면, realm 내의 새 promise를 "InvalidStateError" DOMException으로 rejected하여 반환한다.

  4. descriptor가 주어졌을 때 차원을 검사한 결과가 false를 반환하면, realm 내의 새 promiseTypeErrorrejected하여 반환한다.

  5. inputDatadescriptor가 주어졌을 때 디스크립터로 버퍼를 검증한 결과가 false를 반환하면, realm 내의 새 promiseTypeErrorrejected하여 반환한다.

  6. bytesinputData가 주어졌을 때 버퍼 소스가 보유한 바이트의 복사본을 얻은 결과로 둔다.

  7. Assert: bytes길이descriptor바이트 길이와 같다.

  8. tensor상수 MLTensor 생성의 결과로 둔다. 이때 thisdescriptor가 주어진다.

  9. promiserealm 내의 새 promise로 둔다.

  10. 다음 단계를 this.[[timeline]]에 enqueue한다.

    1. 이 단계를 실행하되, thislost 상태이면 중단한다:

      1. descriptor가 주어졌을 때 tensor.[[data]]를 생성한다.

      2. 그것이 실패하면, global과 함께 ML 작업을 큐에 넣어 promise를 "UnknownError" DOMException으로 reject하고, 이 단계를 중단한다.

      3. bytestensor.[[data]]로 복사한다.

      4. 그것이 실패하면, global과 함께 ML 작업을 큐에 넣어 promise를 "UnknownError" DOMException으로 reject하고, 이 단계를 중단한다.

      5. 그렇지 않으면, global과 함께 ML 작업을 큐에 넣어 promisetensorresolve한다.

    2. 중단된 경우, global과 함께 ML 작업을 큐에 넣어 promise를 "InvalidStateError" DOMException으로 reject한다.

  11. promise를 반환한다.

8.3.4. readTensor(tensor)

[[data]] of an MLTensorMLContext.[[timeline]]에서 스크립트로 다시 읽는다.

인수:

반환: Promise<ArrayBuffer>. 읽기 결과를 포함하는 버퍼.

readTensor(tensor) 메서드 단계는 다음과 같다.
  1. globalthis관련 전역 객체로 둔다.

  2. realmthis관련 realm으로 둔다.

  3. tensor.[[context]]this가 아니면, realm 내의 새 promiseTypeErrorrejected하여 반환한다.

  4. tensor.[[isDestroyed]]가 true이면, realm 내의 새 promiseTypeErrorrejected하여 반환한다.

  5. tensor.[[descriptor]].readable이 false이면, realm 내의 새 promiseTypeErrorrejected하여 반환한다.

  6. promiserealm 내의 새 promise로 둔다.

  7. promisetensor.[[pendingPromises]]추가한다.

  8. 다음 단계를 tensor.[[context]].[[timeline]]에 enqueue한다.

    1. 이 단계를 실행하되, thislost 상태이면 중단한다:

      1. bytestensor.[[data]]의 복사본을 포함하는 바이트 시퀀스로 둔다.

      2. 그것이 실패하면, global과 함께 ML 작업을 큐에 넣고 다음 단계를 실행한다.

        1. promisetensor.[[pendingPromises]]에서 제거한다.

        2. promise를 "UnknownError" DOMException으로 Reject하고, 이 단계를 중단한다.

      3. 그렇지 않으면, global과 함께 ML 작업을 큐에 넣고 다음 단계를 실행한다.

        1. promisetensor.[[pendingPromises]]에서 제거한다.

        2. bufferrealm 내에서 bytes로부터 ArrayBuffer생성한 결과로 둔다.

        3. promisebufferResolve한다.

    2. 중단된 경우, global과 함께 ML 작업을 큐에 넣어 promise를 "InvalidStateError" DOMException으로 reject한다.

  9. promise를 반환한다.

8.3.5. readTensor(tensor, outputData)

readTensor(tensor)の bring-your-own-bufferバリアント。 [[data]] を、MLTensor から、提供されたバッファへ読み戻す。

引数:

戻り値: Promise<undefined>。

readTensor(tensor, outputData) メソッドの手順は次のとおりである。
  1. globalを、this関連グローバルオブジェクトとする。

  2. realmを、this関連realmとする。

  3. tensor.[[context]]thisでない場合、TypeErrorrejectされた、 realm内の新しい promiseを返す。

  4. tensor.[[isDestroyed]] がtrueである場合、TypeErrorrejectされた、 realm内の新しい promiseを返す。

  5. tensor.[[descriptor]].readable がfalseである場合、TypeErrorrejectされた、 realm内の新しい promiseを返す。

  6. outputDataおよびtensor.[[descriptor]] が与えられて記述子でバッファを検証する結果がfalseを返す場合、 TypeErrorrejectされた、 realm内の新しい promiseを返す。

  7. promiserealm内の新しい promiseとする。

  8. promisetensor.[[pendingPromises]]追加する。

  9. 次の手順をtensor.[[context]].[[timeline]]へ エンキューする。

    1. これらの手順を実行する。ただし、thislostであるときは中止する

      1. bytesを、tensor.[[data]]のコピーを含む バイト列とする。

      2. それが失敗した場合、次の手順を実行するため、globalとともにMLタスクをキューに入れる

        1. tensor.[[pendingPromises]]から promise削除する。

        2. promiseを"UnknownError" DOMExceptionRejectし、 これらの手順を中止する。

      3. それ以外の場合、次の手順を実行するため、globalとともにMLタスクをキューに入れる

        1. tensor.[[pendingPromises]]から promise削除する。

        2. outputDatadetachされている場合、 promiseTypeErrorrejectし、 これらの手順を中止する。

          注記: 上記の記述子でバッファを検証するは、 outputDataがdetachされている場合に失敗するが、その手順とこの手順の間に outputDataがdetachされる可能性がある。

        3. bytesoutputData書き込む

        4. promiseundefinedResolveする。

    2. 中止された場合globalとともにMLタスクをキューに入れpromiseを"InvalidStateError" DOMExceptionrejectする。

  10. promiseを返す。

8.3.6. writeTensor()

MLTensor[[data]] へ、MLContext[[timeline]]上でデータを書き込む。

引数:

戻り値: undefined

writeTensor(tensor, inputData) メソッドの手順は次のとおりである。
  1. tensor.[[context]]thisでない場合、TypeErrorthrowする。

  2. tensor.[[isDestroyed]] がtrueである場合、TypeErrorthrowする。

  3. tensor.[[descriptor]].writable がfalseである場合、TypeErrorthrowする。

  4. inputDataおよびtensor.[[descriptor]] が与えられて記述子でバッファを検証する結果がfalseを返す場合、 TypeErrorthrowする。

  5. bytesを、inputDataが与えられてバッファソースが保持するバイトのコピーを取得する結果とする。

  6. Assert: bytes長さは、tensor.[[descriptor]]バイト長と等しい。

  7. 次の手順をtensor.[[context]].[[timeline]]へ エンキューする。

    1. これらの手順を実行する。ただし、thislostであるときは中止する

      1. bytestensor.[[data]]へコピーする。

        テンソルへの書き込み中にエラーを報告する仕組みを追加する。 [Issue #778]

注記: dispatch()と同様に、 writeTensor()自体は、書き込みが完了したことを示すシグナルを提供しない。テンソルの内容を調べるために、 呼び出し側はテンソルを読み戻した結果をawaitできる。

8.3.7. opSupportLimits()

opSupportLimits()は、 実装間で演算子レベルにおいて異なるサポートレベルを公開する。WebNN APIの利用者は、 各ターゲットプラットフォームに配備する最適なモデルアーキテクチャを決定するために、opSupportLimits()を 使用して機能サポートレベルを調べることが推奨される。

注記: opSupportLimits() APIは、ブラウザーフィンガープリンティングのために追加のエントロピーを提供することを意図していない。現在の実装では、 この機能サポート情報はOSおよびブラウザーバージョンだけから推論できる。将来の実装の多様性がそれを正当化する場合、 このAPIにより、将来の実装は、エントロピーを低減するためWebGPUと同様に能力をバケット化するなど、 新しいプライバシー緩和策を追加できる。

フィンガープリンティングに関する考慮事項の追加の議論については、§ 5 プライバシーの考慮事項を参照。

8.3.7.1. MLOpSupportLimits 辞書
MLOpSupportLimitsは 次のトップレベルメンバーを持つ。これらに加えて、各演算子には、そのビルダーメソッドで定義される対応するメンバーがある。
dictionary MLOpSupportLimits {
  MLInputOperandLayout preferredInputLayout;
  [EnforceRange] unsigned long long maxTensorByteLength;
  MLTensorLimits input;
  MLTensorLimits constant;
  MLTensorLimits output;
};
preferredInputLayout, 型はMLInputOperandLayout

conv2d()など、 レイアウト依存演算子に対する推奨入力レイアウト。

maxTensorByteLength, 型はunsigned long long

テンソルのサポートされる最大長(バイト単位)。

input, 型はMLTensorLimits

MLGraphに対する 入力MLOperandのサポート制限。

constant, 型はMLTensorLimits

MLGraphに対する 定数MLOperandのサポート制限。

output, 型はMLTensorLimits

MLGraphに対する 出力MLOperandのサポート制限。

8.3.7.2. MLRankRange 辞書
dictionary MLRankRange {
  unsigned long min;
  unsigned long max;
};
min, 型はunsigned long

サポートされる最小ランク。

max, 型はunsigned long

サポートされる最大ランク。

8.3.7.3. MLTensorLimits 辞書
typedef sequence<MLOperandDataType> MLDataTypeList;

dictionary MLTensorLimits {
  MLDataTypeList dataTypes;
  MLRankRange rankRange;
};
dataTypes, 型はMLDataTypeList

サポートされるデータ型。

rankRange, 型はMLRankRange

サポートされる最小および最大ランク。

8.3.7.4. MLBinarySupportLimits 辞書
dictionary MLBinarySupportLimits {
  MLTensorLimits a;
  MLTensorLimits b;
  MLTensorLimits output;
};
a, 型はMLTensorLimits

aオペランド用のMLTensorLimits

b, 型はMLTensorLimits

bオペランド用のMLTensorLimits

output, 型はMLTensorLimits

出力オペランド用のMLTensorLimits

8.3.7.5. MLSingleInputSupportLimits 辞書
dictionary MLSingleInputSupportLimits {
  MLTensorLimits input;
  MLTensorLimits output;
};
input, 型はMLTensorLimits

入力オペランド用のMLTensorLimits

output, 型はMLTensorLimits

出力オペランド用のMLTensorLimits

8.3.8. destroy()

destroy() メソッドは、コンテキストに関連付けられたすべてのリソースを解放するために呼び出すことができる。未完了の計算要求、 およびMLTensorの 作成/読み取り/書き込み要求は失敗する。

destroy()メソッドの手順は次のとおりである。
  1. thislostである場合、これらの手順を中止する。

  2. 実装定義のメッセージで、thisloseする手順を実行する。

    注記: destroy()が呼び出されたことを示すメッセージは、開発者がコンテキスト喪失の原因を区別するのに役立つ。

8.3.9. エラー

ユーザーエージェントが、MLContextが 要求を満たすために利用できなくなったと判断した場合、そのためのコンテキスト喪失手順を実行しなければならない。

MLContext contextに対するコンテキスト喪失 手順は次のとおりである。
  1. globalを、context関連グローバルオブジェクトとする。

  2. 次の手順を実行するため、globalとともにMLタスクを キューに入れる

    1. Lose contextする。メッセージは実装定義とする。

MLContext contextを、DOMString messageloseするには:
  1. infoを新しいMLContextLostInfoとする。

  2. info.messagemessageに設定する。

  3. context.[[lost]]infoResolveする。

  4. graph.[[context]]thisと等しい各MLGraph graphについて:

    1. graphthisとして、 graphに対するdestroy() メソッド手順を実行する。

  5. tensor.[[context]]thisと等しい各MLTensor tensorについて:

    1. tensorthisとして、 tensorに対するdestroy() メソッド手順を実行する。

message, 型はDOMString

発生したエラーに関する情報を提供する実装定義のメッセージ。

lost取得手順は、this[[lost]] Promiseを返すことである。

MLContextは、 その[[lost]] Promisesettledしている場合、lostである

8.4. MLGraph インターフェイス

MLGraph インターフェイスは、コンパイル済み計算グラフを表す。コンパイル済みグラフは、一度構築されると不変であり、 その後変更できない。
[SecureContext, Exposed=(Window, Worker)]
interface MLGraph {
  undefined destroy();
};
MLGraphは 次の内部スロットを持つ。
[[context]]、型はMLContext

このMLGraphに関連付けられた MLContext型のコンテキスト。

[[inputDescriptors]]、型は record<USVString, MLOperandDescriptor>

このMLGraphのすべての 入力MLOperandについて、 入力MLOperandの名前を そのMLOperandDescriptorに対応付ける。

[[outputDescriptors]]、型は record<USVString, MLOperandDescriptor>

このMLGraphのすべての 出力MLOperandについて、 出力MLOperandの名前を そのMLOperandDescriptorに対応付ける。

[[implementation]]

ユーザーエージェントにより提供される基盤実装。

[[isDestroyed]]、型はboolean

MLGraph.destroy() メソッド手順が実行されたかどうか。いったん破棄されると、MLGraph はもはや使用できない。

8.4.1. destroy()

destroy() メソッドは、グラフに関連付けられたすべてのリソースを解放するために呼び出すことができる。

destroy()メソッドの手順は次のとおりである。
  1. this.[[isDestroyed]] がtrueである場合、これらの手順を中止する。

  2. this.[[isDestroyed]] をtrueに設定する。

  3. このグラフが所有するリソースを解放可能としてマークするために、this.[[context]].[[timeline]] 上にタスクをキューに入れる。

注記: このグラフを使用してこれ以上ワークロードをキューに入れることはできないため、 実装は、このグラフを使用して以前に送信されたすべてのワークロードが完了した後、このグラフに関連付けられた追加のリソース割り当てを解放できる。

8.5. MLOperandDescriptor 辞書

MLOperandDescriptorは、 オペランドの形状(次元)およびデータ型を記述する。これはMLGraphの入力および 定数を記述するために使用され、各MLOperandは 内部MLOperandDescriptorを持つ。

enum MLInputOperandLayout {
  "nchw",
  "nhwc"
};

enum MLOperandDataType {
  "float32",
  "float16",
  "int32",
  "uint32",
  "int64",
  "uint64",
  "int8",
  "uint8"
};

dictionary MLOperandDescriptor {
  required MLOperandDataType dataType;
  required sequence<[EnforceRange] unsigned long> shape;
};
dataType, 型はMLOperandDataType

オペランドのデータ型。

shape, 型はsequence<[EnforceRange] unsigned long>

オペランドの次元のリスト。スカラーオペランドの場合は空である。

MLOperandDescriptor Aは、A.dataTypeB.dataTypeと等しく、 かつA.shapeB.shape等しい場合、MLOperandDescriptor B等しい
MLOperandDataType dataTypeおよびリストshapeが与えられたとき、MLOperandDescriptorを 作成するには、次の手順を実行する。
  1. descriptorを新しいMLOperandDescriptorとする。

  2. descriptor.dataTypedataTypeに設定する。

  3. descriptor.shapeshapeクローンに設定する。

  4. descriptorを返す。

MLOperandDescriptor descバイト長は、次の手順により返される値である。
  1. elementLengthを1とする。

  2. desc.shapeの 各dimensionについて反復する

    1. elementLengthelementLength * dimensionに設定する。

  3. elementSizeを、この 表に従ってdesc.dataTypeと 一致するArrayBufferView 型の1つの要素サイズとする。

  4. elementLength * elementSizeを返す。

MLOperandDescriptor desc要素数は、次の手順により返される値である。
  1. elementCountを1とする。

  2. desc.shapeの 各dimensionについて反復する

    1. elementCountelementCount * dimensionに設定する。

  3. elementCountを返す。

妥当な次元は、 0より大きく、longの範囲内にある整数である。 実装はより小さな上限を課してもよい。

妥当なテンソル 数は、0より大きく8192以下の整数である。実装はより小さな上限を課してもよい。

サイズ0の次元は サポートされるべきか? [Issue #391]

MLOperandDescriptor descriptorが与えられたとき、次元をチェックするには、次の手順を実行する。
  1. descriptor.shapeの いずれかの項目妥当な 次元でない場合、falseを返す。

  2. descriptor.shapeサイズが実装でサポートするには大きすぎる場合、 falseを返す。

    オペランド次元の最大数は 定義されていないが、ネイティブML APIは通常、サポートされる最大サイズを持つ。[Issue #456]

  3. descriptor要素数妥当な 次元でない場合、falseを返す。

  4. descriptorバイト長が実装でサポートされていない場合、 falseを返す。

  5. trueを返す。

8.6. MLOperand インターフェイス

MLOperandは、 演算の一部を完全に合成された演算へ合成した結果として構築される、中間グラフを表す。

例えば、MLOperandは、 演算に供給される定数、または複数の定数を1つの演算へ結合した結果を表すことができる。 § 7 プログラミングモデルも参照。

[SecureContext, Exposed=(Window, Worker)]
interface MLOperand {
  readonly attribute MLOperandDataType dataType;
  readonly attribute FrozenArray<unsigned long> shape;
};

dictionary MLOperatorOptions {
  USVString label = "";
};

typedef (bigint or unrestricted double) MLNumber;
MLOperand は次の内部スロットを持つ。
[[builder]]、型はMLGraphBuilder

MLOperandの 関連ビルダーオブジェクト。

[[descriptor]]、型はMLOperandDescriptor

MLOperandの 記述子。

[[name]]、型は文字列

MLOperandの 名前(入力オペランドの場合のみ)。

[[operator]]、型は演算子

MLOperandに 対応する演算子への参照。

[[constantTensor]]、型は MLTensor

MLOperandの テンソル(定数オペランドの場合のみ)。

MLOperanddataTypeは、その[[descriptor]].dataTypeである。

MLOperandshapeは、その[[descriptor]].shapeである。

MLOperandrankは、そのshapeサイズである。

dataType取得手順は、 thisdataTypeを返すことである。

shape取得手順は、 thisshapeを返すことである。

[[builder]] オブジェクトは、MLGraphBuilder() コンストラクターによりMLContext オブジェクトに束縛されるため、MLOperandも 常に同じMLContext オブジェクトに束縛される。

演算がMLOperandDataTypeの サブセットのみをサポートする場合、位置引数とオプションの両方を含む、演算の各入力オペランドに対する許可されるデータ 型は、MLOperandDataTypeの 明示的なリスト、またはオペランドのdataTypeが別の入力オペランドのdataType同じでなければならないという制約、または任意のMLOperandDataTypeを 許可する任意として与えられる。

実装は、指定されているより少ないデータ型をオペランドに対してサポートしてもよい。これは、 MLContext上のopSupportLimits() メソッドを使用し、演算に対応するメンバーのdataTypes 値を調べることにより、各演算について照会できる。

各演算子に対して サポートされなければならないデータ型のサブセットを指定すべきか?

演算が特定のrankを持つ入力オペランドを必要とする場合、位置引数とオプションの両方を含む、 演算の各入力オペランドに対する許可されるランクは、明示的なランク(例: 1)、または任意の次元数を許可するN、または別のオペランドと 同じとして与えられる。より具体的な制約も一般的であり、例えば入力オペランドの形状が 別の入力オペランドに対して単方向にブロードキャスト可能でなければならない場合、または双方向にブロードキャスト可能でなければならない場合がある。 これらの場合、許可される ランクは範囲として列挙され、具体的な検証は演算内の手順として与えられる。

実装は、オペランドのrankに対して、指定されているより制限された下限および/または上限を課してもよい。 これは、MLContext上のopSupportLimits() メソッドを使用し、演算に対応するメンバーのrankRange.min およびrankRange.max 値を調べることにより、各演算について照会できる。

MLOperatorOptions は次のメンバーを持つ。

label, 型はUSVString、デフォルトは""

MLOperandを作成する MLGraphBuilder メソッドを使用して演算子が作成されるときに任意で提供される。 実装はこの値を使用して演算子ラベルを初期化してもよい。

注記: ラベルは自然言語文字列であることを意図していない。 これは、"mul#1234"のような、変数名またはエラーコードに類似した言語非依存の識別子である。

注記: 実装は、開発者から提供されたlabelを 使用して、グラフ構築中の同期エラー、および非同期build() メソッド中に発生するエラーの両方を含め、エラーメッセージを強化しデバッグ容易性を向上させることが推奨される。

デバッグツール、ログ、またはエラーメッセージで、開発者がlabel を通じて提供したラベルを表示するとき、実装は出力をサニタイズして、悪意あるUnicodeシーケンスの注入などの セキュリティリスクを防止すべきである(例: 双方向テキスト スプーフィング [UTR36]ソースコードスプーフィング [UTS55]および その他の懸念)。例えば、実装は制御文字(例: U+202A からU+202E、U+2066からU+2069)をエスケープまたはフィルタリングするか、安全なレンダリング機構を使用して潜在的な スプーフィングを無効化すべきである。

8.6.1. MLOperandの作成

MLOperand オブジェクトは、MLGraphBuilderの メソッドにより、内部的に次のアルゴリズムを使用して作成される。
MLGraphBuilder builderおよびMLOperandDescriptor descが与えられたとき、MLOperandを 作成するには、次の手順を実行する。
  1. realmを、builder関連realmとする。

  2. operandrealm内の新しいMLOperand とする。

  3. operand.[[builder]]builderに設定する。

  4. operand.[[descriptor]]descに設定する。

  5. operandを返す。

MLOperand operandが与えられたとき、MLOperandを コピーするには、次の手順を実行する。
  1. builderoperand.[[builder]]とする。

  2. realmを、builder関連realmとする。

  3. resultrealm内の新しいMLOperand とする。

  4. result.[[builder]]builderに設定する。

  5. result.[[descriptor]]operand.[[descriptor]]に設定する。

  6. operand.[[name]]存在する場合、result.[[name]]operand.[[name]]に設定する。

  7. resultを返す。

MLGraphBuilder builderおよびMLOperand operandが与えられたとき、オペランドを検証するには、operand.[[builder]]builderであればtrueを返し、そうでなければfalseを返す。

8.6.1.1. MLNumber

MLNumberは、64ビット整数型("uint64" および"int64")と 32ビット浮動小数点("float32")の 両方を含む、任意のMLOperandDataTypeであり得る MLOperandに対する数値オプションの型を指定するときに使用される。 実装は、対応するMLOperandDataTypeに従って値を処理する。 例えば、clamp(input, options)が、 dataType"uint32"である MLOperandで呼び出された場合、 MLNumber パラメーターは明示的にunsigned longキャストされる。

オプションをdoubleとして指定すると、 253を超える値を渡すときに精度が失われ、long longを 指定すると263を超える値が許可されなくなる。

bigint数値型のunionのサポートは[WEBIDL]で新しく、実装サポートも限定的である。 プロトタイプ実装には、このアプローチについてフィードバックを提供することが推奨される。[whatwg/webidl Issue #1388]

8.7. MLTensorDescriptor 딕셔너리

MLTensorDescriptorMLTensor의 특성과 기능을 설명한다.

dictionary MLTensorDescriptor : MLOperandDescriptor {
  boolean readable = false;
  boolean writable = false;
};
readable, 타입은 boolean, 기본값은 false

tensor의 내용을 readTensor(tensor) 또는 readTensor(tensor, outputData)를 통해 읽을 수 있는지 여부.

writable, 타입은 boolean, 기본값은 false

tensor의 내용을 writeTensor()를 통해 쓸 수 있는지 여부.

8.8. MLTensor 인터페이스

MLTensor 인터페이스는 MLGraph의 입력 또는 출력으로 사용될 수 있는 tensor를 나타낸다. MLTensor를 뒷받침하는 메모리는 그것을 생성하는 데 사용된 MLContextMLTensorDescriptor의 요구 사항에 따라 구현 정의 방식으로 할당되어야 한다. MLTensor[[data]]와 관련된 연산은 연결된 MLContext[[timeline]]에서 발생한다.

MLTensor가 어떻게 할당되는지에 대한 구현 정의 요구 사항에는, 메모리가 특정 바이트 정렬로 할당되거나 특정 메모리 풀에 할당되어야 한다는 등의 제약이 포함될 수 있다.

[SecureContext, Exposed=(Window, Worker)]
interface MLTensor {
  readonly attribute MLOperandDataType dataType;
  readonly attribute FrozenArray<unsigned long> shape;
  readonly attribute boolean readable;
  readonly attribute boolean writable;
  readonly attribute boolean constant;

  undefined destroy();
};
MLTensor는 다음 내부 슬롯을 가진다.
[[context]], 타입은 MLContext

MLTensor의 연결된 컨텍스트.

[[descriptor]], 타입은 MLTensorDescriptor

MLTensor의 디스크립터.

[[pendingPromises]], 타입은 Promise들의 set

진행 중이며 아직 resolve되지 않은 MLContext.readTensor(tensor) 메서드 호출에 대응하는 Promise들. 모든 pending promise는 MLTensor가 destroy될 때 reject된다.

[[isDestroyed]], 타입은 boolean

MLTensor.destroy() 단계가 실행되었는지 여부. destroy된 후에는 MLTensor를 더 이상 사용할 수 없다.

[[data]], 구현 정의 타입

MLTensor를 뒷받침하는 바이트들. 이 데이터는 [[context]].[[timeline]]에서만 접근하거나 수정될 수 있다.

[[isConstant]], 타입은 boolean

MLTensor상수 MLTensor 생성에 의해 생성되었는지 여부.

MLTensordataType은 그 [[descriptor]]dataType이다.

MLTensorshape는 그 [[descriptor]]shape이다.

dataType getter 단계thisdataType을 반환하는 것이다.

shape getter 단계thisshape를 반환하는 것이다.

readable getter 단계this.[[descriptor]].readable를 반환하는 것이다.

writable getter 단계this.[[descriptor]].writable를 반환하는 것이다.

constant getter 단계this[[isConstant]]를 반환하는 것이다.

8.8.1. MLTensor 생성하기

MLTensor는 연결된 MLContext에 의해 생성된다.

MLContext contextMLTensorDescriptor descriptor가 주어졌을 때 MLTensor를 생성한다는 것은 다음 단계를 실행하는 것이다.
  1. realmcontext관련 realm으로 둔다.

  2. tensorrealm 내의 새 MLTensor로 둔다.

  3. tensor.[[context]]context로 설정한다.

  4. tensor.[[descriptor]]descriptor로 설정한다.

  5. tensor.[[isDestroyed]]를 false로 설정한다.

  6. tensor.[[isConstant]]를 false로 설정한다.

  7. tensor를 반환한다.

8.8.2. destroy()

MLTensor와 관련된 리소스를 해제한다. 이 메서드는 멱등적이다.

반환: undefined.
destroy() 메서드 단계는 다음과 같다.
  1. this.[[isDestroyed]]를 true로 설정한다.

  2. this.[[pendingPromises]]의 각 promise에 대해 반복한다:

    1. this.[[pendingPromises]]에서 promise제거한다.

    2. promise를 "InvalidStateError" DOMException으로 Reject한다.

  3. 다음 단계를 this.[[context]].[[timeline]]에 enqueue한다.

    1. this.[[data]]를 해제한다.

참고: 이 tensor를 사용하여 더 이상 연산을 enqueue할 수 없으므로, 구현은 이전에 제출된 이 tensor 사용 연산이 모두 완료된 후 이 tensor와 관련된 추가 리소스 할당을 해제할 수 있다.

8.8.3. 상수 MLTensor 생성하기

상수 MLTensor는 연결된 MLContext에 의해 생성된다.

MLContext context, MLOperandDescriptor inputDescriptor가 주어졌을 때 상수 MLTensor를 생성한다는 것은 다음 단계를 실행하는 것이다.
  1. realmcontext관련 realm으로 둔다.

  2. tensorrealm 내의 새 MLTensor로 둔다.

  3. tensor.[[context]]context로 설정한다.

  4. tensorDescriptor를 새 MLTensorDescriptor로 둔다.

  5. tensorDescriptor.readable를 false로 설정한다.

  6. tensorDescriptor.writable을 false로 설정한다.

  7. tensorDescriptor.dataTypeinputDescriptor.dataType으로 설정한다.

  8. tensorDescriptor.shapeinputDescriptor.shape로 설정한다.

  9. tensor.[[descriptor]]tensorDescriptor로 설정한다.

  10. tensor.[[isDestroyed]]를 false로 설정한다.

  11. tensor.[[isConstant]]를 true로 설정한다.

  12. tensor를 반환한다.

8.9. MLGraphBuilder 인터페이스

MLGraphBuilder 인터페이스는 § 2 사용 사례에서 식별된, 계산 그래프로 합성될 수 있는 일련의 연산을 정의한다. 또한 그래프 빌딩 세션의 중간 상태를 나타낸다.

typedef record<USVString, MLOperand> MLNamedOperands;

[SecureContext, Exposed=(Window, Worker)]
interface MLGraphBuilder {
  // Construct the graph builder from the context.
  constructor(MLContext context);

  // Create an operand for a graph input.
  MLOperand input(USVString name, MLOperandDescriptor descriptor);

  // Create an operand for a graph constant.
  MLOperand constant(MLOperandDescriptor descriptor,
                     AllowSharedBufferSource buffer);

  // Create a scalar operand from the specified number of the specified type.
  MLOperand constant(MLOperandDataType dataType, MLNumber value);

  // Create an operand from a specified constant tensor.
  MLOperand constant(MLTensor tensor);

  // Compile the graph up to the specified output operands asynchronously.
  Promise<MLGraph> build(MLNamedOperands outputs);
};
MLGraphBuilder.build() 메서드는 그래프 빌더 상태를 지정된 출력 피연산자까지, 이를 생성한 MLContext의 타입에 따라 컴파일된 그래프로 컴파일한다. MLContext[[contextType]]가 "default"로 설정되어 있으면, 컴파일된 그래프는 MLGraph가 반환되기 직전에 초기화된다. 이 그래프 초기화 단계는 이후 그래프 실행의 최적 성능을 위해 중요하다. 이는 일반적으로 "가중치 전처리"로 알려진 과정을 포함하며, 여기서는 그래프에 대한 모든 상수 입력이 전처리되어 이후 그래프 실행 호출을 위해 운영 체제 수준에서 캐시된다. 초기화 입력은 일반적으로 그래프 구성 시 상수 피연산자로서 constant() 메서드를 통해 지정된 상수 가중치 데이터이다.
MLGraphBuilder는 다음 내부 슬롯을 가진다.
[[context]], 타입은 MLContext

MLGraphBuilder와 연결된 MLContext 타입의 컨텍스트.

[[hasBuilt]], 타입은 boolean

MLGraphBuilder.build()가 호출되었는지 여부. 한 번 빌드되면 MLGraphBuilder는 더 이상 오퍼레이터를 생성하거나 MLGraph를 컴파일할 수 없다.

MLGraphBuilder는 그 [[hasBuilt]]가 false이고 그 [[context]]lost 상태가 아니면 빌드할 수 있다.

8.9.1. MLGraphBuilder 생성자

인수:
new MLGraphBuilder(context) 생성자 단계는 다음과 같다.
  1. this관련 전역 객체연관된 Document사용이 허용된 webnn 기능이 아니라면, "SecurityError" DOMExceptionthrow한다.

  2. contextlost 상태이면, "InvalidStateError" DOMExceptionthrow한다.

  3. this.[[context]]context로 설정한다.

  4. this.[[hasBuilt]]를 false로 설정한다.

8.9.2. 입력 피연산자

입력으로 사용할 수 있는, 디스크립터를 기반으로 한 이름 있는 MLOperand를 생성한다.

인수: 반환: MLOperand.
input(name, descriptor) 메서드 단계는 다음과 같다.
  1. this빌드할 수 없으면, "InvalidStateError" DOMExceptionthrow한다.

  2. name이 비어 있으면, TypeErrorthrow한다.

  3. thisgraphinputs 내의 어떤 MLOperand라도 name과 같은 [[name]]을 가지면, TypeErrorthrow한다.

  4. descriptor가 주어졌을 때 차원을 검사한 결과가 false를 반환하면, TypeErrorthrow한다.

  5. 그래프 연결 만들기:

    1. operandthisdescriptor가 주어졌을 때 MLOperand를 생성한 결과로 둔다.

    2. operand.[[name]]name으로 설정한다.

    3. operandthisgraphinputs에 추가한다.

  6. operand를 반환한다.

MLGraphBuilder API는 입력 피연산자 없이 MLGraph를 생성할 수 있게 한다. 기반 플랫폼이 이를 지원하지 않으면, 구현은 stub 입력을 추가하거나 상수를 그래프에 대한 입력으로 전달할 수 있다.

8.9.3. 상수 피연산자

MLGraphBuilder 메서드에서 사용할 수 있는 상수 MLOperand를 생성한다.
8.9.3.1. constant(descriptor, buffer)
초기화 데이터를 포함하는, 지정된 데이터 타입과 shape의 상수 MLOperand를 생성한다.
인수: 반환: MLOperand. 상수 출력 tensor.
constant(descriptor, buffer) 메서드 단계는 다음과 같다.
  1. this빌드할 수 없으면, "InvalidStateError" DOMExceptionthrow한다.

  2. descriptor가 주어졌을 때 차원을 검사한 결과가 false를 반환하면, TypeErrorthrow한다.

  3. bufferdescriptor가 주어졌을 때 디스크립터로 버퍼를 검증한 결과가 false를 반환하면, TypeErrorthrow한다.

  4. 그래프 연결 만들기:

    1. operandthisdescriptor가 주어졌을 때 MLOperand를 생성한 결과로 둔다.

    2. bytesbuffer가 주어졌을 때 버퍼 소스가 보유한 바이트의 복사본을 얻은 결과로 둔다.

    3. operandthisgraphconstantsbytes를 값으로 하여 추가한다.

  5. operand를 반환한다.

8.9.3.2. constant(tensor)
초기화된 데이터를 포함하는, 지정된 데이터 타입과 shape의 상수 MLOperand를 생성한다.
인수: 반환: MLOperand. 상수 출력 tensor.
constant(tensor) 메서드 단계는 다음과 같다.
  1. tensor.[[context]]this.[[context]]가 아니면, TypeErrorthrow한다.

  2. tensor.[[isDestroyed]]가 true이면, TypeErrorthrow한다.

  3. tensor.[[isConstant]]가 false이면, TypeErrorthrow한다.

  4. this빌드할 수 없으면, "InvalidStateError" DOMExceptionthrow한다.

  5. 그래프 연결 만들기:

    1. operandthistensor.[[descriptor]]가 주어졌을 때 MLOperand를 생성한 결과로 둔다.

    2. operand.[[constantTensor]]tensor로 설정한다.

    3. operandthisgraphconstantstensor를 값으로 하여 추가한다.

  6. operand를 반환한다.

8.9.3.3. constant(dataType, value)
지정된 값과 데이터 타입의 스칼라 상수 MLOperand를 생성한다.
지정된 값이 지정된 출력 데이터 타입의 범위를 초과하면 데이터 잘림이 발생한다. 예를 들어 부동 소수점 값이 "int8" 데이터 타입에 할당되는 경우 등이 그렇다.
인수: 반환: MLOperand. 상수 출력.
constant(dataType, value) 메서드 단계는 다음과 같다.
  1. this빌드할 수 없으면, "InvalidStateError" DOMExceptionthrow한다.

  2. valuedataType으로 캐스팅한 결과로 설정한다.

  3. descriptordataType 및 « »가 주어졌을 때 MLOperandDescriptor를 생성한 결과로 둔다.

  4. 그래프 연결 만들기:

    1. operandthisdescriptor가 주어졌을 때 MLOperand를 생성한 결과로 둔다.

    2. operandthisgraphconstantsvalue를 값으로 하여 추가한다.

  5. operand를 반환한다.

8.9.4. build 메서드

주어진 출력 피연산자까지 합성된 그래프를 비동기적으로 계산 그래프로 빌드한다.
인수: 반환: Promise<MLGraph>.
build(outputs) 메서드 단계는 다음과 같다.
  1. realmthis관련 realm으로 둔다.

  2. this빌드할 수 없으면, realm 내의 새 promise를 "InvalidStateError" DOMException으로 rejected하여 반환한다.

  3. outputs가 비어 있으면, realm 내의 새 promiseTypeErrorrejected하여 반환한다.

  4. outputs의 각 nameoperand에 대해 반복한다:

    1. name이 비어 있으면, realm 내의 새 promiseTypeErrorrejected하여 반환한다.

    2. 피연산자를 검증한 결과가 thisoperand가 주어졌을 때 false를 반환하면, realm 내의 새 promiseTypeErrorrejected하여 반환한다.

    3. operandthisgraphinputs 또는 constants 안에 있으면, realm 내의 새 promiseTypeErrorrejected하여 반환한다.

    4. operand.[[constantTensor]]가 존재하고 operand.[[constantTensor]].[[isDestroyed]]가 true이면, realm 내의 새 promiseTypeErrorrejected하여 반환한다.

  5. operands를 새 빈 set으로 둔다.

  6. operators를 새 빈 set으로 둔다.

  7. inputs를 새 빈 set으로 둔다.

  8. queueoutputsqueue를 포함하는 새 들로 둔다.

  9. queue비어 있지 않은 동안:

    1. queue에서 operanddequeue한다.

    2. operandoperands추가한다.

    3. operand.[[operator]]operators추가한다.

    4. operandthisgraphinputs 안에 있으면, operandinputs추가한다.

    5. operand.[[operator]]inputs의 각 input에 대해 반복한다:

      1. inputqueueenqueue한다.

  10. globalthis관련 전역 객체로 둔다.

  11. graphrealm 내의 새 MLGraph로 둔다.

  12. graph.[[context]]this.[[context]]로 설정한다.

  13. graph.[[isDestroyed]]를 false로 설정한다.

  14. inputs 내의 각 operand에 대해 반복한다:

    1. graph.[[inputDescriptors]][operand.[[name]]]를 operand.[[descriptor]]로 설정한다.

  15. outputs의 각 nameoperand에 대해 반복한다:

    1. graph.[[outputDescriptors]][name]을 operand.[[descriptor]]로 설정한다.

  16. this.[[hasBuilt]]를 true로 설정한다.

  17. promiserealm 내의 새 promise로 둔다.

  18. 다음 단계를 graph.[[context]].[[timeline]]에 enqueue한다.

    1. 이 단계를 실행하되, graph.[[context]]lost 상태이면 중단한다:

      1. graphImplthisgraphoperands, operators, inputs, outputs, 그리고 graph.[[context]].[[powerPreference]]graph.[[context]].[[accelerated]]와 함께, 기반 플랫폼에서 해석할 수 있는 구현 정의 형식으로 변환한 결과로 둔다.

      2. 이전 단계가 실패하면, global과 함께 ML 작업을 큐에 넣어 promise를 "OperationError" DOMException으로 reject하고, 이 단계를 중단한다.

      3. graph.[[implementation]]graphImpl로 설정한다.

      4. global과 함께 ML 작업을 큐에 넣어 promisegraphresolve한다.

    2. 중단된 경우, global과 함께 ML 작업을 큐에 넣어 promise를 "InvalidStateError" DOMException으로 reject한다.

  19. promise를 반환한다.

참고: 입력 피연산자 또는 상수 피연산자를 그래프 output으로 지정하면 오류가 발생한다. 이는 보통 API를 잘못 사용한 것이기 때문이다. 호출자는 identity() 오퍼레이터를 도입하여 이를 우회할 수 있다.

8.9.5. argMin/argMax 연산

축을 따라 모든 입력 값 중 최소값 또는 최대값의 인덱스 위치를 반환한다. 동률인 경우, 반환 값의 식별은 구현에 따라 달라진다.
dictionary MLArgMinMaxOptions : MLOperatorOptions {
  boolean keepDimensions = false;
  MLOperandDataType outputDataType = "int32";
};

partial interface MLGraphBuilder {
  MLOperand argMin(MLOperand input, [EnforceRange] unsigned long axis,
                   optional MLArgMinMaxOptions options = {});
  MLOperand argMax(MLOperand input, [EnforceRange] unsigned long axis,
                   optional MLArgMinMaxOptions options = {});
};

partial dictionary MLOpSupportLimits {
  MLSingleInputSupportLimits argMin;
  MLSingleInputSupportLimits argMax;
};

MLArgMinMaxOptions는 다음 멤버를 가진다.

keepDimensions, 타입은 boolean, 기본값은 false

true이면, 축소된 차원을 크기 1로 유지한다.

outputDataType, 타입은 MLOperandDataType, 기본값은 "int32"

MLOperandDataType. 출력 데이터 타입.

인수:

반환: MLOperand. keepDimensions가 true이면 inputrank와 같은 rank를 가진 출력 N-D tensor이며, keepDimensions가 false이면 inputrank - 1이다. 값은 outputDataType 타입이어야 하며, axis로 지정된 입력 차원의 크기를 N이라고 할 때 [0, N-1] 범위에 있어야 한다.

argMin()/argMax()에 대한 tensor 제한
피연산자 허용되는 데이터 타입 허용되는 rank
input any 1에서 N까지
output "int32", "int64" N

MLOpSupportLimitsargMin()argMax()에 대해 다음 멤버를 가진다.

argMin, 타입은 MLSingleInputSupportLimits

argMin() 오퍼레이터에 대한 지원 제한.

argMax, 타입은 MLSingleInputSupportLimits

argMax() 오퍼레이터에 대한 지원 제한.

string op, MLOperand input, unsigned long axis, 및 MLArgMinMaxOptions options가 주어졌을 때 argMin/argMax 연산을 생성한다는 것은 다음 단계를 실행하는 것이다.
  1. Assert: op는 "argMin", "argMax" 중 하나이다.

  2. this빌드할 수 없으면, "InvalidStateError" DOMExceptionthrow한다.

  3. thisinput으로 피연산자를 검증한 결과가 false를 반환하면, TypeErrorthrow한다.

  4. axisinputrank보다 크거나 같으면, TypeErrorthrow한다.

  5. options.outputDataType이 (이 표에 따른) 출력 tensor의 허용되는 데이터 타입이 아니면, TypeErrorthrow한다.

  6. inputshape[axis]가 options.outputDataType의 최대값보다 크면, TypeErrorthrow한다.

  7. outputShapeinputshape, « axis », 및 options.keepDimensions가 주어졌을 때 축소 출력 크기를 계산한 결과로 둔다. 그것이 failure를 반환하면, TypeErrorthrow한다.

  8. descoptions.outputDataTypeoutputShape가 주어졌을 때 MLOperandDescriptor를 생성한 결과로 둔다.

  9. 그래프 연결 만들기:

    1. operatoroptions가 주어진 op 연산에 대한 오퍼레이터로 둔다.

    2. outputthisdesc가 주어졌을 때 MLOperand를 생성한 결과로 둔다.

    3. output.[[operator]]operator로 설정한다.

    4. operatorinputinput으로 설정한다.

    5. operatoroutputoutput으로 설정한다.

  10. output을 반환한다.

다음 argMin/argMax 알고리즘이 지원된다.
argMin(input, axis, options) 메서드 단계는 다음과 같다.
  1. output을 "argMin", input, axisoptions가 주어졌을 때 argMin/argMax 연산을 생성한 결과로 둔다.

    1. 그것이 오류를 throw하면, 그 오류를 다시 throw한다.

  2. output을 반환한다.

argMax(input, axis, options) 메서드 단계는 다음과 같다.
  1. output을 "argMax", input, axisoptions가 주어졌을 때 argMin/argMax 연산을 생성한 결과로 둔다.

    1. 그것이 오류를 throw하면, 그 오류를 다시 throw한다.

  2. output을 반환한다.

8.9.6. batchNormalization

[Batch-Normalization]을 사용하여 입력 tensor의 값을 정규화한다. 각 입력 feature에 대해, 모델이 훈련되는 동안 해당 feature의 mean 및 variance 값은 batch 차원의 모든 sample에 걸쳐 계산된다. 그런 다음 이 mean 및 variance 값은 이후 모델 추론 중에 이 연산에 제공된다.
dictionary MLBatchNormalizationOptions : MLOperatorOptions {
  MLOperand scale;
  MLOperand bias;
  [EnforceRange] unsigned long axis = 1;
  double epsilon = 1e-5;
};

partial interface MLGraphBuilder {
  MLOperand batchNormalization(MLOperand input, MLOperand mean, MLOperand variance,
                               optional MLBatchNormalizationOptions options = {});
};

dictionary MLBatchNormalizationSupportLimits {
  MLTensorLimits input;
  MLTensorLimits mean;
  MLTensorLimits variance;
  MLTensorLimits scale;
  MLTensorLimits bias;
  MLTensorLimits output;
};

partial dictionary MLOpSupportLimits {
  MLBatchNormalizationSupportLimits batchNormalization;
};

MLBatchNormalizationOptions는 다음 멤버를 가진다.

scale, 타입은 MLOperand

axis가 나타내는 입력 차원의 크기와 같은 크기를 가지는 scaling 값의 1-D tensor.

bias, 타입은 MLOperand

axis가 나타내는 입력 차원의 크기와 같은 크기를 가지는 bias 값의 1-D tensor.

axis, 타입은 unsigned long, 기본값은 1

mean 및 variance 값이 대응되는 입력 shape의 feature 수 차원에 대한 인덱스. 그 값은 입력 tensor의 rank를 N이라고 할 때 [0, N-1] 범위에 있어야 한다. 기본값은 1이며, "nchw" 데이터 layout에서 channel("c") 차원에 대응한다.

epsilon, 타입은 double, 기본값은 1e-5

0으로 나눔으로 인한 계산 오류를 방지하기 위한 작은 값.

인수:

반환: MLOperand. input과 같은 shape의 batch-normalized N-D tensor.

batchNormalization()에 대한 tensor 제한
피연산자 허용되는 데이터 타입 허용되는 rank
input "float32", "float16" 1에서 N까지
mean input같음 1
variance input같음 1
scale input같음 1
bias input같음 1
output input같음 input같음

MLBatchNormalizationSupportLimits는 다음 멤버를 가진다.

input, 타입은 MLTensorLimits

input 피연산자에 대한 MLTensorLimits.

mean, 타입은 MLTensorLimits

mean 피연산자에 대한 MLTensorLimits.

variance, 타입은 MLTensorLimits

variance 피연산자에 대한 MLTensorLimits.

scale, 타입은 MLTensorLimits

scale 피연산자에 대한 MLTensorLimits.

bias, 타입은 MLTensorLimits

bias 피연산자에 대한 MLTensorLimits.

output, 타입은 MLTensorLimits

output 피연산자에 대한 MLTensorLimits.

MLOpSupportLimitsbatchNormalization()에 대해 다음 멤버를 가진다.

batchNormalization, 타입은 MLBatchNormalizationSupportLimits

batchNormalization() 오퍼레이터에 대한 지원 제한.

batchNormalization(input, mean, variance, options) 메서드 단계는 다음과 같다.
  1. this빌드할 수 없으면, "InvalidStateError" DOMExceptionthrow한다.

  2. 피연산자를 검증한 결과가 thisinput, mean, variance, options.scale (그것이 존재하는 경우), 및 options.bias (그것이 존재하는 경우) 중 하나가 주어졌을 때 false를 반환하면, TypeErrorthrow한다.

  3. inputdataType이 (이 표에 따른) 그 허용되는 데이터 타입 중 하나가 아니면, TypeErrorthrow한다.

  4. options.axis가 0부터 inputrank까지의 범위 안에 있지 않으면, 끝값은 제외하고, TypeErrorthrow한다.

  5. meandataType이 (이 표에 따른) 그 허용되는 데이터 타입 중 하나가 아니면, TypeErrorthrow한다.

  6. meanshape가 « inputshape[options.axis] »와 같지 않으면, TypeErrorthrow한다.

  7. variancedataType이 (이 표에 따른) 그 허용되는 데이터 타입 중 하나가 아니면, TypeErrorthrow한다.

  8. varianceshape가 « inputshape[options.axis] »와 같지 않으면, TypeErrorthrow한다.

  9. options.epsilonoptions.epsiloninputdataType으로 캐스팅한 결과로 설정한다.

  10. options.scale존재하면:

    1. dataType이 (이 표에 따른) 그 허용되는 데이터 타입 중 하나가 아니면, TypeErrorthrow한다.

    2. shape가 « inputshape[options.axis] »와 같지 않으면, TypeErrorthrow한다.

  11. options.bias존재하면:

    1. dataType이 (이 표에 따른) 그 허용되는 데이터 타입 중 하나가 아니면, TypeErrorthrow한다.

    2. shape가 « inputshape[options.axis] »와 같지 않으면, TypeErrorthrow한다.

  12. 그래프 연결 만들기:

    1. operatorinput, mean, varianceoptions가 주어진 "batchNormalization" 연산에 대한 오퍼레이터로 둔다.

    2. outputthisinput.[[descriptor]]가 주어졌을 때 MLOperand를 생성한 결과로 둔다.

    3. output.[[operator]]operator로 설정한다.

    4. operatorinputsinput, meanvariance로 설정한다.

    5. options.scale존재하면, 그것을 operatorinputs에 추가한다.

    6. options.bias존재하면, 그것을 operatorinputs에 추가한다.

    7. operatoroutputoutput으로 설정한다.

  13. output을 반환한다.

입력 tensor가 "nchw" layout의 4-D인 경우 이 연산의 동작은, user agent가 일반적으로 더 효율적인 구현을 가지고 있지만, 다음과 같이 다른 연산의 사용으로 일반적으로 에뮬레이트될 수 있다. 기반 플랫폼이 어떤 연산을 직접 지원하지 않는 경우, 이 분해는 구현을 안내하기 위한 템플릿으로 사용할 수 있다.
function batchNormalization(builder, input, mean, variance, options) {
  const shape = [1, input.shape[options.axis], 1, 1];
  return builder.add(
    builder.mul(
      builder.reshape(options.scale, shape),
      builder.div(
        builder.sub(input, builder.reshape(mean, shape)),
        builder.sqrt(builder.add(
          builder.reshape(variance, shape),
          builder.constant(input.dataType, options.epsilon))))),
    builder.reshape(options.bias, shape));
}

8.9.7. cast

입력 tensor의 각 element를 대상 데이터 타입으로 캐스팅한다.
partial interface MLGraphBuilder {
  MLOperand cast(MLOperand input,
                 MLOperandDataType dataType,
                 optional MLOperatorOptions options = {});
};

partial dictionary MLOpSupportLimits {
  MLSingleInputSupportLimits cast;
};
인수:

반환: MLOperand. 각 element가 대상 데이터 타입으로 캐스팅된, input과 같은 shape의 N-D tensor.

cast()에 대한 tensor 제한
피연산자 허용되는 데이터 타입 허용되는 rank
input any N
output any input같음

MLOpSupportLimitscast()에 대해 다음 멤버를 가진다.

cast, 타입은 MLSingleInputSupportLimits

cast() 오퍼레이터에 대한 지원 제한.

MLOperandDataType들 사이의 캐스팅은 다음 표에 따라, 일부 경우에는 지정되어 있고 다른 경우에는 구현 정의이다.

cast() 연산의 동작. inputdataType(행)과 대상 dataType (열)이 주어졌을 때.
대상 타입 입력 타입 "float32", "float16" "int32", "uint32", "int64", "uint64", "int8", "uint8"
"float32", "float16" 범위 안이면, 가장 가까운 표현 가능한 값.

범위를 벗어나면, +/-Infinity.

범위 안이면, truncation됨.

범위를 벗어나면, 구현 정의.

"int32", "uint32", "int64", "uint64", "int8", "uint8" 범위 안이면, 가장 가까운 표현 가능한 값.

범위를 벗어나면, +/-Infinity.

범위 안이면, 같은 값.

범위를 벗어나면, signed 타입에는 two’s complement를 가정하여 최하위 N비트를 대상 타입으로 재해석한다.

참고: 예를 들어 "int8"에서 "uint8"로 -1을 캐스팅하면 255가 산출되도록 지정되어 있다. 그러나 "float32"에서 "uint8"로 -1을 캐스팅하는 것은 구현 정의이다.

cast(input, dataType, options) 메서드 단계는 다음과 같다.
  1. this빌드할 수 없으면, "InvalidStateError" DOMExceptionthrow한다.

  2. 피연산자를 검증한 결과가 thisinput이 주어졌을 때 false를 반환하면, TypeErrorthrow한다.

  3. dataType이 (이 표에 따른) output tensor의 허용되는 데이터 타입이 아니면, TypeErrorthrow한다.

  4. 그래프 연결 만들기:

    1. operatordataTypeoptions가 주어진 "cast" 연산에 대한 오퍼레이터로 둔다.

    2. outputinput이 주어졌을 때 MLOperand를 복사한 결과로 둔다.

    3. output.[[operator]]operator로 설정한다.

    4. operatorinputinput으로 설정한다.

    5. operatoroutputoutput으로 설정한다.

  5. output을 반환한다.

8.9.8. clamp

최솟값과 최댓값으로 지정된 범위 안에서 입력 tensor를 element-wise로 clamp한다.
dictionary MLClampOptions : MLOperatorOptions {
  MLNumber minValue;
  MLNumber maxValue;
};

partial interface MLGraphBuilder {
  MLOperand clamp(MLOperand input, optional MLClampOptions options = {});
};

partial dictionary MLOpSupportLimits {
  MLSingleInputSupportLimits clamp;
};

MLClampOptions는 다음 멤버를 가진다.

minValue, 타입은 MLNumber

범위의 최솟값. 지정되지 않으면, 범위의 하한에 대한 clamping은 수행되지 않는다.

maxValue, 타입은 MLNumber

범위의 최댓값. 지정되지 않으면, 범위의 상한에 대한 clamping은 수행되지 않는다.

인수: 반환:
clamp()에 대한 tensor 제한
피연산자 허용되는 데이터 타입 허용되는 rank
input any N
output input같음 input같음

MLOpSupportLimitsclamp()에 대해 다음 멤버를 가진다.

clamp, 타입은 MLSingleInputSupportLimits

clamp() 오퍼레이터에 대한 지원 제한.

clamp(input, options) 메서드 단계는 다음과 같다.
  1. this빌드할 수 없으면, "InvalidStateError" DOMExceptionthrow한다.

  2. 피연산자를 검증한 결과가 thisinput이 주어졌을 때 false를 반환하면, TypeErrorthrow한다.

  3. minValue를 주어졌다면 options.minValue로, 그렇지 않으면 Infinity로 둔다.

  4. options.minValueminValueinputdataType으로 캐스팅한 결과로 설정한다.

  5. maxValue를 주어졌다면 options.maxValue로, 그렇지 않으면 -Infinity로 둔다.

  6. options.maxValuemaxValueinputdataType으로 캐스팅한 결과로 설정한다.

  7. options.minValueoptions.maxValue보다 크면, TypeErrorthrow한다.

  8. 그래프 연결 만들기:

    1. outputinput이 주어졌을 때 MLOperand를 복사한 결과로 둔다.

    2. operatoroptions가 주어진 "clamp" 연산에 대한 오퍼레이터로 둔다.

    3. output.[[operator]]operator로 설정한다.

    4. operatorinputinput으로 설정한다.

    5. operatoroutputoutput으로 설정한다.

  9. output을 반환한다.

이 연산의 동작은, user agent가 일반적으로 더 효율적인 구현을 가지고 있지만, 다음과 같이 다른 연산의 사용으로 일반적으로 에뮬레이트될 수 있다. 기반 플랫폼이 어떤 연산을 직접 지원하지 않는 경우, 이 분해는 구현을 안내하기 위한 템플릿으로 사용할 수 있다.
function clamp(builder, input, options) {
  if (options.minValue === undefined) {
    if (options.maxValue === undefined) {
      return input;
    } else {
      return builder.min(
        input, builder.constant(input.dataType, options.maxValue));
    }
  } else {
    if (options.maxValue === undefined) {
      return builder.max(
        input, builder.constant(input.dataType, options.minValue));
    } else {
      return builder.min(
        builder.max(input, builder.constant(input.dataType, options.minValue)),
        builder.constant(input.dataType, options.maxValue));
    }
  }
}

8.9.9. concat

주어진 축을 따라 입력 tensor들을 연결한다.
partial interface MLGraphBuilder {
  MLOperand concat(sequence<MLOperand> inputs,
                   [EnforceRange] unsigned long axis,
                   optional MLOperatorOptions options = {});
};

dictionary MLConcatSupportLimits {
  MLTensorLimits inputs;
  MLTensorLimits output;
};

partial dictionary MLOpSupportLimits {
  MLConcatSupportLimits concat;
};
인수:

반환: MLOperand. 모든 입력을 axis를 따라 연결한 tensor. 출력 tensor는 모든 입력이 연결된 차원을 제외하고 같은 shape를 가진다. 해당 차원의 크기는 같은 차원의 모든 입력 크기의 합으로 계산된다.

concat()에 대한 tensor 제한
피연산자 허용되는 데이터 타입 허용되는 rank
inputsitems any 1에서 N까지
output inputsitems같음 inputsitems같음

MLConcatSupportLimits는 다음 멤버를 가진다.

inputs, 타입은 MLTensorLimits

모든 input 피연산자에 대한 MLTensorLimits.

output, 타입은 MLTensorLimits

output 피연산자에 대한 MLTensorLimits.

MLOpSupportLimitsconcat()에 대해 다음 멤버를 가진다.

concat, 타입은 MLConcatSupportLimits

concat() 오퍼레이터에 대한 지원 제한.

concat(inputs, axis, options) 메서드 단계는 다음과 같다.
  1. this빌드할 수 없으면, "InvalidStateError" DOMExceptionthrow한다.

  2. 피연산자를 검증한 결과가 thisinputs 안의 어떤 item이 주어졌을 때 false를 반환하면, TypeErrorthrow한다.

  3. inputs size유효한 tensor 수가 아니면, TypeErrorthrow한다.

  4. firstinputs[0]으로 둔다.

  5. axisfirstrank보다 크거나 같으면, TypeErrorthrow한다.

  6. descfirstdataTypefirstshape가 주어졌을 때 MLOperandDescriptor를 생성한 결과로 둔다.

  7. desc.shape[axis]를 firstshape[axis]로 설정한다.

  8. 반복한다, 범위 1부터 inputssize까지, 끝값은 제외하고, 각 index에 대해:

    1. inputinputs[index]로 둔다.

    2. inputdataTypefirstdataType과 같지 않으면, TypeErrorthrow한다.

    3. inputrankfirstrank와 같지 않으면, TypeErrorthrow한다.

    4. 반복한다, 범위 0부터 inputrank까지, 끝값은 제외하고, 각 dim에 대해:

      axis가 지정한 차원의 shape와 타입을 제외하고, 피연산자들의 각 대응 차원 shape와 타입이 같지 않으면 실패한다.
      1. dimaxis와 같지 않고, inputshape[dim]이 firstshape[dim]과 같지 않으면, TypeErrorthrow한다.

      2. dimaxis와 같으면:

        1. sizedesc.shape[axis]와 inputshape[dim]의 합으로 둔다.

        2. size유효한 차원이 아니면, TypeErrorthrow한다.

        3. desc.shape[axis]를 size로 설정한다.

  9. 그래프 연결 만들기:

    1. outputthisdesc가 주어졌을 때 MLOperand를 생성한 결과로 둔다.

    2. operatorinputs, axis, 및 options가 주어진 "concat" 연산에 대한 오퍼레이터로 둔다.

    3. output.[[operator]]operator로 설정한다.

    4. operatorinputsinputs로 설정한다.

    5. operatoroutputoutput으로 설정한다.

  10. output을 반환한다.

8.9.10. conv2d

4-D input 및 filter tensor가 주어졌을 때 2-D convolution을 계산한다
enum MLConv2dFilterOperandLayout {
  "oihw",
  "hwio",
  "ohwi",
  "ihwo"
};

dictionary MLConv2dOptions : MLOperatorOptions {
  sequence<[EnforceRange] unsigned long> padding;
  sequence<[EnforceRange] unsigned long> strides;
  sequence<[EnforceRange] unsigned long> dilations;
  [EnforceRange] unsigned long groups = 1;
  MLInputOperandLayout inputLayout = "nchw";
  MLConv2dFilterOperandLayout filterLayout = "oihw";
  MLOperand bias;
};

partial interface MLGraphBuilder {
  MLOperand conv2d(MLOperand input,
                   MLOperand filter,
                   optional MLConv2dOptions options = {});
};

dictionary MLConv2dSupportLimits {
  MLTensorLimits input;
  MLTensorLimits filter;
  MLTensorLimits bias;
  MLTensorLimits output;
};

partial dictionary MLOpSupportLimits {
  MLConv2dSupportLimits conv2d;
};

MLConv2dOptions는 다음 멤버를 가진다.

padding, 타입은 sequence<[EnforceRange] unsigned long>

길이 4의 list: [beginningHeight, endingHeight, beginningWidth, endingWidth]. convolution input의 각 spatial dimension의 시작과 끝에 추가되는 행과 열을 지정한다. 기본값은 [0, 0, 0, 0]이다.

strides, 타입은 sequence<[EnforceRange] unsigned long>

길이 2의 list: [strideHeight, strideWidth]. convolution input의 각 spatial dimension에 대한 sliding window의 stride를 지정한다. 기본값은 [1, 1]이다.

dilations, 타입은 sequence<[EnforceRange] unsigned long>

길이 2의 list: [dilationHeight, dilationWidth]. convolution filter(kernel)에 적용되는 각 spatial dimension의 dilation factor를 지정한다. 기본값은 [1, 1]이다.

groups, 타입은 unsigned long, 기본값은 1

input channel과 output channel을 나누는 그룹 수.

inputLayout, 타입은 MLInputOperandLayout, 기본값은 "nchw"

입력 및 출력 tensor의 layout 형식을 다음과 같이 지정한다.

  • "nchw"

    • input tensor: [batches, inputChannels, height, width]

    • output tensor: [batches, outputChannels, height, width]

  • "nhwc":

    • input tensor: [batches, height, width, inputChannels]

    • output tensor: [batches, height, width, outputChannels]

filterLayout, 타입은 MLConv2dFilterOperandLayout, 기본값은 "oihw"

filter tensor의 layout 형식을 다음과 같이 지정한다.

  • "oihw": [outputChannels, inputChannels/groups, height, width]

  • "hwio": [height, width, inputChannels/groups, outputChannels]

  • "ohwi": [outputChannels, height, width, inputChannels/groups]

  • "ihwo": [inputChannels/groups, height, width, outputChannels]

bias, 타입은 MLOperand

convolution 결과에 더해질 값들을 가지는, [outputChannels] shape의 추가 1-D tensor.

인수:

반환: MLOperand. convolution 결과를 포함하는 출력 4-D tensor. 출력 shape는 inputLayout에 따라 해석된다. 더 구체적으로, "nchw" input layout에 대한 출력 tensor의 spatial dimension 또는 마지막 두 차원의 크기는 다음과 같이 계산할 수 있다.

outputSize = 1 + (inputSize - (filterSize - 1) * dilation - 1 + beginningPadding + endingPadding) / stride

conv2d()에 대한 tensor 제한
피연산자 허용되는 데이터 타입 허용되는 rank
input "float32", "float16" 4
filter input같음 4
bias input같음 1
output input같음 4

MLConv2dSupportLimits는 다음 멤버를 가진다.

input, 타입은 MLTensorLimits

input 피연산자에 대한 MLTensorLimits.

filter, 타입은 MLTensorLimits

filter 피연산자에 대한 MLTensorLimits.

bias, 타입은 MLTensorLimits

bias 피연산자에 대한 MLTensorLimits.

output, 타입은 MLTensorLimits

output 피연산자에 대한 MLTensorLimits.

MLOpSupportLimitsconv2d()에 대해 다음 멤버를 가진다.

conv2d, 타입은 MLConv2dSupportLimits

conv2d() 오퍼레이터에 대한 지원 제한.

depthwise conv2d 연산은 MobileNet과 같은 모델에서 사용되는 grouped convolution의 변형이다. 여기서 groups = inputChannels = outputChannels이며, filter tensor의 shape는 "oihw" layout의 경우 [options.groups, 1, height, width], "hwio" layout의 경우 [height, width, 1, options.groups], "ohwi" layout의 경우 [options.groups, height, width, 1], 그리고 "ihwo" layout의 경우 [1, height, width, options.groups]이다.
unsigned integer inputSize, filterSize, beginningPadding, endingPadding, stridedilation이 주어졌을 때 conv output size를 계산한다는 것은 다음 단계를 수행하는 것이다. 이는 number를 반환한다.
  1. effectiveFilterSize를 ( filterSize - 1 ) * dilation + 1로 둔다.

  2. outputSize를 ( inputSize - effectiveFilterSize + beginningPadding + endingPadding ) / stride + 1로 둔다.

  3. outputSize를 반환한다.

unsigned integer inputHeight, inputWidth, filterHeightfilterWidth, 4개의 unsigned integer로 된 list padding, 2개의 unsigned integer로 된 list strides, 그리고 2개의 unsigned integer로 된 list dilations가 주어졌을 때 conv2d output size를 계산한다는 것은 다음 단계를 수행하는 것이다. 이는 두 number의 list를 반환한다.
  1. outputHeightinputHeight, filterHeight, padding[0], padding[1], strides[0] 및 dilations[0]이 주어졌을 때 conv output size를 계산한 결과로 둔다.

  2. outputWidthinputWidth, filterWidth, padding[2], padding[3], strides[1] 및 dilations[1]이 주어졌을 때 conv output size를 계산한 결과로 둔다.

  3. « outputHeight, outputWidth »를 반환한다.

conv2d(input, filter, options) 메서드 단계는 다음과 같다.
  1. this빌드할 수 없으면, "InvalidStateError" DOMExceptionthrow한다.

  2. 피연산자를 검증한 결과가 thisinput, filter, 및 options.bias (그것이 존재하는 경우) 중 하나가 주어졌을 때 false를 반환하면, TypeErrorthrow한다.

  3. inputdataType이 (이 표에 따른) 그 허용되는 데이터 타입 중 하나가 아니면, TypeErrorthrow한다.

  4. inputrank가 그 허용되는 rank가 아니면, TypeErrorthrow한다.

  5. filterrank가 그 허용되는 rank가 아니면, TypeErrorthrow한다.

  6. filterdataType이 (이 표에 따른) 그 허용되는 데이터 타입 중 하나가 아니면, TypeErrorthrow한다.

  7. options.padding존재하지 않으면, 그것을 list « 0, 0, 0, 0 »로 설정한다.

  8. 그렇지 않고, options.paddingsize가 4가 아니면, TypeErrorthrow한다.

  9. options.strides존재하지 않으면, 그것을 list « 1, 1 »로 설정한다.

  10. 그렇지 않고, options.stridessize가 2가 아니면, TypeErrorthrow한다.

  11. options.strides의 어떤 item이라도 0이면, TypeErrorthrow한다.

  12. options.dilations존재하지 않으면, 그것을 list « 1, 1 »로 설정한다.

  13. 그렇지 않고, options.dilationssize가 2가 아니면, TypeErrorthrow한다.

  14. options.dilations의 어떤 item이라도 0이면, TypeErrorthrow한다.

  15. options.groups가 0이면, TypeErrorthrow한다.

  16. 출력 shape 계산하기:

    1. inputShapeinputshape로 둔다.

    2. options.inputLayout에 대해 switch한다:

      "nchw"

      « batches, inputChannels, inputHeight, inputWidth »를 inputShape로 둔다.

      "nhwc"

      « batches, inputHeight, inputWidth, inputChannels »를 inputShape로 둔다.

    3. filterShapefiltershape로 둔다.

    4. options.filterLayout에 대해 switch한다:

      "hwio"

      « filterHeight, filterWidth, filterInputChannels, outputChannels »를 filterShape로 둔다.

      "ohwi"

      « outputChannels, filterHeight, filterWidth, filterInputChannels »를 filterShape로 둔다.

      "ihwo"

      « filterInputChannels, filterHeight, filterWidth, outputChannels »를 filterShape로 둔다.

      "oihw"

      « outputChannels, filterInputChannels, filterHeight, filterWidth »를 filterShape로 둔다.

    5. inputChannels % options.groups가 0이 아니면, TypeErrorthrow한다.

    6. 그렇지 않고, inputChannels / options.groupsfilterInputChannels와 같지 않으면, TypeErrorthrow한다.

    7. outputChannels % options.groups가 0이 아니면, TypeErrorthrow한다.

    8. options.bias존재하면:

      1. shape가 « outputChannels »와 같지 않으면, TypeErrorthrow한다.

      2. dataType이 (이 표에 따른) 그 허용되는 데이터 타입 중 하나가 아니면, TypeErrorthrow한다.

    9. « outputHeight, outputWidth »를 inputHeight, inputWidth, filterHeight, filterWidth, options.padding, options.strides, 및 options.dilations가 주어졌을 때 conv2d output size를 계산한 결과로 둔다.

    10. outputHeight를 floor( outputHeight )로 설정한다.

    11. outputWidth를 floor( outputWidth )로 설정한다.

    12. outputHeight 또는 outputWidth 중 하나라도 유효한 차원이 아니면, TypeErrorthrow한다.

    13. options.inputLayout에 대해 switch한다:

      "nchw"

      outputShape를 « batches, outputChannels, outputHeight, outputWidth »로 둔다.

      "nhwc"

      outputShape를 « batches, outputHeight, outputWidth, outputChannels »로 둔다.

    14. descinputdataTypeoutputShape가 주어졌을 때 MLOperandDescriptor를 생성한 결과로 둔다.

  17. 그래프 연결 만들기:

    1. outputthisdesc가 주어졌을 때 MLOperand를 생성한 결과로 둔다.

    2. operatoroptionsfilter가 주어진 "conv2d" 연산에 대한 오퍼레이터로 둔다.

    3. output.[[operator]]operator로 설정한다.

    4. operatorinputsinputfilter로 설정한다.

    5. options.bias존재하면, 그것을 operatorinputs에 추가한다.

    6. operatoroutputoutput으로 설정한다.

  18. output을 반환한다.

8.9.11. convTranspose2d

4-D input 및 filter tensor가 주어졌을 때 2-D transposed convolution을 계산한다
enum MLConvTranspose2dFilterOperandLayout {
  "iohw",
  "hwoi",
  "ohwi"
};

dictionary MLConvTranspose2dOptions : MLOperatorOptions {
  sequence<[EnforceRange] unsigned long> padding;
  sequence<[EnforceRange] unsigned long> strides;
  sequence<[EnforceRange] unsigned long> dilations;
  sequence<[EnforceRange] unsigned long> outputPadding;
  sequence<[EnforceRange] unsigned long> outputSizes;
  [EnforceRange] unsigned long groups = 1;
  MLInputOperandLayout inputLayout = "nchw";
  MLConvTranspose2dFilterOperandLayout filterLayout = "iohw";
  MLOperand bias;
};

partial interface MLGraphBuilder {
  MLOperand convTranspose2d(MLOperand input, MLOperand filter,
                            optional MLConvTranspose2dOptions options = {});
};

partial dictionary MLOpSupportLimits {
  MLConv2dSupportLimits convTranspose2d;
};

MLConvTranspose2dOptions는 다음 멤버를 가진다.

padding, 타입은 sequence<[EnforceRange] unsigned long>

길이 4의 list: [beginningHeight, endingHeight, beginningWidth, endingWidth]. convolution input의 각 spatial dimension의 시작과 끝에 추가되는 행과 열을 지정한다. 기본값은 [0, 0, 0, 0]이다.

strides, 타입은 sequence<[EnforceRange] unsigned long>

길이 2의 list: [strideHeight, strideWidth]. convolution input의 각 spatial dimension에 대한 sliding window의 stride를 지정한다. 기본값은 [1, 1]이다.

dilations, 타입은 sequence<[EnforceRange] unsigned long>

길이 2의 list: [dilationHeight, dilationWidth]. convolution filter(kernel)에 적용되는 각 spatial dimension의 dilation factor를 지정한다. 기본값은 [1, 1]이다.

outputPadding, 타입은 sequence<[EnforceRange] unsigned long>

길이 2의 list. 출력 tensor의 각 spatial dimension에 적용되는 padding 값을 지정한다. 명시적인 padding 값은 strides의 값이 1보다 클 때 transposed convolution의 출력 tensor shape를 명확히 하기 위해 필요하다.

이 값들은 필요할 때 출력 shape를 명확히 하기 위해서만 사용되며, 반드시 어떤 padding 값이 출력 tensor에 쓰이게 하는 것은 아니라는 점에 유의한다.

기본값은 [0, 0]이다.

outputSizes, 타입은 sequence<[EnforceRange] unsigned long>

길이 2의 list. 출력 tensor의 마지막 두 차원의 크기를 지정한다. 출력 크기가 명시적으로 지정되면, outputPadding의 output padding 값은 무시된다.

지정되지 않으면, 출력 크기는 자동으로 계산된다.

groups, 타입은 unsigned long, 기본값은 1

input channel과 output channel을 나누는 그룹 수.

inputLayout, 타입은 MLInputOperandLayout, 기본값은 "nchw"

입력 및 출력 tensor의 layout 형식을 다음과 같이 지정한다.

  • "nchw"

    • input tensor: [batches, inputChannels, height, width]

    • output tensor: [batches, outputChannels, height, width]

  • "nhwc":

    • input tensor: [batches, height, width, inputChannels]

    • output tensor: [batches, height, width, outputChannels]

filterLayout, 타입은 MLConvTranspose2dFilterOperandLayout, 기본값은 "iohw"

filter tensor의 layout 형식을 다음과 같이 지정한다.

  • "iohw": [inputChannels, outputChannels/groups, height, width]

  • "hwoi": [height, width, outputChannels/groups, inputChannels]

  • "ohwi": [outputChannels/groups, height, width, inputChannels]

bias, 타입은 MLOperand

convolution 결과에 더해질 값들을 가지는, [outputChannels] shape의 추가 1-D tensor.

인수:

반환: MLOperand. transposed convolution 결과를 포함하는 출력 4-D tensor. 출력 shape는 inputLayout에 따라 해석된다. 더 구체적으로, outputSizes가 명시적으로 지정되지 않는 한, 출력 tensor의 spatial dimension 값을 다음과 같이 계산하려면 outputPadding이 필요하다.

outputSize = (inputSize - 1) * stride + (filterSize - 1) * dilation + 1 - beginningPadding - endingPadding + outputPadding

convTranspose2d()에 대한 tensor 제한
피연산자 허용되는 데이터 타입 허용되는 rank
input "float32", "float16" 4
filter input같음 4
bias input같음 1
output input같음 4

MLOpSupportLimitsconvTranspose2d()에 대해 다음 멤버를 가진다.

convTranspose2d, 타입은 MLConv2dSupportLimits

convTranspose2d() 오퍼레이터에 대한 지원 제한.

unsigned integer inputSize, filterSize, beginningPadding, endingPadding, stride, 및 dilation이 주어졌을 때 convtranspose output size를 계산한다는 것은 다음 단계를 수행하는 것이다. 이는 number를 반환한다.
  1. effectiveFilterSize를 ( filterSize - 1 ) * dilation + 1로 둔다.

  2. outputSize를 ( inputSize - 1 ) * stride + effectiveFilterSize - beginningPadding - endingPadding로 둔다.

  3. outputSize를 반환한다.

convTranspose2d(input, filter, options) 메서드 단계는 다음과 같다.
  1. this빌드할 수 없으면, "InvalidStateError" DOMExceptionthrow한다.

  2. 피연산자를 검증한 결과가 thisinput, filter, 및 options.bias (그것이 존재하는 경우) 중 하나가 주어졌을 때 false를 반환하면, TypeErrorthrow한다.

  3. inputrank가 그 허용되는 rank가 아니면, TypeErrorthrow한다.

  4. inputdataType이 (이 표에 따른) 그 허용되는 데이터 타입 중 하나가 아니면, TypeErrorthrow한다.

  5. filterrank가 그 허용되는 rank가 아니면, TypeErrorthrow한다.

  6. filterdataType이 (이 표에 따른) 그 허용되는 데이터 타입 중 하나가 아니면, TypeErrorthrow한다.

  7. options.padding존재하지 않으면, 그것을 list « 0, 0, 0, 0 »로 설정한다.

  8. 그렇지 않고, options.paddingsize가 4가 아니면, TypeErrorthrow한다.

  9. options.strides존재하지 않으면, 그것을 list « 1, 1 »로 설정한다.

  10. 그렇지 않고, options.stridessize가 2가 아니면, TypeErrorthrow한다.

  11. options.strides의 어떤 item이라도 0이면, TypeErrorthrow한다.

  12. options.dilations존재하지 않으면, 그것을 list « 1, 1 »로 설정한다.

  13. 그렇지 않고, options.dilationssize가 2가 아니면, TypeErrorthrow한다.

  14. options.dilations의 어떤 item이라도 0이면, TypeErrorthrow한다.

  15. options.outputPadding존재하지 않으면, 그것을 list « 0, 0 »로 설정한다.

  16. 그렇지 않고, options.outputPaddingsize가 2가 아니면, TypeErrorthrow한다.

  17. options.outputSizes존재하면:

    1. size가 2가 아니면, TypeErrorthrow한다.

  18. 그렇지 않으면:

    1. options.outputPadding[0]이 options.strides[0]보다 크거나 같거나, options.outputPadding[1]이 options.strides[1]보다 크거나 같으면, TypeErrorthrow한다.

  19. options.groups가 0이면, TypeErrorthrow한다.

  20. 출력 shape 계산하기:

    1. inputShapeinputshape로 둔다.

    2. options.inputLayout에 대해 switch한다:

      "nchw"

      « batches, inputChannels, inputHeight, inputWidth »를 inputShape로 둔다.

      "nhwc"

      « batches, inputHeight, inputWidth, inputChannels »를 inputShape로 둔다.

    3. filterShapefiltershape로 둔다.

    4. options.filterLayout에 대해 switch한다:

      "iohw"

      « filterInputChannels, filterOutputChannels, filterHeight, filterWidth »를 filterShape로 둔다.

      "hwoi"

      « filterHeight, filterWidth, filterOutputChannels, filterInputChannels »를 filterShape로 둔다.

      "ohwi"

      « filterOutputChannels, filterHeight, filterWidth, filterInputChannels »를 filterShape로 둔다.

    5. inputChannelsfilterInputChannels와 같지 않으면, TypeErrorthrow한다.

    6. outputChannelsfilterOutputChannels * options.groups로 둔다.

    7. outputChannels유효한 차원이 아니면, TypeErrorthrow한다.

    8. options.bias존재하면:

      1. shape가 « outputChannels »와 같지 않으면, TypeErrorthrow한다.

      2. dataType이 (이 표에 따른) 그 허용되는 데이터 타입 중 하나가 아니면, TypeErrorthrow한다.

    9. calculatedOutputHeightinputHeight, filterHeight, padding[0], padding[1], strides[0] 및 dilations[0]이 주어졌을 때 convtranspose output size를 계산한 결과로 둔다.

    10. calculatedOutputWidthinputWidth, filterWidth, padding[2], padding[3], strides[1] 및 dilations[1]이 주어졌을 때 convtranspose output size를 계산한 결과로 둔다.

    11. options.outputSizes존재하면:

      1. « outputHeight, outputWidth »를 options.outputSizes로 둔다.

      2. outputHeightcalculatedOutputHeight보다 작거나, outputHeightcalculatedOutputHeight + strides[0]보다 크거나 같으면, TypeErrorthrow한다.

      3. outputWidthcalculatedOutputWidth보다 작거나, outputWidthcalculatedOutputWidth + strides[1]보다 크거나 같으면, TypeErrorthrow한다.

    12. 그렇지 않으면:

      1. outputHeightcalculatedOutputHeight + options.outputPadding[0]으로 둔다.

      2. outputWidthcalculatedOutputWidth + options.outputPadding[1]로 둔다.

    13. outputHeight 또는 outputWidth 중 하나라도 유효한 차원이 아니면, TypeErrorthrow한다.

    14. options.inputLayout에 대해 switch한다:

      "nchw"

      outputShape를 « batches, outputChannels, floor( outputHeight ), floor( outputWidth ) »로 둔다.

      "nhwc"

      outputShape를 « batches, floor( outputHeight ), floor( outputWidth ), outputChannels »로 둔다.

    15. descinputdataTypeoutputShape가 주어졌을 때 MLOperandDescriptor를 생성한 결과로 둔다.

  21. 그래프 연결 만들기:

    1. outputthisdesc가 주어졌을 때 MLOperand를 생성한 결과로 둔다.

    2. operatoroptionsfilter가 주어진 "convTranspose2d" 연산에 대한 오퍼레이터로 둔다.

    3. output.[[operator]]operator로 설정한다.

    4. operatorinputsinputfilter로 설정한다.

    5. options.bias존재하면, 그것을 operatorinputs에 추가한다.

    6. operatoroutputoutput으로 설정한다.

  22. output을 반환한다.

8.9.12. cumulativeSum

주어진 axis를 따라 일련의 값들의 누적 합을 계산하며, 현재 값을 포함하거나 제외할 수 있다.
dictionary MLCumulativeSumOptions : MLOperatorOptions {
  boolean exclusive = false;
  boolean reversed = false;
};

partial interface MLGraphBuilder {
  MLOperand cumulativeSum(MLOperand input,
                          unsigned long axis,
                          optional MLCumulativeSumOptions options = {});
};

partial dictionary MLOpSupportLimits {
  MLSingleInputSupportLimits cumulativeSum;
};
cumulativeSum()에 대한 tensor 제한
피연산자 허용되는 데이터 타입 허용되는 rank
input "float32", "float16", "int32", "uint32", "int64", "uint64" 1에서 N까지
output input같음 input같음

MLCumulativeSumOptions는 다음 멤버를 가진다.

exclusive, 타입은 boolean, 기본값은 false

출력에 현재 값을 포함할지 제외할지 여부. 즉, inclusive prefix sum 또는 exclusive prefix sum [Prefix-sum]을 의미한다. input [1,2,3,4]가 주어졌을 때, inclusive summation은 [1,3,6,10]의 출력을 산출하는 반면 exclusive는 [0,1,3,6]을 산출한다. 기본값은 inclusive이다.

reversed, 타입은 boolean, 기본값은 false

active axis를 따라 합산 방향을 반대로 하여 높은 coordinate에서 낮은 coordinate로 시작할지 여부. input [1,2,3,4]가 주어졌을 때, inclusive forward summation은 [1,3,6,10]의 출력을 산출하는 반면 inclusive backward summation은 [10,9,7,4]를 산출한다. 기본값은 forward이다.

인수:

반환:

MLOpSupportLimitscumulativeSum()에 대해 다음 멤버를 가진다.

cumulativeSum, 타입은 MLSingleInputSupportLimits

cumulativeSum() 오퍼레이터에 대한 지원 제한.

cumulativeSum(input, axis, options) 메서드 단계는 다음과 같다.
  1. this빌드할 수 없으면, "InvalidStateError" DOMExceptionthrow한다.

  2. 피연산자를 검증한 결과가 thisinput이 주어졌을 때 false를 반환하면, TypeErrorthrow한다.

  3. inputdataType이 (이 표에 따른) 그 허용되는 데이터 타입 중 하나가 아니면, TypeErrorthrow한다.

  4. axisinputrank보다 크거나 같으면, TypeErrorthrow한다.

  5. 그래프 연결 만들기:

    1. outputinput이 주어졌을 때 MLOperand를 복사한 결과로 둔다.

    2. operator를 "cumulativeSum" 연산 및 options에 대한 오퍼레이터로 둔다.

    3. output.[[operator]]operator로 설정한다.

    4. operatorinputinput으로 설정한다.

    5. operatoroutputoutput으로 설정한다.

  6. output을 반환한다.

8.9.13. Element-wise 이항 연산

두 입력 tensor의 element-wise 이항 덧셈, 뺄셈, 곱셈, 나눗셈, 거듭제곱, 최댓값 및 최솟값을 계산한다.

연산은 broadcast되며, [numpy-broadcasting-rule]를 따른다. 입력 tensor들은 bidirectionally broadcastable이어야 한다. 출력 tensor의 rank는 입력 tensor들의 최대 rank이다. 출력 tensor의 각 dimension에 대해, 그 크기는 입력 tensor들의 해당 dimension을 따라 가장 큰 크기이다.

partial interface MLGraphBuilder {
  MLOperand add(MLOperand a, MLOperand b, optional MLOperatorOptions options = {});
  MLOperand sub(MLOperand a, MLOperand b, optional MLOperatorOptions options = {});
  MLOperand mul(MLOperand a, MLOperand b, optional MLOperatorOptions options = {});
  MLOperand div(MLOperand a, MLOperand b, optional MLOperatorOptions options = {});
  MLOperand max(MLOperand a, MLOperand b, optional MLOperatorOptions options = {});
  MLOperand min(MLOperand a, MLOperand b, optional MLOperatorOptions options = {});
  MLOperand pow(MLOperand a, MLOperand b, optional MLOperatorOptions options = {});
};

partial dictionary MLOpSupportLimits {
  MLBinarySupportLimits add;
  MLBinarySupportLimits sub;
  MLBinarySupportLimits mul;
  MLBinarySupportLimits div;
  MLBinarySupportLimits max;
  MLBinarySupportLimits min;
  MLBinarySupportLimits pow;
};
인수:

반환: MLOperand. 두 입력 tensor의 element-wise 이항 연산 결과를 포함하는 출력 tensor.

연산 타입:
element-wise 이항 옵션에 대한 tensor 제한
피연산자 허용되는 데이터 타입 허용되는 rank
a any N
b a같음 N
output a같음 N

MLOpSupportLimits는 element-wise 이항 연산에 대해 다음 멤버를 가진다.

add, 타입은 MLBinarySupportLimits

add() 오퍼레이터에 대한 지원 제한.

sub, 타입은 MLBinarySupportLimits

sub() 오퍼레이터에 대한 지원 제한.

mul, 타입은 MLBinarySupportLimits

mul() 오퍼레이터에 대한 지원 제한.

div, 타입은 MLBinarySupportLimits

div() 오퍼레이터에 대한 지원 제한.

max, 타입은 MLBinarySupportLimits

max() 오퍼레이터에 대한 지원 제한.

min, 타입은 MLBinarySupportLimits

min() 오퍼레이터에 대한 지원 제한.

pow, 타입은 MLBinarySupportLimits

pow() 오퍼레이터에 대한 지원 제한.

string op, MLOperand a, MLOperand b, 및 MLOperatorOptions options가 주어졌을 때 element-wise 이항 연산을 생성하려면, 다음 단계를 실행한다.
  1. Assert: op는 "add", "sub", "mul", "div", "max", "min", "pow" 중 하나이다.

  2. this빌드할 수 없으면, "InvalidStateError" DOMExceptionthrow한다.

  3. 피연산자를 검증한 결과가 thisa 또는 b 중 어느 하나가 주어졌을 때 false를 반환하면, TypeErrorthrow한다.

  4. adataTypebdataType과 같지 않으면, TypeErrorthrow한다.

  5. outputShapeashapebshapebidirectionally broadcasting한 결과로 둔다.

    1. 그것이 failure를 반환하면, TypeErrorthrow한다.

  6. descriptoradataTypeoutputShape가 주어졌을 때 MLOperandDescriptor를 생성한 결과로 둔다.

  7. 그래프 연결 만들기:

    1. outputthisdescriptor가 주어졌을 때 MLOperand를 생성한 결과로 둔다.

    2. operatora, b, 및 options가 주어진 op 연산에 대한 오퍼레이터로 둔다.

    3. output.[[operator]]operator로 설정한다.

    4. operatorinputsab로 설정한다.

    5. operatoroutputoutput으로 설정한다.

  8. output을 반환한다.

element-wise 이항 연산 알고리즘은 다음과 같이 element-wise 이항 연산을 생성하는 단계를 호출한다.
add(a, b, options) 메서드 단계는 다음과 같다.
  1. output을 "add", a, b, 및 options가 주어졌을 때 element-wise 이항 연산을 생성한 결과로 둔다.

    1. 그것이 error를 throw하면, 해당 error를 다시 throw한다.

  2. output을 반환한다.

sub(a, b, options) 메서드 단계는 다음과 같다.
  1. output을 "sub", a, b, 및 options가 주어졌을 때 element-wise 이항 연산을 생성한 결과로 둔다.

    1. 그것이 error를 throw하면, 해당 error를 다시 throw한다.

  2. output을 반환한다.

mul(a, b, options) 메서드 단계는 다음과 같다.
  1. output을 "mul", a, b, 및 options가 주어졌을 때 element-wise 이항 연산을 생성한 결과로 둔다.

    1. 그것이 error를 throw하면, 해당 error를 다시 throw한다.

  2. output을 반환한다.

div(a, b, options) 메서드 단계는 다음과 같다.
  1. output을 "div", a, b, 및 options가 주어졌을 때 element-wise 이항 연산을 생성한 결과로 둔다.

    1. 그것이 error를 throw하면, 해당 error를 다시 throw한다.

  2. output을 반환한다.

max(a, b, options) 메서드 단계는 다음과 같다.
  1. output을 "max", a, b, 및 options가 주어졌을 때 element-wise 이항 연산을 생성한 결과로 둔다.

    1. 그것이 error를 throw하면, 해당 error를 다시 throw한다.

  2. output을 반환한다.

min(a, b, options) 메서드 단계는 다음과 같다.
  1. output을 "min", a, b, 및 options가 주어졌을 때 element-wise 이항 연산을 생성한 결과로 둔다.

    1. 그것이 error를 throw하면, 해당 error를 다시 throw한다.

  2. output을 반환한다.

pow(a, b, options) 메서드 단계는 다음과 같다.
  1. output을 "pow", a, b, 및 options가 주어졌을 때 element-wise 이항 연산을 생성한 결과로 둔다.

    1. 그것이 error를 throw하면, 해당 error를 다시 throw한다.

  2. output을 반환한다.

8.9.14. Element-wise 논리 연산

input tensor들을 element-wise로 비교하고, 비교에 대해 0(false) 또는 1(true) 값을 가지는 "uint8" tensor를 반환한다. 단일 피연산자 연산의 경우, 해당 연산의 논리 결과를 반환한다.

여러 피연산자 연산의 경우, 연산은 broadcast되며 [numpy-broadcasting-rule]를 따른다. 입력 tensor들은 bidirectionally broadcastable이어야 한다. 출력 tensor의 rank는 입력 tensor들의 최대 rank이다. 출력 tensor의 각 dimension에 대해, 그 크기는 입력 tensor들의 해당 dimension을 따라 가장 큰 크기이다.

partial interface MLGraphBuilder {
  MLOperand equal(MLOperand a,
                  MLOperand b,
                  optional MLOperatorOptions options = {});
  MLOperand notEqual(MLOperand a,
                     MLOperand b,
                     optional MLOperatorOptions options = {});
  MLOperand greater(MLOperand a,
                    MLOperand b,
                    optional MLOperatorOptions options = {});
  MLOperand greaterOrEqual(MLOperand a,
                           MLOperand b,
                           optional MLOperatorOptions options = {});
  MLOperand lesser(MLOperand a,
                   MLOperand b,
                   optional MLOperatorOptions options = {});
  MLOperand lesserOrEqual(MLOperand a,
                          MLOperand b,
                          optional MLOperatorOptions options = {});
  MLOperand logicalNot(MLOperand a, optional MLOperatorOptions options = {});
  MLOperand logicalAnd(MLOperand a,
                       MLOperand b,
                       optional MLOperatorOptions options = {});
  MLOperand logicalOr(MLOperand a,
                      MLOperand b,
                      optional MLOperatorOptions options = {});
  MLOperand logicalXor(MLOperand a,
                       MLOperand b,
                       optional MLOperatorOptions options = {});
  MLOperand isNaN(MLOperand a, optional MLOperatorOptions options = {});
  MLOperand isInfinite(MLOperand a, optional MLOperatorOptions options = {});
};

dictionary MLLogicalNotSupportLimits {
  MLTensorLimits a;
  MLTensorLimits output;
};

partial dictionary MLOpSupportLimits {
  MLBinarySupportLimits equal;
  MLBinarySupportLimits notEqual;
  MLBinarySupportLimits greater;
  MLBinarySupportLimits greaterOrEqual;
  MLBinarySupportLimits lesser;
  MLBinarySupportLimits lesserOrEqual;
  MLLogicalNotSupportLimits logicalNot;
  MLBinarySupportLimits logicalAnd;
  MLBinarySupportLimits logicalOr;
  MLBinarySupportLimits logicalXor;
  MLLogicalNotSupportLimits isNaN;
  MLLogicalNotSupportLimits isInfinite;
};
인수:

반환: MLOperand. 두 입력 tensor의 element-wise 비교 결과를 포함하는 출력 tensor.

element-wise 논리 옵션에 대한 tensor 제한
피연산자 허용되는 데이터 타입 허용되는 rank
a 연산 단계의 일부로 지정됨 N
b a같음 N
output "uint8" N

MLLogicalNotSupportLimits는 다음 멤버를 가진다.

a, 타입은 MLTensorLimits

a 피연산자에 대한 MLTensorLimits.

output, 타입은 MLTensorLimits

output 피연산자에 대한 MLTensorLimits.

MLOpSupportLimits는 element-wise 논리 연산에 대해 다음 멤버를 가진다.

equal, 타입은 MLBinarySupportLimits

equal() 오퍼레이터에 대한 지원 제한.

notEqual, 타입은 MLBinarySupportLimits

notEqual() 오퍼레이터에 대한 지원 제한.

greater, 타입은 MLBinarySupportLimits

greater() 오퍼레이터에 대한 지원 제한.

greaterOrEqual, 타입은 MLBinarySupportLimits

greaterOrEqual() 오퍼레이터에 대한 지원 제한.

lesser, 타입은 MLBinarySupportLimits

lesser() 오퍼레이터에 대한 지원 제한.

lesserOrEqual, 타입은 MLBinarySupportLimits

lesserOrEqual() 오퍼레이터에 대한 지원 제한.

logicalNot, 타입은 MLLogicalNotSupportLimits

logicalNot() 오퍼레이터에 대한 지원 제한.

logicalAnd, 타입은 MLBinarySupportLimits

logicalAnd() 오퍼레이터에 대한 지원 제한.

logicalOr, 타입은 MLBinarySupportLimits

logicalOr() 오퍼레이터에 대한 지원 제한.

logicalXor, 타입은 MLBinarySupportLimits

logicalXor() 오퍼레이터에 대한 지원 제한.

isNaN, 타입은 MLLogicalNotSupportLimits

isNaN() 오퍼레이터에 대한 지원 제한.

isInfinite, 타입은 MLLogicalNotSupportLimits

isInfinite() 오퍼레이터에 대한 지원 제한.

연산 타입:
greaterOrEqual()lesserOrEqual() 연산은 각각 logicalNot(), lesser(), 및 greater() 연산으로 구현될 수 있지만(다시 말해 builder.greaterOrEqual(a, b)builder.logicalNot(builder.lesser(a, b))임), NaN 경우를 처리하고 성능상 이유로 이중 비교를 피하기 위해 별도로 정의된다.
string op, MLOperand a, 선택적 MLOperand b, 및 MLOperatorOptions options가 주어졌을 때 element-wise 논리 연산을 생성하려면, 다음 단계를 실행한다.
  1. Assert: op는 "equal", "notEqual", "greater", "greaterOrEqual", "lesser", "lesserOrEqual", "logicalNot", "logicalAnd", "logicalOr", "logicalXor", "isNaN", "isInfinite" 중 하나이다.

  2. this빌드할 수 없으면, "InvalidStateError" DOMExceptionthrow한다.

  3. 피연산자를 검증한 결과가 thisa가 주어졌을 때 false를 반환하면, TypeErrorthrow한다.

  4. op가 "logicalNot", "logicalAnd", "logicalOr", "logicalXor" 중 하나이면:

    1. adataType"uint8"이 아니면, TypeErrorthrow한다.

  5. op가 "isNaN", "isInfinite" 중 하나이면:

    1. adataType이 « "float32", "float16" » 중 하나가 아니면, TypeErrorthrow한다.

  6. b가 전달되었으면:

    1. 피연산자를 검증한 결과가 thisb가 주어졌을 때 false를 반환하면, TypeErrorthrow한다.

    2. adataTypebdataType과 같지 않으면, TypeErrorthrow한다.

    3. outputShapeashapebshapebidirectionally broadcasting한 결과로 둔다. 그것이 failure를 반환하면, TypeErrorthrow한다.

  7. 그렇지 않으면:

    1. outputShapeashapeclone으로 둔다.

  8. descriptor"uint8"outputShape가 주어졌을 때 MLOperandDescriptor를 생성한 결과로 둔다.

  9. 그래프 연결 만들기:

    1. outputthisdescriptor가 주어졌을 때 MLOperand를 생성한 결과로 둔다.

    2. operatora 및 (b가 전달된 경우) b, 그리고 options가 주어진 op 연산에 대한 오퍼레이터로 둔다.

    3. output.[[operator]]operator로 설정한다.

    4. operatorinputsa 및 (b가 전달된 경우) b로 설정한다.

    5. operatoroutputoutput으로 설정한다.

  10. output을 반환한다.

element-wise 논리 연산 알고리즘은 다음과 같이 element-wise 논리 연산을 생성하는 단계를 호출한다.
equal(a, b, options) 메서드 단계는 다음과 같다.
  1. output을 "equal", a, b, 및 options가 주어졌을 때 element-wise 논리 연산을 생성한 결과로 둔다.

    1. 그것이 error를 throw하면, 해당 error를 다시 throw한다.

  2. output을 반환한다.

notEqual(a, b, options) 메서드 단계는 다음과 같다.
  1. output을 "notEqual", a, b, 및 options가 주어졌을 때 element-wise 논리 연산을 생성한 결과로 둔다.

    1. 그것이 error를 throw하면, 해당 error를 다시 throw한다.

  2. output을 반환한다.

greater(a, b, options) 메서드 단계는 다음과 같다.
  1. output을 "greater", a, b, 및 options가 주어졌을 때 element-wise 논리 연산을 생성한 결과로 둔다.

    1. 그것이 error를 throw하면, 해당 error를 다시 throw한다.

  2. output을 반환한다.

greaterOrEqual(a, b, options) 메서드 단계는 다음과 같다.
  1. output을 "greaterOrEqual", a, b, 및 options가 주어졌을 때 element-wise 논리 연산을 생성한 결과로 둔다.

    1. 그것이 error를 throw하면, 해당 error를 다시 throw한다.

  2. output을 반환한다.

lesser(a, b, options) 메서드 단계는 다음과 같다.
  1. output을 "lesser", a, b, 및 options가 주어졌을 때 element-wise 논리 연산을 생성한 결과로 둔다.

    1. 그것이 error를 throw하면, 해당 error를 다시 throw한다.

  2. output을 반환한다.

lesserOrEqual(a, b, options) 메서드 단계는 다음과 같다.
  1. output을 "lesserOrEqual", a, b, 및 options가 주어졌을 때 element-wise 논리 연산을 생성한 결과로 둔다.

    1. 그것이 error를 throw하면, 해당 error를 다시 throw한다.

  2. output을 반환한다.

logicalNot(a, options) 메서드 단계는 다음과 같다.
  1. output을 "logicalNot", a, 및 options가 주어졌을 때 element-wise 논리 연산을 생성한 결과로 둔다.

    1. 그것이 error를 throw하면, 해당 error를 다시 throw한다.

  2. output을 반환한다.

logicalAnd(a, b, options) 메서드 단계는 다음과 같다.
  1. output을 "logicalAnd", a, b, 및 options가 주어졌을 때 element-wise 논리 연산을 생성한 결과로 둔다.

    1. 그것이 error를 throw하면, 해당 error를 다시 throw한다.

  2. output을 반환한다.

logicalOr(a, b, options) 메서드 단계는 다음과 같다.
  1. output을 "logicalOr", a, b, 및 options가 주어졌을 때 element-wise 논리 연산을 생성한 결과로 둔다.

    1. 그것이 error를 throw하면, 해당 error를 다시 throw한다.

  2. output을 반환한다.

logicalXor(a, b, options) 메서드 단계는 다음과 같다.
  1. output을 "logicalXor", a, b, 및 options가 주어졌을 때 element-wise 논리 연산을 생성한 결과로 둔다.

    1. 그것이 error를 throw하면, 해당 error를 다시 throw한다.

  2. output을 반환한다.

isNaN(a, options) 메서드 단계는 다음과 같다.
  1. output을 "isNaN", a, 및 options가 주어졌을 때 element-wise 논리 연산을 생성한 결과로 둔다.

    1. 그것이 error를 throw하면, 해당 error를 다시 throw한다.

  2. output을 반환한다.

isInfinite(a, options) 메서드 단계는 다음과 같다.
  1. output을 "isInfinite", a, 및 options가 주어졌을 때 element-wise 논리 연산을 생성한 결과로 둔다.

    1. 그것이 error를 throw하면, 해당 error를 다시 throw한다.

  2. output을 반환한다.

8.9.15. Element-wise 단항 연산

input tensor에 대한 element-wise 단항 연산을 계산한다.
partial interface MLGraphBuilder {
  MLOperand abs(MLOperand input, optional MLOperatorOptions options = {});
  MLOperand ceil(MLOperand input, optional MLOperatorOptions options = {});
  MLOperand cos(MLOperand input, optional MLOperatorOptions options = {});
  MLOperand erf(MLOperand input, optional MLOperatorOptions options = {});
  MLOperand exp(MLOperand input, optional MLOperatorOptions options = {});
  MLOperand floor(MLOperand input, optional MLOperatorOptions options = {});
  MLOperand identity(MLOperand input, optional MLOperatorOptions options = {});
  MLOperand log(MLOperand input, optional MLOperatorOptions options = {});
  MLOperand neg(MLOperand input, optional MLOperatorOptions options = {});
  MLOperand reciprocal(MLOperand input, optional MLOperatorOptions options = {});
  MLOperand roundEven(MLOperand input, optional MLOperatorOptions options = {});
  MLOperand sin(MLOperand input, optional MLOperatorOptions options = {});
  MLOperand sign(MLOperand input, optional MLOperatorOptions options = {});
  MLOperand sqrt(MLOperand input, optional MLOperatorOptions options = {});
  MLOperand tan(MLOperand input, optional MLOperatorOptions options = {});
};

partial dictionary MLOpSupportLimits {
  MLSingleInputSupportLimits abs;
  MLSingleInputSupportLimits ceil;
  MLSingleInputSupportLimits cos;
  MLSingleInputSupportLimits erf;
  MLSingleInputSupportLimits exp;
  MLSingleInputSupportLimits floor;
  MLSingleInputSupportLimits identity;
  MLSingleInputSupportLimits log;
  MLSingleInputSupportLimits neg;
  MLSingleInputSupportLimits reciprocal;
  MLSingleInputSupportLimits roundEven;
  MLSingleInputSupportLimits sin;
  MLSingleInputSupportLimits sign;
  MLSingleInputSupportLimits sqrt;
  MLSingleInputSupportLimits tan;
};
인수:

반환: MLOperand. input tensor의 element-wise 단항 연산 결과를 포함하는 출력 tensor. 출력 tensor의 shape는 input tensor의 shape와 같다.

element-wise 단항 옵션에 대한 tensor 제한
피연산자 허용되는 데이터 타입 허용되는 rank
input 연산 단계의 일부로 지정됨 N
output input같음 input같음

MLOpSupportLimits는 element-wise 단항 연산에 대해 다음 멤버를 가진다.

abs, 타입은 MLSingleInputSupportLimits

abs() 오퍼레이터에 대한 지원 제한.

ceil, 타입은 MLSingleInputSupportLimits

ceil() 오퍼레이터에 대한 지원 제한.

cos, 타입은 MLSingleInputSupportLimits

cos() 오퍼레이터에 대한 지원 제한.

erf, 타입은 MLSingleInputSupportLimits

erf() 오퍼레이터에 대한 지원 제한.

exp, 타입은 MLSingleInputSupportLimits

exp() 오퍼레이터에 대한 지원 제한.

floor, 타입은 MLSingleInputSupportLimits

floor() 오퍼레이터에 대한 지원 제한.

identity, 타입은 MLSingleInputSupportLimits

identity() 오퍼레이터에 대한 지원 제한.

log, 타입은 MLSingleInputSupportLimits

log() 오퍼레이터에 대한 지원 제한.

neg, 타입은 MLSingleInputSupportLimits

neg() 오퍼레이터에 대한 지원 제한.

reciprocal, 타입은 MLSingleInputSupportLimits

reciprocal() 오퍼레이터에 대한 지원 제한.

roundEven, 타입은 MLSingleInputSupportLimits

roundEven() 오퍼레이터에 대한 지원 제한.

sin, 타입은 MLSingleInputSupportLimits

sin() 오퍼레이터에 대한 지원 제한.

sign, 타입은 MLSingleInputSupportLimits

sign() 오퍼레이터에 대한 지원 제한.

sqrt, 타입은 MLSingleInputSupportLimits

sqrt() 오퍼레이터에 대한 지원 제한.

tan, 타입은 MLSingleInputSupportLimits

tan() 오퍼레이터에 대한 지원 제한.

연산 타입:
string op, MLOperand input, 선택적 list allowedDataTypes, 및 options가 주어졌을 때 element-wise 단항 연산을 생성하려면, 다음 단계를 실행한다.
  1. Assert: op는 "abs", "ceil", "cos", "erf", "exp", "floor", "identity", "log", "neg", "reciprocal", "roundEven", "sin", "sign", "sqrt", "tan" 중 하나이다.

  2. this빌드할 수 없으면, "InvalidStateError" DOMExceptionthrow한다.

  3. 피연산자를 검증한 결과가 thisinput이 주어졌을 때 false를 반환하면, TypeErrorthrow한다.

  4. allowedDataTypes가 주어졌고 그것이 inputdataTypecontain하지 않으면, TypeErrorthrow한다.

  5. 그래프 연결 만들기:

    1. outputinput이 주어졌을 때 MLOperand를 복사한 결과로 둔다.

    2. operatoroptions가 주어진 op 연산에 대한 오퍼레이터로 둔다.

    3. output.[[operator]]operator로 설정한다.

    4. operatorinputinput으로 설정한다.

    5. operatoroutputoutput으로 설정한다.

  6. output을 반환한다.

element-wise 단항 연산 알고리즘은 다음과 같이 element-wise 단항 연산을 생성하는 단계를 호출한다.
abs(input, options) 메서드 단계는 다음과 같다.
  1. output을 "abs", input, « "float32", "float16", "int64", "int32", "int8" », 및 options가 주어졌을 때 element-wise 단항 연산을 생성한 결과로 둔다.

    1. 그것이 error를 throw하면, 해당 error를 다시 throw한다.

  2. output을 반환한다.

ceil(input, options) 메서드 단계는 다음과 같다.
  1. output을 "ceil", input, « "float32", "float16" », 및 options가 주어졌을 때 element-wise 단항 연산을 생성한 결과로 둔다.

    1. 그것이 error를 throw하면, 해당 error를 다시 throw한다.

  2. output을 반환한다.

cos(input, options) 메서드 단계는 다음과 같다.
  1. output을 "cos", input, « "float32", "float16" », 및 options가 주어졌을 때 element-wise 단항 연산을 생성한 결과로 둔다.

    1. 그것이 error를 throw하면, 해당 error를 다시 throw한다.

  2. output을 반환한다.

erf(input, options) 메서드 단계는 다음과 같다.
  1. output을 "erf", input, « "float32", "float16" », 및 options가 주어졌을 때 element-wise 단항 연산을 생성한 결과로 둔다.

    1. 그것이 error를 throw하면, 해당 error를 다시 throw한다.

  2. output을 반환한다.

exp(input, options) 메서드 단계는 다음과 같다.
  1. output을 "exp", input, « "float32", "float16" », 및 options가 주어졌을 때 element-wise 단항 연산을 생성한 결과로 둔다.

    1. 그것이 error를 throw하면, 해당 error를 다시 throw한다.

  2. output을 반환한다.

floor(input, options) 메서드 단계는 다음과 같다.
  1. output을 "floor", input, « "float32", "float16" », 및 options가 주어졌을 때 element-wise 단항 연산을 생성한 결과로 둔다.

    1. 그것이 error를 throw하면, 해당 error를 다시 throw한다.

  2. output을 반환한다.

identity(input, options) 메서드 단계는 다음과 같다.
  1. output을 "identity", input, 및 options가 주어졌을 때 element-wise 단항 연산을 생성한 결과로 둔다.

    1. 그것이 error를 throw하면, 해당 error를 다시 throw한다.

  2. output을 반환한다.

log(input, options) 메서드 단계는 다음과 같다.
  1. output을 "log", input, « "float32", "float16" », 및 options가 주어졌을 때 element-wise 단항 연산을 생성한 결과로 둔다.

    1. 그것이 error를 throw하면, 해당 error를 다시 throw한다.

  2. output을 반환한다.

neg(input, options) 메서드 단계는 다음과 같다.
  1. output을 "neg", input, « "float32", "float16", "int64", "int32", "int8" », 및 options가 주어졌을 때 element-wise 단항 연산을 생성한 결과로 둔다.

    1. 그것이 error를 throw하면, 해당 error를 다시 throw한다.

  2. output을 반환한다.

reciprocal(input, options) 메서드 단계는 다음과 같다.
  1. output을 "reciprocal", input, « "float32", "float16" », 및 options가 주어졌을 때 element-wise 단항 연산을 생성한 결과로 둔다.

    1. 그것이 error를 throw하면, 해당 error를 다시 throw한다.

  2. output을 반환한다.

roundEven(input, options) 메서드 단계는 다음과 같다.
  1. output을 "roundEven", input, « "float32", "float16" », 및 options가 주어졌을 때 element-wise 단항 연산을 생성한 결과로 둔다.

    1. 그것이 error를 throw하면, 해당 error를 다시 throw한다.

  2. output을 반환한다.

sin(input, options) 메서드 단계는 다음과 같다.
  1. output을 "sin", input, « "float32", "float16" », 및 options가 주어졌을 때 element-wise 단항 연산을 생성한 결과로 둔다.

    1. 그것이 error를 throw하면, 해당 error를 다시 throw한다.

  2. output을 반환한다.

sign(input, options) 메서드 단계는 다음과 같다.
  1. output을 "sign", input, « "float32", "float16", "int64", "int32", "int8" », 및 options가 주어졌을 때 element-wise 단항 연산을 생성한 결과로 둔다.

    1. 그것이 error를 throw하면, 해당 error를 다시 throw한다.

  2. output을 반환한다.

sqrt(input, options) 메서드 단계는 다음과 같다.
  1. output을 "sqrt", input, « "float32", "float16" », 및 options가 주어졌을 때 element-wise 단항 연산을 생성한 결과로 둔다.

    1. 그것이 error를 throw하면, 해당 error를 다시 throw한다.

  2. output을 반환한다.

tan(input, options) 메서드 단계는 다음과 같다.
  1. output을 "tan", input, « "float32", "float16" », 및 options가 주어졌을 때 element-wise 단항 연산을 생성한 결과로 둔다.

    1. 그것이 error를 throw하면, 해당 error를 다시 throw한다.

  2. output을 반환한다.

sign() 연산의 동작은 다음과 같이 다른 연산을 사용하는 방식으로 일반적으로 에뮬레이션할 수 있지만, user agent는 보통 더 효율적인 구현을 가진다. 기반 플랫폼이 어떤 연산을 직접 지원하지 않는 경우, 이 분해는 구현을 안내하는 템플릿으로 사용될 수 있다.
function sign(builder, input, options) {
  const zero = builder.constant(input.dataType, 0);
  const positiveOne = builder.constant(input.dataType, 1);
  const negativeOne = builder.constant(input.dataType, -1);

  return builder.where(
    builder.greater(input, zero),
    positiveOne,
    builder.where(builder.lesser(input, zero), negativeOne, zero));
}

8.9.16. dequantizeLinear

scale 및 zero-point bias를 사용하여 integer tensor를 floating point tensor로 dequantize하며, 여기서 output = (input - zeroPoint) * scale이다. scalezeroPoint tensor들은 blockwise broadcastable이므로 input tensor보다 작을 수 있다.
partial interface MLGraphBuilder {
  MLOperand dequantizeLinear(MLOperand input,
                             MLOperand scale,
                             MLOperand zeroPoint,
                             optional MLOperatorOptions options = {});
};

dictionary MLQuantizeDequantizeLinearSupportLimits {
  MLTensorLimits input;
  MLTensorLimits scale;
  MLTensorLimits zeroPoint;
  MLTensorLimits output;
};

partial dictionary MLOpSupportLimits {
  MLQuantizeDequantizeLinearSupportLimits dequantizeLinear;
};
인수:

반환: MLOperand. dequantize된 값을 포함하는 출력 tensor.

dequantizeLinear()에 대한 tensor 제한
피연산자 허용되는 데이터 타입 허용되는 rank
input "uint8", "int8", "uint32", "int32" N
scale "float32", "float16" input같음
zeroPoint input같음 input같음
output scale같음 input같음

MLQuantizeDequantizeLinearSupportLimits는 다음 멤버를 가진다.

input, 타입은 MLTensorLimits

input 피연산자에 대한 MLTensorLimits.

scale, 타입은 MLTensorLimits

scale 피연산자에 대한 MLTensorLimits.

zeroPoint, 타입은 MLTensorLimits

zeroPoint 피연산자에 대한 MLTensorLimits.

output, 타입은 MLTensorLimits

output 피연산자에 대한 MLTensorLimits.

MLOpSupportLimitsdequantizeLinear()에 대해 다음 멤버를 가진다.

dequantizeLinear, 타입은 MLQuantizeDequantizeLinearSupportLimits

dequantizeLinear() 오퍼레이터에 대한 지원 제한.

dequantizeLinear(input, scale, zeroPoint, options) 메서드 단계는 다음과 같다.
  1. this.[[hasBuilt]]가 true이면, "InvalidStateError" DOMExceptionthrow한다.

  2. 피연산자를 검증한 결과가 thisinput, scale, 및 zeroPoint 중 어느 하나가 주어졌을 때 false를 반환하면, TypeErrorthrow한다.

  3. inputdataType이 (이 표에 따른) 그 허용되는 데이터 타입 중 하나가 아니면, TypeErrorthrow한다.

  4. scaledataType이 (이 표에 따른) 그 허용되는 데이터 타입 중 하나가 아니면, TypeErrorthrow한다.

  5. zeroPointdataType이 (이 표에 따른) 그 허용되는 데이터 타입 중 하나가 아니면, TypeErrorthrow한다.

  6. zeroPointdataTypeinputdataType과 같지 않으면, TypeErrorthrow한다.

  7. scalerank 또는 zeroPointrankinputrank와 같지 않으면, TypeErrorthrow한다.

  8. scaleshapezeroPointshape같지 않으면, TypeErrorthrow한다.

  9. scaleshapeinputshapeblockwise broadcasting한 결과가 false를 반환하면, TypeErrorthrow한다.

  10. zeroPointshapeinputshapeblockwise broadcasting한 결과가 false를 반환하면, TypeErrorthrow한다.

  11. outputDescriptorscaledataTypeinputshape가 주어졌을 때 MLOperandDescriptor를 생성한 결과로 둔다.

  12. 그래프 연결 만들기:

    1. outputthisoutputDescriptor가 주어졌을 때 MLOperand를 생성한 결과로 둔다.

    2. operatorinput, scale, zeroPoint, 및 options가 주어진 "dequantizeLinear" 연산에 대한 오퍼레이터로 둔다.

    3. output.[[operator]]operator로 설정한다.

    4. operatorinputinput으로 설정한다.

    5. operatoroutputoutput으로 설정한다.

  13. output을 반환한다.

이 연산의 동작은 다음과 같이 다른 연산을 사용하는 방식으로 일반적으로 에뮬레이션할 수 있지만, user agent는 보통 더 효율적인 구현을 가진다. 기반 플랫폼이 어떤 연산을 직접 지원하지 않는 경우, 이 분해는 구현을 안내하는 템플릿으로 사용될 수 있다.
function dequantizeLinear(builder, input, scale, zeroPoint, options) {
  // output = (input - zeroPoint) * scale
  const floatInput = builder.cast(input, scale.dataType);
  const floatZeroPoint = builder.cast(zeroPoint, scale.dataType);
  const upsampledScale = blockwiseExpand(builder, scale, input.shape);
  const upsampledZeroPoint =
    blockwiseExpand(builder, floatZeroPoint, input.shape);
  return builder.mul(
    builder.sub(floatInput, upsampledZeroPoint), upsampledScale);
}

function blockwiseExpand(builder, input, outputShape) {
  // 원래 input과 원하는 output shape가 주어지면, 이 함수는 각 axis를
  // 해당 axis별 반복 횟수만큼 block을 반복하여 확장한다. 다만 backend
  // 구현은 모든 dimension을 한 번에 upsample하기 위해 여러 dimension을
  // 허용할 수 있는, 훨씬 더 효율적인 upsampling operator를 가질 수 있다.
  // nearest neighbor resampling을 사용하는 integer multiple 방식이다:
  // output = resample(scale, {sizes: input.shape})

  let output = input;

  for (let axis = 0; axis < input.shape.length; ++axis) {
    const oldShape = output.shape;
    const oldDimensionLength = oldShape[axis];
    const newDimensionLength = outputShape[axis];

    if (newDimensionLength != oldDimensionLength) {
      // tile/expand는 전체 dimension slice의 반복만 허용하고
      // axis를 따라 개별 element를 반복할 수 없으므로, element를
      // 전체 block size까지 broadcast할 수 있게 tensor를 일시적으로
      // reshape한다. 이때 size 1인 dimension을 삽입한다.
      const elementRepeatCount = newDimensionLength / oldDimensionLength;
      const flattenedShape = getFlattenedShapeAroundAxis(oldShape, axis);
      const unexpandedShape =
        [flattenedShape[0], flattenedShape[1], 1, flattenedShape[2]];
      const expandedShape = [
        flattenedShape[0],
        flattenedShape[1],
        elementRepeatCount,
        flattenedShape[2]
      ];
      const reshapedInput = builder.reshape(output, unexpandedShape);
      output = builder.expand(reshapedInput, expandedShape);

      let newShape = [...oldShape];
      newShape[axis] = newDimensionLength;
      output = builder.reshape(output, newShape);
    }
  }

  return output;
}

// 주어진 axis 전후의 flattened shape를 계산하여
// 3-element list를 산출한다. 예:
// - inputShape = [2,3,4,5,6] with axis = 2 yields shape [6,4,30].
// - inputShape = [4] with axis = 0 yields shape [1,4,1].
function getFlattenedShapeAroundAxis(inputShape, axis) {
  axis = Math.max(Math.min(axis, inputShape.length - 1), 0);
  const shapeBefore = inputShape.slice(0, axis);
  const shapeAfter = inputShape.slice(axis + 1, inputShape.length);
  const countBefore = shapeBefore.reduce((a, b) => a * b, 1);
  const countAfter = shapeAfter.reduce((a, b) => a * b, 1);
  return [countBefore, inputShape[axis], countAfter];
}

8.9.17. quantizeLinear

scale 및 zero-point bias를 사용하여 floating point tensor를 integer tensor로 quantize한다(예: "uint8"의 경우 output = clamp(roundEven(input / scale) + zeroPoint, 0, 255)). scalezeroPoint tensor들은 blockwise broadcast되므로 input tensor보다 작을 수 있다.
partial interface MLGraphBuilder {
  MLOperand quantizeLinear(MLOperand input,
                           MLOperand scale,
                           MLOperand zeroPoint,
                           optional MLOperatorOptions options = {});
};

partial dictionary MLOpSupportLimits {
  MLQuantizeDequantizeLinearSupportLimits quantizeLinear;
};
인수:

반환: MLOperand. quantize된 값을 포함하는 출력 tensor.

quantizeLinear()에 대한 tensor 제한
피연산자 허용되는 데이터 타입 허용되는 rank
input "float32", "float16" N
scale input같음 input같음
zeroPoint "uint8", "int8", "uint32", "int32" input같음
output zeroPoint같음 input같음

MLOpSupportLimitsquantizeLinear()에 대해 다음 멤버를 가진다.

quantizeLinear, 타입은 MLQuantizeDequantizeLinearSupportLimits

quantizeLinear() 오퍼레이터에 대한 지원 제한.

quantizeLinear(input, scale, zeroPoint, options) 메서드 단계는 다음과 같다.
  1. this.[[hasBuilt]]가 true이면, "InvalidStateError" DOMExceptionthrow한다.

  2. 피연산자를 검증한 결과가 thisinput, scale, 및 zeroPoint 중 어느 하나가 주어졌을 때 false를 반환하면, TypeErrorthrow한다.

  3. inputdataType이 (이 표에 따른) 그 허용되는 데이터 타입 중 하나가 아니면, TypeErrorthrow한다.

  4. scaledataType이 (이 표에 따른) 그 허용되는 데이터 타입 중 하나가 아니면, TypeErrorthrow한다.

  5. scaledataTypeinputdataType과 같지 않으면, TypeErrorthrow한다.

  6. zeroPointdataType이 (이 표에 따른) 그 허용되는 데이터 타입 중 하나가 아니면, TypeErrorthrow한다.

  7. scalerank 또는 zeroPointrankinputrank와 같지 않으면, TypeErrorthrow한다.

  8. scaleshapezeroPointshape같지 않으면, TypeErrorthrow한다.

  9. scaleshapeinputshapeblockwise broadcasting한 결과가 false를 반환하면, TypeErrorthrow한다.

  10. zeroPointshapeinputshapeblockwise broadcasting한 결과가 false를 반환하면, TypeErrorthrow한다.

  11. outputDescriptorzeroPointdataTypeinputshape가 주어졌을 때 MLOperandDescriptor를 생성한 결과로 둔다.

  12. 그래프 연결 만들기:

    1. outputthisoutputDescriptor가 주어졌을 때 MLOperand를 생성한 결과로 둔다.

    2. operatorinput, scale, zeroPoint, 및 options가 주어진 "quantizeLinear" 연산에 대한 오퍼레이터로 둔다.

    3. output.[[operator]]operator로 설정한다.

    4. operatorinputinput으로 설정한다.

    5. operatoroutputoutput으로 설정한다.

  13. output을 반환한다.

이 연산의 동작은 다음과 같이 다른 연산을 사용하는 방식으로 일반적으로 에뮬레이션할 수 있지만, user agent는 보통 더 효율적인 구현을 가진다. 기반 플랫폼이 어떤 연산을 직접 지원하지 않는 경우, 이 분해는 구현을 안내하는 템플릿으로 사용될 수 있다.
function quantizeLinear(builder, input, scale, zeroPoint, options) {
  // output = clamp(roundEven(input / scale) + zeroPoint, 0, 255)
  // blockwiseExpand는 dequantizeLinear에서 정의된다.

  const floatZeroPoint = builder.cast(zeroPoint, scale.dataType);
  const upsampledScale = blockwiseExpand(builder, scale, input.shape);
  const upsampledZeroPoint =
    blockwiseExpand(builder, floatZeroPoint, input.shape);
  const quantizedInput = builder.roundEven(builder.div(input, upsampledScale));
  const zeroPointAdjustedInput =
    builder.add(quantizedInput, upsampledZeroPoint);
  const clampedInput =
    builder.clamp(zeroPointAdjustedInput, {'minValue': 0, 'maxValue': 255});
  return builder.cast(clampedInput, zeroPoint.dataType);
}

8.9.18. elu

input tensor에 대해 exponential linear unit function(ELU)을 element-wise로 계산한다. 계산은 max(0, x) + alpha * (exp(min(0, x)) - 1) 표현식을 따른다.
dictionary MLEluOptions : MLOperatorOptions {
  double alpha = 1;
};

partial interface MLGraphBuilder {
  MLOperand elu(MLOperand input, optional MLEluOptions options = {});
};

partial dictionary MLOpSupportLimits {
  MLSingleInputSupportLimits elu;
};

MLEluOptions는 다음 멤버를 가진다.

alpha, 타입은 double, 기본값은 1

scalar multiplier.

인수:

반환:

elu()에 대한 tensor 제한
피연산자 허용되는 데이터 타입 허용되는 rank
input "float32", "float16" N
output input같음 input같음

MLOpSupportLimitselu()에 대해 다음 멤버를 가진다.

elu, 타입은 MLSingleInputSupportLimits

elu() 오퍼레이터에 대한 지원 제한.

elu(input, options) 메서드 단계는 다음과 같다.
  1. this빌드할 수 없으면, "InvalidStateError" DOMExceptionthrow한다.

  2. 피연산자를 검증한 결과가 thisinput이 주어졌을 때 false를 반환하면, TypeErrorthrow한다.

  3. inputdataType이 (이 표에 따른) 그 허용되는 데이터 타입 중 하나가 아니면, TypeErrorthrow한다.

  4. options.alphaoptions.alphainputdataType으로 casting한 결과로 설정한다.

  5. 그래프 연결 만들기:

    1. outputinput이 주어졌을 때 MLOperand를 복사한 결과로 둔다.

    2. operatoroptions가 주어진 "elu" 연산에 대한 오퍼레이터로 둔다.

    3. output.[[operator]]operator로 설정한다.

    4. operatorinputinput으로 설정한다.

    5. operatoroutputoutput으로 설정한다.

  6. output을 반환한다.

이 연산의 동작은 다음과 같이 다른 연산을 사용하는 방식으로 일반적으로 에뮬레이션할 수 있지만, user agent는 보통 더 효율적인 구현을 가진다. 기반 플랫폼이 어떤 연산을 직접 지원하지 않는 경우, 이 분해는 구현을 안내하는 템플릿으로 사용될 수 있다.
function elu(builder, input, options) {
  return builder.add(
    builder.max(builder.constant(input.dataType, 0), input),
    builder.mul(
      builder.constant(input.dataType, options.alpha),
      builder.sub(
        builder.exp(builder.min(builder.constant(input.dataType, 0), input)),
        builder.constant(input.dataType, 1))));
}

8.9.19. expand

input tensor의 size가 1인 임의의 dimension을 새 shape에 따라 더 큰 size로 확장한다. 이 확장은 [numpy-broadcasting-rule]와 일치한다. input tensor는 새 shape로 unidirectionally broadcastable이어야 한다. 각 dimension은 size가 1이거나 새 shape에 따른 해당 output dimension의 size와 일치해야 한다.
partial interface MLGraphBuilder {
  MLOperand expand(MLOperand input,
                   sequence<[EnforceRange] unsigned long> newShape,
                   optional MLOperatorOptions options = {});
};

partial dictionary MLOpSupportLimits {
  MLSingleInputSupportLimits expand;
};
인수:

반환: MLOperand. 확장된 size shape를 가진 tensor.

expand()에 대한 tensor 제한
피연산자 허용되는 데이터 타입 허용되는 rank
input any N
output input같음 N

MLOpSupportLimitsexpand()에 대해 다음 멤버를 가진다.

expand, 타입은 MLSingleInputSupportLimits

expand() 오퍼레이터에 대한 지원 제한.

expand(input, newShape, options) 메서드 단계는 다음과 같다.
  1. this빌드할 수 없으면, "InvalidStateError" DOMExceptionthrow한다.

  2. 피연산자를 검증한 결과가 thisinput이 주어졌을 때 false를 반환하면, TypeErrorthrow한다.

  3. outputShapeinputshapenewShapeunidirectionally broadcasting한 결과로 둔다.

    1. 그것이 failure를 반환하면, TypeErrorthrow한다.

  4. outputShapesize가 (이 표에 따른) output tensor의 허용되는 rank가 아니면, TypeErrorthrow한다.

  5. outputDescriptorinputdataTypeoutputShape가 주어졌을 때 MLOperandDescriptor를 생성한 결과로 둔다.

  6. 그래프 연결 만들기:

    1. outputthisoutputDescriptor가 주어졌을 때 MLOperand를 생성한 결과로 둔다.

    2. operatorinput, newShape, 및 options가 주어진 "expand" 연산에 대한 오퍼레이터로 둔다.

    3. output.[[operator]]operator로 설정한다.

    4. operatorinputinput으로 설정한다.

    5. operatoroutputoutput으로 설정한다.

  7. output을 반환한다.

8.9.20. gather

indices에 따라 axis를 따라 input tensor의 값들을 gather한다.
dictionary MLGatherOptions : MLOperatorOptions {
  [EnforceRange] unsigned long axis = 0;
};

partial interface MLGraphBuilder {
  MLOperand gather(MLOperand input,
                   MLOperand indices,
                   optional MLGatherOptions options = {});
};

dictionary MLGatherSupportLimits {
  MLTensorLimits input;
  MLTensorLimits indices;
  MLTensorLimits output;
};

partial dictionary MLOpSupportLimits {
  MLGatherSupportLimits gather;
};

MLGatherOptions는 다음 멤버를 가진다.

axis, 타입은 unsigned long, 기본값은 0

gather된 값들이 얻어지는 axis. 그 값은 N이 input tensor의 rank일 때 [0, N-1] 범위 안에 있어야 한다.

인수:

반환: MLOperand. inputrank + indicesrank - 1과 같은 rank를 가지는 출력 N-D tensor.

indices 매개변수는 input이 실행 전까지 알려지지 않으므로 graph가 build될 때 gather()에 대해 허용 범위로 clamp될 수 없다. 지정된 clamping 동작이 기반 플랫폼에서 제공되지 않으면, 구현은 컴파일된 graph 안에 clamp()를 도입할 수 있다. 마찬가지로, 기반 플랫폼이 negative indices를 지원하지 않으면, 구현은 dimension의 끝에서부터의 negative index를 positive index로 변환하는 연산들을 컴파일된 graph 안에 도입할 수 있다.
gather()에 대한 tensor 제한
피연산자 허용되는 데이터 타입 허용되는 rank
input any 1에서 N까지
indices "int32", "uint32", "int64" N
output input같음 N

MLGatherSupportLimits는 다음 멤버를 가진다.

input, 타입은 MLTensorLimits

input 피연산자에 대한 MLTensorLimits.

indices, 타입은 MLTensorLimits

indices 피연산자에 대한 MLTensorLimits.

output, 타입은 MLTensorLimits

output 피연산자에 대한 MLTensorLimits.

MLOpSupportLimitsgather()에 대해 다음 멤버를 가진다.

gather, 타입은 MLGatherSupportLimits

gather() 오퍼레이터에 대한 지원 제한.

gather(input, indices, options) 메서드 단계는 다음과 같다.
  1. this빌드할 수 없으면, "InvalidStateError" DOMExceptionthrow한다.

  2. 피연산자를 검증한 결과가 thisinput 또는 indices 중 어느 하나가 주어졌을 때 false를 반환하면, TypeErrorthrow한다.

  3. indicesdataType이 (이 표에 따른) 그 허용되는 데이터 타입 중 하나가 아니면, TypeErrorthrow한다.

  4. inputShapeinputshape로, inputRankinputrank로 둔다.

  5. indicesShapeindicesshape로 둔다.

  6. axisoptions.axis로 둔다.

  7. axisinputRank보다 크거나 같으면, TypeErrorthrow한다.

  8. dimCount를 0으로 둔다.

  9. outputRank를 0으로 둔다.

  10. outputShape를 빈 list로 둔다.

  11. inputShape의 각 size에 대해 반복한다:

    1. dimCountaxis와 같으면, break한다.

    2. outputShape[dimCount]를 size로 설정한다.

    3. dimCount를 1 증가시킨다.

  12. outputRankdimCount로 설정한다.

  13. dimCount를 0으로 둔다.

  14. indicesShape의 각 size에 대해 반복한다:

    1. outputShape[outputRank + dimCount]를 size로 설정한다.

    2. dimCount를 1 증가시킨다.

  15. outputRankoutputRank + dimCount로 설정한다.

  16. dimCount를 0으로 둔다.

  17. inputShape의 각 size에 대해 반복한다:

    1. dimCountaxis보다 작거나 같으면, continue한다.

    2. outputShape[outputRank + dimCount - axis - 1]를 size로 설정한다.

    3. dimCount를 1 증가시킨다.

  18. descinputdataTypeoutputShape가 주어졌을 때 MLOperandDescriptor를 생성한 결과로 둔다.

  19. 그래프 연결 만들기:

    1. outputdesc가 주어졌을 때 MLOperand를 생성한 결과로 둔다.

    2. operatorinput, indices, 및 options가 주어진 "gather" 연산에 대한 오퍼레이터로 둔다.

    3. output.[[operator]]operator로 설정한다.

    4. operatorinputsinputindices로 설정한다.

    5. operatoroutputoutput으로 설정한다.

  20. output을 반환한다.

gather가 서로 다른 slicing scheme에서 어떻게 동작하는지에 대한 예.
// shape [4,3]인 input:
//   [[ 0,  1,  2],
//    [10, 11, 12],
//    [20, 21, 22],
//    [30, 31, 32]]
const input = builder.constant(
  {dataType: 'float32', shape: [4, 3]},
  new Float32Array([0, 1, 2, 10, 11, 12, 20, 21, 22, 30, 31, 32]));

// axis = 0 (default)
// shape [2]인 indices:
//   [3,1]
// shape [2,3]인 output:
//   [[30, 31, 32],
//    [10, 11, 12]]

const indices1 =
  builder.constant({dataType: 'uint32', shape: [2]}, new Uint32Array([3, 1]));

const output1 = builder.gather(input, indices1);

// axis = 1
// shape [3]인 indices:
//   [2,1,1]
// shape [4,3]인 output:
//   [[ 2,  1,  1],
//    [12, 11, 11],
//    [22, 21, 21],
//    [32, 31, 31]]

const indices2 = builder.constant(
  {dataType: 'uint32', shape: [3]}, new Uint32Array([2, 1, 1]));

const output2 = builder.gather(input, indices2, {axis: 1});

// axis = 1
// shape [2,2]인 indices:
//   [[0, 1],
//    [1, 2]]
// shape [4,2,2]인 output:
//   [[[ 0,  1], [ 1,  2]],
//    [[10, 11], [11, 12]],
//    [[20, 21], [21, 22]],
//    [[30, 31], [31, 32]]]

const indices3 = builder.constant(
  {dataType: 'uint32', shape: [2, 2]}, new Uint32Array([0, 1, 1, 2]));

const output3 = builder.gather(input, indices3, {axis: 1});

8.9.21. gatherElements

indices에 따라 axis를 따라 input tensor의 값들을 gather한다.
partial interface MLGraphBuilder {
  MLOperand gatherElements(MLOperand input,
                           MLOperand indices,
                           optional MLGatherOptions options = {});
};

partial dictionary MLOpSupportLimits {
  MLGatherSupportLimits gatherElements;
};
인수:

반환: MLOperand. inputrank와 같은 rank를 가지는 출력 N-D tensor.

gatherElements()에 대한 tensor 제한
피연산자 허용되는 데이터 타입 허용되는 rank
input any 1에서 N까지
indices "int32", "uint32", "int64" input같음
output input같음 input같음

MLOpSupportLimitsgatherElements()에 대해 다음 멤버를 가진다.

gatherElements, 타입은 MLGatherSupportLimits

gatherElements() 오퍼레이터에 대한 지원 제한.

indices 매개변수는 input이 실행 전까지 알려지지 않으므로 graph가 build될 때 gatherElements()에 대해 허용 범위로 clamp될 수 없다. 지정된 clamping 동작이 기반 플랫폼에서 제공되지 않으면, 구현은 컴파일된 graph 안에 clamp()를 도입할 수 있다. 마찬가지로, 기반 플랫폼이 negative indices를 지원하지 않으면, 구현은 dimension의 끝에서부터의 negative index를 positive index로 변환하는 연산들을 컴파일된 graph 안에 도입할 수 있다.
gatherElements(input, indices, options) 메서드 단계는 다음과 같다.
  1. this빌드할 수 없으면, "InvalidStateError" DOMExceptionthrow한다.

  2. 피연산자를 검증한 결과가 thisinput 또는 indices 중 어느 하나가 주어졌을 때 false를 반환하면, TypeErrorthrow한다.

  3. indicesdataType이 (이 표에 따른) 그 허용되는 데이터 타입 중 하나가 아니면, TypeErrorthrow한다.

  4. input 또는 indices 중 어느 하나의 rank가 그 허용되는 rank가 아니면, TypeErrorthrow한다.

  5. axisoptions.axis로 둔다.

  6. axisinputrank보다 크거나 같으면, TypeErrorthrow한다.

  7. indicesShapeExpectedinputshape의 copy로 둔다.

  8. indicesShapeExpected[axis]를 indicesshape[axis]로 설정한다.

  9. indicesshapeindicesShapeExpected와 같지 않으면, TypeErrorthrow한다.

  10. 그래프 연결 만들기:

    1. outputinput이 주어졌을 때 MLOperand를 복사한 결과로 둔다.

    2. operatorinput, indices, 및 options가 주어진 "gatherElements" 연산에 대한 오퍼레이터로 둔다.

    3. output.[[operator]]operator로 설정한다.

    4. operatorinputsinputindices로 설정한다.

    5. operatoroutputoutput으로 설정한다.

  11. output을 반환한다.

gatherElements가 서로 다른 slicing scheme에서 어떻게 동작하는지에 대한 예.
// shape [4,3]인 input:
//   [[ 0,  1,  2],
//    [10, 11, 12],
//    [20, 21, 22],
//    [30, 31, 32]]
// shape [2,3]인 indices:
//   [[3, 1, 1],
//    [2, 0, 3]]
// axis = 0 (default)
// shape [2,3]인 output:
//   [[30, 11, 12],
//    [20,  1, 32]]

const input1 = builder.constant(
  {dataType: 'float32', shape: [4, 3]},
  new Float32Array([0, 1, 2, 10, 11, 12, 20, 21, 22, 30, 31, 32]));

const indices1 = builder.constant(
  {dataType: 'uint32', shape: [2, 3]}, new Uint32Array([3, 1, 1, 2, 0, 3]));

const output1 = builder.gatherElements(input1, indices1);

// shape [4,3]인 input:
//   [[ 0,  1,  2],
//    [10, 11, 12],
//    [20, 21, 22],
//    [30, 31, 32]]
// shape [4,1]인 indices:
//   [[2],
//    [1],
//    [0],
//    [2]],
// axis = 1
// shape [4,1]인 output:
//   [[ 2],
//    [11],
//    [20],
//    [32]]

const indices2 = builder.constant(
  {dataType: 'uint32', shape: [4, 1]}, new Uint32Array([2, 1, 0, 2]));

const output2 = builder.gatherElements(input1, indices2, {axis: 1});

// shape [4,2,2]인 input:
//   [[[  0,   1],
//     [ 10,  11]],
//    [[100, 101],
//     [110, 111]],
//    [[200, 201],
//     [210, 211]],
//    [[300, 301],
//     [310, 311]],]
// shape [1,2,2]인 indices:
//   [[[0, 2],
//     [1, 3]]],
// axis = 0
// shape [1,2,2]인 output:
//   [[[  0, 201],
//     [110, 311]]]

const inputData3 = new Float32Array(
  [0, 1, 10, 11, 100, 101, 110, 111, 200, 201, 210, 211, 300, 301, 310, 311]);

const input3 =
  builder.constant({dataType: 'float32', shape: [4, 2, 2]}, inputData3);

const indices3 = builder.constant(
  {dataType: 'uint32', shape: [1, 2, 2]}, new Uint32Array([0, 2, 1, 3]));

const output3 = builder.gatherElements(input3, indices3, {axis: 0});

8.9.22. gatherND

indices에 따라 input tensor의 slice들을 gather한다.
partial interface MLGraphBuilder {
  MLOperand gatherND(MLOperand input,
                     MLOperand indices,
                     optional MLOperatorOptions options = {});
};

partial dictionary MLOpSupportLimits {
  MLGatherSupportLimits gatherND;
};
인수:

반환: MLOperand. inputrank + indicesrank - indicesshape[-1] - 1과 같은 rank를 가지는 출력 N-D tensor.

gatherND()에 대한 tensor 제한
피연산자 허용되는 데이터 타입 허용되는 rank
input any 1에서 N까지
indices "int32", "uint32", "int64" 1에서 N까지
output input같음 N

MLOpSupportLimitsgatherND()에 대해 다음 멤버를 가진다.

gatherND, 타입은 MLGatherSupportLimits

gatherND() 오퍼레이터에 대한 지원 제한.

indices 매개변수는 input이 실행 전까지 알려지지 않으므로 graph가 build될 때 gatherND()에 대해 허용 범위로 clamp될 수 없다. 지정된 clamping 동작이 기반 플랫폼에서 제공되지 않으면, 구현은 컴파일된 graph 안에 clamp()를 도입할 수 있다. 마찬가지로, 기반 플랫폼이 negative indices를 지원하지 않으면, 구현은 dimension의 끝에서부터의 negative index를 positive index로 변환하는 연산들을 컴파일된 graph 안에 도입할 수 있다.
gatherND(input, indices, options) 메서드 단계는 다음과 같다.
  1. this빌드할 수 없으면, "InvalidStateError" DOMExceptionthrow한다.

  2. 피연산자를 검증한 결과가 thisinput 또는 indices 중 어느 하나가 주어졌을 때 false를 반환하면, TypeErrorthrow한다.

  3. indicesdataType이 (이 표에 따른) 허용되는 데이터 타입 중 하나가 아니면, TypeErrorthrow한다.

  4. input 또는 indices 중 어느 하나의 rank가 그 허용되는 rank가 아니면, TypeErrorthrow한다.

  5. inputShapeinputshape로, inputRankinputrank로 둔다.

  6. indicesShapeindicesshape로, indicesRankindicesrank로 둔다.

  7. input 또는 indices 중 어느 하나의 rank가 그 허용되는 rank가 아니면, TypeErrorthrow한다.

  8. indexableSizeindicesRank - 1로 둔다.

  9. coordinateSizeindicesShape[indexableSize]로 둔다.

  10. coordinateSizeinputRank보다 크면, TypeErrorthrow한다.

  11. outputShape를 빈 list로 둔다.

  12. 0부터 indexableSize까지의 범위에서 끝값을 제외하고 각 index에 대해 반복한다:

    1. indicesShape[index]를 outputShapeappend한다.

  13. coordinateSize부터 inputRank까지의 범위에서 끝값을 제외하고 각 index에 대해 반복한다:

    1. inputShape[index]를 outputShapeappend한다.

  14. outputDescinputdataTypeoutputShape가 주어졌을 때 MLOperandDescriptor를 생성한 결과로 둔다.

  15. 그래프 연결 만들기:

    1. outputoutputDesc가 주어졌을 때 MLOperand를 생성한 결과로 둔다.

    2. operatorinput, indices, 및 options가 주어진 "gatherND" 연산에 대한 오퍼레이터로 둔다.

    3. output.[[operator]]operator로 설정한다.

    4. operatorinputsinputindices로 설정한다.

    5. operatoroutputoutput으로 설정한다.

  16. output을 반환한다.

gatherND가 서로 다른 slicing scheme에서 어떻게 동작하는지에 대한 예.
// shape [2,2]인 input:
//   [[0, 1],
//    [2, 3]]
// shape [3,2]인 indices:
//   [[0, 0],
//    [1, 1],
//    [1, 0]]
// shape [3]인 output:
//   [0, 3, 2]

const input1 = builder.constant(
  {dataType: 'float32', shape: [2, 2]}, new Float32Array([0, 1, 2, 3]));

const indices1 = builder.constant(
  {dataType: 'uint32', shape: [3, 2]}, new Uint32Array([0, 0, 1, 1, 1, 0]));

const output1 = builder.gatherND(input1, indices1);

// shape [2,2]인 input:
//   [[0, 1],
//    [2, 3]]
// shape [2,1]인 indices:
//   [[1],
//    [0]]
// shape [2,2]인 output:
//   [[2, 3]    <= input coordinate [1, *]의 row [2, 3]
//    [0, 1]]   <= input coordinate [0, *]의 row [0, 1]

const indices2 = builder.constant(
  {dataType: 'uint32', shape: [2, 1]}, new Uint32Array([1, 0]));

const output2 = builder.gatherND(input1, indices2);

// shape [2,2,2]인 input:
//   [[[0, 1],
//     [2, 3]],
//    [[4, 5],
//     [6, 7]]]
// shape [2,2]인 indices:
//   [[0, 1],
//    [1, 0]]
// shape [2,2]인 output:
//   [[2, 3],   <= input coordinate [0, 1, *]의 row [2, 3]
//    [4, 5]]   <= input coordinate [1, 0, *]의 row [4, 5]

const input2 = builder.constant(
  {dataType: 'float32', shape: [2, 2, 2]},
  new Float32Array([0, 1, 2, 3, 4, 5, 6, 7]));

const indices3 = builder.constant(
  {dataType: 'uint32', shape: [2, 2]}, new Uint32Array([0, 1, 1, 0]));

const output3 = builder.gatherND(input2, indices3);

// shape [2,2,2]인 input:
//   [[[0, 1],
//     [2, 3]],
//    [[4, 5],
//     [6, 7]]]
// shape [3,1]인 indices:
//   [[1],
//    [0],
//    [1]]
// shape [3,2,2]인 output:
//   [[[4, 5],   <= input coordinate [1, *, *]의 block [[4, 5], [6, 7]]
//     [6, 7]],
//    [[0, 1],   <= input coordinate [0, *, *]의 block [[0, 1], [2, 3]]
//     [2, 3]],
//    [[4, 5],   <= input coordinate [1, *, *]의 block [[4, 5], [6, 7]]
//     [6, 7]]]

const indices4 = builder.constant(
  {dataType: 'uint32', shape: [3, 1]}, new Uint32Array([1, 0, 1]));

const output4 = builder.gatherND(input2, indices4);

// shape [2,2,2]인 input:
//   [[[0, 1],
//     [2, 3]],
//    [[4, 5],
//     [6, 7]]]
// shape [5,3]인 indices:
//   [[0,0,1],
//    [0,1,0],
//    [1,0,0],
//    [1,1,0],
//    [1,1,1]]
// shape [5]인 output:
//   [1,2,4,6,7]

const indices5 = builder.constant(
  {dataType: 'uint32', shape: [5, 3]},
  new Uint32Array([0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1]));

const output5 = builder.gatherND(input2, indices5);

8.9.23. gelu

input tensor의 gaussian error linear unit function(GELU)을 계산한다. 계산은 다음 표현식을 따른다. 0.5 * x * (1 + erf(x / sqrt(2))).
partial interface MLGraphBuilder {
  MLOperand gelu(MLOperand input, optional MLOperatorOptions options = {});
};

partial dictionary MLOpSupportLimits {
  MLSingleInputSupportLimits gelu;
};
인수:

반환:

gelu()에 대한 tensor 제한
피연산자 허용되는 데이터 타입 허용되는 rank
input "float32", "float16" N
output 같음 input 같음 input

MLOpSupportLimitsgelu()에 대해 다음 멤버를 가진다.

gelu, 타입은 MLSingleInputSupportLimits

gelu() 오퍼레이터에 대한 지원 제한.

gelu(input, options) 메서드 단계는 다음과 같다.
  1. this빌드할 수 없으면, "InvalidStateError" DOMExceptionthrow한다.

  2. 피연산자를 검증한 결과가 thisinput이 주어졌을 때 false를 반환하면, TypeErrorthrow한다.

  3. inputdataType이 (이 표에 따른) 그 허용되는 데이터 타입 중 하나가 아니면, TypeErrorthrow한다.

  4. 그래프 연결 만들기:

    1. outputinput이 주어졌을 때 MLOperand를 복사한 결과로 둔다.

    2. operatoroptions가 주어진 "gelu" 연산에 대한 오퍼레이터로 둔다.

    3. output.[[operator]]operator로 설정한다.

    4. operatorinputinput으로 설정한다.

    5. operatoroutputoutput으로 설정한다.

  5. output을 반환한다.

이 연산의 동작은 다음과 같이 다른 연산을 사용하는 방식으로 일반적으로 에뮬레이션할 수 있지만, user agent는 보통 더 효율적인 구현을 가진다. 기반 플랫폼이 어떤 연산을 직접 지원하지 않는 경우, 이 분해는 구현을 안내하는 템플릿으로 사용될 수 있다.
function gelu(builder, input) {
  return builder.mul(
    builder.mul(input, builder.constant(input.dataType, 0.5)),
    builder.add(
      builder.constant(input.dataType, 1),
      builder.erf(builder.div(
        input, builder.sqrt(builder.constant(input.dataType, 2))))));
}

8.9.24. gemm

Basic Linear Algebra Subprograms의 general matrix multiplication을 계산한다. 계산은 alpha * A * B + beta * C 표현식을 따른다. 여기서 A는 shape가 [M, K] 또는 [K, M]인 2-D tensor이고, B는 shape가 [K, N] 또는 [N, K]인 2-D tensor이며, C는 shape [M, N]unidirectionally broadcastable이다. AB는 계산 전에 선택적으로 transpose될 수 있다.
dictionary MLGemmOptions : MLOperatorOptions {
  MLOperand c;
  double alpha = 1.0;
  double beta = 1.0;
  boolean aTranspose = false;
  boolean bTranspose = false;
};

partial interface MLGraphBuilder {
  MLOperand gemm(MLOperand a, MLOperand b, optional MLGemmOptions options = {});
};

dictionary MLGemmSupportLimits {
  MLTensorLimits a;
  MLTensorLimits b;
  MLTensorLimits c;
  MLTensorLimits output;
};

partial dictionary MLOpSupportLimits {
  MLGemmSupportLimits gemm;
};

MLGemmOptions는 다음 멤버를 가진다.

c, 타입은 MLOperand

세 번째 입력 tensor. 이것은 scalar이거나 shape [M, N]unidirectionally broadcastable인 shape이다. 지정되지 않으면, 계산은 c가 scalar 0.0인 것처럼 수행된다.

alpha, 타입은 double, 기본값은 1.0

첫 번째 입력에 대한 multiplier.

beta, 타입은 double, 기본값은 1.0

세 번째 입력 c에 대한 multiplier.

aTranspose, 타입은 boolean, 기본값은 false

output을 계산하기 전에 첫 번째 입력이 transpose되는지를 나타낸다.

bTranspose, 타입은 boolean, 기본값은 false

output을 계산하기 전에 두 번째 입력이 transpose되는지를 나타낸다.

인수:

반환: MLOperand. 모든 입력의 계산된 product를 포함하는 shape [M, N]의 출력 2-D tensor.

gemm()에 대한 tensor 제한
피연산자 허용되는 데이터 타입 허용되는 rank
a "float32", "float16" 2
b 같음 a 2
c 같음 a 0에서 2까지
output 같음 a 2

MLGemmSupportLimits는 다음 멤버를 가진다.

a, 타입은 MLTensorLimits

a 피연산자에 대한 MLTensorLimits.

b, 타입은 MLTensorLimits

b 피연산자에 대한 MLTensorLimits.

c, 타입은 MLTensorLimits

c 피연산자에 대한 MLTensorLimits.

output, 타입은 MLTensorLimits

output 피연산자에 대한 MLTensorLimits.

MLOpSupportLimitsgemm()에 대해 다음 멤버를 가진다.

gemm, 타입은 MLGemmSupportLimits

gemm() 오퍼레이터에 대한 지원 제한.

gemm(a, b, options) 메서드 단계는 다음과 같다.
  1. this빌드할 수 없으면, "InvalidStateError" DOMExceptionthrow한다.

  2. 피연산자를 검증한 결과가 thisab 중 어느 하나가 주어졌을 때 false를 반환하면, TypeErrorthrow한다.

  3. a 또는 b 중 어느 하나의 dataType이 (이 표에 따른) 그 허용되는 데이터 타입 중 하나가 아니면, TypeErrorthrow한다.

  4. a 또는 b 중 어느 하나의 rank가 그 허용되는 rank가 아니면, TypeErrorthrow한다.

  5. options.alphaoptions.alphaadataType으로 casting한 결과로 설정한다.

  6. options.betaoptions.betaadataType으로 casting한 결과로 설정한다.

  7. shapeAashapeclone으로 둔다.

  8. shapeBbshapeclone으로 둔다.

  9. options.aTranspose가 true이면, shapeA의 item 순서를 reverse한다.

  10. options.bTranspose가 true이면, shapeB의 item 순서를 reverse한다.

  11. shapeA[1]이 shapeB[0]과 같지 않으면, TypeErrorthrow한다.

  12. options.c존재하면:

    1. 그것이 shape « shapeA[0], shapeB[1] »로 unidirectionally broadcastable이 아니면, TypeErrorthrow한다.

    2. 그것의 dataType이 (이 표에 따른) 그 허용되는 데이터 타입 중 하나가 아니면, TypeErrorthrow한다.

  13. descadataType 및 « shapeA[0], shapeB[1] »이 주어졌을 때 MLOperandDescriptor를 생성한 결과로 둔다.

  14. 그래프 연결 만들기:

    1. outputthisdesc가 주어졌을 때 MLOperand를 생성한 결과로 둔다.

    2. operatoroptions가 주어진 "gemm" 연산에 대한 오퍼레이터로 둔다.

    3. output.[[operator]]operator로 설정한다.

    4. operatorinputsab로 설정한다.

    5. options.c존재하면, 그것을 operatorinputs에 추가한다.

    6. operatoroutputoutput으로 설정한다.

  15. output을 반환한다.

이 연산의 동작은 다음과 같이 다른 연산을 사용하는 방식으로 일반적으로 에뮬레이션할 수 있지만, user agent는 보통 더 효율적인 구현을 가진다. 기반 플랫폼이 어떤 연산을 직접 지원하지 않는 경우, 이 분해는 구현을 안내하는 템플릿으로 사용될 수 있다.
function gemm(builder, a, b, options) {
  if (options.aTranspose)
    a = builder.transpose(a);

  if (options.bTranspose)
    b = builder.transpose(b);

  let ab = builder.matmul(
    builder.mul(builder.constant(a.dataType, options.alpha), a), b);
  return (
    options.c ?
      builder.add(
        ab,
        builder.mul(builder.constant(a.dataType, options.beta), options.c)) :
      ab);
}

8.9.25. gru

Gated Recurrent Unit [GRU] recurrent network는 update, reset, new gate를 사용하여 network의 temporal sequence 전체에서 output으로 전달되는 output state를 계산한다.
enum MLGruWeightLayout {
  "zrn",  // update-reset-new gate ordering
  "rzn"   // reset-update-new gate ordering
};

enum MLRecurrentNetworkActivation {
  "relu",
  "sigmoid",
  "tanh"
};

enum MLRecurrentNetworkDirection {
  "forward",
  "backward",
  "both"
};

dictionary MLGruOptions : MLOperatorOptions {
  MLOperand bias;
  MLOperand recurrentBias;
  MLOperand initialHiddenState;
  boolean resetAfter = true;
  boolean returnSequence = false;
  MLRecurrentNetworkDirection direction = "forward";
  MLGruWeightLayout layout = "zrn";
  sequence<MLRecurrentNetworkActivation> activations;
};

partial interface MLGraphBuilder {
  sequence<MLOperand> gru(MLOperand input,
                          MLOperand weight,
                          MLOperand recurrentWeight,
                          [EnforceRange] unsigned long steps,
                          [EnforceRange] unsigned long hiddenSize,
                          optional MLGruOptions options = {});
};

dictionary MLGruSupportLimits {
  MLTensorLimits input;
  MLTensorLimits weight;
  MLTensorLimits recurrentWeight;
  MLTensorLimits bias;
  MLTensorLimits recurrentBias;
  MLTensorLimits initialHiddenState;
  MLTensorLimits output0;
  MLTensorLimits output1;
};

partial dictionary MLOpSupportLimits {
  MLGruSupportLimits gru;
};

MLGruOptions는 다음 멤버를 가진다.

bias, 타입은 MLOperand

shape [numDirections, 3 * hiddenSize]의 2-D 입력 bias tensor. tensor shape의 두 번째 dimension에서 bias vector들의 ordering은 layout에 따라 지정된다.

recurrentBias, 타입은 MLOperand

shape [numDirections, 3 * hiddenSize]의 2-D recurrent bias tensor. tensor shape의 두 번째 dimension에서 bias vector들의 ordering은 layout에 따라 지정된다.

initialHiddenState, 타입은 MLOperand

shape [numDirections, batchSize, hiddenSize]의 3-D 초기 hidden state tensor. 지정되지 않으면, 구현은 0으로 채워진 tensor를 사용해야 한다.

resetAfter, 타입은 boolean, 기본값은 true

reset gate를 matrix multiplication 뒤에 적용할지 또는 전에 적용할지를 나타낸다.

returnSequence, 타입은 boolean, 기본값은 false

마지막 time step의 output에 더해 각 time step의 모든 output을 담은 전체 sequence도 반환할지 여부를 나타낸다.

direction, 타입은 MLRecurrentNetworkDirection, 기본값은 "forward"

input sequence의 처리 방향. "both"로 설정되면, weight 및 bias tensor shape의 첫 번째 dimension size는 2여야 하며, input은 양방향으로 처리된다.

layout, 타입은 MLGruWeightLayout, 기본값은 "zrn"

GRU의 internal gate, 구체적으로 weight 및 bias tensor shape의 두 번째 dimension에 표시되는 update (z), reset (r), new (n) gate에 대한 weight 및 bias vector의 ordering.

activations, 타입은 sequence<MLRecurrentNetworkActivation>

첫 번째 함수가 update 및 reset gate에 사용되고 두 번째 함수가 new gate에 사용되는 한 쌍의 activation functions를 지정한다. 지정되지 않으면, 각각 "sigmoid""tanh" 함수가 기본값이다.

인수:

반환: sequence<MLOperand>. 첫 번째 요소는 network의 마지막 time step의 cell output인 shape [numDirections, batchSize, hiddenSize]의 3-D tensor이다. 또한 returnSequence가 true로 설정되면, 두 번째 요소는 temporal sequence의 각 time step에서 나온 모든 cell output을 포함하는 shape [steps, numDirections, batchSize, hiddenSize]의 4-D output tensor이다.

gru()에 대한 tensor 제한
피연산자 허용되는 데이터 타입 허용되는 rank
input "float32", "float16" 3
weight 같음 input 3
recurrentWeight 같음 input 3
bias 같음 input 2
recurrentBias 같음 input 2
initialHiddenState 같음 input 3
outputs[0] 같음 input 3
outputs[1] if returnSequence is true 같음 input 4

MLGruSupportLimits는 다음 멤버를 가진다.

input, 타입은 MLTensorLimits

input 피연산자에 대한 MLTensorLimits.

weight, 타입은 MLTensorLimits

weight 피연산자에 대한 MLTensorLimits.

recurrentWeight, 타입은 MLTensorLimits

recurrentWeight 피연산자에 대한 MLTensorLimits.

bias, 타입은 MLTensorLimits

bias 피연산자에 대한 MLTensorLimits.

recurrentBias, 타입은 MLTensorLimits

recurrentBias 피연산자에 대한 MLTensorLimits.

initialHiddenState, 타입은 MLTensorLimits

initialHiddenState 피연산자에 대한 MLTensorLimits.

output0, 타입은 MLTensorLimits

모든 output operands[0]에 대한 MLTensorLimits.

output1, 타입은 MLTensorLimits

모든 output operands[1]에 대한 MLTensorLimits.

MLOpSupportLimitsgru()에 대해 다음 멤버를 가진다.

gru, 타입은 MLGruSupportLimits

gru() 오퍼레이터에 대한 지원 제한.

gru(input, weight, recurrentWeight, steps, hiddenSize, options) 메서드 단계는 다음과 같다.
  1. this빌드할 수 없으면, "InvalidStateError" DOMExceptionthrow한다.

  2. 피연산자를 검증한 결과가 thisinput, weight, recurrentWeight, options.bias (그것이 존재하면), options.recurrentBias (그것이 존재하면), 및 options.initialHiddenState (그것이 존재하면) 중 어느 하나가 주어졌을 때 false를 반환하면, TypeErrorthrow한다.

  3. input, weight 또는 recurrentWeight 중 어느 하나의 dataType이 (이 표에 따른) 그 허용되는 데이터 타입 중 하나가 아니면, TypeErrorthrow한다.

  4. input, weight 또는 recurrentWeight 중 어느 하나의 rank가 그 허용되는 rank가 아니면, TypeErrorthrow한다.

  5. inputshape[0]이 steps와 같지 않으면, TypeErrorthrow한다.

  6. batchSizeinputshape[1]로 둔다.

  7. inputSizeinputshape[2]로 둔다.

  8. numDirectionsoptions.direction"both"이면 2로, 그렇지 않으면 1로 둔다.

  9. weightshape가 « numDirections, 3 * hiddenSize, inputSize »와 같지 않으면, TypeErrorthrow한다.

  10. recurrentWeightshape가 « numDirections, 3 * hiddenSize, hiddenSize »와 같지 않으면, TypeErrorthrow한다.

  11. hiddenSize * 6이 유효한 dimension이 아니면, TypeErrorthrow한다.

    hiddenSize * 6인가? 일부 기반 플랫폼은 biasrecurrentBias를 concat한 단일 bias tensor에서 동작한다. 따라서 3 * hiddenSize + 3 * hiddenSize유효한 dimension이어야 한다.
  12. options.bias존재하면:

    1. 그것의 dataType이 (이 표에 따른) 그 허용되는 데이터 타입 중 하나가 아니면, TypeErrorthrow한다.

    2. 그것의 shape가 « numDirections, 3 * hiddenSize »와 같지 않으면, TypeErrorthrow한다.

  13. options.recurrentBias존재하면:

    1. 그것의 dataType이 (이 표에 따른) 그 허용되는 데이터 타입 중 하나가 아니면, TypeErrorthrow한다.

    2. 그것의 shape가 « numDirections, 3 * hiddenSize »와 같지 않으면, TypeErrorthrow한다.

  14. options.initialHiddenState존재하면:

    1. 그것의 dataType이 (이 표에 따른) 그 허용되는 데이터 타입 중 하나가 아니면, TypeErrorthrow한다.

    2. 그것의 shape가 « numDirections, batchSize, hiddenSize »와 같지 않으면, TypeErrorthrow한다.

  15. options.activations존재하면:

    1. 그것의 size가 2가 아니면, TypeErrorthrow한다.

    2. activationsoptions.activationsclone으로 둔다.

  16. 그렇지 않으면:

    1. activations를 « "sigmoid", "tanh" »로 둔다.

  17. output shape 계산하기:

    1. desc0inputdataType 및 « numDirections, batchSize, hiddenSize »가 주어졌을 때 MLOperandDescriptor를 생성한 결과로 둔다.

    2. options.returnSequence가 true이면:

      1. desc1inputdataType 및 « steps, numDirections, batchSize, hiddenSize »가 주어졌을 때 MLOperandDescriptor를 생성한 결과로 둔다.

  18. 그래프 연결 만들기:

    1. operatorweight, recurrentWeight, steps, hiddenSizeoptions가 주어진 "gru" 연산에 대한 오퍼레이터로 둔다.

    2. output0thisdesc0가 주어졌을 때 MLOperand를 생성한 결과로 둔다.

    3. options.returnSequence가 true이면:

      1. output1thisdesc1이 주어졌을 때 MLOperand를 생성한 결과로 둔다.

      2. outputlist « output0, output1 »로 둔다.

      3. output0.[[operator]]output1.[[operator]]operator로 설정한다.

    4. 그렇지 않으면:

      1. outputlist « output0 »로 둔다.

      2. output0.[[operator]]operator로 설정한다.

    5. operatorinputsinput, weightrecurrentWeight로 설정한다.

    6. options.bias존재하면, 그것을 operatorinputs에 추가한다.

    7. options.recurrentBias존재하면, 그것을 operatorinputs에 추가한다.

    8. options.initialHiddenState존재하면, 그것을 operatorinputs에 추가한다.

    9. operatoractivation functionsactivationsclone으로 설정한다.

    10. operatoroutputoutput으로 설정한다.

  19. output을 반환한다.

squeeze() helper를 사용하면, 이 연산의 동작은 다음과 같이 다른 연산을 사용하는 방식으로 일반적으로 에뮬레이션할 수 있지만, user agent는 보통 더 효율적인 구현을 가진다. 기반 플랫폼이 어떤 연산을 직접 지원하지 않는 경우, 이 분해는 구현을 안내하는 템플릿으로 사용될 수 있다.
function gru(
  builder, input, weight, recurrentWeight, steps, hiddenSize, options) {
  const batchSize = input.shape[1];
  const inputSize = input.shape[2];
  const direction = options.direction || 'forward';
  const numDirections = (direction == 'both' ? 2 : 1);
  let hiddenState = options.initialHiddenState;

  if (!hiddenState) {
    const desc = {
      dataType: 'float32',
      shape: [numDirections, batchSize, hiddenSize]
    };
    const totalSize = numDirections * batchSize * hiddenSize;
    hiddenState = builder.constant(desc, new Float32Array(totalSize).fill(0));
  }

  let currentWeight = [];
  let currentRecurrentWeight = [];
  let currentBias = [];
  let currentRecurrentBias = [];
  let forwardSequence = null;
  let backwardSequence = null;
  let outputHidden = null;

  for (let dir = 0; dir < numDirections; ++dir) {
    currentWeight.push(squeeze(
      builder,
      builder.slice(weight, [dir, 0, 0], [1, 3 * hiddenSize, inputSize])));
    currentRecurrentWeight.push(squeeze(
      builder,
      builder.slice(
        recurrentWeight, [dir, 0, 0], [1, 3 * hiddenSize, hiddenSize])));
    currentBias.push(
      options.bias ?
        (squeeze(
          builder,
          builder.slice(options.bias, [dir, 0], [1, 3 * hiddenSize]))) :
        null);
    currentRecurrentBias.push(
      options.recurrentBias ?
        (squeeze(
          builder,
          builder.slice(
            options.recurrentBias, [dir, 0], [1, 3 * hiddenSize]))) :
        null);
    let currentHidden = squeeze(
      builder,
      builder.slice(hiddenState, [dir, 0, 0], [1, batchSize, hiddenSize]), [0]);

    for (let step = 0; step < steps; ++step) {
      const slice =
        (dir == 1 || direction == 'backward' ? steps - step - 1 : step);
      const currentInput = squeeze(
        builder,
        builder.slice(input, [slice, 0, 0], [1, batchSize, inputSize]), [0]);

      currentHidden = builder.gruCell(
        currentInput,
        currentWeight[dir],
        currentRecurrentWeight[dir],
        currentHidden,
        hiddenSize,
        {
          bias: currentBias[dir],
          recurrentBias: currentRecurrentBias[dir],
          resetAfter: options.resetAfter,
          layout: options.layout,
          activations: options.activations
        });

      if (options.returnSequence) {
        // Expand currentHidden of 2D([batchSize, hiddenSize])
        // to 4D([steps, numDirections, batchSize, hiddenSize])
        const expandedHiddenAs4D =
          builder.reshape(currentHidden, [1, 1, batchSize, hiddenSize]);

        if (direction == 'forward' || (dir == 0 && direction == 'both')) {
          forwardSequence = forwardSequence ?
            builder.concat([forwardSequence, expandedHiddenAs4D], 0) :
            expandedHiddenAs4D;
        } else if (
          direction == 'backward' || (dir == 1 && direction == 'both')) {
          backwardSequence = backwardSequence ?
            builder.concat([expandedHiddenAs4D, backwardSequence], 0) :
            expandedHiddenAs4D;
        }
      }
    }

    // Expand currentHidden of 2D([batchSize, hiddenSize])
    // to 3D([numDirections, batchSize, hiddenSize])
    const expandedHiddenAs3D =
      builder.reshape(currentHidden, [1, batchSize, hiddenSize]);
    outputHidden = outputHidden ?
      builder.concat([outputHidden, expandedHiddenAs3D], 0) :
      expandedHiddenAs3D;
  }

  if (options.returnSequence) {
    let outputSequence = null;

    if (direction == 'forward') {
      outputSequence = forwardSequence;
    } else if (direction == 'backward') {
      outputSequence = backwardSequence;
    } else if (direction == 'both') {
      // Concat along axis 1 (numDirections dimension)
      outputSequence = builder.concat([forwardSequence, backwardSequence], 1);
    }

    return [outputHidden, outputSequence];
  } else {
    return [outputHidden];
  }
}

8.9.26. gruCell

Gated Recurrent Unit [GRU] recurrent network의 단일 time step으로, update gate와 reset gate를 사용하여 recurrent network의 temporal sequence 전체에서 output으로 전달되는 hidden state를 계산한다.
dictionary MLGruCellOptions : MLOperatorOptions {
  MLOperand bias;
  MLOperand recurrentBias;
  boolean resetAfter = true;
  MLGruWeightLayout layout = "zrn";
  sequence<MLRecurrentNetworkActivation> activations;
};

partial interface MLGraphBuilder {
  MLOperand gruCell(MLOperand input,
                    MLOperand weight,
                    MLOperand recurrentWeight,
                    MLOperand hiddenState,
                    [EnforceRange] unsigned long hiddenSize,
                    optional MLGruCellOptions options = {});
};

dictionary MLGruCellSupportLimits {
  MLTensorLimits input;
  MLTensorLimits weight;
  MLTensorLimits recurrentWeight;
  MLTensorLimits hiddenState;
  MLTensorLimits bias;
  MLTensorLimits recurrentBias;
  MLTensorLimits output;
};

partial dictionary MLOpSupportLimits {
  MLGruCellSupportLimits gruCell;
};

MLGruCellOptions는 다음 멤버를 가진다.

bias, 타입은 MLOperand

shape [3 * hiddenSize]의 1-D 입력 bias tensor. tensor shape의 두 번째 dimension에서 bias vector들의 ordering은 layout에 따라 지정된다.

recurrentBias, 타입은 MLOperand

shape [3 * hiddenSize]의 1-D recurrent bias tensor. tensor shape의 두 번째 dimension에서 bias vector들의 ordering은 layout에 따라 지정된다.

resetAfter, 타입은 boolean, 기본값은 true

reset gate를 matrix multiplication 뒤에 적용할지 또는 전에 적용할지를 나타낸다.

layout, 타입은 MLGruWeightLayout, 기본값은 "zrn"

GRU의 internal gate, 구체적으로 weight 및 bias tensor shape의 두 번째 dimension에 표시되는 update (z), reset (r), new (n) gate에 대한 weight 및 bias vector의 ordering.

activations, 타입은 sequence<MLRecurrentNetworkActivation>

첫 번째 함수가 update 및 reset gate에 사용되고 두 번째 함수가 new gate에 사용되는 한 쌍의 activation functions를 지정한다. 지정되지 않으면, 각각 "sigmoid""tanh" 함수가 기본값이다.

인수:

반환: MLOperand. recurrent network의 단일 time step의 cell output hidden state인 shape [batchSize, hiddenSize]의 2-D tensor.

gruCell()에 대한 tensor 제한
피연산자 허용되는 데이터 타입 허용되는 rank
input "float32", "float16" 2
weight 같음 input 2
recurrentWeight 같음 input 2
bias 같음 input 1
recurrentBias 같음 input 1
output 같음 input 2

MLGruCellSupportLimits는 다음 멤버를 가진다;

input, 타입은 MLTensorLimits

input 피연산자에 대한 MLTensorLimits.

weight, 타입은 MLTensorLimits

weight 피연산자에 대한 MLTensorLimits.

recurrentWeight, 타입은 MLTensorLimits

recurrentWeight 피연산자에 대한 MLTensorLimits.

hiddenState, 타입은 MLTensorLimits

hiddenState 피연산자에 대한 MLTensorLimits.

bias, 타입은 MLTensorLimits

bias 피연산자에 대한 MLTensorLimits.

recurrentBias, 타입은 MLTensorLimits

recurrentBias 피연산자에 대한 MLTensorLimits.

output, 타입은 MLTensorLimits

output 피연산자에 대한 MLTensorLimits.

MLOpSupportLimitsgruCell()에 대해 다음 멤버를 가진다.

gruCell, 타입은 MLGruCellSupportLimits

gruCell() 오퍼레이터에 대한 지원 제한.

gruCell(input, weight, recurrentWeight, hiddenState, hiddenSize, options) 메서드 단계는 다음과 같다.
  1. this빌드할 수 없으면, "InvalidStateError" DOMExceptionthrow한다.

  2. 피연산자를 검증한 결과가 thisinput, weight, recurrentWeight, hiddenState, options.bias (그것이 존재하면), 및 options.recurrentBias (그것이 존재하면) 중 어느 하나가 주어졌을 때 false를 반환하면, TypeErrorthrow한다.

  3. input, weight, recurrentWeight, 또는 hiddenState 중 어느 하나의 dataType이 (이 표에 따른) 그 허용되는 데이터 타입 중 하나가 아니면, TypeErrorthrow한다.

  4. input, weight, recurrentWeight 또는 hiddenState 중 어느 하나의 rank가 (이 표에 따른) 그 허용되는 rank가 아니면, TypeErrorthrow한다.

  5. batchSizeinputshape[0]으로 둔다.

  6. inputSizeinputshape[1]로 둔다.

  7. weightshape가 « 3 * hiddenSize, inputSize »와 같지 않으면, TypeErrorthrow한다.

  8. recurrentWeightshape가 « 3 * hiddenSize, hiddenSize »와 같지 않으면, TypeErrorthrow한다.

  9. hiddenStateshape가 « batchSize, hiddenSize »와 같지 않으면, TypeErrorthrow한다.

  10. hiddenSize * 6이 유효한 dimension이 아니면, TypeErrorthrow한다.

    hiddenSize * 6인가? 일부 기반 플랫폼은 biasrecurrentBias를 concat한 단일 bias tensor에서 동작한다. 따라서 3 * hiddenSize + 3 * hiddenSize유효한 dimension이어야 한다.
  11. options.bias존재하면:

    1. 그것의 dataType이 (이 표에 따른) 그 허용되는 데이터 타입 중 하나가 아니면, TypeErrorthrow한다.

    2. 그것의 shape가 « 3 * hiddenSize »와 같지 않으면, TypeErrorthrow한다.

  12. options.recurrentBias존재하면:

    1. 그것의 dataType이 (이 표에 따른) 그 허용되는 데이터 타입 중 하나가 아니면, TypeErrorthrow한다.

    2. 그것의 shape가 « 3 * hiddenSize »와 같지 않으면, TypeErrorthrow한다.

  13. options.activations존재하면:

    1. 그것의 size가 2가 아니면, TypeErrorthrow한다.

    2. activationsoptions.activationsclone으로 둔다.

  14. 그렇지 않으면:

    1. activations를 « "sigmoid", "tanh" »로 둔다.

  15. descinputdataType 및 « batchSize, hiddenSize »가 주어졌을 때 MLOperandDescriptor를 생성한 결과로 둔다.

  16. 그래프 연결 만들기:

    1. outputthisdesc가 주어졌을 때 MLOperand를 생성한 결과로 둔다.

    2. operatorweight, recurrentWeight, hiddenState, hiddenSizeoptions가 주어진 "gruCell" 연산에 대한 오퍼레이터로 둔다.

    3. output.[[operator]]operator로 설정한다.

    4. operatorinputsinput, weight, recurrentWeighthiddenState로 설정한다.

    5. options.bias존재하면, 그것을 operatorinputs에 추가한다.

    6. options.recurrentBias존재하면, 그것을 operatorinputs에 추가한다.

    7. operatoractivation functionsactivationsclone으로 설정한다.

    8. operatoroutputoutput으로 설정한다.

  17. output을 반환한다.

weight layout이 기본 "zrn" layout이고, update/reset gate와 new gate의 activation functions가 각각 sigmoid()tanh()일 때 이 연산의 동작은 다음과 같이 다른 연산을 사용하는 방식으로 일반적으로 에뮬레이션할 수 있지만, user agent는 보통 더 효율적인 구현을 가진다. 기반 플랫폼이 어떤 연산을 직접 지원하지 않는 경우, 이 분해는 구현을 안내하는 템플릿으로 사용될 수 있다.
function gruCell(
  builder, input, weight, recurrentWeight, hiddenState, hiddenSize, options) {
  const one = builder.constant(input.dataType, 1);
  const zero = builder.constant(input.dataType, 0);

  const inputSize = input.shape[1];

  // update gate (z)
  let z = builder.sigmoid(builder.add(
    builder.add(
      (options.bias ? builder.slice(options.bias, [0], [hiddenSize]) : zero),
      (options.recurrentBias ?
         builder.slice(options.recurrentBias, [0], [hiddenSize]) :
         zero)),
    builder.add(
      builder.matmul(
        input,
        builder.transpose(
          builder.slice(weight, [0, 0], [hiddenSize, inputSize]))),
      builder.matmul(
        hiddenState,
        builder.transpose(
          builder.slice(recurrentWeight, [0, 0], [hiddenSize, hiddenSize]))))));

  // reset gate (r)
  let r = builder.sigmoid(builder.add(
    builder.add(
      (options.bias ? builder.slice(options.bias, [hiddenSize], [hiddenSize]) :
                      zero),
      (options.recurrentBias ?
         builder.slice(options.recurrentBias, [hiddenSize], [hiddenSize]) :
         zero)),
    builder.add(
      builder.matmul(
        input,
        builder.transpose(
          builder.slice(weight, [hiddenSize, 0], [hiddenSize, inputSize]))),
      builder.matmul(
        hiddenState,
        builder.transpose(builder.slice(
          recurrentWeight, [hiddenSize, 0], [hiddenSize, hiddenSize]))))));

  // new gate (n)
  let n;
  if (options.resetAfter) {
    n = builder.tanh(builder.add(
      (options.bias ?
         builder.slice(options.bias, [2 * hiddenSize], [hiddenSize]) :
         zero),
      builder.add(
        builder.matmul(
          input,
          builder.transpose(builder.slice(
            weight, [2 * hiddenSize, 0], [hiddenSize, inputSize]))),
        builder.mul(
          r,
          builder.add(
            (options.recurrentBias ?
               builder.slice(
                 options.recurrentBias, [2 * hiddenSize], [hiddenSize]) :
               zero),
            builder.matmul(
              hiddenState,
              builder.transpose(builder.slice(
                recurrentWeight,
                [2 * hiddenSize, 0],
                [hiddenSize, hiddenSize]))))))));
  } else {
    n = builder.tanh(builder.add(
      builder.add(
        (options.bias ?
           builder.slice(options.bias, [2 * hiddenSize], [hiddenSize]) :
           zero),
        (options.recurrentBias ?
           builder.slice(
             options.recurrentBias, [2 * hiddenSize], [hiddenSize]) :
           zero)),
      builder.add(
        builder.matmul(
          input,
          builder.transpose(builder.slice(
            weight, [2 * hiddenSize, 0], [hiddenSize, inputSize]))),
        builder.matmul(
          builder.mul(r, hiddenState),
          builder.transpose(builder.slice(
            recurrentWeight,
            [2 * hiddenSize, 0],
            [hiddenSize, hiddenSize]))))));
  }

  // compute the new hidden state
  return builder.add(
    builder.mul(z, hiddenState), builder.mul(n, builder.sub(one, z)));
}

8.9.27. hardSigmoid

더 빠른 계산을 위해 sigmoid function 대신 사용되는 비평활 hard sigmoid function을 input tensor에 대해 계산한다.
dictionary MLHardSigmoidOptions : MLOperatorOptions {
  double alpha = 0.2;
  double beta = 0.5;
};

partial interface MLGraphBuilder {
  MLOperand hardSigmoid(MLOperand input, optional MLHardSigmoidOptions options = {});
};

partial dictionary MLOpSupportLimits {
  MLSingleInputSupportLimits hardSigmoid;
};

MLHardSigmoidOptions는 다음 멤버를 가진다.

alpha, 타입은 double, 기본값은 0.2

scalar multiplier.

beta, 타입은 double, 기본값은 0.5

scalar addition.

인수:

반환:

hardSigmoid()에 대한 tensor 제한
피연산자 허용되는 데이터 타입 허용되는 rank
input "float32", "float16" N
output 같음 input 같음 input

MLOpSupportLimitshardSigmoid()에 대해 다음 멤버를 가진다.

hardSigmoid, 타입은 MLSingleInputSupportLimits

hardSigmoid() 오퍼레이터에 대한 지원 제한.

hardSigmoid(input, options) 메서드 단계는 다음과 같다.
  1. this빌드할 수 없으면, "InvalidStateError" DOMExceptionthrow한다.

  2. 피연산자를 검증한 결과가 thisinput이 주어졌을 때 false를 반환하면, TypeErrorthrow한다.

  3. inputdataType이 (이 표에 따른) 그 허용되는 데이터 타입 중 하나가 아니면, TypeErrorthrow한다.

  4. options.alphaoptions.alphainputdataType으로 casting한 결과로 설정한다.

  5. options.betaoptions.betainputdataType으로 casting한 결과로 설정한다.

  6. 그래프 연결 만들기:

    1. outputinput이 주어졌을 때 MLOperand를 복사한 결과로 둔다.

    2. operatoroptions가 주어진 "hardSigmoid" 연산에 대한 오퍼레이터로 둔다.

    3. output.[[operator]]operator로 설정한다.

    4. operatorinputinput으로 설정한다.

    5. operatoroutputoutput으로 설정한다.

  7. output을 반환한다.

이 연산의 동작은 다음과 같이 다른 연산을 사용하는 방식으로 일반적으로 에뮬레이션할 수 있지만, user agent는 보통 더 효율적인 구현을 가진다. 기반 플랫폼이 어떤 연산을 직접 지원하지 않는 경우, 이 분해는 구현을 안내하는 템플릿으로 사용될 수 있다.
function hardSigmoid(builder, input, options) {
  return builder.max(
    builder.min(
      builder.add(
        builder.mul(builder.constant(input.dataType, options.alpha), input),
        builder.constant(input.dataType, options.beta)),
      builder.constant(input.dataType, 1)),
    builder.constant(input.dataType, 0));
}

8.9.28. hardSwish

[MobileNetV3]에서 도입된 비선형 함수 y = x * max(0, min(6, (x + 3))) / 6를 input tensor에 대해 element-wise로 계산한다.
partial interface MLGraphBuilder {
  MLOperand hardSwish(MLOperand input, optional MLOperatorOptions options = {});
};

partial dictionary MLOpSupportLimits {
  MLSingleInputSupportLimits hardSwish;
};
인수:

반환:

hardSwish()에 대한 tensor 제한
피연산자 허용되는 데이터 타입 허용되는 rank
input "float32", "float16" N
output 같음 input 같음 input

MLOpSupportLimitshardSwish()에 대해 다음 멤버를 가진다.

hardSwish, 타입은 MLSingleInputSupportLimits

hardSwish() 오퍼레이터에 대한 지원 제한.

hardSwish(input, options) 메서드 단계는 다음과 같다.
  1. this빌드할 수 없으면, "InvalidStateError" DOMExceptionthrow한다.

  2. 피연산자를 검증한 결과가 thisinput이 주어졌을 때 false를 반환하면, TypeErrorthrow한다.

  3. inputdataType이 (이 표에 따른) 그 허용되는 데이터 타입 중 하나가 아니면, TypeErrorthrow한다.

  4. 그래프 연결 만들기:

    1. outputinput이 주어졌을 때 MLOperand를 복사한 결과로 둔다.

    2. operatoroptions가 주어진 "hardSwish" 연산에 대한 오퍼레이터로 둔다.

    3. output.[[operator]]operator로 설정한다.

    4. operatorinputinput으로 설정한다.

    5. operatoroutputoutput으로 설정한다.

  5. output을 반환한다.

이 연산의 동작은 다음과 같이 다른 연산을 사용하는 방식으로 일반적으로 에뮬레이션할 수 있지만, user agent는 보통 더 효율적인 구현을 가진다. 기반 플랫폼이 어떤 연산을 직접 지원하지 않는 경우, 이 분해는 구현을 안내하는 템플릿으로 사용될 수 있다.
function hardSwish(builder, input, options) {
  return builder.div(
    builder.mul(
      input,
      builder.max(
        builder.constant(input.dataType, 0),
        builder.min(
          builder.constant(input.dataType, 6),
          builder.add(input, builder.constant(input.dataType, 3))))),
    builder.constant(input.dataType, 6));
}

8.9.29. instanceNormalization

[Instance-Normalization]을 사용하여 input을 정규화한다. batchNormalization()에서 정규화에 사용되는 mean 및 variance 값이 model을 훈련하는 동안 batch dimension의 모든 sample에 걸쳐 계산되는 것과 달리, instance normalization에서 사용되는 mean 및 variance 값은 batch 안의 각 개별 sample의 각 input feature에 대해 즉시 계산된다.
dictionary MLInstanceNormalizationOptions : MLOperatorOptions {
  MLOperand scale;
  MLOperand bias;
  double epsilon = 1e-5;
  MLInputOperandLayout layout = "nchw";
};

partial interface MLGraphBuilder {
  MLOperand instanceNormalization(
    MLOperand input,
    optional MLInstanceNormalizationOptions options = {});
};

dictionary MLNormalizationSupportLimits {
  MLTensorLimits input;
  MLTensorLimits scale;
  MLTensorLimits bias;
  MLTensorLimits output;
};

partial dictionary MLOpSupportLimits {
  MLNormalizationSupportLimits instanceNormalization;
};

MLInstanceNormalizationOptions는 다음 멤버를 가진다.

scale, 타입은 MLOperand

size가 channel 수, 즉 input의 feature dimension size와 같은 scaling 값들의 1-D tensor. 예를 들어 input tensor가 "nchw" layout을 가지는 경우, sizeinputshape[1]과 같다.

bias, 타입은 MLOperand

size가 input의 feature dimension size와 같은 bias 값들의 1-D tensor. 예를 들어 input tensor가 "nchw" layout을 가지는 경우, sizeinputshape[1]과 같다.

epsilon, 타입은 double, 기본값은 1e-5

0으로 나누기 때문에 발생하는 계산 오류를 방지하기 위한 작은 값.

layout, 타입은 MLInputOperandLayout, 기본값은 "nchw"

input의 layout format.

인수:

반환: MLOperand. input과 같은 shape의 instance-normalized 4-D tensor.

instanceNormalization()에 대한 tensor 제한
피연산자 허용되는 데이터 타입 허용되는 rank
input "float32", "float16" 4
scale 같음 input 1
bias 같음 input 1
output 같음 input 4

MLNormalizationSupportLimits는 다음 멤버를 가진다.

input, 타입은 MLTensorLimits

input 피연산자에 대한 MLTensorLimits.

scale, 타입은 MLTensorLimits

scale 피연산자에 대한 MLTensorLimits.

bias, 타입은 MLTensorLimits

bias 피연산자에 대한 MLTensorLimits.

output, 타입은 MLTensorLimits

output 피연산자에 대한 MLTensorLimits.

MLOpSupportLimitsinstanceNormalization()에 대해 다음 멤버를 가진다.

instanceNormalization, 타입은 MLNormalizationSupportLimits

instanceNormalization() 오퍼레이터에 대한 지원 제한.

instanceNormalization(input, options) 메서드 단계는 다음과 같다.
  1. this빌드할 수 없으면, "InvalidStateError" DOMExceptionthrow한다.

  2. 피연산자를 검증한 결과가 thisinput, options.scale (그것이 존재하면), 및 options.bias (그것이 존재하면) 중 어느 하나가 주어졌을 때 false를 반환하면, TypeErrorthrow한다.

  3. inputdataType이 (이 표에 따른) 그 허용되는 데이터 타입 중 하나가 아니면, TypeErrorthrow한다.

  4. inputrank가 그 허용되는 rank가 아니면, TypeErrorthrow한다.

  5. options.epsilonoptions.epsiloninputdataType으로 casting한 결과로 설정한다.

  6. axisoptions.layout"nchw"이면 1로, 그렇지 않으면 3으로 둔다.

  7. options.scale존재하면:

    1. 그것의 dataType이 (이 표에 따른) 그 허용되는 데이터 타입 중 하나가 아니면, TypeErrorthrow한다.

    2. 그것의 shape가 « inputshape[axis] »와 같지 않으면, TypeErrorthrow한다.

  8. options.bias존재하면:

    1. 그것의 dataType이 (이 표에 따른) 그 허용되는 데이터 타입 중 하나가 아니면, TypeErrorthrow한다.

    2. 그것의 shape가 « inputshape[axis] »와 같지 않으면, TypeErrorthrow한다.

  9. 그래프 연결 만들기:

    1. outputinput이 주어졌을 때 MLOperand를 복사한 결과로 둔다.

    2. operatoroptions가 주어진 "instanceNormalization" 연산에 대한 오퍼레이터로 둔다.

    3. output.[[operator]]operator로 설정한다.

    4. operatorinputinput으로 설정한다.

    5. options.scale존재하면, 그것을 operatorinputs에 추가한다.

    6. options.bias존재하면, 그것을 operatorinputs에 추가한다.

    7. operatoroutputoutput으로 설정한다.

  10. output을 반환한다.

input tensor가 "nchw" layout의 4-D일 때 이 연산의 동작은 다음과 같이 다른 연산을 사용하는 방식으로 일반적으로 에뮬레이션할 수 있지만, user agent는 보통 더 효율적인 구현을 가진다. 기반 플랫폼이 어떤 연산을 직접 지원하지 않는 경우, 이 분해는 구현을 안내하는 템플릿으로 사용될 수 있다.
function instanceNormalization(builder, input, options) {
  // The reduction of the mean and variance values happens over the spatial
  // dimensions of the input e.g. axis 2 and 3 of the input tensor.
  const reduceOptions = {axes: [2, 3], keepDimensions: true};
  const mean = builder.reduceMean(input, reduceOptions);
  const variance = builder.reduceMean(
    builder.pow(builder.sub(input, mean), builder.constant(input.dataType, 2)),
    reduceOptions);

  // The scale and bias values are applied per input feature
  // e.g. axis 1 of the input tensor.
  const shape = [1, input.shape[1], 1, 1];
  return builder.add(
    builder.mul(
      builder.reshape(options.scale, shape),
      builder.div(
        builder.sub(input, mean),
        builder.sqrt(builder.add(variance, options.epsilon)))),
    builder.reshape(options.bias, shape));
}

8.9.30. layerNormalization

[Layer-Normalization]을 사용하여 input을 정규화한다. batchNormalization()에서는 model이 훈련되는 동안 mean 및 variance 값이 batch dimension의 모든 sample에 걸쳐 계산되고, instanceNormalization()에서는 mean 및 variance 값이 batch 안의 각 개별 sample의 각 input feature에 대해 즉시 계산되는 것과 달리, layer normalization의 mean 및 variance 값은 batch 안의 각 개별 sample의 모든 input feature에 걸쳐 즉시 계산된다.
dictionary MLLayerNormalizationOptions : MLOperatorOptions {
  MLOperand scale;
  MLOperand bias;
  sequence<[EnforceRange] unsigned long> axes;
  double epsilon = 1e-5;
};

partial interface MLGraphBuilder {
  MLOperand layerNormalization(MLOperand input,
                               optional MLLayerNormalizationOptions options = {});
};

partial dictionary MLOpSupportLimits {
  MLNormalizationSupportLimits layerNormalization;
};

MLLayerNormalizationOptions는 다음 멤버를 가진다.

scale, 타입은 MLOperand

axes 멤버에 의해 shape가 결정되는 scaling 값들의 N-D tensor. 즉 axes의 각 값은 scaling 값을 가지는 input tensor의 dimension을 나타낸다. 예를 들어 axes 값이 [1,2,3]이면, 이 tensor의 shape는 input dimension 1, 2, 3의 대응하는 size들의 list이다. 이 멤버가 없으면, scaling 값은 1로 간주된다.

bias, 타입은 MLOperand

axes 멤버에 의해 shape가 결정되는 bias 값들의 N-D tensor. 즉 axes의 각 값은 bias 값을 가지는 input tensor의 dimension을 나타낸다. 예를 들어 axes 값이 [1,2,3]이면, 이 tensor의 shape는 input dimension 1, 2, 3의 대응하는 size들의 list이다. 이 멤버가 없으면, bias 값은 0으로 간주된다.

axes, 타입은 sequence<[EnforceRange] unsigned long>

reduce할 input dimension에 대한 index들. 이 멤버가 없으면, 첫 번째 dimension을 제외한 모든 dimension이 주어진 것처럼 처리된다(예: 4-D input tensor의 경우, axes = [1,2,3]). 즉 mean 및 variance 값에 대한 reduction은 각 독립 batch에 대해 모든 input feature에 걸쳐 계산된다. 비어 있으면, 어떤 dimension도 reduce되지 않는다.

epsilon, 타입은 double, 기본값은 1e-5

0으로 나누기 때문에 발생하는 계산 오류를 방지하기 위한 작은 값.

인수:

반환: MLOperand. input과 같은 shape의 layer-normalized N-D tensor.

layerNormalization()에 대한 tensor 제한
피연산자 허용되는 데이터 타입 허용되는 rank
input "float32", "float16" N
scale 같음 input N
bias 같음 input N
output 같음 input 같음 input

MLOpSupportLimitslayerNormalization()에 대해 다음 멤버를 가진다.

layerNormalization, 타입은 MLNormalizationSupportLimits

layerNormalization() 오퍼레이터에 대한 지원 제한.

layerNormalization(input, options) 메서드 단계는 다음과 같다.
  1. this빌드할 수 없으면, "InvalidStateError" DOMExceptionthrow한다.

  2. 피연산자를 검증한 결과가 thisinput, options.scale (그것이 존재하면), 및 options.bias (그것이 존재하면) 중 어느 하나가 주어졌을 때 false를 반환하면, TypeErrorthrow한다.

  3. inputdataType이 (이 표에 따른) 그 허용되는 데이터 타입 중 하나가 아니면, TypeErrorthrow한다.

  4. options.axes존재하지 않으면, options.axes를 새 list로 설정한다. inputrank가 1보다 크면 1부터 inputrank까지의 range(exclusive)로, 그렇지 않으면 빈 list로 설정한다.

  5. 그렇지 않고, options.axes가 중복 값을 포함하거나, 그 items 중 어느 하나가 0부터 inputrank까지의 range(exclusive) 안에 없으면, TypeErrorthrow한다.

  6. options.epsilonoptions.epsiloninputdataType으로 casting한 결과로 설정한다.

  7. options.scale존재하면:

    1. 그것의 dataType이 (이 표에 따른) 그 허용되는 데이터 타입 중 하나가 아니면, TypeErrorthrow한다.

    2. 그것의 rankoptions.axessize와 같지 않으면, TypeErrorthrow한다.

  8. options.bias존재하면:

    1. 그것의 dataType이 (이 표에 따른) 그 허용되는 데이터 타입 중 하나가 아니면, TypeErrorthrow한다.

    2. 그것의 rankoptions.axessize와 같지 않으면, TypeErrorthrow한다.

  9. options.axessize까지 0부터의 range(exclusive)의 각 index에 대해:

    1. axisoptions.axes[index]로 둔다.

    2. axisinputrank보다 크거나 같으면, TypeErrorthrow한다.

    3. sizeinputshape[axis]로 둔다.

    4. options.scale존재하면:

      1. 그것의 shape[index]가 size와 같지 않으면, TypeErrorthrow한다.

    5. options.bias존재하면:

      1. 그것의 shape[index]가 size와 같지 않으면, TypeErrorthrow한다.

  10. 그래프 연결 만들기:

    1. outputinput이 주어졌을 때 MLOperand를 복사한 결과로 둔다.

    2. operatoroptions가 주어진 "layerNormalization" 연산에 대한 오퍼레이터로 둔다.

    3. output.[[operator]]operator로 설정한다.

    4. operatorinputinput으로 설정한다.

    5. options.scale존재하면, 그것을 operatorinputs에 추가한다.

    6. options.bias존재하면, 그것을 operatorinputs에 추가한다.

    7. operatoroutputoutput으로 설정한다.

  11. output을 반환한다.

axes 매개변수가 [1,2,3]으로 설정된 경우 이 연산의 동작은 다음과 같이 다른 연산을 사용하는 방식으로 일반적으로 에뮬레이션할 수 있지만, user agent는 보통 더 효율적인 구현을 가진다. 기반 플랫폼이 어떤 연산을 직접 지원하지 않는 경우, 이 분해는 구현을 안내하는 템플릿으로 사용될 수 있다.
function layerNormalization(builder, input, options) {
  // The reduction of the mean and variance values happens over the spatial
  // dimensions across all the input features (i.e. all channels) of the input
  // tensor.
  const reduceOptions = {axes: [1, 2, 3], keepDimensions: true};
  const mean = builder.reduceMean(input, reduceOptions);
  const variance = builder.reduceMean(
    builder.pow(builder.sub(input, mean), builder.constant(input.dataType, 2)),
    reduceOptions);

  // The scale and bias tensors are of the shape of the input
  // specified by the values in the axes parameter (i.e. [1,2,3]).
  return builder.add(
    builder.mul(
      options.scale,
      builder.div(
        builder.sub(input, mean),
        builder.sqrt(builder.add(variance, options.epsilon)))),
    options.bias);
}

8.9.31. leakyRelu

input tensor에 대해 rectified linear function의 leaky version을 element-wise로 계산한다. 계산은 max(0, x) + alpha * min(0, x) 식을 따른다.
dictionary MLLeakyReluOptions : MLOperatorOptions {
  double alpha = 0.01;
};

partial interface MLGraphBuilder {
  MLOperand leakyRelu(MLOperand input, optional MLLeakyReluOptions options = {});
};

partial dictionary MLOpSupportLimits {
  MLSingleInputSupportLimits leakyRelu;
};

MLLeakyReluOptions는 다음 멤버를 가진다:

alpha, 타입은 double, 기본값은 0.01

scalar multiplier.

인수:

반환:

leakyRelu()에 대한 tensor 제한
피연산자 허용되는 데이터 타입 허용되는 rank
input "float32", "float16" N
output 같음 input 같음 input

MLOpSupportLimitsleakyRelu()에 대해 다음 멤버를 가진다:

leakyRelu, 타입은 MLSingleInputSupportLimits

leakyRelu() 오퍼레이터에 대한 지원 제한.

leakyRelu(input, options) 메서드 단계는 다음과 같다:
  1. this빌드할 수 없으면, "InvalidStateError" DOMExceptionthrow한다.

  2. 피연산자를 검증한 결과가 thisinput이 주어졌을 때 false를 반환하면, TypeErrorthrow한다.

  3. inputdataType이 (이 표에 따른) 그 허용되는 데이터 타입 중 하나가 아니면, TypeErrorthrow한다.

  4. options.alphaoptions.alphainputdataType으로 casting한 결과로 설정한다.

  5. 그래프 연결 만들기:

    1. outputinput이 주어졌을 때 MLOperand를 복사한 결과로 둔다.

    2. operatoroptions가 주어진 "leakyRelu" 연산에 대한 오퍼레이터로 둔다.

    3. output.[[operator]]operator로 설정한다.

    4. operatorinputinput으로 설정한다.

    5. operatoroutputoutput으로 설정한다.

  6. output을 반환한다.

이 연산의 동작은 다음과 같이 다른 연산을 사용하는 방식으로 일반적으로 에뮬레이션할 수 있지만, user agent는 보통 더 효율적인 구현을 가진다. 기반 플랫폼이 어떤 연산을 직접 지원하지 않는 경우, 이 분해는 구현을 안내하는 템플릿으로 사용될 수 있다.
function leakyRelu(builder, input, options) {
  return builder.add(
    builder.max(builder.constant(input.dataType, 0), input),
    builder.mul(
      builder.constant(input.dataType, options.alpha),
      builder.min(builder.constant(input.dataType, 0), input)));
}

8.9.32. linear

input tensor에 대해 linear function y = alpha * x + beta를 계산한다.
dictionary MLLinearOptions : MLOperatorOptions {
  double alpha = 1;
  double beta = 0;
};

partial interface MLGraphBuilder {
  MLOperand linear(MLOperand input, optional MLLinearOptions options = {});
};

partial dictionary MLOpSupportLimits {
  MLSingleInputSupportLimits linear;
};

MLLinearOptions는 다음 멤버를 가진다:

alpha, 타입은 double, 기본값은 1

scalar multiplier.

beta, 타입은 double, 기본값은 0

scalar addition.

인수:

반환:

linear()에 대한 tensor 제한
피연산자 허용되는 데이터 타입 허용되는 rank
input "float32", "float16" N
output 같음 input 같음 input

MLOpSupportLimitslinear()에 대해 다음 멤버를 가진다:

linear, 타입은 MLSingleInputSupportLimits

linear() 오퍼레이터에 대한 지원 제한.

linear(input, options) 메서드 단계는 다음과 같다:
  1. this빌드할 수 없으면, "InvalidStateError" DOMExceptionthrow한다.

  2. 피연산자를 검증한 결과가 thisinput이 주어졌을 때 false를 반환하면, TypeErrorthrow한다.

  3. inputdataType이 (이 표에 따른) 그 허용되는 데이터 타입 중 하나가 아니면, TypeErrorthrow한다.

  4. options.alphaoptions.alphainputdataType으로 casting한 결과로 설정한다.

  5. options.betaoptions.betainputdataType으로 casting한 결과로 설정한다.

  6. 그래프 연결 만들기:

    1. outputinput이 주어졌을 때 MLOperand를 복사한 결과로 둔다.

    2. operatoroptions가 주어진 "linear" 연산에 대한 오퍼레이터로 둔다.

    3. output.[[operator]]operator로 설정한다.

    4. operatorinputinput으로 설정한다.

    5. operatoroutputoutput으로 설정한다.

  7. output을 반환한다.

이 연산의 동작은 다음과 같이 다른 연산을 사용하는 방식으로 일반적으로 에뮬레이션할 수 있지만, user agent는 보통 더 효율적인 구현을 가진다. 기반 플랫폼이 어떤 연산을 직접 지원하지 않는 경우, 이 분해는 구현을 안내하는 템플릿으로 사용될 수 있다.
function linear(builder, input, options) {
  return builder.add(
    builder.mul(input, builder.constant(input.dataType, options.alpha)),
    builder.constant(input.dataType, options.beta));
}

8.9.33. lstm

Long Short-Term Memory [LSTM] recurrent network는 input, output, forget 및 cell gate를 사용하여 network의 temporal sequence 전체에서 output으로 전달되는 output state를 계산한다.
enum MLLstmWeightLayout {
  "iofg", // input-output-forget-cell gate ordering
  "ifgo"  // input-forget-cell-output gate ordering
};

dictionary MLLstmOptions : MLOperatorOptions {
  MLOperand bias;
  MLOperand recurrentBias;
  MLOperand peepholeWeight;
  MLOperand initialHiddenState;
  MLOperand initialCellState;
  boolean returnSequence = false;
  MLRecurrentNetworkDirection direction = "forward";
  MLLstmWeightLayout layout = "iofg";
  sequence<MLRecurrentNetworkActivation> activations;
};

partial interface MLGraphBuilder {
  sequence<MLOperand> lstm(MLOperand input,
                           MLOperand weight,
                           MLOperand recurrentWeight,
                           [EnforceRange] unsigned long steps,
                           [EnforceRange] unsigned long hiddenSize,
                           optional MLLstmOptions options = {});
};

dictionary MLLstmSupportLimits {
  MLTensorLimits input;
  MLTensorLimits weight;
  MLTensorLimits recurrentWeight;
  MLTensorLimits bias;
  MLTensorLimits recurrentBias;
  MLTensorLimits peepholeWeight;
  MLTensorLimits initialHiddenState;
  MLTensorLimits initialCellState;
  MLTensorLimits output0;
  MLTensorLimits output1;
  MLTensorLimits output2;
};

partial dictionary MLOpSupportLimits {
  MLLstmSupportLimits lstm;
};

MLLstmOptions는 다음 멤버를 가진다:

bias, 타입은 MLOperand

shape [numDirections, 4 * hiddenSize]의 2-D input bias tensor. tensor shape의 두 번째 dimension에서 bias vector들의 ordering은 layout에 따라 지정된다.

recurrentBias, 타입은 MLOperand

shape [numDirections, 4 * hiddenSize]의 2-D recurrent bias tensor. tensor shape의 첫 번째 dimension에서 bias vector들의 ordering은 layout에 따라 지정된다.

peepholeWeight, 타입은 MLOperand

shape [numDirections, 3 * hiddenSize]인 peephole용 2-D weight tensor. weight vector들의 pack ordering은 각각 input (i), output (o), 및 forget (f) gate용이다.

initialHiddenState, 타입은 MLOperand

shape [numDirections, batchSize, hiddenSize]의 3-D initial hidden state tensor. 지정되지 않으면, 구현은 0으로 채워진 tensor를 사용해야 한다.

initialCellState, 타입은 MLOperand

shape [numDirections, batchSize, hiddenSize]의 3-D initial hidden state tensor. 지정되지 않으면, 구현은 0으로 채워진 tensor를 사용해야 한다.

returnSequence, 타입은 boolean, 기본값은 false

마지막 time step의 output 외에도 각 time step의 모든 output을 포함하는 전체 sequence를 함께 반환할지를 나타낸다.

direction, 타입은 MLRecurrentNetworkDirection, 기본값은 "forward"

input sequence의 처리 방향. "both"로 설정되면, weight 및 bias tensor shape의 첫 번째 dimension size는 2여야 하며, input은 양방향으로 처리된다.

layout, 타입은 MLLstmWeightLayout, 기본값은 "iofg"

LSTM의 internal gate, 구체적으로 weight 및 bias tensor shape의 첫 번째 dimension에 표시되는 input (i), output (o), forget (f), 및 cell (g) gate에 대한 weight 및 bias vector의 ordering.

activations, 타입은 sequence<MLRecurrentNetworkActivation>

세 개의 activation functions의 list. 첫 번째 것은 input (i), forget (f), 및 output (o) gate에 사용되고, 두 번째 것은 cell (g) gate에 사용되며, 마지막 것은 output gate의 결과와 결합하여 output hidden state를 형성하기 전에 output cell state를 필터링하는 데 사용된다. 지정되지 않으면 각각 "sigmoid", "tanh", 및 "tanh" 함수의 sequence가 기본값이다.

인수:

반환: sequence<MLOperand>. 첫 번째 요소는 shape [numDirections, batchSize, hiddenSize]의 3-D tensor로, network의 마지막 time step에서 나온 output hidden state이다. 두 번째 요소는 shape [numDirections, batchSize, hiddenSize]의 3-D tensor로, network의 마지막 time step에서 나온 output cell state이다. 추가로, returnSequence가 true로 설정되면, 세 번째 요소는 temporal sequence에서 각 time step의 모든 output을 포함하는 shape [steps, numDirections, batchSize, hiddenSize]의 4-D output tensor이다.

lstm()에 대한 tensor 제한
피연산자 허용되는 데이터 타입 허용되는 rank
input "float32", "float16" 3
weight 같음 input 3
recurrentWeight 같음 input 3
bias 같음 input 2
recurrentBias 같음 input 2
peepholeWeight 같음 input 2
initialHiddenState 같음 input 3
initialCellState 같음 input 3
outputs[0] 같음 input 3
outputs[1] 같음 input 3
outputs[2] if returnSequence is true 같음 input 4

MLLstmSupportLimits는 다음 멤버를 가진다:

input, 타입은 MLTensorLimits

input 피연산자에 대한 MLTensorLimits.

weight, 타입은 MLTensorLimits

weight 피연산자에 대한 MLTensorLimits.

recurrentWeight, 타입은 MLTensorLimits

recurrentWeight 피연산자에 대한 MLTensorLimits.

bias, 타입은 MLTensorLimits

bias 피연산자에 대한 MLTensorLimits.

recurrentBias, 타입은 MLTensorLimits

recurrentBias 피연산자에 대한 MLTensorLimits.

peepholeWeight, 타입은 MLTensorLimits

peepholeWeight 피연산자에 대한 MLTensorLimits.

initialHiddenState, 타입은 MLTensorLimits

initialHiddenState 피연산자에 대한 MLTensorLimits.

initialCellState, 타입은 MLTensorLimits

initialCellState 피연산자에 대한 MLTensorLimits.

output0, 타입은 MLTensorLimits

모든 output operands[0]에 대한 MLTensorLimits.

output1, 타입은 MLTensorLimits

모든 output operands[1]에 대한 MLTensorLimits.

output2, 타입은 MLTensorLimits

모든 output operands[2]에 대한 MLTensorLimits.

MLOpSupportLimitslstm()에 대해 다음 멤버를 가진다:

lstm, 타입은 MLLstmSupportLimits

lstm() 오퍼레이터에 대한 지원 제한.

lstm(input, weight, recurrentWeight, steps, hiddenSize, options) 메서드 단계는 다음과 같다:
  1. this빌드할 수 없으면, "InvalidStateError" DOMExceptionthrow한다.

  2. 피연산자를 검증한 결과가 thisinput, weight, recurrentWeight, options.bias (그것이 존재하면), options.recurrentBias (그것이 존재하면), options.peepholeWeight (그것이 존재하면), options.initialHiddenState (그것이 존재하면), 및 options.initialCellState (그것이 존재하면) 중 어느 하나가 주어졌을 때 false를 반환하면, TypeErrorthrow한다.

  3. numDirectionsoptions.direction"both"이면 2로, 그렇지 않으면 1로 둔다.

  4. input, weight 또는 recurrentWeight 중 어느 하나의 dataType이 (이 표에 따른) 그 허용되는 데이터 타입 중 하나가 아니면, TypeErrorthrow한다.

  5. input, weight 또는 recurrentWeight 중 어느 하나의 rank가 그 허용되는 rank가 아니면, TypeErrorthrow한다.

  6. steps가 0이면, TypeErrorthrow한다.

  7. inputshape[0]이 steps와 같지 않으면, TypeErrorthrow한다.

  8. batchSizeinputshape[1]로 둔다.

  9. inputSizeinputshape[2]로 둔다.

  10. weightshape가 « numDirections, 4 * hiddenSize, inputSize »와 같지 않으면, TypeErrorthrow한다.

  11. recurrentWeightshape가 « numDirections, 4 * hiddenSize, hiddenSize »와 같지 않으면, TypeErrorthrow한다.

  12. hiddenSize * 8이 유효한 dimension이 아니면, TypeErrorthrow한다.

    hiddenSize * 8인가? 일부 기반 플랫폼은 biasrecurrentBias를 concat한 단일 bias tensor에서 동작한다. 따라서 4 * hiddenSize + 4 * hiddenSize유효한 dimension이어야 한다.
  13. options.bias존재하면:

    1. 그것의 dataType이 (이 표에 따른) 그 허용되는 데이터 타입 중 하나가 아니면, TypeErrorthrow한다.

    2. 그것의 shape가 « numDirections, 4 * hiddenSize »와 같지 않으면, TypeErrorthrow한다.

  14. options.recurrentBias존재하면:

    1. 그것의 dataType이 (이 표에 따른) 그 허용되는 데이터 타입 중 하나가 아니면, TypeErrorthrow한다.

    2. 그것의 shape가 « numDirections, 4 * hiddenSize »와 같지 않으면, TypeErrorthrow한다.

  15. options.peepholeWeight존재하면:

    1. 그것의 dataType이 (이 표에 따른) 그 허용되는 데이터 타입 중 하나가 아니면, TypeErrorthrow한다.

    2. 그것의 shape가 « numDirections, 3 * hiddenSize »와 같지 않으면, TypeErrorthrow한다.

  16. options.initialHiddenState존재하면:

    1. 그것의 dataType이 (이 표에 따른) 그 허용되는 데이터 타입 중 하나가 아니면, TypeErrorthrow한다.

    2. 그것의 shape가 « numDirections, batchSize, hiddenSize »와 같지 않으면, TypeErrorthrow한다.

  17. options.initialCellState존재하면:

    1. 그것의 dataType이 (이 표에 따른) 그 허용되는 데이터 타입 중 하나가 아니면, TypeErrorthrow한다.

    2. 그것의 shape가 « numDirections, batchSize, hiddenSize »와 같지 않으면, TypeErrorthrow한다.

  18. options.activations존재하면:

    1. 그것의 size가 3이 아니면, TypeErrorthrow한다.

    2. activationsoptions.activationsclone으로 둔다.

  19. 그렇지 않으면:

    1. activations를 « "sigmoid", "tanh", "tanh" »로 둔다.

  20. output shape 계산하기:

    1. descinputdataType 및 « numDirections, batchSize, hiddenSize »가 주어졌을 때 MLOperandDescriptor를 생성한 결과로 둔다.

    2. options.returnSequence가 true이면:

      1. desc2inputdataType 및 « steps, numDirections, batchSize, hiddenSize »가 주어졌을 때 MLOperandDescriptor를 생성한 결과로 둔다.

  21. 그래프 연결 만들기:

    1. operatorweight, recurrentWeight, steps, hiddenSizeoptions가 주어진 "lstm" 연산에 대한 오퍼레이터로 둔다.

    2. output0thisdesc가 주어졌을 때 MLOperand를 생성한 결과로 둔다.

    3. output1thisdesc가 주어졌을 때 MLOperand를 생성한 결과로 둔다.

    4. options.returnSequence가 true이면:

      1. output2thisdesc2가 주어졌을 때 MLOperand를 생성한 결과로 둔다.

      2. outputlist « output0, output1, output2 »로 둔다.

      3. output0.[[operator]], output1.[[operator]]output2.[[operator]]operator로 설정한다.

    5. 그렇지 않으면:

      1. outputlist « output0, output1 »로 둔다.

      2. output0.[[operator]]output1.[[operator]]operator로 설정한다.

    6. operatorinputsinput, weightrecurrentWeight로 설정한다.

    7. options.bias존재하면, 그것을 operatorinputs에 추가한다.

    8. options.recurrentBias존재하면, 그것을 operatorinputs에 추가한다.

    9. options.peepholeWeight존재하면, 그것을 operatorinputs에 추가한다.

    10. options.initialHiddenState존재하면, 그것을 operatorinputs에 추가한다.

    11. options.initialCellState존재하면, 그것을 operatorinputs에 추가한다.

    12. operatoractivation functionsactivationsclone으로 설정한다.

    13. operatoroutputoutput으로 설정한다.

  22. output을 반환한다.

squeeze() helper를 사용하면, 이 연산의 동작은 다음과 같이 다른 연산을 사용하는 방식으로 일반적으로 에뮬레이션할 수 있지만, user agent는 보통 더 효율적인 구현을 가진다. 기반 플랫폼이 어떤 연산을 직접 지원하지 않는 경우, 이 분해는 구현을 안내하는 템플릿으로 사용될 수 있다.
function lstm(
  builder, input, weight, recurrentWeight, steps, hiddenSize, options) {
  const batchSize = input.shape[1];
  const inputSize = input.shape[2];
  const direction = options.direction || 'forward';
  const numDirections = (direction == 'both' ? 2 : 1);
  let hiddenState = options.initialHiddenState;
  let cellState = options.initialCellState;

  if (!hiddenState) {
    const desc = {
      dataType: 'float32',
      shape: [numDirections, batchSize, hiddenSize]
    };
    const totalSize = numDirections * batchSize * hiddenSize;
    hiddenState = builder.constant(desc, new Float32Array(totalSize).fill(0));
  }

  if (!cellState) {
    const desc = {
      dataType: 'float32',
      shape: [numDirections, batchSize, hiddenSize]
    };
    const totalSize = numDirections * batchSize * hiddenSize;
    cellState = builder.constant(desc, new Float32Array(totalSize).fill(0));
  }

  let currentWeight = [];
  let currentRecurrentWeight = [];
  let currentBias = [];
  let currentRecurrentBias = [];
  let currentPeepholeWeight = [];
  let forwardSequence = null;
  let backwardSequence = null;
  let outputHidden = null;
  let outputCell = null;

  for (let dir = 0; dir < numDirections; ++dir) {
    currentWeight.push(squeeze(
      builder,
      builder.slice(weight, [dir, 0, 0], [1, 4 * hiddenSize, inputSize])));
    currentRecurrentWeight.push(squeeze(
      builder,
      builder.slice(
        recurrentWeight, [dir, 0, 0], [1, 4 * hiddenSize, hiddenSize])));
    currentBias.push(
      options.bias ?
        (squeeze(
          builder,
          builder.slice(options.bias, [dir, 0], [1, 4 * hiddenSize]))) :
        null);
    currentRecurrentBias.push(
      options.recurrentBias ?
        (squeeze(
          builder,
          builder.slice(
            options.recurrentBias, [dir, 0], [1, 4 * hiddenSize]))) :
        null);
    currentPeepholeWeight.push(
      options.peepholeWeight ?
        (squeeze(
          builder,
          builder.slice(
            options.peepholeWeight, [dir, 0], [1, 3 * hiddenSize]))) :
        null);

    let currentHidden = squeeze(
      builder,
      builder.slice(hiddenState, [dir, 0, 0], [1, batchSize, hiddenSize]), [0]);
    let currentCell = squeeze(
      builder,
      builder.slice(cellState, [dir, 0, 0], [1, batchSize, hiddenSize]), [0]);

    for (let step = 0; step < steps; ++step) {
      const slice =
        (dir == 1 || direction == 'backward' ? steps - step - 1 : step);
      const currentInput = squeeze(
        builder,
        builder.slice(input, [slice, 0, 0], [1, batchSize, inputSize]), [0]);

      [currentHidden, currentCell] = builder.lstmCell(
        currentInput,
        currentWeight[dir],
        currentRecurrentWeight[dir],
        currentHidden,
        currentCell,
        hiddenSize,
        {
          bias: currentBias[dir],
          recurrentBias: currentRecurrentBias[dir],
          peepholeWeight: currentPeepholeWeight[dir],
          layout: options.layout,
          activations: options.activations
        });

      if (options.returnSequence) {
        // Expand currentHidden of 2D([batchSize, hiddenSize])
        // to 4D([steps, numDirections, batchSize, hiddenSize])
        const expandedHiddenAs4D =
          builder.reshape(currentHidden, [1, 1, batchSize, hiddenSize]);

        if (direction == 'forward' || (dir == 0 && direction == 'both')) {
          forwardSequence = forwardSequence ?
            builder.concat([forwardSequence, expandedHiddenAs4D], 0) :
            expandedHiddenAs4D;
        } else if (
          direction == 'backward' || (dir == 1 && direction == 'both')) {
          backwardSequence = backwardSequence ?
            builder.concat([expandedHiddenAs4D, backwardSequence], 0) :
            expandedHiddenAs4D;
        }
      }
    }

    // Expand currentHidden of 2D([batchSize, hiddenSize])
    // to 3D([numDirections, batchSize, hiddenSize])
    const expandedHiddenAs3D =
      builder.reshape(currentHidden, [1, batchSize, hiddenSize]);
    outputHidden = outputHidden ?
      builder.concat([outputHidden, expandedHiddenAs3D], 0) :
      expandedHiddenAs3D;

    // Expand currentCell of 2D([batchSize, hiddenSize])
    // to 3D([numDirections, batchSize, hiddenSize])
    const expandedCellAs3D =
      builder.reshape(currentCell, [1, batchSize, hiddenSize]);
    outputCell = outputCell ?
      builder.concat([outputCell, expandedCellAs3D], 0) :
      expandedCellAs3D;
  }

  if (options.returnSequence) {
    let outputSequence = null;

    if (direction == 'forward') {
      outputSequence = forwardSequence;
    } else if (direction == 'backward') {
      outputSequence = backwardSequence;
    } else if (direction == 'both') {
      // Concat along axis 1 (numDirections dimension)
      outputSequence = builder.concat([forwardSequence, backwardSequence], 1);
    }

    return [outputHidden, outputCell, outputSequence];
  } else {
    return [outputHidden, outputCell];
  }
}

8.9.34. lstmCell

Long Short-Term Memory [LSTM] recurrent network의 단일 time step으로, cell state와 input, output, forget gate를 사용하여 network의 temporal sequence 전체에서 output으로 전달되는 다음 time step의 cell state 및 hidden state를 계산한다.
dictionary MLLstmCellOptions : MLOperatorOptions {
  MLOperand bias;
  MLOperand recurrentBias;
  MLOperand peepholeWeight;
  MLLstmWeightLayout layout = "iofg";
  sequence<MLRecurrentNetworkActivation> activations;
};

partial interface MLGraphBuilder {
  sequence<MLOperand> lstmCell(MLOperand input,
                               MLOperand weight,
                               MLOperand recurrentWeight,
                               MLOperand hiddenState,
                               MLOperand cellState,
                               [EnforceRange] unsigned long hiddenSize,
                               optional MLLstmCellOptions options = {});
};

dictionary MLLstmCellSupportLimits {
  MLTensorLimits input;
  MLTensorLimits weight;
  MLTensorLimits recurrentWeight;
  MLTensorLimits hiddenState;
  MLTensorLimits cellState;
  MLTensorLimits bias;
  MLTensorLimits recurrentBias;
  MLTensorLimits peepholeWeight;
  MLTensorLimits output0;
  MLTensorLimits output1;
};

partial dictionary MLOpSupportLimits {
  MLLstmCellSupportLimits lstmCell;
};

MLLstmCellOptions는 다음 멤버를 가진다:

bias, 타입은 MLOperand

shape [4 * hiddenSize]의 1-D input bias tensor. tensor shape의 첫 번째 dimension에서 bias vector들의 ordering은 layout에 따라 지정된다.

recurrentBias, 타입은 MLOperand

shape [4 * hiddenSize]의 1-D recurrent bias tensor. tensor shape의 첫 번째 dimension에서 bias vector들의 ordering은 layout에 따라 지정된다.

peepholeWeight, 타입은 MLOperand

shape [3 * hiddenSize]인 peephole용 1-D weight tensor. weight vector들의 pack ordering은 각각 input (i), output (o), 및 forget (f) gate용이다.

layout, 타입은 MLLstmWeightLayout, 기본값은 "iofg"

LSTM의 internal gate, 구체적으로 weight 및 bias tensor shape의 첫 번째 dimension에 표시되는 input (i), output (o), forget (f), 및 cell (g) gate에 대한 weight 및 bias vector의 ordering.

activations, 타입은 sequence<MLRecurrentNetworkActivation>

세 개의 activation functions의 list. 첫 번째 것은 input (i), forget (f), 및 output (o) gate에 사용되고, 두 번째 것은 cell (g) gate에 사용되며, 마지막 것은 output gate의 결과와 결합하여 output hidden state를 형성하기 전에 output cell state를 필터링하는 데 사용된다. 지정되지 않으면 각각 "sigmoid", "tanh", 및 "tanh" 함수의 sequence가 기본값이다.

인수:

반환: sequence<MLOperand>. 첫 번째 요소는 recurrent network의 현재 time step의 output hidden state이다. 다음 요소는 output cell state이다. 두 요소 모두 shape [batchSize, hiddenSize]의 2-D tensor이다.

lstmCell()에 대한 tensor 제한
피연산자 허용되는 데이터 타입 허용되는 rank
input "float32", "float16" 2
weight 같음 input 2
recurrentWeight 같음 input 2
hiddenState 같음 input 2
cellState 같음 input 2
bias 같음 input 1
recurrentBias 같음 input 1
peepholeWeight 같음 input 1
outputs[0] 같음 input 2
outputs[1] 같음 input 2

MLLstmCellSupportLimits는 다음 멤버를 가진다:

input, 타입은 MLTensorLimits

input 피연산자에 대한 MLTensorLimits.

weight, 타입은 MLTensorLimits

weight 피연산자에 대한 MLTensorLimits.

recurrentWeight, 타입은 MLTensorLimits

recurrentWeight 피연산자에 대한 MLTensorLimits.

hiddenState, 타입은 MLTensorLimits

hiddenState 피연산자에 대한 MLTensorLimits.

cellState, 타입은 MLTensorLimits

cellState 피연산자에 대한 MLTensorLimits.

bias, 타입은 MLTensorLimits

bias 피연산자에 대한 MLTensorLimits.

recurrentBias, 타입은 MLTensorLimits

recurrentBias 피연산자에 대한 MLTensorLimits.

peepholeWeight, 타입은 MLTensorLimits

peepholeWeight 피연산자에 대한 MLTensorLimits.

output0, 타입은 MLTensorLimits

모든 output operands[0]에 대한 MLTensorLimits.

output1, 타입은 MLTensorLimits

모든 output operands[1]에 대한 MLTensorLimits.

MLOpSupportLimitslstmCell()에 대해 다음 멤버를 가진다:

lstmCell, 타입은 MLLstmCellSupportLimits

lstmCell() 오퍼레이터에 대한 지원 제한.

lstmCell(input, weight, recurrentWeight, hiddenState, cellState, hiddenSize, options) 메서드 단계는 다음과 같다:
  1. this빌드할 수 없으면, "InvalidStateError" DOMExceptionthrow한다.

  2. 피연산자를 검증한 결과가 thisinput, weight, recurrentWeight, hiddenState, cellState, options.bias (그것이 존재하면), options.recurrentBias (그것이 존재하면), 및 options.peepholeWeight (그것이 존재하면) 중 어느 하나가 주어졌을 때 false를 반환하면, TypeErrorthrow한다.

  3. input, weight, recurrentWeight, hiddenState 또는 cellState 중 어느 하나의 dataType이 (이 표에 따른) 그 허용되는 데이터 타입 중 하나가 아니면, TypeErrorthrow한다.

  4. input, weight, recurrentWeight, hiddenState 또는 cellState 중 어느 하나의 rank가 그 허용되는 rank가 아니면, TypeErrorthrow한다.

  5. batchSizeinputshape[0]로 둔다.

  6. inputSizeinputshape[1]로 둔다.

  7. weightshape가 « 4 * hiddenSize, inputSize »와 같지 않으면, TypeErrorthrow한다.

  8. recurrentWeightshape가 « 4 * hiddenSize, hiddenSize »와 같지 않으면, TypeErrorthrow한다.

  9. hiddenStateshape가 « batchSize, hiddenSize »와 같지 않으면, TypeErrorthrow한다.

  10. cellStateshape가 « batchSize, hiddenSize »와 같지 않으면, TypeErrorthrow한다.

  11. hiddenSize * 8이 유효한 dimension이 아니면, TypeErrorthrow한다.

    hiddenSize * 8인가? 일부 기반 플랫폼은 biasrecurrentBias를 concat한 단일 bias tensor에서 동작한다. 따라서 4 * hiddenSize + 4 * hiddenSize유효한 dimension이어야 한다.
  12. options.bias존재하면:

    1. 그것의 dataType이 (이 표에 따른) 그 허용되는 데이터 타입 중 하나가 아니면, TypeErrorthrow한다.

    2. 그것의 shape가 « 4 * hiddenSize »와 같지 않으면, TypeErrorthrow한다.

  13. options.recurrentBias존재하면:

    1. 그것의 dataType이 (이 표에 따른) 그 허용되는 데이터 타입 중 하나가 아니면, TypeErrorthrow한다.

    2. 그것의 shape가 « 4 * hiddenSize »와 같지 않으면, TypeErrorthrow한다.

  14. options.peepholeWeight존재하면:

    1. 그것의 dataType이 (이 표에 따른) 그 허용되는 데이터 타입 중 하나가 아니면, TypeErrorthrow한다.

    2. 그것의 shape가 « 3 * hiddenSize »와 같지 않으면, TypeErrorthrow한다.

  15. options.activations존재하면:

    1. 그것의 size가 3이 아니면, TypeErrorthrow한다.

    2. activationsoptions.activationsclone으로 둔다.

  16. 그렇지 않으면:

    1. activations를 « "sigmoid", "tanh", "tanh" »로 둔다.

  17. desc를 새 MLOperandDescriptor로 둔다.

  18. desc.shapelist « batchSize, hiddenSize »로 설정한다.

  19. desc.dataTypeinputdataType으로 설정한다.

  20. 그래프 연결 만들기:

    1. output0thisdesc가 주어졌을 때 MLOperand를 생성한 결과로 둔다.

    2. output1thisdesc가 주어졌을 때 MLOperand를 생성한 결과로 둔다.

    3. outputlist « output0, output1 »로 둔다.

    4. operatorweight, recurrentWeight, hiddenState, cellState, hiddenSizeoptions가 주어진 "lstmCell" 연산에 대한 오퍼레이터로 둔다.

    5. output0.[[operator]]output1.[[operator]]operator로 설정한다.

    6. operatorinputsinput, weight, recurrentWeight, hiddenState, 및 cellState로 설정한다.

    7. options.bias존재하면, 그것을 operatorinputs에 추가한다.

    8. options.recurrentBias존재하면, 그것을 operatorinputs에 추가한다.

    9. options.peepholeWeight존재하면, 그것을 operatorinputs에 추가한다.

    10. operatoractivation functionsactivationsclone으로 설정한다.

    11. operatoroutputoutput으로 설정한다.

  21. output을 반환한다.

weight layout이 기본 "iofg" layout이고, input/forget/output gate 및 cell gate/output hidden state에 대한 cell state filter의 activation functions가 각각 sigmoid()tanh()인 경우, 이 연산의 동작은 다음과 같이 다른 연산을 사용하는 방식으로 일반적으로 에뮬레이션할 수 있지만, user agent는 보통 더 효율적인 구현을 가진다. 기반 플랫폼이 어떤 연산을 직접 지원하지 않는 경우, 이 분해는 구현을 안내하는 템플릿으로 사용될 수 있다.
function lstmCell(
  builder,
  input,
  weight,
  recurrentWeight,
  hiddenState,
  cellState,
  hiddenSize,
  options) {
  const zero = builder.constant(input.dataType, 0);

  const inputSize = input.shape[1];

  // input gate (i)
  let i = builder.sigmoid(builder.add(
    builder.mul(
      cellState,
      (options.peepholeWeight ?
         builder.slice(options.peepholeWeight, [0], [hiddenSize]) :
         zero)),
    builder.add(
      builder.add(
        (options.bias ? builder.slice(options.bias, [0], [hiddenSize]) : zero),
        (options.recurrentBias ?
           builder.slice(options.recurrentBias, [0], [hiddenSize]) :
           zero)),
      builder.add(
        builder.matmul(
          input,
          builder.transpose(
            builder.slice(weight, [0, 0], [hiddenSize, inputSize]))),
        builder.matmul(
          hiddenState,
          builder.transpose(builder.slice(
            recurrentWeight, [0, 0], [hiddenSize, hiddenSize])))))));

  // forget gate (f)
  let f = builder.sigmoid(builder.add(
    builder.mul(
      cellState,
      (options.peepholeWeight ?
         builder.slice(options.peepholeWeight, [2 * hiddenSize], [hiddenSize]) :
         zero)),
    builder.add(
      builder.add(
        (options.bias ?
           builder.slice(options.bias, [2 * hiddenSize], [hiddenSize]) :
           zero),
        (options.recurrentBias ?
           builder.slice(
             options.recurrentBias, [2 * hiddenSize], [hiddenSize]) :
           zero)),
      builder.add(
        builder.matmul(
          input,
          builder.transpose(builder.slice(
            weight, [2 * hiddenSize, 0], [hiddenSize, inputSize]))),
        builder.matmul(
          hiddenState,
          builder.transpose(builder.slice(
            recurrentWeight,
            [2 * hiddenSize, 0],
            [hiddenSize, hiddenSize])))))));

  // cell gate (g)
  let g = builder.tanh(builder.add(
    builder.add(
      (options.bias ?
         builder.slice(options.bias, [3 * hiddenSize], [hiddenSize]) :
         zero),
      (options.recurrentBias ?
         builder.slice(options.recurrentBias, [3 * hiddenSize], [hiddenSize]) :
         zero)),
    builder.add(
      builder.matmul(
        input,
        builder.transpose(
          builder.slice(weight, [3 * hiddenSize, 0], [hiddenSize, inputSize]))),
      builder.matmul(
        hiddenState,
        builder.transpose(builder.slice(
          recurrentWeight, [3 * hiddenSize, 0], [hiddenSize, hiddenSize]))))));

  // output gate (o)
  let o = builder.sigmoid(builder.add(
    builder.mul(
      cellState,
      (options.peepholeWeight ?
         builder.slice(options.peepholeWeight, [hiddenSize], [hiddenSize]) :
         zero)),
    builder.add(
      builder.add(
        (options.bias ?
           builder.slice(options.bias, [hiddenSize], [hiddenSize]) :
           zero),
        (options.recurrentBias ?
           builder.slice(options.recurrentBias, [hiddenSize], [hiddenSize]) :
           zero)),
      builder.add(
        builder.matmul(
          input,
          builder.transpose(
            builder.slice(weight, [hiddenSize, 0], [hiddenSize, inputSize]))),
        builder.matmul(
          hiddenState,
          builder.transpose(builder.slice(
            recurrentWeight, [hiddenSize, 0], [hiddenSize, hiddenSize])))))));

  // output cell state (ct)
  let ct = builder.add(builder.mul(f, cellState), builder.mul(i, g));

  // output hidden state (ht)
  let ht = builder.mul(o, builder.tanh(ct));

  return [ht, ct];
}

8.9.35. matmul

두 input tensor의 matrix product를 계산한다.
partial interface MLGraphBuilder {
  MLOperand matmul(MLOperand a, MLOperand b, optional MLOperatorOptions options = {});
};

partial dictionary MLOpSupportLimits {
  MLBinarySupportLimits matmul;
};
인수:

반환: MLOperand. 두 input tensor의 matrix product를 포함하는 output tensor.

두 input tensor의 matrix product를 다음과 같이 계산한다:
matmul()에 대한 tensor 제한
피연산자 허용되는 데이터 타입 허용되는 rank
a "float32", "float16" 2 to N
b 같음 a 2 or N
output 같음 a 2 or N

MLOpSupportLimitsmatmul()에 대해 다음 멤버를 가진다:

matmul, 타입은 MLBinarySupportLimits

matmul() 오퍼레이터에 대한 지원 제한.

matmul(a, b, options) 메서드 단계는 다음과 같다:
  1. this빌드할 수 없으면, "InvalidStateError" DOMExceptionthrow한다.

  2. 피연산자를 검증한 결과가 thisab 중 어느 하나가 주어졌을 때 false를 반환하면, TypeErrorthrow한다.

  3. a 또는 b 중 어느 하나의 dataType이 (이 표에 따른) 그 허용되는 데이터 타입 중 하나가 아니면, TypeErrorthrow한다.

  4. output shape 계산하기:

    1. shapeAashapeclone으로 둔다.

    2. rankAarank로 둔다.

    3. shapeBbshapeclone으로 둔다.

    4. rankBbrank로 둔다.

    5. rankA 또는 rankB 중 하나라도 2보다 작으면, TypeErrorthrow한다.

    6. colsAshapeA[rankA - 1]로 둔다.

    7. rowsAshapeA[rankA - 2]로 둔다.

    8. colsBshapeB[rankB - 1]로 둔다.

    9. rowsBshapeB[rankB - 2]로 둔다.

    10. colsArowsB와 같지 않으면, TypeErrorthrow한다.

    11. batchShapeA를 spatial dimensions(마지막 2 items)가 제거된 shapeAclone으로 둔다.

    12. batchShapeB를 spatial dimensions(마지막 2 items)가 제거된 shapeBclone으로 둔다.

    13. outputShapebatchShapeAbatchShapeBbidirectionally broadcasting한 결과로 둔다. 그것이 failure를 반환하면, TypeErrorthrow한다.

    14. « rowsA, colsB »를 outputShapeappend한다.

    15. descadataTypeoutputShape가 주어졌을 때 MLOperandDescriptor를 생성한 결과로 둔다.

  5. 그래프 연결 만들기:

    1. outputthisdesc가 주어졌을 때 MLOperand를 생성한 결과로 둔다.

    2. operatoroptions가 주어진 "matmul" 연산에 대한 오퍼레이터로 둔다.

    3. output.[[operator]]operator로 설정한다.

    4. operatorinputsab로 설정한다.

    5. operatoroutputoutput으로 설정한다.

  6. output을 반환한다.

8.9.36. pad

edge에서 constant 또는 mirrored 값으로 tensor를 확장한다.
enum MLPaddingMode {
  "constant",
  "edge",
  "reflection"
};

dictionary MLPadOptions : MLOperatorOptions {
  MLPaddingMode mode = "constant";
  MLNumber value = 0;
};

partial interface MLGraphBuilder {
  MLOperand pad(MLOperand input,
                sequence<[EnforceRange] unsigned long> beginningPadding,
                sequence<[EnforceRange] unsigned long> endingPadding,
                optional MLPadOptions options = {});
};

partial dictionary MLOpSupportLimits {
  MLSingleInputSupportLimits pad;
};

MLPadOptions는 다음 멤버를 가진다:

mode, 타입은 MLPaddingMode, 기본값은 "constant"

tensor를 padding하는 여러 방식.

value, 타입은 MLNumber, 기본값은 0

mode"constant"로 설정된 경우의 padding 값.

인수:

반환: MLOperand. padding된 output tensor. output tensor의 각 dimension은 다음과 같이 계산할 수 있다:

output size = beginning padding + input size + ending padding

pad()에 대한 tensor 제한
피연산자 허용되는 데이터 타입 허용되는 rank
input any N
output 같음 input 같음 input

MLOpSupportLimitspad()에 대해 다음 멤버를 가진다:

pad, 타입은 MLSingleInputSupportLimits

pad() 오퍼레이터에 대한 지원 제한.

pad(input, beginningPadding, endingPadding, options) 메서드 단계는 다음과 같다:
  1. this빌드할 수 없으면, "InvalidStateError" DOMExceptionthrow한다.

  2. 피연산자를 검증한 결과가 thisinput이 주어졌을 때 false를 반환하면, TypeErrorthrow한다.

  3. beginningPaddingsizeendingPaddingsize가 둘 다 inputrank와 같지 않으면, TypeErrorthrow한다.

  4. descinput.[[descriptor]]의 copy로 둔다.

  5. outputShapeinputshape의 copy로 둔다.

  6. 0부터 outputShaperank까지의 range에 있는 각 index에 대해 For each, exclusive:

    1. options.mode에 대해 switch한다:

      "constant"

      아무것도 하지 않는다.

      "edge"

      아무것도 하지 않는다.

      "reflection"
      1. beginningPadding[index]가 outputShape[index]보다 크거나 같으면, TypeErrorthrow한다.

      2. endingPadding[index]가 outputShape[index]보다 크거나 같으면, TypeErrorthrow한다.

    2. beginningPadding[index]의 값을 outputShape[index]에 더한다.

    3. endingPadding[index]의 값을 outputShape[index]에 더한다.

  7. outputShape의 어떤 item이라도 유효한 dimension이 아니면, TypeErrorthrow한다.

  8. options.valueoptions.valueinputdataType으로 casting한 결과로 설정한다.

  9. desc.shapeoutputShape로 설정한다.

  10. 그래프 연결 만들기:

    1. outputthisdesc가 주어졌을 때 MLOperand를 생성한 결과로 둔다.

    2. operatorbeginningPadding, endingPaddingoptions가 주어진 "padding" 연산에 대한 오퍼레이터로 둔다.

    3. output.[[operator]]operator로 설정한다.

    4. operatorinputinput으로 설정한다.

    5. operatoroutputoutput으로 설정한다.

  11. output을 반환한다.

constant, edge, reflection padding 예:
// input: [[1,2,3], [4,5,6]]
const input = builder.constant(
  {dataType: 'float32', shape: [2, 3]}, new Float32Array([1, 2, 3, 4, 5, 6]));

const beginningPadding = [1, 2];
const endingPadding = [1, 2];

// "constant" padding 적용:
//    [[0,0,0,0,0,0,0],
//     [0,0,1,2,3,0,0],
//     [0,0,4,5,6,0,0],
//     [0,0,0,0,0,0,0]]
builder.pad(input, beginningPadding, endingPadding);

// "edge" padding 적용:
//    [[1,1,1,2,3,3,3],
//     [1,1,1,2,3,3,3],
//     [4,4,4,5,6,6,6],
//     [4,4,4,5,6,6,6]]
builder.pad(input, beginningPadding, endingPadding, {mode: 'edge'});

// "reflection" padding 적용:
//    [[6,5,4,5,6,5,4],
//     [3,2,1,2,3,2,1],
//     [6,5,4,5,6,5,4],
//     [3,2,1,2,3,2,1]]
builder.pad(input, beginningPadding, endingPadding, {mode: 'reflection'});

8.9.37. Pooling operations

input tensor 위를 이동하는 window 내의 모든 요소에 걸쳐 pooling 연산을 계산한다.
enum MLRoundingType {
  "floor",
  "ceil"
};

dictionary MLPool2dOptions : MLOperatorOptions {
  sequence<[EnforceRange] unsigned long> windowDimensions;
  sequence<[EnforceRange] unsigned long> padding;
  sequence<[EnforceRange] unsigned long> strides;
  sequence<[EnforceRange] unsigned long> dilations;
  MLInputOperandLayout layout = "nchw";
  MLRoundingType outputShapeRounding = "floor";
  sequence<[EnforceRange] unsigned long> outputSizes;
};

partial interface MLGraphBuilder {
  MLOperand averagePool2d(MLOperand input, optional MLPool2dOptions options = {});
  MLOperand l2Pool2d(MLOperand input, optional MLPool2dOptions options = {});
  MLOperand maxPool2d(MLOperand input, optional MLPool2dOptions options = {});
};

partial dictionary MLOpSupportLimits {
  MLSingleInputSupportLimits averagePool2d;
  MLSingleInputSupportLimits l2Pool2d;
  MLSingleInputSupportLimits maxPool2d;
};

MLPool2dOptions는 다음 멤버를 가진다:

windowDimensions, 타입은 sequence<[EnforceRange] unsigned long>

길이 2의 list: [windowHeight, windowWidth]. sliding window의 dimensions를 지정한다. window dimensions의 기본값은 input shape의 height 및 width dimensions이다.

padding, 타입은 sequence<[EnforceRange] unsigned long>

길이 4의 list: [beginningHeight, endingHeight, beginningWidth, endingWidth]. convolution input의 각 spatial dimension의 beginning 및 ending에 추가되는 row와 column을 지정한다. 기본값은 [0,0,0,0]이다.

strides, 타입은 sequence<[EnforceRange] unsigned long>

길이 2의 list: [strideHeight, strideWidth]. convolution input의 각 spatial dimension에 대한 sliding window의 stride를 지정한다. 기본값은 [1,1]이다.

dilations, 타입은 sequence<[EnforceRange] unsigned long>

길이 2의 list: [dilationHeight, dilationWidth]. convolution filter(kernel)에 적용되는 각 spatial dimension의 dilation factor를 지정한다. 기본값은 [1,1]이다.

layout, 타입은 MLInputOperandLayout, 기본값은 "nchw"

input 및 output tensor의 layout format을 다음과 같이 지정한다:

  • "nchw"

    • input tensor: [batches, inputChannels, height, width]

    • output tensor: [batches, outputChannels, height, width]

  • "nhwc":

    • input tensor: [batches, height, width, inputChannels]

    • output tensor: [batches, height, width, outputChannels]

outputShapeRounding, 타입은 MLRoundingType, 기본값은 "floor"

full window 결과를 원하는지 partial window 결과를 원하는지에 따라, output shape를 계산하는 데 사용되는 rounding function.

outputSizes, 타입은 sequence<[EnforceRange] unsigned long>

길이 2의 list: [outputHeight, outputWidth] output tensor의 두 spatial dimensions의 size를 지정한다. output sizes가 명시적으로 지정되면, outputShapeRounding은 무시된다. 지정되지 않으면, output sizes는 자동으로 계산된다.

인수:

반환: MLOperand. reduction 결과를 포함하는 output 4-D tensor. logical shape는 layout의 값에 따라 해석된다. 더 구체적으로, outputShapeRounding"floor"이면, output tensor의 단일 dimension에 대한 spatial dimensions는 다음과 같이 계산할 수 있다:

output size = floor(1 + (input size - filter size + beginning padding + ending padding) / stride)

또는 outputShapeRounding"ceil"인 경우:

output size = ceil(1 + (input size - filter size + beginning padding + ending padding) / stride)

pooling operations에 대한 tensor 제한
피연산자 허용되는 데이터 타입 허용되는 rank
input operation steps의 일부로 지정됨 4
output 같음 input 4

MLOpSupportLimits는 pooling operations에 대해 다음 멤버를 가진다:

averagePool2d, 타입은 MLSingleInputSupportLimits

averagePool2d() 오퍼레이터에 대한 지원 제한.

l2Pool2d, 타입은 MLSingleInputSupportLimits

l2Pool2d() 오퍼레이터에 대한 지원 제한.

maxPool2d, 타입은 MLSingleInputSupportLimits

maxPool2d() 오퍼레이터에 대한 지원 제한.

max pooling operation을 위한 것과 같은 global pooling operation은 window dimensions가 input shape의 spatial dimensions(마지막 두 dimensions)인 pooling의 variant로, 다음과 같다.
// 'global' max pooling
builder.maxPool2d(input);
string op, MLOperand input, MLPool2dOptions options, 및 선택적 list allowedDataTypes가 주어졌을 때 pooling operation을 생성하려면, 다음 단계를 실행한다:
  1. Assert: op는 "averagePool2d", "l2Pool2d", "maxPool2d" 중 하나이다.

  2. this빌드할 수 없으면, "InvalidStateError" DOMExceptionthrow한다.

  3. 피연산자를 검증한 결과가 thisinput이 주어졌을 때 false를 반환하면, TypeErrorthrow한다.

  4. allowedDataTypes가 주어졌고 그것이 inputdataTypecontain하지 않으면, TypeErrorthrow한다.

  5. inputrank가 4가 아니면, TypeErrorthrow한다.

  6. options.layout에 대해 switch한다:

    "nchw"

    « batches, channels, inputHeight, inputWidth »를 inputshape로 둔다.

    "nhwc"

    « batches, inputHeight, inputWidth, channels »를 inputshape로 둔다.

  7. options.windowDimensionsexist하지 않으면, options.windowDimensions를 « inputHeight, inputWidth »로 설정한다.

  8. options.windowDimensionssize가 2가 아니면, TypeErrorthrow한다.

  9. options.windowDimensions의 어떤 item이라도 0과 같으면, TypeErrorthrow한다.

  10. options.outputSizes존재하거나, 또는 options.paddingexist하지 않으면, options.paddinglist « 0, 0, 0, 0 »로 설정한다.

  11. options.paddingsize가 4가 아니면, TypeErrorthrow한다.

  12. options.stridesexist하지 않으면, options.strideslist « 1, 1 »로 설정한다.

  13. options.stridessize가 2가 아니면, TypeErrorthrow한다.

  14. options.strides의 어떤 item이라도 0이면, TypeErrorthrow한다.

  15. options.outputSizes존재하면:

    1. 그것의 size가 2가 아니면, TypeErrorthrow한다.

    2. 그것의 itemsoptions.strides의 같은 dimension(index)에 있는 items보다 작지 않으면, TypeErrorthrow한다.

  16. options.dilationsexist하지 않으면, options.dilationslist « 1, 1 »로 설정한다.

  17. options.dilationssize가 2가 아니면, TypeErrorthrow한다.

  18. options.dilations의 어떤 item이라도 0이면, TypeErrorthrow한다.

  19. descinput.[[descriptor]]의 copy로 둔다.

  20. output shape 계산하기:

    1. « windowHeight, windowWidth »를 options.windowDimensions로 둔다.

    2. « calculatedOutputHeight, calculatedOutputWidth »를 inputHeight, inputWidth, windowHeight, windowWidth, options.padding, options.strides, 및 options.dilations가 주어졌을 때 conv2d output sizes를 계산한 결과로 둔다.

    3. options.outputSizes존재하면:

      1. « outputHeight, outputWidth »를 options.outputSizes로 둔다.

      2. outputHeight가 floor( calculatedOutputHeight )와 같고 outputWidth가 floor( calculatedOutputWidth )와 같은 것도 아니고, outputHeight가 ceil( calculatedOutputHeight )와 같고 outputWidth가 ceil( calculatedOutputWidth )와 같은 것도 아니면, TypeErrorthrow한다.

    4. 그렇지 않으면:

      1. « outputHeight, outputWidth »를 « calculatedOutputHeight, calculatedOutputWidth »로 둔다.

      2. options.outputShapeRounding에 대해 switch한다:

        "floor"
        1. outputWidth를 floor(outputWidth)로 설정한다.

        2. outputHeight를 floor(outputHeight)로 설정한다.

        "ceil"
        1. outputWidth를 ceiling(outputWidth)으로 설정한다.

        2. outputHeight를 ceiling(outputHeight)으로 설정한다.

    5. outputHeight 또는 outputWidth 중 하나라도 유효한 dimension이 아니면, TypeErrorthrow한다.

    6. options.layout에 대해 switch한다:

      "nchw"

      outputShape를 « batches, channels, outputHeight, outputWidth »로 둔다.

      "nhwc"

      outputShape를 « batches, outputHeight, outputWidth, channels »로 둔다.

    7. desc.shapeoutputShape로 설정한다.

  21. 그래프 연결 만들기:

    1. outputthisdesc가 주어졌을 때 MLOperand를 생성한 결과로 둔다.

    2. operatoroptions가 주어진 op 연산에 대한 오퍼레이터로 둔다.

    3. output.[[operator]]operator로 설정한다.

    4. operatorinputinput으로 설정한다.

    5. operatoroutputoutput으로 설정한다.

  22. output을 반환한다.

다음 pooling 알고리즘이 지원된다.
averagePool2d(input, options) 메서드 단계는 다음과 같다:
  1. output을 "averagePool2d", input, options, 및 « "float32", "float16" »가 주어졌을 때 pooling operation을 생성한 결과로 둔다.

    1. 그것이 error를 throws하면, 해당 error를 다시 throw한다.

  2. output을 반환한다.

l2Pool2d(input, options) 메서드 단계는 다음과 같다:
  1. output을 "l2Pool2d", input, options, 및 « "float32", "float16" »가 주어졌을 때 pooling operation을 생성한 결과로 둔다.

    1. 그것이 error를 throws하면, 해당 error를 다시 throw한다.

  2. output을 반환한다.

maxPool2d(input, options) 메서드 단계는 다음과 같다:
  1. output을 "maxPool2d", inputoptions가 주어졌을 때 pooling operation을 생성한 결과로 둔다.

    1. 그것이 error를 throws하면, 해당 error를 다시 throw한다.

  2. output을 반환한다.

8.9.37.1. averagePool2d
feature map의 patch들에 대한 평균값을 계산하고, 이를 사용하여 pooled feature map을 생성한다. 자세한 내용은 § 8.9.37 Pooling operations를 참조하라.
8.9.37.2. l2Pool2d
L2 norm 함수를 input feature map의 region에 적용한다. L2 norm은 그 요소들의 제곱 합의 제곱근이다. 자세한 내용은 § 8.9.37 Pooling operations를 참조하라.
8.9.37.3. maxPool2d
feature map의 patch들에 대한 최댓값을 계산하고, 이를 사용하여 pooled feature map을 생성한다. 자세한 내용은 § 8.9.37 Pooling operations를 참조하라.

8.9.38. prelu

input tensor에 rectified linear function의 parametric version(Parametric ReLU)을 element-wise로 계산한다. Parametric ReLU는 0.01과 같은 scalar slope를 가지는 대신 slope(leakage의 coefficient)를 이 연산의 model training 단계에서 학습되는 parameter로 만드는 leaky ReLU의 한 종류이다. 계산은 max(0, x) + slope * min(0, x) 표현식을 따른다.

연산은 broadcast되며, 이는 [numpy-broadcasting-rule]에 따른다. input tensor들은 bidirectionally broadcastable이어야 한다. output tensor의 rank는 input tensor들의 최대 rank이다. output tensor의 각 dimension에 대해, 그 size는 input tensor들의 해당 dimension에서의 최대 size이다.

partial interface MLGraphBuilder {
  MLOperand prelu(MLOperand input,
                  MLOperand slope,
                  optional MLOperatorOptions options = {});
};

dictionary MLPreluSupportLimits {
  MLTensorLimits input;
  MLTensorLimits slope;
  MLTensorLimits output;
};

partial dictionary MLOpSupportLimits {
  MLPreluSupportLimits prelu;
};
인수:

반환:

prelu()에 대한 tensor 제한
피연산자 허용되는 데이터 타입 허용되는 rank
input "float32", "float16", "int64", "int32", "int8" N
slope 같음 input N
output 같음 input N

MLPreluSupportLimits는 다음 멤버를 가진다:

input, 타입은 MLTensorLimits

input 피연산자에 대한 MLTensorLimits.

slope, 타입은 MLTensorLimits

slope 피연산자에 대한 MLTensorLimits.

output, 타입은 MLTensorLimits

output 피연산자에 대한 MLTensorLimits.

MLOpSupportLimitsprelu()에 대해 다음 멤버를 가진다:

prelu, 타입은 MLPreluSupportLimits

prelu() 오퍼레이터에 대한 지원 제한.

prelu(input, slope, options) 메서드 단계는 다음과 같다:
  1. this빌드할 수 없으면, "InvalidStateError" DOMExceptionthrow한다.

  2. 피연산자를 검증한 결과가 thisinputslope 중 어느 하나가 주어졌을 때 false를 반환하면, TypeErrorthrow한다.

  3. input 또는 slope 중 어느 하나의 dataType이 (이 표에 따른) 그 허용되는 데이터 타입 중 하나가 아니면, TypeErrorthrow한다.

  4. outputShapeslopeshapeinputshapebidirectionally broadcasting한 결과로 둔다.

    1. 그것이 failure를 반환하면, TypeErrorthrow한다.

  5. descriptorinputdataTypeoutputShape가 주어졌을 때 MLOperandDescriptor를 생성한 결과로 둔다.

  6. 그래프 연결 만들기:

    1. outputthisdescriptor가 주어졌을 때 MLOperand를 생성한 결과로 둔다.

    2. operatorslopeoptions가 주어진 "prelu" 연산에 대한 오퍼레이터로 둔다.

    3. output.[[operator]]operator로 설정한다.

    4. operatorinputsinputslope로 설정한다.

    5. operatoroutputoutput으로 설정한다.

  7. output을 반환한다.

이 연산의 동작은 다음과 같이 다른 연산을 사용하는 방식으로 일반적으로 에뮬레이션할 수 있지만, user agent는 보통 더 효율적인 구현을 가진다. 기반 플랫폼이 어떤 연산을 직접 지원하지 않는 경우, 이 분해는 구현을 안내하는 템플릿으로 사용될 수 있다.
function prelu(builder, input, slope) {
  return builder.add(
    builder.max(builder.constant(input.dataType, 0), input),
    builder.mul(
      slope, builder.min(builder.constant(input.dataType, 0), input)));
}

8.9.39. Reduction operations

input tensor를 모든 dimensions를 따라, 또는 axes array parameter에 지정된 axes를 따라 reduce한다. 지정된 각 axis에 대해, 해당 index를 가진 dimension이 reduce된다. 즉, keepDimensions가 지정되지 않는 한 결과 tensor에는 그 dimension이 포함되지 않는다. 결과 tensor의 값은 reduced dimensions 전체에 걸친 모든 input 값을 parameter로 받는 지정된 reduction function을 사용하여 계산된다.
dictionary MLReduceOptions : MLOperatorOptions {
  sequence<[EnforceRange] unsigned long> axes;
  boolean keepDimensions = false;
};

partial interface MLGraphBuilder {
  MLOperand reduceL1(MLOperand input, optional MLReduceOptions options = {});
  MLOperand reduceL2(MLOperand input, optional MLReduceOptions options = {});
  MLOperand reduceLogSum(MLOperand input, optional MLReduceOptions options = {});
  MLOperand reduceLogSumExp(MLOperand input, optional MLReduceOptions options = {});
  MLOperand reduceMax(MLOperand input, optional MLReduceOptions options = {});
  MLOperand reduceMean(MLOperand input, optional MLReduceOptions options = {});
  MLOperand reduceMin(MLOperand input, optional MLReduceOptions options = {});
  MLOperand reduceProduct(MLOperand input, optional MLReduceOptions options = {});
  MLOperand reduceSum(MLOperand input, optional MLReduceOptions options = {});
  MLOperand reduceSumSquare(MLOperand input, optional MLReduceOptions options = {});
};

partial dictionary MLOpSupportLimits {
  MLSingleInputSupportLimits reduceL1;
  MLSingleInputSupportLimits reduceL2;
  MLSingleInputSupportLimits reduceLogSum;
  MLSingleInputSupportLimits reduceLogSumExp;
  MLSingleInputSupportLimits reduceMax;
  MLSingleInputSupportLimits reduceMean;
  MLSingleInputSupportLimits reduceMin;
  MLSingleInputSupportLimits reduceProduct;
  MLSingleInputSupportLimits reduceSum;
  MLSingleInputSupportLimits reduceSumSquare;
};

MLReduceOptions는 다음 멤버를 가진다:

axes, 타입은 sequence<[EnforceRange] unsigned long>

reduce할 dimensions로, reduction function에 input tensor의 어떤 값들이 사용되는지도 지정한다. list의 axes는 [0, N-1] 범위 안에 있어야 하며, 여기서 N은 input tensor의 rank이다.

존재하지 않으면 모든 dimensions가 reduce된다. reduction function에 대한 input 값은 input tensor의 모든 값이다.

존재하고 비어 있지 않으면, reduction function에 대한 input 값은 input tensor의 지정된 dimensions에 대한 모든 값이다.

존재하고 비어 있으면, 어떤 dimensions도 reduce되지 않으며 output tensor의 shape는 input tensor의 shape와 같다. reduction function은 tensor의 각 값에 개별적으로 적용된다.

keepDimensions, 타입은 boolean, 기본값은 false

true이면, output은 input과 같은 rank를 가지며, reduce된 모든 dimensions를 size 1로 설정한다.

인수:

반환: MLOperand. inputrank까지 포함하여 0부터 그 rank까지의 범위에 있는 rank를 가지는 output N-D tensor이며, 이는 axeskeepDimensions에 따라 달라진다. input operand가 scalar이면, reduction function은 scalar 값에 적용되고 output도 scalar이다.

reduction-operations에 대한 tensor 제한
피연산자 허용되는 데이터 타입 허용되는 rank
input operation steps의 일부로 지정됨 N
output 같음 input N

MLOpSupportLimits는 reduction operations에 대해 다음 멤버를 가진다:

reduceL1, 타입은 MLSingleInputSupportLimits

reduceL1() 오퍼레이터에 대한 지원 제한.

reduceL2, 타입은 MLSingleInputSupportLimits

reduceL2() 오퍼레이터에 대한 지원 제한.

reduceLogSum, 타입은 MLSingleInputSupportLimits

reduceLogSum() 오퍼레이터에 대한 지원 제한.

reduceLogSumExp, 타입은 MLSingleInputSupportLimits

reduceLogSumExp() 오퍼레이터에 대한 지원 제한.

reduceMax, 타입은 MLSingleInputSupportLimits

reduceMax() 오퍼레이터에 대한 지원 제한.

reduceMean, 타입은 MLSingleInputSupportLimits

reduceMean() 오퍼레이터에 대한 지원 제한.

reduceMin, 타입은 MLSingleInputSupportLimits

reduceMin() 오퍼레이터에 대한 지원 제한.

reduceProduct, 타입은 MLSingleInputSupportLimits

reduceProduct() 오퍼레이터에 대한 지원 제한.

reduceSum, 타입은 MLSingleInputSupportLimits

reduceSum() 오퍼레이터에 대한 지원 제한.

reduceSumSquare, 타입은 MLSingleInputSupportLimits

reduceSumSquare() 오퍼레이터에 대한 지원 제한.

Reduction types:
unsigned integers의 list inputShape, unsigned integers의 선택적 list axes, 및 boolean keepDimensions가 주어졌을 때 reduction output sizes를 계산하려면, 다음 단계를 수행한다. 이는 unsigned integers의 새 list 또는 failure를 반환한다.
  1. inputRankinputShapesize로 둔다.

  2. axes가 주어지지 않았으면, axes를 0부터 inputRank까지의 range로 둔다, exclusive.

  3. 그렇지 않고, axes가 중복 값을 포함하거나, 그것의 items 중 하나라도 0부터 inputRank까지의 range 안에 있지 않으면, exclusive, failure를 반환한다.

  4. keepDimensions가 true이면:

    1. outputShapeinputShapeclone으로 둔다.

    2. axes의 각 axis에 대해 For each:

      1. outputShape[axis]를 1로 설정한다.

  5. 그렇지 않으면:

    1. outputShape를 빈 list로 둔다.

    2. 0부터 inputRank까지의 range에 있는 각 index에 대해 For each, exclusive:

      1. axesindexcontain하지 않으면, inputShape[index]를 outputShapeappend한다.

  6. outputShape를 반환한다.

string op, MLOperand input, MLReduceOptions options, 및 선택적 list allowedDataTypes가 주어졌을 때 reduction operation을 생성하려면, 다음 단계를 실행한다:
  1. Assert: op는 "reduceL1", "reduceL2", "reduceLogSum", "reduceLogSumExp", "reduceMax", "reduceMean", "reduceMin", "reduceProduct", "reduceSum", "reduceSumSquare" 중 하나이다.

  2. this빌드할 수 없으면, "InvalidStateError" DOMExceptionthrow한다.

  3. 피연산자를 검증한 결과가 thisinput이 주어졌을 때 false를 반환하면, TypeErrorthrow한다.

  4. allowedDataTypes가 주어졌고 그것이 inputdataTypecontain하지 않으면, TypeErrorthrow한다.

  5. outputShapeinputshape, options.axes (그것이 존재하면), 및 options.keepDimensions가 주어졌을 때 reduction output sizes를 계산한 결과로 둔다. 그것이 failure를 반환하면, TypeErrorthrow한다.

  6. descinputdataTypeoutputShape가 주어졌을 때 MLOperandDescriptor를 생성한 결과로 둔다.

  7. 그래프 연결 만들기:

    1. outputthisdesc가 주어졌을 때 MLOperand를 생성한 결과로 둔다.

    2. operatoroptions가 주어진 op 연산에 대한 오퍼레이터로 둔다.

    3. output.[[operator]]operator로 설정한다.

    4. operatorinputinput으로 설정한다.

    5. operatoroutputoutput으로 설정한다.

  8. output을 반환한다.

다음 reduction 알고리즘이 지원된다.
reduceL1(input, options) 메서드 단계는 다음과 같다:
  1. output을 "reduceL1", input, options, 및 « "float32", "float16", "int32", "uint32", "int64", "uint64" »가 주어졌을 때 reduction operation을 생성한 결과로 둔다.

    1. 그것이 error를 throws하면, 해당 error를 다시 throw한다.

  2. output을 반환한다.

reduceL2(input, options) 메서드 단계는 다음과 같다:
  1. output을 "reduceL2", input, options, 및 « "float32", "float16" »가 주어졌을 때 reduction operation을 생성한 결과로 둔다.

    1. 그것이 error를 throws하면, 해당 error를 다시 throw한다.

  2. output을 반환한다.

reduceLogSum(input, options) 메서드 단계는 다음과 같다:
  1. output을 "reduceLogSum", input, options, 및 « "float32", "float16" »가 주어졌을 때 reduction operation을 생성한 결과로 둔다.

    1. 그것이 error를 throws하면, 해당 error를 다시 throw한다.

  2. output을 반환한다.

reduceLogSumExp(input, options) 메서드 단계는 다음과 같다:
  1. output을 "reduceLogSumExp", input, options, 및 « "float32", "float16" »가 주어졌을 때 reduction operation을 생성한 결과로 둔다.

    1. 그것이 error를 throws하면, 해당 error를 다시 throw한다.

  2. output을 반환한다.

reduceMax(input, options) 메서드 단계는 다음과 같다:
  1. output을 "reduceMax", inputoptions가 주어졌을 때 reduction operation을 생성한 결과로 둔다.

    1. 그것이 error를 throws하면, 해당 error를 다시 throw한다.

  2. output을 반환한다.

reduceMean(input, options) 메서드 단계는 다음과 같다:
  1. output을 "reduceMean", input, options, 및 « "float32", "float16" »가 주어졌을 때 reduction operation을 생성한 결과로 둔다.

    1. 그것이 error를 throws하면, 해당 error를 다시 throw한다.

  2. output을 반환한다.

reduceMin(input, options) 메서드 단계는 다음과 같다:
  1. output을 "reduceMin", inputoptions가 주어졌을 때 reduction operation을 생성한 결과로 둔다.

    1. 그것이 error를 throws하면, 해당 error를 다시 throw한다.

  2. output을 반환한다.

reduceProduct(input, options) 메서드 단계는 다음과 같다:
  1. output을 "reduceProduct", input, options, 및 « "float32", "float16", "int32", "uint32", "int64", "uint64" »가 주어졌을 때 reduction operation을 생성한 결과로 둔다.

    1. 그것이 error를 throws하면, 해당 error를 다시 throw한다.

  2. output을 반환한다.

reduceSum(input, options) 메서드 단계는 다음과 같다:
  1. output을 "reduceSum", input, options, 및 « "float32", "float16", "int32", "uint32", "int64", "uint64" »가 주어졌을 때 reduction operation을 생성한 결과로 둔다.

    1. 그것이 error를 throws하면, 해당 error를 다시 throw한다.

  2. output을 반환한다.

reduceSumSquare(input, options) 메서드 단계는 다음과 같다:
  1. output을 "reduceSumSquare", input, options, 및 « "float32", "float16", "int32", "uint32", "int64", "uint64" »가 주어졌을 때 reduction operation을 생성한 결과로 둔다.

    1. 그것이 error를 throws하면, 해당 error를 다시 throw한다.

  2. output을 반환한다.

여러 reduction operations의 동작은 다음과 같이 다른 연산을 사용하는 방식으로 일반적으로 에뮬레이션할 수 있지만, user agent는 보통 더 효율적인 구현을 가진다. 기반 플랫폼이 어떤 연산을 직접 지원하지 않는 경우, 이 분해는 구현을 안내하는 템플릿으로 사용될 수 있다.
function reduceLogSum(builder, input, options) {
  return builder.log(builder.reduceSum(input, options));
}

function reduceLogSumExp(builder, input, options) {
  return builder.log(builder.reduceSum(builder.exp(input), options));
}

function reduceSumSquare(builder, input, options) {
  return builder.reduceSum(builder.pow(input, 2), options);
}
일부 기반 플랫폼은 keepDimensions와 같은 option을 직접 지원하지 않는다. 이는 기반 tensor data에는 영향을 주지 않고 shape에만 영향을 준다. 예를 들어, input shape가 [2, 3, 4]이고, axis가 1이며, keepDimensions가 true이면, 기대되는 output shape는 [2, 1 ,4]이다. 기반 플랫폼이 reduce된 dimensions를 절대 유지하지 않으면, output shape [2, 4]를 생성한다. 구현은 [2, 1, 4]로 no-op reshape를 도입할 수 있다. keepDimensions가 false이지만 기반 플랫폼이 항상 reduce된 dimensions를 유지하는 경우에도 유사한 no-op reshape를 도입할 수 있다.

8.9.40. relu

input tensor의 rectified linear function을 계산한다.
partial interface MLGraphBuilder {
  MLOperand relu(MLOperand input, optional MLOperatorOptions options = {});
};

partial dictionary MLOpSupportLimits {
  MLSingleInputSupportLimits relu;
};
인수:

반환:

relu()에 대한 tensor 제한
피연산자 허용되는 데이터 타입 허용되는 rank
input "float32", "float16", "int64", "int32", "int8" N
output 같음 input 같음 input

MLOpSupportLimitsrelu()에 대해 다음 멤버를 가진다:

relu, 타입은 MLSingleInputSupportLimits

relu() 오퍼레이터에 대한 지원 제한.

relu(input, options) 메서드 단계는 다음과 같다:
  1. this빌드할 수 없으면, "InvalidStateError" DOMExceptionthrow한다.

  2. 피연산자를 검증한 결과가 thisinput이 주어졌을 때 false를 반환하면, TypeErrorthrow한다.

  3. inputdataType이 (이 표에 따른) 그 허용되는 데이터 타입 중 하나가 아니면, TypeErrorthrow한다.

  4. 그래프 연결 만들기:

    1. outputinput이 주어졌을 때 MLOperand를 copy한 결과로 둔다.

    2. operatoroptions가 주어진 "relu" 연산에 대한 오퍼레이터로 둔다.

    3. output.[[operator]]operator로 설정한다.

    4. operatorinputinput으로 설정한다.

    5. operatoroutputoutput으로 설정한다.

  5. output을 반환한다.

이 연산의 동작은 다음과 같이 다른 연산을 사용하는 방식으로 일반적으로 에뮬레이션할 수 있지만, user agent는 보통 더 효율적인 구현을 가진다. 기반 플랫폼이 어떤 연산을 직접 지원하지 않는 경우, 이 분해는 구현을 안내하는 템플릿으로 사용될 수 있다.
function relu(builder, input) {
  return builder.max(builder.constant(input.dataType, 0), input);
}

8.9.41. resample2d

axes 및 scaling factors에 따라 source dimensions에서 destination dimensions로 tensor 값을 resample한다.
enum MLInterpolationMode {
  "nearest-neighbor",
  "linear"
};

dictionary MLResample2dOptions : MLOperatorOptions {
  MLInterpolationMode mode = "nearest-neighbor";
  sequence<float> scales;
  sequence<[EnforceRange] unsigned long> sizes;
  sequence<[EnforceRange] unsigned long> axes;
};

partial interface MLGraphBuilder {
  MLOperand resample2d(MLOperand input, optional MLResample2dOptions options = {});
};

partial dictionary MLOpSupportLimits {
  MLSingleInputSupportLimits resample2d;
};
인수:

반환: MLOperand. output 4-D tensor.

MLResample2dOptions는 다음 멤버를 가진다:

mode, 타입은 MLInterpolationMode, 기본값은 "nearest-neighbor"

output tensor 값을 채우는 데 사용되는 interpolation 알고리즘.

두 알고리즘은 각 spatial axis에 대해 계산되는 다음 inputs로 시작한다(axes에 기반함). 여기서 inputSizeinput tensor의 shape로 주어지고, outputSizesizes 또는 scales로 주어지며, outputCoordinate는 계산 중인 output tensor의 element를 식별한다.

scale = outputSize / inputSize
unclampedCoordinate = (outputCoordinate + 0.5) / scale - 0.5
inputCoordinate = clamp(unclampedCoordinate, 0, inputSize - 1)
output tensor에서 주어진 outputCoordinate.xoutputCoordinate.y 위치에 대해, 위 식은 rational inputCoordinate.xinputCoordinate.y를 제공한다.
nearest-neighbor

위에서 계산된 inputCoordinate.xinputCoordinate.y는 output tensor 값을 다음과 같이 계산하기 위해 nearest-neighbor sampling 알고리즘의 inputs로 사용된다:

x = ceil(inputCoordinate.x - 0.5)
y = ceil(inputCoordinate.y - 0.5)
output tensor value = input tensor value at (x, y)
linear

위에서 계산된 inputCoordinate.xinputCoordinate.y는 output tensor 값을 다음과 같이 계산하기 위해 bilinear sampling 알고리즘의 inputs로 사용된다:

x0 = floor(inputCoordinate.x)
x1 = ceil(inputCoordinate.x)
y0 = floor(inputCoordinate.y)
y1 = ceil(inputCoordinate.y)
vx0y0 = input tensor value at (x0, y0)
vx1y0 = input tensor value at (x1, y0)
vx0y1 = input tensor value at (x0, y1)
vx1y1 = input tensor value at (x1, y1)
tx = inputCoordinate.x - x0
ty = inputCoordinate.y - y0

vy0 = vx0y0 * (1 - tx) + vx1y0 * tx
vy1 = vx0y1 * (1 - tx) + vx1y1 * tx
output tensor value = vy0 * (1 - ty) + vy1 * ty
scales, 타입은 sequence<float>

길이 2의 list. axes의 각 input dimension에 대한 scaling factor를 지정한다: [scaleForFirstAxis, scaleForSecondAxis]. 기본값은 [1.0, 1.0]이다.

sizes, 타입은 sequence<[EnforceRange] unsigned long>

길이 2의 list. axes의 각 input dimension에 대한 target sizes를 지정한다: [sizeForFirstAxis, sizeForSecondAxis]. sizes가 지정되면, scaling factor 값은 input의 target sizes에서 파생되므로 scales는 무시된다.

axes, 타입은 sequence<[EnforceRange] unsigned long>

길이 2의 list. interpolation 알고리즘이 적용되는 input tensor의 두 dimensions를 지정한다. 기본값은 [2, 3]이다.

resample2d()에 대한 tensor 제한
피연산자 허용되는 데이터 타입 허용되는 rank
input "float32", "float16", "uint8", "int8" 4
output 같음 input 4

MLOpSupportLimitsresample2d()에 대해 다음 멤버를 가진다:

resample2d, 타입은 MLSingleInputSupportLimits

resample2d() 오퍼레이터에 대한 지원 제한.

resample2d(input, options) 메서드 단계는 다음과 같다:
  1. this빌드할 수 없으면, "InvalidStateError" DOMExceptionthrow한다.

  2. 피연산자를 검증한 결과가 thisinput이 주어졌을 때 false를 반환하면, TypeErrorthrow한다.

  3. inputdataType이 (이 표에 따른) 그 허용되는 데이터 타입 중 하나가 아니면, TypeErrorthrow한다.

  4. inputrank가 그 허용되는 rank가 아니면, TypeErrorthrow한다.

  5. options.scales존재하지 않으면, 이를 list « 1.0, 1.0 »로 설정한다.

  6. 그렇지 않고, 그것의 items 중 하나라도 0 이하이거나, 그것의 size가 2가 아니면, TypeErrorthrow한다.

  7. options.sizes존재하고, 그것의 size가 2가 아니거나, 그것의 items 중 하나라도 0이면, TypeErrorthrow한다.

  8. options.axes존재하지 않으면, 이를 list « 2, 3 »로 설정한다.

  9. 그렇지 않고, options.axes가 중복 값을 포함하거나, 그것의 items 중 하나라도 0부터 inputrank까지의 range 안에 있지 않으면, exclusive, TypeErrorthrow한다.

  10. output shape 계산하기:

    1. inputDescriptorinput.[[descriptor]]로 둔다.

    2. outputShapeinputDescriptor.shapeclone으로 둔다.

    3. 0부터 options.axessize까지의 range에 있는 각 index에 대해 For each, exclusive:

      1. options.sizes존재하면, sizeoptions.sizes[index]로 둔다.

      2. 그렇지 않으면, size를 floor(inputshape[options.axes[index]] * options.scales[index])로 둔다.

      3. size유효한 dimension이 아니면, TypeErrorthrow한다.

      4. outputShape[options.axes[index]]를 size로 설정한다.

    4. descinputDescriptor.dataTypeoutputShape가 주어졌을 때 MLOperandDescriptor를 생성한 결과로 둔다.

  11. 그래프 연결 만들기:

    1. outputthisdesc가 주어졌을 때 MLOperand를 생성한 결과로 둔다.

    2. operatoroptions가 주어진 "resample2d" 연산에 대한 오퍼레이터로 둔다.

    3. output.[[operator]]operator로 설정한다.

    4. operatorinputinput으로 설정한다.

    5. operatoroutputoutput으로 설정한다.

  12. output을 반환한다.

구체적인 sampling 알고리즘은 기존 Machine Learning frameworks에서 널리 사용되는 알고리즘에 기반한다. 예를 들어, 다음 [4, 4] input tensor에서 linear resampling을 수행할 때(spatial dimensions만 고려):
[   0   1   2   3  ]
[   0   1   2   3  ]
[  12  13  14  15  ]
[  12  13  14  15  ]

[8, 8] output tensor에 대해, 기대되는 값은 다음과 같다:

[   0   0.25   0.75   1.25   1.75   2.25   2.75   3  ]
[   0   0.25   0.75   1.25   1.75   2.25   2.75   3  ]
[   0   0.25   0.75   1.25   1.75   2.25   2.75   3  ]
[   3   3.25   3.75   4.25   4.75   5.25   5.75   6  ]
[   9   9.25   9.75  10.25  10.75  11.25  11.75  12  ]
[  12  12.25  12.75  13.25  13.75  14.25  14.75  15  ]
[  12  12.25  12.75  13.25  13.75  14.25  14.75  15  ]
[  12  12.25  12.75  13.25  13.75  14.25  14.75  15  ]

이는 sampling이 균등하게 분포되고, 대칭적이며, image mirroring에 견고하고, corner 값이 align된다는 편리한 속성을 가진다.

8.9.42. reshape

tensor의 shape를 새 shape로 변경한다. Reshape는 tensor의 content를 copy하거나 변경하지 않는다. 후속 연산을 위해 tensor의 logical shape만 변경한다.
partial interface MLGraphBuilder {
  MLOperand reshape(MLOperand input,
                    sequence<[EnforceRange] unsigned long> newShape,
                    optional MLOperatorOptions options = {});
};

partial dictionary MLOpSupportLimits {
  MLSingleInputSupportLimits reshape;
};
인수:

반환: MLOperand. output tensor. output tensor의 값은 input tensor의 값과 같다. output tensor의 shape는 newShape로 지정된다.

reshape()에 대한 tensor 제한
피연산자 허용되는 데이터 타입 허용되는 rank
input any N
output 같음 input N

MLOpSupportLimitsreshape()에 대해 다음 멤버를 가진다:

reshape, 타입은 MLSingleInputSupportLimits

reshape() 오퍼레이터에 대한 지원 제한.

reshape(input, newShape, options) 메서드 단계는 다음과 같다:
  1. this빌드할 수 없으면, "InvalidStateError" DOMExceptionthrow한다.

  2. 피연산자를 검증한 결과가 thisinput이 주어졌을 때 false를 반환하면, TypeErrorthrow한다.

  3. newShapesize가 (이 표에 따른) output tensor의 허용되는 ranks가 아니면, TypeErrorthrow한다.

  4. outputShapeunsigned long의 빈 array로 둔다.

  5. newShapesize가 0이면, scalar를 위해 outputShape를 빈 list로 설정한다.

  6. newShape의 어떤 item이라도 유효한 dimension이 아니면, TypeErrorthrow한다.

  7. inputElementCountinputshape에 있는 모든 items의 곱으로 둔다. 빈 dimensions는 inputElementCount 1을 산출한다.

  8. newShape의 모든 값의 곱이 inputElementCount와 같지 않으면, TypeErrorthrow한다.

  9. descinput.[[descriptor]]의 copy로 둔다.

  10. desc.shapenewShape로 설정한다.

  11. 그래프 연결 만들기:

    1. outputthisdesc가 주어졌을 때 MLOperand를 생성한 결과로 둔다.

    2. operatoroptions가 주어진 "reshape" 연산에 대한 오퍼레이터로 둔다.

    3. output.[[operator]]operator로 설정한다.

    4. operatorinputinput으로 설정한다.

    5. operatoroutputoutput으로 설정한다.

  12. output을 반환한다.

8.9.43. reverse

주어진 axes를 따라 tensor를 reverse한다.
dictionary MLReverseOptions : MLOperatorOptions {
  sequence<[EnforceRange] unsigned long> axes;
};

partial interface MLGraphBuilder {
  MLOperand reverse(MLOperand input, optional MLReverseOptions options = {});
};

partial dictionary MLOpSupportLimits {
  MLSingleInputSupportLimits reverse;
};

MLReverseOptions는 다음 멤버를 가진다:

axes, 타입은 sequence<[EnforceRange] unsigned long>

reverse할 input dimensions에 대한 indices. 이 멤버가 존재하지 않으면 모든 dimensions가 reverse되는 것처럼 처리된다. 명시적으로 빈 값으로 전달되면 어떤 dimensions도 reverse되지 않는다.

인수:

반환:

reverse()에 대한 tensor 제한
피연산자 허용되는 데이터 타입 허용되는 rank
input any N
output 같음 input 같음 input

MLOpSupportLimitsreverse()에 대해 다음 멤버를 가진다:

reverse, 타입은 MLSingleInputSupportLimits

reverse() 오퍼레이터에 대한 지원 제한.

reverse(input, options) 메서드 단계는 다음과 같다:
  1. this빌드할 수 없으면, "InvalidStateError" DOMExceptionthrow한다.

  2. 피연산자를 검증한 결과가 thisinput이 주어졌을 때 false를 반환하면, TypeErrorthrow한다.

  3. inputdataType이 (이 표에 따른) 그 허용되는 데이터 타입 중 하나가 아니면, TypeErrorthrow한다.

  4. inputRankinputrank로 둔다.

  5. axes가 주어지지 않았으면, axes를 0부터 inputRank까지의 range로 둔다, exclusive.

  6. 그렇지 않고, axes가 중복 값을 포함하거나, 그것의 elements 중 하나라도 0부터 inputRank까지의 range 안에 있지 않으면, exclusive, failure를 반환한다.

  7. 그래프 연결 만들기:

    1. outputinput이 주어졌을 때 MLOperand를 copy한 결과로 둔다.

    2. operator를 "reverse" 연산 및 options에 대한 오퍼레이터로 둔다.

    3. output.[[operator]]operator로 설정한다.

    4. operatorinputinput으로 설정한다.

    5. operatoroutputoutput으로 설정한다.

  8. output을 반환한다.

8.9.44. scatterElements

indices에 따라 axis를 따라 input tensor의 copy 위에 updates tensor의 값들을 scatter한다.
dictionary MLScatterOptions : MLOperatorOptions {
  [EnforceRange] unsigned long axis = 0;
};

partial interface MLGraphBuilder {
  MLOperand scatterElements(MLOperand input,
                            MLOperand indices,
                            MLOperand updates,
                            optional MLScatterOptions options = {});
};

dictionary MLScatterSupportLimits {
  MLTensorLimits input;
  MLTensorLimits indices;
  MLTensorLimits updates;
  MLTensorLimits output;
};

partial dictionary MLOpSupportLimits {
  MLScatterSupportLimits scatterElements;
};

MLScatterOptions는 다음 멤버를 가진다:

axis, 타입은 unsigned long, 기본값은 0

scattered values가 얻어지는 axis. 그 값은 [0, N-1] 범위 안에 있어야 하며, 여기서 N은 input tensor의 rank이다.

인수:

반환: MLOperand. inputrank와 같은 rank를 가지는 output N-D tensor.

scatterElements()에 대한 tensor 제한
피연산자 허용되는 데이터 타입 허용되는 rank
input any 1부터 N까지
indices "int32", "uint32", "int64" 같음 input
updates 같음 input 같음 input
output 같음 input 같음 input

MLScatterSupportLimits는 다음 멤버를 가진다:

input, 타입은 MLTensorLimits

input 피연산자에 대한 MLTensorLimits.

indices, 타입은 MLTensorLimits

indices 피연산자에 대한 MLTensorLimits.

updates, 타입은 MLTensorLimits

updates 피연산자에 대한 MLTensorLimits.

output, 타입은 MLTensorLimits

output 피연산자에 대한 MLTensorLimits.

MLOpSupportLimitsscatterElements()에 대해 다음 멤버를 가진다:

scatterElements, 타입은 MLScatterSupportLimits

scatterElements() 오퍼레이터에 대한 지원 제한.

indices parameter를 scatterElements()에 대해 graph가 build될 때 허용 범위로 clamp할 수 없다. inputs는 실행 시점까지 알 수 없기 때문이다. 지정된 clamping behavior가 기반 플랫폼에서 제공되지 않는 경우, 구현은 compiled graph에 clamp()를 도입할 수 있다. 마찬가지로, 기반 플랫폼이 negative indices를 지원하지 않는 경우, 구현은 dimension의 끝에서부터의 negative index를 positive index로 변환하기 위해 compiled graph에 operations를 도입할 수 있다.
scatterElements(input, indices, updates, options) 메서드 단계는 다음과 같다:
  1. this빌드할 수 없으면, "InvalidStateError" DOMExceptionthrow한다.

  2. 피연산자를 검증한 결과가 thisinput, indicesupdates 중 어느 하나가 주어졌을 때 false를 반환하면, TypeErrorthrow한다.

  3. indicesdataType이 (이 표에 따른) 그 허용되는 데이터 타입 중 하나가 아니면, TypeErrorthrow한다.

  4. updatesdataTypeinputdataType과 같지 않으면, TypeErrorthrow한다.

  5. input, indices 또는 updates 중 어느 하나의 rank가 그 허용되는 rank가 아니면, TypeErrorthrow한다.

  6. axisoptions.axis로 둔다.

  7. axisinputrank보다 크거나 같으면, TypeErrorthrow한다.

  8. indicesShapeExpectedinputshape의 copy로 둔다.

  9. indicesShapeExpected[axis]를 indicesshape[axis]로 설정한다.

  10. indicesshapeindicesShapeExpected같지 않으면, TypeErrorthrow한다.

  11. updatesshapeindicesshape같지 않으면, TypeErrorthrow한다.

  12. 그래프 연결 만들기:

    1. outputinput이 주어졌을 때 MLOperand를 copy한 결과로 둔다.

    2. operatorinput, indices, updatesoptions가 주어진 "scatterElements" 연산에 대한 오퍼레이터로 둔다.

    3. output.[[operator]]operator로 설정한다.

    4. operatorinputsinput, indices, 및 updates로 설정한다.

    5. operatoroutputoutput으로 설정한다.

  13. output을 반환한다.

서로 다른 slicing schemes에서 scatterElements가 동작하는 방식의 예.
// shape [4,3]의 input:
//   [[ 0,  1,  2],
//    [10, 11, 12],
//    [20, 21, 22],
//    [30, 31, 32]]
// shape [2,3]의 indices:
//   [[3, 1, 1],
//    [2, 0, 3]]
// shape [2,3]의 updates:
//   [[-1, -2, -3],
//    [-4, -5, -6]]
// axis = 0 (기본값)
// shape [4,3]의 output:
//   [[ 0, -5,  2],
//    [10, -2, -3],
//    [-4, 21, 22],
//    [-1, 31, -6]]

const input1 = builder.constant(
  {dataType: 'float32', shape: [4, 3]},
  new Float32Array([0, 1, 2, 10, 11, 12, 20, 21, 22, 30, 31, 32]));

const indices1 = builder.constant(
  {dataType: 'uint32', shape: [2, 3]}, new Uint32Array([3, 1, 1, 2, 0, 3]));

const updates1 = builder.constant(
  {dataType: 'float32', shape: [2, 3]},
  new Uint32Array([-1, -2, -3, -4, -5, -6]));

const output1 = builder.scatterElements(input1, indices1, updates1);

// shape [4,3]의 input:
//   [[ 0,  1,  2],
//    [10, 11, 12],
//    [20, 21, 22],
//    [30, 31, 32]]
// shape [4,1]의 indices:
//   [[2],
//    [1],
//    [0],
//    [2]],
// shape [4,1]의 updates:
//   [[-1],
//    [-2],
//    [-3],
//    [-4]],
// axis = 1
// shape [4,3]의 output:
//   [[ 0,  1, -1],
//    [10, -2, 12],
//    [-3, 21, 22],
//    [30, 31, -4]]

const indices2 = builder.constant(
  {dataType: 'uint32', shape: [4, 1]}, new Uint32Array([2, 1, 0, 2]));

const updates2 = builder.constant(
  {dataType: 'float32', shape: [4, 1]}, new Uint32Array([-1, -2, -3, -4]));

const output2 = builder.scatterElements(input1, indices2, updates2, {axis: 1});

// shape [4,2,2]의 input:
//   [[[  0,   1],
//     [ 10,  11]],
//    [[100, 101],
//     [110, 111]],
//    [[200, 201],
//     [210, 211]],
//    [[300, 301],
//     [310, 311]],]
// shape [1,2,2]의 indices:
//   [[[0, 2],
//     [1, 3]]],
// shape [1,2,2]의 updates:
//   [[[-1, -2],
//     [-3, -4]]],
// axis = 0
// shape [4,2,2]의 output:
//   [[[ -1,   1],
//     [ 10,  11]],
//    [[100, 101],
//     [ -3, 111]],
//    [[200,  -2],
//     [210, 211]],
//    [[300, 301],
//     [310,  -4]],]

const inputData3 = new Float32Array(
  [0, 1, 10, 11, 100, 101, 110, 111, 200, 201, 210, 211, 300, 301, 310, 311]);

const input3 =
  builder.constant({dataType: 'float32', shape: [4, 2, 2]}, inputData3);

const indices3 = builder.constant(
  {dataType: 'uint32', shape: [1, 2, 2]}, new Uint32Array([0, 2, 1, 3]));

const updates3 = builder.constant(
  {dataType: 'float32', shape: [1, 2, 2]}, new Uint32Array([-1, -2, -3, -4]));

const output3 = builder.scatterElements(input3, indices3, updates3, {axis: 0});

8.9.45. scatterND

indices에 따라 input tensor의 copy 위에 update tensor의 값 slice를 scatter한다.
partial interface MLGraphBuilder {
  MLOperand scatterND(MLOperand input,
                      MLOperand indices,
                      MLOperand updates,
                      optional MLOperatorOptions options = {});
};

partial dictionary MLOpSupportLimits {
  MLScatterSupportLimits scatterND;
};
인수:

반환: MLOperand. inputrank + indicesrank - indicesshape[-1] - 1과 같은 rank를 가지는 output N-D tensor.

scatterND()에 대한 tensor 제한
피연산자 허용되는 데이터 타입 허용되는 rank
input any 1부터 N까지
indices "int32", "uint32", "int64" 1부터 N까지
updates 같음 input N
output 같음 input 1부터 N까지

MLOpSupportLimitsscatterND()에 대해 다음 멤버를 가진다:

scatterND, 타입은 MLScatterSupportLimits

scatterND() 오퍼레이터에 대한 지원 제한.

indices parameter를 scatterND()에 대해 graph가 build될 때 허용 범위로 clamp할 수 없다. inputs는 실행 시점까지 알 수 없기 때문이다. 지정된 clamping behavior가 기반 플랫폼에서 제공되지 않는 경우, 구현은 compiled graph에 clamp()를 도입할 수 있다. 마찬가지로, 기반 플랫폼이 negative indices를 지원하지 않는 경우, 구현은 dimension의 끝에서부터의 negative index를 positive index로 변환하기 위해 compiled graph에 operations를 도입할 수 있다.
scatterND(input, indices, updates, options) 메서드 단계는 다음과 같다:
  1. this빌드할 수 없으면, "InvalidStateError" DOMExceptionthrow한다.

  2. 피연산자를 검증한 결과가 thisinput, indicesupdates 중 어느 하나가 주어졌을 때 false를 반환하면, TypeErrorthrow한다.

  3. indicesdataType이 (이 표에 따른) 허용되는 데이터 타입 중 하나가 아니면, TypeErrorthrow한다.

  4. updatesdataTypeinputdataType과 같지 않으면, TypeErrorthrow한다.

  5. input, indices 또는 updates 중 어느 하나의 rank가 그 허용되는 rank가 아니면, TypeErrorthrow한다.

  6. inputShapeinputshape로 두고, inputRankinputrank로 둔다.

  7. indicesShapeindicesshape로 두고, indicesRankindicesrank로 둔다.

  8. indexableSizeindicesRank - 1로 둔다.

  9. coordinateSizeindicesShape[indexableSize]로 둔다.

  10. coordinateSizeinputRank보다 크면, TypeErrorthrow한다.

  11. expectedUpdatesShape를 빈 list로 둔다.

  12. 0부터 indexableSize까지의 range에 있는 각 index에 대해 For each, exclusive:

    1. indicesShape[index]를 expectedUpdatesShapeappend한다.

  13. coordinateSize부터 inputRank까지의 range에 있는 각 index에 대해 For each, exclusive:

    1. inputShape[index]를 expectedUpdatesShapeappend한다.

  14. updatesshapeexpectedUpdatesShape같지 않으면, TypeErrorthrow한다.

  15. outputShapeinputshape의 copy로 둔다.

  16. outputDescinputdataTypeoutputShape가 주어졌을 때 MLOperandDescriptor를 생성한 결과로 둔다.

  17. 그래프 연결 만들기:

    1. outputoutputDesc가 주어졌을 때 MLOperand를 생성한 결과로 둔다.

    2. operatorinput, indices, updatesoptions가 주어진 "scatterND" 연산에 대한 오퍼레이터로 둔다.

    3. output.[[operator]]operator로 설정한다.

    4. operatorinputsinput, indices, 및 updates로 설정한다.

    5. operatoroutputoutput으로 설정한다.

  18. output을 반환한다.

서로 다른 slicing schemes에서 scatterND가 동작하는 방식의 예.
// shape [8]의 input:
//   [0, 1, 2, 3, 4, 5, 6, 7]
// shape [4, 1]의 indices:
//   [[4],
//    [3],
//    [1],
//    [7]]
// shape [4]의 updates:
//   [-1, -2, -3, -4]
// shape [8]의 output:
//   [0, -3, 2, -2, -1, 5, 6, -4]

const input1 = builder.constant(
  {dataType: 'float32', shape: [8]},
  new Float32Array([0, 1, 2, 3, 4, 5, 6, 7]));

const indices1 = builder.constant(
  {dataType: 'uint32', shape: [4, 1]}, new Uint32Array([4, 3, 1, 7]));

const updates1 = builder.constant(
  {dataType: 'uint32', shape: [4]}, new Uint32Array([-1, -2, -3, -4]));

const output1 = builder.scatterND(input1, indices1, updates1);

// shape [2,2]의 input:
//   [[0, 1],
//    [2, 3]]
// shape [2,2]의 indices:
//   [[0, 0],
//    [1, 1]]
// shape [2]의 updates:
//   [-1, -2]
// shape [2,2]의 output:
//   [[-1,  1],   <= -1이 output coordinate [0, 0]에 쓰임
//    [ 2, -2]]   <= -2가 output coordinate [1, 1]에 쓰임

const input2 = builder.constant(
  {dataType: 'float32', shape: [2, 2]}, new Float32Array([0, 1, 2, 3]));

const indices2 = builder.constant(
  {dataType: 'uint32', shape: [2, 2]}, new Uint32Array([0, 0, 1, 1]));

const updates2 =
  builder.constant({dataType: 'uint32', shape: [2]}, new Uint32Array([-1, -2]));

const output2 = builder.scatterND(input2, indices2, updates2);

// shape [3,2]의 input:
//   [[0, 1],
//    [2, 3],
//    [4, 5]]
// shape [2,1]의 indices:
//   [[2],
//    [0]]
// shape [2,2]의 updates:
//   [[-1, -2],
//    [-3, -4]]
// shape [3,2]의 output:
//   [[-3 ,-4],    <= [-3, -4]가 output coordinates [0, *]에 쓰임
//    [ 2,  3],
//    [-1, -2]]    <= [-1, -2]가 output coordinates [2, *]에 쓰임

const input3 = builder.constant(
  {dataType: 'float32', shape: [3, 2]}, new Float32Array([0, 1, 2, 3, 4, 5]));

const indices3 = builder.constant(
  {dataType: 'uint32', shape: [2, 1]}, new Uint32Array([1, 0]));

const updates3 = builder.constant(
  {dataType: 'uint32', shape: [2, 2]}, new Uint32Array([-1, -2, -3, 4]));

const output3 = builder.scatterND(input3, indices3, updates3);

// shape [2,2,2]의 input:
//   [[[0, 1],
//     [2, 3]],
//    [[4, 5],
//     [6, 7]]]
// shape [2,2]의 indices:
//   [[0, 1],
//    [1, 0]]
// shape [2,2]의 updates:
//   [[-1, -2],
//    [-3, -4]]
// shape [2,2,2]의 output:
//   [[[ 0,  1],
//     [-1, -2]],   <= [-1, -2]가 output coordinates [0, 1, *]에 쓰임
//    [[-3, -4],    <= [-3, -4]가 output coordinates [1, 0, *]에 쓰임
//     [ 6,  7]]]

const input4 = builder.constant(
  {dataType: 'float32', shape: [2, 2, 2]},
  new Float32Array([0, 1, 2, 3, 4, 5, 6, 7]));

const indices4 = builder.constant(
  {dataType: 'uint32', shape: [2, 2]}, new Uint32Array([0, 1, 1, 0]));

const updates4 = builder.constant(
  {dataType: 'uint32', shape: [2, 2]}, new Uint32Array([-1, -2, -3, 4]));

const output4 = builder.scatterND(input4, indices4, updates4);

8.9.46. sigmoid

input tensor의 sigmoid function을 계산한다. 계산은 1 / (exp(-x) + 1) 식을 따른다.
partial interface MLGraphBuilder {
  MLOperand sigmoid(MLOperand input, optional MLOperatorOptions options = {});
};

partial dictionary MLOpSupportLimits {
  MLSingleInputSupportLimits sigmoid;
};
인수:

반환:

sigmoid()에 대한 tensor 제한
피연산자 허용되는 데이터 타입 허용되는 rank
input "float32", "float16" N
output 같음 input 같음 input

MLOpSupportLimitssigmoid()에 대해 다음 멤버를 가진다:

sigmoid, 타입은 MLSingleInputSupportLimits

sigmoid() 오퍼레이터에 대한 지원 제한.

sigmoid(input, options) 메서드 단계는 다음과 같다:
  1. this빌드할 수 없으면, "InvalidStateError" DOMExceptionthrow한다.

  2. 피연산자를 검증한 결과가 thisinput이 주어졌을 때 false를 반환하면, TypeErrorthrow한다.

  3. inputdataType이 (이 표에 따른) 그 허용되는 데이터 타입 중 하나가 아니면, TypeErrorthrow한다.

  4. 그래프 연결 만들기:

    1. outputinput이 주어졌을 때 MLOperand를 copy한 결과로 둔다.

    2. operatoroptions가 주어진 "sigmoid" 연산에 대한 오퍼레이터로 둔다.

    3. output.[[operator]]operator로 설정한다.

    4. operatorinputinput으로 설정한다.

    5. operatoroutputoutput으로 설정한다.

  5. output을 반환한다.

이 연산의 동작은 다음과 같이 다른 연산의 사용으로 일반적으로 emulate할 수 있다. 다만 user agents는 보통 더 효율적인 구현을 가진다. 기반 플랫폼이 어떤 연산을 직접 지원하지 않는 경우, 이 decomposition은 구현을 안내하는 template으로 사용될 수 있다.
function sigmoid(builder, input) {
  return builder.div(
    builder.constant(input.dataType, 1),
    builder.add(
      builder.exp(builder.neg(input)), builder.constant(input.dataType, 1)));
}

8.9.47. slice

input tensor의 slice를 생성한다.
dictionary MLSliceOptions : MLOperatorOptions {
  sequence<[EnforceRange] unsigned long> strides;
};

partial interface MLGraphBuilder {
  MLOperand slice(MLOperand input,
                  sequence<[EnforceRange] unsigned long> starts,
                  sequence<[EnforceRange] unsigned long> sizes,
                  optional MLSliceOptions options = {});
};

partial dictionary MLOpSupportLimits {
  MLSingleInputSupportLimits slice;
};

MLSliceOptions는 다음 멤버를 가진다:

strides, 타입은 sequence<[EnforceRange] unsigned long>

각 axis를 따라 각 input을 건너뛰는 stride. strides array의 길이는 input tensor의 rank와 같아야 한다. 기본값은 모두 1로 구성된 길이 rank의 array이다. 예: 3-D tensor의 경우 [1,1,1]. Strides는 0보다 커야 한다.

인수:

반환: MLOperand. input tensor와 같은 rank를 가지며, 각 dimension에서 지정된 starting 및 ending indices로 tensor 값이 잘라진 output tensor.

slice()에 대한 tensor 제한
피연산자 허용되는 데이터 타입 허용되는 rank
input any N
output 같음 input 같음 input

MLOpSupportLimitsslice()에 대해 다음 멤버를 가진다:

slice, 타입은 MLSingleInputSupportLimits

slice() 오퍼레이터에 대한 지원 제한.

slice(input, starts, sizes, options) 메서드 단계는 다음과 같다:
  1. this빌드할 수 없으면, "InvalidStateError" DOMExceptionthrow한다.

  2. 피연산자를 검증한 결과가 thisinput이 주어졌을 때 false를 반환하면, TypeErrorthrow한다.

  3. sizesitems 중 하나라도 0이면, TypeErrorthrow한다.

  4. startssizesizessize가 모두 inputrank와 같지 않으면, TypeErrorthrow한다.

  5. strides를 새 list로 둔다.

  6. options.strides존재하면:

    1. stridesoptions.strides로 설정한다.

    2. stridessizeinputrank와 같지 않으면, TypeErrorthrow한다.

  7. inputShapeinputshape로 두고, inputRankinputrank로 둔다.

  8. outputShape를 새 list로 둔다.

  9. 0부터 inputRank까지의 range에 있는 각 index에 대해 For each, exclusive:

    1. inputSizeinputShape[index]로 둔다.

    2. inputSliceSizesizes[index]로 둔다.

    3. stride를 비어 있지 않으면 strides[index]로, 그렇지 않으면 1로 둔다:

    4. inputSliceSize가 0이면, TypeErrorthrow한다.

      0-size dimensions가 허용된다면, 이 단계들을 수정한다. [Issue #391]

    5. stride가 1보다 작으면, TypeErrorthrow한다.

    6. starts[index]가 inputSize보다 크면, TypeErrorthrow한다.

    7. starts[index] + inputSliceSizeinputSize보다 크면, TypeErrorthrow한다.

    8. outputSizeRoundingExcessinputSliceSize % stride != 0이면 1, 그렇지 않으면 0으로 둔다.

    9. outputSize를 floor(inputSliceSize / stride) + outputSizeRoundingExcess로 둔다:

    10. outputSizeoutputShapeappend한다.

  10. outputDescinputdataTypeoutputShape가 주어졌을 때 MLOperandDescriptor를 생성한 결과로 둔다.

  11. 그래프 연결 만들기:

    1. outputoutputDesc가 주어졌을 때 MLOperand를 생성한 결과로 둔다.

    2. operatorstarts, sizesoptions가 주어진 "slice" 연산에 대한 오퍼레이터로 둔다.

    3. output.[[operator]]operator로 설정한다.

    4. operatorinputinput으로 설정한다.

    5. operatoroutputoutput으로 설정한다.

  12. output을 반환한다.

8.9.48. softmax

주어진 axis를 따라 N-D input tensor의 softmax 값을 계산한다.
partial interface MLGraphBuilder {
  MLOperand softmax(MLOperand input,
                    [EnforceRange] unsigned long axis,
                    optional MLOperatorOptions options = {});
};

partial dictionary MLOpSupportLimits {
  MLSingleInputSupportLimits softmax;
};
인수:

반환:

softmax()에 대한 tensor 제한
피연산자 허용되는 데이터 타입 허용되는 rank
input "float32", "float16" 1부터 N까지
output 같음 input 같음 input

MLOpSupportLimitssoftmax()에 대해 다음 멤버를 가진다:

softmax, 타입은 MLSingleInputSupportLimits

softmax() 오퍼레이터에 대한 지원 제한.

softmax(input, axis, options) 메서드 단계는 다음과 같다:
  1. this빌드할 수 없으면, "InvalidStateError" DOMExceptionthrow한다.

  2. 피연산자를 검증한 결과가 thisinput이 주어졌을 때 false를 반환하면, TypeErrorthrow한다.

  3. inputdataType이 (이 표에 따른) 그 허용되는 데이터 타입 중 하나가 아니면, TypeErrorthrow한다.

  4. axisinputrank보다 크거나 같으면, TypeErrorthrow한다.

  5. 그래프 연결 만들기:

    1. outputinput이 주어졌을 때 MLOperand를 copy한 결과로 둔다.

    2. operatoraxisoptions가 주어진 "softmax" 연산에 대한 오퍼레이터로 둔다.

    3. output.[[operator]]operator로 설정한다.

    4. operatorinputinput으로 설정한다.

    5. operatoroutputoutput으로 설정한다.

  6. output을 반환한다.

이 연산의 동작은 다음과 같이 다른 연산의 사용으로 일반적으로 emulate할 수 있다. 다만 user agents는 보통 더 효율적인 구현을 가진다. 기반 플랫폼이 어떤 연산을 직접 지원하지 않는 경우, 이 decomposition은 구현을 안내하는 template으로 사용될 수 있다.
function softmax(builder, input, axis) {
  // 이 sample은 결과의 numerical stability를 높이기 위해 input 값 자체의 exponentials 대신
  // max 값까지의 거리의 exponentials를 계산하는 잘 알려진 구현 trick [1]을 사용한다.
  // [1]: https://cs231n.github.io/linear-classify/#softmax
  const maxX = builder.reduceMax(input, {axes: [axis], keepDimensions: true});
  const expX = builder.exp(builder.sub(input, maxX));
  return builder.div(
    expX, builder.reduceSum(expX, {axes: [axis], keepDimensions: true}));
}

8.9.49. softplus

input tensor의 softplus function을 계산한다. 계산은 ln(1 + exp(x)) 식을 따른다.
partial interface MLGraphBuilder {
  MLOperand softplus(MLOperand input, optional MLOperatorOptions options = {});
};

partial dictionary MLOpSupportLimits {
  MLSingleInputSupportLimits softplus;
};
인수:

반환:

softplus()에 대한 tensor 제한
피연산자 허용되는 데이터 타입 허용되는 rank
input "float32", "float16" N
output 같음 input 같음 input

MLOpSupportLimitssoftplus()에 대해 다음 멤버를 가진다:

softplus, 타입은 MLSingleInputSupportLimits

softplus() 오퍼레이터에 대한 지원 제한.

softplus(input, options) 메서드 단계는 다음과 같다:
  1. this빌드할 수 없으면, "InvalidStateError" DOMExceptionthrow한다.

  2. 피연산자를 검증한 결과가 thisinput이 주어졌을 때 false를 반환하면, TypeErrorthrow한다.

  3. inputdataType이 (이 표에 따른) 그 허용되는 데이터 타입 중 하나가 아니면, TypeErrorthrow한다.

  4. 그래프 연결 만들기:

    1. outputinput이 주어졌을 때 MLOperand를 copy한 결과로 둔다.

    2. operator를 "softplus" 연산 및 options에 대한 오퍼레이터로 둔다.

    3. output.[[operator]]operator로 설정한다.

    4. operatorinputinput으로 설정한다.

    5. operatoroutputoutput으로 설정한다.

  5. output을 반환한다.

이 연산의 동작은 다음과 같이 다른 연산의 사용으로 일반적으로 emulate할 수 있다. 다만 user agents는 보통 더 효율적인 구현을 가진다. 기반 플랫폼이 어떤 연산을 직접 지원하지 않는 경우, 이 decomposition은 구현을 안내하는 template으로 사용될 수 있다.
function softplus(builder, input) {
  return builder.log(
    builder.add(builder.exp(input), builder.constant(input.dataType, 1)));
}

8.9.50. softsign

input tensor의 softsign function을 계산한다. 계산은 x / (1 + |x|) 식을 따른다.
partial interface MLGraphBuilder {
  MLOperand softsign(MLOperand input, optional MLOperatorOptions options = {});
};

partial dictionary MLOpSupportLimits {
  MLSingleInputSupportLimits softsign;
};
이 연산의 동작은 다음과 같이 다른 연산의 사용으로 일반적으로 emulate할 수 있다. 다만 user agents는 보통 더 효율적인 구현을 가진다. 기반 플랫폼이 어떤 연산을 직접 지원하지 않는 경우, 이 decomposition은 구현을 안내하는 template으로 사용될 수 있다.
function softsign(builder, input) {
  return builder.div(
    input,
    builder.add(builder.constant(input.dataType, 1), builder.abs(input)));
}
인수:

반환:

softsign()에 대한 tensor 제한
피연산자 허용되는 데이터 타입 허용되는 rank
input "float32", "float16" N
output 같음 input 같음 input

MLOpSupportLimitssoftsign()에 대해 다음 멤버를 가진다:

softsign, 타입은 MLSingleInputSupportLimits

softsign() 오퍼레이터에 대한 지원 제한.

softsign(input, options) 메서드 단계는 다음과 같다:
  1. this빌드할 수 없으면, "InvalidStateError" DOMExceptionthrow한다.

  2. 피연산자를 검증한 결과가 thisinput이 주어졌을 때 false를 반환하면, TypeErrorthrow한다.

  3. inputdataType이 (이 표에 따른) 그 허용되는 데이터 타입 중 하나가 아니면, TypeErrorthrow한다.

  4. 그래프 연결 만들기:

    1. outputinput이 주어졌을 때 MLOperand를 복사한 결과로 둔다.

    2. operator를 "softsign" 연산 및 options에 대한 오퍼레이터로 둔다.

    3. output.[[operator]]operator로 설정한다.

    4. operatorinputinput으로 설정한다.

    5. operatoroutputoutput으로 설정한다.

  5. output을 반환한다.

8.9.51. split

주어진 axis를 따라 input tensor를 여러 sub tensors로 분할한다.
dictionary MLSplitOptions : MLOperatorOptions {
  [EnforceRange] unsigned long axis = 0;
};

partial interface MLGraphBuilder {
  sequence<MLOperand> split(
      MLOperand input,
      ([EnforceRange] unsigned long or sequence<[EnforceRange] unsigned long>) splits,
      optional MLSplitOptions options = {});
};

dictionary MLSplitSupportLimits {
  MLTensorLimits input;
  MLTensorLimits outputs;
};

partial dictionary MLOpSupportLimits {
  MLSplitSupportLimits split;
};
인수:

반환: sequence<MLOperand>. 분할된 output tensors. splitsunsigned long이면, output의 sizesplits와 같다. 각 output tensor의 shape는 input과 같지만, axis의 dimension size는 inputaxis를 따른 dimension size를 splits로 나눈 몫과 같다. splitssequence<unsigned long>이면, output의 sizesplitssize와 같다. i번째 output tensor의 shape는 input과 같지만, axis를 따른 dimension size는 splits[i]이다.

MLSplitOptions는 다음 멤버를 가진다:

axis, 타입은 unsigned long, 기본값은 0

분할할 dimension. 그 값은 [0, N-1] 범위 안에 있어야 하며, 여기서 N은 input tensor의 rank이다.

split()에 대한 tensor 제한
피연산자 허용되는 데이터 타입 허용되는 rank
input any 1부터 N까지
outputs 같음 input 같음 input

MLSplitSupportLimits는 다음 멤버를 가진다:

input, 타입은 MLTensorLimits

input 피연산자에 대한 MLTensorLimits.

outputs, 타입은 MLTensorLimits

모든 output 피연산자에 대한 MLTensorLimits.

MLOpSupportLimitssplit()에 대해 다음 멤버를 가진다:

split, 타입은 MLSplitSupportLimits

split() 오퍼레이터에 대한 지원 제한.

split(input, splits, options) 메서드 단계는 다음과 같다:
  1. this빌드할 수 없으면, "InvalidStateError" DOMExceptionthrow한다.

  2. 피연산자를 검증한 결과가 thisinput이 주어졌을 때 false를 반환하면, TypeErrorthrow한다.

  3. axisoptions.axis로 둔다.

  4. axisinputrank보다 크거나 같으면, TypeErrorthrow한다.

  5. splitsunsigned long이면:

    1. splitsvalid tensor count가 아니면, TypeErrorthrow한다.

    2. inputshape[axis] % splits가 0이 아니면, TypeErrorthrow한다.

    3. 그렇지 않으면, splitCountsplits로 둔다.

  6. splitssequence<unsigned long>이면:

    1. splitssizevalid tensor count가 아니면, TypeErrorthrow한다.

    2. items 중 하나라도 0과 같으면, TypeErrorthrow한다.

      0-size dimensions가 허용된다면, 위 단계를 수정한다. [Issue #391]

    3. items의 합이 inputshape[axis]와 같지 않으면, TypeErrorthrow한다.

    4. 그렇지 않으면, splitCountsplitssize로 둔다.

  7. 그래프 연결 만들기:

    1. operatorsplitsoptions가 주어진 "split" 연산에 대한 오퍼레이터로 둔다.

    2. outputs를 새 list로 둔다.

    3. 0부터 splitCount까지의 range에 있는 각 index에 대해 For each, exclusive:

      1. operandinput이 주어졌을 때 MLOperand를 복사한 결과로 둔다.

      2. splitsunsigned long이면, newDimensionoperandshape[axis] / splits로 둔다.

      3. 그렇지 않으면, newDimensionsplits[index]로 둔다.

      4. operandshape[axis]를 newDimension으로 설정한다.

      5. operand.[[operator]]operator로 설정한다.

      6. operandoutputsappend한다.

    4. operatorinputinput으로 설정한다.

    5. operatoroutputsoutputs로 설정한다.

  8. outputs를 반환한다.

이 연산의 동작은 다음과 같이 다른 연산의 사용으로 일반적으로 emulate할 수 있다. 다만 user agents는 보통 더 효율적인 구현을 가진다. 기반 플랫폼이 어떤 연산을 직접 지원하지 않는 경우, 이 decomposition은 구현을 안내하는 template으로 사용될 수 있다.
function split(builder, input, splits, options) {
  // 이 sample은 splits parameter가 array인 경우를 보여준다.
  const outputs = [];
  const inputShape = input.shape;
  const inputRank = inputShape.length;
  let starts = Array(inputRank).fill(0);
  let sizes = inputShape;
  let start = 0;
  for (const size of splits) {
    starts[options.axis] = start;
    sizes[options.axis] = size;
    outputs.push(builder.slice(input, starts, sizes));
    start += size;
  }
  return outputs;
}

8.9.52. tanh

input tensor의 hyperbolic tangent function을 계산한다. 계산은 (exp(2 * x) - 1) / (exp(2 * x) + 1) 식을 따른다.
partial interface MLGraphBuilder {
  MLOperand tanh(MLOperand input, optional MLOperatorOptions options = {});
};

partial dictionary MLOpSupportLimits {
  MLSingleInputSupportLimits tanh;
};
인수:

반환:

tanh()에 대한 tensor 제한
피연산자 허용되는 데이터 타입 허용되는 rank
input "float32", "float16" N
output 같음 input 같음 input

MLOpSupportLimitstanh()에 대해 다음 멤버를 가진다:

tanh, 타입은 MLSingleInputSupportLimits

tanh() 오퍼레이터에 대한 지원 제한.

tanh(input, options) 메서드 단계는 다음과 같다:
  1. this빌드할 수 없으면, "InvalidStateError" DOMExceptionthrow한다.

  2. 피연산자를 검증한 결과가 thisinput이 주어졌을 때 false를 반환하면, TypeErrorthrow한다.

  3. inputdataType이 (이 표에 따른) 그 허용되는 데이터 타입 중 하나가 아니면, TypeErrorthrow한다.

  4. 그래프 연결 만들기:

    1. outputinput이 주어졌을 때 MLOperand를 복사한 결과로 둔다.

    2. operatoroptions가 주어진 "tanh" 연산에 대한 오퍼레이터로 둔다.

    3. output.[[operator]]operator로 설정한다.

    4. operatorinputinput으로 설정한다.

    5. operatoroutputoutput으로 설정한다.

  5. output을 반환한다.

이 연산의 동작은 다음과 같이 다른 연산의 사용으로 일반적으로 emulate할 수 있다. 다만 user agents는 보통 더 효율적인 구현을 가진다. 기반 플랫폼이 어떤 연산을 직접 지원하지 않는 경우, 이 decomposition은 구현을 안내하는 template으로 사용될 수 있다.
function tanh(builder, input) {
  return builder.div(
    builder.sub(
      builder.exp(builder.mul(builder.constant(input.dataType, 2), input)),
      builder.constant(input.dataType, 1)),
    builder.add(
      builder.exp(builder.mul(builder.constant(input.dataType, 2), input)),
      builder.constant(input.dataType, 1)));
}

8.9.53. tile

각 dimension을 따라 주어진 횟수만큼 tensor를 반복한다.
partial interface MLGraphBuilder {
  MLOperand tile(MLOperand input,
                 sequence<unsigned long> repetitions,
                 optional MLOperatorOptions options = {});
};

partial dictionary MLOpSupportLimits {
  MLSingleInputSupportLimits tile;
};
인수:

반환: MLOperand. 반전된 N-D tensor.

tile()에 대한 tensor 제한
피연산자 허용되는 데이터 타입 허용되는 rank
input any N
output 같음 input 같음 input

MLOpSupportLimitstile()에 대해 다음 멤버들을 가진다:

tile, 타입은 MLSingleInputSupportLimits

tile() 오퍼레이터에 대한 지원 제한.

tile(input, repetitions, options) 메서드 단계는 다음과 같다:
  1. this빌드할 수 없으면, "InvalidStateError" DOMExceptionthrow한다.

  2. 피연산자를 검증한 결과가 thisinput이 주어졌을 때 false를 반환하면, TypeErrorthrow한다.

  3. repetitionssizeinputrank와 같지 않으면, TypeErrorthrow한다.

  4. repetitions의 값들에 0이 포함되어 있으면, TypeErrorthrow한다.

    0-size dimensions가 허용된다면, 이 단계들을 수정한다. [Issue #391]

  5. outputShapeinputshape의 copy로 둔다.

  6. 0부터 outputShapesize까지의 range에 있는 각 index에 대해 For each, exclusive:

    1. outputShape[index]를 outputShape[index] * repetitions[index]로 설정한다.

  7. outputDescriptorinputdataTypeoutputShape가 주어졌을 때 MLOperandDescriptor를 생성한 결과로 둔다.

  8. 그래프 연결 만들기:

    1. outputoutputDescriptor가 주어졌을 때 MLOperand를 생성한 결과로 둔다.

    2. operatoroptions가 주어진 "tile" 연산에 대한 오퍼레이터로 둔다.

    3. output.[[operator]]operator로 설정한다.

    4. operatorinputinput으로 설정한다.

    5. operatoroutputoutput으로 설정한다.

  9. output을 반환한다.

8.9.54. transpose

permutation에 따라 input tensor의 dimensions를 permute한다.
dictionary MLTransposeOptions : MLOperatorOptions {
  sequence<[EnforceRange] unsigned long> permutation;
};

partial interface MLGraphBuilder {
  MLOperand transpose(MLOperand input, optional MLTransposeOptions options = {});
};

partial dictionary MLOpSupportLimits {
  MLSingleInputSupportLimits transpose;
};

MLTransposeOptions는 다음 멤버를 가진다:

permutation, 타입은 sequence<[EnforceRange] unsigned long>

output shape를 permute하는 데 사용되는 값들. 기본값은 [N-1, ..., 0]이며, 여기서 N은 input tensor의 rank이다. 예: 3-D tensor의 경우 [2,1,0]. 이러한 기본값은 output이 input의 transposed tensor가 되게 한다. 지정된 경우, 값의 수는 input tensor의 rank와 같아야 하며, 값은 중복 없이 0부터 N-1까지의 범위 안에 있어야 한다.

인수:

반환: MLOperand. permuted 또는 transposed N-D tensor.

transpose()에 대한 tensor 제한
피연산자 허용되는 데이터 타입 허용되는 rank
input any N
output 같음 input 같음 input

MLOpSupportLimitstranspose()에 대해 다음 멤버를 가진다:

transpose, 타입은 MLSingleInputSupportLimits

transpose() 오퍼레이터에 대한 지원 제한.

transpose(input, options) 메서드 단계는 다음과 같다:
  1. this빌드할 수 없으면, "InvalidStateError" DOMExceptionthrow한다.

  2. 피연산자를 검증한 결과가 thisinput이 주어졌을 때 false를 반환하면, TypeErrorthrow한다.

  3. options.permutation존재하지 않으면, options.permutationinputshape에 대한 모든 indices의 reversed sequence로 둔다.

  4. 그렇지 않고, options.permutation존재하면:

    1. sizeinputrank와 같지 않으면, TypeErrorthrow한다.

    2. itemsinputrank exclusive인 0부터 해당 rank까지의 range 안에 있지 않으면, TypeErrorthrow한다.

    3. 중복 값을 포함하면, TypeErrorthrow한다.

  5. 그래프 연결 만들기:

    1. outputinput이 주어졌을 때 MLOperand를 복사한 결과로 둔다.

    2. operatoroptions가 주어진 "transpose" 연산에 대한 오퍼레이터로 둔다.

    3. output.[[operator]]operator로 설정한다.

    4. operatorinputinput으로 설정한다.

    5. operatoroutputoutput으로 설정한다.

  6. output을 반환한다.

8.9.55. triangular

2-D tensor(matrix)가 주어지면, input tensor의 upper 또는 lower triangular part를 포함하는 2-D tensor를 반환한다. input tensor가 2보다 큰 dimensions를 가지면, 이는 matrices의 batch로 취급되며 결과는 같은 shape를 가진다.
dictionary MLTriangularOptions : MLOperatorOptions {
  boolean upper = true;
  [EnforceRange] long diagonal = 0;
};

partial interface MLGraphBuilder {
  MLOperand triangular(MLOperand input, optional MLTriangularOptions options = {});
};

partial dictionary MLOpSupportLimits {
  MLSingleInputSupportLimits triangular;
};

MLTriangularOptions는 다음 멤버를 가진다:

upper, 타입은 boolean, 기본값은 true

input matrix의 upper part 또는 lower part 중 output에 유지되는 부분을 나타낸다. True는 upper part가 유지됨을 나타낸다.

diagonal, 타입은 long, 기본값은 0

input matrix의 main diagonals 위 또는 아래 몇 개의 diagonals가 유지되거나 제외되는지를 지정한다. 값 0은 main diagonals 이외의 diagonals에는 영향이 없음을 의미한다.

인수:

반환: MLOperand. triangular matrix, 또는 input과 같은 shape의 matrices batch를 나타내는 output tensor.

triangular()에 대한 tensor 제한
피연산자 허용되는 데이터 타입 허용되는 rank
input any 2부터 N까지
output 같음 input 같음 input

MLOpSupportLimitstriangular()에 대해 다음 멤버를 가진다:

triangular, 타입은 MLSingleInputSupportLimits

triangular() 오퍼레이터에 대한 지원 제한.

triangular(input, options) 메서드 단계는 다음과 같다:
  1. this빌드할 수 없으면, "InvalidStateError" DOMExceptionthrow한다.

  2. 피연산자를 검증한 결과가 thisinput이 주어졌을 때 false를 반환하면, TypeErrorthrow한다.

  3. inputrank가 (이 표에 따른) 그 허용되는 rank 중 하나가 아니면, TypeErrorthrow한다.

  4. 그래프 연결 만들기:

    1. outputinput이 주어졌을 때 MLOperand를 복사한 결과로 둔다.

    2. operatoroptions가 주어진 "triangular" 연산에 대한 오퍼레이터로 둔다.

    3. output.[[operator]]operator로 설정한다.

    4. operatorinputinput으로 설정한다.

    5. operatoroutputoutput으로 설정한다.

  5. output을 반환한다.

서로 다른 diagonal 설정에서 triangular가 동작하는 방식의 예.
// input:
//   [[7, 1, 2],
//    [9, 4, 8],
//    [2, 6, 3]]
const input = builder.constant(
  {dataType: 'float32', shape: [3, 3]},
  new Float32Array([7, 1, 2, 9, 4, 8, 2, 6, 3]));

// upper triangular matrix:
//   [[7, 1, 2],
//    [0, 4, 8],
//    [0, 0, 3]]
const upper = builder.triangular(input);

// diagonals 한 세트를 추가로 제외한 upper triangular matrix:
//   [[0, 1, 2],
//    [0, 0, 8],
//    [0, 0, 0]]
const upperPositive = builder.triangular(input, {diagonal: 1});

// diagonals 한 세트를 추가로 유지한 upper triangular matrix:
//   [[7, 1, 2],
//    [9, 4, 8],
//    [0, 6, 3]]
const upperNegative = builder.triangular(input, {diagonal: -1});

// lower triangular matrix:
//   [[7, 0, 0],
//    [9, 4, 0],
//    [2, 6, 3]]
const lower = builder.triangular(input, {upper: false});

// diagonals 한 세트를 추가로 유지한 lower triangular matrix:
//   [[7, 1, 0],
//    [9, 4, 8],
//    [2, 6, 3]]
const lowerPositive = builder.triangular(input, {upper: false, diagonal: 1});

// diagonals 한 세트를 추가로 제외한 lower triangular matrix:
//   [[0, 0, 0],
//    [9, 0, 0],
//    [2, 6, 0]]
const lowerNegative = builder.triangular(input, {upper: false, diagonal: -1})

// 두 batch가 있는 lower triangular matrix:
//   [[[7, 0, 0],
//     [9, 4, 0],
//     [2, 6, 3]],
//    [[1, 0, 0],
//     [4, 5, 0],
//     [7, 8, 9]]]
const lowerWithBatches = builder.triangular(input, {upper: false});

8.9.56. where

condition tensor의 대응하는 값에 따라 trueValue 또는 falseValue tensor에서 값을 선택한다. 여기서 non-zero는 true이고 zero는 false이다. condition tensor는 흔히 element-wise logical operations 중 하나의 output이다.

이 연산은 broadcast되며, [numpy-broadcasting-rule]를 따른다. input tensors는 bidirectionally broadcastable이어야 한다. output tensor의 rank는 input tensors의 최대 rank이다. output tensor의 각 dimension에 대해, 그 size는 input tensors의 해당 dimension을 따른 최대 size이다.

partial interface MLGraphBuilder {
  MLOperand where(MLOperand condition,
                  MLOperand trueValue,
                  MLOperand falseValue,
                  optional MLOperatorOptions options = {});
};

dictionary MLWhereSupportLimits {
  MLTensorLimits condition;
  MLTensorLimits trueValue;
  MLTensorLimits falseValue;
  MLTensorLimits output;
};

partial dictionary MLOpSupportLimits {
  MLWhereSupportLimits where;
};
인수:

반환: MLOperand. trueValue 또는 falseValue tensor 중 하나에서 element-wise로 선택된 값들을 포함하는 output tensor.

where()에 대한 tensor 제한
피연산자 허용되는 데이터 타입 허용되는 rank
condition "uint8" N
trueValue any N
falseValue 같음 trueValue N
output 같음 trueValue N

MLWhereSupportLimits는 다음 멤버를 가진다:

condition, 타입은 MLTensorLimits

condition 피연산자에 대한 MLTensorLimits.

trueValue, 타입은 MLTensorLimits

trueValue 피연산자에 대한 MLTensorLimits.

falseValue, 타입은 MLTensorLimits

falseValue 피연산자에 대한 MLTensorLimits.

output, 타입은 MLTensorLimits

output 피연산자에 대한 MLTensorLimits.

MLOpSupportLimitswhere()에 대해 다음 멤버를 가진다:

where, 타입은 MLWhereSupportLimits

where() 오퍼레이터에 대한 지원 제한.

where(condition, trueValue, falseValue, options) 메서드 단계는 다음과 같다:
  1. this빌드할 수 없으면, "InvalidStateError" DOMExceptionthrow한다.

  2. 피연산자를 검증한 결과가 thiscondition, trueValuefalseValue 중 어느 하나가 주어졌을 때 false를 반환하면, TypeErrorthrow한다.

  3. condition, trueValue 또는 falseValue 중 어느 하나의 dataType이 (이 표에 따른) 그 허용되는 데이터 타입 중 하나가 아니면, TypeErrorthrow한다.

  4. outputShapetrueValueshapefalseValueshapebidirectionally broadcasting한 결과로 둔다.

    1. 그것이 failure를 반환하면, TypeErrorthrow한다.

  5. outputShapeconditionshapeoutputShapebidirectionally broadcasting한 결과로 설정한다.

    1. 그것이 failure를 반환하면, TypeErrorthrow한다.

  6. descriptortrueValuedataTypeoutputShape가 주어졌을 때 MLOperandDescriptor를 생성한 결과로 둔다.

  7. 그래프 연결 만들기:

    1. outputthisdescriptor가 주어졌을 때 MLOperand를 생성한 결과로 둔다.

    2. operatorcondition, trueValue, falseValueoptions가 주어진 "where" 연산에 대한 오퍼레이터로 둔다.

    3. output.[[operator]]operator로 설정한다.

    4. operatorinputscondition, trueValuefalseValue로 설정한다.

    5. operatoroutputoutput으로 설정한다.

  8. output을 반환한다.

이 연산의 동작은 다음과 같이 다른 연산의 사용으로 일반적으로 emulate할 수 있다. 다만 user agents는 보통 더 효율적인 구현을 가진다. 기반 플랫폼이 어떤 연산을 직접 지원하지 않는 경우, 이 decomposition은 구현을 안내하는 template으로 사용될 수 있다.
function where(builder, condition, trueValue, falseValue) {
  const c = builder.clamp(condition, {'minValue': 0, 'maxValue': 1});
  builder.add(
    builder.mul(trueValue, builder.cast(c, trueValue.dataType)),
    builder.mul(
      falseValue, builder.cast(builder.logicalNot(c), falseValue.dataType)));
}

9. 알고리즘

9.1. 브로드캐스팅

Broadcasting은 graph 구성과 계산 중 WebNN이 서로 다른 shape를 가진 tensors를 어떻게 다루는지를 설명한다. 이는 [NumPy]의 영향을 크게 받았으며 [numpy-broadcasting-rule]을 따른다. 대략적으로 말해, 이는 더 작은 tensor에 대한 연산을 더 큰 tensor의 shape 전체로 "broadcast"할 수 있게 하여, 같은 data를 copy하지 않고도 반복적으로 적용할 수 있게 한다.

가장 단순한 예는 add() 또는 mul() 같은 element-wise binary operations에서 N-dimension tensor에 scalar constant를 적용하는 것이다. scalar constant의 여러 copy를 포함하는 일치하는 N-dimensional tensor를 allocate하고 채울 필요 없이, 이러한 element-wise operations는 scalar constant를 직접 사용할 수 있게 하고, scalar 값을 N-dimensional tensor 전체에 broadcast한다. 다음 고려 사항과 함께, 같은 logic은 다른 dimensions의 tensors에도 적용된다.

input tensors의 shapes는 compatible해야 한다. 첫 번째 tensor가 마지막(가장 오른쪽) dimension부터 시작해, size가 1인 axis를 따라 첫 번째 tensor를 반복하거나 새 dimensions 전체에 반복함으로써 "stretch"될 수 있으면, tensor는 다른 tensor로 unidirectionally broadcastable하다. 예를 들어, [4] tensor는 5번 반복하여 [5, 4] tensor로 broadcast할 수 있다. [1] tensor는 마지막 dimension에서 4번, 앞선 dimension에서 5번 반복하여 [5,4] tensor로 broadcast할 수 있다. Unidirectional broadcasting은 target tensor shape가 명시적으로 주어지는 expand() 같은 operations에서 중요하다.

두 tensors가 마지막 dimension부터 시작해 여러 dimensions 전체에서 서로 "stretch"(반복)될 수 있으면, 두 tensors는 bidirectionally broadcastable하다. 예를 들어, [5,1] tensor는 마지막 dimension에서 첫 번째 tensor를 6번 반복하고 앞선 dimension에서 두 번째 tensor를 5번 반복하여 [1,6] tensor와 bidirectionally broadcast할 수 있다. 연산의 결과는 [5,6] tensor가 된다. Bidirectional broadcasting은 element-wise operations에 편리하다.

모든 dimensions를 integer multiples로 target tensor의 shape까지 upsample할 수 있으면, tensor는 blockwise broadcastable하다. 예를 들어, [4,5] tensor는 정확한 multiple(16 % 4 = 0, 10 % 5 = 0)이므로 첫 번째 dimension에서 모든 element를 4번, 마지막 dimension에서 모든 element를 2번 반복하여 [16,10] tensor까지 blockwise broadcast할 수 있다(예: 마지막 dimensions의 값 [1,2,3,4,5][1,1,2,2,3,3,4,4,5,5]로 반복된다). 그러나 [4,5] tensor는 두 dimensions 모두 nonzero remainder(9 % 4 = 1, 3 % 5 = 3)를 가지므로 [9,3] tensor와 incompatible하다. Blockwise broadcasting은 더 큰 blocks에서 공통 값을 공유하여 memory를 절약하는 데 유용하다. 두 tensors는 같은 rank를 가져야 하며, output shape는 단순히 더 작은 것이 upsample되는 target tensor의 shape이다.

일부 operations는 특별한 semantics로 broadcasting을 허용한다. 예를 들어, matmul()은 input tensors의 마지막 두 dimensions를 matrices의 rows와 columns로 취급하며, 첫 번째 matrix의 columns 수는 두 번째 matrix의 rows 수와 같아야 한다. matrix multiplication은 추가 dimensions 전체에 bidirectionally broadcast되며, input tensors를 곱할 matrices의 stacks로 취급한다.

shapes shapeFromshapeTounidirectionally broadcast하려면 다음 단계를 수행한다. shapeFromshapeTo는 tensors의 dimensions를 나타내는 positive integers의 lists이고, 이 단계들은 positive integers의 새 list 또는 failure를 반환한다.
  1. sizeFromshapeFromsize로 둔다.

  2. sizeToshapeTosize로 둔다.

  3. sizeFrom > sizeTo이면, failure를 반환한다.

  4. paddedShapeFromshapeFromclone으로 둔다.

  5. paddedShapeFromsizesizeTo보다 작은 동안, paddedShapeFrom에 1을 prepend한다.

  6. outputShape를 새 list로 둔다.

  7. 0부터 sizeTo까지의 range에 있는 각 index에 대해 For each, exclusive:

    1. dimFrompaddedShapeFrom[index]로 둔다.

    2. dimToshapeTo[index]로 둔다.

    3. dimTodimFrom와 같지 않고 dimFrom가 1과 같지 않으면, failure를 반환한다.

    4. dimTooutputShapeAppend한다.

  8. outputShape를 반환한다.

shapeFromshapeTounidirectionally broadcasting한 결과가 failure가 아니면, shapeFromshapeTounidirectionally broadcastable하다.

shapes shapeAshapeBbidirectionally broadcast하려면 다음 단계를 수행한다. shapeAshapeB는 tensors의 dimensions를 나타내는 positive integers의 lists이고, 이 단계들은 positive integers의 새 list 또는 failure를 반환한다.
  1. sizeAshapeAsize로 둔다.

  2. sizeBshapeBsize로 둔다.

  3. outputSizesizeAsizeB의 maximum으로 둔다.

  4. paddedAshapeAclone으로 둔다.

  5. paddedAsizeoutputSize보다 작은 동안, paddedA에 1을 prepend한다.

  6. paddedBshapeBclone으로 둔다.

  7. paddedBsizeoutputSize보다 작은 동안, paddedB에 1을 prepend한다.

  8. outputShape를 새 list로 둔다.

  9. 0부터 outputSize까지의 range에 있는 각 index에 대해 For each, exclusive:

    1. dimApaddedA[index]로 둔다.

    2. dimBpaddedB[index]로 둔다.

    3. dimAdimB와 같지 않고, dimA가 1과 같지 않고, dimB가 1과 같지 않으면, failure를 반환한다.

    4. dimAdimB의 maximum을 outputShapeAppend한다.

  10. outputShape를 반환한다.

shapeAshapeBbidirectionally broadcasting한 결과가 failure가 아니면, shapeAshapeBbidirectionally broadcastable하다.

shapes shapeFromshapeToblockwise broadcast하려면 다음 단계를 수행한다. shapeFromshapeTo는 tensors의 dimensions를 나타내는 positive integers의 lists이고, 이 단계들은 true 또는 false를 반환한다.
  1. shapeFromsizeshapeTosize와 같지 않으면, false를 반환한다.

  2. 0부터 shapeTosize까지의 range에 있는 각 index에 대해 For each, exclusive:

    1. shapeFrom[index]가 shapeTo[index]로 exactly divisible하지 않으면, false를 반환한다.

  3. true를 반환한다.

shapeFromshapeToblockwise broadcasting한 결과가 true를 반환하면, shapeFromshapeToblockwise broadcastable하다.

9.2. 캐스팅

명시적 numeric casting은 MLNumber 또는 double로 전달된 parameters가 input 또는 output MLOperands의 MLOperandDataType에 맞게 변환되어야 하는 algorithms에서 사용된다.

number x를 주어진 MLOperandDataType dataType으로 cast하려면, 다음 단계를 수행한다. 이 단계들은 number를 반환한다.
  1. dataType에 대해 switch한다:

    "float32"

    ConvertToFloat(x, 32)를 반환한다.

    "float16"

    ConvertToFloat(x, 16)을 반환한다.

    "int64"

    ConvertToInt(x, 64, "signed")를 반환한다.

    "uint64"

    ConvertToInt(x, 64, "unsigned")를 반환한다.

    "int32"

    ConvertToInt(x, 32, "signed")를 반환한다.

    "uint32"

    ConvertToInt(x, 32, "signed")를 반환한다.

    "int8"

    ConvertToInt(x, 8, "signed")를 반환한다.

    "uint8"

    ConvertToInt(x, 8, "unsigned")를 반환한다.

참고: cast의 input은 special values Infinity, -Infinity 및 NaN을 포함해 range와 precision이 unlimited인 abstract number이다. output도 abstract number이지만, 지정된 type으로 정확히 representable하다.

ConvertToFloat(x, bitLength) 단계는 다음과 같다:
  1. x가 NaN이면, NaN을 반환한다.

  2. bitLength에 대해 switch한다:

    32
    1. upperBound를 2128로 둔다.

    2. lowerBound를 -2128로 둔다.

    3. S를 -0을 제외하되 special values upperBoundlowerBound가 추가된 [IEEE-754-2019] binary32 floating point values의 set으로 둔다.

    16
    1. upperBound를 216으로 둔다.

    2. lowerBound를 -216으로 둔다.

    3. S를 -0을 제외하되 special values upperBoundlowerBound가 추가된 [IEEE-754-2019] binary16 floating point values의 set으로 둔다.

  3. yx에 가장 가까운 S의 number로 둔다. 두 개의 equally close values가 있으면 even significand를 가진 number를 선택한다. 두 special values lowerBoundupperBound는 이 목적상 even significands를 가진 것으로 간주한다.

  4. yupperBound이면, +Infinity를 반환한다.

  5. ylowerBound이면, -Infinity를 반환한다.

  6. y가 +0이고 x가 negative이면, -0을 반환한다.

  7. y를 반환한다.

참고: 이는 [WEBIDL]의 정의를 기반으로 하지만, 16-bit floating point values를 다루도록 확장되었다.

ConvertToInt(x, bitLength, signedness) 단계는 다음과 같다:
  1. signedness가 "unsigned"이면:

    1. lowerBound를 0으로 둔다.

    2. upperBound를 2bitLength - 1로 둔다.

  2. 그렇지 않으면:

    1. lowerBound를 -(2bitLength - 1)로 둔다.

    2. upperBound를 2bitLength - 1 - 1로 둔다.

  3. x가 -0이면, x를 +0으로 설정한다.

  4. x가 NaN이면, +0을 반환한다.

  5. x를 min(max(x, lowerBound), upperBound)로 설정한다.

  6. x를 가장 가까운 integer로 round하되, 두 integer 사이의 halfway에 있으면 even integer를 선택하고, -0보다 +0을 선택한다.

  7. x를 반환한다.

참고: 이는 [WEBIDL]의 정의를 기반으로 하며 다음 차이가 있다: 64-bit integers는 특별하게 취급되지 않고, input x는 abstract number이며, clamping은 항상 수행된다.

9.3. 기타

list AAsizeBsize와 같고, A의 각 itemB에서 같은 index에 있는 item과 같으면, list Bequal하다.

[INFRA]에 definition이 제공되면 이를 제거한다. [whatwg/infra Issue #664]

10.

다음 build graph가 주어졌다고 하자:
constant1 ---+
             +--- Add ---> intermediateOutput1 ---+
input1    ---+                                    |
                                                  +--- Mul---> output
constant2 ---+                                    |
             +--- Add ---> intermediateOutput2 ---+
input2    ---+
다음 code는 graph를 구현한다:
// 4 dimensions의 tensors를 사용한다.
const TENSOR_SHAPE = [1, 2, 2, 2];
const TENSOR_SIZE = 8;

const context = await navigator.ml.createContext();
const builder = new MLGraphBuilder(context);

// MLOperandDescriptor object를 생성한다.
const desc = {
  dataType: 'float32',
  shape: TENSOR_SHAPE
};

// constant1은 값 0.5를 가진 constant MLOperand이다.
const constantBuffer1 = new Float32Array(TENSOR_SIZE).fill(0.5);
const constant1 = builder.constant(desc, constantBuffer1);

// input1은 input MLOperands 중 하나이다. 그 값은 execution 전에 설정된다.
const input1 = builder.input('input1', desc);

// constant2는 값 0.5를 가진 또 다른 constant MLOperand이다.
const constantBuffer2 = new Float32Array(TENSOR_SIZE).fill(0.5);
const constant2 = builder.constant(desc, constantBuffer2);

// input2는 또 다른 input MLOperand이다. 그 값은 execution 전에 설정된다.
const input2 = builder.input('input2', desc);

// intermediateOutput1은 첫 번째 Add operation의 output이다.
const intermediateOutput1 = builder.add(constant1, input1);

// intermediateOutput2는 두 번째 Add operation의 output이다.
const intermediateOutput2 = builder.add(constant2, input2);

// output은 Mul operation의 output MLOperand이다.
const output = builder.mul(intermediateOutput1, intermediateOutput2);

11. 오퍼레이터 에뮬레이션

이 섹션은 비규범적이다.

다른 neural network inference APIs에 존재하는 operations는 WebNN에 존재하는 operations를 사용해 emulated할 수 있는 경우가 많다.

11.1. squeeze

squeeze operation은 size 1인 input의 모든 지정된 dimensions가 제거된 tensor를 반환한다. 이는 다음과 같이 reshape() operation을 사용해 일반적으로 구현할 수 있다:
function squeeze(builder, input, axes) {
  if (!axes)
    axes = [];
  if (!axes.length)
    input.shape.forEach((item, i) => {
      axes.push(i);
    });
  const shape = Array.from(input.shape);
  for (let axis of axes.sort().reverse())
    if (axis < shape.length && shape[axis] == 1)
      shape.splice(axis, 1);
  return builder.reshape(input, shape);
}

11.2. unsqueeze

unsqueeze operation은 지정된 위치에 size one의 dimension이 삽입된 새 tensor를 반환한다. 이는 다음과 같이 reshape() operation을 사용해 일반적으로 구현할 수 있다:
function unsqueeze(builder, input, axes) {
  const shape = Array.from(input.shape);
  for (let axis of axes.sort())
    shape.splice(axis, 0, 1);
  return builder.reshape(input, shape);
}

11.3. flatten

flatten operation은 input을 one-dimensional tensor로 reshape한다. 이는 다음과 같이 reshape() operation을 사용해 일반적으로 구현할 수 있다:
function flatten(builder, input, axis) {
  if (axis > input.shape.length)
    return input;
  const before = axis.slice(0, axis).reduce((a, b) => a * b, 1);
  const after = axis.slice(axis, input.shape.length).reduce((a, b) => a * b, 1);
  return builder.reshape(input, [before, after]);
}

12. 부록

12.1. MLOperandDataTypeArrayBufferView compatibility

MLOperandDataType ArrayBufferView
float32 Float32Array
float16 Float16Array
int64 BigInt64Array
uint64 BigUint64Array
int32 Int32Array
uint32 Uint32Array
int8 Int8Array
uint8 Uint8Array

Float16Array는 설계가 완료되었음을 나타내는 ECMA Stage 3에 있다. native implementations에 앞서 이 type을 enable하려는 implementers는 Uint16Array를 통해 raw bits를 전달함으로써 이 type을 emulate할 수 있다. [Issue webnn#373]

13. 감사의 말

이 명세는 Android Neural Networks API C API의 concept들을 따른다.

use cases에 대해 Tomoyuki Shimizu, Ningxin Hu, Zhiqiang Yu 및 Belem Zhang에게 감사한다.

API 명세에 기여해 준 Nikhil Thorat, Daniel Smilkov, Ganesan Ramalingam, Rafael Cintron 및 Benjamin Poulain에게 감사한다.

web architecture fit, design consistency 및 developer ergonomics에 대해 이 명세를 검토해 준 Sangwhan Moon 및 W3C Technical Architecture Group에게 감사한다.

algorithms를 추가하고 이 명세를 탐색하기 즐거운 경험으로 만들어 준 Zoltan Kis에게 감사한다. 명세를 modern editorial conventions에 맞춰 준 Joshua Bell에게 감사한다. 세심한 review와 comments에 대해 Ningxin Hu, Lisha Guo, Shiyi Zou, Mingming Xu, Junwei Fu, Bruce Dai 및 Bin Miao에게 감사한다.

privacy and security review 및 feedback에 대해 W3C Privacy Interest Group에게 감사한다.

security review 및 questions에 대해 Alex Gough 및 Chrome Security team에게 감사한다.

ONNX로부터의 practical guidelines 및 learnings를 공유해 준 Michal Karzynski에게 감사한다.

feedback 및 privacy considerations에 대해 Kaustubha Govind 및 Chrome privacy reviewers에게 감사한다.

Chromium implementation review 및 feedback에 대해 Jiewei Qian에게 감사한다.

transformer support에 대한 recommendation을 조사하고 제공한 작업에 대해 Dwayne Robinson, Joshua Lochner 및 Wanming Lin에게 감사한다. operator conformance 및 web-platform-tests implementation의 reviews를 제공해 준 Dwayne과 Wanming에게도 추가로 감사한다.

web-platform-tests가 명세와 함께 발전하도록 계속 기여해 준 Feng Dai에게 감사한다.

reviews 및 suggestions에 대해 Fuqiao Xue 및 W3C Internationalization Activity에게 감사한다.

14. 변경 사항

이 섹션은 비규범적이다.

이 섹션은 이 명세의 이전 major publication 이후의 변경 사항을 Classes of Changes 관점에서 문서화한다.

Candidate Recommendation Snapshot 2024년 4월 11일2026년 1월 22일 사이의 상세 변경 사항

새 기능(class 4)

새 기능을 추가하지 않는 기타 변경 사항(class 3)

문서 해석에 기능적으로 영향을 주지 않는 변경 사항(class 2)

Horizontal(class 2class 3)

Editorial(class 2)

적합성

문서 규약

적합성 요구사항은 설명적 assertion과 RFC 2119 terminology의 조합으로 표현된다. 이 문서의 규범적 부분에 있는 key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, 및 “OPTIONAL”은 RFC 2119에서 설명한 대로 해석되어야 한다. 다만, 가독성을 위해 이 명세에서는 이러한 단어들이 모두 대문자로 나타나지는 않는다.

명시적으로 비규범적이라고 표시된 섹션, 예 및 참고를 제외하고 이 명세의 모든 텍스트는 규범적이다. [RFC2119]

이 명세의 예는 “for example”이라는 단어로 도입되거나, 다음과 같이 class="example"을 사용하여 규범적 텍스트와 구분된다:

이는 informative example의 예이다.

Informative notes는 “Note”라는 단어로 시작하며, 다음과 같이 class="note"를 사용하여 규범적 텍스트와 구분된다:

참고, 이는 informative note이다.

적합한 알고리즘

알고리즘의 일부로 명령형으로 표현된 요구사항 (예: "strip any leading space characters" 또는 "return false and abort these steps")은 알고리즘을 도입할 때 사용된 key word ("must", "should", "may" 등)의 의미로 해석되어야 한다.

알고리즘 또는 특정 단계로 표현된 적합성 요구사항은 최종 결과가 equivalent한 한, 어떤 방식으로든 구현될 수 있다. 특히, 이 명세에서 정의된 알고리즘은 이해하기 쉽도록 의도된 것이며 performant하도록 의도된 것은 아니다. Implementers는 최적화가 권장된다.

인덱스

이 명세에서 정의한 용어

참조에서 정의한 용어

참조

규범적 참조

[ECMASCRIPT]
ECMAScript Language Specification. URL: https://tc39.es/ecma262/multipage/
[HTML]
Anne van Kesteren; et al. HTML Standard. Living Standard. URL: https://html.spec.whatwg.org/multipage/
[INFRA]
Anne van Kesteren; Domenic Denicola. Infra Standard. Living Standard. URL: https://infra.spec.whatwg.org/
[NUMPY-BROADCASTING-RULE]
The SciPy community. General Broadcasting Rules of NumPy. 2019년 7월. URL: https://numpy.org/doc/stable/user/basics.broadcasting.html#general-broadcasting-rules
[PERMISSIONS-POLICY-1]
Ian Clelland. Permissions Policy. 2025년 10월 6일. WD. URL: https://www.w3.org/TR/permissions-policy-1/
[RFC2119]
S. Bradner. Key words for use in RFCs to Indicate Requirement Levels. 1997년 3월. Best Current Practice. URL: https://datatracker.ietf.org/doc/html/rfc2119
[WEBGPU]
Kai Ninomiya; Brandon Jones; Jim Blandy. WebGPU. 2026년 5월 12일. CRD. URL: https://www.w3.org/TR/webgpu/
[WEBIDL]
Edgar Chen; Timothy Gu. Web IDL Standard. Living Standard. URL: https://webidl.spec.whatwg.org/

비규범적 참조

[Batch-Normalization]
Sergey Ioffe; Christian Szegedy. Batch Normalization: Accelerating Deep Network Training by Reducing Internal Covariate Shift. 2015년 3월. URL: https://arxiv.org/abs/1502.03167
[ContextualLoss]
Roey Mechrez; Itamar Talmi; Lihi Zelnik-Manor. The Contextual Loss for Image Transformation with Non-Aligned Data. 2018년 7월. URL: https://arxiv.org/abs/1803.02077
[DeepLabv3+]
Liang-Chieh Chen; et al. Encoder-Decoder with Atrous Separable Convolution for Semantic Image Segmentation. 2018년 8월. URL: https://arxiv.org/abs/1802.02611
[DeepMoji]
Bjarke Felbo; et al. Using millions of emoji occurrences to learn any-domain representations for detecting sentiment, emotion and sarcasm. 2017년 10월. URL: https://arxiv.org/abs/1708.00524
[ELU]
Djork-Arné Clevert; Thomas Unterthiner; Sepp Hochreiter. Fast and Accurate Deep Network Learning by Exponential Linear Units (ELUs). 2016년 2월. URL: https://arxiv.org/abs/1511.07289
[Error-Function]
Larry C. Andrews. Special functions of mathematics for engineers. 1998. URL: https://books.google.com/books?id=2CAqsF-RebgC&pg=PA110
[FaceForensics++]
Andreas Rössler; et al. FaceForensics++. 2019년 1월. URL: https://github.com/ondyari/FaceForensics
[FaceNet]
Florian Schroff; Dmitry Kalenichenko; James Philbin. FaceNet: A Unified Embedding for Face Recognition and Clustering. 2015년 6월. URL: https://arxiv.org/abs/1503.03832
[FAN]
Adrian Bulat; Georgios Tzimiropoulos. How far are we from solving the 2D & 3D Face Alignment problem? (and a dataset of 230,000 3D facial landmarks). 2017년 9월. URL: https://arxiv.org/abs/1703.07332
[GNMT]
Minh-Thang Luong; Eugene Brevdo; Rui Zhao. Neural Machine Translation (seq2seq) Tutorial. 2017년 5월. URL: https://github.com/tensorflow/nmt
[GPT2]
Alec Radford; et al. Language Models are Unsupervised Multitask Learners. 2019년 2월. URL: https://d4mucfpksywv.cloudfront.net/better-language-models/language-models.pdf
[GRU]
Kyunghyun Cho; et al. Learning Phrase Representations using RNN Encoder–Decoder for Statistical Machine Translation. 2014년 9월. URL: https://arxiv.org/pdf/1406.1078.pdf
[HR-TIME-3]
Yoav Weiss. High Resolution Time. 2026년 3월 24일. WD. URL: https://www.w3.org/TR/hr-time-3/
[IEEE-754-2019]
IEEE Standard for Floating-Point Arithmetic. 2019년 7월 22일. URL: https://ieeexplore.ieee.org/document/8766229
[IM2TXT]
Oriol Vinyals; et al. Show and Tell: Lessons learned from the 2015 MSCOCO Image Captioning Challenge. 2016년 9월. URL: https://arxiv.org/abs/1609.06647
[Instance-Normalization]
Dmitry Ulyanov; Andrea Vedaldi; Victor Lempitsky. Instance Normalization: The Missing Ingredient for Fast Stylization. 2016년 7월. URL: https://arxiv.org/abs/1607.08022
[Layer-Normalization]
Jimmy Lei Ba; Jamie Ryan Kiros; Geoffrey E. Hinton. Layer Normalization. 2016년 7월. URL: https://arxiv.org/abs/1607.06450
[LDM]
Robin Rombach; et al. High-Resolution Image Synthesis with Latent Diffusion Models. 2022년 4월. URL: https://arxiv.org/abs/2112.10752
[LeakyReLU]
Andrew L. Maas; Awni Y. Hannun; Andrew Y. Ng. Rectifier Nonlinearities Improve Neural Network Acoustic Models. 2013년 6월. URL: https://pdfs.semanticscholar.org/367f/2c63a6f6a10b3b64b8729d601e69337ee3cc.pdf
[LLAMA-2-7B]
Hugo Touvron; et al. Llama 2: Open Foundation and Fine-Tuned Chat Models. 2023년 7월. URL: https://arxiv.org/abs/2307.09288
[LSTM]
Sepp Hochreiter; Jürgen Schmidhuber. Long Short-Term Memory. 1997년 11월. URL: https://doi.org/10.1162/neco.1997.9.8.1735
[m2m100_418M]
Angela Fan; et al. Beyond English-Centric Multilingual Machine Translation. 2020년 10월. URL: https://arxiv.org/abs/2010.11125
[MaskR-CNN]
Kaiming He; et al. Mask R-CNN. 2018년 1월. URL: https://arxiv.org/abs/1703.06870
[MobileNetV3]
Andrew Howard; et al. Searching for MobileNetV3. 2019년 11월. URL: https://arxiv.org/pdf/1905.02244
[MODELS]
Machine Learning for the Web Community Group. The first-wave models. 2020. URL: https://github.com/webmachinelearning/webnn/blob/master/op_compatibility/first_wave_models.md
[NumPy]
The SciPy community. NumPy. 2019년 7월. URL: https://numpy.org/doc/stable/
[OpenNMT]
Guillaume Klein; et al. OpenNMT: Open-Source Toolkit for Neural Machine Translation. 2017년 3월. URL: https://arxiv.org/abs/1701.02810
[PairedCycleGAN]
Huiwen Chang; et al. PairedCycleGAN: Asymmetric Style Transfer for Applying and Removing Makeup. 2018년 6월. URL: http://openaccess.thecvf.com/content_cvpr_2018/html/Chang_PairedCycleGAN_Asymmetric_Style_CVPR_2018_paper.html
[PoseNet]
Dan Oved. Real-time Human Pose Estimation in the Browser with TensorFlow.js. 2018년 5월. URL: https://medium.com/tensorflow/real-time-human-pose-estimation-in-the-browser-with-tensorflow-js-7dd0bc881cd5
[POWERFUL-FEATURES]
Mike West. Secure Contexts. 2023년 11월 10일. CRD. URL: https://www.w3.org/TR/secure-contexts/
[Prefix-sum]
The Wikipedia community. Prefix Sum. 2025년 1월. URL: https://en.wikipedia.org/wiki/Prefix_sum
[RNNoise]
Jean-Marc Valin. Recurrent neural network for audio noise reduction. 2017년 9월. URL: https://github.com/xiph/rnnoise
[SECURITY-PRIVACY-QUESTIONNAIRE]
Theresa O'Connor; Peter Snyder; Simone Onofri. Self-Review Questionnaire: Security and Privacy. 2025년 4월 18일. NOTE. URL: https://www.w3.org/TR/security-privacy-questionnaire/
[SegAny]
Alexander Kirillov; et al. Segment Anything. 2023년 4월. URL: https://arxiv.org/abs/2304.02643
[SRGAN]
Christian Ledig; et al. Photo-Realistic Single Image Super-Resolution Using a Generative Adversarial Network. 2017년 5월. URL: https://arxiv.org/abs/1609.04802
[SSD]
Wei Liu; et al. SSD: Single Shot MultiBox Detector. 2016년 12월. URL: https://arxiv.org/abs/1512.02325
[T5-SMALL]
Colin Raffel; et al. Exploring the Limits of Transfer Learning with a Unified Text-to-Text Transformer. 2020년 6월. URL: https://jmlr.org/papers/volume21/20-074/20-074.pdf
[UTR36]
Mark Davis; Michel Suignard. Unicode Security Considerations. 2014년 9월 19일. Unicode Technical Report #36. URL: https://www.unicode.org/reports/tr36/tr36-15.html
[UTS55]
Robin Leroy; Mark Davis. Unicode Source Code Handling. 2024년 1월 29일. Unicode Technical Standard #55. URL: https://www.unicode.org/reports/tr55/tr55-5.html
[Video-Summarization-with-LSTM]
Ke Zhang; et al. Video summarization with long short-term memory. 2016년 10월. URL: http://www-scf.usc.edu/~zhan355/ke_eccv2016.pdf
[WASM-JS-API-2]
. Ms2ger; Ryan Hunt. WebAssembly JavaScript Interface. 2026년 5월 14일. CRD. URL: https://www.w3.org/TR/wasm-js-api-2/
[WCAG]
Michael Cooper; et al. Web Content Accessibility Guidelines (WCAG) 2.2. 2024년 12월 12일. REC. URL: https://www.w3.org/TR/WCAG22/
[WEBMACHINELEARNING-ETHICS]
Anssi Kostiainen. Ethical Principles for Web Machine Learning. 2024년 1월 8일. DNOTE. URL: https://www.w3.org/TR/webmachinelearning-ethics/
[Whisper]
Alec Radford; et al. Robust Speech Recognition via Large-Scale Weak Supervision. 2022년 12월. URL: https://arxiv.org/abs/2212.04356
[YOLO]
Joseph Redmon; et al. You Only Look Once: Unified, Real-Time Object Detection. 2016년 5월. URL: https://arxiv.org/abs/1506.02640

IDL 인덱스

interface mixin NavigatorML {
  [SecureContext, SameObject] readonly attribute ML ml;
};
Navigator includes NavigatorML;
WorkerNavigator includes NavigatorML;

enum MLPowerPreference {
  "default",
  "high-performance",
  "low-power"
};

dictionary MLContextOptions {
  MLPowerPreference powerPreference = "default";
  boolean accelerated = true;
};

[SecureContext, Exposed=(Window, Worker)]
interface ML {
  Promise<MLContext> createContext(optional MLContextOptions options = {});
  Promise<MLContext> createContext(GPUDevice gpuDevice);
};

typedef record<USVString, MLTensor> MLNamedTensors;

dictionary MLContextLostInfo {
  DOMString message;
};

[SecureContext, Exposed=(Window, Worker)]
interface MLContext {
  undefined dispatch(MLGraph graph, MLNamedTensors inputs, MLNamedTensors outputs);

  Promise<MLTensor> createTensor(MLTensorDescriptor descriptor);
  Promise<MLTensor> createConstantTensor(
    MLOperandDescriptor descriptor, AllowSharedBufferSource inputData);

  Promise<ArrayBuffer> readTensor(MLTensor tensor);
  Promise<undefined> readTensor(MLTensor tensor, AllowSharedBufferSource outputData);

  undefined writeTensor(MLTensor tensor, AllowSharedBufferSource inputData);

  MLOpSupportLimits opSupportLimits();

  undefined destroy();

  readonly attribute boolean accelerated;
  readonly attribute Promise<MLContextLostInfo> lost;
};

dictionary MLOpSupportLimits {
  MLInputOperandLayout preferredInputLayout;
  [EnforceRange] unsigned long long maxTensorByteLength;
  MLTensorLimits input;
  MLTensorLimits constant;
  MLTensorLimits output;
};

dictionary MLRankRange {
  unsigned long min;
  unsigned long max;
};

typedef sequence<MLOperandDataType> MLDataTypeList;

dictionary MLTensorLimits {
  MLDataTypeList dataTypes;
  MLRankRange rankRange;
};

dictionary MLBinarySupportLimits {
  MLTensorLimits a;
  MLTensorLimits b;
  MLTensorLimits output;
};

dictionary MLSingleInputSupportLimits {
  MLTensorLimits input;
  MLTensorLimits output;
};

[SecureContext, Exposed=(Window, Worker)]
interface MLGraph {
  undefined destroy();
};

enum MLInputOperandLayout {
  "nchw",
  "nhwc"
};

enum MLOperandDataType {
  "float32",
  "float16",
  "int32",
  "uint32",
  "int64",
  "uint64",
  "int8",
  "uint8"
};

dictionary MLOperandDescriptor {
  required MLOperandDataType dataType;
  required sequence<[EnforceRange] unsigned long> shape;
};

[SecureContext, Exposed=(Window, Worker)]
interface MLOperand {
  readonly attribute MLOperandDataType dataType;
  readonly attribute FrozenArray<unsigned long> shape;
};

dictionary MLOperatorOptions {
  USVString label = "";
};

typedef (bigint or unrestricted double) MLNumber;

dictionary MLTensorDescriptor : MLOperandDescriptor {
  boolean readable = false;
  boolean writable = false;
};

[SecureContext, Exposed=(Window, Worker)]
interface MLTensor {
  readonly attribute MLOperandDataType dataType;
  readonly attribute FrozenArray<unsigned long> shape;
  readonly attribute boolean readable;
  readonly attribute boolean writable;
  readonly attribute boolean constant;

  undefined destroy();
};

typedef record<USVString, MLOperand> MLNamedOperands;

[SecureContext, Exposed=(Window, Worker)]
interface MLGraphBuilder {
  // Construct the graph builder from the context.
  constructor(MLContext context);

  // Create an operand for a graph input.
  MLOperand input(USVString name, MLOperandDescriptor descriptor);

  // Create an operand for a graph constant.
  MLOperand constant(MLOperandDescriptor descriptor,
                     AllowSharedBufferSource buffer);

  // Create a scalar operand from the specified number of the specified type.
  MLOperand constant(MLOperandDataType dataType, MLNumber value);

  // Create an operand from a specified constant tensor.
  MLOperand constant(MLTensor tensor);

  // Compile the graph up to the specified output operands asynchronously.
  Promise<MLGraph> build(MLNamedOperands outputs);
};

dictionary MLArgMinMaxOptions : MLOperatorOptions {
  boolean keepDimensions = false;
  MLOperandDataType outputDataType = "int32";
};

partial interface MLGraphBuilder {
  MLOperand argMin(MLOperand input, [EnforceRange] unsigned long axis,
                   optional MLArgMinMaxOptions options = {});
  MLOperand argMax(MLOperand input, [EnforceRange] unsigned long axis,
                   optional MLArgMinMaxOptions options = {});
};

partial dictionary MLOpSupportLimits {
  MLSingleInputSupportLimits argMin;
  MLSingleInputSupportLimits argMax;
};

dictionary MLBatchNormalizationOptions : MLOperatorOptions {
  MLOperand scale;
  MLOperand bias;
  [EnforceRange] unsigned long axis = 1;
  double epsilon = 1e-5;
};

partial interface MLGraphBuilder {
  MLOperand batchNormalization(MLOperand input, MLOperand mean, MLOperand variance,
                               optional MLBatchNormalizationOptions options = {});
};

dictionary MLBatchNormalizationSupportLimits {
  MLTensorLimits input;
  MLTensorLimits mean;
  MLTensorLimits variance;
  MLTensorLimits scale;
  MLTensorLimits bias;
  MLTensorLimits output;
};

partial dictionary MLOpSupportLimits {
  MLBatchNormalizationSupportLimits batchNormalization;
};

partial interface MLGraphBuilder {
  MLOperand cast(MLOperand input,
                 MLOperandDataType dataType,
                 optional MLOperatorOptions options = {});
};

partial dictionary MLOpSupportLimits {
  MLSingleInputSupportLimits cast;
};

dictionary MLClampOptions : MLOperatorOptions {
  MLNumber minValue;
  MLNumber maxValue;
};

partial interface MLGraphBuilder {
  MLOperand clamp(MLOperand input, optional MLClampOptions options = {});
};

partial dictionary MLOpSupportLimits {
  MLSingleInputSupportLimits clamp;
};

partial interface MLGraphBuilder {
  MLOperand concat(sequence<MLOperand> inputs,
                   [EnforceRange] unsigned long axis,
                   optional MLOperatorOptions options = {});
};

dictionary MLConcatSupportLimits {
  MLTensorLimits inputs;
  MLTensorLimits output;
};

partial dictionary MLOpSupportLimits {
  MLConcatSupportLimits concat;
};

enum MLConv2dFilterOperandLayout {
  "oihw",
  "hwio",
  "ohwi",
  "ihwo"
};

dictionary MLConv2dOptions : MLOperatorOptions {
  sequence<[EnforceRange] unsigned long> padding;
  sequence<[EnforceRange] unsigned long> strides;
  sequence<[EnforceRange] unsigned long> dilations;
  [EnforceRange] unsigned long groups = 1;
  MLInputOperandLayout inputLayout = "nchw";
  MLConv2dFilterOperandLayout filterLayout = "oihw";
  MLOperand bias;
};

partial interface MLGraphBuilder {
  MLOperand conv2d(MLOperand input,
                   MLOperand filter,
                   optional MLConv2dOptions options = {});
};

dictionary MLConv2dSupportLimits {
  MLTensorLimits input;
  MLTensorLimits filter;
  MLTensorLimits bias;
  MLTensorLimits output;
};

partial dictionary MLOpSupportLimits {
  MLConv2dSupportLimits conv2d;
};

enum MLConvTranspose2dFilterOperandLayout {
  "iohw",
  "hwoi",
  "ohwi"
};

dictionary MLConvTranspose2dOptions : MLOperatorOptions {
  sequence<[EnforceRange] unsigned long> padding;
  sequence<[EnforceRange] unsigned long> strides;
  sequence<[EnforceRange] unsigned long> dilations;
  sequence<[EnforceRange] unsigned long> outputPadding;
  sequence<[EnforceRange] unsigned long> outputSizes;
  [EnforceRange] unsigned long groups = 1;
  MLInputOperandLayout inputLayout = "nchw";
  MLConvTranspose2dFilterOperandLayout filterLayout = "iohw";
  MLOperand bias;
};

partial interface MLGraphBuilder {
  MLOperand convTranspose2d(MLOperand input, MLOperand filter,
                            optional MLConvTranspose2dOptions options = {});
};

partial dictionary MLOpSupportLimits {
  MLConv2dSupportLimits convTranspose2d;
};

dictionary MLCumulativeSumOptions : MLOperatorOptions {
  boolean exclusive = false;
  boolean reversed = false;
};

partial interface MLGraphBuilder {
  MLOperand cumulativeSum(MLOperand input,
                          unsigned long axis,
                          optional MLCumulativeSumOptions options = {});
};

partial dictionary MLOpSupportLimits {
  MLSingleInputSupportLimits cumulativeSum;
};

partial interface MLGraphBuilder {
  MLOperand add(MLOperand a, MLOperand b, optional MLOperatorOptions options = {});
  MLOperand sub(MLOperand a, MLOperand b, optional MLOperatorOptions options = {});
  MLOperand mul(MLOperand a, MLOperand b, optional MLOperatorOptions options = {});
  MLOperand div(MLOperand a, MLOperand b, optional MLOperatorOptions options = {});
  MLOperand max(MLOperand a, MLOperand b, optional MLOperatorOptions options = {});
  MLOperand min(MLOperand a, MLOperand b, optional MLOperatorOptions options = {});
  MLOperand pow(MLOperand a, MLOperand b, optional MLOperatorOptions options = {});
};

partial dictionary MLOpSupportLimits {
  MLBinarySupportLimits add;
  MLBinarySupportLimits sub;
  MLBinarySupportLimits mul;
  MLBinarySupportLimits div;
  MLBinarySupportLimits max;
  MLBinarySupportLimits min;
  MLBinarySupportLimits pow;
};

partial interface MLGraphBuilder {
  MLOperand equal(MLOperand a,
                  MLOperand b,
                  optional MLOperatorOptions options = {});
  MLOperand notEqual(MLOperand a,
                     MLOperand b,
                     optional MLOperatorOptions options = {});
  MLOperand greater(MLOperand a,
                    MLOperand b,
                    optional MLOperatorOptions options = {});
  MLOperand greaterOrEqual(MLOperand a,
                           MLOperand b,
                           optional MLOperatorOptions options = {});
  MLOperand lesser(MLOperand a,
                   MLOperand b,
                   optional MLOperatorOptions options = {});
  MLOperand lesserOrEqual(MLOperand a,
                          MLOperand b,
                          optional MLOperatorOptions options = {});
  MLOperand logicalNot(MLOperand a, optional MLOperatorOptions options = {});
  MLOperand logicalAnd(MLOperand a,
                       MLOperand b,
                       optional MLOperatorOptions options = {});
  MLOperand logicalOr(MLOperand a,
                      MLOperand b,
                      optional MLOperatorOptions options = {});
  MLOperand logicalXor(MLOperand a,
                       MLOperand b,
                       optional MLOperatorOptions options = {});
  MLOperand isNaN(MLOperand a, optional MLOperatorOptions options = {});
  MLOperand isInfinite(MLOperand a, optional MLOperatorOptions options = {});
};

dictionary MLLogicalNotSupportLimits {
  MLTensorLimits a;
  MLTensorLimits output;
};

partial dictionary MLOpSupportLimits {
  MLBinarySupportLimits equal;
  MLBinarySupportLimits notEqual;
  MLBinarySupportLimits greater;
  MLBinarySupportLimits greaterOrEqual;
  MLBinarySupportLimits lesser;
  MLBinarySupportLimits lesserOrEqual;
  MLLogicalNotSupportLimits logicalNot;
  MLBinarySupportLimits logicalAnd;
  MLBinarySupportLimits logicalOr;
  MLBinarySupportLimits logicalXor;
  MLLogicalNotSupportLimits isNaN;
  MLLogicalNotSupportLimits isInfinite;
};

partial interface MLGraphBuilder {
  MLOperand abs(MLOperand input, optional MLOperatorOptions options = {});
  MLOperand ceil(MLOperand input, optional MLOperatorOptions options = {});
  MLOperand cos(MLOperand input, optional MLOperatorOptions options = {});
  MLOperand erf(MLOperand input, optional MLOperatorOptions options = {});
  MLOperand exp(MLOperand input, optional MLOperatorOptions options = {});
  MLOperand floor(MLOperand input, optional MLOperatorOptions options = {});
  MLOperand identity(MLOperand input, optional MLOperatorOptions options = {});
  MLOperand log(MLOperand input, optional MLOperatorOptions options = {});
  MLOperand neg(MLOperand input, optional MLOperatorOptions options = {});
  MLOperand reciprocal(MLOperand input, optional MLOperatorOptions options = {});
  MLOperand roundEven(MLOperand input, optional MLOperatorOptions options = {});
  MLOperand sin(MLOperand input, optional MLOperatorOptions options = {});
  MLOperand sign(MLOperand input, optional MLOperatorOptions options = {});
  MLOperand sqrt(MLOperand input, optional MLOperatorOptions options = {});
  MLOperand tan(MLOperand input, optional MLOperatorOptions options = {});
};

partial dictionary MLOpSupportLimits {
  MLSingleInputSupportLimits abs;
  MLSingleInputSupportLimits ceil;
  MLSingleInputSupportLimits cos;
  MLSingleInputSupportLimits erf;
  MLSingleInputSupportLimits exp;
  MLSingleInputSupportLimits floor;
  MLSingleInputSupportLimits identity;
  MLSingleInputSupportLimits log;
  MLSingleInputSupportLimits neg;
  MLSingleInputSupportLimits reciprocal;
  MLSingleInputSupportLimits roundEven;
  MLSingleInputSupportLimits sin;
  MLSingleInputSupportLimits sign;
  MLSingleInputSupportLimits sqrt;
  MLSingleInputSupportLimits tan;
};

partial interface MLGraphBuilder {
  MLOperand dequantizeLinear(MLOperand input,
                             MLOperand scale,
                             MLOperand zeroPoint,
                             optional MLOperatorOptions options = {});
};

dictionary MLQuantizeDequantizeLinearSupportLimits {
  MLTensorLimits input;
  MLTensorLimits scale;
  MLTensorLimits zeroPoint;
  MLTensorLimits output;
};

partial dictionary MLOpSupportLimits {
  MLQuantizeDequantizeLinearSupportLimits dequantizeLinear;
};

partial interface MLGraphBuilder {
  MLOperand quantizeLinear(MLOperand input,
                           MLOperand scale,
                           MLOperand zeroPoint,
                           optional MLOperatorOptions options = {});
};

partial dictionary MLOpSupportLimits {
  MLQuantizeDequantizeLinearSupportLimits quantizeLinear;
};

dictionary MLEluOptions : MLOperatorOptions {
  double alpha = 1;
};

partial interface MLGraphBuilder {
  MLOperand elu(MLOperand input, optional MLEluOptions options = {});
};

partial dictionary MLOpSupportLimits {
  MLSingleInputSupportLimits elu;
};

partial interface MLGraphBuilder {
  MLOperand expand(MLOperand input,
                   sequence<[EnforceRange] unsigned long> newShape,
                   optional MLOperatorOptions options = {});
};

partial dictionary MLOpSupportLimits {
  MLSingleInputSupportLimits expand;
};

dictionary MLGatherOptions : MLOperatorOptions {
  [EnforceRange] unsigned long axis = 0;
};

partial interface MLGraphBuilder {
  MLOperand gather(MLOperand input,
                   MLOperand indices,
                   optional MLGatherOptions options = {});
};

dictionary MLGatherSupportLimits {
  MLTensorLimits input;
  MLTensorLimits indices;
  MLTensorLimits output;
};

partial dictionary MLOpSupportLimits {
  MLGatherSupportLimits gather;
};

partial interface MLGraphBuilder {
  MLOperand gatherElements(MLOperand input,
                           MLOperand indices,
                           optional MLGatherOptions options = {});
};

partial dictionary MLOpSupportLimits {
  MLGatherSupportLimits gatherElements;
};

partial interface MLGraphBuilder {
  MLOperand gatherND(MLOperand input,
                     MLOperand indices,
                     optional MLOperatorOptions options = {});
};

partial dictionary MLOpSupportLimits {
  MLGatherSupportLimits gatherND;
};

partial interface MLGraphBuilder {
  MLOperand gelu(MLOperand input, optional MLOperatorOptions options = {});
};

partial dictionary MLOpSupportLimits {
  MLSingleInputSupportLimits gelu;
};

dictionary MLGemmOptions : MLOperatorOptions {
  MLOperand c;
  double alpha = 1.0;
  double beta = 1.0;
  boolean aTranspose = false;
  boolean bTranspose = false;
};

partial interface MLGraphBuilder {
  MLOperand gemm(MLOperand a, MLOperand b, optional MLGemmOptions options = {});
};

dictionary MLGemmSupportLimits {
  MLTensorLimits a;
  MLTensorLimits b;
  MLTensorLimits c;
  MLTensorLimits output;
};

partial dictionary MLOpSupportLimits {
  MLGemmSupportLimits gemm;
};

enum MLGruWeightLayout {
  "zrn",  // update-reset-new gate ordering
  "rzn"   // reset-update-new gate ordering
};

enum MLRecurrentNetworkActivation {
  "relu",
  "sigmoid",
  "tanh"
};

enum MLRecurrentNetworkDirection {
  "forward",
  "backward",
  "both"
};

dictionary MLGruOptions : MLOperatorOptions {
  MLOperand bias;
  MLOperand recurrentBias;
  MLOperand initialHiddenState;
  boolean resetAfter = true;
  boolean returnSequence = false;
  MLRecurrentNetworkDirection direction = "forward";
  MLGruWeightLayout layout = "zrn";
  sequence<MLRecurrentNetworkActivation> activations;
};

partial interface MLGraphBuilder {
  sequence<MLOperand> gru(MLOperand input,
                          MLOperand weight,
                          MLOperand recurrentWeight,
                          [EnforceRange] unsigned long steps,
                          [EnforceRange] unsigned long hiddenSize,
                          optional MLGruOptions options = {});
};

dictionary MLGruSupportLimits {
  MLTensorLimits input;
  MLTensorLimits weight;
  MLTensorLimits recurrentWeight;
  MLTensorLimits bias;
  MLTensorLimits recurrentBias;
  MLTensorLimits initialHiddenState;
  MLTensorLimits output0;
  MLTensorLimits output1;
};

partial dictionary MLOpSupportLimits {
  MLGruSupportLimits gru;
};

dictionary MLGruCellOptions : MLOperatorOptions {
  MLOperand bias;
  MLOperand recurrentBias;
  boolean resetAfter = true;
  MLGruWeightLayout layout = "zrn";
  sequence<MLRecurrentNetworkActivation> activations;
};

partial interface MLGraphBuilder {
  MLOperand gruCell(MLOperand input,
                    MLOperand weight,
                    MLOperand recurrentWeight,
                    MLOperand hiddenState,
                    [EnforceRange] unsigned long hiddenSize,
                    optional MLGruCellOptions options = {});
};

dictionary MLGruCellSupportLimits {
  MLTensorLimits input;
  MLTensorLimits weight;
  MLTensorLimits recurrentWeight;
  MLTensorLimits hiddenState;
  MLTensorLimits bias;
  MLTensorLimits recurrentBias;
  MLTensorLimits output;
};

partial dictionary MLOpSupportLimits {
  MLGruCellSupportLimits gruCell;
};

dictionary MLHardSigmoidOptions : MLOperatorOptions {
  double alpha = 0.2;
  double beta = 0.5;
};

partial interface MLGraphBuilder {
  MLOperand hardSigmoid(MLOperand input, optional MLHardSigmoidOptions options = {});
};

partial dictionary MLOpSupportLimits {
  MLSingleInputSupportLimits hardSigmoid;
};

partial interface MLGraphBuilder {
  MLOperand hardSwish(MLOperand input, optional MLOperatorOptions options = {});
};

partial dictionary MLOpSupportLimits {
  MLSingleInputSupportLimits hardSwish;
};

dictionary MLInstanceNormalizationOptions : MLOperatorOptions {
  MLOperand scale;
  MLOperand bias;
  double epsilon = 1e-5;
  MLInputOperandLayout layout = "nchw";
};

partial interface MLGraphBuilder {
  MLOperand instanceNormalization(
    MLOperand input,
    optional MLInstanceNormalizationOptions options = {});
};

dictionary MLNormalizationSupportLimits {
  MLTensorLimits input;
  MLTensorLimits scale;
  MLTensorLimits bias;
  MLTensorLimits output;
};

partial dictionary MLOpSupportLimits {
  MLNormalizationSupportLimits instanceNormalization;
};

dictionary MLLayerNormalizationOptions : MLOperatorOptions {
  MLOperand scale;
  MLOperand bias;
  sequence<[EnforceRange] unsigned long> axes;
  double epsilon = 1e-5;
};

partial interface MLGraphBuilder {
  MLOperand layerNormalization(MLOperand input,
                               optional MLLayerNormalizationOptions options = {});
};

partial dictionary MLOpSupportLimits {
  MLNormalizationSupportLimits layerNormalization;
};

dictionary MLLeakyReluOptions : MLOperatorOptions {
  double alpha = 0.01;
};

partial interface MLGraphBuilder {
  MLOperand leakyRelu(MLOperand input, optional MLLeakyReluOptions options = {});
};

partial dictionary MLOpSupportLimits {
  MLSingleInputSupportLimits leakyRelu;
};

dictionary MLLinearOptions : MLOperatorOptions {
  double alpha = 1;
  double beta = 0;
};

partial interface MLGraphBuilder {
  MLOperand linear(MLOperand input, optional MLLinearOptions options = {});
};

partial dictionary MLOpSupportLimits {
  MLSingleInputSupportLimits linear;
};

enum MLLstmWeightLayout {
  "iofg", // input-output-forget-cell gate ordering
  "ifgo"  // input-forget-cell-output gate ordering
};

dictionary MLLstmOptions : MLOperatorOptions {
  MLOperand bias;
  MLOperand recurrentBias;
  MLOperand peepholeWeight;
  MLOperand initialHiddenState;
  MLOperand initialCellState;
  boolean returnSequence = false;
  MLRecurrentNetworkDirection direction = "forward";
  MLLstmWeightLayout layout = "iofg";
  sequence<MLRecurrentNetworkActivation> activations;
};

partial interface MLGraphBuilder {
  sequence<MLOperand> lstm(MLOperand input,
                           MLOperand weight,
                           MLOperand recurrentWeight,
                           [EnforceRange] unsigned long steps,
                           [EnforceRange] unsigned long hiddenSize,
                           optional MLLstmOptions options = {});
};

dictionary MLLstmSupportLimits {
  MLTensorLimits input;
  MLTensorLimits weight;
  MLTensorLimits recurrentWeight;
  MLTensorLimits bias;
  MLTensorLimits recurrentBias;
  MLTensorLimits peepholeWeight;
  MLTensorLimits initialHiddenState;
  MLTensorLimits initialCellState;
  MLTensorLimits output0;
  MLTensorLimits output1;
  MLTensorLimits output2;
};

partial dictionary MLOpSupportLimits {
  MLLstmSupportLimits lstm;
};


dictionary MLLstmCellOptions : MLOperatorOptions {
  MLOperand bias;
  MLOperand recurrentBias;
  MLOperand peepholeWeight;
  MLLstmWeightLayout layout = "iofg";
  sequence<MLRecurrentNetworkActivation> activations;
};

partial interface MLGraphBuilder {
  sequence<MLOperand> lstmCell(MLOperand input,
                               MLOperand weight,
                               MLOperand recurrentWeight,
                               MLOperand hiddenState,
                               MLOperand cellState,
                               [EnforceRange] unsigned long hiddenSize,
                               optional MLLstmCellOptions options = {});
};

dictionary MLLstmCellSupportLimits {
  MLTensorLimits input;
  MLTensorLimits weight;
  MLTensorLimits recurrentWeight;
  MLTensorLimits hiddenState;
  MLTensorLimits cellState;
  MLTensorLimits bias;
  MLTensorLimits recurrentBias;
  MLTensorLimits peepholeWeight;
  MLTensorLimits output0;
  MLTensorLimits output1;
};

partial dictionary MLOpSupportLimits {
  MLLstmCellSupportLimits lstmCell;
};

partial interface MLGraphBuilder {
  MLOperand matmul(MLOperand a, MLOperand b, optional MLOperatorOptions options = {});
};

partial dictionary MLOpSupportLimits {
  MLBinarySupportLimits matmul;
};

enum MLPaddingMode {
  "constant",
  "edge",
  "reflection"
};

dictionary MLPadOptions : MLOperatorOptions {
  MLPaddingMode mode = "constant";
  MLNumber value = 0;
};

partial interface MLGraphBuilder {
  MLOperand pad(MLOperand input,
                sequence<[EnforceRange] unsigned long> beginningPadding,
                sequence<[EnforceRange] unsigned long> endingPadding,
                optional MLPadOptions options = {});
};

partial dictionary MLOpSupportLimits {
  MLSingleInputSupportLimits pad;
};

enum MLRoundingType {
  "floor",
  "ceil"
};

dictionary MLPool2dOptions : MLOperatorOptions {
  sequence<[EnforceRange] unsigned long> windowDimensions;
  sequence<[EnforceRange] unsigned long> padding;
  sequence<[EnforceRange] unsigned long> strides;
  sequence<[EnforceRange] unsigned long> dilations;
  MLInputOperandLayout layout = "nchw";
  MLRoundingType outputShapeRounding = "floor";
  sequence<[EnforceRange] unsigned long> outputSizes;
};

partial interface MLGraphBuilder {
  MLOperand averagePool2d(MLOperand input, optional MLPool2dOptions options = {});
  MLOperand l2Pool2d(MLOperand input, optional MLPool2dOptions options = {});
  MLOperand maxPool2d(MLOperand input, optional MLPool2dOptions options = {});
};

partial dictionary MLOpSupportLimits {
  MLSingleInputSupportLimits averagePool2d;
  MLSingleInputSupportLimits l2Pool2d;
  MLSingleInputSupportLimits maxPool2d;
};

partial interface MLGraphBuilder {
  MLOperand prelu(MLOperand input,
                  MLOperand slope,
                  optional MLOperatorOptions options = {});
};

dictionary MLPreluSupportLimits {
  MLTensorLimits input;
  MLTensorLimits slope;
  MLTensorLimits output;
};

partial dictionary MLOpSupportLimits {
  MLPreluSupportLimits prelu;
};

dictionary MLReduceOptions : MLOperatorOptions {
  sequence<[EnforceRange] unsigned long> axes;
  boolean keepDimensions = false;
};

partial interface MLGraphBuilder {
  MLOperand reduceL1(MLOperand input, optional MLReduceOptions options = {});
  MLOperand reduceL2(MLOperand input, optional MLReduceOptions options = {});
  MLOperand reduceLogSum(MLOperand input, optional MLReduceOptions options = {});
  MLOperand reduceLogSumExp(MLOperand input, optional MLReduceOptions options = {});
  MLOperand reduceMax(MLOperand input, optional MLReduceOptions options = {});
  MLOperand reduceMean(MLOperand input, optional MLReduceOptions options = {});
  MLOperand reduceMin(MLOperand input, optional MLReduceOptions options = {});
  MLOperand reduceProduct(MLOperand input, optional MLReduceOptions options = {});
  MLOperand reduceSum(MLOperand input, optional MLReduceOptions options = {});
  MLOperand reduceSumSquare(MLOperand input, optional MLReduceOptions options = {});
};

partial dictionary MLOpSupportLimits {
  MLSingleInputSupportLimits reduceL1;
  MLSingleInputSupportLimits reduceL2;
  MLSingleInputSupportLimits reduceLogSum;
  MLSingleInputSupportLimits reduceLogSumExp;
  MLSingleInputSupportLimits reduceMax;
  MLSingleInputSupportLimits reduceMean;
  MLSingleInputSupportLimits reduceMin;
  MLSingleInputSupportLimits reduceProduct;
  MLSingleInputSupportLimits reduceSum;
  MLSingleInputSupportLimits reduceSumSquare;
};

partial interface MLGraphBuilder {
  MLOperand relu(MLOperand input, optional MLOperatorOptions options = {});
};

partial dictionary MLOpSupportLimits {
  MLSingleInputSupportLimits relu;
};

enum MLInterpolationMode {
  "nearest-neighbor",
  "linear"
};

dictionary MLResample2dOptions : MLOperatorOptions {
  MLInterpolationMode mode = "nearest-neighbor";
  sequence<float> scales;
  sequence<[EnforceRange] unsigned long> sizes;
  sequence<[EnforceRange] unsigned long> axes;
};

partial interface MLGraphBuilder {
  MLOperand resample2d(MLOperand input, optional MLResample2dOptions options = {});
};

partial dictionary MLOpSupportLimits {
  MLSingleInputSupportLimits resample2d;
};

partial interface MLGraphBuilder {
  MLOperand reshape(MLOperand input,
                    sequence<[EnforceRange] unsigned long> newShape,
                    optional MLOperatorOptions options = {});
};

partial dictionary MLOpSupportLimits {
  MLSingleInputSupportLimits reshape;
};

dictionary MLReverseOptions : MLOperatorOptions {
  sequence<[EnforceRange] unsigned long> axes;
};

partial interface MLGraphBuilder {
  MLOperand reverse(MLOperand input, optional MLReverseOptions options = {});
};

partial dictionary MLOpSupportLimits {
  MLSingleInputSupportLimits reverse;
};

dictionary MLScatterOptions : MLOperatorOptions {
  [EnforceRange] unsigned long axis = 0;
};

partial interface MLGraphBuilder {
  MLOperand scatterElements(MLOperand input,
                            MLOperand indices,
                            MLOperand updates,
                            optional MLScatterOptions options = {});
};

dictionary MLScatterSupportLimits {
  MLTensorLimits input;
  MLTensorLimits indices;
  MLTensorLimits updates;
  MLTensorLimits output;
};

partial dictionary MLOpSupportLimits {
  MLScatterSupportLimits scatterElements;
};

partial interface MLGraphBuilder {
  MLOperand scatterND(MLOperand input,
                      MLOperand indices,
                      MLOperand updates,
                      optional MLOperatorOptions options = {});
};

partial dictionary MLOpSupportLimits {
  MLScatterSupportLimits scatterND;
};

partial interface MLGraphBuilder {
  MLOperand sigmoid(MLOperand input, optional MLOperatorOptions options = {});
};

partial dictionary MLOpSupportLimits {
  MLSingleInputSupportLimits sigmoid;
};

dictionary MLSliceOptions : MLOperatorOptions {
  sequence<[EnforceRange] unsigned long> strides;
};

partial interface MLGraphBuilder {
  MLOperand slice(MLOperand input,
                  sequence<[EnforceRange] unsigned long> starts,
                  sequence<[EnforceRange] unsigned long> sizes,
                  optional MLSliceOptions options = {});
};

partial dictionary MLOpSupportLimits {
  MLSingleInputSupportLimits slice;
};

partial interface MLGraphBuilder {
  MLOperand softmax(MLOperand input,
                    [EnforceRange] unsigned long axis,
                    optional MLOperatorOptions options = {});
};

partial dictionary MLOpSupportLimits {
  MLSingleInputSupportLimits softmax;
};

partial interface MLGraphBuilder {
  MLOperand softplus(MLOperand input, optional MLOperatorOptions options = {});
};

partial dictionary MLOpSupportLimits {
  MLSingleInputSupportLimits softplus;
};

partial interface MLGraphBuilder {
  MLOperand softsign(MLOperand input, optional MLOperatorOptions options = {});
};

partial dictionary MLOpSupportLimits {
  MLSingleInputSupportLimits softsign;
};

dictionary MLSplitOptions : MLOperatorOptions {
  [EnforceRange] unsigned long axis = 0;
};

partial interface MLGraphBuilder {
  sequence<MLOperand> split(
      MLOperand input,
      ([EnforceRange] unsigned long or sequence<[EnforceRange] unsigned long>) splits,
      optional MLSplitOptions options = {});
};

dictionary MLSplitSupportLimits {
  MLTensorLimits input;
  MLTensorLimits outputs;
};

partial dictionary MLOpSupportLimits {
  MLSplitSupportLimits split;
};

partial interface MLGraphBuilder {
  MLOperand tanh(MLOperand input, optional MLOperatorOptions options = {});
};

partial dictionary MLOpSupportLimits {
  MLSingleInputSupportLimits tanh;
};

partial interface MLGraphBuilder {
  MLOperand tile(MLOperand input,
                 sequence<unsigned long> repetitions,
                 optional MLOperatorOptions options = {});
};

partial dictionary MLOpSupportLimits {
  MLSingleInputSupportLimits tile;
};

dictionary MLTransposeOptions : MLOperatorOptions {
  sequence<[EnforceRange] unsigned long> permutation;
};

partial interface MLGraphBuilder {
  MLOperand transpose(MLOperand input, optional MLTransposeOptions options = {});
};

partial dictionary MLOpSupportLimits {
  MLSingleInputSupportLimits transpose;
};

dictionary MLTriangularOptions : MLOperatorOptions {
  boolean upper = true;
  [EnforceRange] long diagonal = 0;
};

partial interface MLGraphBuilder {
  MLOperand triangular(MLOperand input, optional MLTriangularOptions options = {});
};

partial dictionary MLOpSupportLimits {
  MLSingleInputSupportLimits triangular;
};

partial interface MLGraphBuilder {
  MLOperand where(MLOperand condition,
                  MLOperand trueValue,
                  MLOperand falseValue,
                  optional MLOperatorOptions options = {});
};

dictionary MLWhereSupportLimits {
  MLTensorLimits condition;
  MLTensorLimits trueValue;
  MLTensorLimits falseValue;
  MLTensorLimits output;
};

partial dictionary MLOpSupportLimits {
  MLWhereSupportLimits where;
};

이슈 인덱스

구현자에 대한 지침으로, out-of-bounds access에 취약한 operations를 문서화한다.
렌더러를 실행하는 프로세스들 사이에서 CPU가 공유되는 현재 상태를 고려하여 side channel attack의 실행 가능성을 조사한다.
Hinting은 우려를 부분적으로 완화한다. 추가 mitigations를 조사한다.
graph가 완전히 constructed되고 compiled된 후 execution을 위해 선택된 실제 devices를 expose하기 위해 MLGraph.devices API extension이 제안되었다. 이 API extension의 privacy implications는 조사 중이다. [Issue #836]
dispatch() 중 errors를 보고하기 위한 mechanism 추가를 고려한다. [Issue #778]
이 timeline을 더 엄밀하게 정의한다. [Issue #529]
graph execution 중 errors를 보고하기 위한 mechanism을 추가한다. [Issue #778]
tensor에 write하는 동안 errors를 보고하기 위한 mechanism을 추가한다. [Issue #778]
0-size dimensions가 지원되어야 하는가? [Issue #391]
operand dimensions의 최대 수는 정의되어 있지 않지만, native ML APIs에는 보통 지원되는 최대 size가 있다. [Issue #456]
각 operator에 대해 반드시 지원되어야 하는 data types의 subset을 지정해야 하는가?
bigintnumeric types의 unions 지원은 [WEBIDL]에서 새로 추가되었으며, implementation support 역시 제한적이다. Prototype implementations는 이 접근 방식에 대한 feedback을 제공하는 것이 권장된다. [whatwg/webidl Issue #1388]
0-size dimensions가 허용된다면, 이 steps를 개정한다. [Issue #391]
0-size dimensions가 허용된다면, 위 step을 개정한다. [Issue #391]
0-size dimensions가 허용된다면, 이 steps를 개정한다. [Issue #391]
[INFRA]에 definition이 제공되면 이를 제거한다. [whatwg/infra Issue #664]