|
|
|
|
Quelle ort.webgpu-dev.mjs
Sprache: unbekannt
|
|
Spracherkennung für: .mjs vermutete Sprache: Unknown {[0] [0] [0]} [Methode: Schwerpunktbildung, einfache Gewichte, sechs Dimensionen]
/*!
* ONNX Runtime Web v1.20.1
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License.
*/
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy != = "undefined" ? new Proxy(x, {
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
}) : x)(function(x) {
if (typeof require !== "undefined")
return require.apply(this, arguments);
throw Error('Dynamic require of "' + x + '" is not supported');
});
var __esm = (fn, res) => function __init() {
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
};
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// common/dist/esm/backend-impl.js
var backends, backendsSortedByPriority, registerBackend, tryResolveAndInitializeBackend, resolveBackendAndExecutionProviders;
var init_backend_impl = __esm({
"common/dist/esm/backend-impl.js"() {
"use strict";
backends = /* @__PURE__ */ new Map();
backendsSortedByPriority = [];
registerBackend = (name, backend, priority) => {
if (backend && typeof backend.init === "function" && typeof backend.createInferenceSessionHandler === "function") {
const currentBackend = backends.get(name);
if (currentBackend === void 0) {
backends.set(name, { backend, priority });
} else if (currentBackend.priority > priority) {
return;
} else if (currentBackend.priority === priority) {
if (currentBackend.backend !== backend) {
throw new Error(`cannot register backend "${name}" using priority ${priority}`);
}
}
if (priority >= 0) {
const i = backendsSortedByPriority.indexOf(name);
if (i !== -1) {
backendsSortedByPriority.splice(i, 1);
}
for (let i2 = 0; i2 < backendsSortedByPriority.length; i2++) {
if (backends.get(backendsSortedByPriority[i2]).priority <= priority) {
backendsSortedByPriority.splice(i2, 0, name);
return;
}
}
backendsSortedByPriority.push(name);
}
return;
}
throw new TypeError("not a valid backend");
};
tryResolveAndInitializeBackend = async (backendName) => {
const backendInfo = backends.get(backendName);
if (!backendInfo) {
return "backend not found.";
}
if (backendInfo.initialized) {
return backendInfo.backend;
} else if (backendInfo.aborted) {
return backendInfo.error;
} else {
const isInitializing = !!backendInfo.initPromise;
try {
if (!isInitializing) {
backendInfo.initPromise = backendInfo.backend.init(backendName);
}
await backendInfo.initPromise;
backendInfo.initialized = true;
return backendInfo.backend;
} catch (e) {
if (!isInitializing) {
backendInfo.error = `${e}`;
backendInfo.aborted = true;
}
return backendInfo.error;
} finally {
delete backendInfo.initPromise;
}
}
};
resolveBackendAndExecutionProviders = async (options) => {
const eps = options.executionProviders || [];
const backendHints = eps.map((i) => typeof i === "string" ? i : i.name);
const backendNames = backendHints.length === 0 ? backendsSortedByPriority : backendHints;
let backend;
const errors = [];
const availableBackendNames = /* @__PURE__ */ new Set();
for (const backendName of backendNames) {
const resolveResult = await tryResolveAndInitializeBackend(backendName);
if (typeof resolveResult === "string") {
errors.push({ name: backendName, err: resolveResult });
} else {
if (!backend) {
backend = resolveResult;
}
if (backend === resolveResult) {
availableBackendNames.add(backendName);
}
}
}
if (!backend) {
throw new Error(`no available backend found. ERR: ${errors.map((e) => `[${e.name}] ${e.err}`).join(", ")}`);
}
for (const { name, err } of errors) {
if (backendHints.includes(name)) {
console.warn(`removing requested execution provider "${name}" from session options because it is not available: ${err}`);
}
}
const filteredEps = eps.filter((i) => availableBackendNames.has(typeof i === "string" ? i : i.name));
return [
backend,
new Proxy(options, {
get: (target, prop) => {
if (prop === "executionProviders") {
return filteredEps;
}
return Reflect.get(target, prop);
}
})
];
};
}
});
// common/dist/esm/backend.js
var init_backend = __esm({
"common/dist/esm/backend.js"() {
"use strict";
init_backend_impl();
}
});
// common/dist/esm/version.js
var version;
var init_version = __esm({
"common/dist/esm/version.js"() {
"use strict";
version = "1.20.1";
}
});
// common/dist/esm/env-impl.js
var logLevelValue, env;
var init_env_impl = __esm({
"common/dist/esm/env-impl.js"() {
"use strict";
init_version();
logLevelValue = "warning";
env = {
wasm: {},
webgl: {},
webgpu: {},
versions: { common: version },
set logLevel(value) {
if (value === void 0) {
return;
}
if (typeof value !== "string" || ["verbose", "info", "warning", "error", "fatal"].indexOf(value) === -1) {
throw new Error(`Unsupported logging level: ${value}`);
}
logLevelValue = value;
},
get logLevel() {
return logLevelValue;
}
};
Object.defineProperty(env, "logLevel", { enumerable: true });
}
});
// common/dist/esm/env.js
var env2;
var init_env = __esm({
"common/dist/esm/env.js"() {
"use strict";
init_env_impl();
env2 = env;
}
});
// common/dist/esm/tensor-conversion-impl.js
var tensorToDataURL, tensorToImageData;
var init_tensor_conversion_impl = __esm({
"common/dist/esm/tensor-conversion-impl.js"() {
"use strict";
tensorToDataURL = (tensor, options) => {
const canvas = typeof document !== "undefined" ? document.createElement("canvas") : new OffscreenCanvas(1, 1);
canvas.width = tensor.dims[3];
canvas.height = tensor.dims[2];
const pixels2DContext = canvas.getContext("2d");
if (pixels2DContext != null) {
let width;
let height;
if (options?.tensorLayout !== void 0 && options.tensorLayout === "NHWC") {
width = tensor.dims[2];
height = tensor.dims[3];
} else {
width = tensor.dims[3];
height = tensor.dims[2];
}
const inputformat = options?.format !== void 0 ? options.format : "RGB";
const norm = options?.norm;
let normMean;
let normBias;
if (norm === void 0 || norm.mean === void 0) {
normMean = [255, 255, 255, 255];
} else {
if (typeof norm.mean === "number") {
normMean = [norm.mean, norm.mean, norm.mean, norm.mean];
} else {
normMean = [norm.mean[0], norm.mean[1], norm.mean[2], 0];
if (norm.mean[3] !== void 0) {
normMean[3] = norm.mean[3];
}
}
}
if (norm === void 0 || norm.bias === void 0) {
normBias = [0, 0, 0, 0];
} else {
if (typeof norm.bias === "number") {
normBias = [norm.bias, norm.bias, norm.bias, norm.bias];
} else {
normBias = [norm.bias[0], norm.bias[1], norm.bias[2], 0];
if (norm.bias[3] !== void 0) {
normBias[3] = norm.bias[3];
}
}
}
const stride = height * width;
let rTensorPointer = 0, gTensorPointer = stride, bTensorPointer = stride * 2, aTensorPointer = -1;
if (inputformat === "RGBA") {
rTensorPointer = 0;
gTensorPointer = stride;
bTensorPointer = stride * 2;
aTensorPointer = stride * 3;
} else if (inputformat === "RGB") {
rTensorPointer = 0;
gTensorPointer = stride;
bTensorPointer = stride * 2;
} else if (inputformat === "RBG") {
rTensorPointer = 0;
bTensorPointer = stride;
gTensorPointer = stride * 2;
}
for (let i = 0; i < height; i++) {
for (let j = 0; j < width; j++) {
const R = (tensor.data[rTensorPointer++] - normBias[0]) * normMean[0];
const G = (tensor.data[gTensorPointer++] - normBias[1]) * normMean[1];
const B = (tensor.data[bTensorPointer++] - normBias[2]) * normMean[2];
const A = aTensorPointer === -1 ? 255 : (tensor.data[aTensorPointer++] - normBias[3]) * normMean[3];
pixels2DContext.fillStyle = "rgba(" + R + "," + G + "," + B + "," + A + ")";
pixels2DContext.fillRect(j, i, 1, 1);
}
}
if ("toDataURL" in canvas) {
return canvas.toDataURL();
} else {
throw new Error("toDataURL is not supported");
}
} else {
throw new Error("Can not access image data");
}
};
tensorToImageData = (tensor, options) => {
const pixels2DContext = typeof document !== "undefined" ? document.createElement("canvas").getContext("2d") : new OffscreenCanvas(1, 1).getContext("2d");
let image;
if (pixels2DContext != null) {
let width;
let height;
let channels;
if (options?.tensorLayout !== void 0 && options.tensorLayout === "NHWC") {
width = tensor.dims[2];
height = tensor.dims[1];
channels = tensor.dims[3];
} else {
width = tensor.dims[3];
height = tensor.dims[2];
channels = tensor.dims[1];
}
const inputformat = options !== void 0 ? options.format !== void 0 ? options.format : "RGB" : "RGB";
const norm = options?.norm;
let normMean;
let normBias;
if (norm === void 0 || norm.mean === void 0) {
normMean = [255, 255, 255, 255];
} else {
if (typeof norm.mean === "number") {
normMean = [norm.mean, norm.mean, norm.mean, norm.mean];
} else {
normMean = [norm.mean[0], norm.mean[1], norm.mean[2], 255];
if (norm.mean[3] !== void 0) {
normMean[3] = norm.mean[3];
}
}
}
if (norm === void 0 || norm.bias === void 0) {
normBias = [0, 0, 0, 0];
} else {
if (typeof norm.bias === "number") {
normBias = [norm.bias, norm.bias, norm.bias, norm.bias];
} else {
normBias = [norm.bias[0], norm.bias[1], norm.bias[2], 0];
if (norm.bias[3] !== void 0) {
normBias[3] = norm.bias[3];
}
}
}
const stride = height * width;
if (options !== void 0) {
if (options.format !== void 0 && channels === 4 && options.format !== "RGBA" || channels === 3 && options.format !== "RGB" && options.format !== "BGR") {
throw new Error("Tensor format doesn't match input tensor dims");
}
}
const step = 4;
let rImagePointer = 0, gImagePointer = 1, bImagePointer = 2, aImagePointer = 3;
let rTensorPointer = 0, gTensorPointer = stride, bTensorPointer = stride * 2, aTensorPointer = -1;
if (inputformat === "RGBA") {
rTensorPointer = 0;
gTensorPointer = stride;
bTensorPointer = stride * 2;
aTensorPointer = stride * 3;
} else if (inputformat === "RGB") {
rTensorPointer = 0;
gTensorPointer = stride;
bTensorPointer = stride * 2;
} else if (inputformat === "RBG") {
rTensorPointer = 0;
bTensorPointer = stride;
gTensorPointer = stride * 2;
}
image = pixels2DContext.createImageData(width, height);
for (let i = 0; i < height * width; rImagePointer += step, gImagePointer += step, bImagePointer += step, aImagePointer += step, i++) {
image.data[rImagePointer] = (tensor.data[rTensorPointer++] - normBias[0]) * normMean[0];
image.data[gImagePointer] = (tensor.data[gTensorPointer++] - normBias[1]) * normMean[1];
image.data[bImagePointer] = (tensor.data[bTensorPointer++] - normBias[2]) * normMean[2];
image.data[aImagePointer] = aTensorPointer === -1 ? 255 : (tensor.data[aTensorPointer++] - normBias[3]) * normMean[3];
}
} else {
throw new Error("Can not access image data");
}
return image;
};
}
});
// common/dist/esm/tensor-factory-impl.js
var bufferToTensor, tensorFromImage, tensorFromTexture, tensorFromGpuBuffer, tensorFromMLTensor, tensorFromPinnedBuffer;
var init_tensor_factory_impl = __esm({
"common/dist/esm/tensor-factory-impl.js"() {
"use strict";
init_tensor_impl();
bufferToTensor = (buffer, options) => {
if (buffer === void 0) {
throw new Error("Image buffer must be defined");
}
if (options.height === void 0 || options.width === void 0) {
throw new Error("Image height and width must be defined");
}
if (options.tensorLayout === "NHWC") {
throw new Error("NHWC Tensor layout is not supported yet");
}
const { height, width } = options;
const norm = options.norm ?? { mean: 255, bias: 0 };
let normMean;
let normBias;
if (typeof norm.mean === "number") {
normMean = [norm.mean, norm.mean, norm.mean, norm.mean];
} else {
normMean = [norm.mean[0], norm.mean[1], norm.mean[2], norm.mean[3] ?? 255];
}
if (typeof norm.bias === "number") {
normBias = [norm.bias, norm.bias, norm.bias, norm.bias];
} else {
normBias = [norm.bias[0], norm.bias[1], norm.bias[2], norm.bias[3] ?? 0];
}
const inputformat = options.format !== void 0 ? options.format : "RGBA";
const outputformat = options.tensorFormat !== void 0 ? options.tensorFormat !== void 0 ? options.tensorFormat : "RGB" : "RGB";
const stride = height * width;
const float32Data = outputformat === "RGBA" ? new Float32Array(stride * 4) : new Float32Array(stride * 3);
let step = 4, rImagePointer = 0, gImagePointer = 1, bImagePointer = 2, aImagePointer = 3;
let rTensorPointer = 0, gTensorPointer = stride, bTensorPointer = stride * 2, aTensorPointer = -1;
if (inputformat === "RGB") {
step = 3;
rImagePointer = 0;
gImagePointer = 1;
bImagePointer = 2;
aImagePointer = -1;
}
if (outputformat === "RGBA") {
aTensorPointer = stride * 3;
} else if (outputformat === "RBG") {
rTensorPointer = 0;
bTensorPointer = stride;
gTensorPointer = stride * 2;
} else if (outputformat === "BGR") {
bTensorPointer = 0;
gTensorPointer = stride;
rTensorPointer = stride * 2;
}
for (let i = 0; i < stride; i++, rImagePointer += step, bImagePointer += step, gImagePointer += step, aImagePointer += step) {
float32Data[rTensorPointer++] = (buffer[rImagePointer] + normBias[0]) / normMean[0];
float32Data[gTensorPointer++] = (buffer[gImagePointer] + normBias[1]) / normMean[1];
float32Data[bTensorPointer++] = (buffer[bImagePointer] + normBias[2]) / normMean[2];
if (aTensorPointer !== -1 && aImagePointer !== -1) {
float32Data[aTensorPointer++] = (buffer[aImagePointer] + normBias[3]) / normMean[3];
}
}
const outputTensor = outputformat === "RGBA" ? new Tensor("float32", float32Data, [1, 4, height, width]) : new Tensor("float32", float32Data, [1, 3, height, width]);
return outputTensor;
};
tensorFromImage = async (image, options) => {
const isHTMLImageEle = typeof HTMLImageElement !== "undefined" && image instanceof HTMLImageElement;
const isImageDataEle = typeof ImageData !== "undefined" && image instanceof ImageData;
const isImageBitmap = typeof ImageBitmap !== "undefined" && image instanceof ImageBitmap;
const isString = typeof image === "string";
let data;
let bufferToTensorOptions = options ?? {};
const createCanvas = () => {
if (typeof document !== "undefined") {
return document.createElement("canvas");
} else if (typeof OffscreenCanvas !== "undefined") {
return new OffscreenCanvas(1, 1);
} else {
throw new Error("Canvas is not supported");
}
};
const createCanvasContext = (canvas) => {
if (typeof HTMLCanvasElement !== "undefined" && canvas instanceof HTMLCanvasElement) {
return canvas.getContext("2d");
} else if (canvas instanceof OffscreenCanvas) {
return canvas.getContext("2d");
} else {
return null;
}
};
if (isHTMLImageEle) {
const canvas = createCanvas();
canvas.width = image.width;
canvas.height = image.height;
const pixels2DContext = createCanvasContext(canvas);
if (pixels2DContext != null) {
let height = image.height;
let width = image.width;
if (options !== void 0 && options.resizedHeight !== void 0 && options.resizedWidth !== void 0) {
height = options.resizedHeight;
width = options.resizedWidth;
}
if (options !== void 0) {
bufferToTensorOptions = options;
if (options.tensorFormat !== void 0) {
throw new Error("Image input config format must be RGBA for HTMLImageElement");
} else {
bufferToTensorOptions.tensorFormat = "RGBA";
}
bufferToTensorOptions.height = height;
bufferToTensorOptions.width = width;
} else {
bufferToTensorOptions.tensorFormat = "RGBA";
bufferToTensorOptions.height = height;
bufferToTensorOptions.width = width;
}
pixels2DContext.drawImage(image, 0, 0);
data = pixels2DContext.getImageData(0, 0, width, height).data;
} else {
throw new Error("Can not access image data");
}
} else if (isImageDataEle) {
let height;
let width;
if (options !== void 0 && options.resizedWidth !== void 0 && options.resizedHeight !== void 0) {
height = options.resizedHeight;
width = options.resizedWidth;
} else {
height = image.height;
width = image.width;
}
if (options !== void 0) {
bufferToTensorOptions = options;
}
bufferToTensorOptions.format = "RGBA";
bufferToTensorOptions.height = height;
bufferToTensorOptions.width = width;
if (options !== void 0) {
const tempCanvas = createCanvas();
tempCanvas.width = width;
tempCanvas.height = height;
const pixels2DContext = createCanvasContext(tempCanvas);
if (pixels2DContext != null) {
pixels2DContext.putImageData(image, 0, 0);
data = pixels2DContext.getImageData(0, 0, width, height).data;
} else {
throw new Error("Can not access image data");
}
} else {
data = image.data;
}
} else if (isImageBitmap) {
if (options === void 0) {
throw new Error("Please provide image config with format for Imagebitmap");
}
const canvas = createCanvas();
canvas.width = image.width;
canvas.height = image.height;
const pixels2DContext = createCanvasContext(canvas);
if (pixels2DContext != null) {
const height = image.height;
const width = image.width;
pixels2DContext.drawImage(image, 0, 0, width, height);
data = pixels2DContext.getImageData(0, 0, width, height).data;
bufferToTensorOptions.height = height;
bufferToTensorOptions.width = width;
return bufferToTensor(data, bufferToTensorOptions);
} else {
throw new Error("Can not access image data");
}
} else if (isString) {
return new Promise((resolve, reject) => {
const canvas = createCanvas();
const context = createCanvasContext(canvas);
if (!image || !context) {
return reject();
}
const newImage = new Image();
newImage.crossOrigin = "Anonymous";
newImage.src = image;
newImage.onload = () => {
canvas.width = newImage.width;
canvas.height = newImage.height;
context.drawImage(newImage, 0, 0, canvas.width, canvas.height);
const img = context.getImageData(0, 0, canvas.width, canvas.height);
bufferToTensorOptions.height = canvas.height;
bufferToTensorOptions.width = canvas.width;
resolve(bufferToTensor(img.data, bufferToTensorOptions));
};
});
} else {
throw new Error("Input data provided is not supported - aborted tensor creation");
}
if (data !== void 0) {
return bufferToTensor(data, bufferToTensorOptions);
} else {
throw new Error("Input data provided is not supported - aborted tensor creation");
}
};
tensorFromTexture = (texture, options) => {
const { width, height, download, dispose } = options;
const dims = [1, height, width, 4];
return new Tensor({ location: "texture", type: "float32", texture, dims, download, dispose });
};
tensorFromGpuBuffer = (gpuBuffer, options) => {
const { dataType, dims, download, dispose } = options;
return new Tensor({ location: "gpu-buffer", type: dataType ?? "float32", gpuBuffer, dims, download, dispose });
};
tensorFromMLTensor = (mlTensor, options) => {
const { dataType, dims, download, dispose } = options;
return new Tensor({ location: "ml-tensor", type: dataType ?? "float32", mlTensor, dims, download, dispose });
};
tensorFromPinnedBuffer = (type, buffer, dims) => new Tensor({ location: "cpu-pinned", type, data: buffer, dims: dims ?? [buffer.length] });
}
});
// common/dist/esm/tensor-impl-type-mapping.js
var NUMERIC_TENSOR_TYPE_TO_TYPEDARRAY_MAP, NUMERIC_TENSOR_TYPEDARRAY_TO_TYPE_MAP, isTypedArrayChecked, checkTypedArray;
var init_tensor_impl_type_mapping = __esm({
"common/dist/esm/tensor-impl-type-mapping.js"() {
"use strict";
NUMERIC_TENSOR_TYPE_TO_TYPEDARRAY_MAP = /* @__PURE__ */ new Map([
["float32", Float32Array],
["uint8", Uint8Array],
["int8", Int8Array],
["uint16", Uint16Array],
["int16", Int16Array],
["int32", Int32Array],
["bool", Uint8Array],
["float64", Float64Array],
["uint32", Uint32Array],
["int4", Uint8Array],
["uint4", Uint8Array]
]);
NUMERIC_TENSOR_TYPEDARRAY_TO_TYPE_MAP = /* @__PURE__ */ new Map([
[Float32Array, "float32"],
[Uint8Array, "uint8"],
[Int8Array, "int8"],
[Uint16Array, "uint16"],
[Int16Array, "int16"],
[Int32Array, "int32"],
[Float64Array, "float64"],
[Uint32Array, "uint32"]
]);
isTypedArrayChecked = false;
checkTypedArray = () => {
if (!isTypedArrayChecked) {
isTypedArrayChecked = true;
const isBigInt64ArrayAvailable = typeof BigInt64Array !== "undefined" && BigInt64Array.from;
const isBigUint64ArrayAvailable = typeof BigUint64Array !== "undefined" && BigUint64Array.from;
const isFloat16ArrayAvailable = typeof Float16Array !== "undefined" && Float16Array.from;
if (isBigInt64ArrayAvailable) {
NUMERIC_TENSOR_TYPE_TO_TYPEDARRAY_MAP.set("int64", BigInt64Array);
NUMERIC_TENSOR_TYPEDARRAY_TO_TYPE_MAP.set(BigInt64Array, "int64");
}
if (isBigUint64ArrayAvailable) {
NUMERIC_TENSOR_TYPE_TO_TYPEDARRAY_MAP.set("uint64", BigUint64Array);
NUMERIC_TENSOR_TYPEDARRAY_TO_TYPE_MAP.set(BigUint64Array, "uint64");
}
if (isFloat16ArrayAvailable) {
NUMERIC_TENSOR_TYPE_TO_TYPEDARRAY_MAP.set("float16", Float16Array);
NUMERIC_TENSOR_TYPEDARRAY_TO_TYPE_MAP.set(Float16Array, "float16");
} else {
NUMERIC_TENSOR_TYPE_TO_TYPEDARRAY_MAP.set("float16", Uint16Array);
}
}
};
}
});
// common/dist/esm/tensor-utils-impl.js
var calculateSize, tensorReshape;
var init_tensor_utils_impl = __esm({
"common/dist/esm/tensor-utils-impl.js"() {
"use strict";
init_tensor_impl();
calculateSize = (dims) => {
let size = 1;
for (let i = 0; i < dims.length; i++) {
const dim = dims[i];
if (typeof dim !== "number" || !Number.isSafeInteger(dim)) {
throw new TypeError(`dims[${i}] must be an integer, got: ${dim}`);
}
if (dim < 0) {
throw new RangeError(`dims[${i}] must be a non-negative integer, got: ${dim}`);
}
size *= dim;
}
return size;
};
tensorReshape = (tensor, dims) => {
switch (tensor.location) {
case "cpu":
return new Tensor(tensor.type, tensor.data, dims);
case "cpu-pinned":
return new Tensor({
location: "cpu-pinned",
data: tensor.data,
type: tensor.type,
dims
});
case "texture":
return new Tensor({
location: "texture",
texture: tensor.texture,
type: tensor.type,
dims
});
case "gpu-buffer":
return new Tensor({
location: "gpu-buffer",
gpuBuffer: tensor.gpuBuffer,
type: tensor.type,
dims
});
case "ml-tensor":
return new Tensor({
location: "ml-tensor",
mlTensor: tensor.mlTensor,
type: tensor.type,
dims
});
default:
throw new Error(`tensorReshape: tensor location ${tensor.location} is not supported`);
}
};
}
});
// common/dist/esm/tensor-impl.js
var Tensor;
var init_tensor_impl = __esm({
"common/dist/esm/tensor-impl.js"() {
"use strict";
init_tensor_conversion_impl();
init_tensor_factory_impl();
init_tensor_impl_type_mapping();
init_tensor_utils_impl();
Tensor = class {
/**
* implementation.
*/
constructor(arg0, arg1, arg2) {
checkTypedArray();
let type;
let dims;
if (typeof arg0 === "object" && "location" in arg0) {
this.dataLocation = arg0.location;
type = arg0.type;
dims = arg0.dims;
switch (arg0.location) {
case "cpu-pinned": {
const expectedTypedArrayConstructor = NUMERIC_TENSOR_TYPE_TO_TYPEDARRAY_MAP.get(type);
if (!expectedTypedArrayConstructor) {
throw new TypeError(`unsupported type "${type}" to create tensor from pinned buffer`);
}
if (!(arg0.data instanceof expectedTypedArrayConstructor)) {
throw new TypeError(`buffer should be of type ${expectedTypedArrayConstructor.name}`);
}
this.cpuData = arg0.data;
break;
}
case "texture": {
if (type !== "float32") {
throw new TypeError(`unsupported type "${type}" to create tensor from texture`);
}
this.gpuTextureData = arg0.texture;
this.downloader = arg0.download;
this.disposer = arg0.dispose;
break;
}
case "gpu-buffer": {
if (type !== "float32" && type !== "float16" && type !== "int32" && type !== "int64" && type !== "uint32" && type !== "uint8" && type !== "bool" && type !== "uint4" && type !== "int4") {
throw new TypeError(`unsupported type "${type}" to create tensor from gpu buffer`);
}
this.gpuBufferData = arg0.gpuBuffer;
this.downloader = arg0.download;
this.disposer = arg0.dispose;
break;
}
case "ml-tensor": {
if (type !== "float32" && type !== "float16" && type !== "int32" && type !== "int64" && type !== "uint32" && type !== "uint64" && type !== "int8" && type !== "uint8" && type !== "bool") {
throw new TypeError(`unsupported type "${type}" to create tensor from MLTensor`);
}
this.mlTensorData = arg0.mlTensor;
this.downloader = arg0.download;
this.disposer = arg0.dispose;
break;
}
default:
throw new Error(`Tensor constructor: unsupported location '${this.dataLocation}'`);
}
} else {
let data;
let maybeDims;
if (typeof arg0 === "string") {
type = arg0;
maybeDims = arg2;
if (arg0 === "string") {
if (!Array.isArray(arg1)) {
throw new TypeError("A string tensor's data must be a string array.");
}
data = arg1;
} else {
const typedArrayConstructor = NUMERIC_TENSOR_TYPE_TO_TYPEDARRAY_MAP.get(arg0);
if (typedArrayConstructor === void 0) {
throw new TypeError(`Unsupported tensor type: ${arg0}.`);
}
if (Array.isArray(arg1)) {
if (arg0 === "float16" && typedArrayConstructor === Uint16Array || arg0 === "uint4" || arg0 === "int4") {
throw new TypeError(`Creating a ${arg0} tensor from number array is not supported. Please use ${typedArrayConstructor.name} as data.`);
} else if (arg0 === "uint64" || arg0 === "int64") {
data = typedArrayConstructor.from(arg1, BigInt);
} else {
data = typedArrayConstructor.from(arg1);
}
} else if (arg1 instanceof typedArrayConstructor) {
data = arg1;
} else if (arg1 instanceof Uint8ClampedArray) {
if (arg0 === "uint8") {
data = Uint8Array.from(arg1);
} else {
throw new TypeError(`A Uint8ClampedArray tensor's data must be type of uint8`);
}
} else {
throw new TypeError(`A ${type} tensor's data must be type of ${typedArrayConstructor}`);
}
}
} else {
maybeDims = arg1;
if (Array.isArray(arg0)) {
if (arg0.length === 0) {
throw new TypeError("Tensor type cannot be inferred from an empty array.");
}
const firstElementType = typeof arg0[0];
if (firstElementType === "string") {
type = "string";
data = arg0;
} else if (firstElementType === "boolean") {
type = "bool";
data = Uint8Array.from(arg0);
} else {
throw new TypeError(`Invalid element type of data array: ${firstElementType}.`);
}
} else if (arg0 instanceof Uint8ClampedArray) {
type = "uint8";
data = Uint8Array.from(arg0);
} else {
const mappedType = NUMERIC_TENSOR_TYPEDARRAY_TO_TYPE_MAP.get(arg0.constructor);
if (mappedType === void 0) {
throw new TypeError(`Unsupported type for tensor data: ${arg0.constructor}.`);
}
type = mappedType;
data = arg0;
}
}
if (maybeDims === void 0) {
maybeDims = [data.length];
} else if (!Array.isArray(maybeDims)) {
throw new TypeError("A tensor's dims must be a number array");
}
dims = maybeDims;
this.cpuData = data;
this.dataLocation = "cpu";
}
const size = calculateSize(dims);
if (this.cpuData && size !== this.cpuData.length) {
if ((type === "uint4" || type === "int4") && Math.ceil(size / 2) === this.cpuData.length) {
} else {
throw new Error(`Tensor's size(${size}) does not match data length(${this.cpuData.length}).`);
}
}
this.type = type;
this.dims = dims;
this.size = size;
}
// #endregion
// #region factory
static async fromImage(image, options) {
return tensorFromImage(image, options);
}
static fromTexture(texture, options) {
return tensorFromTexture(texture, options);
}
static fromGpuBuffer(gpuBuffer, options) {
return tensorFromGpuBuffer(gpuBuffer, options);
}
static fromMLTensor(mlTensor, options) {
return tensorFromMLTensor(mlTensor, options);
}
static fromPinnedBuffer(type, buffer, dims) {
return tensorFromPinnedBuffer(type, buffer, dims);
}
// #endregion
// #region conversions
toDataURL(options) {
return tensorToDataURL(this, options);
}
toImageData(options) {
return tensorToImageData(this, options);
}
// #endregion
// #region properties
get data() {
this.ensureValid();
if (!this.cpuData) {
throw new Error("The data is not on CPU. Use `getData()` to download GPU data to CPU, or use `texture` or `gpuBuffer` property to access the GPU data directly.");
}
return this.cpuData;
}
get location() {
return this.dataLocation;
}
get texture() {
this.ensureValid();
if (!this.gpuTextureData) {
throw new Error("The data is not stored as a WebGL texture.");
}
return this.gpuTextureData;
}
get gpuBuffer() {
this.ensureValid();
if (!this.gpuBufferData) {
throw new Error("The data is not stored as a WebGPU buffer.");
}
return this.gpuBufferData;
}
get mlTensor() {
this.ensureValid();
if (!this.mlTensorData) {
throw new Error("The data is not stored as a WebNN MLTensor.");
}
return this.mlTensorData;
}
// #endregion
// #region methods
async getData(releaseData) {
this.ensureValid();
switch (this.dataLocation) {
case "cpu":
case "cpu-pinned":
return this.data;
case "texture":
case "gpu-buffer":
case "ml-tensor": {
if (!this.downloader) {
throw new Error("The current tensor is not created with a specified data downloader.");
}
if (this.isDownloading) {
throw new Error("The current tensor is being downloaded.");
}
try {
this.isDownloading = true;
const data = await this.downloader();
this.downloader = void 0;
this.dataLocation = "cpu";
this.cpuData = data;
if (releaseData && this.disposer) {
this.disposer();
this.disposer = void 0;
}
return data;
} finally {
this.isDownloading = false;
}
}
default:
throw new Error(`cannot get data from location: ${this.dataLocation}`);
}
}
dispose() {
if (this.isDownloading) {
throw new Error("The current tensor is being downloaded.");
}
if (this.disposer) {
this.disposer();
this.disposer = void 0;
}
this.cpuData = void 0;
this.gpuTextureData = void 0;
this.gpuBufferData = void 0;
this.mlTensorData = void 0;
this.downloader = void 0;
this.isDownloading = void 0;
this.dataLocation = "none";
}
// #endregion
// #region tensor utilities
ensureValid() {
if (this.dataLocation === "none") {
throw new Error("The tensor is disposed.");
}
}
reshape(dims) {
this.ensureValid();
if (this.downloader || this.disposer) {
throw new Error("Cannot reshape a tensor that owns GPU resource.");
}
return tensorReshape(this, dims);
}
};
}
});
// common/dist/esm/tensor.js
var Tensor2;
var init_tensor = __esm({
"common/dist/esm/tensor.js"() {
"use strict";
init_tensor_impl();
Tensor2 = Tensor;
}
});
// common/dist/esm/trace.js
var TRACE, TRACE_FUNC, TRACE_FUNC_BEGIN, TRACE_FUNC_END;
var init_trace = __esm({
"common/dist/esm/trace.js"() {
"use strict";
init_env_impl();
TRACE = (deviceType, label) => {
if (typeof env.trace === "undefined" ? !env.wasm.trace : !env.trace) {
return;
}
console.timeStamp(`${deviceType}::ORT::${label}`);
};
TRACE_FUNC = (msg, extraMsg) => {
const stack = new Error().stack?.split(/\r\n|\r|\n/g) || [];
let hasTraceFunc = false;
for (let i = 0; i < stack.length; i++) {
if (hasTraceFunc && !stack[i].includes("TRACE_FUNC")) {
let label = `FUNC_${msg}::${stack[i].trim().split(" ")[1]}`;
if (extraMsg) {
label += `::${extraMsg}`;
}
TRACE("CPU", label);
return;
}
if (stack[i].includes("TRACE_FUNC")) {
hasTraceFunc = true;
}
}
};
TRACE_FUNC_BEGIN = (extraMsg) => {
if (typeof env.trace === "undefined" ? !env.wasm.trace : !env.trace) {
return;
}
TRACE_FUNC("BEGIN", extraMsg);
};
TRACE_FUNC_END = (extraMsg) => {
if (typeof env.trace === "undefined" ? !env.wasm.trace : !env.trace) {
return;
}
TRACE_FUNC("END", extraMsg);
};
}
});
// common/dist/esm/inference-session-impl.js
var InferenceSession;
var init_inference_session_impl = __esm({
"common/dist/esm/inference-session-impl.js"() {
"use strict";
init_backend_impl();
init_tensor();
init_trace();
InferenceSession = class _InferenceSession {
constructor(handler) {
this.handler = handler;
}
async run(feeds, arg1, arg2) {
TRACE_FUNC_BEGIN();
const fetches = {};
let options = {};
if (typeof feeds !== "object" || feeds === null || feeds instanceof Tensor2 || Array.isArray(feeds)) {
throw new TypeError("'feeds' must be an object that use input names as keys and OnnxValue as corresponding values.");
}
let isFetchesEmpty = true;
if (typeof arg1 === "object") {
if (arg1 === null) {
throw new TypeError("Unexpected argument[1]: cannot be null.");
}
if (arg1 instanceof Tensor2) {
throw new TypeError("'fetches' cannot be a Tensor");
}
if (Array.isArray(arg1)) {
if (arg1.length === 0) {
throw new TypeError("'fetches' cannot be an empty array.");
}
isFetchesEmpty = false;
for (const name of arg1) {
if (typeof name !== "string") {
throw new TypeError("'fetches' must be a string array or an object.");
}
if (this.outputNames.indexOf(name) === -1) {
throw new RangeError(`'fetches' contains invalid output name: ${name}.`);
}
fetches[name] = null;
}
if (typeof arg2 === "object" && arg2 !== null) {
options = arg2;
} else if (typeof arg2 !== "undefined") {
throw new TypeError("'options' must be an object.");
}
} else {
let isFetches = false;
const arg1Keys = Object.getOwnPropertyNames(arg1);
for (const name of this.outputNames) {
if (arg1Keys.indexOf(name) !== -1) {
const v = arg1[name];
if (v === null || v instanceof Tensor2) {
isFetches = true;
isFetchesEmpty = false;
fetches[name] = v;
}
}
}
if (isFetches) {
if (typeof arg2 === "object" && arg2 !== null) {
options = arg2;
} else if (typeof arg2 !== "undefined") {
throw new TypeError("'options' must be an object.");
}
} else {
options = arg1;
}
}
} else if (typeof arg1 !== "undefined") {
throw new TypeError("Unexpected argument[1]: must be 'fetches' or 'options'.");
}
for (const name of this.inputNames) {
if (typeof feeds[name] === "undefined") {
throw new Error(`input '${name}' is missing in 'feeds'.`);
}
}
if (isFetchesEmpty) {
for (const name of this.outputNames) {
fetches[name] = null;
}
}
const results = await this.handler.run(feeds, fetches, options);
const returnValue = {};
for (const key in results) {
if (Object.hasOwnProperty.call(results, key)) {
const result = results[key];
if (result instanceof Tensor2) {
returnValue[key] = result;
} else {
returnValue[key] = new Tensor2(result.type, result.data, result.dims);
}
}
}
TRACE_FUNC_END();
return returnValue;
}
async release() {
return this.handler.dispose();
}
static async create(arg0, arg1, arg2, arg3) {
TRACE_FUNC_BEGIN();
let filePathOrUint8Array;
let options = {};
if (typeof arg0 === "string") {
filePathOrUint8Array = arg0;
if (typeof arg1 === "object" && arg1 !== null) {
options = arg1;
} else if (typeof arg1 !== "undefined") {
throw new TypeError("'options' must be an object.");
}
} else if (arg0 instanceof Uint8Array) {
filePathOrUint8Array = arg0;
if (typeof arg1 === "object" && arg1 !== null) {
options = arg1;
} else if (typeof arg1 !== "undefined") {
throw new TypeError("'options' must be an object.");
}
} else if (arg0 instanceof ArrayBuffer || typeof SharedArrayBuffer !== "undefined" && arg0 instanceof SharedArrayBuffer) {
const buffer = arg0;
let byteOffset = 0;
let byteLength = arg0.byteLength;
if (typeof arg1 === "object" && arg1 !== null) {
options = arg1;
} else if (typeof arg1 === "number") {
byteOffset = arg1;
if (!Number.isSafeInteger(byteOffset)) {
throw new RangeError("'byteOffset' must be an integer.");
}
if (byteOffset < 0 || byteOffset >= buffer.byteLength) {
throw new RangeError(`'byteOffset' is out of range [0, ${buffer.byteLength}).`);
}
byteLength = arg0.byteLength - byteOffset;
if (typeof arg2 === "number") {
byteLength = arg2;
if (!Number.isSafeInteger(byteLength)) {
throw new RangeError("'byteLength' must be an integer.");
}
if (byteLength <= 0 || byteOffset + byteLength > buffer.byteLength) {
throw new RangeError(`'byteLength' is out of range (0, ${buffer.byteLength - byteOffset}].`);
}
if (typeof arg3 === "object" && arg3 !== null) {
options = arg3;
} else if (typeof arg3 !== "undefined") {
throw new TypeError("'options' must be an object.");
}
} else if (typeof arg2 !== "undefined") {
throw new TypeError("'byteLength' must be a number.");
}
} else if (typeof arg1 !== "undefined") {
throw new TypeError("'options' must be an object.");
}
filePathOrUint8Array = new Uint8Array(buffer, byteOffset, byteLength);
} else {
throw new TypeError("Unexpected argument[0]: must be 'path' or 'buffer'.");
}
const [backend, optionsWithValidatedEPs] = await resolveBackendAndExecutionProviders(options);
const handler = await backend.createInferenceSessionHandler(filePathOrUint8Array, optionsWithValidatedEPs);
TRACE_FUNC_END();
return new _InferenceSession(handler);
}
startProfiling() {
this.handler.startProfiling();
}
endProfiling() {
this.handler.endProfiling();
}
get inputNames() {
return this.handler.inputNames;
}
get outputNames() {
return this.handler.outputNames;
}
};
}
});
// common/dist/esm/inference-session.js
var InferenceSession2;
var init_inference_session = __esm({
"common/dist/esm/inference-session.js"() {
"use strict";
init_inference_session_impl();
InferenceSession2 = InferenceSession;
}
});
// common/dist/esm/tensor-conversion.js
var init_tensor_conversion = __esm({
"common/dist/esm/tensor-conversion.js"() {
"use strict";
}
});
// common/dist/esm/tensor-factory.js
var init_tensor_factory = __esm({
"common/dist/esm/tensor-factory.js"() {
"use strict";
}
});
// common/dist/esm/onnx-model.js
var init_onnx_model = __esm({
"common/dist/esm/onnx-model.js"() {
"use strict";
}
});
// common/dist/esm/onnx-value.js
var init_onnx_value = __esm({
"common/dist/esm/onnx-value.js"() {
"use strict";
}
});
// common/dist/esm/training-session-impl.js
var noBackendErrMsg, TrainingSession;
var init_training_session_impl = __esm({
"common/dist/esm/training-session-impl.js"() {
"use strict";
init_backend_impl();
init_tensor();
noBackendErrMsg = "Training backend could not be resolved. Make sure you're using the correct configuration & WebAssembly files.";
TrainingSession = class _TrainingSession {
constructor(handler, hasOptimizerModel, hasEvalModel) {
this.handler = handler;
this.hasOptimizerModel = hasOptimizerModel;
this.hasEvalModel = hasEvalModel;
}
get trainingInputNames() {
return this.handler.inputNames;
}
get trainingOutputNames() {
return this.handler.outputNames;
}
get evalInputNames() {
if (this.hasEvalModel) {
return this.handler.evalInputNames;
} else {
throw new Error("This training session has no evalModel loaded.");
}
}
get evalOutputNames() {
if (this.hasEvalModel) {
return this.handler.evalOutputNames;
} else {
throw new Error("This training session has no evalModel loaded.");
}
}
static async create(trainingOptions, sessionOptions) {
const evalModel = trainingOptions.evalModel || "";
const optimizerModel = trainingOptions.optimizerModel || "";
const options = sessionOptions || {};
const [backend, optionsWithValidatedEPs] = await resolveBackendAndExecutionProviders(options);
if (backend.createTrainingSessionHandler) {
const handler = await backend.createTrainingSessionHandler(trainingOptions.checkpointState, trainingOptions.trainModel, evalModel, optimizerModel, optionsWithValidatedEPs);
return new _TrainingSession(handler, !!trainingOptions.optimizerModel, !!trainingOptions.evalModel);
} else {
throw new Error(noBackendErrMsg);
}
}
/**
* Helper function for runTrainStep and future runStep methods that handles the type-narrowing conversion from
* the given parameters to SessionHandler.FetchesType and RunOptions.
*
* @param inputNames the feeds object is checked that they contain all input names in the provided list of input
* names.
* @param outputNames the fetches object is checked that their keys match up with valid names in the list of output
* names.
* @param feeds the required input
* @param arg1 narrowed & converted into the SessionHandler.FetchesType or RunOptions object
* @param arg2 optional RunOptions object.
* @returns
*/
typeNarrowingForRunStep(inputNames, outputNames, feeds, arg1, arg2) {
const fetches = {};
let options = {};
if (typeof feeds !== "object" || feeds === null || feeds instanceof Tensor2 || Array.isArray(feeds)) {
throw new TypeError("'feeds' must be an object that use input names as keys and OnnxValue as corresponding values.");
}
let isFetchesEmpty = true;
if (typeof arg1 === "object") {
if (arg1 === null) {
throw new TypeError("Unexpected argument[1]: cannot be null.");
}
if (arg1 instanceof Tensor2) {
throw new TypeError("'fetches' cannot be a Tensor");
}
if (Array.isArray(arg1)) {
if (arg1.length === 0) {
throw new TypeError("'fetches' cannot be an empty array.");
}
isFetchesEmpty = false;
for (const name of arg1) {
if (typeof name !== "string") {
throw new TypeError("'fetches' must be a string array or an object.");
}
if (outputNames.indexOf(name) === -1) {
throw new RangeError(`'fetches' contains invalid output name: ${name}.`);
}
fetches[name] = null;
}
if (typeof arg2 === "object" && arg2 !== null) {
options = arg2;
} else if (typeof arg2 !== "undefined") {
throw new TypeError("'options' must be an object.");
}
} else {
let isFetches = false;
const arg1Keys = Object.getOwnPropertyNames(arg1);
for (const name of outputNames) {
if (arg1Keys.indexOf(name) !== -1) {
const v = arg1[name];
if (v === null || v instanceof Tensor2) {
isFetches = true;
isFetchesEmpty = false;
fetches[name] = v;
}
}
}
if (isFetches) {
if (typeof arg2 === "object" && arg2 !== null) {
options = arg2;
} else if (typeof arg2 !== "undefined") {
throw new TypeError("'options' must be an object.");
}
} else {
options = arg1;
}
}
} else if (typeof arg1 !== "undefined") {
throw new TypeError("Unexpected argument[1]: must be 'fetches' or 'options'.");
}
for (const name of inputNames) {
if (typeof feeds[name] === "undefined") {
throw new Error(`input '${name}' is missing in 'feeds'.`);
}
}
if (isFetchesEmpty) {
for (const name of outputNames) {
fetches[name] = null;
}
}
return [fetches, options];
}
/**
* Helper method for runTrainStep and any other runStep methods. Takes the ReturnType result from the SessionHandler
* and changes it into a map of Tensors.
*
* @param results
* @returns
*/
convertHandlerReturnTypeToMapOfTensors(results) {
const returnValue = {};
for (const key in results) {
if (Object.hasOwnProperty.call(results, key)) {
const result = results[key];
if (result instanceof Tensor2) {
returnValue[key] = result;
} else {
returnValue[key] = new Tensor2(result.type, result.data, result.dims);
}
}
}
return returnValue;
}
async lazyResetGrad() {
await this.handler.lazyResetGrad();
}
async runTrainStep(feeds, arg1, arg2) {
const [fetches, options] = this.typeNarrowingForRunStep(this.trainingInputNames, this.trainingOutputNames, feeds, arg1, arg2);
const results = await this.handler.runTrainStep(feeds, fetches, options);
return this.convertHandlerReturnTypeToMapOfTensors(results);
}
async runOptimizerStep(options) {
if (this.hasOptimizerModel) {
await this.handler.runOptimizerStep(options || {});
} else {
throw new Error("This TrainingSession has no OptimizerModel loaded.");
}
}
async runEvalStep(feeds, arg1, arg2) {
if (this.hasEvalModel) {
const [fetches, options] = this.typeNarrowingForRunStep(this.evalInputNames, this.evalOutputNames, feeds, arg1, arg2);
const results = await this.handler.runEvalStep(feeds, fetches, options);
return this.convertHandlerReturnTypeToMapOfTensors(results);
} else {
throw new Error("This TrainingSession has no EvalModel loaded.");
}
}
async getParametersSize(trainableOnly = true) {
return this.handler.getParametersSize(trainableOnly);
}
async loadParametersBuffer(array, trainableOnly = true) {
const paramsSize = await this.getParametersSize(trainableOnly);
if (array.length !== 4 * paramsSize) {
throw new Error("Size of the buffer passed into loadParametersBuffer must match the number of parameters in the model. Please use getParametersSize method to check.");
}
return this.handler.loadParametersBuffer(array, trainableOnly);
}
async getContiguousParameters(trainableOnly = true) {
return this.handler.getContiguousParameters(trainableOnly);
}
async release() {
return this.handler.dispose();
}
};
}
});
// common/dist/esm/training-session.js
var TrainingSession2;
var init_training_session = __esm({
"common/dist/esm/training-session.js"() {
"use strict";
init_training_session_impl();
TrainingSession2 = TrainingSession;
}
});
// common/dist/esm/index.js
var esm_exports = {};
__export(esm_exports, {
InferenceSession: () => InferenceSession2,
TRACE: () => TRACE,
TRACE_FUNC_BEGIN: () => TRACE_FUNC_BEGIN,
TRACE_FUNC_END: () => TRACE_FUNC_END,
Tensor: () => Tensor2,
TrainingSession: () => TrainingSession2,
env: () => env2,
registerBackend: () => registerBackend
});
var init_esm = __esm({
"common/dist/esm/index.js"() {
"use strict";
init_backend();
init_env();
init_inference_session();
init_tensor();
init_tensor_conversion();
init_tensor_factory();
init_trace();
init_onnx_model();
init_onnx_value();
init_training_session();
}
});
// web/lib/wasm/wasm-utils-env.ts
var isNode;
var init_wasm_utils_env = __esm({
"web/lib/wasm/wasm-utils-env.ts"() {
"use strict";
isNode = false;
}
});
// web/lib/wasm/proxy-worker/main.ts
var main_exports = {};
__export(main_exports, {
default: () => main_default
});
var WORKER_NAME, isProxyWorker, main_default;
var init_main = __esm({
"web/lib/wasm/proxy-worker/main.ts"() {
"use strict";
init_wasm_core_impl();
init_wasm_factory();
init_wasm_utils_import();
WORKER_NAME = "ort-wasm-proxy-worker";
isProxyWorker = globalThis.self?.name === WORKER_NAME;
if (isProxyWorker) {
self.onmessage = (ev) => {
const { type, in: message } = ev.data;
try {
switch (type) {
case "init-wasm":
initializeWebAssembly(message.wasm).then(
() => {
initRuntime(message).then(
() => {
postMessage({ type });
},
(err) => {
postMessage({ type, err });
}
);
},
(err) => {
postMessage({ type, err });
}
);
break;
case "init-ep": {
const { epName, env: env3 } = message;
initEp(env3, epName).then(
() => {
postMessage({ type });
},
(err) => {
postMessage({ type, err });
}
);
break;
}
case "copy-from": {
const { buffer } = message;
const bufferData = copyFromExternalBuffer(buffer);
postMessage({ type, out: bufferData });
break;
}
case "create": {
const { model, options } = message;
createSession(model, options).then(
(sessionMetadata) => {
postMessage({ type, out: sessionMetadata });
},
(err) => {
postMessage({ type, err });
}
);
break;
}
case "release":
releaseSession(message);
postMessage({ type });
break;
case "run": {
const { sessionId, inputIndices, inputs, outputIndices, options } = message;
run(sessionId, inputIndices, inputs, outputIndices, new Array(outputIndices.length).fill(null), options).then(
(outputs) => {
if (outputs.some((o) => o[3] !== "cpu")) {
postMessage({ type, err: "Proxy does not support non-cpu tensor location." });
} else {
postMessage(
{ type, out: outputs },
extractTransferableBuffers([...inputs, ...outputs])
);
}
},
(err) => {
postMessage({ type, err });
}
);
break;
}
case "end-profiling":
endProfiling(message);
postMessage({ type });
break;
default:
}
} catch (err) {
postMessage({ type, err });
}
};
}
main_default = isProxyWorker ? null : (urlOverride) => new Worker(urlOverride ?? scriptSrc, { type: true ? "module" : "classic", name: WORKER_NAME });
}
});
// web/lib/wasm/wasm-utils-import.ts
var scriptSrc, origin, isSameOrigin, normalizeUrl, fallbackUrl, preload, dynamicImportDefault, createProxyWorker, importProxyWorker, embeddedWasmModule, importWasmModule;
var init_wasm_utils_import = __esm({
"web/lib/wasm/wasm-utils-import.ts"() {
"use strict";
init_wasm_utils_env();
scriptSrc = // if Nodejs, return undefined
isNode ? void 0 : (
// if It's ESM, use import.meta.url
import.meta.url ?? // use `document.currentScript.src` if available
(typeof document !== "undefined" ? document.currentScript?.src : (
// use `self.location.href` if available
typeof self !== "undefined" ? self.location?.href : void 0
))
);
origin = isNode || typeof location === "undefined" ? void 0 : location.origin;
isSameOrigin = (filename, prefixOverride) => {
try {
const baseUrl = prefixOverride ?? scriptSrc;
const url = baseUrl ? new URL(filename, baseUrl) : new URL(filename);
return url.origin === origin;
} catch {
return false;
}
};
normalizeUrl = (filename, prefixOverride) => {
const baseUrl = prefixOverride ?? scriptSrc;
try {
const url = baseUrl ? new URL(filename, baseUrl) : new URL(filename);
return url.href;
} catch {
return void 0;
}
};
fallbackUrl = (filename, prefixOverride) => `${prefixOverride ?? "./"}${filename}`;
preload = async (absoluteUrl) => {
const response = await fetch(absoluteUrl, { credentials: "same-origin" });
const blob = await response.blob();
return URL.createObjectURL(blob);
};
dynamicImportDefault = async (url) => (await import(
/* webpackIgnore: true */
url
)).default;
createProxyWorker = // eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires
false ? void 0 : (init_main(), __toCommonJS(main_exports)).default;
importProxyWorker = async () => {
if (!scriptSrc) {
throw new Error("Failed to load proxy worker: cannot determine the script source URL.");
}
if (isSameOrigin(scriptSrc)) {
return [void 0, createProxyWorker()];
}
const url = await preload(scriptSrc);
return [url, createProxyWorker(url)];
};
embeddedWasmModule = false ? (
// eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires
(true ? null : null).default
) : void 0;
importWasmModule = async (urlOverride, prefixOverride, isMultiThreaded) => {
if (false) {
return [void 0, embeddedWasmModule];
} else {
const wasmModuleFilename = true ? "ort-wasm-simd-threaded.jsep.mjs" : "ort-wasm-simd-threaded.mjs";
const wasmModuleUrl = urlOverride ?? normalizeUrl(wasmModuleFilename, prefixOverride);
const needPreload = !isNode && isMultiThreaded && wasmModuleUrl && !isSameOrigin(wasmModuleUrl, prefixOverride);
const url = needPreload ? await preload(wasmModuleUrl) : wasmModuleUrl ?? fallbackUrl(wasmModuleFilename, prefixOverride);
return [needPreload ? url : void 0, await dynamicImportDefault(url)];
}
};
}
});
// web/lib/wasm/wasm-factory.ts
var wasm, initialized, initializing, aborted, isMultiThreadSupported, isSimdSupported, initializeWebAssembly, getInstance;
var init_wasm_factory = __esm({
"web/lib/wasm/wasm-factory.ts"() {
"use strict";
init_wasm_utils_import();
initialized = false;
initializing = false;
aborted = false;
isMultiThreadSupported = () => {
if (typeof SharedArrayBuffer === "undefined") {
return false;
}
try {
if (typeof MessageChannel !== "undefined") {
new MessageChannel().port1.postMessage(new SharedArrayBuffer(1));
}
return WebAssembly.validate(
new Uint8Array([
0,
97,
115,
109,
1,
0,
0,
0,
1,
4,
1,
96,
0,
0,
3,
2,
1,
0,
5,
4,
1,
3,
1,
1,
10,
11,
1,
9,
0,
65,
0,
254,
16,
2,
0,
26,
11
])
);
} catch (e) {
return false;
}
};
isSimdSupported = () => {
try {
return WebAssembly.validate(
new Uint8Array([
0,
97,
115,
109,
1,
0,
0,
0,
1,
4,
1,
96,
0,
0,
3,
2,
1,
0,
10,
30,
1,
28,
0,
65,
0,
253,
15,
253,
12,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
253,
186,
1,
26,
11
])
);
} catch (e) {
return false;
}
};
initializeWebAssembly = async (flags) => {
if (initialized) {
return Promise.resolve();
}
if (initializing) {
throw new Error("multiple calls to 'initializeWebAssembly()' detected.");
}
if (aborted) {
throw new Error("previous call to 'initializeWebAssembly()' failed.");
}
initializing = true;
const timeout = flags.initTimeout;
let numThreads = flags.numThreads;
if (!isSimdSupported()) {
throw new Error("WebAssembly SIMD is not supported in the current environment.");
}
const multiThreadSupported = isMultiThreadSupported();
if (numThreads > 1 && !multiThreadSupported) {
if (typeof self !== "undefined" && !self.crossOriginIsolated) {
console.warn(
"env.wasm.numThreads is set to " + numThreads + ", but this will not work unless you enable crossOriginIsolated mode. See https://web.dev/cross-origin-isolation-guide/ for more info."
);
}
console.warn(
"WebAssembly multi-threading is not supported in the current environment. Falling back to single-threading."
);
flags.numThreads = numThreads = 1;
}
const wasmPaths = flags.wasmPaths;
const wasmPrefixOverride = typeof wasmPaths === "string" ? wasmPaths : void 0;
const mjsPathOverrideFlag = wasmPaths?.mjs;
const mjsPathOverride = mjsPathOverrideFlag?.href ?? mjsPathOverrideFlag;
const wasmPathOverrideFlag = wasmPaths?.wasm;
const wasmPathOverride = wasmPathOverrideFlag?.href ?? wasmPathOverrideFlag;
const wasmBinaryOverride = flags.wasmBinary;
const [objectUrl, ortWasmFactory] = await importWasmModule(mjsPathOverride, wasmPrefixOverride, numThreads > 1);
let isTimeout = false;
const tasks = [];
if (timeout > 0) {
tasks.push(
new Promise((resolve) => {
setTimeout(() => {
isTimeout = true;
resolve();
}, timeout);
})
);
}
tasks.push(
new Promise((resolve, reject) => {
const config = {
/**
* The number of threads. WebAssembly will create (Module.numThreads - 1) workers. If it is 1, no worker will be
* created.
*/
numThreads
};
if (wasmBinaryOverride) {
config.wasmBinary = wasmBinaryOverride;
} else if (wasmPathOverride || wasmPrefixOverride) {
config.locateFile = (fileName, scriptDirectory) => wasmPathOverride ?? (wasmPrefixOverride ?? scriptDirectory) + fileName;
}
ortWasmFactory(config).then(
// wasm module initialized successfully
(module) => {
initializing = false;
initialized = true;
wasm = module;
resolve();
if (objectUrl) {
URL.revokeObjectURL(objectUrl);
}
},
// wasm module failed to initialize
(what) => {
initializing = false;
aborted = true;
reject(what);
}
);
})
);
await Promise.race(tasks);
if (isTimeout) {
throw new Error(`WebAssembly backend initializing failed due to timeout: ${timeout}ms`);
}
};
getInstance = () => {
if (initialized && wasm) {
return wasm;
}
throw new Error("WebAssembly is not initialized yet.");
};
}
});
// web/lib/wasm/wasm-utils.ts
var allocWasmString, iterateExtraOptions, checkLastError;
var init_wasm_utils = __esm({
"web/lib/wasm/wasm-utils.ts"() {
"use strict";
init_wasm_factory();
allocWasmString = (data, allocs) => {
const wasm2 = getInstance();
const dataLength = wasm2.lengthBytesUTF8(data) + 1;
const dataOffset = wasm2._malloc(dataLength);
wasm2.stringToUTF8(data, dataOffset, dataLength);
allocs.push(dataOffset);
return dataOffset;
};
iterateExtraOptions = (options, prefix, seen, handler) => {
if (typeof options == "object" && options !== null) {
if (seen.has(options)) {
throw new Error("Circular reference in options");
} else {
seen.add(options);
}
}
Object.entries(options).forEach(([key, value]) => {
const name = prefix ? prefix + key : key;
if (typeof value === "object") {
iterateExtraOptions(value, name + ".", seen, handler);
} else if (typeof value === "string" || typeof value === "number") {
handler(name, value.toString());
} else if (typeof value === "boolean") {
handler(name, value ? "1" : "0");
} else {
throw new Error(`Can't handle extra config type: ${typeof value}`);
}
});
};
checkLastError = (message) => {
const wasm2 = getInstance();
const stack = wasm2.stackSave();
try {
const paramsOffset = wasm2.stackAlloc(8);
wasm2._OrtGetLastError(paramsOffset, paramsOffset + 4);
const errorCode = wasm2.HEAP32[paramsOffset / 4];
const errorMessagePointer = wasm2.HEAPU32[paramsOffset / 4 + 1];
const errorMessage = errorMessagePointer ? wasm2.UTF8ToString(errorMessagePointer) : "";
throw new Error(`${message} ERROR_CODE: ${errorCode}, ERROR_MESSAGE: ${errorMessage}`);
} finally {
wasm2.stackRestore(stack);
}
};
}
});
// web/lib/wasm/run-options.ts
var setRunOptions;
var init_run_options = __esm({
"web/lib/wasm/run-options.ts"() {
"use strict";
init_wasm_factory();
init_wasm_utils();
setRunOptions = (options) => {
const wasm2 = getInstance();
let runOptionsHandle = 0;
const allocs = [];
const runOptions = options || {};
try {
if (options?.logSeverityLevel === void 0) {
runOptions.logSeverityLevel = 2;
} else if (typeof options.logSeverityLevel !== "number" || !Number.isInteger(options.logSeverityLevel) || options.logSeverityLevel < 0 || options.logSeverityLevel > 4) {
throw new Error(`log serverity level is not valid: ${options.logSeverityLevel}`);
}
if (options?.logVerbosityLevel === void 0) {
runOptions.logVerbosityLevel = 0;
} else if (typeof options.logVerbosityLevel !== "number" || !Number.isInteger(options.logVerbosityLevel)) {
throw new Error(`log verbosity level is not valid: ${options.logVerbosityLevel}`);
}
if (options?.terminate === void 0) {
runOptions.terminate = false;
}
let tagDataOffset = 0;
if (options?.tag !== void 0) {
tagDataOffset = allocWasmString(options.tag, allocs);
}
runOptionsHandle = wasm2._OrtCreateRunOptions(
runOptions.logSeverityLevel,
runOptions.logVerbosityLevel,
!!runOptions.terminate,
tagDataOffset
);
if (runOptionsHandle === 0) {
checkLastError("Can't create run options.");
}
if (options?.extra !== void 0) {
iterateExtraOptions(options.extra, "", /* @__PURE__ */ new WeakSet(), (key, value) => {
const keyDataOffset = allocWasmString(key, allocs);
const valueDataOffset = allocWasmString(value, allocs);
if (wasm2._OrtAddRunConfigEntry(runOptionsHandle, keyDataOffset, valueDataOffset) !== 0) {
checkLastError(`Can't set a run config entry: ${key} - ${value}.`);
}
});
}
return [runOptionsHandle, allocs];
} catch (e) {
if (runOptionsHandle !== 0) {
wasm2._OrtReleaseRunOptions(runOptionsHandle);
}
allocs.forEach((alloc) => wasm2._free(alloc));
throw e;
}
};
}
});
// web/lib/wasm/session-options.ts
var getGraphOptimzationLevel, getExecutionMode, appendDefaultOptions, setExecutionProviders, setSessionOptions;
var init_session_options = __esm({
"web/lib/wasm/session-options.ts"() {
"use strict";
init_wasm_factory();
init_wasm_utils();
getGraphOptimzationLevel = (graphOptimizationLevel) => {
switch (graphOptimizationLevel) {
case "disabled":
return 0;
case "basic":
return 1;
case "extended":
return 2;
case "all":
return 99;
default:
throw new Error(`unsupported graph optimization level: ${graphOptimizationLevel}`);
}
};
getExecutionMode = (executionMode) => {
switch (executionMode) {
case "sequential":
return 0;
case "parallel":
return 1;
default:
throw new Error(`unsupported execution mode: ${executionMode}`);
}
};
appendDefaultOptions = (options) => {
if (!options.extra) {
options.extra = {};
}
if (!options.extra.session) {
options.extra.session = {};
}
const session = options.extra.session;
if (!session.use_ort_model_bytes_directly) {
session.use_ort_model_bytes_directly = "1";
}
if (options.executionProviders && options.executionProviders.some((ep) => (typeof ep === "string" ? ep : ep.name) === "webgpu")) {
options.enableMemPattern = false;
}
};
setExecutionProviders = (sessionOptionsHandle, executionProviders, allocs) => {
for (const ep of executionProviders) {
let epName = typeof ep === "string" ? ep : ep.name;
switch (epName) {
case "webnn":
epName = "WEBNN";
if (typeof ep !== "string") {
const webnnOptions = ep;
const deviceType = webnnOptions?.deviceType;
if (deviceType) {
const keyDataOffset = allocWasmString("deviceType", allocs);
const valueDataOffset = allocWasmString(deviceType, allocs);
if (getInstance()._OrtAddSessionConfigEntry(sessionOptionsHandle, keyDataOffset, valueDataOffset) !== 0) {
checkLastError(`Can't set a session config entry: 'deviceType' - ${deviceType}.`);
}
}
}
break;
case "webgpu":
epName = "JS";
if (typeof ep !== "string") {
const webgpuOptions = ep;
if (webgpuOptions?.preferredLayout) {
if (webgpuOptions.preferredLayout !== "NCHW" && webgpuOptions.preferredLayout !== "NHWC") {
throw new Error(`preferredLayout must be either 'NCHW' or 'NHWC': ${webgpuOptions.preferredLayout}`);
}
const keyDataOffset = allocWasmString("preferredLayout", allocs);
const valueDataOffset = allocWasmString(webgpuOptions.preferredLayout, allocs);
if (getInstance()._OrtAddSessionConfigEntry(sessionOptionsHandle, keyDataOffset, valueDataOffset) !== 0) {
checkLastError(`Can't set a session config entry: 'preferredLayout' - ${webgpuOptions.preferredLayout}.`);
}
}
}
break;
case "wasm":
case "cpu":
continue;
default:
throw new Error(`not supported execution provider: ${epName}`);
}
const epNameDataOffset = allocWasmString(epName, allocs);
if (getInstance()._OrtAppendExecutionProvider(sessionOptionsHandle, epNameDataOffset) !== 0) {
checkLastError(`Can't append execution provider: ${epName}.`);
}
}
};
setSessionOptions = (options) => {
const wasm2 = getInstance();
let sessionOptionsHandle = 0;
const allocs = [];
const sessionOptions = options || {};
appendDefaultOptions(sessionOptions);
try {
const graphOptimizationLevel = getGraphOptimzationLevel(sessionOptions.graphOptimizationLevel ?? "all");
const executionMode = getExecutionMode(sessionOptions.executionMode ?? "sequential");
const logIdDataOffset = typeof sessionOptions.logId === "string" ? allocWasmString(sessionOptions.logId, allocs) : 0;
const logSeverityLevel = sessionOptions.logSeverityLevel ?? 2;
if (!Number.isInteger(logSeverityLevel) || logSeverityLevel < 0 || logSeverityLevel > 4) {
throw new Error(`log serverity level is not valid: ${logSeverityLevel}`);
}
const logVerbosityLevel = sessionOptions.logVerbosityLevel ?? 0;
if (!Number.isInteger(logVerbosityLevel) || logVerbosityLevel < 0 || logVerbosityLevel > 4) {
throw new Error(`log verbosity level is not valid: ${logVerbosityLevel}`);
}
const optimizedModelFilePathOffset = typeof sessionOptions.optimizedModelFilePath === "string" ? allocWasmString(sessionOptions.optimizedModelFilePath, allocs) : 0;
sessionOptionsHandle = wasm2._OrtCreateSessionOptions(
graphOptimizationLevel,
!!sessionOptions.enableCpuMemArena,
!!sessionOptions.enableMemPattern,
executionMode,
!!sessionOptions.enableProfiling,
0,
logIdDataOffset,
logSeverityLevel,
logVerbosityLevel,
optimizedModelFilePathOffset
);
if (sessionOptionsHandle === 0) {
checkLastError("Can't create session options.");
}
if (sessionOptions.executionProviders) {
setExecutionProviders(sessionOptionsHandle, sessionOptions.executionProviders, allocs);
}
if (sessionOptions.enableGraphCapture !== void 0) {
if (typeof sessionOptions.enableGraphCapture !== "boolean") {
throw new Error(`enableGraphCapture must be a boolean value: ${sessionOptions.enableGraphCapture}`);
}
const keyDataOffset = allocWasmString("enableGraphCapture", allocs);
const valueDataOffset = allocWasmString(sessionOptions.enableGraphCapture.toString(), allocs);
if (wasm2._OrtAddSessionConfigEntry(sessionOptionsHandle, keyDataOffset, valueDataOffset) !== 0) {
checkLastError(
`Can't set a session config entry: 'enableGraphCapture' - ${sessionOptions.enableGraphCapture}.`
);
}
}
if (sessionOptions.freeDimensionOverrides) {
for (const [name, value] of Object.entries(sessionOptions.freeDimensionOverrides)) {
if (typeof name !== "string") {
throw new Error(`free dimension override name must be a string: ${name}`);
}
if (typeof value !== "number" || !Number.isInteger(value) || value < 0) {
throw new Error(`free dimension override value must be a non-negative integer: ${value}`);
}
const nameOffset = allocWasmString(name, allocs);
if (wasm2._OrtAddFreeDimensionOverride(sessionOptionsHandle, nameOffset, value) !== 0) {
checkLastError(`Can't set a free dimension override: ${name} - ${value}.`);
}
}
}
if (sessionOptions.extra !== void 0) {
iterateExtraOptions(sessionOptions.extra, "", /* @__PURE__ */ new WeakSet(), (key, value) => {
const keyDataOffset = allocWasmString(key, allocs);
const valueDataOffset = allocWasmString(value, allocs);
if (wasm2._OrtAddSessionConfigEntry(sessionOptionsHandle, keyDataOffset, valueDataOffset) !== 0) {
checkLastError(`Can't set a session config entry: ${key} - ${value}.`);
}
});
}
return [sessionOptionsHandle, allocs];
} catch (e) {
if (sessionOptionsHandle !== 0) {
wasm2._OrtReleaseSessionOptions(sessionOptionsHandle);
}
allocs.forEach((alloc) => wasm2._free(alloc));
throw e;
}
};
}
});
// web/lib/wasm/wasm-common.ts
var tensorDataTypeStringToEnum, tensorDataTypeEnumToString, calculateTensorSizeInBytes, tensorTypeToTypedArrayConstructor, logLevelStringToEnum, isGpuBufferSupportedType, isMLTensorSupportedType, dataLocationStringToEnum;
var init_wasm_common = __esm({
"web/lib/wasm/wasm-common.ts"() {
"use strict";
tensorDataTypeStringToEnum = (type) => {
switch (type) {
case "int8":
return 3 /* int8 */;
case "uint8":
return 2 /* uint8 */;
case "bool":
return 9 /* bool */;
case "int16":
return 5 /* int16 */;
case "uint16":
return 4 /* uint16 */;
case "int32":
return 6 /* int32 */;
case "uint32":
return 12 /* uint32 */;
case "float16":
return 10 /* float16 */;
case "float32":
return 1 /* float */;
case "float64":
return 11 /* double */;
case "string":
return 8 /* string */;
case "int64":
return 7 /* int64 */;
case "uint64":
return 13 /* uint64 */;
case "int4":
return 22 /* int4 */;
case "uint4":
return 21 /* uint4 */;
default:
throw new Error(`unsupported data type: ${type}`);
}
};
tensorDataTypeEnumToString = (typeProto) => {
switch (typeProto) {
case 3 /* int8 */:
return "int8";
case 2 /* uint8 */:
return "uint8";
case 9 /* bool */:
return "bool";
case 5 /* int16 */:
return "int16";
case 4 /* uint16 */:
return "uint16";
case 6 /* int32 */:
return "int32";
case 12 /* uint32 */:
return "uint32";
case 10 /* float16 */:
return "float16";
case 1 /* float */:
return "float32";
case 11 /* double */:
return "float64";
case 8 /* string */:
return "string";
case 7 /* int64 */:
return "int64";
case 13 /* uint64 */:
return "uint64";
case 22 /* int4 */:
return "int4";
case 21 /* uint4 */:
return "uint4";
default:
throw new Error(`unsupported data type: ${typeProto}`);
}
};
calculateTensorSizeInBytes = (dateType, dimsOrSize) => {
const elementSize = [
-1,
// undefined = 0
4,
// float = 1
1,
// uint8 = 2
1,
// int8 = 3
2,
// uint16 = 4
2,
// int16 = 5
4,
// int32 = 6
8,
// int64 = 7
-1,
// string = 8
1,
// bool = 9
2,
// float16 = 10
8,
// double = 11
4,
// uint32 = 12
8,
// uint64 = 13
-1,
// complex64 = 14
-1,
// complex128 = 15
-1,
// bfloat16 = 16
-1,
// FLOAT8E4M3FN = 17
-1,
// FLOAT8E4M3FNUZ = 18
-1,
// FLOAT8E5M2 = 19
-1,
// FLOAT8E5M2FNUZ = 20
0.5,
// uint4 = 21
0.5
// int4 = 22
][dateType];
const size = typeof dimsOrSize === "number" ? dimsOrSize : dimsOrSize.reduce((a, b) => a * b, 1);
return elementSize > 0 ? Math.ceil(size * elementSize) : void 0;
};
tensorTypeToTypedArrayConstructor = (type) => {
switch (type) {
case "float16":
return typeof Float16Array !== "undefined" && Float16Array.from ? Float16Array : Uint16Array;
case "float32":
return Float32Array;
case "uint8":
return Uint8Array;
case "int8":
return Int8Array;
case "uint16":
return Uint16Array;
case "int16":
return Int16Array;
case "int32":
return Int32Array;
case "bool":
return Uint8Array;
case "float64":
return Float64Array;
case "uint32":
return Uint32Array;
case "int64":
return BigInt64Array;
case "uint64":
return BigUint64Array;
default:
throw new Error(`unsupported type: ${type}`);
}
};
logLevelStringToEnum = (logLevel) => {
switch (logLevel) {
case "verbose":
return 0;
case "info":
return 1;
case "warning":
return 2;
case "error":
return 3;
case "fatal":
return 4;
default:
throw new Error(`unsupported logging level: ${logLevel}`);
}
};
isGpuBufferSupportedType = (type) => type === "float32" || type === "float16" || type === "int32" || type === "int64" || type === "uint32" || type === "uint8" || type === "bool" || type === "uint4" || type === "int4";
isMLTensorSupportedType = (type) => type === "float32" || type === "float16" || type === "int32" || type === "int64" || type === "uint32" || type === "uint64" || type === "int8" || type === "uint8" || type === "bool";
dataLocationStringToEnum = (location2) => {
switch (location2) {
case "none":
return 0;
case "cpu":
return 1;
case "cpu-pinned":
return 2;
case "texture":
return 3;
case "gpu-buffer":
return 4;
case "ml-tensor":
return 5;
default:
throw new Error(`unsupported data location: ${location2}`);
}
};
}
});
// web/lib/wasm/wasm-utils-load-file.ts
var loadFile;
var init_wasm_utils_load_file = __esm({
"web/lib/wasm/wasm-utils-load-file.ts"() {
"use strict";
init_wasm_utils_env();
loadFile = async (file) => {
if (typeof file === "string") {
if (isNode) {
try {
const { readFile } = __require("node:fs/promises");
return new Uint8Array(await readFile(file));
} catch (e) {
if (e.code === "ERR_FS_FILE_TOO_LARGE") {
const { createReadStream } = __require("node:fs");
const stream = createReadStream(file);
const chunks = [];
for await (const chunk of stream) {
chunks.push(chunk);
}
return new Uint8Array(Buffer.concat(chunks));
}
throw e;
}
} else {
const response = await fetch(file);
if (!response.ok) {
throw new Error(`failed to load external data file: ${file}`);
}
const contentLengthHeader = response.headers.get("Content-Length");
const fileSize = contentLengthHeader ? parseInt(contentLengthHeader, 10) : 0;
if (fileSize < 1073741824) {
return new Uint8Array(await response.arrayBuffer());
} else {
if (!response.body) {
throw new Error(`failed to load external data file: ${file}, no response body.`);
}
const reader = response.body.getReader();
let buffer;
try {
buffer = new ArrayBuffer(fileSize);
} catch (e) {
if (e instanceof RangeError) {
const pages = Math.ceil(fileSize / 65536);
buffer = new WebAssembly.Memory({ initial: pages, maximum: pages }).buffer;
} else {
throw e;
}
}
let offset = 0;
while (true) {
const { done, value } = await reader.read();
if (done) {
break;
}
const chunkSize = value.byteLength;
const chunk = new Uint8Array(buffer, offset, chunkSize);
chunk.set(value);
offset += chunkSize;
}
return new Uint8Array(buffer, 0, fileSize);
}
}
} else if (file instanceof Blob) {
return new Uint8Array(await file.arrayBuffer());
} else if (file instanceof Uint8Array) {
return file;
} else {
return new Uint8Array(file);
}
};
}
});
// web/lib/wasm/jsep/log.ts
var logLevelPrefix, doLog, configLogLevel, debug, configureLogger, LOG, LOG_DEBUG;
var init_log = __esm({
"web/lib/wasm/jsep/log.ts"() {
"use strict";
init_wasm_common();
logLevelPrefix = ["V", "I", "W", "E", "F"];
doLog = (level, message) => {
console.log(`[${logLevelPrefix[level]},${(/* @__PURE__ */ new Date()).toISOString()}]${message}`);
};
configureLogger = ($configLogLevel, $debug) => {
configLogLevel = $configLogLevel;
debug = $debug;
};
LOG = (logLevel, msg) => {
const messageLevel = logLevelStringToEnum(logLevel);
const configLevel = logLevelStringToEnum(configLogLevel);
if (messageLevel >= configLevel) {
doLog(messageLevel, typeof msg === "function" ? msg() : msg);
}
};
LOG_DEBUG = (...args) => {
if (debug) {
LOG(...args);
}
};
}
});
// web/lib/wasm/jsep/tensor-view.ts
var createView;
var init_tensor_view = __esm({
"web/lib/wasm/jsep/tensor-view.ts"() {
"use strict";
init_wasm_common();
createView = (dataBuffer, type) => new (tensorTypeToTypedArrayConstructor(type))(dataBuffer);
}
});
// web/lib/wasm/jsep/webgpu/types.ts
var init_types = __esm({
"web/lib/wasm/jsep/webgpu/types.ts"() {
"use strict";
}
});
// web/lib/wasm/jsep/webgpu/gpu-data-manager.ts
var bucketFreelist, bucketArr, calcNormalizedBufferSize, calcBucketBufferSize, guid, createNewGpuDataId, downloadGpuData, GpuDataManagerImpl, createGpuDataManager;
var init_gpu_data_manager = __esm({
"web/lib/wasm/jsep/webgpu/gpu-data-manager.ts"() {
"use strict";
init_log();
init_types();
bucketFreelist = /* @__PURE__ */ new Map([
[64, 250],
[128, 200],
[256, 200],
[512, 200],
[2048, 230],
[4096, 200],
[8192, 50],
[16384, 50],
[32768, 50],
[65536, 50],
[131072, 50],
[262144, 50],
[524288, 50],
[1048576, 50],
[2097152, 30],
[4194304, 20],
[8388608, 10],
[12582912, 10],
[16777216, 10],
[26214400, 15],
[33554432, 22],
[44236800, 2],
[58982400, 6],
// we don't want to cache the bucket sizes below but not caching them
// results in some major performance hits for models like sd-turbo.
[67108864, 6],
[134217728, 6],
[167772160, 6]
]);
bucketArr = [];
calcNormalizedBufferSize = (size) => Math.ceil(size / 16) * 16;
calcBucketBufferSize = (size) => {
for (let idx = 0; idx < bucketArr.length; idx++) {
const sizeForBucket = bucketArr[idx];
if (size <= sizeForBucket) {
return sizeForBucket;
}
}
return Math.ceil(size / 16) * 16;
};
guid = 1;
createNewGpuDataId = () => guid++;
downloadGpuData = async (backend, gpuBuffer, originalSize, getTargetBuffer) => {
const bufferSize = calcNormalizedBufferSize(originalSize);
const gpuReadBuffer = backend.device.createBuffer(
// eslint-disable-next-line no-bitwise
{ size: bufferSize, usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ }
);
try {
const commandEncoder = backend.getCommandEncoder();
backend.endComputePass();
commandEncoder.copyBufferToBuffer(
gpuBuffer,
0,
gpuReadBuffer,
0,
bufferSize
);
backend.flush();
await gpuReadBuffer.mapAsync(GPUMapMode.READ);
const arrayBuffer = gpuReadBuffer.getMappedRange();
if (getTargetBuffer) {
const targetBuffer = getTargetBuffer();
targetBuffer.set(new Uint8Array(arrayBuffer, 0, originalSize));
return targetBuffer;
} else {
return new Uint8Array(arrayBuffer.slice(0, originalSize));
}
} finally {
gpuReadBuffer.destroy();
}
};
GpuDataManagerImpl = class {
constructor(backend) {
this.backend = backend;
this.storageCache = /* @__PURE__ */ new Map();
this.freeBuffers = /* @__PURE__ */ new Map();
this.freeUniformBuffers = /* @__PURE__ */ new Map();
this.buffersForUploadingPending = [];
this.buffersPending = [];
this.capturedPendingBuffers = /* @__PURE__ */ new Map();
for (const [key] of bucketFreelist) {
bucketArr.push(key);
this.freeBuffers.set(key, []);
this.freeUniformBuffers.set(key, []);
}
}
upload(id, data) {
const srcArrayBuffer = data.buffer;
const srcOffset = data.byteOffset;
const srcLength = data.byteLength;
const size = calcNormalizedBufferSize(srcLength);
const gpuDataCache = this.storageCache.get(id);
if (!gpuDataCache) {
throw new Error("gpu data for uploading does not exist");
}
if (gpuDataCache.originalSize !== srcLength) {
throw new Error(`inconsistent data size. gpu data size=${gpuDataCache.originalSize}, data size=${srcLength}`);
}
const gpuBufferForUploading = this.backend.device.createBuffer(
// eslint-disable-next-line no-bitwise
{ mappedAtCreation: true, size, usage: GPUBufferUsage.MAP_WRITE | GPUBufferUsage.COPY_SRC }
);
const arrayBuffer = gpuBufferForUploading.getMappedRange();
new Uint8Array(arrayBuffer).set(new Uint8Array(srcArrayBuffer, srcOffset, srcLength));
gpuBufferForUploading.unmap();
const commandEncoder = this.backend.getCommandEncoder();
this.backend.endComputePass();
commandEncoder.copyBufferToBuffer(gpuBufferForUploading, 0, gpuDataCache.gpuData.buffer, 0, size);
LOG_DEBUG("verbose", () => `[WebGPU] GpuDataManager.upload(id=${id})`);
this.buffersForUploadingPending.push(gpuBufferForUploading);
}
memcpy(sourceId, destinationId) {
const sourceGpuDataCache = this.storageCache.get(sourceId);
if (!sourceGpuDataCache) {
throw new Error("source gpu data for memcpy does not exist");
}
const destinationGpuDataCache = this.storageCache.get(destinationId);
if (!destinationGpuDataCache) {
throw new Error("destination gpu data for memcpy does not exist");
}
if (sourceGpuDataCache.originalSize !== destinationGpuDataCache.originalSize) {
throw new Error("inconsistent source and destination gpu data size");
}
const size = calcNormalizedBufferSize(sourceGpuDataCache.originalSize);
const commandEncoder = this.backend.getCommandEncoder();
this.backend.endComputePass();
commandEncoder.copyBufferToBuffer(
sourceGpuDataCache.gpuData.buffer,
0,
destinationGpuDataCache.gpuData.buffer,
0,
size
);
}
registerExternalBuffer(buffer, originalSize, previous) {
let id;
if (previous) {
id = previous[0];
if (buffer === previous[1]) {
LOG_DEBUG(
"verbose",
() => `[WebGPU] GpuDataManager.registerExternalBuffer(size=${originalSize}) => id=${id}, buffer is the same, skip.`
);
return id;
} else if (this.backend.capturedCommandList.has(this.backend.currentSessionId)) {
throw new Error(`Registering a different external buffer under graph capture mode is not supported yet.
Please use the previous external buffer!`);
}
} else {
id = createNewGpuDataId();
}
this.storageCache.set(id, { gpuData: { id, type: 0 /* default */, buffer }, originalSize });
LOG_DEBUG(
"verbose",
() => `[WebGPU] GpuDataManager.registerExternalBuffer(size=${originalSize}) => id=${id}, registered.`
);
return id;
}
unregisterExternalBuffer(id) {
if (id !== void 0) {
this.storageCache.delete(id);
LOG_DEBUG("verbose", () => `[WebGPU] GpuDataManager.unregisterExternalBuffer() => id=${id}`);
}
}
// eslint-disable-next-line no-bitwise
create(size, usage = GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST) {
const bufferSize = calcBucketBufferSize(size);
let gpuBuffer;
const isStorage = (usage & GPUBufferUsage.STORAGE) === GPUBufferUsage.STORAGE;
const isUniform = (usage & GPUBufferUsage.UNIFORM) === GPUBufferUsage.UNIFORM;
if (isStorage || isUniform) {
const freeBuffers = isStorage ? this.freeBuffers : this.freeUniformBuffers;
const buffers = freeBuffers.get(bufferSize);
if (!buffers) {
gpuBuffer = this.backend.device.createBuffer({ size: bufferSize, usage });
} else {
if (buffers.length > 0) {
gpuBuffer = buffers.pop();
} else {
gpuBuffer = this.backend.device.createBuffer({ size: bufferSize, usage });
}
}
} else {
gpuBuffer = this.backend.device.createBuffer({ size: bufferSize, usage });
}
const gpuData = { id: createNewGpuDataId(), type: 0 /* default */, buffer: gpuBuffer };
this.storageCache.set(gpuData.id, { gpuData, originalSize: size });
LOG_DEBUG("verbose", () => `[WebGPU] GpuDataManager.create(size=${size}) => id=${gpuData.id}`);
return gpuData;
}
get(id) {
return this.storageCache.get(id)?.gpuData;
}
release(id) {
const cachedData = this.storageCache.get(id);
if (!cachedData) {
throw new Error("releasing data does not exist");
}
LOG_DEBUG("verbose", () => `[WebGPU] GpuDataManager.release(id=${id}), gpuDataId=${cachedData.gpuData.id}`);
this.storageCache.delete(id);
this.buffersPending.push(cachedData.gpuData.buffer);
return cachedData.originalSize;
}
async download(id, getTargetBuffer) {
const cachedData = this.storageCache.get(id);
if (!cachedData) {
throw new Error("data does not exist");
}
await downloadGpuData(this.backend, cachedData.gpuData.buffer, cachedData.originalSize, getTargetBuffer);
}
refreshPendingBuffers() {
for (const buffer of this.buffersForUploadingPending) {
buffer.destroy();
}
this.buffersForUploadingPending = [];
if (this.buffersPending.length === 0) {
return;
}
if (this.backend.sessionStatus === "default") {
for (const buffer of this.buffersPending) {
const maxInFreeList = bucketFreelist.get(buffer.size);
if ((buffer.usage & GPUBufferUsage.STORAGE) === GPUBufferUsage.STORAGE) {
const freelist = this.freeBuffers.get(buffer.size) || [];
if (maxInFreeList === void 0 || freelist.length >= maxInFreeList) {
buffer.destroy();
} else {
freelist.push(buffer);
}
} else if ((buffer.usage & GPUBufferUsage.UNIFORM) === GPUBufferUsage.UNIFORM) {
const freelist = this.freeUniformBuffers.get(buffer.size) || [];
if (maxInFreeList === void 0 || freelist.length >= maxInFreeList) {
buffer.destroy();
} else {
freelist.push(buffer);
}
} else {
buffer.destroy();
}
}
this.buffersPending = [];
} else {
let capturedBuffers = this.capturedPendingBuffers.get(this.backend.currentSessionId);
if (!capturedBuffers) {
capturedBuffers = [];
this.capturedPendingBuffers.set(this.backend.currentSessionId, capturedBuffers);
}
for (const buffer of this.buffersPending) {
capturedBuffers.push(buffer);
}
this.buffersPending = [];
}
}
dispose() {
this.freeBuffers.forEach((buffers) => {
buffers.forEach((buffer) => {
buffer.destroy();
});
});
this.freeUniformBuffers.forEach((buffers) => {
buffers.forEach((buffer) => {
buffer.destroy();
});
});
this.storageCache.forEach((storage) => {
storage.gpuData.buffer.destroy();
});
this.capturedPendingBuffers.forEach((buffers) => {
buffers.forEach((buffer) => {
buffer.destroy();
});
});
this.storageCache = /* @__PURE__ */ new Map();
this.freeBuffers = /* @__PURE__ */ new Map();
this.freeUniformBuffers = /* @__PURE__ */ new Map();
this.capturedPendingBuffers = /* @__PURE__ */ new Map();
}
onReleaseSession(sessionId) {
const pendingBuffers = this.capturedPendingBuffers.get(sessionId);
if (pendingBuffers) {
pendingBuffers.forEach((buffer) => {
buffer.destroy();
});
this.capturedPendingBuffers.delete(sessionId);
}
}
};
createGpuDataManager = (...args) => new GpuDataManagerImpl(...args);
}
});
// web/lib/wasm/jsep/webgpu/attribute-with-cache-key.ts
var AttributeWithCacheKeyImpl, createAttributeWithCacheKey;
var init_attribute_with_cache_key = __esm({
"web/lib/wasm/jsep/webgpu/attribute-with-cache-key.ts"() {
"use strict";
AttributeWithCacheKeyImpl = class {
constructor(attribute) {
Object.assign(this, attribute);
}
get cacheKey() {
if (!this.key) {
this.key = Object.getOwnPropertyNames(this).sort().map((name) => `${this[name]}`).join(";");
}
return this.key;
}
};
createAttributeWithCacheKey = (attribute) => new AttributeWithCacheKeyImpl(attribute);
}
});
// web/lib/wasm/jsep/util.ts
var MatMulUtil, BroadcastUtil, ShapeUtil, PoolConvUtil, GemmUtil, MIN_CLIP, MAX_CLIP;
var init_util = __esm({
"web/lib/wasm/jsep/util.ts"() {
"use strict";
MatMulUtil = class {
/**
* Calculate the expected shape when matrix multiplication
* @param a The shape of tensor A. Should be a tuple of 2 positive integers
* @param b The shape of tensor B. Should be a tuple of 2 positive integers
* @returns The expected shape of the result, or undefined if N/A
*/
static calcMatMulShape(a, b) {
return a[1] !== b[0] ? void 0 : [a[0], b[1]];
}
};
BroadcastUtil = class {
/**
* Calculate the expected shape when broadcasting 2 tensors
* @param a The shape of tensor A. Should be an array of positive integers
* @param b The shape of tensor B. Should be an array of positive integers
* @param isMatMul Whether the operation is MatMul
* @returns The expected shape of the result, or undefined if N/A
*/
static calcShape(adims, bdims, isMatMul = false) {
const arank = adims.length;
const brank = bdims.length;
if (arank === 0) {
return bdims;
}
if (brank === 0) {
return adims;
}
const crank = Math.max(adims.length, bdims.length);
const cdims = new Array(crank);
if (isMatMul) {
if (arank < 2 || brank < 2) {
return void 0;
}
const cShapeMatMul = MatMulUtil.calcMatMulShape(
[adims[arank - 2], adims[arank - 1]],
[bdims[brank - 2], bdims[brank - 1]]
);
if (cShapeMatMul === void 0) {
return void 0;
}
[cdims[crank - 2], cdims[crank - 1]] = cShapeMatMul;
}
for (let i = isMatMul ? 3 : 1; i <= crank; i++) {
const aLen = arank - i < 0 ? 1 : adims[arank - i];
const bLen = brank - i < 0 ? 1 : bdims[brank - i];
if (aLen !== bLen && aLen > 1 && bLen > 1) {
return void 0;
}
const max = Math.max(aLen, bLen);
if (aLen && bLen) {
cdims[crank - i] = Math.max(aLen, bLen);
} else {
if (max > 1) {
return void 0;
}
cdims[crank - i] = 0;
}
}
return cdims;
}
/**
* Determine if a shape is unidirectional broadcastable to another shape
* @param shape The input shape
* @param finalShape The desired shape after broadcasting
*/
static isValidBroadcast(shape, finalShape) {
const inputRank = shape.length;
const finalRank = finalShape.length;
if (inputRank > finalRank) {
return false;
}
for (let i = 1; i <= inputRank; i++) {
if (shape[inputRank - i] !== 1 && shape[inputRank - i] !== finalShape[finalRank - i]) {
return false;
}
}
return true;
}
};
ShapeUtil = class _ShapeUtil {
/**
* calculate the size (number of elements)
*/
static size(dims) {
return _ShapeUtil.getSizeFromDimensionRange(dims, 0, dims.length);
}
/**
* convert dims corresponding to type change to pack. ex. uint8 data to uint32
*/
static convertShape(dims, size = 4) {
const rank = dims.length;
if (rank === 0) {
return [];
}
const newDims = new Array(rank);
let i = rank - 1;
while (i >= 0) {
if (dims[i] % size === 0) {
newDims[i] = dims[i] / size;
break;
}
if (size % dims[i] !== 0) {
throw new Error("cannot convert shape");
}
newDims[i] = 1;
size /= dims[i];
i--;
}
for (i--; i >= 0; i--) {
newDims[i] = dims[i];
}
return newDims;
}
/**
* calculate the size (number of elements) from the given axis (inclusive)
*/
static sizeFromDimension(dims, axis) {
if (axis < 0 || axis > dims.length) {
throw new Error(`invalid dimension of ${axis} for sizeFromDimension as Tensor has ${dims.length} dimensions.`);
}
return _ShapeUtil.getSizeFromDimensionRange(dims, axis, dims.length);
}
/**
* calculate the size (number of elements) to the given axis (exclusive)
*/
static sizeToDimension(dims, axis) {
if (axis < 0 || axis > dims.length) {
throw new Error(`invalid dimension of ${axis} for sizeToDimension as Tensor has ${dims.length} dimensions.`);
}
return _ShapeUtil.getSizeFromDimensionRange(dims, 0, axis);
}
/**
* calculate the size (number of elements) from and to the given axis [start, end)
*/
static getSizeFromDimensionRange(dims, start, end) {
let size = 1;
for (let i = start; i < end; i++) {
if (dims[i] < 0) {
throw new Error(
// eslint-disable-next-line max-len
"cannot get valid size from specified dimension range. Most likely the range contains negative values in them."
);
}
size *= dims[i];
}
return size;
}
static computeStrides(dims) {
const rank = dims.length;
if (rank === 0) {
return [];
} else if (rank === 1) {
return [1];
}
const strides = new Array(rank);
strides[rank - 1] = 1;
strides[rank - 2] = dims[rank - 1];
for (let i = rank - 3; i >= 0; --i) {
strides[i] = strides[i + 1] * dims[i + 1];
}
return strides;
}
/**
* normailze axis of range [-r, r) into [0, r).
*/
static normalizeAxis(axis, tensorRank) {
if (axis < -tensorRank && axis >= tensorRank) {
throw new Error("unsupported axis for this operation.");
}
return axis < 0 ? axis + tensorRank : axis;
}
static normalizeAxes(axes, tensorRank) {
return axes.map((x) => this.normalizeAxis(x, tensorRank ?? axes.length));
}
/**
* Sorts a given array based on the indices in the Perm array
* Used in Transpose
* @param a Array to be sorted such as dims or strides
* @param perm Perm given; if null a will be reversed
*/
static sortBasedOnPerm(a, perm) {
if (perm) {
return perm.map((v) => a[v]);
} else {
return a.slice().reverse();
}
}
/**
* Pads a given shape according to the padding values
* @param dims shape of the Tensor to be padded
* @param pad pad values
*/
static padShape(dims, pad2) {
const rank = dims.length;
return dims.map((v, i) => v + pad2[i] + pad2[i + rank]);
}
/**
* Determines if the two shapes are identical
* @param shape1
* @param shape2
*/
static areEqual(shape1, shape2) {
if (shape1.length !== shape2.length) {
return false;
}
return shape1.every((v, i) => v === shape2[i]);
}
};
PoolConvUtil = class _PoolConvUtil {
/**
* Adjust the kernel, strides, pads to correct rank. Set to default value if not present
* @param isGlobalOperator If true, perform global pooling.
* @param inputDims The input tensor dimension.
* @param kernelShape The size of the kernel along each axis.
* @param strides Stride along each axis.
* @param dilations Dilation along each axis.
* @param pads Padding for the beginning and ending along each axis.
*/
static adjustPoolAttributes(isGlobalOperator, inputDims, kernelShape, strides, dilations, pads) {
if (!isGlobalOperator && kernelShape.length !== inputDims.length - 2) {
throw new Error("length of specified kernel shapes should be 2 less than length of input dimensions");
}
if (isGlobalOperator) {
for (let dim = 0; dim < inputDims.length - 2; dim++) {
if (dim >= kernelShape.length) {
kernelShape.push(inputDims[dim + 2]);
} else {
kernelShape[dim] = inputDims[dim + 2];
}
}
}
for (let dim = 0; dim < kernelShape.length; dim++) {
if (dim < strides.length) {
if (strides[dim] < 0) {
throw new Error("strides should be greater than or equal to 1");
}
} else {
strides.push(1);
}
}
for (let dim = 0; dim < kernelShape.length; dim++) {
if (dim < dilations.length) {
if (dilations[dim] < 0) {
throw new Error("dilations should be greater than or equal to 1");
}
} else {
dilations.push(1);
}
}
for (let dim = 0; dim < kernelShape.length * 2; dim++) {
if (dim < pads.length) {
if (pads[dim] < 0) {
throw new Error("pad should be greater than or equal to 1");
}
} else {
pads.push(0);
}
}
for (let dim = 0; dim < kernelShape.length; dim++) {
if (kernelShape[dim] <= 0) {
throw new Error("kernel shapes need to be greater than 0");
}
if (pads[dim] >= kernelShape[dim] || pads[dim + kernelShape.length] >= kernelShape[dim]) {
throw new Error("pads should be smaller than kernel");
}
}
}
// adjust pad values based on 'autoPad' attribute
static adjustPadsBasedOnAutoPad(inputDims, strides, dilations, kernelShape, pads, isChannelLast, autoPad) {
if (!autoPad) {
return;
}
if (pads.length !== 2 * (inputDims.length - 2)) {
throw new Error("length of pads should be twice the length of data dimensions");
}
if (strides.length !== inputDims.length - 2) {
throw new Error("length of strides should be the length of data dimensions");
}
if (kernelShape.length !== inputDims.length - 2) {
throw new Error("length of kernel shapes should be the length of data dimensions");
}
for (let dim = 0; dim < inputDims.length - 2; dim++) {
_PoolConvUtil.adjustPadAndReturnShape(
inputDims[dim + (isChannelLast ? 1 : 2)],
strides[dim],
dilations[dim],
kernelShape[dim],
pads,
dim,
dim + inputDims.length - 2,
autoPad
);
}
}
/**
* Calculate the output shape for Pool ops based on input attributes. (Should be used only for Pool ops)
* @param isGlobalOperator If true, perform global pooling.
* @param inputDims The input tensor dimension. (inputs[0].dims)
* @param strides Stride along each axis.
* @param dilations Dilation along each axis.
* @param kernelShape The size of the kernel along each axis.
* @param pads Padding for the beginning and ending along each axis.
* @param autoPad DEPRECATED attribute supported for legacy models. Specifies how to implicitly calculate pads in each
* dimension. Can take values NOTSET, SAME_UPPER, SAME_LOWER, or VALID.
*/
static computePoolOutputShape(isGlobalOperator, inputDims, strides, dilations, kernelShape, pads, autoPad) {
if (inputDims.length <= 0) {
throw new Error("input shape must be of size greater than 0");
}
const outputDims = [inputDims[0], inputDims[1]];
_PoolConvUtil.computeShapeHelper(
isGlobalOperator,
inputDims,
outputDims,
strides,
dilations,
kernelShape,
pads,
autoPad
);
return outputDims;
}
/**
* Calculate the output shape for Conv op based on input attributes. (Should be used only for Conv op)
* @param inputDims The input tensor dimension. (inputs[0].dims)
* @param filterDims The filter tensor dimension. (inputs[1].dims)
* @param strides Stride along each axis.
* @param kernelShape The size of the kernel along each axis.
* @param pads Padding for the beginning and ending along each axis.
* @param autoPad DEPRECATED attribute supported for legacy models. Specifies how to implicitly calculate pads in each
* dimension. Can take values NOTSET, SAME_UPPER, SAME_LOWER, or VALID.
*/
static computeConvOutputShape(inputDims, filterDims, strides, dilations, kernelShape, pads, autoPad) {
if (inputDims.length <= 0 || filterDims.length <= 0) {
throw new Error("invalid input tensor dims or invalid filter tensor dims");
}
const outputDims = [inputDims[0], filterDims[0]];
_PoolConvUtil.computeShapeHelper(false, inputDims, outputDims, strides, dilations, kernelShape, pads, autoPad);
return outputDims;
}
// will compute output shapes for data dimensions ONLY (i.e.) no batch size and channels
// called by computePoolOutputShape() and computeConvOutputShape()
// adjust pads based on 'autoPad' attribute prior to shape computation
static computeShapeHelper(isGlobalOperator, inputDims, outputDims, strides, dilations, kernelShape, pads, autoPad) {
if (isGlobalOperator) {
for (let dim = 0; dim < inputDims.length - 2; dim++) {
outputDims.push(1);
}
} else {
for (let dim = 0; dim < inputDims.length - 2; dim++) {
outputDims.push(
_PoolConvUtil.adjustPadAndReturnShape(
inputDims[dim + 2],
strides[dim],
dilations[dim],
kernelShape[dim],
pads,
dim,
dim + inputDims.length - 2,
autoPad
)
);
}
}
}
// helper for computeShapeHelper() and adjustPadsBasedOnAutoPad()
// adjusts pad value for given 'autoPad' string and computes output shape along a particular dimension
static adjustPadAndReturnShape(inSize, stride, dilation, kernel, pads, padHeadIndex, padTailIndex, autoPad) {
const dkernel = dilation * (kernel - 1) + 1;
if (autoPad && autoPad !== "NOTSET") {
switch (autoPad) {
case "VALID":
pads[padHeadIndex] = 0;
pads[padTailIndex] = 0;
return Math.floor((inSize - dkernel) / stride + 1);
case "SAME_LOWER":
case "SAME_UPPER":
if (dilation !== 1) {
throw new Error("Dilation not supported for SAME_UPPER or SAME_LOWER");
} else {
const legacyTargetSize = (inSize + stride - 1) / stride;
const padNeeded = (legacyTargetSize - 1) * stride + kernel - inSize;
pads[padHeadIndex] = autoPad === "SAME_LOWER" ? Math.floor((padNeeded + 1) / 2) : Math.floor(padNeeded / 2);
pads[padTailIndex] = padNeeded - pads[padHeadIndex];
return Math.floor((inSize + padNeeded - kernel) / stride + 1);
}
default:
throw new Error("Unsupported AutoPad type");
}
} else {
return Math.floor((inSize + pads[padHeadIndex] + pads[padTailIndex] - dkernel) / stride + 1);
}
}
};
GemmUtil = class {
// will make sure input shapes are compatible for this op
// and return back the shape of the output in the form of a tuple
// will throw exception if the input shapes are not compatible
static getShapeOfGemmResult(leftShape, transLeft, rightShape, transRight, biasShape) {
if (leftShape.length !== 2 || rightShape.length !== 2) {
throw new Error("shape need to be of size 2");
}
let M;
let K;
let N;
if (transLeft) {
M = leftShape[1];
K = leftShape[0];
} else {
M = leftShape[0];
K = leftShape[1];
}
let kDim = -1;
if (transRight) {
N = rightShape[0];
kDim = 1;
} else {
N = rightShape[1];
kDim = 0;
}
if (rightShape[kDim] !== K) {
throw new Error("dimension mismatch");
}
if (M <= 0 || N <= 0 || K <= 0) {
throw new Error("invalid shape specified");
}
if (biasShape && !BroadcastUtil.isValidBroadcast(biasShape, [M, N])) {
throw new Error("gemm: invalid bias shape for broadcast");
}
return [M, N, K];
}
};
MIN_CLIP = -34028234663852886e22;
MAX_CLIP = 34028234663852886e22;
}
});
// web/lib/wasm/jsep/webgpu/ops/common.ts
var WORKGROUP_SIZE, getWgslMappedType, tensorTypeToWsglStorageType, tensorTypeToWsglValueType, createTensorShapeVariables, getMaxComponents, fillVector, castToF32, sumVector, getElementAt, createIndicesHelper, inputVariable, outputVariable, internalVariable, ShaderHelperImpl, createShaderHelper, getBroadcastDims;
var init_common = __esm({
"web/lib/wasm/jsep/webgpu/ops/common.ts"() {
"use strict";
init_wasm_common();
init_util();
WORKGROUP_SIZE = 64;
getWgslMappedType = (type, components) => {
if (components === 3) {
throw new Error("vec3 has same alignment as vec4, use vec4 instead");
}
switch (type) {
case 10 /* float16 */:
return components > 1 ? `vec${components}<f16>` : "f16";
case 1 /* float */:
return components > 1 ? `vec${components}<f32>` : "f32";
case 6 /* int32 */:
return components > 1 ? `vec${components}<i32>` : "i32";
case 12 /* uint32 */:
return components > 1 ? `vec${components}<u32>` : "u32";
case 7 /* int64 */:
if (components > 1) {
throw new Error("currently not supported vecX of uint64 yet");
}
return ["vec2<u32>", "i32"];
case 13 /* uint64 */:
if (components > 1) {
throw new Error("currently not supported vecX of uint64 yet");
}
return ["vec2<u32>", "u32"];
case 9 /* bool */:
if (components !== 4) {
throw new Error("bool must be vec4");
}
return ["u32", "vec4<bool>"];
case 22 /* int4 */:
return "i32";
case 21 /* uint4 */:
return "u32";
default:
throw new Error(`Unknown data type: ${type}`);
}
};
tensorTypeToWsglStorageType = (type, components = 1) => {
const mappedType = getWgslMappedType(type, components);
return typeof mappedType === "string" ? mappedType : mappedType[0];
};
tensorTypeToWsglValueType = (type, components = 1) => {
const mappedType = getWgslMappedType(type, components);
return typeof mappedType === "string" ? mappedType : mappedType[1];
};
createTensorShapeVariables = (...dims) => {
const programUniforms = [];
dims.forEach((dim) => {
if (dim.length !== 0) {
programUniforms.push(
{ type: 12 /* uint32 */, data: dim },
{ type: 12 /* uint32 */, data: ShapeUtil.computeStrides(dim) }
);
}
});
return programUniforms;
};
getMaxComponents = (size) => {
if (size % 4 === 0) {
return 4;
} else if (size % 2 === 0) {
return 2;
}
return 1;
};
fillVector = (dataType = "f32", components, value = "0") => {
if (!components || components === 1) {
return `${dataType}(${value})`;
}
return `vec${components}<${dataType}>(${value})`;
};
castToF32 = (dataType, components, value) => {
if (dataType === "f32") {
return value;
}
if (components === 1) {
return `f32(${value})`;
}
return `vec${components}<f32>(${value})`;
};
sumVector = (name, components) => {
if (components === 4) {
return `(${name}.x + ${name}.y + ${name}.z + ${name}.w)`;
} else if (components === 2) {
return `(${name}.x + ${name}.y)`;
} else if (components === 3) {
return `(${name}.x + ${name}.y + ${name}.z)`;
}
return name;
};
getElementAt = (name, index, length, type) => {
if (name.startsWith("uniforms.") && length > 4) {
if (typeof index === "string") {
if (type === "f16") {
return `${name}[(${index}) / 8][(${index}) % 8 / 4][(${index}) % 8 % 4]`;
} else {
return `${name}[(${index}) / 4][(${index}) % 4]`;
}
} else {
if (type === "f16") {
return `${name}[${Math.floor(index / 8)}][${Math.floor(index % 8 / 4)}][${index % 8 % 4}]`;
} else {
return `${name}[${Math.floor(index / 4)}][${index % 4}]`;
}
}
} else {
return length > 1 ? `${name}[${index}]` : name;
}
};
createIndicesHelper = (name, tensorType, shapeOrRank, usage, components) => {
const useUniform = typeof shapeOrRank === "number";
const rank = useUniform ? shapeOrRank : shapeOrRank.length;
const rankIdentity = [...new Array(rank).keys()];
const indicesType = rank < 2 ? "u32" : rank <= 4 ? `vec${rank}<u32>` : `array<u32, ${rank}>`;
const mappedType = getWgslMappedType(tensorType, components);
const valueType = typeof mappedType === "string" ? mappedType : mappedType[1];
const storageType = typeof mappedType === "string" ? mappedType : mappedType[0];
const type = { indices: indicesType, value: valueType, storage: storageType, tensor: tensorType };
const normalizeDim = (dim) => typeof dim === "string" ? dim : `${dim}u`;
const implementationUsed = {
offsetToIndices: false,
indicesToOffset: false,
broadcastedIndicesToOffset: false,
set: false,
setByIndices: false,
get: false,
getByIndices: false
};
const uniformPrefix = useUniform ? "uniforms." : "";
const shape = `${uniformPrefix}${name}_shape`;
const strides = `${uniformPrefix}${name}_strides`;
let o2iSnippet = "";
for (let i = 0; i < rank - 1; i++) {
o2iSnippet += `
let dim${i} = current / ${getElementAt(strides, i, rank)};
let rest${i} = current % ${getElementAt(strides, i, rank)};
indices[${i}] = dim${i};
current = rest${i};
`;
}
o2iSnippet += `indices[${rank - 1}] = current;`;
const offsetToIndicesImplementation = rank < 2 ? "" : `
fn o2i_${name}(offset: u32) -> ${type.indices} {
var indices: ${type.indices};
var current = offset;
${o2iSnippet}
return indices;
}`;
const offsetToIndices = (varOffset) => {
implementationUsed.offsetToIndices = true;
return rank < 2 ? varOffset : `o2i_${name}(${varOffset})`;
};
const offsets = [];
if (rank >= 2) {
for (let i = rank - 1; i >= 0; i--) {
offsets.push(`${getElementAt(strides, i, rank)} * (indices[${i}])`);
}
}
const indicesToOffsetImplementation = rank < 2 ? "" : `
fn i2o_${name}(indices: ${type.indices}) -> u32 {
return ${offsets.join("+")};
}`;
const indicesToOffset = (varIndices) => {
implementationUsed.indicesToOffset = true;
return rank < 2 ? varIndices : `i2o_${name}(${varIndices})`;
};
const indices = (...init2) => rank === 0 ? "0u" : `${type.indices}(${init2.map(normalizeDim).join(",")})`;
const indicesGet = (varIndices, idx) => {
if (rank < 2) {
return `${varIndices}`;
} else {
return `${getElementAt(varIndices, idx, rank)}`;
}
};
const indicesSet = (varIndices, idx, value) => {
if (rank < 2) {
return `${varIndices}=${value};`;
} else {
return `${getElementAt(varIndices, idx, rank)}=${value};`;
}
};
const broadcastedIndicesToOffsetImplementation = {};
const broadcastedIndicesToOffset = (varIndices, output) => {
implementationUsed.broadcastedIndicesToOffset = true;
const implKey = `${output.name}broadcastedIndicesTo${name}Offset`;
if (implKey in broadcastedIndicesToOffsetImplementation) {
return `${implKey}(${varIndices})`;
}
const offsets2 = [];
for (let i = rank - 1; i >= 0; i--) {
const idx = output.indicesGet("outputIndices", i + output.rank - rank);
offsets2.push(`${indicesGet(strides, i)} * (${idx} % ${indicesGet(shape, i)})`);
}
broadcastedIndicesToOffsetImplementation[implKey] = `fn ${implKey}(outputIndices: ${output.type.indices}) -> u32 {
return ${offsets2.length > 0 ? offsets2.join("+") : "0u"};
}`;
return `${implKey}(${varIndices})`;
};
const setByOffset = (offset, value) => (() => {
if (type.storage === type.value) {
return `${name}[${offset}]=${value};`;
} else if (type.storage === "vec2<u32>" && type.value === "i32") {
return `${name}[${offset}]=vec2<u32>(u32(${value}), select(0u, 0xFFFFFFFFu, ${value} < 0));`;
} else if (type.storage === "vec2<u32>" && type.value === "u32") {
return `${name}[${offset}]=vec2<u32>(u32(${value}), 0u);`;
} else if (type.storage === "u32" && type.value === "vec4<bool>") {
return `${name}[${offset}]=dot(vec4<u32>(0x1, 0x100, 0x10000, 0x1000000), vec4<u32>(${value}));`;
} else {
throw new Error(`not supported combination of storage type ${type.storage} and value type ${type.value} yet`);
}
})();
const getByOffset = (offset) => (() => {
if (type.storage === type.value) {
return `${name}[${offset}]`;
} else if (type.storage === "vec2<u32>" && type.value === "i32") {
return `i32(${name}[${offset}].x)`;
} else if (type.storage === "vec2<u32>" && type.value === "u32") {
return `u32(${name}[${offset}].x)`;
} else if (type.storage === "u32" && type.value === "vec4<bool>") {
return `vec4<bool>(bool(${name}[${offset}] & 0xFFu), bool(${name}[${offset}] & 0xFF00u), bool(${name}[${offset}] & 0xFF0000u), bool(${name}[${offset}] & 0xFF000000u))`;
} else {
throw new Error(`not supported combination of storage type ${type.storage} and value type ${type.value} yet`);
}
})();
const getByIndicesImplementation = rank < 2 ? "" : `
fn get_${name}ByIndices(indices: ${type.indices}) -> ${valueType} {
return ${getByOffset(`i2o_${name}(indices)`)};
}`;
const getImplementation = rank < 2 ? "" : (() => {
const functionParams = rankIdentity.map((i) => `d${i}: u32`).join(", ");
const dimsParams = rankIdentity.map((i) => `d${i}`).join(", ");
return `
fn get_${name}(${functionParams}) -> ${valueType} {
return get_${name}ByIndices(${indices(dimsParams)});
}`;
})();
const get = (...indices2) => {
if (indices2.length !== rank) {
throw new Error(`indices length must be ${rank}`);
}
const normalizedIndices = indices2.map(normalizeDim).join(",");
if (rank === 0) {
return getByOffset("0u");
} else if (rank === 1) {
return getByOffset(normalizedIndices[0]);
} else {
implementationUsed.get = true;
implementationUsed.getByIndices = true;
implementationUsed.indicesToOffset = true;
return `get_${name}(${normalizedIndices})`;
}
};
const getByIndices = (varIndices) => {
if (rank < 2) {
return getByOffset(varIndices);
} else {
implementationUsed.getByIndices = true;
implementationUsed.indicesToOffset = true;
return `get_${name}ByIndices(${varIndices})`;
}
};
const setByIndicesImplementation = rank < 2 ? "" : `
fn set_${name}ByIndices(indices: ${type.indices}, value: ${valueType}) {
${setByOffset(`i2o_${name}(indices)`, "value")}
}`;
const setImplementation = rank < 2 ? "" : (() => {
const functionParams = rankIdentity.map((i) => `d${i}: u32`).join(", ");
const dimsParams = rankIdentity.map((i) => `d${i}`).join(", ");
return `
fn set_${name}(${functionParams}, value: ${valueType}) {
set_${name}ByIndices(${indices(dimsParams)}, value);
}`;
})();
const set = (...indicesAndValue) => {
if (indicesAndValue.length !== rank + 1) {
throw new Error(`indices length must be ${rank}`);
}
const value = indicesAndValue[rank];
if (typeof value !== "string") {
throw new Error("value must be string");
}
const normalizedIndices = indicesAndValue.slice(0, rank).map(normalizeDim).join(",");
if (rank === 0) {
return setByOffset("0u", value);
} else if (rank === 1) {
return setByOffset(normalizedIndices[0], value);
} else {
implementationUsed.set = true;
implementationUsed.setByIndices = true;
implementationUsed.indicesToOffset = true;
return `set_${name}(${normalizedIndices}, ${value})`;
}
};
const setByIndices = (varIndices, value) => {
if (rank < 2) {
return setByOffset(varIndices, value);
} else {
implementationUsed.setByIndices = true;
implementationUsed.indicesToOffset = true;
return `set_${name}ByIndices(${varIndices}, ${value});`;
}
};
const impl = () => {
const impls = [];
let needShapeStrides = false;
if (implementationUsed.offsetToIndices) {
impls.push(offsetToIndicesImplementation);
needShapeStrides = true;
}
if (implementationUsed.indicesToOffset) {
impls.push(indicesToOffsetImplementation);
needShapeStrides = true;
}
if (implementationUsed.broadcastedIndicesToOffset) {
Object.values(broadcastedIndicesToOffsetImplementation).forEach((impl2) => impls.push(impl2));
needShapeStrides = true;
}
if (implementationUsed.set) {
impls.push(setImplementation);
needShapeStrides = true;
}
if (implementationUsed.setByIndices) {
impls.push(setByIndicesImplementation);
needShapeStrides = true;
}
if (implementationUsed.get) {
impls.push(getImplementation);
needShapeStrides = true;
}
if (implementationUsed.getByIndices) {
impls.push(getByIndicesImplementation);
needShapeStrides = true;
}
if (!useUniform && needShapeStrides) {
impls.unshift(
`const ${shape} = ${type.indices}(${shapeOrRank.join(",")});`,
`const ${strides} = ${type.indices}(${ShapeUtil.computeStrides(shapeOrRank).join(",")});`
);
}
return impls.join("\n");
};
return {
impl,
type,
offsetToIndices,
indicesToOffset,
broadcastedIndicesToOffset,
indices,
indicesGet,
indicesSet,
set,
setByOffset,
setByIndices,
get,
getByOffset,
getByIndices,
// isVec4,
usage,
name,
strides,
shape,
rank
};
};
inputVariable = (name, type, shapeOrRank, components = 1) => createIndicesHelper(name, type, shapeOrRank, "input", components);
outputVariable = (name, type, shapeOrRank, components = 1) => createIndicesHelper(name, type, shapeOrRank, "output", components);
internalVariable = (name, type, shapeOrRank, components = 1) => createIndicesHelper(name, type, shapeOrRank, "internal", components);
ShaderHelperImpl = class {
constructor(normalizedDispatchGroup, limits) {
this.normalizedDispatchGroup = normalizedDispatchGroup;
this.limits = limits;
this.internalVariables = [];
this.variables = [];
this.uniforms = [];
this.variableIndex = 0;
}
guardAgainstOutOfBoundsWorkgroupSizes(size) {
const sizeInCode = typeof size === "number" ? `${size}u` : size;
return `if (global_idx >= ${sizeInCode}) { return; }`;
}
mainStart(workgroupSize = WORKGROUP_SIZE) {
const workgroupSizeX = typeof workgroupSize === "number" ? workgroupSize : workgroupSize[0];
const workgroupSizeY = typeof workgroupSize === "number" ? 1 : workgroupSize[1];
const workgroupSizeZ = typeof workgroupSize === "number" ? 1 : workgroupSize[2];
if (workgroupSizeX > this.limits.maxComputeWorkgroupSizeX || workgroupSizeY > this.limits.maxComputeWorkgroupSizeY || workgroupSizeZ > this.limits.maxComputeWorkgroupSizeZ) {
throw new Error(
`workgroup size [${workgroupSizeX}, ${workgroupSizeY}, ${workgroupSizeZ}] exceeds the maximum workgroup size [${this.limits.maxComputeWorkgroupSizeX}, ${this.limits.maxComputeWorkgroupSizeY}, ${this.limits.maxComputeWorkgroupSizeZ}].`
);
}
if (workgroupSizeX * workgroupSizeY * workgroupSizeZ > this.limits.maxComputeInvocationsPerWorkgroup) {
throw new Error(
`workgroup size [${workgroupSizeX}, ${workgroupSizeY}, ${workgroupSizeZ}] exceeds the maximum workgroup invocations ${this.limits.maxComputeInvocationsPerWorkgroup}.`
);
}
const is1DimensionDispatch = this.normalizedDispatchGroup[1] === 1 && this.normalizedDispatchGroup[2] === 1;
const paramList = is1DimensionDispatch ? `@builtin(global_invocation_id) global_id : vec3<u32>,
@builtin(workgroup_id) workgroup_id : vec3<u32>,
@builtin(local_invocation_index) local_idx : u32,
@builtin(local_invocation_id) local_id : vec3<u32>` : `@builtin(global_invocation_id) global_id : vec3<u32>,
@builtin(local_invocation_id) local_id : vec3<u32>,
@builtin(local_invocation_index) local_idx : u32,
@builtin(workgroup_id) workgroup_id : vec3<u32>,
@builtin(num_workgroups) num_workgroups : vec3<u32>`;
const globalIdxDefinition = is1DimensionDispatch ? `let global_idx = global_id.x;
let workgroup_index = workgroup_id.x;` : `let workgroup_index = workgroup_id.z * num_workgroups[0] * num_workgroups[1] +
workgroup_id.y * num_workgroups[0] + workgroup_id.x;
let global_idx = workgroup_index * ${workgroupSizeX * workgroupSizeY * workgroupSizeZ}u + local_idx;`;
return `@compute @workgroup_size(${workgroupSizeX}, ${workgroupSizeY}, ${workgroupSizeZ})
fn main(${paramList}) {
${globalIdxDefinition}
`;
}
appendVariableUniforms(variable) {
if (variable.rank !== 0) {
if (variable.shape.startsWith("uniforms.")) {
this.uniforms.push({ name: variable.shape.replace("uniforms.", ""), type: "u32", length: variable.rank });
}
if (variable.strides.startsWith("uniforms.")) {
this.uniforms.push({ name: variable.strides.replace("uniforms.", ""), type: "u32", length: variable.rank });
}
}
}
declareVariable(variable, bindingIndex) {
if (variable.usage === "internal") {
throw new Error("cannot use internal variable with declareVariable(). use registerInternalVariables() instead.");
}
this.variables.push(variable);
this.appendVariableUniforms(variable);
const access = variable.usage === "input" ? "read" : "read_write";
const storageType = variable.type.storage;
return `@group(0) @binding(${bindingIndex}) var<storage, ${access}> ${variable.name}: array<${storageType}>;`;
}
declareVariables(...variables) {
return variables.map((v) => this.declareVariable(v, this.variableIndex++)).join("\n");
}
registerInternalVariable(variable) {
if (variable.usage !== "internal") {
throw new Error(
"cannot use input or output variable with registerInternalVariable(). use declareVariables() instead."
);
}
this.internalVariables.push(variable);
this.appendVariableUniforms(variable);
}
registerInternalVariables(...variables) {
variables.forEach((v) => this.registerInternalVariable(v));
return this;
}
registerUniform(name, type, length = 1) {
this.uniforms.push({ name, type, length });
return this;
}
registerUniforms(additionalUniforms) {
this.uniforms = this.uniforms.concat(additionalUniforms);
return this;
}
uniformDeclaration() {
if (this.uniforms.length === 0) {
return "";
}
const uniformSnippets = [];
for (const { name, type, length } of this.uniforms) {
if (length && length > 4) {
if (type === "f16") {
uniformSnippets.push(`@align(16) ${name}:array<mat2x4<${type}>, ${Math.ceil(length / 8)}>`);
} else {
uniformSnippets.push(`${name}:array<vec4<${type}>, ${Math.ceil(length / 4)}>`);
}
} else {
const typeTemp = length == null || length === 1 ? type : `vec${length}<${type}>`;
uniformSnippets.push(`${name}:${typeTemp}`);
}
}
return `
struct Uniforms { ${uniformSnippets.join(", ")} };
@group(0) @binding(${this.variableIndex}) var<uniform> uniforms: Uniforms;`;
}
/**
* Get additional implementation that needs to be added to the shader source.
*/
get additionalImplementations() {
return this.uniformDeclaration() + this.variables.map((i) => i.impl()).join("\n") + this.internalVariables.map((i) => i.impl()).join("\n");
}
/**
* Get the variable info of the shader program.
*/
get variablesInfo() {
if (this.uniforms.length === 0) {
return void 0;
}
const uniformWgslTypeToDataType = (type) => [12 /* uint32 */, 10 /* float16 */, 1 /* float */, 6 /* int32 */][["u32", "f16", "f32", "i32"].indexOf(type)];
return this.uniforms.map((u) => [uniformWgslTypeToDataType(u.type), u.length ?? 1]);
}
};
createShaderHelper = (dispatchGroup, limits) => new ShaderHelperImpl(dispatchGroup, limits);
getBroadcastDims = (inShape, outShape) => {
const inRank = inShape.length;
const dims = [];
for (let i = 0; i < inRank; i++) {
const dim = inRank - 1 - i;
const a = inShape[dim] || 1;
const b = outShape[outShape.length - 1 - i] || 1;
if (b > 1 && a === 1) {
dims.unshift(dim);
}
}
return dims;
};
}
});
// web/lib/wasm/jsep/webgpu/ops/transpose.ts
var validateInputs, getAdjustedPerm, getOutputShape, permFunctionBody, squeezeShape, createTransposeProgramInfo, transpose, parseTransposeAttributes;
var init_transpose = __esm({
"web/lib/wasm/jsep/webgpu/ops/transpose.ts"() {
"use strict";
init_wasm_common();
init_util();
init_attribute_with_cache_key();
init_common();
validateInputs = (inputs) => {
if (!inputs || inputs.length !== 1) {
throw new Error("Transpose requires 1 input.");
}
};
getAdjustedPerm = (inputRank, perm) => perm && perm.length !== inputRank ? [...new Array(inputRank).keys()].reverse() : perm;
getOutputShape = (inputShape, perm) => ShapeUtil.sortBasedOnPerm(inputShape, getAdjustedPerm(inputShape.length, perm));
permFunctionBody = (perm, rank, input, output) => {
let reverseFunc = `fn perm(i: ${output.type.indices}) -> ${input.type.indices} {
var a: ${input.type.indices};`;
for (let i = 0; i < rank; ++i) {
reverseFunc += input.indicesSet("a", perm[i], `i[${i}]`);
}
return reverseFunc += "return a;}";
};
squeezeShape = (shape, adjustedPerm) => {
const newShape = [];
const newPerm = [];
for (let i = 0; i < shape.length; ++i) {
if (shape[i] !== 1) {
newShape.push(shape[i]);
}
if (shape[adjustedPerm[i]] !== 1) {
newPerm.push(adjustedPerm[i]);
}
}
return { newShape, newPerm };
};
createTransposeProgramInfo = (inputTensor, permAttr) => {
const inputDataType = inputTensor.dataType;
const inputRank = inputTensor.dims.length;
const perm = getAdjustedPerm(inputRank, permAttr);
const outputShape = getOutputShape(inputTensor.dims, perm);
const { newShape, newPerm } = squeezeShape(inputTensor.dims, perm);
const channelsLast = ShapeUtil.areEqual(newPerm, [2, 3, 1]);
const channelsFirst = ShapeUtil.areEqual(newPerm, [3, 1, 2]);
const useShared = newShape.length === 2 && newPerm[0] > newPerm[1] || channelsLast || channelsFirst;
let newInputShape = useShared ? newShape : inputTensor.dims;
let newOutputShape = outputShape;
if (useShared) {
newInputShape = channelsLast ? [newShape[0], newShape[1] * newShape[2]] : channelsFirst ? [newShape[0] * newShape[1], newShape[2]] : newShape;
newOutputShape = [newInputShape[1], newInputShape[0]];
}
const input = inputVariable("a", inputDataType, newInputShape.length);
const output = outputVariable("output", inputDataType, newOutputShape.length);
const tileSize = 16;
let getShaderSource;
if (useShared) {
getShaderSource = (shaderHelper) => `
${shaderHelper.registerUniform("output_size", "u32").declareVariables(input, output)}
var<workgroup> tile : array<array<${output.type.value}, ${tileSize + 1}>, ${tileSize}>;
${shaderHelper.mainStart([tileSize, tileSize, 1])}
let stride = (uniforms.output_shape[1] - 1) / ${tileSize} + 1;
let workgroup_id_x = workgroup_index % stride;
let workgroup_id_y = workgroup_index / stride;
let input_col = workgroup_id_y * ${tileSize}u + local_id.x;
let input_row = workgroup_id_x * ${tileSize}u + local_id.y;
if (input_row < uniforms.a_shape[0] && input_col < uniforms.a_shape[1]) {
tile[local_id.y][local_id.x] = ${input.getByIndices(`${input.type.indices}(input_row, input_col)`)};
}
workgroupBarrier();
let output_col = workgroup_id_x * ${tileSize}u + local_id.x;
let output_row = workgroup_id_y * ${tileSize}u + local_id.y;
if (output_row < uniforms.output_shape[0] && output_col < uniforms.output_shape[1]) {
${output.setByIndices(`${output.type.indices}(output_row, output_col)`, "tile[local_id.x][local_id.y]")}
}
}`;
} else {
getShaderSource = (shaderHelper) => `
${shaderHelper.registerUniform("output_size", "u32").declareVariables(input, output)}
${permFunctionBody(perm, inputRank, input, output)}
${shaderHelper.mainStart()}
${shaderHelper.guardAgainstOutOfBoundsWorkgroupSizes("uniforms.output_size")}
let indices = ${output.offsetToIndices("global_idx")};
let aIndices = perm(indices);
${output.setByOffset("global_idx", input.getByIndices("aIndices"))}
}`;
}
return {
name: useShared ? "TransposeShared" : "Transpose",
shaderCache: { hint: `${permAttr}`, inputDependencies: ["rank"] },
getRunData: () => {
const outputSize = ShapeUtil.size(outputShape);
return {
outputs: [{ dims: outputShape, dataType: inputTensor.dataType }],
dispatchGroup: useShared ? { x: Math.ceil(newOutputShape[1] / tileSize), y: Math.ceil(newOutputShape[0] / tileSize) } : { x: Math.ceil(
outputSize / 64
/* workgroup size */
) },
programUniforms: [
{ type: 12 /* uint32 */, data: outputSize },
...createTensorShapeVariables(newInputShape, newOutputShape)
]
};
},
getShaderSource
};
};
transpose = (context, attributes) => {
validateInputs(context.inputs);
context.compute(createTransposeProgramInfo(context.inputs[0], attributes.perm));
};
parseTransposeAttributes = (attributes) => createAttributeWithCacheKey({ perm: attributes.perm });
}
});
// web/lib/wasm/jsep/webgpu/ops/reduce-shared.ts
var reduceOps, reduceSharedOps, reduceInitValues, reduceOutputValues, getInnerMostAxes, computeOutAndReduceShapes, expandShapeToKeepDim, areAxesInnerMostDims, getAxesPermutation, createReduceSharedProgramInfo, reduceCommon, reduceMeanShared, reduceL1Shared, reduceL2Shared, reduceLogSumExpShared, reduceMaxShared, reduceMinShared, reduceProdShared, reduceSumShared, reduceSumSquareShared, reduceLogSumShared;
var init_reduce_shared = __esm({
"web/lib/wasm/jsep/webgpu/ops/reduce-shared.ts"() {
"use strict";
init_wasm_common();
init_util();
init_common();
init_reduce();
init_transpose();
reduceOps = {
max: "select(bestValue, candidate, candidate > bestValue)",
min: "select(bestValue, candidate, candidate < bestValue)",
mean: "bestValue + candidate",
sum: "bestValue + candidate",
prod: "bestValue * candidate",
sumSquare: "bestValue + candidate * candidate",
logSumExp: "bestValue + exp(candidate)",
l1: "bestValue + abs(candidate)",
l2: "bestValue + candidate * candidate",
logSum: "bestValue + candidate"
};
reduceSharedOps = {
max: "select(bestValue, candidate, candidate > bestValue)",
min: "select(bestValue, candidate, candidate < bestValue)",
mean: "bestValue + candidate",
sum: "bestValue + candidate",
prod: "bestValue * candidate",
sumSquare: "bestValue + candidate",
logSumExp: "bestValue + candidate",
l1: "bestValue + candidate",
l2: "bestValue + candidate",
logSum: "bestValue + candidate"
};
reduceInitValues = {
max: "_A[offset]",
min: "_A[offset]",
mean: "0",
sum: "0",
prod: "1",
sumSquare: "0",
logSumExp: "0",
l1: "0",
l2: "0",
logSum: "0"
};
reduceOutputValues = {
max: "bestValue",
min: "bestValue",
sum: "bestValue",
prod: "bestValue",
sumSquare: "bestValue",
logSumExp: "log(bestValue)",
l1: "bestValue",
l2: "sqrt(bestValue)",
logSum: "log(bestValue)"
};
getInnerMostAxes = (numInnerAxes, rank) => {
const res = [];
for (let i = rank - numInnerAxes; i < rank; ++i) {
res.push(i);
}
return res;
};
computeOutAndReduceShapes = (shape, axes) => {
const outputShape = [];
const rank = shape.length;
for (let dim = 0; dim < rank; dim++) {
if (axes.indexOf(dim) === -1) {
outputShape.push(shape[dim]);
}
}
const reduceShape = axes.map((dim) => shape[dim]);
return [outputShape, reduceShape];
};
expandShapeToKeepDim = (shape, axes) => {
const rank = shape.length + axes.length;
const expandShape = [];
let shapeIdx = 0;
for (let dim = 0; dim < rank; dim++) {
if (axes.indexOf(dim) === -1) {
expandShape.push(shape[shapeIdx++]);
} else {
expandShape.push(1);
}
}
return expandShape;
};
areAxesInnerMostDims = (axes, rank) => {
for (let i = 0; i < axes.length; ++i) {
if (axes[axes.length - i - 1] !== rank - 1 - i) {
return false;
}
}
return true;
};
getAxesPermutation = (axes, rank) => {
const res = [];
if (!areAxesInnerMostDims(axes, rank)) {
for (let i = 0; i < rank; ++i) {
if (axes.indexOf(i) === -1) {
res.push(i);
}
}
axes.forEach((axis) => res.push(axis));
}
return res;
};
createReduceSharedProgramInfo = (name, shaderCache, inputs, reduceType, outputDataType, outputShape, reduceShape) => {
const inputShape = inputs[0].dims;
const outputSize = ShapeUtil.size(outputShape);
const reduceSize = ShapeUtil.size(reduceShape);
const input = inputVariable("_A", inputs[0].dataType, inputShape);
const output = outputVariable("output", outputDataType, outputShape);
const workgroupSize = 32;
const sharedMemorySnippet = `
var<workgroup> aBestValues : array<f32, ${workgroupSize}>;
`;
const getShaderSource = (shaderHelper) => `
${shaderHelper.registerUniform("reduceSize", "u32").declareVariables(input, output)}
${sharedMemorySnippet}
fn DIV_CEIL(a : u32, b : u32) -> u32 {
return ((a - 1u) / b + 1u);
}
${shaderHelper.mainStart(workgroupSize)}
let outputIndex = global_idx / ${workgroupSize};
let offset = outputIndex * uniforms.reduceSize;
var bestValue = f32(${reduceInitValues[reduceType]});
let Length = uniforms.reduceSize;
for (var k = local_idx; k < Length; k = k + ${workgroupSize}) {
let candidate = f32(${input.getByOffset("offset + k")});
bestValue = ${reduceOps[reduceType]};
}
aBestValues[local_idx] = bestValue;
workgroupBarrier();
var reduceSize = min(Length, ${workgroupSize}u);
for (var currentSize = reduceSize / 2u; reduceSize > 1u;
currentSize = reduceSize / 2u) {
let interval = DIV_CEIL(reduceSize, 2u);
if (local_idx < currentSize) {
let candidate = aBestValues[local_idx + interval];
bestValue = ${reduceSharedOps[reduceType]};
aBestValues[local_idx] = bestValue;
}
reduceSize = interval;
workgroupBarrier();
}
if (local_idx == 0u) {
${output.setByOffset(
"outputIndex",
`${reduceType === "mean" ? `${output.type.storage}(bestValue / f32(uniforms.reduceSize))` : `${output.type.storage}(${reduceOutputValues[reduceType]})`}`
)};
}
}`;
return {
name,
shaderCache,
getShaderSource,
getRunData: () => ({
outputs: [{ dims: outputShape, dataType: outputDataType }],
dispatchGroup: { x: outputSize },
programUniforms: [{ type: 12 /* uint32 */, data: reduceSize }]
})
};
};
reduceCommon = (context, name, attributes, reduceType) => {
const updatedAttributes = context.inputs.length === 1 ? attributes : createReduceAttributesFromInputs(context.inputs, attributes);
let updatedAxes = updatedAttributes.axes;
if (updatedAxes.length === 0 && !updatedAttributes.noopWithEmptyAxes) {
updatedAxes = context.inputs[0].dims.map((_dim, i) => i);
}
const normalizeAxes = ShapeUtil.normalizeAxes(updatedAxes, context.inputs[0].dims.length);
let axes = normalizeAxes;
let input = context.inputs[0];
const permutedAxes = getAxesPermutation(axes, context.inputs[0].dims.length);
if (permutedAxes.length > 0) {
input = context.compute(createTransposeProgramInfo(context.inputs[0], permutedAxes), {
inputs: [0],
outputs: [-1]
})[0];
axes = getInnerMostAxes(axes.length, input.dims.length);
}
const [outputShape, reduceShape] = computeOutAndReduceShapes(input.dims, axes);
let finalOutputShape = outputShape;
if (updatedAttributes.keepDims) {
finalOutputShape = expandShapeToKeepDim(outputShape, normalizeAxes);
}
context.compute(
createReduceSharedProgramInfo(
name,
{ hint: updatedAttributes.cacheKey, inputDependencies: ["type"] },
[input],
reduceType,
context.inputs[0].dataType,
finalOutputShape,
reduceShape
),
{ inputs: [input] }
);
};
reduceMeanShared = (context, attributes) => {
reduceCommon(context, "ReduceMeanShared", attributes, "mean");
};
reduceL1Shared = (context, attributes) => {
reduceCommon(context, "ReduceL1Shared", attributes, "l1");
};
reduceL2Shared = (context, attributes) => {
reduceCommon(context, "ReduceL2Shared", attributes, "l2");
};
reduceLogSumExpShared = (context, attributes) => {
reduceCommon(context, "ReduceLogSumExpShared", attributes, "logSumExp");
};
reduceMaxShared = (context, attributes) => {
reduceCommon(context, "ReduceMaxShared", attributes, "max");
};
reduceMinShared = (context, attributes) => {
reduceCommon(context, "ReduceMinShared", attributes, "min");
};
reduceProdShared = (context, attributes) => {
reduceCommon(context, "ReduceProdShared", attributes, "prod");
};
reduceSumShared = (context, attributes) => {
reduceCommon(context, "ReduceSumShared", attributes, "sum");
};
reduceSumSquareShared = (context, attributes) => {
reduceCommon(context, "ReduceSumSquareShared", attributes, "sumSquare");
};
reduceLogSumShared = (context, attributes) => {
reduceCommon(context, "ReduceLogSumShared", attributes, "logSum");
};
}
});
// web/lib/wasm/jsep/webgpu/ops/reduce.ts
var validateInputs2, noOp, createReduceProgramInfo, createReduceAttributesFromInputs, runReduceProgram, reduceLogSumNaive, reduceL1Naive, reduceL2Naive, reduceLogSumExpNaive, reduceMaxNaive, reduceMeanNaive, reduceMinNaive, reduceProdNaive, reduceSumNaive, reduceSumSquareNaive, useNaiveReduceMethod, reduceMean, reduceL1, reduceL2, reduceLogSumExp, reduceMax, reduceMin, reduceProd, reduceSum, reduceSumSquare, reduceLogSum;
var init_reduce = __esm({
"web/lib/wasm/jsep/webgpu/ops/reduce.ts"() {
"use strict";
init_wasm_common();
init_util();
init_attribute_with_cache_key();
init_common();
init_reduce_shared();
validateInputs2 = (inputs) => {
if (!inputs || inputs.length === 0 || inputs.length > 2) {
throw new Error("Reduce op requires 1 or 2 inputs.");
}
if (inputs.length === 2 && inputs[1].dims.length !== 1) {
throw new Error("Invalid axes input dims.");
}
};
noOp = (input) => ["", "", `var value = ${input.getByIndices("input_indices")};`, ""];
createReduceProgramInfo = (name, shaderCache, inputs, reduceOp, axesInput, outputDataType, keepDims = false, noopWithEmptyAxes = false) => {
const outputShape = [];
const inputShape = inputs[0].dims;
const inputRank = inputShape.length;
const axes = ShapeUtil.normalizeAxes(axesInput, inputRank);
const reduceOnAllAxes = !noopWithEmptyAxes && axes.length === 0;
inputShape.forEach((d, i) => {
if (reduceOnAllAxes || axes.indexOf(i) >= 0) {
if (keepDims) {
outputShape.push(1);
}
} else {
outputShape.push(d);
}
});
const outputRank = outputShape.length;
const outputSize = ShapeUtil.size(outputShape);
const getShaderSource = (shaderHelper) => {
const idxCopy = [];
const input = inputVariable("_A", inputs[0].dataType, inputRank);
const output = outputVariable("output", outputDataType, outputRank);
const ops = reduceOp(input, output, axes);
let reduceOps2 = ops[2];
for (let k = 0, l = 0; k < inputRank; k++) {
if (reduceOnAllAxes || axes.indexOf(k) >= 0) {
if (keepDims) {
l++;
}
reduceOps2 = `for(var j${k}: u32 = 0; j${k} < ${inputShape[k]}; j${k}++) {
${ops[2].includes("last_index") ? `let last_index = j${k};` : ""}
${input.indicesSet("input_indices", k, `j${k}`)}
${reduceOps2}
}`;
} else {
idxCopy.push(`${input.indicesSet("input_indices", k, output.indicesGet("output_indices", l))};`);
l++;
}
}
return `
${shaderHelper.registerUniform("output_size", "u32").declareVariables(input, output)}
${shaderHelper.mainStart()}
${shaderHelper.guardAgainstOutOfBoundsWorkgroupSizes("uniforms.output_size")}
var input_indices: ${input.type.indices};
let output_indices = ${output.offsetToIndices("global_idx")};
${idxCopy.join("\n")}
${ops[0]} // init ops for reduce max/min
${ops[1]}
${reduceOps2}
${ops[3]}
${ops.length === 4 ? output.setByOffset("global_idx", "value") : ops.slice(4).join("\n")}
}`;
};
return {
name,
shaderCache,
getShaderSource,
getRunData: () => ({
outputs: [{ dims: outputShape, dataType: outputDataType }],
dispatchGroup: { x: Math.ceil(
outputSize / 64
/* workgroup size */
) },
programUniforms: [
{ type: 12 /* uint32 */, data: outputSize },
...createTensorShapeVariables(inputShape, outputShape)
]
})
};
};
createReduceAttributesFromInputs = (inputs, attributes) => {
const axes = [];
if (inputs[1].dims[0] > 0) {
inputs[1].getBigInt64Array().forEach((v) => axes.push(Number(v)));
}
return createAttributeWithCacheKey({
axes,
keepDims: attributes.keepDims,
noopWithEmptyAxes: attributes.noopWithEmptyAxes
});
};
runReduceProgram = (context, name, attributes, reduceOp) => {
const inputs = context.inputs;
const updatedAttributes = inputs.length === 1 ? attributes : createReduceAttributesFromInputs(inputs, attributes);
context.compute(
createReduceProgramInfo(
name,
{ hint: updatedAttributes.cacheKey, inputDependencies: ["rank"] },
[inputs[0]],
updatedAttributes.noopWithEmptyAxes && updatedAttributes.axes.length === 0 ? noOp : reduceOp,
updatedAttributes.axes,
inputs[0].dataType,
updatedAttributes.keepDims,
updatedAttributes.noopWithEmptyAxes
),
{ inputs: [0] }
);
};
reduceLogSumNaive = (context, attributes) => {
validateInputs2(context.inputs);
const reduceOp = (input, output) => [
`var value = ${output.type.storage}(0);`,
"",
`value += ${input.getByIndices("input_indices")};`,
"value = log(value);"
];
runReduceProgram(context, "ReduceLogSum", attributes, reduceOp);
};
reduceL1Naive = (context, attributes) => {
validateInputs2(context.inputs);
const reduceOp = (input, output) => [
`var value = ${output.type.storage}(0);`,
"",
`value += abs(${input.getByIndices("input_indices")});`,
""
];
runReduceProgram(context, "ReduceL1", attributes, reduceOp);
};
reduceL2Naive = (context, attributes) => {
validateInputs2(context.inputs);
const reduceOp = (input, output) => [
`var t = ${output.type.value}(0); var value = ${output.type.value}(0);`,
"",
`t = ${input.getByIndices("input_indices")}; value += (t * t);`,
"value = sqrt(value);"
];
runReduceProgram(context, "ReduceL2", attributes, reduceOp);
};
reduceLogSumExpNaive = (context, attributes) => {
validateInputs2(context.inputs);
const reduceOp = (input, output) => [
`var value = ${output.type.storage}(0);`,
"",
`value += exp(${input.getByIndices("input_indices")});`,
"value = log(value);"
];
runReduceProgram(context, "ReduceLogSumExp", attributes, reduceOp);
};
reduceMaxNaive = (context, attributes) => {
validateInputs2(context.inputs);
const reduceOp = (input, _output, axes) => {
const idxZero = [];
for (let k = 0; k < input.rank; k++) {
if (axes.indexOf(k) >= 0 || axes.length === 0) {
idxZero.push(input.indicesSet("input_indices", k, 0));
}
}
return [
`${idxZero.join("\n")}`,
`var value = ${input.getByIndices("input_indices")};`,
`value = max(value, ${input.getByIndices("input_indices")});`,
""
];
};
runReduceProgram(context, "ReduceMax", attributes, reduceOp);
};
reduceMeanNaive = (context, attributes) => {
validateInputs2(context.inputs);
const reduceOp = (input, output, axes) => {
let size = 1;
for (let k = 0; k < input.rank; k++) {
if (axes.indexOf(k) >= 0 || axes.length === 0) {
size *= context.inputs[0].dims[k];
}
}
return [
"var sum = f32(0);",
"",
`sum += f32(${input.getByIndices("input_indices")});`,
`let value = ${output.type.value}(sum / ${size});`
];
};
runReduceProgram(context, "ReduceMean", attributes, reduceOp);
};
reduceMinNaive = (context, attributes) => {
validateInputs2(context.inputs);
const reduceOp = (input, _output, axes) => {
const idxZero = [];
for (let k = 0; k < input.rank; k++) {
if (axes.indexOf(k) >= 0 || axes.length === 0) {
idxZero.push(`input_indices[${k}] = 0;`);
}
}
return [
`${idxZero.join("\n")}`,
`var value = ${input.getByIndices("input_indices")};`,
`value = min(value, ${input.getByIndices("input_indices")});`,
""
];
};
runReduceProgram(context, "ReduceMin", attributes, reduceOp);
};
reduceProdNaive = (context, attributes) => {
validateInputs2(context.inputs);
const reduceOp = (input, output) => [
`var value = ${output.type.storage}(1);`,
"",
`value *= ${input.getByIndices("input_indices")};`,
""
];
runReduceProgram(context, "ReduceProd", attributes, reduceOp);
};
reduceSumNaive = (context, attributes) => {
validateInputs2(context.inputs);
const reduceOp = (input, output) => [
`var value = ${output.type.storage}(0);`,
"",
`value += ${input.getByIndices("input_indices")};`,
""
];
runReduceProgram(context, "ReduceSum", attributes, reduceOp);
};
reduceSumSquareNaive = (context, attributes) => {
validateInputs2(context.inputs);
const reduceOp = (input, output) => [
`var t = ${output.type.value}(0); var value = ${output.type.value}(0);`,
"",
`t = ${input.getByIndices("input_indices")}; value += t * t;`,
""
];
runReduceProgram(context, "ReduceSumSquare", attributes, reduceOp);
};
useNaiveReduceMethod = (shape, axes, noopWithEmptyAxes) => {
if (axes.length === 0) {
return noopWithEmptyAxes;
}
let outputSize = 1;
let reduceSize = 1;
for (let dim = 0; dim < axes.length; dim++) {
if (axes.indexOf(dim) === -1) {
outputSize *= shape[dim];
} else {
reduceSize *= shape[dim];
}
}
return reduceSize < 32 && outputSize > 1024;
};
reduceMean = (context, attributes) => {
if (useNaiveReduceMethod(context.inputs[0].dims, attributes.axes, attributes.noopWithEmptyAxes)) {
reduceMeanNaive(context, attributes);
} else {
reduceMeanShared(context, attributes);
}
};
reduceL1 = (context, attributes) => {
if (useNaiveReduceMethod(context.inputs[0].dims, attributes.axes, attributes.noopWithEmptyAxes)) {
reduceL1Naive(context, attributes);
} else {
reduceL1Shared(context, attributes);
}
};
reduceL2 = (context, attributes) => {
if (useNaiveReduceMethod(context.inputs[0].dims, attributes.axes, attributes.noopWithEmptyAxes)) {
reduceL2Naive(context, attributes);
} else {
reduceL2Shared(context, attributes);
}
};
reduceLogSumExp = (context, attributes) => {
if (useNaiveReduceMethod(context.inputs[0].dims, attributes.axes, attributes.noopWithEmptyAxes)) {
reduceLogSumExpNaive(context, attributes);
} else {
reduceLogSumExpShared(context, attributes);
}
};
reduceMax = (context, attributes) => {
if (useNaiveReduceMethod(context.inputs[0].dims, attributes.axes, attributes.noopWithEmptyAxes)) {
reduceMaxNaive(context, attributes);
} else {
reduceMaxShared(context, attributes);
}
};
reduceMin = (context, attributes) => {
if (useNaiveReduceMethod(context.inputs[0].dims, attributes.axes, attributes.noopWithEmptyAxes)) {
reduceMinNaive(context, attributes);
} else {
reduceMinShared(context, attributes);
}
};
reduceProd = (context, attributes) => {
if (useNaiveReduceMethod(context.inputs[0].dims, attributes.axes, attributes.noopWithEmptyAxes)) {
reduceProdNaive(context, attributes);
} else {
reduceProdShared(context, attributes);
}
};
reduceSum = (context, attributes) => {
if (useNaiveReduceMethod(context.inputs[0].dims, attributes.axes, attributes.noopWithEmptyAxes)) {
reduceSumNaive(context, attributes);
} else {
reduceSumShared(context, attributes);
}
};
reduceSumSquare = (context, attributes) => {
if (useNaiveReduceMethod(context.inputs[0].dims, attributes.axes, attributes.noopWithEmptyAxes)) {
reduceSumSquareNaive(context, attributes);
} else {
reduceSumSquareShared(context, attributes);
}
};
reduceLogSum = (context, attributes) => {
if (useNaiveReduceMethod(context.inputs[0].dims, attributes.axes, attributes.noopWithEmptyAxes)) {
reduceLogSumNaive(context, attributes);
} else {
reduceLogSumShared(context, attributes);
}
};
}
});
// web/lib/wasm/jsep/webgpu/ops/argminmax.ts
var validateInputs3, argMin, argMax, parseArgMinMaxAttributes;
var init_argminmax = __esm({
"web/lib/wasm/jsep/webgpu/ops/argminmax.ts"() {
"use strict";
init_wasm_common();
init_attribute_with_cache_key();
init_reduce();
validateInputs3 = (inputs) => {
if (!inputs || inputs.length === 0 || inputs.length > 2) {
throw new Error("ArgMinMaxOp op requires 1 or 2 inputs.");
}
if (inputs[0].dataType !== 1 /* float */) {
throw new Error("Invalid input type.");
}
};
argMin = (context, attributes) => {
validateInputs3(context.inputs);
const argMinMaxOp = (input, output, axes) => {
const idxZero = [];
for (let k = 0; k < input.rank; k++) {
if (axes.indexOf(k) >= 0 || axes.length === 0) {
idxZero.push(`input_indices[${k}] = 0;`);
}
}
return [
`${idxZero.join("\n")}`,
`var value = ${input.getByIndices("input_indices")};
var best_index : i32 = 0;`,
`if (${input.getByIndices("input_indices")} ${attributes.selectLastIndex > 0 ? "<=" : "<"} value) {
value = ${input.getByIndices("input_indices")};
best_index = i32(last_index);
}`,
"",
output.setByOffset("global_idx", "best_index")
];
};
context.compute(
createReduceProgramInfo(
"ArgMin",
{ hint: attributes.cacheKey, inputDependencies: ["rank"] },
[context.inputs[0]],
argMinMaxOp,
[attributes.axis],
7 /* int64 */,
attributes.keepDims
),
{ inputs: [0] }
);
};
argMax = (context, attributes) => {
validateInputs3(context.inputs);
const argMinMaxOp = (input, output, axes) => {
const idxZero = [];
for (let k = 0; k < input.rank; k++) {
if (axes.indexOf(k) >= 0 || axes.length === 0) {
idxZero.push(`input_indices[${k}] = 0;`);
}
}
return [
`${idxZero.join("\n")}`,
`var value = ${input.getByIndices("input_indices")};
var best_index : i32 = 0;`,
`if (${input.getByIndices("input_indices")} ${attributes.selectLastIndex > 0 ? ">=" : ">"} value) {
value = ${input.getByIndices("input_indices")};
best_index = i32(last_index);
}`,
"",
output.setByOffset("global_idx", "best_index")
];
};
context.compute(
createReduceProgramInfo(
"argMax",
{ hint: attributes.cacheKey, inputDependencies: ["rank"] },
[context.inputs[0]],
argMinMaxOp,
[attributes.axis],
7 /* int64 */,
attributes.keepDims
),
{ inputs: [0] }
);
};
parseArgMinMaxAttributes = (attributes) => createAttributeWithCacheKey(attributes);
}
});
// web/lib/wasm/jsep/webgpu/ops/attention.ts
var validateAttentionInputs, createInPlaceSoftmaxProgramInfo, createAttentionProbsProgramInfo, createVxAttentionScoreProgramInfo, applyAttention, prepare, attention;
var init_attention = __esm({
"web/lib/wasm/jsep/webgpu/ops/attention.ts"() {
"use strict";
init_wasm_common();
init_util();
init_types();
init_common();
validateAttentionInputs = (inputs, attributes) => {
const input = inputs[0];
const weights = inputs[1];
const bias = inputs[2];
const maskIndex = inputs[3];
const past = inputs[4];
const attentionBias = inputs[5];
if (past && attentionBias) {
throw new Error("Attention cannot have both past and attention_bias");
}
if (input.dims.length !== 3) {
throw new Error('Input "input" must have 3 dimensions');
}
const batchSize = input.dims[0];
const sequenceLength = input.dims[1];
const inputHiddenSize = input.dims[2];
if (bias.dims.length !== 1) {
throw new Error('Input "bias" is expected to have 1 dimensions');
}
if (weights.dims.length !== 2) {
throw new Error('Input "weights" is expected to have 2 dimensions');
}
if (weights.dims[0] !== inputHiddenSize) {
throw new Error("Input 1 dimension 0 should have same length as dimension 2 of input 0");
}
if (bias.dims[0] !== weights.dims[1]) {
throw new Error('Input "bias" dimension 0 should have same length as dimension 1 of input "weights"');
}
let qHiddenSize = bias.dims[0] / 3;
let kHiddenSize = qHiddenSize;
let vHiddenSize = kHiddenSize;
if (attributes.qkvHiddenSizes.length > 0) {
if (attributes.qkvHiddenSizes.length !== 3) {
throw new Error("qkv_hidden_sizes attribute should have 3 elements");
}
for (const sz of attributes.qkvHiddenSizes) {
if (sz % attributes.numHeads !== 0) {
throw new Error("qkv_hidden_sizes should be divisible by num_heads");
}
}
qHiddenSize = attributes.qkvHiddenSizes[0];
kHiddenSize = attributes.qkvHiddenSizes[1];
vHiddenSize = attributes.qkvHiddenSizes[2];
}
const kvSequenceLength = sequenceLength;
if (qHiddenSize !== kHiddenSize) {
throw new Error("qkv_hidden_sizes first element should be same as the second");
}
if (bias.dims[0] !== qHiddenSize + kHiddenSize + vHiddenSize) {
throw new Error('Input "bias" dimension 0 should have same length as sum of Q/K/V hidden sizes');
}
let pastSequenceLength = 0;
if (past) {
if (kHiddenSize !== vHiddenSize) {
throw new Error('Input "past" expect k_hidden_size == v_hidden_size');
}
if (past.dims.length !== 5) {
throw new Error('Input "past" must have 5 dimensions');
}
if (past.dims[0] !== 2) {
throw new Error('Input "past" first dimension must be 2');
}
if (past.dims[1] !== batchSize) {
throw new Error('Input "past" second dimension must be batch_size');
}
if (past.dims[2] !== attributes.numHeads) {
throw new Error('Input "past" third dimension must be num_heads');
}
if (past.dims[4] !== kHiddenSize / attributes.numHeads) {
throw new Error('Input "past" fifth dimension must be k_hidden_size / num_heads');
}
if (!attributes.pastPresentShareBuffer) {
pastSequenceLength = past.dims[3];
}
}
const totalSequenceLength = kvSequenceLength + pastSequenceLength;
const maxSequenceLength = -1;
const maskType = 0 /* none */;
if (maskIndex) {
throw new Error("Mask not supported");
}
if (past) {
throw new Error("past is not supported");
}
if (attentionBias) {
if (attentionBias.dims.length !== 4) {
throw new Error('Input "attention_bias" must have 4 dimensions');
}
if (attentionBias.dims[0] !== batchSize || attentionBias.dims[1] !== attributes.numHeads || attentionBias.dims[2] !== sequenceLength || attentionBias.dims[3] !== totalSequenceLength) {
throw new Error('Expect "attention_bias" shape (batch_size, num_heads, sequence_length, total_sequence_length)');
}
}
return {
batchSize,
sequenceLength,
pastSequenceLength,
kvSequenceLength,
totalSequenceLength,
maxSequenceLength,
inputHiddenSize,
hiddenSize: qHiddenSize,
vHiddenSize,
headSize: Math.floor(qHiddenSize / attributes.numHeads),
vHeadSize: Math.floor(vHiddenSize / attributes.numHeads),
numHeads: attributes.numHeads,
isUnidirectional: false,
pastPresentShareBuffer: false,
maskFilterValue: attributes.maskFilterValue,
maskType,
scale: attributes.scale,
broadcastResPosBias: false,
passPastInKv: false,
qkvFormat: 1 /* qkvBNSH */
};
};
createInPlaceSoftmaxProgramInfo = (input, n, d) => {
const components = getMaxComponents(d);
let WG = 64;
const dComp = d / components;
if (dComp < WG) {
WG = 32;
}
const elementsPerThread = Math.ceil(d / components / WG);
const programUniforms = [
{ type: 1 /* float */, data: 1 / d },
{ type: 12 /* uint32 */, data: dComp },
{ type: 12 /* uint32 */, data: elementsPerThread }
];
const dataType = tensorTypeToWsglStorageType(input.dataType, components);
const f32Type = tensorTypeToWsglValueType(1 /* float */, components);
const inputDependencies = ["type"];
const getShaderSource = (shaderHelper) => {
const inputHelper = outputVariable("x", input.dataType, input.dims, components);
const elemValueType = tensorTypeToWsglValueType(input.dataType);
const uniforms = [
{ name: "d_inv", type: "f32" },
{ name: "d_comp", type: "u32" },
{ name: "elements_per_thread", type: "u32" }
];
return `
var<workgroup> thread_max: array<f32, ${WG}>;
var<workgroup> thread_sum: array<f32, ${WG}>;
${shaderHelper.registerUniforms(uniforms).declareVariables(inputHelper)}
${shaderHelper.mainStart([WG, 1, 1])}
let local_offset = local_idx * uniforms.elements_per_thread;
let offset = (global_idx / ${WG}) * uniforms.d_comp + local_offset;
var thread_max_vector = ${f32Type}(-3.402823e+38f);
for (var i: u32 = 0; i < uniforms.elements_per_thread && i + local_offset < uniforms.d_comp; i++) {
thread_max_vector = max(${f32Type}(x[offset + i]), thread_max_vector);
}
thread_max[local_idx] = ${(() => {
switch (components) {
case 1:
return "thread_max_vector";
case 2:
return "max(thread_max_vector.x, thread_max_vector.y)";
case 4:
return "max(max(thread_max_vector.x, thread_max_vector.y), max(thread_max_vector.z, thread_max_vector.w))";
default:
throw new Error(`Unsupported components: ${components}`);
}
})()};
workgroupBarrier();
var max_value = f32(-3.402823e+38f);
for (var i = 0u; i < ${WG}; i++) {
max_value = max(thread_max[i], max_value);
}
var sum_vector = ${f32Type}(0);
for (var i: u32 = 0; i < uniforms.elements_per_thread && i + local_offset < uniforms.d_comp; i++) {
sum_vector += exp(${f32Type}(x[offset + i]) - max_value);
}
thread_sum[local_idx] = ${(() => {
switch (components) {
case 1:
return "sum_vector";
case 2:
return "sum_vector.x + sum_vector.y";
case 4:
return "sum_vector.x + sum_vector.y + sum_vector.z + sum_vector.w";
default:
throw new Error(`Unsupported components: ${components}`);
}
})()};
workgroupBarrier();
var sum: f32 = 0;
for (var i = 0u; i < ${WG}; i++) {
sum += thread_sum[i];
}
if (sum == 0) {
for (var i: u32 = 0; i < uniforms.elements_per_thread && i + local_offset < uniforms.d_comp; i++) {
x[offset + i] = ${inputHelper.type.value}(${elemValueType}(uniforms.d_inv));
}
} else {
for (var i: u32 = 0; i < uniforms.elements_per_thread && i + local_offset < uniforms.d_comp; i++) {
var f32input = ${f32Type}(x[offset + i]);
x[offset + i] = ${inputHelper.type.value}(exp(f32input - max_value) / sum);
}
}
}`;
};
return {
name: "AttentionProbsSoftmax",
shaderCache: { hint: `${WG};${dataType};${components}`, inputDependencies },
getShaderSource,
getRunData: () => ({ outputs: [], dispatchGroup: { x: n }, programUniforms })
};
};
createAttentionProbsProgramInfo = (outputCount, q, key, pastKey, attentionBias, parameters, attributes, pastSequenceLength) => {
const totalSequenceLength = pastSequenceLength + parameters.kvSequenceLength;
const probsShape = [parameters.batchSize, parameters.numHeads, parameters.sequenceLength, totalSequenceLength];
const presentKey = parameters.kvNumHeads === void 0 && outputCount > 1 && pastKey;
const presentKeyShape = presentKey ? [parameters.batchSize, parameters.numHeads, totalSequenceLength, parameters.headSize] : void 0;
const alpha = attributes.scale === 0 ? 1 / Math.sqrt(parameters.headSize) : attributes.scale;
const components = getMaxComponents(parameters.headSize);
const vectorizedHeadSize = parameters.headSize / components;
const TILE_SIZE = 12;
const dispatch = {
x: Math.ceil(totalSequenceLength / TILE_SIZE),
y: Math.ceil(parameters.sequenceLength / TILE_SIZE),
z: parameters.batchSize * parameters.numHeads
};
const programUniforms = [
{ type: 12 /* uint32 */, data: parameters.sequenceLength },
{ type: 12 /* uint32 */, data: vectorizedHeadSize },
{ type: 12 /* uint32 */, data: totalSequenceLength },
{ type: 12 /* uint32 */, data: parameters.numHeads },
{ type: 1 /* float */, data: alpha },
{ type: 12 /* uint32 */, data: pastSequenceLength },
{ type: 12 /* uint32 */, data: parameters.kvSequenceLength }
];
const feedPastKey = presentKey && pastKey && ShapeUtil.size(pastKey.dims) > 0;
const inputDependencies = ["type", "type"];
if (feedPastKey) {
inputDependencies.push("type");
}
if (attentionBias) {
inputDependencies.push("type");
}
const outputs = [{ dims: probsShape, dataType: q.dataType, gpuDataType: 0 /* default */ }];
if (presentKey) {
outputs.push({ dims: presentKeyShape, dataType: q.dataType, gpuDataType: 0 /* default */ });
}
const getShaderSource = (shaderHelper) => {
const qInput = inputVariable("q", q.dataType, q.dims, components);
const kInput = inputVariable("key", key.dataType, key.dims, components);
const inputVars = [qInput, kInput];
if (feedPastKey) {
const pastKeyInput = inputVariable("past_key", pastKey.dataType, pastKey.dims, components); | | |