MLGraphBuilder
实验性: 这是一项实验性技术。在生产环境中使用前,请仔细检查浏览器兼容性表格。
Web 神经网络(WebNN)API 的 MLGraphBuilder 接口用于构建计算图。它保存图构建会话的状态:你声明输入和常量,在得到的 MLOperand 对象上组合操作,最后使用 build() 将图编译为 MLGraph。
图的构建是同步的,并会立即验证每个操作:形状和数据类型会随构建过程计算出来,无效的参数会在出错的调用处抛出 TypeError。只有 build() 是异步的。
此功能仅在安全上下文 (HTTPS 或 localhost)中可用,并且在主线程和 Web Worker 中均可用。
Web IDL
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);
};各种操作(add()、conv2d()、softmax() 等)被定义为 MLGraphBuilder 的部分接口,并记录在 MLGraphBuilder 操作中。
构造函数
MLGraphBuilder()
创建与 MLContext 关联的新 MLGraphBuilder。
语法
new MLGraphBuilder(context)参数
-
context图将为其编译并在其上执行的
MLContext。
异常
-
SecurityErrorDOMException如果文档不被允许使用
webnn权限策略特性,则抛出。 -
InvalidStateErrorDOMException如果
context已丢失,则抛出。
实例属性
无。
实例方法
| 方法 | 描述 |
|---|---|
input() | 创建具名的输入操作数。 |
constant() | 根据缓冲区、标量值或常量 MLTensor 创建常量操作数。 |
build() | 编译图,直到给定的输出操作数。 |
| 操作 | 超过 90 个方法,例如 add()、conv2d()、matmul() 和 softmax(),用于创建操作。 |
除 build() 之外的所有方法,如果构建器无法构建(即已对其调用过 build(),或其上下文已丢失),都会抛出 InvalidStateError DOMException。
input()
input() 方法创建表示图输入的具名 MLOperand。执行图时,必须在 MLContext.dispatch() 的 inputs 参数中提供具有相同名称、数据类型和形状的张量。
语法
input(name, descriptor)参数
-
name为输入命名的非空字符串。名称在构建器内必须唯一。
-
descriptor给出输入的
dataType和shape的MLOperandDescriptor。
返回值
一个 MLOperand。
异常
-
TypeError如果
name为空或已被其他输入使用,或者descriptor的形状无效,则抛出。 -
InvalidStateErrorDOMException如果构建器无法构建,则抛出。
图可以完全没有输入,例如仅对常量进行变换的图。
constant()
constant() 方法创建一个 MLOperand,其值在构建图时固定,通常是模型权重。常量使实现能够在 build() 期间以设备友好的格式预处理并缓存数据(即所谓的权重预处理),从而加快后续执行。
语法
constant(descriptor, buffer)
constant(dataType, value)
constant(tensor)参数
-
descriptor给出常量的
dataType和shape的MLOperandDescriptor。 -
buffer带有初始数据的
ArrayBuffer、SharedArrayBuffer或ArrayBufferView。其字节长度必须等于描述符的字节长度,并且类型化数组必须与数据类型匹配,或者是Uint8Array(参见缓冲区要求)。数据会在调用constant()时被复制,因此缓冲区可以立即重用。 -
dataType用于标量(0 维)常量的
MLOperandDataType。 -
value带有标量值的
MLNumber(number或bigint)。它会被转换为dataType;超出该类型范围的值会被截断。 -
tensor在同一上下文中使用
MLContext.createConstantTensor()创建的常量MLTensor。该操作数使用张量的数据类型和形状。张量可以在build()完成后销毁。
返回值
一个 MLOperand。
异常
-
TypeError如果
descriptor的形状无效或buffer与其不匹配,则抛出;对于constant(tensor),如果张量属于不同的上下文、已被销毁或不是常量张量,也会抛出。 -
InvalidStateErrorDOMException如果构建器无法构建,则抛出。
build()
build() 方法将图(从给定的输出操作数回溯到它们所依赖的输入和常量)编译为 MLGraph。输出不依赖的操作数会被忽略。
MLGraphBuilder 只能构建一次。调用 build() 之后,构建器不能再创建操作数,也不能再次构建;请为每个图创建一个新的构建器。
语法
build(outputs)参数
-
outputs一个对象(
MLNamedOperands),将每个输出名称映射到由此构建器创建的MLOperand。执行图时,必须在MLContext.dispatch()的outputs参数中为这些名称各提供一个张量。
返回值
一个 Promise,兑现为 MLGraph。
异常
返回的 Promise 会以如下异常被拒绝:
-
TypeErroroutputs为空;某个输出名称为空;某个操作数由不同的构建器创建;某个操作数是输入或常量操作数;或者某个常量操作数由一个此后已被销毁的张量创建。 -
InvalidStateErrorDOMException构建器无法构建(已构建过,或上下文已丢失),或者上下文在编译期间丢失。
-
OperationErrorDOMException底层平台无法编译该图。
直接将输入或常量操作数作为图的输出会被拒绝,因为这通常意味着出现了错误。如果确实需要,请使用
identity()包装该操作数。
操作
操作是接受一个或多个 MLOperand 对象(通常还有一个派生自 MLOperatorOptions 的选项字典)并返回新的 MLOperand 或操作数序列的方法。完整详情请参见 MLGraphBuilder 操作。
| 类别 | 操作 |
|---|---|
| 逐元素二元 | add(), sub(), mul(), div(), max(), min(), pow() |
| 比较与逻辑 | equal(), notEqual(), greater(), greaterOrEqual(), lesser(), lesserOrEqual(), logicalNot(), logicalAnd(), logicalOr(), logicalXor(), isNaN(), isInfinite() |
| 逐元素一元 | abs(), ceil(), cos(), erf(), exp(), floor(), identity(), log(), neg(), reciprocal(), roundEven(), sign(), sin(), sqrt(), tan() |
| 激活函数 | elu(), gelu(), hardSigmoid(), hardSwish(), leakyRelu(), linear(), prelu(), relu(), sigmoid(), softmax(), softplus(), softsign(), tanh() |
| 卷积 | conv2d(), convTranspose2d() |
| 池化 | averagePool2d(), l2Pool2d(), maxPool2d() |
| 归一化 | batchNormalization(), instanceNormalization(), layerNormalization() |
| 矩阵 | gemm(), matmul(), triangular() |
| 归约 | argMax(), argMin(), cumulativeSum(), reduceL1(), reduceL2(), reduceLogSum(), reduceLogSumExp(), reduceMax(), reduceMean(), reduceMin(), reduceProduct(), reduceSum(), reduceSumSquare() |
| 形状与数据移动 | cast(), clamp(), concat(), expand(), pad(), reshape(), reverse(), slice(), split(), tile(), transpose() |
| 聚集与分散 | gather(), gatherElements(), gatherND(), scatterElements(), scatterND(), where() |
| 量化 | dequantizeLinear(), quantizeLinear() |
| 循环网络 | gru(), gruCell(), lstm(), lstmCell() |
| 重采样 | resample2d() |
示例
构建一个简单的图
const context = await navigator.ml.createContext();
const builder = new MLGraphBuilder(context);
const a = builder.input('a', { dataType: 'float32', shape: [3, 4] });
const b = builder.input('b', { dataType: 'float32', shape: [4, 3] });
const c = builder.matmul(a, b);
console.log(c.shape); // [3, 3]
const graph = await builder.build({ c });使用三种常量
const builder = new MLGraphBuilder(context);
const x = builder.input('x', { dataType: 'float32', shape: [2, 2] });
// 1. 来自缓冲区。
const w = builder.constant({ dataType: 'float32', shape: [2, 2] },
new Float32Array([1, 2, 3, 4]));
// 2. 标量;与其他操作数组合时会进行广播。
const half = builder.constant('float32', 0.5);
// 3. 来自常量 MLTensor,例如由多个图共享的权重。
const biasTensor = await context.createConstantTensor(
{ dataType: 'float32', shape: [2] }, new Float32Array([0.1, 0.2]));
const bias = builder.constant(biasTensor);
const y = builder.add(builder.mul(builder.matmul(x, w), half), bias);
const graph = await builder.build({ y });一个小型卷积块
const builder = new MLGraphBuilder(context);
const input = builder.input('input', { dataType: 'float32', shape: [1, 3, 32, 32] }); // NCHW
const filter = builder.constant({ dataType: 'float32', shape: [16, 3, 3, 3] }, filterData); // OIHW
const bias = builder.constant({ dataType: 'float32', shape: [16] }, biasData);
let x = builder.conv2d(input, filter, { padding: [1, 1, 1, 1], bias });
x = builder.relu(x);
x = builder.maxPool2d(x, { windowDimensions: [2, 2], strides: [2, 2] });
console.log(x.shape); // [1, 16, 16, 16]
const graph = await builder.build({ output: x });处理构建错误
const builder = new MLGraphBuilder(context);
const x = builder.input('x', { dataType: 'float32', shape: [4] });
try {
await builder.build({ x }); // 被拒绝:输入不能作为图的输出。
} catch (e) {
console.log(e.name); // "TypeError"
}
// 改为使用 identity() 包装该操作数(使用新的构建器)。
const builder2 = new MLGraphBuilder(context);
const x2 = builder2.input('x', { dataType: 'float32', shape: [4] });
const graph = await builder2.build({ y: builder2.identity(x2) });规范
| 规范 | 状态 |
|---|---|
Web 神经网络 API — MLGraphBuilder 接口 | 候选推荐草案 |
最新的编辑草案可在 webmachinelearning.github.io/webnn 获取。
浏览器兼容性
WebNN 正在积极开发中,不同浏览器、操作系统和硬件的支持情况各不相同。
constant(tensor)是最近新增的,可能尚未实现。
参见 浏览器兼容性:WebNN API 以及 Windows ML、LiteRT 和 Core ML 各后端的算子表格。