1. 引言
Web 神经网络 API 定义了一个适合 Web 的、与硬件无关的抽象层,它利用 操作系统和底层硬件平台的机器学习能力,而不绑定到 特定平台的能力。该抽象层满足关键机器学习 JavaScript 框架的需求,也允许熟悉 ML 领域的 Web 开发者在 不借助库的情况下编写自定义代码。
有关图示化介绍,请参见解释文档。
2. 用 例
2.1. 应用程序用例
本节说明用于神经网络 推理硬件加速的应用程序级用例。这些用例中的所有应用程序都可以 构建在预训练的深度神经网络(DNN)[models]之上。
注: 请注意,此处描述的某些用例 就其本质而言会侵犯隐私。计划将此 API 用于 此类用例的开发者应当确保 API 的使用是为了让用户受益, 用于用户理解并同意的目的。他们应当应用 Web 机器学习伦理原则 [webmachinelearning-ethics],并实现 适当的隐私风险缓解措施,例如透明度、数据最小化和用户控制。
注: § 3 可访问性 考虑提供了如何改进这些用例可访问性的指导。
2.1.1. 人体检测
用户打开一个基于 Web 的视频会议应用程序,但她暂时 离开了房间。该应用程序通过使用对象检测(例如,使用 [SSD] 或 [YOLO] 等使用单个 DNN 的对象检测方法), 来观察她是否在 PC 前面,以检测摄像头 输入帧中包含人的区域。
当她回来时,应用程序会自动检测到她,并通知 其他在线用户她现在处于活动状态。
2.1.2. 语义分割
用户在办公桌前通过基于 Web 的视频会议应用程序加入电话会议, 因为她的办公室没有可用的会议室。在 电话会议期间,她不希望自己的房间以及背景中的人 可见。为了保护其他人和周围环境的隐私,该 应用程序运行机器学习模型,例如 [DeepLabv3+]、 [MaskR-CNN] 或 [SegAny],以在语义上 将图像拆分为分段,并用另一张图片替换 表示其他人和背景的分段。
2.1.3. 骨架检测
基于 Web 的视频会议应用程序通过运行一种支持实时人体姿态 估计的机器学习模型来跟踪用户骨架的姿态,例如 [PoseNet],以识别她的 手势和肢体语言。当 她举手时,她的麦克风会自动取消静音,她可以开始在 电话会议中发言。
2.1.4. 人脸识别
会议室里有多人,他们使用基于 Web 的视频会议应用程序 加入在线会议。应用程序使用对象检测(例如,使用 [SSD] 等对象检测方法)来检测 参与者的人脸,并通过运行一种机器学习模型,例如 [FaceNet], 来检查每张人脸是否曾出现在 上一次会议中,该模型会验证两张人脸是否相同。
2.1.5. 面部标志点检测
用户想在在线眼镜商店中寻找一副适合她的漂亮眼镜。 该在线商店提供一个基于 Web 的试戴模拟器,它运行 Face Alignment Network 等机器学习模型 [FAN] 来检测眼睛、鼻子、嘴巴等 面部标志点。当她选择一副眼镜时,模拟器会 将所选眼镜正确渲染到她面部图像中检测到的眼睛位置。
2.1.6. 风格迁移
用户在在线商店中寻找化妆品,并想知道哪种颜色可能 适合她的脸。该在线商店展示化妆品的面部妆容示例图像, 并提供一个妆容模拟器,该模拟器运行类似 [ContextualLoss] 或 [PairedCycleGAN] 的机器学习模型,将 示例妆容图像的妆容风格迁移到她的面部图像。她可以通过模拟器 查看所选妆容在她脸上的效果。
2.1.7. 超分辨率
基于 Web 的视频会议应用程序正在从其对等方接收视频流,但 视频分辨率由于网络拥塞而降低。为了防止 感知视频质量下降,应用程序运行一种用于超分辨率的机器 学习模型,例如 [SRGAN], 来生成 更高分辨率的视频帧。
2.1.8. 图像说明生成
为了提升可访问性,基于 Web 的演示应用程序通过运行 [im2txt] 等机器学习模型来提供自动图像说明生成,该模型会预测演示幻灯片的说明性词语。
2.1.9. 文本到图像
图像是现代 Web 体验的核心组成部分。以保护隐私的方式 基于文本输入生成图像的能力,使 Web 应用程序和内容能够进行视觉 个性化和适配。例如,Web 应用程序可以将网页上的自然语言描述, 或用户在文本提示中提供的描述作为输入,以生成 与文本描述匹配的图像。由潜在扩散模型架构 [LDM] 支持的这种文本到图像用例 构成了其他 文本到图像用例的基础。例如,修复(inpainting)可以使用新生成的内容 有选择地修改网页上现有图像的一部分, 或者相反,扩展(outpainting)可以将原始图像扩展到其 原始尺寸之外,并用生成内容填充空白区域。
2.1.10. 机器翻译
来自不同国家的多人通过基于 Web 的实时 文本聊天应用程序交谈。该应用程序使用 [GNMT] 或 [OpenNMT] 等机器学习模型来翻译他们的 对话,该模型会将 每段文本翻译成不同语言。
2.1.11. 情感分析
用户正在通过基于 Web 的实时文本聊天应用程序与朋友交谈, 由于她看不到朋友的脸,所以想知道朋友的感受。 该应用程序通过使用 [DeepMoji] 等机器学习模型来分析朋友的情绪, 该模型从输入文本中推断情绪,并显示 代表估计情绪的表情符号。
2.1.12. 视频摘要
基于 Web 的视频会议应用程序记录接收到的视频流,并且 需要减少要存储的已记录视频数据。该应用程序使用用于 视频摘要的机器学习模型,例如 [Video-Summarization-with-LSTM],来生成 已记录视频的短版本。
2.1.13. 噪声抑制
基于 Web 的视频会议应用程序记录接收到的音频流,但 背景噪声通常无处不在。该应用程序利用实时 噪声抑制,使用 [RNNoise] 等循环神经网络来 抑制婴儿哭声或狗叫声等背景动态噪声,以改善 视频会议中的音频体验。
2.1.14. 语音识别
语音识别,也称为语音转文本,能够识别并 将口语翻译为文本。语音识别的示例应用包括 转录、自动翻译、多模态交互、 实时字幕和虚拟助手。语音识别改善了 听觉内容的可访问性,并使得能够以保护隐私的方式 以文本形式与此类内容交互。常见用例示例包括 使用实时字幕观看视频或参加在线会议。 [Whisper] 等模型在 准确性和鲁棒性方面接近人类,并且非常适合改进此类用例的可访问性。
2.1.15. 文本生成
大型语言模型(LLM)支持各种文本生成用例,这些模型 能够执行需要预测文本序列中下一个项目的一般能力的任务。 这类模型可以翻译文本、基于文本输入回答 问题、总结较大的文本主体,或基于文本输入生成 文本输出。与基于 RNN、CNN 或 LSTM 架构的 较旧模型相比,LLM 能够提供更好的性能,并进一步提升 本节讨论的许多其他用例的性能。 LLM 的示例包括 [t5-small]、 [m2m100_418M]、[gpt2] 和 [llama-2-7b]。
2.1.16. 检测伪造视频
用户在 Web 上接触到由“deepfake”生成的逼真伪造视频。 该伪造视频可以将发言者的脸替换为总统的脸,以煽动 用户的政治情绪或操纵用户观点。[FaceForensics++] 等深度伪造检测 应用程序会分析视频,并保护用户免受 伪造视频或图像的侵害。当她在 Web 上观看伪造视频时, 检测应用程序会实时提醒她该视频存在欺诈。
2.2. 框架用例
本节收集了用于神经网络推理硬件加速的专用低级 API 的框架级用例。预计机器学习 框架将成为 Web 神经网络 API(WebNN API)的关键使用者,并且通过 WebNN API 暴露的低级细节会 从典型 Web 开发者那里抽象出来。不过,也预计对 机器学习具有特定兴趣和能力的 Web 开发者会希望直接与 WebNN API 交互,而不是使用更高级别的 ML 框架。
2.2.1. 自定义层
Web 应用程序开发者想在 WebNN API 上运行 DNN 模型。但是, 她发现某些激活函数,例如 [LeakyReLU]、[ELU] 等,并未包含在 WebNN API 中。为了解决这个问题,她在 WebNN API 之上 构造了这些附加激活函数的自定义层。 请注意,自定义层的范围除了激活以外,也可能包括卷积、归一化 等。
2.2.2. 网络拼接
Web 应用程序使用一个 DNN 模型,并且该模型的上层卷积 层和下层全连接层的模型数据存储在不同文件中,因为 全连接层的模型数据会由于服务器端的微调而定期更新。
因此,应用程序首先下载这两个部分模型文件,并将它们 拼接为一个单一模型。当模型更新时, 应用程序下载模型中经过微调的部分,并仅用它替换 全连接层。
2.2.3. 性能适配
Web 应用程序开发者担心她的 DNN 模型在 移动设备上的性能。她已确认,在没有 GPU 加速的移动设备上 它可能运行得太慢。为了解决这个问题,她的 Web 应用程序 参考 WebNN API 来确认加速是否可用,从而 使应用程序能够针对没有加速的设备显示警告。
几周后,她开发了一个甚至可以在 CPU 上运行的小型 DNN 模型。为了适配 CPU 执行,她修改了应用程序, 使应用程序在仅有 CPU 的设备情况下加载该小型模型。
2.2.4. 运算级执行
JavaScript ML 框架负责加载、解释和执行 ML 模型。在模型 执行阶段,框架遍历模型的运算,并在 CPU、GPU 或 ML 加速器等硬件设备上执行每个运算。为避免跨设备进行不必要的数据复制, 框架会选择同一个设备来执行这些运算。对于计算密集型运算,例如 二维卷积或矩阵乘法,框架会使用 WebNN API 在所选设备上利用可用的 ML 专用 加速来执行它。
2.2.5. 与实时视频处理集成
通过使用实时视频处理,可以增强基于 WebRTC 的视频会议用户体验。例如, 使用 § 2.1.2 语义 分割模型实现的背景模糊,会模糊用户实时摄像头画面中的背景。为了满足此用例的性能 要求,WebNN API 与组成媒体流水线的其他 Web API 的原语集成, 以允许基于 WebNN API 对实时视频流进行转换。
3. 可访问性考虑
本节向 Web 作者提供指导,说明如何改进由神经网络推理 硬件加速支持的 § 2.1 应用程序用例的可访问性。 此指导超出了本 规范中概述的具体用例,鼓励 Web 作者查阅 [wcag] 以获取进一步的可访问性指导, 并查阅 § 6 伦理考虑以了解伦理 原则背景下的数字可访问性。
§ 2.1.8 图像说明生成可以通过确保说明暴露给 屏幕阅读器和其他辅助技术(AT)用户来改进。鼓励 Web 作者确保 生成的图像说明与其相应图像在语义上关联,无论是通过标准的 alt 属性,还是通过其他方式;具体方式可能取决于描述是在初始页面加载时更新, 还是之后作为用户操作的结果更新。
§ 2.1.11 情感分析可能会错误标记并因此错误分类用户, 从而导致歧视性体验。鼓励 Web 作者公开置信度分数,并为用户提供 关闭该特性的选项。
§ 2.1.13 噪声抑制在使用激进过滤器时可能会抹除 构音障碍用户的语音,导致字幕和识别失败。鼓励 Web 作者提供 绕过或灵敏度控制,并且在实时字幕处于活动状态时不要硬性绑定噪声抑制。
§ 2.2.5 与实时视频处理集成中 由背景模糊驱动的分割有助于消除干扰,但可能会增加过多延迟,从而破坏 唇读和实时字幕。鼓励 Web 作者提供面向用户的、可由键盘 和屏幕阅读器操作的“背景模糊开/关”控制,并将其显示在其他可访问性/媒体 设置旁边。
§ 7.2 设备选择允许 Web 作者指示 对执行速度和功耗的偏好。鼓励实现者允许用户在浏览器 UI 中 覆盖 Web 作者提示,以确保使用低端或电池敏感设备的人能够 保持字幕和其他关键可访问性特性的响应性,尤其是在便携式 AAC 或眼动 设置上。
4. 安全性考虑
本规范定义了一个用于神经网络推理硬件加速的低级 API。此 API 被 视为强大特性 [POWERFUL-FEATURES],因为它授予对用户计算机的低级访问。为了 满足强大特性在认证和机密性方面的期望,并防止中间人 攻击,本规范定义的所有接口仅在安全上下文中可用。默认情况下,此 API 在所有跨源框架中通过 § 7.5 权限策略集成被禁用。这会防止 第三方内容使用此 API,除非嵌入页面显式设置授予 权限的策略。
此 API 允许从 WebGPU 规范定义的
GPUDevice
创建
MLContext。有关此上下文安全特性的更多信息,请参见
WebGPU 安全性考虑。
此 API 在 GPU、CPU 和专用 ML 加速器硬件之间提供抽象。使用 GPU 时,与 WebGPU 类似的 拒绝服务考虑适用。使用 CPU 或专用 ML 加速器时,潜在资源争用的类型 不同,缓解措施将取决于实现和配置。实现应使用 平台提供的任何机制,防止站点使用不公平数量的系统 资源。这些计算单元是共享资源,使用任何计算 API 都会影响满载 系统的整体性能。
一旦图被完全构造并编译,图中每个运算的输入形状 就会被推断并最终确定。边界检查发生在调用执行 图并处理实际数据的计算方法时。在此阶段之前,没有实际数据绑定到已编译图。 实现负责确保针对当时已经推断出的数据形状 进行适当的边界检查。
实现必须防御基于被视为常量的数据变化的控制流攻击。 例如,底层平台中的优化可能会假设权重在整个 计算过程中保持不变。如果 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. 新运算指南
本节为非规范性内容。
为了确保本规范中定义的运算以可安全实现的方式成形, 本节包含关于预期如何定义运算以减少潜在 实现问题的指南。这些指南预计会随着时间推移而演进,以符合行业最佳 实践:
-
优先选择简单的参数
-
不要为复杂数据格式使用解析器
-
如果一个运算可以分解为低级原语:
-
添加一条信息性仿真路径
-
优先使用原语而不是新的高级运算,但要考虑性能后果
-
-
对运算输入和属性遵循一致风格
-
为池化和归约等运算族共享 API 形状和选项
-
尽可能将失败情形形式化为测试用例
-
拿不准时就省略:保持 API 表面尽可能小以满足用例, 但不要更小
-
尽量让 API 不包含可能妨碍未来演进的实现细节,不要 过度规定
-
快速失败:Web 开发者越早获知问题越好
一般而言,在添加新特性时,始终应考虑由 技术架构组和隐私兴趣组在 [security-privacy-questionnaire] 中记录的安全性和隐私影响。
5. 隐私考虑
与基于云的推理替代方案相比,此 API 通过将敏感用户 数据保留在浏览器沙箱内,提供了隐私改进。图像、音频、视频流以及其他个人 信息等输入数据永远不会离开用户设备,从而消除与将数据传输到远程 服务器和第三方数据处理相关的风险。
然而,作为一个与硬件加速能力密切交互的强大本地计算 API, WebNN API 必须在性能优化与隐私保护之间取得平衡。该 API 包含多项 隐私保护措施,用于缓解指纹识别,同时仍能支持有效的机器 学习推理能力。
5.1. 指纹识别
按照设计,此 API 旨在暴露为以最佳性能和结果可靠性解决已识别的 § 2 用例所必需的最少信息。首先,该 API 通过标准化来缓解指纹识别:定义跨不同 平台 API 的一致行为,并最小化关于符合要求实现之间底层硬件差异的信息泄露。 这是通过以下方式实现的:
-
§ 7.3 运算符 与硬件无关,并且按照数据 最小化原则,最小化底层平台低级细节的暴露。
-
§ 8.2.1 MLContextOptions API 允许 Web 开发者 指示对执行速度和功耗的偏好,但不暴露实际选择用于执行的设备, 也不允许 Web 开发者枚举或选择特定设备。 这种提示机制不会增加熵。
-
§ 8.3.7 opSupportLimits() API 允许 Web 开发者使用显式查询 API 查询对特定运算符的支持,而不是通过侧信道推断 此信息。此 API 可能有助于指纹识别,但可以通过适当地使用桶限制通过此 API 暴露的可区分配置数量来降低其 熵。
-
跨不同后端实现的一致错误处理。
整体设计确保实现能够在不同平台上保持一致接口, 同时提供必要功能。通过抽象平台特定细节,该 API 可以提供 保护隐私的可预测行为,无论底层加速由 CPU、GPU 还是专用 ML 硬件提供。
注: MLContextOptions
正在积极开发中,其设计预计会根据进一步实现
经验和更广泛 Web 社区的新用例而发生变化。
已提议添加 MLGraph.devices API 扩展,用于在图完全构造并编译后暴露实际选择用于
执行的设备。此 API 扩展的隐私影响仍在
调查中。[Issue #836]
5.2. 执行时间分析
运算的计时特性可以提供一些关于底层硬件 性能的间接信息,这是任何计算 API 固有的特性。在某些情况下,执行时间分析可以 间接揭示底层平台的神经网络硬件加速 能力相对于另一个底层平台的性能。另请参见 § 4 安全性 考虑中关于计时攻击的进一步讨论。
注: 该小组欢迎进一步输入有关拟议的 执行时间分析指纹识别向量和缓解措施的意见。
5.3. WebGPU 比较
与 WebGPU 不同,此 API 本身不支持自定义着色器编写;因此不会容易受到
依赖着色器缓存或其他持久数据的计时攻击。该 API 建立在浏览器或底层 OS 的
既有着色器和更低级原语之上。与
GPUDevice
交互的 Web 开发者应当了解 WebGPU
编译缓存考虑。
WebGPU API 将机器特定工件识别为 隐私考虑。同样,WebNN API 的计算单元调度在某些情况下 可能引入指纹。不过,与 WebGPU 类似,这类指纹在每个供应商的大多数或所有 设备上是相同的,从而缓解了该问题。此外,可以使用软件实现来 进一步消除此类工件。
一般而言,此 API 的实现者应在适用时将 WebGPU 隐私考虑应用到 其实现中。
6. 伦理考虑
工作组已开始记录与在 Web 上使用机器学习相关的伦理问题, 以帮助识别其规范性规范应考虑哪些缓解措施。工作组 发布并维护一份 Web 机器学习伦理原则文档 [webmachinelearning-ethics],该文档通过专门的 GitHub 仓库向更广泛社区开放 贡献。
7. 编程模型
7.1. 概述
神经网络的核心是由数学运算组成的 计算图。 这些运算是计算机视觉、自然语言处理和机器人技术中 现代机器学习技术的构建块。 WebNN API 是一项用于构造、编译和执行神经网络计算 图的规范。
MLGraph
接口表示一个不可变的已编译计算图(也就是模型)。
MLGraphBuilder
接口充当构建器(工厂),用于构造一个计算图(其 图),
随后将其编译以创建一个 MLGraph。
在 WebNN 中,计算图由作用于数据并作为
图节点的 运算符组成。MLOperand 是
计算图内流动数据的一种表示,并且是图的边。MLOperand
包括用于推理的计算图的 输入值、用于推理的 常量(包括经过训练的权重)、
推理期间计算出的中间值(通常称为激活),以及推理的输出
值。运算符的 输入是一个或多个 MLOperand。运算符的 输出是一个或
多个 MLOperand。运算符具有运算符特定
参数,用于控制其行为,其中可以包括零个或多个 激活函数。
MLGraphBuilder
接口的一个关键部分是诸如 gemm()
和 relu()
之类的方法,它们创建一个运算符,
该运算符表示计算运行时要对输入数据执行的实际操作,并返回一个新的
MLOperand
来持有该运算符。创建 MLOperand
的方法会将任何输入和激活连接到该
运算符。每次方法调用都会返回一个不同的新值,而不会改变任何其他 MLOperand 的值。
运算符具有一个 标签,它是一个字符串,可包含在诸如异常消息等诊断信息中。创建运算符时,其标签会以实现定义的方式初始化,并且可以包括传入的 label。
考虑添加一种
在 dispatch()
期间报告错误的机制。
[Issue #778]
在推理时,每个 MLOperand 都会
绑定到一个张量(实际数据),它们本质上是多维数组。张量的表示
取决于实现,但通常包括存储在某个缓冲区
(内存)中的数组数据,以及描述数组数据的一些元数据(例如其形状)。
计算图中的运算具有函数式语义。这允许实现 在多个张量之间潜在地共享数组数据。例如,诸如 reshape 或 slice 之类的运算 的实现可以返回其输入张量的一个视图, 该视图与输入张量共享同一个缓冲区。(在 reshape 的情况下, 整个数据都会被共享,而在 slice 的情况下,输入数据的一部分被共享。) 实现可以如上所述对中间值使用视图。
在执行之前,用于计算一个或多个指定输出的计算图需要被 转换、编译和优化。编译步骤的关键目的在于启用跨越 两个或多个运算的优化,例如运算或循环融合。用户代理也可以在图转换期间执行这些 优化。
MLGraphBuilder.build()
方法在后台编译图,而不会阻塞调用线程,并返回一个 Promise,
该 Promise 会兑现为一个 MLGraph。每个 MLGraphBuilder
最多只能构建一个 MLGraph。
MLGraph
底层实现将由与 MLGraphBuilder
的
运算符和 MLOperand
相对应的平台特定运算符和操作数表示组成,但
这些表示对脚本不可见,并且可能是脚本所构造图的组合或分解。
一旦 MLGraph
被构造出来,MLContext.dispatch()
方法就会异步执行该图:对于 CPU 执行,会在单独 worker
线程中的并行时间线上执行;对于 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 设备时不会发生这种情况。此外,图执行的结果
采用已知的布局格式。虽然执行可能会针对图中间结果中的原生内存访问
模式进行优化,但图中最后一个运算的输出必须
在图结束时将内容转换回已知布局格式,以维持从调用者角度看
预期的行为。
MLContext
通过
MLContextOptions
创建时,用户代理会考虑这些选项来选择并创建底层执行设备。
根据底层平台,用户代理可以选择 CPU、NPU 和 GPU 设备的不同 组合。
有关此设计的历史和理由,请参见设备 选择解释文档。
7.3. 运算符
本节为非规范性内容。
WebNN API 定义了一组知名 CNN 和 RNN、transformer 以及生成式 模型所需的运算符,这些模型用于处理关键 § 2.1 应用程序用例。每个 运算符的详细信息在本规范的规范性章节中按运算符 名称的字母顺序定义。这些运算符根据其功能被分组到以下 非规范性表格中的类别,以给出 API 表面的功能概览。
注: 某些运算符属于多个类别。例如,
clamp()
既是数学函数,也用作激活。
7.4. 任务源
ML 任务源是一个
任务源,用于与 MLGraph 的异步编译和执行以及
MLContext
的创建相关的所有任务。
7.5. 权限策略集成
本规范定义了一个由字符串
"webnn"
标识的策略控制特性。
其默认允许列表为 'self'。
8. API
8.1. navigator.ml 接口
ML 对象可通过
Window
和 WorkerGlobalScope
上下文中的 Navigator
和 WorkerNavigator
接口分别获得,并通过 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
正在积极开发中,其设计预计会根据进一步的实现
经验和更广泛 Web 社区的新用例而发生变化。工作组正在考虑额外的 API
控制,以允许定义回退设备、按偏好顺序排列的多个设备,或
排除某个特定设备。正在讨论的其他考虑包括错误处理、最终
回退和量化运算符。欢迎 Web
开发者、库作者、OS 和硬件厂商以及其他利益相关者通过 GitHub
对这些设计考虑提供反馈。关于指纹识别
考虑的更多讨论,见 § 5 隐私考虑。
powerPreference 选项是一个 MLPowerPreference,并指示应用程序
与功耗相关的偏好。它是以下值之一:
- "
default" - 让用户代理选择最合适的行为。
- "
high-performance" - 优先考虑执行速度而不是功耗。
- "
low-power" - 优先考虑功耗,而不是执行速度等其他考虑。
accelerated 选项指示应用程序
与大规模并行加速相关的偏好。此选项的优先级低于 powerPreference。
当设置为 true(默认)时,底层平台将尝试使用可用的
大规模并行加速器,例如 GPU 或 NPU,同时也取决于 powerPreference。
当设置为 false 时,应用程序表示其偏好 CPU 推理。如果存在
相互矛盾的输入,例如 powerPreference
为 "high-performance"
且 accelerated
为 false,则实现将选择底层
平台中可用的最佳匹配(例如高性能 CPU 模式,或忽略 accelerated,
因为它的优先级低于 powerPreference)。
8.2.2. createContext()
-
options:一个MLContextOptions。 提供应用程序对上下文的偏好。 -
gpuDevice:一个GPUDevice。 要与上下文一起使用的特定设备。
MLContext。
要创建上下文,给定 realm realm 和 options(一个 GPUDevice
或 MLContextOptions),
运行以下步骤:
-
令 context 为 realm 中的一个新的
MLContext。 -
如果 options 是一个
GPUDevice对象,则:-
将 context.
[[contextType]]设置为 "webgpu"。 -
将 context.
[[powerPreference]]设置为"default"。 -
将 context.
[[accelerated]]设置为true。
-
-
否则:
-
将 context.
[[contextType]]设置为 "default"。 -
将 context.
[[lost]]设置为 realm 中的一个新的 promise。 -
如果 options["
powerPreference"] 存在,则将 context.[[powerPreference]]设置为 options["powerPreference"]。 -
否则,将 context.
[[powerPreference]]设置为"default"。 -
如果 options["
accelerated"] 存在,则将 context.[[accelerated]]设置为 options["accelerated"]。 -
否则,将 context.
[[accelerated]]设置为true。
-
-
如果用户代理无法支持 context.
[[contextType]], 则返回失败。 -
返回 context。
createContext(options) 步骤为:
-
如果 global 的关联 Document 不允许使用 webnn 特性,则返回 realm 中一个新的 promise,并以 "
SecurityError"DOMException拒绝。 -
令 promise 为 realm 中一个新的 promise。
-
并行地运行以下步骤。
-
令 context 为给定 realm 和 options 时创建上下文的结果。如果其返回失败,则使用 global 排队一个 ML 任务,以用 "
NotSupportedError"DOMException拒绝 promise,并中止这些步骤。 -
使用 global 排队一个 ML 任务,以用 context 解决 promise。
-
-
返回 promise。
createContext(gpuDevice) 方法
步骤为:
-
如果 global 的关联 Document 不允许使用 webnn 特性,则返回 realm 中一个新的 promise,并以 "
SecurityError"DOMException拒绝。 -
令 promise 为 realm 中一个新的 promise。
-
并行地运行以下步骤。
-
令 context 为给定 realm 和 gpuDevice 时创建上下文的结果。如果其返回失败,则使用 global 排队一个 ML 任务,以用 "
NotSupportedError"DOMException拒绝 promise,并中止这些步骤。 -
使用 global 排队一个 ML 任务,以用 context 解决 promise。
-
-
返回 promise。
8.3. MLContext
接口
MLContext
接口表示神经网络计算工作负载和执行过程的全局状态。每个 MLContext 对象
都有关联的上下文类型和 MLPowerPreference。
typedef record <USVString ,MLTensor >;MLNamedTensors dictionary {MLContextLostInfo DOMString message ; }; [SecureContext ,Exposed =(Window ,Worker )]interface {MLContext undefined dispatch (MLGraph graph ,MLNamedTensors inputs ,MLNamedTensors outputs );Promise <MLTensor >createTensor (MLTensorDescriptor descriptor );Promise <MLTensor >createConstantTensor (MLOperandDescriptor descriptor ,AllowSharedBufferSource inputData );Promise <ArrayBuffer >readTensor (MLTensor tensor );Promise <undefined >readTensor (MLTensor tensor ,AllowSharedBufferSource outputData );undefined writeTensor (MLTensor tensor ,AllowSharedBufferSource inputData );MLOpSupportLimits ();opSupportLimits undefined destroy ();readonly attribute boolean accelerated ;readonly attribute Promise <MLContextLostInfo >lost ; };
MLContext
具有以下内部槽:
[[contextType]],类型为上下文类型。[[powerPreference]],类型为MLPowerPreference。[[accelerated]],类型为boolean。-
MLContext的 处理类型(CPU 或大规模并行处理)。 [[lost]],类型为Promise<MLContextLostInfo>。[[timeline]]-
一个与在
MLContext的计算单元上执行运算相关联的时间线。 这些运算包括在计算图上进行推理,以及修改[[data]]中的MLTensor。更 严格地定义此时间线。[Issue #529]
上下文类型是 管理资源并促进神经网络图编译和执行的执行上下文类型:
- "default"
- 按用户偏好选项创建的上下文。
- "webgpu"
- 从 WebGPU 设备创建的上下文。
要根据描述符验证缓冲区,给定 AllowSharedBufferSource
bufferSource 和 MLOperandDescriptor
descriptor,运行以下步骤:
-
根据 bufferSource 的类型进行切换:
ArrayBuffer-
返回 true。
SharedArrayBuffer-
返回 true。
ArrayBufferView-
-
如果 bufferSource 是一个
Uint8Array对象,则返回 true。 -
返回 false。
-
注: 无论 descriptor 的 dataType
如何,使用 Uint8Array
都作为表示 ArrayBuffer
切片的一种通用方式受支持,例如 WebAssembly.Memory
实例的一部分。鼓励开发者在编写 WebNN 代码时使用更具体的视图类型,以提高
可读性和可维护性。
要根据描述符验证张量,给定一个 MLNamedTensors
namedTensors 和 record<USVString,
MLOperandDescriptor>
namedDescriptors:
-
对于 namedTensors 的每个 name → tensor:
-
如果 tensor.
[[isConstant]]为 true,则返回 false。 -
如果 namedDescriptors[name] 不存在, 则返回 false。
-
如果 tensor.
[[descriptor]]不等于 namedDescriptors[name],则返回 false。
-
-
返回 true。
8.3.1.
dispatch()
在
MLContext 的
[[timeline]]
上调度已编译 MLGraph
的计算工作负载。
-
graph:一个MLGraph。 要执行的计算图。 -
inputs:一个MLNamedTensors。 计算图的输入。 -
outputs:一个MLNamedTensors。 计算图的输出。
返回:undefined。
注: dispatch() 本身不提供
图执行已完成的信号。相反,调用者可以 await 读回
输出张量的结果。见下方 § 8.3.1.1 示例。
dispatch(graph, inputs, outputs)
方法步骤为:
-
如果 graph.
[[context]]不是 this,则抛出一个TypeError。 -
如果 graph.
[[isDestroyed]]为 true,则抛出一个 "InvalidStateError"DOMException。 -
令 allTensors 为一个
MLTensor的列表, 由 inputs 的值经由 outputs 的值扩展组成。 -
对于 allTensors 的每个 tensor:
-
如果 tensor.
[[context]]不是 this,则抛出一个TypeError。 -
如果 tensor.
[[isDestroyed]]为 true,则抛出一个TypeError。
-
-
如果给定 inputs 和 graph.
[[inputDescriptors]]时根据描述符验证张量 返回 false,则抛出一个TypeError。 -
如果给定 outputs 和 graph.
[[outputDescriptors]]时根据描述符验证张量 返回 false,则抛出一个TypeError。 -
将以下步骤入队到 graph.
[[context]].[[timeline]]:-
-
向 graph.
[[implementation]]发出一个计算请求,给定 inputs 和 outputs。添加一种在 图执行期间报告错误的机制。[Issue #778]
-
-
当使用张量创建常量操作数时,在 build 完成后销毁该张量是合法的。 实现应确保已编译图保持有效,并且不受这种 销毁影响。
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. 创建可复用的输入和输出张量。 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( 'Output value:' , new Float32Array( result)); // [1, 1, 1, 1]
8.3.2.
createTensor()
创建一个与此 MLContext
关联的 MLTensor。
-
descriptor:一个MLTensorDescriptor。
createTensor(descriptor) 方法步骤
为:
-
如果 this 已丢失,则返回 realm 中一个新的 promise,并以 "
InvalidStateError"DOMException拒绝。 -
令 tensor 为给定 this 和 descriptor 时创建 MLTensor 的结果。
-
令 promise 为 realm 中一个新的 promise。
-
将以下步骤入队到 this.
[[timeline]]:-
-
给定 descriptor,创建 tensor.
[[data]]并将所有字节初始化为零。 -
如果失败,则使用 global 排队一个 ML 任务,以用 "
UnknownError"DOMException拒绝 promise, 并中止这些步骤。 -
否则,使用 global 排队一个 ML 任务,以用 tensor 解决 promise。
-
-
如果已中止,则使用 global 排队一个 ML 任务,以用 "
InvalidStateError"DOMException拒绝 promise。
-
-
返回 promise。
8.3.3. createConstantTensor()
创建一个与此 MLContext
关联的常量 MLTensor。
-
descriptor: 一个MLOperandDescriptor。 -
inputData: 一个AllowSharedBufferSource。 其字节将写入张量的缓冲区。
createConstantTensor(descriptor, inputData)
方法步骤为:
-
如果 this 已丢失,则返回 realm 中一个新的 promise,并以 "
InvalidStateError"DOMException拒绝。 -
如果给定 descriptor 时检查维度返回 false,则返回 realm 中一个新的 promise,并以
TypeError拒绝。 -
如果给定 inputData 和 descriptor 时根据描述符验证缓冲区返回 false,则返回 realm 中一个新的 promise,并以
TypeError拒绝。 -
令 bytes 为给定 inputData 时获取缓冲区源所持字节的副本的结果。
-
令 tensor 为给定 this 和 descriptor 时创建常量 MLTensor 的结果。
-
令 promise 为 realm 中一个新的 promise。
-
将以下步骤入队到 this.
[[timeline]]:-
-
给定 descriptor,创建 tensor.
[[data]]。 -
如果失败,则使用 global 排队一个 ML 任务,以用 "
UnknownError"DOMException拒绝 promise, 并中止这些步骤。 -
将 bytes 复制到 tensor.
[[data]]。 -
如果失败,则使用 global 排队一个 ML 任务,以用 "
UnknownError"DOMException拒绝 promise, 并中止这些步骤。 -
否则,使用 global 排队一个 ML 任务,以用 tensor 解决 promise。
-
-
如果已中止,则使用 global 排队一个 ML 任务,以用 "
InvalidStateError"DOMException拒绝 promise。
-
-
返回 promise。
8.3.4.
readTensor(tensor)
从 MLContext.[[timeline]]
将一个 MLTensor
的 [[data]]
读回到脚本。
-
tensor:一个MLTensor。 要读取的张量。
返回:Promise<ArrayBuffer>。
一个包含读取结果的缓冲区。
readTensor(tensor) 方法步骤为:
-
如果 tensor.
[[context]]不是 this,则返回 realm 中一个新的 promise,并以TypeError拒绝。 -
如果 tensor.
[[isDestroyed]]为 true,则返回 realm 中一个新的 promise,并以TypeError拒绝。 -
如果 tensor.
[[descriptor]].readable为 false,则返回 realm 中一个新的 promise,并以TypeError拒绝。 -
令 promise 为 realm 中一个新的 promise。
-
将 promise 追加到 tensor.
[[pendingPromises]]。 -
将以下步骤入队到 tensor.
[[context]].[[timeline]]:-
-
如果失败,则使用 global 排队一个 ML 任务并执行以下步骤:
-
从 tensor.
[[pendingPromises]]移除 promise。 -
以 "
UnknownError"DOMException拒绝 promise, 并中止这些步骤。
-
-
否则,使用 global 排队一个 ML 任务并执行以下步骤:
-
从 tensor.
[[pendingPromises]]移除 promise。 -
令 buffer 为在 realm 中从 bytes 创建一个
ArrayBuffer的结果。 -
用 buffer 解决 promise。
-
-
如果已中止,则使用 global 排队一个 ML 任务,以用 "
InvalidStateError"DOMException拒绝 promise。
-
-
返回 promise。
8.3.5.
readTensor(tensor, outputData)
readTensor(tensor)
的自带缓冲区变体。
将 [[data]]
从一个 MLTensor
读回到所提供的缓冲区中。
-
tensor:一个MLTensor。 要读取的张量。 -
outputData:一个AllowSharedBufferSource。 用于读入结果的缓冲区。
readTensor(tensor, outputData)
方法步骤为:
-
如果 tensor.
[[context]]不是 this,则返回 realm 中一个新的 promise,并以TypeError拒绝。 -
如果 tensor.
[[isDestroyed]]为 true,则返回 realm 中一个新的 promise,并以TypeError拒绝。 -
如果 tensor.
[[descriptor]].readable为 false,则返回 realm 中一个新的 promise,并以TypeError拒绝。 -
如果给定 outputData 和 tensor.
[[descriptor]]时根据描述符验证缓冲区 返回 false,则返回 realm 中一个新的 promise,并以TypeError拒绝。 -
令 promise 为 realm 中一个新的 promise。
-
将 promise 追加到 tensor.
[[pendingPromises]]。 -
将以下步骤入队到 tensor.
[[context]].[[timeline]]:-
-
如果失败,则使用 global 排队一个 ML 任务来运行这些步骤:
-
从 tensor.
[[pendingPromises]]移除 promise。 -
以 "
UnknownError"DOMException拒绝 promise, 并中止这些步骤。
-
-
否则,使用 global 排队一个 ML 任务来运行这些步骤:
-
从 tensor.
[[pendingPromises]]移除 promise。 -
如果 outputData 已分离,则以
TypeError拒绝 promise, 并中止这些步骤。注: 上面的根据描述符验证缓冲区 会在 outputData 已分离时失败, 但 outputData 可能在 该步骤与此步骤之间被分离。
-
将 bytes 写入 outputData。
-
-
如果已中止,则使用 global 排队一个 ML 任务,以用 "
InvalidStateError"DOMException拒绝 promise。
-
-
返回 promise。
8.3.6.
writeTensor()
在 MLContext 的
[[timeline]]
上将数据写入一个 MLTensor
的 [[data]]。
-
tensor:一个MLTensor。 要写入的张量。 -
inputData:一个AllowSharedBufferSource。 其字节将写入张量的缓冲区。
返回:undefined。
writeTensor(tensor, inputData)
方法步骤为:
-
如果 tensor.
[[context]]不是 this,则抛出一个TypeError。 -
如果 tensor.
[[isDestroyed]]为 true,则抛出一个TypeError。 -
如果 tensor.
[[descriptor]].writable为 false,则抛出一个TypeError。 -
如果给定 inputData 和 tensor.
[[descriptor]]时根据描述符验证缓冲区 返回 false,则抛出一个TypeError。 -
令 bytes 为给定 inputData 时获取缓冲区源所持字节的副本的结果。
-
断言:bytes 的长度等于 tensor.
[[descriptor]]的 字节长度。 -
将以下步骤入队到 tensor.
[[context]].[[timeline]]:-
-
将 bytes 复制到 tensor.
[[data]]。添加一种在写入张量时报告错误的机制。[Issue #778]
-
-
注: 与 dispatch() 类似,
writeTensor() 本身不提供写入已完成的信号。要检查张量的内容,
调用者可以 await 读回张量的结果。
8.3.7.
opSupportLimits()
opSupportLimits()
暴露在运算符级别跨实现而异的支持水平。鼓励 WebNN API 的使用者
使用 opSupportLimits()
探测特性支持水平,以确定要部署到每个目标平台的最佳模型架构。
注: opSupportLimits()
API 并非旨在为浏览器指纹识别提供额外熵。在当前实现中,
此特性支持信息仅从 OS 和浏览器版本即可推断。如果未来实现的多样性
需要它,此 API 允许未来实现添加新的隐私缓解措施,
例如像 WebGPU 一样对能力进行分桶以降低熵。
关于指纹识别考虑的更多讨论,见 § 5 隐私考虑。
8.3.7.1. MLOpSupportLimits
字典
MLOpSupportLimits
具有以下顶级成员;除此之外,每个运算符都有一个在其构建器方法中定义的对应成员。
dictionary {MLOpSupportLimits MLInputOperandLayout preferredInputLayout ; [EnforceRange ]unsigned long long maxTensorByteLength ;MLTensorLimits input ;MLTensorLimits constant ;MLTensorLimits output ; };
preferredInputLayout, 类型为 MLInputOperandLayout-
诸如
conv2d()等依赖布局的运算符的首选输入布局。 maxTensorByteLength, 类型为 unsigned long long-
支持的张量最大长度,以字节为单位。
input,类型为 MLTensorLimitsconstant,类型为 MLTensorLimitsoutput,类型为 MLTensorLimits
8.3.7.2. MLRankRange
字典
dictionary {MLRankRange unsigned long min ;unsigned long max ; };
min,类型为 unsigned long-
支持的最小秩。
max,类型为 unsigned long-
支持的最大秩。
8.3.7.3. MLTensorLimits
字典
typedef sequence <MLOperandDataType >;MLDataTypeList dictionary {MLTensorLimits MLDataTypeList dataTypes ;MLRankRange rankRange ; };
dataTypes,类型为 MLDataTypeList-
支持的数据类型。
rankRange,类型为 MLRankRange-
支持的最小秩和最大秩。
8.3.7.4. MLBinarySupportLimits
字典
dictionary {MLBinarySupportLimits MLTensorLimits a ;MLTensorLimits b ;MLTensorLimits output ; };
a, 类型为 MLTensorLimits-
用于 a 操作数的
MLTensorLimits。 b, 类型为 MLTensorLimits-
用于 b 操作数的
MLTensorLimits。 output,类型为 MLTensorLimits-
用于输出操作数的
MLTensorLimits。
8.3.7.5. MLSingleInputSupportLimits
字典
dictionary {MLSingleInputSupportLimits MLTensorLimits input ;MLTensorLimits output ; };
input,类型为 MLTensorLimits-
用于输入操作数的
MLTensorLimits。 output,类型为 MLTensorLimits-
用于输出操作数的
MLTensorLimits。
8.3.8.
destroy()
可以调用 destroy()
方法来释放与上下文关联的所有资源。任何未完成的计算请求
以及 MLTensor
创建/读取/写入请求都将失败。
destroy() 方法步骤为:
8.3.9. 错误
当用户代理确定某个 MLContext 不再
可用于满足请求时,必须为其运行上下文丢失步骤。
对于 MLContext
context,上下文丢失
步骤为:
-
令 global 为 context 的相关全局对象。
-
使用 global 排队一个 ML 任务来运行这些步骤:
要使用 DOMString
message 丢失 MLContext
context:
-
令 info 为一个新的
MLContextLostInfo。 -
将 info.
message设置为 message。 -
对于每个
MLGraphgraph,其中 graph.[[context]]等于 this: -
对于每个
MLTensortensor,其中 tensor.[[context]]等于 this:
message,类型为 DOMString-
提供有关所发生错误信息的实现定义消息。
一个 MLContext
在其 [[lost]]
Promise
已敲定时
已丢失。
8.4. MLGraph
接口
MLGraph
接口表示一个已编译的计算图。已编译图一旦构造完成就是不可变的,之后不能
再被更改。
[SecureContext ,Exposed =(Window ,Worker )]interface {MLGraph undefined destroy (); };
MLGraph 具有
以下内部槽:
[[context]],类型为MLContext[[inputDescriptors]],类型为 record<USVString,MLOperandDescriptor>-
将此
MLGraph的所有输入MLOperand的名称映射到其MLOperandDescriptor。 [[outputDescriptors]],类型为 record<USVString,MLOperandDescriptor>-
将此
MLGraph的所有输出MLOperand的名称映射到其MLOperandDescriptor。 [[implementation]]-
由用户代理提供的底层实现。
[[isDestroyed]],类型为boolean
8.4.1. destroy()
可以调用 destroy()
方法来释放与图关联的所有资源。
destroy() 方法步骤为:
-
如果 this.
[[isDestroyed]]为 true,则中止这些步骤。 -
将 this.
[[isDestroyed]]设置为 true。 -
在 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>-
操作数的维度列表。对于标量操作数,它为空。
dataType
等于 B.dataType
且 A.shape
等于 B.shape,
则一个 MLOperandDescriptor
A 等于一个 MLOperandDescriptor
B。
要创建
一个 MLOperandDescriptor,
给定 MLOperandDataType
dataType 和列表 shape,运行以下步骤:
-
令 descriptor 为一个新的
MLOperandDescriptor。 -
将 descriptor.
dataType设置为 dataType。 -
返回 descriptor。
MLOperandDescriptor
desc 的字节长度是以下步骤返回的值:
MLOperandDescriptor
desc 的元素数量是以下步骤返回的值:
有效维度是
一个大于零且位于 long
范围内的整数。实现可以施加更小的上限。
有效张量 数量是一个大于零且小于或等于 8192 的整数。实现可以施加 更小的上限。
是否应支持大小为 0 的维度? [Issue #391]
要检查维度,给定 MLOperandDescriptor
descriptor,运行以下步骤:
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
具有以下内部槽:
MLOperand 的
dataType 是其 [[descriptor]].dataType。
MLOperand 的
shape 是其 [[descriptor]].shape。
MLOperand 的
rank 是其 shape 的大小。
dataType getter 步骤是
返回 this 的 dataType。
shape getter 步骤是
返回 this 的 shape。
由于 [[builder]]
对象由 MLGraphBuilder()
构造函数绑定到一个 MLContext
对象,因此一个 MLOperand 也
始终绑定到同一个 MLContext
对象。
如果某个运算仅支持 MLOperandDataType
的
一个子集,则该运算每个输入操作数(包括位置参数和选项)的允许数据
类型会以 MLOperandDataType
的显式列表给出,
或者以约束的形式给出,即操作数的 dataType 必须与另一个输入操作数的 dataType 相同,或以
any 允许任何 MLOperandDataType。
与规范指定相比,实现可以为操作数支持更少的数据类型。可以对每个
运算使用 opSupportLimits()
方法在 MLContext
上查询这一点,并
检查该运算对应成员的 dataTypes
值。
如果某个运算要求输入操作数具有特定 rank,则该运算每个输入操作数(包括 位置参数和选项)的允许秩会以显式秩(例如 1)给出,或以 N 允许任意维度数, 或者以与另一个操作数相同给出。更具体的约束很常见,例如当 输入操作数的形状必须单向可广播到另一个输入操作数,或与其双向可广播; 在这些情况下,允许 秩会列为一个范围,并在运算中以步骤给出具体验证。
实现可以对操作数的 rank
施加比规范指定更受限制的下限和/或上限。可以对每个运算使用
opSupportLimits()
方法在 MLContext
上查询这一点,并
检查该运算对应成员的 rankRange.min
和 rankRange.max
值。
MLOperatorOptions
具有以下成员:
label,类型为 USVString,默认为""-
当使用
MLGraphBuilder中创建MLOperand的方法创建运算符时可选提供。 实现可以使用此值初始化该运算符的标签。
注: 标签并非旨在作为自然语言
字符串。它是一个与语言无关的标识符,类似于变量名或错误代码,例如
"mul#1234"。
注: 鼓励实现使用开发者提供的 label
来增强错误消息并改进可调试性,包括图构造期间的同步
错误,以及异步 build()
方法期间发生的错误。
当在调试工具、日志或错误消息中显示开发者通过 label
提供的标签时,实现应当净化输出,以防止安全风险,例如恶意 Unicode 序列的注入(例如双向文本
欺骗 [UTR36]、源代码欺骗 [UTS55] 以及
其他问题)。例如,实现应转义或过滤控制字符(例如 U+202A
到 U+202E、U+2066 到 U+2069),或使用安全渲染机制来中和潜在
欺骗。
8.6.1. 创建 MLOperand
MLOperand
对象由 MLGraphBuilder
的方法创建,内部使用以下算法。
要创建
MLOperand,给定 MLGraphBuilder
builder 和 MLOperandDescriptor
desc,运行以下步骤:
-
令 realm 为 builder 的相关 realm。
-
令 operand 为 realm 中的一个新的
MLOperand。 -
将 operand.
[[builder]]设置为 builder。 -
将 operand.
[[descriptor]]设置为 desc。 -
返回 operand。
要复制
MLOperand,给定 MLOperand
operand,运行以下步骤:
-
令 builder 为 operand.
[[builder]]。 -
令 realm 为 builder 的相关 realm。
-
令 result 为 realm 中的一个新的
MLOperand。 -
将 result.
[[builder]]设置为 builder。 -
将 result.
[[descriptor]]设置为 operand.[[descriptor]]。 -
如果 operand.
[[name]]存在,则将 result.[[name]]设置为 operand.[[name]]。 -
返回 result。
要验证操作数,给定 MLGraphBuilder
builder 和 MLOperand
operand,如果 operand.[[builder]]
是 builder,则返回 true,否则返回 false。
8.6.1.1.
MLNumber
MLNumber 用于指定 MLOperand
的数值选项的类型,该操作数可以是任意 MLOperandDataType,
包括两种 64 位整数类型("uint64"
和 "int64")
以及 32 位浮点类型("float32")。
实现根据相应的 MLOperandDataType
处理该值。
例如,如果调用 clamp(input, options)
时传入一个 MLOperand,其
dataType 为 "uint32",
则 MLNumber
参数会被显式转换为 unsigned long。
对 bigint
与数值类型联合的支持是 [WEBIDL] 中的新内容,实现支持也有限。
鼓励原型实现为这种方案提供反馈。[whatwg/webidl Issue #1388]
8.7. MLTensorDescriptor
字典
MLTensorDescriptor
描述一个 MLTensor
的特征和能力。
dictionary :MLTensorDescriptor MLOperandDescriptor {boolean readable =false ;boolean writable =false ; };
readable,类型为 boolean,默认为false-
是否可以通过
readTensor(tensor)或readTensor(tensor, outputData)读取张量的内容。 writable,类型为 boolean,默认为false-
是否可以通过
writeTensor()写入张量的内容。
8.8. MLTensor
接口
MLTensor
接口表示一个可用作 MLGraph
输入或输出的张量。支持
MLTensor 的内存应
根据创建它时所用的 MLContext 和
MLTensorDescriptor
的要求,以实现定义的方式分配。涉及 [[data]]
的 MLTensor
的操作发生在其关联 MLContext 的
[[timeline]]
上。
关于如何分配 MLTensor
的实现定义要求可包括如下约束:
内存以特定字节对齐方式分配,或在特定内存池中分配。
[SecureContext ,Exposed =(Window ,Worker )]interface {MLTensor readonly attribute MLOperandDataType dataType ;readonly attribute FrozenArray <unsigned long >shape ;readonly attribute boolean readable ;readonly attribute boolean writable ;readonly attribute boolean constant ;undefined destroy (); };
MLTensor 具有
以下内部槽:
[[context]],类型为MLContext-
MLTensor的 关联上下文。 [[descriptor]],类型为MLTensorDescriptor-
MLTensor的 描述符。 [[pendingPromises]],类型为Promise的集合-
对应于正在进行且尚未解决的
MLContext.readTensor(tensor)方法调用的 Promise。当MLTensor被销毁时,所有待处理的 promise 都将被拒绝。 [[isDestroyed]],类型为boolean[[data]],类型为实现定义类型-
支持
MLTensor的字节。 此数据只能从[[context]].[[timeline]]访问或修改。 [[isConstant]],类型为boolean-
MLTensor是否由创建常量 MLTensor创建。
MLTensor 的
dataType 是其 [[descriptor]]
的
dataType。
MLTensor 的
shape 是其 [[descriptor]]
的
shape。
dataType getter 步骤是
返回 this 的 dataType。
shape getter 步骤是
返回 this 的 shape。
readable getter 步骤是
返回 this.[[descriptor]].readable。
writable getter 步骤是
返回 this.[[descriptor]].writable。
constant getter 步骤是
返回 this 的
[[isConstant]]。
8.8.1. 创建 MLTensor
要创建
MLTensor,给定 MLContext
context 和 MLTensorDescriptor
descriptor,运行以下步骤:
-
令 realm 为 context 的相关 realm。
-
令 tensor 为 realm 中的一个新的
MLTensor。 -
将 tensor.
[[context]]设置为 context。 -
将 tensor.
[[descriptor]]设置为 descriptor。 -
将 tensor.
[[isDestroyed]]设置为 false。 -
将 tensor.
[[isConstant]]设置为 false。 -
返回 tensor。
8.8.2. destroy()
释放与 MLTensor
关联的资源。此
方法是幂等的。
undefined。
destroy() 方法步骤为:
-
将 this.
[[isDestroyed]]设置为 true。 -
对于 this.
[[pendingPromises]]中的每个 promise:-
从 this.
[[pendingPromises]]移除 promise。 -
以 "
InvalidStateError"DOMException拒绝 promise。
-
-
将以下步骤入队到 this.
[[context]].[[timeline]]:
注: 由于无法再使用 此张量入队更多操作,一旦所有之前提交且使用此张量的操作都完成, 实现即可释放与此张量关联的任何额外资源分配。
8.8.3.
创建常量 MLTensor
常量 MLTensor
由其关联的
MLContext
创建。
要创建
常量 MLTensor,给定 MLContext
context、MLOperandDescriptor
inputDescriptor,运行以下步骤:
-
令 realm 为 context 的相关 realm。
-
令 tensor 为 realm 中的一个新的
MLTensor。 -
将 tensor.
[[context]]设置为 context。 -
令 tensorDescriptor 为一个新的
MLTensorDescriptor。 -
将 tensorDescriptor.
readable设置为 false。 -
将 tensorDescriptor.
writable设置为 false。 -
将 tensor.
[[descriptor]]设置为 tensorDescriptor。 -
将 tensor.
[[isDestroyed]]设置为 false。 -
将 tensor.
[[isConstant]]设置为 true。 -
返回 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 ); // 从指定常量张量创建操作数。MLOperand constant (MLTensor tensor ); // 异步编译图,直到指定的输出操作数为止。Promise <MLGraph >build (MLNamedOperands outputs ); };
MLGraphBuilder.build()
方法会按照创建它的 MLContext 的类型,
将图构建器状态编译到指定输出操作数为止,并生成已编译图。当
MLContext 的
[[contextType]]
被设置为 "default"
时,已编译图会在
MLGraph
返回前立即初始化。
此图初始化阶段对于后续图执行的最佳性能很重要。它通常涉及一个称为
"weight preprocessing" 的过程,其中图的所有常量输入都会在操作系统层面进行预处理并缓存,
以便后续图执行调用使用。初始化输入通常是在图构建期间通过
constant()
方法指定为常量操作数的常量权重数据。
MLGraphBuilder
具有以下内部槽:
[[context]],类型为MLContext-
与此
MLGraphBuilder关联的、类型为MLContext的上下文。 [[hasBuilt]],类型为boolean-
MLGraphBuilder.build()是否已被调用。一旦构建完成,MLGraphBuilder就不能再创建运算符或编译MLGraph。
8.9.1.
MLGraphBuilder
构造函数
-
context:一个MLContext。 要与MLGraphBuilder关联的上下文。
new MLGraphBuilder(context)
构造函数步骤为:
-
如果 this 的相关全局对象的关联 Document 不允许使用 webnn 特性,则抛出一个 "
SecurityError"DOMException。 -
如果 context 已丢失,则抛出一个 "
InvalidStateError"DOMException。 -
将 this.
[[context]]设置为 context。 -
将 this.
[[hasBuilt]]设置为 false。
8.9.2. 输入操作数
基于描述符创建一个具名 MLOperand,
可用作输入。
-
name:输入的字符串名称。 -
descriptor:一个MLOperandDescriptor对象。
MLOperand。
input(name, descriptor)
方法步骤为:
MLGraphBuilder
API 允许创建一个没有输入操作数的 MLGraph。如果底层平台不支持这种情况,
实现可以添加一个存根输入,或将常量作为输入传递给图。
8.9.3. 常量操作数
创建一个可在MLGraphBuilder
方法中使用的常量 MLOperand。
8.9.3.1. constant(descriptor, buffer)
创建指定数据类型和形状、且包含初始化数据的常量 MLOperand。
-
descriptor: 一个MLOperandDescriptor。 输出张量的描述符。 -
buffer:一个AllowSharedBufferSource。 包含初始化数据的缓冲区。
MLOperand。常量
输出张量。
constant(descriptor, buffer)
方法步骤为:
-
如果 this 不可构建,则抛出一个 "
InvalidStateError"DOMException。 -
如果给定 buffer 和 descriptor 时根据描述符验证缓冲区返回 false,则抛出一个
TypeError。 -
建立图连接:
-
令 operand 为给定 this 和 descriptor 时创建 MLOperand的结果。
-
令 bytes 为给定 buffer 时获取缓冲区源所持字节的副本的结果。
-
-
返回 operand。
8.9.3.2. constant(tensor)
创建指定数据类型和形状、且包含已初始化数据的常量 MLOperand。
constant(tensor) 方法步骤
为:
-
如果 tensor.
[[context]]不是 this.[[context]], 则抛出一个TypeError。 -
如果 tensor.
[[isDestroyed]]为 true,则抛出一个TypeError。 -
如果 tensor.
[[isConstant]]为 false,则抛出一个TypeError。 -
如果 this 不可构建,则抛出一个 "
InvalidStateError"DOMException。 -
建立图连接:
-
令 operand 为给定 this 和 tensor.
[[descriptor]]时创建 MLOperand的结果。 -
将 operand.
[[constantTensor]]设置为 tensor。
-
-
返回 operand。
8.9.3.3. constant(dataType, value)
创建具有指定值和数据类型的标量常量 MLOperand。
"int8"
数据类型时,等等。
-
dataType:一个MLOperandDataType。 -
value:一个MLNumber。 常量的值。
MLOperand。常量
输出。
constant(dataType, value)
方法步骤为:
-
如果 this 不可构建,则抛出一个 "
InvalidStateError"DOMException。 -
将 value 设置为将 value 转换为 dataType 的结果。
-
令 descriptor 为给定 dataType 和 « » 时创建 MLOperandDescriptor的结果。
-
建立图连接:
-
令 operand 为给定 this 和 descriptor 时创建 MLOperand的结果。
-
-
返回 operand。
8.9.4. build 方法
将组合图构建到给定输出操作数为止,并异步生成计算图。-
outputs:一个MLNamedOperands。 标识将成为图输出的MLOperand。
MLGraph>。
build(outputs) 方法步骤为:
-
如果 this 不可构建,则返回 realm 中一个新的 promise,并以 "
InvalidStateError"DOMException拒绝。 -
如果 outputs 为空,则返回 realm 中一个新的 promise,并以
TypeError拒绝。 -
对于 outputs 的每个 name → operand:
-
如果 name 为空,则返回 realm 中一个 新的 promise,并以
TypeError拒绝。 -
如果给定 this 和 operand 时验证操作数返回 false,则返回 realm 中一个新的 promise,并以
TypeError拒绝。 -
如果 operand 位于 this 的图的输入 或常量中,则返回 realm 中一个新的 promise,并以
TypeError拒绝。 -
如果 operand.
[[constantTensor]]存在且 operand.[[constantTensor]].[[isDestroyed]]为 true,则返回 realm 中一个 新的 promise,并以TypeError拒绝。
-
-
令 operands 为一个新的空集合。
-
令 operators 为一个新的空集合。
-
令 inputs 为一个新的空集合。
-
当 queue 非空时:
-
令 graph 为 realm 中的一个新的
MLGraph。 -
将 graph.
[[context]]设置为 this.[[context]]。 -
将 graph.
[[isDestroyed]]设置为 false。 -
对于 inputs 中的每个 operand:
-
将 graph.
[[inputDescriptors]][operand.[[name]]] 设置为 operand.[[descriptor]]。
-
-
对于 outputs 的每个 name → operand:
-
将 graph.
[[outputDescriptors]][name] 设置为 operand.[[descriptor]]。
-
-
将 this.
[[hasBuilt]]设置为 true。 -
令 promise 为 realm 中一个新的 promise。
-
将以下步骤入队到 graph.
[[context]].[[timeline]]:-
运行这些步骤,但在 graph.
[[context]]丢失时中止:-
令 graphImpl 为将 this 的 图连同 operands、 operators、inputs 和 outputs 的值,以及 graph.
[[context]].[[powerPreference]]和 graph.[[context]].[[accelerated]]转换为可由底层平台解释的实现定义格式的结果。 -
如果上一步失败,则使用 global 排队一个 ML 任务,以用 "
OperationError"DOMException拒绝 promise, 并中止这些步骤。 -
将 graph.
[[implementation]]设置为 graphImpl。 -
使用 global 排队一个 ML 任务,以用 graph 解决 promise。
-
-
如果已中止,则使用 global 排队一个 ML 任务,以用 "
InvalidStateError"DOMException拒绝 promise。
-
-
返回 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。 输出数据类型。
-
input:一个MLOperand。 输入 N 维张量。 -
axis:要 归约的维度。该值必须在 [0, N-1] 范围内,其中 N 是 输入张量的秩。 -
options:一个 可选的MLArgMinMaxOptions。 该操作的可选参数。
返回:一个 MLOperand。
输出 N 维张量;如果 keepDimensions
为 true,其秩等于 input
的
秩;如果 keepDimensions
为 false,则等于 input
的
秩 - 1。其值必须为
outputDataType
类型,且位于 [0, N-1] 范围内,其中 N 是由 axis
指定的输入维度的大小。
| 操作数 | 允许的 数据类型 | 允许的秩 |
|---|---|---|
input
| any | 1 到 N |
| output | "int32",
"int64"
| N |
MLOpSupportLimits
具有以下用于 argMin()
和 argMax()
的成员:
argMin,类型为 MLSingleInputSupportLimits-
运算符
argMin()的支持限制。 argMax,类型为 MLSingleInputSupportLimits-
运算符
argMax()的支持限制。
要创建 argMin/argMax 操作,给定字符串
op、MLOperand
input、unsigned long
axis 和 MLArgMinMaxOptions
options,运行以下步骤:
-
断言:op 是 "argMin"、"argMax" 之一。
-
如果 this 不可构建,则抛出一个 "
InvalidStateError"DOMException。 -
如果 options.
outputDataType不是输出张量的允许数据类型(根据此表),则抛出一个TypeError。 -
如果 input 的shape[axis] 大于 options.
outputDataType的 最大值,则抛出一个TypeError。 -
令 outputShape 为给定 input 的shape、« axis » 和 options.
keepDimensions时计算归约输出大小的结果。 如果返回失败,则抛出一个TypeError。 -
令 desc 为给定 options.
outputDataType和 outputShape 时创建 MLOperandDescriptor的结果。 -
建立图连接:
-
令 operator 为给定 options 时用于 op 操作的一个运算符。
-
令 output 为给定 this 和 desc 时创建 MLOperand的结果。
-
将 output.
[[operator]]设置为 operator。 -
将 operator 的输入设置为 input。
-
将 operator 的输出设置为 output。
-
-
返回 output。
支持以下 argMin/argMax 算法。
argMin(input, axis, options)
方法步骤为:
-
令 output 为给定 "argMin"、input、axis 和 options 时创建 argMin/argMax 操作的结果。
-
返回 output。
argMax(input, axis, options)
方法步骤为:
-
令 output 为给定 "argMax"、input、axis 和 options 时创建 argMin/argMax 操作的结果。
-
返回 output。
8.9.6. batchNormalization
使用 [Batch-Normalization] 对输入张量的值进行归一化。对于每个输入特征,在模型训练期间, 该特征的均值和方差值会跨批量维度中的所有样本计算。随后在模型推理期间, 这些均值和方差值会提供给此操作。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,类型为 MLOperandbias,类型为 MLOperandaxis,类型为 unsigned long,默认为1-
输入形状中特征计数维度的索引,均值和方差值即针对该维度。其值必须在 [0, N-1] 范围内,其中 N 是输入张量的秩。默认值为 1, 对应于
"nchw"数据布局中的通道("c")维度。 epsilon,类型为 double,默认为1e-5-
用于防止除零导致计算错误的小值。
| 操作数 | 允许的 数据类型 | 允许的秩 |
|---|---|---|
input
| "float32",
"float16"
| 1 到 N |
mean
| 与 input
相同
| 1 |
variance
| 与 input
相同
| 1 |
scale
| 与 input
相同
| 1 |
bias
| 与 input
相同
| 1 |
| output | 与 input
相同
| 与 input
相同
|
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)
方法步骤为:
-
如果 this 不可构建,则抛出一个 "
InvalidStateError"DOMException。 -
如果以 验证操作数处理 this 和 input、mean、 variance、options.
scale(如果它存在)以及 options.bias(如果它存在)中的任一项返回 false,则抛出一个TypeError。 -
如果 options.
axis不在 0 到 input 的秩之间的范围内(不含端点),则抛出一个TypeError。 -
如果 mean 的shape 不等于 « input 的shape[options.
axis] »,则抛出一个TypeError。 -
如果 variance 的shape 不等于 « input 的shape[options.
axis] »,则抛出一个TypeError。 -
将 options.
epsilon设置为将 options.epsilon转换为 input 的dataType 的结果。 -
建立图连接:
-
令 operator 为给定 input、mean、variance 和 options 时用于 "batchNormalization" 操作的一个运算符。
-
令 output 为给定 this 和 input.
[[descriptor]]时创建 MLOperand的结果。 -
将 output.
[[operator]]设置为 operator。 -
将 operator 的输入设置为 input、mean 和 variance。
-
将 operator 的输出设置为 output。
-
-
返回 output。
当输入张量是 "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
将输入张量中的每个元素转换为目标数据类型。partial interface MLGraphBuilder {MLOperand cast (MLOperand input ,MLOperandDataType dataType ,optional MLOperatorOptions options = {}); };partial dictionary MLOpSupportLimits {MLSingleInputSupportLimits cast ; };
-
input:一个MLOperand。 输入 N 维张量。 -
dataType:一个MLOperandDataType。 目标数据类型。 -
options:一个MLOperatorOptions。 指定该操作的可选参数。
| 操作数 | 允许的 数据类型 | 允许的秩 |
|---|---|---|
input
| any | N |
| output | any | 与 input
相同
|
MLOpSupportLimits
具有以下用于 cast()
的成员:
cast,类型为 MLSingleInputSupportLimits-
运算符
cast()的支持限制。
根据下表,MLOperandDataType
之间的转换在某些情况下已指定,而在其他情况下是实现定义的:
| 目标类型 输入类型 |
"float32",
"float16"
|
"int32",
"uint32",
"int64",
"uint64",
"int8",
"uint8"
|
|---|---|---|
"float32",
"float16"
|
如果在范围内,则为最接近的可表示值。
如果超出范围,则为 +/-Infinity。 |
如果在范围内,则截断。
如果超出范围,则为实现定义。 |
"int32",
"uint32",
"int64",
"uint64",
"int8",
"uint8"
|
如果在范围内,则为最接近的可表示值。
如果超出范围,则为 +/-Infinity。 |
如果在范围内,则为相同值。
如果超出范围,则将最低 N 位重新解释为目标类型,有符号类型假定为二进制补码。 |
注: 例如,将 -1 从 "int8"
转换为 "uint8"
被指定为产生 255。但将 -1 从 "float32"
转换为 "uint8"
是实现定义的。
cast(input, dataType, options)
方法步骤为:
-
如果 this 不可构建,则抛出一个 "
InvalidStateError"DOMException。 -
建立图连接:
-
令 operator 为给定 dataType 和 options 时用于 "cast" 操作的一个运算符。
-
令 output 为给定 input 时复制 MLOperand的结果。
-
将 output.
[[operator]]设置为 operator。 -
将 operator 的输入设置为 input。
-
将 operator 的输出设置为 output。
-
-
返回 output。
8.9.8. clamp
将输入张量按元素夹取到由最小值和最大值指定的范围内。dictionary :MLClampOptions MLOperatorOptions {MLNumber minValue ;MLNumber maxValue ; };partial interface MLGraphBuilder {MLOperand clamp (MLOperand input ,optional MLClampOptions options = {}); };partial dictionary MLOpSupportLimits {MLSingleInputSupportLimits clamp ; };
MLClampOptions
具有以下成员:
minValue,类型为 MLNumber-
范围的最小值。未指定时,不会对该范围的下限执行夹取。
maxValue,类型为 MLNumber-
范围的最大值。未指定时,不会对该范围的上限执行夹取。
-
input:一个MLOperand。 输入张量。 -
options:一个可选的MLClampOptions。 该操作的可选参数。
| 操作数 | 允许的 数据类型 | 允许的秩 |
|---|---|---|
input
| any | N |
| output | 与 input
相同
| 与 input
相同
|
MLOpSupportLimits
具有以下用于 clamp()
的成员:
clamp,类型为 MLSingleInputSupportLimits-
运算符
clamp()的支持限制。
clamp(input, options) 方法
步骤为:
-
如果 this 不可构建,则抛出一个 "
InvalidStateError"DOMException。 -
令 minValue 为给定时的 options.
minValue, 否则为 Infinity。 -
令 maxValue 为给定时的 options.
maxValue, 否则为 -Infinity。 -
建立图连接:
-
令 output 为给定 input 时复制 MLOperand的结果。
-
令 operator 为给定 options 时用于 "clamp" 操作的一个运算符。
-
将 output.
[[operator]]设置为 operator。 -
将 operator 的输入设置为 input。
-
将 operator 的输出设置为 output。
-
-
返回 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
沿给定轴连接输入张量。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 ; };
-
inputs:一个 sequence<MLOperand>。 所有输入张量都必须具有相同形状,除了要连接的维度大小以外。 -
axis:一个unsigned long标量。输入沿其连接的轴。其值必须在 [0, N-1] 范围内, 其中 N 是输入张量的秩。 -
options:一个MLOperatorOptions。 指定该操作的可选参数。
返回:一个 MLOperand。
所有输入沿
axis
连接后的张量。输出张量具有相同形状,除了所有输入沿其连接的维度以外。
该维度的大小计算为同一维度的所有输入大小之和。
| 操作数 | 允许的 数据类型 | 允许的秩 |
|---|---|---|
inputs
的
项
| any | 1 到 N |
| output | 与 inputs
的
项相同
| 与 inputs
的
项相同
|
MLConcatSupportLimits
具有以下成员:
inputs,类型为 MLTensorLimits-
用于所有输入操作数的
MLTensorLimits。 output,类型为 MLTensorLimits-
用于输出操作数的
MLTensorLimits。
MLOpSupportLimits
具有以下用于 concat()
的成员:
concat,类型为 MLConcatSupportLimits-
运算符
concat()的支持限制。
concat(inputs, axis, options)
方法步骤为:
-
如果 this 不可构建,则抛出一个 "
InvalidStateError"DOMException。 -
令 first 为 inputs[0]。
-
令 desc 为给定 first 的dataType 和 first 的shape 时创建 MLOperandDescriptor的结果。
-
建立图连接:
-
令 output 为给定 this 和 desc 时创建 MLOperand的结果。
-
令 operator 为给定 inputs、axis 和 options 时用于 "concat" 操作的一个运算符。
-
将 output.
[[operator]]设置为 operator。 -
将 operator 的输入设置为 inputs。
-
将 operator 的输出设置为 output。
-
-
返回 output。
8.9.10. conv2d
给定 4 维输入张量和滤波器张量,计算 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]。 指定卷积输入每个空间维度上滑动窗口的步幅。 默认值为 [1, 1]。
dilations,类型为sequence<[EnforceRange] unsigned long>-
长度为 2 的列表:[dilationHeight, dilationWidth]。指定应用于卷积滤波器(核)的每个 空间维度的膨胀因子。 默认值为 [1, 1]。
groups,类型为 unsigned long,默认为1-
输入通道和输出通道被划分成的组数。
inputLayout,类型为 MLInputOperandLayout,默认为"nchw"-
指定输入和输出张量的布局格式,如下所示:
filterLayout,类型为 MLConv2dFilterOperandLayout,默认为"oihw"-
指定滤波器张量的布局格式,如下所示:
bias,类型为 MLOperand-
形状为 [outputChannels] 的额外 1 维张量,其值将添加到卷积结果中。
-
input:一个MLOperand。 输入 4 维张量。逻辑形状会根据inputLayout的值解释。 -
filter:一个MLOperand。 滤波器 4 维张量。逻辑形状会根据filterLayout和groups的值解释。 -
options:一个MLConv2dOptions。 该操作的可选参数。
返回:一个 MLOperand。
包含卷积结果的输出 4 维张量。输出形状会根据
inputLayout
解释。更具体地,对于 "nchw"
输入布局,输出张量的空间维度或最后两个维度的大小可按如下方式计算:
outputSize = 1 + (inputSize - (filterSize - 1) * dilation - 1 + beginningPadding + endingPadding) / stride
| 操作数 | 允许的 数据类型 | 允许的秩 |
|---|---|---|
input
| "float32",
"float16"
| 4 |
filter
| 与 input
相同
| 4 |
bias
| 与 input
相同
| 1 |
| output | 与 input
相同
| 4 |
MLConv2dSupportLimits
具有以下成员:
input,类型为 MLTensorLimits-
用于输入操作数的
MLTensorLimits。 filter,类型为 MLTensorLimits-
用于 filter 操作数的
MLTensorLimits。 bias, 类型为 MLTensorLimits-
用于 bias 操作数的
MLTensorLimits。 output,类型为 MLTensorLimits-
用于输出操作数的
MLTensorLimits。
MLOpSupportLimits
具有以下用于 conv2d()
的成员:
conv2d,类型为 MLConv2dSupportLimits-
运算符
conv2d()的支持限制。
groups
= inputChannels = outputChannels,并且对于 "oihw"
布局,滤波器张量的形状为 [options.groups, 1,
height, width];
对于 "hwio"
布局为 [height, width, 1, options.groups];
对于 "ohwi"
布局为 [options.groups, height, width, 1];
对于 "ihwo"
布局为 [1, height, width, options.groups]。
要计算 conv 输出大小,给定无符号 整数 inputSize、filterSize、beginningPadding、 endingPadding、stride 和 dilation,执行这些步骤。它们返回一个 数值。
-
令 effectiveFilterSize 为 ( filterSize - 1 ) * dilation + 1。
-
令 outputSize 为 ( inputSize - effectiveFilterSize + beginningPadding + endingPadding ) / stride + 1。
-
返回 outputSize。
要计算 conv2d 输出大小,给定无符号 整数 inputHeight、inputWidth、filterHeight 和 filterWidth,4 个无符号整数的列表 padding,2 个无符号整数的列表 strides,以及 2 个无符号整数的列表 dilations,执行这些步骤。它们返回 2 个数值的列表。
-
令 outputHeight 为给定 inputHeight、filterHeight、 padding[0]、 padding[1]、strides[0] 和 dilations[0] 时计算 conv 输出大小的结果。
-
令 outputWidth 为给定 inputWidth、filterWidth、 padding[2]、 padding[3]、strides[1] 和 dilations[1] 时计算 conv 输出大小的结果。
-
返回 « outputHeight, outputWidth »。
conv2d(input, filter, options)
方法步骤为:
-
如果 this 不可构建,则抛出一个 "
InvalidStateError"DOMException。 -
如果以 验证操作数处理 this 和 input、filter 以及 options.
bias(如果它存在)中的任一项返回 false,则抛出一个TypeError。 -
计算输出形状:
-
令 inputShape 为 input 的shape。
-
根据 options.
inputLayout进行切换: -
令 filterShape 为 filter 的shape。
-
根据 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。
-
否则,如果 inputChannels / options.
groups不等于 filterInputChannels,则抛出 一个TypeError。 -
令 « outputHeight, outputWidth » 为给定 inputHeight、inputWidth、 filterHeight、filterWidth、options.
padding、 options.strides和 options.dilations时计算 conv2d 输出大小的结果。 -
将 outputHeight 设置为 floor( outputHeight )。
-
将 outputWidth 设置为 floor( outputWidth )。
-
根据 options.
inputLayout进行切换: -
令 desc 为给定 input 的dataType 和 outputShape 时创建 MLOperandDescriptor的结果。
-
-
建立图连接:
-
令 output 为给定 this 和 desc 时创建 MLOperand的结果。
-
令 operator 为给定 options 和 filter 时用于 "conv2d" 操作的一个运算符。
-
将 output.
[[operator]]设置为 operator。 -
将 operator 的输入设置为 input 和 filter。
-
将 operator 的输出设置为 output。
-
-
返回 output。
8.9.11. convTranspose2d
给定 4 维输入张量和滤波器张量,计算 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]。 指定卷积输入每个空间维度上滑动窗口的步幅。 默认值为 [1, 1]。
dilations,类型为sequence<[EnforceRange] unsigned long>-
长度为 2 的列表:[dilationHeight, dilationWidth]。指定应用于卷积滤波器(核)的每个 空间维度的膨胀因子。 默认值为 [1, 1]。
outputPadding,类型为sequence<[EnforceRange] unsigned long>-
长度为 2 的列表。 指定应用于输出张量每个空间维度的填充值。当
strides的值大于 1 时,需要显式填充值来消除转置卷积输出张量形状的歧义。注意,这些值仅在需要时用于消除输出形状的歧义;它不一定会导致任何填充值写入输出张量。
默认值为 [0, 0]。
outputSizes,类型为sequence<[EnforceRange] unsigned long>-
长度为 2 的列表。 指定输出张量最后两个维度的大小。当显式指定输出大小时,
outputPadding中的输出填充值会被忽略。如果未指定,则会自动计算输出大小。
groups,类型为 unsigned long,默认为1-
输入通道和输出通道被划分成的组数。
inputLayout,类型为 MLInputOperandLayout,默认为"nchw"-
指定输入和输出张量的布局格式,如下所示:
filterLayout,类型为 MLConvTranspose2dFilterOperandLayout, 默认为"iohw"-
指定滤波器张量的布局格式,如下所示:
bias,类型为 MLOperand-
形状为 [outputChannels] 的额外 1 维张量,其值将添加到卷积结果中。
-
input: 一个MLOperand。 输入 4 维张量。逻辑形状会根据inputLayout的值解释。 -
filter: 一个MLOperand。 滤波器 4 维张量。逻辑形状会根据filterLayout和groups的值解释。 -
options: 一个可选的MLConvTranspose2dOptions。
返回:一个 MLOperand。
包含转置卷积结果的输出 4 维张量。输出形状会根据 inputLayout
解释。更具体地,除非显式指定 outputSizes,
否则需要 outputPadding
来按如下方式计算输出张量的空间维度值:
outputSize = (inputSize - 1) * stride + (filterSize - 1) * dilation + 1 - beginningPadding - endingPadding + outputPadding
| 操作数 | 允许的 数据类型 | 允许的秩 |
|---|---|---|
input
| "float32",
"float16"
| 4 |
filter
| 与 input
相同
| 4 |
bias
| 与 input
相同
| 1 |
| output | 与 input
相同
| 4 |
MLOpSupportLimits
具有以下用于 convTranspose2d()
的成员:
convTranspose2d,类型为 MLConv2dSupportLimits-
运算符
convTranspose2d()的支持限制。
要计算 convtranspose 输出大小, 给定无符号整数 inputSize、filterSize、beginningPadding、 endingPadding、stride 和 dilation,执行这些步骤。它们返回一个 数值。
-
令 effectiveFilterSize 为 ( filterSize - 1 ) * dilation + 1。
-
令 outputSize 为 ( inputSize - 1 ) * stride + effectiveFilterSize - beginningPadding - endingPadding。
-
返回 outputSize。
convTranspose2d(input, filter, options)
方法步骤为:
-
如果 this 不可构建,则抛出一个 "
InvalidStateError"DOMException。 -
如果以 验证操作数处理 this 和 input、filter 以及 options.
bias(如果它存在)中的任一项返回 false,则抛出一个TypeError。 -
如果 options.
outputPadding不存在,则将其设置为列表 « 0, 0 »。 -
否则,如果 options.
outputPadding的 大小不是 2,则抛出一个TypeError。 -
如果 options.
outputSizes存在,则: -
否则:
-
如果 options.
outputPadding[0] 大于或等于 options.strides[0], 或者 options.outputPadding[1] 大于或等于 options.strides[1], 则抛出一个TypeError。
-
-
计算输出形状:
-
令 inputShape 为 input 的shape。
-
根据 options.
inputLayout进行切换: -
令 filterShape 为 filter 的shape。
-
根据 options.
filterLayout进行切换: -
令 outputChannels 为 filterOutputChannels * options.
groups。 -
令 calculatedOutputHeight 为给定 inputHeight、filterHeight、 padding[0]、padding[1]、strides[0] 和 dilations[0] 时计算 convtranspose 输出大小的结果。
-
令 calculatedOutputWidth 为给定 inputWidth、filterWidth、 padding[2]、padding[3]、strides[1] 和 dilations[1] 时计算 convtranspose 输出大小的结果。
-
如果 options.
outputSizes存在,则:-
令 « outputHeight, outputWidth » 为 options.
outputSizes。 -
如果 outputHeight 小于 calculatedOutputHeight,或 outputHeight 大于或等于 calculatedOutputHeight + strides[0],则抛出一个
TypeError。 -
如果 outputWidth 小于 calculatedOutputWidth,或 outputWidth 大于或等于 calculatedOutputWidth + strides[1],则抛出一个
TypeError。
-
-
否则:
-
令 outputHeight 为 calculatedOutputHeight + options.
outputPadding[0]。 -
令 outputWidth 为 calculatedOutputWidth + options.
outputPadding[1]。
-
-
根据 options.
inputLayout进行切换: -
令 desc 为给定 input 的dataType 和 outputShape 时创建 MLOperandDescriptor的结果。
-
-
建立图连接:
-
令 output 为给定 this 和 desc 时创建 MLOperand的结果。
-
令 operator 为给定 options 和 filter 时用于 "convTranspose2d" 操作的一个运算符。
-
将 output.
[[operator]]设置为 operator。 -
将 operator 的输入设置为 input 和 filter。
-
将 operator 的输出设置为 output。
-
-
返回 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 ; };
| 操作数 | 允许的 数据类型 | 允许的秩 |
|---|---|---|
input
| "float32",
"float16",
"int32",
"uint32",
"int64",
"uint64"
| 1 到 N |
| output | 与 input
相同
| 与 input
相同
|
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]。默认是正向。
-
input:一个MLOperand。 输入张量。 -
axis:一个unsigned long标量。将在其上执行求和的轴。其值必须在 [0, N-1] 范围内, 其中 N 是input的 秩。 -
options: 一个MLCumulativeSumOptions。 指定该操作的可选参数。
返回:
MLOpSupportLimits
具有以下用于 cumulativeSum()
的成员:
cumulativeSum,类型为 MLSingleInputSupportLimits-
运算符
cumulativeSum()的支持限制。
cumulativeSum(input, axis, options)
方法步骤为:
-
如果 this 不可构建,则抛出一个 "
InvalidStateError"DOMException。 -
建立图连接:
-
令 output 为给定 input 时复制 MLOperand的结果。
-
令 operator 为用于 "cumulativeSum" 操作和 options 的一个运算符。
-
将 output.
[[operator]]设置为 operator。 -
将 operator 的输入设置为 input。
-
将 operator 的输出设置为 output。
-
-
返回 output。
8.9.13. 逐元素二元运算
计算两个输入张量的逐元素二元加法、减法、乘法、除法、幂、最大值和最小值。该操作将根据 [numpy-broadcasting-rule] 进行广播。 输入张量必须是双向可广播的。输出张量的秩 是输入张量的最大秩。 对于输出张量的每个维度,其大小是输入张量在该维度上的最大大小。
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 ; };
-
a:一个MLOperand。 第一个输入张量。 -
b:一个MLOperand。 第二个输入张量。 -
options:一个MLOperatorOptions。 指定该操作的可选参数。
返回:一个 MLOperand。
包含两个输入张量逐元素二元运算结果的输出张量。
-
add:逐元素相加两个输入张量的值。
-
sub:逐元素从第一个输入张量的值中减去第二个输入张量的值。
-
mul:逐元素相乘两个输入张量的值。
-
div:逐元素将第一个输入张量的值除以第二个张量的值。整数类型向零截断。
-
max:逐元素选择两个输入张量中较大的值。
-
min:逐元素选择两个输入张量中较小的值。
-
pow:逐元素计算第一个输入张量的值的幂,指数为第二个输入张量的值。
| 操作数 | 允许的 数据类型 | 允许的秩 |
|---|---|---|
a
| any | N |
b
| 与 a
相同
| N |
| output | 与 a
相同
| N |
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,运行以下步骤:
-
断言:op 是 "add"、"sub"、"mul"、"div"、"max"、 "min"、"pow" 之一。
-
如果 this 不可构建,则抛出一个 "
InvalidStateError"DOMException。 -
令 descriptor 为给定 a 的dataType 和 outputShape 时创建 MLOperandDescriptor的结果。
-
建立图连接:
-
令 output 为给定 this 和 descriptor 时创建 MLOperand的结果。
-
令 operator 为给定 a、b 和 options 时用于 op 操作的一个运算符。
-
将 output.
[[operator]]设置为 operator。 -
将 operator 的输入设置为 a 和 b。
-
将 operator 的输出设置为 output。
-
-
返回 output。
逐元素二元运算算法按如下方式调用创建逐元素二元运算步骤。
add(a, b, options)
方法步骤为:
-
令 output 为给定 "add"、a、b 和 options 时创建逐元素二元 运算的结果。
-
返回 output。
sub(a, b, options)
方法步骤为:
-
令 output 为给定 "sub"、a、b 和 options 时创建逐元素二元 运算的结果。
-
返回 output。
mul(a, b, options)
方法步骤为:
-
令 output 为给定 "mul"、a、b 和 options 时创建逐元素二元 运算的结果。
-
返回 output。
div(a, b, options)
方法步骤为:
-
令 output 为给定 "div"、a、b 和 options 时创建逐元素二元 运算的结果。
-
返回 output。
max(a, b, options)
方法步骤为:
-
令 output 为给定 "max"、a、b 和 options 时创建逐元素二元 运算的结果。
-
返回 output。
min(a, b, options)
方法步骤为:
-
令 output 为给定 "min"、a、b 和 options 时创建逐元素二元 运算的结果。
-
返回 output。
pow(a, b, options)
方法步骤为:
-
令 output 为给定 "pow"、a、b 和 options 时创建逐元素二元 运算的结果。
-
返回 output。
8.9.14. 逐元素逻辑运算
逐元素比较输入张量,并为比较返回一个值为 0(false)或 1(true)的"uint8"
张量。对于单操作数操作,返回该操作的逻辑结果。
对于多操作数操作,该操作将根据 [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 ; };
-
a:一个MLOperand。 第一个输入张量。 -
b:一个MLOperand。 指定时的第二个输入张量。 -
options:一个MLOperatorOptions。 指定该操作的可选参数。
返回:一个 MLOperand。
包含两个输入张量逐元素比较结果的输出张量。
| 操作数 | 允许的 数据类型 | 允许的秩 |
|---|---|---|
a
| 作为操作步骤的一部分指定 | N |
b
| 与 a
相同
| N |
| output | "uint8"
| N |
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()的支持限制。
-
equal:逐元素比较两个输入张量的值是否相等。
-
notEqual:逐元素比较两个输入张量的值是否不相等。
-
greater:逐元素比较第一个输入张量的值是否更大。
-
greaterOrEqual:逐元素比较第一个输入张量的值是否更大或相等。
-
lesser:逐元素比较第一个输入张量的值是否更小。
-
lesserOrEqual:逐元素比较第一个输入张量的值是否更小或相等。
-
logicalNot:逐元素将输入张量的值取反为 0 或 1。具体而言,当输入值非零时, 将其反转为 0。反之,对于零输入值,将其反转为 1。
-
logicalAnd:逐元素计算两个输入张量的逻辑 and, 将任何非零值视为 true,并返回 0 或 1 的元素。
-
logicalOr:逐元素计算两个输入张量的逻辑 or, 将任何非零值视为 true,并返回 0 或 1 的元素。
-
logicalXor:逐元素计算两个输入张量的逻辑 xor, 将任何非零值视为 true,并返回 0 或 1 的元素。
-
isNaN:逐元素检查输入张量的值是否为无效数值表示(NaN), 对 NaN 返回 1,否则返回 0。
-
isInfinite:逐元素检查输入张量的值是否为无穷大, 对正无穷或负无穷返回 1,否则返回 0。
greaterOrEqual()
和 lesserOrEqual()
各自都可以用操作 logicalNot()、
lesser()
和 greater()
来实现(换言之,builder.greaterOrEqual(a, b) 是
builder.logicalNot(builder.lesser(a, b))),但它们被专门定义为处理 NaN 情况,
并出于性能原因避免双重比较。
要创建
逐元素逻辑运算,给定字符串 op、MLOperand
a、一个可选的 MLOperand
b,以及 MLOperatorOptions
options,运行以下步骤:
-
断言:op 是 "equal"、"notEqual"、"greater"、 "greaterOrEqual"、"lesser"、"lesserOrEqual"、"logicalNot"、"logicalAnd"、"logicalOr"、 "logicalXor"、"isNaN"、"isInfinite" 之一。
-
如果 this 不可构建,则抛出一个 "
InvalidStateError"DOMException。 -
如果 op 是 "logicalNot"、"logicalAnd"、"logicalOr"、"logicalXor" 之一,则:
-
如果 op 是 "isNaN"、"isInfinite" 之一,则:
-
如果传入了 b,则:
-
否则:
-
令 descriptor 为给定
"uint8"和 outputShape 时创建 MLOperandDescriptor的结果。 -
建立图连接:
-
令 output 为给定 this 和 descriptor 时创建 MLOperand的结果。
-
令 operator 为给定 a、(如果传入了 b)b 和 options 时用于 op 操作的一个运算符。
-
将 output.
[[operator]]设置为 operator。 -
将 operator 的输入设置为 a 和(如果传入了 b) b。
-
将 operator 的输出设置为 output。
-
-
返回 output。
逐元素逻辑运算算法按如下方式调用创建逐元素逻辑运算步骤。
equal(a, b, options)
方法步骤为:
-
令 output 为给定 "equal"、a、b 和 options 时创建逐元素逻辑 运算的结果。
-
返回 output。
notEqual(a, b, options)
方法步骤为:
-
令 output 为给定 "notEqual"、a、b 和 options 时创建逐元素逻辑 运算的结果。
-
返回 output。
greater(a, b, options)
方法步骤为:
-
令 output 为给定 "greater"、a、b 和 options 时创建逐元素逻辑 运算的结果。
-
返回 output。
greaterOrEqual(a, b, options)
方法步骤为:
-
令 output 为给定 "greaterOrEqual"、a、b 和 options 时创建逐元素逻辑 运算的结果。
-
返回 output。
lesser(a, b, options)
方法步骤为:
-
令 output 为给定 "lesser"、a、b 和 options 时创建逐元素逻辑 运算的结果。
-
返回 output。
lesserOrEqual(a, b, options)
方法步骤为:
-
令 output 为给定 "lesserOrEqual"、a、b 和 options 时创建逐元素逻辑 运算的结果。
-
返回 output。
logicalNot(a, options)
方法步骤为:
-
令 output 为给定 "logicalNot"、a 和 options 时创建逐元素逻辑 运算的结果。
-
返回 output。
logicalAnd(a, b, options)
方法步骤为:
-
令 output 为给定 "logicalAnd"、a、b 和 options 时创建逐元素逻辑 运算的结果。
-
返回 output。
logicalOr(a, b, options)
方法步骤为:
-
令 output 为给定 "logicalOr"、a、b 和 options 时创建逐元素逻辑 运算的结果。
-
返回 output。
logicalXor(a, b, options)
方法步骤为:
-
令 output 为给定 "logicalXor"、a、b 和 options 时创建逐元素逻辑 运算的结果。
-
返回 output。
isNaN(a, options) 方法
步骤为:
-
令 output 为给定 "isNaN"、a 和 options 时创建逐元素逻辑 运算的结果。
-
返回 output。
isInfinite(a, options)
方法步骤为:
-
令 output 为给定 "isInfinite"、a 和 options 时创建逐元素逻辑 运算的结果。
-
返回 output。
8.9.15. 逐元素一元运算
计算输入张量的逐元素一元运算。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 ; };
-
input:一个MLOperand。 输入张量。 -
options:一个MLOperatorOptions。 指定该操作的可选参数。
返回:一个 MLOperand。
包含输入张量逐元素一元运算结果的输出张量。输出张量的形状
与输入张量的形状相同。
| 操作数 | 允许的 数据类型 | 允许的秩 |
|---|---|---|
input
| 作为操作步骤的一部分指定 | N |
| output | 与 input
相同
| 与 input
相同
|
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()的支持限制。
-
abs:逐元素计算输入张量的绝对值。
-
ceil:逐元素计算输入张量的向上取整值。
-
cos:逐元素计算输入张量的余弦。
-
erf:逐元素计算输入张量的误差函数 [Error-Function]。
-
exp:逐元素计算输入张量的指数。
-
floor:逐元素计算输入张量的向下取整值。
-
identity:逐元素将输入张量的值复制到输出张量。
-
log:逐元素计算输入张量的自然对数。
-
neg:逐元素计算输入张量的数值相反数。
-
reciprocal:逐元素计算输入张量的倒数。
-
roundEven:逐元素将输入张量四舍六入五取偶到最接近的偶数值 (例如 [0.1, 0.9, 1.1, 1.9, -3.5, -2.5, -1.5, 1.5, 2.5, 3.5] 产生 [0.0, 1.0, 1.0, 2.0, -4.0, -2.0, -2.0, 2.0, 2.0, 4.0])。
-
sin:逐元素计算输入张量的正弦。
-
sign:逐元素计算输入张量的符号(-1、0、1),如果 > 0 则返回 1, 如果 < 0 则返回 -1,否则返回 0。
-
sqrt:逐元素计算输入张量的平方根。
-
tan:逐元素计算输入张量的正切。
要创建
逐元素一元运算,给定字符串 op、MLOperand
input,可选列表 allowedDataTypes,以及 options,运行以下步骤:
-
断言:op 是 "abs"、"ceil"、"cos"、"erf"、"exp"、 "floor"、"identity"、"log"、"neg"、"reciprocal"、"roundEven"、"sin"、"sign"、"sqrt"、"tan" 之一。
-
如果 this 不可构建,则抛出一个 "
InvalidStateError"DOMException。 -
如果给定了 allowedDataTypes,且它不包含 input 的dataType,则抛出一个
TypeError。 -
建立图连接:
-
令 output 为给定 input 时复制 MLOperand的结果。
-
令 operator 为给定 options 时用于 op 操作的一个运算符。
-
将 output.
[[operator]]设置为 operator。 -
将 operator 的输入设置为 input。
-
将 operator 的输出设置为 output。
-
-
返回 output。
逐元素一元运算算法按如下方式调用创建逐元素一元运算步骤。
abs(input, options) 方法
步骤为:
ceil(input, options) 方法
步骤为:
-
令 output 为给定 "ceil"、input、«
"float32","float16"» 和 options 时创建逐元素一元 运算的结果。 -
返回 output。
cos(input, options) 方法
步骤为:
-
令 output 为给定 "cos"、input、«
"float32","float16"» 和 options 时创建逐元素一元 运算的结果。 -
返回 output。
erf(input, options) 方法
步骤为:
-
令 output 为给定 "erf"、input、«
"float32","float16"» 和 options 时创建逐元素一元 运算的结果。 -
返回 output。
exp(input, options) 方法
步骤为:
-
令 output 为给定 "exp"、input、«
"float32","float16"» 和 options 时创建逐元素一元 运算的结果。 -
返回 output。
floor(input, options) 方法
步骤为:
-
令 output 为给定 "floor"、input、«
"float32","float16"» 和 options 时创建逐元素一元 运算的结果。 -
返回 output。
identity(input, options)
方法步骤为:
-
令 output 为给定 "identity"、input 和 options 时创建逐元素一元 运算的结果。
-
返回 output。
log(input, options) 方法
步骤为:
-
令 output 为给定 "log"、input、«
"float32","float16"» 和 options 时创建逐元素一元 运算的结果。 -
返回 output。
neg(input, options) 方法
步骤为:
reciprocal(input, options)
方法步骤为:
-
令 output 为给定 "reciprocal"、input、«
"float32","float16"» 和 options 时创建逐元素一元 运算的结果。 -
返回 output。
roundEven(input, options)
方法步骤为:
-
令 output 为给定 "roundEven"、input、«
"float32","float16"» 和 options 时创建逐元素一元 运算的结果。 -
返回 output。
sin(input, options) 方法
步骤为:
-
令 output 为给定 "sin"、input、«
"float32","float16"» 和 options 时创建逐元素一元 运算的结果。 -
返回 output。
sign(input, options) 方法
步骤为:
sqrt(input, options) 方法
步骤为:
-
令 output 为给定 "sqrt"、input、«
"float32","float16"» 和 options 时创建逐元素一元 运算的结果。 -
返回 output。
tan(input, options) 方法
步骤为:
-
令 output 为给定 "tan"、input、«
"float32","float16"» 和 options 时创建逐元素一元 运算的结果。 -
返回 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。scale
和 zeroPoint
张量可以小于 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 ; };
-
input: 一个MLOperand。 输入张量。 -
scale: 一个MLOperand。 在按 zero point 调整后,要与每个 input 值相乘的 scale 张量。它必须与输入按块可广播。值必须为正且非零,否则行为是实现定义的(例如正确结果、 错误结果,或编译失败)。 -
zeroPoint: 一个MLOperand。 要从每个 input 值中减去的 zero point 张量。它与 scale 具有相同的 shape。 -
options: 一个MLOperatorOptions。 指定该操作的可选参数。
返回:一个 MLOperand。
包含反量化值的输出张量。
| 操作数 | 允许的 数据类型 | 允许的秩 |
|---|---|---|
input
| "uint8",
"int8",
"uint32",
"int32"
| N |
scale
| "float32",
"float16"
| 与 input
相同
|
zeroPoint
| 与 input
相同
| 与 input
相同
|
| output | 与 scale
相同
| 与 input
相同
|
MLQuantizeDequantizeLinearSupportLimits
具有以下成员:
input,类型为 MLTensorLimits-
用于 input 操作数的
MLTensorLimits。 scale,类型为 MLTensorLimits-
用于 scale 操作数的
MLTensorLimits。 zeroPoint, 类型为 MLTensorLimits-
用于 zeroPoint 操作数的
MLTensorLimits。 output,类型为 MLTensorLimits-
用于 output 操作数的
MLTensorLimits。
MLOpSupportLimits
具有以下用于 dequantizeLinear()
的成员:
dequantizeLinear, 类型为 MLQuantizeDequantizeLinearSupportLimits-
运算符
dequantizeLinear()的支持限制。
dequantizeLinear(input, scale, zeroPoint, options)
方法步骤为:
-
如果 this.
[[hasBuilt]]为 true,则抛出一个 "InvalidStateError"DOMException。 -
如果以 验证操作数处理 this 以及 input、scale 和 zeroPoint 中的任一项返回 false,则抛出一个
TypeError。 -
如果对 scale 的shape 和 input 的shape 进行按块广播返回 false,则抛出一个
TypeError。 -
如果对 zeroPoint 的shape 和 input 的shape 进行按块广播返回 false,则抛出一个
TypeError。 -
令 outputDescriptor 为给定 scale 的dataType 和 input 的shape 时创建 MLOperandDescriptor的结果。
-
建立图连接:
-
令 output 为给定 this 和 outputDescriptor 时创建 MLOperand的结果。
-
令 operator 为给定 input、scale、zeroPoint 和 options 时用于 "dequantizeLinear" 操作的一个运算符。
-
将 output.
[[operator]]设置为 operator。 -
将 operator 的输入设置为 input。
-
将 operator 的输出设置为 output。
-
-
返回 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) { // Given the original input and a desired output shape, this expands each axis // by repeating the block the number of times per that axis. Though, backend // implementations might have much more efficient upsampling operators that // can accept multiple dimensions to upsample all dimensions at once by // integer multiples (like tile) using nearest neighbor resampling: // 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) { // Since tile/expand can only accept repetitions of entire dimension // slices (not repeating individual elements along an axis), temporarily // reshape the tensor to enable them to broadcast the elements up to the // full block size, utilizing an inserted dimension of size 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; } // Compute the flattened shape before and after the given axis, yielding a // 3-element list: e.g. // - 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))。scale 和
zeroPoint 张量可以小于 input 张量,因为它们会被按块广播。
partial interface MLGraphBuilder {MLOperand quantizeLinear (MLOperand input ,MLOperand scale ,MLOperand zeroPoint ,optional MLOperatorOptions options = {}); };partial dictionary MLOpSupportLimits {MLQuantizeDequantizeLinearSupportLimits quantizeLinear ; };
-
input: 一个MLOperand。 输入张量。 -
scale: 一个MLOperand。 在按 zero point 调整前,要用来除每个 input 值的 scale 张量。它必须与输入按块可广播。值必须为正且非零,否则行为依赖于实现 (例如正确结果、错误结果,或编译失败)。 -
zeroPoint: 一个MLOperand。 要加到每个重新缩放后的 input 值上的 zero point 张量。它与 scale 具有相同的 shape。 -
options: 一个MLOperatorOptions。 指定该操作的可选参数。
返回:一个 MLOperand。
包含量化值的输出张量。
| 操作数 | 允许的 数据类型 | 允许的秩 |
|---|---|---|
input
| "float32",
"float16"
| N |
scale
| 与 input
相同
| 与 input
相同
|
zeroPoint
| "uint8",
"int8",
"uint32",
"int32"
| 与 input
相同
|
| output | 与 zeroPoint
相同
| 与 input
相同
|
MLOpSupportLimits
具有以下用于 quantizeLinear()
的成员:
quantizeLinear, 类型为 MLQuantizeDequantizeLinearSupportLimits-
运算符
quantizeLinear()的支持限制。
quantizeLinear(input, scale, zeroPoint, options)
方法步骤为:
-
如果 this.
[[hasBuilt]]为 true,则抛出一个 "InvalidStateError"DOMException。 -
如果以 验证操作数处理 this 以及 input、scale 和 zeroPoint 中的任一项返回 false,则抛出一个
TypeError。 -
如果对 scale 的shape 和 input 的shape 进行按块广播返回 false,则抛出一个
TypeError。 -
如果对 zeroPoint 的shape 和 input 的shape 进行按块广播返回 false,则抛出一个
TypeError。 -
令 outputDescriptor 为给定 zeroPoint 的dataType 和 input 的shape 时创建 MLOperandDescriptor的结果。
-
建立图连接:
-
令 output 为给定 this 和 outputDescriptor 时创建 MLOperand的结果。
-
令 operator 为给定 input、scale、zeroPoint 和 options 时用于 "quantizeLinear" 操作的一个运算符。
-
将 output.
[[operator]]设置为 operator。 -
将 operator 的输入设置为 input。
-
将 operator 的输出设置为 output。
-
-
返回 output。
该操作的行为可以按如下方式由其他操作的使用进行通用仿真,尽管用户代理通常具有更高效的实现。 在底层平台不直接支持某个操作的情况下,这种分解可用作指导实现的模板。
function quantizeLinear( builder, input, scale, zeroPoint, options) { // output = clamp(roundEven(input / scale) + zeroPoint, 0, 255) // Note blockwiseExpand is defined in 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-
标量乘数。
-
input:一个MLOperand。 输入张量。 -
options:一个可选的MLEluOptions。 该操作的可选参数。
返回:
| 操作数 | 允许的 数据类型 | 允许的秩 |
|---|---|---|
input
| "float32",
"float16"
| N |
| output | 与 input
相同
| 与 input
相同
|
MLOpSupportLimits
具有以下用于 elu()
的成员:
elu,类型为 MLSingleInputSupportLimits-
运算符
elu()的支持限制。
elu(input, options) 方法
步骤为:
-
如果 this 不可构建,则抛出一个 "
InvalidStateError"DOMException。 -
将 options.
alpha设置为将 options.alpha转换为 input 的 dataType 的结果。 -
建立图连接:
-
令 output 为给定 input 时复制 MLOperand的结果。
-
令 operator 为给定 options 时用于 "elu" 操作的一个运算符。
-
将 output.
[[operator]]设置为 operator。 -
将 operator 的输入设置为 input。
-
将 operator 的输出设置为 output。
-
-
返回 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
根据新形状,将输入张量中任意大小为 1 的维度扩展为更大的大小。该扩展与 [numpy-broadcasting-rule] 一致。输入张量必须可单向广播到新形状;根据新形状,每个 维度的大小必须为 1,或者与对应输出维度的大小匹配。partial interface MLGraphBuilder {MLOperand expand (MLOperand input ,sequence <[EnforceRange ]unsigned long >newShape ,optional MLOperatorOptions options = {}); };partial dictionary MLOpSupportLimits {MLSingleInputSupportLimits expand ; };
-
input:一个MLOperand。 输入张量。 -
newShape: sequence<unsigned long>。 输入张量要扩展到的新形状。 -
options:一个MLOperatorOptions。 指定该操作的可选参数。
返回:一个 MLOperand。
具有扩展后大小形状的张量。
| 操作数 | 允许的 数据类型 | 允许的秩 |
|---|---|---|
input
| 任意 | N |
| output | 与 input
相同
| N |
MLOpSupportLimits
具有以下用于 expand()
的成员:
expand,类型为 MLSingleInputSupportLimits-
运算符
expand()的支持限制。
expand(input, newShape, options)
方法步骤为:
-
如果 this 不可构建,则抛出一个 "
InvalidStateError"DOMException。 -
令 outputDescriptor 为给定 input 的dataType 和 outputShape 时创建 MLOperandDescriptor的结果。
-
建立图连接:
-
令 output 为给定 this 和 outputDescriptor 时创建 MLOperand的结果。
-
令 operator 为给定 input、newShape 和 options 时用于 "expand" 操作的一个运算符。
-
将 output.
[[operator]]设置为 operator。 -
将 operator 的输入设置为 input。
-
将 operator 的输出设置为 output。
-
-
返回 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 是输入张量的秩。
indices
参数夹取到 gather()
的允许范围,因为直到执行时才知道输入。如果指定的夹取行为未由底层平台提供,实现可以在编译后的图中引入 clamp()。
类似地,如果底层平台不支持负索引,实现可以在编译后的图中引入操作,
将从维度末尾开始的负索引转换为正索引。
| 操作数 | 允许的 数据类型 | 允许的秩 |
|---|---|---|
input
| 任意 | 1 到 N |
indices
| "int32",
"uint32",
"int64"
| N |
| output | 与 input
相同
| N |
MLGatherSupportLimits
具有以下成员:
input,类型为 MLTensorLimits-
用于 input 操作数的
MLTensorLimits。 indices,类型为 MLTensorLimits-
用于 indices 操作数的
MLTensorLimits。 output,类型为 MLTensorLimits-
用于 output 操作数的
MLTensorLimits。
MLOpSupportLimits
具有以下用于 gather()
的成员:
gather,类型为 MLGatherSupportLimits-
运算符
gather()的支持限制。
gather(input, indices, options)
方法步骤为:
-
如果 this 不可构建,则抛出一个 "
InvalidStateError"DOMException。 -
如果以 验证操作数处理 this 以及 input 和 indices 中的任一项返回 false,则抛出一个
TypeError。 -
令 indicesShape 为 indices 的shape。
-
令 axis 为 options.
axis。 -
令 dimCount 为零。
-
令 outputRank 为零。
-
令 outputShape 为空列表。
-
对于 inputShape 的每个 size:
-
如果 dimCount 等于 axis,则中断。
-
将 outputShape[dimCount] 设置为 size。
-
将 dimCount 加一。
-
-
将 outputRank 设置为 dimCount。
-
令 dimCount 为零。
-
对于 indicesShape 的每个 size:
-
将 outputShape[outputRank + dimCount] 设置为 size。
-
将 dimCount 加一。
-
-
将 outputRank 设置为 outputRank + dimCount。
-
令 dimCount 为零。
-
对于 inputShape 的每个 size:
-
如果 dimCount 小于或等于 axis,则继续。
-
将 outputShape[outputRank + dimCount - axis - 1] 设置为 size。
-
将 dimCount 加一。
-
-
令 desc 为给定 input 的dataType 和 outputShape 时创建 MLOperandDescriptor的结果。
-
建立图连接:
-
令 output 为给定 desc 时创建 MLOperand的结果。
-
令 operator 为给定 input、indices 和 options 时用于 "gather" 操作的一个运算符。
-
将 output.
[[operator]]设置为 operator。 -
将 operator 的输入设置为 input 和 indices。
-
将 operator 的输出设置为 output。
-
-
返回 output。
gather 如何在不同切片方案中工作的示例。
// input of shape [4,3]: // [[ 0, 1, 2], // [10, 11, 12], // [20, 21, 22], // [30, 31, 32]] const input= builder. constant( { dataType: 'float32' , shape: [ 4 , 3 ]}, new Float32Array([ 0 , 1 , 2 , 10 , 11 , 12 , 20 , 21 , 22 , 30 , 31 , 32 ])); // axis = 0 (default) // indices of shape [2]: // [3,1] // output of shape [2,3]: // [[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 // indices of shape [3]: // [2,1,1] // output of shape [4,3]: // [[ 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 // indices of shape [2,2]: // [[0, 1], // [1, 2]] // output of shape [4,2,2]: // [[[ 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 ; };
| 操作数 | 允许的 数据类型 | 允许的秩 |
|---|---|---|
input
| 任意 | 1 到 N |
indices
| "int32",
"uint32",
"int64"
| 与 input
相同
|
| output | 与 input
相同
| 与 input
相同
|
MLOpSupportLimits
具有以下用于 gatherElements()
的成员:
gatherElements, 类型为 MLGatherSupportLimits-
运算符
gatherElements()的支持限制。
indices
参数夹取到 gatherElements()
的允许范围,因为直到执行时才知道输入。如果指定的夹取行为未由底层平台提供,实现可以在编译后的图中引入 clamp()。
类似地,如果底层平台不支持负索引,实现可以在编译后的图中引入操作,
将从维度末尾开始的负索引转换为正索引。
gatherElements(input, indices, options)
方法步骤为:
-
如果 this 不可构建,则抛出一个 "
InvalidStateError"DOMException。 -
如果以 验证操作数处理 this 以及 input 和 indices 中的任一项返回 false,则抛出一个
TypeError。 -
令 axis 为 options.
axis。 -
令 indicesShapeExpected 为 input 的shape 的副本。
-
将 indicesShapeExpected[axis] 设置为 indices 的shape[axis]。
-
如果 indices 的shape 不等于 indicesShapeExpected, 则抛出一个
TypeError。 -
建立图连接:
-
令 output 为给定 input 时复制 MLOperand的结果。
-
令 operator 为给定 input、indices 和 options 时用于 "gatherElements" 操作的一个运算符。
-
将 output.
[[operator]]设置为 operator。 -
将 operator 的输入设置为 input 和 indices。
-
将 operator 的输出设置为 output。
-
-
返回 output。
gatherElements 如何在不同切片方案中工作的示例。
// input of shape [4,3]: // [[ 0, 1, 2], // [10, 11, 12], // [20, 21, 22], // [30, 31, 32]] // indices of shape [2,3]: // [[3, 1, 1], // [2, 0, 3]] // axis = 0 (default) // output of shape [2,3]: // [[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); // input of shape [4,3]: // [[ 0, 1, 2], // [10, 11, 12], // [20, 21, 22], // [30, 31, 32]] // indices of shape [4,1]: // [[2], // [1], // [0], // [2]], // axis = 1 // output of shape [4,1]: // [[ 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 }); // input of shape [4,2,2]: // [[[ 0, 1], // [ 10, 11]], // [[100, 101], // [110, 111]], // [[200, 201], // [210, 211]], // [[300, 301], // [310, 311]],] // indices of shape [1,2,2]: // [[[0, 2], // [1, 3]]], // axis = 0 // output of shape [1,2,2]: // [[[ 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 ; };
-
input:一个MLOperand。 要从中收集值的输入 N 维张量。 -
indices: 一个MLOperand。 indices 数组包含指向输入张量的完整坐标,最右侧维度保存每个坐标的维度数。 因此,形状为 [10,1] 的 indices 张量保存 10 个单轴索引, 形状为 [4,3] 的张量保存 4 个三维坐标索引。这些值必须是"int32"、"uint32"或"int64"类型,并且每个值都必须位于 -N(含)到 N(不含)的范围内,其中 N 是对应输入维度的大小, 负索引表示从对应维度末尾开始索引。 -
options: 一个可选的MLOperatorOptions。 该操作的可选参数。
返回:一个 MLOperand。
输出 N 维张量,其秩等于 input
的
秩 + indices
的
秩 - indices
的
shape[-1] - 1。
| 操作数 | 允许的 数据类型 | 允许的秩 |
|---|---|---|
input
| 任意 | 1 到 N |
indices
| "int32",
"uint32",
"int64"
| 1 到 N |
| output | 与 input
相同
| N |
MLOpSupportLimits
具有以下用于 gatherND()
的成员:
gatherND,类型为 MLGatherSupportLimits-
运算符
gatherND()的支持限制。
indices
参数夹取到 gatherND()
的允许范围,因为直到执行时才知道输入。如果指定的夹取行为未由底层平台提供,实现可以在编译后的图中引入 clamp()。
类似地,如果底层平台不支持负索引,实现可以在编译后的图中引入操作,
将从维度末尾开始的负索引转换为正索引。
gatherND(input, indices, options)
方法步骤为:
-
如果 this 不可构建,则抛出一个 "
InvalidStateError"DOMException。 -
如果以 验证操作数处理 this 以及 input 和 indices 中的任一项返回 false,则抛出一个
TypeError。 -
令 indicesShape 为 indices 的shape,并令 indicesRank 为 indices 的秩。
-
令 indexableSize 为 indicesRank - 1。
-
令 coordinateSize 为 indicesShape[indexableSize]。
-
令 outputShape 为空列表。
-
对于范围 0 到 indexableSize(不含)中的每个 index:
-
将 indicesShape[index] 追加到 outputShape。
-
-
对于范围 coordinateSize 到 inputRank(不含)中的每个 index:
-
将 inputShape[index] 追加到 outputShape。
-
-
令 outputDesc 为给定 input 的dataType 和 outputShape 时创建 MLOperandDescriptor的结果。
-
建立图连接:
-
令 output 为给定 outputDesc 时创建 MLOperand的结果。
-
令 operator 为给定 input、indices 和 options 时用于 "gatherND" 操作的一个运算符。
-
将 output.
[[operator]]设置为 operator。 -
将 operator 的输入设置为 input 和 indices。
-
将 operator 的输出设置为 output。
-
-
返回 output。
gatherND 如何在不同切片方案中工作的示例。
// input of shape [2,2]: // [[0, 1], // [2, 3]] // indices of shape [3,2]: // [[0, 0], // [1, 1], // [1, 0]] // output of shape [3]: // [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); // input of shape [2,2]: // [[0, 1], // [2, 3]] // indices of shape [2,1]: // [[1], // [0]] // output of shape [2,2]: // [[2, 3] <= row [2, 3] from input coordinates [1, *] // [0, 1]] <= row [0, 1] from input coordinates [0, *] const indices2= builder. constant( { dataType: 'uint32' , shape: [ 2 , 1 ]}, new Uint32Array([ 1 , 0 ])); const output2= builder. gatherND( input1, indices2); // input of shape [2,2,2]: // [[[0, 1], // [2, 3]], // [[4, 5], // [6, 7]]] // indices of shape [2,2]: // [[0, 1], // [1, 0]] // output of shape [2,2]: // [[2, 3], <= row [2, 3] from input coordinates [0, 1, *] // [4, 5]] <= row [4, 5] from input coordinates [1, 0, *] 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); // input of shape [2,2,2]: // [[[0, 1], // [2, 3]], // [[4, 5], // [6, 7]]] // indices of shape [3,1]: // [[1], // [0], // [1]] // output of shape [3,2,2]: // [[[4, 5], <= block [[4, 5], [6, 7]] from input coordinates [1, *, *] // [6, 7]], // [[0, 1], <= block [[0, 1], [2, 3]] from input coordinates [0, *, *] // [2, 3]], // [[4, 5], <= block [[4, 5], [6, 7]] from input coordinates [1, *, *] // [6, 7]]] const indices4= builder. constant( { dataType: 'uint32' , shape: [ 3 , 1 ]}, new Uint32Array([ 1 , 0 , 1 ])); const output4= builder. gatherND( input2, indices4); // input of shape [2,2,2]: // [[[0, 1], // [2, 3]], // [[4, 5], // [6, 7]]] // indices of shape [5,3]: // [[0,0,1], // [0,1,0], // [1,0,0], // [1,1,0], // [1,1,1]] // output of shape [5]: // [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 ; };
-
input:一个MLOperand。 输入张量。 -
options:一个MLOperatorOptions。 指定该操作的可选参数。
返回:
| 操作数 | 允许的 数据类型 | 允许的秩 |
|---|---|---|
input
| "float32",
"float16"
| N |
| output | 与 input
相同
| 与 input
相同
|
MLOpSupportLimits
具有以下用于 gelu()
的成员:
gelu,类型为 MLSingleInputSupportLimits-
运算符
gelu()的支持限制。
gelu(input, options) 方法
步骤为:
-
如果 this 不可构建,则抛出一个 "
InvalidStateError"DOMException。 -
建立图连接:
-
令 output 为给定 input 时复制 MLOperand的结果。
-
令 operator 为给定 options 时用于 "gelu" 操作的一个运算符。
-
将 output.
[[operator]]设置为 operator。 -
将 operator 的输入设置为 input。
-
将 operator 的输出设置为 output。
-
-
返回 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
计算 基本线性代数子程序的通用矩阵 乘法。计算遵循表达式alpha * A * B + beta * C,其中 A 是形状为 [M, K] 或
[K, M] 的二维张量,B 是形状为 [K, N] 或 [N, K] 的二维张量,并且
C 可单向广播到形状 [M,
N]。A 和 B 可选地在计算前进行转置。
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,类型为 MLOperandalpha,类型为 double,默认为1.0-
第一个输入的乘数。
beta,类型为 double,默认为1.0-
第三个输入
c的乘数。 aTranspose,类型为 boolean,默认为false-
指示在计算输出前是否转置第一个输入。
bTranspose,类型为 boolean,默认为false-
指示在计算输出前是否转置第二个输入。
-
a:一个MLOperand。 第一个输入二维张量,当aTranspose为 false 时其形状为 [M, K],当aTranspose为 true 时其形状为 [K, M]。 -
b:一个MLOperand。 第二个输入二维张量,当bTranspose为 false 时其形状为 [K, N],当bTranspose为 true 时其形状为 [N, K]。 -
options:一个可选的MLGemmOptions。 该操作的可选参数。
返回:一个 MLOperand。
形状为 [M, N] 的输出二维张量,其中包含所有输入的计算乘积。
| 操作数 | 允许的 数据类型 | 允许的秩 |
|---|---|---|
a
| "float32",
"float16"
| 2 |
b
| 与 a
相同
| 2 |
c
| 与 a
相同
| 0 到 2 |
| output | 与 a
相同
| 2 |
MLGemmSupportLimits
具有以下成员:
a,类型为 MLTensorLimits-
用于 a 操作数的
MLTensorLimits。 b,类型为 MLTensorLimits-
用于 b 操作数的
MLTensorLimits。 c,类型为 MLTensorLimits-
用于 c 操作数的
MLTensorLimits。 output,类型为 MLTensorLimits-
用于 output 操作数的
MLTensorLimits。
MLOpSupportLimits
具有以下用于 gemm()
的成员:
gemm,类型为 MLGemmSupportLimits-
运算符
gemm()的支持限制。
gemm(a, b, options)
方法步骤为:
-
如果 this 不可构建,则抛出一个 "
InvalidStateError"DOMException。 -
如果 options.
aTranspose为 true,则反转 shapeA 中项的顺序。 -
如果 options.
bTranspose为 true,则反转 shapeB 中项的顺序。 -
令 desc 为给定 a 的dataType 和 « shapeA[0], shapeB[1] » 时创建 MLOperandDescriptor的结果。
-
建立图连接:
-
令 output 为给定 this 和 desc 时创建 MLOperand的结果。
-
令 operator 为给定 options 时用于 "gemm" 操作的一个运算符。
-
将 output.
[[operator]]设置为 operator。 -
将 operator 的输入设置为 a 和 b。
-
将 operator 的输出设置为 output。
-
-
返回 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
门控循环单元 [GRU] 循环网络使用 update、reset 和 new 门来计算输出状态,该状态会在网络的时间序列中滚入输出。enum {MLGruWeightLayout , // update-reset-new gate ordering"zrn" // reset-update-new gate ordering };"rzn" 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-
形状为 [numDirections, 3 * hiddenSize] 的二维输入偏置张量。张量形状的第二个维度中的偏置 向量顺序按
layout指定。 recurrentBias,类型为 MLOperand-
形状为 [numDirections, 3 * hiddenSize] 的二维循环偏置张量。张量形状的第二个维度中的 偏置向量顺序按
layout指定。 initialHiddenState, 类型为 MLOperand-
形状为 [numDirections, batchSize, hiddenSize] 的三维初始隐藏状态张量。 未指定时,实现必须使用以零填充的张量。
resetAfter,类型为 boolean,默认为true-
指示是在矩阵乘法之后还是之前应用 reset 门。
returnSequence,类型为 boolean,默认为false-
指示除最后一个时间步的输出外,是否还返回包含每个时间步中每个输出的整个序列。
direction,类型为 MLRecurrentNetworkDirection,默认为"forward"-
输入序列的处理方向。当设置为
"both"时,weight 和 bias 张量形状的第一个维度大小必须为 2,并且输入会在两个方向上处理。 layout,类型为 MLGruWeightLayout,默认为"zrn"-
GRU 内部门的权重和偏置向量的顺序,具体为
update (z)、reset (r)和new (n)门,按 weight 和 bias 张量形状的第二个维度所示。 activations,类型为 sequence<MLRecurrentNetworkActivation>-
指定一对激活函数,第一个函数用于 update 和 reset 门,第二个用于 new 门。 未指定时,分别默认为
"sigmoid"和"tanh"函数。
-
input: 一个MLOperand。 形状为 [steps, batchSize, inputSize] 的输入三维张量。 -
weight: 一个MLOperand。 形状为 [numDirections, 3 * hiddenSize, inputSize] 的三维输入权重张量。张量形状的 第二个维度中的权重向量顺序按layout指定。 -
recurrentWeight: 一个MLOperand。 形状为 [numDirections, 3 * hiddenSize, hiddenSize] 的三维循环权重张量。 张量形状的第二个维度中的权重向量顺序按layout指定。 -
steps: 一个unsigned long标量。循环网络中的时间步数。该值必须大于 0。 -
hiddenSize: 一个unsigned long标量。单元输出张量形状第三个维度的值。它指示隐藏状态中的特征数量。 -
options: 一个可选的MLGruOptions。 该操作的可选参数。
返回:sequence<MLOperand>。
第一个元素是形状为 [numDirections, batchSize, hiddenSize] 的三维张量,即网络最后一个时间步的
单元输出。此外,如果 returnSequence
设置为 true,则第二个元素是形状为 [steps, numDirections,
batchSize, hiddenSize] 的四维输出张量,包含时间序列中每个时间步的每个单元输出。
| 操作数 | 允许的 数据类型 | 允许的秩 |
|---|---|---|
| "float32",
"float16"
| 3 |
| 与
相同
| 3 |
| 与
相同
| 3 |
bias
| 与
相同
| 2 |
recurrentBias
| 与
相同
| 2 |
| 与
相同
| 3 |
| outputs[0] | 与
相同
| 3 |
如果 returnSequence
为 true,则 outputs[1]
| 与
相同
| 4 |
MLGruSupportLimits
具有以下成员:
input,类型为 MLTensorLimits-
用于 input 操作数的
MLTensorLimits。 weight,类型为 MLTensorLimits-
用于 weight 操作数的
MLTensorLimits。 recurrentWeight, 类型为 MLTensorLimits-
用于 recurrentWeight 操作数的
MLTensorLimits。 bias,类型为 MLTensorLimits-
用于 bias 操作数的
MLTensorLimits。 recurrentBias, 类型为 MLTensorLimits-
用于 recurrentBias 操作数的
MLTensorLimits。 initialHiddenState, 类型为 MLTensorLimits-
用于 initialHiddenState 操作数的
MLTensorLimits。 output0,类型为 MLTensorLimits-
用于所有 output 操作数[0]的
MLTensorLimits。 output1,类型为 MLTensorLimits-
用于所有 output 操作数[1]的
MLTensorLimits。
MLOpSupportLimits
具有以下用于 gru()
的成员:
gru,类型为 MLGruSupportLimits-
运算符
gru()的支持限制。
gru(input, weight, recurrentWeight, steps, hiddenSize, options)
方法步骤为:
-
如果 this 不可构建,则抛出一个 "
InvalidStateError"DOMException。 -
如果以 验证操作数处理 this 以及 input、weight、 recurrentWeight、options.
bias(如果它存在)、options.recurrentBias(如果它存在)和 options.(如果它存在)中的任一项返回 false,则抛出一个TypeError。 -
如果 input、weight 或 recurrentWeight 中任一项的dataType 不是其允许的数据类型之一 (根据此表),则抛出一个
TypeError。 -
如果 input、weight 或 recurrentWeight 中任一项的秩不是其允许的秩, 则抛出一个
TypeError。 -
令 batchSize 为 input 的shape[1]。
-
令 inputSize 为 input 的shape[2]。
-
如果 weight 的shape 不等于 « numDirections, 3 * hiddenSize, inputSize »,则抛出一个
TypeError。 -
如果 recurrentWeight 的shape 不等于 « numDirections, 3 * hiddenSize, hiddenSize »,则抛出一个
TypeError。 -
如果 hiddenSize * 6 不是有效维度,则抛出一个
TypeError。为什么是 hiddenSize * 6?
某些底层平台在单个 bias 张量上操作,该张量是bias和recurrentBias的连接。因此,3 * hiddenSize + 3 * hiddenSize 也需要是有效 维度。 -
如果 options.
recurrentBias存在,则: -
如果 options.
存在,则: -
如果 options.
activations存在,则:-
令 activations 为 options.
activations的克隆。
-
否则:
-
计算输出形状:
-
令 desc0 为给定 input 的dataType 和 « numDirections, batchSize, hiddenSize » 时创建 MLOperandDescriptor 的结果。
-
如果 options.
returnSequence为 true,则:-
令 desc1 为给定 input 的dataType 和 « steps, numDirections, batchSize, hiddenSize » 时创建 MLOperandDescriptor的结果。
-
-
-
建立图连接:
-
令 operator 为给定 weight、recurrentWeight、steps、hiddenSize 和 options 时用于 "gru" 操作的一个运算符。
-
令 output0 为给定 this 和 desc0 时创建 MLOperand的结果。
-
如果 options.
returnSequence为 true,则:-
令 output1 为给定 this 和 desc1 时创建 MLOperand的结果。
-
令 output 为列表 « output0, output1 »。
-
将 output0.
[[operator]]和 output1.[[operator]]设置为 operator。
-
-
否则:
-
令 output 为列表 « output0 »。
-
将 output0.
[[operator]]设置为 operator。
-
-
将 operator 的输入设置为 input、weight 和 recurrentWeight。
-
如果 options.
recurrentBias存在,则将它添加到 operator 的输入。 -
将 operator 的输出设置为 output。
-
-
返回 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) { // Expand currentHidden of 2D([batchSize, hiddenSize]) // to 4D([steps, numDirections, batchSize, hiddenSize]) const expandedHiddenAs4D= builder. reshape( currentHidden, [ 1 , 1 , batchSize, hiddenSize]); if ( direction== 'forward' || ( dir== 0 && direction== 'both' )) { forwardSequence= forwardSequence? builder. concat([ forwardSequence, expandedHiddenAs4D], 0 ) : expandedHiddenAs4D; } else if ( direction== 'backward' || ( dir== 1 && direction== 'both' )) { backwardSequence= backwardSequence? builder. concat([ expandedHiddenAs4D, backwardSequence], 0 ) : expandedHiddenAs4D; } } } // Expand currentHidden of 2D([batchSize, hiddenSize]) // to 3D([numDirections, batchSize, hiddenSize]) const expandedHiddenAs3D= builder. reshape( currentHidden, [ 1 , batchSize, hiddenSize]); outputHidden= outputHidden? builder. concat([ outputHidden, expandedHiddenAs3D], 0 ) : expandedHiddenAs3D; } if ( options. returnSequence) { let outputSequence= null ; if ( direction== 'forward' ) { outputSequence= forwardSequence; } else if ( direction== 'backward' ) { outputSequence= backwardSequence; } else if ( direction== 'both' ) { // Concat along axis 1 (numDirections dimension) outputSequence= builder. concat([ forwardSequence, backwardSequence], 1 ); } return [ outputHidden, outputSequence]; } else { return [ outputHidden]; } }
8.9.26. gruCell
门控循环单元 [GRU] 循环网络的单个时间步,使用 update 门和 reset 门来计算隐藏状态,该状态会在循环网络的时间序列中滚入输出。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-
形状为 [3 * hiddenSize] 的一维输入偏置张量。张量形状的第二个维度中的偏置向量顺序 按
layout指定。 recurrentBias,类型为 MLOperand-
形状为 [3 * hiddenSize] 的一维循环偏置张量。张量形状的第二个维度中的偏置向量顺序 按
layout指定。 resetAfter,类型为 boolean,默认为true-
指示是在矩阵乘法之后还是之前应用 reset 门。
layout,类型为 MLGruWeightLayout,默认为"zrn"-
GRU 内部门的权重和偏置向量的顺序,具体为
update (z)、reset (r)和new (n)门,按 weight 和 bias 张量形状的第二个维度所示。 activations,类型为 sequence<MLRecurrentNetworkActivation>-
指定一对激活函数,第一个函数用于 update 和 reset 门,第二个用于 new 门。 未指定时,分别默认为
"sigmoid"和"tanh"函数。
-
input: 一个MLOperand。 形状为 [batchSize, inputSize] 的输入二维张量。 -
weight: 一个MLOperand。 形状为 [3 * hiddenSize, inputSize] 的二维输入权重张量。张量形状的第一个维度中的 权重向量顺序按layout指定。 -
recurrentWeight: 一个MLOperand。 形状为 [3 * hiddenSize, hiddenSize] 的二维循环权重张量。张量形状的第一个维度中的 权重向量顺序按layout指定。 -
hiddenState: 一个MLOperand。 形状为 [batchSize, hiddenSize] 的输入二维隐藏状态张量。 -
hiddenSize: 一个unsigned long标量。输出张量形状第二个维度的值。它指示隐藏状态中的特征数量。 -
options: 一个可选的MLGruCellOptions。 该操作的可选参数。
返回:一个 MLOperand。
形状为 [batchSize, hiddenSize] 的二维张量,即循环网络单个时间步的单元输出隐藏状态。
| 操作数 | 允许的 数据类型 | 允许的秩 |
|---|---|---|
| "float32",
"float16"
| 2 |
| 与
相同
| 2 |
| 与
相同
| 2 |
bias
| 与
相同
| 1 |
recurrentBias
| 与
相同
| 1 |
| output | 与
相同
| 2 |
MLGruCellSupportLimits
具有以下成员:
input,类型为 MLTensorLimits-
用于 input 操作数的
MLTensorLimits。 weight,类型为 MLTensorLimits-
用于 weight 操作数的
MLTensorLimits。 recurrentWeight,类型为 MLTensorLimits-
用于 recurrentWeight 操作数的
MLTensorLimits。 hiddenState,类型为 MLTensorLimits-
用于 hiddenState 操作数的
MLTensorLimits。 bias,类型为 MLTensorLimits-
用于 bias 操作数的
MLTensorLimits。 recurrentBias,类型为 MLTensorLimits-
用于 recurrentBias 操作数的
MLTensorLimits。 output,类型为 MLTensorLimits-
用于 output 操作数的
MLTensorLimits。
MLOpSupportLimits
具有以下用于 gruCell()
的成员:
gruCell,类型为 MLGruCellSupportLimits-
运算符
gruCell()的支持限制。
gruCell(input, weight, recurrentWeight, hiddenState, hiddenSize, options)
方法步骤为:
-
如果 this 不可构建,则抛出一个 "
InvalidStateError"DOMException。 -
如果以 验证操作数处理 this 以及 input、weight、 recurrentWeight、hiddenState、options.
bias(如果它存在)和 options.recurrentBias(如果它存在)中的任一项返回 false,则抛出一个TypeError。 -
如果 input、weight、recurrentWeight 或 hiddenState 中任一项的dataType 不是其允许的 数据类型之一(根据此表),则抛出一个
TypeError。 -
如果 input、weight、recurrentWeight 或 hiddenState 中任一项的秩 不是其允许的 秩(根据此表),则抛出一个
TypeError。 -
令 batchSize 为 input 的shape[0]。
-
令 inputSize 为 input 的shape[1]。
-
如果 weight 的shape 不等于 « 3 * hiddenSize, inputSize », 则抛出一个
TypeError。 -
如果 recurrentWeight 的shape 不等于 « 3 * hiddenSize, hiddenSize », 则抛出一个
TypeError。 -
如果 hiddenState 的shape 不等于 « batchSize, hiddenSize »,则 抛出一个
TypeError。 -
如果 hiddenSize * 6 不是有效维度,则抛出一个
TypeError。为什么是 hiddenSize * 6?
某些底层平台在单个 bias 张量上操作,该张量是bias和recurrentBias的连接。因此,3 * hiddenSize + 3 * hiddenSize 也需要是有效 维度。 -
如果 options.
recurrentBias存在,则: -
如果 options.
activations存在,则:-
令 activations 为 options.
activations的克隆。
-
否则:
-
令 desc 为给定 input 的dataType 和 « batchSize, hiddenSize » 时创建 MLOperandDescriptor的结果。
-
建立图连接:
-
令 output 为给定 this 和 desc 时创建 MLOperand的结果。
-
令 operator 为给定 weight、recurrentWeight、hiddenState、 hiddenSize 和 options 时用于 "gruCell" 操作的一个运算符。
-
将 output.
[[operator]]设置为 operator。 -
将 operator 的输入设置为 input、weight、 recurrentWeight 和 hiddenState。
-
如果 options.
recurrentBias存在,则将它添加到 operator 的输入。 -
将 operator 的输出设置为 output。
-
-
返回 output。
当权重布局为默认的 "zrn"
布局,并且 update/reset 门和 new 门的激活函数分别为 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])))))); } // compute the new hidden state return builder. add( builder. mul( z, hiddenState), builder. mul( n, builder. sub( one, z))); }
8.9.27. hardSigmoid
对输入张量计算非平滑 hard sigmoid 函数, 用它代替 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-
标量加数。
-
input:一个MLOperand。 输入张量。 -
options:一个 可选的MLHardSigmoidOptions。 该操作的可选参数。
返回:
| 操作数 | 允许的 数据类型 | 允许的秩 |
|---|---|---|
input
| "float32",
"float16"
| N |
| output | 与 input
相同
| 与 input
相同
|
MLOpSupportLimits
具有以下用于 hardSigmoid()
的成员:
hardSigmoid,类型为 MLSingleInputSupportLimits-
运算符
hardSigmoid()的支持限制。
hardSigmoid(input, options)
方法步骤为:
-
如果 this 不可构建,则抛出一个 "
InvalidStateError"DOMException。 -
将 options.
alpha设置为将 options.alpha转换为 input 的 dataType 的结果。 -
建立图连接:
-
令 output 为给定 input 时复制 MLOperand的结果。
-
令 operator 为给定 options 时用于 "hardSigmoid" 操作的一个运算符。
-
将 output.
[[operator]]设置为 operator。 -
将 operator 的输入设置为 input。
-
将 operator 的输出设置为 output。
-
-
返回 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 ; };
-
input:一个MLOperand。 输入张量。 -
options:一个MLOperatorOptions。 指定该操作的可选参数。
返回:
| 操作数 | 允许的 数据类型 | 允许的秩 |
|---|---|---|
input
| "float32",
"float16"
| N |
| output | 与 input
相同
| 与 input
相同
|
MLOpSupportLimits
具有以下用于 hardSwish()
的成员:
hardSwish,类型为 MLSingleInputSupportLimits-
运算符
hardSwish()的支持限制。
hardSwish(input, options)
方法步骤为:
-
如果 this 不可构建,则抛出一个 "
InvalidStateError"DOMException。 -
建立图连接:
-
令 output 为给定 input 时复制 MLOperand的结果。
-
令 operator 为给定 options 时用于 "hardSwish" 操作的一个运算符。
-
将 output.
[[operator]]设置为 operator。 -
将 operator 的输入设置为 input。
-
将 operator 的输出设置为 output。
-
-
返回 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] 对输入进行归一化。不同于batchNormalization()
中在训练模型时跨批量维度中的所有样本计算用于归一化的均值和方差值,实例归一化中使用的均值和方差值会针对批量中
每个单独样本的每个输入特征即时计算。
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-
缩放值的一维张量,其大小等于通道数, 即输入的特征维度大小。例如,对于具有
input张量的"nchw"布局,其大小等于input的 shape[1]。 bias,类型为 MLOperand-
偏置值的一维张量,其大小等于输入的 特征维度大小。例如,对于具有
input张量的"nchw"布局,其大小等于input的 shape[1]。 epsilon,类型为 double,默认为1e-5-
用于防止因除以零而导致计算错误的小值。
layout,类型为 MLInputOperandLayout,默认为"nchw"-
输入的布局格式。
-
input: 一个MLOperand。 输入四维张量。 -
options: 一个可选的MLInstanceNormalizationOptions。 该操作的可选参数。
| 操作数 | 允许的 数据类型 | 允许的秩 |
|---|---|---|
input
| "float32",
"float16"
| 4 |
scale
| 与 input
相同
| 1 |
bias
| 与 input
相同
| 1 |
| output | 与 input
相同
| 4 |
MLNormalizationSupportLimits
具有以下成员:
input,类型为 MLTensorLimits-
用于 input 操作数的
MLTensorLimits。 scale,类型为 MLTensorLimits-
用于 scale 操作数的
MLTensorLimits。 bias,类型为 MLTensorLimits-
用于 bias 操作数的
MLTensorLimits。 output,类型为 MLTensorLimits-
用于 output 操作数的
MLTensorLimits。
MLOpSupportLimits
具有以下用于 instanceNormalization()
的成员:
instanceNormalization, 类型为 MLNormalizationSupportLimits-
运算符
instanceNormalization()的支持限制。
instanceNormalization(input, options)
方法步骤为:
当输入张量是 "nchw"
布局的四维张量时,该操作的行为可以按如下方式由其他操作的使用进行通用仿真,尽管用户代理通常具有更高效的实现。
在底层平台不直接支持某个操作的情况下,这种分解可用作指导实现的模板。
function instanceNormalization( builder, input, options) { // The reduction of the mean and variance values happens over the spatial // dimensions of the input e.g. axis 2 and 3 of the input tensor. const reduceOptions= { axes: [ 2 , 3 ], keepDimensions: true }; const mean= builder. reduceMean( input, reduceOptions); const variance= builder. reduceMean( builder. pow( builder. sub( input, mean), builder. constant( input. dataType, 2 )), reduceOptions); // The scale and bias values are applied per input feature // e.g. axis 1 of the input tensor. const shape= [ 1 , input. shape[ 1 ], 1 , 1 ]; return builder. add( builder. mul( builder. reshape( options. scale, shape), builder. div( builder. sub( input, mean), builder. sqrt( builder. add( variance, options. epsilon)))), builder. reshape( options. bias, shape)); }
8.9.30. layerNormalization
使用 [Layer-Normalization] 对输入进行归一化。不同于batchNormalization()
中在训练模型时跨批量维度中的所有样本计算均值和方差值,以及 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 ; };
MLLayerNormalizationOptions
具有以下成员:
scale,类型为 MLOperand-
缩放值的 N 维张量,其形状由
axes成员决定,其中axes中的每个值指示输入张量中具有缩放值的维度。例如,对于值为 [1,2,3] 的axes, 该张量的形状是输入维度 1、2 和 3 的对应大小列表。未存在该成员时,缩放值假定为 1。 bias,类型为 MLOperand-
偏置值的 N 维张量,其形状由
axes成员决定,其中axes中的每个值指示输入张量中具有偏置值的维度。例如,对于值为 [1,2,3] 的axes, 该张量的形状是输入维度 1、2 和 3 的对应大小列表。未存在该成员时,偏置值假定为 0。 axes,类型为sequence<[EnforceRange] unsigned long>-
要规约的输入维度索引。未存在该成员时,会按给出除第一个维度之外的所有维度处理 (例如,对于四维输入张量,
axes= [1,2,3])。也就是说,均值和方差值的规约是跨每个独立批次的所有输入特征计算的。 如果为空,则不规约任何维度。 epsilon,类型为 double,默认为1e-5-
用于防止因除以零而导致计算错误的小值。
-
input:一个MLOperand。 输入 N 维张量。 -
options: 一个可选的MLLayerNormalizationOptions。 该操作的可选参数。
| 操作数 | 允许的 数据类型 | 允许的秩 |
|---|---|---|
input
| "float32",
"float16"
| N |
scale
| 与 input
相同
| N |
bias
| 与 input
相同
| N |
| output | 与 input
相同
| 与 input
相同
|
MLOpSupportLimits
具有以下用于 layerNormalization()
的成员:
layerNormalization, 类型为 MLNormalizationSupportLimits-
运算符
layerNormalization()的支持限制。
layerNormalization(input, options)
方法步骤为:
-
如果 this 不可构建,则抛出一个 "
InvalidStateError"DOMException。 -
如果以 验证操作数处理 this 以及 input、options.
scale(如果它存在)和 options.bias(如果它存在)中的任一项返回 false,则抛出一个TypeError。 -
如果 options.
axes不存在,则将 options.axes设置为一个新的列表:如果 input 的秩大于 1,则为从 1 到 input 的秩(不含)的范围; 否则为空列表。 -
否则,如果 options.
axes包含重复值,或者其任一项不在从 0 到 input 的秩(不含)的范围内,则抛出一个TypeError。 -
将 options.
epsilon设置为将 options.epsilon转换为 input 的 dataType 的结果。 -
建立图连接:
-
返回 output。
当 axes 参数设置为 [1,2,3] 时,该操作的行为可以按如下方式由其他操作的使用进行通用仿真,尽管用户代理通常具有 更高效的实现。在底层平台不直接支持某个操作的情况下,这种分解可用作指导实现的模板。
function layerNormalization( builder, input, options) { // 均值和方差值的规约发生在输入张量所有输入特征 //(即所有通道)上的空间维度。 // tensor. const reduceOptions= { axes: [ 1 , 2 , 3 ], keepDimensions: true }; const mean= builder. reduceMean( input, reduceOptions); const variance= builder. reduceMean( builder. pow( builder. sub( input, mean), builder. constant( input. dataType, 2 )), reduceOptions); // scale 和 bias 张量的形状由 axes 参数中的值指定的 // input 的形状决定(即 [1,2,3])。 return builder. add( builder. mul( options. scale, builder. div( builder. sub( input, mean), builder. sqrt( builder. add( variance, options. epsilon)))), options. bias); }
8.9.31. leakyRelu
对输入张量逐元素计算带泄漏版本的 修正线性函数。计算遵循表达式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-
标量乘数。
-
input:一个MLOperand。 输入张量。 -
options:一个可选的MLLeakyReluOptions。 该操作的可选参数。
返回:
| 操作数 | 允许的 数据类型 | 允许的秩 |
|---|---|---|
input
| "float32",
"float16"
| N |
| output | 与 input
相同
| 与 input
相同
|
MLOpSupportLimits
具有以下用于 leakyRelu()
的成员:
leakyRelu,类型为 MLSingleInputSupportLimits-
运算符
leakyRelu()的支持限制。
leakyRelu(input, options)
方法步骤为:
-
如果 this 不可构建,则抛出一个 "
InvalidStateError"DOMException。 -
将 options.
alpha设置为将 options.alpha转换为 input 的 dataType 的结果。 -
建立图连接:
-
令 output 为给定 input 时复制 MLOperand的结果。
-
令 operator 为给定 options 时用于 "leakyRelu" 操作的一个运算符。
-
将 output.
[[operator]]设置为 operator。 -
将 operator 的输入设置为 input。
-
将 operator 的输出设置为 output。
-
-
返回 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-
标量加数。
-
input:一个MLOperand。 输入张量。 -
options:一个可选的MLLinearOptions。 该操作的可选参数。
返回:
| 操作数 | 允许的 数据类型 | 允许的秩 |
|---|---|---|
input
| "float32",
"float16"
| N |
| output | 与 input
相同
| 与 input
相同
|
MLOpSupportLimits
具有以下用于 linear()
的成员:
linear,类型为 MLSingleInputSupportLimits-
运算符
linear()的支持限制。
linear(input, options)
方法步骤为:
-
如果 this 不可构建,则抛出一个 "
InvalidStateError"DOMException。 -
将 options.
alpha设置为将 options.alpha转换为 input 的 dataType 的结果。 -
建立图连接:
-
令 output 为给定 input 时复制 MLOperand的结果。
-
令 operator 为给定 options 时用于 "linear" 操作的一个运算符。
-
将 output.
[[operator]]设置为 operator。 -
将 operator 的输入设置为 input。
-
将 operator 的输出设置为 output。
-
-
返回 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
长短期记忆 [LSTM] 循环网络使用 input、output、forget 和 cell 门来计算输出状态,该状态会在网络的时间序列中滚入输出。enum {MLLstmWeightLayout , // input-output-forget-cell gate ordering"iofg" // input-forget-cell-output gate ordering };"ifgo" 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-
形状为 [numDirections, 4 * hiddenSize] 的二维输入偏置张量。张量形状第二个维度中的偏置 向量顺序按
layout指定。 recurrentBias,类型为 MLOperand-
形状为 [numDirections, 4 * hiddenSize] 的二维循环偏置张量。张量形状第一个维度中的 偏置向量顺序按
layout指定。 peepholeWeight,类型为 MLOperand-
用于 peephole 的二维权重张量,形状为 [numDirections, 3 * hiddenSize]。权重向量的打包 顺序分别对应
input (i)、output (o)和forget (f)门。 initialHiddenState, 类型为 MLOperand-
形状为 [numDirections, batchSize, hiddenSize] 的三维初始隐藏状态张量。 未指定时,实现必须使用以零填充的张量。
initialCellState,类型为 MLOperand-
形状为 [numDirections, batchSize, hiddenSize] 的三维初始隐藏状态张量。 未指定时,实现必须使用以零填充的张量。
returnSequence,类型为 boolean,默认为false-
指示除最后一个时间步的输出外,是否还返回包含每个时间步中每个输出的整个序列。
direction,类型为 MLRecurrentNetworkDirection,默认为"forward"-
输入序列的处理方向。当设置为
"both"时,weight 和 bias 张量形状的第一个维度大小必须为 2,并且输入会在两个方向上处理。 layout,类型为 MLLstmWeightLayout,默认为"iofg"-
LSTM 内部门的权重和偏置向量的顺序,具体为
input (i)、output (o)、forget (f)和cell (g)门,如 weight 和 bias 张量形状的第一个维度所示。 activations,类型为 sequence<MLRecurrentNetworkActivation>-
由三个激活函数组成的列表,第一个用于
input (i)、forget (f)和output (o)门,第二个用于cell (g)门,最后一个用于在将输出单元状态与输出门的结果组合以形成输出隐藏状态之前 过滤该输出单元状态。未指定时,分别默认为由"sigmoid"、"tanh"和"tanh"函数组成的序列。
-
input: 一个MLOperand。 形状为 [steps, batchSize, inputSize] 的输入三维张量。 -
weight: 一个MLOperand。 形状为 [numDirections, 4 * hiddenSize, inputSize] 的三维输入权重张量。 张量形状第二个维度中的权重向量顺序按layout指定。 -
recurrentWeight: 一个MLOperand。 形状为 [numDirections, 4 * hiddenSize, hiddenSize] 的三维循环权重张量。 张量形状第二个维度中的权重向量顺序按layout指定。 -
steps: 一个unsigned long标量。循环网络中的时间步数。该值必须大于 0。 -
hiddenSize: 一个unsigned long标量。单元输出张量形状第三个维度的值。它指示隐藏状态中的特征数量。 -
options: 一个可选的MLLstmOptions。 该操作的可选参数。
返回:sequence<MLOperand>。
第一个元素是形状为 [numDirections, batchSize, hiddenSize] 的三维张量,即网络最后一个时间步的
输出隐藏状态。第二个元素是形状为 [numDirections, batchSize, hiddenSize] 的三维张量,即网络最后一个
时间步的输出单元状态。此外,如果 returnSequence
设置为 true,则第三个元素是形状为 [steps, numDirections,
batchSize, hiddenSize] 的四维输出张量,包含时间序列中每个时间步的每个输出。
| 操作数 | 允许的 数据类型 | 允许的秩 |
|---|---|---|
| "float32",
"float16"
| 3 |
| 与
相同
| 3 |
| 与
相同
| 3 |
bias
| 与
相同
| 2 |
recurrentBias
| 与
相同
| 2 |
peepholeWeight
| 与
相同
| 2 |
| 与
相同
| 3 |
initialCellState
| 与
相同
| 3 |
| outputs[0] | 与
相同
| 3 |
| outputs[1] | 与
相同
| 3 |
如果 returnSequence
为 true,则 outputs[2]
| 与
相同
| 4 |
MLLstmSupportLimits
具有以下成员:
input,类型为 MLTensorLimits-
用于 input 操作数的
MLTensorLimits。 weight,类型为 MLTensorLimits-
用于 weight 操作数的
MLTensorLimits。 recurrentWeight, 类型为 MLTensorLimits-
用于 recurrentWeight 操作数的
MLTensorLimits。 bias,类型为 MLTensorLimits-
用于 bias 操作数的
MLTensorLimits。 recurrentBias,类型为 MLTensorLimits-
用于 recurrentBias 操作数的
MLTensorLimits。 peepholeWeight,类型为 MLTensorLimits-
用于 peepholeWeight 操作数的
MLTensorLimits。 initialHiddenState, 类型为 MLTensorLimits-
用于 initialHiddenState 操作数的
MLTensorLimits。 initialCellState, 类型为 MLTensorLimits-
用于 initialCellState 操作数的
MLTensorLimits。 output0,类型为 MLTensorLimits-
用于所有 output 操作数[0]的
MLTensorLimits。 output1,类型为 MLTensorLimits-
用于所有 output 操作数[1]的
MLTensorLimits。 output2,类型为 MLTensorLimits-
用于所有 output 操作数[2]的
MLTensorLimits。
MLOpSupportLimits
具有以下用于 lstm()
的成员:
lstm,类型为 MLLstmSupportLimits-
运算符
lstm()的支持限制。
lstm(input, weight, recurrentWeight, steps, hiddenSize, options)
方法步骤为:
-
如果 this 不可构建,则抛出一个 "
InvalidStateError"DOMException。 -
如果以 验证操作数处理 this 以及 input、weight、 recurrentWeight、options.
bias(如果它存在)、options.recurrentBias(如果它存在)、options.peepholeWeight(如果它存在)、options.(如果它存在)和 options.initialCellState(如果它存在)中的任一项返回 false,则抛出一个TypeError。 -
如果 input、weight 或 recurrentWeight 中任一项的dataType不是其允许的数据类型之一 (根据此表),则抛出一个
TypeError。 -
如果 input、weight 或 recurrentWeight 中任一项的秩不是其允许的秩,则 抛出一个
TypeError。 -
令 batchSize 为 input 的shape[1]。
-
令 inputSize 为 input 的shape[2]。
-
如果 weight 的shape 不等于 « numDirections, 4 * hiddenSize, inputSize »,则抛出一个
TypeError。 -
如果 recurrentWeight 的shape 不等于 « numDirections, 4 * hiddenSize, hiddenSize »,则抛出一个
TypeError。 -
如果 hiddenSize * 8 不是有效维度,则抛出一个
TypeError。为什么是 hiddenSize * 8?
某些底层平台在单个 bias 张量上操作,该张量是bias和recurrentBias的连接。因此,4 * hiddenSize + 4 * hiddenSize 也需要是有效 维度。 -
如果 options.
recurrentBias存在,则: -
如果 options.
peepholeWeight存在,则: -
如果 options.
存在,则: -
如果 options.
initialCellState存在,则: -
如果 options.
activations存在,则:-
令 activations 为 options.
activations的克隆。
-
否则:
-
计算输出形状:
-
令 desc 为给定 input 的dataType 和 « numDirections, batchSize, hiddenSize » 时创建 MLOperandDescriptor 的结果。
-
如果 options.
returnSequence为 true,则:-
令 desc2 为给定 input 的dataType 和 « steps, numDirections, batchSize, hiddenSize » 时创建 MLOperandDescriptor的结果。
-
-
-
建立图连接:
-
令 operator 为给定 weight、recurrentWeight、steps、hiddenSize 和 options 时用于 "lstm" 操作的一个运算符。
-
令 output0 为给定 this 和 desc 时创建 MLOperand的结果。
-
令 output1 为给定 this 和 desc 时创建 MLOperand的结果。
-
如果 options.
returnSequence为 true,则:-
令 output2 为给定 this 和 desc2 时创建 MLOperand的结果。
-
令 output 为列表 « output0, output1, output2 »。
-
将 output0.
[[operator]]、 output1.[[operator]]和 output2.[[operator]]设置为 operator。
-
-
否则:
-
令 output 为列表 « output0, output1 »。
-
将 output0.
[[operator]]和 output1.[[operator]]设置为 operator。
-
-
将 operator 的输入设置为 input、weight 和 recurrentWeight。
-
如果 options.
recurrentBias存在,则将它添加到 operator 的输入。 -
如果 options.
peepholeWeight存在,则将它添加到 operator 的输入。 -
如果 options.
initialCellState存在,则将它添加到 operator 的输入。 -
将 operator 的输出设置为 output。
-
-
返回 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) { // 将二维 currentHidden([batchSize, hiddenSize])扩展为 // 四维([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; } } } // 将二维 currentHidden([batchSize, hiddenSize])扩展为 // 三维([numDirections, batchSize, hiddenSize]) const expandedHiddenAs3D= builder. reshape( currentHidden, [ 1 , batchSize, hiddenSize]); outputHidden= outputHidden? builder. concat([ outputHidden, expandedHiddenAs3D], 0 ) : expandedHiddenAs3D; // 将二维 currentCell([batchSize, hiddenSize])扩展为 // 三维([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
长短期记忆 [LSTM] 循环网络的单个时间步,使用 cell state 以及 input、output 和 forget 门来计算下一个时间步的 cell state 和 hidden state,该状态会在网络的时间序列中滚入输出。dictionary :MLLstmCellOptions MLOperatorOptions {MLOperand bias ;MLOperand recurrentBias ;MLOperand peepholeWeight ;MLLstmWeightLayout layout = "iofg";sequence <MLRecurrentNetworkActivation >activations ; };partial interface MLGraphBuilder {sequence <MLOperand >lstmCell (MLOperand input ,MLOperand weight ,MLOperand recurrentWeight ,MLOperand hiddenState ,MLOperand cellState , [EnforceRange ]unsigned long hiddenSize ,optional MLLstmCellOptions options = {}); };dictionary {MLLstmCellSupportLimits MLTensorLimits input ;MLTensorLimits weight ;MLTensorLimits recurrentWeight ;MLTensorLimits hiddenState ;MLTensorLimits cellState ;MLTensorLimits bias ;MLTensorLimits recurrentBias ;MLTensorLimits peepholeWeight ;MLTensorLimits output0 ;MLTensorLimits output1 ; };partial dictionary MLOpSupportLimits {MLLstmCellSupportLimits lstmCell ; };
MLLstmCellOptions
具有以下成员:
bias,类型为 MLOperand-
形状为 [4 * hiddenSize] 的一维输入偏置张量。张量形状第一个维度中的偏置向量顺序按
layout指定。 recurrentBias,类型为 MLOperand-
形状为 [4 * hiddenSize] 的一维循环偏置张量。张量形状第一个维度中的偏置向量顺序按
layout指定。 peepholeWeight,类型为 MLOperand-
用于 peephole 的一维权重张量,形状为 [3 * hiddenSize]。权重向量的打包顺序分别对应
input (i)、output (o)和forget (f)门。 layout,类型为 MLLstmWeightLayout,默认为"iofg"-
LSTM 内部门的权重和偏置向量的顺序,具体为
input (i)、output (o)、forget (f)和cell (g)门,如 weight 和 bias 张量形状的第一个维度所示。 activations,类型为 sequence<MLRecurrentNetworkActivation>-
由三个激活函数组成的列表,第一个用于
input (i)、forget (f)和output (o)门,第二个用于cell (g)门,最后一个用于在将输出单元状态与输出门的结果组合以形成输出隐藏状态之前 过滤该输出单元状态。未指定时,分别默认为由"sigmoid"、"tanh"和"tanh"函数组成的序列。
-
input: 一个MLOperand。 形状为 [batchSize, inputSize] 的输入二维张量。 -
weight: 一个MLOperand。 形状为 [4 * hiddenSize, inputSize] 的二维输入权重张量。张量形状第一个维度中的 权重向量顺序按layout指定。 -
recurrentWeight: 一个MLOperand。 形状为 [4 * hiddenSize, hiddenSize] 的二维循环权重张量。张量形状第一个维度中的 权重向量顺序按layout指定。 -
hiddenState: 一个MLOperand。 形状为 [batchSize, hiddenSize] 的输入二维 hidden state 张量。 -
cellState: 一个MLOperand。 形状为 [batchSize, hiddenSize] 的输入二维 cell state 张量。 -
hiddenSize: 一个unsigned long标量。输出张量形状第二个维度的值。它指示 hidden state 中的特征数量。 -
options: 一个可选的MLLstmCellOptions。 该操作的可选参数。
返回:sequence<MLOperand>。
第一个元素是循环网络当前时间步的输出 hidden state。后一个元素是输出 cell state。两个元素都是形状为
[batchSize, hiddenSize] 的二维张量。
| 操作数 | 允许的 数据类型 | 允许的秩 |
|---|---|---|
| "float32",
"float16"
| 2 |
| 与
相同
| 2 |
| 与
相同
| 2 |
| 与
相同
| 2 |
| 与
相同
| 2 |
bias
| 与
相同
| 1 |
recurrentBias
| 与
相同
| 1 |
peepholeWeight
| 与
相同
| 1 |
| outputs[0] | 与
相同
| 2 |
| outputs[1] | 与
相同
| 2 |
MLLstmCellSupportLimits
具有以下成员:
input,类型为 MLTensorLimits-
用于 input 操作数的
MLTensorLimits。 weight,类型为 MLTensorLimits-
用于 weight 操作数的
MLTensorLimits。 recurrentWeight,类型为 MLTensorLimits-
用于 recurrentWeight 操作数的
MLTensorLimits。 hiddenState,类型为 MLTensorLimits-
用于 hiddenState 操作数的
MLTensorLimits。 cellState,类型为 MLTensorLimits-
用于 cellState 操作数的
MLTensorLimits。 bias,类型为 MLTensorLimits-
用于 bias 操作数的
MLTensorLimits。 recurrentBias,类型为 MLTensorLimits-
用于 recurrentBias 操作数的
MLTensorLimits。 peepholeWeight,类型为 MLTensorLimits-
用于 peepholeWeight 操作数的
MLTensorLimits。 output0,类型为 MLTensorLimits-
用于所有 output 操作数[0]的
MLTensorLimits。 output1,类型为 MLTensorLimits-
用于所有 output 操作数[1]的
MLTensorLimits。
MLOpSupportLimits
具有以下用于 lstmCell()
的成员:
lstmCell,类型为 MLLstmCellSupportLimits-
运算符
lstmCell()的支持限制。
lstmCell(input, weight, recurrentWeight, hiddenState, cellState, hiddenSize, options)
方法步骤为:
-
如果 this 不可构建,则抛出一个 "
InvalidStateError"DOMException。 -
如果以 验证操作数处理 this 以及 input、weight、 recurrentWeight、hiddenState、cellState、 options.
bias(如果它存在)、options.recurrentBias(如果它存在)和 options.peepholeWeight(如果它存在)中的任一项返回 false,则抛出一个TypeError。 -
如果 input、weight、recurrentWeight、hiddenState 或 cellState 中任一项的dataType不是其允许的数据类型之一 (根据此表),则抛出一个
TypeError。 -
如果 input、weight、recurrentWeight、hiddenState 或 cellState 中任一项的秩不是其允许的秩,则抛出一个
TypeError。 -
令 batchSize 为 input 的shape[0]。
-
令 inputSize 为 input 的shape[1]。
-
如果 weight 的shape 不等于 « 4 * hiddenSize, inputSize », 则抛出一个
TypeError。 -
如果 recurrentWeight 的shape 不等于 « 4 * hiddenSize, hiddenSize », 则抛出一个
TypeError。 -
如果 hiddenState 的shape 不等于 « batchSize, hiddenSize »,则 抛出一个
TypeError。 -
如果 cellState 的shape 不等于 « batchSize, hiddenSize »,则 抛出一个
TypeError。 -
如果 hiddenSize * 8 不是有效维度,则抛出一个
TypeError。为什么是 hiddenSize * 8?
某些底层平台在单个 bias 张量上操作,该张量是bias和recurrentBias的连接。因此,4 * hiddenSize + 4 * hiddenSize 也需要是有效 维度。 -
如果 options.
recurrentBias存在,则: -
如果 options.
peepholeWeight存在,则: -
如果 options.
activations存在,则:-
令 activations 为 options.
activations的克隆。
-
否则:
-
令 desc 为一个新的
MLOperandDescriptor。 -
建立图连接:
-
令 output0 为给定 this 和 desc 时创建 MLOperand的结果。
-
令 output1 为给定 this 和 desc 时创建 MLOperand的结果。
-
令 output 为列表 « output0, output1 »。
-
令 operator 为给定 weight、recurrentWeight、hiddenState、 cellState、hiddenSize 和 options 时用于 "lstmCell" 操作的一个运算符。
-
将 output0.
[[operator]]和 output1.[[operator]]设置为 operator。 -
将 operator 的输入设置为 input、weight、 recurrentWeight、hiddenState 和 cellState。
-
如果 options.
recurrentBias存在,则将它添加到 operator 的输入。 -
如果 options.
peepholeWeight存在,则将它添加到 operator 的输入。 -
将 operator 的输出设置为 output。
-
-
返回 output。
当权重布局为默认 "iofg"
布局,并且 input/forget/output 门以及 cell 门/用于输出 hidden state 的 cell state 过滤器的
激活函数分别为
sigmoid()
和 tanh()
时,该操作的行为可以按如下方式由其他操作的使用进行通用仿真,尽管用户代理通常具有更高效的实现。
在底层平台不直接支持某个操作的情况下,这种分解可用作指导实现的模板。
function lstmCell( builder, input, weight, recurrentWeight, hiddenState, cellState, hiddenSize, options) { const zero= builder. constant( input. dataType, 0 ); const inputSize= input. shape[ 1 ]; // input gate (i) let i= builder. sigmoid( builder. add( builder. mul( cellState, ( options. peepholeWeight? builder. slice( options. peepholeWeight, [ 0 ], [ hiddenSize]) : zero)), builder. add( builder. add( ( options. bias? builder. slice( options. bias, [ 0 ], [ hiddenSize]) : zero), ( options. recurrentBias? builder. slice( options. recurrentBias, [ 0 ], [ hiddenSize]) : zero)), builder. add( builder. matmul( input, builder. transpose( builder. slice( weight, [ 0 , 0 ], [ hiddenSize, inputSize]))), builder. matmul( hiddenState, builder. transpose( builder. slice( recurrentWeight, [ 0 , 0 ], [ hiddenSize, hiddenSize]))))))); // forget gate (f) let f= builder. sigmoid( builder. add( builder. mul( cellState, ( options. peepholeWeight? builder. slice( options. peepholeWeight, [ 2 * hiddenSize], [ hiddenSize]) : zero)), builder. add( builder. add( ( options. bias? builder. slice( options. bias, [ 2 * hiddenSize], [ hiddenSize]) : zero), ( options. recurrentBias? builder. slice( options. recurrentBias, [ 2 * hiddenSize], [ hiddenSize]) : zero)), builder. add( builder. matmul( input, builder. transpose( builder. slice( weight, [ 2 * hiddenSize, 0 ], [ hiddenSize, inputSize]))), builder. matmul( hiddenState, builder. transpose( builder. slice( recurrentWeight, [ 2 * hiddenSize, 0 ], [ hiddenSize, hiddenSize]))))))); // cell gate (g) let g= builder. tanh( builder. add( builder. add( ( options. bias? builder. slice( options. bias, [ 3 * hiddenSize], [ hiddenSize]) : zero), ( options. recurrentBias? builder. slice( options. recurrentBias, [ 3 * hiddenSize], [ hiddenSize]) : zero)), builder. add( builder. matmul( input, builder. transpose( builder. slice( weight, [ 3 * hiddenSize, 0 ], [ hiddenSize, inputSize]))), builder. matmul( hiddenState, builder. transpose( builder. slice( recurrentWeight, [ 3 * hiddenSize, 0 ], [ hiddenSize, hiddenSize])))))); // output gate (o) let o= builder. sigmoid( builder. add( builder. mul( cellState, ( options. peepholeWeight? builder. slice( options. peepholeWeight, [ hiddenSize], [ hiddenSize]) : zero)), builder. add( builder. add( ( options. bias? builder. slice( options. bias, [ hiddenSize], [ hiddenSize]) : zero), ( options. recurrentBias? builder. slice( options. recurrentBias, [ hiddenSize], [ hiddenSize]) : zero)), builder. add( builder. matmul( input, builder. transpose( builder. slice( weight, [ hiddenSize, 0 ], [ hiddenSize, inputSize]))), builder. matmul( hiddenState, builder. transpose( builder. slice( recurrentWeight, [ hiddenSize, 0 ], [ hiddenSize, hiddenSize]))))))); // output cell state (ct) let ct= builder. add( builder. mul( f, cellState), builder. mul( i, g)); // output hidden state (ht) let ht= builder. mul( o, builder. tanh( ct)); return [ ht, ct]; }
8.9.35. matmul
计算两个输入张量的矩阵乘积。partial interface MLGraphBuilder {MLOperand matmul (MLOperand a ,MLOperand b ,optional MLOperatorOptions options = {}); };partial dictionary MLOpSupportLimits {MLBinarySupportLimits matmul ; };
-
a:一个MLOperand。 第一个输入张量,至少为二维。 -
b:一个MLOperand。 第二个输入张量,至少为二维。 -
options:一个MLOperatorOptions。 指定该操作的可选参数。
返回:一个 MLOperand。
包含两个输入张量矩阵乘积的输出张量。
| 操作数 | 允许的 数据类型 | 允许的秩 |
|---|---|---|
a
| "float32",
"float16"
| 2 到 N |
b
| 与 a
相同
| 2 或 N |
| output | 与 a
相同
| 2 或 N |
MLOpSupportLimits
具有以下用于 matmul()
的成员:
matmul,类型为 MLBinarySupportLimits-
运算符
matmul()的支持限制。
matmul(a, b, options)
方法步骤为:
-
如果 this 不可构建,则抛出一个 "
InvalidStateError"DOMException。 -
计算输出形状:
-
令 rankA 为 a 的秩。
-
令 rankB 为 b 的秩。
-
令 colsA 为 shapeA[rankA - 1]。
-
令 rowsA 为 shapeA[rankA - 2]。
-
令 colsB 为 shapeB[rankB - 1]。
-
令 rowsB 为 shapeB[rankB - 2]。
-
令 batchShapeA 为移除空间维度(最后 2 项)后的 shapeA 的克隆。
-
令 batchShapeB 为移除空间维度(最后 2 项)后的 shapeB 的克隆。
-
令 outputShape 为双向广播 batchShapeA 和 batchShapeB 的结果。如果返回 failure,则抛出一个
TypeError。 -
将 « rowsA, colsB » 追加到 outputShape。
-
令 desc 为给定 a 的dataType 和 outputShape 时创建 MLOperandDescriptor的结果。
-
建立图连接:
-
令 output 为给定 this 和 desc 时创建 MLOperand的结果。
-
令 operator 为给定 options 时用于 "matmul" 操作的一个 运算符。
-
将 output.
[[operator]]设置为 operator。 -
将 operator 的输入设置为 a 和 b。
-
将 operator 的输出设置为 output。
-
-
返回 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"时的填充值。
-
input: 一个MLOperand。 输入张量。 -
beginningPadding: sequence<unsigned long>。 要添加到每个输入维度开头的填充值数量,长度为 N,其中 N 是输入张量的 秩。对于input的每个维度 d,beginningPadding[d] 指示在该维度的内容之前添加多少个值。 -
endingPadding: sequence<unsigned long>。 要添加到每个输入维度末尾的填充值数量,长度为 N,其中 N 是输入张量的 秩。对于input的每个维度 d,endingPadding[d] 指示在该维度的内容之后添加多少个值。 -
options: 一个可选的MLPadOptions。 该操作的可选参数。
返回:一个 MLOperand。
填充后的输出张量。输出张量的每个维度可按如下方式计算:
output size = beginning padding + input size + ending padding
| 操作数 | 允许的 数据类型 | 允许的秩 |
|---|---|---|
input
| 任意 | N |
| output | 与 input
相同
| 与 input
相同
|
MLOpSupportLimits
具有以下用于 pad()
的成员:
pad,类型为 MLSingleInputSupportLimits-
运算符
pad()的支持限制。
pad(input, beginningPadding, endingPadding, options)
方法步骤为:
-
如果 this 不可构建,则抛出一个 "
InvalidStateError"DOMException。 -
如果 beginningPadding 的大小和 endingPadding 的大小不是 都等于 input 的秩,则抛出一个
TypeError。 -
令 desc 为 input.
[[descriptor]]的副本。 -
令 outputShape 为 input 的shape 的副本。
-
对于 0 到 outputShape 的秩(不含)的 范围中的每个 index:
-
根据 options.
mode切换:"constant"-
什么也不做。
"edge"-
什么也不做。
"reflection"
-
将 beginningPadding[index] 的值加到 outputShape[index]。
-
将 endingPadding[index] 的值加到 outputShape[index]。
-
-
将 options.
value设置为将 options.value转换为 input 的 dataType 的结果。 -
将 desc.
shape设置为 outputShape。 -
建立图连接:
-
令 output 为给定 this 和 desc 时创建 MLOperand的结果。
-
令 operator 为给定 beginningPadding、endingPadding 和 options 时用于 "padding" 操作的一个运算符。
-
将 output.
[[operator]]设置为 operator。 -
将 operator 的输入设置为 input。
-
将 operator 的输出设置为 output。
-
-
返回 output。
constant、edge 和 reflection 填充的示例:
// input: [[1,2,3], [4,5,6]] const input= builder. constant( { dataType: 'float32' , shape: [ 2 , 3 ]}, new Float32Array([ 1 , 2 , 3 , 4 , 5 , 6 ])); const beginningPadding= [ 1 , 2 ]; const endingPadding= [ 1 , 2 ]; // "constant" 填充后: // [[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]。 指定滑动窗口的维度。 窗口维度的默认值为输入形状的高度和宽度维度。
padding,类型为sequence<[EnforceRange] unsigned long>-
长度为 4 的列表:[beginningHeight, endingHeight, beginningWidth, endingWidth]。 指定添加到卷积输入每个空间维度的开头和末尾的额外行和列。 默认值为 [0,0,0,0]。
strides,类型为sequence<[EnforceRange] unsigned long>-
长度为 2 的列表:[strideHeight, strideWidth]。 指定卷积输入每个空间维度的滑动窗口步幅。 默认值为 [1,1]。
dilations,类型为sequence<[EnforceRange] unsigned long>-
长度为 2 的列表:[dilationHeight, dilationWidth]。指定应用于卷积滤波器(核)的每个 空间维度的膨胀因子。 默认值为 [1,1]。
layout,类型为 MLInputOperandLayout,默认为"nchw"-
按如下方式指定输入和输出张量的布局格式:
outputShapeRounding, 类型为 MLRoundingType,默认为"floor"-
用于计算输出形状的舍入函数,取决于是否需要完整窗口或部分窗口的结果。
outputSizes,类型为sequence<[EnforceRange] unsigned long>-
长度为 2 的列表:[outputHeight, outputWidth] 指定输出张量两个空间维度的大小。 当显式指定输出大小时,会忽略
outputShapeRounding。 如果未指定,则自动计算输出大小。
-
options:一个 可选的MLPool2dOptions。 该操作的可选参数。
返回:一个 MLOperand。
包含规约结果的输出四维张量。逻辑形状根据 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)
| 操作数 | 允许的 数据类型 | 允许的秩 |
|---|---|---|
input
| 作为操作步骤的一部分指定 | 4 |
| output | 与 input
相同
| 4 |
MLOpSupportLimits
具有以下用于池化操作的成员:
averagePool2d,类型为 MLSingleInputSupportLimits-
运算符
averagePool2d()的支持限制。 l2Pool2d,类型为 MLSingleInputSupportLimits-
运算符
l2Pool2d()的支持限制。 maxPool2d,类型为 MLSingleInputSupportLimits-
运算符
maxPool2d()的支持限制。
// “全局” max pooling builder. maxPool2d( input);
要创建池化操作,给定 字符串
op、MLOperand
input、MLPool2dOptions
options,以及可选的列表 allowedDataTypes,运行以下步骤:
-
断言:op 是 "averagePool2d"、"l2Pool2d"、 "maxPool2d" 之一。
-
如果 this 不可构建,则抛出一个 "
InvalidStateError"DOMException。 -
如果给定了 allowedDataTypes 且它不包含 input 的dataType,则抛出一个
TypeError。 -
根据 options.
layout切换: -
如果 options.
windowDimensions不存在,则将 options.windowDimensions设置为 « inputHeight, inputWidth »。 -
如果 options.
windowDimensions的 大小不是 2,则抛出一个TypeError。 -
如果 options.
windowDimensions中的任一项等于 0,则抛出一个TypeError。 -
如果 options.
outputSizes存在,或者如果 options.padding不存在,则将 options.padding设置为列表 « 0, 0, 0, 0 »。 -
如果 options.
outputSizes存在,则: -
如果 options.
dilations不存在,则将 options.dilations设置为列表 « 1, 1 »。 -
令 desc 为 input.
[[descriptor]]的副本。 -
计算输出形状:
-
令 « windowHeight, windowWidth » 为 options.
windowDimensions。 -
令 « calculatedOutputHeight, calculatedOutputWidth » 为给定 inputHeight、inputWidth、windowHeight、windowWidth、 options.
padding、 options.strides和 options.dilations时计算 conv2d 输出大小的结果。 -
如果 options.
outputSizes存在,则:-
令 « outputHeight, outputWidth » 为 options.
outputSizes。 -
如果不是 outputHeight 等于 floor( calculatedOutputHeight ) 且 outputWidth 等于 floor( calculatedOutputWidth ),也不是 outputHeight 等于 ceil( calculatedOutputHeight ) 且 outputWidth 等于 ceil( calculatedOutputWidth ),则抛出一个
TypeError。
-
-
否则:
-
令 « outputHeight, outputWidth » 为 « calculatedOutputHeight, calculatedOutputWidth »。
-
根据 options.
outputShapeRounding切换:
-
-
根据 options.
layout切换: -
将 desc.
shape设置为 outputShape。
-
-
建立图连接:
-
令 output 为给定 this 和 desc 时创建 MLOperand的结果。
-
令 operator 为给定 options 时用于 op 操作的一个 运算符。
-
将 output.
[[operator]]设置为 operator。 -
将 operator 的输入设置为 input。
-
将 operator 的输出设置为 output。
-
-
返回 output。
支持以下池化算法。
averagePool2d(input, options)
方法步骤为:
l2Pool2d(input, options)
方法步骤为:
8.9.37.1. averagePool2d
计算特征图中各个补丁的平均值,并用它来创建池化后的特征图。更多细节见§ 8.9.37 池化操作。8.9.37.2. l2Pool2d
将 L2 范数函数应用于输入特征图的一个区域。L2 范数是其元素平方和的平方根。更多细节见 § 8.9.37 池化操作。8.9.37.3. maxPool2d
计算特征图中各个补丁的最大值,并用它来创建池化后的特征图。更多细节见§ 8.9.37 池化操作。8.9.38. prelu
对输入张量逐元素计算参数化版本的 修正线性函数(Parametric ReLU)。Parametric ReLU 是 leaky ReLU 的一种类型,不同于具有 0.01 这样的标量斜率,它把斜率(泄漏系数)作为此操作模型训练阶段学习得到的参数。计算遵循表达式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 ; };
-
input:一个MLOperand。 输入张量。 -
options:一个MLOperatorOptions。 指定该操作的可选参数。
返回:
| 操作数 | 允许的 数据类型 | 允许的秩 |
|---|---|---|
input
| "float32",
"float16",
"int64",
"int32",
"int8"
| N |
slope
| 与 input
相同
| N |
| output | 与 input
相同
| N |
MLPreluSupportLimits
具有以下成员:
input,类型为 MLTensorLimits-
用于 input 操作数的
MLTensorLimits。 slope,类型为 MLTensorLimits-
用于 slope 操作数的
MLTensorLimits。 output,类型为 MLTensorLimits-
用于 output 操作数的
MLTensorLimits。
MLOpSupportLimits
具有以下用于 prelu()
的成员:
prelu,类型为 MLPreluSupportLimits-
运算符
prelu()的支持限制。
prelu(input, slope, options)
方法步骤为:
-
如果 this 不可构建,则抛出一个 "
InvalidStateError"DOMException。 -
如果以 验证操作数处理 this 以及 input 和 slope 中任一项返回 false,则抛出一个
TypeError。 -
如果 input 或 slope 中任一项的dataType 不是其允许的数据类型之一 (根据此表),则抛出一个
TypeError。 -
令 descriptor 为给定 input 的dataType 和 outputShape 时创建 MLOperandDescriptor的结果。
-
建立图连接:
-
令 output 为给定 this 和 descriptor 时创建 MLOperand的结果。
-
令 operator 为给定 slope 和 options 时用于 "prelu" 操作的一个运算符。
-
将 output.
[[operator]]设置为 operator。 -
将 operator 的输入设置为 input 和 slope。
-
将 operator 的输出设置为 output。
-
-
返回 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>-
要规约的维度,这也指定输入张量中的哪些值会用于规约函数。列表中的轴必须在 [0, N-1] 范围内, 其中 N 是输入张量的秩。
如果不存在,则规约所有维度。规约函数的输入值是输入张量中的所有值。
如果存在且非空,则规约函数的输入值是输入张量指定维度上的所有值。
如果存在且为空,则不规约任何维度,输出张量的形状与输入张量的形状相同;规约函数会分别应用于 张量中的每个值。
keepDimensions,类型为 boolean,默认为false-
如果为 true,则输出与输入具有相同的秩,并将任何被规约的维度设置为大小 1。
-
input:一个MLOperand。 输入张量。 -
options:一个 可选的MLReduceOptions。 该操作的可选参数。
返回:一个 MLOperand。
输出 N 维张量,其秩位于 0 到 input
的
秩之间(含),
取决于 axes
和 keepDimensions。
如果输入操作数是标量,则规约函数会应用于该标量值,并且输出也是标量。
| 操作数 | 允许的 数据类型 | 允许的秩 |
|---|---|---|
input
| 作为操作步骤的一部分指定 | N |
| output | 与 input
相同
| N |
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,执行以下步骤。它们返回一个新的 无符号整数列表, 或 failure。
要创建规约操作,给定字符串
op、MLOperand
input、MLReduceOptions
options,以及可选的列表 allowedDataTypes,运行以下步骤:
-
断言:op 是 "reduceL1"、"reduceL2"、 "reduceLogSum"、"reduceLogSumExp"、"reduceMax"、"reduceMean"、"reduceMin"、"reduceProduct"、 "reduceSum"、"reduceSumSquare" 之一。
-
如果 this 不可构建,则抛出一个 "
InvalidStateError"DOMException。 -
如果给定了 allowedDataTypes 且它不包含 input 的dataType,则抛出一个
TypeError。 -
令 outputShape 为给定 input 的shape、options.
axes(如果它存在)以及 options.keepDimensions时计算规约输出大小的结果。 如果这返回 failure,则抛出一个TypeError。 -
令 desc 为给定 input 的dataType 和 outputShape 时创建 MLOperandDescriptor的结果。
-
建立图连接:
-
令 output 为给定 this 和 desc 时创建 MLOperand的结果。
-
令 operator 为给定 options 时用于 op 操作的一个 运算符。
-
将 output.
[[operator]]设置为 operator。 -
将 operator 的输入设置为 input。
-
将 operator 的输出设置为 output。
-
-
返回 output。
支持以下规约算法。
reduceL1(input, options)
方法步骤为:
reduceL2(input, options)
方法步骤为:
reduceLogSum(input, options)
方法步骤为:
reduceLogSumExp(input, options)
方法步骤为:
reduceMax(input, options)
方法步骤为:
reduceMean(input, options)
方法步骤为:
reduceMin(input, options)
方法步骤为:
reduceProduct(input, options)
方法步骤为:
reduceSum(input, options)
方法步骤为:
几个规约操作的行为可以按如下方式由其他操作的使用进行通用仿真,尽管用户代理通常具有更高效的实现。 在底层平台不直接支持某个操作的情况下,这种分解可用作指导实现的模板。
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
这样的选项。这不会影响底层张量数据,只会影响形状。例如,如果输入形状为 [2, 3, 4],
轴为 1,且 keepDimensions
为 true,则预期输出形状为 [2, 1 ,4]。如果底层平台从不保留被规约维度,则它会生成
形状为 [2, 4] 的输出。实现可以引入一个无操作 reshape 到 [2, 1, 4]。
如果 keepDimensions
为 false,但底层平台总是保留被规约维度,也可以引入类似的无操作 reshape。
8.9.40. relu
计算输入张量的修正线性函数。partial interface MLGraphBuilder {MLOperand relu (MLOperand input ,optional MLOperatorOptions options = {}); };partial dictionary MLOpSupportLimits {MLSingleInputSupportLimits relu ; };
-
input:一个MLOperand。 输入张量。 -
options:一个MLOperatorOptions。 指定该操作的可选参数。
返回:
| 操作数 | 允许的 数据类型 | 允许的秩 |
|---|---|---|
input
| "float32",
"float16",
"int64",
"int32",
"int8"
| N |
| output | 与 input
相同
| 与 input
相同
|
MLOpSupportLimits
具有以下用于 relu()
的成员:
relu,类型为 MLSingleInputSupportLimits-
运算符
relu()的支持限制。
relu(input, options) 方法
步骤为:
-
如果 this 不可构建,则抛出一个 "
InvalidStateError"DOMException。 -
建立图连接:
-
令 output 为给定 input 时复制 MLOperand的结果。
-
令 operator 为给定 options 时用于 "relu" 操作的一个运算符。
-
将 output.
[[operator]]设置为 operator。 -
将 operator 的输入设置为 input。
-
将 operator 的输出设置为 output。
-
-
返回 output。
该操作的行为可以按如下方式由其他操作的使用进行通用仿真,尽管用户代理通常具有更高效的实现。 在底层平台不直接支持某个操作的情况下,这种分解可用作指导实现的模板。
function relu( builder, input) { return builder. max( builder. constant( input. dataType, 0 ), input); }
8.9.41. resample2d
根据轴和缩放因子,将张量值从源维度重采样到目标维度。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 ; };
-
input:一个MLOperand。 输入四维张量。 -
options:一个 可选的MLResample2dOptions。 该操作的可选参数。
返回:一个 MLOperand。
输出四维张量。
MLResample2dOptions
具有以下成员:
mode,类型为 MLInterpolationMode,默认为"nearest-neighbor"-
用于填充输出张量值的插值算法。
这两种算法都从这些输入开始,这些输入针对每个空间轴计算(基于
axes), 其中inputSize由input张量的 shape 给出,outputSize由sizes或scales给出,而outputCoordinate标识正在计算的输出张量中的元素。scale = outputSize / inputSize unclampedCoordinate = (outputCoordinate + 0.5) / scale - 0.5 inputCoordinate = clamp(unclampedCoordinate, 0, inputSize - 1)
对于输出张量中给定的outputCoordinate.x和outputCoordinate.y位置, 上述方程给出有理的inputCoordinate.x和inputCoordinate.y。nearest-neighbor-
上面计算出的
inputCoordinate.x和inputCoordinate.y会用作 最近邻采样算法的输入,以按如下方式计算输出张量值:x = ceil(inputCoordinate.x - 0.5) y = ceil(inputCoordinate.y - 0.5) 输出张量值 = (x, y) 处的输入张量值
linear-
上面计算出的
inputCoordinate.x和inputCoordinate.y会用作 双线性采样算法的输入,以按如下方式计算输出张量值:x0 = floor(inputCoordinate.x) x1 = ceil(inputCoordinate.x) y0 = floor(inputCoordinate.y) y1 = ceil(inputCoordinate.y) vx0y0 = (x0, y0) 处的输入张量值 vx1y0 = (x1, y0) 处的输入张量值 vx0y1 = (x0, y1) 处的输入张量值 vx1y1 = (x1, y1) 处的输入张量值 tx = inputCoordinate.x - x0 ty = inputCoordinate.y - y0 vy0 = vx0y0 * (1 - tx) + vx1y0 * tx vy1 = vx0y1 * (1 - tx) + vx1y1 * tx 输出张量值 = vy0 * (1 - ty) + vy1 * ty
scales,类型为 sequence<float>-
长度为 2 的列表。 指定来自
axes的每个输入维度的缩放因子: [scaleForFirstAxis, scaleForSecondAxis]。 默认值为 [1.0, 1.0]。 sizes,类型为sequence<[EnforceRange] unsigned long>-
长度为 2 的列表。 指定来自
axes的每个输入维度的目标大小: [sizeForFirstAxis, sizeForSecondAxis]。当指定了sizes时,会忽略scales, 因为缩放因子的值会从输入的目标大小派生出来。 axes,类型为sequence<[EnforceRange] unsigned long>-
长度为 2 的列表。 指定要应用插值算法的输入张量的两个维度。 默认值为 [2, 3]。
| 操作数 | 允许的 数据类型 | 允许的秩 |
|---|---|---|
input
| "float32",
"float16",
"uint8",
"int8"
| 4 |
| output | 与 input
相同
| 4 |
MLOpSupportLimits
具有以下用于 resample2d()
的成员:
resample2d,类型为 MLSingleInputSupportLimits-
运算符
resample2d()的支持限制。
resample2d(input, options)
方法步骤为:
-
如果 this 不可构建,则抛出一个 "
InvalidStateError"DOMException。 -
否则,如果 options.
axes包含重复值,或如果它的任一项不在 0 到 input 的秩(不含)的范围内,则抛出一个TypeError。 -
计算输出形状:
-
令 inputDescriptor 为 input.
[[descriptor]]。 -
令 desc 为给定 inputDescriptor.
dataType和 outputShape 时创建 MLOperandDescriptor的结果。
-
-
建立图连接:
-
令 output 为给定 this 和 desc 时创建 MLOperand的结果。
-
令 operator 为给定 options 时用于 "resample2d" 操作的一个 运算符。
-
将 output.
[[operator]]设置为 operator。 -
将 operator 的输入设置为 input。
-
将 operator 的输出设置为 output。
-
-
返回 output。
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
将张量的形状更改为新形状。Reshape 不复制或更改张量的内容。它只会为后续操作更改张量的逻辑形状。partial interface MLGraphBuilder {MLOperand reshape (MLOperand input ,sequence <[EnforceRange ]unsigned long >newShape ,optional MLOperatorOptions options = {}); };partial dictionary MLOpSupportLimits {MLSingleInputSupportLimits reshape ; };
-
input:一个MLOperand。 输入张量。 -
newShape: sequence<unsigned long>。 输出张量的形状。newShape所隐含的元素数量必须与输入张量中的元素数量相同。 -
options: 一个MLOperatorOptions。 指定该操作的可选参数。
| 操作数 | 允许的 数据类型 | 允许的秩 |
|---|---|---|
input
| 任意 | N |
| output | 与 input
相同
| N |
MLOpSupportLimits
具有以下用于 reshape()
的成员:
reshape,类型为 MLSingleInputSupportLimits-
运算符
reshape()的支持限制。
reshape(input, newShape, options)
方法步骤为:
-
如果 this 不可构建,则抛出一个 "
InvalidStateError"DOMException。 -
令 outputShape 为空的
unsigned long数组。 -
令 inputElementCount 为 input 的shape 中所有项 的乘积。空维度会产生值为 1 的 inputElementCount。
-
令 desc 为 input.
[[descriptor]]的副本。 -
将 desc.
shape设置为 newShape。 -
建立图连接:
-
令 output 为给定 this 和 desc 时创建 MLOperand的结果。
-
令 operator 为给定 options 时用于 "reshape" 操作的一个 运算符。
-
将 output.
[[operator]]设置为 operator。 -
将 operator 的输入设置为 input。
-
将 operator 的输出设置为 output。
-
-
返回 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>-
要反转的输入维度的索引。当此成员不存在时,会将其视为反转所有维度。如果显式传入为空,则不反转任何维度。
-
input:一个MLOperand。 输入张量。 -
options:一个MLOperatorOptions。 指定该操作的可选参数。
返回:
| 操作数 | 允许的 数据类型 | 允许的秩 |
|---|---|---|
input
| 任意 | N |
| output | 与 input
相同
| 与 input
相同
|
MLOpSupportLimits
具有以下用于 reverse()
的成员:
reverse,类型为 MLSingleInputSupportLimits-
运算符
reverse()的支持限制。
reverse(input, options)
方法步骤为:
-
如果 this 不可构建,则抛出一个 "
InvalidStateError"DOMException。 -
令 inputRank 为 input 的秩。
-
如果未给定 axes,则令 axes 为 0 到 inputRank(不含)的范围。
-
否则,如果 axes 包含重复值,或如果它的任一元素不在 0 到 inputRank(不含)的范围内,则返回 failure。
-
建立图连接:
-
令 output 为给定 input 时复制 MLOperand的结果。
-
令 operator 为用于 "reverse" 操作且给定 options 的一个运算符。
-
将 output.
[[operator]]设置为 operator。 -
将 operator 的输入设置为 input。
-
将 operator 的输出设置为 output。
-
-
返回 output。
8.9.44. scatterElements
根据 indices,沿一个轴将 updates 张量中的值散布到 input 张量副本之上。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-
获取散布值所沿的轴。它的值必须在 [0, N-1] 范围内,其中 N 是输入张量的秩。
| 操作数 | 允许的 数据类型 | 允许的秩 |
|---|---|---|
input
| 任意 | 1 到 N |
indices
| "int32",
"uint32",
"int64"
| 与 input
相同
|
updates
| 与 input
相同
| 与 input
相同
|
| output | 与 input
相同
| 与 input
相同
|
MLScatterSupportLimits
具有以下成员:
input,类型为 MLTensorLimits-
用于 input 操作数的
MLTensorLimits。 indices,类型为 MLTensorLimits-
用于 indices 操作数的
MLTensorLimits。 updates,类型为 MLTensorLimits-
用于 updates 操作数的
MLTensorLimits。 output,类型为 MLTensorLimits-
用于 output 操作数的
MLTensorLimits。
MLOpSupportLimits
具有以下用于 scatterElements()
的成员:
scatterElements,类型为 MLScatterSupportLimits-
运算符
scatterElements()的支持限制。
indices
参数传给 scatterElements()
时,在构建图时不能将其夹取到允许范围内,因为输入要到执行时才知道。如果底层平台不提供指定的夹取行为,
实现可以在编译后的图中引入 clamp()。
类似地,如果底层平台不支持负索引,则实现可以在编译后的图中引入操作,以将从维度末尾开始的负索引转换为
正索引。
scatterElements(input, indices, updates, options)
方法步骤为:
-
如果 this 不可构建,则抛出一个 "
InvalidStateError"DOMException。 -
如果以 验证操作数处理 this 以及 input、indices 和 updates 中的任一项返回 false,则抛出一个
TypeError。 -
令 axis 为 options.
axis。 -
令 indicesShapeExpected 为 input 的shape 的副本。
-
将 indicesShapeExpected[axis] 设置为 indices 的shape[axis]。
-
建立图连接:
-
令 output 为给定 input 时复制 MLOperand的结果。
-
令 operator 为给定 input、indices、 updates 和 options 时用于 "scatterElements" 操作的一个运算符。
-
将 output.
[[operator]]设置为 operator。 -
将 operator 的输入设置为 input、indices 和 updates。
-
将 operator 的输出设置为 output。
-
-
返回 output。
scatterElements 在不同切片方案中如何工作的示例。
// shape 为 [4,3] 的 input: // [[ 0, 1, 2], // [10, 11, 12], // [20, 21, 22], // [30, 31, 32]] // shape 为 [2,3] 的 indices: // [[3, 1, 1], // [2, 0, 3]] // shape 为 [2,3] 的 updates: // [[-1, -2, -3], // [-4, -5, -6]] // axis = 0(默认) // shape 为 [4,3] 的 output: // [[ 0, -5, 2], // [10, -2, -3], // [-4, 21, 22], // [-1, 31, -6]] const input1= builder. constant( { dataType: 'float32' , shape: [ 4 , 3 ]}, new Float32Array([ 0 , 1 , 2 , 10 , 11 , 12 , 20 , 21 , 22 , 30 , 31 , 32 ])); const indices1= builder. constant( { dataType: 'uint32' , shape: [ 2 , 3 ]}, new Uint32Array([ 3 , 1 , 1 , 2 , 0 , 3 ])); const updates1= builder. constant( { dataType: 'float32' , shape: [ 2 , 3 ]}, new Uint32Array([ - 1 , - 2 , - 3 , - 4 , - 5 , - 6 ])); const output1= builder. scatterElements( input1, indices1, updates1); // shape 为 [4,3] 的 input: // [[ 0, 1, 2], // [10, 11, 12], // [20, 21, 22], // [30, 31, 32]] // shape 为 [4,1] 的 indices: // [[2], // [1], // [0], // [2]], // shape 为 [4,1] 的 updates: // [[-1], // [-2], // [-3], // [-4]], // axis = 1 // shape 为 [4,3] 的 output: // [[ 0, 1, -1], // [10, -2, 12], // [-3, 21, 22], // [30, 31, -4]] const indices2= builder. constant( { dataType: 'uint32' , shape: [ 4 , 1 ]}, new Uint32Array([ 2 , 1 , 0 , 2 ])); const updates2= builder. constant( { dataType: 'float32' , shape: [ 4 , 1 ]}, new Uint32Array([ - 1 , - 2 , - 3 , - 4 ])); const output2= builder. scatterElements( input1, indices2, updates2, { axis: 1 }); // shape 为 [4,2,2] 的 input: // [[[ 0, 1], // [ 10, 11]], // [[100, 101], // [110, 111]], // [[200, 201], // [210, 211]], // [[300, 301], // [310, 311]],] // shape 为 [1,2,2] 的 indices: // [[[0, 2], // [1, 3]]], // shape 为 [1,2,2] 的 updates: // [[[-1, -2], // [-3, -4]]], // axis = 0 // shape 为 [4,2,2] 的 output: // [[[ -1, 1], // [ 10, 11]], // [[100, 101], // [ -3, 111]], // [[200, -2], // [210, 211]], // [[300, 301], // [310, -4]],] const inputData3= new Float32Array( [ 0 , 1 , 10 , 11 , 100 , 101 , 110 , 111 , 200 , 201 , 210 , 211 , 300 , 301 , 310 , 311 ]); const input3= builder. constant({ dataType: 'float32' , shape: [ 4 , 2 , 2 ]}, inputData3); const indices3= builder. constant( { dataType: 'uint32' , shape: [ 1 , 2 , 2 ]}, new Uint32Array([ 0 , 2 , 1 , 3 ])); const updates3= builder. constant( { dataType: 'float32' , shape: [ 1 , 2 , 2 ]}, new Uint32Array([ - 1 , - 2 , - 3 , - 4 ])); const output3= builder. scatterElements( input3, indices3, updates3, { axis: 0 });
8.9.45. scatterND
根据 indices,将 update 张量中的值切片散布到 input 张量的副本之上。partial interface MLGraphBuilder {MLOperand scatterND (MLOperand input ,MLOperand indices ,MLOperand updates ,optional MLOperatorOptions options = {}); };partial dictionary MLOpSupportLimits {MLScatterSupportLimits scatterND ; };
-
input: 一个MLOperand。 用来初始化输出的输入 N 维张量。 -
indices: 一个MLOperand。 indices 数组包含输出张量中的完整坐标,最右侧维度保存每个坐标的维度数量。因此,形状为 [10,1] 的 indices 张量保存 10 个单轴索引,形状为 [4,3] 则保存 4 个三维坐标索引。这些值 必须为"int32"、"uint32"或"int64"类型,并且每个值都必须在 -N(含)到 N(不含)的范围内,其中 N 是对应输出维度的大小, 负索引表示从对应维度的末尾开始索引。 -
updates: 一个MLOperand。 要在 input 之上替换的新值。 -
options: 一个可选的MLScatterOptions。 该操作的可选参数。
返回:一个 MLOperand。
输出 N 维张量,其秩等于 input
的
秩 + indices
的
秩 - indices
的
shape[-1] - 1。
| 操作数 | 允许的 数据类型 | 允许的秩 |
|---|---|---|
input
| 任意 | 1 到 N |
indices
| "int32",
"uint32",
"int64"
| 1 到 N |
updates
| 与 input
相同
| N |
| output | 与 input
相同
| 1 到 N |
MLOpSupportLimits
具有以下用于 scatterND()
的成员:
scatterND,类型为 MLScatterSupportLimits-
运算符
scatterND()的支持限制。
indices
的 scatterND()
参数,在构建图时不能被夹取到允许范围内,因为输入要到执行时才知道。如果底层平台不提供指定的夹取行为,
实现可以在编译后的图中引入 clamp()。
类似地,如果底层平台不支持负索引,则实现可以在编译后的图中引入操作,以将从维度末尾开始的负索引转换为
正索引。
scatterND(input, indices, updates, options)
方法步骤为:
-
如果 this 不可构建,则抛出一个 "
InvalidStateError"DOMException。 -
如果以 验证操作数处理 this 以及 input、indices 和 updates 中的任一项返回 false,则抛出一个
TypeError。 -
令 indexableSize 为 indicesRank - 1。
-
令 coordinateSize 为 indicesShape[indexableSize]。
-
令 expectedUpdatesShape 为空列表。
-
对于 0 到 indexableSize(不含)的范围中的每个 index:
-
追加 indicesShape[index] 到 expectedUpdatesShape。
-
-
对于 coordinateSize 到 inputRank(不含)的范围 中的每个 index:
-
追加 inputShape[index] 到 expectedUpdatesShape。
-
-
令 outputShape 为 input 的shape 的副本。
-
令 outputDesc 为给定 input 的dataType 和 outputShape 时创建 MLOperandDescriptor的结果。
-
建立图连接:
-
令 output 为给定 outputDesc 时创建 MLOperand的结果。
-
令 operator 为给定 input、indices、 updates 和 options 时用于 "scatterND" 操作的一个运算符。
-
将 output.
[[operator]]设置为 operator。 -
将 operator 的输入设置为 input、indices 和 updates。
-
将 operator 的输出设置为 output。
-
-
返回 output。
scatterND 在不同切片方案中如何工作的示例。
// shape 为 [8] 的 input: // [0, 1, 2, 3, 4, 5, 6, 7] // shape 为 [4, 1] 的 indices: // [[4], // [3], // [1], // [7]] // shape 为 [4] 的 updates: // [-1, -2, -3, -4] // shape 为 [8] 的 output: // [0, -3, 2, -2, -1, 5, 6, -4] const input1= builder. constant( { dataType: 'float32' , shape: [ 8 ]}, new Float32Array([ 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 ])); const indices1= builder. constant( { dataType: 'uint32' , shape: [ 4 , 1 ]}, new Uint32Array([ 4 , 3 , 1 , 7 ])); const updates1= builder. constant( { dataType: 'uint32' , shape: [ 4 ]}, new Uint32Array([ - 1 , - 2 , - 3 , - 4 ])); const output1= builder. scatterND( input1, indices1, updates1); // shape 为 [2,2] 的 input: // [[0, 1], // [2, 3]] // shape 为 [2,2] 的 indices: // [[0, 0], // [1, 1]] // shape 为 [2] 的 updates: // [-1, -2] // shape 为 [2,2] 的 output: // [[-1, 1], <= -1 写入到输出坐标 [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] 的 input: // [[0, 1], // [2, 3], // [4, 5]] // shape 为 [2,1] 的 indices: // [[2], // [0]] // shape 为 [2,2] 的 updates: // [[-1, -2], // [-3, -4]] // shape 为 [3,2] 的 output: // [[-3 ,-4], <= [-3, -4] 写入到输出坐标 [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] 的 input: // [[[0, 1], // [2, 3]], // [[4, 5], // [6, 7]]] // shape 为 [2,2] 的 indices: // [[0, 1], // [1, 0]] // shape 为 [2,2] 的 updates: // [[-1, -2], // [-3, -4]] // shape 为 [2,2,2] 的 output: // [[[ 0, 1], // [-1, -2]], <= [-1, -2] 写入到输出坐标 [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
计算输入张量的 sigmoid 函数。 计算遵循表达式1 / (exp(-x) + 1)。
partial interface MLGraphBuilder {MLOperand sigmoid (MLOperand input ,optional MLOperatorOptions options = {}); };partial dictionary MLOpSupportLimits {MLSingleInputSupportLimits sigmoid ; };
-
input:一个MLOperand。 输入张量。 -
options:一个MLOperatorOptions。 指定该操作的可选参数。
返回:
| 操作数 | 允许的 数据类型 | 允许的秩 |
|---|---|---|
input
| "float32",
"float16"
| N |
| output | 与 input
相同
| 与 input
相同
|
MLOpSupportLimits
具有以下用于 sigmoid()
的成员:
sigmoid,类型为 MLSingleInputSupportLimits-
运算符
sigmoid()的支持限制。
sigmoid(input, options)
方法步骤为:
-
如果 this 不可构建,则抛出一个 "
InvalidStateError"DOMException。 -
建立图连接:
-
令 output 为给定 input 时复制 MLOperand的结果。
-
令 operator 为给定 options 时用于 "sigmoid" 操作的一个运算符。
-
将 output.
[[operator]]设置为 operator。 -
将 operator 的输入设置为 input。
-
将 operator 的输出设置为 output。
-
-
返回 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>-
沿每个轴跨过每个输入的步幅。 strides 数组的长度必须等于输入张量的秩。 默认值是长度为秩且全部由 1 组成的数组。 例如,对于三维张量为 [1,1,1]。 strides 必须大于零。
-
input: 一个MLOperand。 输入张量。 -
starts: 一个 sequence<unsigned long>。 每个输入维度的切片起始索引,长度为 N,其中 N 是输入张量的秩。 对于input的每个维度 d,starts[d] 表示该维度中的切片起始索引。起始索引必须在该维度的 [0, input size - 1] 范围内。 -
sizes: 一个 sequence<unsigned long>。 每个输入维度要切片的元素数量,长度为 N,其中 N 是输入张量的秩。 对于input的每个维度 d,sizes[d] 表示该维度中要切片的元素数量。该大小不能为 0,并且必须满足该维度中的约束starting index + size <= input size。 -
options: 一个MLSliceOptions。 指定该操作的可选参数。
返回:一个 MLOperand。
与输入张量具有相同秩的输出张量,其张量值被截取为每个维度中指定的起始索引和结束索引。
| 操作数 | 允许的 数据类型 | 允许的秩 |
|---|---|---|
input
| 任意 | N |
| output | 与 input
相同
| 与 input
相同
|
MLOpSupportLimits
具有以下用于 slice()
的成员:
slice,类型为 MLSingleInputSupportLimits-
运算符
slice()的支持限制。
slice(input, starts, sizes, options)
方法步骤为:
-
如果 this 不可构建,则抛出一个 "
InvalidStateError"DOMException。 -
令 strides 为新的列表。
-
令 outputShape 为新的列表。
-
对于 0 到 inputRank(不含)的范围中的每个 index:
-
令 inputSize 为 inputShape[index]。
-
令 inputSliceSize 为 sizes[index]。
-
令 stride 为 strides[index](如果它不为空),否则为 1:
-
如果 inputSliceSize 为 0,则抛出 一个
TypeError。如果 允许大小为 0 的维度,请修订这些步骤。[Issue #391]
-
如果 starts[index] + inputSliceSize 大于 inputSize,则抛出 一个
TypeError。 -
令 outputSizeRoundingExcess 为 1,如果 inputSliceSize % stride != 0;否则为 0。
-
令 outputSize 为 floor(inputSliceSize / stride) + outputSizeRoundingExcess:
-
追加 outputSize 到 outputShape。
-
-
令 outputDesc 为给定 input 的dataType 和 outputShape 时创建 MLOperandDescriptor的结果。
-
建立图连接:
-
令 output 为给定 outputDesc 时创建 MLOperand的结果。
-
令 operator 为给定 starts、sizes 和 options 时用于 "slice" 操作的一个运算符。
-
将 output.
[[operator]]设置为 operator。 -
将 operator 的输入设置为 input。
-
将 operator 的输出设置为 output。
-
-
返回 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 ; };
-
input:一个MLOperand。 输入 N 维张量。 -
axis:一个unsigned long标量。将执行归约的维度。 -
options:一个MLOperatorOptions。 指定该操作的可选参数。
返回:
| 操作数 | 允许的 数据类型 | 允许的秩 |
|---|---|---|
input
| "float32",
"float16"
| 1 到 N |
| output | 与 input
相同
| 与 input
相同
|
MLOpSupportLimits
具有以下用于 softmax()
的成员:
softmax,类型为 MLSingleInputSupportLimits-
运算符
softmax()的支持限制。
softmax(input, axis, options)
方法步骤为:
-
如果 this 不可构建,则抛出一个 "
InvalidStateError"DOMException。 -
建立图连接:
-
令 output 为给定 input 时复制 MLOperand的结果。
-
令 operator 为给定 axis 和 options 时用于 "softmax" 操作的一个运算符。
-
将 output.
[[operator]]设置为 operator。 -
将 operator 的输入设置为 input。
-
将 operator 的输出设置为 output。
-
-
返回 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 ; };
-
input:一个MLOperand。 输入张量。 -
options:一个MLOperatorOptions。 指定该操作的可选参数。
返回:
| 操作数 | 允许的 数据类型 | 允许的秩 |
|---|---|---|
input
| "float32",
"float16"
| N |
| output | 与 input
相同
| 与 input
相同
|
MLOpSupportLimits
具有以下用于 softplus()
的成员:
softplus,类型为 MLSingleInputSupportLimits-
运算符
softplus()的支持限制。
softplus(input, options)
方法步骤为:
-
如果 this 不可构建,则抛出一个 "
InvalidStateError"DOMException。 -
建立图连接:
-
令 output 为给定 input 时复制 MLOperand的结果。
-
令 operator 为用于 "softplus" 操作且给定 options 的一个运算符。
-
将 output.
[[operator]]设置为 operator。 -
将 operator 的输入设置为 input。
-
将 operator 的输出设置为 output。
-
-
返回 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))); }
-
input:一个MLOperand。 输入张量。 -
options:一个MLOperatorOptions。 指定该操作的可选参数。
返回:
| 操作数 | 允许的 数据类型 | 允许的秩 |
|---|---|---|
input
| "float32",
"float16"
| N |
| output | 与 input
相同
| 与 input
相同
|
MLOpSupportLimits
具有以下用于 softsign()
的成员:
softsign,类型为 MLSingleInputSupportLimits-
运算符
softsign()的支持限制。
softsign(input, options)
方法步骤为:
-
如果 this 不可构建,则抛出一个 "
InvalidStateError"DOMException。 -
建立图连接:
-
令 output 为给定 input 时复制 MLOperand的结果。
-
令 operator 为用于 "softsign" 操作且给定 options 的一个运算符。
-
将 output.
[[operator]]设置为 operator。 -
将 operator 的输入设置为 input。
-
将 operator 的输出设置为 output。
-
-
返回 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 ; };
-
input:一个MLOperand。 输入张量。 -
splits:一个unsigned long或 sequence<unsigned long>。 如果为unsigned long, 则它指定沿该轴的输出张量数量。该数量必须能够整除input沿axis的维度大小。 如果为 sequence<unsigned long>, 则它指定沿axis的每个输出张量的大小。 各大小之和必须等于input沿axis的维度大小。 -
options:一个 可选的MLSplitOptions。 该操作的可选参数。
返回:sequence<MLOperand>。
拆分后的输出张量。如果 splits
是一个 unsigned long,
则输出的大小等于 splits。
每个输出张量的形状与 input
相同,但 axis
的维度大小等于 input
沿 axis
的维度大小除以 splits
所得的商。
如果 splits
是一个 sequence<unsigned long>,
则输出的大小等于 splits
的大小。
第 i 个输出张量的形状与 input
相同,但沿 axis
的维度大小为 splits[i]。
MLSplitOptions
具有以下成员:
axis,类型为 unsigned long,默认值为0-
用于拆分的维度。其值必须在 [0, N-1] 范围内,其中 N 是输入张量的秩。
| 操作数 | 允许的 数据类型 | 允许的秩 |
|---|---|---|
input
| 任意 | 1 到 N |
| outputs | 与 input
相同
| 与 input
相同
|
MLSplitSupportLimits
具有以下成员:
input,类型为 MLTensorLimits-
用于输入操作数的
MLTensorLimits。 outputs,类型为 MLTensorLimits-
用于所有输出操作数的
MLTensorLimits。
MLOpSupportLimits
具有以下用于 split()
的成员:
split,类型为 MLSplitSupportLimits-
运算符
split()的支持限制。
split(input, splits, options)
方法步骤为:
-
如果 this 不可构建,则抛出一个 "
InvalidStateError"DOMException。 -
令 axis 为 options.
axis。 -
如果 splits 是一个
unsigned long, 则: -
如果 splits 是一个 sequence<
unsigned long>, 则: -
建立图连接:
-
令 operator 为给定 splits 和 options 时用于 "split" 操作的一个运算符。
-
令 outputs 为新的列表。
-
对于 0 到 splitCount(不含)的范围中的每个 index:
-
令 operand 为给定 input 时复制 MLOperand的结果。
-
如果 splits 是一个
unsigned long, 则令 newDimension 为 operand 的shape[axis] / splits。 -
否则,令 newDimension 为 splits[index]。
-
将 operand 的shape[axis] 设置为 newDimension。
-
将 operand.
[[operator]]设置为 operator。 -
追加 operand 到 outputs。
-
-
将 operator 的输入设置为 input。
-
将 operator 的输出设置为 outputs。
-
-
返回 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 sizeof 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 ; };
-
input:一个MLOperand。 输入张量。 -
options:一个MLOperatorOptions。 指定该操作的可选参数。
返回:
| 操作数 | 允许的 数据类型 | 允许的秩 |
|---|---|---|
input
| "float32",
"float16"
| N |
| output | 与 input
相同
| 与 input
相同
|
MLOpSupportLimits
具有以下用于 tanh()
的成员:
tanh,类型为 MLSingleInputSupportLimits-
运算符
tanh()的支持限制。
tanh(input, options) 方法
步骤为:
-
如果 this 不可构建,则抛出一个 "
InvalidStateError"DOMException。 -
建立图连接:
-
令 output 为给定 input 时复制 MLOperand的结果。
-
令 operator 为给定 options 时用于 "tanh" 操作的一个运算符。
-
将 output.
[[operator]]设置为 operator。 -
将 operator 的输入设置为 input。
-
将 operator 的输出设置为 output。
-
-
返回 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 ; };
-
input:一个MLOperand。 输入 N 维张量。 -
repetitions: 每个维度要重复该维度的次数。其大小必须与input的 秩匹配,对于 应保持相同大小的任何轴使用 1。 -
options: 一个可选的MLOperatorOptions。 该操作的可选参数。
返回:一个 MLOperand。
反转后的 N 维张量。
| 操作数 | 允许的 数据类型 | 允许的秩 |
|---|---|---|
input
| 任意 | N |
| output | 与 input
相同
| 与 input
相同
|
MLOpSupportLimits
具有以下用于 tile()
的成员:
tile,类型为 MLSingleInputSupportLimits-
运算符
tile()的支持限制。
tile(input, repetitions, options)
方法步骤为:
-
如果 this 不可构建,则抛出一个 "
InvalidStateError"DOMException。 -
如果 repetitions 的值包含 0,则抛出一个
TypeError。如果允许 大小为 0 的维度,请修订这些步骤。[Issue #391]
-
令 outputShape 为 input 的shape 的副本。
-
对于 0 到 outputShape 的大小(不含)的范围中的每个 index:
-
将 outputShape[index] 设置为 outputShape[index] * repetitions[index]。
-
-
令 outputDescriptor 为给定 input 的dataType 和 outputShape 时创建 MLOperandDescriptor的结果。
-
建立图连接:
-
令 output 为给定 outputDescriptor 时创建 MLOperand的结果。
-
令 operator 为给定 options 时用于 "tile" 操作的一个运算符。
-
将 output.
[[operator]]设置为 operator。 -
将 operator 的输入设置为 input。
-
将 operator 的输出设置为 output。
-
-
返回 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>-
用于置换输出形状的值。 默认值为 [N-1, ..., 0],其中 N 是输入张量的秩,例如对于 3 维张量为 [2,1,0]。 这些默认值会使输出成为输入的转置张量。指定时, 值的数量必须与输入张量的秩相同,并且这些值必须在 0 到 N-1 的范围内且不能重复。
-
input:一个MLOperand。 输入 N 维张量。 -
options:一个 可选的MLTransposeOptions。 该操作的可选参数。
返回:一个 MLOperand。
置换后或转置后的 N 维张量。
| 操作数 | 允许的 数据类型 | 允许的秩 |
|---|---|---|
input
| 任意 | N |
| output | 与 input
相同
| 与 input
相同
|
MLOpSupportLimits
具有以下用于 transpose()
的成员:
transpose,类型为 MLSingleInputSupportLimits-
运算符
transpose()的支持限制。
transpose(input, options)
方法步骤为:
-
如果 this 不可构建,则抛出一个 "
InvalidStateError"DOMException。 -
如果 options.
permutation不存在,则令 options.permutation为 input 的shape 的所有索引的反向序列。 -
否则,如果 options.
permutation存在: -
建立图连接:
-
令 output 为给定 input 时复制 MLOperand的结果。
-
令 operator 为给定 options 时用于 "transpose" 操作的一个运算符。
-
将 output.
[[operator]]设置为 operator。 -
将 operator 的输入设置为 input。
-
将 operator 的输出设置为 output。
-
-
返回 output。
8.9.55. triangular
给定一个 2 维张量(矩阵),返回一个 2 维张量,其中包含输入张量的上三角部分或下三角部分。 如果输入张量具有超过 2 个维度,则将其视为一批矩阵,结果具有相同形状。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 表示除主对角线之外的对角线不受影响。
-
input:一个MLOperand。 至少为 2 维的输入张量。 -
options:一个 可选的MLTriangularOptions。 该操作的可选参数。
返回:一个 MLOperand。
表示三角矩阵或一批矩阵的输出张量,其形状与输入相同。
| 操作数 | 允许的 数据类型 | 允许的秩 |
|---|---|---|
input
| 任意 | 2 到 N |
| output | 与 input
相同
| 与 input
相同
|
MLOpSupportLimits
具有以下用于 triangular()
的成员:
triangular,类型为 MLSingleInputSupportLimits-
运算符
triangular()的支持限制。
triangular(input, options)
方法步骤为:
-
如果 this 不可构建,则抛出一个 "
InvalidStateError"DOMException。 -
建立图连接:
-
令 output 为给定 input 时复制 MLOperand的结果。
-
令 operator 为给定 options 时用于 "triangular" 操作的一个运算符。
-
将 output.
[[operator]]设置为 operator。 -
将 operator 的输入设置为 input。
-
将 operator 的输出设置为 output。
-
-
返回 output。
triangular 在不同 diagonal 设置中如何工作的示例。
// input: // [[7, 1, 2], // [9, 4, 8], // [2, 6, 3]] const input= builder. constant( { dataType: 'float32' , shape: [ 3 , 3 ]}, new Float32Array([ 7 , 1 , 2 , 9 , 4 , 8 , 2 , 6 , 3 ])); // 上三角矩阵: // [[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
根据condition
张量中对应值的情况,从 trueValue
或 falseValue
张量中选择值,其中非零为 true,零为 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 ; };
-
condition: 一个MLOperand。 条件张量。 -
trueValue: 一个MLOperand。 当对应元素的条件被设置为 true 时,从中选择值的张量。 -
falseValue: 一个MLOperand。 当对应元素的条件被设置为 false 时,从中选择值的张量。 -
options: 一个MLOperatorOptions。 指定该操作的可选参数。
返回:一个 MLOperand。
输出张量,其中包含逐元素从 trueValue
或 falseValue
张量中选择的值。
| 操作数 | 允许的 数据类型 | 允许的秩 |
|---|---|---|
condition
| "uint8"
| N |
trueValue
| 任意 | N |
falseValue
| 与 trueValue
相同
| N |
| output | 与 trueValue
相同
| N |
MLWhereSupportLimits
具有以下成员:
condition,类型为 MLTensorLimits-
用于 condition 操作数的
MLTensorLimits。 trueValue,类型为 MLTensorLimits-
用于 trueValue 操作数的
MLTensorLimits。 falseValue,类型为 MLTensorLimits-
用于 falseValue 操作数的
MLTensorLimits。 output,类型为 MLTensorLimits-
用于 output 操作数的
MLTensorLimits。
MLOpSupportLimits
具有以下用于 where()
的成员:
where,类型为 MLWhereSupportLimits-
运算符
where()的支持限制。
where(condition, trueValue, falseValue, options)
方法步骤为:
-
如果 this 不可构建,则抛出一个 "
InvalidStateError"DOMException。 -
如果以 验证操作数处理 this 以及 condition、trueValue 和 falseValue 中任一项返回 false,则抛出一个
TypeError。 -
如果 condition、trueValue 或 falseValue 中任一项的dataType 不是其允许的数据类型之一 (根据此表),则抛出一个
TypeError。 -
令 outputShape 为对 trueValue 的shape 和 falseValue 的shape 进行双向广播的结果。
-
将 outputShape 设置为对 condition 的shape 和 outputShape 进行双向广播的结果。
-
令 descriptor 为给定 trueValue 的dataType 和 outputShape 时创建 MLOperandDescriptor的结果。
-
建立图连接:
-
令 output 为给定 this 和 descriptor 时创建 MLOperand的结果。
-
令 operator 为给定 condition、trueValue、 falseValue 和 options 时用于 "where" 操作的一个运算符。
-
将 output.
[[operator]]设置为 operator。 -
将 operator 的输入设置为 condition、 trueValue 和 falseValue。
-
将 operator 的输出设置为 output。
-
-
返回 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 在图构建和计算期间如何 处理具有不同形状的张量。它深受 [NumPy] 影响,并遵循 [numpy-broadcasting-rule]。宽泛地说,它允许 对较小张量的操作被“广播”到较大张量的形状上,这样同一份数据就可以重复应用,而无需创建副本。
最简单的例子是将一个标量常量应用于 N 维张量,并使用逐元素二元操作,例如 add()
或 mul()。
这些逐元素操作允许直接使用该标量常量,并将标量值广播到 N 维张量,而不需要分配和填充一个
包含多份该标量常量副本的匹配 N 维张量。在遵循下列考虑事项的情况下,同样的逻辑也适用于
其他维度的张量。
输入张量的形状必须兼容。如果第一个张量可以从最后一个(最右侧)维度开始,通过沿大小为 1 的轴
重复第一个张量或跨新维度重复而被“拉伸”到另一个张量,则该张量单向可广播到
另一个张量。例如,可以通过重复 5 次将一个 [4] 张量广播到一个 [5, 4] 张量。
可以通过在最后一个维度重复 4 次并在前一个维度重复 5 次,将一个 [1] 张量广播到 [5,4]
张量。单向广播对于诸如 expand()
这样显式给出目标张量形状的操作很重要。
如果两个张量可以从最后一个维度开始,在它们的各个维度上相互“拉伸”(重复),则它们是双向可广播的。例如,可以通过在最后一个维度上将第一个 张量重复 6 次,并在前一个维度上将第二个张量重复 5 次,使一个 [5,1] 张量与一个 [1,6] 张量进行双向广播。该操作的结果将是一个 [5,6] 张量。双向广播对逐元素操作很方便。
如果所有维度都可以按整数倍上采样到目标张量的形状,则张量是分块可广播的。 例如,一个 [4,5] 张量可以分块广播到一个 [16,10] 张量,因为它是精确倍数 (16 % 4 = 0,10 % 5 = 0),做法是在第一个维度上将每个元素重复 4 次,并在最后一个维度上将 每个元素重复 2 次(例如,最后维度中的值 [1,2,3,4,5] 会被重复为 [1,1,2,2,3,3,4,4,5,5])。但是,一个 [4,5] 张量与一个 [9,3] 张量不兼容,因为两个维度都有非零余数(9 % 4 = 1,3 % 5 = 3)。分块广播对于在更大的块中 共享公共值以节省内存很有用。两个张量预期具有相同的秩,输出形状就是较小张量正在上采样到的 目标张量形状。
有些操作允许使用特殊语义进行广播。例如,matmul()
将输入张量的最后两个维度视为矩阵的行和列,并且第一个矩阵的列数必须等于第二个矩阵的行数。
矩阵乘法会在任何额外维度上进行双向广播,把输入张量视为要相乘的矩阵堆栈。
要单向广播形状 shapeFrom 和 shapeTo,执行以下步骤。shapeFrom 和 shapeTo 是表示张量维度的正整数列表, 这些步骤返回一个新的正整数列表, 或 failure。
-
令 sizeFrom 为 shapeFrom 的大小。
-
令 sizeTo 为 shapeTo 的大小。
-
如果 sizeFrom > sizeTo,则返回 failure。
-
令 paddedShapeFrom 为 shapeFrom 的一个克隆。
-
令 outputShape 为一个新的列表。
-
对于 0 到 sizeTo(不含)的范围中的每个 index:
-
令 dimFrom 为 paddedShapeFrom[index]。
-
令 dimTo 为 shapeTo[index]。
-
如果 dimTo 不等于 dimFrom 且 dimFrom 不等于 1,则返回 failure。
-
将 dimTo 追加到 outputShape。
-
-
返回 outputShape。
如果对 shapeFrom 和 shapeTo 进行单向广播不会得到 failure,则 shapeFrom 单向可广播到 shapeTo。
要双向广播形状 shapeA 和 shapeB,执行以下步骤。shapeA 和 shapeB 是表示张量维度的正整数列表, 这些步骤返回一个新的正整数列表, 或 failure。
-
令 sizeA 为 shapeA 的大小。
-
令 sizeB 为 shapeB 的大小。
-
令 outputSize 为 sizeA 和 sizeB 中的较大值。
-
令 paddedA 为 shapeA 的一个克隆。
-
令 paddedB 为 shapeB 的一个克隆。
-
令 outputShape 为一个新的列表。
-
对于 0 到 outputSize(不含)的范围中的每个 index:
-
令 dimA 为 paddedA[index]。
-
令 dimB 为 paddedB[index]。
-
如果 dimA 不等于 dimB,且 dimA 不等于 1,且 dimB 不等于 1,则返回 failure。
-
将 dimA 和 dimB 中的较大值追加到 outputShape。
-
-
返回 outputShape。
如果对 shapeA 和 shapeB 进行双向广播不会得到 failure,则 shapeA 双向可广播到 shapeB。
要分块广播形状 shapeFrom 和 shapeTo,执行以下步骤。shapeFrom 和 shapeTo 是表示张量维度的正整数列表, 这些步骤返回 true 或 false。
如果对 shapeFrom 和 shapeTo 进行分块广播 返回 true,则 shapeFrom 分块可广播到 shapeTo。
9.2. 转换
显式数值转换用于一些算法中,在这些算法里,以 MLNumber
或 double
传入的参数需要被转换为与输入或输出 MLOperand 的
MLOperandDataType
匹配。
要将一个数字 x 转换为给定的
MLOperandDataType
dataType,执行以下步骤。它们返回一个数字。
-
对 dataType 执行 switch:
"float32"-
返回 ConvertToFloat(x, 32)。
"float16"-
返回 ConvertToFloat(x, 16)。
"int64"-
返回 ConvertToInt(x, 64, "signed")。
"uint64"-
返回 ConvertToInt(x, 64, "unsigned")。
"int32"-
返回 ConvertToInt(x, 32, "signed")。
"uint32"-
返回 ConvertToInt(x, 32, "signed")。
"int8"-
返回 ConvertToInt(x, 8, "signed")。
"uint8"-
返回 ConvertToInt(x, 8, "unsigned")。
注: cast 的输入是一个具有无限范围和精度的抽象数字, 包括特殊值 Infinity、-Infinity 和 NaN。输出也是一个抽象数字,但可以精确表示为指定类型。
-
如果 x 是 NaN,则返回 NaN。
-
对 bitLength 执行 switch:
- 32
-
-
令 upperBound 为 2128。
-
令 lowerBound 为 -2128。
-
令 S 为 [IEEE-754-2019] binary32 浮点值的集合,排除 -0,但加入特殊值 upperBound 和 lowerBound。
-
- 16
-
-
令 upperBound 为 216。
-
令 lowerBound 为 -216。
-
令 S 为 [IEEE-754-2019] binary16 浮点值的集合,排除 -0,但加入特殊值 upperBound 和 lowerBound。
-
-
令 y 为 S 中最接近 x 的数字;如果存在两个同样接近的值,则选择具有偶数有效数的数字。 为此目的,将两个特殊值 lowerBound 和 upperBound 视为具有偶数有效数。
-
如果 y 是 upperBound,则返回 +Infinity。
-
如果 y 是 lowerBound,则返回 -Infinity。
-
如果 y 是 +0 且 x 为负,则返回 -0。
-
返回 y。
注: 这基于 [WEBIDL] 中的一个定义, 但扩展为覆盖 16 位浮点值。
-
如果 signedness 是 "unsigned",则:
-
令 lowerBound 为 0。
-
令 upperBound 为 2bitLength - 1。
-
-
否则:
-
令 lowerBound 为 -(2bitLength - 1)。
-
令 upperBound 为 2bitLength - 1 - 1。
-
-
如果 x 是 -0,则将 x 设置为 +0。
-
如果 x 是 NaN,则返回 +0。
-
将 x 设置为 min(max(x, lowerBound), upperBound)。
-
将 x 舍入到最接近的整数;如果它正好位于两个整数之间,则选择偶数整数,并选择 +0 而不是 -0。
-
返回 x。
注: 这基于 [WEBIDL] 中的一个定义, 但有以下差异:64 位整数不被特殊处理,输入 x 是一个抽象数字,并且始终执行夹取。
9.3. 杂项
当 [INFRA] 中有可用定义时移除此内容。 [whatwg/infra Issue #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 axisof axes. sort(). reverse()) if ( axis< shape. length&& shape[ axis] == 1 ) shape. splice( axis, 1 ); return builder. reshape( input, shape); }
11.2. unsqueeze
11.3. flatten
flatten 操作将输入重塑为一维张量。
它可以按如下方式使用 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. MLOperandDataType
和 ArrayBufferView
兼容性
MLOperandDataType
| ArrayBufferView
|
|---|---|
float32
| Float32Array
|
float16
| Float16Array
|
int64
| BigInt64Array
|
uint64
| BigUint64Array
|
int32
| Int32Array
|
uint32
| Uint32Array
|
int8
| Int8Array
|
uint8
| Uint8Array
|
Float16Array
处于 ECMA Stage 3,表示其设计已经完成。
想要在原生实现之前启用此类型的实现者,可以通过经由 Uint16Array
传递原始位来模拟该类型。
[Issue webnn#373]
13. 致谢
本规范遵循 Android Neural Networks API C API 的概念。
感谢 Tomoyuki Shimizu、Ningxin Hu、Zhiqiang Yu 和 Belem Zhang 提供用例。
感谢 Nikhil Thorat、Daniel Smilkov、Ganesan Ramalingam、Rafael Cintron 和 Benjamin Poulain 对 API 规范的贡献。
感谢 Sangwhan Moon 和 W3C Technical Architecture Group 对本规范在 Web 架构适配、设计一致性和开发者人体工程学方面的审阅。
感谢 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 团队进行安全审阅并提出问题。
感谢 Michal Karzynski 分享来自 ONNX 的实践指南和经验。
感谢 Kaustubha Govind 和 Chrome 隐私审阅者提供反馈和隐私方面的考虑。
感谢 Jiewei Qian 提供 Chromium 实现审阅和反馈。
感谢 Dwayne Robinson、Joshua Lochner 和 Wanming Lin 对 transformer 支持进行调研并提供建议。 还要感谢 Dwayne 和 Wanming 对运算符一致性和 web-platform-tests 实现进行审阅。
感谢 Feng Dai 持续贡献,使 web-platform-tests 与本规范同步演进。
感谢 Fuqiao Xue 和 W3C Internationalization Activity 提供审阅和建议。
14. 变更
本节为非规范性内容。
本节按照变更类别记录自上一次主要发布以来对本规范所做的变更。
Candidate Recommendation Snapshot 2024 年 4 月 11 日 与 2026 年 1 月 22 日 之间的详细变更
新功能(class 4)
- 扩展运算符集“wave 3”,加入包括 dequantizeLinear、quantizeLinear 和 attention 操作在内的新运算符 (#805)
- 添加 MLTensor API,这是一个用于在 WebNN 和 WebGPU 之间共享缓冲区,并跨多个 MLGraph 重用的接口 (#787)
- 添加 isNaN 和 isInfinite 运算符,这些是用于检查 NaN 和无限值的新逐元素运算符 (#858)
- 添加 roundEven 运算符,这是使用银行家舍入的新舍入运算符(#859)
- 添加加速器选择机制,一种用于选择 ML 加速器的简单机制(#895)
- 向 shared worker 和 service worker 暴露 WebNN API,以将 WebNN 可用性扩展到 window 和 dedicated worker 之外 (#823)
- 添加可选运算符标签,用于提供更易诊断的错误消息(#742)
- 引入 MLNumber,一种用于指定任何类型数值输入的统一类型(#647)
- 向 opSupportLimits() 添加 rankRange,以支持在支持限制中指定秩范围(#828)
- 为 op 输出张量支持 rankRange,以将 rankRange 支持扩展到输出张量(#857)
添加 MLDeviceType npu,一种 Neural Processing Unit (NPU) 设备类型(#696)- 此功能在上次发布后 被添加又被移除,以简化设备选择,参见 #809- 为 MLContext 和 MLGraph 添加 destroy() 方法,指定上下文丢失行为和错误报告 (#744)
- 向 softmax 操作添加可选 axis 参数(#649)
- 向 argmin/argmax 添加 outputDataType,以支持指定输出数据类型(#730)
- 允许 resample2d 使用任意 axes,以将 resample2d 泛化为可配合任何 axes 工作 (#752)
- 添加 Resample 数据类型 uint8/int8,以扩展 resample 对 8 位整数类型的支持 (#891)
- 简化 conv2d 和 pool2d 操作的操作数布局支持,移除 pool2d 中的 MLRoundingType,简化布局支持 (#770)
- 限制 padding 选项,以更好匹配后端限制(#843)
不添加新功能的其他变更(class 3)
- 移除 MLContext.compute() 方法,改用 MLTensor API(#795)
- 移除 MLDeviceType,通过移除设备类型枚举来简化设备选择(#809)
- 将 MLOperand 方法转换为 readonly 属性,并将 dataType() 和 shape() 从方法改为属性 (#774)
- 使 MLOperandDescriptor.shape 成为必需属性(#764)
- 只允许调用一次 MLGraphBuilder.build(),以将 build 方法限制为单次调用 (#717)
- 移除 constant() 的 fillSequence 重载,以移除基于 sequence 的常量创建 (#656)
- 交换 scalar constant() 操作数方法的参数,以重新排序参数来保持一致性 (#650)
- 移除 argmin/argmax 的 selectLastIndex 参数,以简化 argmin/argmax API (#722)
- 将 cast/constant 参数类型重命名为 dataType,以保持整个 API 的一致性 (#888)
- 将 MLActivation 替换为 MLRecurrentNetworkActivation,使递归网络激活使用更具体的类型 (#718)
- 将 DOMString 改为 USVString,以获得更好的 Unicode 支持(#715)
- 重命名 where 的参数名,以提高参数命名的清晰度(#719)
- 将 MLLstmCellSupportLimits 的成员 output 重命名为 outputs,以保持一致性 (#757)
- 拒绝已销毁 MLTensor 上正在进行操作的 promise,以实现正确的 promise 拒绝 (#799)
- 指定操作的操作数数据类型约束,以启用数据类型验证规则(#646)
- 为若干 op 添加缺失的验证步骤,以改进验证(#820)
- 为 pad()、slice() 和 split() 添加缺失验证,以增强数组操作的验证 (#690)
- 简化、更正并添加 GRU/LSTM 验证,以改进递归网络验证(#659)
- 验证 GRU 和 LSTM 运算符的隐藏大小(#644)
- 验证 convTranspose2d 中 output padding 的限制,以对转置卷积进行更严格的验证 (#631)
- 增强 gather 操作验证(#642)
- 一般验证改进(#643)
- 改进资源验证(#622)
- 定义 MLNamedArrayBufferViews 转移算法的错误处理,以正确处理缓冲区转移错误 (#723)
- 将维度有效范围更新为有符号整数(#738)
- 引入“有效维度”概念,以形式化维度有效性(#641)
- 确保对象创建指定 realm,以正确处理对象创建的 realm(#810)
- 阐明除法运算符的舍入(#909)
- 更正 pad 标量不一致(#894)
- 修复 split op 的 opSupportLimits 错误(#776)
- 为 softmax() axis 参数使用 EnforceRange,以进行正确的范围强制 (#746)
- 向 conv2d 算法添加缺失的 inputShape 定义(#680)
- 修复单向广播形状步骤(#663)
- 修复当缓冲区转移失败时 compute() promise 拒绝行为(#639)
- 使用 64 位整数类型更新 ArrayBufferView 兼容性表(#698)
不在功能上影响文档解释的变更(class 2)
- 使操作数数据类型和秩验证由表驱动,以系统化验证方式(#657)
- 添加按类别列出的非规范性运算符表(#868)
- 阐明 cast() op 在不同数据类型之间的行为(#726)
- 阐明 resample2d 的插值算法(#816)
- 阐明使用空 axes 和标量输入的 reduction,以明确边界情况(#741)
- 添加关于空操作图的注(#665)
- 添加关于 reduction ops 的 keepDimensions 的注,以阐明 reduction 操作行为(#648)
- 重组模拟文档(#598)
- 添加 reduceLogSum、reduceLogSumExp 和 reduceSumSquare 的分解(#637)
- 移除关于 clamp() minValue == maxValue 的互操作问题的过时注(#684)
- 更新规范样板元数据信息(#769)
- 添加架构资源竞争方面的考虑(#765)
- 添加 Unicode 相关安全考虑(#851)
- 添加关于计算控制流攻击的安全考虑(#725)
- 修订隐私考虑(#890)
- 添加关于 opSupportLimits() 指纹识别的隐私考虑(#881)
- 添加无障碍考虑(#869)
- 添加关于 label 使用的国际化注(#841)
编辑性(class 2)
- 各种编辑性改进(#834)
- 各种样式和措辞调整(#797)
- 语法和拼写更正(#782)
- 使用辅助算法简化规范步骤(#737)
- 改进类型引用(#735)
- 引用 WebIDL transferable 定义(#732)
- 在 prose 中避免使用 "sequence",以改进术语使用(#729)
- 改进验证算法步骤的逻辑,以增强 linting 和验证(#727)
- 链接方法参数定义以改进交叉引用(#721)
- 移除不必要的小节以改进组织(#711)
- 当意图为形容词时,链接到 "is empty" 而不是 "empty"(#708)
- 添加实用工具以简化本规范的编写和审阅(#702)
- 修复 "transferred" 交叉引用(#679)
- 将 "generically emulated" 文本制作为宏,以改善编写体验(#638)
- 修复 LSTM 通过 'backward' 和 'both' directions 模拟时的错误(#802)
- 修复 GRU 通过 'backward' 和 'both' directions 模拟时的错误(#803)
- 更正分解中的拼写错误/JS 错误(#699)