1. 简介
Web 神经网络 API 定义了一个面向 Web、与硬件无关的抽象层,它利用 操作系统和底层硬件平台的机器学习能力,而无需绑定到 特定于平台的能力。该抽象层满足主要机器学习 JavaScript 框架的需求,同时也允许熟悉 ML 领域的 Web 开发者编写自定义代码, 而无需借助库。
有关图示简介,请参阅说明文档。
2. 用例
2.1. 应用用例
本节说明神经网络 推理硬件加速的应用级用例。这些用例中的所有应用都可以 构建于预训练深度神经网络(DNN)[models]之上。
注: 请注意,这里描述的一些用例 就其本质而言会侵犯隐私。计划将该 API 用于 此类用例的开发者应当确保使用该 API 是为了让用户受益, 用于用户能够理解并认可的目的。他们应当应用 Web 机器学习伦理原则 [webmachinelearning-ethics],并实施 适当的隐私风险缓解措施,例如透明度、数据最小化和用户控制。
注: § 3 无障碍 考虑提供了有关如何改善这些用例无障碍性的指导。
2.1.1. 人员检测
用户打开一个基于 Web 的视频会议应用,但她暂时 离开了房间。该应用使用对象检测来监测她是否位于 PC 前(例如,使用对象检测方法, 如使用单个 DNN 的 [SSD] 或 [YOLO]),以 检测摄像头输入帧中包含人员的区域。
当她回来时,应用会自动检测到她,并通知 其他在线用户她现在处于活动状态。
2.1.2. 语义分割
由于办公室没有可用的会议室,用户在 办公桌前通过基于 Web 的视频会议应用加入电话会议。在 电话会议期间,她不希望自己的房间和背景中的人员 可见。为了保护其他人员和周围环境的隐私, 应用运行机器学习模型,例如 [DeepLabv3+]、 [MaskR-CNN] 或 [SegAny],从语义上 将图像划分成多个分段,并将 表示其他人员和背景的分段替换为另一张图片。
2.1.3. 骨架检测
基于 Web 的视频会议应用通过 运行支持实时人体姿态 估计的机器学习模型来跟踪用户的骨架姿态,例如 [PoseNet],以识别她的 手势和肢体语言。当 她举手时,她的麦克风会自动取消静音,她可以开始 在电话会议中发言。
2.1.4. 人脸识别
会议室中有多个人,他们使用 基于 Web 的视频会议应用加入在线会议。应用使用对象检测来检测 参与者的人脸(例如,使用对象检测 方法,如 [SSD]),并通过运行机器学习模型(例如 [FaceNet])检查每张人脸是否在 上一次会议中出现过, 该模型会验证两张人脸是否相同。
2.1.5. 面部关键点检测
用户希望在在线眼镜 商店中找到一副非常适合她的新眼镜。该在线商店提供基于 Web 的试戴模拟器,该模拟器运行 机器学习模型,例如人脸对齐网络 [FAN] 来检测面部关键点, 例如眼睛、鼻子、嘴巴等。当她选择一副眼镜时,模拟器 会将所选眼镜正确渲染到她 面部图像中检测到的眼睛位置上。
2.1.6. 风格迁移
用户正在在线商店寻找化妆品,并想知道哪种颜色可能 适合她的脸。在线商店显示化妆品的面部妆容示例图像, 并提供一个化妆模拟器,该模拟器运行类似 [ContextualLoss] 或 [PairedCycleGAN] 的机器学习模型,将 示例妆容图像的妆容风格迁移到她的面部图像。她可以通过模拟器查看所选妆容 在她脸上的效果。
2.1.7. 超分辨率
基于 Web 的视频会议应用正在接收来自对端的视频流,但 由于网络拥塞,视频分辨率降低。为了防止 感知到的视频质量下降,应用运行用于超分辨率的机器 学习模型,例如 [SRGAN] 来生成 更高分辨率的视频帧。
2.1.8. 图像描述生成
为了提高无障碍性,基于 Web 的演示应用通过运行机器学习模型(例如 [im2txt]) 自动生成图像描述, 该模型会预测演示幻灯片的说明性文字。
2.1.9. 文本生成图像
图像是现代 Web 体验的核心组成部分。在保护隐私的前提下,根据文本输入生成图像 的能力可实现 Web 应用和内容的视觉 个性化和适配。例如,一个 Web 应用可以将网页上的自然语言描述 或用户在文本提示中提供的描述作为输入,从而生成 与文本描述匹配的图像。由 潜在扩散模型架构 [LDM] 实现的这种文本生成图像用例构成了 其他 文本生成图像用例的基础。例如,图像修补,即利用新生成的内容有选择地修改 网页上现有图像的一部分; 或相反的图像扩展,即将原始图像扩展到其 原始尺寸之外,并用生成的内容填充空白区域。
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++] 之类的 deepfake 检测 应用会分析视频,并保护用户免受 伪造视频或图像的影响。当她在 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 加速器等硬件设备上执行每项运算。为了避免设备之间不必要的数据复制, 框架选择同一设备来执行这些运算。对于计算密集型运算,例如 2D 卷积或矩阵乘法,框架使用 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],因为它授予对用户计算机的底层访问权限。为了 满足强大功能的身份验证和机密性预期,并防止中间人 攻击,本规范定义的所有接口仅在安全上下文中可用。使用§ 7.5 权限策略集成时,所有跨源框架默认禁用此 API。这可以防止 第三方内容使用此 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.9 opSupportLimits() API 允许 Web 开发者使用显式查询 API 查询对特定运算符的支持,而不是通过侧信道推断 此信息。此 API 可能会增加可指纹识别性,但可以通过酌情使用分桶来限制通过该 API 暴露的可区分配置数量,从而降低其 熵。
-
不同后端实现之间具有一致的错误处理。
总体设计确保实现可以在不同平台之间保持一致的接口, 同时提供必要的功能。通过抽象特定于平台的细节,无论底层加速由 CPU、GPU 还是专用 ML 硬件提供,该 API 都可以提供 保护隐私且可预测的行为。
注: MLContextOptions
正在积极开发中,并且预计设计会根据进一步的实现
经验和更广泛 Web 社区中的新用例而发生变化。
已提出 MLGraph.devices API 扩展,用于在图完全构建和编译后暴露实际选择用于
执行的设备。目前正在研究此 API 扩展的隐私影响。[问题 #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()
期间的错误。
[问题 #778]
在推理时,每个 MLOperand 都会
绑定到一个张量(实际数据),张量本质上是多维数组。张量的表示
取决于实现,但通常包括存储在某个缓冲区
(内存)中的数组数据,以及描述数组数据的一些元数据(例如其形状)。
计算图中的运算具有函数式语义。这使实现 有可能在多个张量之间共享数组数据。例如,reshape 或 slice 等运算的实现可能返回其输入张量的视图, 该视图与输入张量共享同一个缓冲区。(对于 reshape, 会共享全部数据,而对于 slice,则共享输入数据的一部分。) 实现可以如上所述对中间值使用视图。
执行之前,需要将用于计算一个或多个指定输出的计算图 转换、编译和优化。编译步骤的主要目的是启用跨越 两个或更多运算的优化,例如运算融合或循环融合。用户代理也可以在图转换期间执行这些 优化。
MLGraphBuilder.build()
方法会在后台编译图,而不会阻塞调用线程,并返回一个 Promise,
该 Promise 会兑现为一个 MLGraph。每个 MLGraphBuilder
最多只能构建一个 MLGraph。
MLGraph
的底层实现将由运算符和操作数的特定平台表示组成,
这些表示对应于 MLGraphBuilder
的
运算符和 MLOperand,
但它们对脚本不可见,并且可能是脚本所构建图的组合或分解形式。
一旦构建了 MLGraph,
MLContext.dispatch()
方法会异步执行图,对于 CPU 执行,会在单独工作线程中的并行时间线上执行;
对于 GPU,则会在 GPU 命令队列中的 GPU 时间线上执行。此方法立即返回,
不会阻塞调用线程,而实际执行会卸载到不同的时间线。调用者使用 MLNamedTensors
提供输入值,将输入 MLOperand
绑定到其值。调用者还为输出 MLOperand
提供 MLNamedTensors,
如果成功,这些输出将包含图执行的结果,可以使用
MLContext.readTensor(tensor)
方法将其读回脚本。这种执行方式支持 CPU、GPU 和 NPU 设备。
7.2. 设备选择
MLContext
接口表示神经网络执行的全局状态。一个重要的上下文状态是
底层执行设备,该设备负责管理资源,并促进神经网络图的编译和最终
执行。除了使用 MLContextOptions
的默认创建方法外,也可以从应用已经在使用的特定 GPUDevice
创建 MLContext。
当 GPU 上下文执行一个图,并且该图的常量或输入以
ArrayBufferView
的形式位于系统内存中时,输入内容会自动从系统内存上传到 GPU 内存,并在图执行结束时下载回
ArrayBufferView
输出缓冲区所在的系统内存。只有在执行设备要求将数据从系统内存复制出去并再复制回来时,
才会发生这种数据上传和下载循环,例如
GPU 就属于这种情况。当设备是 CPU 设备时,不会发生这种情况。此外,图执行结果采用已知的布局格式。
虽然执行过程可能针对图中的中间结果使用原生内存访问
模式进行优化,但图中最后一个运算的输出必须
在图末尾将内容转换回已知布局格式,以维持调用者视角下预期的
行为。
MLContextOptions
创建 MLContext
时,
用户代理会在考虑这些选项的情况下选择并创建底层执行设备。
根据底层平台,用户代理可以选择不同的 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 对象可分别通过 Navigator
和 WorkerNavigator
接口在 Window
和 WorkerGlobalScope
上下文中使用,并通过 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 和 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,该 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,该 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 >createExportableTensor (MLTensorDescriptor descriptor ,GPUDevice gpuDevice );Promise <MLTensor >createConstantTensor (MLOperandDescriptor descriptor ,AllowSharedBufferSource inputData );Promise <ArrayBuffer >readTensor (MLTensor tensor );Promise <undefined >readTensor (MLTensor tensor ,AllowSharedBufferSource outputData );undefined writeTensor (MLTensor tensor ,AllowSharedBufferSource inputData );GPUBuffer exportToGPU (MLTensor tensor );MLOpSupportLimits ();opSupportLimits undefined destroy ();readonly attribute boolean accelerated ;readonly attribute Promise <MLContextLostInfo >lost ; };
MLContext
具有以下内部槽:
上下文类型是 管理资源并促进神经网络图编译和执行的执行上下文类型:
- "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]]:-
-
给定 inputs 和 outputs,向 graph.
[[implementation]]发出计算请求。添加一种用于报告 图执行期间错误的机制。[问题 #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( '输出值:' , new Float32Array( result)); // [1, 1, 1, 1]
8.3.2.
createTensor()
创建一个与此 MLContext 关联的
MLTensor。
-
descriptor:一个MLTensorDescriptor。
createTensor(descriptor) 方法的步骤
为:
-
如果 this 已丢失,则返回 realm 中一个新的 promise,该 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. createExportableTensor()
创建一个与此 MLContext
关联的 MLTensor,
该张量可以使用 exportToGPU()
导出到给定的 GPUDevice。
-
descriptor: 一个MLTensorDescriptor。 -
gpuDevice: 一个GPUDevice。 张量可以导出到的设备。
createExportableTensor(descriptor, gpuDevice)
方法的步骤为:
-
如果 this 已丢失,则返回 realm 中一个新的 promise,该 promise 以 "
InvalidStateError"DOMException拒绝。 -
如果 gpuDevice 已丢失,则返回 realm 中一个新的 promise,该 promise 以 "
InvalidStateError"DOMException拒绝。 -
如果 this 不支持将
MLTensor导出到 gpuDevice,则返回 realm 中一个新的 promise,该 promise 以 "NotSupportedError"DOMException拒绝。注:
MLContext是否支持导出到给定的GPUDevice是实现定义的,并且可能取决于MLContext的 上下文类型和 底层平台。 -
令 tensor 为给定 this、 descriptor 和 gpuDevice 创建 可导出 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.4. createConstantTensor()
创建一个与此 MLContext
关联的常量 MLTensor。
-
descriptor: 一个MLOperandDescriptor。 -
inputData: 一个AllowSharedBufferSource。 其字节将写入张量的缓冲区。
createConstantTensor(descriptor, inputData)
方法的步骤为:
-
如果 this 已丢失,则返回 realm 中一个新的 promise,该 promise 以 "
InvalidStateError"DOMException拒绝。 -
如果给定 descriptor 检查维度返回 false,则返回 realm 中一个新的 promise,该 promise 以
TypeError拒绝。 -
如果给定 inputData 和 descriptor 使用描述符验证缓冲区返回 false,则返回 realm 中一个新的 promise,该 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.5.
readTensor(tensor)
将 MLTensor
的 [[data]]
从 MLContext.[[timeline]]
读回脚本。
-
tensor:一个MLTensor。 要读取的张量。
返回: Promise<ArrayBuffer>。
一个包含读取结果的缓冲区。
readTensor(tensor) 方法的步骤为:
-
如果 tensor.
[[context]]不是 this,则返回 realm 中一个新的 promise,该 promise 以TypeError拒绝。 -
如果 tensor.
[[isDestroyed]]为 true,则返回 realm 中一个新的 promise,该 promise 以TypeError拒绝。 -
如果 tensor.
[[descriptor]].readable为 false,则返回 realm 中一个新的 promise,该 promise 以TypeError拒绝。 -
如果 tensor 已导出,则返回 realm 中一个新的 promise,该 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.6.
readTensor(tensor, outputData)
readTensor(tensor)
的自带缓冲区变体。
将 MLTensor
的 [[data]]
读回到所提供的缓冲区中。
-
tensor:一个MLTensor。 要读取的张量。 -
outputData:一个AllowSharedBufferSource。 用于读入结果的缓冲区。
readTensor(tensor, outputData)
方法的步骤为:
-
如果 tensor.
[[context]]不是 this,则返回 realm 中一个新的 promise,该 promise 以TypeError拒绝。 -
如果 tensor.
[[isDestroyed]]为 true,则返回 realm 中一个新的 promise,该 promise 以TypeError拒绝。 -
如果 tensor.
[[descriptor]].readable为 false,则返回 realm 中一个新的 promise,该 promise 以TypeError拒绝。 -
如果 tensor 已导出,则返回 realm 中一个新的 promise,该 promise 以
TypeError拒绝。 -
如果给定 outputData 和 tensor.
[[descriptor]]使用描述符验证缓冲区 返回 false,则返回 realm 中一个新的 promise,该 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.7.
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]]:
注: 与 dispatch() 类似,
writeTensor() 本身不会提供写入已完成的信号。要检查张量的内容,
调用者可以 await 读回张量的结果。
8.3.8.
exportToGPU()
将一个可导出的 MLTensor
作为 GPUBuffer
导出到其关联的 GPUDevice,
并将其借给该 GPUDevice,
直到返回的 GPUBuffer
被销毁。
当一个 MLTensor 已导出时,
[[gpuDevice]]
对 MLTensor 的
内容具有独占访问权,并且任何依赖该 MLTensor 的 WebNN
运算——
包括 dispatch()、
readTensor(tensor)、
readTensor(tensor, outputData)
和 writeTensor()
——都会抛出一个 TypeError。
返回的 GPUBuffer
创建时,其 usage
为 GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST,且其 size
等于 MLTensor 的
[[descriptor]]
的
字节长度。当返回的 GPUBuffer
被销毁时,MLTensor
会被归还给 MLContext,并且
可以再次用于 WebNN 运算。
注: 无法保证导出 MLTensor 时
会实现零拷贝。如果为 MLTensor
提供支持的内存无法被
[[gpuDevice]]
访问,则导出可能需要将 MLTensor 的
内容复制到返回的 GPUBuffer
中,
并在 GPUBuffer
被销毁后再将其复制回来。
exportToGPU(tensor) 方法的步骤为:
-
如果 tensor.
[[context]]不是 this,则抛出一个TypeError。 -
如果 tensor.
[[isDestroyed]]为 true,则抛出一个TypeError。 -
如果 tensor.
[[exportableToGPU]]为 false,则抛出一个TypeError。 -
令 gpuDevice 为 tensor.
[[gpuDevice]]。 -
如果 gpuDevice 已丢失,则抛出一个 "
InvalidStateError"DOMException。 -
如果 tensor 已导出,则返回 tensor.
[[exportedBuffer]]。 -
令 usage 为
GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST。 -
令 buffer 为 realm 中一个与 gpuDevice 关联的新
GPUBuffer, 其size为 tensor.[[descriptor]]的 字节长度,其usage为 usage。 -
将以下步骤排入 tensor.
[[context]].[[timeline]]: -
将 tensor.
[[exportedBuffer]]设置为 buffer。 -
返回 buffer。
用户代理必须确保,任何排入 gpuDevice 的 GPUQueue
且读取或写入 buffer 的运算,都不得在上面用于确保
buffer 的内容反映 tensor.[[data]]
的排队步骤完成之前执行。
注: 此顺序保证是用户代理内部的;
它不要求应用执行任何可观察到的同步。应用可以在 exportToGPU()
返回后立即安全地记录并提交使用 buffer 的 GPUQueue
工作。
当由 exportToGPU()
返回的 GPUBuffer
被销毁时,用户代理必须给定导出该缓冲区所来自的 MLTensor 归还已导出的 MLTensor。
注: 当 MLTensor 或其
MLContext
已
导出时将其销毁,并不会使返回的 GPUBuffer
失效;
GPUBuffer
在被销毁之前仍可由 [[gpuDevice]]
使用。
注: 如果当 MLTensor 已导出时,
[[gpuDevice]]
变为已丢失,则返回的 GPUBuffer
不会被隐式销毁,并且 MLTensor 仍保持
已导出状态(因此
无法由 WebNN 运算使用),直到应用调用 destroy();
即使 gpuDevice 已丢失,调用该方法仍然有效。
8.3.8.1. 示例
以下代码展示了使用可导出张量的最小 WebNN 到 WebGPU 流程。
// 1. 创建 WebGPU 和 WebNN 上下文。 const gpuAdapter= await navigator. gpu. requestAdapter(); const gpuDevice= await gpuAdapter. requestDevice(); const context= await navigator. ml. createContext(); // 2. 构建一个简单的图:y = x + 1。 const builder= new MLGraphBuilder( context); const descriptor= { dataType: 'float32' , shape: [ 4 ]}; const x= builder. input( 'x' , descriptor); const one= builder. constant( descriptor, new Float32Array([ 1 , 1 , 1 , 1 ])); const y= builder. add( x, one); const graph= await builder. build({ y}); // 3. 创建可导出张量,运行 WebNN dispatch。 const inputTensor= await context. createExportableTensor( { dataType: 'float32' , shape: [ 4 ], writable: true }, gpuDevice); const outputTensor= await context. createExportableTensor( { dataType: 'float32' , shape: [ 4 ], readable: true }, gpuDevice); context. writeTensor( inputTensor, new Float32Array([ 1 , 2 , 3 , 4 ])); context. dispatch( graph, { x: inputTensor}, { y: outputTensor}); // 4. 导出到 WebGPU 并在 GPU 命令中使用。 const gpuBuffer= context. exportToGPU( outputTensor); // ... 在 WebGPU 计算/渲染工作中使用 gpuBuffer ... // 5. 将张量归还给 WebNN,然后再次从 WebNN 读取。 gpuBuffer. destroy(); const result= new Float32Array( await context. readTensor( outputTensor)); console. log( result); // [2, 3, 4, 5]
8.3.9.
opSupportLimits()
opSupportLimits()
暴露不同实现在运算符级别上的支持程度。鼓励 WebNN API 的使用者通过使用 opSupportLimits()
探测功能支持级别,以确定要部署到每个目标平台上的最佳模型架构。
注: opSupportLimits()
API 并非旨在为浏览器指纹识别提供额外的熵。在当前实现中,
仅根据 OS 和浏览器版本即可推断这些功能支持信息。如果未来实现的多样性
有此必要,此 API 允许未来实现添加新的隐私缓解措施,
例如像 WebGPU 一样对能力进行分桶以减少熵。
有关指纹识别 考虑事项的进一步讨论,请参阅§ 5 隐私考虑。
8.3.9.1. MLOpSupportLimits
字典
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.9.2. MLRankRange
字典
dictionary {MLRankRange unsigned long min ;unsigned long max ; };
min, 类型为 unsigned long-
支持的最小秩。
max, 类型为 unsigned long-
支持的最大秩。
8.3.9.3. MLTensorLimits
字典
typedef sequence <MLOperandDataType >;MLDataTypeList dictionary {MLTensorLimits MLDataTypeList dataTypes ;MLRankRange rankRange ; };
dataTypes, 类型为 MLDataTypeList-
支持的数据类型。
rankRange, 类型为 MLRankRange-
支持的最小秩和最大秩。
8.3.9.4. MLBinarySupportLimits
字典
dictionary {MLBinarySupportLimits MLTensorLimits a ;MLTensorLimits b ;MLTensorLimits output ; };
a, 类型为 MLTensorLimits-
用于 a 操作数的
MLTensorLimits。 b, 类型为 MLTensorLimits-
用于 b 操作数的
MLTensorLimits。 output, 类型为 MLTensorLimits-
用于输出操作数的
MLTensorLimits。
8.3.9.5. MLSingleInputSupportLimits
字典
dictionary {MLSingleInputSupportLimits MLTensorLimits input ;MLTensorLimits output ; };
input, 类型为 MLTensorLimits-
用于输入操作数的
MLTensorLimits。 output, 类型为 MLTensorLimits-
用于输出操作数的
MLTensorLimits。
8.3.10.
destroy()
destroy()
方法可被调用以释放与上下文关联的所有资源。任何未完成的计算请求
以及 MLTensor
创建/读取/写入请求都将失败。
destroy() 方法的步骤为:
8.3.11. 错误
当用户代理确定一个 MLContext
不再可用于满足请求时,它必须为其运行上下文丢失步骤。
MLContext
context 的上下文丢失
步骤为:
-
令 global 为 context 的相关全局对象。
-
使用 global 将 ML 任务排入队列,以运行以下步骤:
要使用 DOMString
message 丢失 MLContext
context:
-
令 info 为一个新的
MLContextLostInfo。 -
将 info.
message设置为 message。 -
对于满足 graph.
[[context]]等于 this 的每个MLGraphgraph: -
对于满足 tensor.
[[context]]等于 this 的每个MLTensortensor:
message, 类型为 DOMString-
一条提供有关所发生错误信息的实现定义消息。
A MLContext
如果其 [[lost]]
Promise
已敲定,则已丢失。
8.4. MLGraph
接口
MLGraph
接口表示一个已编译的计算图。一个已编译的图一旦构建便不可变,之后无法
更改。
[SecureContext ,Exposed =(Window ,Worker )]interface {MLGraph undefined destroy (); };
MLGraph 具有
以下内部槽:
[[context]],类型为MLContext[[inputDescriptors]],类型 为 record<USVString,MLOperandDescriptor>-
将此
MLGraph的所有输入MLOperand中每个输入MLOperand的名称映射到其MLOperandDescriptor。 [[outputDescriptors]],类型 为 record<USVString,MLOperandDescriptor>-
将此
MLGraph的所有输出MLOperand中每个输出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" ,"bfloat16" ,"float8e4m3" };dictionary {MLOperandDescriptor required MLOperandDataType dataType ;required sequence <[EnforceRange ]unsigned long >shape ; };
dataType, 类型为 MLOperandDataType-
操作数的数据类型。
shape, 类型为sequence<[EnforceRange] unsigned long>-
操作数的维度列表。对于标量操作数,该列表为空。
MLOperandDataType
枚举指定操作数的每个元素的数据类型:
float32-
32 位浮点数,采用 [IEEE-754-2019]的 binary32 交换格式。
float16-
16 位浮点数,采用 [IEEE-754-2019]的 binary16 交换格式。
int32-
32 位有符号整数,采用二进制补码表示。
uint32-
32 位无符号整数。
int64-
64 位有符号整数,采用二进制补码表示。
uint64-
64 位无符号整数。
int8-
8 位有符号整数,采用二进制补码表示。
uint8-
8 位无符号整数。
bfloat16-
16 位“脑浮点”数,具有 1 个符号位、8 个指数位(指数偏置为 127)和 7 个尾随有效数位。其指数范围与
"float32"相同,无穷大、NaN、带符号的零和次正规值的表示方式与 [IEEE-754-2019]的二进制交换格式相同。此格式中某个值的位布局,与同一值的 binary32 编码的最高 16 位完全相同。 float8e4m3-
8 位浮点数,采用 OCP 8 位浮点规范 [OCP-OFP8]的 E4M3 格式,具有 1 个符号位、4 个指数位(指数偏置为 7)和 3 个尾随有效数位。与其他浮点数据类型不同,此格式无法表示无穷大;最大有限绝对值为 448,NaN 的编码将所有指数位和有效数位设为 1。支持带符号的零和次正规值。向此格式的转换采用饱和转换:绝对值超过 448 的值(包括无穷大)会转换为同符号的最大有限值,参见
cast()。
"bfloat16"
和 "float8e4m3"
都不是任何运算的 必需数据类型 。可以使用 opSupportLimits()逐个查询运算的支持情况。
注意: "float8e4m3"
格式对应 PyTorch 的 float8_e4m3fn 类型和 ONNX 的 FLOAT8E4M3FN 类型。它与为无穷大保留编码的 E4M3 编码不同,也与不含负零的“FNUZ”变体不同;本枚举均不表示这两者。
注意: 采用 "float8e4m3"
的量化计算通过 dequantizeLinear()
和 quantizeLinear()
包围其他运算来表达,这些运算的操作数为 "float32",
"float16"
或 "bfloat16",因此 "float8e4m3"
是此类子图的量化输入、权重和输出的数据类型,而不是算术运算本身的操作数类型。对于原生支持 "float8e4m3"
算术的平台,鼓励实现将量化和反量化运算融合到它们所包围的运算中,并以 "float8e4m3"执行,例如作为 "float8e4m3"
matmul();其他实现则显式执行它们。另外,一些运算的 允许的数据类型 为
任意类型;这包括数据移动运算,例如 reshape()
和 concat(),也包括算术运算,例如 add()
和 clamp()。图构建不会拒绝这些运算的 "float8e4m3"
操作数,实现是否支持它们由 opSupportLimits()报告。
注意: 由于没有适用于以下类型的 ArrayBufferView
类型: "bfloat16"
和 "float8e4m3",因此其原始位分别通过 Uint16Array
和 Uint8Array
传递,参见 § 12.1 MLOperandDataType 与 ArrayBufferView 的兼容性。即使平台缺乏这些数据类型的原生支持,实现仍可能在特定位置支持它们,例如在图执行前转换一个 constant()
操作数,该操作数馈入 cast()
或 dequantizeLinear()
运算。这样可以保留模型权重下载大小的缩减,但无法保留低精度格式带来的内存占用缩减或任何计算收益。
dataType
等于 B.dataType
且 A.shape
等于 B.shape,则一个
MLOperandDescriptor
A 等于另一个 MLOperandDescriptor
B。
给定 MLOperandDataType
dataType 和列表 shape,要创建
一个 MLOperandDescriptor,
运行以下步骤:
一个 MLOperandDescriptor
desc 的字节长度是以下步骤返回的值:
一个 MLOperandDescriptor
desc 的元素数量是以下步骤返回的值:
有效维度是
大于零且位于 long
范围内的整数。
实现可以施加更小的上限。
有效张量 数量是大于零且小于或等于 8192 的整数。实现可以施加 更小的上限。
是否应支持大小为 0 的维度? [问题 #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。
dataType 的getter 步骤是
返回 this 的dataType。
shape 的getter 步骤是
返回 this 的shape。
由于 [[builder]]
对象由 MLGraphBuilder()
构造函数绑定到一个 MLContext
对象,因此一个 MLOperand
也始终绑定到同一个 MLContext
对象。
如果某项运算仅支持 MLOperandDataType
的一个子集,
则该运算每个输入操作数(包括位置参数和选项)的允许的数据
类型会以以下方式给出:MLOperandDataType
的显式列表,
或要求操作数的 dataType
必须与另一个输入操作数的 dataType 相同的约束,或者使用
任意类型以允许任意 MLOperandDataType。
实现可以支持比指定范围更少的操作数数据类型,但必须至少支持
指定的必需数据
类型。现在可以通过在 MLContext 上使用
opSupportLimits()
方法,并检查 Chromium 原型中 ONNX Runtime、LiteRT 和 CoreML 后端上
该运算对应成员的 dataTypes
值,来查询每项运算的支持情况。
必需数据 类型集合是根据广泛平台上的实现经验确定的,以确保 开发者能够通过设计仅使用这些数据类型的模型来生成可互操作的内容。本规范的 Web 平台测试使用此能力检测机制来验证所有允许的数据 类型的正确行为,但只支持必需数据类型也可以通过测试。
如果某项运算要求输入操作数具有特定秩,则该运算每个输入操作数(包括 位置参数和选项)的允许的秩会以显式秩(例如 1)给出,或者使用 N 以允许任意维度, 或者与另一个操作数的秩相同。更具体的约束很常见,例如当一个 输入操作数的形状必须可单向广播到另一个输入操作数,或与另一个输入操作数双向可广播时; 在这些情况下,允许的 秩会列为一个范围,并且具体的验证会作为该运算中的步骤给出。
实现可以对操作数的秩施加比指定范围更严格的下限和/或上限,但必须
至少支持指定的必需秩。现在可以通过在
MLContext
上使用 opSupportLimits()
方法,并检查 Chromium 原型中 ONNX Runtime、LiteRT 和 CoreML 后端上
该运算对应成员的 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
的方法创建,
其内部使用以下算法。
给定 MLGraphBuilder
builder 和 MLOperandDescriptor
desc,要创建一个
MLOperand,运行以下步骤:
-
令 realm 为 builder 的相关领域。
-
令 operand 为 realm 中一个新的
MLOperand。 -
将 operand.
[[builder]]设置为 builder。 -
将 operand.
[[descriptor]]设置为 desc。 -
返回 operand。
给定 MLOperand
operand,要复制一个
MLOperand,运行以下步骤:
-
令 builder 为 operand.
[[builder]]。 -
令 realm 为 builder 的相关领域。
-
令 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 问题 #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
的要求,以实现定义的方式分配。涉及 MLTensor 的 [[data]]
的运算发生在其关联 MLContext 的
[[timeline]]
上。
有关如何分配 MLTensor
的实现定义要求可能包括一些约束,例如要求内存以特定字节对齐方式
分配,或在特定内存池中分配。
[SecureContext ,Exposed =(Window ,Worker )]interface {MLTensor readonly attribute MLOperandDataType dataType ;readonly attribute FrozenArray <unsigned long >shape ;readonly attribute boolean readable ;readonly attribute boolean writable ;readonly attribute boolean constant ;undefined destroy (); };
MLTensor 具有
以下内部槽:
[[context]],类型为MLContext-
MLTensor的 关联上下文。 [[descriptor]],类型为MLTensorDescriptor-
MLTensor的 描述符。 [[pendingPromises]],类型 为Promise的集合-
与正在进行且尚未兑现的
MLContext.readTensor(tensor)方法调用对应的 Promise。当MLTensor被销毁时,所有待处理的 promise 都将被拒绝。 [[isDestroyed]],类型为boolean[[data]],具有实现定义的类型-
为
MLTensor提供支持的字节。 此数据只能从[[context]].[[timeline]]访问或修改。 [[isConstant]],类型为boolean-
MLTensor是否由创建常量 MLTensor所创建。 [[exportableToGPU]],类型 为boolean-
MLTensor是否由创建可导出 MLTensor所创建,并且可以 使用exportToGPU()导出到一个GPUDevice。 [[gpuDevice]],类型为GPUDevice或 null-
MLTensor可以导出到的GPUDevice, 如果MLTensor不可导出,则为 null。仅当[[exportableToGPU]]为 true 时设置。 [[exportedBuffer]],类型为GPUBuffer或 null-
由于
exportToGPU()而当前借给[[gpuDevice]]的GPUBuffer, 如果MLTensor当前未导出,则为 null。
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]]。
一个 MLTensor
已导出,如果其 [[exportedBuffer]]
不为 null。
8.8.1. 创建 MLTensor
MLTensor 由
与其关联的 MLContext 创建。
给定 MLContext
context 和 MLTensorDescriptor
descriptor,要创建一个
MLTensor,运行以下步骤:
-
令 realm 为 context 的相关领域。
-
令 tensor 为 realm 中一个新的
MLTensor。 -
将 tensor.
[[context]]设置为 context。 -
将 tensor.
[[descriptor]]设置为 descriptor。 -
将 tensor.
[[isDestroyed]]设置为 false。 -
将 tensor.
[[isConstant]]设置为 false。 -
将 tensor.
[[exportableToGPU]]设置为 false。 -
将 tensor.
[[gpuDevice]]设置为 null。 -
将 tensor.
[[exportedBuffer]]设置为 null。 -
返回 tensor。
给定 MLContext
context、MLTensorDescriptor
descriptor 和 GPUDevice
gpuDevice,要创建
可导出的 MLTensor,运行以下步骤:
-
令 tensor 为给定 context 和 descriptor 创建 MLTensor 的结果。
-
将 tensor.
[[exportableToGPU]]设置为 true。 -
将 tensor.
[[gpuDevice]]设置为 gpuDevice。 -
返回 tensor。
给定 MLTensor
tensor,要归还
已导出的 MLTensor,运行以下步骤:
-
如果 tensor 未导出,则中止这些步骤。
-
令 buffer 为 tensor.
[[exportedBuffer]]。 -
将 tensor.
[[exportedBuffer]]设置为 null。 -
如果 tensor.
[[isDestroyed]]为 true,则中止这些步骤。 -
将以下步骤排入 tensor.
[[context]].[[timeline]]:-
运行以下步骤,但当 tensor.
[[context]]已 丢失时中止:
-
用户代理必须确保,上面排入队列、用于确保 tensor.[[data]]
反映 buffer 内容的步骤,不得在此前所有排入
gpuDevice 的 GPUQueue
且读取或写入 buffer 的运算完成之前执行。
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 创建。
给定 MLContext
context、MLOperandDescriptor
inputDescriptor,要创建
常量 MLTensor,运行以下步骤:
-
令 realm 为 context 的相关领域。
-
令 tensor 为 realm 中一个新的
MLTensor。 -
将 tensor.
[[context]]设置为 context。 -
令 tensorDescriptor 为一个新的
MLTensorDescriptor。 -
将 tensorDescriptor.
readable设置为 false。 -
将 tensorDescriptor.
writable设置为 false。 -
将 tensor.
[[descriptor]]设置为 tensorDescriptor。 -
将 tensor.
[[isDestroyed]]设置为 false。 -
将 tensor.
[[isConstant]]设置为 true。 -
将 tensor.
[[exportableToGPU]]设置为 false。 -
将 tensor.
[[gpuDevice]]设置为 null。 -
将 tensor.
[[exportedBuffer]]设置为 null。 -
返回 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
返回之前立即初始化。此图初始化阶段对于后续图
执行的最佳性能非常重要。它通常涉及一个称为“权重预处理”的过程,其中图的所有常量输入
都会在操作系统层进行预处理和缓存,以供后续图执行调用使用。
初始化输入通常是在图构建期间通过 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 为创建一个 MLOperand(给定 this 和 descriptor)的结果。
-
令 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 为创建一个 MLOperand(给定 this 和 tensor.
[[descriptor]])的结果。 -
将 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 为在给定 创建 MLOperand、this 和 descriptor 的情况下所得的结果。
-
-
返回 operand。
8.9.4. build 方法
将截至给定输出操作数的组合图异步构建为计算图。-
outputs:一个MLNamedOperands。 标识将作为图输出的MLOperand。
MLGraph>。
build(outputs) 方法步骤如下:
-
如果 this 无法构建,则返回 realm 中一个新的 promise,该 promise 以一个 "
InvalidStateError"DOMException拒绝。 -
如果 outputs 为空,则返回 realm 中一个新的 promise,该 promise 以一个
TypeError拒绝。 -
对于每个 outputs 中的 name → operand:
-
如果 name 为空,则返回 realm 中一个 新的 promise,该 promise 以一个
TypeError拒绝。 -
如果在给定 this 和 operand 的情况下验证操作数返回 false,则返回 realm 中一个新的 promise,该 promise 以一个
TypeError拒绝。 -
如果 operand 位于 this 的图的输入 或常量中,则返回 realm 中一个新的 promise,该 promise 以一个
TypeError拒绝。 -
如果 operand.
[[constantTensor]]存在且 operand.[[constantTensor]].[[isDestroyed]]为 true,则返回 realm 中一个 新的 promise,该 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。
如果 keepDimensions
为 true,则输出 N 维张量的秩等于
input
的
秩;如果 keepDimensions
为 false,则其秩为 input
的
秩 - 1。这些值的类型必须为 outputDataType,
且位于 [0, N-1] 范围内,其中 N 是由 axis
指定的输入维度的大小。
| 操作数 | 允许的数据 类型 | 必需的 数据类型 | 允许的秩 | 必需的秩 |
|---|---|---|---|---|
input
| 任意 | "float32",
"float16",
"int32"
| 1 到 N | 1 到 5 |
| 输出 | "int32",
"int64"
| "int32"
| N | 0 到 5 |
MLOpSupportLimits
对 argMin()
和 argMax()
具有以下成员:
argMin,类型为 MLSingleInputSupportLimits-
运算符
argMin()的支持限制。 argMax,类型为 MLSingleInputSupportLimits-
运算符
argMax()的支持限制。
要在给定字符串
op、MLOperand
input、unsigned long
axis 和 MLArgMinMaxOptions
options 的情况下创建 argMin/argMax
操作,运行以下步骤:
-
断言:op 是 "argMin"、"argMax" 之一。
-
如果 this 无法构建,则抛出一个 "
InvalidStateError"DOMException。 -
如果 options.
outputDataType不是输出张量的允许的数据类型(根据此表),则抛出一个TypeError。 -
如果 input 的形状[axis] 大于 options.
outputDataType的 最大值,则抛出一个TypeError。 -
令 outputShape 为在给定 input 的形状、« 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",
"bfloat16"
| "float32",
"float16"
| 1 到 N | 3 到 5 |
mean
| 与 input
相同
| "float32",
"float16"
| 1 | 1 |
variance
| 与 input
相同
| "float32",
"float16"
| 1 | 1 |
scale
| 与 input
相同
| "float32",
"float16"
| 1 | 1 |
bias
| 与 input
相同
| "float32",
"float16"
| 1 | 1 |
| 输出 | 与 input
相同
| "float32",
"float16"
| 与 input
相同
| 3 到 5 |
MLBatchNormalizationSupportLimits
具有以下成员:
input,类型为 MLTensorLimits-
用于输入操作数的
MLTensorLimits。 mean,类型为 MLTensorLimits-
用于均值操作数的
MLTensorLimits。 variance,类型为 MLTensorLimits-
用于方差操作数的
MLTensorLimits。 scale,类型为 MLTensorLimits-
用于缩放操作数的
MLTensorLimits。 bias,类型为 MLTensorLimits-
用于偏置操作数的
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。 -
如果 mean 的形状不与 « input 的形状[options.
axis] » 相等,则抛出一个TypeError。 -
如果 variance 的形状不与 « input 的形状[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-D 张量时,此操作的行为可以通过使用其他操作按如下方式进行通用模拟,不过用户
代理通常具有更高效的实现。此分解是一个说明性示例
而不是参考实现:它不规定算法或
中间结果的精度。在底层平台不直接支持某项操作的情况下,
此分解可用作指导实现的模板。
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
| 任意 | "float32",
"float16",
"int32",
"int8",
"uint8"
| N | 0 到 5 |
| 输出 | 任意 | "float32",
"float16",
"int32",
"int8",
"uint8"
| 与 input
相同
| 0 到 5 |
MLOpSupportLimits
对 cast()
具有以下成员:
cast,类型为 MLSingleInputSupportLimits-
运算符
cast()的支持限制。
根据下表,MLOperandDataType
之间的转换
在某些情况下有明确规定,而在其他情况下则由实现定义:
| 目标类型 输入类型 |
"float32",
"float16",
"bfloat16"
|
"float8e4m3"
|
"int32",
"uint32",
"int64",
"uint64",
"int8",
"uint8"
|
|---|---|---|---|
"float32",
"float16",
"bfloat16",
"float8e4m3"
|
如果在范围内,则取最接近的可表示值。
如果超出范围,则为 +/-Infinity。 如果是 NaN,则为 NaN。 |
如果在范围内,则为最近的可表示值。
如果超出范围或为无穷大,则为同符号的最大有限值。 如果是 NaN,则为 NaN。 |
如果在范围内,则截断。
如果超出范围,则由实现定义. 如果是 NaN,则 由实现定义。 |
"int32",
"uint32",
"int64",
"uint64",
"int8",
"uint8"
|
如果在范围内,则取最接近的可表示值。
如果超出范围,则为 +/-Infinity。 |
如果在范围内,则为最近的可表示值。
如果超出范围,则为同符号的最大有限值。 |
如果在范围内,则保持相同值。
如果超出范围,则将最低 N 位重新解释为目标类型,对于有符号类型,假定使用二进制补码。 |
注意:例如,将 -1 从 "int8"
转换为 "uint8"
规定会得到 255。但将 -1 从 "float32"
转换为 "uint8"
则由实现定义。由于 "float8e4m3"
无法表示无穷大,将 1000 或 +Infinity 从 "float32"
转换为 "float8e4m3"
时会饱和到 448,即最大的有限 "float8e4m3"
值。这对应于 [OCP-OFP8]的饱和转换模式;不使用会产生 NaN 的非饱和模式。
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
| 任意 | "float32",
"float16"
| N | 0 到 5 |
| 输出 | 与 input
相同
| "float32",
"float16"
| 与 input
相同
| 0 到 5 |
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 ; };
-
axis:一个unsigned long标量。输入沿其拼接的轴。其值必须在 [0, N-1] 范围内, 其中 N 是输入张量的秩。 -
options:一个MLOperatorOptions。 指定此操作的可选参数。
返回值:一个 MLOperand。
所有输入沿
axis
拼接后的张量。
输出张量在所有输入
进行拼接的维度之外具有相同的形状。该维度的大小
计算为所有输入在同一维度上的大小之和。
| 操作数 | 允许的 数据类型 | 必需的 数据类型 | 允许的秩 | 必需的秩 |
|---|---|---|---|---|
inputs
的
项
| 任意 | "float32",
"float16",
"int32"
| 1 到 N | 1 到 5 |
| 输出 | 与 inputs
的
项 相同
| "float32",
"float16",
"int32"
| 与 inputs
的
项 相同
| 1 到 5 |
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 和 outputShape 的情况下创建 MLOperandDescriptor 的结果。
-
建立图连接:
-
令 output 为在给定 this 和 desc 的情况下创建 MLOperand 的结果。
-
令 operator 为给定 inputs、axis 和 options 的 "concat" 操作的一个运算符。
-
将 output.
[[operator]]设置为 operator。 -
将 operator 的输入设置为 inputs。
-
将 operator 的输出设置为 output。
-
-
返回 output。
8.9.10. conv2d
给定 4 维输入张量和滤波器张量,计算二维卷积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] 的额外一维张量,其值将加到 卷积结果中。
-
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",
"bfloat16"
| "float32",
"float16"
| 4 | 4 |
filter
| 与 input
相同
| "float32",
"float16"
| 4 | 4 |
bias
| 与 input
相同
| "float32",
"float16"
| 1 | 1 |
| 输出 | 与 input
相同
| "float32",
"float16"
| 4 | 4 |
MLConv2dSupportLimits
具有以下成员:
input, 类型为 MLTensorLimits-
用于输入操作数的
MLTensorLimits。 filter, 类型为 MLTensorLimits-
用于 filter 操作数的
MLTensorLimits。 bias, 类型为 MLTensorLimits-
用于 bias 操作数的
MLTensorLimits。 output, 类型为 MLTensorLimits-
用于输出操作数的
MLTensorLimits。
MLOpSupportLimits
对于 conv2d()
具有以下成员:
conv2d, 类型为 MLConv2dSupportLimits-
运算符
conv2d()的支持限制。
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]。
给定无符号 整数 inputSize、filterSize、beginningPadding、 endingPadding、stride 和 dilation,要计算卷积输出大小,执行以下步骤。它们返回一个 数值。
-
令 effectiveFilterSize 为 ( filterSize - 1 ) * dilation + 1。
-
令 outputSize 为 ( inputSize - effectiveFilterSize + beginningPadding + endingPadding ) / stride + 1。
-
返回 outputSize。
给定无符号 整数 inputHeight、inputWidth、filterHeight 和 filterWidth,以及由 4 个无符号整数组成的列表 padding、由 2 个无符号整数组成的列表 strides,以及由 2 个无符号整数组成的列表 dilations,要计算 conv2d 输出大小,执行以下步骤。它们 返回一个由 2 个数值组成的列表。
conv2d(input, filter, options)
方法步骤如下:
-
如果 this 无法构建,则抛出一个 "
InvalidStateError"DOMException。 -
如果在给定 验证操作数所需的 this 以及 input、filter 和 options.
bias(如果它存在)中的任意一个时返回 false,则抛出一个TypeError。 -
计算输出形状:
-
令 inputShape 为 input 的形状。
-
根据 options.
inputLayout分情况处理: -
令 filterShape 为 filter 的形状。
-
根据 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 » 为在给定 计算 conv2d 输出 大小所需的 inputHeight、inputWidth、 filterHeight、filterWidth、options.
padding、 options.strides和 options.dilations时的结果。 -
将 outputHeight 设置为 floor( outputHeight )。
-
将 outputWidth 设置为 floor( outputWidth )。
-
根据 options.
inputLayout分情况处理: -
令 desc 为在给定 创建 MLOperandDescriptor 所需的 input 的dataType 和 outputShape 时的结果。
-
-
建立图连接:
-
令 output 为在给定 创建 MLOperand所需的 this 和 desc 时的结果。
-
令 operator 为给定 运算符所需的 "conv2d" 操作、 options 和 filter。
-
将 output.
[[operator]]设置为 operator。 -
将 operator 的输入设置为 input 和 filter。
-
将 operator 的输出设置为 output。
-
-
返回 output。
8.9.11. convTranspose2d
根据四维输入张量和滤波器张量计算二维转置卷积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] 的额外一维张量,其值将加到 卷积结果中。
-
input: 一个MLOperand。 输入四维张量。其逻辑形状 根据inputLayout的值进行解释。 -
filter: 一个MLOperand。 滤波器四维张量。其逻辑形状 根据filterLayout和groups的值进行解释。 -
options: 一个可选的MLConvTranspose2dOptions。
返回值:一个 MLOperand。
包含转置卷积结果的输出四维张量。输出形状
根据 inputLayout
进行解释。
更具体地说,除非显式指定 outputSizes,
否则需要使用 outputPadding
按如下公式计算输出张量的空间维度值:
outputSize = (inputSize - 1) * stride + (filterSize - 1) * dilation + 1 - beginningPadding - endingPadding + outputPadding
| 操作数 | 允许的 数据类型 | 必需的 数据类型 | 允许的秩 | 必需的秩 |
|---|---|---|---|---|
input
| "float32",
"float16",
"bfloat16"
| "float32",
"float16"
| 4 | 4 |
filter
| 与 input
相同
| "float32",
"float16"
| 4 | 4 |
bias
| 与 input
相同
| "float32",
"float16"
| 1 | 1 |
| 输出 | 与 input
相同
| "float32",
"float16"
| 4 | 4 |
MLOpSupportLimits
对 convTranspose2d()
具有以下成员:
convTranspose2d,类型为 MLConv2dSupportLimits-
运算符
convTranspose2d()的支持限制。
要在给定无符号整数 inputSize、filterSize、beginningPadding、 endingPadding、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 的形状。
-
根据 options.
inputLayout分情况处理: -
令 filterShape 为 filter 的形状。
-
根据 options.
filterLayout分情况处理: -
令 outputChannels 为 filterOutputChannels * options.
groups。 -
令 calculatedOutputHeight 为在给定 计算 转置卷积输出大小所需的 inputHeight、filterHeight、 padding[0]、padding[1]、strides[0] 和 dilations[0] 时的结果。
-
令 calculatedOutputWidth 为在给定 计算 转置卷积输出大小所需的 inputWidth、filterWidth、 padding[2]、padding[3]、strides[1] 和 dilations[1] 时的结果。
-
如果 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 为在给定 创建 MLOperandDescriptor 所需的 input 的dataType 和 outputShape 时的结果。
-
-
建立图连接:
-
令 output 为在给定 创建 MLOperand所需的 this 和 desc 时的结果。
-
令 operator 为给定 运算符所需的 "convTranspose2d" 操作、 options 和 filter。
-
将 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",
"bfloat16",
"int32",
"uint32",
"int64",
"uint64"
| "float32",
"float16",
"int32"
| 1 到 N | 1 到 5 |
| 输出 | 与 input
相同
| "float32",
"float16",
"int32"
| 与 input
相同
| 1 到 5 |
MLCumulativeSumOptions
具有以下成员:
exclusive,类型为 boolean,默认值为false-
是否在输出中包含或排除当前值,即计算包含当前值的前缀和或 不包含当前值的前缀和 [Prefix-sum]。给定输入 [1,2,3,4],包含当前值的求和将 产生输出 [1,3,6,10],而不包含当前值的求和将产生 [0,1,3,6]。默认 为包含当前值。
reversed,类型为 boolean,默认值为false-
是否沿当前轴反转求和方向,改为从较高 坐标向较低坐标求和。给定输入 [1,2,3,4],包含当前值的正向求和将 产生输出 [1,3,6,10],而包含当前值的反向求和将产生 [10,9,7,4]。默认为正向。
-
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
| 任意类型 | "float32",
"float16",
"int32"
| N | 0 到 5 |
b
| 与 a
相同
| "float32",
"float16",
"int32"
| N | 0 到 5 |
| 输出 | 与 a
相同
| "float32",
"float16",
"int32"
| N | 0 到 5 |
MLOpSupportLimits
对逐元素二元运算具有以下成员:
add, 类型为 MLBinarySupportLimits-
运算符
add()的支持限制。 sub, 类型为 MLBinarySupportLimits-
运算符
sub()的支持限制。 mul, 类型为 MLBinarySupportLimits-
运算符
mul()的支持限制。 div, 类型为 MLBinarySupportLimits-
运算符
div()的支持限制。 max, 类型为 MLBinarySupportLimits-
运算符
max()的支持限制。 min, 类型为 MLBinarySupportLimits-
运算符
min()的支持限制。 pow, 类型为 MLBinarySupportLimits-
运算符
pow()的支持限制。
要在给定字符串
op、MLOperand
a、MLOperand
b 和 MLOperatorOptions
options 的情况下创建逐元素二元操作,运行以下步骤:
-
断言: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. 逐元素逻辑操作
逐元素比较输入张量,并返回一个"uint8"
张量,其中比较结果为 0(假)或 1(真)。对于单操作数操作,返回该操作的逻辑
结果。
对于多操作数操作,将根据 [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
| 任意 | "float32",
"float16",
"int32"
| N | 0 到 5 |
b
| 与 a
相同
| "float32",
"float16",
"int32"
| N | 0 到 5 |
| 输出 | "uint8"
| "uint8"
| N | 0 到 5 |
| 操作数 | 允许的 数据类型 | 必需的 数据类型 | 允许的秩 | 必需的秩 |
|---|---|---|---|---|
a
| "uint8"
| "uint8"
| N | 0 到 5 |
| 输出 | "uint8"
| "uint8"
| N | 0 到 5 |
| 操作数 | 允许的 数据类型 | 必需的 数据类型 | 允许的秩 | 必需的秩 |
|---|---|---|---|---|
a
| "uint8"
| "uint8"
| N | 0 到 5 |
b
| 与 a
相同
| "uint8"
| N | 0 到 5 |
| 输出 | "uint8"
| "uint8"
| N | 0 到 5 |
| 操作数 | 允许的 数据类型 | 必需的 数据类型 | 允许的秩 | 必需的秩 |
|---|---|---|---|---|
a
| "float32",
"float16",
"bfloat16",
"float8e4m3"
| "float32",
"float16"
| N | 0 到 5 |
| 输出 | "uint8"
| "uint8"
| N | 0 到 5 |
注意: "float8e4m3"
无法表示无穷大,因此 isInfinite()
会对该数据类型操作数的每个元素产生零。 isNaN()
会检测 "float8e4m3"
的 NaN 编码,与其他浮点数据类型一样。
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:逐元素计算两个输入张量的逻辑与, 将任何非零值视为真,并返回值为 0 或 1 的元素。
-
logicalOr:逐元素计算两个输入张量的逻辑或, 将任何非零值视为真,并返回值为 0 或 1 的元素。
-
logicalXor:逐元素计算两个输入张量的逻辑异或, 将任何非零值视为真,并返回值为 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" 之一,则:
-
如果 a 的dataType 不是 «
"float32"、"float16","bfloat16","float8e4m3"» 之一,则抛出一个TypeError。
-
-
如果传入了 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
| "float32",
"float16",
"bfloat16",
"int64",
"int32",
"int8"
| "float32",
"float16",
"int32"
| N | 0 到 5 |
| 输出 | 与 input
相同
| "float32",
"float16",
"int32"
| 与 input
相同
| 0 到 5 |
| 操作数 | 允许的 数据类型 | 必需的 数据类型 | 允许的秩 | 必需的秩 |
|---|---|---|---|---|
input
| "float32",
"float16",
"bfloat16"
| "float32",
"float16"
| N | 0 到 5 |
| 输出 | 与 input
相同
| "float32",
"float16"
| 与 input
相同
| 0 到 5 |
| 操作数 | 允许的 数据类型 | 必需的 数据类型 | 允许的秩 | 必需的秩 |
|---|---|---|---|---|
input
| 任意 | "float32",
"float16",
"int32"
| N | 0 到 5 |
| 输出 | 与 input
相同
| "float32",
"float16",
"int32"
| 与 input
相同
| 0 到 5 |
| 操作数 | 允许的 数据类型 | 必需的 数据类型 | 允许的秩 | 必需的秩 |
|---|---|---|---|---|
input
| "float32",
"float16",
"bfloat16",
"int64",
"int32",
"int8"
| "float32",
"float16",
"int32"
| N | 0 到 5 |
| 输出 | 与 input
相同
| "float32",
"float16",
"int32"
| 与 input
相同
| 0 到 5 |
MLOpSupportLimits
对逐元素一元操作具有以下成员:
abs,类型为 MLSingleInputSupportLimits-
运算符
abs()的支持限制。 ceil,类型为 MLSingleInputSupportLimits-
运算符
ceil()的支持限制。 cos,类型为 MLSingleInputSupportLimits-
运算符
cos()的支持限制。 erf,类型为 MLSingleInputSupportLimits-
运算符
erf()的支持限制。 exp,类型为 MLSingleInputSupportLimits-
运算符
exp()的支持限制。 floor,类型为 MLSingleInputSupportLimits-
运算符
floor()的支持限制。 identity,类型为 MLSingleInputSupportLimits-
运算符
identity()的支持限制。 log,类型为 MLSingleInputSupportLimits-
运算符
log()的支持限制。 neg,类型为 MLSingleInputSupportLimits-
运算符
neg()的支持限制。 reciprocal,类型为 MLSingleInputSupportLimits-
运算符
reciprocal()的支持限制。 roundEven,类型为 MLSingleInputSupportLimits-
运算符
roundEven()的支持限制。 sin,类型为 MLSingleInputSupportLimits-
运算符
sin()的支持限制。 sign,类型为 MLSingleInputSupportLimits-
运算符
sign()的支持限制。 sqrt,类型为 MLSingleInputSupportLimits-
运算符
sqrt()的支持限制。 tan,类型为 MLSingleInputSupportLimits-
运算符
tan()的支持限制。
-
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) 方法
步骤如下:
-
令 output 为在给定 "abs"、input、«
"float32"、"float16","bfloat16"、"int64"、"int32"、"int8"» 和 options 的情况下创建逐元素一元 操作的结果。 -
返回 output。
ceil(input, options) 方法
步骤如下:
-
令 output 为在给定 "ceil"、input、«
"float32"、"float16","bfloat16"» 和 options 的情况下创建逐元素一元 操作的结果。 -
返回 output。
cos(input, options) 方法
步骤如下:
-
令 output 为在给定 "cos"、input、«
"float32"、"float16","bfloat16"» 和 options 的情况下创建逐元素一元 操作的结果。 -
返回 output。
erf(input, options) 方法
步骤如下:
-
令 output 为在给定 "erf"、input、«
"float32"、"float16","bfloat16"» 和 options 的情况下创建逐元素一元 操作的结果。 -
返回 output。
exp(input, options) 方法
步骤如下:
-
令 output 为在给定 "exp"、input、«
"float32"、"float16","bfloat16"» 和 options 的情况下创建逐元素一元 操作的结果。 -
返回 output。
floor(input, options) 方法
步骤如下:
-
令 output 为在给定 "floor"、input、«
"float32"、"float16","bfloat16"» 和 options 的情况下创建逐元素一元 操作的结果。 -
返回 output。
identity(input, options)
方法步骤如下:
-
令 output 为在给定 "identity"、input 和 options 的情况下创建逐元素一元 操作的结果。
-
返回 output。
log(input, options) 方法
步骤如下:
-
令 output 为在给定 "log"、input、«
"float32"、"float16","bfloat16"» 和 options 的情况下创建逐元素一元 操作的结果。 -
返回 output。
neg(input, options) 方法
步骤如下:
-
令 output 为在给定 "neg"、input、«
"float32"、"float16","bfloat16"、"int64"、"int32"、"int8"» 和 options 的情况下创建逐元素一元 操作的结果。 -
返回 output。
reciprocal(input, options)
方法步骤如下:
-
令 output 为在给定 "reciprocal"、input、«
"float32"、"float16","bfloat16"» 和 options 的情况下创建逐元素一元 操作的结果。 -
返回 output。
roundEven(input, options)
方法步骤如下:
-
令 output 为在给定 "roundEven"、input、«
"float32"、"float16","bfloat16"» 和 options 的情况下创建逐元素一元 操作的结果。 -
返回 output。
sin(input, options) 方法
步骤如下:
-
令 output 为在给定 "sin"、input、«
"float32"、"float16","bfloat16"» 和 options 的情况下创建逐元素一元 操作的结果。 -
返回 output。
sign(input, options) 方法
步骤如下:
-
令 output 为在给定 "sign"、input、«
"float32"、"float16","bfloat16"、"int64"、"int32"、"int8"» 和 options 的情况下创建逐元素一元 操作的结果。 -
返回 output。
sqrt(input, options) 方法
步骤如下:
-
令 output 为在给定 "sqrt"、input、«
"float32"、"float16","bfloat16"» 和 options 的情况下创建逐元素一元 操作的结果。 -
返回 output。
tan(input, options) 方法
步骤如下:
-
令 output 为在给定 "tan"、input、«
"float32"、"float16","bfloat16"» 和 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
使用缩放比例和零点偏置,将量化整数张量或低精度浮点张量反量化为浮点张量,其中output = (input - zeroPoint) * scale。scale
和 zeroPoint
张量可以小于 input
张量,因为它们可分块广播。 input
和 zeroPoint
的值会在减法运算前转换为 scale
的 dataType ,算术运算在该数据类型中进行。
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。 在根据零点调整每个输入值后,与其相乘的缩放张量。它必须 与输入可分块广播。其值 必须为正且非零,否则行为由实现定义(例如产生正确结果、 错误结果或编译失败)。 -
options: 一个MLOperatorOptions。 指定此操作的可选参数。
返回值:一个 MLOperand。
包含反量化值的输出张量。
| 操作数 | 允许的 数据类型 | 必需的 数据类型 | 允许的秩 | 必需的秩 |
|---|---|---|---|---|
input
| "uint8",
"int8",
"uint32",
"int32",
"float8e4m3"
| "uint8",
"int8"
| N | 0 到 5 |
scale
| "float32",
"float16",
"bfloat16"
| "float32",
"float16"
| 与 input
相同
| 0 到 5 |
zeroPoint
| 与 input
相同
| "uint8",
"int8",
"int32"
| 与 input
相同
| 0 到 5 |
| 输出 | 与 scale
相同
| "float32",
"float16"
| 与 input
相同
| 0 到 5 |
MLQuantizeDequantizeLinearSupportLimits
具有以下成员:
input,类型为 MLTensorLimits-
用于输入操作数的
MLTensorLimits。 scale,类型为 MLTensorLimits-
用于缩放操作数的
MLTensorLimits。 zeroPoint, 类型为 MLTensorLimits-
用于零点操作数的
MLTensorLimits。 output,类型为 MLTensorLimits-
用于输出操作数的
MLTensorLimits。
MLOpSupportLimits
对 dequantizeLinear()
具有以下成员:
dequantizeLinear, 类型为 MLQuantizeDequantizeLinearSupportLimits-
运算符
dequantizeLinear()的支持限制。
dequantizeLinear(input, scale, zeroPoint, options)
方法步骤如下:
-
如果 this.
[[hasBuilt]]为 true,则抛出一个 "InvalidStateError"DOMException。 -
如果在给定 验证操作数所需的 this 和 input、scale 与 zeroPoint 中的任意一个时返回 false,则抛出一个
TypeError。 -
令 outputDescriptor 为在给定 scale 的dataType 和 input 的形状的情况下创建 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) { // 给定原始输入和所需输出形状,沿每个轴进行扩展 // 方法是按该轴所需次数重复数据块。不过,后端 // 实现可能具有效率高得多的上采样运算符, // 能够接受多个维度,一次性按整数倍 // (类似 tile)使用最近邻重采样对所有维度进行上采样: // output = resample(scale, {sizes: input.shape}) let output= input; for ( let axis= 0 ; axis< input. shape. length; ++ axis) { const oldShape= output. shape; const oldDimensionLength= oldShape[ axis]; const newDimensionLength= outputShape[ axis]; if ( newDimensionLength!= oldDimensionLength) { // 由于 tile/expand 只能重复整个维度的 // 切片(而不能沿某个轴重复单个元素),因此暂时 // 重塑张量,使其能够通过广播将元素扩展到 // 完整的数据块大小,利用一个插入的大小为 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; } // 计算给定轴前后各部分展平后的形状,得到一个 // 包含 3 个元素的列表,例如: // - inputShape = [2,3,4,5,6] 且 axis = 2 时,得到形状 [6,4,30]。 // - inputShape = [4] 且 axis = 0 时,得到形状 [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
使用缩放比例和零点偏置,将浮点张量量化为整数张量或低精度浮点张量(例如,对于 "uint8",output = clamp(roundEven(input / scale) + zeroPoint, 0, 255) ,其中钳制边界是输出数据类型的范围)。 scale 和
zeroPoint 张量可以小于 input 张量,因为它们进行分块广播。 zeroPoint 的值转换为
input 的 dataType ,并在该数据类型中执行算术运算,然后将结果转换为
zeroPoint的 dataType 。
当输出数据类型是浮点数据类型,例如 "float8e4m3"时,重新缩放后的值既不会舍入为整数,也不会被钳制。而是使用
output = cast(input / scale + cast(zeroPoint, input.dataType), zeroPoint.dataType),其中舍入到最近可表示值和超范围值的饱和处理遵循
cast()的行为。
注意: 量化为 "float8e4m3"
通常是对称的,在这种情况下, zeroPoint 是全零张量,其形状与
scale相同。
partial interface MLGraphBuilder {MLOperand quantizeLinear (MLOperand input ,MLOperand scale ,MLOperand zeroPoint ,optional MLOperatorOptions options = {}); };partial dictionary MLOpSupportLimits {MLQuantizeDequantizeLinearSupportLimits quantizeLinear ; };
-
input: 一个MLOperand。 输入张量。 -
scale: 一个MLOperand。 在根据零点调整每个输入值之前,用作每个输入值的除数的缩放张量。它必须与输入可分块广播。其值 必须为正且非零,否则行为取决于实现(例如产生正确 结果、错误结果或编译失败)。 -
zeroPoint: 一个MLOperand。 要加到每个重新缩放后的输入值上的零点张量。它与 缩放张量具有相同的形状。 -
options: 一个MLOperatorOptions。 指定此操作的可选参数。
返回值:一个 MLOperand。
包含量化值的输出张量。
| 操作数 | 允许的 数据类型 | 必需的 数据类型 | 允许的秩 | 必需的秩 |
|---|---|---|---|---|
input
| "float32",
"float16",
"bfloat16"
| "float32",
"float16"
| N | 0 到 5 |
scale
| 与 input
相同
| "float32",
"float16"
| 与 input
相同
| 0 到 5 |
zeroPoint
| "uint8",
"int8",
"uint32",
"int32",
"float8e4m3"
| "uint8",
"int8"
| 与 input
相同
| 0 到 5 |
| 输出 | 与 zeroPoint
相同
| "uint8",
"int8"
| 与 input
相同
| 0 到 5 |
MLOpSupportLimits
对 quantizeLinear()
具有以下成员:
quantizeLinear, 类型为 MLQuantizeDequantizeLinearSupportLimits-
运算符
quantizeLinear()的支持限制。
quantizeLinear(input, scale, zeroPoint, options)
方法步骤如下:
-
如果 this.
[[hasBuilt]]为 true,则抛出一个 "InvalidStateError"DOMException。 -
如果在给定 验证操作数所需的 this 和 input、scale 与 zeroPoint 中的任意一个时返回 false,则抛出一个
TypeError。 -
令 outputDescriptor 为在给定 zeroPoint 的dataType 和 input 的形状的情况下创建 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) { // For integer output types: // output = clamp(roundEven(input / scale) + zeroPoint, min, max) // where [min, max] is the range of the output data type. // For floating point output types such as 'float8e4m3': // output = cast(input / scale + cast(zeroPoint, input.dataType), // zeroPoint.dataType) // 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 scaledInput= builder. div( input, upsampledScale); if ( zeroPoint. dataType== 'float8e4m3' ) { return builder. cast( builder. add( scaledInput, upsampledZeroPoint), zeroPoint. dataType); } const integerRanges= { 'int8' : [ - 128 , 127 ], 'uint8' : [ 0 , 255 ], 'int32' : [ - 2147483648 , 2147483647 ], 'uint32' : [ 0 , 4294967295 ] }; const [ minValue, maxValue] = integerRanges[ zeroPoint. dataType]; const quantizedInput= builder. roundEven( scaledInput); const zeroPointAdjustedInput= builder. add( quantizedInput, upsampledZeroPoint); const clampedInput= builder. clamp( zeroPointAdjustedInput, { 'minValue' : minValue, 'maxValue' : maxValue}); 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",
"bfloat16"
| "float32",
"float16"
| N | 0 到 5 |
| 输出 | 与 input
相同
| "float32",
"float16"
| 与 input
相同
| 0 到 5 |
MLOpSupportLimits
对 elu()
具有以下成员:
elu,类型为 MLSingleInputSupportLimits-
运算符
elu()的支持限制。
elu(input, options) 方法
步骤如下:
-
如果 this 无法构建,则抛出一个 "
InvalidStateError"DOMException。 -
建立图连接:
-
令 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: 序列<unsigned long>。 输入张量要扩展到的新形状。 -
options:一个MLOperatorOptions。 指定此操作的可选参数。
返回值:一个 MLOperand。
具有扩展后大小和形状的张量。
| 操作数 | 允许的 数据类型 | 必需的 数据类型 | 允许的秩 | 必需的秩 |
|---|---|---|---|---|
input
| 任意 | "float32",
"float16",
"int32"
| N | 0 到 5 |
| 输出 | 与 input
相同
| "float32",
"float16",
"int32"
| N | 0 到 5 |
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 是输入张量的秩。
-
input:一个MLOperand。 从中收集值的输入 N 维张量。 -
indices:一个MLOperand。 指定要收集的输入值索引的 N 维张量。其值的类型必须为"int32"、"uint32"或"int64", 且必须位于 -N(含)至 N(不含)的范围内,其中 N 是由axis指定的输入维度的大小, 负索引表示从该维度的末尾开始索引。 -
options:一个 可选的MLGatherOptions。 此操作的可选参数。
返回值:一个 MLOperand。
输出 N 维张量,其秩等于 input
的秩
加上 indices
的秩
再减去 1。
gather()
的 indices
参数无法在构建图时限制到允许范围内,因为直到
执行时才能知道输入。如果底层平台未提供指定的截断行为,实现可以在编译后的图中引入 clamp()
操作。同样,如果底层平台不支持负索引,实现可以在
编译后的图中引入操作,将从维度末尾开始的负索引转换为正
索引。
| 操作数 | 允许的 数据类型 | 必需的 数据类型 | 允许的秩 | 必需的秩 |
|---|---|---|---|---|
input
| 任意 | "float32",
"float16",
"int32",
"int8",
"uint8"
| 1 到 N | 1 到 5 |
indices
| "int32",
"uint32",
"int64"
| "int32"
| N | 0 到 5 |
| 输出 | 与 input
相同
| "float32",
"float16",
"int32",
"int8",
"uint8"
| N | 0 到 5 |
MLGatherSupportLimits
具有以下成员:
input,类型为 MLTensorLimits-
用于输入操作数的
MLTensorLimits。 indices,类型为 MLTensorLimits-
用于索引操作数的
MLTensorLimits。 output,类型为 MLTensorLimits-
用于输出操作数的
MLTensorLimits。
MLOpSupportLimits
对 gather()
具有以下成员:
gather,类型为 MLGatherSupportLimits-
运算符
gather()的支持限制。
gather(input, indices, options)
方法步骤如下:
-
如果 this 无法构建,则抛出一个 "
InvalidStateError"DOMException。 -
如果在给定 验证操作数所需的 this 以及 input 和 indices 中的任意一个时返回 false,则抛出一个
TypeError。 -
令 indicesShape 为 indices 的形状。
-
令 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 在不同切片方案下的工作示例。
// 形状为 [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(默认值) // 形状为 [2] 的索引: // [3,1] // 形状为 [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 // 形状为 [3] 的索引: // [2,1,1] // 形状为 [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 // 形状为 [2,2] 的索引: // [[0, 1], // [1, 2]] // 形状为 [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
| 任意 | "float32",
"float16",
"int32"
| 1 到 N | 1 到 5 |
indices
| "int32",
"uint32",
"int64"
| "int32"
| 与 input
相同
| 1 到 5 |
| 输出 | 与 input
相同
| "float32",
"float16",
"int32"
| 与 input
相同
| 1 到 5 |
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 的形状的副本。
-
将 indicesShapeExpected[axis] 设置为 indices 的形状[axis]。
-
建立图连接:
-
令 output 为在给定 input 的情况下复制 MLOperand 的结果。
-
令 operator 为给定 input、indices 和 options 的 "gatherElements" 操作的一个运算符。
-
将 output.
[[operator]]设置为 operator。 -
将 operator 的输入设置为 input 和 indices。
-
将 operator 的输出设置为 output。
-
-
返回 output。
gatherElements 在不同切片方案下的工作示例。
// 形状为 [4,3] 的输入: // [[ 0, 1, 2], // [10, 11, 12], // [20, 21, 22], // [30, 31, 32]] // 形状为 [2,3] 的索引: // [[3, 1, 1], // [2, 0, 3]] // axis = 0(默认值) // 形状为 [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); // 形状为 [4,3] 的输入: // [[ 0, 1, 2], // [10, 11, 12], // [20, 21, 22], // [30, 31, 32]] // 形状为 [4,1] 的索引: // [[2], // [1], // [0], // [2]], // axis = 1 // 形状为 [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 }); // 形状为 [4,2,2] 的输入: // [[[ 0, 1], // [ 10, 11]], // [[100, 101], // [110, 111]], // [[200, 201], // [210, 211]], // [[300, 301], // [310, 311]],] // 形状为 [1,2,2] 的索引: // [[[0, 2], // [1, 3]]], // axis = 0 // 形状为 [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。 索引数组包含输入张量中的完整坐标,其中最右侧 维度表示每个坐标的维度数。因此,形状为 [10,1] 的索引张量 包含 10 个单轴索引,而形状为 [4,3] 的张量包含 4 个三维坐标索引。其值 的类型必须为"int32"、"uint32"或"int64", 且每个值都必须位于 -N(含)至 N(不含)的范围内,其中 N 是 对应输入维度的大小,负索引表示从 对应维度的末尾开始索引。 -
options: 一个可选的MLOperatorOptions。 此操作的可选参数。
返回值:一个 MLOperand。
输出 N 维张量,其秩等于 input
的
秩加上 indices
的
秩,减去 indices
的
形状[-1],再减去 1。
| 操作数 | 允许的 数据类型 | 必需的 数据类型 | 允许的秩 | 必需的秩 |
|---|---|---|---|---|
input
| 任意 | "float32",
"float16",
"int32",
"int8",
"uint8"
| 1 到 N | 1 到 5 |
indices
| "int32",
"uint32",
"int64"
| "int32"
| 1 到 N | 1 到 5 |
| 输出 | 与 input
相同
| "float32",
"float16",
"int32",
"int8",
"uint8"
| N | 0 到 5 |
MLOpSupportLimits
对 gatherND()
具有以下成员:
gatherND,类型为 MLGatherSupportLimits-
运算符
gatherND()的支持限制。
gatherND()
的 indices
参数无法在构建图时限制到允许范围内,因为直到
执行时才能知道输入。如果底层平台未提供指定的截断行为,实现可以在编译后的图中引入 clamp()
操作。同样,如果底层平台不支持负索引,实现可以在
编译后的图中引入操作,将从维度末尾开始的负索引转换为正
索引。
gatherND(input, indices, options)
方法步骤如下:
-
如果 this 无法构建,则抛出一个 "
InvalidStateError"DOMException。 -
如果在给定 验证操作数所需的 this 以及 input 和 indices 中的任意一个时返回 false,则抛出一个
TypeError。 -
令 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 在不同切片方案下的工作示例。
// 形状为 [2,2] 的输入: // [[0, 1], // [2, 3]] // 形状为 [3,2] 的索引: // [[0, 0], // [1, 1], // [1, 0]] // 形状为 [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); // 形状为 [2,2] 的输入: // [[0, 1], // [2, 3]] // 形状为 [2,1] 的索引: // [[1], // [0]] // 形状为 [2,2] 的输出: // [[2, 3] <= 来自输入坐标 [1, *] 的行 [2, 3] // [0, 1]] <= 来自输入坐标 [0, *] 的行 [0, 1] const indices2= builder. constant( { dataType: 'uint32' , shape: [ 2 , 1 ]}, new Uint32Array([ 1 , 0 ])); const output2= builder. gatherND( input1, indices2); // 形状为 [2,2,2] 的输入: // [[[0, 1], // [2, 3]], // [[4, 5], // [6, 7]]] // 形状为 [2,2] 的索引: // [[0, 1], // [1, 0]] // 形状为 [2,2] 的输出: // [[2, 3], <= 来自输入坐标 [0, 1, *] 的行 [2, 3] // [4, 5]] <= 来自输入坐标 [1, 0, *] 的行 [4, 5] const input2= builder. constant( { dataType: 'float32' , shape: [ 2 , 2 , 2 ]}, new Float32Array([ 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 ])); const indices3= builder. constant( { dataType: 'uint32' , shape: [ 2 , 2 ]}, new Uint32Array([ 0 , 1 , 1 , 0 ])); const output3= builder. gatherND( input2, indices3); // 形状为 [2,2,2] 的输入: // [[[0, 1], // [2, 3]], // [[4, 5], // [6, 7]]] // 形状为 [3,1] 的索引: // [[1], // [0], // [1]] // 形状为 [3,2,2] 的输出: // [[[4, 5], <= 来自输入坐标 [1, *, *] 的块 [[4, 5], [6, 7]] // [6, 7]], // [[0, 1], <= 来自输入坐标 [0, *, *] 的块 [[0, 1], [2, 3]] // [2, 3]], // [[4, 5], <= 来自输入坐标 [1, *, *] 的块 [[4, 5], [6, 7]] // [6, 7]]] const indices4= builder. constant( { dataType: 'uint32' , shape: [ 3 , 1 ]}, new Uint32Array([ 1 , 0 , 1 ])); const output4= builder. gatherND( input2, indices4); // 形状为 [2,2,2] 的输入: // [[[0, 1], // [2, 3]], // [[4, 5], // [6, 7]]] // 形状为 [5,3] 的索引: // [[0,0,1], // [0,1,0], // [1,0,0], // [1,1,0], // [1,1,1]] // 形状为 [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",
"bfloat16"
| "float32",
"float16"
| N | 0 到 5 |
| 输出 | 与 input
相同
| "float32",
"float16"
| 与 input
相同
| 0 到 5 |
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,类型为 MLOperand-
第三个输入张量。它可以是标量,也可以具有能够向形状 [M, N] 单向广播的形状。如果未指定,则计算时将
c视为标量 0.0。 alpha,类型为 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",
"bfloat16"
| "float32",
"float16"
| 2 | 2 |
b
| 与 a
相同
| "float32",
"float16"
| 2 | 2 |
c
| 与 a
相同
| "float32",
"float16"
| 0 到 2 | 0 到 2 |
| 输出 | 与 a
相同
| "float32",
"float16"
| 2 | 2 |
MLGemmSupportLimits
具有以下成员:
a,类型为 MLTensorLimits-
用于 a 操作数的
MLTensorLimits。 b,类型为 MLTensorLimits-
用于 b 操作数的
MLTensorLimits。 c,类型为 MLTensorLimits-
用于 c 操作数的
MLTensorLimits。 output,类型为 MLTensorLimits-
用于输出操作数的
MLTensorLimits。
MLOpSupportLimits
对 gemm()
具有以下成员:
gemm,类型为 MLGemmSupportLimits-
运算符
gemm()的支持限制。
gemm(a, b, options)
方法步骤如下:
-
如果 this 无法构建,则抛出一个 "
InvalidStateError"DOMException。 -
如果在给定 验证操作数所需的 this 以及 a 和 b 中的任意一个时返回 false,则 抛出一个
TypeError。 -
如果 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] 循环网络使用更新门、重置门和新门来计算输出状态,该状态会在网络的时间序列中 传递到输出。enum {MLGruWeightLayout , // 更新-重置-新门的顺序"zrn" // 重置-更新-新门的顺序 };"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-
指示是在矩阵乘法之后还是之前应用重置门。
returnSequence, 类型为 boolean,默认为false-
指示除最后一个时间步的输出外,是否还返回包含每个时间步所有输出的整个 序列。
direction, 类型为 MLRecurrentNetworkDirection,默认为"forward"-
输入序列的处理方向。当设置为
"both"时,权重和偏置张量形状的第一维大小必须为 2,并且输入会 在两个方向上处理。 layout, 类型为 MLGruWeightLayout,默认为"zrn"-
GRU 内部门的权重和偏置向量顺序,具体为
update (z)、reset (r)和new (n)门,如权重和偏置张量形状的 第二维所示。 activations, 类型为 sequence<MLRecurrentNetworkActivation>-
指定一对激活函数,第一个函数用于 更新门和重置门,第二个函数用于新门。未指定时,分别默认为
"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",
"bfloat16"
| "float32",
"float16"
| 3 | 3 |
| 与
相同
| "float32",
"float16"
| 3 | 3 |
| 与
相同
| "float32",
"float16"
| 3 | 3 |
bias
| 与
相同
| "float32",
"float16"
| 2 | 2 |
recurrentBias
| 与
相同
| "float32",
"float16"
| 2 | 2 |
| 与
相同
| "float32",
"float16"
| 3 | 3 |
| outputs[0] | 与
相同
| "float32",
"float16"
| 3 | 3 |
outputs[1] 如果 returnSequence
为 true
| 与
相同
| "float32",
"float16"
| 4 | 4 |
MLGruSupportLimits
具有以下成员:
input, 类型为 MLTensorLimits-
MLTensorLimits用于 input 操作数。 weight, 类型为 MLTensorLimits-
MLTensorLimits用于 weight 操作数。 recurrentWeight, 类型为 MLTensorLimits-
MLTensorLimits用于 recurrentWeight 操作数。 bias, 类型为 MLTensorLimits-
MLTensorLimits用于 bias 操作数。 recurrentBias, 类型为 MLTensorLimits-
MLTensorLimits用于 recurrentBias 操作数。 initialHiddenState, 类型为 MLTensorLimits-
MLTensorLimits用于 initialHiddenState 操作数。 output0, 类型为 MLTensorLimits-
MLTensorLimits用于所有输出操作数[0]。 output1, 类型为 MLTensorLimits-
MLTensorLimits用于所有输出操作数[1]。
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 的形状[1]。
-
令 inputSize 为 input 的形状[2]。
-
如果 weight 的形状不等于 « numDirections, 3 * hiddenSize, inputSize »,则抛出一个
TypeError。 -
如果 recurrentWeight 的形状不等于 « numDirections, 3 * hiddenSize, hiddenSize »,则抛出一个
TypeError。 -
如果 hiddenSize * 6 不是有效维度,则抛出一个
TypeError。为什么是 hiddenSize * 6?
某些底层平台使用由bias和recurrentBias拼接而成的单个偏置张量。 因此,3 * hiddenSize + 3 * hiddenSize 也必须是一个有效 维度。 -
如果 options.
recurrentBias存在,则: -
如果 options.
存在,则: -
如果 options.
activations存在,则:-
令 activations 为 options.
activations的克隆 。
-
否则:
-
计算输出形状:
-
令 desc0 为在给定 input 的dataType 和 « numDirections、 batchSize、hiddenSize » 的情况下创建 MLOperandDescriptor的结果 。
-
令 desc1 为在给定 input 的dataType 和 « steps、 numDirections、batchSize、hiddenSize » 的情况下创建 MLOperandDescriptor的结果 。
为什么无条件构建 desc1?
某些底层平台无论returnSequence的值如何,都会生成完整序列的输出张量。 因此,desc1 也必须有效。
-
-
建立图连接:
-
令 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) { // 将二维的 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; } if ( options. returnSequence) { let outputSequence= null ; if ( direction== 'forward' ) { outputSequence= forwardSequence; } else if ( direction== 'backward' ) { outputSequence= backwardSequence; } else if ( direction== 'both' ) { // 沿轴 1(numDirections 维度)拼接 outputSequence= builder. concat([ forwardSequence, backwardSequence], 1 ); } return [ outputHidden, outputSequence]; } else { return [ outputHidden]; } }
8.9.26. gruCell
门控循环单元 [GRU] 循环网络的单个时间步,使用更新门和重置门计算隐藏状态,该状态 沿循环网络的时间序列传递到输出。dictionary :MLGruCellOptions MLOperatorOptions {MLOperand bias ;MLOperand recurrentBias ;boolean resetAfter =true ;MLGruWeightLayout layout = "zrn";sequence <MLRecurrentNetworkActivation >activations ; };partial interface MLGraphBuilder {MLOperand gruCell (MLOperand input ,MLOperand weight ,MLOperand recurrentWeight ,MLOperand hiddenState , [EnforceRange ]unsigned long hiddenSize ,optional MLGruCellOptions options = {}); };dictionary {MLGruCellSupportLimits MLTensorLimits input ;MLTensorLimits weight ;MLTensorLimits recurrentWeight ;MLTensorLimits hiddenState ;MLTensorLimits bias ;MLTensorLimits recurrentBias ;MLTensorLimits output ; };partial dictionary MLOpSupportLimits {MLGruCellSupportLimits gruCell ; };
MLGruCellOptions
具有以下成员:
bias,类型为 MLOperand-
形状为 [3 * hiddenSize] 的一维输入偏置张量。偏置向量在张量形状的 第二个维度中的排列顺序由
layout指定。 recurrentBias,类型为 MLOperand-
形状为 [3 * hiddenSize] 的一维循环偏置张量。偏置向量在 张量形状第二个维度中的排列顺序由
layout指定。 resetAfter,类型为 boolean,默认值为true-
指示在矩阵乘法之后还是之前应用重置门。
layout,类型为 MLGruWeightLayout,默认值为"zrn"-
GRU 内部门的权重和偏置向量的排列顺序,具体包括
update (z)、reset (r)和new (n)门,如权重和偏置张量形状的 第二个维度所示。 activations,类型为 sequence<MLRecurrentNetworkActivation>-
指定一对激活函数,第一个函数用于 更新门和重置门,第二个函数用于新门。如果未指定,则分别默认为
"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",
"bfloat16"
| "float32",
"float16"
| 2 | 2 |
| 与
相同
| "float32",
"float16"
| 2 | 2 |
| 与
相同
| "float32",
"float16"
| 2 | 2 |
| 与
相同
| "float32",
"float16"
| 2 | 2 |
bias
| 与
相同
| "float32",
"float16"
| 1 | 1 |
recurrentBias
| 与
相同
| "float32",
"float16"
| 1 | 1 |
| 输出 | 与
相同
| "float32",
"float16"
| 2 | 2 |
MLGruCellSupportLimits
具有以下成员:
input,类型为 MLTensorLimits-
用于输入操作数的
MLTensorLimits。 weight,类型为 MLTensorLimits-
用于权重操作数的
MLTensorLimits。 recurrentWeight,类型为 MLTensorLimits-
用于 recurrentWeight 操作数的
MLTensorLimits。 hiddenState,类型为 MLTensorLimits-
用于 hiddenState 操作数的
MLTensorLimits。 bias,类型为 MLTensorLimits-
用于偏置操作数的
MLTensorLimits。 recurrentBias,类型为 MLTensorLimits-
用于 recurrentBias 操作数的
MLTensorLimits。 output,类型为 MLTensorLimits-
用于输出操作数的
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 的形状[0]。
-
令 inputSize 为 input 的形状[1]。
-
如果 weight 的形状不等于 « 3 * hiddenSize, inputSize », 则抛出一个
TypeError。 -
如果 recurrentWeight 的形状不等于 « 3 * hiddenSize, hiddenSize », 则抛出一个
TypeError。 -
如果 hiddenState 的形状不等于 « batchSize, hiddenSize »,则 抛出一个
TypeError。 -
如果 hiddenSize * 6 不是有效维度,则抛出一个
TypeError。为什么是 hiddenSize * 6?
某些底层平台使用由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"
布局,且更新门/重置门和新门的 激活函数
分别为 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 ]; // 更新门 (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])))))); // 重置门 (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])))))); // 新门 (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])))))); } // 计算新的隐藏状态 return builder. add( builder. mul( z, hiddenState), builder. mul( n, builder. sub( one, z))); }
8.9.27. hardSigmoid
对输入张量计算非平滑的硬 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",
"bfloat16"
| "float32",
"float16"
| N | 0 到 5 |
| 输出 | 与 input
相同
| "float32",
"float16"
| 与 input
相同
| 0 到 5 |
MLOpSupportLimits
对 hardSigmoid()
具有以下成员:
hardSigmoid,类型为 MLSingleInputSupportLimits-
运算符
hardSigmoid()的支持限制。
hardSigmoid(input, options)
方法步骤如下:
-
如果 this 无法构建,则抛出一个 "
InvalidStateError"DOMException。 -
建立图连接:
-
令 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",
"bfloat16"
| "float32",
"float16"
| N | 0 到 5 |
| 输出 | 与 input
相同
| "float32",
"float16"
| 与 input
相同
| 0 到 5 |
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-
包含缩放值的一维张量,其大小等于 通道数,即输入的特征维度的大小。例如,对于采用
"nchw"布局的input张量,其大小等于input的 形状[1]。 bias,类型为 MLOperand-
包含偏置值的一维张量,其大小等于 输入特征维度的大小。例如,对于采用
"nchw"布局的input张量,其大小等于input的 形状[1]。 epsilon,类型为 double,默认值为1e-5-
用于防止除零导致计算错误的较小数值。
layout,类型为 MLInputOperandLayout,默认值为"nchw"-
输入的布局格式。
-
input: 一个MLOperand。 输入四维张量。 -
options: 一个可选的MLInstanceNormalizationOptions。 此操作的可选参数。
| 操作数 | 允许的 数据类型 | 必需的 数据类型 | 允许的秩 | 必需的秩 |
|---|---|---|---|---|
input
| "float32",
"float16",
"bfloat16"
| "float32",
"float16"
| 4 | 4 |
scale
| 与 input
相同
| "float32",
"float16"
| 1 | 1 |
bias
| 与 input
相同
| "float32",
"float16"
| 1 | 1 |
| 输出 | 与 input
相同
| "float32",
"float16"
| 4 | 4 |
MLNormalizationSupportLimits
具有以下成员:
input,类型为 MLTensorLimits-
用于输入操作数的
MLTensorLimits。 scale,类型为 MLTensorLimits-
用于缩放操作数的
MLTensorLimits。 bias,类型为 MLTensorLimits-
用于偏置操作数的
MLTensorLimits。 output,类型为 MLTensorLimits-
用于输出操作数的
MLTensorLimits。
MLOpSupportLimits
对 instanceNormalization()
具有以下成员:
instanceNormalization,类型为 MLNormalizationSupportLimits-
运算符
instanceNormalization()的支持限制。
instanceNormalization(input, options)
方法步骤如下:
当输入张量是采用 "nchw"
布局的 4-D 张量时,此操作的行为可以通过使用其他操作按如下方式进行通用模拟,不过用户
代理通常具有更高效的实现。此分解是一个说明性示例,
而不是参考实现:它不规定算法或
中间结果的精度。在底层平台不直接支持某项操作的情况下,
此分解可用作指导实现的模板。
function instanceNormalization( builder, input, options) { // 均值和方差值的归约在输入的空间 // 维度上进行,例如输入张量的轴 2 和轴 3。 const reduceOptions= { axes: [ 2 , 3 ], keepDimensions: true }; const mean= builder. reduceMean( input, reduceOptions); const variance= builder. reduceMean( builder. pow( builder. sub( input, mean), builder. constant( input. dataType, 2 )), reduceOptions); // 缩放值和偏置值按每个输入特征应用, // 例如输入张量的轴 1。 const shape= [ 1 , input. shape[ 1 ], 1 , 1 ]; return builder. add( builder. mul( builder. reshape( options. scale, shape), builder. div( builder. sub( input, mean), builder. sqrt( builder. add( variance, options. epsilon)))), builder. reshape( options. bias, shape)); }
8.9.30. layerNormalization
使用[Layer-Normalization]对输入进行归一化。与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中的每个值都表示输入张量中具有缩放值的维度。例如,当axes的值为 [1,2,3] 时,此张量的形状是输入张量 第 1、2 和 3 维对应大小组成的列表。如果未提供此成员,则假定缩放值为 1。 bias,类型为 MLOperand-
包含偏置值的 N 维张量,其形状由
axes成员决定,其中axes中的每个值都表示输入张量中具有偏置值的维度。例如,当axes的值为 [1,2,3] 时,此张量的形状是输入张量 第 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",
"bfloat16"
| "float32",
"float16"
| N | 0 到 5 |
scale
| 与 input
相同
| "float32",
"float16"
| N | 0 到 5 |
bias
| 与 input
相同
| "float32",
"float16"
| N | 0 到 5 |
| 输出 | 与 input
相同
| "float32",
"float16"
| 与 input
相同
| 0 到 5 |
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) { // 均值和方差值的归约在输入张量所有输入特征 // (即所有通道)的空间维度上进行。 // 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); // 缩放张量和偏置张量的形状由 axes 参数 // 中指定的输入维度确定(即 [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",
"bfloat16"
| "float32",
"float16"
| N | 0 到 5 |
| 输出 | 与 input
相同
| "float32",
"float16"
| 与 input
相同
| 0 到 5 |
MLOpSupportLimits
对 leakyRelu()
具有以下成员:
leakyRelu,类型为 MLSingleInputSupportLimits-
运算符
leakyRelu()的支持限制。
leakyRelu(input, options)
方法步骤如下:
-
如果 this 无法构建,则抛出一个 "
InvalidStateError"DOMException。 -
建立图连接:
-
令 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",
"bfloat16"
| "float32",
"float16"
| N | 0 到 5 |
| 输出 | 与 input
相同
| "float32",
"float16"
| 与 input
相同
| 0 到 5 |
MLOpSupportLimits
对 linear()
具有以下成员:
linear, 类型为 MLSingleInputSupportLimits-
运算符
linear()的支持限制。
linear(input, options)
方法步骤如下:
-
如果 this 无法构建,则抛出一个 "
InvalidStateError"DOMException。 -
建立图连接:
-
令 output 为在给定 input 的情况下复制 MLOperand 的结果。
-
令 operator 为用于 "linear" 操作的一个运算符,给定 options。
-
将 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] 循环网络使用输入门、输出门、遗忘门和单元门来计算输出状态,该状态会在网络的 时间序列中传递到输出。enum {MLLstmWeightLayout , // 输入-输出-遗忘-单元门的顺序"iofg" // 输入-遗忘-单元-输出门的顺序 };"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-
形状为 [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"时,权重和偏置张量形状的第一维大小必须为 2,并且输入会 在两个方向上处理。 layout, 类型为 MLLstmWeightLayout,默认为"iofg"-
LSTM 内部门的权重和偏置向量顺序,具体为
input (i)、output (o)、forget (f)和cell (g)门,如权重和偏置张量形状的第一维所示。 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",
"bfloat16"
| "float32",
"float16"
| 3 | 3 |
| 与
相同
| "float32",
"float16"
| 3 | 3 |
| 与
相同
| "float32",
"float16"
| 3 | 3 |
bias
| 与
相同
| "float32",
"float16"
| 2 | 2 |
recurrentBias
| 与
相同
| "float32",
"float16"
| 2 | 2 |
peepholeWeight
| 与
相同
| "float32",
"float16"
| 2 | 2 |
| 与
相同
| "float32",
"float16"
| 3 | 3 |
initialCellState
| 与
相同
| "float32",
"float16"
| 3 | 3 |
| outputs[0] | 与
相同
| "float32",
"float16"
| 3 | 3 |
| outputs[1] | 与
相同
| "float32",
"float16"
| 3 | 3 |
outputs[2] 如果 returnSequence
为 true
| 与
相同
| "float32",
"float16"
| 4 | 4 |
MLLstmSupportLimits
具有以下成员:
input, 类型为 MLTensorLimits-
MLTensorLimits用于 input 操作数。 weight, 类型为 MLTensorLimits-
MLTensorLimits用于 weight 操作数。 recurrentWeight, 类型为 MLTensorLimits-
MLTensorLimits用于 recurrentWeight 操作数。 bias, 类型为 MLTensorLimits-
MLTensorLimits用于 bias 操作数。 recurrentBias, 类型为 MLTensorLimits-
MLTensorLimits用于 recurrentBias 操作数。 peepholeWeight, 类型为 MLTensorLimits-
MLTensorLimits用于 peepholeWeight 操作数。 initialHiddenState, 类型为 MLTensorLimits-
MLTensorLimits用于 initialHiddenState 操作数。 initialCellState, 类型为 MLTensorLimits-
MLTensorLimits用于 initialCellState 操作数。 output0, 类型为 MLTensorLimits-
MLTensorLimits用于所有输出操作数[0]。 output1, 类型为 MLTensorLimits-
MLTensorLimits用于所有输出操作数[1]。 output2, 类型为 MLTensorLimits-
MLTensorLimits用于所有输出操作数[2]。
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 的形状[1]。
-
令 inputSize 为 input 的形状[2]。
-
如果 weight 的形状不等于 « numDirections, 4 * hiddenSize, inputSize »,则抛出一个
TypeError。 -
如果 recurrentWeight 的形状不等于 « numDirections, 4 * hiddenSize, hiddenSize »,则抛出一个
TypeError。 -
如果 hiddenSize * 8 不是有效维度,则抛出一个
TypeError。为什么是 hiddenSize * 8?
某些底层平台使用由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的结果 。
-
令 desc2 为在给定 input 的dataType 和 « steps、 numDirections、batchSize、hiddenSize » 的情况下创建 MLOperandDescriptor的结果 。
为什么无条件构建 desc2?
某些底层平台无论returnSequence的值如何,都会生成完整序列的输出张量。 因此,desc2 也必须有效。
-
-
建立图连接:
-
令 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] 循环网络的单个时间步,使用单元状态、输入门、输出门和遗忘 门来计算下一个时间步的单元状态和隐藏状态,该状态会在网络的 时间序列中传递到输出。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-
形状为 [3 * hiddenSize] 的一维窥孔权重张量。权重向量的打包 顺序分别对应
input (i)、output (o)和forget (f)门。 layout, 类型为 MLLstmWeightLayout,默认为"iofg"-
LSTM 内部门的权重和偏置向量的顺序,具体为
input (i)、output (o)、forget (f)和cell (g)门,如权重和偏置张量形状的第一维所示。 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] 的输入二维隐藏状态张量。 -
cellState: 一个MLOperand。 形状为 [batchSize, hiddenSize] 的输入二维单元状态张量。 -
hiddenSize: 一个unsigned long标量。输出张量形状第二个维度的值。它表示 隐藏状态中的特征数量。 -
options: 一个可选的MLLstmCellOptions。 运算的可选参数。
返回: sequence<MLOperand>。
第一个元素是循环网络当前时间步的输出隐藏状态。后
一个元素是输出单元状态。两个元素都是形状为 [batchSize,
hiddenSize] 的二维张量。
| 操作数 | 允许的 数据类型 | 必需的 数据类型 | 允许的秩 | 必需的秩 |
|---|---|---|---|---|
| "float32",
"float16",
"bfloat16"
| "float32",
"float16"
| 2 | 2 |
| 与……相同
| "float32",
"float16"
| 2 | 2 |
| 与……相同
| "float32",
"float16"
| 2 | 2 |
| 与……相同
| "float32",
"float16"
| 2 | 2 |
| 与……相同
| "float32",
"float16"
| 2 | 2 |
bias
| 与……相同
| "float32",
"float16"
| 1 | 1 |
recurrentBias
| 与……相同
| "float32",
"float16"
| 1 | 1 |
peepholeWeight
| 与……相同
| "float32",
"float16"
| 1 | 1 |
| outputs[0] | 与……相同
| "float32",
"float16"
| 2 | 2 |
| outputs[1] | 与……相同
| "float32",
"float16"
| 2 | 2 |
MLLstmCellSupportLimits
具有以下成员:
input, 类型为 MLTensorLimits-
MLTensorLimits用于 input 操作数。 weight, 类型为 MLTensorLimits-
MLTensorLimits用于 weight 操作数。 recurrentWeight, 类型为 MLTensorLimits-
MLTensorLimits用于 recurrentWeight 操作数。 hiddenState, 类型为 MLTensorLimits-
MLTensorLimits用于 hiddenState 操作数。 cellState, 类型为 MLTensorLimits-
MLTensorLimits用于 cellState 操作数。 bias, 类型为 MLTensorLimits-
MLTensorLimits用于 bias 操作数。 recurrentBias, 类型为 MLTensorLimits-
MLTensorLimits用于 recurrentBias 操作数。 peepholeWeight, 类型为 MLTensorLimits-
MLTensorLimits用于 peepholeWeight 操作数。 output0, 类型为 MLTensorLimits-
MLTensorLimits用于所有 output 操作数[0]。 output1, 类型为 MLTensorLimits-
MLTensorLimits用于所有 output 操作数[1]。
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 的形状[0]。
-
令 inputSize 为 input 的形状[1]。
-
如果 weight 的形状不等于 « 4 * hiddenSize, inputSize », 则抛出一个
TypeError。 -
如果 recurrentWeight 的形状不等于 « 4 * hiddenSize, hiddenSize », 则抛出一个
TypeError。 -
如果 hiddenState 的形状不等于 « batchSize, hiddenSize »,则 抛出一个
TypeError。 -
如果 cellState 的形状不等于 « batchSize, hiddenSize »,则 抛出一个
TypeError。 -
如果 hiddenSize * 8 不是一个有效维度,则抛出一个
TypeError。为什么是 hiddenSize * 8?
某些底层平台使用由bias和recurrentBias拼接而成的单个偏置张量。 因此,4 * hiddenSize + 4 * hiddenSize 也必须是一个有效 维度。 -
如果 options.
recurrentBias存在,则: -
如果 options.
peepholeWeight存在,则: -
如果 options.
activations存在,则:-
令 activations 为 options.
activations的克隆 。
-
否则:
-
令 desc 为一个新的
MLOperandDescriptor。 -
建立图连接:
-
令 output0 为创建 MLOperand 的结果,给定 this 和 desc。
-
令 output1 为创建 MLOperand 的结果,给定 this 和 desc。
-
令 output 为列表 « output0, output1 »。
-
令 operator 为用于 "lstmCell" 操作的一个运算符,给定 weight、recurrentWeight、hiddenState、 cellState、hiddenSize 和 options。
-
将 output0.
[[operator]]和 output1.[[operator]]设置为 operator。 -
将 operator 的输入设置为 input、weight、 recurrentWeight、hiddenState 和 cellState。
-
如果 options.
recurrentBias存在,则将其添加到 operator 的输入中。 -
如果 options.
peepholeWeight存在,则将其添加到 operator 的输入中。 -
将 operator 的输出设置为 output。
-
-
返回 output。
当权重布局为默认的 "iofg"
布局,且输入门/遗忘门/输出门和
单元门/用于输出隐藏状态的单元状态过滤器的 激活函数 分别为
sigmoid()
和 tanh()
时,可以通过使用其他操作按如下方式通用模拟此操作的行为,不过
用户代理通常具有更高效的实现。此分解是一个说明性
示例,而不是参考实现:它不规定算法或
中间结果的精度。在底层平台不直接支持某项
操作的情况下,此分解可用作指导实现的模板。
function lstmCell( builder, input, weight, recurrentWeight, hiddenState, cellState, hiddenSize, options) { const zero= builder. constant( input. dataType, 0 ); const inputSize= input. shape[ 1 ]; // 输入门(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]))))))); // 遗忘门(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]))))))); // 单元门(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])))))); // 输出门(o) let o= builder. sigmoid( builder. add( builder. mul( cellState, ( options. peepholeWeight? builder. slice( options. peepholeWeight, [ hiddenSize], [ hiddenSize]) : zero)), builder. add( builder. add( ( options. bias? builder. slice( options. bias, [ hiddenSize], [ hiddenSize]) : zero), ( options. recurrentBias? builder. slice( options. recurrentBias, [ hiddenSize], [ hiddenSize]) : zero)), builder. add( builder. matmul( input, builder. transpose( builder. slice( weight, [ hiddenSize, 0 ], [ hiddenSize, inputSize]))), builder. matmul( hiddenState, builder. transpose( builder. slice( recurrentWeight, [ hiddenSize, 0 ], [ hiddenSize, hiddenSize]))))))); // 输出单元状态(ct) let ct= builder. add( builder. mul( f, cellState), builder. mul( i, g)); // 输出隐藏状态(ht) let ht= builder. mul( o, builder. tanh( ct)); return [ ht, ct]; }
8.9.35. matmul
计算两个输入张量的矩阵乘积。partial interface MLGraphBuilder {MLOperand matmul (MLOperand a ,MLOperand b ,optional MLOperatorOptions options = {}); };partial dictionary MLOpSupportLimits {MLBinarySupportLimits matmul ; };
-
a:一个MLOperand。 至少为二维的第一个输入张量。 -
b:一个MLOperand。 至少为二维的第二个输入张量。 -
options:一个MLOperatorOptions。 指定运算的可选参数。
返回:一个 MLOperand。
包含两个输入张量矩阵
乘积的输出张量。
| 操作数 | 允许的 数据类型 | 必需的 数据类型 | 允许的秩 | 必需的秩 |
|---|---|---|---|---|
a
| "float32",
"float16",
"bfloat16"
| "float32",
"float16"
| 2 到 N | 2 到 5 |
b
| 与……相同 a
| "float32",
"float16"
| 2 到 N | 2 到 5 |
| 输出 | 与……相同 a
| "float32",
"float16"
| 2 到 N | 2 到 5 |
MLOpSupportLimits
对 matmul()
具有以下成员:
matmul, 类型为 MLBinarySupportLimits-
运算符
matmul()的支持限制。
matmul(a, b, options)
方法步骤如下:
-
如果 this 无法构建,则抛出一个 "
InvalidStateError"DOMException。 -
如果使用 验证操作数所需的 this 和 a 与 b 中的任意一个时返回 false,则 抛出一个
TypeError。 -
计算输出形状:
-
令 rankA 为 a 的秩。
-
令 rankB 为 b 的秩。
-
令 colsA 为 shapeA[rankA - 1]。
-
令 rowsA 为 shapeA[rankA - 2]。
-
令 colsB 为 shapeB[rankB - 1]。
-
令 rowsB 为 shapeB[rankB - 2]。
-
令 outputShape 为将 batchShapeA 和 batchShapeB 双向广播 的结果。如果返回失败,则抛出一个
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
| 任意 | "float32",
"float16"
| N | 0 到 5 |
| 输出 | 与……相同 input
| "float32",
"float16"
| 与……相同 input
| 0 到 5 |
MLOpSupportLimits
对 pad()
具有以下成员:
pad, 类型为 MLSingleInputSupportLimits-
运算符
pad()的支持限制。
pad(input, beginningPadding, endingPadding, options)
方法步骤如下:
-
如果 this 无法构建,则抛出一个 "
InvalidStateError"DOMException。 -
如果 beginningPadding 的大小和 endingPadding 的大小并非 都等于 input 的秩,则抛出一个
TypeError。 -
对于每个 index,其位于范围 0 到 outputShape 的秩之间, 不包含上限:
-
根据 options.
mode进行分支:"constant"-
不执行任何操作。
"edge"-
不执行任何操作。
"reflection"
-
将 beginningPadding[index] 的值加到 outputShape[index] 上。
-
将 endingPadding[index] 的值加到 outputShape[index] 上。
-
-
令 desc 为在给定 input 的dataType 和 outputShape 的情况下创建 MLOperandDescriptor 的结果。
-
建立图连接:
-
令 output 为在给定 this 和 desc 的情况下创建 MLOperand 的结果。
-
令 operator 为给定 beginningPadding、 endingPadding 和 options 的 "padding" 操作的一个运算符。
-
将 output.
[[operator]]设置为 operator。 -
将 operator 的输入设置为 input。
-
将 operator 的输出设置为 output。
-
-
返回 output。
常量、边缘和反射填充的示例:
// 输入:[[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
| "float32",
"float16",
"bfloat16"
| "float32",
"float16"
| 4 | 4 |
| 输出 | 与……相同 input
| "float32",
"float16"
| 4 | 4 |
| 操作数 | 允许的 数据类型 | 必需的 数据类型 | 允许的秩 | 必需的秩 |
|---|---|---|---|---|
input
| 任意 | "float32",
"float16"
| 4 | 4 |
| 输出 | 与……相同 input
| "float32",
"float16"
| 4 | 4 |
MLOpSupportLimits
对池化运算具有以下成员:
averagePool2d, 类型为 MLSingleInputSupportLimits-
运算符
averagePool2d()的支持限制。 l2Pool2d, 类型为 MLSingleInputSupportLimits-
运算符
l2Pool2d()的支持限制。 maxPool2d, 类型为 MLSingleInputSupportLimits-
运算符
maxPool2d()的支持限制。
// “全局”最大池化 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 »。 -
计算输出形状:
-
令 « 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进行分支:
-
-
如果 outputHeight 或 outputWidth 中任意一个不是有效 维度,则抛出 一个
TypeError。 -
根据 options.
layout进行分支: -
令 desc 为在给定 input 的dataType 和 outputShape 的情况下创建 MLOperandDescriptor 的结果。
-
-
建立图连接:
-
令 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 是一种泄漏 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",
"bfloat16",
"int64",
"int32",
"int8"
| "float32",
"float16"
| N | 0 到 5 |
slope
| 与……相同 input
| "float32",
"float16"
| N | 0 到 5 |
| 输出 | 与……相同 input
| "float32",
"float16"
| N | 0 到 5 |
MLPreluSupportLimits
具有以下成员:
input, 类型为 MLTensorLimits-
MLTensorLimits用于 input 操作数。 slope, 类型为 MLTensorLimits-
MLTensorLimits用于 slope 操作数。 output, 类型为 MLTensorLimits-
MLTensorLimits用于 output 操作数。
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 为用于 "prelu" 操作的一个运算符,给定 slope 和 options。
-
将 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
| "float32",
"float16",
"bfloat16",
"int32",
"uint32",
"int64",
"uint64"
| "float32",
"float16",
"int32"
| N | 0 到 5 |
| 输出 | 与……相同 input
| "float32",
"float16",
"int32"
| N | 0 到 5 |
| 操作数 | 允许的 数据类型 | 必需的 数据类型 | 允许的秩 | 必需的秩 |
|---|---|---|---|---|
input
| "float32",
"float16",
"bfloat16"
| "float32",
"float16"
| N | 0 到 5 |
| 输出 | 与……相同 input
| "float32",
"float16"
| N | 0 到 5 |
| 操作数 | 允许的 数据类型 | 必需的 数据类型 | 允许的秩 | 必需的秩 |
|---|---|---|---|---|
input
| 任意 | "float32",
"float16",
"int32"
| N | 0 到 5 |
| 输出 | 与……相同 input
| "float32",
"float16",
"int32"
| N | 0 到 5 |
| 操作数 | 允许的 数据类型 | 必需的 数据类型 | 允许的秩 | 必需的秩 |
|---|---|---|---|---|
input
| "float32",
"float16",
"bfloat16",
"int32",
"uint32",
"int64",
"uint64"
| "float32",
"float16"
| N | 0 到 5 |
| 输出 | 与……相同 input
| "float32",
"float16"
| N | 0 到 5 |
MLOpSupportLimits
对归约运算具有以下成员:
reduceL1, 类型为 MLSingleInputSupportLimits-
运算符
reduceL1()的支持限制。 reduceL2, 类型为 MLSingleInputSupportLimits-
运算符
reduceL2()的支持限制。 reduceLogSum, 类型为 MLSingleInputSupportLimits-
运算符
reduceLogSum()的支持限制。 reduceLogSumExp, 类型为 MLSingleInputSupportLimits-
运算符
reduceLogSumExp()的支持限制。 reduceMax, 类型为 MLSingleInputSupportLimits-
运算符
reduceMax()的支持限制。 reduceMean, 类型为 MLSingleInputSupportLimits-
运算符
reduceMean()的支持限制。 reduceMin, 类型为 MLSingleInputSupportLimits-
运算符
reduceMin()的支持限制。 reduceProduct, 类型为 MLSingleInputSupportLimits-
运算符
reduceProduct()的支持限制。 reduceSum, 类型为 MLSingleInputSupportLimits-
运算符
reduceSum()的支持限制。 reduceSumSquare, 类型为 MLSingleInputSupportLimits-
运算符
reduceSumSquare()的支持限制。
要在给定一个由无符号整数构成的列表 inputShape、一个可选的由无符号整数构成的列表 axes 以及布尔值 keepDimensions 的情况下计算归约输出大小,执行以下步骤。它们返回 一个由无符号整数构成的新列表, 或返回失败。
要在给定字符串
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 的形状、options.
axes(如果它存在)和 options.keepDimensions的情况下计算归约输出 大小的结果。 如果返回失败,则抛出一个TypeError。 -
令 desc 为在给定 input 的dataType 和 outputShape 的情况下创建 MLOperandDescriptor 的结果。
-
建立图连接:
-
令 output 为在给定 this 和 desc 的情况下创建 MLOperand 的结果。
-
令 operator 为用于 op 操作的一个运算符,给定 options。
-
将 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) { // 这在数值上比直接分解更稳定 // log(reduceSum(exp(input))):减去最大值可使 // 指数值保持在有效范围内,并在最后将最大值加回。 const maxX= builder. reduceMax( input, { axes: options. axes, keepDimensions: true }); const sumExpX= builder. reduceSum( builder. exp( builder. sub( input, maxX)), options); return builder. add( builder. log( sumExpX), builder. reshape( maxX, sumExpX. shape)); } 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",
"bfloat16",
"int64",
"int32",
"int8"
| "float32",
"float16"
| N | 0 到 5 |
| 输出 | 与……相同 input
| "float32",
"float16"
| 与……相同 input
| 0 到 5 |
MLOpSupportLimits
对 relu()
具有以下成员:
relu, 类型为 MLSingleInputSupportLimits-
运算符
relu()的支持限制。
relu(input, options) 方法
的步骤如下:
-
如果 this 无法构建,则抛出一个 "
InvalidStateError"DOMException。 -
建立图连接:
-
令 output 为在给定 input 时复制 MLOperand 的结果。
-
令 operator 为用于 "relu" 操作的一个运算符,给定 options。
-
将 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) output tensor value = input tensor value at (x, y)
linear-
上面计算出的
inputCoordinate.x和inputCoordinate.y被用作 双线性采样算法的输入,以按如下方式计算输出张量值:x0 = floor(inputCoordinate.x) x1 = ceil(inputCoordinate.x) y0 = floor(inputCoordinate.y) y1 = ceil(inputCoordinate.y) vx0y0 = input tensor value at (x0, y0) vx1y0 = input tensor value at (x1, y0) vx0y1 = input tensor value at (x0, y1) vx1y1 = input tensor value at (x1, y1) tx = inputCoordinate.x - x0 ty = inputCoordinate.y - y0 vy0 = vx0y0 * (1 - tx) + vx1y0 * tx vy1 = vx0y1 * (1 - tx) + vx1y1 * tx output tensor value = vy0 * (1 - ty) + vy1 * ty
scales, 类型为 sequence<float>-
长度为 2 的列表。 指定来自
axes的每个输入维度的缩放因子: [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",
"bfloat16",
"uint8",
"int8"
| "float32",
"float16"
| 4 | 4 |
| 输出 | 与……相同 input
| "float32",
"float16"
| 4 | 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 为用于 "resample2d" 操作的一个运算符,给定 options。
-
将 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。 指定运算的可选参数。
返回:一个 MLOperand。
输出张量。输出
张量的值与输入张量的值相同。输出
张量的形状由 newShape
指定。
| 操作数 | 允许的 数据类型 | 必需的 数据类型 | 允许的秩 | 必需的秩 |
|---|---|---|---|---|
input
| 任意 | "float32",
"float16",
"int32",
"int8",
"uint8"
| N | 0 到 5 |
| 输出 | 与……相同 input
| "float32",
"float16",
"int32",
"int8",
"uint8"
| N | 0 到 5 |
MLOpSupportLimits
对 reshape()
具有以下成员:
reshape, 类型为 MLSingleInputSupportLimits-
运算符
reshape()的支持限制。
reshape(input, newShape, options)
方法步骤如下:
-
如果 this 无法构建,则抛出一个 "
InvalidStateError"DOMException。 -
令 outputShape 为一个空的
unsigned long数组。 -
令 inputElementCount 为 input 的形状中所有项的乘积。空维度产生的 inputElementCount 为 1。
-
令 desc 为创建 MLOperandDescriptor 的结果,给定 input 的dataType 和 newShape。
-
建立图连接:
-
令 output 为创建 MLOperand 的结果,给定 this 和 desc。
-
令 operator 为用于 "reshape" 操作的运算符,给定 options。
-
将 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
| 任意 | "float32",
"float16",
"int32"
| N | 0 到 5 |
| 输出 | 与……相同 input
| "float32",
"float16",
"int32"
| 与……相同 input
| 0 到 5 |
MLOpSupportLimits
对 reverse()
具有以下成员:
reverse, 类型为 MLSingleInputSupportLimits-
运算符
reverse()的支持限制。
reverse(input, options)
方法步骤如下:
-
如果 this 无法构建,则抛出一个 "
InvalidStateError"DOMException。 -
令 inputRank 为 input 的秩。
-
如果未给定 axes,则令 axes 为范围,从 0 到 inputRank,不含上限。
-
否则,如果 axes 包含重复值,或者其任何元素不在范围 0 到 inputRank(不含上限)内,则返回 失败。
-
建立图连接:
-
令 output 为在给定 input 时复制 MLOperand 的结果。
-
令 operator 为用于 "reverse" 操作和 options 的一个运算符。
-
将 output.
[[operator]]设置为 operator。 -
将 operator 的输入设置为 input。
-
将 operator 的输出设置为 output。
-
-
返回 output。
8.9.44. scatterElements
根据索引,沿某个轴将 updates 张量中的值散布到输入张量副本之上。dictionary :MLScatterOptions MLOperatorOptions { [EnforceRange ]unsigned long axis = 0; };partial interface MLGraphBuilder {MLOperand scatterElements (MLOperand input ,MLOperand indices ,MLOperand updates ,optional MLScatterOptions options = {}); };dictionary {MLScatterSupportLimits MLTensorLimits input ;MLTensorLimits indices ;MLTensorLimits updates ;MLTensorLimits output ; };partial dictionary MLOpSupportLimits {MLScatterSupportLimits scatterElements ; };
MLScatterOptions
具有以下成员:
axis, 类型为 unsigned long,默认为0-
获取散布值所沿的轴。其值必须位于 [0, N-1] 范围内,其中 N 是输入张量的秩。
| 操作数 | 允许的 数据类型 | 必需的 数据类型 | 允许的秩 | 必需的秩 |
|---|---|---|---|---|
input
| 任意 | "float32",
"float16",
"int32"
| 1 到 N | 1 到 5 |
indices
| "int32",
"uint32",
"int64"
| "int32"
| 与……相同 input
| 1 到 5 |
updates
| 与……相同 input
| "float32",
"float16",
"int32"
| 与……相同 input
| 1 到 5 |
| 输出 | 与……相同 input
| "float32",
"float16",
"int32"
| 与……相同 input
| 1 到 5 |
MLScatterSupportLimits
具有以下成员:
input, 类型为 MLTensorLimits-
MLTensorLimits用于 input 操作数。 indices, 类型为 MLTensorLimits-
MLTensorLimits用于 indices 操作数。 updates, 类型为 MLTensorLimits-
MLTensorLimits用于 updates 操作数。 output, 类型为 MLTensorLimits-
MLTensorLimits用于 output 操作数。
MLOpSupportLimits
对 scatterElements()
具有以下成员:
scatterElements, 类型为 MLScatterSupportLimits-
运算符
scatterElements()的支持限制。
indices
参数传给 scatterElements()
后将其限制在允许范围内,因为直到执行时输入才可知。
如果底层平台未提供指定的限制行为,实现可以在已编译图中引入 clamp()
。类似地,如果底层平台不支持负索引,实现可以在
已编译图中引入运算,将从维度末尾计算的负索引转换为正
索引。
scatterElements(input, indices, updates, options)
方法步骤如下:
-
如果 this 无法构建,则抛出一个 "
InvalidStateError"DOMException。 -
如果以 验证操作数所需的 this 和 input、indices 与 updates 中的任意一个执行验证返回 false,则抛出一个
TypeError。 -
如果 input、indices 或 updates 中任意一个的秩 不属于其允许的秩, 则抛出一个
TypeError。 -
令 axis 为 options.
axis。 -
令 indicesShapeExpected 为 input 的形状的副本。
-
将 indicesShapeExpected[axis] 设置为 indices 的形状[axis]。
-
建立图连接:
-
令 output 为在给定 input 时复制 MLOperand 的结果。
-
令 operator 为给定 input、indices、updates 和 options 的 "scatterElements" 操作的一个运算符。
-
将 output.
[[operator]]设置为 operator。 -
将 operator 的输入设置为 input、indices 和 updates。
-
将 operator 的输出设置为 output。
-
-
返回 output。
scatterElements 在不同切片方案下如何工作的示例。
// 形状为 [4,3] 的 input: // [[ 0, 1, 2], // [10, 11, 12], // [20, 21, 22], // [30, 31, 32]] // 形状为 [2,3] 的 indices: // [[3, 1, 1], // [2, 0, 3]] // 形状为 [2,3] 的 updates: // [[-1, -2, -3], // [-4, -5, -6]] // axis = 0(默认值) // 形状为 [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); // 形状为 [4,3] 的 input: // [[ 0, 1, 2], // [10, 11, 12], // [20, 21, 22], // [30, 31, 32]] // 形状为 [4,1] 的 indices: // [[2], // [1], // [0], // [2]], // 形状为 [4,1] 的 updates: // [[-1], // [-2], // [-3], // [-4]], // axis = 1 // 形状为 [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 }); // 形状为 [4,2,2] 的 input: // [[[ 0, 1], // [ 10, 11]], // [[100, 101], // [110, 111]], // [[200, 201], // [210, 211]], // [[300, 301], // [310, 311]],] // 形状为 [1,2,2] 的 indices: // [[[0, 2], // [1, 3]]], // 形状为 [1,2,2] 的 updates: // [[[-1, -2], // [-3, -4]]], // axis = 0 // 形状为 [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
根据索引,将 update 张量中的值切片散布到输入张量副本之上。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。 用于替换输入中值的新值。 -
options: 一个可选的MLScatterOptions。 运算的可选参数。
返回:一个 MLOperand。
输出 N 维张量,其秩等于 input
的
秩 + indices
的
秩 - indices
的
shape[-1] - 1。
| 操作数 | 允许的 数据类型 | 必需的 数据类型 | 允许的秩 | 必需的秩 |
|---|---|---|---|---|
input
| 任意 | "float32",
"float16",
"int32"
| 1 到 N | 1 到 5 |
indices
| "int32",
"uint32",
"int64"
| "int32"
| 1 到 N | 1 到 5 |
updates
| 与……相同 input
| "float32",
"float16",
"int32"
| N | 0 到 5 |
| 输出 | 与……相同 input
| "float32",
"float16",
"int32"
| 1 到 N | 1 到 5 |
MLOpSupportLimits
对 scatterND()
具有以下成员:
scatterND, 类型为 MLScatterSupportLimits-
运算符
scatterND()的支持限制。
indices
参数 scatterND()
限制在允许范围内,因为直到执行时输入才可知。
如果底层平台未提供指定的限制行为,实现可以在已编译图中引入 clamp()。
类似地,如果底层平台不支持负索引,实现可以在
已编译图中引入运算,将从维度末尾计算的负索引转换为正
索引。
scatterND(input, indices, updates, options)
方法步骤如下:
-
如果 this 无法构建,则抛出一个 "
InvalidStateError"DOMException。 -
如果以 验证操作数所需的 this 和 input、indices 与 updates 中的任意一个执行验证返回 false,则抛出一个
TypeError。 -
如果 input、indices 或 updates 中任意一个的秩 不属于其允许的秩, 则抛出一个
TypeError。 -
令 indexableSize 为 indicesRank - 1。
-
令 coordinateSize 为 indicesShape[indexableSize]。
-
令 expectedUpdatesShape 为一个空列表。
-
对于从 0 到 indexableSize(不含)的每个 index,其位于范围内:
-
将 indicesShape[index] 追加到 expectedUpdatesShape。
-
-
对于从 coordinateSize 到 inputRank(不含)的每个 index,其位于范围内:
-
将 inputShape[index] 追加到 expectedUpdatesShape。
-
-
令 outputShape 为 input 的形状的副本。
-
令 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 在不同切片方案下如何工作的示例。
// 形状为 [8] 的 input: // [0, 1, 2, 3, 4, 5, 6, 7] // 形状为 [4, 1] 的 indices: // [[4], // [3], // [1], // [7]] // 形状为 [4] 的 updates: // [-1, -2, -3, -4] // 形状为 [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); // 形状为 [2,2] 的 input: // [[0, 1], // [2, 3]] // 形状为 [2,2] 的 indices: // [[0, 0], // [1, 1]] // 形状为 [2] 的 updates: // [-1, -2] // 形状为 [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); // 形状为 [3,2] 的 input: // [[0, 1], // [2, 3], // [4, 5]] // 形状为 [2,1] 的 indices: // [[2], // [0]] // 形状为 [2,2] 的 updates: // [[-1, -2], // [-3, -4]] // 形状为 [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); // 形状为 [2,2,2] 的 input: // [[[0, 1], // [2, 3]], // [[4, 5], // [6, 7]]] // 形状为 [2,2] 的 indices: // [[0, 1], // [1, 0]] // 形状为 [2,2] 的 updates: // [[-1, -2], // [-3, -4]] // 形状为 [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",
"bfloat16"
| "float32",
"float16"
| N | 0 到 5 |
| 输出 | 与……相同 input
| "float32",
"float16"
| 与……相同 input
| 0 到 5 |
MLOpSupportLimits
对 sigmoid()
具有以下成员:
sigmoid, 类型为 MLSingleInputSupportLimits-
运算符
sigmoid()的支持限制。
sigmoid(input, options)
方法步骤如下:
-
如果 this 无法构建,则抛出一个 "
InvalidStateError"DOMException。 -
建立图连接:
-
令 output 为复制 MLOperand 的结果,给定 input。
-
令 operator 为用于 "sigmoid" 操作的运算符,给定 options。
-
将 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]。 步幅必须大于零。
-
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
| 任意 | "float32",
"float16",
"int32",
"int8",
"uint8"
| N | 0 到 5 |
| 输出 | 与……相同 input
| "float32",
"float16",
"int32",
"int8",
"uint8"
| 与……相同 input
| 0 到 5 |
MLOpSupportLimits
对 slice()
具有以下成员:
slice, 类型为 MLSingleInputSupportLimits-
运算符
slice()的支持限制。
slice(input, starts, sizes, options)
方法步骤如下:
-
如果 this 无法构建,则抛出一个 "
InvalidStateError"DOMException。 -
令 strides 为一个新列表。
-
令 outputShape 为一个新列表。
-
对于每个 index,其位于范围 0 到 inputRank 之间,不含上限:
-
令 inputSize 为 inputShape[index]。
-
令 inputSliceSize 为 sizes[index]。
-
如果 strides 非空,则令 stride 为 strides[index],否则为 1 :
-
如果 inputSliceSize 为 0,则抛出 一个
TypeError。如果 允许大小为 0 的维度,则需要修订这些步骤。[议题 #391]
-
如果 starts[index] + inputSliceSize 大于 inputSize,则抛出 一个
TypeError。 -
如果 inputSliceSize % stride != 0,则令 outputSizeRoundingExcess 为 1,否则为 0。
-
令 outputSize 为 floor(inputSliceSize / stride) + outputSizeRoundingExcess:
-
追加 outputSize 到 outputShape。
-
-
令 outputDesc 为创建 MLOperandDescriptor 的结果,给定 input 的dataType 和 outputShape。
-
建立图连接:
-
令 output 为创建 MLOperand 的结果,给定 outputDesc。
-
令 operator 为用于 "slice" 操作的运算符,给定 starts、sizes 和 options。
-
将 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",
"bfloat16"
| "float32",
"float16"
| 1 到 N | 1 到 5 |
| 输出 | 与……相同 input
| "float32",
"float16"
| 与……相同 input
| 1 到 5 |
MLOpSupportLimits
对 softmax()
具有以下成员:
softmax, 类型为 MLSingleInputSupportLimits-
运算符
softmax()的支持限制。
softmax(input, axis, options)
方法步骤如下:
-
如果 this 无法构建,则抛出一个 "
InvalidStateError"DOMException。 -
建立图连接:
-
令 output 为复制 MLOperand 的结果,给定 input。
-
令 operator 为用于 "softmax" 操作的一个运算符,给定 axis 和 options。
-
将 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",
"bfloat16"
| "float32",
"float16"
| N | 0 到 5 |
| 输出 | 与……相同 input
| "float32",
"float16"
| 与……相同 input
| 0 到 5 |
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) { const zero= builder. constant( input. dataType, 0 ); const one= builder. constant( input. dataType, 1 ); return builder. add( builder. max( zero, input), builder. log( builder. add( one, builder. exp( builder. neg( builder. abs( input)))))); }
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",
"bfloat16"
| "float32",
"float16"
| N | 0 到 5 |
| 输出 | 与……相同 input
| "float32",
"float16"
| 与……相同 input
| 0 到 5 |
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
| 任意 | "float32",
"float16",
"int32"
| 1 到 N | 1 到 5 |
| 输出 | 与……相同 input
| "float32",
"float16",
"int32"
| 与……相同 input
| 1 到 5 |
MLSplitSupportLimits
具有以下成员:
input, 类型为 MLTensorLimits-
MLTensorLimits用于 input 操作数。 outputs, 类型为 MLTensorLimits-
MLTensorLimits用于所有输出操作数。
MLOpSupportLimits
对 split()
具有以下成员:
split, 类型为 MLSplitSupportLimits-
运算符
split()的支持限制。
split(input, splits, options)
方法步骤如下:
-
如果 this 无法构建,则抛出一个 "
InvalidStateError"DOMException。 -
令 axis 为 options.
axis。 -
如果 splits 是
unsigned long, 则: -
如果 splits 是一个序列<
unsigned long>, 则: -
建立图连接:
-
令 operator 为用于 "split" 操作的一个运算符,给定 splits 和 options。
-
令 outputs 为一个新列表。
-
对于每个 index,其位于范围 0 到 splitCount 之间,不含上限:
-
令 operand 为复制 MLOperand 的结果,给定 input。
-
如果 splits 是
unsigned long, 则令 newDimension 为 operand 的形状[axis] / splits。 -
否则,令 newDimension 为 splits[index]。
-
将 operand 的形状[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",
"bfloat16"
| "float32",
"float16"
| N | 0 到 5 |
| 输出 | 与……相同 input
| "float32",
"float16"
| 与……相同 input
| 0 到 5 |
MLOpSupportLimits
对 tanh()
具有以下成员:
tanh, 类型为 MLSingleInputSupportLimits-
运算符
tanh()的支持限制。
tanh(input, options) 方法
的步骤如下:
-
如果 this 无法构建,则抛出一个 "
InvalidStateError"DOMException。 -
建立图连接:
-
令 output 为复制 MLOperand 的结果,给定 input。
-
令 operator 为用于 "tanh" 操作的运算符,给定 options。
-
将 output.
[[operator]]设置为 operator。 -
将 operator 的输入设置为 input。
-
将 operator 的输出设置为 output。
-
-
返回 output。
此操作的行为可以通过使用其他操作按如下方式进行通用模拟, 不过用户代理通常具有更高效的实现。此分解 是一个说明性示例,而不是参考实现:它不规定算法 或中间结果的精度。在底层平台不直接 支持某项操作的情况下,此分解可用作指导实现的模板。
function tanh( builder, input) { const one= builder. constant( input. dataType, 1 ); const expNeg2AbsX= builder. exp( builder. mul( builder. constant( input. dataType, - 2 ), builder. abs( input))); return builder. mul( builder. sign( input), builder. div( builder. sub( one, expNeg2AbsX), builder. add( one, expNeg2AbsX))); }
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
| 任意 | "float32",
"float16",
"int32"
| N | 0 到 5 |
| 输出 | 与……相同 input
| "float32",
"float16",
"int32"
| 与……相同 input
| 0 到 5 |
MLOpSupportLimits
对 tile()
具有以下成员:
tile, 类型为 MLSingleInputSupportLimits-
运算符
tile()的支持限制。
tile(input, repetitions, options)
方法步骤如下:
-
如果 this 无法构建,则抛出一个 "
InvalidStateError"DOMException。 -
如果 repetitions 的值中包含 0,则抛出一个
TypeError。如果允许大小为 0 的 维度,则需修订这些步骤。[议题 #391]
-
令 outputShape 为 input 的形状的副本。
-
对于每个 index,其位于范围 0 到 outputShape 的大小之间,不含上限:
-
将 outputShape[index] 设置为 outputShape[index] * repetitions[index]。
-
-
令 outputDescriptor 为创建 MLOperandDescriptor 的结果,给定 input 的dataType 和 outputShape。
-
建立图连接:
-
令 output 为创建 MLOperand 的结果,给定 outputDescriptor。
-
令 operator 为用于 "tile" 操作的一个运算符,给定 options。
-
将 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 是输入张量的秩,例如三维张量为 [2,1,0]。 这些默认值会使输出成为输入的转置张量。指定时, 值的数量必须与输入张量的秩相同,并且值必须位于 0 到 N-1 的范围内且不得重复。
-
input:一个MLOperand。 输入 N 维张量。 -
options:一个 可选的MLTransposeOptions。 运算的可选参数。
返回:一个 MLOperand。
置换或转置后的 N 维张量。
| 操作数 | 允许的 数据类型 | 必需的 数据类型 | 允许的秩 | 必需的秩 |
|---|---|---|---|---|
input
| 任意 | "float32",
"float16",
"int32"
| N | 0 到 5 |
| 输出 | 与……相同 input
| "float32",
"float16",
"int32"
| 与……相同 input
| 0 到 5 |
MLOpSupportLimits
对 transpose()
具有以下成员:
transpose, 类型为 MLSingleInputSupportLimits-
运算符
transpose()的支持限制。
transpose(input, options)
方法步骤如下:
-
如果 this 无法构建,则抛出一个 "
InvalidStateError"DOMException。 -
如果 options.
permutation不存在,则令 options.permutation为 input 的形状所有索引的逆序序列。 -
否则,如果 options.
permutation存在: -
建立图连接:
-
令 output 为在给定 input 时复制 MLOperand 的结果。
-
令 operator 为用于 "transpose" 操作的一个运算符,给定 options。
-
将 output.
[[operator]]设置为 operator。 -
将 operator 的输入设置为 input。
-
将 operator 的输出设置为 output。
-
-
返回 output。
8.9.55. triangular
给定一个二维张量(矩阵),返回一个包含输入张量上三角或下三角部分的二维张量。 如果输入张量具有多于 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。 至少为二维的输入张量。 -
options:一个 可选的MLTriangularOptions。 运算的可选参数。
返回:一个 MLOperand。
表示三角矩阵的输出张量,或一批与输入具有相同形状的
矩阵。
| 操作数 | 允许的 数据类型 | 必需的 数据类型 | 允许的秩 | 必需的秩 |
|---|---|---|---|---|
input
| 任意 | "float32",
"float16"
| 2 到 N | 2 到 5 |
| 输出 | 与……相同 input
| "float32",
"float16"
| 与……相同 input
| 2 到 5 |
MLOpSupportLimits
对 triangular()
具有以下成员:
triangular, 类型为 MLSingleInputSupportLimits-
运算符
triangular()的支持限制。
triangular(input, options)
方法步骤如下:
-
如果 this 无法构建,则抛出一个 "
InvalidStateError"DOMException。 -
建立图连接:
-
令 output 为复制 MLOperand 的结果,给定 input。
-
令 operator 为用于 "triangular" 操作的一个运算符,给定 options。
-
将 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"
| "uint8"
| N | 0 到 5 |
trueValue
| 任意 | "float32",
"float16",
"int32"
| N | 0 到 5 |
falseValue
| 与……相同 trueValue
| "float32",
"float16",
"int32"
| N | 0 到 5 |
| 输出 | 与……相同 trueValue
| "float32",
"float16",
"int32"
| N | 0 到 5 |
MLWhereSupportLimits
具有以下成员:
condition, 类型为 MLTensorLimits-
MLTensorLimits用于 condition 操作数。 trueValue, 类型为 MLTensorLimits-
MLTensorLimits用于 trueValue 操作数。 falseValue, 类型为 MLTensorLimits-
MLTensorLimits用于 falseValue 操作数。 output, 类型为 MLTensorLimits-
MLTensorLimits用于 output 操作数。
MLOpSupportLimits
对 where()
具有以下成员:
where, 类型为 MLWhereSupportLimits-
运算符
where()的支持限制。
where(condition, trueValue, falseValue, options)
方法步骤如下:
-
如果 this 无法构建,则抛出一个 "
InvalidStateError"DOMException。 -
如果验证操作数,给定 this 以及 condition、trueValue 和 falseValue 中任意一个时返回 false,则抛出一个
TypeError。 -
如果 condition、trueValue 或 falseValue 中任意一个的dataType 不属于其允许的数据类型 (根据此表),则抛出一个
TypeError。 -
令 descriptor 为创建 MLOperandDescriptor 的结果,给定 trueValue 的dataType 和 outputShape。
-
建立图连接:
-
令 output 为创建 MLOperand 的结果,给定 this 和 descriptor。
-
令 operator 为用于 "where" 操作的一个运算符,给定 condition、trueValue、falseValue 和 options。
-
将 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 的轴重复第一个张量
或跨新维度重复,并从最后一个(最右侧)维度开始扩展,则一个张量可以单向
广播到另一个张量。
例如,可以将一个 [4] 张量重复 5 次广播为 [5, 4] 张量。一个
[1] 张量可以通过在最后一个维度重复 4 次并在前一个维度重复 5
次广播为 [5,4] 张量。单向广播对于诸如 expand()
这样的运算很重要,其中目标张量形状是显式给定的。
如果两个张量可以从最后一个维度开始,在各个维度上相互 “扩展”(重复),则它们可以双向广播。例如,可以将一个 [5,1] 张量与一个 [1,6] 张量进行双向广播,方法是在最后一个维度将第一个 张量重复 6 次,并在前一个维度将第二个张量重复 5 次。运算 结果将是一个 [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 是表示张量维度的正整数列表, 这些步骤返回一个新的正整数列表, 或失败。
-
令 sizeFrom 为 shapeFrom 的大小。
-
令 sizeTo 为 shapeTo 的大小。
-
如果 sizeFrom > sizeTo,则返回失败。
-
令 paddedShapeFrom 为 shapeFrom 的一个克隆。
-
令 outputShape 为一个新的列表。
-
对于每一个 index,位于范围 0 到 sizeTo 内(不含上界):
-
令 dimFrom 为 paddedShapeFrom[index]。
-
令 dimTo 为 shapeTo[index]。
-
如果 dimTo 不等于 dimFrom 且 dimFrom 不 等于 1,则返回失败。
-
附加 dimTo 到 outputShape。
-
-
返回 outputShape。
如果单向广播 shapeFrom 和 shapeTo 不会导致失败,则 shapeFrom 可以单向广播到 shapeTo。
要双向广播形状 shapeA 和 shapeB,执行以下步骤。shapeA 和 shapeB 是表示张量维度的正整数列表, 这些步骤返回一个新的正整数列表, 或失败。
-
令 sizeA 为 shapeA 的大小。
-
令 sizeB 为 shapeB 的大小。
-
令 outputSize 为 sizeA 和 sizeB 中的最大值。
-
令 paddedA 为 shapeA 的一个克隆。
-
令 paddedB 为 shapeB 的一个克隆。
-
令 outputShape 为一个新的列表。
-
对于每一个 index,位于范围 0 到 outputSize 内(不含上界):
-
令 dimA 为 paddedA[index]。
-
令 dimB 为 paddedB[index]。
-
如果 dimA 不等于 dimB,并且 dimA 不等于 1,并且 dimB 不等于 1,则返回失败。
-
附加 dimA 和 dimB 中的最大值到 outputShape。
-
-
返回 outputShape。
如果双向广播 shapeA 和 shapeB 不会导致失败,则 shapeA 可以双向广播到 shapeB。
要块级广播形状 shapeFrom 和 shapeTo,执行以下步骤。shapeFrom 和 shapeTo 是表示张量维度的正整数列表, 这些步骤返回 true 或 false。
如果块级 广播 shapeFrom 和 shapeTo 返回 true,则 shapeFrom 可以块级广播到 shapeTo。
9.2. 类型转换
在算法中,当作为 MLNumber
或 double
传入的参数需要转换以匹配输入或输出 MLOperand 的
MLOperandDataType
时,会使用显式数值类型转换。
要将数字 x 转换
为给定的 MLOperandDataType
dataType,执行以下步骤。它们返回一个数值。
-
根据 dataType 进行切换:
"float32"-
返回 ConvertToFloat(x,
"float32"). "float16"-
返回 ConvertToFloat(x,
"float16"). "bfloat16"-
返回 ConvertToFloat(x,
"bfloat16"). "float8e4m3"-
返回 ConvertToFloat(x,
"float8e4m3"). "int64"-
返回 ConvertToInt(x, 64, "signed")。
"uint64"-
返回 ConvertToInt(x, 64, "unsigned")。
"int32"-
返回 ConvertToInt(x, 32, "signed")。
"uint32"-
返回 ConvertToInt(x, 32, "signed")。
"int8"-
返回 ConvertToInt(x, 8, "signed")。
"uint8"-
返回 ConvertToInt(x, 8, "unsigned")。
注:转换的输入是一个范围和精度均不受限制的抽象数值, 包括特殊值 Infinity、-Infinity 和 NaN。输出也是一个抽象数值,但 可以由指定类型精确表示。
-
如果 x 为 NaN,则返回 NaN。
-
根据 dataType 进行切换:
"float32"-
-
令 upperBound 为 2128。
-
令 lowerBound 为 -2128。
-
令 S 为以下有限浮点值的集合: [IEEE-754-2019] 的 binary32 格式值,不包括 -0,但将特殊值 upperBound 和 lowerBound 添加到集合中。
-
"float16"-
-
令 upperBound 为 216。
-
令 lowerBound 为 -216。
-
令 S 为以下有限浮点值的集合: [IEEE-754-2019] 的 binary16 格式值,不包括 -0,但将特殊值 upperBound 和 lowerBound 添加到集合中。
-
"bfloat16"-
-
令 upperBound 为 2128.
-
令 lowerBound 为 -2128.
-
令 S 为以下有限值的集合: [IEEE-754-2019] 的 binary32 浮点值,其编码的最低 16 位均为零(即可以用
"bfloat16"表示的有限值),不包括 -0,但将特殊值 upperBound 和 lowerBound 添加到集合中。
-
"float8e4m3"-
-
令 upperBound 为 480。
-
令 lowerBound 为 -480。
-
令 S 为以下格式的有限浮点值集合: [OCP-OFP8] 的 E4M3 格式,不包括 -0,但将特殊值 upperBound 和 lowerBound 添加到集合中。
-
-
令 y 为 S 中最接近 x 的数值,如果有两个同样接近的值,则选择 有效数字为偶数的数值。为此,两个 特殊值 lowerBound 和 upperBound 被视为具有偶数 有效数字。
-
如果 y 是 upperBound,则:
-
如果 dataType 为
"float8e4m3",则返回 448。 -
返回 +Infinity。
-
-
如果 y 是 lowerBound,则:
-
如果 dataType 为
"float8e4m3",则返回 -448。 -
返回 -Infinity。
-
-
如果 y 是 +0 且 x 为负数,则返回 -0。
-
返回 y。
注:这基于 [WEBIDL],但扩展为涵盖 16 位和 8 位浮点值。特殊值 upperBound
和 lowerBound 表示若编码继续延伸,会紧随最大有限绝对值之后的值。对于 "float8e4m3"
,这些值不可表示,因为该格式没有无穷大,因此本算法执行 [OCP-OFP8]的饱和转换:超出范围的值和无穷大转换为最大有限绝对值 448,而 NaN 保持不变。
-
如果 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 问题 #664]
10. 示例
constant1 ---+
+--- Add ---> intermediateOutput1 ---+
input1 ---+ |
+--- Mul---> output
constant2 ---+ |
+--- Add ---> intermediateOutput2 ---+
input2 ---+
以下代码实现该图:
// 使用四维张量。 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
的兼容性
Float16Array
现已成为 [ECMASCRIPT]的一部分。在其可用之前,本 API 的实现通过传递 "float16"
值的原始位来模拟它,使用 Uint16Array
([Issue webnn#373])。根据此表, Uint16Array
不能用于 "float16",且 Float16Array
不能用于 "bfloat16"。
没有专门用于这些数据类型的 ArrayBufferView
类型: "bfloat16"
和 "float8e4m3"。 Uint16Array
的每个元素都以平台原生字节序的位模式保存一个 "bfloat16"
值的 16 位编码,这与 Float16Array
用于 "float16"
值的约定相同; Uint8Array
的每个元素都保存一个 "float8e4m3"
值的 8 位编码,采用 § 8.5 MLOperandDescriptor 字典中描述的编码。独立于此表, Uint8Array
可用作任何 MLOperandDataType的通用视图,参见 使用描述符验证缓冲区.
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. 变更
本节为非规范性内容。
本节按照变更类别记录自上一次主要发布以来对本规范所做的变更。
候选推荐快照 2024 年 4 月 11 日与 2026 年 1 月 22 日之间的详细变更
新功能(第 4 类)
- 扩展“第 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)
- 支持运算输出张量的 rankRange,将 rankRange 支持扩展到输出张量(#857)
添加 MLDeviceType npu,即神经处理单元(NPU)设备类型(#696)- 此功能在 上一次发布后被添加又移除,以简化设备选择,参见 #809- 为 MLContext 和 MLGraph 添加 destroy() 方法,规定上下文丢失行为和错误报告 (#744)
- 向 softmax 运算添加可选的 axis 参数(#649)
- 向 argmin/argmax 添加 outputDataType,以支持指定输出数据类型(#730)
- 允许 resample2d 使用任意轴,使 resample2d 能处理任意轴(#752)
- 添加 Resample 数据类型 uint8/int8,将 resample 扩展为支持 8 位整数类型(#891)
- 简化 conv2d 和 pool2d 运算的操作数布局支持,从 pool2d 中移除 MLRoundingType, 简化布局支持(#770)
- 限制 padding 选项,以更好地匹配后端限制(#843)
不添加新功能的其他变更(第 3 类)
- 移除 MLContext.compute() 方法,改用 MLTensor API(#795)
- 移除 MLDeviceType,通过移除设备类型枚举简化设备选择(#809)
- 将 MLOperand 方法转换为 readonly 属性,并将 dataType() 和 shape() 从方法改为 属性(#774)
- 将 MLOperandDescriptor.shape 设为必需属性(#764)
- 仅允许调用一次 MLGraphBuilder.build(),将 build 方法限制为单次调用 (#717)
- 移除 constant() 的 fillSequence 重载,以移除基于 sequence 的常量创建(#656)
- 交换标量 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)
- 为若干运算添加缺失的验证步骤,以改进验证(#820)
- 为 pad()、slice() 和 split() 添加缺失的验证,以增强数组运算的验证 (#690)
- 简化、纠正并为 GRU/LSTM 添加验证,以改进循环网络验证(#659)
- 验证 GRU 和 LSTM 运算符的 hidden size(#644)
- 验证 convTranspose2d 中 output padding 的限制,以对转置 卷积进行更严格的验证(#631)
- 增强 gather 运算验证(#642)
- 常规验证改进(#643)
- 改进资源验证(#622)
- 定义 MLNamedArrayBufferViews 传输算法的错误处理,以正确处理 缓冲区传输错误(#723)
- 将维度有效范围更新为有符号整数(#738)
- 引入“有效维度”概念,以形式化维度有效性(#641)
- 确保对象创建指定领域,以便正确处理对象创建的领域(#810)
- 澄清除法运算符的舍入(#909)
- 纠正 pad 标量不一致问题(#894)
- 修复 split 运算的 opSupportLimits 错误(#776)
- 对 softmax() axis 参数使用 EnforceRange,以正确实施范围限制(#746)
- 向 conv2d 算法添加缺失的 inputShape 定义(#680)
- 修复单向广播形状步骤(#663)
- 修复缓冲区传输失败时 compute() 的 promise 拒绝行为(#639)
- 使用 64 位整数类型更新 ArrayBufferView 兼容性表(#698)
不影响文档解释功能的变更(第 2 类)
- 使操作数数据类型和秩验证由表格驱动,以系统化方式进行验证(#657)
- 添加按类别划分的运算符非规范性表格(#868)
- 澄清 cast() 在不同数据类型之间的运算行为(#726)
- 澄清 resample2d 的插值算法(#816)
- 澄清空 axes 和标量输入的归约行为,以澄清边界情况(#741)
- 添加关于无操作图的注释(#665)
- 添加关于归约运算 keepDimensions 的注释,以澄清归约运算行为(#648)
- 重组模拟文档(#598)
- 添加 reduceLogSum、reduceLogSumExp 和 reduceSumSquare 的分解(#637)
- 移除关于 clamp() minValue == maxValue 互操作问题的过时注释(#684)
- 更新规范样板元数据信息(#769)
- 添加架构资源竞争方面的考虑(#765)
- 添加 Unicode 安全考虑(#851)
- 添加计算控制流攻击的安全考虑(#725)
- 修订隐私考虑(#890)
- 添加 opSupportLimits() 指纹识别的隐私考虑(#881)
- 添加无障碍考虑(#869)
- 添加关于标签使用的国际化注释(#841)
编辑性变更(第 2 类)
- 各种编辑改进(#834)
- 各种样式和措辞调整(#797)
- 语法和拼写更正(#782)
- 使用辅助算法简化规范步骤(#737)
- 改进类型引用(#735)
- 引用 WebIDL transferable 定义(#732)
- 避免在正文中使用“sequence”,以改进术语使用(#729)
- 改进算法步骤的验证逻辑,以增强 lint 和验证(#727)
- 链接方法参数定义以改进交叉引用(#721)
- 移除不必要的子节,以改进组织结构(#711)
- 在意图表达形容词时链接到“is empty”而非“empty”(#708)
- 添加实用工具,以便于编写和审查本规范(#702)
- 修复“transferred”交叉引用(#679)
- 将“generically emulated”文本改为宏,以改善编写体验(#638)
- 修复 LSTM 在 'backward' 和 'both' 方向上的模拟错误(#802)
- 修复 GRU 在 'backward' 和 'both' 方向上的模拟错误(#803)
- 纠正分解中的拼写错误/JS 错误(#699)