웹 신경망 API

W3C 후보 권고안 초안,

이 문서에 대한 자세한 정보
이 버전:
https://www.w3.org/TR/2026/CRD-webnn-20260910/
최신 공개 버전:
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 표준 및 초안 색인에서 확인할 수 있습니다.

이 문서는 웹 머신 러닝 워킹 그룹에서 권고안 트랙을 사용하여 후보 권고안 초안으로 게시했습니다.

후보 권고안으로 게시되었다고 해서 W3C 및 그 회원의 승인을 의미하는 것은 아닙니다. 후보 권고안 초안에는 워킹 그룹이 이후 후보 권고안 스냅샷에 포함하려는 이전 후보 권고안의 변경 사항이 통합되어 있습니다.

이 문서는 초안이며 언제든지 다른 문서에 의해 업데이트되거나 대체되거나 폐기될 수 있습니다. 이 문서를 진행 중인 작업 이외의 것으로 인용하는 것은 적절하지 않습니다.

웹 머신 러닝 워킹 그룹은 그룹에서 아직 처리하지 않은 모든 버그 보고서 목록을 유지합니다. 미해결 문제에 대해 제안된 명세 텍스트가 포함된 풀 리퀘스트를 적극 권장합니다.

이 문서는 W3C 특허 정책에 따라 운영되는 그룹에서 작성했습니다. W3C는 그룹의 산출물과 관련하여 이루어진 모든 특허 공개의 공개 목록을 유지하며, 해당 페이지에는 특허 공개 방법에 대한 지침도 포함되어 있습니다. 본인이 필수 청구항을 포함한다고 판단하는 특허에 대해 실제로 알고 있는 개인은 W3C 특허 정책의 섹션 6에 따라 해당 정보를 공개해야 합니다.

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

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

이 문서는 언제든지 유지 관리되고 업데이트됩니다. 이 문서의 일부는 아직 작업 중이며 추가 개선 사항은 개정된 후보 권고안 초안 및 스냅샷에 반영될 것으로 예상됩니다.

제안 권고안으로의 전환을 요청하기 전에 워킹 그룹은 다음 사항을 입증하고자 합니다.

1. 소개

웹 신경망 API는 플랫폼별 기능에 종속되지 않으면서 운영 체제와 기반 하드웨어 플랫폼의 머신 러닝 기능을 활용하는 웹 친화적인 하드웨어 독립적 추상화 계층을 정의합니다. 이 추상화 계층은 주요 머신 러닝 JavaScript 프레임워크의 요구 사항을 충족하며, ML 분야에 익숙한 웹 개발자가 라이브러리의 도움 없이 사용자 정의 코드를 작성할 수도 있도록 합니다.

그림이 포함된 소개는 설명 문서를 참조하십시오.

2. 사용 사례

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

이 섹션에서는 신경망 추론 하드웨어 가속의 애플리케이션 수준 사용 사례를 설명합니다. 이러한 사용 사례의 모든 애플리케이션은 사전 학습된 심층 신경망(DNN) [models]을 기반으로 구축할 수 있습니다.

참고: 여기에 설명된 일부 사용 사례는 본질적으로 개인정보 침해 소지가 있음을 유의하십시오. 이러한 사용 사례에 API를 사용할 계획인 개발자는 API가 사용자가 이해하고 승인한 목적을 위해 사용자에게 이익이 되도록 사용되는지 확인해야 합니다. 또한 웹 머신 러닝을 위한 윤리 원칙 [webmachinelearning-ethics]을 적용하고 투명성, 데이터 최소화 및 사용자 제어와 같은 적절한 개인정보 보호 위험 완화 조치를 구현해야 합니다.

참고: § 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. 음성 인식

음성-텍스트 변환이라고도 하는 음성 인식은 말로 표현된 언어를 인식하고 텍스트로 변환할 수 있도록 합니다. 음성 인식 애플리케이션의 예로는 전사, 자동 번역, 다중 모달 상호작용, 실시간 자막 및 가상 비서가 있습니다. 음성 인식은 청각 콘텐츠의 접근성을 개선하고 개인정보를 보호하는 방식으로 이러한 콘텐츠와 텍스트 형태로 상호작용할 수 있도록 합니다. 일반적인 사용 사례의 예로는 실시간 자막을 사용하여 비디오를 시청하거나 온라인 회의에 참여하는 것이 있습니다. [Whisper]와 같은 모델은 정확성과 강건성 측면에서 인간 수준에 근접하며 이러한 사용 사례의 접근성을 개선하는 데 매우 적합합니다.

2.1.15. 텍스트 생성

텍스트 시퀀스의 다음 항목을 예측하는 일반적인 능력이 필요한 작업을 수행할 수 있는 대규모 언어 모델(LLM)을 통해 다양한 텍스트 생성 사용 사례를 구현할 수 있습니다. 이 유형의 모델은 텍스트를 번역하거나, 텍스트 입력을 기반으로 질문에 답하거나, 더 큰 분량의 텍스트를 요약하거나, 텍스트 입력을 기반으로 텍스트 출력을 생성할 수 있습니다. LLM은 RNN, CNN 또는 LSTM 아키텍처를 기반으로 한 이전 모델보다 더 나은 성능을 제공하며 이 섹션에서 설명하는 여러 다른 사용 사례의 성능도 더욱 개선합니다. LLM의 예로는 [t5-small], [m2m100_418M], [gpt2], 그리고 [llama-2-7b]가 있습니다.

2.1.16. 가짜 비디오 감지

사용자가 웹에서 ‘딥페이크’로 생성된 사실적인 가짜 비디오에 노출됩니다. 가짜 비디오는 화자의 얼굴을 대통령의 얼굴로 바꾸어 사용자를 정치적으로 선동하거나 사용자의 의견을 조작할 수 있습니다. [FaceForensics++]와 같은 딥페이크 감지 애플리케이션은 비디오를 분석하여 사용자를 가짜 비디오나 이미지로부터 보호합니다. 사용자가 웹에서 가짜 비디오를 시청하면 감지 애플리케이션이 사기성 비디오임을 실시간으로 경고합니다.

2.2. 프레임워크 사용 사례

이 섹션에서는 신경망 추론 하드웨어 가속을 위한 전용 저수준 API의 프레임워크 수준 사용 사례를 모아 설명합니다. 머신 러닝 프레임워크가 웹 신경망 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 또는 행렬 곱셈과 같이 계산 집약적인 연산의 경우 프레임워크는 WebNN API를 사용하여 선택한 장치에서 사용 가능한 ML 전용 가속을 통해 이를 실행합니다.

2.2.5. 실시간 비디오 처리와의 통합

실시간 비디오 처리를 사용하여 WebRTC 기반 화상 회의의 사용자 경험을 향상할 수 있습니다. 예를 들어 § 2.1.2 의미론적 분할 모델을 사용해 구현한 배경 흐림 기능은 사용자의 실시간 카메라 영상에서 배경을 흐리게 처리합니다. 이 사용 사례의 성능 요구 사항을 충족하기 위해 WebNN API는 미디어 파이프라인을 구성하는 다른 Web API의 기본 요소와 통합되어 WebNN API를 기반으로 실시간 비디오 스트림을 변환할 수 있도록 합니다.

3. 접근성 고려 사항

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

§ 2.1.8 이미지 캡셔닝은 캡션이 스크린 리더 및 기타 보조 기술(AT) 사용자에게 제공되도록 함으로써 개선할 수 있습니다. 웹 작성자는 생성된 이미지 캡션이 표준 alt 속성이나 기타 방법을 통해 해당 이미지와 의미론적으로 연결되도록 하는 것이 좋습니다. 사용할 방법은 설명이 최초 페이지 로드 시 업데이트되는지, 아니면 사용자 동작의 결과로 나중에 업데이트되는지에 따라 달라질 수 있습니다.

§ 2.1.11 감정 분석은 사용자에게 잘못된 레이블을 부여하고 그 결과 잘못 분류하여 차별적인 경험으로 이어질 수 있습니다. 웹 작성자는 신뢰도 점수를 공개하고 사용자가 이 기능을 끌 수 있는 옵션을 제공할 것을 권장합니다.

§ 2.1.13 노이즈 억제에서 강한 필터를 사용하면 구음장애가 있는 사용자의 음성이 제거되어 캡션과 인식이 실패할 수 있습니다. 웹 작성자는 우회 기능이나 감도 제어를 제공하고, 실시간 캡션이 활성화된 경우 노이즈 억제를 강제로 적용하지 않을 것을 권장합니다.

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

§ 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 설계는 일반적으로 에뮬레이션할 수 있는 특정 연산을 호환성을 깨뜨리지 않고 보안, 성능 또는 기타 이유로 더 이상 사용하지 않도록 지정할 수 있게 합니다. 이는 이 명세에 정의된 더 작은 기본 연산으로 정의되는 상위 수준 함수 덕분에 가능합니다. 이를 통해 상위 수준 함수의 네이티브 구현을 polyfill 구현으로 대체할 수 있습니다.

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 확장의 개인정보 보호 영향은 조사 중입니다. [이슈 #836]

5.2. 실행 시간 분석

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

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

5.3. WebGPU 비교

WebGPU와 달리 이 API는 본질적으로 사용자 정의 셰이더 작성을 지원하지 않으므로 셰이더 캐시나 기타 영구 데이터를 이용하는 타이밍 공격에 취약하지 않습니다. 이 API는 브라우저 또는 기반 OS의 기존 셰이더와 저수준 기본 요소를 기반으로 합니다. GPUDevice와 상호작용하는 웹 개발자는 WebGPU 컴파일 캐시 고려 사항을 알고 있어야 합니다.

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

일반적으로 이 API의 구현자는 적용 가능한 경우 WebGPU 개인정보 보호 고려 사항을 구현에 적용해야 합니다.

6. 윤리적 고려 사항

워킹 그룹은 규범적 명세에서 고려해야 할 완화책을 식별하는 데 도움을 주기 위해 웹에서 머신 러닝을 사용하는 것과 관련된 윤리적 문제를 문서화하기 시작했습니다. 워킹 그룹은 웹 머신 러닝을 위한 윤리 원칙 문서 [webmachinelearning-ethics]를 게시하고 유지하며, 전용 GitHub 저장소를 통해 더 넓은 커뮤니티의 기여를 받습니다.

7. 프로그래밍 모델

7.1. 개요

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

MLGraph 인터페이스는 변경할 수 없는 컴파일된 계산 그래프(즉, 모델)를 나타냅니다.

MLGraphBuilder 인터페이스는 계산 그래프(그 그래프)를 구성하기 위한 빌더(팩터리) 역할을 하며, 이후 이를 컴파일하여 MLGraph를 생성합니다.

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

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

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

dispatch() 중 오류를 보고하는 메커니즘을 추가하는 것을 고려하십시오. [이슈 #778]

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

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

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

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

MLGraph의 기반 구현은 MLGraphBuilder연산자MLOperand에 대응하는 연산자와 피연산자의 플랫폼별 표현으로 구성되지만, 이러한 표현은 스크립트에 표시되지 않으며 스크립트가 구성한 그래프를 결합하거나 분해한 형태일 수 있습니다.

MLGraph가 구성되면 MLContext.dispatch() 메서드는 CPU 실행의 경우 별도의 워커 스레드에 있는 병렬 타임라인에서, GPU 실행의 경우 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, Transformer 및 생성형 모델에 필요한 연산자 집합을 정의합니다. 각 연산자의 세부 사항은 이 명세의 규범적 섹션에서 연산자 이름의 알파벳순으로 정의됩니다. 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(), roundEven(), sin(), sqrt(), tan(), tanh(), sign(), clamp()
논리 equal(), notEqual(), greater(), greaterOrEqual(), lesser(), lesserOrEqual(), logicalNot(), logicalAnd(), logicalOr(), logicalXor(), isNaN(), isInfinite()
행렬 곱셈 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 태스크를 큐에 넣으려면, 전역 태스크를 큐에 넣기ML 태스크 소스에서 globalsteps를 사용하여 수행합니다.

7.5. Permissions Policy 통합

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

8. API

8.1. navigator.ml 인터페이스

ML 객체는 각각 NavigatorWorkerNavigator 인터페이스를 통해 WindowWorkerGlobalScope 컨텍스트에서 사용할 수 있으며 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]]을 지원할 수 없으면 실패를 반환합니다.

  5. context를 반환합니다.

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

  2. realmthis관련 realm으로 둡니다.

  3. global연관된 Document사용이 허용되지 않은 webnn 기능이면 realm에서 "SecurityError" DOMException으로 거부된 새 promise를 반환합니다.

  4. promiserealm새 promise로 둡니다.

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

    1. contextrealmoptions이 주어진 상태에서 컨텍스트를 생성한 결과로 둡니다. 실패가 반환되면 global을 사용하여 ML 태스크를 큐에 넣어 promise를 "NotSupportedError" DOMException으로 거부하고 이 단계를 중단합니다.

    2. global을 사용하여 ML 태스크를 큐에 넣어 promisecontext이행합니다.

  6. promise를 반환합니다.

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

  2. realmthis관련 realm으로 둡니다.

  3. global연관된 Document사용이 허용되지 않은 webnn 기능이면 realm에서 "SecurityError" DOMException으로 거부된 새 promise를 반환합니다.

  4. promiserealm새 promise로 둡니다.

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

    1. contextrealmgpuDevice가 주어진 상태에서 컨텍스트를 생성한 결과로 둡니다. 실패가 반환되면 global을 사용하여 ML 태스크를 큐에 넣어 promise를 "NotSupportedError" DOMException으로 거부하고 이 단계를 중단합니다.

    2. global을 사용하여 ML 태스크를 큐에 넣어 promisecontext이행합니다.

  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> createExportableTensor(
    MLTensorDescriptor descriptor, GPUDevice gpuDevice);
  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);

  GPUBuffer exportToGPU(MLTensor tensor);

  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의 기반 실행 장치를 더 이상 사용할 수 없을 때 이행되는 Promise입니다.

[[timeline]]

MLContext의 계산 장치에서 연산을 실행하는 것과 연관된 타임라인입니다. 이러한 연산에는 계산 그래프에 대한 추론 및 MLTensor[[data]] 수정이 포함됩니다.

이 타임라인을 더 엄밀하게 정의하십시오. [이슈 #529]

컨텍스트 유형은 리소스를 관리하고 신경망 그래프의 컴파일 및 실행을 지원하는 실행 컨텍스트의 유형입니다.

"default"
사용자 선호 옵션에 따라 생성된 컨텍스트입니다.
"webgpu"
WebGPU 장치에서 생성된 컨텍스트입니다.
accelerated getter 단계는 this.[[accelerated]]를 반환하는 것입니다.
AllowSharedBufferSource bufferSourceMLOperandDescriptor descriptor가 주어졌을 때 descriptor를 사용하여 buffer를 검증하려면 다음 단계를 실행합니다.
  1. bufferSource바이트 길이descriptor바이트 길이와 같지 않으면 false를 반환합니다.

  2. bufferSource의 유형에 따라 분기합니다.

    ArrayBuffer

    true를 반환합니다.

    SharedArrayBuffer

    true를 반환합니다.

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

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

    3. false를 반환합니다.

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

record<USVString, MLOperandDescriptor> namedDescriptors를 사용하여 MLNamedTensors namedTensors가 주어졌을 때 descriptor를 사용하여 tensor를 검증하려면:
  1. namedTensors크기namedDescriptors크기와 같지 않으면 false를 반환합니다.

  2. namedTensors의 각 nametensor에 대해 각각:

    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() 자체는 그래프 실행이 완료되었다는 신호를 제공하지 않습니다. 대신 호출자는 출력 tensor를 다시 읽은 결과를 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합니다.

    3. tensor내보내진 상태이면 TypeErrorthrow합니다.

  6. inputsgraph.[[inputDescriptors]]가 주어진 상태에서 descriptor를 사용하여 tensor를 검증한 결과가 false이면 TypeErrorthrow합니다.

  7. outputsgraph.[[outputDescriptors]]가 주어진 상태에서 descriptor를 사용하여 tensor를 검증한 결과가 false이면 TypeErrorthrow합니다.

  8. 다음 단계를 graph.[[context]].[[timeline]]에 큐잉합니다.

    1. 다음 단계를 실행하되, this손실될 때 중단합니다.

      1. inputsoutputs을 사용하여 graph.[[implementation]]에 계산 요청을 발행합니다.

        그래프 실행 중 오류를 보고하는 메커니즘을 추가하십시오. [이슈 #778]

tensor를 사용하여 상수 피연산자를 생성한 경우 build가 완료된 후 해당 tensor를 파기하는 것은 허용됩니다. 구현은 이러한 파기로 인해 컴파일된 그래프가 영향을 받지 않고 유효한 상태를 유지하도록 해야 합니다.

8.3.1.1. 예제
다음 코드는 MLTensor를 사용하여 MLGraph를 실행하는 방법을 보여줍니다.
const descriptor = {
  dataType: 'float32',
  shape: [2, 2]
};
const context = await navigator.ml.createContext();
const builder = new MLGraphBuilder(context);

// 1. 계산 그래프 '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. 그래프를 컴파일합니다.
const graph = await builder.build({'C': C});

// 3. 재사용 가능한 입력 및 출력 tensor를 생성합니다.
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. 입력을 초기화합니다.
context.writeTensor(inputTensorA, new Float32Array(4).fill(1.0));
context.writeTensor(inputTensorB, new Float32Array(4).fill(0.8));

// 5. 그래프를 실행합니다.
const inputs = {
  'A': inputTensorA,
  'B': inputTensorB
};
const outputs = {
  'C': outputTensorC
};
context.dispatch(graph, inputs, outputs);

// 6. 계산된 결과를 다시 읽습니다.
const result = await context.readTensor(outputTensorC);
console.log('출력 값:', new Float32Array(result));  // [1, 1, 1, 1]

8.3.2. createTensor()

MLContext와 연관된 MLTensor를 생성합니다.

인수:

반환: Promise<MLTensor>.

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

  2. realmthis관련 realm으로 둡니다.

  3. this손실된 상태이면 realm에서 "InvalidStateError" DOMException으로 거부된 새 promise를 반환합니다.

  4. tensorthisdescriptor가 주어진 상태에서 MLTensor를 생성한 결과로 둡니다.

  5. promiserealm새 promise로 둡니다.

  6. 다음 단계를 this.[[timeline]]에 큐잉합니다.

    1. 다음 단계를 실행하되, this손실될 때 중단합니다.

      1. descriptor를 사용하여 tensor.[[data]]를 생성하고 모든 바이트를 0으로 초기화합니다.

      2. 실패하면 global을 사용하여 ML 태스크를 큐에 넣어 promise를 "UnknownError" DOMException으로 거부하고 이 단계를 중단합니다.

      3. 그렇지 않으면 global을 사용하여 ML 태스크를 큐에 넣어 promisetensor이행합니다.

    2. 중단된 경우, global을 사용하여 ML 태스크를 큐에 넣어 promise를 "InvalidStateError" DOMException으로 거부합니다.

  7. promise를 반환합니다.

8.3.3. createExportableTensor()

MLContext와 연관되고 exportToGPU()를 사용하여 주어진 GPUDevice로 내보낼 수 있는 MLTensor를 생성합니다.

인수:

반환: Promise<MLTensor>.

createExportableTensor(descriptor, gpuDevice) 메서드의 단계는 다음과 같습니다.
  1. globalthis관련 전역 객체로 둡니다.

  2. realmthis관련 realm으로 둡니다.

  3. this손실된 상태이면 realm에서 "InvalidStateError" DOMException으로 거부된 새 promise를 반환합니다.

  4. gpuDevice가 손실된 상태이면 realm에서 새 promise를 반환하며, 이 promise는 "InvalidStateError" DOMException으로 거부됩니다.

  5. thisMLTensorgpuDevice로 내보내는 것을 지원할 수 없으면 realm에서 새 promise를 반환하며, 이 promise는 "NotSupportedError" DOMException으로 거부됩니다.

    참고: MLContext가 주어진 GPUDevice로의 내보내기를 지원하는지 여부는 구현 정의이며, MLContext컨텍스트 유형과 기반 플랫폼에 따라 달라질 수 있습니다.

  6. tensorthis, descriptorgpuDevice가 주어진 상태에서 내보낼 수 있는 MLTensor를 생성한 결과로 둡니다.

  7. promiserealm새 promise로 둡니다.

  8. 다음 단계를 this.[[timeline]]에 큐잉합니다.

    1. 다음 단계를 실행하되, this손실될 때 중단합니다.

      1. descriptor를 사용하여 tensor.[[data]]를 생성하고 모든 바이트를 0으로 초기화합니다.

      2. 실패하면 global을 사용하여 ML 태스크를 큐에 넣어 promise를 "UnknownError" DOMException으로 거부하고 이 단계를 중단합니다.

      3. 그렇지 않으면 global을 사용하여 ML 태스크를 큐에 넣어 promisetensor이행합니다.

    2. 중단된 경우, global을 사용하여 ML 태스크를 큐에 넣어 promise를 "InvalidStateError" DOMException으로 거부합니다.

  9. promise를 반환합니다.

8.3.4. createConstantTensor()

MLContext와 연관된 상수 MLTensor를 생성합니다.

인수:

반환: Promise<MLTensor>입니다.

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

  2. realmthis관련 realm으로 둡니다.

  3. this손실된 상태이면 realm에서 "InvalidStateError" DOMException으로 거부된 새 promise를 반환합니다.

  4. descriptor가 주어진 상태에서 차원을 검사한 결과가 false이면 realm에서 TypeError거부된 새 promise를 반환합니다.

  5. inputDatadescriptor가 주어진 상태에서 descriptor를 사용하여 buffer를 검증한 결과가 false이면 realm에서 TypeError거부된 새 promise를 반환합니다.

  6. bytesinputData가 주어진 상태에서 buffer source가 보유한 바이트의 복사본을 가져온 결과로 둡니다.

  7. 단언: bytes길이descriptor바이트 길이와 같습니다.

  8. tensorthisdescriptor가 주어진 상태에서 상수 MLTensor를 생성한 결과로 둡니다.

  9. promiserealm새 promise로 둡니다.

  10. 다음 단계를 this.[[timeline]]에 큐잉합니다.

    1. 다음 단계를 실행하되, this손실될 때 중단합니다.

      1. descriptor가 주어진 상태에서 tensor.[[data]]를 생성합니다.

      2. 실패하면 global을 사용하여 ML 태스크를 큐에 넣어 promise를 "UnknownError" DOMException으로 거부하고 이 단계를 중단합니다.

      3. bytestensor.[[data]]에 복사합니다.

      4. 실패하면 global을 사용하여 ML 태스크를 큐에 넣어 promise를 "UnknownError" DOMException으로 거부하고 이 단계를 중단합니다.

      5. 그렇지 않으면 global을 사용하여 ML 태스크를 큐에 넣어 promisetensor이행합니다.

    2. 중단된 경우, global을 사용하여 ML 태스크를 큐에 넣어 promise를 "InvalidStateError" DOMException으로 거부합니다.

  11. promise를 반환합니다.

8.3.5. readTensor(tensor)

MLContext.[[timeline]]에서 MLTensor[[data]]를 스크립트로 다시 읽습니다.

인수:

반환: Promise<ArrayBuffer>입니다. 읽기 결과를 포함하는 buffer입니다.

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

  2. realmthis관련 realm으로 둡니다.

  3. tensor.[[context]]this가 아니면 realm에서 TypeError거부된 새 promise를 반환합니다.

  4. tensor.[[isDestroyed]] 가 true이면 realm에서 TypeError거부된 새 promise를 반환합니다.

  5. tensor.[[descriptor]].readable 이 false이면 realm에서 TypeError거부된 새 promise를 반환합니다.

  6. tensor내보내진 상태이면 realm에서 TypeError거부된 새 promise를 반환합니다.

  7. promiserealm새 promise로 둡니다.

  8. promisetensor.[[pendingPromises]]추가합니다.

  9. 다음 단계를 tensor.[[context]].[[timeline]]에 큐잉합니다.

    1. 다음 단계를 실행하되, this손실될 때 중단합니다.

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

      2. 실패하면 global을 사용하여 ML 태스크를 큐에 넣고 다음 단계를 수행합니다.

        1. promisetensor.[[pendingPromises]]에서 제거합니다.

        2. promise를 "UnknownError" DOMException으로 거부하고 이 단계를 중단합니다.

      3. 그렇지 않으면 global을 사용하여 ML 태스크를 큐에 넣고 다음 단계를 수행합니다.

        1. promisetensor.[[pendingPromises]]에서 제거합니다.

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

        3. promisebuffer이행합니다.

    2. 중단된 경우, global을 사용하여 ML 태스크를 큐에 넣어 promise를 "InvalidStateError" DOMException으로 거부합니다.

  10. promise를 반환합니다.

8.3.6. readTensor(tensor, outputData)

readTensor(tensor)의 자체 buffer 제공 변형입니다. MLTensor[[data]]를 제공된 buffer로 다시 읽습니다.

인수:

반환: Promise<undefined>입니다.

readTensor(tensor, outputData) 메서드의 단계는 다음과 같습니다.
  1. globalthis관련 전역 객체로 둡니다.

  2. realmthis관련 realm으로 둡니다.

  3. tensor.[[context]]this가 아니면 realm에서 TypeError거부된 새 promise를 반환합니다.

  4. tensor.[[isDestroyed]] 가 true이면 realm에서 TypeError거부된 새 promise를 반환합니다.

  5. tensor.[[descriptor]].readable 이 false이면 realm에서 TypeError거부된 새 promise를 반환합니다.

  6. tensor내보내진 상태이면 realm에서 TypeError거부된 새 promise를 반환합니다.

  7. outputDatatensor.[[descriptor]]가 주어진 상태에서 descriptor를 사용하여 buffer를 검증한 결과가 false이면 realm에서 TypeError거부된 새 promise를 반환합니다.

  8. promiserealm새 promise로 둡니다.

  9. promisetensor.[[pendingPromises]]추가합니다.

  10. 다음 단계를 tensor.[[context]].[[timeline]]에 큐잉합니다.

    1. 다음 단계를 실행하되, this손실될 때 중단합니다.

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

      2. 실패하면 global을 사용하여 ML 태스크를 큐에 넣어 다음 단계를 실행합니다.

        1. promisetensor.[[pendingPromises]]에서 제거합니다.

        2. promise를 "UnknownError" DOMException으로 거부하고 이 단계를 중단합니다.

      3. 그렇지 않으면 global을 사용하여 ML 태스크를 큐에 넣어 다음 단계를 실행합니다.

        1. promisetensor.[[pendingPromises]]에서 제거합니다.

        2. outputData분리된 상태이면 promiseTypeError거부하고 이 단계를 중단합니다.

          참고: 위의 descriptor를 사용한 buffer 검증outputData가 분리된 상태이면 실패하지만, 해당 단계와 이 단계 사이에 outputData가 분리될 수도 있습니다.

        3. bytesoutputData기록합니다.

        4. promiseundefined이행합니다.

    2. 중단된 경우, global을 사용하여 ML 태스크를 큐에 넣어 promise를 "InvalidStateError" DOMException으로 거부합니다.

  11. promise를 반환합니다.

8.3.7. writeTensor()

MLContext[[timeline]]에서 MLTensor[[data]]에 데이터를 기록합니다.

인수:

반환: undefined입니다.

writeTensor(tensor, inputData) 메서드의 단계는 다음과 같습니다.
  1. tensor.[[context]]this가 아니면 TypeErrorthrow합니다.

  2. tensor.[[isDestroyed]] 가 true이면 TypeErrorthrow합니다.

  3. tensor.[[descriptor]].writable 이 false이면 TypeErrorthrow합니다.

  4. tensor내보내진 상태이면 TypeErrorthrow합니다.

  5. inputDatatensor.[[descriptor]]가 주어진 상태에서 descriptor를 사용하여 buffer를 검증한 결과가 false이면 TypeErrorthrow합니다.

  6. bytesinputData가 주어진 상태에서 buffer source가 보유한 바이트의 복사본을 가져온 결과로 둡니다.

  7. 단언: bytes길이tensor.[[descriptor]]바이트 길이와 같습니다.

  8. 다음 단계를 tensor.[[context]].[[timeline]]에 큐잉합니다.

    1. 다음 단계를 실행하되, this손실될 때 중단합니다.

      1. bytestensor.[[data]]에 복사합니다.

        tensor에 기록하는 동안 오류를 보고하는 메커니즘을 추가하십시오. [이슈 #778]

참고: dispatch()와 마찬가지로 writeTensor() 자체는 기록이 완료되었다는 신호를 제공하지 않습니다. tensor의 내용을 검사하려면 호출자는 tensor를 다시 읽은 결과를 await할 수 있습니다.

8.3.8. exportToGPU()

내보낼 수 있는 MLTensor를 연관된 GPUDeviceGPUBuffer로 내보내고, 반환된 GPUBuffer가 파기될 때까지 해당 GPUDevice에 이를 대여합니다.

인수:

반환: GPUBuffer입니다.

MLTensor내보내진 상태인 동안 [[gpuDevice]]MLTensor의 내용에 독점적으로 접근하며, MLTensor에 의존하는 모든 WebNN 연산 — dispatch(), readTensor(tensor), readTensor(tensor, outputData), 및 writeTensor() — 은 TypeError를 throw합니다.

반환된 GPUBufferGPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DSTusageMLTensor[[descriptor]]바이트 길이와 같은 size로 생성됩니다. 반환된 GPUBuffer가 파기되면 MLTensorMLContext반환되며 WebNN 연산에서 다시 사용할 수 있습니다.

참고: MLTensor 내보내기가 zero-copy라는 보장은 없습니다. MLTensor을 뒷받침하는 메모리에 [[gpuDevice]]가 접근할 수 없다면 내보내기에는 MLTensor의 내용을 반환되는 GPUBuffer로 복사하고, GPUBuffer가 파기되면 다시 복사해야 할 수 있습니다.

exportToGPU(tensor) 메서드의 단계는 다음과 같습니다.
  1. tensor.[[context]]this가 아니면 TypeErrorthrow합니다.

  2. tensor.[[isDestroyed]] 가 true이면 TypeErrorthrow합니다.

  3. tensor.[[exportableToGPU]] 가 false이면 TypeErrorthrow합니다.

  4. realmthis관련 realm으로 둡니다.

  5. gpuDevicetensor.[[gpuDevice]]로 둡니다.

  6. gpuDevice가 손실된 상태이면 "InvalidStateError" DOMExceptionthrow합니다.

  7. tensor내보내진 상태이면 tensor.[[exportedBuffer]]를 반환합니다.

  8. usageGPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST로 둡니다.

  9. bufferrealm에서 gpuDevice와 연관된 새로운 GPUBuffer로 두며, 그 sizetensor.[[descriptor]]바이트 길이이고, 그 usageusage입니다.

  10. 다음 단계를 tensor.[[context]].[[timeline]]에 큐잉합니다.

    1. 다음 단계를 실행하되, this손실될 때 중단합니다.

      1. buffer의 내용이 tensor.[[data]]를 반영하도록 합니다.

        참고: 내보내기가 zero-copy이면 buffertensor.[[data]]는 동일한 메모리를 기반으로 하며 복사가 수행되지 않습니다.

  11. tensor.[[exportedBuffer]]buffer로 설정합니다.

  12. buffer를 반환합니다.

사용자 에이전트는 위에서 큐잉된, buffer의 내용이 tensor.[[data]]를 반영하도록 하는 단계가 완료되기 전에 buffer에서 읽거나 buffer에 쓰는 gpuDeviceGPUQueue에 큐잉된 연산이 실행되지 않도록 반드시 보장해야 합니다.

참고: 이 순서 보장은 사용자 에이전트 내부의 것이며, 애플리케이션 측에서 관찰 가능한 동기화를 수행할 필요가 없습니다. 애플리케이션은 exportToGPU()가 반환된 직후 buffer를 사용하는 GPUQueue 작업을 안전하게 기록하고 제출할 수 있습니다.

exportToGPU()가 반환한 GPUBuffer가 파기되면 사용자 에이전트는 내보낸 원본 MLTensor가 주어진 상태에서 반드시 내보낸 MLTensor를 반환해야 합니다.

참고: MLTensor 또는 해당 MLContext내보낸 상태인 동안 파괴해도 반환된 GPUBuffer는 무효화되지 않습니다; GPUBuffer는 파괴될 때까지 [[gpuDevice]]에서 계속 사용할 수 있습니다.

참고: MLTensor내보내진 상태인 동안 [[gpuDevice]]가 손실된 상태가 되더라도 반환된 GPUBuffer는 암묵적으로 파기되지 않으며, MLTensor는 애플리케이션이 destroy()를 호출할 때까지 내보내진 상태로 유지됩니다 (따라서 WebNN 연산에서는 사용할 수 없습니다). destroy()gpuDevice가 손실된 후에도 계속 유효하게 호출할 수 있습니다.

8.3.8.1. 예제
다음 코드는 내보낼 수 있는 tensor를 사용하는 최소한의 WebNN에서 WebGPU로의 흐름을 보여줍니다.
// 1. WebGPU 및 WebNN 컨텍스트를 생성합니다.
const gpuAdapter = await navigator.gpu.requestAdapter();
const gpuDevice = await gpuAdapter.requestDevice();
const context = await navigator.ml.createContext();

// 2. 간단한 그래프를 빌드합니다: y = x + 1.
const builder = new MLGraphBuilder(context);
const descriptor = {dataType: 'float32', shape: [4]};
const x = builder.input('x', descriptor);
const one = builder.constant(descriptor, new Float32Array([1, 1, 1, 1]));
const y = builder.add(x, one);
const graph = await builder.build({y});

// 3. 내보낼 수 있는 tensor를 생성하고 WebNN dispatch를 실행합니다.
const inputTensor = await context.createExportableTensor(
    {dataType: 'float32', shape: [4], writable: true}, gpuDevice);
const outputTensor = await context.createExportableTensor(
    {dataType: 'float32', shape: [4], readable: true}, gpuDevice);
context.writeTensor(inputTensor, new Float32Array([1, 2, 3, 4]));
context.dispatch(graph, {x: inputTensor}, {y: outputTensor});

// 4. WebGPU로 내보내고 GPU 명령에서 사용합니다.
const gpuBuffer = context.exportToGPU(outputTensor);
// ... WebGPU 계산/렌더링 작업에서 gpuBuffer를 사용합니다 ...

// 5. tensor를 WebNN으로 반환한 다음 WebNN에서 다시 읽습니다.
gpuBuffer.destroy();
const result = new Float32Array(await context.readTensor(outputTensor));
console.log(result);  // [2, 3, 4, 5]

8.3.9. opSupportLimits()

opSupportLimits()는 구현마다 연산자 수준에서 달라지는 지원 수준을 노출합니다. WebNN API 사용자는 각 대상 플랫폼에 배포할 최적의 모델 아키텍처를 결정하기 위해 opSupportLimits()를 사용하여 기능 지원 수준을 확인하는 것이 좋습니다.

참고: opSupportLimits() API는 브라우저 핑거프린팅을 위한 추가 엔트로피를 제공하기 위한 것이 아닙니다. 현재 구현에서는 이 기능 지원 정보를 OS와 브라우저 버전만으로 추론할 수 있습니다. 향후 구현의 다양성이 이를 필요로 한다면, 이 API는 향후 구현에서 엔트로피를 줄이기 위해 예를 들어 WebGPU와 유사하게 기능을 버킷화하는 새로운 개인정보 보호 완화책을 추가할 수 있도록 합니다.

핑거프린팅 고려 사항에 대한 추가 논의는 § 5 개인정보 보호 고려 사항을 참조하십시오.

8.3.9.1. MLOpSupportLimits dictionary
MLOpSupportLimits에는 다음과 같은 최상위 멤버가 있으며, 이들 외에도 각 연산자에는 해당 빌더 메서드에 정의된 대응 멤버가 있습니다.
dictionary MLOpSupportLimits {
  MLInputOperandLayout preferredInputLayout;
  [EnforceRange] unsigned long long maxTensorByteLength;
  MLTensorLimits input;
  MLTensorLimits constant;
  MLTensorLimits output;
};
preferredInputLayout, 유형은 MLInputOperandLayout

conv2d()와 같이 레이아웃에 의존하는 연산자의 선호 입력 레이아웃입니다.

maxTensorByteLength, 유형은 unsigned long long

지원되는 tensor의 최대 길이(바이트 단위)입니다.

input, 유형은 MLTensorLimits

MLGraph의 입력 MLOperand에 대한 지원 제한입니다.

constant, 유형은 MLTensorLimits

MLGraph의 상수 MLOperand에 대한 지원 제한입니다.

output, 유형은 MLTensorLimits

MLGraph의 출력 MLOperand에 대한 지원 제한입니다.

8.3.9.2. MLRankRange dictionary
dictionary MLRankRange {
  unsigned long min;
  unsigned long max;
};
min, 유형은 unsigned long

지원되는 최소 rank입니다.

max, 유형은 unsigned long

지원되는 최대 rank입니다.

8.3.9.3. MLTensorLimits dictionary
typedef sequence<MLOperandDataType> MLDataTypeList;

dictionary MLTensorLimits {
  MLDataTypeList dataTypes;
  MLRankRange rankRange;
};
dataTypes, 유형은 MLDataTypeList

지원되는 데이터 유형입니다.

rankRange, 유형은 MLRankRange

지원되는 최소 및 최대 rank입니다.

8.3.9.4. MLBinarySupportLimits dictionary
dictionary MLBinarySupportLimits {
  MLTensorLimits a;
  MLTensorLimits b;
  MLTensorLimits output;
};
a, 유형은 MLTensorLimits

a operand에 대한 MLTensorLimits입니다.

b, 유형은 MLTensorLimits

b operand에 대한 MLTensorLimits입니다.

output, 유형은 MLTensorLimits

출력 operand에 대한 MLTensorLimits입니다.

8.3.9.5. MLSingleInputSupportLimits dictionary
dictionary MLSingleInputSupportLimits {
  MLTensorLimits input;
  MLTensorLimits output;
};
input, 유형은 MLTensorLimits

입력 operand에 대한 MLTensorLimits입니다.

output, 유형은 MLTensorLimits

출력 operand에 대한 MLTensorLimits입니다.

8.3.10. destroy()

destroy() 메서드를 호출하여 컨텍스트와 관련된 모든 리소스를 해제할 수 있습니다. 미처리된 모든 계산 요청과 MLTensor 생성/읽기/쓰기 요청은 실패합니다.

destroy() 메서드의 단계는 다음과 같습니다.
  1. this손실된 상태이면 이 단계를 중단합니다.

  2. 구현 정의 메시지를 사용하여 this손실시키는 단계를 실행합니다.

    참고: destroy()가 호출되었음을 나타내는 메시지는 개발자가 컨텍스트 손실의 원인을 구별하는 데 도움이 될 수 있습니다.

8.3.11. 오류

사용자 에이전트가 MLContext를 더 이상 요청 처리에 사용할 수 없다고 판단하면 해당 컨텍스트에 대해 컨텍스트 손실 단계를 실행해야 합니다.

MLContext context에 대한 컨텍스트 손실 단계는 다음과 같습니다.
  1. globalcontext관련 전역 객체로 둡니다.

  2. global을 사용하여 ML 태스크를 큐에 넣고 다음 단계를 실행합니다.

    1. 구현 정의 메시지를 사용하여 context손실시킵니다.

DOMString message를 사용하여 MLContext context손실시키려면:
  1. info를 새로운 MLContextLostInfo로 둡니다.

  2. info.messagemessage로 설정합니다.

  3. context.[[lost]]info이행합니다.

  4. graph.[[context]]this와 같은 각 MLGraph graph에 대해:

    1. graphthis로 하여 graph에 대한 destroy() 메서드 단계를 실행합니다.

  5. tensor.[[context]]this와 같은 각 MLTensor tensor에 대해:

    1. tensorthis로 하여 tensor에 대한 destroy() 메서드 단계를 실행합니다.

message, 유형은 DOMString

발생한 오류에 대한 정보를 제공하는 구현 정의 메시지입니다.

lost getter 단계는 this[[lost]] Promise를 반환합니다.

MLContext 손실된 상태인 것은 해당 [[lost]] Promisesettled 상태인 경우입니다.

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동일한 하나의 MLOperandDescriptor B인 것은 A.dataType과 동일한 것이 B.dataType이고 A.shape동일한 것은 B.shape인 경우입니다.
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. elementSizedesc.dataType이 표에 따라 일치하는 ArrayBufferView 유형 중 하나의 요소 크기로 둡니다.

  4. elementLength * elementSize를 반환합니다.

MLOperandDescriptor desc요소 수는 다음 단계에서 반환되는 값입니다.
  1. elementCount를 1로 둡니다.

  2. desc.shape의 각 dimension에 대해 각각:

    1. elementCountelementCount * dimension으로 설정합니다.

  3. elementCount를 반환합니다.

유효한 차원은 0보다 크고 long 범위에 있는 정수입니다. 구현은 더 작은 상한을 적용할 수 있습니다.

유효한 tensor 수는 0보다 크고 8192 이하인 정수입니다. 구현은 더 작은 상한을 적용할 수 있습니다.

크기가 0인 차원을 지원해야 합니까? [이슈 #391]

MLOperandDescriptor descriptor가 주어졌을 때 차원을 검사하려면 다음 단계를 실행합니다.
  1. descriptor.shape항목 중 하나라도 유효한 차원이 아니면 false를 반환합니다.

  2. descriptor.shape크기가 구현에서 지원하기에 너무 크면 false를 반환합니다.

    피연산자 차원의 최대 개수는 정의되어 있지 않지만, 네이티브 ML API에는 일반적으로 지원되는 최대 크기가 있습니다. [이슈 #456]

  3. descriptor요소 수유효한 차원이 아니면 false를 반환합니다.

  4. descriptor바이트 길이가 구현에서 지원되지 않으면 false를 반환합니다.

  5. true를 반환합니다.

8.6. MLOperand 인터페이스

MLOperand는 연산의 여러 부분을 완전히 구성된 연산으로 조합한 결과로 구성 중인 중간 그래프를 나타냅니다.

예를 들어 MLOperand는 연산에 입력되는 상수 또는 여러 상수를 하나의 연산으로 결합한 결과를 나타낼 수 있습니다. § 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와 연관된 builder 객체입니다.

[[descriptor]]의 유형은 MLOperandDescriptor입니다.

MLOperand의 descriptor입니다.

[[name]]의 유형은 문자열입니다.

MLOperand의 이름입니다(입력 피연산자에만 해당합니다).

[[operator]]의 유형은 연산자입니다.

MLOperand에 대응하는 연산자에 대한 참조입니다.

[[constantTensor]]의 유형은 MLTensor입니다.

MLOperand의 tensor입니다(상수 피연산자에만 해당합니다).

MLOperanddataType은 해당 [[descriptor]].dataType입니다.

MLOperandshape은 해당 [[descriptor]].shape입니다.

MLOperandrank는 해당 shape크기입니다.

dataType getter 단계thisdataType을 반환합니다.

shape getter 단계thisshape을 반환합니다.

[[builder]] 객체는 MLGraphBuilder() 생성자에 의해 MLContext 객체에 바인딩되므로, MLOperand도 항상 동일한 MLContext 객체에 바인딩됩니다.

연산이 MLOperandDataType의 일부만 지원하는 경우, 위치 인수와 옵션을 모두 포함하여 연산의 각 입력 피연산자에 대한 허용되는 데이터 유형MLOperandDataType의 명시적 목록으로 제공되거나, 피연산자의 dataType이 다른 입력 피연산자의 dataType같아야 한다는 제약 조건으로 제공되거나, 모든 MLOperandDataType을 허용하기 위해 임의의 유형으로 제공됩니다.

구현은 명시된 것보다 더 적은 피연산자 데이터 유형을 지원할 수 있지만, 최소한 명시된 필수 데이터 유형은 반드시 지원해야 합니다. 현재 Chromium 프로토타입의 ONNX Runtime, LiteRT 및 CoreML 백엔드 전반에서 각 연산에 대한 지원 여부는 MLContextopSupportLimits() 메서드를 사용하고 연산에 대응하는 멤버의 dataTypes 값을 검사하여 조회할 수 있습니다.

필수 데이터 유형 집합은 개발자가 이러한 데이터 유형만 사용하도록 모델을 설계하여 상호운용 가능한 콘텐츠를 만들 수 있도록 광범위한 플랫폼에서의 구현 경험을 기반으로 결정되었습니다. 이 명세의 Web Platform Tests는 이 기능 감지 메커니즘을 사용하여 모든 허용되는 데이터 유형에 대해 올바른 동작을 검증하지만, 필수 데이터 유형만 지원해도 통과할 수 있습니다.

연산에 특정 rank의 입력 피연산자가 필요한 경우, 위치 인수와 옵션을 모두 포함하여 연산의 각 입력 피연산자에 대한 허용되는 rank는 명시적인 rank(예: 1), 임의의 차원 수를 허용하는 N, 또는 다른 피연산자와 동일한 rank로 제공됩니다. 입력 피연산자의 shape이 다른 입력 피연산자에 대해 단방향 브로드캐스트 가능해야 하거나 다른 입력 피연산자와 양방향 브로드캐스트 가능해야 하는 경우처럼 더 구체적인 제약 조건도 일반적입니다. 이러한 경우 허용되는 rank는 범위로 나열되며 구체적인 검증은 연산의 단계로 제공됩니다.

구현은 피연산자의 rank에 대해 명시된 것보다 더 제한적인 하한 및/또는 상한을 적용할 수 있지만, 최소한 명시된 필수 rank는 반드시 지원해야 합니다. 현재 Chromium 프로토타입의 ONNX Runtime, LiteRT 및 CoreML 백엔드 전반에서 각 연산에 대한 지원 여부는 MLContextopSupportLimits() 메서드를 사용하고 연산에 대응하는 멤버의 rankRange.minrankRange.max 값을 검사하여 조회할 수 있습니다.

필수 rank 집합은 개발자가 이러한 rank의 입력 피연산자로만 구성된 모델을 설계하여 상호운용 가능한 콘텐츠를 만들 수 있도록 광범위한 플랫폼에서의 구현 경험을 기반으로 결정되었습니다.

MLOperatorOptions에는 다음 멤버가 있습니다.

label, 유형은 USVString이며 기본값은 ""

MLOperand를 생성하는 MLGraphBuilder 메서드를 사용하여 연산자를 생성할 때 선택적으로 제공됩니다. 구현은 이 값을 사용하여 연산자label을 초기화할 수 있습니다.

참고: label은 자연어 문자열로 사용하기 위한 것이 아닙니다. "mul#1234"와 같이 변수 이름이나 오류 코드와 유사한 언어 독립적인 식별자입니다.

참고: 구현은 개발자가 제공한 label을 사용하여 그래프 구성 중의 동기 오류 및 비동기 build() 메서드 중 발생하는 오류를 포함하여 오류 메시지를 개선하고 디버깅 가능성을 높일 것을 권장합니다.

디버깅 도구, 로그 또는 오류 메시지에 label을 통해 개발자가 제공한 label을 표시할 때 구현은 악의적인 Unicode 시퀀스 삽입과 같은 보안 위험을 방지하도록 출력을 정제해야 합니다(예: 양방향 텍스트 스푸핑 [UTR36], 소스 코드 스푸핑 [UTS55] 및 기타 우려 사항). 예를 들어 구현은 제어 문자(예: U+202A ~ U+202E, U+2066 ~ U+2069)를 이스케이프하거나 필터링하거나 안전한 렌더링 메커니즘을 사용하여 잠재적인 스푸핑을 무력화해야 합니다.

8.6.1. MLOperand 생성

MLOperand 객체는 MLGraphBuilder의 메서드에서 생성되며, 내부적으로 다음 알고리즘을 사용합니다.
MLGraphBuilder builderMLOperandDescriptor desc가 주어졌을 때 MLOperand를 생성하려면 다음 단계를 실행합니다.
  1. realmbuilder관련 realm으로 둡니다.

  2. operandrealm의 새로운 MLOperand로 둡니다.

  3. operand.[[builder]]builder로 설정합니다.

  4. operand.[[descriptor]]desc로 설정합니다.

  5. operand를 반환합니다.

MLOperand operand가 주어졌을 때 MLOperand를 복사하려면 다음 단계를 실행합니다.
  1. builderoperand.[[builder]]로 둡니다.

  2. realmbuilder관련 realm으로 둡니다.

  3. resultrealm의 새로운 MLOperand로 둡니다.

  4. result.[[builder]]builder로 설정합니다.

  5. result.[[descriptor]]operand.[[descriptor]]로 설정합니다.

  6. operand.[[name]]존재하면 result.[[name]]operand.[[name]]으로 설정합니다.

  7. result를 반환합니다.

MLGraphBuilder builderMLOperand 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 이슈 #1388]

8.7. MLTensorDescriptor 딕셔너리

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

dictionary MLTensorDescriptor : MLOperandDescriptor {
  boolean readable = false;
  boolean writable = false;
};
readable, 유형은 boolean이며 기본값은 false

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

writable, 유형은 boolean이며 기본값은 false

writeTensor()를 통해 tensor의 내용을 기록할 수 있는지 여부입니다.

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의 descriptor입니다.

[[pendingPromises]]의 유형은 Promise집합입니다.

진행 중이며 아직 이행되지 않은 MLContext.readTensor(tensor) 메서드 호출에 대응하는 Promise입니다. MLTensor가 파기되면 모든 대기 중인 promise가 거부됩니다.

[[isDestroyed]]의 유형은 boolean입니다.

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

[[data]]의 유형은 구현 정의 유형입니다.

MLTensor을 뒷받침하는 바이트입니다. 이 데이터는 [[context]].[[timeline]]에서만 접근하거나 수정할 수 있습니다.

[[isConstant]]의 유형은 boolean입니다.

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

[[exportableToGPU]]의 유형은 boolean입니다.

MLTensor내보낼 수 있는 MLTensor 생성에 의해 생성되었으며 exportToGPU()를 사용하여 GPUDevice로 내보낼 수 있는지 여부입니다.

[[gpuDevice]]의 유형은 GPUDevice 또는 null입니다.

MLTensor를 내보낼 수 있는 GPUDevice이며, MLTensor를 내보낼 수 없는 경우 null입니다. [[exportableToGPU]] 가 true일 때만 설정됩니다.

[[exportedBuffer]]의 유형은 GPUBuffer 또는 null입니다.

exportToGPU()의 결과로 현재 [[gpuDevice]]에 대여된 GPUBuffer이며, MLTensor가 현재 내보내진 상태가 아니면 null입니다.

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]]을 반환합니다.

하나의 MLTensor내보낸 상태인 것은 해당 [[exportedBuffer]]가 null이 아닌 경우입니다.

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.[[exportableToGPU]] 를 false로 설정합니다.

  8. tensor.[[gpuDevice]] 를 null로 설정합니다.

  9. tensor.[[exportedBuffer]] 를 null로 설정합니다.

  10. tensor를 반환합니다.

MLContext context, MLTensorDescriptor descriptor, 그리고 GPUDevice gpuDevice가 주어졌을 때 내보낼 수 있는 MLTensor를 생성하려면 다음 단계를 실행합니다.
  1. tensorcontextdescriptor가 주어진 상태에서 MLTensor를 생성한 결과로 둡니다.

  2. tensor.[[exportableToGPU]] 를 true로 설정합니다.

  3. tensor.[[gpuDevice]]gpuDevice로 설정합니다.

  4. tensor를 반환합니다.

MLTensor tensor가 주어졌을 때 내보낸 MLTensor를 반환하려면 다음 단계를 실행합니다.
  1. tensor내보내진 상태가 아니면 이 단계를 중단합니다.

  2. buffertensor.[[exportedBuffer]]로 둡니다.

  3. tensor.[[exportedBuffer]] 를 null로 설정합니다.

  4. tensor.[[isDestroyed]] 가 true이면 이 단계를 중단합니다.

  5. 다음 단계를 tensor.[[context]].[[timeline]]에 큐잉합니다.

    1. 다음 단계를 실행하되, tensor.[[context]]손실될 때 중단합니다.

      1. tensor.[[data]]buffer의 내용을 반영하도록 합니다.

        참고: 내보내기가 zero-copy였다면 buffertensor.[[data]]는 동일한 메모리를 기반으로 하며 복사가 수행되지 않습니다.

사용자 에이전트는 위에서 큐잉된, tensor.[[data]]buffer의 내용을 반영하도록 하는 단계가, 이전에 gpuDeviceGPUQueue에 큐잉되어 buffer에서 읽거나 buffer에 쓰는 모든 연산이 완료되기 전에 실행되지 않도록 반드시 보장해야 합니다.

8.8.2. destroy()

MLTensor과 연관된 리소스를 해제합니다. 이 메서드는 멱등적입니다.

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

  2. this.[[pendingPromises]]의 각 promise에 대해 각각:

    1. promisethis.[[pendingPromises]]에서 제거합니다.

    2. promise를 "InvalidStateError" DOMException으로 거부합니다.

  3. 다음 단계를 this.[[context]].[[timeline]]에 큐잉합니다.

    1. this.[[data]]를 해제합니다.

참고: 이 tensor를 사용하여 더 이상 연산을 큐에 넣을 수 없으므로, 구현은 이전에 제출된 이 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.[[exportableToGPU]] 를 false로 설정합니다.

  13. tensor.[[gpuDevice]] 를 null로 설정합니다.

  14. tensor.[[exportedBuffer]] 를 null로 설정합니다.

  15. tensor를 반환합니다.

8.9. MLGraphBuilder 인터페이스

MLGraphBuilder 인터페이스는 § 2 사용 사례에서 식별된 계산 그래프로 조합할 수 있는 연산 집합을 정의합니다. 또한 그래프 빌드 세션의 중간 상태를 나타냅니다.

typedef record<USVString, MLOperand> MLNamedOperands;

[SecureContext, Exposed=(Window, Worker)]
interface MLGraphBuilder {
  // 컨텍스트에서 그래프 빌더를 구성합니다.
  constructor(MLContext context);

  // 그래프 입력용 피연산자를 생성합니다.
  MLOperand input(USVString name, MLOperandDescriptor descriptor);

  // 그래프 상수용 피연산자를 생성합니다.
  MLOperand constant(MLOperandDescriptor descriptor,
                     AllowSharedBufferSource buffer);

  // 지정된 유형의 지정된 숫자로부터 스칼라 피연산자를 생성합니다.
  MLOperand constant(MLOperandDataType dataType, MLNumber value);

  // 지정된 상수 tensor로부터 피연산자를 생성합니다.
  MLOperand constant(MLTensor tensor);

  // 지정된 출력 피연산자까지 그래프를 비동기적으로 컴파일합니다.
  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]]손실된 상태가 아닌 경우입니다.

8.9.1. MLGraphBuilder 생성자

인수:
new MLGraphBuilder(context) 생성자의 단계는 다음과 같습니다.
  1. this관련 전역 객체연관된 Document사용이 허용되지 않은 webnn 기능이면 "SecurityError" DOMExceptionthrow합니다.

  2. context손실된 상태이면 "InvalidStateError" DOMExceptionthrow합니다.

  3. this.[[context]]context로 설정합니다.

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

8.9.2. 입력 피연산자

descriptor를 기반으로 입력으로 사용할 수 있는 이름이 지정된 MLOperand를 생성합니다.

인수: 반환: MLOperand입니다.
input(name, descriptor) 메서드의 단계는 다음과 같습니다.
  1. this빌드할 수 없는 상태이면 "InvalidStateError" DOMExceptionthrow합니다.

  2. name이 비어 있으면 TypeErrorthrow합니다.

  3. this그래프입력에 있는 MLOperand 중 하나라도 [[name]]name과 같으면 TypeErrorthrow합니다.

  4. descriptor가 주어진 상태에서 차원을 검사한 결과가 false이면 TypeErrorthrow합니다.

  5. 그래프 연결을 구성합니다.

    1. operandthisdescriptor가 주어진 상태에서 MLOperand를 생성한 결과로 둡니다.

    2. operand.[[name]]name으로 설정합니다.

    3. operandthis그래프입력에 추가합니다.

  6. operand를 반환합니다.

MLGraphBuilder API는 입력 피연산자 없이 MLGraph를 생성할 수 있도록 합니다. 기반 플랫폼이 이를 지원하지 않는 경우 구현은 더미 입력을 추가하거나 상수를 그래프의 입력으로 전달할 수 있습니다.

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가 주어진 상태에서 descriptor를 사용하여 buffer를 검증한 결과가 false이면 TypeErrorthrow합니다.

  4. 그래프 연결을 구성합니다.

    1. operandthisdescriptor가 주어진 상태에서 MLOperand를 생성한 결과로 둡니다.

    2. bytesbuffer가 주어진 상태에서 buffer source가 보유한 바이트의 복사본을 가져온 결과로 둡니다.

    3. operandthis그래프상수bytes를 값으로 하여 추가합니다.

  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. operandthis그래프상수tensor를 값으로 하여 추가합니다.

  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. operandthis그래프상수value를 값으로 하여 추가합니다.

  5. operand를 반환합니다.

8.9.4. build 메서드

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

  2. this빌드할 수 없는 상태이면 realm에서 "InvalidStateError" DOMException으로 거부된 새 promise를 반환합니다.

  3. outputs가 비어 있으면 realm에서 TypeError거부된 새 promise를 반환합니다.

  4. outputs의 각 nameoperand에 대해 각각:

    1. name이 비어 있으면 realm에서 TypeError거부된 새 promise를 반환합니다.

    2. thisoperand가 주어진 상태에서 피연산자를 검증한 결과가 false이면 realm에서 TypeError거부된 새 promise를 반환합니다.

    3. operandthis그래프입력 또는 상수에 있으면 realm에서 TypeError거부된 새 promise를 반환합니다.

    4. operand.[[constantTensor]] 가 존재하고 operand.[[constantTensor]].[[isDestroyed]] 가 true이면 realm에서 TypeError거부된 새 promise를 반환합니다.

  5. operands를 새로운 빈 집합으로 둡니다.

  6. operators를 새로운 빈 집합으로 둡니다.

  7. inputs를 새로운 빈 집합으로 둡니다.

  8. queueoutputs을 포함하는 새로운 로 둡니다.

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

    1. queue에서 operand디큐합니다.

    2. operandoperands추가합니다.

    3. operand.[[operator]]operators추가합니다.

    4. operandthis그래프입력에 있으면 operandinputs추가합니다.

    5. operand.[[operator]]입력에 있는 각 input에 대해 각각:

      1. inputqueue인큐합니다.

  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]]에 큐잉합니다.

    1. 다음 단계를 실행하되, graph.[[context]]손실될 때 중단합니다.

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

      2. 이전 단계가 실패하면 global을 사용하여 ML 태스크를 큐에 넣어 promise를 "OperationError" DOMException으로 거부하고 이 단계를 중단합니다.

      3. graph.[[implementation]]graphImpl로 설정합니다.

      4. global을 사용하여 ML 태스크를 큐에 넣어 promisegraph이행합니다.

    2. 중단된 경우, global을 사용하여 ML 태스크를 큐에 넣어 promise를 "InvalidStateError" DOMException으로 거부합니다.

  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를 가지며, keepDimensions 가 false이면 inputrank - 1인 출력 N차원 tensor입니다. 값은 outputDataType 유형이어야 하며 [0, N-1] 범위여야 합니다. 여기서 N은 axis로 지정한 입력 차원의 크기입니다.

argMin()/argMax()의 tensor 제한
피연산자 허용되는 데이터 유형 필수 데이터 유형 허용되는 rank 필수 rank
input 모든 유형 "float32", "float16", "int32" 1에서 N까지 1에서 5까지
출력 "int32", "int64" "int32" N 0에서 5까지

MLOpSupportLimits에는 argMin()argMax()에 대해 다음 멤버가 있습니다.

argMin, 유형은 MLSingleInputSupportLimits

argMin() 연산자의 지원 제한입니다.

argMax, 유형은 MLSingleInputSupportLimits

argMax() 연산자의 지원 제한입니다.

문자열 op, MLOperand input, unsigned long axis, 그리고 MLArgMinMaxOptions options가 주어졌을 때 argMin/argMax 연산을 생성하려면 다음 단계를 실행합니다.
  1. 단언: 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가 주어진 상태에서 축소 출력 크기를 계산한 결과로 둡니다. 실패가 반환되면 TypeErrorthrow합니다.

  8. descoptions.outputDataTypeoutputShape가 주어진 상태에서 MLOperandDescriptor를 생성한 결과로 둡니다.

  9. 그래프 연결을 구성합니다.

    1. operatoroptions가 주어진 op 연산에 대한 연산자로 둡니다.

    2. outputthisdesc가 주어진 상태에서 MLOperand를 생성한 결과로 둡니다.

    3. output.[[operator]]operator로 설정합니다.

    4. operator입력input으로 설정합니다.

    5. operator출력output으로 설정합니다.

  10. output을 반환합니다.

다음 argMin/argMax 알고리즘이 지원됩니다.
argMin(input, axis, options) 메서드의 단계는 다음과 같습니다.
  1. output을 "argMin", input, axis, 그리고 options가 주어진 상태에서 argMin/argMax 연산을 생성한 결과로 둡니다.

    1. 오류를 throw하면 해당 오류를 다시 throw합니다.

  2. output을 반환합니다.

argMax(input, axis, options) 메서드의 단계는 다음과 같습니다.
  1. output을 "argMax", input, axis, 그리고 options가 주어진 상태에서 argMin/argMax 연산을 생성한 결과로 둡니다.

    1. 오류를 throw하면 해당 오류를 다시 throw합니다.

  2. output을 반환합니다.

8.9.6. batchNormalization

[Batch-Normalization]을 사용하여 입력 tensor의 값을 정규화합니다. 각 입력 특성에 대해 모델을 학습하는 동안 해당 특성의 평균값과 분산값을 배치 차원의 모든 샘플에 걸쳐 계산합니다. 이후 모델 추론 중에 이러한 평균값과 분산값이 이 연산에 제공됩니다.
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가 나타내는 입력 차원의 크기와 크기가 같은 스케일링 값의 1차원 tensor입니다.

bias, 유형은 MLOperand

axis가 나타내는 입력 차원의 크기와 크기가 같은 바이어스 값의 1차원 tensor입니다.

axis, 유형은 unsigned long이며 기본값은 1

평균값과 분산값이 대응하는 입력 shape의 특성 수 차원에 대한 인덱스입니다. 값은 [0, N-1] 범위여야 하며, 여기서 N은 입력 tensor의 rank입니다. 기본값은 1이며, "nchw" 데이터 레이아웃의 채널("c") 차원에 해당합니다.

epsilon, 유형은 double이며 기본값은 1e-5

0으로 나누어 발생하는 계산 오류를 방지하기 위한 작은 값입니다.

인수:

반환: MLOperand입니다. input과 동일한 shape을 갖는 배치 정규화된 N차원 tensor입니다.

batchNormalization()의 tensor 제한
피연산자 허용되는 데이터 유형 필수 데이터 유형 허용되는 rank 필수 rank
input "float32", "float16" "float32", "float16" 1에서 N까지 3에서 5까지
mean input동일한 유형 "float32", "float16" 1 1
variance input동일한 유형 "float32", "float16" 1 1
scale input동일한 유형 "float32", "float16" 1 1
bias input동일한 유형 "float32", "float16" 1 1
출력 input동일한 유형 "float32", "float16" input동일한 rank 3에서 5까지

MLBatchNormalizationSupportLimits에는 다음 멤버가 있습니다.

input, 유형은 MLTensorLimits

입력 피연산자에 대한 MLTensorLimits입니다.

mean, 유형은 MLTensorLimits

mean 피연산자에 대한 MLTensorLimits입니다.

variance, 유형은 MLTensorLimits

variance 피연산자에 대한 MLTensorLimits입니다.

scale, 유형은 MLTensorLimits

scale 피연산자에 대한 MLTensorLimits입니다.

bias, 유형은 MLTensorLimits

bias 피연산자에 대한 MLTensorLimits입니다.

output, 유형은 MLTensorLimits

출력 피연산자에 대한 MLTensorLimits입니다.

MLOpSupportLimits에는 batchNormalization()에 대해 다음 멤버가 있습니다.

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, variance, 그리고 options가 주어진 "batchNormalization" 연산에 대한 연산자로 둡니다.

    2. outputthisinput.[[descriptor]]가 주어진 상태에서 MLOperand를 생성한 결과로 둡니다.

    3. output.[[operator]]operator로 설정합니다.

    4. operator입력input, mean, 그리고 variance로 설정합니다.

    5. options.scale존재하면 이를 operator입력에 추가합니다.

    6. options.bias존재하면 이를 operator입력에 추가합니다.

    7. operator출력output으로 설정합니다.

  13. output을 반환합니다.

입력 tensor가 "nchw" 레이아웃의 4차원인 경우, 사용자 에이전트에는 일반적으로 더 효율적인 구현이 있지만 이 연산의 동작을 다음과 같이 다른 연산을 사용하여 일반적으로 에뮬레이션할 수 있습니다. 기반 플랫폼에서 연산을 직접 지원하지 않는 경우 이 분해를 구현을 안내하는 템플릿으로 사용할 수 있습니다.
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의 각 요소를 대상 데이터 유형으로 캐스트합니다.
partial interface MLGraphBuilder {
  MLOperand cast(MLOperand input,
                 MLOperandDataType dataType,
                 optional MLOperatorOptions options = {});
};

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

반환: MLOperand입니다. 각 요소가 대상 데이터 유형으로 캐스트된 input과 동일한 shape의 N차원 tensor입니다.

cast()의 tensor 제한
피연산자 허용되는 데이터 유형 필수 데이터 유형 허용되는 rank 필수 rank
input 모든 유형 "float32", "float16", "int32", "int8", "uint8" N 0에서 5까지
출력 모든 유형 "float32", "float16", "int32", "int8", "uint8" input동일한 rank 0에서 5까지

MLOpSupportLimits에는 cast()에 대해 다음 멤버가 있습니다.

cast, 유형은 MLSingleInputSupportLimits

cast() 연산자의 지원 제한입니다.

MLOperandDataType 간의 캐스팅은 다음 표에 따라 일부 경우에는 명세되어 있고 다른 경우에는 구현 정의입니다.

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

범위를 벗어나면 +/-Infinity입니다.

범위 내이면 잘립니다.

범위를 벗어나면 구현 정의입니다.

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

범위를 벗어나면 +/-Infinity입니다.

범위 내이면 동일한 값입니다.

범위를 벗어나면 하위 N비트를 대상 유형으로 재해석하며, 부호 있는 유형에는 2의 보수를 가정합니다.

참고: 예를 들어 "int8"의 -1을 "uint8"로 캐스트하면 255가 되도록 명세되어 있습니다. 그러나 "float32"의 -1을 "uint8"로 캐스트하는 것은 구현 정의입니다.

cast(input, dataType, options) 메서드의 단계는 다음과 같습니다.
  1. this빌드할 수 없는 상태이면 "InvalidStateError" DOMExceptionthrow합니다.

  2. thisinput을 사용하여 피연산자를 검증한 결과가 false이면 TypeErrorthrow합니다.

  3. dataType이 출력 tensor의 허용되는 데이터 유형 중 하나가 아니면(이 표에 따름) TypeErrorthrow합니다.

  4. 그래프 연결을 구성합니다.

    1. operatordataTypeoptions가 주어진 "cast" 연산에 대한 연산자로 둡니다.

    2. outputinput이 주어진 상태에서 MLOperand를 복사한 결과로 둡니다.

    3. output.[[operator]]operator로 설정합니다.

    4. operator입력input으로 설정합니다.

    5. operator출력output으로 설정합니다.

  5. output을 반환합니다.

8.9.8. clamp

최솟값과 최댓값으로 지정된 범위 내에서 입력 tensor의 각 요소를 제한합니다.
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

범위의 최솟값입니다. 지정하지 않으면 범위의 하한에 대해 제한이 수행되지 않습니다.

maxValue, 유형은 MLNumber

범위의 최댓값입니다. 지정하지 않으면 범위의 상한에 대해 제한이 수행되지 않습니다.

인수: 반환:
clamp()의 tensor 제한
피연산자 허용되는 데이터 유형 필수 데이터 유형 허용되는 rank 필수 rank
input 모든 유형 "float32", "float16" N 0에서 5까지
출력 input동일한 유형 "float32", "float16" input동일한 rank 0에서 5까지

MLOpSupportLimits에는 clamp()에 대해 다음 멤버가 있습니다.

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. operator입력input으로 설정합니다.

    5. operator출력output으로 설정합니다.

  9. output을 반환합니다.

사용자 에이전트에는 일반적으로 더 효율적인 구현이 있지만, 이 연산의 동작은 다음과 같이 다른 연산을 사용하여 일반적으로 에뮬레이션할 수 있습니다. 기반 플랫폼에서 연산을 직접 지원하지 않는 경우 이 분해를 구현을 안내하는 템플릿으로 사용할 수 있습니다.
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 필수 rank
inputs항목 모든 유형 "float32", "float16", "int32" 1에서 N까지 1에서 5까지
출력 inputs항목동일한 유형 "float32", "float16", "int32" inputs항목동일한 rank 1에서 5까지

MLConcatSupportLimits에는 다음 멤버가 있습니다.

inputs, 유형은 MLTensorLimits

모든 입력 피연산자에 대한 MLTensorLimits입니다.

output, 유형은 MLTensorLimits

출력 피연산자에 대한 MLTensorLimits입니다.

MLOpSupportLimits에는 concat()에 대해 다음 멤버가 있습니다.

concat, 유형은 MLConcatSupportLimits

concat() 연산자의 지원 제한입니다.

concat(inputs, axis, options) 메서드의 단계는 다음과 같습니다.
  1. this빌드할 수 없는 상태이면 "InvalidStateError" DOMExceptionthrow합니다.

  2. thisinputs의 임의의 항목을 사용하여 피연산자를 검증한 결과가 false이면 TypeErrorthrow합니다.

  3. inputs크기유효한 tensor 수가 아니면 TypeErrorthrow합니다.

  4. firstinputs[0]으로 둡니다.

  5. axisfirstrank보다 크거나 같으면 TypeErrorthrow합니다.

  6. descfirstdataTypefirstshape이 주어진 상태에서 MLOperandDescriptor를 생성한 결과로 둡니다.

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

  8. 1부터 inputs크기까지의 범위에서 각 index에 대해 각각(상한 제외):

    1. inputinputs[index]로 둡니다.

    2. inputdataTypefirstdataType과 같지 않으면 TypeErrorthrow합니다.

    3. inputrankfirstrank와 같지 않으면 TypeErrorthrow합니다.

    4. 0부터 inputrank까지의 범위에서 각 dim에 대해 각각(상한 제외):

      axis로 주어진 차원을 제외하고 피연산자의 각 대응 차원의 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. operator입력inputs로 설정합니다.

    5. operator출력output으로 설정합니다.

  10. output을 반환합니다.

8.9.10. conv2d

4차원 입력 및 필터 tensor가 주어졌을 때 2차원 컨볼루션을 계산합니다.
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인 목록입니다: [beginningHeight, endingHeight, beginningWidth, endingWidth]. 컨볼루션 입력의 각 공간 차원의 시작과 끝에 추가되는 행과 열을 지정합니다. 기본값은 [0, 0, 0, 0]입니다.

strides, 유형은 sequence<[EnforceRange] unsigned long>

길이가 2인 목록입니다: [strideHeight, strideWidth]. 컨볼루션 입력의 각 공간 차원에 대한 슬라이딩 윈도우의 stride를 지정합니다. 기본값은 [1, 1]입니다.

dilations, 유형은 sequence<[EnforceRange] unsigned long>

길이가 2인 목록입니다: [dilationHeight, dilationWidth]. 컨볼루션 필터(커널)에 적용되는 각 공간 차원의 dilation 계수를 지정합니다. 기본값은 [1, 1]입니다.

groups, 유형은 unsigned long이며 기본값은 1

입력 채널과 출력 채널이 나뉘는 그룹 수입니다.

inputLayout, 유형은 MLInputOperandLayout이며 기본값은 "nchw"

입력 및 출력 tensor의 레이아웃 형식을 다음과 같이 지정합니다.

  • "nchw"

    • 입력 tensor: [batches, inputChannels, height, width]

    • 출력 tensor: [batches, outputChannels, height, width]

  • "nhwc":

    • 입력 tensor: [batches, height, width, inputChannels]

    • 출력 tensor: [batches, height, width, outputChannels]

filterLayout, 유형은 MLConv2dFilterOperandLayout이며 기본값은 "oihw"

필터 tensor의 레이아웃 형식을 다음과 같이 지정합니다.

  • "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

컨볼루션 결과에 값을 더할 [outputChannels] shape의 추가 1차원 tensor입니다.

인수:

반환: MLOperand입니다. 컨볼루션 결과를 포함하는 출력 4차원 tensor입니다. 출력 shape은 inputLayout에 따라 해석됩니다. 더 구체적으로 "nchw" 입력 레이아웃에서 출력 tensor의 공간 차원 또는 마지막 두 차원의 크기는 다음과 같이 계산할 수 있습니다.

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

conv2d()의 tensor 제한
피연산자 허용되는 데이터 유형 필수 데이터 유형 허용되는 rank 필수 rank
input "float32", "float16" "float32", "float16" 4 4
filter input동일한 유형 "float32", "float16" 4 4
bias input동일한 유형 "float32", "float16" 1 1
출력 input동일한 유형 "float32", "float16" 4 4

MLConv2dSupportLimits에는 다음 멤버가 있습니다.

input, 유형은 MLTensorLimits

입력 피연산자에 대한 MLTensorLimits입니다.

filter, 유형은 MLTensorLimits

filter 피연산자에 대한 MLTensorLimits입니다.

bias, 유형은 MLTensorLimits

bias 피연산자에 대한 MLTensorLimits입니다.

output, 유형은 MLTensorLimits

출력 피연산자에 대한 MLTensorLimits입니다.

MLOpSupportLimits에는 conv2d()에 대해 다음 멤버가 있습니다.

conv2d, 유형은 MLConv2dSupportLimits

conv2d() 연산자의 지원 제한입니다.

depthwise conv2d 연산은 MobileNet과 같은 모델에서 사용되는 그룹 컨볼루션의 변형으로, groups = inputChannels = outputChannels이고 필터 tensor의 shape은 "oihw" 레이아웃의 경우 [options.groups, 1, height, width], "hwio" 레이아웃의 경우 [height, width, 1, options.groups], "ohwi" 레이아웃의 경우 [options.groups, height, width, 1], 그리고 "ihwo" 레이아웃의 경우 [1, height, width, options.groups]입니다.
부호 없는 정수 inputSize, filterSize, beginningPadding, endingPadding, stridedilation이 주어졌을 때 conv 출력 크기를 계산하려면 다음 단계를 수행합니다. 숫자를 반환합니다.
  1. effectiveFilterSize를 ( filterSize - 1 ) * dilation + 1로 둡니다.

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

  3. outputSize를 반환합니다.

부호 없는 정수 inputHeight, inputWidth, filterHeightfilterWidth, 부호 없는 정수 4개로 이루어진 목록 padding, 부호 없는 정수 2개로 이루어진 목록 strides, 그리고 부호 없는 정수 2개로 이루어진 목록 dilations가 주어졌을 때 conv2d 출력 크기를 계산하려면 다음 단계를 수행합니다. 숫자 2개로 이루어진 목록을 반환합니다.
  1. outputHeightinputHeight, filterHeight, padding[0], padding[1], strides[0] 및 dilations[0]이 주어진 상태에서 conv 출력 크기를 계산한 결과로 둡니다.

  2. outputWidthinputWidth, filterWidth, padding[2], padding[3], strides[1] 및 dilations[1]이 주어진 상태에서 conv 출력 크기를 계산한 결과로 둡니다.

  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존재하지 않으면 목록 « 0, 0, 0, 0 »으로 설정합니다.

  8. 그렇지 않고 options.padding크기가 4가 아니면 TypeErrorthrow합니다.

  9. options.strides존재하지 않으면 목록 « 1, 1 »로 설정합니다.

  10. 그렇지 않고 options.strides크기가 2가 아니면 TypeErrorthrow합니다.

  11. options.strides항목 중 하나라도 0이면 TypeErrorthrow합니다.

  12. options.dilations존재하지 않으면 목록 « 1, 1 »로 설정합니다.

  13. 그렇지 않고 options.dilations크기가 2가 아니면 TypeErrorthrow합니다.

  14. options.dilations항목 중 하나라도 0이면 TypeErrorthrow합니다.

  15. options.groups 가 0이면 TypeErrorthrow합니다.

  16. 출력 shape을 계산합니다.

    1. inputShapeinputshape으로 둡니다.

    2. options.inputLayout에 따라 분기합니다.

      "nchw"

      « batches, inputChannels, inputHeight, inputWidth »를 inputShape으로 둡니다.

      "nhwc"

      « batches, inputHeight, inputWidth, inputChannels »를 inputShape으로 둡니다.

    3. filterShapefiltershape으로 둡니다.

    4. options.filterLayout에 따라 분기합니다.

      "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 출력 크기를 계산한 결과로 둡니다.

    10. outputHeight를 floor( outputHeight )로 설정합니다.

    11. outputWidth를 floor( outputWidth )로 설정합니다.

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

    13. options.inputLayout에 따라 분기합니다.

      "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. operator입력inputfilter로 설정합니다.

    5. options.bias존재하면 이를 operator입력에 추가합니다.

    6. operator출력output으로 설정합니다.

  18. output을 반환합니다.

8.9.11. convTranspose2d

4차원 입력 및 필터 tensor가 주어졌을 때 2차원 전치 컨볼루션을 계산합니다.
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인 목록입니다: [beginningHeight, endingHeight, beginningWidth, endingWidth]. 컨볼루션 입력의 각 공간 차원의 시작과 끝에 추가되는 행과 열을 지정합니다. 기본값은 [0, 0, 0, 0]입니다.

strides, 유형은 sequence<[EnforceRange] unsigned long>

길이가 2인 목록입니다: [strideHeight, strideWidth]. 컨볼루션 입력의 각 공간 차원에 대한 슬라이딩 윈도우의 stride를 지정합니다. 기본값은 [1, 1]입니다.

dilations, 유형은 sequence<[EnforceRange] unsigned long>

길이가 2인 목록입니다: [dilationHeight, dilationWidth]. 컨볼루션 필터(커널)에 적용되는 각 공간 차원의 dilation 계수를 지정합니다. 기본값은 [1, 1]입니다.

outputPadding, 유형은 sequence<[EnforceRange] unsigned long>

길이가 2인 목록입니다. 출력 tensor의 각 공간 차원에 적용되는 padding 값을 지정합니다. strides 값이 1보다 큰 경우 전치 컨볼루션의 출력 tensor shape을 명확하게 결정하기 위해 명시적인 padding 값이 필요합니다.

이 값은 필요한 경우 출력 shape을 명확하게 결정하는 데만 사용되며, 반드시 어떤 padding 값이 출력 tensor에 기록되도록 하는 것은 아닙니다.

기본값은 [0, 0]입니다.

outputSizes, 유형은 sequence<[EnforceRange] unsigned long>

길이가 2인 목록입니다. 출력 tensor의 마지막 두 차원의 크기를 지정합니다. 출력 크기가 명시적으로 지정되면 outputPadding의 출력 padding 값은 무시됩니다.

지정하지 않으면 출력 크기가 자동으로 계산됩니다.

groups, 유형은 unsigned long이며 기본값은 1

입력 채널과 출력 채널이 나뉘는 그룹 수입니다.

inputLayout, 유형은 MLInputOperandLayout이며 기본값은 "nchw"

입력 및 출력 tensor의 레이아웃 형식을 다음과 같이 지정합니다.

  • "nchw"

    • 입력 tensor: [batches, inputChannels, height, width]

    • 출력 tensor: [batches, outputChannels, height, width]

  • "nhwc":

    • 입력 tensor: [batches, height, width, inputChannels]

    • 출력 tensor: [batches, height, width, outputChannels]

filterLayout, 유형은 MLConvTranspose2dFilterOperandLayout이며 기본값은 "iohw"

필터 tensor의 레이아웃 형식을 다음과 같이 지정합니다.

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

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

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

bias, 유형은 MLOperand

컨볼루션 결과에 값을 더할 [outputChannels] shape의 추가 1차원 tensor입니다.

인수:

반환: MLOperand입니다. 전치 컨볼루션 결과를 포함하는 출력 4차원 tensor입니다. 출력 shape은 inputLayout에 따라 해석됩니다. 더 구체적으로 outputSizes가 명시적으로 지정되지 않은 경우, 출력 tensor의 공간 차원 값을 다음과 같이 계산하려면 outputPadding이 필요합니다.

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

convTranspose2d()의 tensor 제한
피연산자 허용되는 데이터 유형 필수 데이터 유형 허용되는 rank 필수 rank
input "float32", "float16" "float32", "float16" 4 4
filter input동일한 유형 "float32", "float16" 4 4
bias input동일한 유형 "float32", "float16" 1 1
출력 input동일한 유형 "float32", "float16" 4 4

MLOpSupportLimits에는 convTranspose2d()에 대해 다음 멤버가 있습니다.

convTranspose2d, 유형은 MLConv2dSupportLimits

convTranspose2d() 연산자의 지원 제한입니다.

부호 없는 정수 inputSize, filterSize, beginningPadding, endingPadding, stridedilation이 주어졌을 때 convtranspose 출력 크기를 계산하려면 다음 단계를 수행합니다. 숫자를 반환합니다.
  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존재하지 않으면 목록 « 0, 0, 0, 0 »으로 설정합니다.

  8. 그렇지 않고 options.padding크기가 4가 아니면 TypeErrorthrow합니다.

  9. options.strides존재하지 않으면 목록 « 1, 1 »로 설정합니다.

  10. 그렇지 않고 options.strides크기가 2가 아니면 TypeErrorthrow합니다.

  11. options.strides항목 중 하나라도 0이면 TypeErrorthrow합니다.

  12. options.dilations존재하지 않으면 목록 « 1, 1 »로 설정합니다.

  13. 그렇지 않고 options.dilations크기가 2가 아니면 TypeErrorthrow합니다.

  14. options.dilations항목 중 하나라도 0이면 TypeErrorthrow합니다.

  15. options.outputPadding존재하지 않으면 목록 « 0, 0 »으로 설정합니다.

  16. 그렇지 않고 options.outputPadding크기가 2가 아니면 TypeErrorthrow합니다.

  17. options.outputSizes존재하면:

    1. 크기가 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에 따라 분기합니다.

      "nchw"

      « batches, inputChannels, inputHeight, inputWidth »를 inputShape으로 둡니다.

      "nhwc"

      « batches, inputHeight, inputWidth, inputChannels »를 inputShape으로 둡니다.

    3. filterShapefiltershape으로 둡니다.

    4. options.filterLayout에 따라 분기합니다.

      "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 출력 크기를 계산한 결과로 둡니다.

    10. calculatedOutputWidthinputWidth, filterWidth, padding[2], padding[3], strides[1] 및 dilations[1]이 주어진 상태에서 convtranspose 출력 크기를 계산한 결과로 둡니다.

    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에 따라 분기합니다.

      "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. operator입력inputfilter로 설정합니다.

    5. options.bias존재하면 이를 operator입력에 추가합니다.

    6. operator출력output으로 설정합니다.

  22. output을 반환합니다.

8.9.12. cumulativeSum

주어진 축을 따라 일련의 값의 누적합을 계산하며, 현재 값을 포함하거나 제외할 수 있습니다.
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 필수 rank
input "float32", "float16", "int32", "uint32", "int64", "uint64" "float32", "float16", "int32" 1에서 N까지 1에서 5까지
출력 input동일한 유형 "float32", "float16", "int32" input동일한 rank 1에서 5까지

MLCumulativeSumOptions에는 다음 멤버가 있습니다.

exclusive, 유형은 boolean이며 기본값은 false

출력에 현재 값을 포함할지 제외할지 여부이며, 각각 포함 누적합 또는 배타 누적합 [Prefix-sum]을 의미합니다. 입력 [1,2,3,4]가 주어지면 포함 합산은 [1,3,6,10]을 출력하고 배타 합산은 [0,1,3,6]을 출력합니다. 기본값은 포함입니다.

reversed, 유형은 boolean이며 기본값은 false

활성 축을 따라 합산 방향을 반대로 하여 높은 좌표에서 낮은 좌표로 시작할지 여부입니다. 입력 [1,2,3,4]가 주어지면 포함 순방향 합산은 [1,3,6,10]을 출력하고 포함 역방향 합산은 [10,9,7,4]을 출력합니다. 기본값은 순방향입니다.

인수:

반환:

MLOpSupportLimits에는 cumulativeSum()에 대해 다음 멤버가 있습니다.

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. operator입력input으로 설정합니다.

    5. operator출력output으로 설정합니다.

  6. output을 반환합니다.

8.9.13. 요소별 이항 연산

두 입력 tensor의 요소별 이항 덧셈, 뺄셈, 곱셈, 나눗셈, 거듭제곱, 최댓값 및 최솟값을 계산합니다.

연산은 [numpy-broadcasting-rule]에 따라 브로드캐스트됩니다. 입력 tensor는 양방향 브로드캐스트 가능해야 합니다. 출력 tensor의 rank는 입력 tensor의 최대 rank입니다. 출력 tensor의 각 차원에 대해 그 크기는 입력 tensor에서 해당 차원을 따른 최대 크기입니다.

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에 대한 요소별 이항 연산의 결과를 포함하는 출력 tensor입니다.

연산 유형:
요소별 이항 연산의 tensor 제한
피연산자 허용되는 데이터 유형 필수 데이터 유형 허용되는 rank 필수 rank
a 모든 유형 "float32", "float16", "int32" N 0에서 5까지
b a동일한 유형 "float32", "float16", "int32" N 0에서 5까지
출력 a동일한 유형 "float32", "float16", "int32" N 0에서 5까지

MLOpSupportLimits에는 요소별 이항 연산에 대해 다음 멤버가 있습니다.

add, 유형은 MLBinarySupportLimits

add() 연산자의 지원 제한입니다.

sub, 유형은 MLBinarySupportLimits

sub() 연산자의 지원 제한입니다.

mul, 유형은 MLBinarySupportLimits

mul() 연산자의 지원 제한입니다.

div, 유형은 MLBinarySupportLimits

div() 연산자의 지원 제한입니다.

max, 유형은 MLBinarySupportLimits

max() 연산자의 지원 제한입니다.

min, 유형은 MLBinarySupportLimits

min() 연산자의 지원 제한입니다.

pow, 유형은 MLBinarySupportLimits

pow() 연산자의 지원 제한입니다.

문자열 op, MLOperand a, MLOperand b, 그리고 MLOperatorOptions options가 주어졌을 때 요소별 이항 연산을 생성하려면 다음 단계를 실행합니다.
  1. 단언: op는 "add", "sub", "mul", "div", "max", "min", "pow" 중 하나입니다.

  2. this빌드할 수 없는 상태이면 "InvalidStateError" DOMExceptionthrow합니다.

  3. 다음 피연산자 검증thisab 중 하나로 수행한 결과가 false이면, 예외를 발생시킵니다: TypeError.

  4. adataTypebdataType과 같지 않으면 TypeErrorthrow합니다.

  5. outputShapeashapebshape양방향 브로드캐스트한 결과로 둡니다.

    1. 그 결과가 실패이면 TypeErrorthrow합니다.

  6. descriptoradataTypeoutputShape이 주어진 상태에서 MLOperandDescriptor를 생성한 결과로 둡니다.

  7. 그래프 연결을 구성합니다.

    1. outputthisdescriptor가 주어진 상태에서 MLOperand를 생성한 결과로 둡니다.

    2. operatora, b, 그리고 options가 주어진 op 연산에 대한 연산자로 둡니다.

    3. output.[[operator]]operator로 설정합니다.

    4. operator입력ab로 설정합니다.

    5. operator출력output으로 설정합니다.

  8. output을 반환합니다.

요소별 이항 연산 알고리즘은 다음과 같이 요소별 이항 연산을 생성하는 단계를 호출합니다.
add(a, b, options) 메서드의 단계는 다음과 같습니다.
  1. output을 "add", a, b, 그리고 options가 주어진 상태에서 요소별 이항 연산을 생성한 결과로 둡니다.

    1. 그 결과가 오류를 throw하면 해당 오류를 다시 throw합니다.

  2. output을 반환합니다.

sub(a, b, options) 메서드의 단계는 다음과 같습니다.
  1. output을 "sub", a, b, 그리고 options가 주어진 상태에서 요소별 이항 연산을 생성한 결과로 둡니다.

    1. 그 결과가 오류를 throw하면 해당 오류를 다시 throw합니다.

  2. output을 반환합니다.

mul(a, b, options) 메서드의 단계는 다음과 같습니다.
  1. output을 "mul", a, b, 그리고 options가 주어진 상태에서 요소별 이항 연산을 생성한 결과로 둡니다.

    1. 그 결과가 오류를 throw하면 해당 오류를 다시 throw합니다.

  2. output을 반환합니다.

div(a, b, options) 메서드의 단계는 다음과 같습니다.
  1. output을 "div", a, b, 그리고 options가 주어진 상태에서 요소별 이항 연산을 생성한 결과로 둡니다.

    1. 그 결과가 오류를 throw하면 해당 오류를 다시 throw합니다.

  2. output을 반환합니다.

max(a, b, options) 메서드의 단계는 다음과 같습니다.
  1. output을 "max", a, b, 그리고 options가 주어진 상태에서 요소별 이항 연산을 생성한 결과로 둡니다.

    1. 그 결과가 오류를 throw하면 해당 오류를 다시 throw합니다.

  2. output을 반환합니다.

min(a, b, options) 메서드의 단계는 다음과 같습니다.
  1. output을 "min", a, b, 그리고 options가 주어진 상태에서 요소별 이항 연산을 생성한 결과로 둡니다.

    1. 그 결과가 오류를 throw하면 해당 오류를 다시 throw합니다.

  2. output을 반환합니다.

pow(a, b, options) 메서드의 단계는 다음과 같습니다.
  1. output을 "pow", a, b, 그리고 options가 주어진 상태에서 요소별 이항 연산을 생성한 결과로 둡니다.

    1. 그 결과가 오류를 throw하면 해당 오류를 다시 throw합니다.

  2. output을 반환합니다.

8.9.14. 요소별 논리 연산

입력 tensor를 요소별로 비교하고 비교 결과에 대해 0(false) 또는 1(true) 값을 갖는 "uint8" tensor를 반환합니다. 단일 피연산자 연산의 경우 해당 연산의 논리 결과를 반환합니다.

여러 피연산자 연산의 경우, 연산은 브로드캐스트되며 [numpy-broadcasting-rule]을 따릅니다. 입력 텐서는 양방향 브로드캐스트 가능해야 합니다. 출력 텐서의 랭크는 입력 텐서의 최대 랭크입니다. 출력 텐서의 각 차원에 대해 그 크기는 입력 텐서의 해당 차원을 따른 최대 크기입니다.

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의 요소별 비교 결과를 포함하는 출력 tensor입니다.

equal()/notEqual()/greater()/greaterOrEqual()/lesser()/lesserOrEqual()의 tensor 제한
피연산자 허용되는 데이터 유형 필수 데이터 유형 허용되는 rank 필수 rank
a 모든 유형 "float32", "float16", "int32" N 0에서 5까지
b a동일한 유형 "float32", "float16", "int32" N 0에서 5까지
출력 "uint8" "uint8" N 0에서 5까지
logicalNot()의 tensor 제한
피연산자 허용되는 데이터 유형 필수 데이터 유형 허용되는 rank 필수 rank
a "uint8" "uint8" N 0에서 5까지
출력 "uint8" "uint8" N 0에서 5까지
logicalAnd()/logicalOr()/logicalXor()의 tensor 제한
피연산자 허용되는 데이터 유형 필수 데이터 유형 허용되는 rank 필수 rank
a "uint8" "uint8" N 0에서 5까지
b a동일한 유형 "uint8" N 0에서 5까지
출력 "uint8" "uint8" N 0에서 5까지
isNaN()/isInfinite()의 tensor 제한
피연산자 허용되는 데이터 유형 필수 데이터 유형 허용되는 rank 필수 rank
a 모든 유형 "float32", "float16" N 0에서 5까지
출력 "uint8" "uint8" N 0에서 5까지

MLLogicalNotSupportLimits에는 다음 멤버가 있습니다.

a, 유형은 MLTensorLimits

a 피연산자에 대한 MLTensorLimits입니다.

output, 유형은 MLTensorLimits

출력 피연산자에 대한 MLTensorLimits입니다.

MLOpSupportLimits에는 요소별 논리 연산에 대해 다음 멤버가 있습니다.

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 사례를 처리하고 이중 비교를 피하여 성능을 높이기 위해 별도로 정의되어 있습니다.
문자열 op, MLOperand a, 선택적 MLOperand b, 그리고 MLOperatorOptions options가 주어졌을 때 요소별 논리 연산을 생성하려면 다음 단계를 실행합니다.
  1. 단언: 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. outputShapeashapebshape양방향 브로드캐스트한 결과로 둡니다. 그 결과가 실패이면 TypeErrorthrow합니다.

  7. 그렇지 않으면:

    1. outputShapeashape복제본으로 둡니다.

  8. descriptor"uint8"outputShape이 주어진 상태에서 MLOperandDescriptor를 생성한 결과로 둡니다.

  9. 그래프 연결을 구성합니다.

    1. outputthisdescriptor가 주어진 상태에서 MLOperand를 생성한 결과로 둡니다.

    2. operatora와 (b가 전달된 경우) b, 그리고 options가 주어진 op 연산에 대한 연산자로 둡니다.

    3. output.[[operator]]operator로 설정합니다.

    4. operator입력a와 (b가 전달된 경우) b로 설정합니다.

    5. operator출력output으로 설정합니다.

  10. output을 반환합니다.

요소별 논리 연산 알고리즘은 다음과 같이 요소별 논리 연산을 생성하는 단계를 호출합니다.
equal(a, b, options) 메서드의 단계는 다음과 같습니다.
  1. output을 "equal", a, b, 그리고 options가 주어진 상태에서 요소별 논리 연산을 생성한 결과로 둡니다.

    1. 그 결과가 오류를 throw하면 해당 오류를 다시 throw합니다.

  2. output을 반환합니다.

notEqual(a, b, options) 메서드의 단계는 다음과 같습니다.
  1. output을 "notEqual", a, b, 그리고 options가 주어진 상태에서 요소별 논리 연산을 생성한 결과로 둡니다.

    1. 그 결과가 오류를 throw하면 해당 오류를 다시 throw합니다.

  2. output을 반환합니다.

greater(a, b, options) 메서드의 단계는 다음과 같습니다.
  1. output을 "greater", a, b, 그리고 options가 주어진 상태에서 요소별 논리 연산을 생성한 결과로 둡니다.

    1. 그 결과가 오류를 throw하면 해당 오류를 다시 throw합니다.

  2. output을 반환합니다.

greaterOrEqual(a, b, options) 메서드의 단계는 다음과 같습니다.
  1. output을 "greaterOrEqual", a, b, 그리고 options가 주어진 상태에서 요소별 논리 연산을 생성한 결과로 둡니다.

    1. 그 결과가 오류를 throw하면 해당 오류를 다시 throw합니다.

  2. output을 반환합니다.

lesser(a, b, options) 메서드의 단계는 다음과 같습니다.
  1. output을 "lesser", a, b, 그리고 options가 주어진 상태에서 요소별 논리 연산을 생성한 결과로 둡니다.

    1. 그 결과가 오류를 throw하면 해당 오류를 다시 throw합니다.

  2. output을 반환합니다.

lesserOrEqual(a, b, options) 메서드의 단계는 다음과 같습니다.
  1. output을 "lesserOrEqual", a, b, 그리고 options가 주어진 상태에서 요소별 논리 연산을 생성한 결과로 둡니다.

    1. 그 결과가 오류를 throw하면 해당 오류를 다시 throw합니다.

  2. output을 반환합니다.

logicalNot(a, options) 메서드의 단계는 다음과 같습니다.
  1. output을 "logicalNot", a, 그리고 options가 주어진 상태에서 요소별 논리 연산을 생성한 결과로 둡니다.

    1. 그 결과가 오류를 throw하면 해당 오류를 다시 throw합니다.

  2. output을 반환합니다.

logicalAnd(a, b, options) 메서드의 단계는 다음과 같습니다.
  1. output을 "logicalAnd", a, b, 그리고 options가 주어진 상태에서 요소별 논리 연산을 생성한 결과로 둡니다.

    1. 그 결과가 오류를 throw하면 해당 오류를 다시 throw합니다.

  2. output을 반환합니다.

logicalOr(a, b, options) 메서드의 단계는 다음과 같습니다.
  1. output을 "logicalOr", a, b, 그리고 options가 주어진 상태에서 요소별 논리 연산을 생성한 결과로 둡니다.

    1. 그 결과가 오류를 throw하면 해당 오류를 다시 throw합니다.

  2. output을 반환합니다.

logicalXor(a, b, options) 메서드의 단계는 다음과 같습니다.
  1. output을 "logicalXor", a, b, 그리고 options가 주어진 상태에서 요소별 논리 연산을 생성한 결과로 둡니다.

    1. 그 결과가 오류를 throw하면 해당 오류를 다시 throw합니다.

  2. output을 반환합니다.

isNaN(a, options) 메서드의 단계는 다음과 같습니다.
  1. output을 "isNaN", a, 그리고 options가 주어진 상태에서 요소별 논리 연산을 생성한 결과로 둡니다.

    1. 그 결과가 오류를 throw하면 해당 오류를 다시 throw합니다.

  2. output을 반환합니다.

isInfinite(a, options) 메서드의 단계는 다음과 같습니다.
  1. output을 "isInfinite", a, 그리고 options가 주어진 상태에서 요소별 논리 연산을 생성한 결과로 둡니다.

    1. 그 결과가 오류를 throw하면 해당 오류를 다시 throw합니다.

  2. output을 반환합니다.

8.9.15. 요소별 단항 연산

입력 tensor에 대해 요소별 단항 연산을 계산합니다.
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입니다. 입력 tensor에 대한 요소별 단항 연산의 결과를 포함하는 출력 tensor입니다. 출력 tensor의 shape은 입력 tensor의 shape과 같습니다.

abs()/neg()의 tensor 제한
피연산자 허용되는 데이터 유형 필수 데이터 유형 허용되는 rank 필수 rank
input "float32", "float16", "int64", "int32", "int8" "float32", "float16", "int32" N 0에서 5까지
출력 input동일한 유형 "float32", "float16", "int32" input동일한 rank 0에서 5까지
ceil()/cos()/erf()/exp()/floor()/log()/reciprocal()/roundEven()/sin()/sqrt()/tan()의 tensor 제한
피연산자 허용되는 데이터 유형 필수 데이터 유형 허용되는 rank 필수 rank
input "float32", "float16" "float32", "float16" N 0에서 5까지
출력 input동일한 유형 "float32", "float16" input동일한 rank 0에서 5까지
identity()의 tensor 제한
피연산자 허용되는 데이터 유형 필수 데이터 유형 허용되는 rank 필수 rank
input 모든 유형 "float32", "float16", "int32" N 0에서 5까지
출력 input동일한 유형 "float32", "float16", "int32" input동일한 rank 0에서 5까지
sign()의 tensor 제한
피연산자 허용되는 데이터 유형 필수 데이터 유형 허용되는 rank 필수 rank
input "float32", "float16", "int64", "int32", "int8" "float32", "float16", "int32" N 0에서 5까지
출력 input동일한 유형 "float32", "float16", "int32" input동일한 rank 0에서 5까지

MLOpSupportLimits에는 요소별 단항 연산에 대해 다음 멤버가 있습니다.

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() 연산자의 지원 제한입니다.

연산 유형:
문자열 op, MLOperand input, 선택적 목록 allowedDataTypes, 그리고 options가 주어졌을 때 요소별 단항 연산을 생성하려면 다음 단계를 실행합니다.
  1. 단언: 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가 주어지고 inputdataType포함하지 않으면 TypeErrorthrow합니다.

  5. 그래프 연결을 구성합니다.

    1. outputinput이 주어진 상태에서 MLOperand를 복사한 결과로 둡니다.

    2. operatoroptions가 주어진 op 연산에 대한 연산자로 둡니다.

    3. output.[[operator]]operator로 설정합니다.

    4. operator입력input으로 설정합니다.

    5. operator출력output으로 설정합니다.

  6. output을 반환합니다.

요소별 단항 연산 알고리즘은 다음과 같이 요소별 단항 연산을 생성하는 단계를 호출합니다.
abs(input, options) 메서드의 단계는 다음과 같습니다.
  1. output을 "abs", input, « "float32", "float16", "int64", "int32", "int8" », 그리고 options가 주어진 상태에서 요소별 단항 연산을 생성한 결과로 둡니다.

    1. 그 결과가 오류를 throw하면 해당 오류를 다시 throw합니다.

  2. output을 반환합니다.

ceil(input, options) 메서드의 단계는 다음과 같습니다.
  1. output을 "ceil", input, « "float32", "float16" », 그리고 options가 주어진 상태에서 요소별 단항 연산을 생성한 결과로 둡니다.

    1. 그 결과가 오류를 throw하면 해당 오류를 다시 throw합니다.

  2. output을 반환합니다.

cos(input, options) 메서드의 단계는 다음과 같습니다.
  1. output을 "cos", input, « "float32", "float16" », 그리고 options가 주어진 상태에서 요소별 단항 연산을 생성한 결과로 둡니다.

    1. 그 결과가 오류를 throw하면 해당 오류를 다시 throw합니다.

  2. output을 반환합니다.

erf(input, options) 메서드의 단계는 다음과 같습니다.
  1. output을 "erf", input, « "float32", "float16" », 그리고 options가 주어진 상태에서 요소별 단항 연산을 생성한 결과로 둡니다.

    1. 그 결과가 오류를 throw하면 해당 오류를 다시 throw합니다.

  2. output을 반환합니다.

exp(input, options) 메서드의 단계는 다음과 같습니다.
  1. output을 "exp", input, « "float32", "float16" », 그리고 options가 주어진 상태에서 요소별 단항 연산을 생성한 결과로 둡니다.

    1. 그 결과가 오류를 throw하면 해당 오류를 다시 throw합니다.

  2. output을 반환합니다.

floor(input, options) 메서드의 단계는 다음과 같습니다.
  1. output을 "floor", input, « "float32", "float16" », 그리고 options가 주어진 상태에서 요소별 단항 연산을 생성한 결과로 둡니다.

    1. 그 결과가 오류를 throw하면 해당 오류를 다시 throw합니다.

  2. output을 반환합니다.

identity(input, options) 메서드의 단계는 다음과 같습니다.
  1. output을 "identity", input, 그리고 options가 주어진 상태에서 요소별 단항 연산을 생성한 결과로 둡니다.

    1. 그 결과가 오류를 throw하면 해당 오류를 다시 throw합니다.

  2. output을 반환합니다.

log(input, options) 메서드의 단계는 다음과 같습니다.
  1. output을 "log", input, « "float32", "float16" », 그리고 options가 주어진 상태에서 요소별 단항 연산을 생성한 결과로 둡니다.

    1. 그 결과가 오류를 throw하면 해당 오류를 다시 throw합니다.

  2. output을 반환합니다.

neg(input, options) 메서드의 단계는 다음과 같습니다.
  1. output을 "neg", input, « "float32", "float16", "int64", "int32", "int8" », 그리고 options가 주어진 상태에서 요소별 단항 연산을 생성한 결과로 둡니다.

    1. 그 결과가 오류를 throw하면 해당 오류를 다시 throw합니다.

  2. output을 반환합니다.

reciprocal(input, options) 메서드의 단계는 다음과 같습니다.
  1. output을 "reciprocal", input, « "float32", "float16" », 그리고 options가 주어진 상태에서 요소별 단항 연산을 생성한 결과로 둡니다.

    1. 그 결과가 오류를 throw하면 해당 오류를 다시 throw합니다.

  2. output을 반환합니다.

roundEven(input, options) 메서드의 단계는 다음과 같습니다.
  1. output을 "roundEven", input, « "float32", "float16" », 그리고 options가 주어진 상태에서 요소별 단항 연산을 생성한 결과로 둡니다.

    1. 그 결과가 오류를 throw하면 해당 오류를 다시 throw합니다.

  2. output을 반환합니다.

sin(input, options) 메서드의 단계는 다음과 같습니다.
  1. output을 "sin", input, « "float32", "float16" », 그리고 options가 주어진 상태에서 요소별 단항 연산을 생성한 결과로 둡니다.

    1. 그 결과가 오류를 throw하면 해당 오류를 다시 throw합니다.

  2. output을 반환합니다.

sign(input, options) 메서드의 단계는 다음과 같습니다.
  1. output을 "sign", input, « "float32", "float16", "int64", "int32", "int8" », 그리고 options가 주어진 상태에서 요소별 단항 연산을 생성한 결과로 둡니다.

    1. 그 결과가 오류를 throw하면 해당 오류를 다시 throw합니다.

  2. output을 반환합니다.

sqrt(input, options) 메서드의 단계는 다음과 같습니다.
  1. output을 "sqrt", input, « "float32", "float16" », 그리고 options가 주어진 상태에서 요소별 단항 연산을 생성한 결과로 둡니다.

    1. 그 결과가 오류를 throw하면 해당 오류를 다시 throw합니다.

  2. output을 반환합니다.

tan(input, options) 메서드의 단계는 다음과 같습니다.
  1. output을 "tan", input, « "float32", "float16" », 그리고 options가 주어진 상태에서 요소별 단항 연산을 생성한 결과로 둡니다.

    1. 그 결과가 오류를 throw하면 해당 오류를 다시 throw합니다.

  2. output을 반환합니다.

사용자 에이전트에는 일반적으로 더 효율적인 구현이 있지만, sign() 연산의 동작은 다음과 같이 다른 연산을 사용하여 일반적으로 에뮬레이션할 수 있습니다. 기반 플랫폼에서 연산을 직접 지원하지 않는 경우 이 분해를 구현을 안내하는 템플릿으로 사용할 수 있습니다.
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 바이어스를 사용하여 정수 텐서를 부동 소수점 텐서로 역양자화하며, 여기서 output = (input - zeroPoint) * scale입니다. scalezeroPoint 텐서는 input 텐서보다 작을 수 있으며, 이는 블록 단위 브로드캐스트 가능하기 때문입니다.
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입니다. 역양자화된 값을 포함하는 출력 텐서입니다.

dequantizeLinear()의 텐서 제한
피연산자 허용되는 데이터 유형 필수 데이터 유형 허용되는 rank 필수 rank
input "uint8", "int8", "uint32", "int32" "uint8", "int8" N 0에서 5까지
scale "float32", "float16" "float32", "float16" input동일한 rank 0에서 5까지
zeroPoint input동일한 유형 "uint8", "int8", "int32" input동일한 rank 0에서 5까지
출력 scale동일한 유형 "float32", "float16" input동일한 rank 0에서 5까지

MLQuantizeDequantizeLinearSupportLimits에는 다음 멤버가 있습니다.

input, 유형은 MLTensorLimits

입력 피연산자에 대한 MLTensorLimits입니다.

scale, 유형은 MLTensorLimits

scale 피연산자에 대한 MLTensorLimits입니다.

zeroPoint, 유형은 MLTensorLimits

zeroPoint 피연산자에 대한 MLTensorLimits입니다.

output, 유형은 MLTensorLimits

출력 피연산자에 대한 MLTensorLimits입니다.

MLOpSupportLimits에는 dequantizeLinear()에 대해 다음 멤버가 있습니다.

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. scaleshapeinputshape블록 단위 브로드캐스트한 결과가 false이면 TypeErrorthrow합니다.

  10. zeroPointshapeinputshape블록 단위 브로드캐스트한 결과가 false이면 TypeErrorthrow합니다.

  11. outputDescriptorscaledataTypeinputshape이 주어진 상태에서 MLOperandDescriptor를 생성한 결과로 둡니다.

  12. 그래프 연결을 구성합니다.

    1. outputthisoutputDescriptor가 주어진 상태에서 MLOperand를 생성한 결과로 둡니다.

    2. operatorinput, scale, zeroPoint, 그리고 options가 주어진 "dequantizeLinear" 연산에 대한 연산자로 둡니다.

    3. output.[[operator]]operator로 설정합니다.

    4. operator입력input으로 설정합니다.

    5. operator출력output으로 설정합니다.

  13. output을 반환합니다.

사용자 에이전트에는 일반적으로 더 효율적인 구현이 있지만, 이 연산의 동작은 다음과 같이 다른 연산을 사용하여 일반적으로 에뮬레이션할 수 있습니다. 기반 플랫폼이 연산을 직접 지원하지 않는 경우 이 분해를 구현을 안내하는 템플릿으로 사용할 수 있습니다.
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) {
  // 원래 입력과 원하는 출력 shape이 주어지면 각 축을 확장합니다.
  // 해당 축별 블록을 필요한 횟수만큼 반복합니다. 다만 백엔드
  // 구현에는 여러 차원을 받아 모든 차원을 한 번에
  // 정수 배수로 업샘플링할 수 있는 훨씬 효율적인 업샘플링 연산자가 있을 수 있습니다.
  // 최근접 이웃 리샘플링을 사용하는 경우(tile과 유사):
  // 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는 전체 차원의 반복만 허용하므로
      // 슬라이스(축을 따라 개별 요소를 반복하는 것이 아님)를 위해 일시적으로
      // 텐서의 shape을 변경하여 요소를 전체
      // 블록 크기까지 브로드캐스트할 수 있게 하며, 크기가 1인 차원을 삽입합니다.
      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;
}

// 주어진 축의 앞과 뒤에서 평탄화된 shape을 계산하여
// 3개 요소 목록을 생성합니다. 예:
// - 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 바이어스를 사용하여 부동 소수점 텐서를 정수 텐서로 양자화합니다(예: "uint8"의 경우 output = clamp(roundEven(input / scale) + zeroPoint, 0, 255)). scalezeroPoint 텐서는 input 텐서보다 작을 수 있으며, 이는 블록 단위 브로드캐스트되기 때문입니다.
partial interface MLGraphBuilder {
  MLOperand quantizeLinear(MLOperand input,
                           MLOperand scale,
                           MLOperand zeroPoint,
                           optional MLOperatorOptions options = {});
};

partial dictionary MLOpSupportLimits {
  MLQuantizeDequantizeLinearSupportLimits quantizeLinear;
};
인수:

반환: MLOperand입니다. 양자화된 값을 포함하는 출력 텐서입니다.

quantizeLinear()의 텐서 제한
피연산자 허용되는 데이터 유형 필수 데이터 유형 허용되는 rank 필수 rank
input "float32", "float16" "float32", "float16" N 0에서 5까지
scale input동일한 유형 "float32", "float16" input동일한 rank 0에서 5까지
zeroPoint "uint8", "int8", "uint32", "int32" "uint8", "int8" input동일한 rank 0에서 5까지
출력 zeroPoint동일한 유형 "uint8", "int8" input동일한 rank 0에서 5까지

MLOpSupportLimits에는 quantizeLinear()에 대해 다음 멤버가 있습니다.

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. scaleshapeinputshape블록 단위 브로드캐스트한 결과가 false이면 TypeErrorthrow합니다.

  10. zeroPointshapeinputshape블록 단위 브로드캐스트한 결과가 false이면 TypeErrorthrow합니다.

  11. outputDescriptorzeroPointdataTypeinputshape이 주어진 상태에서 MLOperandDescriptor를 생성한 결과로 둡니다.

  12. 그래프 연결을 구성합니다.

    1. outputthisoutputDescriptor가 주어진 상태에서 MLOperand를 생성한 결과로 둡니다.

    2. operatorinput, scale, zeroPoint, 그리고 options가 주어진 "quantizeLinear" 연산에 대한 연산자로 둡니다.

    3. output.[[operator]]operator로 설정합니다.

    4. operator입력input으로 설정합니다.

    5. operator출력output으로 설정합니다.

  13. output을 반환합니다.

사용자 에이전트에는 일반적으로 더 효율적인 구현이 있지만, 이 연산의 동작은 다음과 같이 다른 연산을 사용하여 일반적으로 에뮬레이션할 수 있습니다. 기반 플랫폼이 연산을 직접 지원하지 않는 경우 이 분해를 구현을 안내하는 템플릿으로 사용할 수 있습니다.
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

입력 텐서에 대해 요소별로 지수 선형 유닛 함수(ELU)를 계산합니다. 계산은 다음 식을 따릅니다. 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

스칼라 배수입니다.

인수:

반환:

elu()의 텐서 제한
피연산자 허용되는 데이터 유형 필수 데이터 유형 허용되는 rank 필수 rank
input "float32", "float16" "float32", "float16" N 0에서 5까지
출력 input동일한 유형 "float32", "float16" input동일한 rank 0에서 5까지

MLOpSupportLimits에는 elu()에 대해 다음 멤버가 있습니다.

elu, 유형은 MLSingleInputSupportLimits

elu() 연산자의 지원 제한입니다.

elu(input, options) 메서드의 단계는 다음과 같습니다.
  1. this빌드할 수 없는 상태이면 "InvalidStateError" DOMExceptionthrow합니다.

  2. thisinput을 사용하여 피연산자를 검증한 결과가 false이면 TypeErrorthrow합니다.

  3. inputdataType이 해당 허용되는 데이터 유형 중 하나가 아니면(이 표에 따름) TypeErrorthrow합니다.

  4. options.alphaoptions.alphainputdataType으로 캐스트한 결과로 설정합니다.

  5. 그래프 연결을 구성합니다.

    1. outputinput이 주어진 상태에서 MLOperand를 복사한 결과로 둡니다.

    2. operatoroptions가 주어진 "elu" 연산에 대한 연산자로 둡니다.

    3. output.[[operator]]operator로 설정합니다.

    4. operator입력input으로 설정합니다.

    5. operator출력output으로 설정합니다.

  6. output을 반환합니다.

사용자 에이전트에는 일반적으로 더 효율적인 구현이 있지만, 이 연산의 동작은 다음과 같이 다른 연산을 사용하여 일반적으로 에뮬레이션할 수 있습니다. 기반 플랫폼이 연산을 직접 지원하지 않는 경우 이 분해를 구현을 안내하는 템플릿으로 사용할 수 있습니다.
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

새 shape에 따라 입력 텐서에서 크기가 1인 임의의 차원을 더 큰 크기로 확장합니다. 이 확장은 [numpy-broadcasting-rule]과 일치합니다. 입력 텐서는 새 shape으로 단방향 브로드캐스트 가능해야 하며, 각 차원의 크기는 1이거나 새 shape에 따른 대응 출력 차원의 크기와 일치해야 합니다.
partial interface MLGraphBuilder {
  MLOperand expand(MLOperand input,
                   sequence<[EnforceRange] unsigned long> newShape,
                   optional MLOperatorOptions options = {});
};

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

반환: MLOperand입니다. 크기가 확장된 shape을 가진 텐서입니다.

expand()의 텐서 제한
피연산자 허용되는 데이터 유형 필수 데이터 유형 허용되는 rank 필수 rank
input 모든 유형 "float32", "float16", "int32" N 0에서 5까지
출력 input동일한 유형 "float32", "float16", "int32" N 0에서 5까지

MLOpSupportLimits에는 expand()에 대해 다음 멤버가 있습니다.

expand, 유형은 MLSingleInputSupportLimits

expand() 연산자의 지원 제한입니다.

expand(input, newShape, options) 메서드의 단계는 다음과 같습니다.
  1. this빌드할 수 없는 상태이면 "InvalidStateError" DOMExceptionthrow합니다.

  2. thisinput을 사용하여 피연산자를 검증한 결과가 false이면 TypeErrorthrow합니다.

  3. outputShapeinputshapenewShape단방향 브로드캐스트한 결과로 둡니다.

    1. 그 결과가 실패이면 TypeErrorthrow합니다.

  4. outputShape크기가 출력 텐서의 허용되는 rank가 아니면(이 표에 따름) TypeErrorthrow합니다.

  5. outputDescriptorinputdataTypeoutputShape이 주어진 상태에서 MLOperandDescriptor를 생성한 결과로 둡니다.

  6. 그래프 연결을 구성합니다.

    1. outputthisoutputDescriptor가 주어진 상태에서 MLOperand를 생성한 결과로 둡니다.

    2. operatorinput, newShape, 그리고 options가 주어진 "expand" 연산에 대한 연산자로 둡니다.

    3. output.[[operator]]operator로 설정합니다.

    4. operator입력input으로 설정합니다.

    5. operator출력output으로 설정합니다.

  7. output을 반환합니다.

8.9.20. 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

수집된 값을 가져올 축입니다. 값은 [0, N-1] 범위여야 하며, 여기서 N은 입력 텐서의 rank입니다.

인수:

반환: MLOperand입니다. rankinputrank + indicesrank - 1과 같은 출력 N차원 텐서입니다.

indices 매개변수는 gather()에 대해 그래프를 빌드할 때 입력을 실행 전까지 알 수 없으므로 허용 범위로 제한할 수 없습니다. 기반 플랫폼이 지정된 제한 동작을 제공하지 않는 경우 구현은 컴파일된 그래프에 clamp()를 도입할 수 있습니다. 마찬가지로 기반 플랫폼이 음수 인덱스를 지원하지 않는 경우 구현은 컴파일된 그래프에 연산을 도입하여 차원의 끝에서부터의 음수 인덱스를 양수 인덱스로 변환할 수 있습니다.
gather()의 텐서 제한
피연산자 허용되는 데이터 유형 필수 데이터 유형 허용되는 rank 필수 rank
input 모든 유형 "float32", "float16", "int32", "int8", "uint8" 1에서 N까지 1에서 5까지
indices "int32", "uint32", "int64" "int32" N 0에서 5까지
출력 input동일한 유형 "float32", "float16", "int32", "int8", "uint8" N 0에서 5까지

MLGatherSupportLimits에는 다음 멤버가 있습니다.

input, 유형은 MLTensorLimits

입력 피연산자에 대한 MLTensorLimits입니다.

indices, 유형은 MLTensorLimits

indices 피연산자에 대한 MLTensorLimits입니다.

output, 유형은 MLTensorLimits

출력 피연산자에 대한 MLTensorLimits입니다.

MLOpSupportLimits에는 gather()에 대해 다음 멤버가 있습니다.

gather, 유형은 MLGatherSupportLimits

gather() 연산자의 지원 제한입니다.

gather(input, indices, options) 메서드의 단계는 다음과 같습니다.
  1. this빌드할 수 없는 상태이면 "InvalidStateError" DOMExceptionthrow합니다.

  2. thisinputindices 중 하나를 사용하여 피연산자를 검증한 결과가 false이면 TypeErrorthrow합니다.

  3. indicesdataType이 해당 허용되는 데이터 유형 중 하나가 아니면(이 표에 따름) TypeErrorthrow합니다.

  4. inputShapeinputshape으로, inputRankinputrank로 둡니다.

  5. indicesShapeindicesshape으로 둡니다.

  6. axisoptions.axis로 둡니다.

  7. axisinputRank보다 크거나 같으면 TypeErrorthrow합니다.

  8. dimCount를 0으로 둡니다.

  9. outputRank를 0으로 둡니다.

  10. outputShape을 빈 목록으로 둡니다.

  11. inputShape의 각 size에 대해 각각:

    1. dimCountaxis와 같으면 중단합니다.

    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보다 작거나 같으면 계속합니다.

    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. operator입력inputindices로 설정합니다.

    5. operator출력output으로 설정합니다.

  20. output을 반환합니다.

다양한 슬라이싱 방식에서 gather가 작동하는 방식의 예입니다.
// shape이 [4,3]인 input:
//   [[ 0,  1,  2],
//    [10, 11, 12],
//    [20, 21, 22],
//    [30, 31, 32]]
// axis = 0 (기본값)
// 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

인덱스에 따라 축을 따라 입력 텐서의 값을 수집합니다.
partial interface MLGraphBuilder {
  MLOperand gatherElements(MLOperand input,
                           MLOperand indices,
                           optional MLGatherOptions options = {});
};

partial dictionary MLOpSupportLimits {
  MLGatherSupportLimits gatherElements;
};
인수:

반환: MLOperand입니다. rankinputrank와 같은 출력 N차원 텐서입니다.

gatherElements()의 텐서 제한
피연산자 허용되는 데이터 유형 필수 데이터 유형 허용되는 rank 필수 rank
input 모든 유형 "float32", "float16", "int32" 1에서 N까지 1에서 5까지
indices "int32", "uint32", "int64" "int32" input동일한 rank 1에서 5까지
출력 input동일한 유형 "float32", "float16", "int32" input동일한 rank 1에서 5까지

MLOpSupportLimits에는 gatherElements()에 대해 다음 멤버가 있습니다.

gatherElements, 유형은 MLGatherSupportLimits

gatherElements() 연산자의 지원 제한입니다.

indices 매개변수는 gatherElements()에 대해 그래프를 빌드할 때 입력을 실행 전까지 알 수 없으므로 허용 범위로 제한할 수 없습니다. 기반 플랫폼이 지정된 제한 동작을 제공하지 않는 경우 구현은 컴파일된 그래프에 clamp()를 도입할 수 있습니다. 마찬가지로 기반 플랫폼이 음수 인덱스를 지원하지 않는 경우 구현은 컴파일된 그래프에 연산을 도입하여 차원의 끝에서부터의 음수 인덱스를 양수 인덱스로 변환할 수 있습니다.
gatherElements(input, indices, options) 메서드의 단계는 다음과 같습니다.
  1. this빌드할 수 없는 상태이면 "InvalidStateError" DOMExceptionthrow합니다.

  2. thisinputindices 중 하나를 사용하여 피연산자를 검증한 결과가 false이면 TypeErrorthrow합니다.

  3. indicesdataType이 해당 허용되는 데이터 유형 중 하나가 아니면(이 표에 따름) TypeErrorthrow합니다.

  4. input 또는 indices 중 하나의 rank가 해당 허용되는 rank가 아니면 TypeErrorthrow합니다.

  5. axisoptions.axis로 둡니다.

  6. axisinputrank보다 크거나 같으면 TypeErrorthrow합니다.

  7. indicesShapeExpectedinputshape의 복사본으로 둡니다.

  8. indicesShapeExpected[axis]를 indicesshape[axis]로 설정합니다.

  9. indicesshapeindicesShapeExpected와 같지 않으면 TypeErrorthrow합니다.

  10. 그래프 연결을 구성합니다.

    1. outputinput이 주어진 상태에서 MLOperand를 복사한 결과로 둡니다.

    2. operatorinput, indices, 그리고 options가 주어진 "gatherElements" 연산에 대한 연산자로 둡니다.

    3. output.[[operator]]operator로 설정합니다.

    4. operator입력inputindices로 설정합니다.

    5. operator출력output으로 설정합니다.

  11. output을 반환합니다.

다양한 슬라이싱 방식에서 gatherElements가 작동하는 방식의 예입니다.
// 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 (기본값)
// 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

인덱스에 따라 입력 텐서의 슬라이스를 수집합니다.
partial interface MLGraphBuilder {
  MLOperand gatherND(MLOperand input,
                     MLOperand indices,
                     optional MLOperatorOptions options = {});
};

partial dictionary MLOpSupportLimits {
  MLGatherSupportLimits gatherND;
};
인수:

반환: MLOperand입니다. rankinputrank + indicesrank - indicesshape[-1] - 1과 같은 출력 N차원 텐서입니다.

gatherND()의 텐서 제한
피연산자 허용되는 데이터 유형 필수 데이터 유형 허용되는 rank 필수 rank
input 모든 유형 "float32", "float16", "int32", "int8", "uint8" 1에서 N까지 1에서 5까지
indices "int32", "uint32", "int64" "int32" 1에서 N까지 1에서 5까지
출력 input동일한 유형 "float32", "float16", "int32", "int8", "uint8" N 0에서 5까지

MLOpSupportLimits에는 gatherND()에 대해 다음 멤버가 있습니다.

gatherND, 유형은 MLGatherSupportLimits

gatherND() 연산자의 지원 제한입니다.

indices 매개변수는 gatherND()에 대해 그래프를 빌드할 때 입력을 실행 전까지 알 수 없으므로 허용 범위로 제한할 수 없습니다. 기반 플랫폼이 지정된 제한 동작을 제공하지 않는 경우 구현은 컴파일된 그래프에 clamp()를 도입할 수 있습니다. 마찬가지로 기반 플랫폼이 음수 인덱스를 지원하지 않는 경우 구현은 컴파일된 그래프에 연산을 도입하여 차원의 끝에서부터의 음수 인덱스를 양수 인덱스로 변환할 수 있습니다.
gatherND(input, indices, options) 메서드의 단계는 다음과 같습니다.
  1. this빌드할 수 없는 상태이면 "InvalidStateError" DOMExceptionthrow합니다.

  2. thisinputindices 중 하나를 사용하여 피연산자를 검증한 결과가 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을 빈 목록으로 둡니다.

  12. 0부터 indexableSize까지의 범위에서 각 index에 대해 각각(상한 제외):

    1. indicesShape[index]를 outputShape추가합니다.

  13. coordinateSize부터 inputRank까지의 범위에서 각 index에 대해 각각(상한 제외):

    1. inputShape[index]를 outputShape추가합니다.

  14. outputDescinputdataTypeoutputShape이 주어진 상태에서 MLOperandDescriptor를 생성한 결과로 둡니다.

  15. 그래프 연결을 구성합니다.

    1. outputoutputDesc가 주어진 상태에서 MLOperand를 생성한 결과로 둡니다.

    2. operatorinput, indices, 그리고 options가 주어진 "gatherND" 연산에 대한 연산자로 둡니다.

    3. output.[[operator]]operator로 설정합니다.

    4. operator입력inputindices로 설정합니다.

    5. operator출력output으로 설정합니다.

  16. output을 반환합니다.

다양한 슬라이싱 방식에서 gatherND가 작동하는 방식의 예입니다.
// 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 좌표 [1, *]의 행 [2, 3]
//    [0, 1]]   <= input 좌표 [0, *]의 행 [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 좌표 [0, 1, *]의 행 [2, 3]
//    [4, 5]]   <= input 좌표 [1, 0, *]의 행 [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 좌표 [1, *, *]의 블록 [[4, 5], [6, 7]]
//     [6, 7]],
//    [[0, 1],   <= input 좌표 [0, *, *]의 블록 [[0, 1], [2, 3]]
//     [2, 3]],
//    [[4, 5],   <= input 좌표 [1, *, *]의 블록 [[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

입력 텐서의 가우시안 오류 선형 유닛 함수(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()의 텐서 제한
피연산자 허용되는 데이터 유형 필수 데이터 유형 허용되는 rank 필수 rank
input "float32", "float16" "float32", "float16" N 0에서 5까지
출력 input동일한 유형 "float32", "float16" input동일한 rank 0에서 5까지

MLOpSupportLimits에는 gelu()에 대해 다음 멤버가 있습니다.

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. operator입력input으로 설정합니다.

    5. operator출력output으로 설정합니다.

  5. output을 반환합니다.

사용자 에이전트에는 일반적으로 더 효율적인 구현이 있지만, 이 연산의 동작은 다음과 같이 다른 연산을 사용하여 일반적으로 에뮬레이션할 수 있습니다. 기반 플랫폼이 연산을 직접 지원하지 않는 경우 이 분해를 구현을 안내하는 템플릿으로 사용할 수 있습니다.
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의 일반 행렬 곱셈을 계산합니다. 계산은 다음 식을 따릅니다. alpha * A * B + beta * C. 여기서 A는 shape이 [M, K] 또는 [K, M]인 2차원 텐서이고, B는 shape이 [K, N] 또는 [N, K]인 2차원 텐서이며, C는 shape [M, N]으로 단방향 브로드캐스트 가능합니다. AB는 계산 전에 선택적으로 전치할 수 있습니다.
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

세 번째 입력 텐서입니다. 스칼라이거나 shape [M, N]으로 단방향 브로드캐스트 가능한 shape입니다. 지정되지 않으면 c가 스칼라 0.0인 것처럼 계산합니다.

alpha, 유형은 double이며 기본값은 1.0

첫 번째 입력에 대한 배수입니다.

beta, 유형은 double이며 기본값은 1.0

세 번째 입력 c에 대한 배수입니다.

aTranspose, 유형은 boolean이며 기본값은 false

출력을 계산하기 전에 첫 번째 입력을 전치할지 나타냅니다.

bTranspose, 유형은 boolean이며 기본값은 false

출력을 계산하기 전에 두 번째 입력을 전치할지 나타냅니다.

인수:

반환: MLOperand입니다. 모든 입력의 계산된 곱을 포함하는 shape [M, N]의 출력 2차원 텐서입니다.

gemm()의 텐서 제한
피연산자 허용되는 데이터 유형 필수 데이터 유형 허용되는 rank 필수 rank
a "float32", "float16" "float32", "float16" 2 2
b a동일한 유형 "float32", "float16" 2 2
c a동일한 유형 "float32", "float16" 0에서 2까지 0에서 2까지
출력 a동일한 유형 "float32", "float16" 2 2

MLGemmSupportLimits에는 다음 멤버가 있습니다.

a, 유형은 MLTensorLimits

a 피연산자에 대한 MLTensorLimits입니다.

b, 유형은 MLTensorLimits

b 피연산자에 대한 MLTensorLimits입니다.

c, 유형은 MLTensorLimits

c 피연산자에 대한 MLTensorLimits입니다.

output, 유형은 MLTensorLimits

출력 피연산자에 대한 MLTensorLimits입니다.

MLOpSupportLimits에는 gemm()에 대해 다음 멤버가 있습니다.

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으로 캐스트한 결과로 설정합니다.

  6. options.betaoptions.betaadataType으로 캐스트한 결과로 설정합니다.

  7. shapeAashape복제본으로 둡니다.

  8. shapeBbshape복제본으로 둡니다.

  9. options.aTranspose 가 true이면 shapeA의 항목 순서를 뒤집습니다.

  10. options.bTranspose 가 true이면 shapeB의 항목 순서를 뒤집습니다.

  11. shapeA[1]이 shapeB[0]과 같지 않으면 TypeErrorthrow합니다.

  12. options.c존재하면:

    1. shape « shapeA[0], shapeB[1] »로 단방향 브로드캐스트 가능하지 않으면 TypeErrorthrow합니다.

    2. dataType이 해당 허용되는 데이터 유형 중 하나가 아니면(이 표에 따름) TypeErrorthrow합니다.

  13. descadataType과 « shapeA[0], shapeB[1] »이 주어진 상태에서 MLOperandDescriptor를 생성한 결과로 둡니다.

  14. 그래프 연결을 구성합니다.

    1. outputthisdesc가 주어진 상태에서 MLOperand를 생성한 결과로 둡니다.

    2. operatoroptions가 주어진 "gemm" 연산에 대한 연산자로 둡니다.

    3. output.[[operator]]operator로 설정합니다.

    4. operator입력ab로 설정합니다.

    5. options.c존재하면 이를 operator입력에 추가합니다.

    6. operator출력output으로 설정합니다.

  15. output을 반환합니다.

사용자 에이전트에는 일반적으로 더 효율적인 구현이 있지만, 이 연산의 동작은 다음과 같이 다른 연산을 사용하여 일반적으로 에뮬레이션할 수 있습니다. 기반 플랫폼이 연산을 직접 지원하지 않는 경우 이 분해를 구현을 안내하는 템플릿으로 사용할 수 있습니다.
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] 순환 네트워크는 update, reset 및 new gate를 사용하여 네트워크의 시간적 시퀀스를 따라 출력으로 전달되는 출력 상태를 계산합니다.
enum MLGruWeightLayout {
  "zrn",  // update-reset-new gate 순서
  "rzn"   // reset-update-new gate 순서
};

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차원 입력 bias 텐서입니다. 텐서 shape의 두 번째 차원에서 bias 벡터의 순서는 layout에 따라 지정됩니다.

recurrentBias, 유형은 MLOperand

shape이 [numDirections, 3 * hiddenSize]인 2차원 recurrent bias 텐서입니다. 텐서 shape의 두 번째 차원에서 bias 벡터의 순서는 layout에 따라 지정됩니다.

initialHiddenState, 유형은 MLOperand

shape이 [numDirections, batchSize, hiddenSize]인 3차원 초기 hidden state 텐서입니다. 지정되지 않은 경우 구현은 반드시 0으로 채운 텐서를 사용해야 합니다.

resetAfter, 유형은 boolean이며 기본값은 true

행렬 곱셈 후 또는 전에 reset gate를 적용할지를 나타냅니다.

returnSequence, 유형은 boolean이며 기본값은 false

마지막 time step의 출력과 더불어 각 time step의 모든 출력을 포함하는 전체 시퀀스도 반환할지를 나타냅니다.

direction, 유형은 MLRecurrentNetworkDirection이며 기본값은 "forward"

입력 시퀀스의 처리 방향입니다. "both"로 설정하면 weight 및 bias 텐서 shape의 첫 번째 차원 크기는 반드시 2여야 하며, 입력은 양방향으로 처리됩니다.

layout, 유형은 MLGruWeightLayout이며 기본값은 "zrn"

GRU의 내부 gate에 대한 weight 및 bias 벡터의 순서로, 구체적으로 update (z), reset (r), 그리고 new (n) gate이며, 이는 weight 및 bias 텐서 shape의 두 번째 차원에 표시됩니다.

activations, 유형은 sequence<MLRecurrentNetworkActivation>

첫 번째 함수는 update 및 reset gate에 사용되고 두 번째 함수는 new gate에 사용되는 한 쌍의 활성화 함수를 지정합니다. 지정되지 않은 경우 각각 "sigmoid""tanh" 함수가 기본값입니다.

인수:

반환: sequence<MLOperand>. 첫 번째 요소는 shape이 [numDirections, batchSize, hiddenSize]인 3차원 텐서이며, 네트워크의 마지막 time step에서의 cell 출력입니다. 또한 returnSequence 가 true로 설정된 경우 두 번째 요소는 shape이 [steps, numDirections, batchSize, hiddenSize]인 4차원 출력 텐서이며 시간적 시퀀스의 각 time step에서 나온 모든 cell 출력을 포함합니다.

gru()의 텐서 제한
피연산자 허용되는 데이터 유형 필수 데이터 유형 허용되는 rank 필수 rank
input "float32", "float16" "float32", "float16" 3 3
weight 동일한 유형 input "float32", "float16" 3 3
recurrentWeight 동일한 유형 input "float32", "float16" 3 3
bias 동일한 유형 input "float32", "float16" 2 2
recurrentBias 동일한 유형 input "float32", "float16" 2 2
initialHiddenState 동일한 유형 input "float32", "float16" 3 3
outputs[0] 동일한 유형 input "float32", "float16" 3 3
outputs[1] if returnSequence 가 true인 경우 동일한 유형 input "float32", "float16" 4 4

MLGruSupportLimits 에는 다음 멤버가 있습니다.

input, 유형은 MLTensorLimits

입력 피연산자에 대한 MLTensorLimits입니다.

weight, 유형은 MLTensorLimits

weight 피연산자에 대한 MLTensorLimits입니다.

recurrentWeight, 유형은 MLTensorLimits

recurrentWeight 피연산자에 대한 MLTensorLimits입니다.

bias, 유형은 MLTensorLimits

bias 피연산자에 대한 MLTensorLimits입니다.

recurrentBias, 유형은 MLTensorLimits

recurrentBias 피연산자에 대한 MLTensorLimits입니다.

initialHiddenState, 유형은 MLTensorLimits

initialHiddenState 피연산자에 대한 MLTensorLimits입니다.

output0, 유형은 MLTensorLimits

모든 출력 피연산자[0]에 대한 MLTensorLimits입니다.

output1, 유형은 MLTensorLimits

모든 출력 피연산자[1]에 대한 MLTensorLimits입니다.

MLOpSupportLimits 에는 gru()에 대해 다음 멤버가 있습니다.

gru, 유형은 MLGruSupportLimits

gru() 연산자의 지원 제한입니다.

gru(input, weight, recurrentWeight, steps, hiddenSize, options) 메서드의 단계는 다음과 같습니다.
  1. this빌드할 수 없는 상태이면 예외를 발생시킵니다. "InvalidStateError" DOMException입니다.

  2. 피연산자를 검증할 때 thisinput, weight, recurrentWeight, options.bias (존재하는 경우), options.recurrentBias (존재하는 경우), 그리고 options.initialHiddenState (존재하는 경우) 중 하나가 false를 반환하면 예외를 발생시킵니다. TypeError입니다.

  3. input, weight 또는 recurrentWeight 중 하나의 dataType이 해당 허용되는 데이터 유형 중 하나가 아니면(이 표에 따름) 예외를 발생시킵니다. TypeError입니다.

  4. input, weight 또는 recurrentWeight 중 하나의 rank가 해당 허용되는 rank가 아니면 예외를 발생시킵니다. TypeError입니다.

  5. inputshape[0]이 steps와 같지 않으면 예외를 발생시킵니다. TypeError입니다.

  6. batchSizeinputshape[1]로 둡니다.

  7. inputSizeinputshape[2]로 둡니다.

  8. numDirectionsoptions.direction"both"이면 2로, 그렇지 않으면 1로 둡니다.

  9. weightshape이 « numDirections, 3 * hiddenSize, inputSize »와 같지 않으면 예외를 발생시킵니다. TypeError입니다.

  10. recurrentWeightshape이 « numDirections, 3 * hiddenSize, hiddenSize »와 같지 않으면 예외를 발생시킵니다. TypeError입니다.

  11. hiddenSize * 6이 유효한 차원이 아니면 예외를 발생시킵니다. TypeError입니다.

    hiddenSize * 6인가요? 일부 기반 플랫폼은 biasrecurrentBias를 연결한 단일 bias 텐서에서 동작합니다. 따라서 3 * hiddenSize + 3 * hiddenSize 역시 유효한 차원이어야 합니다.
  12. options.bias존재하면:

    1. dataType이 해당 허용되는 데이터 유형 중 하나가 아니면(이 표에 따름) 예외를 발생시킵니다. TypeError입니다.

    2. shape이 « numDirections, 3 * hiddenSize »와 같지 않으면 예외를 발생시킵니다. TypeError입니다.

  13. options.recurrentBias존재하면:

    1. dataType이 해당 허용되는 데이터 유형 중 하나가 아니면(이 표에 따름) 예외를 발생시킵니다. TypeError입니다.

    2. shape이 « numDirections, 3 * hiddenSize »와 같지 않으면 예외를 발생시킵니다. TypeError입니다.

  14. options.initialHiddenState존재하면:

    1. dataType이 해당 허용되는 데이터 유형 중 하나가 아니면(이 표에 따름) 예외를 발생시킵니다. TypeError입니다.

    2. shape이 « numDirections, batchSize, hiddenSize »와 같지 않으면 예외를 발생시킵니다. TypeError입니다.

  15. options.activations존재하면:

    1. 크기가 2가 아니면 예외를 발생시킵니다. TypeError입니다.

    2. activationsoptions.activations복제본으로 둡니다.

  16. 그렇지 않으면:

    1. activations를 « "sigmoid", "tanh" »로 둡니다.

  17. 출력 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. output목록 « output0, output1 »로 둡니다.

      3. output0.[[operator]]output1.[[operator]]operator로 설정합니다.

    4. 그렇지 않으면:

      1. output목록 « output0 »로 둡니다.

      2. output0.[[operator]]operator로 설정합니다.

    5. operator입력input, weight, 그리고 recurrentWeight로 설정합니다.

    6. options.bias존재하면 이를 operator입력에 추가합니다.

    7. options.recurrentBias존재하면 이를 operator입력에 추가합니다.

    8. options.initialHiddenState존재하면 이를 operator입력에 추가합니다.

    9. operator활성화 함수activations복제본으로 설정합니다.

    10. operator출력output으로 설정합니다.

  19. output을 반환합니다.

squeeze() 헬퍼를 사용하면, 사용자 에이전트에는 일반적으로 더 효율적인 구현이 있지만 이 연산의 동작을 다음과 같이 다른 연산을 사용하여 일반적으로 에뮬레이션할 수 있습니다. 기반 플랫폼이 연산을 직접 지원하지 않는 경우 이 분해를 구현을 안내하는 템플릿으로 사용할 수 있습니다.
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) {
        // 2차원([batchSize, hiddenSize])인 currentHidden을 확장합니다.
        // 4차원([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;
        }
      }
    }

    // 2차원([batchSize, hiddenSize])인 currentHidden을 확장합니다.
    // 3차원([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') {
      // 축 1을 따라 연결합니다(numDirections 차원).
      outputSequence = builder.concat([forwardSequence, backwardSequence], 1);
    }

    return [outputHidden, outputSequence];
  } else {
    return [outputHidden];
  }
}

8.9.26. gruCell

Gated Recurrent Unit [GRU] 순환 네트워크의 단일 time step으로, update gate와 reset gate를 사용하여 순환 네트워크의 시간적 시퀀스를 따라 출력으로 전달되는 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차원 입력 bias 텐서입니다. 텐서 shape의 두 번째 차원에서 bias 벡터의 순서는 layout에 따라 지정됩니다.

recurrentBias, 유형은 MLOperand

shape이 [3 * hiddenSize]인 1차원 recurrent bias 텐서입니다. 텐서 shape의 두 번째 차원에서 bias 벡터의 순서는 layout에 따라 지정됩니다.

resetAfter, 유형은 boolean이며 기본값은 true

행렬 곱셈 후 또는 전에 reset gate를 적용할지를 나타냅니다.

layout, 유형은 MLGruWeightLayout이며 기본값은 "zrn"

GRU의 내부 gate에 대한 weight 및 bias 벡터의 순서로, 구체적으로 update (z), reset (r), 그리고 new (n) gate이며, 이는 weight 및 bias 텐서 shape의 두 번째 차원에 표시됩니다.

activations, 유형은 sequence<MLRecurrentNetworkActivation>

첫 번째 함수는 update 및 reset gate에 사용되고 두 번째 함수는 new gate에 사용되는 한 쌍의 활성화 함수를 지정합니다. 지정되지 않은 경우 각각 "sigmoid""tanh" 함수가 기본값입니다.

인수:

반환: MLOperand입니다. shape이 [batchSize, hiddenSize]인 2차원 텐서로, 순환 네트워크의 단일 time step에 대한 cell 출력 hidden state입니다.

gruCell()의 텐서 제한
피연산자 허용되는 데이터 유형 필수 데이터 유형 허용되는 rank 필수 rank
input "float32", "float16" "float32", "float16" 2 2
weight 동일한 유형 input "float32", "float16" 2 2
recurrentWeight 동일한 유형 input "float32", "float16" 2 2
hiddenState 동일한 유형 input "float32", "float16" 2 2
bias 동일한 유형 input "float32", "float16" 1 1
recurrentBias 동일한 유형 input "float32", "float16" 1 1
출력 동일한 유형 input "float32", "float16" 2 2

MLGruCellSupportLimits 에는 다음 멤버가 있습니다;

input, 유형은 MLTensorLimits

입력 피연산자에 대한 MLTensorLimits입니다.

weight, 유형은 MLTensorLimits

weight 피연산자에 대한 MLTensorLimits입니다.

recurrentWeight, 유형은 MLTensorLimits

recurrentWeight 피연산자에 대한 MLTensorLimits입니다.

hiddenState, 유형은 MLTensorLimits

hiddenState 피연산자에 대한 MLTensorLimits입니다.

bias, 유형은 MLTensorLimits

bias 피연산자에 대한 MLTensorLimits입니다.

recurrentBias, 유형은 MLTensorLimits

recurrentBias 피연산자에 대한 MLTensorLimits입니다.

output, 유형은 MLTensorLimits

출력 피연산자에 대한 MLTensorLimits입니다.

MLOpSupportLimits 에는 gruCell()에 대해 다음 멤버가 있습니다.

gruCell, 유형은 MLGruCellSupportLimits

gruCell() 연산자의 지원 제한입니다.

gruCell(input, weight, recurrentWeight, hiddenState, hiddenSize, options) 메서드의 단계는 다음과 같습니다.
  1. this빌드할 수 없는 상태이면 예외를 발생시킵니다. "InvalidStateError" DOMException입니다.

  2. 피연산자를 검증할 때 thisinput, weight, recurrentWeight, hiddenState, options.bias (존재하는 경우), 그리고 options.recurrentBias (존재하는 경우) 중 하나가 false를 반환하면 예외를 발생시킵니다. TypeError입니다.

  3. input, weight, recurrentWeight, 또는 hiddenState 중 하나의 dataType이 해당 허용되는 데이터 유형 중 하나가 아니면(이 표에 따름) 예외를 발생시킵니다. TypeError입니다.

  4. input, weight, recurrentWeight 또는 hiddenState 중 하나의 rank가 해당 허용되는 rank가 아니면(이 표에 따름) 예외를 발생시킵니다. TypeError입니다.

  5. batchSizeinputshape[0]으로 둡니다.

  6. inputSizeinputshape[1]로 둡니다.

  7. weightshape이 « 3 * hiddenSize, inputSize »와 같지 않으면 예외를 발생시킵니다. TypeError입니다.

  8. recurrentWeightshape이 « 3 * hiddenSize, hiddenSize »와 같지 않으면 예외를 발생시킵니다. TypeError입니다.

  9. hiddenStateshape이 « batchSize, hiddenSize »와 같지 않으면 예외를 발생시킵니다. TypeError입니다.

  10. hiddenSize * 6이 유효한 차원이 아니면 예외를 발생시킵니다. TypeError입니다.

    hiddenSize * 6인가요? 일부 기반 플랫폼은 biasrecurrentBias를 연결한 단일 bias 텐서에서 동작합니다. 따라서 3 * hiddenSize + 3 * hiddenSize 역시 유효한 차원이어야 합니다.
  11. options.bias존재하면:

    1. dataType이 해당 허용되는 데이터 유형 중 하나가 아니면(이 표에 따름) 예외를 발생시킵니다. TypeError입니다.

    2. shape이 « 3 * hiddenSize »와 같지 않으면 예외를 발생시킵니다. TypeError입니다.

  12. options.recurrentBias존재하면:

    1. dataType이 해당 허용되는 데이터 유형 중 하나가 아니면(이 표에 따름) 예외를 발생시킵니다. TypeError입니다.

    2. shape이 « 3 * hiddenSize »와 같지 않으면 예외를 발생시킵니다. TypeError입니다.

  13. options.activations존재하면:

    1. 크기가 2가 아니면 예외를 발생시킵니다. TypeError입니다.

    2. activationsoptions.activations복제본으로 둡니다.

  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. operator입력input, weight, recurrentWeight, 그리고 hiddenState로 설정합니다.

    5. options.bias존재하면 이를 operator입력에 추가합니다.

    6. options.recurrentBias존재하면 이를 operator입력에 추가합니다.

    7. operator활성화 함수activations복제본으로 설정합니다.

    8. operator출력output으로 설정합니다.

  17. output을 반환합니다.

weight 레이아웃이 기본 "zrn" 레이아웃이고, update/reset gate 및 new gate의 활성화 함수가 각각 sigmoid()tanh() 인 경우 이 연산의 동작은 다음과 같이 다른 연산을 사용하여 일반적으로 에뮬레이션할 수 있지만 사용자 에이전트에는 일반적으로 더 효율적인 구현이 있습니다. 기반 플랫폼이 연산을 직접 지원하지 않는 경우 이 분해를 구현을 안내하는 템플릿으로 사용할 수 있습니다.
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]))))));
  }

  // 새로운 hidden state를 계산합니다.
  return builder.add(
    builder.mul(z, hiddenState), builder.mul(n, builder.sub(one, z)));
}

8.9.27. hardSigmoid

더 빠른 계산을 위해 sigmoid 함수 대신 사용하는 비평활 hard sigmoid 함수를 입력 텐서에 대해 계산합니다.
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

스칼라 배수입니다.

beta, 유형은 double이며 기본값은 0.5

스칼라 가산값입니다.

인수:

반환:

hardSigmoid()의 텐서 제한
피연산자 허용되는 데이터 유형 필수 데이터 유형 허용되는 rank 필수 rank
input "float32", "float16" "float32", "float16" N 0에서 5까지
출력 동일한 유형 input "float32", "float16" 동일한 rank input 0에서 5까지

MLOpSupportLimits 에는 hardSigmoid()에 대해 다음 멤버가 있습니다.

hardSigmoid, 유형은 MLSingleInputSupportLimits

hardSigmoid() 연산자의 지원 제한입니다.

hardSigmoid(input, options) 메서드의 단계는 다음과 같습니다.
  1. this빌드할 수 없는 상태이면 예외를 발생시킵니다. "InvalidStateError" DOMException입니다.

  2. 피연산자를 검증할 때 thisinput이 false를 반환하면 예외를 발생시킵니다. TypeError입니다.

  3. inputdataType이 해당 허용되는 데이터 유형 중 하나가 아니면(이 표에 따름) 예외를 발생시킵니다. TypeError입니다.

  4. options.alphaoptions.alphainputdataType으로 캐스트한 결과로 설정합니다.

  5. options.betaoptions.betainputdataType으로 캐스트한 결과로 설정합니다.

  6. 그래프 연결을 구성합니다.

    1. outputinput이 주어진 상태에서 MLOperand를 복사한 결과로 둡니다.

    2. operatoroptions가 주어진 "hardSigmoid" 연산에 대한 연산자로 둡니다.

    3. output.[[operator]]operator로 설정합니다.

    4. operator입력input으로 설정합니다.

    5. operator출력output으로 설정합니다.

  7. output을 반환합니다.

사용자 에이전트에는 일반적으로 더 효율적인 구현이 있지만, 이 연산의 동작은 다른 연산을 사용하여 다음과 같이 일반적으로 에뮬레이션할 수 있습니다. 기반 플랫폼이 연산을 직접 지원하지 않는 경우 이 분해를 구현을 안내하는 템플릿으로 사용할 수 있습니다.
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를 입력 텐서에 요소별로 계산합니다.
partial interface MLGraphBuilder {
  MLOperand hardSwish(MLOperand input, optional MLOperatorOptions options = {});
};

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

반환:

hardSwish()의 텐서 제한
피연산자 허용되는 데이터 유형 필수 데이터 유형 허용되는 rank 필수 rank
input "float32", "float16" "float32", "float16" N 0에서 5까지
출력 동일한 유형 input "float32", "float16" 동일한 rank input 0에서 5까지

MLOpSupportLimits 에는 hardSwish()에 대해 다음 멤버가 있습니다.

hardSwish, 유형은 MLSingleInputSupportLimits

hardSwish() 연산자의 지원 제한입니다.

hardSwish(input, options) 메서드의 단계는 다음과 같습니다.
  1. this빌드할 수 없는 상태이면 예외를 발생시킵니다. "InvalidStateError" DOMException입니다.

  2. 피연산자를 검증할 때 thisinput이 false를 반환하면 예외를 발생시킵니다. TypeError입니다.

  3. inputdataType이 해당 허용되는 데이터 유형 중 하나가 아니면(이 표에 따름) 예외를 발생시킵니다. TypeError입니다.

  4. 그래프 연결을 구성합니다.

    1. outputinput이 주어진 상태에서 MLOperand를 복사한 결과로 둡니다.

    2. operatoroptions가 주어진 "hardSwish" 연산에 대한 연산자로 둡니다.

    3. output.[[operator]]operator로 설정합니다.

    4. operator입력input으로 설정합니다.

    5. operator출력output으로 설정합니다.

  5. output을 반환합니다.

사용자 에이전트에는 일반적으로 더 효율적인 구현이 있지만, 이 연산의 동작은 다른 연산을 사용하여 다음과 같이 일반적으로 에뮬레이션할 수 있습니다. 기반 플랫폼이 연산을 직접 지원하지 않는 경우 이 분해를 구현을 안내하는 템플릿으로 사용할 수 있습니다.
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]을 사용하여 입력을 정규화합니다. 모델을 학습하는 동안 정규화에 사용되는 평균과 분산 값이 batch 차원의 모든 샘플에 걸쳐 계산되는 batchNormalization() 과 달리, instance normalization에서 사용하는 평균과 분산 값은 batch의 각 개별 샘플의 각 입력 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

크기가 채널 수, 즉 입력 feature 차원의 크기와 같은 스케일링 값의 1차원 텐서입니다. 예를 들어 input 텐서의 레이아웃이 "nchw" 인 경우 크기inputshape[1]과 같습니다.

bias, 유형은 MLOperand

크기가 입력 feature 차원의 크기와 같은 bias 값의 1차원 텐서입니다. 예를 들어 input 텐서의 레이아웃이 "nchw" 인 경우 크기inputshape[1]과 같습니다.

epsilon, 유형은 double이며 기본값은 1e-5

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

layout, 유형은 MLInputOperandLayout이며 기본값은 "nchw"

입력의 레이아웃 형식입니다.

인수:

반환: MLOperand입니다. input과 동일한 shape을 가진 instance-normalized 4차원 텐서입니다.

instanceNormalization()의 텐서 제한
피연산자 허용되는 데이터 유형 필수 데이터 유형 허용되는 rank 필수 rank
input "float32", "float16" "float32", "float16" 4 4
scale 동일한 유형 input "float32", "float16" 1 1
bias 동일한 유형 input "float32", "float16" 1 1
출력 동일한 유형 input "float32", "float16" 4 4

MLNormalizationSupportLimits 에는 다음 멤버가 있습니다.

input, 유형은 MLTensorLimits

입력 피연산자에 대한 MLTensorLimits입니다.

scale, 유형은 MLTensorLimits

scale 피연산자에 대한 MLTensorLimits입니다.

bias, 유형은 MLTensorLimits

bias 피연산자에 대한 MLTensorLimits입니다.

output, 유형은 MLTensorLimits

출력 피연산자에 대한 MLTensorLimits입니다.

MLOpSupportLimits 에는 instanceNormalization()에 대해 다음 멤버가 있습니다.

instanceNormalization, 유형은 MLNormalizationSupportLimits

instanceNormalization() 연산자의 지원 제한입니다.

instanceNormalization(input, options) 메서드의 단계는 다음과 같습니다.
  1. this빌드할 수 없는 상태이면 예외를 발생시킵니다. "InvalidStateError" DOMException입니다.

  2. 피연산자를 검증할 때 thisinput, options.scale (존재하는 경우), 그리고 options.bias (존재하는 경우) 중 하나가 false를 반환하면 예외를 발생시킵니다. TypeError입니다.

  3. inputdataType이 해당 허용되는 데이터 유형 중 하나가 아니면(이 표에 따름) 예외를 발생시킵니다. TypeError입니다.

  4. inputrank가 해당 허용되는 rank가 아니면 예외를 발생시킵니다. TypeError입니다.

  5. options.epsilonoptions.epsiloninputdataType으로 캐스트한 결과로 설정합니다.

  6. axisoptions.layout"nchw"이면 1로, 그렇지 않으면 3으로 둡니다.

  7. options.scale존재하면:

    1. dataType이 해당 허용되는 데이터 유형 중 하나가 아니면(이 표에 따름) 예외를 발생시킵니다. TypeError입니다.

    2. shape이 « inputshape[axis] »와 같지 않으면 예외를 발생시킵니다. TypeError입니다.

  8. options.bias존재하면:

    1. dataType이 해당 허용되는 데이터 유형 중 하나가 아니면(이 표에 따름) 예외를 발생시킵니다. TypeError입니다.

    2. shape이 « inputshape[axis] »와 같지 않으면 예외를 발생시킵니다. TypeError입니다.

  9. 그래프 연결을 구성합니다.

    1. outputinput이 주어진 상태에서 MLOperand를 복사한 결과로 둡니다.

    2. operatoroptions가 주어진 "instanceNormalization" 연산에 대한 연산자로 둡니다.

    3. output.[[operator]]operator로 설정합니다.

    4. operator입력input으로 설정합니다.

    5. options.scale존재하면 이를 operator입력에 추가합니다.

    6. options.bias존재하면 이를 operator입력에 추가합니다.

    7. operator출력output으로 설정합니다.

  10. output을 반환합니다.

입력 텐서가 "nchw" 레이아웃의 4차원 텐서인 경우, 이 연산의 동작은 다른 연산을 사용하여 다음과 같이 일반적으로 에뮬레이션할 수 있지만 사용자 에이전트에는 일반적으로 더 효율적인 구현이 있습니다. 기반 플랫폼이 연산을 직접 지원하지 않는 경우 이 분해를 구현을 안내하는 템플릿으로 사용할 수 있습니다.
function instanceNormalization(builder, input, options) {
  // 평균 및 분산 값의 축소는 입력의 공간
  // 차원, 예를 들어 입력 텐서의 축 2와 3에서 수행됩니다.
  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);

  // scale 및 bias 값은 입력 feature별로 적용됩니다.
  // 예를 들어 입력 텐서의 축 1입니다.
  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]을 사용하여 입력을 정규화합니다. 모델을 학습하는 동안 평균과 분산 값이 batch 차원의 모든 샘플에 걸쳐 계산되는 batchNormalization() 및 batch의 각 개별 샘플의 각 입력 feature에 대해 평균과 분산 값이 즉석에서 계산되는 instanceNormalization() 과 달리, layer normalization의 평균과 분산 값은 batch의 각 개별 샘플의 모든 입력 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이 결정되는 스케일링 값의 N차원 텐서이며, axes 의 각 값은 스케일링 값이 있는 입력 텐서의 차원을 나타냅니다. 예를 들어 axes 값이 [1,2,3]이면 이 텐서의 shape은 입력 차원 1, 2 및 3의 대응하는 크기 목록입니다. 이 멤버가 없으면 스케일링 값은 1로 간주됩니다.

bias, 유형은 MLOperand

axes 멤버에 의해 shape이 결정되는 bias 값의 N차원 텐서이며, axes 의 각 값은 bias 값이 있는 입력 텐서의 차원을 나타냅니다. 예를 들어 axes 값이 [1,2,3]이면 이 텐서의 shape은 입력 차원 1, 2 및 3의 대응하는 크기 목록입니다. 이 멤버가 없으면 bias 값은 0으로 간주됩니다.

axes, 유형은 sequence<[EnforceRange] unsigned long>

축소할 입력 차원의 인덱스입니다. 이 멤버가 없으면 첫 번째 차원을 제외한 모든 차원이 지정된 것으로 처리됩니다(예: 4차원 입력 텐서의 경우 axes = [1,2,3]). 즉, 평균과 분산 값에 대한 축소는 각 독립적인 batch의 모든 입력 feature에 걸쳐 계산됩니다. 비어 있으면 어떤 차원도 축소하지 않습니다.

epsilon, 유형은 double이며 기본값은 1e-5

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

인수:

반환: MLOperand입니다. input과 동일한 shape을 가진 layer-normalized N차원 텐서입니다.

layerNormalization()의 텐서 제한
피연산자 허용되는 데이터 유형 필수 데이터 유형 허용되는 rank 필수 rank
input "float32", "float16" "float32", "float16" N 0에서 5까지
scale 동일한 유형 input "float32", "float16" N 0에서 5까지
bias 동일한 유형 input "float32", "float16" N 0에서 5까지
출력 동일한 유형 input "float32", "float16" 동일한 rank input 0에서 5까지

MLOpSupportLimits 에는 layerNormalization()에 대해 다음 멤버가 있습니다.

layerNormalization, 유형은 MLNormalizationSupportLimits

layerNormalization() 연산자의 지원 제한입니다.

layerNormalization(input, options) 메서드의 단계는 다음과 같습니다.
  1. this빌드할 수 없는 상태이면 예외를 발생시킵니다. "InvalidStateError" DOMException입니다.

  2. 피연산자를 검증할 때 thisinput, options.scale (존재하는 경우), 그리고 options.bias (존재하는 경우) 중 하나가 false를 반환하면 예외를 발생시킵니다. TypeError입니다.

  3. inputdataType이 해당 허용되는 데이터 유형 중 하나가 아니면(이 표에 따름) 예외를 발생시킵니다. TypeError입니다.

  4. options.axes존재하지 않으면 options.axes 를 새 목록으로 설정합니다. inputrank가 1보다 크면 1부터 inputrank까지의 범위(상한 제외)로 하고, 그렇지 않으면 빈 목록으로 합니다.

  5. 그렇지 않고 options.axes 에 중복 값이 포함되어 있거나 그 항목 중 하나라도 0부터 inputrank까지의 범위(상한 제외)에 없으면 예외를 발생시킵니다. TypeError입니다.

  6. options.epsilonoptions.epsiloninputdataType으로 캐스트한 결과로 설정합니다.

  7. options.scale존재하면:

    1. dataType이 해당 허용되는 데이터 유형 중 하나가 아니면(이 표에 따름) 예외를 발생시킵니다. TypeError입니다.

    2. rankoptions.axes크기와 같지 않으면 예외를 발생시킵니다. TypeError입니다.

  8. options.bias존재하면:

    1. dataType이 해당 허용되는 데이터 유형 중 하나가 아니면(이 표에 따름) 예외를 발생시킵니다. TypeError입니다.

    2. rankoptions.axes크기와 같지 않으면 예외를 발생시킵니다. TypeError입니다.

  9. 0부터 options.axes크기까지의 범위에서 각 index에 대해 각각(상한 제외):

    1. axisoptions.axes[index]로 둡니다.

    2. axisinputrank보다 크거나 같으면 예외를 발생시킵니다. TypeError입니다.

    3. sizeinputshape[axis]로 둡니다.

    4. options.scale존재하면:

      1. shape[index]가 size와 같지 않으면 예외를 발생시킵니다. TypeError입니다.

    5. options.bias존재하면:

      1. shape[index]가 size와 같지 않으면 예외를 발생시킵니다. TypeError입니다.

  10. 그래프 연결을 구성합니다.

    1. outputinput이 주어진 상태에서 MLOperand를 복사한 결과로 둡니다.

    2. operatoroptions가 주어진 "layerNormalization" 연산에 대한 연산자로 둡니다.

    3. output.[[operator]]operator로 설정합니다.

    4. operator입력input으로 설정합니다.

    5. options.scale존재하면 이를 operator입력에 추가합니다.

    6. options.bias존재하면 이를 operator입력에 추가합니다.

    7. operator출력output으로 설정합니다.

  11. output을 반환합니다.

axes 매개변수가 [1,2,3]으로 설정된 경우 이 연산의 동작은 다른 연산을 사용하여 다음과 같이 일반적으로 에뮬레이션할 수 있지만 사용자 에이전트에는 일반적으로 더 효율적인 구현이 있습니다. 기반 플랫폼이 연산을 직접 지원하지 않는 경우 이 분해를 구현을 안내하는 템플릿으로 사용할 수 있습니다.
function layerNormalization(builder, input, options) {
  // 평균 및 분산 값의 축소는 입력의 모든 feature
  // (즉, 모든 채널)에 걸친 공간 차원에서 수행됩니다.
  // 텐서입니다.
  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);

  // scale 및 bias 텐서는 입력의 shape 중
  // axes 매개변수의 값(즉 [1,2,3])으로 지정된 shape을 가집니다.
  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

입력 텐서에 대해 요소별로 정류 선형 함수의 leaky 버전을 계산합니다. 계산은 다음 식을 따릅니다. 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

스칼라 배수입니다.

인수:

반환:

leakyRelu()의 텐서 제한
피연산자 허용되는 데이터 유형 필수 데이터 유형 허용되는 rank 필수 rank
input "float32", "float16" "float32", "float16" N 0에서 5까지
출력 동일한 유형 input "float32", "float16" 동일한 rank input 0에서 5까지

MLOpSupportLimits 에는 leakyRelu()에 대해 다음 멤버가 있습니다.

leakyRelu, 유형은 MLSingleInputSupportLimits

leakyRelu() 연산자의 지원 제한입니다.

leakyRelu(input, options) 메서드의 단계는 다음과 같습니다.
  1. this빌드할 수 없는 상태이면 예외를 발생시킵니다. "InvalidStateError" DOMException입니다.

  2. 피연산자를 검증할 때 thisinput이 false를 반환하면 예외를 발생시킵니다. TypeError입니다.

  3. inputdataType이 해당 허용되는 데이터 유형 중 하나가 아니면(이 표에 따름) 예외를 발생시킵니다. TypeError입니다.

  4. options.alphaoptions.alphainputdataType으로 캐스트한 결과로 설정합니다.

  5. 그래프 연결을 구성합니다.

    1. outputinput이 주어진 상태에서 MLOperand를 복사한 결과로 둡니다.

    2. operatoroptions가 주어진 "leakyRelu" 연산에 대한 연산자로 둡니다.

    3. output.[[operator]]operator로 설정합니다.

    4. operator입력input으로 설정합니다.

    5. operator출력output으로 설정합니다.

  6. output을 반환합니다.

사용자 에이전트에는 일반적으로 더 효율적인 구현이 있지만, 이 연산의 동작은 다른 연산을 사용하여 다음과 같이 일반적으로 에뮬레이션할 수 있습니다. 기반 플랫폼이 연산을 직접 지원하지 않는 경우 이 분해를 구현을 안내하는 템플릿으로 사용할 수 있습니다.
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

입력 텐서에 대해 선형 함수 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

스칼라 배수입니다.

beta, 유형은 double이며 기본값은 0

스칼라 가산값입니다.

인수:

반환:

linear()의 텐서 제한
피연산자 허용되는 데이터 유형 필수 데이터 유형 허용되는 rank 필수 rank
input "float32", "float16" "float32", "float16" N 0에서 5까지
출력 동일한 유형 input "float32", "float16" 동일한 rank input 0에서 5까지

MLOpSupportLimits 에는 linear()에 대해 다음 멤버가 있습니다.

linear, 유형은 MLSingleInputSupportLimits

linear() 연산자의 지원 제한입니다.

linear(input, options) 메서드의 단계는 다음과 같습니다.
  1. this빌드할 수 없는 상태이면 예외를 발생시킵니다. "InvalidStateError" DOMException입니다.

  2. 피연산자를 검증할 때 thisinput이 false를 반환하면 예외를 발생시킵니다. TypeError입니다.

  3. inputdataType이 해당 허용되는 데이터 유형 중 하나가 아니면(이 표에 따름) 예외를 발생시킵니다. TypeError입니다.

  4. options.alphaoptions.alphainputdataType으로 캐스트한 결과로 설정합니다.

  5. options.betaoptions.betainputdataType으로 캐스트한 결과로 설정합니다.

  6. 그래프 연결을 구성합니다.

    1. outputinput이 주어진 상태에서 MLOperand를 복사한 결과로 둡니다.

    2. operatoroptions가 주어진 "linear" 연산에 대한 연산자로 둡니다.

    3. output.[[operator]]operator로 설정합니다.

    4. operator입력input으로 설정합니다.

    5. operator출력output으로 설정합니다.

  7. output을 반환합니다.

사용자 에이전트에는 일반적으로 더 효율적인 구현이 있지만, 이 연산의 동작은 다른 연산을 사용하여 다음과 같이 일반적으로 에뮬레이션할 수 있습니다. 기반 플랫폼이 연산을 직접 지원하지 않는 경우 이 분해를 구현을 안내하는 템플릿으로 사용할 수 있습니다.
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] 순환 네트워크는 input, output, forget 및 cell gate를 사용하여 네트워크의 시간적 시퀀스를 따라 출력으로 전달되는 출력 상태를 계산합니다.
enum MLLstmWeightLayout {
  "iofg", // input-output-forget-cell gate 순서
  "ifgo"  // input-forget-cell-output gate 순서
};

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차원 입력 bias 텐서입니다. 텐서 shape의 두 번째 차원에서 bias 벡터의 순서는 layout에 따라 지정됩니다.

recurrentBias, 유형은 MLOperand

shape이 [numDirections, 4 * hiddenSize]인 2차원 recurrent bias 텐서입니다. 텐서 shape의 첫 번째 차원에서 bias 벡터의 순서는 layout에 따라 지정됩니다.

peepholeWeight, 유형은 MLOperand

shape이 [numDirections, 3 * hiddenSize]인 peephole용 2차원 weight 텐서입니다. weight 벡터의 패킹 순서는 각각 input (i), output (o), 그리고 forget (f) gate입니다.

initialHiddenState, 유형은 MLOperand

shape이 [numDirections, batchSize, hiddenSize]인 3차원 초기 hidden state 텐서입니다. 지정되지 않은 경우 구현은 반드시 0으로 채운 텐서를 사용해야 합니다.

initialCellState, 유형은 MLOperand

shape이 [numDirections, batchSize, hiddenSize]인 3차원 초기 hidden state 텐서입니다. 지정되지 않은 경우 구현은 반드시 0으로 채운 텐서를 사용해야 합니다.

returnSequence, 유형은 boolean이며 기본값은 false

마지막 time step의 출력과 더불어 각 time step의 모든 출력을 포함하는 전체 시퀀스도 반환할지를 나타냅니다.

direction, 유형은 MLRecurrentNetworkDirection이며 기본값은 "forward"

입력 시퀀스의 처리 방향입니다. "both"로 설정하면 weight 및 bias 텐서 shape의 첫 번째 차원 크기는 반드시 2여야 하며, 입력은 양방향으로 처리됩니다.

layout, 유형은 MLLstmWeightLayout이며 기본값은 "iofg"

LSTM의 내부 gate에 대한 weight 및 bias 벡터의 순서로, 구체적으로 input (i), output (o), forget (f), 그리고 cell (g) gate이며, 이는 weight 및 bias 텐서 shape의 첫 번째 차원에 표시됩니다.

activations, 유형은 sequence<MLRecurrentNetworkActivation>

세 개의 활성화 함수 목록입니다. 첫 번째 함수는 input (i), forget (f), 그리고 output (o) gate에 사용되고, 두 번째 함수는 cell (g) gate에 사용되며, 마지막 함수는 출력 hidden state를 형성하기 위해 output gate의 결과와 결합하기 전에 출력 cell state를 필터링하는 데 사용됩니다. 지정되지 않은 경우 각각 "sigmoid", "tanh", 그리고 "tanh" 함수의 시퀀스가 기본값입니다.

인수:

반환: sequence<MLOperand>. 첫 번째 요소는 shape이 [numDirections, batchSize, hiddenSize]인 3차원 텐서로, 네트워크의 마지막 time step에서의 출력 hidden state입니다. 두 번째 요소는 shape이 [numDirections, batchSize, hiddenSize]인 3차원 텐서로, 네트워크의 마지막 time step에서의 출력 cell state입니다. 또한 returnSequence 가 true로 설정된 경우 세 번째 요소는 shape이 [steps, numDirections, batchSize, hiddenSize]인 4차원 출력 텐서이며 시간적 시퀀스의 각 time step에서 나온 모든 출력을 포함합니다.

lstm()의 텐서 제한
피연산자 허용되는 데이터 유형 필수 데이터 유형 허용되는 rank 필수 rank
input "float32", "float16" "float32", "float16" 3 3
weight 동일한 유형 input "float32", "float16" 3 3
recurrentWeight 동일한 유형 input "float32", "float16" 3 3
bias 동일한 유형 input "float32", "float16" 2 2
recurrentBias 동일한 유형 input "float32", "float16" 2 2
peepholeWeight 동일한 유형 input "float32", "float16" 2 2
initialHiddenState 동일한 유형 input "float32", "float16" 3 3
initialCellState 동일한 유형 input "float32", "float16" 3 3
outputs[0] 동일한 유형 input "float32", "float16" 3 3
outputs[1] 동일한 유형 input "float32", "float16" 3 3
outputs[2] if returnSequence 가 true인 경우 동일한 유형 input "float32", "float16" 4 4

MLLstmSupportLimits 에는 다음 멤버가 있습니다.

input, 유형은 MLTensorLimits

입력 피연산자에 대한 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

모든 출력 피연산자[0]에 대한 MLTensorLimits입니다.

output1, 유형은 MLTensorLimits

모든 출력 피연산자[1]에 대한 MLTensorLimits입니다.

output2, 유형은 MLTensorLimits

모든 출력 피연산자[2]에 대한 MLTensorLimits입니다.

MLOpSupportLimits 에는 lstm()에 대해 다음 멤버가 있습니다.

lstm, 유형은 MLLstmSupportLimits

lstm() 연산자의 지원 제한입니다.

lstm(input, weight, recurrentWeight, steps, hiddenSize, options) 메서드의 단계는 다음과 같습니다.
  1. this빌드할 수 없는 상태이면 예외를 발생시킵니다. "InvalidStateError" DOMException입니다.

  2. 피연산자를 검증할 때 thisinput, weight, recurrentWeight, options.bias (존재하는 경우), options.recurrentBias (존재하는 경우), options.peepholeWeight (존재하는 경우), options.initialHiddenState (존재하는 경우), 그리고 options.initialCellState (존재하는 경우) 중 하나가 false를 반환하면 예외를 발생시킵니다. TypeError입니다.

  3. numDirectionsoptions.direction"both"이면 2로, 그렇지 않으면 1로 둡니다.

  4. input, weight 또는 recurrentWeight 중 하나의 dataType이 해당 허용되는 데이터 유형 중 하나가 아니면(이 표에 따름) 예외를 발생시킵니다. TypeError입니다.

  5. input, weight 또는 recurrentWeight 중 하나의 rank가 해당 허용되는 rank가 아니면 예외를 발생시킵니다. TypeError입니다.

  6. steps가 0이면 예외를 발생시킵니다. TypeError입니다.

  7. inputshape[0]이 steps와 같지 않으면 예외를 발생시킵니다. TypeError입니다.

  8. batchSizeinputshape[1]로 둡니다.

  9. inputSizeinputshape[2]로 둡니다.

  10. weightshape이 « numDirections, 4 * hiddenSize, inputSize »와 같지 않으면 예외를 발생시킵니다. TypeError입니다.

  11. recurrentWeightshape이 « numDirections, 4 * hiddenSize, hiddenSize »와 같지 않으면 예외를 발생시킵니다. TypeError입니다.

  12. hiddenSize * 8이 유효한 차원이 아니면 예외를 발생시킵니다. TypeError입니다.

    hiddenSize * 8인가요? 일부 기반 플랫폼은 biasrecurrentBias를 연결한 단일 bias 텐서에서 동작합니다. 따라서 4 * hiddenSize + 4 * hiddenSize 역시 유효한 차원이어야 합니다.
  13. options.bias존재하면:

    1. dataType이 해당 허용되는 데이터 유형 중 하나가 아니면(이 표에 따름) 예외를 발생시킵니다. TypeError입니다.

    2. shape이 « numDirections, 4 * hiddenSize »와 같지 않으면 예외를 발생시킵니다. TypeError입니다.

  14. options.recurrentBias존재하면:

    1. dataType이 해당 허용되는 데이터 유형 중 하나가 아니면(이 표에 따름) 예외를 발생시킵니다. TypeError입니다.

    2. shape이 « numDirections, 4 * hiddenSize »와 같지 않으면 예외를 발생시킵니다. TypeError입니다.

  15. options.peepholeWeight존재하면:

    1. dataType이 해당 허용되는 데이터 유형 중 하나가 아니면(이 표에 따름) 예외를 발생시킵니다. TypeError입니다.

    2. shape이 « numDirections, 3 * hiddenSize »와 같지 않으면 예외를 발생시킵니다. TypeError입니다.

  16. options.initialHiddenState존재하면:

    1. dataType이 해당 허용되는 데이터 유형 중 하나가 아니면(이 표에 따름) 예외를 발생시킵니다. TypeError입니다.

    2. shape이 « numDirections, batchSize, hiddenSize »와 같지 않으면 예외를 발생시킵니다. TypeError입니다.

  17. options.initialCellState존재하면:

    1. dataType이 해당 허용되는 데이터 유형 중 하나가 아니면(이 표에 따름) 예외를 발생시킵니다. TypeError입니다.

    2. shape이 « numDirections, batchSize, hiddenSize »와 같지 않으면 예외를 발생시킵니다. TypeError입니다.

  18. options.activations존재하면:

    1. 크기가 3이 아니면 예외를 발생시킵니다. TypeError입니다.

    2. activationsoptions.activations복제본으로 둡니다.

  19. 그렇지 않으면:

    1. activations를 « "sigmoid", "tanh", "tanh" »로 둡니다.

  20. 출력 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. output목록 « output0, output1, output2 »로 둡니다.

      3. output0.[[operator]], output1.[[operator]]output2.[[operator]]operator로 설정합니다.

    5. 그렇지 않으면:

      1. output목록 « output0, output1 »로 둡니다.

      2. output0.[[operator]]output1.[[operator]]operator로 설정합니다.

    6. operator입력input, weight, 그리고 recurrentWeight로 설정합니다.

    7. options.bias존재하면 이를 operator입력에 추가합니다.

    8. options.recurrentBias존재하면 이를 operator입력에 추가합니다.

    9. options.peepholeWeight존재하면 이를 operator입력에 추가합니다.

    10. options.initialHiddenState존재하면 이를 operator입력에 추가합니다.

    11. options.initialCellState존재하면 이를 operator입력에 추가합니다.

    12. operator활성화 함수activations복제본으로 설정합니다.

    13. operator출력output으로 설정합니다.

  22. output을 반환합니다.

squeeze() 헬퍼를 사용하면, 사용자 에이전트에는 일반적으로 더 효율적인 구현이 있지만 이 연산의 동작을 다른 연산을 사용하여 다음과 같이 일반적으로 에뮬레이션할 수 있습니다. 기반 플랫폼이 연산을 직접 지원하지 않는 경우 이 분해를 구현을 안내하는 템플릿으로 사용할 수 있습니다.
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) {
        // 2차원([batchSize, hiddenSize])인 currentHidden을 확장합니다.
        // 4차원([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;
        }
      }
    }

    // 2차원([batchSize, hiddenSize])인 currentHidden을 확장합니다.
    // 3차원([numDirections, batchSize, hiddenSize])으로
    const expandedHiddenAs3D =
      builder.reshape(currentHidden, [1, batchSize, hiddenSize]);
    outputHidden = outputHidden ?
      builder.concat([outputHidden, expandedHiddenAs3D], 0) :
      expandedHiddenAs3D;

    // 2차원([batchSize, hiddenSize])인 currentCell을 확장합니다.
    // 3차원([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') {
      // 축 1을 따라 연결합니다(numDirections 차원).
      outputSequence = builder.concat([forwardSequence, backwardSequence], 1);
    }

    return [outputHidden, outputCell, outputSequence];
  } else {
    return [outputHidden, outputCell];
  }
}

8.9.34. lstmCell

셀 상태, 입력, 출력 및 망각 gate를 사용하여 셀 상태와 다음 타임 스텝의 은닉 상태를 계산하고, 이 상태가 네트워크의 시간적 시퀀스에 걸쳐 출력으로 전달되는 Long Short-Term Memory [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;
};

MLLstmCellOptions 에는 다음 멤버가 있습니다:

bias, 유형은 MLOperand

shape이 [4 * hiddenSize]인 1차원 입력 bias 텐서입니다. 텐서 shape의 첫 번째 차원에서 bias 벡터의 순서는 layout에 따라 지정됩니다.

recurrentBias, 유형은 MLOperand

shape이 [4 * hiddenSize]인 1차원 순환 bias 텐서입니다. 텐서 shape의 첫 번째 차원에서 bias 벡터의 순서는 layout에 따라 지정됩니다.

peepholeWeight, 유형은 MLOperand

shape이 [3 * hiddenSize]인 peephole용 1차원 weight 텐서입니다. weight 벡터의 패킹 순서는 각각 input (i), output (o), 그리고 forget (f) gate입니다.

layout, 유형은 MLLstmWeightLayout이며 기본값은 "iofg"

LSTM 내부 gate의 weight 및 bias 벡터 순서로, 구체적으로 input (i), output (o), forget (f), 그리고 cell (g) gate이며, weight 및 bias 텐서 shape의 첫 번째 차원에 표시됩니다.

activations, 유형은 sequence<MLRecurrentNetworkActivation>

세 개의 활성화 함수 목록입니다. 첫 번째 함수는 input (i), forget (f), 그리고 output (o) gate에 사용되고, 두 번째 함수는 cell (g) gate에 사용되며, 마지막 함수는 출력 은닉 상태를 만들기 위해 출력 gate의 결과와 결합하기 전에 출력 셀 상태를 필터링하는 데 사용됩니다. 지정하지 않으면 각각 "sigmoid", "tanh", 그리고 "tanh" 함수의 시퀀스가 기본값입니다.

인수:

반환: sequence<MLOperand>. 첫 번째 요소는 순환 네트워크의 현재 타임 스텝의 출력 은닉 상태입니다. 다음 요소는 출력 셀 상태입니다. 두 요소 모두 shape이 [batchSize, hiddenSize]인 2차원 텐서입니다.

lstmCell()의 텐서 제한
피연산자 허용되는 데이터 유형 필수 데이터 유형 허용되는 랭크 필수 랭크
input "float32", "float16" "float32", "float16" 2 2
weight 동일한 유형 input "float32", "float16" 2 2
recurrentWeight 동일한 유형 input "float32", "float16" 2 2
hiddenState 동일한 유형 input "float32", "float16" 2 2
cellState 동일한 유형 input "float32", "float16" 2 2
bias 동일한 유형 input "float32", "float16" 1 1
recurrentBias 동일한 유형 input "float32", "float16" 1 1
peepholeWeight 동일한 유형 input "float32", "float16" 1 1
outputs[0] 동일한 유형 input "float32", "float16" 2 2
outputs[1] 동일한 유형 input "float32", "float16" 2 2

MLLstmCellSupportLimits 에는 다음 멤버가 있습니다:

input, 유형은 MLTensorLimits

MLTensorLimits 입력 피연산자에 대한 것입니다.

weight, 유형은 MLTensorLimits

MLTensorLimits weight 피연산자에 대한 것입니다.

recurrentWeight, 유형은 MLTensorLimits

MLTensorLimits recurrentWeight 피연산자에 대한 것입니다.

hiddenState, 유형은 MLTensorLimits

MLTensorLimits hiddenState 피연산자에 대한 것입니다.

cellState, 유형은 MLTensorLimits

MLTensorLimits cellState 피연산자에 대한 것입니다.

bias, 유형은 MLTensorLimits

MLTensorLimits bias 피연산자에 대한 것입니다.

recurrentBias, 유형은 MLTensorLimits

MLTensorLimits recurrentBias 피연산자에 대한 것입니다.

peepholeWeight, 유형은 MLTensorLimits

MLTensorLimits peepholeWeight 피연산자에 대한 것입니다.

output0, 유형은 MLTensorLimits

MLTensorLimits 모든 출력 피연산자[0]에 대한 것입니다.

output1, 유형은 MLTensorLimits

MLTensorLimits 모든 출력 피연산자[1]에 대한 것입니다.

MLOpSupportLimits 에는 lstmCell()에 대해 다음 멤버가 있습니다:

lstmCell, 유형은 MLLstmCellSupportLimits

lstmCell() 연산자의 지원 제한입니다.

lstmCell(input, weight, recurrentWeight, hiddenState, cellState, hiddenSize, options) 메서드 단계는 다음과 같습니다:
  1. this빌드할 수 없는 상태이면 예외를 발생시킵니다. "InvalidStateError" DOMException입니다.

  2. 피연산자를 검증할 때 thisinput, weight, recurrentWeight, hiddenState, cellState, options.bias (존재하는 경우), options.recurrentBias (존재하는 경우), 그리고 options.peepholeWeight (존재하는 경우) 중 하나가 false를 반환하면 예외를 발생시킵니다. TypeError입니다.

  3. input, weight, recurrentWeight, hiddenState 또는 cellState 중 하나의 dataType이 해당 허용되는 데이터 유형 중 하나가 아니면(이 표에 따름) 예외를 발생시킵니다. TypeError입니다.

  4. input, weight, recurrentWeight, hiddenState 또는 cellState 중 하나의 랭크가 해당 허용되는 랭크가 아니면 예외를 발생시킵니다. TypeError입니다.

  5. batchSizeinputshape[0]으로 둡니다.

  6. inputSizeinputshape[1]로 둡니다.

  7. weightshape이 « 4 * hiddenSize, inputSize »와 같지 않으면 예외를 발생시킵니다. TypeError입니다.

  8. recurrentWeightshape이 « 4 * hiddenSize, hiddenSize »와 같지 않으면 예외를 발생시킵니다. TypeError입니다.

  9. hiddenStateshape이 « batchSize, hiddenSize »와 같지 않으면 예외를 발생시킵니다. TypeError입니다.

  10. cellStateshape이 « batchSize, hiddenSize »와 같지 않으면 예외를 발생시킵니다. TypeError입니다.

  11. hiddenSize * 8이 유효한 차원이 아니면 예외를 발생시킵니다. TypeError입니다.

    hiddenSize * 8인가요? 일부 기반 플랫폼은 biasrecurrentBias를 연결한 단일 bias 텐서에서 동작합니다. 따라서 4 * hiddenSize + 4 * hiddenSize 역시 유효한 차원이어야 합니다.
  12. options.bias존재하면:

    1. dataType이 해당 허용되는 데이터 유형 중 하나가 아니면(이 표에 따름) 예외를 발생시킵니다. TypeError입니다.

    2. shape이 « 4 * hiddenSize »와 같지 않으면 예외를 발생시킵니다. TypeError입니다.

  13. options.recurrentBias존재하면:

    1. dataType이 해당 허용되는 데이터 유형 중 하나가 아니면(이 표에 따름) 예외를 발생시킵니다. TypeError입니다.

    2. shape이 « 4 * hiddenSize »와 같지 않으면 예외를 발생시킵니다. TypeError입니다.

  14. options.peepholeWeight존재하면:

    1. dataType이 해당 허용되는 데이터 유형 중 하나가 아니면(이 표에 따름) 예외를 발생시킵니다. TypeError입니다.

    2. shape이 « 3 * hiddenSize »와 같지 않으면 예외를 발생시킵니다. TypeError입니다.

  15. options.activations존재하면:

    1. 크기가 3이 아니면 예외를 발생시킵니다. TypeError입니다.

    2. activationsoptions.activations복제본으로 둡니다.

  16. 그렇지 않으면:

    1. activations를 « "sigmoid", "tanh", "tanh" »로 둡니다.

  17. desc를 새 MLOperandDescriptor로 둡니다.

  18. desc.shape목록 « batchSize, hiddenSize »로 설정합니다.

  19. desc.dataTypeinputdataType으로 설정합니다.

  20. 그래프 연결을 구성합니다:

    1. output0MLOperand를 생성한 결과로 두며 thisdesc가 주어집니다.

    2. output1MLOperand를 생성한 결과로 두며 thisdesc가 주어집니다.

    3. output목록 « output0, output1 »로 둡니다.

    4. operatorweight, recurrentWeight, hiddenState, cellState, hiddenSizeoptions가 주어진 "lstmCell" 연산의 연산자로 둡니다.

    5. output0.[[operator]]output1.[[operator]]operator로 설정합니다.

    6. operator입력input, weight, recurrentWeight, hiddenState, 그리고 cellState로 설정합니다.

    7. options.bias존재하면 이를 operator입력에 추가합니다.

    8. options.recurrentBias존재하면 이를 operator입력에 추가합니다.

    9. options.peepholeWeight존재하면 이를 operator입력에 추가합니다.

    10. operator활성화 함수activations복제본으로 설정합니다.

    11. operator출력output으로 설정합니다.

  21. output을 반환합니다.

weight 레이아웃이 기본 "iofg" 레이아웃이고, input/forget/output gate와 cell gate/출력 은닉 상태를 위한 셀 상태 필터의 활성화 함수가 각각 sigmoid()tanh() 인 경우 이 연산의 동작은 다른 연산을 사용하여 다음과 같이 일반적으로 에뮬레이션할 수 있지만, 사용자 에이전트에는 일반적으로 더 효율적인 구현이 있습니다. 기반 플랫폼이 연산을 직접 지원하지 않는 경우 이 분해를 구현을 안내하는 템플릿으로 사용할 수 있습니다.
function lstmCell(
  builder,
  input,
  weight,
  recurrentWeight,
  hiddenState,
  cellState,
  hiddenSize,
  options) {
  const zero = builder.constant(input.dataType, 0);

  const inputSize = input.shape[1];

  // 입력 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])))))));

  // 망각 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])))))));

  // 셀 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]))))));

  // 출력 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])))))));

  // 출력 셀 상태 (ct)
  let ct = builder.add(builder.mul(f, cellState), builder.mul(i, g));

  // 출력 은닉 상태 (ht)
  let ht = builder.mul(o, builder.tanh(ct));

  return [ht, ct];
}

8.9.35. matmul

두 입력 텐서의 행렬 곱을 계산합니다.
partial interface MLGraphBuilder {
  MLOperand matmul(MLOperand a, MLOperand b, optional MLOperatorOptions options = {});
};

partial dictionary MLOpSupportLimits {
  MLBinarySupportLimits matmul;
};
인수:

반환: MLOperand입니다. 두 입력 텐서의 행렬 곱을 포함하는 출력 텐서입니다.

다음과 같이 두 입력 텐서의 행렬 곱을 계산합니다:
matmul()의 텐서 제한
피연산자 허용되는 데이터 유형 필수 데이터 유형 허용되는 랭크 필수 랭크
a "float32", "float16" "float32", "float16" 2에서 N까지 2에서 5까지
b 동일한 유형 a "float32", "float16" 2에서 N까지 2에서 5까지
출력 동일한 유형 a "float32", "float16" 2에서 N까지 2에서 5까지

MLOpSupportLimits 에는 matmul()에 대해 다음 멤버가 있습니다:

matmul, 유형은 MLBinarySupportLimits

matmul() 연산자의 지원 제한입니다.

matmul(a, b, options) 메서드 단계는 다음과 같습니다:
  1. this빌드할 수 없는 상태이면 예외를 발생시킵니다. "InvalidStateError" DOMException입니다.

  2. 피연산자를 검증할 때 thisab 중 하나가 false를 반환하면 예외를 발생시킵니다. TypeError입니다.

  3. a 또는 b 중 하나의 dataType이 해당 허용되는 데이터 유형 중 하나가 아니면(이 표에 따름) 예외를 발생시킵니다. TypeError입니다.

  4. 출력 shape을 계산합니다:

    1. shapeAa복제본 shape으로 둡니다.

    2. rankAa랭크로 둡니다.

    3. shapeBb복제본 shape으로 둡니다.

    4. rankBb랭크로 둡니다.

    5. rankA 또는 rankB 중 하나가 2보다 작으면 예외를 발생시킵니다. TypeError입니다.

    6. colsAshapeA[rankA - 1]로 둡니다.

    7. rowsAshapeA[rankA - 2]로 둡니다.

    8. colsBshapeB[rankB - 1]로 둡니다.

    9. rowsBshapeB[rankB - 2]로 둡니다.

    10. colsArowsB와 같지 않으면 예외를 발생시킵니다. TypeError입니다.

    11. batchShapeAshapeA에서 공간 차원(마지막 2개 항목)이 복제된 뒤 제거된 것으로 둡니다.

    12. batchShapeBshapeB에서 공간 차원(마지막 2개 항목)이 복제된 뒤 제거된 것으로 둡니다.

    13. outputShapebatchShapeAbatchShapeB양방향 브로드캐스트한 결과로 둡니다. 실패를 반환하면 예외를 발생시킵니다. TypeError입니다.

    14. 추가합니다 « rowsA, colsB »를 outputShape에.

    15. descadataTypeoutputShape이 주어진 상태에서 MLOperandDescriptor를 생성한 결과로 둡니다.

  5. 그래프 연결을 구성합니다:

    1. outputMLOperand를 생성한 결과로 두며 thisdesc가 주어집니다.

    2. operatoroptions가 주어진 "matmul" 연산의 연산자로 둡니다.

    3. output.[[operator]]operator로 설정합니다.

    4. operator입력ab로 설정합니다.

    5. operator출력output으로 설정합니다.

  6. output을 반환합니다.

8.9.36. pad

가장자리에 상수 또는 미러링된 값을 사용하여 텐서를 확장합니다.
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"

텐서를 패딩하는 여러 방식입니다.

value, 유형은 MLNumber이며 기본값은 0

mode"constant"로 설정된 경우의 패딩 값입니다.

인수:

반환: MLOperand입니다. 패딩된 출력 텐서입니다. 출력 텐서의 각 차원은 다음과 같이 계산할 수 있습니다:

output size = beginning padding + input size + ending padding

pad()의 텐서 제한
피연산자 허용되는 데이터 유형 필수 데이터 유형 허용되는 랭크 필수 랭크
input 모두 "float32", "float16" N 0에서 5까지
출력 동일한 유형 input "float32", "float16" 동일한 랭크 input 0에서 5까지

MLOpSupportLimits 에는 pad()에 대해 다음 멤버가 있습니다:

pad, 유형은 MLSingleInputSupportLimits

pad() 연산자의 지원 제한입니다.

pad(input, beginningPadding, endingPadding, options) 메서드 단계는 다음과 같습니다:
  1. this빌드할 수 없는 상태이면 예외를 발생시킵니다. "InvalidStateError" DOMException입니다.

  2. 피연산자를 검증할 때 thisinput이 false를 반환하면 예외를 발생시킵니다. TypeError입니다.

  3. beginningPadding크기endingPadding크기가 둘 다 input랭크와 같지 않으면 예외를 발생시킵니다. TypeError입니다.

  4. descinput.[[descriptor]]의 복사본으로 둡니다.

  5. outputShapeinputshape의 복사본으로 둡니다.

  6. 각각 index에 대해 범위 0부터 outputShape랭크까지, 상한 제외:

    1. options.mode에 따라 분기합니다:

      "constant"

      아무 작업도 하지 않습니다.

      "edge"

      아무 작업도 하지 않습니다.

      "reflection"
      1. beginningPadding[index]가 크거나 같으면 outputShape[index]에 대해 예외를 발생시킵니다. TypeError입니다.

      2. endingPadding[index]가 크거나 같으면 outputShape[index]에 대해 예외를 발생시킵니다. TypeError입니다.

    2. outputShape[index]에 다음 값을 더합니다: beginningPadding[index].

    3. outputShape[index]에 다음 값을 더합니다: endingPadding[index].

  7. outputShape항목 중 하나라도 유효한 차원이 아니면 예외를 발생시킵니다. TypeError입니다.

  8. options.valueoptions.valueinput캐스트한 dataType 결과로 설정합니다.

  9. desc.shapeoutputShape으로 설정합니다.

  10. 그래프 연결을 구성합니다:

    1. outputMLOperand를 생성한 결과로 두며 thisdesc가 주어집니다.

    2. operatorbeginningPadding, endingPaddingoptions가 주어진 "padding" 연산의 연산자로 둡니다.

    3. output.[[operator]]operator로 설정합니다.

    4. operator입력input으로 설정합니다.

    5. operator출력output으로 설정합니다.

  11. output을 반환합니다.

constant, edge 및 reflection 패딩의 예:
// 입력: [[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" 패딩:
//    [[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" 패딩:
//    [[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" 패딩:
//    [[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. 풀링 연산

입력 텐서 위를 이동하는 윈도우 내의 모든 요소에 대해 풀링 연산을 계산합니다.
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인 목록입니다: [windowHeight, windowWidth]. 슬라이딩 윈도우의 차원을 지정합니다. 윈도우 차원의 기본값은 입력 shape의 높이 및 너비 차원입니다.

padding, 유형은 sequence<[EnforceRange] unsigned long>

길이가 4인 목록입니다: [beginningHeight, endingHeight, beginningWidth, endingWidth]. 컨볼루션 입력의 각 공간 차원 시작과 끝에 추가되는 행 및 열을 지정합니다. 기본값은 [0,0,0,0]입니다.

strides, 유형은 sequence<[EnforceRange] unsigned long>

길이가 2인 목록입니다: [strideHeight, strideWidth]. 컨볼루션 입력의 각 공간 차원에 대한 슬라이딩 윈도우의 stride를 지정합니다. 기본값은 [1,1]입니다.

dilations, 유형은 sequence<[EnforceRange] unsigned long>

길이가 2인 목록입니다: [dilationHeight, dilationWidth]. 컨볼루션 필터(커널)에 적용되는 각 공간 차원의 dilation factor를 지정합니다. 기본값은 [1,1]입니다.

layout, 유형은 MLInputOperandLayout이며 기본값은 "nchw"

입력 및 출력 텐서의 레이아웃 형식을 다음과 같이 지정합니다:

  • "nchw"

    • 입력 텐서: [batches, inputChannels, height, width]

    • 출력 텐서: [batches, outputChannels, height, width]

  • "nhwc":

    • 입력 텐서: [batches, height, width, inputChannels]

    • 출력 텐서: [batches, height, width, outputChannels]

outputShapeRounding, 유형은 MLRoundingType이며 기본값은 "floor"

전체 또는 부분 윈도우 결과를 원하는지에 따라 출력 shape을 계산하는 데 사용하는 반올림 함수입니다.

outputSizes, 유형은 sequence<[EnforceRange] unsigned long>

길이가 2인 목록입니다: [outputHeight, outputWidth] 출력 텐서의 두 공간 차원 크기를 지정합니다. 출력 크기를 명시적으로 지정하면 outputShapeRounding 은 무시됩니다. 지정하지 않으면 출력 크기가 자동으로 계산됩니다.

인수:

반환: MLOperand입니다. 축소 결과를 포함하는 출력 4차원 텐서입니다. 논리적 shape은 layout 값에 따라 해석됩니다. 더 구체적으로 outputShapeRounding"floor"이면, 출력 텐서의 단일 차원에 대한 공간 차원은 다음과 같이 계산할 수 있습니다:

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)

averagePool2d()/l2Pool2d()의 텐서 제한
피연산자 허용되는 데이터 유형 필수 데이터 유형 허용되는 랭크 필수 랭크
input "float32", "float16" "float32", "float16" 4 4
출력 동일한 유형 input "float32", "float16" 4 4
maxPool2d()의 텐서 제한
피연산자 허용되는 데이터 유형 필수 데이터 유형 허용되는 랭크 필수 랭크
input 모두 "float32", "float16" 4 4
출력 동일한 유형 input "float32", "float16" 4 4

MLOpSupportLimits 에는 풀링 연산에 대해 다음 멤버가 있습니다:

averagePool2d, 유형은 MLSingleInputSupportLimits

averagePool2d() 연산자의 지원 제한입니다.

l2Pool2d, 유형은 MLSingleInputSupportLimits

l2Pool2d() 연산자의 지원 제한입니다.

maxPool2d, 유형은 MLSingleInputSupportLimits

maxPool2d() 연산자의 지원 제한입니다.

max 풀링 연산과 같은 전역 풀링 연산은 윈도우 차원이 입력 shape의 공간 차원(마지막 두 차원)인 풀링의 변형이며 다음과 같습니다.
// '전역' max 풀링
builder.maxPool2d(input);
풀링 연산을 생성하려면 문자열 op, MLOperand input, MLPool2dOptions options, 그리고 선택적 목록 allowedDataTypes가 주어졌을 때 다음 단계를 실행합니다:
  1. 단언: op는 "averagePool2d", "l2Pool2d", "maxPool2d" 중 하나입니다.

  2. this빌드할 수 없는 상태이면 예외를 발생시킵니다. "InvalidStateError" DOMException입니다.

  3. 피연산자를 검증할 때 thisinput이 false를 반환하면 예외를 발생시킵니다. TypeError입니다.

  4. allowedDataTypes가 주어지고 inputdataType포함하지 않으면 예외를 발생시킵니다. TypeError입니다.

  5. input랭크가 4가 아니면 예외를 발생시킵니다. TypeError입니다.

  6. options.layout에 따라 분기합니다:

    "nchw"

    « batches, channels, inputHeight, inputWidth »를 inputshape으로 둡니다.

    "nhwc"

    « batches, inputHeight, inputWidth, channels »를 inputshape으로 둡니다.

  7. options.windowDimensions존재하지 않으면 options.windowDimensions 을 « inputHeight, inputWidth »로 설정합니다.

  8. options.windowDimensions크기가 2가 아니면 예외를 발생시킵니다. TypeError입니다.

  9. options.windowDimensions항목 중 하나라도 0이면 예외를 발생시킵니다. TypeError입니다.

  10. options.outputSizes존재하거나 options.padding존재하지 않으면 options.padding목록 « 0, 0, 0, 0 »로 설정합니다.

  11. options.padding크기가 4가 아니면 예외를 발생시킵니다. TypeError입니다.

  12. options.strides존재하지 않으면 options.strides목록 « 1, 1 »로 설정합니다.

  13. options.strides크기가 2가 아니면 예외를 발생시킵니다. TypeError입니다.

  14. options.strides항목 중 하나라도 0이면 예외를 발생시킵니다. TypeError입니다.

  15. options.outputSizes존재하면:

    1. 크기가 2가 아니면 예외를 발생시킵니다. TypeError입니다.

    2. 항목options.strides의 동일한 차원(인덱스)에 있는 항목보다 작지 않으면 예외를 발생시킵니다. TypeError입니다.

  16. options.dilations존재하지 않으면 options.dilations목록 « 1, 1 »로 설정합니다.

  17. options.dilations크기가 2가 아니면 예외를 발생시킵니다. TypeError입니다.

  18. options.dilations항목 중 하나라도 0이면 예외를 발생시킵니다. TypeError입니다.

  19. descinput.[[descriptor]]의 복사본으로 둡니다.

  20. 출력 shape을 계산합니다:

    1. « windowHeight, windowWidth »를 options.windowDimensions으로 둡니다.

    2. « calculatedOutputHeight, calculatedOutputWidth »를 inputHeight, inputWidth, windowHeight, windowWidth, options.padding, options.strides, 그리고 options.dilations가 주어진 상태에서 conv2d 출력 크기를 계산한 결과로 둡니다.

    3. options.outputSizes존재하면:

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

      2. outputHeight가 floor( calculatedOutputHeight )와 같고 outputWidth가 floor( calculatedOutputWidth )와 같은 것도 아니며, outputHeight가 ceil( calculatedOutputHeight )과 같고 outputWidth가 ceil( calculatedOutputWidth )과 같은 것도 아니면 예외를 발생시킵니다. TypeError입니다.

    4. 그렇지 않으면:

      1. « outputHeight, outputWidth »를 « calculatedOutputHeight, calculatedOutputWidth »로 둡니다.

      2. options.outputShapeRounding에 따라 분기합니다:

        "floor"
        1. outputWidth를 floor(outputWidth)로 설정합니다.

        2. outputHeight를 floor(outputHeight)로 설정합니다.

        "ceil"
        1. outputWidth를 ceiling(outputWidth)로 설정합니다.

        2. outputHeight를 ceiling(outputHeight)로 설정합니다.

    5. outputHeight 또는 outputWidth 중 하나가 유효한 차원이 아니면 예외를 발생시킵니다. TypeError입니다.

    6. options.layout에 따라 분기합니다:

      "nchw"

      outputShape을 « batches, channels, outputHeight, outputWidth »로 둡니다.

      "nhwc"

      outputShape을 « batches, outputHeight, outputWidth, channels »로 둡니다.

    7. desc.shapeoutputShape으로 설정합니다.

  21. 그래프 연결을 구성합니다:

    1. outputMLOperand를 생성한 결과로 두며 thisdesc가 주어집니다.

    2. operatoroptions가 주어진 op 연산의 연산자로 둡니다.

    3. output.[[operator]]operator로 설정합니다.

    4. operator입력input으로 설정합니다.

    5. operator출력output으로 설정합니다.

  22. output을 반환합니다.

다음 풀링 알고리즘을 지원합니다.
averagePool2d(input, options) 메서드 단계는 다음과 같습니다:
  1. output을 "averagePool2d", input, options, 그리고 « "float32", "float16" »가 주어진 상태에서 풀링 연산을 생성한 결과로 둡니다.

    1. 그 과정에서 오류가 발생하면 오류를 다시 발생시킵니다.

  2. output을 반환합니다.

l2Pool2d(input, options) 메서드 단계는 다음과 같습니다:
  1. output을 "l2Pool2d", input, options, 그리고 « "float32", "float16" »가 주어진 상태에서 풀링 연산을 생성한 결과로 둡니다.

    1. 그 과정에서 오류가 발생하면 오류를 다시 발생시킵니다.

  2. output을 반환합니다.

maxPool2d(input, options) 메서드 단계는 다음과 같습니다:
  1. output을 "maxPool2d", inputoptions가 주어진 상태에서 풀링 연산을 생성한 결과로 둡니다.

    1. 그 과정에서 오류가 발생하면 오류를 다시 발생시킵니다.

  2. output을 반환합니다.

8.9.37.1. averagePool2d
feature map의 패치에 대한 평균값을 계산하고 이를 사용하여 풀링된 feature map을 생성합니다. 자세한 내용은 § 8.9.37 풀링 연산을 참조하십시오.
8.9.37.2. l2Pool2d
입력 feature map의 영역에 L2 norm 함수를 적용합니다. L2 norm은 해당 요소 제곱합의 제곱근입니다. 자세한 내용은 § 8.9.37 풀링 연산에서 확인할 수 있습니다.
8.9.37.3. maxPool2d
feature map의 패치에 대한 최댓값을 계산하고 이를 사용하여 풀링된 feature map을 생성합니다. 자세한 내용은 § 8.9.37 풀링 연산을 참조하십시오.

8.9.38. prelu

입력 텐서에 요소별로 정류 선형 함수의 매개변수화된 버전(Parametric ReLU)을 계산합니다. Parametric ReLU는 0.01과 같은 스칼라 slope를 갖는 대신 slope(누설 계수)를 이 연산의 모델 학습 단계에서 학습되는 매개변수로 만드는 leaky ReLU 유형입니다. 계산은 max(0, x) + slope * min(0, x) 식을 따릅니다.

연산은 브로드캐스트되며 [numpy-broadcasting-rule]을 따릅니다. 입력 텐서는 양방향 브로드캐스트 가능해야 합니다. 출력 텐서의 랭크는 입력 텐서의 최대 랭크입니다. 출력 텐서의 각 차원에 대해 그 크기는 입력 텐서에서 해당 차원을 따른 최대 크기입니다.

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()의 텐서 제한
피연산자 허용되는 데이터 유형 필수 데이터 유형 허용되는 랭크 필수 랭크
input "float32", "float16", "int64", "int32", "int8" "float32", "float16" N 0에서 5까지
slope 동일한 유형 input "float32", "float16" N 0에서 5까지
출력 동일한 유형 input "float32", "float16" N 0에서 5까지

MLPreluSupportLimits 에는 다음 멤버가 있습니다:

input, 유형은 MLTensorLimits

MLTensorLimits 입력 피연산자에 대한 것입니다.

slope, 유형은 MLTensorLimits

MLTensorLimits slope 피연산자에 대한 것입니다.

output, 유형은 MLTensorLimits

MLTensorLimits 출력 피연산자에 대한 것입니다.

MLOpSupportLimits 에는 prelu()에 대해 다음 멤버가 있습니다:

prelu, 유형은 MLPreluSupportLimits

prelu() 연산자의 지원 제한입니다.

prelu(input, slope, options) 메서드 단계는 다음과 같습니다:
  1. this빌드할 수 없는 상태이면 예외를 발생시킵니다. "InvalidStateError" DOMException입니다.

  2. 피연산자를 검증할 때 thisinputslope 중 하나가 false를 반환하면 예외를 발생시킵니다. TypeError입니다.

  3. input 또는 slope 중 하나의 dataType이 해당 허용되는 데이터 유형 중 하나가 아니면(이 표에 따름) 예외를 발생시킵니다. TypeError입니다.

  4. outputShapeslopeshapeinputshape양방향 브로드캐스트한 결과로 둡니다.

    1. 실패를 반환하면 예외를 발생시킵니다. TypeError입니다.

  5. descriptorinputdataTypeoutputShape이 주어진 상태에서 MLOperandDescriptor를 생성한 결과로 둡니다.

  6. 그래프 연결을 구성합니다:

    1. outputMLOperand를 생성한 결과로 두며 thisdescriptor가 주어집니다.

    2. operatorslopeoptions가 주어진 "prelu" 연산의 연산자로 둡니다.

    3. output.[[operator]]operator로 설정합니다.

    4. operator입력inputslope로 설정합니다.

    5. operator출력output으로 설정합니다.

  7. output을 반환합니다.

이 연산의 동작은 다른 연산을 사용하여 일반적으로 에뮬레이션할 수 있으며 다음과 같습니다. 다만 사용자 에이전트에는 일반적으로 더 효율적인 구현이 있습니다. 기반 플랫폼이 연산을 직접 지원하지 않는 경우 이 분해를 구현을 안내하는 템플릿으로 사용할 수 있습니다.
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. 축소 연산

모든 차원을 따라 또는 axes 배열 매개변수에 지정된 축을 따라 입력 텐서를 축소합니다. 지정된 각 축에 대해 해당 인덱스의 차원이 축소됩니다. 즉, 결과 텐서에는 해당 차원이 포함되지 않지만 keepDimensions 가 지정된 경우에는 포함됩니다. 결과 텐서의 값은 축소된 차원의 모든 입력 값을 매개변수로 받는 지정된 축소 함수를 사용하여 계산합니다.
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>

축소할 차원이며, 입력 텐서의 어떤 값을 축소 함수에 사용할지도 지정합니다. 목록의 축은 입력 텐서의 랭크가 N일 때 [0, N-1] 범위에 있어야 합니다.

존재하지 않으면 모든 차원이 축소됩니다. 축소 함수의 입력 값은 입력 텐서의 모든 값입니다.

존재하고 비어 있지 않으면 축소 함수의 입력 값은 입력 텐서의 지정된 차원에 있는 모든 값입니다.

존재하고 비어 있으면 어떤 차원도 축소되지 않으며 출력 텐서의 shape은 입력 텐서의 shape과 같습니다. 축소 함수는 텐서의 각 값에 개별적으로 적용됩니다.

keepDimensions, 유형은 boolean이며 기본값은 false

true이면 출력은 입력과 동일한 랭크를 가지며 축소된 모든 차원의 크기를 1로 설정합니다.

인수:

반환: MLOperand입니다. 출력 N차원 텐서의 랭크는 0에서 input랭크까지의 범위이며 양 끝을 포함하고, axeskeepDimensions에 따라 달라집니다. 입력 피연산자가 스칼라이면 축소 함수가 스칼라 값에 적용되며 출력도 스칼라입니다.

reduceL1()/reduceSum()/reduceSumSquare()의 텐서 제한
피연산자 허용되는 데이터 유형 필수 데이터 유형 허용되는 랭크 필수 랭크
input "float32", "float16", "int32", "uint32", "int64", "uint64" "float32", "float16", "int32" N 0에서 5까지
출력 동일한 유형 input "float32", "float16", "int32" N 0에서 5까지
reduceL2()/reduceLogSum()/reduceLogSumExp()/reduceMean()의 텐서 제한
피연산자 허용되는 데이터 유형 필수 데이터 유형 허용되는 랭크 필수 랭크
input "float32", "float16" "float32", "float16" N 0에서 5까지
출력 동일한 유형 input "float32", "float16" N 0에서 5까지
reduceMax()/reduceMin()의 텐서 제한
피연산자 허용되는 데이터 유형 필수 데이터 유형 허용되는 랭크 필수 랭크
input 모두 "float32", "float16", "int32" N 0에서 5까지
출력 동일한 유형 input "float32", "float16", "int32" N 0에서 5까지
reduceProduct()의 텐서 제한
피연산자 허용되는 데이터 유형 필수 데이터 유형 허용되는 랭크 필수 랭크
input "float32", "float16", "int32", "uint32", "int64", "uint64" "float32", "float16" N 0에서 5까지
출력 동일한 유형 input "float32", "float16" N 0에서 5까지

MLOpSupportLimits 에는 축소 연산에 대해 다음 멤버가 있습니다:

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() 연산자의 지원 제한입니다.

축소 유형:
부호 없는 정수의 목록 inputShape, 선택적 부호 없는 정수의 목록 axes, 그리고 불리언 keepDimensions가 주어졌을 때 축소 출력 크기를 계산하려면 다음 단계를 수행합니다. 이 단계는 부호 없는 정수의 새 목록 또는 실패를 반환합니다.
  1. inputRankinputShape크기로 둡니다.

  2. axes가 주어지지 않으면 axes범위 0부터 inputRank까지로 두며, 상한은 제외합니다.

  3. 그렇지 않고 axes에 중복 값이 포함되어 있거나 그 항목 중 하나라도 범위 0부터 inputRank까지에 없으면, 상한은 제외하며, 실패를 반환합니다.

  4. keepDimensions가 true이면:

    1. outputShapeinputShape복제본으로 둡니다.

    2. 각각 axesaxis에 대해:

      1. outputShape[axis]를 1로 설정합니다.

  5. 그렇지 않으면:

    1. outputShape을 빈 목록으로 둡니다.

    2. 각각 index에 대해 범위 0부터 inputRank까지에서, 상한은 제외합니다:

      1. axesindex포함하지 않으면 inputShape[index]를 outputShape추가합니다.

  6. outputShape을 반환합니다.

축소 연산을 생성하려면 문자열 op, MLOperand input, MLReduceOptions options, 그리고 선택적 목록 allowedDataTypes가 주어졌을 때 다음 단계를 실행합니다:
  1. 단언: op는 "reduceL1", "reduceL2", "reduceLogSum", "reduceLogSumExp", "reduceMax", "reduceMean", "reduceMin", "reduceProduct", "reduceSum", "reduceSumSquare" 중 하나입니다.

  2. this빌드할 수 없는 상태이면 예외를 발생시킵니다. "InvalidStateError" DOMException입니다.

  3. 피연산자를 검증할 때 thisinput이 false를 반환하면 예외를 발생시킵니다. TypeError입니다.

  4. allowedDataTypes가 주어지고 inputdataType포함하지 않으면 예외를 발생시킵니다. TypeError입니다.

  5. outputShapeinputshape, options.axes (존재하는 경우), 그리고 options.keepDimensions가 주어진 상태에서 축소 출력 크기를 계산한 결과로 둡니다. 실패를 반환하면 예외를 발생시킵니다. TypeError입니다.

  6. descinputdataTypeoutputShape이 주어진 상태에서 MLOperandDescriptor를 생성한 결과로 둡니다.

  7. 그래프 연결을 구성합니다:

    1. outputMLOperand를 생성한 결과로 두며, thisdesc가 주어집니다.

    2. operatoroptions가 주어진 op 연산에 대한 연산자로 둡니다.

    3. output.[[operator]]operator로 설정합니다.

    4. operator입력input으로 설정합니다.

    5. operator출력output으로 설정합니다.

  8. output을 반환합니다.

다음 축소 알고리즘을 지원합니다.
reduceL1(input, options) 메서드 단계는 다음과 같습니다:
  1. output축소 연산을 생성한 결과로 두며 "reduceL1", input, options, 그리고 « "float32", "float16", "int32", "uint32", "int64", "uint64" »가 주어집니다.

    1. 그 과정에서 오류가 발생하면 오류를 다시 발생시킵니다.

  2. output을 반환합니다.

reduceL2(input, options) 메서드 단계는 다음과 같습니다:
  1. output축소 연산을 생성한 결과로 두며 "reduceL2", input, options, 그리고 « "float32", "float16" »가 주어집니다.

    1. 그 과정에서 오류가 발생하면 오류를 다시 발생시킵니다.

  2. output을 반환합니다.

reduceLogSum(input, options) 메서드 단계는 다음과 같습니다:
  1. output축소 연산을 생성한 결과로 두며 "reduceLogSum", input, options, 그리고 « "float32", "float16" »가 주어집니다.

    1. 그 과정에서 오류가 발생하면 오류를 다시 발생시킵니다.

  2. output을 반환합니다.

reduceLogSumExp(input, options) 메서드 단계는 다음과 같습니다:
  1. output축소 연산을 생성한 결과로 두며 "reduceLogSumExp", input, options, 그리고 « "float32", "float16" »가 주어집니다.

    1. 그 과정에서 오류가 발생하면 오류를 다시 발생시킵니다.

  2. output을 반환합니다.

reduceMax(input, options) 메서드 단계는 다음과 같습니다:
  1. output축소 연산을 생성한 결과로 두며 "reduceMax", inputoptions가 주어집니다.

    1. 그 과정에서 오류가 발생하면 오류를 다시 발생시킵니다.

  2. output을 반환합니다.

reduceMean(input, options) 메서드 단계는 다음과 같습니다:
  1. output축소 연산을 생성한 결과로 두며 "reduceMean", input, options, 그리고 « "float32", "float16" »가 주어집니다.

    1. 그 과정에서 오류가 발생하면 오류를 다시 발생시킵니다.

  2. output을 반환합니다.

reduceMin(input, options) 메서드 단계는 다음과 같습니다:
  1. output축소 연산을 생성한 결과로 두며 "reduceMin", inputoptions가 주어집니다.

    1. 그 과정에서 오류가 발생하면 오류를 다시 발생시킵니다.

  2. output을 반환합니다.

reduceProduct(input, options) 메서드 단계는 다음과 같습니다:
  1. output축소 연산을 생성한 결과로 두며 "reduceProduct", input, options, 그리고 « "float32", "float16", "int32", "uint32", "int64", "uint64" »가 주어집니다.

    1. 그 과정에서 오류가 발생하면 오류를 다시 발생시킵니다.

  2. output을 반환합니다.

reduceSum(input, options) 메서드 단계는 다음과 같습니다:
  1. output축소 연산을 생성한 결과로 두며 "reduceSum", input, options, 그리고 « "float32", "float16", "int32", "uint32", "int64", "uint64" »가 주어집니다.

    1. 그 과정에서 오류가 발생하면 오류를 다시 발생시킵니다.

  2. output을 반환합니다.

reduceSumSquare(input, options) 메서드 단계는 다음과 같습니다:
  1. output축소 연산을 생성한 결과로 두며 "reduceSumSquare", input, options, 그리고 « "float32", "float16", "int32", "uint32", "int64", "uint64" »가 주어집니다.

    1. 그 과정에서 오류가 발생하면 오류를 다시 발생시킵니다.

  2. output을 반환합니다.

여러 축소 연산의 동작은 다른 연산을 사용하여 다음과 같이 일반적으로 에뮬레이션할 수 있지만 사용자 에이전트에는 일반적으로 더 효율적인 구현이 있습니다. 기반 플랫폼이 연산을 직접 지원하지 않는 경우 이 분해를 구현을 안내하는 템플릿으로 사용할 수 있습니다.
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 와 같은 옵션을 직접 지원하지 않습니다. 이는 기반 텐서 데이터에는 영향을 주지 않고 shape에만 영향을 줍니다. 예를 들어 입력 shape이 [2, 3, 4]이고 축이 1이며 keepDimensions 가 true이면 예상되는 출력 shape은 [2, 1 ,4]입니다. 기반 플랫폼이 축소된 차원을 절대 유지하지 않는 경우 출력 shape은 [2, 4]가 됩니다. 구현은 no-op reshape를 [2, 1, 4]로 도입할 수 있습니다. 마찬가지로 keepDimensions 가 false이지만 기반 플랫폼이 항상 축소된 차원을 유지하는 경우에도 비슷한 no-op reshape를 도입할 수 있습니다.

8.9.40. relu

입력 텐서의 정류 선형 함수를 계산합니다.
partial interface MLGraphBuilder {
  MLOperand relu(MLOperand input, optional MLOperatorOptions options = {});
};

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

반환:

relu()의 텐서 제한
피연산자 허용되는 데이터 유형 필수 데이터 유형 허용되는 랭크 필수 랭크
input "float32", "float16", "int64", "int32", "int8" "float32", "float16" N 0에서 5까지
출력 동일한 유형 input "float32", "float16" 동일한 랭크 input 0에서 5까지

MLOpSupportLimits 에는 relu()에 대해 다음 멤버가 있습니다:

relu, 유형은 MLSingleInputSupportLimits

relu() 연산자의 지원 제한입니다.

relu(input, options) 메서드 단계는 다음과 같습니다:
  1. this빌드할 수 없는 상태이면 예외를 발생시킵니다. "InvalidStateError" DOMException입니다.

  2. 피연산자를 검증할 때 thisinput이 false를 반환하면 예외를 발생시킵니다. TypeError입니다.

  3. inputdataType이 해당 허용되는 데이터 유형 중 하나가 아니면(이 표에 따름) 예외를 발생시킵니다. TypeError입니다.

  4. 그래프 연결을 구성합니다:

    1. outputinput이 주어진 상태에서 MLOperand를 복사한 결과로 둡니다.

    2. operatoroptions가 주어진 "relu" 연산의 연산자로 둡니다.

    3. output.[[operator]]operator로 설정합니다.

    4. operator입력input으로 설정합니다.

    5. operator출력output으로 설정합니다.

  5. output을 반환합니다.

이 연산의 동작은 다른 연산을 사용하여 일반적으로 에뮬레이션할 수 있으며 다음과 같습니다. 다만 사용자 에이전트에는 일반적으로 더 효율적인 구현이 있습니다. 기반 플랫폼이 연산을 직접 지원하지 않는 경우 이 분해를 구현을 안내하는 템플릿으로 사용할 수 있습니다.
function relu(builder, input) {
  return builder.max(builder.constant(input.dataType, 0), input);
}

8.9.41. resample2d

축과 스케일링 factor에 따라 소스에서 대상 차원으로 텐서 값을 리샘플링합니다.
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입니다. 출력 4차원 텐서입니다.

MLResample2dOptions 에는 다음 멤버가 있습니다:

mode, 유형은 MLInterpolationMode이며 기본값은 "nearest-neighbor"

출력 텐서 값을 채우는 데 사용하는 보간 알고리즘입니다.

두 알고리즘 모두 각 공간 축에 대해 계산되는 다음 입력으로 시작합니다(axes 기준). 여기서 inputSizeinput 텐서의 shape으로 주어지고, outputSizesizes 또는 scales로 주어지며, outputCoordinate는 계산 중인 출력 텐서의 요소를 식별합니다.

scale = outputSize / inputSize
unclampedCoordinate = (outputCoordinate + 0.5) / scale - 0.5
inputCoordinate = clamp(unclampedCoordinate, 0, inputSize - 1)
출력 텐서의 주어진 outputCoordinate.xoutputCoordinate.y 위치에 대해 위 수식은 유리수 inputCoordinate.xinputCoordinate.y를 제공합니다.
nearest-neighbor

위에서 계산한 inputCoordinate.xinputCoordinate.y는 다음과 같이 출력 텐서 값을 계산하는 nearest-neighbor 샘플링 알고리즘의 입력으로 사용됩니다:

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는 다음과 같이 출력 텐서 값을 계산하는 bilinear 샘플링 알고리즘의 입력으로 사용됩니다:

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인 목록입니다. axes에서 각 입력 차원에 대한 스케일링 factor를 지정합니다: [scaleForFirstAxis, scaleForSecondAxis]. 기본값은 [1.0, 1.0]입니다.

sizes, 유형은 sequence<[EnforceRange] unsigned long>

길이가 2인 목록입니다. axes에서 각 입력 차원에 대한 대상 크기를 지정합니다: [sizeForFirstAxis, sizeForSecondAxis]. sizes 를 지정하면 scales 는 무시됩니다. 스케일링 factor 값이 입력의 대상 크기에서 도출되기 때문입니다.

axes, 유형은 sequence<[EnforceRange] unsigned long>

길이가 2인 목록입니다. 보간 알고리즘을 적용할 입력 텐서의 두 차원을 지정합니다. 기본값은 [2, 3]입니다.

resample2d()의 텐서 제한
피연산자 허용되는 데이터 유형 필수 데이터 유형 허용되는 랭크 필수 랭크
input "float32", "float16", "uint8", "int8" "float32", "float16" 4 4
출력 동일한 유형 input "float32", "float16" 4 4

MLOpSupportLimits 에는 resample2d()에 대해 다음 멤버가 있습니다:

resample2d, 유형은 MLSingleInputSupportLimits

resample2d() 연산자의 지원 제한입니다.

resample2d(input, options) 메서드 단계는 다음과 같습니다:
  1. this빌드할 수 없는 상태이면 예외를 발생시킵니다. "InvalidStateError" DOMException입니다.

  2. 피연산자를 검증할 때 thisinput이 false를 반환하면 예외를 발생시킵니다. TypeError입니다.

  3. inputdataType이 해당 허용되는 데이터 유형 중 하나가 아니면(이 표에 따름) 예외를 발생시킵니다. TypeError입니다.

  4. input랭크가 해당 허용되는 랭크가 아니면 예외를 발생시킵니다. TypeError입니다.

  5. options.scales존재하지 않으면 이를 목록 « 1.0, 1.0 »로 설정합니다.

  6. 그렇지 않고 그 항목 중 하나라도 0보다 작거나 같거나 그 크기가 2가 아니면 예외를 발생시킵니다. TypeError입니다.

  7. options.sizes존재하고 그 크기가 2가 아니거나, 그 항목 중 하나라도 0이면 예외를 발생시킵니다. TypeError입니다.

  8. options.axes존재하지 않으면 이를 목록 « 2, 3 »로 설정합니다.

  9. 그렇지 않고 options.axes 에 중복 값이 포함되어 있거나 그 항목 중 하나라도 범위 0부터 input랭크까지에 없으면, 상한은 제외하며 예외를 발생시킵니다. TypeError입니다.

  10. 출력 shape을 계산합니다:

    1. inputDescriptorinput.[[descriptor]]로 둡니다.

    2. outputShapeinputDescriptor.shape복제본으로 둡니다.

    3. 각각 index에 대해 범위 0부터 options.axes크기까지에서, 상한은 제외합니다:

      1. options.sizes존재하면 sizeoptions.sizes[index]로 둡니다.

      2. 그렇지 않으면 size를 floor(inputshape[options.axes[index]] * options.scales[index])로 둡니다.

      3. size유효한 차원이 아니면 예외를 발생시킵니다. TypeError입니다.

      4. outputShape[options.axes[index]] 를 size로 설정합니다.

    4. descinputDescriptor.dataTypeoutputShape이 주어진 상태에서 MLOperandDescriptor를 생성한 결과로 둡니다.

  11. 그래프 연결을 구성합니다:

    1. outputMLOperand를 생성한 결과로 두며 thisdesc가 주어집니다.

    2. operatoroptions가 주어진 "resample2d" 연산의 연산자로 둡니다.

    3. output.[[operator]]operator로 설정합니다.

    4. operator입력input으로 설정합니다.

    5. operator출력output으로 설정합니다.

  12. output을 반환합니다.

구체적인 샘플링 알고리즘은 기존 Machine Learning 프레임워크에서 널리 사용되는 알고리즘을 기반으로 합니다. 예를 들어 다음 [4, 4] 입력 텐서에서 linear 리샘플링을 수행하는 경우(공간 차원만 고려):
[   0   1   2   3  ]
[   0   1   2   3  ]
[  12  13  14  15  ]
[  12  13  14  15  ]

[8, 8] 출력 텐서에서 예상되는 값은 다음과 같습니다:

[   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  ]

이는 샘플링이 균등하게 분포되고 대칭적이며 이미지 미러링에 강하고 모서리 값이 정렬되는 유용한 특성을 갖습니다.

8.9.42. reshape

텐서의 shape을 새 shape으로 변경합니다. Reshape는 텐서의 내용을 복사하거나 변경하지 않습니다. 단지 후속 연산을 위해 텐서의 논리적 shape만 변경합니다.
partial interface MLGraphBuilder {
  MLOperand reshape(MLOperand input,
                    sequence<[EnforceRange] unsigned long> newShape,
                    optional MLOperatorOptions options = {});
};

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

반환: MLOperand입니다. 출력 텐서입니다. 출력 텐서의 값은 입력 텐서의 값과 같습니다. 출력 텐서의 shape은 newShape로 지정합니다.

reshape()의 텐서 제한
피연산자 허용되는 데이터 유형 필수 데이터 유형 허용되는 랭크 필수 랭크
input 모두 "float32", "float16", "int32", "int8", "uint8" N 0에서 5까지
출력 동일한 유형 input "float32", "float16", "int32", "int8", "uint8" N 0에서 5까지

MLOpSupportLimits 에는 reshape()에 대해 다음 멤버가 있습니다:

reshape, 유형은 MLSingleInputSupportLimits

reshape() 연산자의 지원 제한입니다.

reshape(input, newShape, options) 메서드 단계는 다음과 같습니다:
  1. this빌드할 수 없는 상태이면 예외를 발생시킵니다. "InvalidStateError" DOMException입니다.

  2. 피연산자를 검증할 때 thisinput이 false를 반환하면 예외를 발생시킵니다. TypeError입니다.

  3. newShape크기가 출력 텐서의 허용되는 랭크가 아니면(이 표에 따름) 예외를 발생시킵니다. TypeError입니다.

  4. outputShapeunsigned long의 빈 배열로 둡니다.

  5. newShape크기가 0이면 outputShape을 스칼라용 빈 목록 으로 설정합니다.

  6. newShape항목 중 하나라도 유효한 차원이 아니면 예외를 발생시킵니다. TypeError입니다.

  7. inputElementCountinput항목shape의 모든 항목의 곱으로 둡니다. 빈 차원은 inputElementCount가 1이 되게 합니다.

  8. newShape의 모든 값의 곱이 inputElementCount와 같지 않으면 예외를 발생시킵니다. TypeError입니다.

  9. descinput.[[descriptor]]의 복사본으로 둡니다.

  10. desc.shapenewShape으로 설정합니다.

  11. 그래프 연결을 구성합니다:

    1. outputMLOperand를 생성한 결과로 두며 thisdesc가 주어집니다.

    2. operatoroptions가 주어진 "reshape" 연산의 연산자로 둡니다.

    3. output.[[operator]]operator로 설정합니다.

    4. operator입력input으로 설정합니다.

    5. operator출력output으로 설정합니다.

  12. output을 반환합니다.

8.9.43. 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 모두 "float32", "float16", "int32" N 0에서 5까지
출력 동일한 유형 input "float32", "float16", "int32" 동일한 랭크 input 0에서 5까지

MLOpSupportLimits 에는 reverse()에 대해 다음 멤버가 있습니다:

reverse, 유형은 MLSingleInputSupportLimits

reverse() 연산자의 지원 제한입니다.

reverse(input, options) 메서드 단계는 다음과 같습니다:
  1. this빌드할 수 없는 상태이면 예외를 발생시킵니다. "InvalidStateError" DOMException입니다.

  2. 피연산자를 검증할 때 thisinput이 false를 반환하면 예외를 발생시킵니다. TypeError입니다.

  3. inputdataType이 해당 허용되는 데이터 유형 중 하나가 아니면(이 표에 따름) 예외를 발생시킵니다. TypeError입니다.

  4. inputRankinput랭크로 둡니다.

  5. axes가 주어지지 않으면 axes범위 0부터 inputRank까지로 두며, 상한은 제외합니다.

  6. 그렇지 않고 axes에 중복 값이 포함되어 있거나 그 요소 중 하나라도 범위 0부터 inputRank까지에 없으면, 상한은 제외하며 실패를 반환합니다.

  7. 그래프 연결을 구성합니다:

    1. outputinput이 주어진 상태에서 MLOperand를 복사한 결과로 둡니다.

    2. operator를 "reverse" 연산과 options에 대한 연산자로 둡니다.

    3. output.[[operator]]operator로 설정합니다.

    4. operator입력input으로 설정합니다.

    5. operator출력output으로 설정합니다.

  8. output을 반환합니다.

8.9.44. scatterElements

인덱스에 따라 축을 따라 updates 텐서의 값을 입력 텐서 복사본 위에 분산합니다.
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

분산된 값을 가져오는 축입니다. 그 값은 입력 텐서의 랭크가 N일 때 [0, N-1] 범위에 있어야 합니다.

인수:

반환: MLOperand입니다. 출력 N차원 텐서의 랭크input랭크와 같습니다.

scatterElements()의 텐서 제한
피연산자 허용되는 데이터 유형 필수 데이터 유형 허용되는 랭크 필수 랭크
input 모두 "float32", "float16", "int32" 1에서 N까지 1에서 5까지
indices "int32", "uint32", "int64" "int32" 동일한 랭크 input 1에서 5까지
updates 동일한 유형 input "float32", "float16", "int32" 동일한 랭크 input 1에서 5까지
출력 동일한 유형 input "float32", "float16", "int32" 동일한 랭크 input 1에서 5까지

MLScatterSupportLimits 에는 다음 멤버가 있습니다:

input, 유형은 MLTensorLimits

MLTensorLimits 입력 피연산자에 대한 것입니다.

indices, 유형은 MLTensorLimits

MLTensorLimits indices 피연산자에 대한 것입니다.

updates, 유형은 MLTensorLimits

MLTensorLimits updates 피연산자에 대한 것입니다.

output, 유형은 MLTensorLimits

MLTensorLimits 출력 피연산자에 대한 것입니다.

MLOpSupportLimits 에는 scatterElements()에 대해 다음 멤버가 있습니다:

scatterElements, 유형은 MLScatterSupportLimits

scatterElements() 연산자의 지원 제한입니다.

indices 매개변수는 scatterElements() 에 대해 그래프가 빌드될 때 허용 범위로 clamp할 수 없습니다. 입력은 실행 시점까지 알 수 없기 때문입니다. 지정된 clamping 동작을 기반 플랫폼이 제공하지 않으면 구현은 컴파일된 그래프에 clamp() 를 도입할 수 있습니다. 마찬가지로 기반 플랫폼이 음수 인덱스를 지원하지 않으면 구현은 컴파일된 그래프에 연산을 도입하여 차원 끝에서부터의 음수 인덱스를 양수 인덱스로 변환할 수 있습니다.
scatterElements(input, indices, updates, options) 메서드 단계는 다음과 같습니다:
  1. this빌드할 수 없는 상태이면 예외를 발생시킵니다. "InvalidStateError" DOMException입니다.

  2. 피연산자를 검증할 때 thisinput, indicesupdates 중 하나가 false를 반환하면 예외를 발생시킵니다. TypeError입니다.

  3. indicesdataType이 해당 허용되는 데이터 유형 중 하나가 아니면(이 표에 따름) 예외를 발생시킵니다. TypeError입니다.

  4. updatesdataTypeinputdataType과 같지 않으면 예외를 발생시킵니다. TypeError입니다.

  5. input, indices 또는 updates 중 하나의 랭크가 해당 허용되는 랭크가 아니면 예외를 발생시킵니다. TypeError입니다.

  6. axisoptions.axis로 둡니다.

  7. axisinput랭크보다 크거나 같으면 예외를 발생시킵니다. TypeError입니다.

  8. indicesShapeExpectedinputshape의 복사본으로 둡니다.

  9. indicesShapeExpected[axis]를 indicesshape[axis]로 설정합니다.

  10. indicesshapeindicesShapeExpected같지 않으면 예외를 발생시킵니다. TypeError입니다.

  11. updatesshapeindices같지 않은 shape이면 예외를 발생시킵니다. TypeError입니다.

  12. 그래프 연결을 구성합니다:

    1. outputinput이 주어진 상태에서 MLOperand를 복사한 결과로 둡니다.

    2. operatorinput, indices, updates, 그리고 options가 주어진 "scatterElements" 연산의 연산자로 둡니다.

    3. output.[[operator]]operator로 설정합니다.

    4. operator입력input, indices, 그리고 updates로 설정합니다.

    5. operator출력output으로 설정합니다.

  13. output을 반환합니다.

서로 다른 슬라이싱 방식에서 scatterElements가 동작하는 방식의 예입니다.
// shape이 [4,3]인 입력:
//   [[ 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]인 출력:
//   [[ 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]인 입력:
//   [[ 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]인 출력:
//   [[ 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]인 입력:
//   [[[  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]인 출력:
//   [[[ -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

인덱스에 따라 업데이트 텐서의 값 슬라이스를 입력 텐서 복사본 위에 분산합니다.
partial interface MLGraphBuilder {
  MLOperand scatterND(MLOperand input,
                      MLOperand indices,
                      MLOperand updates,
                      optional MLOperatorOptions options = {});
};

partial dictionary MLOpSupportLimits {
  MLScatterSupportLimits scatterND;
};
인수:

반환: MLOperand입니다. 출력 N차원 텐서의 랭크input랭크 + indices랭크 - indicesshape[-1] - 1과 같습니다.

scatterND()의 텐서 제한
피연산자 허용되는 데이터 유형 필수 데이터 유형 허용되는 랭크 필수 랭크
input 모두 "float32", "float16", "int32" 1에서 N까지 1에서 5까지
indices "int32", "uint32", "int64" "int32" 1에서 N까지 1에서 5까지
updates 동일한 유형 input "float32", "float16", "int32" N 0에서 5까지
출력 동일한 유형 input "float32", "float16", "int32" 1에서 N까지 1에서 5까지

MLOpSupportLimits 에는 scatterND()에 대해 다음 멤버가 있습니다:

scatterND, 유형은 MLScatterSupportLimits

scatterND() 연산자의 지원 제한입니다.

indices 매개변수는 scatterND() 에 대해 그래프가 빌드될 때 허용 범위로 clamp할 수 없습니다. 입력은 실행 시점까지 알 수 없기 때문입니다. 지정된 clamping 동작을 기반 플랫폼이 제공하지 않으면 구현은 clamp() 를 컴파일된 그래프에 도입할 수 있습니다. 마찬가지로 기반 플랫폼이 음수 인덱스를 지원하지 않으면 구현은 컴파일된 그래프에 연산을 도입하여 차원 끝에서부터의 음수 인덱스를 양수 인덱스로 변환할 수 있습니다.
scatterND(input, indices, updates, options) 메서드 단계는 다음과 같습니다:
  1. this빌드할 수 없는 상태이면 예외를 발생시킵니다. "InvalidStateError" DOMException입니다.

  2. 피연산자를 검증할 때 thisinput, indicesupdates 중 하나가 false를 반환하면 예외를 발생시킵니다. TypeError입니다.

  3. indicesdataType허용되는 데이터 유형 중 하나가 아니면(이 표에 따름) 예외를 발생시킵니다. TypeError입니다.

  4. updatesdataTypeinputdataType과 같지 않으면 예외를 발생시킵니다. TypeError입니다.

  5. input, indices 또는 updates 중 하나의 랭크가 해당 허용되는 랭크가 아니면 예외를 발생시킵니다. TypeError입니다.

  6. inputShapeinputshape으로 두고 inputRankinput랭크로 둡니다.

  7. indicesShapeindicesshape으로 두고 indicesRankindices랭크로 둡니다.

  8. indexableSizeindicesRank - 1로 둡니다.

  9. coordinateSizeindicesShape[indexableSize]로 둡니다.

  10. coordinateSizeinputRank보다 크면 예외를 발생시킵니다. TypeError입니다.

  11. expectedUpdatesShape을 빈 목록으로 둡니다.

  12. 각각 index에 대해 범위 0부터 indexableSize까지에서, 상한은 제외합니다:

    1. 추가합니다 indicesShape[index]를 expectedUpdatesShape에.

  13. 각각 index에 대해 범위 coordinateSize부터 inputRank까지에서, 상한은 제외합니다:

    1. 추가합니다 inputShape[index]를 expectedUpdatesShape에.

  14. updatesshapeexpectedUpdatesShape같지 않으면 예외를 발생시킵니다. TypeError입니다.

  15. outputShapeinputshape의 복사본으로 둡니다.

  16. outputDescinputdataTypeoutputShape이 주어진 상태에서 MLOperandDescriptor를 생성한 결과로 둡니다.

  17. 그래프 연결을 구성합니다:

    1. outputoutputDesc가 주어진 상태에서 MLOperand를 생성한 결과로 둡니다.

    2. operatorinput, indices, updates, 그리고 options가 주어진 "scatterND" 연산의 연산자로 둡니다.

    3. output.[[operator]]operator로 설정합니다.

    4. operator입력input, indices, 그리고 updates로 설정합니다.

    5. operator출력output으로 설정합니다.

  18. output을 반환합니다.

서로 다른 슬라이싱 방식에서 scatterND가 동작하는 방식의 예입니다.
// shape이 [8]인 입력:
//   [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]인 출력:
//   [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]인 입력:
//   [[0, 1],
//    [2, 3]]
// shape이 [2,2]인 indices:
//   [[0, 0],
//    [1, 1]]
// shape이 [2]인 updates:
//   [-1, -2]
// shape이 [2,2]인 출력:
//   [[-1,  1],   <= -1이 출력 좌표 [0, 0]에 기록됨
//    [ 2, -2]]   <= -2가 출력 좌표 [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]인 입력:
//   [[0, 1],
//    [2, 3],
//    [4, 5]]
// shape이 [2,1]인 indices:
//   [[2],
//    [0]]
// shape이 [2,2]인 updates:
//   [[-1, -2],
//    [-3, -4]]
// shape이 [3,2]인 출력:
//   [[-3 ,-4],    <= [-3, -4]가 출력 좌표 [0, *]에 기록됨
//    [ 2,  3],
//    [-1, -2]]    <= [-1, -2]가 출력 좌표 [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]인 입력:
//   [[[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]인 출력:
//   [[[ 0,  1],
//     [-1, -2]],   <= [-1, -2]가 출력 좌표 [0, 1, *]에 기록됨
//    [[-3, -4],    <= [-3, -4]가 출력 좌표 [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

입력 텐서의 시그모이드 함수를 계산합니다. 계산은 1 / (exp(-x) + 1) 식을 따릅니다.
partial interface MLGraphBuilder {
  MLOperand sigmoid(MLOperand input, optional MLOperatorOptions options = {});
};

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

반환:

sigmoid()의 텐서 제한
피연산자 허용되는 데이터 유형 필수 데이터 유형 허용되는 랭크 필수 랭크
input "float32", "float16" "float32", "float16" N 0에서 5까지
출력 동일한 유형 input "float32", "float16" 동일한 랭크 input 0에서 5까지

MLOpSupportLimits 에는 sigmoid()에 대해 다음 멤버가 있습니다:

sigmoid, 유형은 MLSingleInputSupportLimits

sigmoid() 연산자의 지원 제한입니다.

sigmoid(input, options) 메서드 단계는 다음과 같습니다:
  1. this빌드할 수 없는 상태이면 예외를 발생시킵니다. "InvalidStateError" DOMException입니다.

  2. 피연산자를 검증할 때 thisinput이 false를 반환하면 예외를 발생시킵니다. TypeError입니다.

  3. inputdataType이 해당 허용되는 데이터 유형 중 하나가 아니면(이 표에 따름) 예외를 발생시킵니다. TypeError입니다.

  4. 그래프 연결을 구성합니다:

    1. outputinput이 주어진 상태에서 MLOperand를 복사한 결과로 둡니다.

    2. operatoroptions가 주어진 "sigmoid" 연산의 연산자로 둡니다.

    3. output.[[operator]]operator로 설정합니다.

    4. operator입력input으로 설정합니다.

    5. operator출력output으로 설정합니다.

  5. output을 반환합니다.

이 연산의 동작은 다른 연산을 사용하여 일반적으로 에뮬레이션할 수 있으며 다음과 같습니다. 다만 사용자 에이전트에는 일반적으로 더 효율적인 구현이 있습니다. 기반 플랫폼이 연산을 직접 지원하지 않는 경우 이 분해를 구현을 안내하는 템플릿으로 사용할 수 있습니다.
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

입력 텐서의 슬라이스를 생성합니다.
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>

각 축을 따라 각 입력에서 건너뛸 stride입니다. strides 배열의 길이는 입력 텐서의 랭크와 같아야 합니다. 기본값은 모두 1로 구성되고 길이가 랭크인 배열입니다. 예: 3차원 텐서의 경우 [1,1,1]. Stride는 0보다 커야 합니다.

인수:

반환: MLOperand입니다. 입력 텐서와 동일한 랭크를 가지며 각 차원에서 지정된 시작 및 끝 인덱스로 텐서 값이 잘린 출력 텐서입니다.

slice()의 텐서 제한
피연산자 허용되는 데이터 유형 필수 데이터 유형 허용되는 랭크 필수 랭크
input 모두 "float32", "float16", "int32", "int8", "uint8" N 0에서 5까지
출력 동일한 유형 input "float32", "float16", "int32", "int8", "uint8" 동일한 랭크 input 0에서 5까지

MLOpSupportLimits 에는 slice()에 대해 다음 멤버가 있습니다:

slice, 유형은 MLSingleInputSupportLimits

slice() 연산자의 지원 제한입니다.

slice(input, starts, sizes, options) 메서드 단계는 다음과 같습니다:
  1. this빌드할 수 없는 상태이면 예외를 발생시킵니다. "InvalidStateError" DOMException입니다.

  2. 피연산자를 검증할 때 thisinput이 false를 반환하면 예외를 발생시킵니다. TypeError입니다.

  3. sizes항목 중 하나라도 0이면 예외를 발생시킵니다. TypeError입니다.

  4. starts크기sizes크기가 둘 다 input랭크와 같지 않으면 예외를 발생시킵니다. TypeError입니다.

  5. strides를 새 목록으로 둡니다.

  6. options.strides존재하면:

    1. stridesoptions.strides로 설정합니다.

    2. strides크기input랭크와 같지 않으면 예외를 발생시킵니다. TypeError입니다.

  7. inputShapeinputshape으로 두고 inputRankinput랭크로 둡니다.

  8. outputShape을 새 목록으로 둡니다.

  9. 각각 index에 대해 범위 0부터 inputRank까지에서, 상한은 제외합니다:

    1. inputSizeinputShape[index]로 둡니다.

    2. inputSliceSizesizes[index]로 둡니다.

    3. stridestrides[index]가 비어 있지 않으면 그 값으로, 그렇지 않으면 1로 둡니다:

    4. inputSliceSize가 0이면 예외를 발생시킵니다. TypeError입니다.

      0 크기 차원이 허용된다면 이 단계를 수정해야 합니다. [이슈 #391]

    5. stride가 1보다 작으면 예외를 발생시킵니다. TypeError입니다.

    6. starts[index]가 inputSize보다 크면 예외를 발생시킵니다. TypeError입니다.

    7. starts[index] + inputSliceSizeinputSize보다 크면 예외를 발생시킵니다. TypeError입니다.

    8. outputSizeRoundingExcessinputSliceSize % stride != 0이면 1로, 그렇지 않으면 0으로 둡니다.

    9. outputSize를 floor(inputSliceSize / stride) + outputSizeRoundingExcess로 둡니다:

    10. 추가합니다 outputSizeoutputShape에.

  10. outputDescinputdataTypeoutputShape이 주어진 상태에서 MLOperandDescriptor를 생성한 결과로 둡니다.

  11. 그래프 연결을 구성합니다:

    1. outputoutputDesc가 주어진 상태에서 MLOperand를 생성한 결과로 둡니다.

    2. operatorstarts, sizes, 그리고 options가 주어진 "slice" 연산의 연산자로 둡니다.

    3. output.[[operator]]operator로 설정합니다.

    4. operator입력input으로 설정합니다.

    5. operator출력output으로 설정합니다.

  12. output을 반환합니다.

8.9.48. softmax

지정된 축을 따라 N차원 입력 텐서의 softmax 값을 계산합니다.
partial interface MLGraphBuilder {
  MLOperand softmax(MLOperand input,
                    [EnforceRange] unsigned long axis,
                    optional MLOperatorOptions options = {});
};

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

반환:

softmax()의 텐서 제한
피연산자 허용되는 데이터 유형 필수 데이터 유형 허용되는 랭크 필수 랭크
input "float32", "float16" "float32", "float16" 1에서 N까지 1에서 5까지
출력 동일한 유형 input "float32", "float16" 동일한 랭크 input 1에서 5까지

MLOpSupportLimits 에는 softmax()에 대해 다음 멤버가 있습니다:

softmax, 유형은 MLSingleInputSupportLimits

softmax() 연산자의 지원 제한입니다.

softmax(input, axis, options) 메서드 단계는 다음과 같습니다:
  1. this빌드할 수 없는 상태이면 예외를 발생시킵니다. "InvalidStateError" DOMException입니다.

  2. 피연산자를 검증할 때 thisinput이 false를 반환하면 예외를 발생시킵니다. TypeError입니다.

  3. inputdataType이 해당 허용되는 데이터 유형 중 하나가 아니면(이 표에 따름) 예외를 발생시킵니다. TypeError입니다.

  4. axisinput랭크보다 크거나 같으면 예외를 발생시킵니다. TypeError입니다.

  5. 그래프 연결을 구성합니다:

    1. outputinput이 주어진 상태에서 MLOperand를 복사한 결과로 둡니다.

    2. operatoraxisoptions가 주어진 "softmax" 연산의 연산자로 둡니다.

    3. output.[[operator]]operator로 설정합니다.

    4. operator입력input으로 설정합니다.

    5. operator출력output으로 설정합니다.

  6. output을 반환합니다.

이 연산의 동작은 다른 연산을 사용하여 일반적으로 에뮬레이션할 수 있으며 다음과 같습니다. 다만 사용자 에이전트에는 일반적으로 더 효율적인 구현이 있습니다. 기반 플랫폼이 연산을 직접 지원하지 않는 경우 이 분해를 구현을 안내하는 템플릿으로 사용할 수 있습니다.
function softmax(builder, input, axis) {
  // 이 샘플은 결과의 수치적 안정성을 높이기 위해 입력 값 자체의 지수 대신
  // 최댓값까지의 거리의 지수를 계산하는 잘 알려진 구현 기법 [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

입력 텐서의 softplus 함수를 계산합니다. 계산은 ln(1 + exp(x)) 식을 따릅니다.
partial interface MLGraphBuilder {
  MLOperand softplus(MLOperand input, optional MLOperatorOptions options = {});
};

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

반환:

softplus()의 텐서 제한
피연산자 허용되는 데이터 유형 필수 데이터 유형 허용되는 랭크 필수 랭크
input "float32", "float16" "float32", "float16" N 0에서 5까지
출력 동일한 유형 input "float32", "float16" 동일한 랭크 input 0에서 5까지

MLOpSupportLimits 에는 softplus()에 대해 다음 멤버가 있습니다:

softplus, 유형은 MLSingleInputSupportLimits

softplus() 연산자의 지원 제한입니다.

softplus(input, options) 메서드 단계는 다음과 같습니다:
  1. this빌드할 수 없는 상태이면 예외를 발생시킵니다. "InvalidStateError" DOMException입니다.

  2. 피연산자를 검증할 때 thisinput이 false를 반환하면 예외를 발생시킵니다. TypeError입니다.

  3. inputdataType이 해당 허용되는 데이터 유형 중 하나가 아니면(이 표에 따름) 예외를 발생시킵니다. TypeError입니다.

  4. 그래프 연결을 구성합니다:

    1. outputinput이 주어진 상태에서 MLOperand를 복사한 결과로 둡니다.

    2. operator를 "softplus" 연산과 options에 대한 연산자로 둡니다.

    3. output.[[operator]]operator로 설정합니다.

    4. operator입력input으로 설정합니다.

    5. operator출력output으로 설정합니다.

  5. output을 반환합니다.

이 연산의 동작은 다른 연산을 사용하여 일반적으로 에뮬레이션할 수 있으며 다음과 같습니다. 다만 사용자 에이전트에는 일반적으로 더 효율적인 구현이 있습니다. 기반 플랫폼이 연산을 직접 지원하지 않는 경우 이 분해를 구현을 안내하는 템플릿으로 사용할 수 있습니다.
function softplus(builder, input) {
  return builder.log(
    builder.add(builder.exp(input), builder.constant(input.dataType, 1)));
}

8.9.50. softsign

입력 텐서의 softsign 함수를 계산합니다. 계산은 x / (1 + |x|) 식을 따릅니다.
partial interface MLGraphBuilder {
  MLOperand softsign(MLOperand input, optional MLOperatorOptions options = {});
};

partial dictionary MLOpSupportLimits {
  MLSingleInputSupportLimits softsign;
};
이 연산의 동작은 다른 연산을 사용하여 일반적으로 에뮬레이션할 수 있으며 다음과 같습니다. 다만 사용자 에이전트에는 일반적으로 더 효율적인 구현이 있습니다. 기반 플랫폼이 연산을 직접 지원하지 않는 경우 이 분해를 구현을 안내하는 템플릿으로 사용할 수 있습니다.
function softsign(builder, input) {
  return builder.div(
    input,
    builder.add(builder.constant(input.dataType, 1), builder.abs(input)));
}
인수:

반환:

softsign()의 텐서 제한
피연산자 허용되는 데이터 유형 필수 데이터 유형 허용되는 랭크 필수 랭크
input "float32", "float16" "float32", "float16" N 0에서 5까지
출력 동일한 유형 input "float32", "float16" 동일한 랭크 input 0에서 5까지

MLOpSupportLimits 에는 softsign()에 대해 다음 멤버가 있습니다:

softsign, 유형은 MLSingleInputSupportLimits

softsign() 연산자의 지원 제한입니다.

softsign(input, options) 메서드 단계는 다음과 같습니다:
  1. this빌드할 수 없는 상태이면 예외를 발생시킵니다. "InvalidStateError" DOMException입니다.

  2. 피연산자를 검증할 때 thisinput이 false를 반환하면 예외를 발생시킵니다. TypeError입니다.

  3. inputdataType이 해당 허용되는 데이터 유형 중 하나가 아니면(이 표에 따름) 예외를 발생시킵니다. TypeError입니다.

  4. 그래프 연결을 구성합니다:

    1. outputinput이 주어진 상태에서 MLOperand를 복사한 결과로 둡니다.

    2. operator를 "softsign" 연산과 options에 대한 연산자로 둡니다.

    3. output.[[operator]]operator로 설정합니다.

    4. operator입력input으로 설정합니다.

    5. operator출력output으로 설정합니다.

  5. output을 반환합니다.

8.9.51. split

지정된 축을 따라 입력 텐서를 여러 하위 텐서로 분할합니다.
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>. 분할된 출력 텐서입니다. splitsunsigned long이면 출력의 크기splits와 같습니다. 각 출력 텐서의 shape은 input과 같지만, axis의 차원 크기는 inputaxis 방향 차원 크기를 splits로 나눈 몫과 같습니다. splitssequence<unsigned long>이면 출력의 크기splits크기와 같습니다. i번째 출력 텐서의 shape은 input과 같지만 axis 방향의 차원 크기는 splits[i]입니다.

MLSplitOptions 에는 다음 멤버가 있습니다:

axis, 유형은 unsigned long이며 기본값은 0

분할할 차원입니다. 그 값은 입력 텐서의 랭크가 N일 때 [0, N-1] 범위에 있어야 합니다.

split()의 텐서 제한
피연산자 허용되는 데이터 유형 필수 데이터 유형 허용되는 랭크 필수 랭크
input 모두 "float32", "float16", "int32" 1에서 N까지 1에서 5까지
출력 동일한 유형 input "float32", "float16", "int32" 동일한 랭크 input 1에서 5까지

MLSplitSupportLimits 에는 다음 멤버가 있습니다:

input, 유형은 MLTensorLimits

MLTensorLimits 입력 피연산자에 대한 것입니다.

outputs, 유형은 MLTensorLimits

MLTensorLimits 모든 출력 피연산자에 대한 것입니다.

MLOpSupportLimits 에는 split()에 대해 다음 멤버가 있습니다:

split, 유형은 MLSplitSupportLimits

split() 연산자의 지원 제한입니다.

split(input, splits, options) 메서드 단계는 다음과 같습니다:
  1. this빌드할 수 없는 상태이면 예외를 발생시킵니다. "InvalidStateError" DOMException입니다.

  2. 피연산자를 검증할 때 thisinput이 false를 반환하면 예외를 발생시킵니다. TypeError입니다.

  3. axisoptions.axis로 둡니다.

  4. axisinput랭크보다 크거나 같으면 예외를 발생시킵니다. TypeError입니다.

  5. splitsunsigned long이면:

    1. splits유효한 텐서 개수가 아니면 예외를 발생시킵니다. TypeError입니다.

    2. inputshape[axis] % splits가 0이 아니면 예외를 발생시킵니다. TypeError입니다.

    3. 그렇지 않으면 splitCountsplits로 둡니다.

  6. splitssequence<unsigned long>이면:

    1. splits크기유효한 텐서 개수가 아니면 예외를 발생시킵니다. TypeError입니다.

    2. 항목 중 하나라도 0이면 예외를 발생시킵니다. TypeError입니다.

      0 크기 차원이 허용된다면 위 단계를 수정해야 합니다. [이슈 #391]

    3. 항목의 합이 inputshape[axis]와 같지 않으면 예외를 발생시킵니다. TypeError입니다.

    4. 그렇지 않으면 splitCountsplits크기로 둡니다.

  7. 그래프 연결을 구성합니다:

    1. operatorsplitsoptions가 주어진 "split" 연산의 연산자로 둡니다.

    2. outputs를 새 목록으로 둡니다.

    3. 각각 index에 대해 범위 0부터 splitCount까지에서, 상한은 제외합니다:

      1. operandinput이 주어진 상태에서 MLOperand를 복사한 결과로 둡니다.

      2. splitsunsigned long이면 newDimensionoperandshape[axis] / splits로 둡니다.

      3. 그렇지 않으면 newDimensionsplits[index]로 둡니다.

      4. operandshape[axis]를 newDimension으로 설정합니다.

      5. operand.[[operator]]operator로 설정합니다.

      6. 추가합니다 operandoutputs에.

    4. operator입력input으로 설정합니다.

    5. operator출력outputs로 설정합니다.

  8. outputs를 반환합니다.

이 연산의 동작은 다른 연산을 사용하여 일반적으로 에뮬레이션할 수 있으며 다음과 같습니다. 다만 사용자 에이전트에는 일반적으로 더 효율적인 구현이 있습니다. 기반 플랫폼이 연산을 직접 지원하지 않는 경우 이 분해를 구현을 안내하는 템플릿으로 사용할 수 있습니다.
function split(builder, input, splits, options) {
  // 이 샘플은 splits 매개변수가 배열인 경우를 보여줍니다.
  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

입력 텐서의 쌍곡 탄젠트 함수를 계산합니다. 계산은 (exp(2 * x) - 1) / (exp(2 * x) + 1) 식을 따릅니다.
partial interface MLGraphBuilder {
  MLOperand tanh(MLOperand input, optional MLOperatorOptions options = {});
};

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

반환:

tanh()의 텐서 제한
피연산자 허용되는 데이터 유형 필수 데이터 유형 허용되는 랭크 필수 랭크
input "float32", "float16" "float32", "float16" N 0에서 5까지
출력 동일한 유형 input "float32", "float16" 동일한 랭크 input 0에서 5까지

MLOpSupportLimits 에는 tanh()에 대해 다음 멤버가 있습니다:

tanh, 유형은 MLSingleInputSupportLimits

tanh() 연산자의 지원 제한입니다.

tanh(input, options) 메서드 단계는 다음과 같습니다:
  1. this빌드할 수 없는 상태이면 예외를 발생시킵니다. "InvalidStateError" DOMException입니다.

  2. 피연산자를 검증할 때 thisinput이 false를 반환하면 예외를 발생시킵니다. TypeError입니다.

  3. inputdataType이 해당 허용되는 데이터 유형 중 하나가 아니면(이 표에 따름) 예외를 발생시킵니다. TypeError입니다.

  4. 그래프 연결을 구성합니다:

    1. outputinput이 주어진 상태에서 MLOperand를 복사한 결과로 둡니다.

    2. operatoroptions가 주어진 "tanh" 연산의 연산자로 둡니다.

    3. output.[[operator]]operator로 설정합니다.

    4. operator입력input으로 설정합니다.

    5. operator출력output으로 설정합니다.

  5. output을 반환합니다.

이 연산의 동작은 다른 연산을 사용하여 일반적으로 에뮬레이션할 수 있으며 다음과 같습니다. 다만 사용자 에이전트에는 일반적으로 더 효율적인 구현이 있습니다. 기반 플랫폼이 연산을 직접 지원하지 않는 경우 이 분해를 구현을 안내하는 템플릿으로 사용할 수 있습니다.
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

각 차원을 따라 지정된 횟수만큼 텐서를 반복합니다.
partial interface MLGraphBuilder {
  MLOperand tile(MLOperand input,
                 sequence<unsigned long> repetitions,
                 optional MLOperatorOptions options = {});
};

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

반환: MLOperand입니다. 반복된 N차원 텐서입니다.

tile()의 텐서 제한
피연산자 허용되는 데이터 유형 필수 데이터 유형 허용되는 랭크 필수 랭크
input 모두 "float32", "float16", "int32" N 0에서 5까지
출력 동일한 유형 input "float32", "float16", "int32" 동일한 랭크 input 0에서 5까지

MLOpSupportLimits 에는 tile()에 대해 다음 멤버가 있습니다:

tile, 유형은 MLSingleInputSupportLimits

tile() 연산자의 지원 제한입니다.

tile(input, repetitions, options) 메서드 단계는 다음과 같습니다:
  1. this빌드할 수 없는 상태이면 예외를 발생시킵니다. "InvalidStateError" DOMException입니다.

  2. 피연산자를 검증할 때 thisinput이 false를 반환하면 예외를 발생시킵니다. TypeError입니다.

  3. repetitions크기input랭크와 같지 않으면 예외를 발생시킵니다. TypeError입니다.

  4. repetitions의 값에 0이 포함되어 있으면 예외를 발생시킵니다. TypeError입니다.

    0 크기 차원이 허용된다면 이 단계를 수정해야 합니다. [이슈 #391]

  5. outputShapeinputshape의 복사본으로 둡니다.

  6. 각각 index에 대해 범위 0부터 outputShape크기까지에서, 상한은 제외합니다:

    1. outputShape[index]를 outputShape[index] * repetitions[index]로 설정합니다.

  7. outputDescriptorinputdataTypeoutputShape이 주어진 상태에서 MLOperandDescriptor를 생성한 결과로 둡니다.

  8. 그래프 연결을 구성합니다:

    1. outputoutputDescriptor가 주어진 상태에서 MLOperand를 생성한 결과로 둡니다.

    2. operatoroptions가 주어진 "tile" 연산의 연산자로 둡니다.

    3. output.[[operator]]operator로 설정합니다.

    4. operator입력input으로 설정합니다.

    5. operator출력output으로 설정합니다.

  9. output을 반환합니다.

8.9.54. transpose

permutation에 따라 입력 텐서의 차원을 순열합니다.
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>

출력 shape을 순열하는 데 사용하는 값입니다. 기본값은 [N-1, ..., 0]이며, 여기서 N은 입력 텐서의 랭크입니다. 예를 들어 3차원 텐서의 경우 [2,1,0]입니다. 이러한 기본값으로 인해 출력은 입력의 전치된 텐서가 됩니다. 지정하는 경우 값의 개수는 입력 텐서의 랭크와 같아야 하며, 값은 중복 없이 0에서 N-1까지의 범위에 있어야 합니다.

인수:

반환: MLOperand입니다. 순열되거나 전치된 N차원 텐서입니다.

transpose()의 텐서 제한
피연산자 허용되는 데이터 유형 필수 데이터 유형 허용되는 랭크 필수 랭크
input 모두 "float32", "float16", "int32" N 0에서 5까지
출력 동일한 유형 input "float32", "float16", "int32" 동일한 랭크 input 0에서 5까지

MLOpSupportLimits 에는 transpose()에 대해 다음 멤버가 있습니다:

transpose, 유형은 MLSingleInputSupportLimits

transpose() 연산자의 지원 제한입니다.

transpose(input, options) 메서드 단계는 다음과 같습니다:
  1. this빌드할 수 없는 상태이면 예외를 발생시킵니다. "InvalidStateError" DOMException입니다.

  2. 피연산자를 검증할 때 thisinput이 false를 반환하면 예외를 발생시킵니다. TypeError입니다.

  3. options.permutation존재하지 않으면 options.permutationinputshape에 대한 모든 인덱스의 역순 시퀀스로 둡니다.

  4. 그렇지 않고 options.permutation존재하면:

    1. 크기input랭크와 같지 않으면 예외를 발생시킵니다. TypeError입니다.

    2. 항목범위 0부터 input랭크까지에 없으면, 상한은 제외하며 예외를 발생시킵니다. TypeError입니다.

    3. 중복 값을 포함하면 예외를 발생시킵니다. TypeError입니다.

  5. 그래프 연결을 구성합니다:

    1. outputinput이 주어진 상태에서 MLOperand를 복사한 결과로 둡니다.

    2. operatoroptions가 주어진 "transpose" 연산의 연산자로 둡니다.

    3. output.[[operator]]operator로 설정합니다.

    4. operator입력input으로 설정합니다.

    5. operator출력output으로 설정합니다.

  6. output을 반환합니다.

8.9.55. triangular

2차원 텐서(행렬)가 주어지면 입력 텐서의 위쪽 또는 아래쪽 삼각 부분을 포함하는 2차원 텐서를 반환합니다. 입력 텐서가 2차원보다 크면 행렬 배치로 처리하며 결과는 동일한 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

입력 행렬의 위쪽 또는 아래쪽 부분 중 어느 쪽을 출력에 유지할지 나타냅니다. true이면 위쪽 부분을 유지합니다.

diagonal, 유형은 long이며 기본값은 0

입력 행렬의 주대각선 위나 아래에서 몇 개의 대각선을 유지하거나 제외할지 지정합니다. 값이 0이면 주대각선 이외의 대각선에는 영향을 주지 않습니다.

인수:

반환: MLOperand입니다. 삼각 행렬 또는 입력과 동일한 shape을 가진 행렬 배치를 나타내는 출력 텐서입니다.

triangular()의 텐서 제한
피연산자 허용되는 데이터 유형 필수 데이터 유형 허용되는 랭크 필수 랭크
input 모두 "float32", "float16" 2에서 N까지 2에서 5까지
출력 동일한 유형 input "float32", "float16" 동일한 랭크 input 2에서 5까지

MLOpSupportLimits 에는 triangular()에 대해 다음 멤버가 있습니다:

triangular, 유형은 MLSingleInputSupportLimits

triangular() 연산자의 지원 제한입니다.

triangular(input, options) 메서드 단계는 다음과 같습니다:
  1. this빌드할 수 없는 상태이면 예외를 발생시킵니다. "InvalidStateError" DOMException입니다.

  2. 피연산자를 검증할 때 thisinput이 false를 반환하면 예외를 발생시킵니다. TypeError입니다.

  3. input랭크가 해당 허용되는 랭크 중 하나가 아니면(이 표에 따름) 예외를 발생시킵니다. TypeError입니다.

  4. 그래프 연결을 구성합니다:

    1. outputinput이 주어진 상태에서 MLOperand를 복사한 결과로 둡니다.

    2. operatoroptions가 주어진 "triangular" 연산의 연산자로 둡니다.

    3. output.[[operator]]operator로 설정합니다.

    4. operator입력input으로 설정합니다.

    5. operator출력output으로 설정합니다.

  5. output을 반환합니다.

서로 다른 diagonal 설정에서 triangular가 동작하는 방식의 예입니다.
// 입력:
//   [[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]));

// 상삼각 행렬:
//   [[7, 1, 2],
//    [0, 4, 8],
//    [0, 0, 3]]
const upper = builder.triangular(input);

// 추가 대각선 한 세트를 제외한 상삼각 행렬:
//   [[0, 1, 2],
//    [0, 0, 8],
//    [0, 0, 0]]
const upperPositive = builder.triangular(input, {diagonal: 1});

// 추가 대각선 한 세트를 유지한 상삼각 행렬:
//   [[7, 1, 2],
//    [9, 4, 8],
//    [0, 6, 3]]
const upperNegative = builder.triangular(input, {diagonal: -1});

// 하삼각 행렬:
//   [[7, 0, 0],
//    [9, 4, 0],
//    [2, 6, 3]]
const lower = builder.triangular(input, {upper: false});

// 추가 대각선 한 세트를 유지한 하삼각 행렬:
//   [[7, 1, 0],
//    [9, 4, 8],
//    [2, 6, 3]]
const lowerPositive = builder.triangular(input, {upper: false, diagonal: 1});

// 추가 대각선 한 세트를 제외한 하삼각 행렬:
//   [[0, 0, 0],
//    [9, 0, 0],
//    [2, 6, 0]]
const lowerNegative = builder.triangular(input, {upper: false, diagonal: -1})

// 배치가 두 개인 하삼각 행렬:
//   [[[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

trueValue 또는 falseValue 텐서에서 대응하는 condition 텐서의 값에 따라 값을 선택합니다. 0이 아니면 true이고 0이면 false입니다. condition 텐서는 대개 요소별 논리 연산 중 하나의 출력입니다.

연산은 브로드캐스트되며 [numpy-broadcasting-rule]을 따릅니다. 입력 텐서는 양방향 브로드캐스트 가능해야 합니다. 출력 텐서의 랭크는 입력 텐서의 최대 랭크입니다. 출력 텐서의 각 차원에 대해 그 크기는 입력 텐서에서 해당 차원을 따른 최대 크기입니다.

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 텐서에서 요소별로 선택한 값을 포함하는 출력 텐서입니다.

where()의 텐서 제한
피연산자 허용되는 데이터 유형 필수 데이터 유형 허용되는 랭크 필수 랭크
condition "uint8" "uint8" N 0에서 5까지
trueValue 모두 "float32", "float16", "int32" N 0에서 5까지
falseValue 동일한 유형 trueValue "float32", "float16", "int32" N 0에서 5까지
출력 동일한 유형 trueValue "float32", "float16", "int32" N 0에서 5까지

MLWhereSupportLimits 에는 다음 멤버가 있습니다:

condition, 유형은 MLTensorLimits

MLTensorLimits condition 피연산자에 대한 것입니다.

trueValue, 유형은 MLTensorLimits

MLTensorLimits trueValue 피연산자에 대한 것입니다.

falseValue, 유형은 MLTensorLimits

MLTensorLimits falseValue 피연산자에 대한 것입니다.

output, 유형은 MLTensorLimits

MLTensorLimits 출력 피연산자에 대한 것입니다.

MLOpSupportLimits 에는 where()에 대해 다음 멤버가 있습니다:

where, 유형은 MLWhereSupportLimits

where() 연산자의 지원 제한입니다.

where(condition, trueValue, falseValue, options) 메서드 단계는 다음과 같습니다:
  1. this빌드할 수 없는 상태이면 예외를 발생시킵니다. "InvalidStateError" DOMException입니다.

  2. 피연산자를 검증할 때 thiscondition, trueValuefalseValue 중 하나가 false를 반환하면 예외를 발생시킵니다. TypeError입니다.

  3. condition, trueValue 또는 falseValue 중 하나의 dataType이 해당 허용되는 데이터 유형 중 하나가 아니면(이 표에 따름) 예외를 발생시킵니다. TypeError입니다.

  4. outputShapetrueValueshapefalseValueshape양방향 브로드캐스트한 결과로 둡니다.

    1. 실패를 반환하면 예외를 발생시킵니다. TypeError입니다.

  5. outputShapeconditionshapeoutputShape양방향 브로드캐스트한 결과로 설정합니다.

    1. 실패를 반환하면 예외를 발생시킵니다. TypeError입니다.

  6. descriptortrueValuedataTypeoutputShape이 주어진 상태에서 MLOperandDescriptor를 생성한 결과로 둡니다.

  7. 그래프 연결을 구성합니다:

    1. outputMLOperand를 생성한 결과로 두며 thisdescriptor가 주어집니다.

    2. operatorcondition, trueValue, falseValue, 그리고 options가 주어진 "where" 연산의 연산자로 둡니다.

    3. output.[[operator]]operator로 설정합니다.

    4. operator입력condition, trueValuefalseValue로 설정합니다.

    5. operator출력output으로 설정합니다.

  8. output을 반환합니다.

이 연산의 동작은 다른 연산을 사용하여 일반적으로 에뮬레이션할 수 있으며 다음과 같습니다. 다만 사용자 에이전트에는 일반적으로 더 효율적인 구현이 있습니다. 기반 플랫폼이 연산을 직접 지원하지 않는 경우 이 분해를 구현을 안내하는 템플릿으로 사용할 수 있습니다.
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. 브로드캐스팅

브로드캐스팅은 그래프 구성과 계산 중에 WebNN이 shape이 서로 다른 텐서를 어떻게 처리하는지 설명합니다. 이는 [NumPy]의 영향을 크게 받으며 [numpy-broadcasting-rule]을 따릅니다. 대략적으로 말하면 더 작은 텐서에 대한 연산을 더 큰 텐서의 shape 전체에 "브로드캐스트"하여 같은 데이터를 복사하지 않고 반복 적용할 수 있게 합니다.

가장 간단한 예는 add() 또는 mul()과 같은 요소별 이항 연산을 통해 스칼라 상수를 N차원 텐서에 적용하는 것입니다. 스칼라 상수의 여러 복사본을 포함하는 일치하는 N차원 텐서를 할당하고 채울 필요 없이 이러한 요소별 연산은 스칼라 상수를 직접 사용하고 스칼라 값을 N차원 텐서 전체에 브로드캐스트할 수 있습니다. 다음 사항을 고려하면 같은 논리가 다른 차원의 텐서에도 적용됩니다.

입력 텐서의 shape은 호환되어야 합니다. 첫 번째 텐서를 크기가 1인 축을 따라 반복하거나 새 차원에 걸쳐 반복하여, 마지막(가장 오른쪽) 차원부터 시작해 "늘릴" 수 있다면 한 텐서는 다른 텐서에 단방향 브로드캐스트 가능합니다. 예를 들어 [4] 텐서는 5번 반복하여 [5, 4] 텐서로 브로드캐스트할 수 있습니다. [1] 텐서는 마지막 차원에서 4번, 그 앞 차원에서 5번 반복하여 [5,4] 텐서로 브로드캐스트할 수 있습니다. 단방향 브로드캐스팅은 대상 텐서 shape이 명시적으로 주어지는 expand() 같은 연산에 중요합니다.

두 텐서가 마지막 차원부터 시작하여 서로의 여러 차원 전체에 걸쳐 상호 "늘어날"(반복될) 수 있다면 양방향 브로드캐스트 가능합니다. 예를 들어 [5,1] 텐서는 첫 번째 텐서를 마지막 차원에서 6번, 두 번째 텐서를 앞 차원에서 5번 반복하여 [1,6] 텐서와 양방향 브로드캐스트할 수 있습니다. 연산 결과는 [5,6] 텐서가 됩니다. 양방향 브로드캐스팅은 요소별 연산에 편리합니다.

모든 차원을 정수 배수로 업샘플링하여 대상 텐서의 shape에 맞출 수 있다면 텐서는 블록 단위 브로드캐스트 가능합니다. 예를 들어 [4,5] 텐서는 정확한 배수이므로 (16 % 4 = 0, 10 % 5 = 0) 첫 번째 차원에서 각 요소를 4번, 마지막 차원에서 각 요소를 2번 반복하여 [16,10] 텐서로 블록 단위 브로드캐스트할 수 있습니다(예: 마지막 차원의 값 [1,2,3,4,5][1,1,2,2,3,3,4,4,5,5]로 반복됩니다). 그러나 [4,5] 텐서는 두 차원 모두 나머지가 0이 아니므로 [9,3] 텐서와 호환되지 않습니다(9 % 4 = 1, 3 % 5 = 3). 블록 단위 브로드캐스팅은 메모리를 절약하기 위해 더 큰 블록에서 공통 값을 공유하는 데 유용합니다. 두 텐서는 동일한 랭크를 가져야 하며 출력 shape은 더 작은 텐서가 업샘플링되는 대상 텐서의 shape입니다.

일부 연산은 특수한 의미의 브로드캐스팅을 허용합니다. 예를 들어 matmul() 은 입력 텐서의 마지막 두 차원을 행렬의 행과 열로 처리하며 첫 번째 행렬의 열 수는 두 번째 행렬의 행 수와 같아야 합니다. 행렬 곱셈은 추가 차원 전체에 양방향 브로드캐스트되며 입력 텐서를 곱할 행렬의 스택으로 처리합니다.

shapeFromshapeToshape을 단방향 브로드캐스트하려면 다음 단계를 수행합니다. shapeFromshapeTo는 텐서 차원을 나타내는 양의 정수 목록이며, 이 단계는 양의 정수의 새 목록 또는 실패를 반환합니다.
  1. sizeFromshapeFrom크기로 둡니다.

  2. sizeToshapeTo크기로 둡니다.

  3. sizeFrom > sizeTo이면 실패를 반환합니다.

  4. paddedShapeFromshapeFrom복제본으로 둡니다.

  5. paddedShapeFrom크기sizeTo보다 작은 동안 paddedShapeFrom 앞에 1을 추가합니다.

  6. outputShape을 새 목록으로 둡니다.

  7. 각각 index에 대해 범위 0부터 sizeTo까지에서, 상한은 제외합니다:

    1. dimFrompaddedShapeFrom[index]로 둡니다.

    2. dimToshapeTo[index]로 둡니다.

    3. dimTodimFrom과 같지 않고 dimFrom도 1과 같지 않으면 실패를 반환합니다.

    4. 추가합니다 dimTooutputShape에.

  8. outputShape을 반환합니다.

shapeFromshapeFromshapeTo단방향 브로드캐스트한 결과가 실패가 아니라면 shapeTo단방향 브로드캐스트 가능합니다.

shapeAshapeBshape을 양방향 브로드캐스트하려면 다음 단계를 수행합니다. shapeAshapeB는 텐서 차원을 나타내는 양의 정수 목록이며, 이 단계는 양의 정수의 새 목록 또는 실패를 반환합니다.
  1. sizeAshapeA크기로 둡니다.

  2. sizeBshapeB크기로 둡니다.

  3. outputSizesizeAsizeB 중 최댓값으로 둡니다.

  4. paddedAshapeA복제본으로 둡니다.

  5. paddedA크기outputSize보다 작은 동안 paddedA 앞에 1을 추가합니다.

  6. paddedBshapeB복제본으로 둡니다.

  7. paddedB크기outputSize보다 작은 동안 paddedB 앞에 1을 추가합니다.

  8. outputShape을 새 목록으로 둡니다.

  9. 각각 index에 대해 범위 0부터 outputSize까지에서, 상한은 제외합니다:

    1. dimApaddedA[index]로 둡니다.

    2. dimBpaddedB[index]로 둡니다.

    3. dimAdimB와 같지 않고 dimA가 1과 같지 않으며 dimB도 1과 같지 않으면 실패를 반환합니다.

    4. 추가합니다 dimAdimB 중 최댓값을 outputShape에.

  10. outputShape을 반환합니다.

shapeAshapeAshapeB양방향 브로드캐스트한 결과가 실패가 아니라면 shapeB양방향 브로드캐스트 가능합니다.

shapeFromshapeToshape을 블록 단위로 브로드캐스트하려면 다음 단계를 수행합니다. shapeFromshapeTo는 텐서 차원을 나타내는 양의 정수 목록이며, 이 단계는 true 또는 false를 반환합니다.
  1. shapeFrom크기shapeTo크기와 같지 않으면 false를 반환합니다.

  2. 각각 index에 대해 범위 0부터 shapeTo크기까지에서, 상한은 제외합니다:

    1. shapeFrom[index]이 shapeTo[index]을 정확히 나누지 못하면 false를 반환합니다.

  3. true를 반환합니다.

shapeFromshapeFromshapeTo블록 단위로 브로드캐스트한 결과가 true이면 shapeTo블록 단위 브로드캐스트 가능합니다.

9.2. 캐스팅

MLNumber 또는 double로 전달된 매개변수를 입력 또는 출력 MLOperandMLOperandDataType에 맞게 변환해야 하는 알고리즘에서는 명시적 숫자 캐스팅을 사용합니다.

숫자 x를 주어진 MLOperandDataType dataType으로 캐스트하려면 다음 단계를 수행합니다. 이 단계는 숫자를 반환합니다.
  1. dataType에 따라 분기합니다:

    "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")를 반환합니다.

참고: 캐스트의 입력은 Infinity, -Infinity 및 NaN 특수 값을 포함하는 범위와 정밀도에 제한이 없는 추상 숫자입니다. 출력도 추상 숫자이지만 지정된 유형으로 정확히 표현할 수 있습니다.

ConvertToFloat(x, bitLength) 단계는 다음과 같습니다:
  1. x가 NaN이면 NaN을 반환합니다.

  2. bitLength에 따라 분기합니다:

    32
    1. upperBound를 2128로 둡니다.

    2. lowerBound를 -2128로 둡니다.

    3. S를 -0을 제외한 [IEEE-754-2019] binary32 부동 소수점 값의 집합으로 두되, 특수 값 upperBoundlowerBound를 추가합니다.

    16
    1. upperBound를 216으로 둡니다.

    2. lowerBound를 -216으로 둡니다.

    3. S를 -0을 제외한 [IEEE-754-2019] binary16 부동 소수점 값의 집합으로 두되, 특수 값 upperBoundlowerBound를 추가합니다.

  3. yS에서 x와 가장 가까운 숫자로 두며, 두 개의 동일하게 가까운 값이 있으면 유효숫자가 짝수인 숫자를 선택합니다. 이 목적에서는 두 특수 값 lowerBoundupperBound의 유효숫자를 짝수로 간주합니다.

  4. yupperBound이면 +Infinity를 반환합니다.

  5. ylowerBound이면 -Infinity를 반환합니다.

  6. y가 +0이고 x가 음수이면 -0을 반환합니다.

  7. y를 반환합니다.

참고: 이는 [WEBIDL]의 정의를 기반으로 하지만 16비트 부동 소수점 값도 다루도록 확장되었습니다.

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를 가장 가까운 정수로 반올림하되 두 정수의 정확히 중간이면 짝수 정수를 선택하고 -0 대신 +0을 선택합니다.

  7. x를 반환합니다.

참고: 이는 [WEBIDL]의 정의를 기반으로 하며 다음과 같은 차이가 있습니다. 64비트 정수를 특별히 처리하지 않고, 입력 x는 추상 숫자이며, clamping은 항상 수행됩니다.

9.3. 기타

목록 AA크기목록 B크기와 같고 A의 각 항목B에서 같은 인덱스의 항목과 같으면 같습니다.

[INFRA]에 정의가 제공되면 이를 제거하십시오. [whatwg/infra 이슈 #664]

10. 예제

다음 빌드 그래프가 주어집니다:
constant1 ---+
             +--- Add ---> intermediateOutput1 ---+
input1    ---+                                    |
                                                  +--- Mul---> output
constant2 ---+                                    |
             +--- Add ---> intermediateOutput2 ---+
input2    ---+
다음 코드는 그래프를 구현합니다:
// 4차원 텐서를 사용합니다.
const TENSOR_SHAPE = [1, 2, 2, 2];
const TENSOR_SIZE = 8;

const context = await navigator.ml.createContext();
const builder = new MLGraphBuilder(context);

// MLOperandDescriptor 객체를 생성합니다.
const desc = {
  dataType: 'float32',
  shape: TENSOR_SHAPE
};

// constant1은 값이 0.5인 상수 MLOperand입니다.
const constantBuffer1 = new Float32Array(TENSOR_SIZE).fill(0.5);
const constant1 = builder.constant(desc, constantBuffer1);

// input1은 입력 MLOperand 중 하나입니다. 그 값은
// 실행 전에 설정됩니다.
const input1 = builder.input('input1', desc);

// constant2는 값이 0.5인 또 다른 상수 MLOperand입니다.
const constantBuffer2 = new Float32Array(TENSOR_SIZE).fill(0.5);
const constant2 = builder.constant(desc, constantBuffer2);

// input2는 또 다른 입력 MLOperand입니다. 그 값은 실행 전에 설정됩니다.
const input2 = builder.input('input2', desc);

// intermediateOutput1은 첫 번째 Add 연산의 출력입니다.
const intermediateOutput1 = builder.add(constant1, input1);

// intermediateOutput2는 두 번째 Add 연산의 출력입니다.
const intermediateOutput2 = builder.add(constant2, input2);

// output은 Mul 연산의 출력 MLOperand입니다.
const output = builder.mul(intermediateOutput1, intermediateOutput2);

11. 연산자 에뮬레이션

이 절은 비규범적입니다.

다른 신경망 추론 API에 있는 연산은 WebNN에 있는 연산을 사용하여 에뮬레이션할 수 있는 경우가 많습니다.

11.1. squeeze

squeeze 연산은 입력에서 크기가 1인 지정된 모든 차원을 제거한 텐서를 반환합니다. 다음과 같이 reshape() 연산을 사용하여 일반적으로 구현할 수 있습니다:
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 연산은 지정된 위치에 크기가 1인 차원을 삽입한 새 텐서를 반환합니다. 다음과 같이 reshape() 연산을 사용하여 일반적으로 구현할 수 있습니다:
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 연산은 입력을 1차원 텐서로 reshape합니다. 다음과 같이 reshape() 연산을 사용하여 일반적으로 구현할 수 있습니다:
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 호환성

MLOperandDataType ArrayBufferView
float32 Float32Array
float16 Float16Array
int64 BigInt64Array
uint64 BigUint64Array
int32 Int32Array
uint32 Uint32Array
int8 Int8Array
uint8 Uint8Array

Float16Array 는 설계가 완료되었음을 나타내는 ECMA Stage 3에 있습니다. 네이티브 구현보다 먼저 이 유형을 활성화하려는 구현자는 Uint16Array를 통해 원시 비트를 전달하여 유형을 에뮬레이션할 수 있습니다. [이슈 webnn#373]

13. 감사의 글

이 명세는 Android Neural Networks API C API의 개념을 따릅니다.

사용 사례를 제공해 주신 Tomoyuki Shimizu, Ningxin Hu, Zhiqiang Yu 및 Belem Zhang께 감사드립니다.

API 명세에 기여해 주신 Nikhil Thorat, Daniel Smilkov, Ganesan Ramalingam, Rafael Cintron 및 Benjamin Poulain께 감사드립니다.

웹 아키텍처 적합성, 설계 일관성 및 개발자 사용성을 위해 이 명세를 검토해 주신 Sangwhan Moon과 W3C Technical Architecture Group에 감사드립니다.

알고리즘을 추가하고 이 명세를 탐색하는 경험을 즐겁게 만들어 주신 Zoltan Kis께 감사드립니다. 명세를 현대적인 편집 관례에 맞춰 주신 Joshua Bell께 감사드립니다. 세심한 검토와 의견을 제공해 주신 Ningxin Hu, Lisha Guo, Shiyi Zou, Mingming Xu, Junwei Fu, Bruce Dai 및 Bin Miao께 감사드립니다.

개인정보 보호 및 보안 검토와 피드백을 제공해 주신 W3C Privacy Interest Group에 감사드립니다.

보안 검토와 질문을 제공해 주신 Alex Gough와 Chrome Security 팀에 감사드립니다.

ONNX의 실용적인 지침과 학습 내용을 공유해 주신 Michal Karzynski께 감사드립니다.

피드백과 개인정보 보호 고려 사항을 제공해 주신 Kaustubha Govind와 Chrome 개인정보 보호 검토자들께 감사드립니다.

Chromium 구현 검토와 피드백을 제공해 주신 Jiewei Qian께 감사드립니다.

transformer 지원을 조사하고 권고안을 제공한 Dwayne Robinson, Joshua Lochner 및 Wanming Lin께 감사드립니다. 연산자 적합성과 web-platform-tests 구현을 검토해 주신 Dwayne과 Wanming께도 추가로 감사드립니다.

web-platform-tests가 명세와 함께 계속 발전하도록 지속적으로 기여해 주신 Feng Dai께 감사드립니다.

검토와 제안을 제공해 주신 Fuqiao Xue와 W3C Internationalization Activity에 감사드립니다.

14. 변경 사항

이 절은 비규범적입니다.

이 절은 이전 주요 발행 이후 이 명세에 적용된 변경 사항을 변경 클래스에 따라 문서화합니다.

Candidate Recommendation Snapshot 2024년 4월 11일2026년 1월 22일 사이의 상세 변경 사항

새 기능(클래스 4)

새 기능을 추가하지 않는 기타 변경 사항(클래스 3)

문서 해석에 기능적으로 영향을 주지 않는 변경 사항(클래스 2)

수평 검토(클래스 2클래스 3)

편집상 변경(클래스 2)

적합성

문서 규칙

적합성 요구 사항은 설명적 단언과 RFC 2119 용어의 조합으로 표현됩니다. 이 문서의 규범적 부분에 있는 “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY” 및 “OPTIONAL”이라는 핵심 단어는 RFC 2119에 설명된 대로 해석해야 합니다. 그러나 가독성을 위해 이 명세에서는 이러한 단어가 모두 대문자로 표시되지는 않습니다.

명시적으로 비규범적이라고 표시된 절, 예제 및 참고를 제외한 이 명세의 모든 텍스트는 규범적입니다. [RFC2119]

이 명세의 예제는 “예를 들어”라는 말로 소개되거나 다음과 같이 규범적 텍스트와 구분되어 class="example"로 표시됩니다:

정보 제공용 예제의 예입니다.

정보 제공용 참고는 “참고”라는 단어로 시작하며 다음과 같이 규범적 텍스트와 구분되어 class="note"로 표시됩니다:

참고: 이는 정보 제공용 참고입니다.

적합한 알고리즘

알고리즘의 일부로 명령형으로 표현된 요구 사항 (예: "선행 공백 문자를 모두 제거합니다" 또는 "false를 반환하고 이 단계를 중단합니다")은 알고리즘을 도입할 때 사용된 핵심 단어 ("must", "should", "may" 등)의 의미로 해석해야 합니다.

알고리즘이나 특정 단계로 표현된 적합성 요구 사항은 최종 결과가 동등한 한 어떤 방식으로든 구현할 수 있습니다. 특히 이 명세에 정의된 알고리즘은 이해하기 쉽도록 작성된 것이며 성능을 목적으로 하지 않습니다. 구현자는 최적화하는 것이 권장됩니다.

색인

이 명세에서 정의된 용어

참조에서 정의된 용어

참고문헌

규범적 참고문헌

[ECMASCRIPT]
ECMAScript 언어 명세. URL: https://tc39.es/ecma262/multipage/
[HTML]
Anne van Kesteren; et al. HTML 표준. 현행 표준. URL: https://html.spec.whatwg.org/multipage/
[INFRA]
Anne van Kesteren; Domenic Denicola. Infra 표준. 현행 표준. URL: https://infra.spec.whatwg.org/
[NUMPY-BROADCASTING-RULE]
SciPy 커뮤니티. NumPy의 일반 브로드캐스팅 규칙. 2019년 7월. URL: https://numpy.org/doc/stable/user/basics.broadcasting.html#general-broadcasting-rules
[PERMISSIONS-POLICY-1]
Ian Clelland. 권한 정책. 2026년 6월 18일. WD. URL: https://www.w3.org/TR/permissions-policy-1/
[RFC2119]
S. Bradner. 요구 수준을 나타내기 위해 RFC에서 사용하는 핵심 단어. 1997년 3월. 현행 최선 관행. URL: https://datatracker.ietf.org/doc/html/rfc2119
[WEBGPU]
Kai Ninomiya; Brandon Jones; Jim Blandy. WebGPU. 2026년 8월 12일. CRD. URL: https://www.w3.org/TR/webgpu/
[WEBIDL]
Edgar Chen; Timothy Gu. Web IDL 표준. 현행 표준. URL: https://webidl.spec.whatwg.org/

비규범적 참고문헌

[Batch-Normalization]
Sergey Ioffe; Christian Szegedy. 배치 정규화: 내부 공변량 이동을 줄여 심층 네트워크 학습 가속. 2015년 3월. URL: https://arxiv.org/abs/1502.03167
[ContextualLoss]
Roey Mechrez; Itamar Talmi; Lihi Zelnik-Manor. 정렬되지 않은 데이터를 사용한 이미지 변환을 위한 컨텍스트 손실. 2018년 7월. URL: https://arxiv.org/abs/1803.02077
[DeepLabv3+]
Liang-Chieh Chen; et al. 의미론적 이미지 분할을 위한 Atrous 분리 가능 컨볼루션을 사용한 인코더-디코더. 2018년 8월. URL: https://arxiv.org/abs/1802.02611
[DeepMoji]
Bjarke Felbo; et al. 감정, 정서 및 풍자를 감지하기 위한 모든 도메인의 표현을 학습하는 데 수백만 건의 이모지 출현 사용. 2017년 10월 . URL: https://arxiv.org/abs/1708.00524
[ELU]
Djork-Arné Clevert; Thomas Unterthiner; Sepp Hochreiter. 지수 선형 유닛(ELU)을 사용한 빠르고 정확한 심층 네트워크 학습. 2016년 2월. URL: https://arxiv.org/abs/1511.07289
[Error-Function]
Larry C. Andrews. 공학자를 위한 수학의 특수 함수. 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: 얼굴 인식 및 클러스터링을 위한 통합 임베딩. 2015년 6월. URL: https://arxiv.org/abs/1503.03832
[FAN]
Adrian Bulat; Georgios Tzimiropoulos. 2D 및 3D 얼굴 정렬 문제 해결까지 얼마나 남았는가? (그리고 230,000개의 3D 얼굴 랜드마크 데이터셋). 2017년 9월. URL: https://arxiv.org/abs/1703.07332
[GNMT]
Minh-Thang Luong; Eugene Brevdo; Rui Zhao. 신경망 기계 번역(seq2seq) 튜토리얼. 2017년 5월. URL: https://github.com/tensorflow/nmt
[GPT2]
Alec Radford; et al. 언어 모델은 비지도 멀티태스크 학습자입니다. 2019년 2월. URL: https://d4mucfpksywv.cloudfront.net/better-language-models/language-models.pdf
[GRU]
Kyunghyun Cho; et al. 통계적 기계 번역을 위한 RNN 인코더-디코더를 사용한 구문 표현 학습. 2014년 9월. URL: https://arxiv.org/pdf/1406.1078.pdf
[HR-TIME-3]
Yoav Weiss. 고해상도 시간. 2026년 3월 24일. WD. URL: https://www.w3.org/TR/hr-time-3/
[IEEE-754-2019]
부동 소수점 산술을 위한 IEEE 표준. 2019년 7월 22일. URL: https://ieeexplore.ieee.org/document/8766229
[IM2TXT]
Oriol Vinyals; et al. Show and Tell: 2015 MSCOCO 이미지 캡셔닝 챌린지에서 얻은 교훈. 2016년 9월. URL: https://arxiv.org/abs/1609.06647
[Instance-Normalization]
Dmitry Ulyanov; Andrea Vedaldi; Victor Lempitsky. 인스턴스 정규화: 빠른 스타일화를 위해 빠졌던 요소. 2016년 7월. URL: https://arxiv.org/abs/1607.08022
[Layer-Normalization]
Jimmy Lei Ba; Jamie Ryan Kiros; Geoffrey E. Hinton. 레이어 정규화. 2016년 7월. URL: https://arxiv.org/abs/1607.06450
[LDM]
Robin Rombach; et al. 잠재 확산 모델을 사용한 고해상도 이미지 합성. 2022년 4월. URL: https://arxiv.org/abs/2112.10752
[LeakyReLU]
Andrew L. Maas; Awni Y. Hannun; Andrew Y. Ng. 정류기 비선형성이 신경망 음향 모델을 개선합니다. 2013년 6월. URL: https://pdfs.semanticscholar.org/367f/2c63a6f6a10b3b64b8729d601e69337ee3cc.pdf
[LLAMA-2-7B]
Hugo Touvron; et al. Llama 2: 개방형 기반 및 미세 조정된 대화 모델. 2023년 7월. URL: https://arxiv.org/abs/2307.09288
[LSTM]
Sepp Hochreiter; Jürgen Schmidhuber. 장단기 기억. 1997년 11월. URL: https://doi.org/10.1162/neco.1997.9.8.1735
[m2m100_418M]
Angela Fan; et al. 영어 중심을 넘어선 다국어 기계 번역. 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. MobileNetV3 검색. 2019년 11월. URL: https://arxiv.org/pdf/1905.02244
[MODELS]
Web용 머신러닝 커뮤니티 그룹. 첫 번째 웨이브 모델. 2020. URL: https://github.com/webmachinelearning/webnn/blob/master/op_compatibility/first_wave_models.md
[NumPy]
SciPy 커뮤니티. NumPy. 2019년 7월. URL: https://numpy.org/doc/stable/
[OpenNMT]
Guillaume Klein; et al. OpenNMT: 신경망 기계 번역을 위한 오픈 소스 툴킷. 2017년 3월. URL: https://arxiv.org/abs/1701.02810
[PairedCycleGAN]
Huiwen Chang; et al. PairedCycleGAN: 메이크업 적용 및 제거를 위한 비대칭 스타일 전송. 2018년 6월. URL: http://openaccess.thecvf.com/content_cvpr_2018/html/Chang_PairedCycleGAN_Asymmetric_Style_CVPR_2018_paper.html
[PoseNet]
Dan Oved. 브라우저에서 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. 보안 컨텍스트. 2023년 11월 10일. CRD. URL: https://www.w3.org/TR/secure-contexts/
[Prefix-sum]
Wikipedia 커뮤니티. 접두사 합. 2025년 1월. URL: https://en.wikipedia.org/wiki/Prefix_sum
[RNNoise]
Jean-Marc Valin. 오디오 잡음 감소를 위한 순환 신경망. 2017년 9월. URL: https://github.com/xiph/rnnoise
[SECURITY-PRIVACY-QUESTIONNAIRE]
Theresa O'Connor; Peter Snyder; Simone Onofri. 자체 검토 설문지: 보안 및 개인정보 보호. 2025년 4월 18일. NOTE. URL: https://www.w3.org/TR/security-privacy-questionnaire/
[SegAny]
Alexander Kirillov; et al. 무엇이든 분할하기. 2023년 4월. URL: https://arxiv.org/abs/2304.02643
[SRGAN]
Christian Ledig; et al. 생성적 적대 신경망을 사용한 사실적인 단일 이미지 초해상도. 2017년 5월. URL: https://arxiv.org/abs/1609.04802
[SSD]
Wei Liu; et al. SSD: 단일 샷 MultiBox 검출기. 2016년 12월. URL: https://arxiv.org/abs/1512.02325
[T5-SMALL]
Colin Raffel; et al. 통합 텍스트-텍스트 Transformer를 사용한 전이 학습의 한계 탐구. 2020년 6월. URL: https://jmlr.org/papers/volume21/20-074/20-074.pdf
[UTR36]
Mark Davis; Michel Suignard. Unicode 보안 고려 사항. 2014년 9월 19일. Unicode 기술 보고서 #36. URL: https://www.unicode.org/reports/tr36/tr36-15.html
[UTS55]
Robin Leroy; Mark Davis. Unicode 소스 코드 처리. 2024년 1월 29일. Unicode 기술 표준 #55. URL: https://www.unicode.org/reports/tr55/tr55-5.html
[Video-Summarization-with-LSTM]
Ke Zhang; et al. 장단기 기억을 사용한 비디오 요약. 2016년 10월. URL: http://www-scf.usc.edu/~zhan355/ke_eccv2016.pdf
[WASM-JS-API-2]
. Ms2ger; Ryan Hunt. WebAssembly JavaScript 인터페이스. 2026년 8월 12일. CRD. URL: https://www.w3.org/TR/wasm-js-api-2/
[WCAG]
Michael Cooper; et al. 웹 콘텐츠 접근성 지침 (WCAG) 2.2. 2024년 12월 12일. REC. URL: https://www.w3.org/TR/WCAG22/
[WEBMACHINELEARNING-ETHICS]
Anssi Kostiainen. 웹 머신러닝을 위한 윤리 원칙. 2024년 1월 8일. DNOTE. URL: https://www.w3.org/TR/webmachinelearning-ethics/
[Whisper]
Alec Radford; et al. 대규모 약지도 학습을 통한 강건한 음성 인식. 2022년 12월. URL: https://arxiv.org/abs/2212.04356
[YOLO]
Joseph Redmon; et al. You Only Look Once: 통합된 실시간 객체 검출. 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> createExportableTensor(
    MLTensorDescriptor descriptor, GPUDevice gpuDevice);
  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);

  GPUBuffer exportToGPU(MLTensor tensor);

  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;
};

이슈 색인

구현자를 위한 지침으로 범위를 벗어난 접근에 취약한 연산을 문서화합니다.
렌더러를 실행하는 프로세스 간에 CPU가 공유되는 현재 상태를 고려하여 사이드 채널 공격의 실현 가능성을 조사합니다.
힌팅은 우려 사항을 부분적으로 완화합니다. 추가 완화 방안을 조사합니다.
MLGraph.devices API 확장은 그래프가 완전히 구성되고 컴파일된 후 실행을 위해 실제로 선택된 장치를 노출하도록 제안되었습니다. 이 API 확장의 개인정보 보호 영향은 조사 중입니다. [이슈 #836]
dispatch() 중 오류를 보고하는 메커니즘 추가를 고려합니다. [이슈 #778]
이 타임라인을 더 엄밀하게 정의합니다. [이슈 #529]
그래프 실행 중 오류를 보고하는 메커니즘을 추가합니다. [이슈 #778]
텐서에 쓰는 동안 오류를 보고하는 메커니즘을 추가합니다. [이슈 #778]
크기가 0인 차원을 지원해야 합니까? [이슈 #391]
피연산자 차원의 최대 개수는 정의되어 있지 않지만, 네이티브 ML API에는 일반적으로 지원되는 최대 크기가 있습니다. [이슈 #456]
bigint숫자 유형의 유니온 지원은 [WEBIDL]에서 새로 도입되었으며 구현 지원도 제한적입니다. 프로토타입 구현에서는 이 접근 방식에 대한 피드백을 제공하는 것이 권장됩니다. [whatwg/webidl 이슈 #1388]
크기가 0인 차원이 허용되면 이 단계들을 수정합니다. [이슈 #391]
크기가 0인 차원이 허용되면 위 단계를 수정합니다. [이슈 #391]
크기가 0인 차원이 허용되면 이 단계들을 수정합니다. [이슈 #391]
[INFRA]에 정의가 제공되면 이를 제거합니다. [whatwg/infra 이슈 #664]