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" dictionary {MLOperandDescriptor required MLOperandDataType dataType ;required sequence <[EnforceRange ]unsigned long >shape ; };
dataType, 类型为 MLOperandDataType-
操作数的数据类型。
shape, 类型为sequence<[EnforceRange] unsigned long>-
操作数的维度列表。对于标量操作数,该列表为空。
dataType
等于 B.dataType
且 A.shape
等于 B.shape,则一个
MLOperandDescriptor
A 等于另一个 MLOperandDescriptor
B。
给定 MLOperandDataType
dataType 和列表 shape,要创建
一个 MLOperandDescriptor,
运行以下步骤:
-
令 descriptor 为一个新的
MLOperandDescriptor。 -
将 descriptor.
dataType设置为 dataType。 -
返回 descriptor。
一个 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 为给定 this 和 descriptor 创建 MLOperand 的结果。
-
令 bytes 为给定 buffer 获取缓冲区源所持字节的副本的结果。
-
-
返回 operand。
8.9.3.2. constant(tensor)
创建一个具有指定数据类型和形状且包含已初始化数据的常量 MLOperand。
constant(tensor) 方法的步骤
为:
-
如果 tensor.
[[context]]不是 this.[[context]], 则抛出一个TypeError。 -
如果 tensor.
[[isDestroyed]]为 true,则抛出一个TypeError。 -
如果 tensor.
[[isConstant]]为 false,则抛出一个TypeError。 -
如果 this 无法构建,则抛出一个 "
InvalidStateError"DOMException。 -
建立图连接:
-
令 operand 为给定 this 和 tensor.
[[descriptor]]创建 MLOperand 的结果。 -
将 operand.
[[constantTensor]]设置为 tensor。
-
-
返回 operand。
8.9.3.3. constant(dataType, value)
创建一个具有指定值和数据类型的标量常量 MLOperand。
"int8"
数据类型等。
-
dataType:一个MLOperandDataType。 -
value:一个MLNumber。 常量的值。
MLOperand。
常量输出。
constant(dataType, value)
方法的步骤为:
-
如果 this 无法构建,则抛出一个 "
InvalidStateError"DOMException。 -
将 value 设置为把 value 转换为 dataType 的结果。
-
令 descriptor 为给定 dataType 和 « » 创建 MLOperandDescriptor 的结果。
-
建立图连接:
-
令 operand 为给定 this 和 descriptor 创建 MLOperand 的结果。
-
-
返回 operand。
8.9.4. build 方法
将组合图构建到给定输出操作数为止,并异步生成计算图。-
outputs:一个MLNamedOperands。 标识将成为图输出的MLOperand。
MLGraph>。
build(outputs) 方法的步骤为:
-
如果 this 无法构建,则返回 realm 中一个新的 promise,该 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。
注: 将输入操作数或常量操作数指定为图的 输出
会导致错误,因为这通常是对 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 的shape[axis] 大于 options.
outputDataType的 最大值,则抛出一个TypeError。 -
令 outputShape 为给定 input 的shape、« axis » 和 options.
keepDimensions计算归约输出 大小的结果。 如果其返回失败,则抛出一个TypeError。 -
令 desc 为给定 options.
outputDataType和 outputShape 创建 MLOperandDescriptor 的结果。 -
建立图连接:
-
令 operator 为给定 options 的 op 运算的一个运算符。
-
令 output 为给定 this 和 desc 创建 MLOperand 的结果。
-
将 output.
[[operator]]设置为 operator。 -
将 operator 的输入设置为 input。
-
将 operator 的输出设置为 output。
-
-
返回 output。
支持以下 argMin/argMax 算法。
argMin(input, axis, options)
方法的步骤为:
-
令 output 为给定 "argMin"、input、axis 和 options 创建 argMin/argMax 运算的结果。
-
返回 output。
argMax(input, axis, options)
方法的步骤为:
-
令 output 为给定 "argMax"、input、axis 和 options 创建 argMin/argMax 运算的结果。
-
返回 output。
8.9.6. batchNormalization
使用 [Batch-Normalization] 对输入张量的值进行归一化。 在模型训练期间,对于每个输入特征,会跨批次维度中的所有样本计算该特征的均值和方差值。 随后在模型推理期间,将这些均值和方差值提供给此运算。dictionary :MLBatchNormalizationOptions MLOperatorOptions {MLOperand scale ;MLOperand bias ; [EnforceRange ]unsigned long axis = 1;double epsilon = 1e-5; };partial interface MLGraphBuilder {MLOperand batchNormalization (MLOperand input ,MLOperand mean ,MLOperand variance ,optional MLBatchNormalizationOptions options = {}); };dictionary {MLBatchNormalizationSupportLimits MLTensorLimits input ;MLTensorLimits mean ;MLTensorLimits variance ;MLTensorLimits scale ;MLTensorLimits bias ;MLTensorLimits output ; };partial dictionary MLOpSupportLimits {MLBatchNormalizationSupportLimits batchNormalization ; };
MLBatchNormalizationOptions
具有以下成员:
scale, 类型为 MLOperandbias, 类型为 MLOperandaxis, 类型为 unsigned long,默认为1-
输入形状中特征数量维度的索引,均值和方差值即针对该维度。 其值必须位于范围 [0, N-1] 内,其中 N 是输入张量的秩。默认 值为 1,对应于
"nchw"数据布局中的通道("c")维度。 epsilon, 类型为 double,默认为1e-5-
用于防止除以零导致计算错误的一个小值。
| 操作数 | 允许的数据 类型 | 必需的 数据类型 | 允许的秩 | 必需的秩 |
|---|---|---|---|---|
input
| "float32",
"float16"
| "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-
用于 mean 操作数的
MLTensorLimits。 variance, 类型为 MLTensorLimits-
用于 variance 操作数的
MLTensorLimits。 scale, 类型为 MLTensorLimits-
用于 scale 操作数的
MLTensorLimits。 bias, 类型为 MLTensorLimits-
用于 bias 操作数的
MLTensorLimits。 output, 类型为 MLTensorLimits-
用于输出操作数的
MLTensorLimits。
MLOpSupportLimits
对于 batchNormalization()
具有以下成员:
batchNormalization, 类型为 MLBatchNormalizationSupportLimits-
运算符
batchNormalization()的支持限制。
batchNormalization(input, mean, variance, options)
方法的步骤为:
-
如果 this 无法构建,则抛出一个 "
InvalidStateError"DOMException。 -
如果使用 this 和 input、mean、 variance、options.
scale(如果其存在)以及 options.bias(如果其存在)中的任一个验证操作数返回 false,则抛出一个TypeError。 -
如果 mean 的shape 不等于 « input 的shape[options.
axis] »,则抛出一个TypeError。 -
如果 variance 的shape 不等于 « input 的shape[options.
axis] »,则抛出一个TypeError。 -
将 options.
epsilon设置为把 options.epsilon转换为 input 的 dataType 的结果。 -
建立图连接:
-
令 operator 为给定 input、mean、variance 和 options 的 "batchNormalization" 运算的一个运算符。
-
令 output 为给定 this 和 input.
[[descriptor]]创建 MLOperand 的结果。 -
将 output.
[[operator]]设置为 operator。 -
将 operator 的输入设置为 input、mean 和 variance。
-
将 operator 的输出设置为 output。
-
-
返回 output。
当输入张量为 "nchw"
布局的 4 维张量时,此运算的行为可以按如下方式使用其他运算进行通用模拟,尽管用户
代理通常具有更高效的实现。当底层平台
不直接支持某项运算时,可以使用此分解作为模板来指导
实现。
function batchNormalization( builder, input, mean, variance, options) { const shape= [ 1 , input. shape[ options. axis], 1 , 1 ]; return builder. add( builder. mul( builder. reshape( options. scale, shape), builder. div( builder. sub( input, builder. reshape( mean, shape)), builder. sqrt( builder. add( builder. reshape( variance, shape), builder. constant( input. dataType, options. epsilon))))), builder. reshape( options. bias, shape)); }
8.9.7. cast
将输入张量中的每个元素转换为目标数据类型。partial interface MLGraphBuilder {MLOperand cast (MLOperand input ,MLOperandDataType dataType ,optional MLOperatorOptions options = {}); };partial dictionary MLOpSupportLimits {MLSingleInputSupportLimits cast ; };
-
input:一个MLOperand。 输入 N 维张量。 -
dataType:一个MLOperandDataType。 目标数据类型。 -
options:一个MLOperatorOptions。 指定运算的可选参数。
| 操作数 | 允许的数据 类型 | 必需的 数据类型 | 允许的秩 | 必需的秩 |
|---|---|---|---|---|
input
| 任意类型 | "float32",
"float16",
"int32",
"int8",
"uint8"
| N | 0 到 5 |
| 输出 | 任意类型 | "float32",
"float16",
"int32",
"int8",
"uint8"
| 与 input
相同
| 0 到 5 |
MLOpSupportLimits
对于 cast()
具有以下成员:
cast, 类型为 MLSingleInputSupportLimits-
运算符
cast()的支持限制。
根据下表,MLOperandDataType
之间的转换在某些情况下已有明确规定,而在其他情况下则为实现定义:
| 目标类型 输入类型 |
"float32",
"float16"
|
"int32",
"uint32",
"int64",
"uint64",
"int8",
"uint8"
|
|---|---|---|
"float32",
"float16"
|
如果在范围内,则取最接近的可表示值。
如果超出范围,则为 +/-Infinity。 |
如果在范围内,则截断。
如果超出范围,则为实现定义。 |
"int32",
"uint32",
"int64",
"uint64",
"int8",
"uint8"
|
如果在范围内,则取最接近的可表示值。
如果超出范围,则为 +/-Infinity。 |
如果在范围内,则保持相同值。
如果超出范围,则将最低 N 位重新解释为目标类型;对于 有符号类型,假定使用二进制补码。 |
注: 例如,将 -1 从 "int8"
转换为 "uint8"
时,规定结果为 255。但将 -1 从 "float32"
转换为 "uint8"
时,则为实现定义。
cast(input, dataType, options)
方法的步骤为:
-
如果 this 无法构建,则抛出一个 "
InvalidStateError"DOMException。 -
建立图连接:
-
令 operator 为给定 dataType 和 options 的 "cast" 运算的一个运算符。
-
令 output 为给定 input 复制 MLOperand 的结果。
-
将 output.
[[operator]]设置为 operator。 -
将 operator 的输入设置为 input。
-
将 operator 的输出设置为 output。
-
-
返回 output。
8.9.8. clamp
按元素将输入张量限制在由最小值和最大值指定的范围内。dictionary :MLClampOptions MLOperatorOptions {MLNumber minValue ;MLNumber maxValue ; };partial interface MLGraphBuilder {MLOperand clamp (MLOperand input ,optional MLClampOptions options = {}); };partial dictionary MLOpSupportLimits {MLSingleInputSupportLimits clamp ; };
MLClampOptions
具有以下成员:
minValue, 类型为 MLNumber-
范围的最小值。如果未指定,则不会对范围的下限 执行限制。
maxValue, 类型为 MLNumber-
范围的最大值。如果未指定,则不会对范围的上限 执行限制。
-
input:一个MLOperand。 输入张量。 -
options:一个可选的MLClampOptions。 运算的可选参数。
| 操作数 | 允许的 数据类型 | 必需的 数据类型 | 允许的秩 | 必需的秩 |
|---|---|---|---|---|
input
| 任意类型 | "float32",
"float16"
| N | 0 到 5 |
| 输出 | 与 input
相同
| "float32",
"float16"
| 与 input
相同
| 0 到 5 |
MLOpSupportLimits
对于 clamp()
具有以下成员:
clamp, 类型为 MLSingleInputSupportLimits-
运算符
clamp()的支持限制。
clamp(input, options) 方法的
步骤为:
-
如果 this 无法构建,则抛出一个 "
InvalidStateError"DOMException。 -
如果已给出 options.
minValue,则令 minValue 为其值, 否则为 Infinity。 -
如果已给出 options.
maxValue,则令 maxValue 为其值, 否则为 -Infinity。 -
建立图连接:
-
令 output 为给定 input 复制 MLOperand 的结果。
-
令 operator 为给定 options 的 "clamp" 运算的一个运算符。
-
将 output.
[[operator]]设置为 operator。 -
将 operator 的输入设置为 input。
-
将 operator 的输出设置为 output。
-
-
返回 output。
此运算的行为可以按如下方式使用其他运算进行通用模拟, 尽管用户代理通常具有更高效的实现。当 底层平台不直接支持某项运算时,可以使用此分解作为 模板来指导实现。
function clamp( builder, input, options) { if ( options. minValue=== undefined ) { if ( options. maxValue=== undefined ) { return input; } else { return builder. min( input, builder. constant( input. dataType, options. maxValue)); } } else { if ( options. maxValue=== undefined ) { return builder. max( input, builder. constant( input. dataType, options. minValue)); } else { return builder. min( builder. max( input, builder. constant( input. dataType, options. minValue)), builder. constant( input. dataType, options. maxValue)); } } }
8.9.9. concat
沿给定轴连接输入张量。partial interface MLGraphBuilder {MLOperand concat (sequence <MLOperand >inputs , [EnforceRange ]unsigned long axis ,optional MLOperatorOptions options = {}); };dictionary {MLConcatSupportLimits MLTensorLimits inputs ;MLTensorLimits output ; };partial dictionary MLOpSupportLimits {MLConcatSupportLimits concat ; };
-
inputs:一个 sequence<MLOperand>。 所有输入张量必须具有 相同的形状,但执行连接的维度大小除外。 -
axis:一个unsigned long标量。输入沿该轴进行连接。其值必须位于范围 [0, N-1] 内,其中 N 是输入张量的秩。 -
options:一个MLOperatorOptions。 指定运算的可选参数。
返回:一个 MLOperand。
沿
axis
连接所有输入后得到的张量。
输出张量具有相同的形状,但所有输入沿其连接的维度
除外。该维度的大小计算为所有输入在相同维度上的大小之和。
| 操作数 | 允许的 数据类型 | 必需的 数据类型 | 允许的秩 | 必需的秩 |
|---|---|---|---|---|
inputs
的
项
| 任意类型 | "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 和 first 的shape 创建 MLOperandDescriptor 的结果。
-
建立图连接:
-
令 output 为给定 this 和 desc 创建 MLOperand 的结果。
-
令 operator 为给定 inputs、axis 和 options 的 "concat" 运算的一个运算符。
-
将 output.
[[operator]]设置为 operator。 -
将 operator 的输入设置为 inputs。
-
将 operator 的输出设置为 output。
-
-
返回 output。
8.9.10. conv2d
给定 4 维输入张量和滤波器张量,计算二维卷积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"
| "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 的shape。
-
根据 options.
inputLayout切换: -
令 filterShape 为 filter 的shape。
-
根据 options.
filterLayout切换:"hwio"-
令 « filterHeight, filterWidth, filterInputChannels, outputChannels » 为 filterShape。
"ohwi"-
令 « outputChannels, filterHeight, filterWidth, filterInputChannels » 为 filterShape。
"ihwo"-
令 « filterInputChannels, filterHeight, filterWidth, outputChannels » 为 filterShape。
"oihw"-
令 « outputChannels, filterInputChannels, filterHeight, filterWidth » 为 filterShape。
-
否则,如果 inputChannels / options.
groups不等于 filterInputChannels,则抛出 一个TypeError。 -
令 « outputHeight, outputWidth » 为给定 inputHeight、inputWidth、 filterHeight、filterWidth、options.
padding、 options.strides和 options.dilations计算 conv2d 输出 大小的结果。 -
将 outputHeight 设置为 floor( outputHeight )。
-
将 outputWidth 设置为 floor( outputWidth )。
-
根据 options.
inputLayout切换: -
令 desc 为给定 input 的 dataType 和 outputShape 创建 MLOperandDescriptor 的结果。
-
-
建立图连接:
-
令 output 为给定 this 和 desc 创建 MLOperand 的结果。
-
令 operator 为给定 options 和 filter 的 "conv2d" 运算的一个运算符。
-
将 output.
[[operator]]设置为 operator。 -
将 operator 的输入设置为 input 和 filter。
-
将 operator 的输出设置为 output。
-
-
返回 output。
8.9.11. convTranspose2d
给定 4 维输入张量和滤波器张量,计算二维转置卷积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。 输入 4 维张量。其逻辑形状 根据inputLayout的值解释。 -
filter: 一个MLOperand。 滤波器 4 维张量。其逻辑形状 根据filterLayout和groups的值解释。 -
options: 一个可选的MLConvTranspose2dOptions。
返回:一个 MLOperand。
包含转置卷积结果的输出 4 维张量。输出形状根据
inputLayout
解释。
更具体地说,除非显式指定 outputSizes,
否则需要 outputPadding
才能按如下方式计算输出张量的空间维度值:
outputSize = (inputSize - 1) * stride + (filterSize - 1) * dilation + 1 - beginningPadding - endingPadding + outputPadding
| 操作数 | 允许的 数据类型 | 必需的 数据类型 | 允许的秩 | 必需的秩 |
|---|---|---|---|---|
input
| "float32",
"float16"
| "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,要计算 convtranspose 输出大小, 执行以下步骤。它们返回一个 数值。
-
令 effectiveFilterSize 为 ( filterSize - 1 ) * dilation + 1。
-
令 outputSize 为 ( inputSize - 1 ) * stride + effectiveFilterSize - beginningPadding - endingPadding。
-
返回 outputSize。
convTranspose2d(input, filter, options)
方法的步骤为:
-
如果 this 无法构建,则抛出一个 "
InvalidStateError"DOMException。 -
如果使用 this 和 input、filter 以及 options.
bias(如果其存在)中的任一个验证操作数返回 false,则抛出一个TypeError。 -
如果 options.
outputPadding不存在,则将其设置为列表 « 0, 0 »。 -
否则,如果 options.
outputPadding的 大小不为 2,则抛出一个TypeError。 -
如果 options.
outputSizes存在,则: -
否则:
-
如果 options.
outputPadding[0] 大于或等于 options.strides[0], 或 options.outputPadding[1] 大于或等于 options.strides[1], 则抛出一个TypeError。
-
-
计算输出形状:
-
令 inputShape 为 input 的shape。
-
根据 options.
inputLayout切换: -
令 filterShape 为 filter 的shape。
-
根据 options.
filterLayout切换: -
令 outputChannels 为 filterOutputChannels * options.
groups。 -
令 calculatedOutputHeight 为给定 inputHeight、filterHeight、 padding[0]、padding[1]、strides[0] 和 dilations[0] 计算 convtranspose 输出大小的结果。
-
令 calculatedOutputWidth 为给定 inputWidth、filterWidth、 padding[2]、padding[3]、strides[1] 和 dilations[1] 计算 convtranspose 输出大小的结果。
-
如果 options.
outputSizes存在,则:-
令 « outputHeight, outputWidth » 为 options.
outputSizes。 -
如果 outputHeight 小于 calculatedOutputHeight,或 outputHeight 大于或等于 calculatedOutputHeight + strides[0],则抛出一个
TypeError。 -
如果 outputWidth 小于 calculatedOutputWidth,或 outputWidth 大于或等于 calculatedOutputWidth + strides[1],则抛出一个
TypeError。
-
-
否则:
-
令 outputHeight 为 calculatedOutputHeight + options.
outputPadding[0]。 -
令 outputWidth 为 calculatedOutputWidth + options.
outputPadding[1]。
-
-
根据 options.
inputLayout切换: -
令 desc 为给定 input 的 dataType 和 outputShape 创建 MLOperandDescriptor 的结果。
-
-
建立图连接:
-
令 output 为给定 this 和 desc 创建 MLOperand 的结果。
-
令 operator 为给定 options 和 filter 的 "convTranspose2d" 运算的一个运算符。
-
将 output.
[[operator]]设置为 operator。 -
将 operator 的输入设置为 input 和 filter。
-
将 operator 的输出设置为 output。
-
-
返回 output。
8.9.12. cumulativeSum
沿给定轴计算一系列值的累加和,可以包含或不包含 当前值。dictionary :MLCumulativeSumOptions MLOperatorOptions {boolean exclusive =false ;boolean reversed =false ; };partial interface MLGraphBuilder {MLOperand cumulativeSum (MLOperand input ,unsigned long axis ,optional MLCumulativeSumOptions options = {}); };partial dictionary MLOpSupportLimits {MLSingleInputSupportLimits cumulativeSum ; };
| 操作数 | 允许的 数据类型 | 必需的 数据类型 | 允许的秩 | 必需的秩 |
|---|---|---|---|---|
input
| "float32",
"float16",
"int32",
"uint32",
"int64",
"uint64"
| "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. 逐元素逻辑运算
逐元素比较输入张量,并针对比较结果返回一个值为 0(false)或 1(true)的"uint8"
张量。对于单操作数运算,返回该运算的逻辑
结果。
对于多操作数运算,该运算将根据 [numpy-broadcasting-rule]进行广播。输入张量必须是双向可广播的。输出张量的秩是输入张量的 最大秩。对于输出张量的 每个维度,其大小是输入张量沿该维度的最大大小。
partial interface MLGraphBuilder {MLOperand equal (MLOperand a ,MLOperand b ,optional MLOperatorOptions options = {});MLOperand notEqual (MLOperand a ,MLOperand b ,optional MLOperatorOptions options = {});MLOperand greater (MLOperand a ,MLOperand b ,optional MLOperatorOptions options = {});MLOperand greaterOrEqual (MLOperand a ,MLOperand b ,optional MLOperatorOptions options = {});MLOperand lesser (MLOperand a ,MLOperand b ,optional MLOperatorOptions options = {});MLOperand lesserOrEqual (MLOperand a ,MLOperand b ,optional MLOperatorOptions options = {});MLOperand logicalNot (MLOperand a ,optional MLOperatorOptions options = {});MLOperand logicalAnd (MLOperand a ,MLOperand b ,optional MLOperatorOptions options = {});MLOperand logicalOr (MLOperand a ,MLOperand b ,optional MLOperatorOptions options = {});MLOperand logicalXor (MLOperand a ,MLOperand b ,optional MLOperatorOptions options = {});MLOperand isNaN (MLOperand a ,optional MLOperatorOptions options = {});MLOperand isInfinite (MLOperand a ,optional MLOperatorOptions options = {}); };dictionary {MLLogicalNotSupportLimits MLTensorLimits a ;MLTensorLimits output ; };partial dictionary MLOpSupportLimits {MLBinarySupportLimits equal ;MLBinarySupportLimits notEqual ;MLBinarySupportLimits greater ;MLBinarySupportLimits greaterOrEqual ;MLBinarySupportLimits lesser ;MLBinarySupportLimits lesserOrEqual ;MLLogicalNotSupportLimits logicalNot ;MLBinarySupportLimits logicalAnd ;MLBinarySupportLimits logicalOr ;MLBinarySupportLimits logicalXor ;MLLogicalNotSupportLimits isNaN ;MLLogicalNotSupportLimits isInfinite ; };
-
a:一个MLOperand。 第一个输入张量。 -
b:一个MLOperand。 指定时为第二个输入张量。 -
options:一个MLOperatorOptions。 指定运算的可选参数。
返回:一个 MLOperand。
包含两个输入张量逐元素比较结果的输出张量。
| 操作数 | 允许的 数据类型 | 必需的 数据类型 | 允许的秩 | 必需的秩 |
|---|---|---|---|---|
a
| 任意类型 | "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"
| N | 0 到 5 |
| 输出 | "uint8"
| "uint8"
| N | 0 到 5 |
MLLogicalNotSupportLimits
具有以下成员:
a, 类型为 MLTensorLimits-
用于 a 操作数的
MLTensorLimits。 output, 类型为 MLTensorLimits-
用于输出操作数的
MLTensorLimits。
MLOpSupportLimits
对逐元素逻辑运算具有以下成员:
equal, 类型为 MLBinarySupportLimits-
运算符
equal()的支持限制。 notEqual, 类型为 MLBinarySupportLimits-
运算符
notEqual()的支持限制。 greater, 类型为 MLBinarySupportLimits-
运算符
greater()的支持限制。 greaterOrEqual, 类型为 MLBinarySupportLimits-
运算符
greaterOrEqual()的支持限制。 lesser, 类型为 MLBinarySupportLimits-
运算符
lesser()的支持限制。 lesserOrEqual, 类型为 MLBinarySupportLimits-
运算符
lesserOrEqual()的支持限制。 logicalNot, 类型为 MLLogicalNotSupportLimits-
运算符
logicalNot()的支持限制。 logicalAnd, 类型为 MLBinarySupportLimits-
运算符
logicalAnd()的支持限制。 logicalOr, 类型为 MLBinarySupportLimits-
运算符
logicalOr()的支持限制。 logicalXor, 类型为 MLBinarySupportLimits-
运算符
logicalXor()的支持限制。 isNaN, 类型为 MLLogicalNotSupportLimits-
运算符
isNaN()的支持限制。 isInfinite, 类型为 MLLogicalNotSupportLimits-
运算符
isInfinite()的支持限制。
-
equal:逐元素比较两个输入张量的值是否相等。
-
notEqual:逐元素比较两个输入张量的值是否不相等。
-
greater:逐元素比较第一个输入张量的值是否较大。
-
greaterOrEqual:逐元素比较第一个输入张量的值是否大于或等于。
-
lesser:逐元素比较第一个输入张量的值是否较小。
-
lesserOrEqual:逐元素比较第一个输入张量的值是否小于或等于。
-
logicalNot:逐元素将输入张量的值取反为 0 或 1。 具体来说,当输入值非零时,将其取反为 0。相反,对于值为零的输入, 将其取反为 1。
-
logicalAnd:逐元素计算两个输入张量的逻辑与, 将任何非零值视为 true,并返回值为 0 或 1 的元素。
-
logicalOr:逐元素计算两个输入张量的逻辑或, 将任何非零值视为 true,并返回值为 0 或 1 的元素。
-
logicalXor:逐元素计算两个输入张量的逻辑异或, 将任何非零值视为 true,并返回值为 0 或 1 的元素。
-
isNaN:逐元素检查输入张量的值是否为无效数值表示 (NaN),对于 NaN 返回 1,否则返回 0。
-
isInfinite:逐元素检查输入张量的值是否为无穷大, 对正无穷或负无穷返回 1,否则返回 0。
greaterOrEqual()
和 lesserOrEqual()
都可以通过运算 logicalNot()、
lesser()
和 greater()
来实现(换言之,builder.greaterOrEqual(a, b) 即
builder.logicalNot(builder.lesser(a, b))),但它们被专门定义以处理 NaN 情况
并出于性能原因避免进行两次比较。
给定字符串
op、MLOperand
a、可选的 MLOperand
b 和 MLOperatorOptions
options,要创建
逐元素逻辑运算,运行以下步骤:
-
断言:op 是 "equal"、"notEqual"、"greater"、 "greaterOrEqual"、"lesser"、"lesserOrEqual"、"logicalNot"、"logicalAnd"、"logicalOr"、 "logicalXor"、"isNaN"、"isInfinite" 之一。
-
如果 this 无法构建,则抛出一个 "
InvalidStateError"DOMException。 -
如果 op 是 "logicalNot"、"logicalAnd"、"logicalOr"、"logicalXor" 之一,则:
-
如果 op 是 "isNaN"、"isInfinite" 之一,则:
-
如果传入了 b,则:
-
否则:
-
令 descriptor 为给定
"uint8"和 outputShape 创建 MLOperandDescriptor 的结果。 -
建立图连接:
-
令 output 为给定 this 和 descriptor 创建 MLOperand 的结果。
-
令 operator 为给定 a、(如果传入了 b)b 和 options 的 op 运算的一个运算符。
-
将 output.
[[operator]]设置为 operator。 -
将 operator 的输入设置为 a 和(如果传入了 b) b。
-
将 operator 的输出设置为 output。
-
-
返回 output。
逐元素逻辑运算算法按如下方式调用创建逐元素逻辑运算 步骤。
equal(a, b, options)
方法的步骤为:
-
令 output 为给定 "equal"、a、b 和 options 创建逐元素逻辑 运算的结果。
-
返回 output。
notEqual(a, b, options)
方法的步骤为:
-
令 output 为给定 "notEqual"、a、b 和 options 创建逐元素逻辑 运算的结果。
-
返回 output。
greater(a, b, options)
方法的步骤为:
-
令 output 为给定 "greater"、a、b 和 options 创建逐元素逻辑 运算的结果。
-
返回 output。
greaterOrEqual(a, b, options)
方法的步骤为:
-
令 output 为给定 "greaterOrEqual"、a、b 和 options 创建逐元素逻辑 运算的结果。
-
返回 output。
lesser(a, b, options)
方法的步骤为:
-
令 output 为给定 "lesser"、a、b 和 options 创建逐元素逻辑 运算的结果。
-
返回 output。
lesserOrEqual(a, b, options)
方法的步骤为:
-
令 output 为给定 "lesserOrEqual"、a、b 和 options 创建逐元素逻辑 运算的结果。
-
返回 output。
logicalNot(a, options)
方法的步骤为:
-
令 output 为给定 "logicalNot"、a 和 options 创建逐元素逻辑 运算的结果。
-
返回 output。
logicalAnd(a, b, options)
方法的步骤为:
-
令 output 为给定 "logicalAnd"、a、b 和 options 创建逐元素逻辑 运算的结果。
-
返回 output。
logicalOr(a, b, options)
方法的步骤为:
-
令 output 为给定 "logicalOr"、a、b 和 options 创建逐元素逻辑 运算的结果。
-
返回 output。
logicalXor(a, b, options)
方法的步骤为:
-
令 output 为给定 "logicalXor"、a、b 和 options 创建逐元素逻辑 运算的结果。
-
返回 output。
isNaN(a, options) 方法的
步骤为:
-
令 output 为给定 "isNaN"、a 和 options 创建逐元素逻辑 运算的结果。
-
返回 output。
isInfinite(a, options)
方法的步骤为:
-
令 output 为给定 "isInfinite"、a 和 options 创建逐元素逻辑 运算的结果。
-
返回 output。
8.9.15. 逐元素一元运算
对输入张量计算逐元素一元运算。partial interface MLGraphBuilder {MLOperand abs (MLOperand input ,optional MLOperatorOptions options = {});MLOperand ceil (MLOperand input ,optional MLOperatorOptions options = {});MLOperand cos (MLOperand input ,optional MLOperatorOptions options = {});MLOperand erf (MLOperand input ,optional MLOperatorOptions options = {});MLOperand exp (MLOperand input ,optional MLOperatorOptions options = {});MLOperand floor (MLOperand input ,optional MLOperatorOptions options = {});MLOperand identity (MLOperand input ,optional MLOperatorOptions options = {});MLOperand log (MLOperand input ,optional MLOperatorOptions options = {});MLOperand neg (MLOperand input ,optional MLOperatorOptions options = {});MLOperand reciprocal (MLOperand input ,optional MLOperatorOptions options = {});MLOperand roundEven (MLOperand input ,optional MLOperatorOptions options = {});MLOperand sin (MLOperand input ,optional MLOperatorOptions options = {});MLOperand sign (MLOperand input ,optional MLOperatorOptions options = {});MLOperand sqrt (MLOperand input ,optional MLOperatorOptions options = {});MLOperand tan (MLOperand input ,optional MLOperatorOptions options = {}); };partial dictionary MLOpSupportLimits {MLSingleInputSupportLimits abs ;MLSingleInputSupportLimits ceil ;MLSingleInputSupportLimits cos ;MLSingleInputSupportLimits erf ;MLSingleInputSupportLimits exp ;MLSingleInputSupportLimits floor ;MLSingleInputSupportLimits identity ;MLSingleInputSupportLimits log ;MLSingleInputSupportLimits neg ;MLSingleInputSupportLimits reciprocal ;MLSingleInputSupportLimits roundEven ;MLSingleInputSupportLimits sin ;MLSingleInputSupportLimits sign ;MLSingleInputSupportLimits sqrt ;MLSingleInputSupportLimits tan ; };
-
input:一个MLOperand。 输入张量。 -
options:一个MLOperatorOptions。 指定运算的可选参数。
返回:一个 MLOperand。
包含输入张量逐元素
一元运算结果的输出张量。输出
张量的形状与输入张量的形状相同。
| 操作数 | 允许的 数据类型 | 必需的 数据类型 | 允许的秩 | 必需的秩 |
|---|---|---|---|---|
input
| "float32",
"float16",
"int64",
"int32",
"int8"
| "float32",
"float16",
"int32"
| N | 0 到 5 |
| 输出 | 与 input
相同
| "float32",
"float16",
"int32"
| 与 input
相同
| 0 到 5 |
| 操作数 | 允许的 数据类型 | 必需的 数据类型 | 允许的秩 | 必需的秩 |
|---|---|---|---|---|
input
| "float32",
"float16"
| "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",
"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) 方法的
步骤为:
ceil(input, options) 方法的
步骤为:
-
令 output 为给定 "ceil"、input、«
"float32"、"float16"» 和 options 创建逐元素一元 运算的结果。 -
返回 output。
cos(input, options) 方法的
步骤为:
-
令 output 为给定 "cos"、input、«
"float32"、"float16"» 和 options 创建逐元素一元 运算的结果。 -
返回 output。
erf(input, options) 方法的
步骤为:
-
令 output 为给定 "erf"、input、«
"float32"、"float16"» 和 options 创建逐元素一元 运算的结果。 -
返回 output。
exp(input, options) 方法的
步骤为:
-
令 output 为给定 "exp"、input、«
"float32"、"float16"» 和 options 创建逐元素一元 运算的结果。 -
返回 output。
floor(input, options) 方法的
步骤为:
-
令 output 为给定 "floor"、input、«
"float32"、"float16"» 和 options 创建逐元素一元 运算的结果。 -
返回 output。
identity(input, options)
方法的步骤为:
-
令 output 为给定 "identity" input 和 options 创建逐元素一元 运算的结果。
-
返回 output。
log(input, options) 方法的
步骤为:
-
令 output 为给定 "log"、input、«
"float32"、"float16"» 和 options 创建逐元素一元 运算的结果。 -
返回 output。
neg(input, options) 方法的
步骤为:
reciprocal(input, options)
方法的步骤为:
-
令 output 为给定 "reciprocal"、input、«
"float32"、"float16"» 和 options 创建逐元素一元 运算的结果。 -
返回 output。
roundEven(input, options)
方法的步骤为:
-
令 output 为给定 "roundEven"、input、«
"float32"、"float16"» 和 options 创建逐元素一元 运算的结果。 -
返回 output。
sin(input, options) 方法的
步骤为:
-
令 output 为给定 "sin"、input、«
"float32"、"float16"» 和 options 创建逐元素一元 运算的结果。 -
返回 output。
sign(input, options) 方法的
步骤为:
sqrt(input, options) 方法的
步骤为:
-
令 output 为给定 "sqrt"、input、«
"float32"、"float16"» 和 options 创建逐元素一元 运算的结果。 -
返回 output。
tan(input, options) 方法的
步骤为:
-
令 output 为给定 "tan"、input、«
"float32"、"float16"» 和 options 创建逐元素一元 运算的结果。 -
返回 output。
sign()
运算的行为可以按如下方式使用其他运算进行通用模拟,尽管用户
代理通常具有更高效的实现。当底层平台
不直接支持某项运算时,可以使用此分解作为模板来指导
实现。
function sign( builder, input, options) { const zero= builder. constant( input. dataType, 0 ); const positiveOne= builder. constant( input. dataType, 1 ); const negativeOne= builder. constant( input. dataType, - 1 ); return builder. where( builder. greater( input, zero), positiveOne, builder. where( builder. lesser( input, zero), negativeOne, zero)); }
8.9.16. dequantizeLinear
使用缩放因子和零点偏置将整数张量反量化为浮点张量,其中output = (input - zeroPoint) * scale。scale
和 zeroPoint
张量可以比 input
张量更小,因为它们是可分块广播的。
partial interface MLGraphBuilder {MLOperand dequantizeLinear (MLOperand input ,MLOperand scale ,MLOperand zeroPoint ,optional MLOperatorOptions options = {}); };dictionary {MLQuantizeDequantizeLinearSupportLimits MLTensorLimits input ;MLTensorLimits scale ;MLTensorLimits zeroPoint ;MLTensorLimits output ; };partial dictionary MLOpSupportLimits {MLQuantizeDequantizeLinearSupportLimits dequantizeLinear ; };
-
input: 一个MLOperand。 输入张量。 -
scale: 一个MLOperand。 在按零点调整后,用于乘以每个输入值的缩放张量。它必须与输入 可分块广播。值 必须为正且非零,否则行为为实现定义(例如正确结果、 错误结果或编译失败)。 -
zeroPoint: 一个MLOperand。 要从每个输入值中减去的零点张量。它与 scale 具有相同的shape。 -
options: 一个MLOperatorOptions。 指定运算的可选参数。
返回:一个 MLOperand。
包含反量化值的输出张量。
| 操作数 | 允许的 数据类型 | 必需的 数据类型 | 允许的秩 | 必需的秩 |
|---|---|---|---|---|
input
| "uint8",
"int8",
"uint32",
"int32"
| "uint8",
"int8"
| N | 0 到 5 |
scale
| "float32",
"float16"
| "float32",
"float16"
| 与 input
相同
| 0 到 5 |
zeroPoint
| 与 input
相同
| "uint8",
"int8",
"int32"
| 与 input
相同
| 0 到 5 |
| 输出 | 与 scale
相同
| "float32",
"float16"
| 与 input
相同
| 0 到 5 |
MLQuantizeDequantizeLinearSupportLimits
具有以下成员:
input, 类型为 MLTensorLimits-
用于 input 操作数的
MLTensorLimits。 scale, 类型为 MLTensorLimits-
用于 scale 操作数的
MLTensorLimits。 zeroPoint, 类型为 MLTensorLimits-
用于 zeroPoint 操作数的
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。 -
如果 zeroPoint 的 dataType 不是其允许的数据类型 之一(根据此表),则抛出一个
TypeError。 -
如果 zeroPoint 的 dataType 不等于 input 的 dataType,则抛出一个
TypeError。 -
如果对 scale 的分块广播 shape 和 input 的shape 返回 false,则抛出一个
TypeError。 -
如果对 zeroPoint 的分块广播 shape 和 input 的shape 返回 false,则抛出一个
TypeError。 -
令 outputDescriptor 为给定 scale 的 创建 MLOperandDescriptor 的结果,给定 scale 的 dataType 和 input 的shape。
-
建立图连接:
-
令 output 为创建 MLOperand的结果,给定 this 和 outputDescriptor。
-
令 operator 为 "dequantizeLinear" 运算的一个运算符,给定 input、scale、zeroPoint 和 options。
-
将 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 张量更小,因为它们会进行分块广播。
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。 要添加到每个重新缩放后的输入值上的零点张量。它与 scale 具有相同的shape。 -
options: 一个MLOperatorOptions。 指定运算的可选参数。
返回:一个 MLOperand。
包含量化值的输出张量。
| 操作数 | 允许的 数据类型 | 必需的 数据类型 | 允许的秩 | 必需的秩 |
|---|---|---|---|---|
input
| "float32",
"float16"
| "float32",
"float16"
| N | 0 到 5 |
scale
| 与 input
相同
| "float32",
"float16"
| 与 input
相同
| 0 到 5 |
zeroPoint
| "uint8",
"int8",
"uint32",
"int32"
| "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。 -
如果 zeroPoint 的 dataType 不是其允许的数据类型 之一(根据此表),则抛出一个
TypeError。 -
如果对 scale 的分块广播 shape 和 input 的shape 返回 false,则抛出一个
TypeError。 -
如果对 zeroPoint 的分块广播 shape 和 input 的shape 返回 false,则抛出一个
TypeError。 -
令 outputDescriptor 为创建 MLOperandDescriptor的结果,给定 zeroPoint 的 dataType 和 input 的shape。
-
建立图连接:
-
令 output 为创建 MLOperand的结果,给定 this 和 outputDescriptor。
-
令 operator 为 "quantizeLinear" 运算的一个运算符,给定 input、scale、zeroPoint 和 options。
-
将 output.
[[operator]]设置为 operator。 -
将 operator 的输入设置为 input。
-
将 operator 的输出设置为 output。
-
-
返回 output。
此运算的行为可以按如下方式使用其他运算进行通用模拟, 尽管用户代理通常具有更高效的实现。当 底层平台不直接支持某项运算时,可以使用此分解作为 模板来指导实现。
function quantizeLinear( builder, input, scale, zeroPoint, options) { // output = clamp(roundEven(input / scale) + zeroPoint, 0, 255) // 注意,blockwiseExpand 在 dequantizeLinear 中定义。 const floatZeroPoint= builder. cast( zeroPoint, scale. dataType); const upsampledScale= blockwiseExpand( builder, scale, input. shape); const upsampledZeroPoint= blockwiseExpand( builder, floatZeroPoint, input. shape); const quantizedInput= builder. roundEven( builder. div( input, upsampledScale)); const zeroPointAdjustedInput= builder. add( quantizedInput, upsampledZeroPoint); const clampedInput= builder. clamp( zeroPointAdjustedInput, { 'minValue' : 0 , 'maxValue' : 255 }); return builder. cast( clampedInput, zeroPoint. dataType); }
8.9.18. elu
对输入张量逐元素计算指数线性单元 函数(ELU)。计算遵循表达式max(0, x) + alpha * (exp(min(0, x)) - 1)。
dictionary :MLEluOptions MLOperatorOptions {double alpha = 1; };partial interface MLGraphBuilder {MLOperand elu (MLOperand input ,optional MLEluOptions options = {}); };partial dictionary MLOpSupportLimits {MLSingleInputSupportLimits elu ; };
MLEluOptions
具有以下成员:
alpha, 类型为 double,默认为1-
一个标量乘数。
-
input:一个MLOperand。 输入张量。 -
options:一个可选的MLEluOptions。 运算的可选参数。
返回:
| 操作数 | 允许的 数据类型 | 必需的 数据类型 | 允许的秩 | 必需的秩 |
|---|---|---|---|---|
input
| "float32",
"float16"
| "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 为 "elu" 运算的一个运算符,给定 options。
-
将 output.
[[operator]]设置为 operator。 -
将 operator 的输入设置为 input。
-
将 operator 的输出设置为 output。
-
-
返回 output。
此运算的行为可以按如下方式使用其他运算进行通用模拟, 尽管用户代理通常具有更高效的实现。当 底层平台不直接支持某项运算时,可以使用此分解作为 模板来指导实现。
function elu( builder, input, options) { return builder. add( builder. max( builder. constant( input. dataType, 0 ), input), builder. mul( builder. constant( input. dataType, options. alpha), builder. sub( builder. exp( builder. min( builder. constant( input. dataType, 0 ), input)), builder. constant( input. dataType, 1 )))); }
8.9.19. expand
根据新形状,将输入张量中大小为 1 的任意维度扩展到更大的大小。该扩展 与 [numpy-broadcasting-rule] 一致。输入张量必须能单向广播到新形状;每个 维度的大小必须为 1,或根据新 形状与相应输出维度的大小匹配。partial interface MLGraphBuilder {MLOperand expand (MLOperand input ,sequence <[EnforceRange ]unsigned long >newShape ,optional MLOperatorOptions options = {}); };partial dictionary MLOpSupportLimits {MLSingleInputSupportLimits expand ; };
-
input:一个MLOperand。 输入张量 -
newShape: sequence<unsigned long>。 输入张量要扩展到的新形状。 -
options:一个MLOperatorOptions。 指定运算的可选参数。
返回:一个 MLOperand。
具有扩展大小形状的张量。
| 操作数 | 允许的 数据类型 | 必需的 数据类型 | 允许的秩 | 必需的秩 |
|---|---|---|---|---|
input
| 任意类型 | "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 为创建 MLOperandDescriptor的结果,给定 input 的 dataType 和 outputShape。
-
建立图连接:
-
令 output 为创建 MLOperand的结果,给定 this 和 outputDescriptor。
-
令 operator 为 "expand" 运算的一个运算符,给定 input、newShape 和 options。
-
将 output.
[[operator]]设置为 operator。 -
将 operator 的输入设置为 input。
-
将 operator 的输出设置为 output。
-
-
返回 output。
8.9.20. gather
根据索引沿某个轴从输入张量中收集值。dictionary :MLGatherOptions MLOperatorOptions { [EnforceRange ]unsigned long axis = 0; };partial interface MLGraphBuilder {MLOperand gather (MLOperand input ,MLOperand indices ,optional MLGatherOptions options = {}); };dictionary {MLGatherSupportLimits MLTensorLimits input ;MLTensorLimits indices ;MLTensorLimits output ; };partial dictionary MLOpSupportLimits {MLGatherSupportLimits gather ; };
MLGatherOptions
具有以下成员:
axis, 类型为 unsigned long,默认为0-
获取所收集值的轴。其值必须位于范围 [0, N-1] 内,其中 N 是输入张量的秩。
indices
参数在构建图时无法为 gather()
限制到允许范围,因为输入直到
执行时才可知。如果底层平台未提供指定的限制行为,实现可以在已编译图中引入 clamp()。
同样,如果底层平台不支持负索引,实现可以在
已编译图中引入运算,将从维度末尾计算的负索引转换为正
索引。
| 操作数 | 允许的 数据类型 | 必需的 数据类型 | 允许的秩 | 必需的秩 |
|---|---|---|---|---|
input
| 任意类型 | "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-
用于 input 操作数的
MLTensorLimits。 indices, 类型为 MLTensorLimits-
用于 indices 操作数的
MLTensorLimits。 output, 类型为 MLTensorLimits-
用于输出操作数的
MLTensorLimits。
MLOpSupportLimits
对于 gather()
具有以下成员:
gather, 类型为 MLGatherSupportLimits-
运算符
gather()的支持限制。
此 gather(input, indices, options)
方法的步骤为:
-
如果 this 无法构建,则抛出一个 "
InvalidStateError"DOMException。 -
如果使用 验证操作数 this 和 input、indices 中任一个返回 false,则抛出一个
TypeError。 -
令 indicesShape 为 indices 的shape。
-
令 axis 为 options.
axis。 -
令 dimCount 为零。
-
令 outputRank 为零。
-
令 outputShape 为空列表。
-
对于每一个 inputShape 中的 size:
-
如果 dimCount 等于 axis,则中断。
-
将 outputShape[dimCount] 设置为 size。
-
将 dimCount 加一。
-
-
将 outputRank 设置为 dimCount。
-
令 dimCount 为零。
-
对于每一个 indicesShape 中的 size:
-
将 outputShape[outputRank + dimCount] 设置为 size。
-
将 dimCount 加一。
-
-
将 outputRank 设置为 outputRank + dimCount。
-
令 dimCount 为零。
-
对于每一个 inputShape 中的 size:
-
如果 dimCount 小于或等于 axis,则继续。
-
将 outputShape[outputRank + dimCount - axis - 1] 设置为 size。
-
将 dimCount 加一。
-
-
令 desc 为创建 MLOperandDescriptor的结果,给定 input 的 dataType 和 outputShape。
-
建立图连接:
-
令 output 为创建 MLOperand的结果,给定 desc。
-
令 operator 为 "gather" 运算的一个运算符,给定 input、indices 和 options。
-
将 output.
[[operator]]设置为 operator。 -
将 operator 的输入设置为 input 和 indices。
-
将 operator 的输出设置为 output。
-
-
返回 output。
gather 在不同切片方案中的工作方式示例。
// 形状为 [4,3] 的 input: // [[ 0, 1, 2], // [10, 11, 12], // [20, 21, 22], // [30, 31, 32]] const input= builder. constant( { dataType: 'float32' , shape: [ 4 , 3 ]}, new Float32Array([ 0 , 1 , 2 , 10 , 11 , 12 , 20 , 21 , 22 , 30 , 31 , 32 ])); // axis = 0(默认) // 形状为 [2] 的 indices: // [3,1] // 形状为 [2,3] 的 output: // [[30, 31, 32], // [10, 11, 12]] const indices1= builder. constant({ dataType: 'uint32' , shape: [ 2 ]}, new Uint32Array([ 3 , 1 ])); const output1= builder. gather( input, indices1); // axis = 1 // 形状为 [3] 的 indices: // [2,1,1] // 形状为 [4,3] 的 output: // [[ 2, 1, 1], // [12, 11, 11], // [22, 21, 21], // [32, 31, 31]] const indices2= builder. constant( { dataType: 'uint32' , shape: [ 3 ]}, new Uint32Array([ 2 , 1 , 1 ])); const output2= builder. gather( input, indices2, { axis: 1 }); // axis = 1 // 形状为 [2,2] 的 indices: // [[0, 1], // [1, 2]] // 形状为 [4,2,2] 的 output: // [[[ 0, 1], [ 1, 2]], // [[10, 11], [11, 12]], // [[20, 21], [21, 22]], // [[30, 31], [31, 32]]] const indices3= builder. constant( { dataType: 'uint32' , shape: [ 2 , 2 ]}, new Uint32Array([ 0 , 1 , 1 , 2 ])); const output3= builder. gather( input, indices3, { axis: 1 });
8.9.21. gatherElements
根据索引沿某个轴从输入张量中收集值。partial interface MLGraphBuilder {MLOperand gatherElements (MLOperand input ,MLOperand indices ,optional MLGatherOptions options = {}); };partial dictionary MLOpSupportLimits {MLGatherSupportLimits gatherElements ; };
| 操作数 | 允许的 数据类型 | 必需的 数据类型 | 允许的秩 | 必需的秩 |
|---|---|---|---|---|
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 的shape 的副本。
-
将 indicesShapeExpected[axis] 设置为 indices 的shape[axis]。
-
如果 indices 的shape 不等于 indicesShapeExpected, 则抛出一个
TypeError。 -
建立图连接:
-
令 output 为给定 input 复制 MLOperand 的结果。
-
令 operator 为 "gatherElements" 运算的一个运算符,给定 input、indices 和 options。
-
将 output.
[[operator]]设置为 operator。 -
将 operator 的输入设置为 input 和 indices。
-
将 operator 的输出设置为 output。
-
-
返回 output。
gatherElements 在不同切片方案中的工作方式示例。
// 形状为 [4,3] 的 input: // [[ 0, 1, 2], // [10, 11, 12], // [20, 21, 22], // [30, 31, 32]] // 形状为 [2,3] 的 indices: // [[3, 1, 1], // [2, 0, 3]] // axis = 0(默认) // 形状为 [2,3] 的 output: // [[30, 11, 12], // [20, 1, 32]] const input1= builder. constant( { dataType: 'float32' , shape: [ 4 , 3 ]}, new Float32Array([ 0 , 1 , 2 , 10 , 11 , 12 , 20 , 21 , 22 , 30 , 31 , 32 ])); const indices1= builder. constant( { dataType: 'uint32' , shape: [ 2 , 3 ]}, new Uint32Array([ 3 , 1 , 1 , 2 , 0 , 3 ])); const output1= builder. gatherElements( input1, indices1); // 形状为 [4,3] 的 input: // [[ 0, 1, 2], // [10, 11, 12], // [20, 21, 22], // [30, 31, 32]] // 形状为 [4,1] 的 indices: // [[2], // [1], // [0], // [2]], // axis = 1 // 形状为 [4,1] 的 output: // [[ 2], // [11], // [20], // [32]] const indices2= builder. constant( { dataType: 'uint32' , shape: [ 4 , 1 ]}, new Uint32Array([ 2 , 1 , 0 , 2 ])); const output2= builder. gatherElements( input1, indices2, { axis: 1 }); // 形状为 [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]]], // axis = 0 // 形状为 [1,2,2] 的 output: // [[[ 0, 201], // [110, 311]]] const inputData3= new Float32Array( [ 0 , 1 , 10 , 11 , 100 , 101 , 110 , 111 , 200 , 201 , 210 , 211 , 300 , 301 , 310 , 311 ]); const input3= builder. constant({ dataType: 'float32' , shape: [ 4 , 2 , 2 ]}, inputData3); const indices3= builder. constant( { dataType: 'uint32' , shape: [ 1 , 2 , 2 ]}, new Uint32Array([ 0 , 2 , 1 , 3 ])); const output3= builder. gatherElements( input3, indices3, { axis: 0 });
8.9.22. gatherND
根据索引收集输入张量的切片。partial interface MLGraphBuilder {MLOperand gatherND (MLOperand input ,MLOperand indices ,optional MLOperatorOptions options = {}); };partial dictionary MLOpSupportLimits {MLGatherSupportLimits gatherND ; };
-
input:一个MLOperand。 从中收集值的输入 N 维张量。 -
indices: 一个MLOperand。 索引数组包含输入张量中的完整坐标,最右侧 维度保存每个坐标的维度数。因此,形状为 [10,1] 的索引张量 保存 10 个单轴索引,而形状为 [4,3] 时保存 4 个三维坐标索引。值 的类型必须为"int32"、"uint32"或"int64", 并且每个值都必须位于 -N(含)到 N(不含)的范围内,其中 N 是 相应输入维度的大小,负索引表示从 相应维度末尾开始索引。 -
options: 一个可选的MLOperatorOptions。 运算的可选参数。
返回:一个 MLOperand。
输出 N 维张量,其秩等于 input
的
秩 + indices
的
秩 - indices
的
shape[-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()的支持限制。
indices
参数在构建图时无法为 gatherND()
限制到允许范围,因为输入直到
执行时才可知。如果底层平台未提供指定的限制行为,实现可以在已编译图中引入 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 为创建 MLOperandDescriptor的结果,给定 input 的 dataType 和 outputShape。
-
建立图连接:
-
令 output 为创建 MLOperand的结果,给定 outputDesc。
-
令 operator 为 "gatherND" 运算的一个运算符,给定 input、indices 和 options。
-
将 output.
[[operator]]设置为 operator。 -
将 operator 的输入设置为 input 和 indices。
-
将 operator 的输出设置为 output。
-
-
返回 output。
gatherND 在不同切片方案中的工作方式示例。
// 形状为 [2,2] 的 input: // [[0, 1], // [2, 3]] // 形状为 [3,2] 的 indices: // [[0, 0], // [1, 1], // [1, 0]] // 形状为 [3] 的 output: // [0, 3, 2] const input1= builder. constant( { dataType: 'float32' , shape: [ 2 , 2 ]}, new Float32Array([ 0 , 1 , 2 , 3 ])); const indices1= builder. constant( { dataType: 'uint32' , shape: [ 3 , 2 ]}, new Uint32Array([ 0 , 0 , 1 , 1 , 1 , 0 ])); const output1= builder. gatherND( input1, indices1); // 形状为 [2,2] 的 input: // [[0, 1], // [2, 3]] // 形状为 [2,1] 的 indices: // [[1], // [0]] // 形状为 [2,2] 的 output: // [[2, 3] <= 来自 input 坐标 [1, *] 的行 [2, 3] // [0, 1]] <= 来自 input 坐标 [0, *] 的行 [0, 1] const indices2= builder. constant( { dataType: 'uint32' , shape: [ 2 , 1 ]}, new Uint32Array([ 1 , 0 ])); const output2= builder. gatherND( input1, indices2); // 形状为 [2,2,2] 的 input: // [[[0, 1], // [2, 3]], // [[4, 5], // [6, 7]]] // 形状为 [2,2] 的 indices: // [[0, 1], // [1, 0]] // 形状为 [2,2] 的 output: // [[2, 3], <= 来自 input 坐标 [0, 1, *] 的行 [2, 3] // [4, 5]] <= 来自 input 坐标 [1, 0, *] 的行 [4, 5] const input2= builder. constant( { dataType: 'float32' , shape: [ 2 , 2 , 2 ]}, new Float32Array([ 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 ])); const indices3= builder. constant( { dataType: 'uint32' , shape: [ 2 , 2 ]}, new Uint32Array([ 0 , 1 , 1 , 0 ])); const output3= builder. gatherND( input2, indices3); // 形状为 [2,2,2] 的 input: // [[[0, 1], // [2, 3]], // [[4, 5], // [6, 7]]] // 形状为 [3,1] 的 indices: // [[1], // [0], // [1]] // 形状为 [3,2,2] 的 output: // [[[4, 5], <= 来自 input 坐标 [1, *, *] 的块 [[4, 5], [6, 7]] // [6, 7]], // [[0, 1], <= 来自 input 坐标 [0, *, *] 的块 [[0, 1], [2, 3]] // [2, 3]], // [[4, 5], <= 来自 input 坐标 [1, *, *] 的块 [[4, 5], [6, 7]] // [6, 7]]] const indices4= builder. constant( { dataType: 'uint32' , shape: [ 3 , 1 ]}, new Uint32Array([ 1 , 0 , 1 ])); const output4= builder. gatherND( input2, indices4); // 形状为 [2,2,2] 的 input: // [[[0, 1], // [2, 3]], // [[4, 5], // [6, 7]]] // 形状为 [5,3] 的 indices: // [[0,0,1], // [0,1,0], // [1,0,0], // [1,1,0], // [1,1,1]] // 形状为 [5] 的 output: // [1,2,4,6,7] const indices5= builder. constant( { dataType: 'uint32' , shape: [ 5 , 3 ]}, new Uint32Array([ 0 , 0 , 1 , 0 , 1 , 0 , 1 , 0 , 0 , 1 , 1 , 0 , 1 , 1 , 1 ])); const output5= builder. gatherND( input2, indices5);
8.9.23. gelu
计算输入张量的高斯 误差线性单元函数(GELU)。计算遵循表达式0.5 * x * (1 + erf(x / sqrt(2)))。
partial interface MLGraphBuilder {MLOperand gelu (MLOperand input ,optional MLOperatorOptions options = {}); };partial dictionary MLOpSupportLimits {MLSingleInputSupportLimits gelu ; };
-
input:一个MLOperand。 输入张量。 -
options:一个MLOperatorOptions。 指定运算的可选参数。
返回:
| 操作数 | 允许的 数据类型 | 必需的 数据类型 | 允许的秩 | 必需的秩 |
|---|---|---|---|---|
input
| "float32",
"float16"
| "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"
| "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。 -
如果 options.
aTranspose为 true,则反转 shapeA 中各项的顺序。 -
如果 options.
bTranspose为 true,则反转 shapeB 中各项的顺序。 -
令 desc 为创建 MLOperandDescriptor的结果,给定 a 的 dataType 和 « shapeA[0], shapeB[1] »。
-
建立图连接:
-
令 output 为创建 MLOperand的结果,给定 this 和 desc。
-
令 operator 为 "gemm" 运算的一个运算符,给定 options。
-
将 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"
| "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 的shape[1]。
-
令 inputSize 为 input 的shape[2]。
-
如果 weight 的shape 不等于 « numDirections, 3 * hiddenSize, inputSize »,则抛出一个
TypeError。 -
如果 recurrentWeight 的shape 不等于 « numDirections, 3 * hiddenSize, hiddenSize »,则抛出一个
TypeError。 -
如果 hiddenSize * 6 不是有效维度,则抛出一个
TypeError。为什么是 hiddenSize * 6?
某些底层平台在单个偏置张量上运算,该张量由bias和recurrentBias拼接而成。 因此,3 * hiddenSize + 3 * hiddenSize 也需要是一个有效 维度。 -
如果 options.
recurrentBias存在,则: -
如果 options.
存在,则: -
如果 options.
activations存在,则:-
令 activations 为 options.
activations的一个克隆。
-
否则:
-
计算输出形状:
-
令 desc0 为创建 MLOperandDescriptor 的结果,给定 input 的 dataType 和 « numDirections, batchSize, hiddenSize »。
-
如果 options.
returnSequence为 true,则:-
令 desc1 为创建 MLOperandDescriptor的结果,给定 input 的 dataType 和 « steps, numDirections, batchSize, hiddenSize »。
-
-
-
建立图连接:
-
令 operator 为 "gru" 运算的一个运算符,给定 weight、recurrentWeight、steps、hiddenSize 和 options。
-
令 output0 为创建 MLOperand的结果,给定 this 和 desc0。
-
如果 options.
returnSequence为 true,则:-
令 output1 为创建 MLOperand的结果,给定 this 和 desc1。
-
令 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"
| "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用于 input 操作数。 weight, 类型为 MLTensorLimits-
MLTensorLimits用于 weight 操作数。 recurrentWeight, 类型为 MLTensorLimits-
MLTensorLimits用于 recurrentWeight 操作数。 hiddenState, 类型为 MLTensorLimits-
MLTensorLimits用于 hiddenState 操作数。 bias, 类型为 MLTensorLimits-
MLTensorLimits用于 bias 操作数。 recurrentBias, 类型为 MLTensorLimits-
MLTensorLimits用于 recurrentBias 操作数。 output, 类型为 MLTensorLimits-
MLTensorLimits用于 output 操作数。
MLOpSupportLimits
对 gruCell()
具有以下成员:
gruCell, 类型为 MLGruCellSupportLimits-
运算符
gruCell()的支持限制。
gruCell(input, weight, recurrentWeight, hiddenState, hiddenSize, options)
方法的步骤为:
-
如果 this 无法构建,则抛出一个 "
InvalidStateError"DOMException。 -
如果使用 验证操作数,给定 this 以及 input、weight、 recurrentWeight、hiddenState、options.
bias(如果它存在)以及 options.recurrentBias(如果它存在)中的任一个返回 false,则抛出一个TypeError。 -
如果 input、 weight、recurrentWeight 或 hiddenState 中任一个的dataType 不是其允许的 数据类型之一(根据此表),则抛出一个
TypeError。 -
如果 input、weight、recurrentWeight 或 hiddenState 中任一个的秩 不是其允许的 秩(根据此表),则抛出一个
TypeError。 -
令 batchSize 为 input 的shape[0]。
-
令 inputSize 为 input 的shape[1]。
-
如果 weight 的shape 不等于 « 3 * hiddenSize, inputSize », 则抛出一个
TypeError。 -
如果 recurrentWeight 的shape 不等于 « 3 * hiddenSize, hiddenSize », 则抛出一个
TypeError。 -
如果 hiddenState 的shape 不等于 « batchSize, hiddenSize »,则 抛出一个
TypeError。 -
如果 hiddenSize * 6 不是有效维度,则抛出一个
TypeError。为什么是 hiddenSize * 6?
某些底层平台在单个偏置张量上运算,该张量由bias和recurrentBias拼接而成。 因此,3 * hiddenSize + 3 * hiddenSize 也需要是一个有效 维度。 -
如果 options.
recurrentBias存在,则: -
如果 options.
activations存在,则:-
令 activations 为 options.
activations的一个克隆。
-
否则:
-
令 desc 为创建 MLOperandDescriptor的结果,给定 input 的 dataType 和 « batchSize, hiddenSize »。
-
建立图连接:
-
令 output 为创建 MLOperand的结果,给定 this 和 desc。
-
令 operator 为 "gruCell" 运算的一个运算符,给定 weight、recurrentWeight、hiddenState、 hiddenSize 和 options。
-
将 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"
| "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 为 "hardSigmoid" 运算的一个运算符,给定 options。
-
将 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"
| "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 为 "hardSwish" 运算的一个运算符,给定 options。
-
将 output.
[[operator]]设置为 operator。 -
将 operator 的输入设置为 input。
-
将 operator 的输出设置为 output。
-
-
返回 output。
此运算的行为可以按如下方式使用其他运算进行通用模拟, 尽管用户代理通常具有更高效的实现。在底层平台 不直接支持某项运算的情况下,可以使用此分解作为 模板来指导实现。
function hardSwish( builder, input, options) { return builder. div( builder. mul( input, builder. max( builder. constant( input. dataType, 0 ), builder. min( builder. constant( input. dataType, 6 ), builder. add( input, builder. constant( input. dataType, 3 ))))), builder. constant( input. dataType, 6 )); }
8.9.29. instanceNormalization
使用[Instance-Normalization]对输入进行归一化。 与batchNormalization()
不同,后者在模型训练期间使用的均值和方差值是在批次
维度中的所有样本上计算的,而实例归一化中使用的均值和方差值则
针对批次中每个独立样本的每个输入特征即时计算。
dictionary :MLInstanceNormalizationOptions MLOperatorOptions {MLOperand scale ;MLOperand bias ;double epsilon = 1e-5;MLInputOperandLayout layout = "nchw"; };partial interface MLGraphBuilder {MLOperand instanceNormalization (MLOperand input ,optional MLInstanceNormalizationOptions options = {}); };dictionary {MLNormalizationSupportLimits MLTensorLimits input ;MLTensorLimits scale ;MLTensorLimits bias ;MLTensorLimits output ; };partial dictionary MLOpSupportLimits {MLNormalizationSupportLimits instanceNormalization ; };
MLInstanceNormalizationOptions
具有以下成员:
scale, 类型为 MLOperand-
缩放值的一维张量,其大小等于 通道数,即输入特征维度的大小。例如,对于一个
input张量,其布局为"nchw"时,该大小等于input的 shape[1]。 bias, 类型为 MLOperand-
偏置值的一维张量,其大小等于 输入特征维度的大小。例如,对于一个
input张量,其布局为"nchw"时,该大小等于input的 shape[1]。 epsilon, 类型为 double,默认为1e-5-
用于防止除以零导致计算错误的一个小值。
layout, 类型为 MLInputOperandLayout,默认为"nchw"-
输入的布局格式。
-
input: 一个MLOperand。 输入四维张量。 -
options: 一个可选的MLInstanceNormalizationOptions。 运算的可选参数。
| 操作数 | 允许的 数据类型 | 必需的 数据类型 | 允许的秩 | 必需的秩 |
|---|---|---|---|---|
input
| "float32",
"float16"
| "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用于 input 操作数。 scale, 类型为 MLTensorLimits-
MLTensorLimits用于 scale 操作数。 bias, 类型为 MLTensorLimits-
MLTensorLimits用于 bias 操作数。 output, 类型为 MLTensorLimits-
MLTensorLimits用于 output 操作数。
MLOpSupportLimits
对 instanceNormalization()
具有以下成员:
instanceNormalization, 类型为 MLNormalizationSupportLimits-
运算符
instanceNormalization()的支持限制。
instanceNormalization(input, options)
方法的步骤为:
当输入张量是 "nchw"
布局的四维张量时,此运算的行为可以按如下方式使用其他运算进行通用模拟,尽管用户
代理通常具有更高效的实现。在底层平台
不直接支持某项运算的情况下,可以使用此分解作为模板来指导
实现。
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"
| "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"
| "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 为 "leakyRelu" 运算的一个运算符,给定 options。
-
将 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"
| "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"
| "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 的shape[1]。
-
令 inputSize 为 input 的shape[2]。
-
如果 weight 的shape 不等于 « numDirections, 4 * hiddenSize, inputSize »,则抛出一个
TypeError。 -
如果 recurrentWeight 的shape 不等于 « numDirections, 4 * hiddenSize, hiddenSize »,则抛出一个
TypeError。 -
如果 hiddenSize * 8 不是有效维度,则抛出一个
TypeError。为什么是 hiddenSize * 8?
某些底层平台在单个偏置张量上运算,该张量由bias和recurrentBias拼接而成。 因此,4 * hiddenSize + 4 * hiddenSize 也需要是一个有效 维度。 -
如果 options.
recurrentBias存在,则: -
如果 options.
peepholeWeight存在,则: -
如果 options.
存在,则: -
如果 options.
initialCellState存在,则: -
如果 options.
activations存在,则:-
令 activations 为 options.
activations的一个克隆。
-
否则:
-
计算输出形状:
-
令 desc 为创建 MLOperandDescriptor 的结果,给定 input 的 dataType 和 « numDirections, batchSize, hiddenSize »。
-
如果 options.
returnSequence为 true,则:-
令 desc2 为创建 MLOperandDescriptor的结果,给定 input 的 dataType 和 « steps, numDirections, batchSize, hiddenSize »。
-
-
-
建立图连接:
-
令 operator 为 "lstm" 运算的一个运算符,给定 weight、recurrentWeight、steps、hiddenSize 和 options。
-
令 output0 为创建 MLOperand的结果,给定 this 和 desc。
-
令 output1 为创建 MLOperand的结果,给定 this 和 desc。
-
如果 options.
returnSequence为 true,则:-
令 output2 为创建 MLOperand的结果,给定 this 和 desc2。
-
令 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"
| "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 的shape[0]。
-
令 inputSize 为 input 的shape[1]。
-
如果 weight 的shape 不等于 « 4 * hiddenSize, inputSize », 则抛出一个
TypeError。 -
如果 recurrentWeight 的shape 不等于 « 4 * hiddenSize, hiddenSize », 则抛出一个
TypeError。 -
如果 hiddenState 的shape 不等于 « batchSize, hiddenSize »,则 抛出一个
TypeError。 -
如果 cellState 的shape 不等于 « batchSize, hiddenSize »,则 抛出一个
TypeError。 -
如果 hiddenSize * 8 不是有效维度,则抛出一个
TypeError。为什么是 hiddenSize * 8?
某些底层平台在单个偏置张量上运算,该张量由bias和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"
| "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。 -
计算输出形状:
-
令 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 为创建 MLOperandDescriptor 的结果,给定 a 的dataType 和 outputShape。
-
建立图连接:
-
令 output 为创建一个 MLOperand 的结果,给定 this 和 desc。
-
令 operator 为一个运算符,用于 "matmul" 运算,给定 options。
-
将 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。 -
令 desc 为 input.
[[descriptor]]的副本。 -
令 outputShape 为 input 的shape 的副本。
-
对于每一个 index,位于范围 0 到 outputShape 的秩, 不含上界:
-
根据 options.
mode进行切换:"constant"-
不执行任何操作。
"edge"-
不执行任何操作。
"reflection"
-
向 outputShape[index] 加上 beginningPadding[index] 的值。
-
向 outputShape[index] 加上 endingPadding[index] 的值。
-
-
将 desc.
shape设置为 outputShape。 -
建立图连接:
-
令 output 为创建一个 MLOperand 的结果,给定 this 和 desc。
-
令 operator 为一个运算符,用于 "padding" 运算,给定 beginningPadding、endingPadding 和 options。
-
将 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"
| "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 »。 -
令 desc 为 input.
[[descriptor]]的副本。 -
计算输出形状:
-
令 « windowHeight, windowWidth » 为 options.
windowDimensions。 -
令 « calculatedOutputHeight, calculatedOutputWidth » 为 计算 conv2d 输出 大小的结果,给定 inputHeight、inputWidth、 windowHeight、windowWidth、options.
padding、 options.strides和 options.dilations。 -
如果 options.
outputSizes存在,则:-
令 « outputHeight, outputWidth » 为 options.
outputSizes。 -
如果既不是 outputHeight 等于 floor( calculatedOutputHeight ) 且 outputWidth 等于 floor( calculatedOutputWidth ),也不是 outputHeight 等于 ceil( calculatedOutputHeight ) 且 outputWidth 等于 ceil( calculatedOutputWidth ),则抛出一个
TypeError。
-
-
否则:
-
令 « outputHeight, outputWidth » 为 « calculatedOutputHeight, calculatedOutputWidth »。
-
根据 options.
outputShapeRounding进行切换:
-
-
根据 options.
layout进行切换: -
将 desc.
shape设置为 outputShape。
-
-
建立图连接:
-
令 output 为创建一个 MLOperand 的结果,给定 this 和 desc。
-
令 operator 为一个运算符,用于 op 运算,给定 options。
-
将 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",
"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 为创建 MLOperandDescriptor 的结果,给定 input 的dataType 和 outputShape。
-
建立图连接:
-
令 output 为创建一个 MLOperand 的结果,给定 this 和 descriptor。
-
令 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",
"int32",
"uint32",
"int64",
"uint64"
| "float32",
"float16",
"int32"
| N | 0 到 5 |
| 输出 | 与……相同 input
| "float32",
"float16",
"int32"
| N | 0 到 5 |
| 操作数 | 允许的 数据类型 | 必需的 数据类型 | 允许的秩 | 必需的秩 |
|---|---|---|---|---|
input
| "float32",
"float16"
| "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",
"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 的shape、options.
axes(如果它存在)和 options.keepDimensions。 如果返回失败,则抛出一个TypeError。 -
令 desc 为创建 MLOperandDescriptor的结果,给定 input 的dataType 和 outputShape。
-
建立图连接:
-
令 output 为创建一个 MLOperand的结果,给定 this 和 desc。
-
令 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) { return builder. log( builder. reduceSum( builder. exp( input), options)); } function reduceSumSquare( builder, input, options) { return builder. reduceSum( builder. pow( input, 2 ), options); }
keepDimensions
的选项。这不会影响底层张量数据,只会影响形状。例如,如果输入形状
为 [2, 3, 4],轴为 1,并且 keepDimensions
为 true,则预期输出形状为 [2, 1 ,4]。如果底层平台从不保留归约
维度,则会生成形状为 [2, 4] 的输出。实现可以引入一个无操作的
reshape,将其变为 [2, 1, 4]。如果 keepDimensions
为 false,但底层平台始终保留归约维度,也可以引入类似的无操作 reshape。
8.9.40. relu
计算输入张量的线性整流函数。partial interface MLGraphBuilder {MLOperand relu (MLOperand input ,optional MLOperatorOptions options = {}); };partial dictionary MLOpSupportLimits {MLSingleInputSupportLimits relu ; };
-
input:一个MLOperand。 输入张量。 -
options:一个MLOperatorOptions。 指定运算的可选参数。
返回:
| 操作数 | 允许的 数据类型 | 必需的 数据类型 | 允许的秩 | 必需的秩 |
|---|---|---|---|---|
input
| "float32",
"float16",
"int64",
"int32",
"int8"
| "float32",
"float16"
| N | 0 到 5 |
| 输出 | 与……相同 input
| "float32",
"float16"
| 与……相同 input
| 0 到 5 |
MLOpSupportLimits
对 relu()
具有以下成员:
relu, 类型为 MLSingleInputSupportLimits-
运算符
relu()的支持限制。
relu(input, options) 方法的
步骤为:
-
如果 this 无法构建,则抛出一个 "
InvalidStateError"DOMException。 -
建立图连接:
-
令 output 为复制 MLOperand的结果,给定 input。
-
令 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",
"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 为创建 MLOperandDescriptor的结果, 给定 inputDescriptor.
dataType和 outputShape。
-
-
建立图连接:
-
令 output 为创建一个 MLOperand的结果,给定 this 和 desc。
-
令 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 的shape 中所有项的乘积。 空维度产生的 inputElementCount 为 1。
-
令 desc 为 input.
[[descriptor]]的副本。 -
将 desc.
shape设置为 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 为复制 MLOperand的结果,给定 input。
-
令 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。 -
令 axis 为 options.
axis。 -
令 indicesShapeExpected 为 input 的shape 的副本。
-
将 indicesShapeExpected[axis] 设置为 indices 的shape[axis]。
-
建立图连接:
-
令 output 为复制 MLOperand的结果,给定 input。
-
令 operator 为一个运算符,用于 "scatterElements" 运算,给定 input、indices、updates 和 options。
-
将 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。 -
令 indicesShape 为 indices 的shape,并令 indicesRank 为 indices 的秩。
-
令 indexableSize 为 indicesRank - 1。
-
令 coordinateSize 为 indicesShape[indexableSize]。
-
令 expectedUpdatesShape 为一个空列表。
-
对于每一个 index,位于范围 0 到 indexableSize 内(不含上界):
-
附加 indicesShape[index] 到 expectedUpdatesShape。
-
-
对于每一个 index,位于范围 coordinateSize 到 inputRank 内(不含上界):
-
附加 inputShape[index] 到 expectedUpdatesShape。
-
-
令 outputShape 为 input 的shape 的副本。
-
令 outputDesc 为创建 MLOperandDescriptor的结果,给定 input 的dataType 和 outputShape。
-
建立图连接:
-
令 output 为创建一个 MLOperand的结果,给定 outputDesc。
-
令 operator 为一个运算符,用于 "scatterND" 运算,给定 input、indices、updates 和 options。
-
将 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"
| "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[index] 非空,则令 stride 为其值,否则为 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"
| "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"
| "float32",
"float16"
| N | 0 到 5 |
| 输出 | 与……相同 input
| "float32",
"float16"
| 与……相同 input
| 0 到 5 |
MLOpSupportLimits
对 softplus()
具有以下成员:
softplus, 类型为 MLSingleInputSupportLimits-
运算符
softplus()的支持限制。
此 softplus(input, options)
方法的步骤为:
-
如果 this 无法构建,则抛出一个 "
InvalidStateError"DOMException。 -
建立图连接:
-
令 output 为复制 MLOperand的结果,给定 input。
-
令 operator 为一个运算符,用于 "softplus" 运算和 options。
-
将 output.
[[operator]]设置为 operator。 -
将 operator 的输入设置为 input。
-
将 operator 的输出设置为 output。
-
-
返回 output。
此运算的行为可以按如下方式使用其他运算进行通用模拟, 尽管用户代理通常具有更高效的实现。在底层 平台不直接支持某项运算的情况下,可以使用此分解作为 模板来指导实现。
function softplus( builder, input) { return builder. log( builder. add( builder. exp( input), builder. constant( input. dataType, 1 ))); }
8.9.50. softsign
计算输入张量的 softsign 函数。 计算遵循表达式x / (1 + |x|)。
partial interface MLGraphBuilder {MLOperand softsign (MLOperand input ,optional MLOperatorOptions options = {}); };partial dictionary MLOpSupportLimits {MLSingleInputSupportLimits softsign ; };
此运算的行为可以按如下方式使用其他运算进行通用模拟, 尽管用户代理通常具有更高效的实现。在底层 平台不直接支持某项运算的情况下,可以使用此分解作为 模板来指导实现。
function softsign( builder, input) { return builder. div( input, builder. add( builder. constant( input. dataType, 1 ), builder. abs( input))); }
-
input:一个MLOperand。 输入张量。 -
options:一个MLOperatorOptions。 指定运算的可选参数。
返回:
| 操作数 | 允许的 数据类型 | 必需的 数据类型 | 允许的秩 | 必需的秩 |
|---|---|---|---|---|
input
| "float32",
"float16"
| "float32",
"float16"
| N | 0 到 5 |
| 输出 | 与……相同 input
| "float32",
"float16"
| 与……相同 input
| 0 到 5 |
MLOpSupportLimits
对 softsign()
具有以下成员:
softsign, 类型为 MLSingleInputSupportLimits-
运算符
softsign()的支持限制。
此 softsign(input, options)
方法的步骤为:
-
如果 this 无法构建,则抛出一个 "
InvalidStateError"DOMException。 -
建立图连接:
-
令 output 为复制 MLOperand的结果,给定 input。
-
令 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 是一个sequence<
unsigned long>, 则: -
建立图连接:
-
令 operator 为一个运算符,用于 "split" 运算,给定 splits 和 options。
-
令 outputs 为一个新的列表。
-
对于每一个 index,位于 范围 0 到 splitCount 内(不含上界):
-
令 operand 为复制 MLOperand的结果,给定 input。
-
如果 splits 是一个
unsigned long, 则令 newDimension 为 operand 的shape[axis] / splits。 -
否则,令 newDimension 为 splits[index]。
-
将 operand 的shape[axis] 设置为 newDimension。
-
将 operand.
[[operator]]设置为 operator。 -
附加 operand 到 outputs。
-
-
将 operator 的输入设置为 input。
-
将 operator 的输出设置为 outputs。
-
-
返回 outputs。
此运算的行为可以按如下方式使用其他运算进行通用模拟, 尽管用户代理通常具有更高效的实现。在底层 平台不直接支持某项运算的情况下,可以使用此分解作为 模板来指导实现。
function split( builder, input, splits, options) { // 此示例展示 splits 参数为数组的情况。 const outputs= []; const inputShape= input. shape; const inputRank= inputShape. length; let starts= Array( inputRank). fill( 0 ); let sizes= inputShape; let start= 0 ; for ( const sizeof splits) { starts[ options. axis] = start; sizes[ options. axis] = size; outputs. push( builder. slice( input, starts, sizes)); start+= size; } return outputs; }
8.9.52. tanh
计算输入张量的双曲正切函数。 计算遵循表达式(exp(2 * x) - 1) / (exp(2 * x) + 1)。
partial interface MLGraphBuilder {MLOperand tanh (MLOperand input ,optional MLOperatorOptions options = {}); };partial dictionary MLOpSupportLimits {MLSingleInputSupportLimits tanh ; };
-
input:一个MLOperand。 输入张量。 -
options:一个MLOperatorOptions。 指定运算的可选参数。
返回:
| 操作数 | 允许的 数据类型 | 必需的 数据类型 | 允许的秩 | 必需的秩 |
|---|---|---|---|---|
input
| "float32",
"float16"
| "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) { return builder. div( builder. sub( builder. exp( builder. mul( builder. constant( input. dataType, 2 ), input)), builder. constant( input. dataType, 1 )), builder. add( builder. exp( builder. mul( builder. constant( input. dataType, 2 ), input)), builder. constant( input. dataType, 1 ))); }
8.9.53. tile
沿每个维度将张量重复给定次数。partial interface MLGraphBuilder {MLOperand tile (MLOperand input ,sequence <unsigned long >repetitions ,optional MLOperatorOptions options = {}); };partial dictionary MLOpSupportLimits {MLSingleInputSupportLimits tile ; };
-
input:一个MLOperand。 输入 N 维张量。 -
repetitions: 每个维度重复该维度的次数。其大小必须与input的 秩相匹配,对于 应保持相同大小的任何轴使用 1。 -
options: 一个可选的MLOperatorOptions。 运算的可选参数。
返回:一个 MLOperand。
反转后的 N 维张量。
| 操作数 | 允许的 数据类型 | 必需的 数据类型 | 允许的秩 | 必需的秩 |
|---|---|---|---|---|
input
| 任意 | "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 的shape 的副本。
-
对于每一个 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 的shape所有索引的反转序列。 -
否则,如果 options.
permutation存在: -
建立图连接:
-
令 output 为复制 MLOperand的结果,给定 input。
-
令 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。 -
令 outputShape 为双向广播 trueValue 的shape 和 falseValue 的shape 的结果。
-
令 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, 32)。
"float16"-
返回 ConvertToFloat(x, 16)。
"int64"-
返回 ConvertToInt(x, 64, "signed")。
"uint64"-
返回 ConvertToInt(x, 64, "unsigned")。
"int32"-
返回 ConvertToInt(x, 32, "signed")。
"uint32"-
返回 ConvertToInt(x, 32, "signed")。
"int8"-
返回 ConvertToInt(x, 8, "signed")。
"uint8"-
返回 ConvertToInt(x, 8, "unsigned")。
注:转换的输入是一个范围和精度均不受限制的抽象数值, 包括特殊值 Infinity、-Infinity 和 NaN。输出也是一个抽象数值,但 可以由指定类型精确表示。
-
如果 x 为 NaN,则返回 NaN。
-
根据 bitLength 进行切换:
- 32
-
-
令 upperBound 为 2128。
-
令 lowerBound 为 -2128。
-
令 S 为 [IEEE-754-2019] binary32 浮点值(-0 除外)的集合,并加入特殊值 upperBound 和 lowerBound。
-
- 16
-
-
令 upperBound 为 216。
-
令 lowerBound 为 -216。
-
令 S 为 [IEEE-754-2019] binary16 浮点值(-0 除外)的集合,并加入特殊值 upperBound 和 lowerBound。
-
-
令 y 为 S 中最接近 x 的数值,如果有两个同样接近的值,则选择 有效数字为偶数的数值。为此,两个 特殊值 lowerBound 和 upperBound 被视为具有偶数 有效数字。
-
如果 y 是 upperBound,则返回 +Infinity。
-
如果 y 是 lowerBound,则返回 -Infinity。
-
如果 y 是 +0 且 x 为负数,则返回 -0。
-
返回 y。
注:这基于 [WEBIDL] 中的定义,但 扩展为涵盖 16 位浮点值。
-
如果 signedness 是 "unsigned",则:
-
令 lowerBound 为 0。
-
令 upperBound 为 2bitLength - 1。
-
-
否则:
-
令 lowerBound 为 -(2bitLength - 1)。
-
令 upperBound 为 2bitLength - 1 - 1。
-
-
如果 x 是 -0,则将 x 设置为 +0。
-
如果 x 是 NaN,则返回 +0。
-
将 x 设置为 min(max(x, lowerBound), upperBound)。
-
将 x 舍入到最近的整数,如果正好位于两个整数中间,则选择偶数整数, 并选择 +0 而不是 -0。
-
返回 x。
注:这基于 [WEBIDL] 中的定义,但有以下 区别:不会特殊处理 64 位整数,输入 x 是一个抽象 数值,并且始终执行限制。
9.3. 其他
当 [INFRA] 中提供 定义后移除此内容。[whatwg/infra 问题 #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
的兼容性
MLOperandDataType
| ArrayBufferView
|
|---|---|
float32
| Float32Array
|
float16
| Float16Array
|
int64
| BigInt64Array
|
uint64
| BigUint64Array
|
int32
| Int32Array
|
uint32
| Uint32Array
|
int8
| Int8Array
|
uint8
| Uint8Array
|
Float16Array
处于 ECMA 第 3 阶段,表明其设计已完成。
希望在原生实现之前启用此类型的实现者可以通过 Uint16Array
传递原始
位来模拟该类型。
[问题 webnn#373]
13. 致谢
本规范遵循 Android Neural Networks API C API 的概念。
感谢 Tomoyuki Shimizu、Ningxin Hu、Zhiqiang Yu 和 Belem Zhang 提供 用例。
感谢 Nikhil Thorat、Daniel Smilkov、Ganesan Ramalingam、Rafael Cintron 和 Benjamin Poulain 对 API 规范所做的贡献。
感谢 Sangwhan Moon 和 W3C Technical Architecture Group 从 Web 架构适配、设计一致性和开发者易用性方面审查本规范。
感谢 Zoltan Kis 添加算法,并使浏览本规范成为一种愉悦的体验。 感谢 Joshua Bell 使本规范与现代编辑惯例保持一致。感谢 Ningxin Hu、Lisha Guo、Shiyi Zou、Mingming Xu、Junwei Fu、Bruce Dai 和 Bin Miao 的细致审查和意见。
感谢 W3C Privacy Interest Group 提供隐私和安全审查及反馈。
感谢 Alex Gough 和 Chrome Security 团队提供安全审查和问题。
感谢 Michal Karzynski 分享来自 ONNX 的实用指南和经验。
感谢 Kaustubha Govind 和 Chrome 隐私审查人员提供反馈和隐私方面的考虑。
感谢 Jiewei Qian 提供 Chromium 实现审查和反馈。
感谢 Dwayne Robinson、Joshua Lochner 和 Wanming Lin 在研究并提供 transformer 支持建议方面所做的工作。还要特别感谢 Dwayne 和 Wanming 对 运算符合性和 web-platform-tests 实现提供审查。
感谢 Feng Dai 持续贡献,使 web-platform-tests 与 规范同步发展。
感谢 Fuqiao Xue 和 W3C Internationalization Activity 提供审查和建议。
14. 变更
本节为非规范性内容。
本节按照变更类别记录自上一次主要发布以来对本规范所做的变更。
候选推荐快照 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)