chore: update node_modules with new binary files and dependencies

- Add new binary files for nodemon, onnxruntime-web, and xenova/transformers
- Update various JavaScript and TypeScript files in node_modules
- Remove unused files and dependencies
- Add new test fixtures and documentation files
This commit is contained in:
你的名字
2025-07-18 08:41:48 +08:00
parent db8c0adc79
commit 4c2f5c69a1
4655 changed files with 811329 additions and 35112 deletions

View File

@@ -0,0 +1,20 @@
"use strict";
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
Object.defineProperty(exports, "__esModule", { value: true });
exports.createAttributeWithCacheKey = void 0;
class AttributeWithCacheKeyImpl {
constructor(attribute) {
Object.assign(this, attribute);
}
get cacheKey() {
if (!this._cacheKey) {
this._cacheKey =
Object.getOwnPropertyNames(this).sort().map(name => `${this[name]}`).join(';');
}
return this._cacheKey;
}
}
const createAttributeWithCacheKey = (attribute) => new AttributeWithCacheKeyImpl(attribute);
exports.createAttributeWithCacheKey = createAttributeWithCacheKey;
//# sourceMappingURL=attribute-with-cache-key.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"attribute-with-cache-key.js","sourceRoot":"","sources":["attribute-with-cache-key.ts"],"names":[],"mappings":";AAAA,4DAA4D;AAC5D,kCAAkC;;;AAElC,MAAM,yBAAyB;IAC7B,YAAY,SAAkC;QAC5C,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;IACjC,CAAC;IAGD,IAAW,QAAQ;QACjB,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE;YACnB,IAAI,CAAC,SAAS;gBACV,MAAM,CAAC,mBAAmB,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,GAAI,IAAgC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;SACjH;QACD,OAAO,IAAI,CAAC,SAAS,CAAC;IACxB,CAAC;CACF;AAMM,MAAM,2BAA2B,GAAG,CAAoC,SAAY,EAA2B,EAAE,CACpH,IAAI,yBAAyB,CAAC,SAAS,CAAyC,CAAC;AADxE,QAAA,2BAA2B,+BAC6C"}

View File

@@ -0,0 +1,24 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
class AttributeWithCacheKeyImpl {
constructor(attribute: Record<string, unknown>) {
Object.assign(this, attribute);
}
private _cacheKey: string;
public get cacheKey(): string {
if (!this._cacheKey) {
this._cacheKey =
Object.getOwnPropertyNames(this).sort().map(name => `${(this as Record<string, unknown>)[name]}`).join(';');
}
return this._cacheKey;
}
}
export interface AttributeWithCacheKey {
readonly cacheKey: string;
}
export const createAttributeWithCacheKey = <T extends Record<string, unknown>>(attribute: T): T&AttributeWithCacheKey =>
new AttributeWithCacheKeyImpl(attribute) as unknown as T & AttributeWithCacheKey;

228
node_modules/onnxruntime-web/lib/onnxjs/attribute.js generated vendored Normal file
View File

@@ -0,0 +1,228 @@
"use strict";
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
Object.defineProperty(exports, "__esModule", { value: true });
exports.Attribute = void 0;
const onnx_proto_1 = require("onnx-proto");
const ort_generated_1 = require("./ort-schema/ort-generated");
const tensor_1 = require("./tensor");
const util_1 = require("./util");
var ortFbs = ort_generated_1.onnxruntime.experimental.fbs;
class Attribute {
constructor(attributes) {
this._attributes = new Map();
if (attributes !== null && attributes !== undefined) {
for (const attr of attributes) {
if (attr instanceof onnx_proto_1.onnx.AttributeProto) {
this._attributes.set(attr.name, [Attribute.getValue(attr), Attribute.getType(attr)]);
}
else if (attr instanceof ortFbs.Attribute) {
this._attributes.set(attr.name(), [Attribute.getValue(attr), Attribute.getType(attr)]);
}
}
if (this._attributes.size < attributes.length) {
throw new Error('duplicated attribute names');
}
}
}
set(key, type, value) {
this._attributes.set(key, [value, type]);
}
delete(key) {
this._attributes.delete(key);
}
getFloat(key, defaultValue) {
return this.get(key, 'float', defaultValue);
}
getInt(key, defaultValue) {
return this.get(key, 'int', defaultValue);
}
getString(key, defaultValue) {
return this.get(key, 'string', defaultValue);
}
getTensor(key, defaultValue) {
return this.get(key, 'tensor', defaultValue);
}
getFloats(key, defaultValue) {
return this.get(key, 'floats', defaultValue);
}
getInts(key, defaultValue) {
return this.get(key, 'ints', defaultValue);
}
getStrings(key, defaultValue) {
return this.get(key, 'strings', defaultValue);
}
getTensors(key, defaultValue) {
return this.get(key, 'tensors', defaultValue);
}
get(key, type, defaultValue) {
const valueAndType = this._attributes.get(key);
if (valueAndType === undefined) {
if (defaultValue !== undefined) {
return defaultValue;
}
throw new Error(`required attribute not found: ${key}`);
}
if (valueAndType[1] !== type) {
throw new Error(`type mismatch: expected ${type} but got ${valueAndType[1]}`);
}
return valueAndType[0];
}
static getType(attr) {
const type = attr instanceof onnx_proto_1.onnx.AttributeProto ? (attr).type : attr.type();
switch (type) {
case onnx_proto_1.onnx.AttributeProto.AttributeType.FLOAT:
return 'float';
case onnx_proto_1.onnx.AttributeProto.AttributeType.INT:
return 'int';
case onnx_proto_1.onnx.AttributeProto.AttributeType.STRING:
return 'string';
case onnx_proto_1.onnx.AttributeProto.AttributeType.TENSOR:
return 'tensor';
case onnx_proto_1.onnx.AttributeProto.AttributeType.FLOATS:
return 'floats';
case onnx_proto_1.onnx.AttributeProto.AttributeType.INTS:
return 'ints';
case onnx_proto_1.onnx.AttributeProto.AttributeType.STRINGS:
return 'strings';
case onnx_proto_1.onnx.AttributeProto.AttributeType.TENSORS:
return 'tensors';
default:
throw new Error(`attribute type is not supported yet: ${onnx_proto_1.onnx.AttributeProto.AttributeType[type]}`);
}
}
static getValue(attr) {
const attrType = attr instanceof onnx_proto_1.onnx.AttributeProto ? attr.type : attr.type();
if (attrType === onnx_proto_1.onnx.AttributeProto.AttributeType.GRAPH || attrType === onnx_proto_1.onnx.AttributeProto.AttributeType.GRAPHS) {
throw new Error('graph attribute is not supported yet');
}
const value = this.getValueNoCheck(attr);
// cast LONG to number
if (attrType === onnx_proto_1.onnx.AttributeProto.AttributeType.INT && util_1.LongUtil.isLong(value)) {
return util_1.LongUtil.longToNumber(value);
}
// cast LONG[] to number[]
if (attrType === onnx_proto_1.onnx.AttributeProto.AttributeType.INTS) {
const arr = value;
const numberValue = new Array(arr.length);
for (let i = 0; i < arr.length; i++) {
const maybeLong = arr[i];
numberValue[i] = util_1.LongUtil.longToNumber(maybeLong);
}
return numberValue;
}
// cast onnx.TensorProto to onnxjs.Tensor
if (attrType === onnx_proto_1.onnx.AttributeProto.AttributeType.TENSOR) {
return attr instanceof onnx_proto_1.onnx.AttributeProto ? tensor_1.Tensor.fromProto(value) :
tensor_1.Tensor.fromOrtTensor(value);
}
// cast onnx.TensorProto[] to onnxjs.Tensor[]
if (attrType === onnx_proto_1.onnx.AttributeProto.AttributeType.TENSORS) {
if (attr instanceof onnx_proto_1.onnx.AttributeProto) {
const tensorProtos = value;
return tensorProtos.map(value => tensor_1.Tensor.fromProto(value));
}
else if (attr instanceof ortFbs.Attribute) {
const tensorProtos = value;
return tensorProtos.map(value => tensor_1.Tensor.fromOrtTensor(value));
}
}
// cast Uint8Array to string
if (attrType === onnx_proto_1.onnx.AttributeProto.AttributeType.STRING) {
// string in onnx attribute is of uint8array type, so we need to convert it to string below. While in ort format,
// string attributes are returned as string, so no conversion is needed.
if (attr instanceof onnx_proto_1.onnx.AttributeProto) {
const utf8String = value;
return (0, util_1.decodeUtf8String)(utf8String);
}
}
// cast Uint8Array[] to string[]
if (attrType === onnx_proto_1.onnx.AttributeProto.AttributeType.STRINGS) {
// strings in onnx attribute is returned as uint8array[], so we need to convert it to string[] below. While in ort
// format strings attributes are returned as string[], so no conversion is needed.
if (attr instanceof onnx_proto_1.onnx.AttributeProto) {
const utf8Strings = value;
return utf8Strings.map(util_1.decodeUtf8String);
}
}
return value;
}
static getValueNoCheck(attr) {
return attr instanceof (onnx_proto_1.onnx.AttributeProto) ? this.getValueNoCheckFromOnnxFormat(attr) :
this.getValueNoCheckFromOrtFormat(attr);
}
static getValueNoCheckFromOnnxFormat(attr) {
switch (attr.type) {
case onnx_proto_1.onnx.AttributeProto.AttributeType.FLOAT:
return attr.f;
case onnx_proto_1.onnx.AttributeProto.AttributeType.INT:
return attr.i;
case onnx_proto_1.onnx.AttributeProto.AttributeType.STRING:
return attr.s;
case onnx_proto_1.onnx.AttributeProto.AttributeType.TENSOR:
return attr.t;
case onnx_proto_1.onnx.AttributeProto.AttributeType.GRAPH:
return attr.g;
case onnx_proto_1.onnx.AttributeProto.AttributeType.FLOATS:
return attr.floats;
case onnx_proto_1.onnx.AttributeProto.AttributeType.INTS:
return attr.ints;
case onnx_proto_1.onnx.AttributeProto.AttributeType.STRINGS:
return attr.strings;
case onnx_proto_1.onnx.AttributeProto.AttributeType.TENSORS:
return attr.tensors;
case onnx_proto_1.onnx.AttributeProto.AttributeType.GRAPHS:
return attr.graphs;
default:
throw new Error(`unsupported attribute type: ${onnx_proto_1.onnx.AttributeProto.AttributeType[attr.type]}`);
}
}
static getValueNoCheckFromOrtFormat(attr) {
switch (attr.type()) {
case ortFbs.AttributeType.FLOAT:
return attr.f();
case ortFbs.AttributeType.INT:
return attr.i();
case ortFbs.AttributeType.STRING:
return attr.s();
case ortFbs.AttributeType.TENSOR:
return attr.t();
case ortFbs.AttributeType.GRAPH:
return attr.g();
case ortFbs.AttributeType.FLOATS:
return attr.floatsArray();
case ortFbs.AttributeType.INTS: {
const ints = [];
for (let i = 0; i < attr.intsLength(); i++) {
ints.push(attr.ints(i));
}
return ints;
}
case ortFbs.AttributeType.STRINGS: {
const strings = [];
for (let i = 0; i < attr.stringsLength(); i++) {
strings.push(attr.strings(i));
}
return strings;
}
case ortFbs.AttributeType.TENSORS: {
const tensors = [];
for (let i = 0; i < attr.tensorsLength(); i++) {
tensors.push(attr.tensors(i));
}
return tensors;
}
// case ortFbs.AttributeType.GRAPHS:
// TODO: Subgraph not supported yet.
// const graphs = [];
// for (let i = 0; i < attr.graphsLength(); i++) {
// graphs.push(attr.graphs(i)!);
// }
// return graphs;
default:
throw new Error(`unsupported attribute type: ${ortFbs.AttributeType[attr.type()]}`);
}
}
}
exports.Attribute = Attribute;
//# sourceMappingURL=attribute.js.map

File diff suppressed because one or more lines are too long

272
node_modules/onnxruntime-web/lib/onnxjs/attribute.ts generated vendored Normal file
View File

@@ -0,0 +1,272 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
import Long from 'long';
import {onnx} from 'onnx-proto';
import {onnxruntime} from './ort-schema/ort-generated';
import {Tensor} from './tensor';
import {decodeUtf8String, LongUtil} from './util';
import ortFbs = onnxruntime.experimental.fbs;
export declare namespace Attribute {
export interface DataTypeMap {
float: number;
int: number;
string: string;
tensor: Tensor;
floats: number[];
ints: number[];
strings: string[];
tensors: Tensor[];
}
export type DataType = keyof DataTypeMap;
}
type ValueTypes = Attribute.DataTypeMap[Attribute.DataType];
type Value = [ValueTypes, Attribute.DataType];
export class Attribute {
constructor(attributes: onnx.IAttributeProto[]|ortFbs.Attribute[]|null|undefined) {
this._attributes = new Map();
if (attributes !== null && attributes !== undefined) {
for (const attr of attributes) {
if (attr instanceof onnx.AttributeProto) {
this._attributes.set(attr.name, [Attribute.getValue(attr), Attribute.getType(attr)]);
} else if (attr instanceof ortFbs.Attribute) {
this._attributes.set(attr.name()!, [Attribute.getValue(attr), Attribute.getType(attr)]);
}
}
if (this._attributes.size < attributes.length) {
throw new Error('duplicated attribute names');
}
}
}
set(key: string, type: Attribute.DataType, value: ValueTypes): void {
this._attributes.set(key, [value, type]);
}
delete(key: string): void {
this._attributes.delete(key);
}
getFloat(key: string, defaultValue?: Attribute.DataTypeMap['float']) {
return this.get(key, 'float', defaultValue);
}
getInt(key: string, defaultValue?: Attribute.DataTypeMap['int']) {
return this.get(key, 'int', defaultValue);
}
getString(key: string, defaultValue?: Attribute.DataTypeMap['string']) {
return this.get(key, 'string', defaultValue);
}
getTensor(key: string, defaultValue?: Attribute.DataTypeMap['tensor']) {
return this.get(key, 'tensor', defaultValue);
}
getFloats(key: string, defaultValue?: Attribute.DataTypeMap['floats']) {
return this.get(key, 'floats', defaultValue);
}
getInts(key: string, defaultValue?: Attribute.DataTypeMap['ints']) {
return this.get(key, 'ints', defaultValue);
}
getStrings(key: string, defaultValue?: Attribute.DataTypeMap['strings']) {
return this.get(key, 'strings', defaultValue);
}
getTensors(key: string, defaultValue?: Attribute.DataTypeMap['tensors']) {
return this.get(key, 'tensors', defaultValue);
}
private get<V extends Attribute.DataTypeMap[Attribute.DataType]>(
key: string, type: Attribute.DataType, defaultValue?: V): V {
const valueAndType = this._attributes.get(key);
if (valueAndType === undefined) {
if (defaultValue !== undefined) {
return defaultValue;
}
throw new Error(`required attribute not found: ${key}`);
}
if (valueAndType[1] !== type) {
throw new Error(`type mismatch: expected ${type} but got ${valueAndType[1]}`);
}
return valueAndType[0] as V;
}
private static getType(attr: onnx.IAttributeProto|ortFbs.Attribute): Attribute.DataType {
const type = attr instanceof onnx.AttributeProto ? (attr).type : (attr as ortFbs.Attribute).type();
switch (type) {
case onnx.AttributeProto.AttributeType.FLOAT:
return 'float';
case onnx.AttributeProto.AttributeType.INT:
return 'int';
case onnx.AttributeProto.AttributeType.STRING:
return 'string';
case onnx.AttributeProto.AttributeType.TENSOR:
return 'tensor';
case onnx.AttributeProto.AttributeType.FLOATS:
return 'floats';
case onnx.AttributeProto.AttributeType.INTS:
return 'ints';
case onnx.AttributeProto.AttributeType.STRINGS:
return 'strings';
case onnx.AttributeProto.AttributeType.TENSORS:
return 'tensors';
default:
throw new Error(`attribute type is not supported yet: ${onnx.AttributeProto.AttributeType[type]}`);
}
}
private static getValue(attr: onnx.IAttributeProto|ortFbs.Attribute) {
const attrType = attr instanceof onnx.AttributeProto ? attr.type : (attr as ortFbs.Attribute).type();
if (attrType === onnx.AttributeProto.AttributeType.GRAPH || attrType === onnx.AttributeProto.AttributeType.GRAPHS) {
throw new Error('graph attribute is not supported yet');
}
const value = this.getValueNoCheck(attr);
// cast LONG to number
if (attrType === onnx.AttributeProto.AttributeType.INT && LongUtil.isLong(value)) {
return LongUtil.longToNumber(value as Long | flatbuffers.Long);
}
// cast LONG[] to number[]
if (attrType === onnx.AttributeProto.AttributeType.INTS) {
const arr = (value as Array<number|Long|flatbuffers.Long>);
const numberValue: number[] = new Array<number>(arr.length);
for (let i = 0; i < arr.length; i++) {
const maybeLong = arr[i];
numberValue[i] = LongUtil.longToNumber(maybeLong);
}
return numberValue;
}
// cast onnx.TensorProto to onnxjs.Tensor
if (attrType === onnx.AttributeProto.AttributeType.TENSOR) {
return attr instanceof onnx.AttributeProto ? Tensor.fromProto(value as onnx.ITensorProto) :
Tensor.fromOrtTensor(value as ortFbs.Tensor);
}
// cast onnx.TensorProto[] to onnxjs.Tensor[]
if (attrType === onnx.AttributeProto.AttributeType.TENSORS) {
if (attr instanceof onnx.AttributeProto) {
const tensorProtos = value as onnx.ITensorProto[];
return tensorProtos.map(value => Tensor.fromProto(value));
} else if (attr instanceof ortFbs.Attribute) {
const tensorProtos = value as ortFbs.Tensor[];
return tensorProtos.map(value => Tensor.fromOrtTensor(value));
}
}
// cast Uint8Array to string
if (attrType === onnx.AttributeProto.AttributeType.STRING) {
// string in onnx attribute is of uint8array type, so we need to convert it to string below. While in ort format,
// string attributes are returned as string, so no conversion is needed.
if (attr instanceof onnx.AttributeProto) {
const utf8String = value as Uint8Array;
return decodeUtf8String(utf8String);
}
}
// cast Uint8Array[] to string[]
if (attrType === onnx.AttributeProto.AttributeType.STRINGS) {
// strings in onnx attribute is returned as uint8array[], so we need to convert it to string[] below. While in ort
// format strings attributes are returned as string[], so no conversion is needed.
if (attr instanceof onnx.AttributeProto) {
const utf8Strings = value as Uint8Array[];
return utf8Strings.map(decodeUtf8String);
}
}
return value as ValueTypes;
}
private static getValueNoCheck(attr: onnx.IAttributeProto|ortFbs.Attribute) {
return attr instanceof (onnx.AttributeProto) ? this.getValueNoCheckFromOnnxFormat(attr) :
this.getValueNoCheckFromOrtFormat(attr as ortFbs.Attribute);
}
private static getValueNoCheckFromOnnxFormat(attr: onnx.IAttributeProto) {
switch (attr.type!) {
case onnx.AttributeProto.AttributeType.FLOAT:
return attr.f;
case onnx.AttributeProto.AttributeType.INT:
return attr.i;
case onnx.AttributeProto.AttributeType.STRING:
return attr.s;
case onnx.AttributeProto.AttributeType.TENSOR:
return attr.t;
case onnx.AttributeProto.AttributeType.GRAPH:
return attr.g;
case onnx.AttributeProto.AttributeType.FLOATS:
return attr.floats;
case onnx.AttributeProto.AttributeType.INTS:
return attr.ints;
case onnx.AttributeProto.AttributeType.STRINGS:
return attr.strings;
case onnx.AttributeProto.AttributeType.TENSORS:
return attr.tensors;
case onnx.AttributeProto.AttributeType.GRAPHS:
return attr.graphs;
default:
throw new Error(`unsupported attribute type: ${onnx.AttributeProto.AttributeType[attr.type!]}`);
}
}
private static getValueNoCheckFromOrtFormat(attr: ortFbs.Attribute) {
switch (attr.type()) {
case ortFbs.AttributeType.FLOAT:
return attr.f();
case ortFbs.AttributeType.INT:
return attr.i();
case ortFbs.AttributeType.STRING:
return attr.s();
case ortFbs.AttributeType.TENSOR:
return attr.t();
case ortFbs.AttributeType.GRAPH:
return attr.g();
case ortFbs.AttributeType.FLOATS:
return attr.floatsArray();
case ortFbs.AttributeType.INTS: {
const ints = [];
for (let i = 0; i < attr.intsLength(); i++) {
ints.push(attr.ints(i)!);
}
return ints;
}
case ortFbs.AttributeType.STRINGS: {
const strings = [];
for (let i = 0; i < attr.stringsLength(); i++) {
strings.push(attr.strings(i));
}
return strings;
}
case ortFbs.AttributeType.TENSORS: {
const tensors = [];
for (let i = 0; i < attr.tensorsLength(); i++) {
tensors.push(attr.tensors(i)!);
}
return tensors;
}
// case ortFbs.AttributeType.GRAPHS:
// TODO: Subgraph not supported yet.
// const graphs = [];
// for (let i = 0; i < attr.graphsLength(); i++) {
// graphs.push(attr.graphs(i)!);
// }
// return graphs;
default:
throw new Error(`unsupported attribute type: ${ortFbs.AttributeType[attr.type()]}`);
}
}
protected _attributes: Map<string, Value>;
}

63
node_modules/onnxruntime-web/lib/onnxjs/backend.js generated vendored Normal file
View File

@@ -0,0 +1,63 @@
"use strict";
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
Object.defineProperty(exports, "__esModule", { value: true });
exports.resolveBackend = exports.backend = void 0;
const backend_webgl_1 = require("./backends/backend-webgl");
// caches all initialized backend instances
const backendsCache = new Map();
exports.backend = {
webgl: new backend_webgl_1.WebGLBackend(),
};
/**
* Resolve a reference to the backend. If a hint is specified, the corresponding
* backend will be used.
*/
async function resolveBackend(hint) {
if (!hint) {
return resolveBackend(['webgl']);
}
else {
const hints = typeof hint === 'string' ? [hint] : hint;
for (const backendHint of hints) {
const cache = backendsCache.get(backendHint);
if (cache) {
return cache;
}
const backend = await tryLoadBackend(backendHint);
if (backend) {
return backend;
}
}
}
throw new Error('no available backend to use');
}
exports.resolveBackend = resolveBackend;
async function tryLoadBackend(backendHint) {
const backendObj = exports.backend;
if (typeof backendObj[backendHint] !== 'undefined' && isBackend(backendObj[backendHint])) {
const backend = backendObj[backendHint];
let init = backend.initialize();
if (typeof init === 'object' && 'then' in init) {
init = await init;
}
if (init) {
backendsCache.set(backendHint, backend);
return backend;
}
}
return undefined;
}
function isBackend(obj) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const o = obj;
// check if an object is a Backend instance
if ('initialize' in o && typeof o.initialize === 'function' && // initialize()
'createSessionHandler' in o && typeof o.createSessionHandler === 'function' && // createSessionHandler()
'dispose' in o && typeof o.dispose === 'function' // dispose()
) {
return true;
}
return false;
}
//# sourceMappingURL=backend.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"backend.js","sourceRoot":"","sources":["backend.ts"],"names":[],"mappings":";AAAA,4DAA4D;AAC5D,kCAAkC;;;AAElC,4DAAsD;AAyEtD,2CAA2C;AAC3C,MAAM,aAAa,GAAyB,IAAI,GAAG,EAAE,CAAC;AAEzC,QAAA,OAAO,GAA8B;IAChD,KAAK,EAAE,IAAI,4BAAY,EAAE;CAC1B,CAAC;AAEF;;;GAGG;AACI,KAAK,UAAU,cAAc,CAAC,IAA+B;IAClE,IAAI,CAAC,IAAI,EAAE;QACT,OAAO,cAAc,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;KAClC;SAAM;QACL,MAAM,KAAK,GAAG,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QAEvD,KAAK,MAAM,WAAW,IAAI,KAAK,EAAE;YAC/B,MAAM,KAAK,GAAG,aAAa,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;YAC7C,IAAI,KAAK,EAAE;gBACT,OAAO,KAAK,CAAC;aACd;YAED,MAAM,OAAO,GAAG,MAAM,cAAc,CAAC,WAAW,CAAC,CAAC;YAClD,IAAI,OAAO,EAAE;gBACX,OAAO,OAAO,CAAC;aAChB;SACF;KACF;IAED,MAAM,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAC;AACjD,CAAC;AApBD,wCAoBC;AAED,KAAK,UAAU,cAAc,CAAC,WAAmB;IAC/C,MAAM,UAAU,GAAG,eAAO,CAAC;IAE3B,IAAI,OAAO,UAAU,CAAC,WAAW,CAAC,KAAK,WAAW,IAAI,SAAS,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC,EAAE;QACxF,MAAM,OAAO,GAAG,UAAU,CAAC,WAAW,CAAC,CAAC;QACxC,IAAI,IAAI,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC;QAChC,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,MAAM,IAAI,IAAI,EAAE;YAC9C,IAAI,GAAG,MAAM,IAAI,CAAC;SACnB;QACD,IAAI,IAAI,EAAE;YACR,aAAa,CAAC,GAAG,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;YACxC,OAAO,OAAO,CAAC;SAChB;KACF;IAED,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,SAAS,SAAS,CAAC,GAAY;IAC7B,8DAA8D;IAC9D,MAAM,CAAC,GAAG,GAAU,CAAC;IAErB,2CAA2C;IAC3C,IACI,YAAY,IAAI,CAAC,IAAI,OAAO,CAAC,CAAC,UAAU,KAAK,UAAU,IAAyB,eAAe;QAC/F,sBAAsB,IAAI,CAAC,IAAI,OAAO,CAAC,CAAC,oBAAoB,KAAK,UAAU,IAAK,yBAAyB;QACzG,SAAS,IAAI,CAAC,IAAI,OAAO,CAAC,CAAC,OAAO,KAAK,UAAU,CAA+B,YAAY;MAC9F;QACA,OAAO,IAAI,CAAC;KACb;IAED,OAAO,KAAK,CAAC;AACf,CAAC"}

146
node_modules/onnxruntime-web/lib/onnxjs/backend.ts generated vendored Normal file
View File

@@ -0,0 +1,146 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
import {WebGLBackend} from './backends/backend-webgl';
import {Graph} from './graph';
import {Operator} from './operators';
import {OpSet} from './opset';
import {Session} from './session';
export interface InferenceHandler {
/**
* dispose the inference handler. it will be called as the last step in Session.run()
*/
dispose(): void;
}
export interface SessionHandler {
/**
* transform the graph at initialization time
* @param graphTransformer the graph transformer to manipulate the model graph
*/
transformGraph?(graphTransformer: Graph.Transformer): void;
/**
* create an instance of InferenceHandler to use in a Session.run() call
*/
createInferenceHandler(): InferenceHandler;
/**
* dispose the session handler. it will be called when a session is being disposed explicitly
*/
dispose(): void;
/**
* Resolves the operator from the name and opset version; backend specific
* @param node the node to resolve
* @param opsets a list of opsets that exported from the model
* @param graph the completely initialized graph
*/
resolve(node: Graph.Node, opsets: readonly OpSet[], graph: Graph): Operator;
/**
* This method let's the sessionHandler know that the graph initialization is complete
* @param graph the completely initialized graph
*/
onGraphInitialized?(graph: Graph): void;
/**
* a reference to the corresponding backend
*/
readonly backend: Backend;
/**
* a reference to the session context
*/
readonly context: Session.Context;
}
export interface Backend {
/**
* initialize the backend. will be called only once, when the first time the
* backend it to be used
*/
initialize(): boolean|Promise<boolean>;
/**
* create an instance of SessionHandler to use in a Session object's lifecycle
*/
createSessionHandler(context: Session.Context): SessionHandler;
/**
* dispose the backend. currently this will not be called
*/
dispose(): void;
}
// caches all initialized backend instances
const backendsCache: Map<string, Backend> = new Map();
export const backend: {[name: string]: Backend} = {
webgl: new WebGLBackend(),
};
/**
* Resolve a reference to the backend. If a hint is specified, the corresponding
* backend will be used.
*/
export async function resolveBackend(hint?: string|readonly string[]): Promise<Backend> {
if (!hint) {
return resolveBackend(['webgl']);
} else {
const hints = typeof hint === 'string' ? [hint] : hint;
for (const backendHint of hints) {
const cache = backendsCache.get(backendHint);
if (cache) {
return cache;
}
const backend = await tryLoadBackend(backendHint);
if (backend) {
return backend;
}
}
}
throw new Error('no available backend to use');
}
async function tryLoadBackend(backendHint: string): Promise<Backend|undefined> {
const backendObj = backend;
if (typeof backendObj[backendHint] !== 'undefined' && isBackend(backendObj[backendHint])) {
const backend = backendObj[backendHint];
let init = backend.initialize();
if (typeof init === 'object' && 'then' in init) {
init = await init;
}
if (init) {
backendsCache.set(backendHint, backend);
return backend;
}
}
return undefined;
}
function isBackend(obj: unknown) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const o = obj as any;
// check if an object is a Backend instance
if (
'initialize' in o && typeof o.initialize === 'function' && // initialize()
'createSessionHandler' in o && typeof o.createSessionHandler === 'function' && // createSessionHandler()
'dispose' in o && typeof o.dispose === 'function' // dispose()
) {
return true;
}
return false;
}
export type BackendType = Backend;
export type SessionHandlerType = ReturnType<BackendType['createSessionHandler']>;
export type InferenceHandlerType = ReturnType<SessionHandlerType['createInferenceHandler']>;

View File

@@ -0,0 +1,78 @@
"use strict";
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
Object.defineProperty(exports, "__esModule", { value: true });
exports.WebGLBackend = void 0;
const onnxruntime_common_1 = require("onnxruntime-common");
const instrument_1 = require("../instrument");
const session_handler_1 = require("./webgl/session-handler");
const webgl_context_factory_1 = require("./webgl/webgl-context-factory");
/**
* WebGLBackend is the entry point for all WebGL opeartions
* When it starts it created the WebGLRenderingContext
* and other main framework components such as Program and Texture Managers
*/
class WebGLBackend {
get contextId() {
return onnxruntime_common_1.env.webgl.contextId;
}
set contextId(value) {
onnxruntime_common_1.env.webgl.contextId = value;
}
get matmulMaxBatchSize() {
return onnxruntime_common_1.env.webgl.matmulMaxBatchSize;
}
set matmulMaxBatchSize(value) {
onnxruntime_common_1.env.webgl.matmulMaxBatchSize = value;
}
get textureCacheMode() {
return onnxruntime_common_1.env.webgl.textureCacheMode;
}
set textureCacheMode(value) {
onnxruntime_common_1.env.webgl.textureCacheMode = value;
}
get pack() {
return onnxruntime_common_1.env.webgl.pack;
}
set pack(value) {
onnxruntime_common_1.env.webgl.pack = value;
}
get async() {
return onnxruntime_common_1.env.webgl.async;
}
set async(value) {
onnxruntime_common_1.env.webgl.async = value;
}
initialize() {
try {
this.glContext = (0, webgl_context_factory_1.createWebGLContext)(this.contextId);
if (typeof this.matmulMaxBatchSize !== 'number') {
this.matmulMaxBatchSize = 16;
}
if (typeof this.textureCacheMode !== 'string') {
this.textureCacheMode = 'full';
}
if (typeof this.pack !== 'boolean') {
this.pack = false;
}
if (typeof this.async !== 'boolean') {
this.async = false;
}
instrument_1.Logger.setWithEnv(onnxruntime_common_1.env);
instrument_1.Logger.verbose('WebGLBackend', `Created WebGLContext: ${typeof this.glContext} with matmulMaxBatchSize: ${this.matmulMaxBatchSize}; textureCacheMode: ${this.textureCacheMode}; pack: ${this.pack}; async: ${this.async}.`);
return true;
}
catch (e) {
instrument_1.Logger.warning('WebGLBackend', `Unable to initialize WebGLBackend. ${e}`);
return false;
}
}
createSessionHandler(context) {
return new session_handler_1.WebGLSessionHandler(this, context);
}
dispose() {
this.glContext.dispose();
}
}
exports.WebGLBackend = WebGLBackend;
//# sourceMappingURL=backend-webgl.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"backend-webgl.js","sourceRoot":"","sources":["backend-webgl.ts"],"names":[],"mappings":";AAAA,4DAA4D;AAC5D,kCAAkC;;;AAElC,2DAAuC;AAGvC,8CAAqC;AAGrC,6DAA4D;AAE5D,yEAAiE;AAEjE;;;;GAIG;AACH,MAAa,YAAY;IAGvB,IAAI,SAAS;QACX,OAAO,wBAAG,CAAC,KAAK,CAAC,SAAS,CAAC;IAC7B,CAAC;IACD,IAAI,SAAS,CAAC,KAAiC;QAC7C,wBAAG,CAAC,KAAK,CAAC,SAAS,GAAG,KAAK,CAAC;IAC9B,CAAC;IAED,IAAI,kBAAkB;QACpB,OAAO,wBAAG,CAAC,KAAK,CAAC,kBAAkB,CAAC;IACtC,CAAC;IACD,IAAI,kBAAkB,CAAC,KAAuB;QAC5C,wBAAG,CAAC,KAAK,CAAC,kBAAkB,GAAG,KAAK,CAAC;IACvC,CAAC;IAED,IAAI,gBAAgB;QAClB,OAAO,wBAAG,CAAC,KAAK,CAAC,gBAAgB,CAAC;IACpC,CAAC;IACD,IAAI,gBAAgB,CAAC,KAAyC;QAC5D,wBAAG,CAAC,KAAK,CAAC,gBAAgB,GAAG,KAAK,CAAC;IACrC,CAAC;IAED,IAAI,IAAI;QACN,OAAO,wBAAG,CAAC,KAAK,CAAC,IAAI,CAAC;IACxB,CAAC;IACD,IAAI,IAAI,CAAC,KAAwB;QAC/B,wBAAG,CAAC,KAAK,CAAC,IAAI,GAAG,KAAK,CAAC;IACzB,CAAC;IAED,IAAI,KAAK;QACP,OAAO,wBAAG,CAAC,KAAK,CAAC,KAAK,CAAC;IACzB,CAAC;IACD,IAAI,KAAK,CAAC,KAAwB;QAChC,wBAAG,CAAC,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC;IAC1B,CAAC;IAED,UAAU;QACR,IAAI;YACF,IAAI,CAAC,SAAS,GAAG,IAAA,0CAAkB,EAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YACpD,IAAI,OAAO,IAAI,CAAC,kBAAkB,KAAK,QAAQ,EAAE;gBAC/C,IAAI,CAAC,kBAAkB,GAAG,EAAE,CAAC;aAC9B;YACD,IAAI,OAAO,IAAI,CAAC,gBAAgB,KAAK,QAAQ,EAAE;gBAC7C,IAAI,CAAC,gBAAgB,GAAG,MAAM,CAAC;aAChC;YACD,IAAI,OAAO,IAAI,CAAC,IAAI,KAAK,SAAS,EAAE;gBAClC,IAAI,CAAC,IAAI,GAAG,KAAK,CAAC;aACnB;YACD,IAAI,OAAO,IAAI,CAAC,KAAK,KAAK,SAAS,EAAE;gBACnC,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;aACpB;YAED,mBAAM,CAAC,UAAU,CAAC,wBAAG,CAAC,CAAC;YAEvB,mBAAM,CAAC,OAAO,CACV,cAAc,EACd,yBAAyB,OAAO,IAAI,CAAC,SAAS,6BAC1C,IAAI,CAAC,kBAAkB,uBAAuB,IAAI,CAAC,gBAAgB,WAAW,IAAI,CAAC,IAAI,YACvF,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC;YACvB,OAAO,IAAI,CAAC;SACb;QAAC,OAAO,CAAC,EAAE;YACV,mBAAM,CAAC,OAAO,CAAC,cAAc,EAAE,sCAAsC,CAAC,EAAE,CAAC,CAAC;YAC1E,OAAO,KAAK,CAAC;SACd;IACH,CAAC;IACD,oBAAoB,CAAC,OAAwB;QAC3C,OAAO,IAAI,qCAAmB,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IAChD,CAAC;IACD,OAAO;QACL,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,CAAC;IAC3B,CAAC;CACF;AAzED,oCAyEC"}

View File

@@ -0,0 +1,92 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
import {env} from 'onnxruntime-common';
import {Backend, SessionHandler} from '../backend';
import {Logger} from '../instrument';
import {Session} from '../session';
import {WebGLSessionHandler} from './webgl/session-handler';
import {WebGLContext} from './webgl/webgl-context';
import {createWebGLContext} from './webgl/webgl-context-factory';
/**
* WebGLBackend is the entry point for all WebGL opeartions
* When it starts it created the WebGLRenderingContext
* and other main framework components such as Program and Texture Managers
*/
export class WebGLBackend implements Backend {
glContext: WebGLContext;
get contextId(): 'webgl'|'webgl2'|undefined {
return env.webgl.contextId;
}
set contextId(value: 'webgl'|'webgl2'|undefined) {
env.webgl.contextId = value;
}
get matmulMaxBatchSize(): number|undefined {
return env.webgl.matmulMaxBatchSize;
}
set matmulMaxBatchSize(value: number|undefined) {
env.webgl.matmulMaxBatchSize = value;
}
get textureCacheMode(): 'initializerOnly'|'full'|undefined {
return env.webgl.textureCacheMode;
}
set textureCacheMode(value: 'initializerOnly'|'full'|undefined) {
env.webgl.textureCacheMode = value;
}
get pack(): boolean|undefined {
return env.webgl.pack;
}
set pack(value: boolean|undefined) {
env.webgl.pack = value;
}
get async(): boolean|undefined {
return env.webgl.async;
}
set async(value: boolean|undefined) {
env.webgl.async = value;
}
initialize(): boolean {
try {
this.glContext = createWebGLContext(this.contextId);
if (typeof this.matmulMaxBatchSize !== 'number') {
this.matmulMaxBatchSize = 16;
}
if (typeof this.textureCacheMode !== 'string') {
this.textureCacheMode = 'full';
}
if (typeof this.pack !== 'boolean') {
this.pack = false;
}
if (typeof this.async !== 'boolean') {
this.async = false;
}
Logger.setWithEnv(env);
Logger.verbose(
'WebGLBackend',
`Created WebGLContext: ${typeof this.glContext} with matmulMaxBatchSize: ${
this.matmulMaxBatchSize}; textureCacheMode: ${this.textureCacheMode}; pack: ${this.pack}; async: ${
this.async}.`);
return true;
} catch (e) {
Logger.warning('WebGLBackend', `Unable to initialize WebGLBackend. ${e}`);
return false;
}
}
createSessionHandler(context: Session.Context): SessionHandler {
return new WebGLSessionHandler(this, context);
}
dispose(): void {
this.glContext.dispose();
}
}

View File

@@ -0,0 +1,78 @@
"use strict";
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
Object.defineProperty(exports, "__esModule", { value: true });
exports.ArrayGlslLib = void 0;
const glsl_definitions_1 = require("./glsl-definitions");
/**
* This library produces routines needed for non-constant access to uniform arrays
*/
class ArrayGlslLib extends glsl_definitions_1.GlslLib {
getFunctions() {
return this.generate();
}
getCustomTypes() {
return {};
}
constructor(context) {
super(context);
}
generate() {
const result = {};
for (let i = 1; i <= 16; i++) {
result[`setItem${i}`] = new glsl_definitions_1.GlslLibRoutine(this.generateSetItem(i));
result[`getItem${i}`] = new glsl_definitions_1.GlslLibRoutine(this.generateGetItem(i));
}
return result;
}
generateSetItem(length) {
let block = `
if(index < 0)
index = ${length} + index;
if (index == 0)
a[0] = value;
`;
for (let i = 1; i < length - 1; ++i) {
block += `
else if (index == ${i})
a[${i}] = value;
`;
}
block += `
else
a[${length - 1}] = value;
`;
const body = `
void setItem${length}(out float a[${length}], int index, float value) {
${block}
}
`;
return body;
}
generateGetItem(length) {
let block = `
if(index < 0)
index = ${length} + index;
if (index == 0)
return a[0];
`;
for (let i = 1; i < length - 1; ++i) {
block += `
else if (index == ${i})
return a[${i}];
`;
}
block += `
else
return a[${length - 1}];
`;
const body = `
float getItem${length}(float a[${length}], int index) {
${block}
}
`;
return body;
}
}
exports.ArrayGlslLib = ArrayGlslLib;
//# sourceMappingURL=glsl-array-lib.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"glsl-array-lib.js","sourceRoot":"","sources":["glsl-array-lib.ts"],"names":[],"mappings":";AAAA,4DAA4D;AAC5D,kCAAkC;;;AAElC,yDAAwE;AACxE;;GAEG;AACH,MAAa,YAAa,SAAQ,0BAAO;IACvC,YAAY;QACV,OAAO,IAAI,CAAC,QAAQ,EAAE,CAAC;IACzB,CAAC;IACD,cAAc;QACZ,OAAO,EAAE,CAAC;IACZ,CAAC;IACD,YAAY,OAAoB;QAC9B,KAAK,CAAC,OAAO,CAAC,CAAC;IACjB,CAAC;IACS,QAAQ;QAChB,MAAM,MAAM,GAAqC,EAAE,CAAC;QACpD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,EAAE,EAAE;YAC5B,MAAM,CAAC,UAAU,CAAC,EAAE,CAAC,GAAG,IAAI,iCAAc,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC;YACpE,MAAM,CAAC,UAAU,CAAC,EAAE,CAAC,GAAG,IAAI,iCAAc,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC;SACrE;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;IACS,eAAe,CAAC,MAAc;QACtC,IAAI,KAAK,GAAG;;qBAEK,MAAM;;;QAGnB,CAAC;QACL,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;YACnC,KAAK,IAAI;2BACY,CAAC;eACb,CAAC;YACJ,CAAC;SACR;QACD,KAAK,IAAI;;eAEE,MAAM,GAAG,CAAC;QACjB,CAAC;QACL,MAAM,IAAI,GAAG;mBACE,MAAM,gBAAgB,MAAM;SACtC,KAAK;;QAEN,CAAC;QACL,OAAO,IAAI,CAAC;IACd,CAAC;IACS,eAAe,CAAC,MAAc;QACtC,IAAI,KAAK,GAAG;;qBAEK,MAAM;;;MAGrB,CAAC;QACH,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;YACnC,KAAK,IAAI;2BACY,CAAC;sBACN,CAAC;MACjB,CAAC;SACF;QACD,KAAK,IAAI;;sBAES,MAAM,GAAG,CAAC;QACxB,CAAC;QACL,MAAM,IAAI,GAAG;oBACG,MAAM,YAAY,MAAM;SACnC,KAAK;;IAEV,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;CACF;AAlED,oCAkEC"}

View File

@@ -0,0 +1,74 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
import {GlslContext, GlslLib, GlslLibRoutine} from './glsl-definitions';
/**
* This library produces routines needed for non-constant access to uniform arrays
*/
export class ArrayGlslLib extends GlslLib {
getFunctions(): {[name: string]: GlslLibRoutine} {
return this.generate();
}
getCustomTypes(): {[name: string]: string} {
return {};
}
constructor(context: GlslContext) {
super(context);
}
protected generate(): {[name: string]: GlslLibRoutine} {
const result: {[name: string]: GlslLibRoutine} = {};
for (let i = 1; i <= 16; i++) {
result[`setItem${i}`] = new GlslLibRoutine(this.generateSetItem(i));
result[`getItem${i}`] = new GlslLibRoutine(this.generateGetItem(i));
}
return result;
}
protected generateSetItem(length: number): string {
let block = `
if(index < 0)
index = ${length} + index;
if (index == 0)
a[0] = value;
`;
for (let i = 1; i < length - 1; ++i) {
block += `
else if (index == ${i})
a[${i}] = value;
`;
}
block += `
else
a[${length - 1}] = value;
`;
const body = `
void setItem${length}(out float a[${length}], int index, float value) {
${block}
}
`;
return body;
}
protected generateGetItem(length: number): string {
let block = `
if(index < 0)
index = ${length} + index;
if (index == 0)
return a[0];
`;
for (let i = 1; i < length - 1; ++i) {
block += `
else if (index == ${i})
return a[${i}];
`;
}
block += `
else
return a[${length - 1}];
`;
const body = `
float getItem${length}(float a[${length}], int index) {
${block}
}
`;
return body;
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,104 @@
"use strict";
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
Object.defineProperty(exports, "__esModule", { value: true });
exports.TopologicalSortGlslRoutines = exports.GlslLibRoutineNode = exports.GlslLibRoutine = exports.GlslLib = exports.GlslContext = exports.FunctionType = void 0;
/* eslint-disable @typescript-eslint/naming-convention */
var FunctionType;
(function (FunctionType) {
FunctionType[FunctionType["ValueBased"] = 0] = "ValueBased";
FunctionType[FunctionType["Positional"] = 1] = "Positional";
})(FunctionType = exports.FunctionType || (exports.FunctionType = {}));
class GlslContext {
constructor(glContext, programInfo, inputTextureLayouts, outputTextureLayout) {
this.glContext = glContext;
this.programInfo = programInfo;
this.inputTextureLayouts = inputTextureLayouts;
this.outputTextureLayout = outputTextureLayout;
}
}
exports.GlslContext = GlslContext;
class GlslLib {
constructor(context) {
this.context = context;
}
}
exports.GlslLib = GlslLib;
// abstraction to represent a GLSL library routine and it's dependencies
class GlslLibRoutine {
constructor(routineBody, dependencies) {
this.routineBody = routineBody;
this.dependencies = dependencies;
}
}
exports.GlslLibRoutine = GlslLibRoutine;
// abstraction to represent a GLSL library routine and it's dependencies AS GRAPH Nodes
// this level of abstraction is used to topologically sort routines before fragment shade inclusion
class GlslLibRoutineNode {
constructor(name, routineBody, dependencies) {
this.name = name;
if (dependencies) {
this.dependencies = dependencies;
}
else {
this.dependencies = [];
}
if (routineBody) {
this.routineBody = routineBody;
}
}
addDependency(node) {
if (node) {
this.dependencies.push(node);
}
}
}
exports.GlslLibRoutineNode = GlslLibRoutineNode;
// topologically sort GLSL library routines (graph nodes abstraction) before shader script inclusion
class TopologicalSortGlslRoutines {
static returnOrderedNodes(nodes) {
if (!nodes || nodes.length === 0) {
return [];
}
if (nodes.length === 1) {
return nodes;
}
const cycleCheck = new Set();
const alreadyTraversed = new Set();
const result = new Array();
this.createOrderedNodes(nodes, cycleCheck, alreadyTraversed, result);
return result;
}
static createOrderedNodes(graphNodes, cycleCheck, alreadyTraversed, result) {
for (let i = 0; i < graphNodes.length; ++i) {
this.dfsTraverse(graphNodes[i], cycleCheck, alreadyTraversed, result);
}
}
static dfsTraverse(root, cycleCheck, alreadyTraversed, result) {
// if this root has already been traversed return
if (!root || alreadyTraversed.has(root.name)) {
return;
}
// cyclic dependency has been detected
if (cycleCheck.has(root.name)) {
throw new Error('Cyclic dependency detected. Can\'t topologically sort routines needed for shader.');
}
// hold this node to detect cycles if any
cycleCheck.add(root.name);
// traverse children in a dfs fashion
const dependencies = root.dependencies;
if (dependencies && dependencies.length > 0) {
for (let i = 0; i < dependencies.length; ++i) {
this.dfsTraverse(dependencies[i], cycleCheck, alreadyTraversed, result);
}
}
// add to result holder
result.push(root);
// mark this node as traversed so that we don't traverse from this again
alreadyTraversed.add(root.name);
// release the hold
cycleCheck.delete(root.name);
}
}
exports.TopologicalSortGlslRoutines = TopologicalSortGlslRoutines;
//# sourceMappingURL=glsl-definitions.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"glsl-definitions.js","sourceRoot":"","sources":["glsl-definitions.ts"],"names":[],"mappings":"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"}

View File

@@ -0,0 +1,121 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
import {ProgramInfo, TextureLayout} from './types';
import {WebGLContext} from './webgl-context';
/* eslint-disable @typescript-eslint/naming-convention */
export enum FunctionType {
ValueBased,
Positional
}
export interface GlslFunction<T extends FunctionType> {
body: string;
name: string;
type: T;
}
export type GlslValueFunction = GlslFunction<FunctionType.ValueBased>;
export interface GlslPositionalFunction extends GlslFunction<FunctionType.Positional> {
inputShape: readonly number[];
outputShape: readonly number[];
}
export class GlslContext {
constructor(
public glContext: WebGLContext, public programInfo: ProgramInfo, public inputTextureLayouts: TextureLayout[],
public outputTextureLayout: TextureLayout) {}
}
export abstract class GlslLib {
constructor(public context: GlslContext) {}
abstract getFunctions(): {[name: string]: GlslLibRoutine};
abstract getCustomTypes(): {[name: string]: string};
}
// abstraction to represent a GLSL library routine and it's dependencies
export class GlslLibRoutine {
constructor(public routineBody: string, public dependencies?: string[]) {}
}
// abstraction to represent a GLSL library routine and it's dependencies AS GRAPH Nodes
// this level of abstraction is used to topologically sort routines before fragment shade inclusion
export class GlslLibRoutineNode {
dependencies: GlslLibRoutineNode[];
routineBody: string;
constructor(public name: string, routineBody?: string, dependencies?: GlslLibRoutineNode[]) {
if (dependencies) {
this.dependencies = dependencies;
} else {
this.dependencies = [];
}
if (routineBody) {
this.routineBody = routineBody;
}
}
addDependency(node: GlslLibRoutineNode) {
if (node) {
this.dependencies.push(node);
}
}
}
// topologically sort GLSL library routines (graph nodes abstraction) before shader script inclusion
export class TopologicalSortGlslRoutines {
static returnOrderedNodes(nodes: GlslLibRoutineNode[]): GlslLibRoutineNode[] {
if (!nodes || nodes.length === 0) {
return [];
}
if (nodes.length === 1) {
return nodes;
}
const cycleCheck = new Set<string>();
const alreadyTraversed = new Set<string>();
const result = new Array<GlslLibRoutineNode>();
this.createOrderedNodes(nodes, cycleCheck, alreadyTraversed, result);
return result;
}
private static createOrderedNodes(
graphNodes: GlslLibRoutineNode[], cycleCheck: Set<string>, alreadyTraversed: Set<string>,
result: GlslLibRoutineNode[]) {
for (let i = 0; i < graphNodes.length; ++i) {
this.dfsTraverse(graphNodes[i], cycleCheck, alreadyTraversed, result);
}
}
private static dfsTraverse(
root: GlslLibRoutineNode, cycleCheck: Set<string>, alreadyTraversed: Set<string>, result: GlslLibRoutineNode[]) {
// if this root has already been traversed return
if (!root || alreadyTraversed.has(root.name)) {
return;
}
// cyclic dependency has been detected
if (cycleCheck.has(root.name)) {
throw new Error('Cyclic dependency detected. Can\'t topologically sort routines needed for shader.');
}
// hold this node to detect cycles if any
cycleCheck.add(root.name);
// traverse children in a dfs fashion
const dependencies = root.dependencies;
if (dependencies && dependencies.length > 0) {
for (let i = 0; i < dependencies.length; ++i) {
this.dfsTraverse(dependencies[i], cycleCheck, alreadyTraversed, result);
}
}
// add to result holder
result.push(root);
// mark this node as traversed so that we don't traverse from this again
alreadyTraversed.add(root.name);
// release the hold
cycleCheck.delete(root.name);
}
}

View File

@@ -0,0 +1,102 @@
"use strict";
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
Object.defineProperty(exports, "__esModule", { value: true });
exports.EncodingGlslLib = void 0;
const glsl_definitions_1 = require("./glsl-definitions");
/**
* This GLSL library handles routines converting
* float32 to/from Unsigned byte or float 16
*/
class EncodingGlslLib extends glsl_definitions_1.GlslLib {
constructor(context) {
super(context);
}
getFunctions() {
return Object.assign(Object.assign({}, this.encodeFloat32()), this.decodeFloat32());
}
getCustomTypes() {
return {};
}
encodeFloat32() {
return {
encode: new glsl_definitions_1.GlslLibRoutine(`highp vec4 encode(highp float f) {
return vec4(f, 0.0, 0.0, 0.0);
}
`)
};
}
decodeFloat32() {
return {
decode: new glsl_definitions_1.GlslLibRoutine(`highp float decode(highp vec4 rgba) {
return rgba.r;
}
`)
};
}
/**
* returns the routine to encode encode a 32bit float to a vec4 (of unsigned bytes)
* @credit: https://stackoverflow.com/questions/7059962/how-do-i-convert-a-vec4-rgba-value-to-a-float
*/
encodeUint8() {
const endianness = EncodingGlslLib.isLittleEndian() ? 'rgba.rgba=rgba.abgr;' : '';
return {
encode: new glsl_definitions_1.GlslLibRoutine(`
highp vec4 encode(highp float f) {
highp float F = abs(f);
highp float Sign = step(0.0,-f);
highp float Exponent = floor(log2(F));
highp float Mantissa = (exp2(- Exponent) * F);
Exponent = floor(log2(F) + 127.0) + floor(log2(Mantissa));
highp vec4 rgba;
rgba[0] = 128.0 * Sign + floor(Exponent*exp2(-1.0));
rgba[1] = 128.0 * mod(Exponent,2.0) + mod(floor(Mantissa*128.0),128.0);
rgba[2] = floor(mod(floor(Mantissa*exp2(23.0 -8.0)),exp2(8.0)));
rgba[3] = floor(exp2(23.0)*mod(Mantissa,exp2(-15.0)));
${endianness}
rgba = rgba / 255.0; // values need to be normalized to [0,1]
return rgba;
}
`)
};
}
/**
* returns the routine to encode a vec4 of unsigned bytes to float32
* @credit: https://stackoverflow.com/questions/7059962/how-do-i-convert-a-vec4-rgba-value-to-a-float
*/
decodeUint8() {
const endianness = EncodingGlslLib.isLittleEndian() ? 'rgba.rgba=rgba.abgr;' : '';
return {
decode: new glsl_definitions_1.GlslLibRoutine(`
highp float decode(highp vec4 rgba) {
rgba = rgba * 255.0; // values need to be de-normalized from [0,1] to [0,255]
${endianness}
highp float Sign = 1.0 - step(128.0,rgba[0])*2.0;
highp float Exponent = 2.0 * mod(rgba[0],128.0) + step(128.0,rgba[1]) - 127.0;
highp float Mantissa = mod(rgba[1],128.0)*65536.0 + rgba[2]*256.0 +rgba[3] + float(0x800000);
highp float Result = Sign * exp2(Exponent) * (Mantissa * exp2(-23.0 ));
return Result;
}
`)
};
}
/**
* Determines if the machine is little endian or not
* @credit: https://gist.github.com/TooTallNate/4750953
*/
static isLittleEndian() {
const b = new ArrayBuffer(4);
const a = new Uint32Array(b);
const c = new Uint8Array(b);
a[0] = 0xdeadbeef;
if (c[0] === 0xef) {
return true;
}
if (c[0] === 0xde) {
return false;
}
throw new Error('unknown endianness');
}
}
exports.EncodingGlslLib = EncodingGlslLib;
//# sourceMappingURL=glsl-encoding-lib.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"glsl-encoding-lib.js","sourceRoot":"","sources":["glsl-encoding-lib.ts"],"names":[],"mappings":";AAAA,4DAA4D;AAC5D,kCAAkC;;;AAElC,yDAAwE;AAExE;;;GAGG;AACH,MAAa,eAAgB,SAAQ,0BAAO;IAC1C,YAAY,OAAoB;QAC9B,KAAK,CAAC,OAAO,CAAC,CAAC;IACjB,CAAC;IACD,YAAY;QACV,uCAAW,IAAI,CAAC,aAAa,EAAE,GAAK,IAAI,CAAC,aAAa,EAAE,EAAE;IAC5D,CAAC;IACD,cAAc;QACZ,OAAO,EAAE,CAAC;IACZ,CAAC;IACS,aAAa;QACrB,OAAO;YACL,MAAM,EAAE,IAAI,iCAAc,CAAC;;;SAGxB,CAAC;SACL,CAAC;IACJ,CAAC;IACS,aAAa;QACrB,OAAO;YACL,MAAM,EAAE,IAAI,iCAAc,CAAC;;;SAGxB,CAAC;SACL,CAAC;IACJ,CAAC;IACD;;;OAGG;IACO,WAAW;QACnB,MAAM,UAAU,GAAG,eAAe,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC,EAAE,CAAC;QAClF,OAAO;YACL,MAAM,EAAE,IAAI,iCAAc,CAAC;;;;;;;;;;;;UAYvB,UAAU;;;;SAIX,CAAC;SACL,CAAC;IACJ,CAAC;IACD;;;OAGG;IACO,WAAW;QACnB,MAAM,UAAU,GAAG,eAAe,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC,EAAE,CAAC;QAClF,OAAO;YACL,MAAM,EAAE,IAAI,iCAAc,CAAC;;;YAGrB,UAAU;;;;;;;SAOb,CAAC;SACL,CAAC;IACJ,CAAC;IACD;;;OAGG;IACH,MAAM,CAAC,cAAc;QACnB,MAAM,CAAC,GAAG,IAAI,WAAW,CAAC,CAAC,CAAC,CAAC;QAC7B,MAAM,CAAC,GAAG,IAAI,WAAW,CAAC,CAAC,CAAC,CAAC;QAC7B,MAAM,CAAC,GAAG,IAAI,UAAU,CAAC,CAAC,CAAC,CAAC;QAC5B,CAAC,CAAC,CAAC,CAAC,GAAG,UAAU,CAAC;QAClB,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE;YACjB,OAAO,IAAI,CAAC;SACb;QACD,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE;YACjB,OAAO,KAAK,CAAC;SACd;QACD,MAAM,IAAI,KAAK,CAAC,oBAAoB,CAAC,CAAC;IACxC,CAAC;CACF;AAzFD,0CAyFC"}

View File

@@ -0,0 +1,99 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
import {GlslContext, GlslLib, GlslLibRoutine} from './glsl-definitions';
/**
* This GLSL library handles routines converting
* float32 to/from Unsigned byte or float 16
*/
export class EncodingGlslLib extends GlslLib {
constructor(context: GlslContext) {
super(context);
}
getFunctions(): {[name: string]: GlslLibRoutine} {
return {...this.encodeFloat32(), ...this.decodeFloat32()};
}
getCustomTypes(): {[name: string]: string} {
return {};
}
protected encodeFloat32(): {[name: string]: GlslLibRoutine} {
return {
encode: new GlslLibRoutine(`highp vec4 encode(highp float f) {
return vec4(f, 0.0, 0.0, 0.0);
}
`)
};
}
protected decodeFloat32(): {[name: string]: GlslLibRoutine} {
return {
decode: new GlslLibRoutine(`highp float decode(highp vec4 rgba) {
return rgba.r;
}
`)
};
}
/**
* returns the routine to encode encode a 32bit float to a vec4 (of unsigned bytes)
* @credit: https://stackoverflow.com/questions/7059962/how-do-i-convert-a-vec4-rgba-value-to-a-float
*/
protected encodeUint8(): {[name: string]: GlslLibRoutine} {
const endianness = EncodingGlslLib.isLittleEndian() ? 'rgba.rgba=rgba.abgr;' : '';
return {
encode: new GlslLibRoutine(`
highp vec4 encode(highp float f) {
highp float F = abs(f);
highp float Sign = step(0.0,-f);
highp float Exponent = floor(log2(F));
highp float Mantissa = (exp2(- Exponent) * F);
Exponent = floor(log2(F) + 127.0) + floor(log2(Mantissa));
highp vec4 rgba;
rgba[0] = 128.0 * Sign + floor(Exponent*exp2(-1.0));
rgba[1] = 128.0 * mod(Exponent,2.0) + mod(floor(Mantissa*128.0),128.0);
rgba[2] = floor(mod(floor(Mantissa*exp2(23.0 -8.0)),exp2(8.0)));
rgba[3] = floor(exp2(23.0)*mod(Mantissa,exp2(-15.0)));
${endianness}
rgba = rgba / 255.0; // values need to be normalized to [0,1]
return rgba;
}
`)
};
}
/**
* returns the routine to encode a vec4 of unsigned bytes to float32
* @credit: https://stackoverflow.com/questions/7059962/how-do-i-convert-a-vec4-rgba-value-to-a-float
*/
protected decodeUint8(): {[name: string]: GlslLibRoutine} {
const endianness = EncodingGlslLib.isLittleEndian() ? 'rgba.rgba=rgba.abgr;' : '';
return {
decode: new GlslLibRoutine(`
highp float decode(highp vec4 rgba) {
rgba = rgba * 255.0; // values need to be de-normalized from [0,1] to [0,255]
${endianness}
highp float Sign = 1.0 - step(128.0,rgba[0])*2.0;
highp float Exponent = 2.0 * mod(rgba[0],128.0) + step(128.0,rgba[1]) - 127.0;
highp float Mantissa = mod(rgba[1],128.0)*65536.0 + rgba[2]*256.0 +rgba[3] + float(0x800000);
highp float Result = Sign * exp2(Exponent) * (Mantissa * exp2(-23.0 ));
return Result;
}
`)
};
}
/**
* Determines if the machine is little endian or not
* @credit: https://gist.github.com/TooTallNate/4750953
*/
static isLittleEndian(): boolean {
const b = new ArrayBuffer(4);
const a = new Uint32Array(b);
const c = new Uint8Array(b);
a[0] = 0xdeadbeef;
if (c[0] === 0xef) {
return true;
}
if (c[0] === 0xde) {
return false;
}
throw new Error('unknown endianness');
}
}

View File

@@ -0,0 +1,44 @@
"use strict";
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
Object.defineProperty(exports, "__esModule", { value: true });
exports.FragColorGlslLib = void 0;
const glsl_definitions_1 = require("./glsl-definitions");
const glsl_source_1 = require("./glsl-source");
/**
* This GLSL library handles routines around reading a texlet and writing to it
* Reading and writing could be more than just dealing with one channel
* It may require encoding/decoding to/from 4 channels into one
*/
class FragColorGlslLib extends glsl_definitions_1.GlslLib {
constructor(context) {
super(context);
}
getFunctions() {
return Object.assign(Object.assign({}, this.setFragColor()), this.getColorAsFloat());
}
getCustomTypes() {
return {};
}
setFragColor() {
const glsl = (0, glsl_source_1.getGlsl)(this.context.glContext.version);
return {
setFragColor: new glsl_definitions_1.GlslLibRoutine(`
void setFragColor(float value) {
${glsl.output} = encode(value);
}
`, ['encoding.encode'])
};
}
getColorAsFloat() {
return {
getColorAsFloat: new glsl_definitions_1.GlslLibRoutine(`
float getColorAsFloat(vec4 color) {
return decode(color);
}
`, ['encoding.decode'])
};
}
}
exports.FragColorGlslLib = FragColorGlslLib;
//# sourceMappingURL=glsl-fragcolor-lib.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"glsl-fragcolor-lib.js","sourceRoot":"","sources":["glsl-fragcolor-lib.ts"],"names":[],"mappings":";AAAA,4DAA4D;AAC5D,kCAAkC;;;AAElC,yDAAwE;AACxE,+CAAsC;AAEtC;;;;GAIG;AACH,MAAa,gBAAiB,SAAQ,0BAAO;IAC3C,YAAY,OAAoB;QAC9B,KAAK,CAAC,OAAO,CAAC,CAAC;IACjB,CAAC;IACD,YAAY;QACV,uCAAW,IAAI,CAAC,YAAY,EAAE,GAAK,IAAI,CAAC,eAAe,EAAE,EAAE;IAC7D,CAAC;IACD,cAAc;QACZ,OAAO,EAAE,CAAC;IACZ,CAAC;IACS,YAAY;QACpB,MAAM,IAAI,GAAG,IAAA,qBAAO,EAAC,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;QACrD,OAAO;YACL,YAAY,EAAE,IAAI,iCAAc,CAC5B;;cAEI,IAAI,CAAC,MAAM;;SAEhB,EACC,CAAC,iBAAiB,CAAC,CAAC;SACzB,CAAC;IACJ,CAAC;IACS,eAAe;QACvB,OAAO;YACL,eAAe,EAAE,IAAI,iCAAc,CAC/B;;;;SAID,EACC,CAAC,iBAAiB,CAAC,CAAC;SACzB,CAAC;IACJ,CAAC;CACF;AAjCD,4CAiCC"}

View File

@@ -0,0 +1,45 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
import {GlslContext, GlslLib, GlslLibRoutine} from './glsl-definitions';
import {getGlsl} from './glsl-source';
/**
* This GLSL library handles routines around reading a texlet and writing to it
* Reading and writing could be more than just dealing with one channel
* It may require encoding/decoding to/from 4 channels into one
*/
export class FragColorGlslLib extends GlslLib {
constructor(context: GlslContext) {
super(context);
}
getFunctions(): {[name: string]: GlslLibRoutine} {
return {...this.setFragColor(), ...this.getColorAsFloat()};
}
getCustomTypes(): {[name: string]: string} {
return {};
}
protected setFragColor(): {[name: string]: GlslLibRoutine} {
const glsl = getGlsl(this.context.glContext.version);
return {
setFragColor: new GlslLibRoutine(
`
void setFragColor(float value) {
${glsl.output} = encode(value);
}
`,
['encoding.encode'])
};
}
protected getColorAsFloat(): {[name: string]: GlslLibRoutine} {
return {
getColorAsFloat: new GlslLibRoutine(
`
float getColorAsFloat(vec4 color) {
return decode(color);
}
`,
['encoding.decode'])
};
}
}

View File

@@ -0,0 +1,57 @@
"use strict";
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
Object.defineProperty(exports, "__esModule", { value: true });
exports.replaceInlines = void 0;
const INLINE_FUNC_DEF_REGEX = /@inline[\s\n\r]+(\w+)[\s\n\r]+([0-9a-zA-Z_]+)\s*\(([^)]*)\)\s*{(([^}]|[\n\r])*)}/gm;
const FUNC_CALL_REGEX = '(\\w+)?\\s+([_0-9a-zA-Z]+)\\s+=\\s+__FUNC__\\((.*)\\)\\s*;';
/**
* GLSL preprocessor responsible for resolving @inline directives
*/
function replaceInlines(script) {
const inlineDefs = {};
let match;
while ((match = INLINE_FUNC_DEF_REGEX.exec(script)) !== null) {
const params = match[3]
.split(',')
.map(s => {
const tokens = s.trim().split(' ');
if (tokens && tokens.length === 2) {
return { type: tokens[0], name: tokens[1] };
}
return null;
})
.filter(v => v !== null);
inlineDefs[match[2]] = { params, body: match[4] };
}
for (const name in inlineDefs) {
const regexString = FUNC_CALL_REGEX.replace('__FUNC__', name);
const regex = new RegExp(regexString, 'gm');
while ((match = regex.exec(script)) !== null) {
const type = match[1];
const variable = match[2];
const params = match[3].split(',');
const declLine = (type) ? `${type} ${variable};` : '';
let newBody = inlineDefs[name].body;
let paramRedecLine = '';
inlineDefs[name].params.forEach((v, i) => {
if (v) {
paramRedecLine += `${v.type} ${v.name} = ${params[i]};\n`;
}
});
newBody = `${paramRedecLine}\n ${newBody}`;
newBody = newBody.replace('return', `${variable} = `);
const replacement = `
${declLine}
{
${newBody}
}
`;
script = script.replace(match[0], replacement);
}
}
script = script.replace(INLINE_FUNC_DEF_REGEX, '');
return script;
}
exports.replaceInlines = replaceInlines;
//# sourceMappingURL=glsl-function-inliner.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"glsl-function-inliner.js","sourceRoot":"","sources":["glsl-function-inliner.ts"],"names":[],"mappings":";AAAA,4DAA4D;AAC5D,kCAAkC;;;AAElC,MAAM,qBAAqB,GAAG,oFAAoF,CAAC;AACnH,MAAM,eAAe,GAAG,4DAA4D,CAAC;AACrF;;GAEG;AACH,SAAgB,cAAc,CAAC,MAAc;IAC3C,MAAM,UAAU,GAAuF,EAAE,CAAC;IAC1G,IAAI,KAAK,CAAC;IACV,OAAO,CAAC,KAAK,GAAG,qBAAqB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,KAAK,IAAI,EAAE;QAC5D,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC;aACH,KAAK,CAAC,GAAG,CAAC;aACV,GAAG,CAAC,CAAC,CAAC,EAAE;YACP,MAAM,MAAM,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YACnC,IAAI,MAAM,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE;gBACjC,OAAO,EAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,EAAC,CAAC;aAC3C;YACD,OAAO,IAAI,CAAC;QACd,CAAC,CAAC;aACD,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC;QAC5C,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,EAAC,MAAM,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,EAAC,CAAC;KACjD;IACD,KAAK,MAAM,IAAI,IAAI,UAAU,EAAE;QAC7B,MAAM,WAAW,GAAG,eAAe,CAAC,OAAO,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;QAC9D,MAAM,KAAK,GAAG,IAAI,MAAM,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC;QAC5C,OAAO,CAAC,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,KAAK,IAAI,EAAE;YAC5C,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;YACtB,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;YAC1B,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YACnC,MAAM,QAAQ,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,IAAI,QAAQ,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;YACtD,IAAI,OAAO,GAAW,UAAU,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC;YAC5C,IAAI,cAAc,GAAG,EAAE,CAAC;YACxB,UAAU,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;gBACvC,IAAI,CAAC,EAAE;oBACL,cAAc,IAAI,GAAG,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,IAAI,MAAM,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC;iBAC3D;YACH,CAAC,CAAC,CAAC;YACH,OAAO,GAAG,GAAG,cAAc,MAAM,OAAO,EAAE,CAAC;YAC3C,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,QAAQ,EAAE,GAAG,QAAQ,KAAK,CAAC,CAAC;YACtD,MAAM,WAAW,GAAG;QAClB,QAAQ;;UAEN,OAAO;;OAEV,CAAC;YACF,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,WAAW,CAAC,CAAC;SAChD;KACF;IACD,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,qBAAqB,EAAE,EAAE,CAAC,CAAC;IACnD,OAAO,MAAM,CAAC;AAChB,CAAC;AA5CD,wCA4CC"}

View File

@@ -0,0 +1,53 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
const INLINE_FUNC_DEF_REGEX = /@inline[\s\n\r]+(\w+)[\s\n\r]+([0-9a-zA-Z_]+)\s*\(([^)]*)\)\s*{(([^}]|[\n\r])*)}/gm;
const FUNC_CALL_REGEX = '(\\w+)?\\s+([_0-9a-zA-Z]+)\\s+=\\s+__FUNC__\\((.*)\\)\\s*;';
/**
* GLSL preprocessor responsible for resolving @inline directives
*/
export function replaceInlines(script: string): string {
const inlineDefs: {[name: string]: {params: Array<{type: string; name: string}|null>; body: string}} = {};
let match;
while ((match = INLINE_FUNC_DEF_REGEX.exec(script)) !== null) {
const params = match[3]
.split(',')
.map(s => {
const tokens = s.trim().split(' ');
if (tokens && tokens.length === 2) {
return {type: tokens[0], name: tokens[1]};
}
return null;
})
.filter(v => v !== null);
inlineDefs[match[2]] = {params, body: match[4]};
}
for (const name in inlineDefs) {
const regexString = FUNC_CALL_REGEX.replace('__FUNC__', name);
const regex = new RegExp(regexString, 'gm');
while ((match = regex.exec(script)) !== null) {
const type = match[1];
const variable = match[2];
const params = match[3].split(',');
const declLine = (type) ? `${type} ${variable};` : '';
let newBody: string = inlineDefs[name].body;
let paramRedecLine = '';
inlineDefs[name].params.forEach((v, i) => {
if (v) {
paramRedecLine += `${v.type} ${v.name} = ${params[i]};\n`;
}
});
newBody = `${paramRedecLine}\n ${newBody}`;
newBody = newBody.replace('return', `${variable} = `);
const replacement = `
${declLine}
{
${newBody}
}
`;
script = script.replace(match[0], replacement);
}
}
script = script.replace(INLINE_FUNC_DEF_REGEX, '');
return script;
}

View File

@@ -0,0 +1,118 @@
"use strict";
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
Object.defineProperty(exports, "__esModule", { value: true });
exports.GlslPreprocessor = void 0;
const glsl_definitions_1 = require("./glsl-definitions");
const glsl_function_inliner_1 = require("./glsl-function-inliner");
const glsl_registered_libs_1 = require("./glsl-registered-libs");
const glsl_source_1 = require("./glsl-source");
/**
* Preprocessor for the additions to the GLSL language
* It deals with:
* @include directives
* @inline
* Loop unrolling (not implemented)
* Macro resolution (not implemented)
*/
class GlslPreprocessor {
constructor(glContext, programInfo, inputTextureLayouts, outputTextureLayout) {
this.libs = {};
this.glslLibRoutineDependencyGraph = {};
this.context = new glsl_definitions_1.GlslContext(glContext, programInfo, inputTextureLayouts, outputTextureLayout);
// construct GlslLibs
Object.keys(glsl_registered_libs_1.glslRegistry).forEach((name) => {
const lib = new glsl_registered_libs_1.glslRegistry[name](this.context);
this.libs[name] = lib;
});
// construct GlslRoutineDependencyGraph
const map = this.glslLibRoutineDependencyGraph;
for (const libName in this.libs) {
const lib = this.libs[libName];
const routinesInLib = lib.getFunctions();
for (const routine in routinesInLib) {
const key = libName + '.' + routine;
let currentNode;
if (map[key]) {
currentNode = map[key];
currentNode.routineBody = routinesInLib[routine].routineBody;
}
else {
currentNode = new glsl_definitions_1.GlslLibRoutineNode(key, routinesInLib[routine].routineBody);
map[key] = currentNode;
}
const dependencies = routinesInLib[routine].dependencies;
if (dependencies) {
for (let i = 0; i < dependencies.length; ++i) {
if (!map[dependencies[i]]) {
const node = new glsl_definitions_1.GlslLibRoutineNode(dependencies[i]);
map[dependencies[i]] = node;
currentNode.addDependency(node);
}
else {
currentNode.addDependency(map[dependencies[i]]);
}
}
}
}
}
}
preprocess() {
const programInfo = this.context.programInfo;
let source = programInfo.shaderSource;
// append main() function
if (!this.context.programInfo.hasMain) {
source = `${source}
${(0, glsl_source_1.getDefaultFragShaderMain)(this.context.glContext.version, this.context.outputTextureLayout.shape.length)}`;
}
// replace inlines
source = (0, glsl_function_inliner_1.replaceInlines)(source);
// concat final source string
return `${(0, glsl_source_1.getFragShaderPreamble)(this.context.glContext.version)}
${this.getUniforms(programInfo.inputNames, programInfo.variables)}
${this.getImports(source)}
${source}`;
}
getImports(script) {
const routinesIncluded = this.selectGlslLibRoutinesToBeIncluded(script);
if (routinesIncluded.length === 0) {
return '';
}
let routines = '';
for (let i = 0; i < routinesIncluded.length; ++i) {
if (routinesIncluded[i].routineBody) {
routines += routinesIncluded[i].routineBody + '\n';
}
else {
throw new Error(`Missing body for the Glsl Library routine: ${routinesIncluded[i].name}`);
}
}
return routines;
}
selectGlslLibRoutinesToBeIncluded(script) {
const nodes = [];
Object.keys(this.glslLibRoutineDependencyGraph).forEach(classAndRoutine => {
const routine = classAndRoutine.split('.')[1];
if (script.indexOf(routine) !== -1) {
nodes.push(this.glslLibRoutineDependencyGraph[classAndRoutine]);
}
});
return glsl_definitions_1.TopologicalSortGlslRoutines.returnOrderedNodes(nodes);
}
getUniforms(samplers, variables) {
const uniformLines = [];
if (samplers) {
for (const sampler of samplers) {
uniformLines.push(`uniform sampler2D ${sampler};`);
}
}
if (variables) {
for (const variable of variables) {
uniformLines.push(`uniform ${variable.type} ${variable.name}${variable.arrayLength ? `[${variable.arrayLength}]` : ''};`);
}
}
return uniformLines.join('\n');
}
}
exports.GlslPreprocessor = GlslPreprocessor;
//# sourceMappingURL=glsl-preprocessor.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"glsl-preprocessor.js","sourceRoot":"","sources":["glsl-preprocessor.ts"],"names":[],"mappings":"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"}

View File

@@ -0,0 +1,131 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
import {GlslContext, GlslLib, GlslLibRoutineNode, TopologicalSortGlslRoutines} from './glsl-definitions';
import {replaceInlines} from './glsl-function-inliner';
import {glslRegistry} from './glsl-registered-libs';
import {getDefaultFragShaderMain, getFragShaderPreamble} from './glsl-source';
import {ProgramInfo, TextureLayout, VariableInfo} from './types';
import {WebGLContext} from './webgl-context';
/**
* Preprocessor for the additions to the GLSL language
* It deals with:
* @include directives
* @inline
* Loop unrolling (not implemented)
* Macro resolution (not implemented)
*/
export class GlslPreprocessor {
readonly context: GlslContext;
readonly libs: {[name: string]: GlslLib} = {};
readonly glslLibRoutineDependencyGraph: {[routineName: string]: GlslLibRoutineNode} = {};
constructor(
glContext: WebGLContext, programInfo: ProgramInfo, inputTextureLayouts: TextureLayout[],
outputTextureLayout: TextureLayout) {
this.context = new GlslContext(glContext, programInfo, inputTextureLayouts, outputTextureLayout);
// construct GlslLibs
Object.keys(glslRegistry).forEach((name: string) => {
const lib = new glslRegistry[name](this.context);
this.libs[name] = lib;
});
// construct GlslRoutineDependencyGraph
const map = this.glslLibRoutineDependencyGraph;
for (const libName in this.libs) {
const lib = this.libs[libName];
const routinesInLib = lib.getFunctions();
for (const routine in routinesInLib) {
const key = libName + '.' + routine;
let currentNode: GlslLibRoutineNode;
if (map[key]) {
currentNode = map[key];
currentNode.routineBody = routinesInLib[routine].routineBody;
} else {
currentNode = new GlslLibRoutineNode(key, routinesInLib[routine].routineBody);
map[key] = currentNode;
}
const dependencies = routinesInLib[routine].dependencies;
if (dependencies) {
for (let i = 0; i < dependencies.length; ++i) {
if (!map[dependencies[i]]) {
const node = new GlslLibRoutineNode(dependencies[i]);
map[dependencies[i]] = node;
currentNode.addDependency(node);
} else {
currentNode.addDependency(map[dependencies[i]]);
}
}
}
}
}
}
preprocess(): string {
const programInfo = this.context.programInfo;
let source = programInfo.shaderSource;
// append main() function
if (!this.context.programInfo.hasMain) {
source = `${source}
${getDefaultFragShaderMain(this.context.glContext.version, this.context.outputTextureLayout.shape.length)}`;
}
// replace inlines
source = replaceInlines(source);
// concat final source string
return `${getFragShaderPreamble(this.context.glContext.version)}
${this.getUniforms(programInfo.inputNames, programInfo.variables)}
${this.getImports(source)}
${source}`;
}
protected getImports(script: string): string {
const routinesIncluded = this.selectGlslLibRoutinesToBeIncluded(script);
if (routinesIncluded.length === 0) {
return '';
}
let routines = '';
for (let i = 0; i < routinesIncluded.length; ++i) {
if (routinesIncluded[i].routineBody) {
routines += routinesIncluded[i].routineBody + '\n';
} else {
throw new Error(`Missing body for the Glsl Library routine: ${routinesIncluded[i].name}`);
}
}
return routines;
}
private selectGlslLibRoutinesToBeIncluded(script: string): GlslLibRoutineNode[] {
const nodes: GlslLibRoutineNode[] = [];
Object.keys(this.glslLibRoutineDependencyGraph).forEach(classAndRoutine => {
const routine = classAndRoutine.split('.')[1];
if (script.indexOf(routine) !== -1) {
nodes.push(this.glslLibRoutineDependencyGraph[classAndRoutine]);
}
});
return TopologicalSortGlslRoutines.returnOrderedNodes(nodes);
}
protected getUniforms(samplers?: string[], variables?: VariableInfo[]): string {
const uniformLines: string[] = [];
if (samplers) {
for (const sampler of samplers) {
uniformLines.push(`uniform sampler2D ${sampler};`);
}
}
if (variables) {
for (const variable of variables) {
uniformLines.push(
`uniform ${variable.type} ${variable.name}${variable.arrayLength ? `[${variable.arrayLength}]` : ''};`);
}
}
return uniformLines.join('\n');
}
}

View File

@@ -0,0 +1,19 @@
"use strict";
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
Object.defineProperty(exports, "__esModule", { value: true });
exports.glslRegistry = void 0;
const glsl_coordinate_lib_1 = require("./glsl-coordinate-lib");
const glsl_encoding_lib_1 = require("./glsl-encoding-lib");
const glsl_fragcolor_lib_1 = require("./glsl-fragcolor-lib");
const glsl_shape_utils_lib_1 = require("./glsl-shape-utils-lib");
const glsl_vec_lib_1 = require("./glsl-vec-lib");
exports.glslRegistry = {
'encoding': glsl_encoding_lib_1.EncodingGlslLib,
'fragcolor': glsl_fragcolor_lib_1.FragColorGlslLib,
'vec': glsl_vec_lib_1.VecGlslLib,
'shapeUtils': glsl_shape_utils_lib_1.ShapeUtilsGlslLib,
'coordinates': glsl_coordinate_lib_1.CoordsGlslLib,
// 'arrays': ArrayGlslSLib
};
//# sourceMappingURL=glsl-registered-libs.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"glsl-registered-libs.js","sourceRoot":"","sources":["glsl-registered-libs.ts"],"names":[],"mappings":";AAAA,4DAA4D;AAC5D,kCAAkC;;;AAElC,+DAAoD;AAEpD,2DAAoD;AACpD,6DAAsD;AACtD,iEAAyD;AACzD,iDAA0C;AAE7B,QAAA,YAAY,GAA4D;IACnF,UAAU,EAAE,mCAAe;IAC3B,WAAW,EAAE,qCAAgB;IAC7B,KAAK,EAAE,yBAAU;IACjB,YAAY,EAAE,wCAAiB;IAC/B,aAAa,EAAE,mCAAa;IAC5B,2BAA2B;CAC5B,CAAC"}

View File

@@ -0,0 +1,18 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
import {CoordsGlslLib} from './glsl-coordinate-lib';
import {GlslContext, GlslLib} from './glsl-definitions';
import {EncodingGlslLib} from './glsl-encoding-lib';
import {FragColorGlslLib} from './glsl-fragcolor-lib';
import {ShapeUtilsGlslLib} from './glsl-shape-utils-lib';
import {VecGlslLib} from './glsl-vec-lib';
export const glslRegistry: {[name: string]: new (context: GlslContext) => GlslLib} = {
'encoding': EncodingGlslLib,
'fragcolor': FragColorGlslLib,
'vec': VecGlslLib,
'shapeUtils': ShapeUtilsGlslLib,
'coordinates': CoordsGlslLib,
// 'arrays': ArrayGlslSLib
};

View File

@@ -0,0 +1,163 @@
"use strict";
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
Object.defineProperty(exports, "__esModule", { value: true });
exports.ShapeUtilsGlslLib = void 0;
const glsl_definitions_1 = require("./glsl-definitions");
/**
* GLSL Library responsible for data types and routines for manipulating
* coordinates and mapping to/from tensor indices
*/
class ShapeUtilsGlslLib extends glsl_definitions_1.GlslLib {
constructor(context) {
super(context);
}
getFunctions() {
return Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, this.bcastIndex()), this.bcastMatmulIndex()), this.offsetToIndices()), this.indicesToOffset()), this.incrementIndices());
}
getCustomTypes() {
return {};
}
bcastIndex() {
const outputRank = this.context.outputTextureLayout.shape.length;
const result = {};
this.context.programInfo.inputNames.forEach((name, i) => {
const shape = this.context.inputTextureLayouts[i].unpackedShape;
if (shape.length <= outputRank) {
const rank = shape.length;
const dimOffset = outputRank - rank;
const funcName = `bcastIndices_${name}`;
let block = '';
for (let i = 0; i < rank; ++i) {
block += `
realIndices[${i}] = int( mod(float(bcastedIndices[${dimOffset + i}]), ${shape[i]}.0) );
`;
}
const body = `
void ${funcName} (int bcastedIndices[${outputRank}], out int realIndices[${rank}]) {
${block}
}
`;
result[funcName] = new glsl_definitions_1.GlslLibRoutine(body);
}
});
return result;
}
bcastMatmulIndex() {
const outputRank = this.context.outputTextureLayout.shape.length;
const result = {};
this.context.programInfo.inputNames.forEach((name, i) => {
const shape = this.context.inputTextureLayouts[i].shape;
if (!(shape.length < 2 || shape.length > outputRank)) {
const rank = shape.length;
const dimOffset = outputRank - rank;
const funcName = `bcastMatmulIndices_${name}`;
let block = '';
for (let i = 0; i < rank - 2; ++i) {
block += `
realIndices[${i}] = int( mod(float(bcastedIndices[${dimOffset + i}]), ${shape[i]}.0) );
`;
}
const body = `
void ${funcName}(int bcastedIndices[${outputRank}], out int realIndices[${rank}]) {
${block}
realIndices[${rank - 1}] = bcastedIndices[${outputRank - 1}];
realIndices[${rank - 2}] = bcastedIndices[${outputRank - 2}];
}
`;
result[funcName] = new glsl_definitions_1.GlslLibRoutine(body);
}
});
return result;
}
indicesToOffset() {
const result = {};
this.context.programInfo.inputNames.forEach((name, i) => {
const shape = this.context.inputTextureLayouts[i].shape;
const strides = this.context.inputTextureLayouts[i].strides;
const rank = shape.length;
let funcName = `indicesToOffset_${name}`;
result[funcName] = new glsl_definitions_1.GlslLibRoutine(ShapeUtilsGlslLib.indexToOffsetSingle(funcName, rank, strides));
funcName = `indicesToOffset_${name}_T`;
result[funcName] =
new glsl_definitions_1.GlslLibRoutine(ShapeUtilsGlslLib.indexToOffsetSingle(funcName, rank, strides.slice().reverse()));
});
return result;
}
static indexToOffsetSingle(name, rank, strides) {
let block = '';
for (let i = rank - 1; i >= 0; --i) {
block += `
offset += indices[${i}] * ${strides[i]};
`;
}
return `
int ${name}(int indices[${rank}]) {
int offset = 0;
${block}
return offset;
}
`;
}
offsetToIndices() {
const result = {};
this.context.programInfo.inputNames.forEach((name, i) => {
const shape = this.context.inputTextureLayouts[i].shape;
const strides = this.context.inputTextureLayouts[i].strides;
const rank = shape.length;
let funcName = `offsetToIndices_${name}`;
result[funcName] = new glsl_definitions_1.GlslLibRoutine(ShapeUtilsGlslLib.offsetToIndicesSingle(funcName, rank, strides));
funcName = `offsetToIndices_${name}_T`;
result[funcName] =
new glsl_definitions_1.GlslLibRoutine(ShapeUtilsGlslLib.offsetToIndicesSingle(funcName, rank, strides.slice().reverse()));
});
return result;
}
static offsetToIndicesSingle(name, rank, strides) {
const stridesBlock = [];
for (let i = 0; i < rank - 1; ++i) {
stridesBlock.push(`
indices[${i}] = offset / ${strides[i]};`);
stridesBlock.push(`
offset -= indices[${i}] * ${strides[i]};`);
}
stridesBlock.push(`
indices[${rank - 1}] = offset;`);
return `
void ${name}(int offset, out int indices[${rank}]) {
${stridesBlock.join('')}
}
`;
}
incrementIndices() {
const result = {};
this.context.programInfo.inputNames.forEach((name, i) => {
const shape = this.context.inputTextureLayouts[i].shape;
const rank = shape.length;
const funcName = `incrementIndices_${name}`;
let shapeInit = '';
for (let i = 0; i < rank; ++i) {
shapeInit += `
shape[${i}] = ${shape[i]};`;
}
const body = `
void ${funcName}(int axis, out int indices[${rank}]) {
int shape[${rank}];
${shapeInit};
for(int i = ${rank} -1 ; i >= 0; --i) {
if(i > axis) continue;
indices[i] += 1;
if(indices[i] < shape[i]) {
break;
}
indices[i] = 0;
}
}
`;
result[funcName] = new glsl_definitions_1.GlslLibRoutine(body);
});
return result;
}
}
exports.ShapeUtilsGlslLib = ShapeUtilsGlslLib;
//# sourceMappingURL=glsl-shape-utils-lib.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,166 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
import {GlslContext, GlslLib, GlslLibRoutine} from './glsl-definitions';
/**
* GLSL Library responsible for data types and routines for manipulating
* coordinates and mapping to/from tensor indices
*/
export class ShapeUtilsGlslLib extends GlslLib {
constructor(context: GlslContext) {
super(context);
}
getFunctions(): {[name: string]: GlslLibRoutine} {
return {
...this.bcastIndex(),
...this.bcastMatmulIndex(),
...this.offsetToIndices(),
...this.indicesToOffset(),
...this.incrementIndices()
};
}
getCustomTypes() {
return {};
}
protected bcastIndex(): {[name: string]: GlslLibRoutine} {
const outputRank = this.context.outputTextureLayout.shape.length;
const result: {[name: string]: GlslLibRoutine} = {};
this.context.programInfo.inputNames.forEach((name, i) => {
const shape = this.context.inputTextureLayouts[i].unpackedShape;
if (shape.length <= outputRank) {
const rank = shape.length;
const dimOffset = outputRank - rank;
const funcName = `bcastIndices_${name}`;
let block = '';
for (let i = 0; i < rank; ++i) {
block += `
realIndices[${i}] = int( mod(float(bcastedIndices[${dimOffset + i}]), ${shape[i]}.0) );
`;
}
const body = `
void ${funcName} (int bcastedIndices[${outputRank}], out int realIndices[${rank}]) {
${block}
}
`;
result[funcName] = new GlslLibRoutine(body);
}
});
return result;
}
protected bcastMatmulIndex(): {[name: string]: GlslLibRoutine} {
const outputRank = this.context.outputTextureLayout.shape.length;
const result: {[name: string]: GlslLibRoutine} = {};
this.context.programInfo.inputNames.forEach((name, i) => {
const shape = this.context.inputTextureLayouts[i].shape;
if (!(shape.length < 2 || shape.length > outputRank)) {
const rank = shape.length;
const dimOffset = outputRank - rank;
const funcName = `bcastMatmulIndices_${name}`;
let block = '';
for (let i = 0; i < rank - 2; ++i) {
block += `
realIndices[${i}] = int( mod(float(bcastedIndices[${dimOffset + i}]), ${shape[i]}.0) );
`;
}
const body = `
void ${funcName}(int bcastedIndices[${outputRank}], out int realIndices[${rank}]) {
${block}
realIndices[${rank - 1}] = bcastedIndices[${outputRank - 1}];
realIndices[${rank - 2}] = bcastedIndices[${outputRank - 2}];
}
`;
result[funcName] = new GlslLibRoutine(body);
}
});
return result;
}
protected indicesToOffset(): {[name: string]: GlslLibRoutine} {
const result: {[name: string]: GlslLibRoutine} = {};
this.context.programInfo.inputNames.forEach((name, i) => {
const shape = this.context.inputTextureLayouts[i].shape;
const strides = this.context.inputTextureLayouts[i].strides;
const rank = shape.length;
let funcName = `indicesToOffset_${name}`;
result[funcName] = new GlslLibRoutine(ShapeUtilsGlslLib.indexToOffsetSingle(funcName, rank, strides));
funcName = `indicesToOffset_${name}_T`;
result[funcName] =
new GlslLibRoutine(ShapeUtilsGlslLib.indexToOffsetSingle(funcName, rank, strides.slice().reverse()));
});
return result;
}
static indexToOffsetSingle(name: string, rank: number, strides: readonly number[]): string {
let block = '';
for (let i = rank - 1; i >= 0; --i) {
block += `
offset += indices[${i}] * ${strides[i]};
`;
}
return `
int ${name}(int indices[${rank}]) {
int offset = 0;
${block}
return offset;
}
`;
}
protected offsetToIndices(): {[name: string]: GlslLibRoutine} {
const result: {[name: string]: GlslLibRoutine} = {};
this.context.programInfo.inputNames.forEach((name, i) => {
const shape = this.context.inputTextureLayouts[i].shape;
const strides = this.context.inputTextureLayouts[i].strides;
const rank = shape.length;
let funcName = `offsetToIndices_${name}`;
result[funcName] = new GlslLibRoutine(ShapeUtilsGlslLib.offsetToIndicesSingle(funcName, rank, strides));
funcName = `offsetToIndices_${name}_T`;
result[funcName] =
new GlslLibRoutine(ShapeUtilsGlslLib.offsetToIndicesSingle(funcName, rank, strides.slice().reverse()));
});
return result;
}
static offsetToIndicesSingle(name: string, rank: number, strides: readonly number[]): string {
const stridesBlock = [];
for (let i = 0; i < rank - 1; ++i) {
stridesBlock.push(`
indices[${i}] = offset / ${strides[i]};`);
stridesBlock.push(`
offset -= indices[${i}] * ${strides[i]};`);
}
stridesBlock.push(`
indices[${rank - 1}] = offset;`);
return `
void ${name}(int offset, out int indices[${rank}]) {
${stridesBlock.join('')}
}
`;
}
protected incrementIndices(): {[name: string]: GlslLibRoutine} {
const result: {[name: string]: GlslLibRoutine} = {};
this.context.programInfo.inputNames.forEach((name, i) => {
const shape = this.context.inputTextureLayouts[i].shape;
const rank = shape.length;
const funcName = `incrementIndices_${name}`;
let shapeInit = '';
for (let i = 0; i < rank; ++i) {
shapeInit += `
shape[${i}] = ${shape[i]};`;
}
const body = `
void ${funcName}(int axis, out int indices[${rank}]) {
int shape[${rank}];
${shapeInit};
for(int i = ${rank} -1 ; i >= 0; --i) {
if(i > axis) continue;
indices[i] += 1;
if(indices[i] < shape[i]) {
break;
}
indices[i] = 0;
}
}
`;
result[funcName] = new GlslLibRoutine(body);
});
return result;
}
}

View File

@@ -0,0 +1,93 @@
"use strict";
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
Object.defineProperty(exports, "__esModule", { value: true });
exports.getDefaultFragShaderMain = exports.getFragShaderPreamble = exports.getVertexShaderSource = exports.getGlsl = void 0;
const GLSL_ES_2_0 = {
version: '',
attribute: 'attribute',
varyingVertex: 'varying',
varyingFrag: 'varying',
texture2D: 'texture2D',
output: 'gl_FragColor',
outputDeclaration: '',
};
const GLSL_ES_3_0 = {
version: '#version 300 es',
attribute: 'in',
varyingVertex: 'out',
varyingFrag: 'in',
texture2D: 'texture',
output: 'outputColor',
outputDeclaration: 'out vec4 outputColor;',
};
function getGlsl(version) {
return version === 1 ? GLSL_ES_2_0 : GLSL_ES_3_0;
}
exports.getGlsl = getGlsl;
function getVertexShaderSource(version) {
const glsl = getGlsl(version);
return `${glsl.version}
precision highp float;
${glsl.attribute} vec3 position;
${glsl.attribute} vec2 textureCoord;
${glsl.varyingVertex} vec2 TexCoords;
void main()
{
gl_Position = vec4(position, 1.0);
TexCoords = textureCoord;
}`;
}
exports.getVertexShaderSource = getVertexShaderSource;
function getFragShaderPreamble(version) {
const glsl = getGlsl(version);
return `${glsl.version}
precision highp float;
precision highp int;
precision highp sampler2D;
${glsl.varyingFrag} vec2 TexCoords;
${glsl.outputDeclaration}
const vec2 halfCR = vec2(0.5, 0.5);
// Custom vector types to handle higher dimenalities.
struct ivec5
{
int x;
int y;
int z;
int w;
int u;
};
struct ivec6
{
int x;
int y;
int z;
int w;
int u;
int v;
};
int imod(int x, int y) {
return x - y * (x / y);
}
`;
}
exports.getFragShaderPreamble = getFragShaderPreamble;
function getDefaultFragShaderMain(version, outputShapeLength) {
const glsl = getGlsl(version);
return `
void main() {
int indices[${outputShapeLength}];
toVec(TexCoords, indices);
vec4 result = vec4(process(indices));
${glsl.output} = result;
}
`;
}
exports.getDefaultFragShaderMain = getDefaultFragShaderMain;
//# sourceMappingURL=glsl-source.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"glsl-source.js","sourceRoot":"","sources":["glsl-source.ts"],"names":[],"mappings":";AAAA,4DAA4D;AAC5D,kCAAkC;;;AAelC,MAAM,WAAW,GAAS;IACxB,OAAO,EAAE,EAAE;IACX,SAAS,EAAE,WAAW;IACtB,aAAa,EAAE,SAAS;IACxB,WAAW,EAAE,SAAS;IACtB,SAAS,EAAE,WAAW;IACtB,MAAM,EAAE,cAAc;IACtB,iBAAiB,EAAE,EAAE;CACtB,CAAC;AACF,MAAM,WAAW,GAAS;IACxB,OAAO,EAAE,iBAAiB;IAC1B,SAAS,EAAE,IAAI;IACf,aAAa,EAAE,KAAK;IACpB,WAAW,EAAE,IAAI;IACjB,SAAS,EAAE,SAAS;IACpB,MAAM,EAAE,aAAa;IACrB,iBAAiB,EAAE,uBAAuB;CAC3C,CAAC;AAEF,SAAgB,OAAO,CAAC,OAAY;IAClC,OAAO,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,WAAW,CAAC;AACnD,CAAC;AAFD,0BAEC;AAED,SAAgB,qBAAqB,CAAC,OAAY;IAChD,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC9B,OAAO,GAAG,IAAI,CAAC,OAAO;;QAEhB,IAAI,CAAC,SAAS;QACd,IAAI,CAAC,SAAS;;QAEd,IAAI,CAAC,aAAa;;;;;;QAMlB,CAAC;AACT,CAAC;AAdD,sDAcC;AAED,SAAgB,qBAAqB,CAAC,OAAY;IAChD,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC9B,OAAO,GAAG,IAAI,CAAC,OAAO;;;;MAIlB,IAAI,CAAC,WAAW;MAChB,IAAI,CAAC,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;KA2BvB,CAAC;AACN,CAAC;AAnCD,sDAmCC;AAED,SAAgB,wBAAwB,CAAC,OAAY,EAAE,iBAAyB;IAC9E,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC9B,OAAO;;kBAES,iBAAiB;;;MAG7B,IAAI,CAAC,MAAM;;GAEd,CAAC;AACJ,CAAC;AAVD,4DAUC"}

View File

@@ -0,0 +1,103 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
/**
* represent a version irrelevant abstraction of for GLSL source code
*/
export interface Glsl {
readonly version: string;
readonly attribute: string;
readonly varyingVertex: string;
readonly varyingFrag: string;
readonly texture2D: string;
readonly output: string;
readonly outputDeclaration: string;
}
const GLSL_ES_2_0: Glsl = {
version: '',
attribute: 'attribute',
varyingVertex: 'varying',
varyingFrag: 'varying',
texture2D: 'texture2D',
output: 'gl_FragColor',
outputDeclaration: '',
};
const GLSL_ES_3_0: Glsl = {
version: '#version 300 es',
attribute: 'in',
varyingVertex: 'out',
varyingFrag: 'in',
texture2D: 'texture',
output: 'outputColor',
outputDeclaration: 'out vec4 outputColor;',
};
export function getGlsl(version: 1|2) {
return version === 1 ? GLSL_ES_2_0 : GLSL_ES_3_0;
}
export function getVertexShaderSource(version: 1|2): string {
const glsl = getGlsl(version);
return `${glsl.version}
precision highp float;
${glsl.attribute} vec3 position;
${glsl.attribute} vec2 textureCoord;
${glsl.varyingVertex} vec2 TexCoords;
void main()
{
gl_Position = vec4(position, 1.0);
TexCoords = textureCoord;
}`;
}
export function getFragShaderPreamble(version: 1|2): string {
const glsl = getGlsl(version);
return `${glsl.version}
precision highp float;
precision highp int;
precision highp sampler2D;
${glsl.varyingFrag} vec2 TexCoords;
${glsl.outputDeclaration}
const vec2 halfCR = vec2(0.5, 0.5);
// Custom vector types to handle higher dimenalities.
struct ivec5
{
int x;
int y;
int z;
int w;
int u;
};
struct ivec6
{
int x;
int y;
int z;
int w;
int u;
int v;
};
int imod(int x, int y) {
return x - y * (x / y);
}
`;
}
export function getDefaultFragShaderMain(version: 1|2, outputShapeLength: number): string {
const glsl = getGlsl(version);
return `
void main() {
int indices[${outputShapeLength}];
toVec(TexCoords, indices);
vec4 result = vec4(process(indices));
${glsl.output} = result;
}
`;
}

View File

@@ -0,0 +1,114 @@
"use strict";
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
Object.defineProperty(exports, "__esModule", { value: true });
exports.VecGlslLib = void 0;
const glsl_definitions_1 = require("./glsl-definitions");
/**
* GLSL Library responsible for vec routines
* Vec is an varible length int array. The length is fixed at the time of
* generating the library functions from the dimensions of the output.
*/
class VecGlslLib extends glsl_definitions_1.GlslLib {
constructor(context) {
super(context);
}
getCustomTypes() {
return {};
}
getFunctions() {
return Object.assign(Object.assign(Object.assign(Object.assign({}, this.binaryVecFunctions()), this.copyVec()), this.setVecItem()), this.getVecItem());
}
binaryVecFunctions() {
const outputLayout = this.context.outputTextureLayout;
const rank = outputLayout.shape.length;
const nameOp = { add: '+=', sub: '-=', mul: '*=', div: '/=' };
const result = {};
for (const name in nameOp) {
const fname = `${name}Vec`;
let assignmentBlock = '';
for (let i = 0; i < rank; ++i) {
assignmentBlock += `
dest[${i}] ${nameOp[name]} src[${i}];
`;
}
const body = `
void ${fname}(int src[${rank}], out int dest[${rank}]) {
${assignmentBlock}
}
`;
result[fname] = new glsl_definitions_1.GlslLibRoutine(body);
}
return result;
}
copyVec() {
const outputLayout = this.context.outputTextureLayout;
const rank = outputLayout.shape.length;
let assignmentBlock = '';
for (let i = 0; i < rank; ++i) {
assignmentBlock += `
dest[${i}] = src[${i}];
`;
}
const body = `
void copyVec(int src[${rank}], out int dest[${rank}]) {
${assignmentBlock}
}
`;
return { copyVec: new glsl_definitions_1.GlslLibRoutine(body) };
}
setVecItem() {
const outputLayout = this.context.outputTextureLayout;
const rank = outputLayout.shape.length;
let block = `
if(index < 0)
index =${rank} + index;
if (index == 0)
m[0] = value;
`;
for (let i = 1; i < rank - 1; ++i) {
block += `
else if (index == ${i})
m[${i}] = value;
`;
}
block += `
else
m[${rank - 1}] = value;
`;
const body = `
void setVecItem(out int m[${rank}], int index, int value) {
${block}
}
`;
return { setVecItem: new glsl_definitions_1.GlslLibRoutine(body) };
}
getVecItem() {
const outputLayout = this.context.outputTextureLayout;
const rank = outputLayout.shape.length;
let block = `
if(index < 0)
index = ${rank} + index;
if (index == 0)
return m[0];
`;
for (let i = 1; i < rank - 1; ++i) {
block += `
else if (index == ${i})
return m[${i}];
`;
}
block += `
else
return m[${rank - 1}];
`;
const body = `
int getVecItem(int m[${rank}], int index) {
${block}
}
`;
return { getVecItem: new glsl_definitions_1.GlslLibRoutine(body) };
}
}
exports.VecGlslLib = VecGlslLib;
//# sourceMappingURL=glsl-vec-lib.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"glsl-vec-lib.js","sourceRoot":"","sources":["glsl-vec-lib.ts"],"names":[],"mappings":"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"}

View File

@@ -0,0 +1,113 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
import {GlslContext, GlslLib, GlslLibRoutine} from './glsl-definitions';
/**
* GLSL Library responsible for vec routines
* Vec is an varible length int array. The length is fixed at the time of
* generating the library functions from the dimensions of the output.
*/
export class VecGlslLib extends GlslLib {
constructor(context: GlslContext) {
super(context);
}
getCustomTypes(): {[name: string]: string} {
return {};
}
getFunctions(): {[name: string]: GlslLibRoutine} {
return {...this.binaryVecFunctions(), ...this.copyVec(), ...this.setVecItem(), ...this.getVecItem()};
}
protected binaryVecFunctions(): {[name: string]: GlslLibRoutine} {
const outputLayout = this.context.outputTextureLayout;
const rank = outputLayout.shape.length;
const nameOp: {[name: string]: string} = {add: '+=', sub: '-=', mul: '*=', div: '/='};
const result: {[name: string]: GlslLibRoutine} = {};
for (const name in nameOp) {
const fname = `${name}Vec`;
let assignmentBlock = '';
for (let i = 0; i < rank; ++i) {
assignmentBlock += `
dest[${i}] ${nameOp[name]} src[${i}];
`;
}
const body = `
void ${fname}(int src[${rank}], out int dest[${rank}]) {
${assignmentBlock}
}
`;
result[fname] = new GlslLibRoutine(body);
}
return result;
}
protected copyVec(): {[name: string]: GlslLibRoutine} {
const outputLayout = this.context.outputTextureLayout;
const rank = outputLayout.shape.length;
let assignmentBlock = '';
for (let i = 0; i < rank; ++i) {
assignmentBlock += `
dest[${i}] = src[${i}];
`;
}
const body = `
void copyVec(int src[${rank}], out int dest[${rank}]) {
${assignmentBlock}
}
`;
return {copyVec: new GlslLibRoutine(body)};
}
protected setVecItem(): {[name: string]: GlslLibRoutine} {
const outputLayout = this.context.outputTextureLayout;
const rank = outputLayout.shape.length;
let block = `
if(index < 0)
index =${rank} + index;
if (index == 0)
m[0] = value;
`;
for (let i = 1; i < rank - 1; ++i) {
block += `
else if (index == ${i})
m[${i}] = value;
`;
}
block += `
else
m[${rank - 1}] = value;
`;
const body = `
void setVecItem(out int m[${rank}], int index, int value) {
${block}
}
`;
return {setVecItem: new GlslLibRoutine(body)};
}
protected getVecItem(): {[name: string]: GlslLibRoutine} {
const outputLayout = this.context.outputTextureLayout;
const rank = outputLayout.shape.length;
let block = `
if(index < 0)
index = ${rank} + index;
if (index == 0)
return m[0];
`;
for (let i = 1; i < rank - 1; ++i) {
block += `
else if (index == ${i})
return m[${i}];
`;
}
block += `
else
return m[${rank - 1}];
`;
const body = `
int getVecItem(int m[${rank}], int index) {
${block}
}
`;
return {getVecItem: new GlslLibRoutine(body)};
}
}

View File

@@ -0,0 +1,267 @@
"use strict";
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
Object.defineProperty(exports, "__esModule", { value: true });
exports.WebGLInferenceHandler = void 0;
const instrument_1 = require("../../instrument");
const tensor_1 = require("../../tensor");
const util_1 = require("../../util");
const pack_1 = require("./ops/pack");
const reshape_packed_1 = require("./ops/reshape-packed");
const uint8_encode_1 = require("./ops/uint8-encode");
const unpack_1 = require("./ops/unpack");
const texture_layout_1 = require("./texture-layout");
const types_1 = require("./types");
const getProgramInfoUniqueKey = (programInfo, inputTextureDatas) => {
const inputs = inputTextureDatas.map(texture => `${texture.unpackedShape.join(',')};${texture.width}x${texture.height}`)
.join('_');
let key = programInfo.name;
if (programInfo.cacheHint) {
key += '[' + programInfo.cacheHint + ']';
}
key += ':' + inputs;
return key;
};
class WebGLInferenceHandler {
constructor(session) {
this.session = session;
this.packedTextureDataCache = new Map();
this.unpackedTextureDataCache = new Map();
}
/**
* @returns [width, height]
*/
calculateTextureWidthAndHeight(shape, textureType) {
return (0, texture_layout_1.calculateTextureWidthAndHeight)(this.session.layoutStrategy, shape, textureType);
}
executeProgram(program, inputs) {
if (inputs.length < program.inputNames.length) {
throw new Error(`Input size mustn't be less than ${program.inputNames.length}.`);
}
if (program.inputNames.length !== program.inputTypes.length) {
throw new Error('input names size does not match input types');
}
// create texture info for input
const inputTextureDatas = [];
for (let i = 0; i < program.inputNames.length; ++i) {
inputTextureDatas[i] = this.getOrCreateTextureData(inputs[i], program.inputTypes[i]);
}
const key = getProgramInfoUniqueKey(program, inputTextureDatas);
let artifact = this.session.programManager.getArtifact(key);
const programInfo = artifact ?
artifact.programInfo :
(typeof program.get === 'function' ? program.get() :
program);
// create texture info for output
const outputTextureLayout = (0, texture_layout_1.createTextureLayoutFromTextureType)(this.session.layoutStrategy, programInfo.output.dims, programInfo.output.textureType);
const outputTextureData = this.createTextureData(outputTextureLayout, programInfo.output.type);
if (!artifact) {
artifact = this.session.programManager.build(programInfo, inputTextureDatas, outputTextureData);
this.session.programManager.setArtifact(key, artifact);
}
this.runProgram(artifact, inputTextureDatas, outputTextureData);
return outputTextureData;
}
run(program, inputs) {
const outputTextureData = this.executeProgram(program, inputs);
return outputTextureData.tensor;
}
runProgram(artifact, inputs, output) {
// input should match
for (let i = 0; i < inputs.length; ++i) {
if (!!inputs[i].isPacked !== (artifact.programInfo.inputTypes[i] === types_1.TextureType.packed)) {
throw new Error(`input[${i}] property packed inconsistent`);
}
}
// output should match
if (!!output.isPacked !== (artifact.programInfo.output.textureType === types_1.TextureType.packed)) {
throw new Error('output property packed inconsistent');
}
this.session.programManager.run(artifact, inputs, output);
}
/**
* Create a TextureData object from a tensor.
* Usage = Encoder.Usage.UploadOnly.
* If a related texture data is found in cache, returns it;
* Otherwise:
* Creates a new texture layout if not provided;
* Creates WebGLTexture with the layout;
* Upload tensor data to the texture;
* Creates a texture data object associated with the given tensor.
* @param tensor the tensor with data to upload
*/
getOrCreateTextureData(tensor, textureType) {
let td = this.getTextureData(tensor.dataId, textureType === types_1.TextureType.packed);
if (!td) {
// check if we have texture data in different type
td = this.getTextureData(tensor.dataId, textureType !== types_1.TextureType.packed);
if (td) {
if (textureType === types_1.TextureType.packed) {
return this.pack(td);
}
else {
return this.unpack(td);
}
}
}
if (!td) {
const layout = (0, texture_layout_1.createTextureLayoutFromTextureType)(this.session.layoutStrategy, tensor.dims, textureType);
if (textureType === types_1.TextureType.packedLastDimension) {
const group = 1;
const channels = 4;
const shape = tensor.dims;
if (shape.length === 4) {
// pre-processing for kernel data of Conv.
//
// TODO: currently this is a hacking to overwrite Conv's weight. The correct way to do this should be:
// 1. implement texture based const-folding
// 2. create a WebGL program "preprocessConvWeight" to do the same work as below
// 3. run the program before dotProduct.
//
const adjustedKernelShape = [shape[0], Math.ceil((shape[1] * shape[2] * shape[3]) / channels)];
const adjustedLayout = (0, texture_layout_1.createTextureLayoutFromTextureType)(this.session.layoutStrategy, adjustedKernelShape, textureType);
let buffer = tensor.numberData;
if (shape[1] * shape[2] * shape[3] % channels !== 0) {
const numFeatureMaps = shape[0];
const oldRowSize = shape[1] * shape[2] * shape[3];
const newRowSize = Math.ceil(oldRowSize * group / channels) * channels;
const newSize = numFeatureMaps * newRowSize;
buffer = new Float32Array(newSize);
for (let f = 0; f < numFeatureMaps; ++f) {
const oldOffset = f * oldRowSize;
const newOffset = f * newRowSize + f % group * oldRowSize;
buffer.set(tensor.numberData.subarray(oldOffset, oldOffset + oldRowSize), newOffset);
}
}
return this.createTextureData(adjustedLayout, tensor.type, buffer, tensor, 1 /* Encoder.Usage.UploadOnly */);
}
}
if (textureType === types_1.TextureType.packed) {
const unpackedTextureLayout = (0, texture_layout_1.createTextureLayoutFromShape)(this.session.layoutStrategy, tensor.dims, 1, [], { reverseWH: true });
const unpackedTextureData = this.createTextureData(unpackedTextureLayout, tensor.type, tensor.numberData, tensor, 1 /* Encoder.Usage.UploadOnly */);
td = this.pack(unpackedTextureData);
}
else {
td = this.createTextureData(layout, tensor.type, tensor.numberData, tensor, 1 /* Encoder.Usage.UploadOnly */);
}
}
return td;
}
/**
* Create a TextureData object using the given data and bind to the given tensor.
* Usage = Encoder.Usage.UploadOnly.
* NOTE: this function is a hack for Conv implementation. should remove this function, after rewriting Conv
* implementation by Graph.Transformer
* @param dataType the tensor data type
* @param data the actual data to upload
* @param tensor the tensor to bind. tensor's data is ignored.
*/
createTextureDataFromLayoutBindTensor(layout, dataType, data, tensor) {
return this.createTextureData(layout, dataType, data, tensor, 1 /* Encoder.Usage.UploadOnly */);
}
createTextureData(layout, dataType, data, tensor, usage) {
instrument_1.Logger.verbose('InferenceHandler', `Creating TextureData: layout:[${JSON.stringify(layout)}]`);
const texture = this.session.textureManager.createTextureFromLayout(dataType, layout, data, usage);
return this.createTextureDataFromTexture(layout, dataType, texture, tensor);
}
reshapeUnpacked(input, reshapedDims) {
const inputTD = this.getOrCreateTextureData(input, types_1.TextureType.unpacked);
const newTextureLayout = {
channels: inputTD.channels,
height: inputTD.height,
width: inputTD.width,
// handle reshaping into scalar Tensors
shape: reshapedDims.length !== 0 ? reshapedDims : [1],
strides: util_1.ShapeUtil.computeStrides(reshapedDims),
unpackedShape: reshapedDims,
};
const newTextureData = this.createTextureDataFromTexture(newTextureLayout, input.type, inputTD.texture);
return newTextureData.tensor;
}
reshapePacked(input, reshapedDims) {
const inputTD = this.getOrCreateTextureData(input, types_1.TextureType.packed);
// check if the reshape is 'cheap'
if ((0, reshape_packed_1.isReshapeCheap)(input.dims, reshapedDims)) {
const newTextureLayout = {
channels: inputTD.channels,
height: inputTD.height,
width: inputTD.width,
// handle reshaping into scalar Tensors
shape: reshapedDims.length !== 0 ? reshapedDims : [1],
strides: util_1.ShapeUtil.computeStrides(reshapedDims),
unpackedShape: reshapedDims,
isPacked: true
};
const newTextureData = this.createTextureDataFromTexture(newTextureLayout, input.type, inputTD.texture);
return newTextureData.tensor;
}
const squeezedInputShape = (0, reshape_packed_1.processDims3D)(input.dims);
const squeezedOutputShape = (0, reshape_packed_1.processDims3D)(reshapedDims);
const squeezedInputTensor = this.reshapePacked(input, squeezedInputShape);
const squeezedOutputTensor = this.run((0, reshape_packed_1.createPackedReshape3DProgramInfoLoader)(this, squeezedInputTensor, squeezedOutputShape), [squeezedInputTensor]);
const outputTensor = this.reshapePacked(squeezedOutputTensor, reshapedDims);
return outputTensor;
}
cast(input, type) {
const inputTD = this.getOrCreateTextureData(input, types_1.TextureType.unpacked);
const newTextureData = this.createTextureDataFromTexture(inputTD, type, inputTD.texture);
return newTextureData.tensor;
}
createTextureDataFromTexture(layout, dataType, texture, tensor, tensorId) {
const textureData = Object.assign(Object.assign({}, layout), { tensor: tensor ||
new tensor_1.Tensor(layout.unpackedShape, dataType, (_id) => this.readTexture(textureData), async (_id) => this.readTextureAsync(textureData), undefined, tensorId), texture });
this.setTextureData(textureData.tensor.dataId, textureData, layout.isPacked);
return textureData;
}
getTextureData(tensorId, isPacked = false) {
return this.session.isInitializer(tensorId) ? this.session.getTextureData(tensorId, isPacked) :
isPacked ? this.packedTextureDataCache.get(tensorId) :
this.unpackedTextureDataCache.get(tensorId);
}
setTextureData(tensorId, td, isPacked = false) {
if (this.session.isInitializer(tensorId)) {
this.session.setTextureData(tensorId, td, isPacked);
}
else {
(isPacked ? this.packedTextureDataCache : this.unpackedTextureDataCache).set(tensorId, td);
}
}
isTextureLayoutCached(tensor, isPacked = false) {
return !!this.getTextureData(tensor.dataId, isPacked);
}
dispose() {
this.session.textureManager.clearActiveTextures();
this.packedTextureDataCache.forEach(td => this.session.textureManager.releaseTexture(td));
this.packedTextureDataCache = new Map();
this.unpackedTextureDataCache.forEach(td => this.session.textureManager.releaseTexture(td));
this.unpackedTextureDataCache = new Map();
}
readTexture(textureData) {
if (textureData.isPacked) {
return this.readTexture(this.unpack(textureData));
}
if (!this.session.backend.glContext.isFloat32DownloadSupported) {
return this.session.textureManager.readUint8TextureAsFloat((0, uint8_encode_1.encodeAsUint8)(this, textureData));
}
return this.session.textureManager.readTexture(textureData, textureData.tensor.type, textureData.channels);
}
async readTextureAsync(textureData) {
if (textureData.isPacked) {
return this.readTextureAsync(this.unpack(textureData));
}
if (!this.session.backend.glContext.isFloat32DownloadSupported) {
return this.session.textureManager.readUint8TextureAsFloat((0, uint8_encode_1.encodeAsUint8)(this, textureData));
}
return this.session.textureManager.readTextureAsync(textureData, textureData.tensor.type, textureData.channels);
}
pack(input) {
const outputTextureData = this.executeProgram((0, pack_1.createPackProgramInfoLoader)(this, input.tensor), [input.tensor]);
return outputTextureData;
}
unpack(input) {
const outputTextureData = this.executeProgram((0, unpack_1.createUnpackProgramInfoLoader)(this, input.tensor), [input.tensor]);
return outputTextureData;
}
}
exports.WebGLInferenceHandler = WebGLInferenceHandler;
//# sourceMappingURL=inference-handler.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,315 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
import {InferenceHandler} from '../../backend';
import {Logger} from '../../instrument';
import {Tensor} from '../../tensor';
import {ShapeUtil} from '../../util';
import {createPackProgramInfoLoader} from './ops/pack';
import {createPackedReshape3DProgramInfoLoader, isReshapeCheap, processDims3D} from './ops/reshape-packed';
import {encodeAsUint8} from './ops/uint8-encode';
import {createUnpackProgramInfoLoader} from './ops/unpack';
import {WebGLSessionHandler} from './session-handler';
import {Encoder} from './texture-data-encoder';
import {calculateTextureWidthAndHeight, createTextureLayoutFromShape, createTextureLayoutFromTextureType} from './texture-layout';
import {Artifact, ProgramInfo, ProgramInfoLoader, TextureData, TextureLayout, TextureType} from './types';
const getProgramInfoUniqueKey =
(programInfo: ProgramInfo|ProgramInfoLoader, inputTextureDatas: TextureData[]): string => {
const inputs =
inputTextureDatas.map(texture => `${texture.unpackedShape.join(',')};${texture.width}x${texture.height}`)
.join('_');
let key = programInfo.name;
if (programInfo.cacheHint) {
key += '[' + programInfo.cacheHint + ']';
}
key += ':' + inputs;
return key;
};
export class WebGLInferenceHandler implements InferenceHandler {
private packedTextureDataCache: Map<Tensor.Id, TextureData>;
private unpackedTextureDataCache: Map<Tensor.Id, TextureData>;
constructor(public session: WebGLSessionHandler) {
this.packedTextureDataCache = new Map();
this.unpackedTextureDataCache = new Map();
}
/**
* @returns [width, height]
*/
calculateTextureWidthAndHeight(shape: readonly number[], textureType: TextureType): [number, number] {
return calculateTextureWidthAndHeight(this.session.layoutStrategy, shape, textureType);
}
executeProgram(program: ProgramInfo|ProgramInfoLoader, inputs: readonly Tensor[]): TextureData {
if (inputs.length < program.inputNames.length) {
throw new Error(`Input size mustn't be less than ${program.inputNames.length}.`);
}
if (program.inputNames.length !== program.inputTypes.length) {
throw new Error('input names size does not match input types');
}
// create texture info for input
const inputTextureDatas: TextureData[] = [];
for (let i = 0; i < program.inputNames.length; ++i) {
inputTextureDatas[i] = this.getOrCreateTextureData(inputs[i], program.inputTypes[i]);
}
const key = getProgramInfoUniqueKey(program, inputTextureDatas);
let artifact = this.session.programManager.getArtifact(key);
const programInfo = artifact ?
artifact.programInfo :
(typeof (program as ProgramInfoLoader).get === 'function' ? (program as ProgramInfoLoader).get() :
(program as ProgramInfo));
// create texture info for output
const outputTextureLayout = createTextureLayoutFromTextureType(
this.session.layoutStrategy, programInfo.output.dims, programInfo.output.textureType);
const outputTextureData = this.createTextureData(outputTextureLayout, programInfo.output.type);
if (!artifact) {
artifact = this.session.programManager.build(programInfo, inputTextureDatas, outputTextureData);
this.session.programManager.setArtifact(key, artifact);
}
this.runProgram(artifact, inputTextureDatas, outputTextureData);
return outputTextureData;
}
run(program: ProgramInfoLoader, inputs: readonly Tensor[]): Tensor {
const outputTextureData = this.executeProgram(program, inputs);
return outputTextureData.tensor;
}
private runProgram(artifact: Artifact, inputs: TextureData[], output: TextureData): void {
// input should match
for (let i = 0; i < inputs.length; ++i) {
if (!!inputs[i].isPacked !== (artifact.programInfo.inputTypes[i] === TextureType.packed)) {
throw new Error(`input[${i}] property packed inconsistent`);
}
}
// output should match
if (!!output.isPacked !== (artifact.programInfo.output.textureType === TextureType.packed)) {
throw new Error('output property packed inconsistent');
}
this.session.programManager.run(artifact, inputs, output);
}
/**
* Create a TextureData object from a tensor.
* Usage = Encoder.Usage.UploadOnly.
* If a related texture data is found in cache, returns it;
* Otherwise:
* Creates a new texture layout if not provided;
* Creates WebGLTexture with the layout;
* Upload tensor data to the texture;
* Creates a texture data object associated with the given tensor.
* @param tensor the tensor with data to upload
*/
private getOrCreateTextureData(tensor: Tensor, textureType: TextureType) {
let td = this.getTextureData(tensor.dataId, textureType === TextureType.packed);
if (!td) {
// check if we have texture data in different type
td = this.getTextureData(tensor.dataId, textureType !== TextureType.packed);
if (td) {
if (textureType === TextureType.packed) {
return this.pack(td);
} else {
return this.unpack(td);
}
}
}
if (!td) {
const layout = createTextureLayoutFromTextureType(this.session.layoutStrategy, tensor.dims, textureType);
if (textureType === TextureType.packedLastDimension) {
const group = 1;
const channels = 4;
const shape = tensor.dims;
if (shape.length === 4) {
// pre-processing for kernel data of Conv.
//
// TODO: currently this is a hacking to overwrite Conv's weight. The correct way to do this should be:
// 1. implement texture based const-folding
// 2. create a WebGL program "preprocessConvWeight" to do the same work as below
// 3. run the program before dotProduct.
//
const adjustedKernelShape = [shape[0], Math.ceil((shape[1] * shape[2] * shape[3]) / channels)];
const adjustedLayout =
createTextureLayoutFromTextureType(this.session.layoutStrategy, adjustedKernelShape, textureType);
let buffer = tensor.numberData;
if (shape[1] * shape[2] * shape[3] % channels !== 0) {
const numFeatureMaps = shape[0];
const oldRowSize = shape[1] * shape[2] * shape[3];
const newRowSize = Math.ceil(oldRowSize * group / channels) * channels;
const newSize = numFeatureMaps * newRowSize;
buffer = new Float32Array(newSize);
for (let f = 0; f < numFeatureMaps; ++f) {
const oldOffset = f * oldRowSize;
const newOffset = f * newRowSize + f % group * oldRowSize;
buffer.set(tensor.numberData.subarray(oldOffset, oldOffset + oldRowSize), newOffset);
}
}
return this.createTextureData(adjustedLayout, tensor.type, buffer, tensor, Encoder.Usage.UploadOnly);
}
}
if (textureType === TextureType.packed) {
const unpackedTextureLayout =
createTextureLayoutFromShape(this.session.layoutStrategy, tensor.dims, 1, [], {reverseWH: true});
const unpackedTextureData = this.createTextureData(
unpackedTextureLayout, tensor.type, tensor.numberData, tensor, Encoder.Usage.UploadOnly);
td = this.pack(unpackedTextureData);
} else {
td = this.createTextureData(layout, tensor.type, tensor.numberData, tensor, Encoder.Usage.UploadOnly);
}
}
return td;
}
/**
* Create a TextureData object using the given data and bind to the given tensor.
* Usage = Encoder.Usage.UploadOnly.
* NOTE: this function is a hack for Conv implementation. should remove this function, after rewriting Conv
* implementation by Graph.Transformer
* @param dataType the tensor data type
* @param data the actual data to upload
* @param tensor the tensor to bind. tensor's data is ignored.
*/
createTextureDataFromLayoutBindTensor(
layout: TextureLayout, dataType: Tensor.DataType, data: Tensor.NumberType, tensor: Tensor): TextureData {
return this.createTextureData(layout, dataType, data, tensor, Encoder.Usage.UploadOnly);
}
private createTextureData(
layout: TextureLayout, dataType: Tensor.DataType, data?: Tensor.NumberType, tensor?: Tensor,
usage?: Encoder.Usage): TextureData {
Logger.verbose('InferenceHandler', `Creating TextureData: layout:[${JSON.stringify(layout)}]`);
const texture = this.session.textureManager.createTextureFromLayout(dataType, layout, data, usage);
return this.createTextureDataFromTexture(layout, dataType, texture, tensor);
}
reshapeUnpacked(input: Tensor, reshapedDims: readonly number[]): Tensor {
const inputTD = this.getOrCreateTextureData(input, TextureType.unpacked);
const newTextureLayout: TextureLayout = {
channels: inputTD.channels,
height: inputTD.height,
width: inputTD.width,
// handle reshaping into scalar Tensors
shape: reshapedDims.length !== 0 ? reshapedDims : [1],
strides: ShapeUtil.computeStrides(reshapedDims),
unpackedShape: reshapedDims,
};
const newTextureData = this.createTextureDataFromTexture(newTextureLayout, input.type, inputTD.texture);
return newTextureData.tensor;
}
reshapePacked(input: Tensor, reshapedDims: readonly number[]): Tensor {
const inputTD = this.getOrCreateTextureData(input, TextureType.packed);
// check if the reshape is 'cheap'
if (isReshapeCheap(input.dims, reshapedDims)) {
const newTextureLayout: TextureLayout = {
channels: inputTD.channels,
height: inputTD.height,
width: inputTD.width,
// handle reshaping into scalar Tensors
shape: reshapedDims.length !== 0 ? reshapedDims : [1],
strides: ShapeUtil.computeStrides(reshapedDims),
unpackedShape: reshapedDims,
isPacked: true
};
const newTextureData = this.createTextureDataFromTexture(newTextureLayout, input.type, inputTD.texture);
return newTextureData.tensor;
}
const squeezedInputShape = processDims3D(input.dims);
const squeezedOutputShape = processDims3D(reshapedDims);
const squeezedInputTensor = this.reshapePacked(input, squeezedInputShape);
const squeezedOutputTensor = this.run(
createPackedReshape3DProgramInfoLoader(this, squeezedInputTensor, squeezedOutputShape), [squeezedInputTensor]);
const outputTensor = this.reshapePacked(squeezedOutputTensor, reshapedDims);
return outputTensor;
}
cast(input: Tensor, type: Tensor.DataType): Tensor {
const inputTD = this.getOrCreateTextureData(input, TextureType.unpacked);
const newTextureData = this.createTextureDataFromTexture(inputTD as TextureLayout, type, inputTD.texture);
return newTextureData.tensor;
}
private createTextureDataFromTexture(
layout: TextureLayout, dataType: Tensor.DataType, texture: WebGLTexture, tensor?: Tensor, tensorId?: Tensor.Id) {
const textureData: TextureData = {
...layout,
tensor: tensor ||
new Tensor(
layout.unpackedShape, dataType, (_id: Tensor.Id) => this.readTexture(textureData),
async (_id: Tensor.Id) => this.readTextureAsync(textureData), undefined, tensorId),
texture
};
this.setTextureData(textureData.tensor.dataId, textureData, layout.isPacked);
return textureData;
}
private getTextureData(tensorId: Tensor.Id, isPacked = false): TextureData|undefined {
return this.session.isInitializer(tensorId) ? this.session.getTextureData(tensorId, isPacked) :
isPacked ? this.packedTextureDataCache.get(tensorId) :
this.unpackedTextureDataCache.get(tensorId);
}
setTextureData(tensorId: Tensor.Id, td: TextureData, isPacked = false): void {
if (this.session.isInitializer(tensorId)) {
this.session.setTextureData(tensorId, td, isPacked);
} else {
(isPacked ? this.packedTextureDataCache : this.unpackedTextureDataCache).set(tensorId, td);
}
}
isTextureLayoutCached(tensor: Tensor, isPacked = false): boolean {
return !!this.getTextureData(tensor.dataId, isPacked);
}
dispose(): void {
this.session.textureManager.clearActiveTextures();
this.packedTextureDataCache.forEach(td => this.session.textureManager.releaseTexture(td));
this.packedTextureDataCache = new Map();
this.unpackedTextureDataCache.forEach(td => this.session.textureManager.releaseTexture(td));
this.unpackedTextureDataCache = new Map();
}
readTexture(textureData: TextureData): Tensor.NumberType {
if (textureData.isPacked) {
return this.readTexture(this.unpack(textureData));
}
if (!this.session.backend.glContext.isFloat32DownloadSupported) {
return this.session.textureManager.readUint8TextureAsFloat(encodeAsUint8(this, textureData));
}
return this.session.textureManager.readTexture(textureData, textureData.tensor.type, textureData.channels);
}
async readTextureAsync(textureData: TextureData): Promise<Tensor.NumberType> {
if (textureData.isPacked) {
return this.readTextureAsync(this.unpack(textureData));
}
if (!this.session.backend.glContext.isFloat32DownloadSupported) {
return this.session.textureManager.readUint8TextureAsFloat(encodeAsUint8(this, textureData));
}
return this.session.textureManager.readTextureAsync(textureData, textureData.tensor.type, textureData.channels);
}
pack(input: TextureData): TextureData {
const outputTextureData = this.executeProgram(createPackProgramInfoLoader(this, input.tensor), [input.tensor]);
return outputTextureData;
}
unpack(input: TextureData): TextureData {
const outputTextureData = this.executeProgram(createUnpackProgramInfoLoader(this, input.tensor), [input.tensor]);
return outputTextureData;
}
}

View File

@@ -0,0 +1,147 @@
"use strict";
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.WEBGL_OP_RESOLVE_RULES = void 0;
const batch_normalization_1 = require("./ops/batch-normalization");
const binaryOps = __importStar(require("./ops/binary-op"));
const cast_1 = require("./ops/cast");
const concat_1 = require("./ops/concat");
const conv_1 = require("./ops/conv");
const conv_transpose_1 = require("./ops/conv-transpose");
const depth_to_space_1 = require("./ops/depth-to-space");
const flatten_1 = require("./ops/flatten");
const gather_1 = require("./ops/gather");
const gemm_1 = require("./ops/gemm");
const image_scaler_1 = require("./ops/image-scaler");
const instance_normalization_1 = require("./ops/instance-normalization");
const matmul_1 = require("./ops/matmul");
const pad_1 = require("./ops/pad");
const pool_1 = require("./ops/pool");
const reduce_1 = require("./ops/reduce");
const reshape_1 = require("./ops/reshape");
const resize_packed_1 = require("./ops/resize-packed");
const shape_1 = require("./ops/shape");
const slice_1 = require("./ops/slice");
const softmax_1 = require("./ops/softmax");
const split_1 = require("./ops/split");
const squeeze_1 = require("./ops/squeeze");
const sum_1 = require("./ops/sum");
const tile_1 = require("./ops/tile");
const transpose_1 = require("./ops/transpose");
const unaryOps = __importStar(require("./ops/unary-op"));
const unsqueeze_1 = require("./ops/unsqueeze");
const upsample_1 = require("./ops/upsample");
exports.WEBGL_OP_RESOLVE_RULES = [
['Abs', '', '6+', unaryOps.abs],
['Acos', '', '7+', unaryOps.acos],
['Add', '', '7+', binaryOps.add],
['And', '', '7+', binaryOps.and],
['Asin', '', '7+', unaryOps.asin],
['Atan', '', '7+', unaryOps.atan],
// TODO: support new attributes for AveragePool-10
['AveragePool', '', '7+', pool_1.averagePool, pool_1.parseAveragePoolAttributes],
['BatchNormalization', '', '7+', batch_normalization_1.batchNormalization, batch_normalization_1.parseBatchNormalizationAttributes],
['Cast', '', '6+', cast_1.cast, cast_1.parseCastAttributes],
['Ceil', '', '6+', unaryOps.ceil],
['Clip', '', '6-10', unaryOps.clip, unaryOps.parseClipAttributes],
['Clip', '', '11+', unaryOps.clipV11],
['Concat', '', '4+', concat_1.concat, concat_1.parseConcatAttributes],
['Conv', '', '1+', conv_1.conv, conv_1.parseConvAttributes],
['ConvTranspose', '', '1+', conv_transpose_1.convTranspose, conv_transpose_1.parseConvTransposeAttributes],
['Cos', '', '7+', unaryOps.cos],
['Div', '', '7+', binaryOps.div],
['Dropout', '', '7+', unaryOps.identity],
['DepthToSpace', '', '1+', depth_to_space_1.depthToSpace, depth_to_space_1.parseDepthToSpaceAttributes],
['Equal', '', '7+', binaryOps.equal],
['Elu', '', '6+', unaryOps.elu, unaryOps.parseEluAttributes],
['Exp', '', '6+', unaryOps.exp],
['Flatten', '', '1+', flatten_1.flatten, flatten_1.parseFlattenAttributes],
['Floor', '', '6+', unaryOps.floor],
['FusedConv', 'com.microsoft', '1+', conv_1.conv, conv_1.parseConvAttributes],
['Gather', '', '1+', gather_1.gather, gather_1.parseGatherAttributes],
['Gemm', '', '7-10', gemm_1.gemm, gemm_1.parseGemmAttributesV7],
['Gemm', '', '11+', gemm_1.gemm, gemm_1.parseGemmAttributesV11],
['GlobalAveragePool', '', '1+', pool_1.globalAveragePool, pool_1.parseGlobalAveragePoolAttributes],
['GlobalMaxPool', '', '1+', pool_1.globalMaxPool],
['Greater', '', '7+', binaryOps.greater],
['Identity', '', '1+', unaryOps.identity],
['ImageScaler', '', '1+', image_scaler_1.imageScaler, image_scaler_1.parseImageScalerAttributes],
['InstanceNormalization', '', '6+', instance_normalization_1.instanceNormalization, instance_normalization_1.parseInstanceNormalizationAttributes],
['LeakyRelu', '', '6+', unaryOps.leakyRelu, unaryOps.parseLeakyReluAttributes],
['Less', '', '7+', binaryOps.less],
['Log', '', '6+', unaryOps.log],
['MatMul', '', '1+', matmul_1.matMul, matmul_1.parseMatMulAttributes],
// TODO: support new attributes for MaxPool-8 and MaxPool-10
['MaxPool', '', '1+', pool_1.maxPool, pool_1.parseMaxPoolAttributes],
['Mul', '', '7+', binaryOps.mul],
['Neg', '', '6+', unaryOps.neg],
['Not', '', '1+', unaryOps.not],
['Or', '', '7+', binaryOps.or],
['Pad', '', '2-10', pad_1.padV2, pad_1.parsePadAttributesV2],
['Pad', '', '11+', pad_1.padV11, pad_1.parsePadAttributesV11],
['Pow', '', '7+', binaryOps.pow],
['PRelu', '', '7+', binaryOps.pRelu],
['ReduceLogSum', '', '1+', reduce_1.reduceLogSum, reduce_1.parseReduceAttributes],
['ReduceMax', '', '1+', reduce_1.reduceMax, reduce_1.parseReduceAttributes],
['ReduceMean', '', '1+', reduce_1.reduceMean, reduce_1.parseReduceAttributes],
['ReduceMin', '', '1+', reduce_1.reduceMin, reduce_1.parseReduceAttributes],
['ReduceProd', '', '1+', reduce_1.reduceProd, reduce_1.parseReduceAttributes],
['ReduceSum', '', '1-12', reduce_1.reduceSum, reduce_1.parseReduceAttributes],
['ReduceSumSquare', '', '1+', reduce_1.reduceLogSumSquare, reduce_1.parseReduceAttributes],
['Relu', '', '6+', unaryOps.relu],
['Reshape', '', '5+', reshape_1.reshape],
['Resize', '', '10', resize_packed_1.resize, resize_packed_1.parseResizeAttributesV10],
['Resize', '', '11+', resize_packed_1.resize, resize_packed_1.parseResizeAttributesV11],
['Shape', '', '1+', shape_1.shape],
['Sigmoid', '', '6+', unaryOps.sigmoid],
['Sin', '', '7+', unaryOps.sin],
['Slice', '', '10+', slice_1.sliceV10],
['Slice', '', '1-9', slice_1.slice, slice_1.parseSliceAttributes],
// The "semantic" meaning of axis has changed in opset-13.
['Softmax', '', '1-12', softmax_1.softmax, softmax_1.parseSoftmaxAttributes],
['Softmax', '', '13+', softmax_1.softmaxV13, softmax_1.parseSoftmaxAttributesV13],
// 'Split' operator has an optional attribute 'split'
// this attribute determines how the specified axis of input data is split.
// When the attribute is missing, we need the count of number of outputs
// so that we can determine the 'split' attribute from the runtime input to the Operator
['Split', '', '2-12', split_1.split, split_1.parseSplitAttributes],
['Sqrt', '', '6+', unaryOps.sqrt],
['Squeeze', '', '1-12', squeeze_1.squeeze, squeeze_1.parseSqueezeAttributes],
['Squeeze', '', '13+', squeeze_1.squeezeV13],
['Sub', '', '7+', binaryOps.sub],
['Sum', '', '6+', sum_1.sum],
['Tan', '', '7+', unaryOps.tan],
['Tanh', '', '6+', unaryOps.tanh],
['Tile', '', '6+', tile_1.tile],
['Transpose', '', '1+', transpose_1.transpose, transpose_1.parseTransposeAttributes],
['Upsample', '', '7-8', upsample_1.upsample, upsample_1.parseUpsampleAttributesV7],
['Upsample', '', '9', upsample_1.upsample, upsample_1.parseUpsampleAttributesV9],
['Unsqueeze', '', '1-12', unsqueeze_1.unsqueeze, unsqueeze_1.parseUnsqueezeAttributes],
['Unsqueeze', '', '13+', unsqueeze_1.unsqueezeV13],
['Xor', '', '7+', binaryOps.xor],
];
//# sourceMappingURL=op-resolve-rules.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,124 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
import {OpSet} from '../../opset';
import {batchNormalization, parseBatchNormalizationAttributes} from './ops/batch-normalization';
import * as binaryOps from './ops/binary-op';
import {cast, parseCastAttributes} from './ops/cast';
import {concat, parseConcatAttributes} from './ops/concat';
import {conv, parseConvAttributes} from './ops/conv';
import {convTranspose, parseConvTransposeAttributes} from './ops/conv-transpose';
import {depthToSpace, parseDepthToSpaceAttributes} from './ops/depth-to-space';
import {flatten, parseFlattenAttributes} from './ops/flatten';
import {gather, parseGatherAttributes} from './ops/gather';
import {gemm, parseGemmAttributesV11, parseGemmAttributesV7} from './ops/gemm';
import {imageScaler, parseImageScalerAttributes} from './ops/image-scaler';
import {instanceNormalization, parseInstanceNormalizationAttributes} from './ops/instance-normalization';
import {matMul, parseMatMulAttributes} from './ops/matmul';
import {padV11, padV2, parsePadAttributesV11, parsePadAttributesV2} from './ops/pad';
import {averagePool, globalAveragePool, globalMaxPool, maxPool, parseAveragePoolAttributes, parseGlobalAveragePoolAttributes, parseMaxPoolAttributes} from './ops/pool';
import {parseReduceAttributes, reduceLogSum, reduceLogSumSquare, reduceMax, reduceMean, reduceMin, reduceProd, reduceSum} from './ops/reduce';
import {reshape} from './ops/reshape';
import {parseResizeAttributesV10, parseResizeAttributesV11, resize} from './ops/resize-packed';
import {shape} from './ops/shape';
import {parseSliceAttributes, slice, sliceV10} from './ops/slice';
import {parseSoftmaxAttributes, parseSoftmaxAttributesV13, softmax, softmaxV13} from './ops/softmax';
import {parseSplitAttributes, split} from './ops/split';
import {parseSqueezeAttributes, squeeze, squeezeV13} from './ops/squeeze';
import {sum} from './ops/sum';
import {tile} from './ops/tile';
import {parseTransposeAttributes, transpose} from './ops/transpose';
import * as unaryOps from './ops/unary-op';
import {parseUnsqueezeAttributes, unsqueeze, unsqueezeV13} from './ops/unsqueeze';
import {parseUpsampleAttributesV7, parseUpsampleAttributesV9, upsample} from './ops/upsample';
export const WEBGL_OP_RESOLVE_RULES: readonly OpSet.ResolveRule[] = [
['Abs', '', '6+', unaryOps.abs],
['Acos', '', '7+', unaryOps.acos],
['Add', '', '7+', binaryOps.add],
['And', '', '7+', binaryOps.and],
['Asin', '', '7+', unaryOps.asin],
['Atan', '', '7+', unaryOps.atan],
// TODO: support new attributes for AveragePool-10
['AveragePool', '', '7+', averagePool, parseAveragePoolAttributes],
['BatchNormalization', '', '7+', batchNormalization, parseBatchNormalizationAttributes],
['Cast', '', '6+', cast, parseCastAttributes],
['Ceil', '', '6+', unaryOps.ceil],
['Clip', '', '6-10', unaryOps.clip, unaryOps.parseClipAttributes],
['Clip', '', '11+', unaryOps.clipV11],
['Concat', '', '4+', concat, parseConcatAttributes],
['Conv', '', '1+', conv, parseConvAttributes],
['ConvTranspose', '', '1+', convTranspose, parseConvTransposeAttributes],
['Cos', '', '7+', unaryOps.cos],
['Div', '', '7+', binaryOps.div],
['Dropout', '', '7+', unaryOps.identity],
['DepthToSpace', '', '1+', depthToSpace, parseDepthToSpaceAttributes],
['Equal', '', '7+', binaryOps.equal],
['Elu', '', '6+', unaryOps.elu, unaryOps.parseEluAttributes],
['Exp', '', '6+', unaryOps.exp],
['Flatten', '', '1+', flatten, parseFlattenAttributes],
['Floor', '', '6+', unaryOps.floor],
['FusedConv', 'com.microsoft', '1+', conv, parseConvAttributes],
['Gather', '', '1+', gather, parseGatherAttributes],
['Gemm', '', '7-10', gemm, parseGemmAttributesV7],
['Gemm', '', '11+', gemm, parseGemmAttributesV11],
['GlobalAveragePool', '', '1+', globalAveragePool, parseGlobalAveragePoolAttributes],
['GlobalMaxPool', '', '1+', globalMaxPool],
['Greater', '', '7+', binaryOps.greater],
['Identity', '', '1+', unaryOps.identity],
['ImageScaler', '', '1+', imageScaler, parseImageScalerAttributes],
['InstanceNormalization', '', '6+', instanceNormalization, parseInstanceNormalizationAttributes],
['LeakyRelu', '', '6+', unaryOps.leakyRelu, unaryOps.parseLeakyReluAttributes],
['Less', '', '7+', binaryOps.less],
['Log', '', '6+', unaryOps.log],
['MatMul', '', '1+', matMul, parseMatMulAttributes],
// TODO: support new attributes for MaxPool-8 and MaxPool-10
['MaxPool', '', '1+', maxPool, parseMaxPoolAttributes],
['Mul', '', '7+', binaryOps.mul],
['Neg', '', '6+', unaryOps.neg],
['Not', '', '1+', unaryOps.not],
['Or', '', '7+', binaryOps.or],
['Pad', '', '2-10', padV2, parsePadAttributesV2],
['Pad', '', '11+', padV11, parsePadAttributesV11],
['Pow', '', '7+', binaryOps.pow],
['PRelu', '', '7+', binaryOps.pRelu],
['ReduceLogSum', '', '1+', reduceLogSum, parseReduceAttributes],
['ReduceMax', '', '1+', reduceMax, parseReduceAttributes],
['ReduceMean', '', '1+', reduceMean, parseReduceAttributes],
['ReduceMin', '', '1+', reduceMin, parseReduceAttributes],
['ReduceProd', '', '1+', reduceProd, parseReduceAttributes],
['ReduceSum', '', '1-12', reduceSum, parseReduceAttributes],
['ReduceSumSquare', '', '1+', reduceLogSumSquare, parseReduceAttributes],
['Relu', '', '6+', unaryOps.relu],
['Reshape', '', '5+', reshape],
['Resize', '', '10', resize, parseResizeAttributesV10],
['Resize', '', '11+', resize, parseResizeAttributesV11],
['Shape', '', '1+', shape],
['Sigmoid', '', '6+', unaryOps.sigmoid],
['Sin', '', '7+', unaryOps.sin],
['Slice', '', '10+', sliceV10], // TODO: support 'steps' for Slice-10
['Slice', '', '1-9', slice, parseSliceAttributes],
// The "semantic" meaning of axis has changed in opset-13.
['Softmax', '', '1-12', softmax, parseSoftmaxAttributes],
['Softmax', '', '13+', softmaxV13, parseSoftmaxAttributesV13],
// 'Split' operator has an optional attribute 'split'
// this attribute determines how the specified axis of input data is split.
// When the attribute is missing, we need the count of number of outputs
// so that we can determine the 'split' attribute from the runtime input to the Operator
['Split', '', '2-12', split, parseSplitAttributes],
['Sqrt', '', '6+', unaryOps.sqrt],
['Squeeze', '', '1-12', squeeze, parseSqueezeAttributes],
['Squeeze', '', '13+', squeezeV13],
['Sub', '', '7+', binaryOps.sub],
['Sum', '', '6+', sum],
['Tan', '', '7+', unaryOps.tan],
['Tanh', '', '6+', unaryOps.tanh],
['Tile', '', '6+', tile],
['Transpose', '', '1+', transpose, parseTransposeAttributes],
['Upsample', '', '7-8', upsample, parseUpsampleAttributesV7],
['Upsample', '', '9', upsample, parseUpsampleAttributesV9],
['Unsqueeze', '', '1-12', unsqueeze, parseUnsqueezeAttributes],
['Unsqueeze', '', '13+', unsqueezeV13],
['Xor', '', '7+', binaryOps.xor],
];

View File

@@ -0,0 +1,68 @@
"use strict";
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseBatchNormalizationAttributes = exports.batchNormalization = void 0;
const attribute_with_cache_key_1 = require("../../../attribute-with-cache-key");
const glsl_source_1 = require("../glsl-source");
const types_1 = require("../types");
const batchNormalizationProgramMetadata = {
name: 'BatchNormalization',
inputNames: ['A', 'Scale', 'B', 'Mean', 'Variance'],
inputTypes: [types_1.TextureType.unpacked, types_1.TextureType.unpacked, types_1.TextureType.unpacked, types_1.TextureType.unpacked, types_1.TextureType.unpacked]
};
const batchNormalization = (inferenceHandler, inputs, attributes) => {
validateInputs(inputs);
const output = inferenceHandler.run(Object.assign(Object.assign({}, batchNormalizationProgramMetadata), { cacheHint: attributes.cacheKey, get: () => createBatchNormalizationProgramInfo(inferenceHandler, inputs, attributes) }), inputs);
return [output];
};
exports.batchNormalization = batchNormalization;
const parseBatchNormalizationAttributes = (node) => {
const epsilon = node.attributes.getFloat('epsilon', 1e-5);
const momentum = node.attributes.getFloat('momentum', 0.9);
const spatial = node.attributes.getInt('spatial', 1);
return (0, attribute_with_cache_key_1.createAttributeWithCacheKey)({ epsilon, momentum, spatial });
};
exports.parseBatchNormalizationAttributes = parseBatchNormalizationAttributes;
const createBatchNormalizationProgramInfo = (inferenceHandler, inputs, attributes) => {
const glsl = (0, glsl_source_1.getGlsl)(inferenceHandler.session.backend.glContext.version);
const rank = inputs[0].dims.length;
const [scaleWidth, scaleHeight] = inferenceHandler.calculateTextureWidthAndHeight(inputs[1].dims, types_1.TextureType.unpacked);
const shaderSource = `
float process(int[${rank}] indices) {
vec2 position = offsetToCoords(indices[1], ${scaleWidth}, ${scaleHeight});
float scale = getColorAsFloat(${glsl.texture2D}(Scale, position));
float mean = getColorAsFloat(${glsl.texture2D}(Mean, position));
float variance = getColorAsFloat(${glsl.texture2D}(Variance, position));
float b = getColorAsFloat(${glsl.texture2D}(B, position));
return scale * ( (_A(indices) - mean) / sqrt(variance + float(${attributes.epsilon})) ) + b;
}`;
return Object.assign(Object.assign({}, batchNormalizationProgramMetadata), { output: { dims: inputs[0].dims, type: inputs[0].type, textureType: types_1.TextureType.unpacked }, shaderSource });
};
const validateInputs = (inputs) => {
if (!inputs || inputs.length !== 5) {
throw new Error('BatchNormalization requires 5 inputs.');
}
const X = inputs[0];
const scale = inputs[1];
const B = inputs[2];
const mean = inputs[3];
const var_ = inputs[4];
// input should atleast have three dimensions - N,C,dim1,...,dimn
// other inputs can have only one dimensions
if (X.dims.length < 3 || scale.dims.length !== 1 || B.dims.length !== 1 || mean.dims.length !== 1 ||
var_.dims.length !== 1) {
throw new Error('invalid input shape.');
}
if (scale.dims[0] !== X.dims[1] || B.dims[0] !== X.dims[1] || mean.dims[0] !== X.dims[1] ||
var_.dims[0] !== X.dims[1]) {
throw new Error('invalid input shape.');
}
if ((X.type !== 'float32' && X.type !== 'float64') || (scale.type !== 'float32' && scale.type !== 'float64') ||
(B.type !== 'float32' && B.type !== 'float64') || (mean.type !== 'float32' && mean.type !== 'float64') ||
(var_.type !== 'float32' && var_.type !== 'float64')) {
throw new Error('invalid input tensor types.');
}
};
//# sourceMappingURL=batch-normalization.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"batch-normalization.js","sourceRoot":"","sources":["batch-normalization.ts"],"names":[],"mappings":"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"}

View File

@@ -0,0 +1,96 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
import {AttributeWithCacheKey, createAttributeWithCacheKey} from '../../../attribute-with-cache-key';
import {Graph} from '../../../graph';
import {OperatorImplementation, OperatorInitialization} from '../../../operators';
import {Tensor} from '../../../tensor';
import {getGlsl} from '../glsl-source';
import {WebGLInferenceHandler} from '../inference-handler';
import {ProgramInfo, TextureType} from '../types';
export interface BatchNormalizationAttributes extends AttributeWithCacheKey {
epsilon: number;
momentum: number;
spatial: number;
}
const batchNormalizationProgramMetadata = {
name: 'BatchNormalization',
inputNames: ['A', 'Scale', 'B', 'Mean', 'Variance'],
inputTypes:
[TextureType.unpacked, TextureType.unpacked, TextureType.unpacked, TextureType.unpacked, TextureType.unpacked]
};
export const batchNormalization: OperatorImplementation<BatchNormalizationAttributes> =
(inferenceHandler: WebGLInferenceHandler, inputs: Tensor[], attributes: BatchNormalizationAttributes): Tensor[] => {
validateInputs(inputs);
const output = inferenceHandler.run(
{
...batchNormalizationProgramMetadata,
cacheHint: attributes.cacheKey,
get: () => createBatchNormalizationProgramInfo(inferenceHandler, inputs, attributes)
},
inputs);
return [output];
};
export const parseBatchNormalizationAttributes: OperatorInitialization<BatchNormalizationAttributes> =
(node: Graph.Node): BatchNormalizationAttributes => {
const epsilon = node.attributes.getFloat('epsilon', 1e-5);
const momentum = node.attributes.getFloat('momentum', 0.9);
const spatial = node.attributes.getInt('spatial', 1);
return createAttributeWithCacheKey({epsilon, momentum, spatial});
};
const createBatchNormalizationProgramInfo =
(inferenceHandler: WebGLInferenceHandler, inputs: Tensor[], attributes: BatchNormalizationAttributes):
ProgramInfo => {
const glsl = getGlsl(inferenceHandler.session.backend.glContext.version);
const rank = inputs[0].dims.length;
const [scaleWidth, scaleHeight] =
inferenceHandler.calculateTextureWidthAndHeight(inputs[1].dims, TextureType.unpacked);
const shaderSource = `
float process(int[${rank}] indices) {
vec2 position = offsetToCoords(indices[1], ${scaleWidth}, ${scaleHeight});
float scale = getColorAsFloat(${glsl.texture2D}(Scale, position));
float mean = getColorAsFloat(${glsl.texture2D}(Mean, position));
float variance = getColorAsFloat(${glsl.texture2D}(Variance, position));
float b = getColorAsFloat(${glsl.texture2D}(B, position));
return scale * ( (_A(indices) - mean) / sqrt(variance + float(${attributes.epsilon})) ) + b;
}`;
return {
...batchNormalizationProgramMetadata,
output: {dims: inputs[0].dims, type: inputs[0].type, textureType: TextureType.unpacked},
shaderSource
};
};
const validateInputs = (inputs: Tensor[]): void => {
if (!inputs || inputs.length !== 5) {
throw new Error('BatchNormalization requires 5 inputs.');
}
const X = inputs[0];
const scale = inputs[1];
const B = inputs[2];
const mean = inputs[3];
const var_ = inputs[4];
// input should atleast have three dimensions - N,C,dim1,...,dimn
// other inputs can have only one dimensions
if (X.dims.length < 3 || scale.dims.length !== 1 || B.dims.length !== 1 || mean.dims.length !== 1 ||
var_.dims.length !== 1) {
throw new Error('invalid input shape.');
}
if (scale.dims[0] !== X.dims[1] || B.dims[0] !== X.dims[1] || mean.dims[0] !== X.dims[1] ||
var_.dims[0] !== X.dims[1]) {
throw new Error('invalid input shape.');
}
if ((X.type !== 'float32' && X.type !== 'float64') || (scale.type !== 'float32' && scale.type !== 'float64') ||
(B.type !== 'float32' && B.type !== 'float64') || (mean.type !== 'float32' && mean.type !== 'float64') ||
(var_.type !== 'float32' && var_.type !== 'float64')) {
throw new Error('invalid input tensor types.');
}
};

View File

@@ -0,0 +1,291 @@
"use strict";
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
Object.defineProperty(exports, "__esModule", { value: true });
exports.xor = exports.sub = exports.pRelu = exports.pow = exports.or = exports.mul = exports.less = exports.greater = exports.equal = exports.div = exports.and = exports.add = exports.glslPRelu = exports.glslPow = exports.glslXor = exports.glslOr = exports.glslAnd = exports.glslLess = exports.glslGreater = exports.glslEqual = exports.glslSub = exports.glslMul = exports.glslDiv = exports.glslAdd = void 0;
const util_1 = require("../../../util");
const glsl_definitions_1 = require("../glsl-definitions");
const glsl_source_1 = require("../glsl-source");
const types_1 = require("../types");
function glslAdd() {
const name = 'add_';
const body = `
float ${name}(float a, float b) {
return a + b;
}
vec4 ${name}(vec4 v1, vec4 v2) {
return v1 + v2;
}
`;
return { body, name, type: glsl_definitions_1.FunctionType.ValueBased };
}
exports.glslAdd = glslAdd;
function glslDiv() {
const name = 'div_';
const body = `
float ${name}(float a, float b) {
return a / b;
}
vec4 ${name}(vec4 v1, vec4 v2) {
return v1 / v2;
}
`;
return { body, name, type: glsl_definitions_1.FunctionType.ValueBased };
}
exports.glslDiv = glslDiv;
function glslMul() {
const name = 'mul_';
const body = `
float ${name}(float a, float b) {
return a * b;
}
vec4 ${name}(vec4 v1, vec4 v2) {
return v1 * v2;
}
`;
return { body, name, type: glsl_definitions_1.FunctionType.ValueBased };
}
exports.glslMul = glslMul;
function glslSub() {
const name = 'sub_';
const body = `
float ${name}(float a, float b) {
return a - b;
}
vec4 ${name}(vec4 v1, vec4 v2) {
return v1 - v2;
}
`;
return { body, name, type: glsl_definitions_1.FunctionType.ValueBased };
}
exports.glslSub = glslSub;
function glslEqual() {
const name = 'equal_';
const body = `
float ${name}(float a, float b) {
return float(a == b);
}
vec4 ${name}(vec4 v1, vec4 v2) {
return vec4(equal(v1, v2));
}
`;
return { body, name, type: glsl_definitions_1.FunctionType.ValueBased };
}
exports.glslEqual = glslEqual;
function glslGreater() {
const name = 'greater_';
const body = `
float ${name}(float a, float b) {
return float(a > b);
}
vec4 ${name}(vec4 v1, vec4 v2) {
return vec4( v1.r > v2.r ,
v1.g > v2.g,
v1.b > v2.b,
v1.a > v2.a );
}
`;
return { body, name, type: glsl_definitions_1.FunctionType.ValueBased };
}
exports.glslGreater = glslGreater;
function glslLess() {
const name = 'less_';
const body = `
float ${name}(float a, float b) {
return float(a < b);
}
vec4 ${name}(vec4 v1, vec4 v2) {
return vec4( v1.r < v2.r ,
v1.g < v2.g,
v1.b < v2.b,
v1.a < v2.a );
}
`;
return { body, name, type: glsl_definitions_1.FunctionType.ValueBased };
}
exports.glslLess = glslLess;
function glslAnd() {
const name = 'and_';
const body = `
float ${name}(float a, float b) {
return float( bool(a) && bool(b) );
}
vec4 ${name}(vec4 v1, vec4 v2) {
bvec4 b1 = bvec4(v1);
bvec4 b2 = bvec4(v2);
return vec4( b1.r && b2.r ,
b1.g && b2.g,
b1.b && b2.b,
b1.a && b2.a );
}
`;
return { body, name, type: glsl_definitions_1.FunctionType.ValueBased };
}
exports.glslAnd = glslAnd;
function glslOr() {
const name = 'or_';
const body = `
float ${name}(float a, float b) {
return float( bool(a) || bool(b) );
}
vec4 ${name}(vec4 v1, vec4 v2) {
bvec4 b1 = bvec4(v1);
bvec4 b2 = bvec4(v2);
return vec4( b1.r || b2.r ,
b1.g || b2.g,
b1.b || b2.b,
b1.a || b2.a );
}
`;
return { body, name, type: glsl_definitions_1.FunctionType.ValueBased };
}
exports.glslOr = glslOr;
function glslXor() {
const name = 'xor_';
const body = `
float ${name}(float a, float b) {
return float( bool(a) ^^ bool(b) );
}
vec4 ${name}(vec4 v1, vec4 v2) {
bvec4 b1 = bvec4(v1);
bvec4 b2 = bvec4(v2);
return vec4( b1.r ^^ b2.r ,
b1.g ^^ b2.g,
b1.b ^^ b2.b,
b1.a ^^ b2.a );
}
`;
return { body, name, type: glsl_definitions_1.FunctionType.ValueBased };
}
exports.glslXor = glslXor;
function glslPow() {
return glslBuiltinBinary('pow');
}
exports.glslPow = glslPow;
function glslPRelu() {
const name = 'prelu_';
const body = `
float ${name}(float a, float b) {
return a < 0.0 ? a * b: a;
}
vec4 ${name}(vec4 v1, vec4 v2) {
return vec4(
v1.r < 0.0 ? v1.r * v2.r: v1.r,
v1.g < 0.0 ? v1.g * v2.g: v1.g,
v1.b < 0.0 ? v1.b * v2.b: v1.b,
v1.a < 0.0 ? v1.a * v2.a: v1.a
);
}
`;
return { body, name, type: glsl_definitions_1.FunctionType.ValueBased };
}
exports.glslPRelu = glslPRelu;
function glslBuiltinBinary(fname) {
const name = `${fname}_`;
const body = `
float ${name}(float a, float b) {
return ${fname}(a, b);
}
vec4 ${name}(vec4 v1, vec4 v2) {
return ${fname}(v1, v2);
}
`;
return { body, name, type: glsl_definitions_1.FunctionType.ValueBased };
}
const createBinaryProgramInfoLoader = (handler, inputs, glslFunc, outputTensorType = inputs[0].type, cacheKey) => {
const textureType = handler.session.pack ? types_1.TextureType.packed : types_1.TextureType.unpacked;
return {
name: glslFunc.name,
inputNames: ['A', 'B'],
inputTypes: [textureType, textureType],
cacheHint: cacheKey,
get: () => createBinaryProgramInfo(handler, inputs, glslFunc, outputTensorType)
};
};
const createBinaryProgramInfo = (handler, inputs, glslFunc, outputTensorType = inputs[0].type) => {
const textureType = handler.session.pack ? types_1.TextureType.packed : types_1.TextureType.unpacked;
const isBroadcast = !util_1.ShapeUtil.areEqual(inputs[0].dims, inputs[1].dims);
let outputShape = inputs[0].dims;
const usePackedTexture = handler.session.pack;
if (isBroadcast) {
const calculatedShape = util_1.BroadcastUtil.calcShape(inputs[0].dims, inputs[1].dims, false);
if (!calculatedShape) {
throw new Error('Can\'t perform binary op on the given tensors');
}
outputShape = calculatedShape;
const outputRank = outputShape.length;
const aRank = inputs[0].dims.length !== 0 ? inputs[0].dims.length : 1;
const bRank = inputs[1].dims.length !== 0 ? inputs[1].dims.length : 1;
const aBcast = inputs[0].dims.length !== 0 ? 'bcastIndices_A(indices, aindices);' : 'aindices[0] = 0;';
const bBcast = inputs[1].dims.length !== 0 ? 'bcastIndices_B(indices, bindices);' : 'bindices[0] = 0;';
const glsl = (0, glsl_source_1.getGlsl)(handler.session.backend.glContext.version);
const shaderSource = usePackedTexture ? `
${glslFunc.body}
void main() {
vec4 a = getAAtOutCoords();
vec4 b = getBAtOutCoords();
vec4 result = ${glslFunc.name}(a, b);
${glsl.output} = result;
}` :
`
${glslFunc.body}
float process(int indices[${outputRank}]) {
int aindices[${aRank}];
int bindices[${bRank}];
${aBcast}
${bBcast}
return ${glslFunc.name}(_A(aindices), _B(bindices));
}`;
return {
name: glslFunc.name,
inputNames: ['A', 'B'],
inputTypes: [textureType, textureType],
output: { dims: outputShape, type: outputTensorType, textureType },
shaderSource,
hasMain: usePackedTexture
};
}
const glsl = (0, glsl_source_1.getGlsl)(handler.session.backend.glContext.version);
const shaderSource = `
${glslFunc.body}
void main() {
vec4 v1 = ${glsl.texture2D}(A, TexCoords);
vec4 v2 = ${glsl.texture2D}(B, TexCoords);
vec4 result = ${glslFunc.name}(v1, v2);
${glsl.output} = result;
}
`;
return {
name: glslFunc.name,
inputNames: ['A', 'B'],
inputTypes: [textureType, textureType],
output: { dims: inputs[0].dims, type: outputTensorType, textureType },
shaderSource,
hasMain: true
};
};
const add = (handler, inputs) => [handler.run(createBinaryProgramInfoLoader(handler, inputs, glslAdd()), inputs)];
exports.add = add;
const and = (handler, inputs) => [handler.run(createBinaryProgramInfoLoader(handler, inputs, glslAnd(), 'bool'), inputs)];
exports.and = and;
const div = (handler, inputs) => [handler.run(createBinaryProgramInfoLoader(handler, inputs, glslDiv()), inputs)];
exports.div = div;
const equal = (handler, inputs) => [handler.run(createBinaryProgramInfoLoader(handler, inputs, glslEqual(), 'bool'), inputs)];
exports.equal = equal;
const greater = (handler, inputs) => [handler.run(createBinaryProgramInfoLoader(handler, inputs, glslGreater(), 'bool'), inputs)];
exports.greater = greater;
const less = (handler, inputs) => [handler.run(createBinaryProgramInfoLoader(handler, inputs, glslLess(), 'bool'), inputs)];
exports.less = less;
const mul = (handler, inputs) => [handler.run(createBinaryProgramInfoLoader(handler, inputs, glslMul()), inputs)];
exports.mul = mul;
const or = (handler, inputs) => [handler.run(createBinaryProgramInfoLoader(handler, inputs, glslOr(), 'bool'), inputs)];
exports.or = or;
const pow = (handler, inputs) => [handler.run(createBinaryProgramInfoLoader(handler, inputs, glslPow()), inputs)];
exports.pow = pow;
const pRelu = (handler, inputs) => [handler.run(createBinaryProgramInfoLoader(handler, inputs, glslPRelu()), inputs)];
exports.pRelu = pRelu;
const sub = (handler, inputs) => [handler.run(createBinaryProgramInfoLoader(handler, inputs, glslSub()), inputs)];
exports.sub = sub;
const xor = (handler, inputs) => [handler.run(createBinaryProgramInfoLoader(handler, inputs, glslXor(), 'bool'), inputs)];
exports.xor = xor;
//# sourceMappingURL=binary-op.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,303 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
import {Tensor} from '../../../tensor';
import {BroadcastUtil, ShapeUtil} from '../../../util';
import {FunctionType, GlslValueFunction} from '../glsl-definitions';
import {getGlsl} from '../glsl-source';
import {WebGLInferenceHandler} from '../inference-handler';
import {ProgramInfo, ProgramInfoLoader, TextureType} from '../types';
export function glslAdd(): GlslValueFunction {
const name = 'add_';
const body = `
float ${name}(float a, float b) {
return a + b;
}
vec4 ${name}(vec4 v1, vec4 v2) {
return v1 + v2;
}
`;
return {body, name, type: FunctionType.ValueBased};
}
export function glslDiv(): GlslValueFunction {
const name = 'div_';
const body = `
float ${name}(float a, float b) {
return a / b;
}
vec4 ${name}(vec4 v1, vec4 v2) {
return v1 / v2;
}
`;
return {body, name, type: FunctionType.ValueBased};
}
export function glslMul(): GlslValueFunction {
const name = 'mul_';
const body = `
float ${name}(float a, float b) {
return a * b;
}
vec4 ${name}(vec4 v1, vec4 v2) {
return v1 * v2;
}
`;
return {body, name, type: FunctionType.ValueBased};
}
export function glslSub(): GlslValueFunction {
const name = 'sub_';
const body = `
float ${name}(float a, float b) {
return a - b;
}
vec4 ${name}(vec4 v1, vec4 v2) {
return v1 - v2;
}
`;
return {body, name, type: FunctionType.ValueBased};
}
export function glslEqual(): GlslValueFunction {
const name = 'equal_';
const body = `
float ${name}(float a, float b) {
return float(a == b);
}
vec4 ${name}(vec4 v1, vec4 v2) {
return vec4(equal(v1, v2));
}
`;
return {body, name, type: FunctionType.ValueBased};
}
export function glslGreater(): GlslValueFunction {
const name = 'greater_';
const body = `
float ${name}(float a, float b) {
return float(a > b);
}
vec4 ${name}(vec4 v1, vec4 v2) {
return vec4( v1.r > v2.r ,
v1.g > v2.g,
v1.b > v2.b,
v1.a > v2.a );
}
`;
return {body, name, type: FunctionType.ValueBased};
}
export function glslLess(): GlslValueFunction {
const name = 'less_';
const body = `
float ${name}(float a, float b) {
return float(a < b);
}
vec4 ${name}(vec4 v1, vec4 v2) {
return vec4( v1.r < v2.r ,
v1.g < v2.g,
v1.b < v2.b,
v1.a < v2.a );
}
`;
return {body, name, type: FunctionType.ValueBased};
}
export function glslAnd(): GlslValueFunction {
const name = 'and_';
const body = `
float ${name}(float a, float b) {
return float( bool(a) && bool(b) );
}
vec4 ${name}(vec4 v1, vec4 v2) {
bvec4 b1 = bvec4(v1);
bvec4 b2 = bvec4(v2);
return vec4( b1.r && b2.r ,
b1.g && b2.g,
b1.b && b2.b,
b1.a && b2.a );
}
`;
return {body, name, type: FunctionType.ValueBased};
}
export function glslOr(): GlslValueFunction {
const name = 'or_';
const body = `
float ${name}(float a, float b) {
return float( bool(a) || bool(b) );
}
vec4 ${name}(vec4 v1, vec4 v2) {
bvec4 b1 = bvec4(v1);
bvec4 b2 = bvec4(v2);
return vec4( b1.r || b2.r ,
b1.g || b2.g,
b1.b || b2.b,
b1.a || b2.a );
}
`;
return {body, name, type: FunctionType.ValueBased};
}
export function glslXor(): GlslValueFunction {
const name = 'xor_';
const body = `
float ${name}(float a, float b) {
return float( bool(a) ^^ bool(b) );
}
vec4 ${name}(vec4 v1, vec4 v2) {
bvec4 b1 = bvec4(v1);
bvec4 b2 = bvec4(v2);
return vec4( b1.r ^^ b2.r ,
b1.g ^^ b2.g,
b1.b ^^ b2.b,
b1.a ^^ b2.a );
}
`;
return {body, name, type: FunctionType.ValueBased};
}
export function glslPow(): GlslValueFunction {
return glslBuiltinBinary('pow');
}
export function glslPRelu(): GlslValueFunction {
const name = 'prelu_';
const body = `
float ${name}(float a, float b) {
return a < 0.0 ? a * b: a;
}
vec4 ${name}(vec4 v1, vec4 v2) {
return vec4(
v1.r < 0.0 ? v1.r * v2.r: v1.r,
v1.g < 0.0 ? v1.g * v2.g: v1.g,
v1.b < 0.0 ? v1.b * v2.b: v1.b,
v1.a < 0.0 ? v1.a * v2.a: v1.a
);
}
`;
return {body, name, type: FunctionType.ValueBased};
}
function glslBuiltinBinary(fname: string): GlslValueFunction {
const name = `${fname}_`;
const body = `
float ${name}(float a, float b) {
return ${fname}(a, b);
}
vec4 ${name}(vec4 v1, vec4 v2) {
return ${fname}(v1, v2);
}
`;
return {body, name, type: FunctionType.ValueBased};
}
const createBinaryProgramInfoLoader =
(handler: WebGLInferenceHandler, inputs: Tensor[], glslFunc: GlslValueFunction,
outputTensorType: Tensor.DataType = inputs[0].type, cacheKey?: string): ProgramInfoLoader => {
const textureType = handler.session.pack ? TextureType.packed : TextureType.unpacked;
return {
name: glslFunc.name,
inputNames: ['A', 'B'],
inputTypes: [textureType, textureType],
cacheHint: cacheKey,
get: () => createBinaryProgramInfo(handler, inputs, glslFunc, outputTensorType)
};
};
const createBinaryProgramInfo =
(handler: WebGLInferenceHandler, inputs: Tensor[], glslFunc: GlslValueFunction,
outputTensorType: Tensor.DataType = inputs[0].type): ProgramInfo => {
const textureType = handler.session.pack ? TextureType.packed : TextureType.unpacked;
const isBroadcast = !ShapeUtil.areEqual(inputs[0].dims, inputs[1].dims);
let outputShape = inputs[0].dims;
const usePackedTexture = handler.session.pack;
if (isBroadcast) {
const calculatedShape = BroadcastUtil.calcShape(inputs[0].dims, inputs[1].dims, false);
if (!calculatedShape) {
throw new Error('Can\'t perform binary op on the given tensors');
}
outputShape = calculatedShape;
const outputRank = outputShape.length;
const aRank = inputs[0].dims.length !== 0 ? inputs[0].dims.length : 1;
const bRank = inputs[1].dims.length !== 0 ? inputs[1].dims.length : 1;
const aBcast = inputs[0].dims.length !== 0 ? 'bcastIndices_A(indices, aindices);' : 'aindices[0] = 0;';
const bBcast = inputs[1].dims.length !== 0 ? 'bcastIndices_B(indices, bindices);' : 'bindices[0] = 0;';
const glsl = getGlsl(handler.session.backend.glContext.version);
const shaderSource = usePackedTexture ? `
${glslFunc.body}
void main() {
vec4 a = getAAtOutCoords();
vec4 b = getBAtOutCoords();
vec4 result = ${glslFunc.name}(a, b);
${glsl.output} = result;
}` :
`
${glslFunc.body}
float process(int indices[${outputRank}]) {
int aindices[${aRank}];
int bindices[${bRank}];
${aBcast}
${bBcast}
return ${glslFunc.name}(_A(aindices), _B(bindices));
}`;
return {
name: glslFunc.name,
inputNames: ['A', 'B'],
inputTypes: [textureType, textureType],
output: {dims: outputShape, type: outputTensorType, textureType},
shaderSource,
hasMain: usePackedTexture
};
}
const glsl = getGlsl(handler.session.backend.glContext.version);
const shaderSource = `
${glslFunc.body}
void main() {
vec4 v1 = ${glsl.texture2D}(A, TexCoords);
vec4 v2 = ${glsl.texture2D}(B, TexCoords);
vec4 result = ${glslFunc.name}(v1, v2);
${glsl.output} = result;
}
`;
return {
name: glslFunc.name,
inputNames: ['A', 'B'],
inputTypes: [textureType, textureType],
output: {dims: inputs[0].dims, type: outputTensorType, textureType},
shaderSource,
hasMain: true
};
};
export const add = (handler: WebGLInferenceHandler, inputs: Tensor[]):
Tensor[] => [handler.run(createBinaryProgramInfoLoader(handler, inputs, glslAdd()), inputs)];
export const and = (handler: WebGLInferenceHandler, inputs: Tensor[]):
Tensor[] => [handler.run(createBinaryProgramInfoLoader(handler, inputs, glslAnd(), 'bool'), inputs)];
export const div = (handler: WebGLInferenceHandler, inputs: Tensor[]):
Tensor[] => [handler.run(createBinaryProgramInfoLoader(handler, inputs, glslDiv()), inputs)];
export const equal = (handler: WebGLInferenceHandler, inputs: Tensor[]):
Tensor[] => [handler.run(createBinaryProgramInfoLoader(handler, inputs, glslEqual(), 'bool'), inputs)];
export const greater = (handler: WebGLInferenceHandler, inputs: Tensor[]):
Tensor[] => [handler.run(createBinaryProgramInfoLoader(handler, inputs, glslGreater(), 'bool'), inputs)];
export const less = (handler: WebGLInferenceHandler, inputs: Tensor[]):
Tensor[] => [handler.run(createBinaryProgramInfoLoader(handler, inputs, glslLess(), 'bool'), inputs)];
export const mul = (handler: WebGLInferenceHandler, inputs: Tensor[]):
Tensor[] => [handler.run(createBinaryProgramInfoLoader(handler, inputs, glslMul()), inputs)];
export const or = (handler: WebGLInferenceHandler, inputs: Tensor[]):
Tensor[] => [handler.run(createBinaryProgramInfoLoader(handler, inputs, glslOr(), 'bool'), inputs)];
export const pow = (handler: WebGLInferenceHandler, inputs: Tensor[]):
Tensor[] => [handler.run(createBinaryProgramInfoLoader(handler, inputs, glslPow()), inputs)];
export const pRelu = (handler: WebGLInferenceHandler, inputs: Tensor[]):
Tensor[] => [handler.run(createBinaryProgramInfoLoader(handler, inputs, glslPRelu()), inputs)];
export const sub = (handler: WebGLInferenceHandler, inputs: Tensor[]):
Tensor[] => [handler.run(createBinaryProgramInfoLoader(handler, inputs, glslSub()), inputs)];
export const xor = (handler: WebGLInferenceHandler, inputs: Tensor[]):
Tensor[] => [handler.run(createBinaryProgramInfoLoader(handler, inputs, glslXor(), 'bool'), inputs)];

View File

@@ -0,0 +1,22 @@
"use strict";
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseCastAttributes = exports.cast = void 0;
const util_1 = require("../../../util");
const cast = (handler, inputs, to) => {
validateInputs(inputs);
return [handler.cast(inputs[0], to)];
};
exports.cast = cast;
const parseCastAttributes = (node) => util_1.ProtoUtil.tensorDataTypeFromProto(node.attributes.getInt('to'));
exports.parseCastAttributes = parseCastAttributes;
const validateInputs = (inputs) => {
if (!inputs || inputs.length !== 1) {
throw new Error('Cast requires 1 input.');
}
if (inputs[0].type === 'string') {
throw new Error('Invalid input type.');
}
};
//# sourceMappingURL=cast.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"cast.js","sourceRoot":"","sources":["cast.ts"],"names":[],"mappings":";AAAA,4DAA4D;AAC5D,kCAAkC;;;AAKlC,wCAAwC;AAGjC,MAAM,IAAI,GACb,CAAC,OAA8B,EAAE,MAAgB,EAAE,EAAmB,EAAY,EAAE;IAClF,cAAc,CAAC,MAAM,CAAC,CAAC;IACvB,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;AACvC,CAAC,CAAC;AAJO,QAAA,IAAI,QAIX;AAEC,MAAM,mBAAmB,GAA4C,CAAC,IAAgB,EAAmB,EAAE,CAC9G,gBAAS,CAAC,uBAAuB,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;AADvD,QAAA,mBAAmB,uBACoC;AAEpE,MAAM,cAAc,GAAG,CAAC,MAAgB,EAAQ,EAAE;IAChD,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE;QAClC,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC;KAC3C;IAED,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,QAAQ,EAAE;QAC/B,MAAM,IAAI,KAAK,CAAC,qBAAqB,CAAC,CAAC;KACxC;AACH,CAAC,CAAC"}

View File

@@ -0,0 +1,27 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
import {Graph} from '../../../graph';
import {OperatorImplementation, OperatorInitialization} from '../../../operators';
import {Tensor} from '../../../tensor';
import {ProtoUtil} from '../../../util';
import {WebGLInferenceHandler} from '../inference-handler';
export const cast: OperatorImplementation<Tensor.DataType> =
(handler: WebGLInferenceHandler, inputs: Tensor[], to: Tensor.DataType): Tensor[] => {
validateInputs(inputs);
return [handler.cast(inputs[0], to)];
};
export const parseCastAttributes: OperatorInitialization<Tensor.DataType> = (node: Graph.Node): Tensor.DataType =>
ProtoUtil.tensorDataTypeFromProto(node.attributes.getInt('to'));
const validateInputs = (inputs: Tensor[]): void => {
if (!inputs || inputs.length !== 1) {
throw new Error('Cast requires 1 input.');
}
if (inputs[0].type === 'string') {
throw new Error('Invalid input type.');
}
};

View File

@@ -0,0 +1,125 @@
"use strict";
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
Object.defineProperty(exports, "__esModule", { value: true });
exports.createPackedConcatProgramInfoLoader = void 0;
const glsl_source_1 = require("../glsl-source");
const types_1 = require("../types");
const utils_1 = require("../utils");
const packing_utils_1 = require("./packing-utils");
const createPackedConcatProgramMetadata = (inputCount, cacheHint) => ({
name: 'Concat (packed)',
inputNames: Array.from({ length: inputCount }, (v, i) => `X${i}`),
inputTypes: Array(inputCount).fill(types_1.TextureType.packed),
cacheHint
});
const createPackedConcatProgramInfo = (handler, metadata, inputs, axis) => {
const inputShape = inputs[0].dims.slice();
if (axis >= inputShape.length || axis < (-1 * inputShape.length)) {
throw new Error('axis specified for concat doesn\'t match input dimensionality');
}
if (axis < 0) {
axis = inputShape.length + axis;
}
// ensure all of the non-concatenated axes match each other
// calculate the shape of the output tensor while we do that
const outputShape = inputShape.slice(0);
for (let i = 1; i < inputs.length; i++) {
const dataNShape = inputs[i].dims.slice();
for (let axisIndex = 0; axisIndex < inputShape.length; axisIndex++) {
// add to the placeholder for computing output shape
if (axisIndex === axis) {
outputShape[axis] += dataNShape[axisIndex];
}
// ensure all non-cancatenated axes match each other
else if (inputShape[axisIndex] !== dataNShape[axisIndex]) {
throw new Error('non concat dimensions must match');
}
}
}
const rank = outputShape.length;
const coords = (0, packing_utils_1.getChannels)('coords', rank);
const dtype = (0, utils_1.getCoordsDataType)(rank);
const unpackChannel = (0, packing_utils_1.unpackFromChannel)();
const shapes = inputs.map(i => i.dims);
const channels = (0, utils_1.getGlChannels)(rank);
const offsets = new Array(shapes.length - 1);
offsets[0] = shapes[0][axis];
for (let i = 1; i < offsets.length; i++) {
offsets[i] = offsets[i - 1] + shapes[i][axis];
}
const channel = channels[axis];
const lastChannels = channels.slice(-2);
const allChannels = channels.join();
let getValueSnippet = `if (${channel} < ${offsets[0]}) {
return getChannel(
getX0(${allChannels}), vec2(${lastChannels.join()}));
}`;
for (let i = 1; i < offsets.length; i++) {
const shift = offsets[i - 1];
getValueSnippet += `
if (${channel} < ${offsets[i]} && ${channel} >= ${offsets[i - 1]}) {
return getChannel(
getX${i}(${getShiftedChannelsSnippet(channels, channel, shift)}),
vec2(${getShiftedChannelsSnippet(lastChannels, channel, shift)}));
}`;
}
const lastIndex = offsets.length;
const shift = offsets[offsets.length - 1];
getValueSnippet += `
return getChannel(
getX${lastIndex}(${getShiftedChannelsSnippet(channels, channel, shift)}),
vec2(${getShiftedChannelsSnippet(lastChannels, channel, shift)}));`;
const glsl = (0, glsl_source_1.getGlsl)(handler.session.backend.glContext.version);
const shaderSource = `
${unpackChannel}
float getValue(${channels.map(x => 'int ' + x)}) {
${getValueSnippet}
}
void main() {
${dtype} coords = getOutputCoords();
int lastDim = coords.${channels[rank - 1]};
coords.${channels[rank - 1]} = coords.${channels[rank - 2]};
coords.${channels[rank - 2]} = lastDim;
vec4 result = vec4(getValue(${coords}), 0., 0., 0.);
${coords[rank - 1]} = ${coords[rank - 1]} + 1;
if (${coords[rank - 1]} < ${outputShape[rank - 1]}) {
result.g = getValue(${coords});
}
${coords[rank - 2]} = ${coords[rank - 2]} + 1;
if (${coords[rank - 2]} < ${outputShape[rank - 2]}) {
result.a = getValue(${coords});
}
${coords[rank - 1]} = ${coords[rank - 1]} - 1;
if (${coords[rank - 2]} < ${outputShape[rank - 2]} &&
${coords[rank - 1]} < ${outputShape[rank - 1]}) {
result.b = getValue(${coords});
}
${glsl.output} = result;
}
`;
return Object.assign(Object.assign({}, metadata), { output: { dims: outputShape, type: inputs[0].type, textureType: types_1.TextureType.packed }, shaderSource, hasMain: true });
};
const createPackedConcatProgramInfoLoader = (handler, inputs, attributes) => {
const metadata = createPackedConcatProgramMetadata(inputs.length, attributes.cacheKey);
return Object.assign(Object.assign({}, metadata), { get: () => createPackedConcatProgramInfo(handler, metadata, inputs, attributes.axis) });
};
exports.createPackedConcatProgramInfoLoader = createPackedConcatProgramInfoLoader;
const getShiftedChannelsSnippet = (channels, channel, shift) => {
const channelIdx = channels.indexOf(channel);
const res = channels.map((c, idx) => {
if (idx === channelIdx) {
return `${c} - ${shift}`;
}
else {
return c;
}
});
return res.join();
};
//# sourceMappingURL=concat-packed.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"concat-packed.js","sourceRoot":"","sources":["concat-packed.ts"],"names":[],"mappings":";AAAA,4DAA4D;AAC5D,kCAAkC;;;AAGlC,gDAAuC;AAEvC,oCAAsF;AACtF,oCAA0D;AAG1D,mDAA+D;AAE/D,MAAM,iCAAiC,GAAG,CAAC,UAAkB,EAAE,SAAiB,EAAE,EAAE,CAAC,CAAC;IACpF,IAAI,EAAE,iBAAiB;IACvB,UAAU,EAAE,KAAK,CAAC,IAAI,CAAC,EAAC,MAAM,EAAE,UAAU,EAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;IAC/D,UAAU,EAAE,KAAK,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,mBAAW,CAAC,MAAM,CAAC;IACtD,SAAS;CACV,CAAC,CAAC;AAEH,MAAM,6BAA6B,GAC/B,CAAC,OAA8B,EAAE,QAAyB,EAAE,MAAgB,EAAE,IAAY,EAAe,EAAE;IACzG,MAAM,UAAU,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;IAC1C,IAAI,IAAI,IAAI,UAAU,CAAC,MAAM,IAAI,IAAI,GAAG,CAAC,CAAC,CAAC,GAAG,UAAU,CAAC,MAAM,CAAC,EAAE;QAChE,MAAM,IAAI,KAAK,CAAC,+DAA+D,CAAC,CAAC;KAClF;IACD,IAAI,IAAI,GAAG,CAAC,EAAE;QACZ,IAAI,GAAG,UAAU,CAAC,MAAM,GAAG,IAAI,CAAC;KACjC;IACD,2DAA2D;IAC3D,4DAA4D;IAC5D,MAAM,WAAW,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACxC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;QACtC,MAAM,UAAU,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;QAC1C,KAAK,IAAI,SAAS,GAAG,CAAC,EAAE,SAAS,GAAG,UAAU,CAAC,MAAM,EAAE,SAAS,EAAE,EAAE;YAClE,oDAAoD;YACpD,IAAI,SAAS,KAAK,IAAI,EAAE;gBACtB,WAAW,CAAC,IAAI,CAAC,IAAI,UAAU,CAAC,SAAS,CAAC,CAAC;aAC5C;YACD,oDAAoD;iBAC/C,IAAI,UAAU,CAAC,SAAS,CAAC,KAAK,UAAU,CAAC,SAAS,CAAC,EAAE;gBACxD,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;aACrD;SACF;KACF;IAED,MAAM,IAAI,GAAG,WAAW,CAAC,MAAM,CAAC;IAChC,MAAM,MAAM,GAAG,IAAA,2BAAW,EAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;IAC3C,MAAM,KAAK,GAAG,IAAA,yBAAiB,EAAC,IAAI,CAAC,CAAC;IACtC,MAAM,aAAa,GAAG,IAAA,iCAAiB,GAAE,CAAC;IAE1C,MAAM,MAAM,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IACvC,MAAM,QAAQ,GAAG,IAAA,qBAAa,EAAC,IAAI,CAAC,CAAC;IACrC,MAAM,OAAO,GAAa,IAAI,KAAK,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAEvD,OAAO,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IAC7B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;QACvC,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;KAC/C;IAED,MAAM,OAAO,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;IAC/B,MAAM,YAAY,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IACxC,MAAM,WAAW,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC;IAEpC,IAAI,eAAe,GAAG,OAAO,OAAO,MAAM,OAAO,CAAC,CAAC,CAAC;;oBAEtC,WAAW,WAAW,YAAY,CAAC,IAAI,EAAE;UACnD,CAAC;IACL,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;QACvC,MAAM,KAAK,GAAG,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QAC7B,eAAe,IAAI;kBACT,OAAO,MAAM,OAAO,CAAC,CAAC,CAAC,QAAQ,OAAO,OAAO,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC;;sBAEvD,CAAC,IAAI,yBAAyB,CAAC,QAAQ,EAAE,OAAO,EAAE,KAAK,CAAC;uBACvD,yBAAyB,CAAC,YAAY,EAAE,OAAO,EAAE,KAAK,CAAC;cAChE,CAAC;KACR;IACD,MAAM,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC;IACjC,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAC1C,eAAe,IAAI;;oBAEL,SAAS,IAAI,yBAAyB,CAAC,QAAQ,EAAE,OAAO,EAAE,KAAK,CAAC;qBAC/D,yBAAyB,CAAC,YAAY,EAAE,OAAO,EAAE,KAAK,CAAC,KAAK,CAAC;IAE5E,MAAM,IAAI,GAAG,IAAA,qBAAO,EAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;IAEhE,MAAM,YAAY,GAAG;YACf,aAAa;2BACE,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC;cAC1C,eAAe;;;;cAIf,KAAK;mCACgB,QAAQ,CAAC,IAAI,GAAG,CAAC,CAAC;qBAChC,QAAQ,CAAC,IAAI,GAAG,CAAC,CAAC,aAAa,QAAQ,CAAC,IAAI,GAAG,CAAC,CAAC;qBACjD,QAAQ,CAAC,IAAI,GAAG,CAAC,CAAC;;0CAEG,MAAM;;cAElC,MAAM,CAAC,IAAI,GAAG,CAAC,CAAC,MAAM,MAAM,CAAC,IAAI,GAAG,CAAC,CAAC;kBAClC,MAAM,CAAC,IAAI,GAAG,CAAC,CAAC,MAAM,WAAW,CAAC,IAAI,GAAG,CAAC,CAAC;oCACzB,MAAM;;;cAG5B,MAAM,CAAC,IAAI,GAAG,CAAC,CAAC,MAAM,MAAM,CAAC,IAAI,GAAG,CAAC,CAAC;kBAClC,MAAM,CAAC,IAAI,GAAG,CAAC,CAAC,MAAM,WAAW,CAAC,IAAI,GAAG,CAAC,CAAC;oCACzB,MAAM;;;cAG5B,MAAM,CAAC,IAAI,GAAG,CAAC,CAAC,MAAM,MAAM,CAAC,IAAI,GAAG,CAAC,CAAC;kBAClC,MAAM,CAAC,IAAI,GAAG,CAAC,CAAC,MAAM,WAAW,CAAC,IAAI,GAAG,CAAC,CAAC;kBAC3C,MAAM,CAAC,IAAI,GAAG,CAAC,CAAC,MAAM,WAAW,CAAC,IAAI,GAAG,CAAC,CAAC;oCACzB,MAAM;;cAE5B,IAAI,CAAC,MAAM;;SAEhB,CAAC;IAEJ,uCACK,QAAQ,KACX,MAAM,EAAE,EAAC,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,WAAW,EAAE,mBAAW,CAAC,MAAM,EAAC,EAClF,YAAY,EACZ,OAAO,EAAE,IAAI,IACb;AACJ,CAAC,CAAC;AAEC,MAAM,mCAAmC,GAC5C,CAAC,OAA8B,EAAE,MAAgB,EAAE,UAA4B,EAAqB,EAAE;IACpG,MAAM,QAAQ,GAAG,iCAAiC,CAAC,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,QAAQ,CAAC,CAAC;IACvF,uCAAW,QAAQ,KAAE,GAAG,EAAE,GAAG,EAAE,CAAC,6BAA6B,CAAC,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,CAAC,IAAI,CAAC,IAAE;AAC7G,CAAC,CAAC;AAJO,QAAA,mCAAmC,uCAI1C;AAEN,MAAM,yBAAyB,GAAG,CAAC,QAAkB,EAAE,OAAe,EAAE,KAAa,EAAU,EAAE;IAC/F,MAAM,UAAU,GAAG,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IAC7C,MAAM,GAAG,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,EAAE;QAClC,IAAI,GAAG,KAAK,UAAU,EAAE;YACtB,OAAO,GAAG,CAAC,MAAM,KAAK,EAAE,CAAC;SAC1B;aAAM;YACL,OAAO,CAAC,CAAC;SACV;IACH,CAAC,CAAC,CAAC;IACH,OAAO,GAAG,CAAC,IAAI,EAAE,CAAC;AACpB,CAAC,CAAC"}

View File

@@ -0,0 +1,143 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
import {Tensor} from '../../../tensor';
import {getGlsl} from '../glsl-source';
import {WebGLInferenceHandler} from '../inference-handler';
import {ProgramInfo, ProgramInfoLoader, ProgramMetadata, TextureType} from '../types';
import {getCoordsDataType, getGlChannels} from '../utils';
import {ConcatAttributes} from './concat';
import {getChannels, unpackFromChannel} from './packing-utils';
const createPackedConcatProgramMetadata = (inputCount: number, cacheHint: string) => ({
name: 'Concat (packed)',
inputNames: Array.from({length: inputCount}, (v, i) => `X${i}`),
inputTypes: Array(inputCount).fill(TextureType.packed),
cacheHint
});
const createPackedConcatProgramInfo =
(handler: WebGLInferenceHandler, metadata: ProgramMetadata, inputs: Tensor[], axis: number): ProgramInfo => {
const inputShape = inputs[0].dims.slice();
if (axis >= inputShape.length || axis < (-1 * inputShape.length)) {
throw new Error('axis specified for concat doesn\'t match input dimensionality');
}
if (axis < 0) {
axis = inputShape.length + axis;
}
// ensure all of the non-concatenated axes match each other
// calculate the shape of the output tensor while we do that
const outputShape = inputShape.slice(0);
for (let i = 1; i < inputs.length; i++) {
const dataNShape = inputs[i].dims.slice();
for (let axisIndex = 0; axisIndex < inputShape.length; axisIndex++) {
// add to the placeholder for computing output shape
if (axisIndex === axis) {
outputShape[axis] += dataNShape[axisIndex];
}
// ensure all non-cancatenated axes match each other
else if (inputShape[axisIndex] !== dataNShape[axisIndex]) {
throw new Error('non concat dimensions must match');
}
}
}
const rank = outputShape.length;
const coords = getChannels('coords', rank);
const dtype = getCoordsDataType(rank);
const unpackChannel = unpackFromChannel();
const shapes = inputs.map(i => i.dims);
const channels = getGlChannels(rank);
const offsets: number[] = new Array(shapes.length - 1);
offsets[0] = shapes[0][axis];
for (let i = 1; i < offsets.length; i++) {
offsets[i] = offsets[i - 1] + shapes[i][axis];
}
const channel = channels[axis];
const lastChannels = channels.slice(-2);
const allChannels = channels.join();
let getValueSnippet = `if (${channel} < ${offsets[0]}) {
return getChannel(
getX0(${allChannels}), vec2(${lastChannels.join()}));
}`;
for (let i = 1; i < offsets.length; i++) {
const shift = offsets[i - 1];
getValueSnippet += `
if (${channel} < ${offsets[i]} && ${channel} >= ${offsets[i - 1]}) {
return getChannel(
getX${i}(${getShiftedChannelsSnippet(channels, channel, shift)}),
vec2(${getShiftedChannelsSnippet(lastChannels, channel, shift)}));
}`;
}
const lastIndex = offsets.length;
const shift = offsets[offsets.length - 1];
getValueSnippet += `
return getChannel(
getX${lastIndex}(${getShiftedChannelsSnippet(channels, channel, shift)}),
vec2(${getShiftedChannelsSnippet(lastChannels, channel, shift)}));`;
const glsl = getGlsl(handler.session.backend.glContext.version);
const shaderSource = `
${unpackChannel}
float getValue(${channels.map(x => 'int ' + x)}) {
${getValueSnippet}
}
void main() {
${dtype} coords = getOutputCoords();
int lastDim = coords.${channels[rank - 1]};
coords.${channels[rank - 1]} = coords.${channels[rank - 2]};
coords.${channels[rank - 2]} = lastDim;
vec4 result = vec4(getValue(${coords}), 0., 0., 0.);
${coords[rank - 1]} = ${coords[rank - 1]} + 1;
if (${coords[rank - 1]} < ${outputShape[rank - 1]}) {
result.g = getValue(${coords});
}
${coords[rank - 2]} = ${coords[rank - 2]} + 1;
if (${coords[rank - 2]} < ${outputShape[rank - 2]}) {
result.a = getValue(${coords});
}
${coords[rank - 1]} = ${coords[rank - 1]} - 1;
if (${coords[rank - 2]} < ${outputShape[rank - 2]} &&
${coords[rank - 1]} < ${outputShape[rank - 1]}) {
result.b = getValue(${coords});
}
${glsl.output} = result;
}
`;
return {
...metadata,
output: {dims: outputShape, type: inputs[0].type, textureType: TextureType.packed},
shaderSource,
hasMain: true,
};
};
export const createPackedConcatProgramInfoLoader =
(handler: WebGLInferenceHandler, inputs: Tensor[], attributes: ConcatAttributes): ProgramInfoLoader => {
const metadata = createPackedConcatProgramMetadata(inputs.length, attributes.cacheKey);
return {...metadata, get: () => createPackedConcatProgramInfo(handler, metadata, inputs, attributes.axis)};
};
const getShiftedChannelsSnippet = (channels: string[], channel: string, shift: number): string => {
const channelIdx = channels.indexOf(channel);
const res = channels.map((c, idx) => {
if (idx === channelIdx) {
return `${c} - ${shift}`;
} else {
return c;
}
});
return res.join();
};

View File

@@ -0,0 +1,159 @@
"use strict";
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseConcatAttributes = exports.concat = void 0;
const attribute_with_cache_key_1 = require("../../../attribute-with-cache-key");
const types_1 = require("../types");
const concat_packed_1 = require("./concat-packed");
const concat = (inferenceHandler, inputs, attributes) => {
validateInputs(inputs);
if (inferenceHandler.session.pack && inputs[0].dims.length > 1) {
const output = inferenceHandler.run((0, concat_packed_1.createPackedConcatProgramInfoLoader)(inferenceHandler, inputs, attributes), inputs);
return [output];
}
else {
const output = inferenceHandler.run(createUnpackedConcatProgramInfoLoader(inferenceHandler, inputs, attributes), inputs);
return [output];
}
};
exports.concat = concat;
const createUnpackedConcatProgramMetadata = (inputCount, cacheHint) => ({
name: 'Concat',
inputNames: Array.from({ length: inputCount }, (v, i) => `X${i}`),
inputTypes: Array(inputCount).fill(types_1.TextureType.unpacked),
cacheHint
});
const createUnpackedConcatProgramInfo = (handler, metadata, inputs, axis) => {
const inputShape = inputs[0].dims.slice();
if (axis >= inputShape.length || axis < (-1 * inputShape.length)) {
throw new Error('axis specified for concat doesn\'t match input dimensionality');
}
if (axis < 0) {
axis = inputShape.length + axis;
}
// ensure all of the non-concatenated axes match each other
// calculate the shape of the output tensor while we do that
const outputShape = inputShape.slice(0);
for (let i = 1; i < inputs.length; i++) {
const dataNShape = inputs[i].dims.slice();
for (let axisIndex = 0; axisIndex < inputShape.length; axisIndex++) {
// add to the placeholder for computing output shape
if (axisIndex === axis) {
outputShape[axis] += dataNShape[axisIndex];
}
// ensure all non-cancatenated axes match each other
else if (inputShape[axisIndex] !== dataNShape[axisIndex]) {
throw new Error('non concat dimensions must match');
}
}
}
const rank = outputShape.length;
const sizeInConcatAxis = new Array(inputs.length);
let previousSum = 0;
for (let i = 0; i < sizeInConcatAxis.length; ++i) {
previousSum += inputs[i].dims[axis];
sizeInConcatAxis[i] = previousSum;
}
let getTextureIndexWhereDataResidesMethod = '';
// in most cases linear search is sufficient, as in most scenarios, only 2 tensors are concatenated
if (inputs.length < 5) {
getTextureIndexWhereDataResidesMethod = getTextureIndexWhereDataResidesLinearSearch(sizeInConcatAxis);
}
else {
getTextureIndexWhereDataResidesMethod = getTextureIndexWhereDataResidesBinarySearch(sizeInConcatAxis);
}
const fetchDataFromCorrectTextureMethod = getFetchDataFromCorrectTextureMethod(inputs.length, rank);
const getSizeInConcatAxisValueFromIndexMethod = getGetSizeInConcatAxisValueFromIndexMethod(sizeInConcatAxis);
const shaderSource = `
${fetchDataFromCorrectTextureMethod}
${getSizeInConcatAxisValueFromIndexMethod}
${getTextureIndexWhereDataResidesMethod}
float process(int indices[${rank}]) {
int textureIndex = getTextureWhereDataResides (indices[${axis}]);
if(textureIndex != 0) {
indices[${axis}] = indices[${axis}] - int(getSizeInConcatAxisValueFromIndex(textureIndex-int(1)));
}
return fetchDataFromCorrectTexture(textureIndex, indices);
}`;
return Object.assign(Object.assign({}, metadata), { output: { dims: outputShape, type: inputs[0].type, textureType: types_1.TextureType.unpacked }, shaderSource });
};
const createUnpackedConcatProgramInfoLoader = (handler, inputs, attributes) => {
const metadata = createUnpackedConcatProgramMetadata(inputs.length, attributes.cacheKey);
return Object.assign(Object.assign({}, metadata), { get: () => createUnpackedConcatProgramInfo(handler, metadata, inputs, attributes.axis) });
};
const getTextureIndexWhereDataResidesLinearSearch = (sizeInConcatAxis) => {
const searchAxis = sizeInConcatAxis.map((size, i) => `if(index<${size}) {return ${i};}
`);
return `int getTextureWhereDataResides(int index) {
${searchAxis.join('')}
}`;
};
// TODO: Implement BinarySearch in GLSL
const getTextureIndexWhereDataResidesBinarySearch = (sizeInConcatAxis) => getTextureIndexWhereDataResidesLinearSearch(sizeInConcatAxis);
const getFetchDataFromCorrectTextureMethod = (numberOfTensors, tensorRank) => {
const codeLines = [`float fetchDataFromCorrectTexture(int textureIndex, int indices[${tensorRank}]) {`];
for (let i = 0; i < numberOfTensors; ++i) {
if (i === 0) {
codeLines.push('\t' +
`if (textureIndex == ${i}) { return _X${i}(indices); }`);
}
else if (i === numberOfTensors - 1) {
codeLines.push('\t' +
`else { return _X${i}(indices); }`);
}
else {
codeLines.push('\t' +
`else if (textureIndex == ${i}) { return _X${i}(indices); }`);
}
}
codeLines.push('\t' +
'}');
return codeLines.join('\n');
};
const getGetSizeInConcatAxisValueFromIndexMethod = (sizeInConcatAxis) => {
const codeLines = ['int getSizeInConcatAxisValueFromIndex(int index) {'];
for (let i = 0; i < sizeInConcatAxis.length; ++i) {
if (i === 0) {
codeLines.push('\t' +
`if (index == ${i}) { return ${sizeInConcatAxis[i]}; }`);
}
else if (i === sizeInConcatAxis.length - 1) {
codeLines.push('\t' +
`else { return ${sizeInConcatAxis[i]}; }`);
}
else {
codeLines.push('\t' +
`else if (index == ${i}) { return ${sizeInConcatAxis[i]}; }`);
}
}
codeLines.push('\t' +
'}');
return codeLines.join('\n');
};
const parseConcatAttributes = (node) => (0, attribute_with_cache_key_1.createAttributeWithCacheKey)({ axis: node.attributes.getInt('axis') });
exports.parseConcatAttributes = parseConcatAttributes;
const validateInputs = (inputs) => {
if (!inputs || inputs.length < 1) {
throw new Error('too few inputs');
}
const inputType = inputs[0].type;
const inputDimensionality = inputs[0].dims.length;
// TODO: Support string concat
if (inputType === 'string') {
throw new Error('string tensor is not supported yet');
}
for (const input of inputs) {
// make sure types of all inputs match
if (input.type !== inputType) {
throw new Error('input tensors should be one type');
}
// make sure the dimensionality of all inputs are the same
if (input.dims.length !== inputDimensionality) {
throw new Error('input tensors should have the same shape');
}
}
};
//# sourceMappingURL=concat.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,195 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
import {AttributeWithCacheKey, createAttributeWithCacheKey} from '../../../attribute-with-cache-key';
import {Graph} from '../../../graph';
import {OperatorImplementation, OperatorInitialization} from '../../../operators';
import {Tensor} from '../../../tensor';
import {WebGLInferenceHandler} from '../inference-handler';
import {ProgramInfo, ProgramInfoLoader, ProgramMetadata, TextureType} from '../types';
import {createPackedConcatProgramInfoLoader} from './concat-packed';
export interface ConcatAttributes extends AttributeWithCacheKey {
readonly axis: number;
}
export const concat: OperatorImplementation<ConcatAttributes> =
(inferenceHandler: WebGLInferenceHandler, inputs: Tensor[], attributes: ConcatAttributes): Tensor[] => {
validateInputs(inputs);
if (inferenceHandler.session.pack && inputs[0].dims.length > 1) {
const output =
inferenceHandler.run(createPackedConcatProgramInfoLoader(inferenceHandler, inputs, attributes), inputs);
return [output];
} else {
const output =
inferenceHandler.run(createUnpackedConcatProgramInfoLoader(inferenceHandler, inputs, attributes), inputs);
return [output];
}
};
const createUnpackedConcatProgramMetadata = (inputCount: number, cacheHint: string) => ({
name: 'Concat',
inputNames: Array.from({length: inputCount}, (v, i) => `X${i}`),
inputTypes: Array(inputCount).fill(TextureType.unpacked),
cacheHint
});
const createUnpackedConcatProgramInfo =
(handler: WebGLInferenceHandler, metadata: ProgramMetadata, inputs: Tensor[], axis: number): ProgramInfo => {
const inputShape = inputs[0].dims.slice();
if (axis >= inputShape.length || axis < (-1 * inputShape.length)) {
throw new Error('axis specified for concat doesn\'t match input dimensionality');
}
if (axis < 0) {
axis = inputShape.length + axis;
}
// ensure all of the non-concatenated axes match each other
// calculate the shape of the output tensor while we do that
const outputShape = inputShape.slice(0);
for (let i = 1; i < inputs.length; i++) {
const dataNShape = inputs[i].dims.slice();
for (let axisIndex = 0; axisIndex < inputShape.length; axisIndex++) {
// add to the placeholder for computing output shape
if (axisIndex === axis) {
outputShape[axis] += dataNShape[axisIndex];
}
// ensure all non-cancatenated axes match each other
else if (inputShape[axisIndex] !== dataNShape[axisIndex]) {
throw new Error('non concat dimensions must match');
}
}
}
const rank = outputShape.length;
const sizeInConcatAxis = new Array<number>(inputs.length);
let previousSum = 0;
for (let i = 0; i < sizeInConcatAxis.length; ++i) {
previousSum += inputs[i].dims[axis];
sizeInConcatAxis[i] = previousSum;
}
let getTextureIndexWhereDataResidesMethod = '';
// in most cases linear search is sufficient, as in most scenarios, only 2 tensors are concatenated
if (inputs.length < 5) {
getTextureIndexWhereDataResidesMethod = getTextureIndexWhereDataResidesLinearSearch(sizeInConcatAxis);
} else {
getTextureIndexWhereDataResidesMethod = getTextureIndexWhereDataResidesBinarySearch(sizeInConcatAxis);
}
const fetchDataFromCorrectTextureMethod = getFetchDataFromCorrectTextureMethod(inputs.length, rank);
const getSizeInConcatAxisValueFromIndexMethod = getGetSizeInConcatAxisValueFromIndexMethod(sizeInConcatAxis);
const shaderSource = `
${fetchDataFromCorrectTextureMethod}
${getSizeInConcatAxisValueFromIndexMethod}
${getTextureIndexWhereDataResidesMethod}
float process(int indices[${rank}]) {
int textureIndex = getTextureWhereDataResides (indices[${axis}]);
if(textureIndex != 0) {
indices[${axis}] = indices[${axis}] - int(getSizeInConcatAxisValueFromIndex(textureIndex-int(1)));
}
return fetchDataFromCorrectTexture(textureIndex, indices);
}`;
return {
...metadata,
output: {dims: outputShape, type: inputs[0].type, textureType: TextureType.unpacked},
shaderSource,
};
};
const createUnpackedConcatProgramInfoLoader =
(handler: WebGLInferenceHandler, inputs: Tensor[], attributes: ConcatAttributes): ProgramInfoLoader => {
const metadata = createUnpackedConcatProgramMetadata(inputs.length, attributes.cacheKey);
return {...metadata, get: () => createUnpackedConcatProgramInfo(handler, metadata, inputs, attributes.axis)};
};
const getTextureIndexWhereDataResidesLinearSearch = (sizeInConcatAxis: number[]): string => {
const searchAxis = sizeInConcatAxis.map((size, i) => `if(index<${size}) {return ${i};}
`);
return `int getTextureWhereDataResides(int index) {
${searchAxis.join('')}
}`;
};
// TODO: Implement BinarySearch in GLSL
const getTextureIndexWhereDataResidesBinarySearch = (sizeInConcatAxis: number[]): string =>
getTextureIndexWhereDataResidesLinearSearch(sizeInConcatAxis);
const getFetchDataFromCorrectTextureMethod = (numberOfTensors: number, tensorRank: number) => {
const codeLines: string[] = [`float fetchDataFromCorrectTexture(int textureIndex, int indices[${tensorRank}]) {`];
for (let i = 0; i < numberOfTensors; ++i) {
if (i === 0) {
codeLines.push(
'\t' +
`if (textureIndex == ${i}) { return _X${i}(indices); }`);
} else if (i === numberOfTensors - 1) {
codeLines.push(
'\t' +
`else { return _X${i}(indices); }`);
} else {
codeLines.push(
'\t' +
`else if (textureIndex == ${i}) { return _X${i}(indices); }`);
}
}
codeLines.push(
'\t' +
'}');
return codeLines.join('\n');
};
const getGetSizeInConcatAxisValueFromIndexMethod = (sizeInConcatAxis: number[]): string => {
const codeLines: string[] = ['int getSizeInConcatAxisValueFromIndex(int index) {'];
for (let i = 0; i < sizeInConcatAxis.length; ++i) {
if (i === 0) {
codeLines.push(
'\t' +
`if (index == ${i}) { return ${sizeInConcatAxis[i]}; }`);
} else if (i === sizeInConcatAxis.length - 1) {
codeLines.push(
'\t' +
`else { return ${sizeInConcatAxis[i]}; }`);
} else {
codeLines.push(
'\t' +
`else if (index == ${i}) { return ${sizeInConcatAxis[i]}; }`);
}
}
codeLines.push(
'\t' +
'}');
return codeLines.join('\n');
};
export const parseConcatAttributes: OperatorInitialization<ConcatAttributes> = (node: Graph.Node): ConcatAttributes =>
createAttributeWithCacheKey({axis: node.attributes.getInt('axis')});
const validateInputs = (inputs: Tensor[]): void => {
if (!inputs || inputs.length < 1) {
throw new Error('too few inputs');
}
const inputType = inputs[0].type;
const inputDimensionality = inputs[0].dims.length;
// TODO: Support string concat
if (inputType === 'string') {
throw new Error('string tensor is not supported yet');
}
for (const input of inputs) {
// make sure types of all inputs match
if (input.type !== inputType) {
throw new Error('input tensors should be one type');
}
// make sure the dimensionality of all inputs are the same
if (input.dims.length !== inputDimensionality) {
throw new Error('input tensors should have the same shape');
}
}
};

View File

@@ -0,0 +1,73 @@
"use strict";
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
Object.defineProperty(exports, "__esModule", { value: true });
exports.createUnpackedGroupedConvProgramInfoLoader = void 0;
const instrument_1 = require("../../../instrument");
const glsl_source_1 = require("../glsl-source");
const types_1 = require("../types");
const conv_1 = require("./conv");
const fuse_utils_1 = require("./fuse-utils");
const createUnpackedGroupedConvProgramMetadata = (hasBias, cacheHint) => ({
name: 'GroupedConv',
inputNames: hasBias ? ['X', 'W', 'Bias'] : ['X', 'W'],
inputTypes: hasBias ? [types_1.TextureType.unpacked, types_1.TextureType.unpacked, types_1.TextureType.unpacked] :
[types_1.TextureType.unpacked, types_1.TextureType.unpacked],
cacheHint
});
const createUnpackedGroupedConvProgramInfo = (inferenceHandler, inputs, metadata, attributes) => {
const hasBias = inputs.length > 2;
const processBias = hasBias ? 'value += getBias(output_channel);' : '';
const xShape = inputs[0].dims.slice();
const wShape = inputs[1].dims.slice();
const outputChannelsPerGroup = wShape[0] / attributes.group;
instrument_1.Logger.verbose('GroupedConv', `autpPad:${attributes.autoPad}, dilations:${attributes.dilations}, group:${attributes.group}, kernelShape:${attributes.kernelShape}, pads:${attributes.pads}, strides:${attributes.strides}`);
const outputShape = (0, conv_1.calculateOutputShape)(xShape, wShape, attributes.dilations, attributes.pads, attributes.strides);
const glsl = (0, glsl_source_1.getGlsl)(inferenceHandler.session.backend.glContext.version);
const { activationFunction, applyActivation } = (0, fuse_utils_1.getActivationSnippet)(attributes);
const shaderSource = `
const ivec2 strides = ivec2(${attributes.strides[0]}, ${attributes.strides[1]});
const ivec2 pads = ivec2(${attributes.pads[0]}, ${attributes.pads[1]});
${activationFunction}
void main() {
ivec4 coords = getOutputCoords();
int batch = coords.x;
int output_channel = coords.y;
ivec2 xRCCorner = coords.zw * strides - pads;
int group_id = output_channel / ${outputChannelsPerGroup};
float value = 0.0;
for (int wInChannel = 0; wInChannel < ${wShape[1]}; wInChannel++) {
int input_channel = group_id * ${wShape[1]} + wInChannel;
for (int wHeight = 0; wHeight < ${wShape[2]}; wHeight++) {
int xHeight = xRCCorner.x + wHeight * ${attributes.dilations[0]};
if (xHeight < 0 || xHeight >= ${xShape[2]}) {
continue;
}
for (int wWidth = 0; wWidth < ${wShape[3]}; wWidth++) {
int xWidth = xRCCorner.y + wWidth * ${attributes.dilations[1]};
if (xWidth < 0 || xWidth >= ${xShape[3]}) {
continue;
}
float xVal = getX(batch, input_channel, xWidth, xHeight);
float wVal = getW(output_channel, wInChannel, wWidth, wHeight);
value += xVal*wVal;
}
}
}
${processBias}
${applyActivation}
${glsl.output} = vec4(value, .0, .0, .0);
}
`;
return Object.assign(Object.assign({}, metadata), { output: { dims: outputShape, type: inputs[0].type, textureType: types_1.TextureType.unpacked }, shaderSource, hasMain: true });
};
const createUnpackedGroupedConvProgramInfoLoader = (inferenceHandler, inputs, attributes) => {
const metadata = createUnpackedGroupedConvProgramMetadata(inputs.length > 2, attributes.cacheKey);
return Object.assign(Object.assign({}, metadata), { get: () => createUnpackedGroupedConvProgramInfo(inferenceHandler, inputs, metadata, attributes) });
};
exports.createUnpackedGroupedConvProgramInfoLoader = createUnpackedGroupedConvProgramInfoLoader;
//# sourceMappingURL=conv-grouped.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"conv-grouped.js","sourceRoot":"","sources":["conv-grouped.ts"],"names":[],"mappings":"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"}

View File

@@ -0,0 +1,92 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
import {Logger} from '../../../instrument';
import {Tensor} from '../../../tensor';
import {getGlsl} from '../glsl-source';
import {WebGLInferenceHandler} from '../inference-handler';
import {ProgramInfo, ProgramInfoLoader, ProgramMetadata, TextureType} from '../types';
import {calculateOutputShape, ConvAttributes} from './conv';
import {getActivationSnippet} from './fuse-utils';
const createUnpackedGroupedConvProgramMetadata = (hasBias: boolean, cacheHint: string): ProgramMetadata => ({
name: 'GroupedConv',
inputNames: hasBias ? ['X', 'W', 'Bias'] : ['X', 'W'],
inputTypes: hasBias ? [TextureType.unpacked, TextureType.unpacked, TextureType.unpacked] :
[TextureType.unpacked, TextureType.unpacked],
cacheHint
});
const createUnpackedGroupedConvProgramInfo =
(inferenceHandler: WebGLInferenceHandler, inputs: readonly Tensor[], metadata: ProgramMetadata,
attributes: ConvAttributes): ProgramInfo => {
const hasBias = inputs.length > 2;
const processBias = hasBias ? 'value += getBias(output_channel);' : '';
const xShape = inputs[0].dims.slice();
const wShape = inputs[1].dims.slice();
const outputChannelsPerGroup = wShape[0] / attributes.group;
Logger.verbose(
'GroupedConv',
`autpPad:${attributes.autoPad}, dilations:${attributes.dilations}, group:${attributes.group}, kernelShape:${
attributes.kernelShape}, pads:${attributes.pads}, strides:${attributes.strides}`);
const outputShape =
calculateOutputShape(xShape, wShape, attributes.dilations, attributes.pads, attributes.strides);
const glsl = getGlsl(inferenceHandler.session.backend.glContext.version);
const {activationFunction, applyActivation} = getActivationSnippet(attributes);
const shaderSource = `
const ivec2 strides = ivec2(${attributes.strides[0]}, ${attributes.strides[1]});
const ivec2 pads = ivec2(${attributes.pads[0]}, ${attributes.pads[1]});
${activationFunction}
void main() {
ivec4 coords = getOutputCoords();
int batch = coords.x;
int output_channel = coords.y;
ivec2 xRCCorner = coords.zw * strides - pads;
int group_id = output_channel / ${outputChannelsPerGroup};
float value = 0.0;
for (int wInChannel = 0; wInChannel < ${wShape[1]}; wInChannel++) {
int input_channel = group_id * ${wShape[1]} + wInChannel;
for (int wHeight = 0; wHeight < ${wShape[2]}; wHeight++) {
int xHeight = xRCCorner.x + wHeight * ${attributes.dilations[0]};
if (xHeight < 0 || xHeight >= ${xShape[2]}) {
continue;
}
for (int wWidth = 0; wWidth < ${wShape[3]}; wWidth++) {
int xWidth = xRCCorner.y + wWidth * ${attributes.dilations[1]};
if (xWidth < 0 || xWidth >= ${xShape[3]}) {
continue;
}
float xVal = getX(batch, input_channel, xWidth, xHeight);
float wVal = getW(output_channel, wInChannel, wWidth, wHeight);
value += xVal*wVal;
}
}
}
${processBias}
${applyActivation}
${glsl.output} = vec4(value, .0, .0, .0);
}
`;
return {
...metadata,
output: {dims: outputShape, type: inputs[0].type, textureType: TextureType.unpacked},
shaderSource,
hasMain: true,
};
};
export const createUnpackedGroupedConvProgramInfoLoader =
(inferenceHandler: WebGLInferenceHandler, inputs: readonly Tensor[], attributes: ConvAttributes):
ProgramInfoLoader => {
const metadata = createUnpackedGroupedConvProgramMetadata(inputs.length > 2, attributes.cacheKey);
return {
...metadata,
get: () => createUnpackedGroupedConvProgramInfo(inferenceHandler, inputs, metadata, attributes)
};
};

View File

@@ -0,0 +1,36 @@
"use strict";
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
Object.defineProperty(exports, "__esModule", { value: true });
exports.conv2DPacked = exports.conv2DPackedPointwise = void 0;
const conv_1 = require("./conv");
const im2col_pack_1 = require("./im2col-pack");
const matmul_pack_1 = require("./matmul-pack");
const conv2DPackedPointwise = (inferenceHandler, inputs, attributes) => {
const xshape = inputs[0].dims;
const kshape = inputs[1].dims;
const outputShape = (0, conv_1.calculateOutputShape)(xshape, kshape, attributes.dilations, attributes.pads, attributes.strides);
const reshapedX = inferenceHandler.reshapePacked(inputs[0], [xshape[1], xshape[2] * xshape[3]]);
const reshapedK = inferenceHandler.reshapePacked(inputs[1], [kshape[0], kshape[1]]);
const matmulInputs = inputs.length > 2 ? [reshapedK, reshapedX, inputs[2]] : [reshapedK, reshapedX];
const matmulOutput = inferenceHandler.run((0, matmul_pack_1.createPackedMatmulProgramInfoLoader)(inferenceHandler, matmulInputs, attributes), matmulInputs);
return inferenceHandler.reshapePacked(matmulOutput, outputShape);
};
exports.conv2DPackedPointwise = conv2DPackedPointwise;
const conv2DPacked = (inferenceHandler, inputs, attributes) => {
const xshape = inputs[0].dims;
const kshape = inputs[1].dims;
const outputShape = (0, conv_1.calculateOutputShape)(xshape, kshape, attributes.dilations, attributes.pads, attributes.strides);
// run im2col
const im2colOutput = inferenceHandler.run((0, im2col_pack_1.createPackedIm2ColProgramInfoLoader)(inferenceHandler, inputs[0], inputs[1], outputShape, attributes), [inputs[0]]);
// reshape kernel
const kernelReshaped = inferenceHandler.reshapePacked(inputs[1], [kshape[0], kshape[1] * kshape[2] * kshape[3]]);
// run matmul
const matmulInputs = (inputs.length === 3) ? [kernelReshaped, im2colOutput, inputs[2]] : [kernelReshaped, im2colOutput];
const matmulOutput = inferenceHandler.run((0, matmul_pack_1.createPackedMatmulProgramInfoLoader)(inferenceHandler, matmulInputs, attributes), matmulInputs);
// reshape output
const outputReshaped = inferenceHandler.reshapePacked(matmulOutput, outputShape);
return outputReshaped;
};
exports.conv2DPacked = conv2DPacked;
//# sourceMappingURL=conv-pack.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"conv-pack.js","sourceRoot":"","sources":["conv-pack.ts"],"names":[],"mappings":"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"}

View File

@@ -0,0 +1,50 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
import {Tensor} from '../../../tensor';
import {WebGLInferenceHandler} from '../inference-handler';
import {calculateOutputShape, ConvAttributes} from './conv';
import {createPackedIm2ColProgramInfoLoader} from './im2col-pack';
import {createPackedMatmulProgramInfoLoader} from './matmul-pack';
export const conv2DPackedPointwise =
(inferenceHandler: WebGLInferenceHandler, inputs: readonly Tensor[], attributes: ConvAttributes): Tensor => {
const xshape = inputs[0].dims;
const kshape = inputs[1].dims;
const outputShape =
calculateOutputShape(xshape, kshape, attributes.dilations, attributes.pads, attributes.strides);
const reshapedX = inferenceHandler.reshapePacked(inputs[0], [xshape[1], xshape[2] * xshape[3]]);
const reshapedK = inferenceHandler.reshapePacked(inputs[1], [kshape[0], kshape[1]]);
const matmulInputs = inputs.length > 2 ? [reshapedK, reshapedX, inputs[2]] : [reshapedK, reshapedX];
const matmulOutput = inferenceHandler.run(
createPackedMatmulProgramInfoLoader(inferenceHandler, matmulInputs, attributes), matmulInputs);
return inferenceHandler.reshapePacked(matmulOutput, outputShape);
};
export const conv2DPacked =
(inferenceHandler: WebGLInferenceHandler, inputs: readonly Tensor[], attributes: ConvAttributes): Tensor => {
const xshape = inputs[0].dims;
const kshape = inputs[1].dims;
const outputShape =
calculateOutputShape(xshape, kshape, attributes.dilations, attributes.pads, attributes.strides);
// run im2col
const im2colOutput = inferenceHandler.run(
createPackedIm2ColProgramInfoLoader(inferenceHandler, inputs[0], inputs[1], outputShape, attributes),
[inputs[0]]);
// reshape kernel
const kernelReshaped = inferenceHandler.reshapePacked(inputs[1], [kshape[0], kshape[1] * kshape[2] * kshape[3]]);
// run matmul
const matmulInputs =
(inputs.length === 3) ? [kernelReshaped, im2colOutput, inputs[2]] : [kernelReshaped, im2colOutput];
const matmulOutput = inferenceHandler.run(
createPackedMatmulProgramInfoLoader(inferenceHandler, matmulInputs, attributes), matmulInputs);
// reshape output
const outputReshaped = inferenceHandler.reshapePacked(matmulOutput, outputShape);
return outputReshaped;
};

View File

@@ -0,0 +1,198 @@
"use strict";
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseConvTransposeAttributes = exports.convTranspose = void 0;
const attribute_with_cache_key_1 = require("../../../attribute-with-cache-key");
const glsl_source_1 = require("../glsl-source");
const types_1 = require("../types");
const fuse_utils_1 = require("./fuse-utils");
const computeTotalPad = (inDim, stride, adj, kernel, dilation, outSize) => (inDim - 1) * stride + adj + (kernel - 1) * dilation + 1 - outSize;
const distributePadding = (totalPad, autoPad, pads, head, tail) => {
const smallPad = Math.floor(totalPad / 2);
if (autoPad === 'SAME_UPPER') {
pads[head] = smallPad;
pads[tail] = totalPad - smallPad;
}
else if (autoPad === 'SAME_LOWER') {
pads[head] = totalPad - smallPad;
pads[tail] = smallPad;
}
};
const calculateOutputShapeAndPads = (inputShape, kernelShape, dilations, autoPad, pads, strides, outputPadding, outputShape) => {
const spatialRank = inputShape.length - 2;
const updateShape = outputShape.length === 0;
for (let i = 0; i < spatialRank; ++i) {
const outSize = updateShape ? inputShape[i + 2] * strides[i] : outputShape[i];
const totalPad = computeTotalPad(inputShape[i + 2], strides[i], pads[i], kernelShape[i], dilations[i], outSize);
distributePadding(totalPad, autoPad, pads, i, i + spatialRank);
if (updateShape) {
outputShape.push(strides[i] * (inputShape[i + 2] - 1) + outputPadding[i] + (kernelShape[i] - 1) * dilations[i] + 1 -
pads[i] - pads[i + spatialRank]);
}
}
};
const convTranspose = (inferenceHandler, inputs, attributes) => {
validateInputs(inputs, attributes); // currently will fail if not convTranspose2D
return convTranspose2d(inferenceHandler, inputs, attributes);
};
exports.convTranspose = convTranspose;
const convTranspose2d = (inferenceHandler, inputs, attributes) => {
const adjustedAttributes = getAdjustedConvTransposeAttributes(attributes, inputs);
return [convTranspose2DUnpacked(inferenceHandler, inputs, adjustedAttributes)];
};
const createConvTransposeProgramMetadata = (hasBias, cacheHint) => ({
name: 'ConvTranspose',
inputNames: hasBias ? ['X', 'W', 'B'] : ['X', 'W'],
inputTypes: hasBias ? [types_1.TextureType.unpacked, types_1.TextureType.unpacked, types_1.TextureType.unpacked] :
[types_1.TextureType.unpacked, types_1.TextureType.unpacked],
cacheHint
});
const createUnpackedConvTransposeProgramInfo = (inferenceHandler, inputs, metadata, attributes) => {
const hasBias = inputs.length > 2;
const valueInit = hasBias ? 'getB(output_channel)' : '0.0';
const xShape = inputs[0].dims;
const wShape = inputs[1].dims;
const outputChannelsPerGroup = wShape[1];
const inputChannelsPerGroup = wShape[0] / attributes.group;
const outputShape = [inputs[0].dims[0], inputs[1].dims[1] * attributes.group, ...attributes.outputShape];
const glsl = (0, glsl_source_1.getGlsl)(inferenceHandler.session.backend.glContext.version);
const { activationFunction, applyActivation } = (0, fuse_utils_1.getActivationSnippet)(attributes);
const shaderSource = `
const ivec2 strides = ivec2(${attributes.strides[0]}, ${attributes.strides[1]});
const ivec2 pads = ivec2(${attributes.pads[0]}, ${attributes.pads[1]});
${activationFunction}
void main() {
ivec4 coords = getOutputCoords();
int batch = coords.x;
int output_channel = coords.y;
ivec2 loc = coords.zw + pads;
int group_id = output_channel / ${outputChannelsPerGroup};
int wOutChannel = output_channel - group_id * ${outputChannelsPerGroup};
float value = ${valueInit};
for (int inChannelOffset = 0; inChannelOffset < ${inputChannelsPerGroup}; inChannelOffset++) {
int input_channel = group_id * ${inputChannelsPerGroup} + inChannelOffset;
for (int wWOff = 0; wWOff < ${wShape[2]}; wWOff++) {
for (int wHOff = 0; wHOff < ${wShape[3]}; wHOff++) {
ivec2 wOff = ivec2(wWOff * ${attributes.dilations[0]}, wHOff * ${attributes.dilations[1]});
ivec2 wLoc = loc - wOff;
ivec2 wLocIn = wLoc / strides;
if (
wLocIn * strides == wLoc &&
wLocIn.x >= 0 && wLocIn.x < ${xShape[2]} &&
wLocIn.y >= 0 && wLocIn.y < ${xShape[3]}
) {
float xVal = getX(batch, input_channel, wLocIn.y, wLocIn.x);
float wVal = getW(input_channel, wOutChannel, wHOff, wWOff);
value += xVal * wVal;
}
}
}
}
${applyActivation}
${glsl.output} = vec4(value, .0, .0, .0);
}
`;
return Object.assign(Object.assign({}, metadata), { output: { dims: outputShape, type: inputs[0].type, textureType: types_1.TextureType.unpacked }, shaderSource, hasMain: true });
};
const createUnpackedConvTransposeProgramInfoLoader = (inferenceHandler, inputs, attributes) => {
const metadata = createConvTransposeProgramMetadata(inputs.length > 2, attributes.cacheKey);
return Object.assign(Object.assign({}, metadata), { get: () => createUnpackedConvTransposeProgramInfo(inferenceHandler, inputs, metadata, attributes) });
};
const convTranspose2DUnpacked = (inferenceHandler, inputs, attributes) => {
const result = inferenceHandler.run(createUnpackedConvTransposeProgramInfoLoader(inferenceHandler, inputs, attributes), inputs);
return result;
};
const getAdjustedConvTransposeAttributes = (attributes, inputs) => {
const kernelShape = attributes.kernelShape.slice();
// if kernelShape is not specified in the attributes of this op, infer it from the weight tensor dims
if (attributes.kernelShape.length === 0) {
for (let i = 2; i < inputs[1].dims.length; ++i) {
kernelShape.push(inputs[1].dims[i]);
}
}
const pads = attributes.pads.slice();
const outputShape = attributes.outputShape.slice();
const inputShape = inputs[0].dims;
// If outputShape is not specified in the attributes of this op, infer it from the parameters
// Similarly, automatically infer pads if not specified
calculateOutputShapeAndPads(inputShape, kernelShape, attributes.dilations, attributes.autoPad, pads, attributes.strides, attributes.outputPadding, outputShape);
// always return a new object so does not modify the original attributes
const newAttributes = Object.assign({}, attributes);
Object.assign(newAttributes, { kernelShape, pads, outputShape, cacheKey: attributes.cacheKey });
return newAttributes;
};
const parseConvTransposeAttributes = (node) => {
const attributes = node.attributes;
const activationAttributes = (0, fuse_utils_1.parseInternalActivationAttributes)(attributes);
// TODO : Make this generic enough to compute default attributes for multi-dimensional conv
const autoPad = attributes.getString('auto_pad', 'NOTSET');
const dilations = attributes.getInts('dilations', [1, 1]);
const group = attributes.getInt('group', 1);
const kernelShape = attributes.getInts('kernel_shape', []);
const outputPadding = attributes.getInts('output_padding', [0, 0]);
const outputShape = attributes.getInts('output_shape', []);
const pads = attributes.getInts('pads', [0, 0, 0, 0]);
const strides = attributes.getInts('strides', [1, 1]);
return (0, attribute_with_cache_key_1.createAttributeWithCacheKey)(Object.assign({ autoPad, dilations, group, kernelShape, outputPadding, outputShape, pads, strides }, activationAttributes));
};
exports.parseConvTransposeAttributes = parseConvTransposeAttributes;
const validateInputs = (inputs, attributes) => {
// Refer to the below link for all input checks
// https://github.com/onnx/onnx/blob/main/docs/Operators.md#Conv
if (!inputs || (inputs.length !== 2 && inputs.length !== 3)) {
throw new Error('Conv requires 2 or 3 inputs');
}
// TODO : Need to add support for multi-dimensional conv
if (inputs[0].dims.length !== 4 || inputs[1].dims.length !== 4) {
throw new Error('currently only support 2-dimensional conv');
}
// FILTER_IN_CHANNEL should be equal to DATA_CHANNEL
const dataChannel = inputs[0].dims[1];
const filterInChannel = inputs[1].dims[0];
if (dataChannel !== filterInChannel) {
throw new Error('FILTER_IN_CHANNEL should be equal to DATA_CHANNEL');
}
const featureMaps = inputs[1].dims[1] * attributes.group;
// if bias is provided it should be 1D and the number of elements should be equal to the number of feature maps
if (inputs.length === 3 && (inputs[2].dims.length !== 1 || inputs[2].dims[0] !== featureMaps)) {
throw new Error('invalid bias');
}
const spatialRank = inputs[0].dims.length - 2;
// wrong dilations dimension
if (attributes.dilations.length !== spatialRank) {
throw new Error(`dilations should be ${spatialRank}D`);
}
// Wrong strides dimension
if (attributes.strides.length !== spatialRank) {
throw new Error(`strides should be ${spatialRank}D`);
}
// Wrong pads dimension
if (attributes.pads.length !== spatialRank * 2) {
throw new Error(`pads should be ${spatialRank * 2}D`);
}
// Wrong output padding dimension
if (attributes.outputPadding.length !== spatialRank) {
throw new Error(`output_padding should be ${spatialRank}D`);
}
// if kernelShape is specified, it's data length must be 2 less than dims length of the weights tensor
// (the first 2 dims are batch_size and channels)
if (attributes.kernelShape.length !== 0 && attributes.kernelShape.length !== inputs[1].dims.length - 2) {
throw new Error('invalid kernel shape');
}
// as with kernelShape, must have same number of spatial dims as input
if (attributes.outputShape.length !== 0 && attributes.outputShape.length !== inputs[0].dims.length - 2) {
throw new Error('invalid output shape');
}
// TODO : Need to add support for float64
if (inputs[0].type !== 'float32' || inputs[1].type !== 'float32') {
throw new Error('ConvTranspose input(X,W) should be float tensor');
}
if (inputs.length === 3 && inputs[2].type !== 'float32') {
throw new Error('ConvTranspose input(bias) should be float tensor');
}
};
//# sourceMappingURL=conv-transpose.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,259 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
import {createAttributeWithCacheKey} from '../../../attribute-with-cache-key';
import {InferenceHandler} from '../../../backend';
import {Graph} from '../../../graph';
import {OperatorImplementation, OperatorInitialization} from '../../../operators';
import {Tensor} from '../../../tensor';
import {getGlsl} from '../glsl-source';
import {WebGLInferenceHandler} from '../inference-handler';
import {ProgramInfo, ProgramInfoLoader, ProgramMetadata, TextureType} from '../types';
import {ConvAttributes} from './conv';
import {getActivationSnippet, parseInternalActivationAttributes} from './fuse-utils';
const computeTotalPad =
(inDim: number, stride: number, adj: number, kernel: number, dilation: number, outSize: number) =>
(inDim - 1) * stride + adj + (kernel - 1) * dilation + 1 - outSize;
const distributePadding = (totalPad: number, autoPad: string, pads: number[], head: number, tail: number) => {
const smallPad = Math.floor(totalPad / 2);
if (autoPad === 'SAME_UPPER') {
pads[head] = smallPad;
pads[tail] = totalPad - smallPad;
} else if (autoPad === 'SAME_LOWER') {
pads[head] = totalPad - smallPad;
pads[tail] = smallPad;
}
};
const calculateOutputShapeAndPads =
(inputShape: readonly number[], kernelShape: readonly number[], dilations: readonly number[], autoPad: string,
pads: number[], strides: readonly number[], outputPadding: readonly number[], outputShape: number[]) => {
const spatialRank = inputShape.length - 2;
const updateShape = outputShape.length === 0;
for (let i = 0; i < spatialRank; ++i) {
const outSize = updateShape ? inputShape[i + 2] * strides[i] : outputShape[i];
const totalPad = computeTotalPad(inputShape[i + 2], strides[i], pads[i], kernelShape[i], dilations[i], outSize);
distributePadding(totalPad, autoPad, pads, i, i + spatialRank);
if (updateShape) {
outputShape.push(
strides[i] * (inputShape[i + 2] - 1) + outputPadding[i] + (kernelShape[i] - 1) * dilations[i] + 1 -
pads[i] - pads[i + spatialRank]);
}
}
};
export interface ConvTransposeAttributes extends ConvAttributes {
readonly outputPadding: readonly number[];
readonly outputShape: readonly number[];
}
export const convTranspose: OperatorImplementation<ConvTransposeAttributes> =
(inferenceHandler: InferenceHandler, inputs: Tensor[], attributes: ConvTransposeAttributes): Tensor[] => {
validateInputs(inputs, attributes); // currently will fail if not convTranspose2D
return convTranspose2d(inferenceHandler, inputs, attributes);
};
const convTranspose2d: OperatorImplementation<ConvTransposeAttributes> =
(inferenceHandler: WebGLInferenceHandler, inputs: Tensor[], attributes: ConvTransposeAttributes): Tensor[] => {
const adjustedAttributes = getAdjustedConvTransposeAttributes(attributes, inputs);
return [convTranspose2DUnpacked(inferenceHandler, inputs, adjustedAttributes)];
};
const createConvTransposeProgramMetadata = (hasBias: boolean, cacheHint: string) => ({
name: 'ConvTranspose',
inputNames: hasBias ? ['X', 'W', 'B'] : ['X', 'W'],
inputTypes: hasBias ? [TextureType.unpacked, TextureType.unpacked, TextureType.unpacked] :
[TextureType.unpacked, TextureType.unpacked],
cacheHint
});
const createUnpackedConvTransposeProgramInfo =
(inferenceHandler: WebGLInferenceHandler, inputs: readonly Tensor[], metadata: ProgramMetadata,
attributes: ConvTransposeAttributes): ProgramInfo => {
const hasBias = inputs.length > 2;
const valueInit = hasBias ? 'getB(output_channel)' : '0.0';
const xShape = inputs[0].dims;
const wShape = inputs[1].dims;
const outputChannelsPerGroup = wShape[1];
const inputChannelsPerGroup = wShape[0] / attributes.group;
const outputShape = [inputs[0].dims[0], inputs[1].dims[1] * attributes.group, ...attributes.outputShape];
const glsl = getGlsl(inferenceHandler.session.backend.glContext.version);
const {activationFunction, applyActivation} = getActivationSnippet(attributes);
const shaderSource = `
const ivec2 strides = ivec2(${attributes.strides[0]}, ${attributes.strides[1]});
const ivec2 pads = ivec2(${attributes.pads[0]}, ${attributes.pads[1]});
${activationFunction}
void main() {
ivec4 coords = getOutputCoords();
int batch = coords.x;
int output_channel = coords.y;
ivec2 loc = coords.zw + pads;
int group_id = output_channel / ${outputChannelsPerGroup};
int wOutChannel = output_channel - group_id * ${outputChannelsPerGroup};
float value = ${valueInit};
for (int inChannelOffset = 0; inChannelOffset < ${inputChannelsPerGroup}; inChannelOffset++) {
int input_channel = group_id * ${inputChannelsPerGroup} + inChannelOffset;
for (int wWOff = 0; wWOff < ${wShape[2]}; wWOff++) {
for (int wHOff = 0; wHOff < ${wShape[3]}; wHOff++) {
ivec2 wOff = ivec2(wWOff * ${attributes.dilations[0]}, wHOff * ${attributes.dilations[1]});
ivec2 wLoc = loc - wOff;
ivec2 wLocIn = wLoc / strides;
if (
wLocIn * strides == wLoc &&
wLocIn.x >= 0 && wLocIn.x < ${xShape[2]} &&
wLocIn.y >= 0 && wLocIn.y < ${xShape[3]}
) {
float xVal = getX(batch, input_channel, wLocIn.y, wLocIn.x);
float wVal = getW(input_channel, wOutChannel, wHOff, wWOff);
value += xVal * wVal;
}
}
}
}
${applyActivation}
${glsl.output} = vec4(value, .0, .0, .0);
}
`;
return {
...metadata,
output: {dims: outputShape, type: inputs[0].type, textureType: TextureType.unpacked},
shaderSource,
hasMain: true,
};
};
const createUnpackedConvTransposeProgramInfoLoader =
(inferenceHandler: WebGLInferenceHandler, inputs: readonly Tensor[], attributes: ConvTransposeAttributes):
ProgramInfoLoader => {
const metadata = createConvTransposeProgramMetadata(inputs.length > 2, attributes.cacheKey);
return {
...metadata,
get: () => createUnpackedConvTransposeProgramInfo(inferenceHandler, inputs, metadata, attributes)
};
};
const convTranspose2DUnpacked =
(inferenceHandler: WebGLInferenceHandler, inputs: readonly Tensor[], attributes: ConvTransposeAttributes):
Tensor => {
const result = inferenceHandler.run(
createUnpackedConvTransposeProgramInfoLoader(inferenceHandler, inputs, attributes), inputs);
return result;
};
const getAdjustedConvTransposeAttributes = <T extends ConvTransposeAttributes>(attributes: T, inputs: Tensor[]): T => {
const kernelShape = attributes.kernelShape.slice();
// if kernelShape is not specified in the attributes of this op, infer it from the weight tensor dims
if (attributes.kernelShape.length === 0) {
for (let i = 2; i < inputs[1].dims.length; ++i) {
kernelShape.push(inputs[1].dims[i]);
}
}
const pads = attributes.pads.slice();
const outputShape = attributes.outputShape.slice();
const inputShape = inputs[0].dims;
// If outputShape is not specified in the attributes of this op, infer it from the parameters
// Similarly, automatically infer pads if not specified
calculateOutputShapeAndPads(
inputShape, kernelShape, attributes.dilations, attributes.autoPad, pads, attributes.strides,
attributes.outputPadding, outputShape);
// always return a new object so does not modify the original attributes
const newAttributes: T = Object.assign({}, attributes);
Object.assign(newAttributes, {kernelShape, pads, outputShape, cacheKey: attributes.cacheKey});
return newAttributes;
};
export const parseConvTransposeAttributes: OperatorInitialization<ConvTransposeAttributes> =
(node: Graph.Node): ConvTransposeAttributes => {
const attributes = node.attributes;
const activationAttributes = parseInternalActivationAttributes(attributes);
// TODO : Make this generic enough to compute default attributes for multi-dimensional conv
const autoPad = attributes.getString('auto_pad', 'NOTSET');
const dilations = attributes.getInts('dilations', [1, 1]);
const group = attributes.getInt('group', 1);
const kernelShape = attributes.getInts('kernel_shape', []);
const outputPadding = attributes.getInts('output_padding', [0, 0]);
const outputShape = attributes.getInts('output_shape', []);
const pads = attributes.getInts('pads', [0, 0, 0, 0]);
const strides = attributes.getInts('strides', [1, 1]);
return createAttributeWithCacheKey(
{autoPad, dilations, group, kernelShape, outputPadding, outputShape, pads, strides, ...activationAttributes});
};
const validateInputs = (inputs: Tensor[], attributes: ConvTransposeAttributes): void => {
// Refer to the below link for all input checks
// https://github.com/onnx/onnx/blob/main/docs/Operators.md#Conv
if (!inputs || (inputs.length !== 2 && inputs.length !== 3)) {
throw new Error('Conv requires 2 or 3 inputs');
}
// TODO : Need to add support for multi-dimensional conv
if (inputs[0].dims.length !== 4 || inputs[1].dims.length !== 4) {
throw new Error('currently only support 2-dimensional conv');
}
// FILTER_IN_CHANNEL should be equal to DATA_CHANNEL
const dataChannel = inputs[0].dims[1];
const filterInChannel = inputs[1].dims[0];
if (dataChannel !== filterInChannel) {
throw new Error('FILTER_IN_CHANNEL should be equal to DATA_CHANNEL');
}
const featureMaps = inputs[1].dims[1] * attributes.group;
// if bias is provided it should be 1D and the number of elements should be equal to the number of feature maps
if (inputs.length === 3 && (inputs[2].dims.length !== 1 || inputs[2].dims[0] !== featureMaps)) {
throw new Error('invalid bias');
}
const spatialRank = inputs[0].dims.length - 2;
// wrong dilations dimension
if (attributes.dilations.length !== spatialRank) {
throw new Error(`dilations should be ${spatialRank}D`);
}
// Wrong strides dimension
if (attributes.strides.length !== spatialRank) {
throw new Error(`strides should be ${spatialRank}D`);
}
// Wrong pads dimension
if (attributes.pads.length !== spatialRank * 2) {
throw new Error(`pads should be ${spatialRank * 2}D`);
}
// Wrong output padding dimension
if (attributes.outputPadding.length !== spatialRank) {
throw new Error(`output_padding should be ${spatialRank}D`);
}
// if kernelShape is specified, it's data length must be 2 less than dims length of the weights tensor
// (the first 2 dims are batch_size and channels)
if (attributes.kernelShape.length !== 0 && attributes.kernelShape.length !== inputs[1].dims.length - 2) {
throw new Error('invalid kernel shape');
}
// as with kernelShape, must have same number of spatial dims as input
if (attributes.outputShape.length !== 0 && attributes.outputShape.length !== inputs[0].dims.length - 2) {
throw new Error('invalid output shape');
}
// TODO : Need to add support for float64
if (inputs[0].type !== 'float32' || inputs[1].type !== 'float32') {
throw new Error('ConvTranspose input(X,W) should be float tensor');
}
if (inputs.length === 3 && inputs[2].type !== 'float32') {
throw new Error('ConvTranspose input(bias) should be float tensor');
}
};

View File

@@ -0,0 +1,143 @@
"use strict";
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseConvAttributes = exports.conv = exports.calculateOutputShape = void 0;
const attribute_with_cache_key_1 = require("../../../attribute-with-cache-key");
const util_1 = require("../../../util");
const conv_grouped_1 = require("./conv-grouped");
const conv_pack_1 = require("./conv-pack");
const dot_product_1 = require("./dot-product");
const fuse_utils_1 = require("./fuse-utils");
const im2col_1 = require("./im2col");
const matmul_1 = require("./matmul");
const calculateOutputShape = (inputShape, kernelShape, dilations, adjustPads, strides) => {
const batchSize = inputShape[0];
const inputSpatialShape = inputShape.slice(2);
const spatialRank = inputSpatialShape.length;
const outChannels = kernelShape[0];
const kernelSpatialShape = kernelShape.slice(2);
const dilatedKernelShape = kernelSpatialShape.map((v, i) => v + (v - 1) * (dilations[i] - 1));
const inputSpatialShapeWithPad = inputSpatialShape.map((v, i) => v + adjustPads[i] + adjustPads[i + spatialRank]);
const outputSpatialShape = inputSpatialShapeWithPad.map((v, i) => Math.floor((v - dilatedKernelShape[i] + strides[i]) / strides[i]));
const outputShape = [batchSize, outChannels].concat(...outputSpatialShape);
return outputShape;
};
exports.calculateOutputShape = calculateOutputShape;
const conv = (inferenceHandler, inputs, attributes) => {
validateInputs(inputs, attributes); // currently will fail if not conv2D
return conv2d(inferenceHandler, inputs, attributes);
};
exports.conv = conv;
const conv2d = (inferenceHandler, inputs, attributes) => {
const adjustedAttributes = getAdjustedConvAttributes(attributes, inputs);
const packMode = inferenceHandler.session.pack;
const isPointwise = adjustedAttributes.kernelShape[0] === 1 && adjustedAttributes.kernelShape[1] === 1;
if (adjustedAttributes.group > 1) {
const result = inferenceHandler.run((0, conv_grouped_1.createUnpackedGroupedConvProgramInfoLoader)(inferenceHandler, inputs, adjustedAttributes), inputs);
return [result];
}
else if (isPointwise && packMode) {
return [conv2DUnpackedPointwise(inferenceHandler, inputs, adjustedAttributes)];
}
else if (packMode && inputs[0].dims.length === 4 && inputs[0].dims[0] === 1 && !isPointwise) {
return [(0, conv_pack_1.conv2DPacked)(inferenceHandler, inputs, adjustedAttributes)];
}
else {
return [conv2DUnpacked(inferenceHandler, inputs, adjustedAttributes)];
}
};
const conv2DUnpackedPointwise = (inferenceHandler, inputs, attributes) => {
const xshape = inputs[0].dims;
const kshape = inputs[1].dims;
const outputShape = (0, exports.calculateOutputShape)(xshape, kshape, attributes.dilations, attributes.pads, attributes.strides);
const reshapedX = inferenceHandler.reshapeUnpacked(inputs[0], [xshape[1], xshape[2] * xshape[3]]);
const reshapedK = inferenceHandler.reshapeUnpacked(inputs[1], [kshape[0], kshape[1]]);
const matmulInputs = inputs.length > 2 ? [reshapedK, reshapedX, inputs[2]] : [reshapedK, reshapedX];
const matmulOutput = inferenceHandler.run((0, matmul_1.createMatmulProgramInfoLoader)(matmulInputs, attributes), matmulInputs);
return inferenceHandler.reshapeUnpacked(matmulOutput, outputShape);
};
const conv2DUnpacked = (inferenceHandler, inputs, attributes) => {
const xshape = inputs[0].dims;
const kshape = inputs[1].dims;
const outputShape = (0, exports.calculateOutputShape)(xshape, kshape, attributes.dilations, attributes.pads, attributes.strides);
const xIm2Col = inferenceHandler.run((0, im2col_1.createIm2ColProgramInfoLoader)(inferenceHandler, inputs[0], inputs[1], outputShape, attributes), [inputs[0]]);
const dotProductInputs = inputs.length === 3 ? [xIm2Col, inputs[1], inputs[2]] : [xIm2Col, inputs[1]];
const output = inferenceHandler.run((0, dot_product_1.createDotProductProgramInfoLoader)(inferenceHandler, inputs, outputShape, attributes), dotProductInputs);
return output;
};
const getAdjustedConvAttributes = (attributes, inputs) => {
const kernelShape = attributes.kernelShape.slice();
// if kernelShape is not specified in the attributes of this op, infer it from the weight tensor dims
if (attributes.kernelShape.length === 0) {
for (let i = 2; i < inputs[1].dims.length; ++i) {
kernelShape.push(inputs[1].dims[i]);
}
}
const pads = attributes.pads.slice();
util_1.PoolConvUtil.adjustPadsBasedOnAutoPad(inputs[0].dims, attributes.strides, attributes.dilations, kernelShape, pads, attributes.autoPad);
// always return a new object so does not modify the original attributes
const newAttributes = Object.assign({}, attributes);
Object.assign(newAttributes, { kernelShape, pads, cacheKey: attributes.cacheKey });
return newAttributes;
};
const parseConvAttributes = (node) => {
const attributes = node.attributes;
const activationAttributes = (0, fuse_utils_1.parseInternalActivationAttributes)(attributes);
// TODO : Make this generic enough to compute default attributes for multi-dimensional conv
const autoPad = attributes.getString('auto_pad', 'NOTSET');
const dilations = attributes.getInts('dilations', [1, 1]);
const group = attributes.getInt('group', 1);
const kernelShape = attributes.getInts('kernel_shape', []);
const pads = attributes.getInts('pads', [0, 0, 0, 0]);
const strides = attributes.getInts('strides', [1, 1]);
return (0, attribute_with_cache_key_1.createAttributeWithCacheKey)(Object.assign({ autoPad, dilations, group, kernelShape, pads, strides }, activationAttributes));
};
exports.parseConvAttributes = parseConvAttributes;
const validateInputs = (inputs, attributes) => {
// Refer to the below link for all input checks
// https://github.com/onnx/onnx/blob/main/docs/Operators.md#Conv
if (!inputs || (inputs.length !== 2 && inputs.length !== 3)) {
throw new Error('Conv requires 2 or 3 inputs');
}
// TODO : Need to add support for multi-dimensional conv
if (inputs[0].dims.length !== 4 || inputs[1].dims.length !== 4) {
throw new Error('currently only support 2-dimensional conv');
}
// FILTER_IN_CHANNEL should be equal to DATA_CHANNEL
const dataChannel = inputs[0].dims[1];
const filterInChannel = inputs[1].dims[1] * attributes.group;
if (dataChannel !== filterInChannel) {
throw new Error('FILTER_IN_CHANNEL should be equal to DATA_CHANNEL');
}
// if bias is provided it should be 1D and the number of elements should be equal to the number of feature maps
if (inputs.length === 3 && (inputs[2].dims.length !== 1 || inputs[1].dims[0] !== inputs[2].dims[0])) {
throw new Error('invalid bias');
}
const spatialRank = inputs[0].dims.length - 2;
// wrong dilations dimension
if (attributes.dilations.length !== spatialRank) {
throw new Error(`dilations should be ${spatialRank}D`);
}
// Wrong strides dimension
if (attributes.strides.length !== spatialRank) {
throw new Error(`strides should be ${spatialRank}D`);
}
// Wrong pads dimension
if (attributes.pads.length !== spatialRank * 2) {
throw new Error(`pads should be ${spatialRank * 2}D`);
}
// if kernelShape is specified, it's data length must be 2 less than dims length of the weights tensor
// (the first 2 dims are batch_size and channels)
if (attributes.kernelShape.length !== 0 && attributes.kernelShape.length !== inputs[1].dims.length - 2) {
throw new Error('invalid kernel shape');
}
// TODO : Need to add support for float64
if (inputs[0].type !== 'float32' || inputs[1].type !== 'float32') {
throw new Error('Conv input(X,W) should be float tensor');
}
if (inputs.length === 3 && inputs[2].type !== 'float32') {
throw new Error('Conv input(bias) should be float tensor');
}
};
//# sourceMappingURL=conv.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,184 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
import {AttributeWithCacheKey, createAttributeWithCacheKey} from '../../../attribute-with-cache-key';
import {InferenceHandler} from '../../../backend';
import {Graph} from '../../../graph';
import {OperatorImplementation, OperatorInitialization} from '../../../operators';
import {Tensor} from '../../../tensor';
import {PoolConvUtil} from '../../../util';
import {WebGLInferenceHandler} from '../inference-handler';
import {createUnpackedGroupedConvProgramInfoLoader} from './conv-grouped';
import {conv2DPacked} from './conv-pack';
import {createDotProductProgramInfoLoader} from './dot-product';
import {InternalActivationAttributes, parseInternalActivationAttributes} from './fuse-utils';
import {createIm2ColProgramInfoLoader} from './im2col';
import {createMatmulProgramInfoLoader} from './matmul';
export const calculateOutputShape =
(inputShape: readonly number[], kernelShape: readonly number[], dilations: readonly number[],
adjustPads: readonly number[], strides: readonly number[]): number[] => {
const batchSize = inputShape[0];
const inputSpatialShape = inputShape.slice(2);
const spatialRank = inputSpatialShape.length;
const outChannels = kernelShape[0];
const kernelSpatialShape = kernelShape.slice(2);
const dilatedKernelShape = kernelSpatialShape.map((v, i) => v + (v - 1) * (dilations[i] - 1));
const inputSpatialShapeWithPad = inputSpatialShape.map((v, i) => v + adjustPads[i] + adjustPads[i + spatialRank]);
const outputSpatialShape =
inputSpatialShapeWithPad.map((v, i) => Math.floor((v - dilatedKernelShape[i] + strides[i]) / strides[i]));
const outputShape = [batchSize, outChannels].concat(...outputSpatialShape);
return outputShape;
};
export interface ConvAttributes extends InternalActivationAttributes, AttributeWithCacheKey {
readonly autoPad: string;
readonly dilations: readonly number[];
readonly group: number;
readonly kernelShape: readonly number[];
readonly pads: readonly number[];
readonly strides: readonly number[];
}
export const conv: OperatorImplementation<ConvAttributes> =
(inferenceHandler: InferenceHandler, inputs: Tensor[], attributes: ConvAttributes): Tensor[] => {
validateInputs(inputs, attributes); // currently will fail if not conv2D
return conv2d(inferenceHandler, inputs, attributes);
};
const conv2d: OperatorImplementation<ConvAttributes> =
(inferenceHandler: WebGLInferenceHandler, inputs: Tensor[], attributes: ConvAttributes): Tensor[] => {
const adjustedAttributes = getAdjustedConvAttributes(attributes, inputs);
const packMode = inferenceHandler.session.pack;
const isPointwise = adjustedAttributes.kernelShape[0] === 1 && adjustedAttributes.kernelShape[1] === 1;
if (adjustedAttributes.group > 1) {
const result = inferenceHandler.run(
createUnpackedGroupedConvProgramInfoLoader(inferenceHandler, inputs, adjustedAttributes), inputs);
return [result];
} else if (isPointwise && packMode) {
return [conv2DUnpackedPointwise(inferenceHandler, inputs, adjustedAttributes)];
} else if (packMode && inputs[0].dims.length === 4 && inputs[0].dims[0] === 1 && !isPointwise) {
return [conv2DPacked(inferenceHandler, inputs, adjustedAttributes)];
} else {
return [conv2DUnpacked(inferenceHandler, inputs, adjustedAttributes)];
}
};
const conv2DUnpackedPointwise =
(inferenceHandler: WebGLInferenceHandler, inputs: readonly Tensor[], attributes: ConvAttributes): Tensor => {
const xshape = inputs[0].dims;
const kshape = inputs[1].dims;
const outputShape =
calculateOutputShape(xshape, kshape, attributes.dilations, attributes.pads, attributes.strides);
const reshapedX = inferenceHandler.reshapeUnpacked(inputs[0], [xshape[1], xshape[2] * xshape[3]]);
const reshapedK = inferenceHandler.reshapeUnpacked(inputs[1], [kshape[0], kshape[1]]);
const matmulInputs = inputs.length > 2 ? [reshapedK, reshapedX, inputs[2]] : [reshapedK, reshapedX];
const matmulOutput = inferenceHandler.run(createMatmulProgramInfoLoader(matmulInputs, attributes), matmulInputs);
return inferenceHandler.reshapeUnpacked(matmulOutput, outputShape);
};
const conv2DUnpacked =
(inferenceHandler: WebGLInferenceHandler, inputs: readonly Tensor[], attributes: ConvAttributes): Tensor => {
const xshape = inputs[0].dims;
const kshape = inputs[1].dims;
const outputShape =
calculateOutputShape(xshape, kshape, attributes.dilations, attributes.pads, attributes.strides);
const xIm2Col = inferenceHandler.run(
createIm2ColProgramInfoLoader(inferenceHandler, inputs[0], inputs[1], outputShape, attributes), [inputs[0]]);
const dotProductInputs = inputs.length === 3 ? [xIm2Col, inputs[1], inputs[2]] : [xIm2Col, inputs[1]];
const output = inferenceHandler.run(
createDotProductProgramInfoLoader(inferenceHandler, inputs, outputShape, attributes), dotProductInputs);
return output;
};
const getAdjustedConvAttributes = <T extends ConvAttributes>(attributes: T, inputs: Tensor[]): T => {
const kernelShape = attributes.kernelShape.slice();
// if kernelShape is not specified in the attributes of this op, infer it from the weight tensor dims
if (attributes.kernelShape.length === 0) {
for (let i = 2; i < inputs[1].dims.length; ++i) {
kernelShape.push(inputs[1].dims[i]);
}
}
const pads = attributes.pads.slice();
PoolConvUtil.adjustPadsBasedOnAutoPad(
inputs[0].dims, attributes.strides, attributes.dilations, kernelShape, pads, attributes.autoPad);
// always return a new object so does not modify the original attributes
const newAttributes: T = Object.assign({}, attributes);
Object.assign(newAttributes, {kernelShape, pads, cacheKey: attributes.cacheKey});
return newAttributes;
};
export const parseConvAttributes: OperatorInitialization<ConvAttributes> = (node: Graph.Node): ConvAttributes => {
const attributes = node.attributes;
const activationAttributes = parseInternalActivationAttributes(attributes);
// TODO : Make this generic enough to compute default attributes for multi-dimensional conv
const autoPad = attributes.getString('auto_pad', 'NOTSET');
const dilations = attributes.getInts('dilations', [1, 1]);
const group = attributes.getInt('group', 1);
const kernelShape = attributes.getInts('kernel_shape', []);
const pads = attributes.getInts('pads', [0, 0, 0, 0]);
const strides = attributes.getInts('strides', [1, 1]);
return createAttributeWithCacheKey({autoPad, dilations, group, kernelShape, pads, strides, ...activationAttributes});
};
const validateInputs = (inputs: Tensor[], attributes: ConvAttributes): void => {
// Refer to the below link for all input checks
// https://github.com/onnx/onnx/blob/main/docs/Operators.md#Conv
if (!inputs || (inputs.length !== 2 && inputs.length !== 3)) {
throw new Error('Conv requires 2 or 3 inputs');
}
// TODO : Need to add support for multi-dimensional conv
if (inputs[0].dims.length !== 4 || inputs[1].dims.length !== 4) {
throw new Error('currently only support 2-dimensional conv');
}
// FILTER_IN_CHANNEL should be equal to DATA_CHANNEL
const dataChannel = inputs[0].dims[1];
const filterInChannel = inputs[1].dims[1] * attributes.group;
if (dataChannel !== filterInChannel) {
throw new Error('FILTER_IN_CHANNEL should be equal to DATA_CHANNEL');
}
// if bias is provided it should be 1D and the number of elements should be equal to the number of feature maps
if (inputs.length === 3 && (inputs[2].dims.length !== 1 || inputs[1].dims[0] !== inputs[2].dims[0])) {
throw new Error('invalid bias');
}
const spatialRank = inputs[0].dims.length - 2;
// wrong dilations dimension
if (attributes.dilations.length !== spatialRank) {
throw new Error(`dilations should be ${spatialRank}D`);
}
// Wrong strides dimension
if (attributes.strides.length !== spatialRank) {
throw new Error(`strides should be ${spatialRank}D`);
}
// Wrong pads dimension
if (attributes.pads.length !== spatialRank * 2) {
throw new Error(`pads should be ${spatialRank * 2}D`);
}
// if kernelShape is specified, it's data length must be 2 less than dims length of the weights tensor
// (the first 2 dims are batch_size and channels)
if (attributes.kernelShape.length !== 0 && attributes.kernelShape.length !== inputs[1].dims.length - 2) {
throw new Error('invalid kernel shape');
}
// TODO : Need to add support for float64
if (inputs[0].type !== 'float32' || inputs[1].type !== 'float32') {
throw new Error('Conv input(X,W) should be float tensor');
}
if (inputs.length === 3 && inputs[2].type !== 'float32') {
throw new Error('Conv input(bias) should be float tensor');
}
};

View File

@@ -0,0 +1,62 @@
"use strict";
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseDepthToSpaceAttributes = exports.depthToSpace = void 0;
const transpose_1 = require("./transpose");
const depthToSpace = (inferenceHandler, inputs, attributes) => {
validateInputs(inputs);
const blocksize = attributes.blocksize;
const blocksizeSqr = blocksize * blocksize;
const transposePerm = attributes.mode === 'DCR' ? [0, 3, 4, 1, 5, 2] : [0, 1, 4, 2, 5, 3];
const firstReshapeShape = attributes.mode === 'DCR' ?
[
inputs[0].dims[0], blocksize, blocksize, inputs[0].dims[1] / blocksizeSqr, inputs[0].dims[2],
inputs[0].dims[3]
] :
[
inputs[0].dims[0], inputs[0].dims[1] / blocksizeSqr, blocksize, blocksize, inputs[0].dims[2],
inputs[0].dims[3]
];
// const transpose = new WebGLTranspose();
// const attributes = new Attribute(undefined);
// attributes.set('perm', 'ints', transposePerm);
// transpose.initialize(attributes);
// First reshape
const firstReshapedTensor = inferenceHandler.reshapeUnpacked(inputs[0], firstReshapeShape);
// transpose
const transposeAttributes = { perm: transposePerm, cacheKey: `${transposePerm}` };
const [transposeOutput] = (0, transpose_1.transpose)(inferenceHandler, [firstReshapedTensor], transposeAttributes);
// Second reshape
const secondReshapeShape = [
inputs[0].dims[0], inputs[0].dims[1] / blocksizeSqr, inputs[0].dims[2] * blocksize,
inputs[0].dims[3] * blocksize
];
const result = inferenceHandler.reshapeUnpacked(transposeOutput, secondReshapeShape);
return [result];
};
exports.depthToSpace = depthToSpace;
const parseDepthToSpaceAttributes = (node) => {
// processing node attributes
const blocksize = node.attributes.getInt('blocksize');
if (blocksize < 1) {
throw new Error(`blocksize must be >= 1, but got : ${blocksize} for DepthToSpace`);
}
const mode = node.attributes.getString('mode', 'DCR');
if (mode !== 'DCR' && mode !== 'CRD') {
throw new Error(`unrecognized mode: ${mode} for DepthToSpace`);
}
return { mode, blocksize };
};
exports.parseDepthToSpaceAttributes = parseDepthToSpaceAttributes;
const validateInputs = (inputs) => {
if (inputs.length !== 1) {
throw new Error(`DepthToSpace expect 1 inputs, but got ${inputs.length}`);
}
// Input has to be a 4-D tensor
// TODO: Support string depth-to-space.
if (inputs[0].type === 'string' || inputs[0].dims.length !== 4) {
throw new TypeError('DepthToSpace input should be a 4-D numeric tensor');
}
};
//# sourceMappingURL=depth-to-space.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"depth-to-space.js","sourceRoot":"","sources":["depth-to-space.ts"],"names":[],"mappings":"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"}

View File

@@ -0,0 +1,77 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
import {Graph} from '../../../graph';
import {OperatorImplementation, OperatorInitialization} from '../../../operators';
import {Tensor} from '../../../tensor';
import {WebGLInferenceHandler} from '../inference-handler';
import {transpose, TransposeAttributes} from './transpose';
export interface DepthToSpaceAttributes {
mode: 'DCR'|'CRD';
blocksize: number;
}
export const depthToSpace: OperatorImplementation<DepthToSpaceAttributes> =
(inferenceHandler: WebGLInferenceHandler, inputs: Tensor[], attributes: DepthToSpaceAttributes): Tensor[] => {
validateInputs(inputs);
const blocksize = attributes.blocksize;
const blocksizeSqr = blocksize * blocksize;
const transposePerm = attributes.mode === 'DCR' ? [0, 3, 4, 1, 5, 2] : [0, 1, 4, 2, 5, 3];
const firstReshapeShape = attributes.mode === 'DCR' ?
[
inputs[0].dims[0], blocksize, blocksize, inputs[0].dims[1] / blocksizeSqr, inputs[0].dims[2],
inputs[0].dims[3]
] :
[
inputs[0].dims[0], inputs[0].dims[1] / blocksizeSqr, blocksize, blocksize, inputs[0].dims[2],
inputs[0].dims[3]
];
// const transpose = new WebGLTranspose();
// const attributes = new Attribute(undefined);
// attributes.set('perm', 'ints', transposePerm);
// transpose.initialize(attributes);
// First reshape
const firstReshapedTensor = inferenceHandler.reshapeUnpacked(inputs[0], firstReshapeShape);
// transpose
const transposeAttributes: TransposeAttributes = {perm: transposePerm, cacheKey: `${transposePerm}`};
const [transposeOutput] = transpose(inferenceHandler, [firstReshapedTensor], transposeAttributes);
// Second reshape
const secondReshapeShape = [
inputs[0].dims[0], inputs[0].dims[1] / blocksizeSqr, inputs[0].dims[2] * blocksize,
inputs[0].dims[3] * blocksize
];
const result = inferenceHandler.reshapeUnpacked(transposeOutput, secondReshapeShape);
return [result];
};
export const parseDepthToSpaceAttributes: OperatorInitialization<DepthToSpaceAttributes> =
(node: Graph.Node): DepthToSpaceAttributes => {
// processing node attributes
const blocksize = node.attributes.getInt('blocksize');
if (blocksize < 1) {
throw new Error(`blocksize must be >= 1, but got : ${blocksize} for DepthToSpace`);
}
const mode = node.attributes.getString('mode', 'DCR');
if (mode !== 'DCR' && mode !== 'CRD') {
throw new Error(`unrecognized mode: ${mode} for DepthToSpace`);
}
return {mode, blocksize};
};
const validateInputs = (inputs: Tensor[]): void => {
if (inputs.length !== 1) {
throw new Error(`DepthToSpace expect 1 inputs, but got ${inputs.length}`);
}
// Input has to be a 4-D tensor
// TODO: Support string depth-to-space.
if (inputs[0].type === 'string' || inputs[0].dims.length !== 4) {
throw new TypeError('DepthToSpace input should be a 4-D numeric tensor');
}
};

View File

@@ -0,0 +1,60 @@
"use strict";
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
Object.defineProperty(exports, "__esModule", { value: true });
exports.createDotProductProgramInfoLoader = void 0;
const util_1 = require("../../../util");
const glsl_source_1 = require("../glsl-source");
const types_1 = require("../types");
const fuse_utils_1 = require("./fuse-utils");
const im2col_1 = require("./im2col");
const createDotProductProgramMetadata = (hasBias, attributes) => ({
name: 'ConvDotProduct',
inputNames: hasBias ? ['Im2Col', 'K', 'B'] : ['Im2Col', 'K'],
inputTypes: hasBias ? [types_1.TextureType.unpacked, types_1.TextureType.packedLastDimension, types_1.TextureType.unpacked] :
[types_1.TextureType.unpacked, types_1.TextureType.packedLastDimension],
cacheKey: attributes.activationCacheKey
});
const createDotProductProgramInfo = (inferenceHandler, metadata, inputs, outputShape, attributes) => {
const xshape = inputs[0].dims;
const kshape = inputs[1].dims;
const adjustedKernelShape = [kshape[0], Math.ceil((xshape[1] * kshape[2] * kshape[3]) / 4)];
const im2colShape = (0, im2col_1.calculateIm2ColDims)(xshape, kshape, outputShape);
const [kWidth, kHeight] = inferenceHandler.calculateTextureWidthAndHeight(adjustedKernelShape, types_1.TextureType.packedLastDimension);
const im2colStrides = util_1.ShapeUtil.computeStrides(im2colShape);
const [im2colWidth, im2colHeight] = inferenceHandler.calculateTextureWidthAndHeight(im2colShape, types_1.TextureType.packedLastDimension);
const rank = outputShape.length;
const initValue = (inputs.length < 3) ? '0.0' : '_B(b)';
const sharedDim = Math.ceil(xshape[1] * kshape[2] * kshape[3] / 4);
const { activationFunction, applyActivation } = (0, fuse_utils_1.getActivationSnippet)(attributes);
const glsl = (0, glsl_source_1.getGlsl)(inferenceHandler.session.backend.glContext.version);
const shaderSource = `
${activationFunction}
float process(int indices[${rank}]) {
int b[1];
b[0] = indices[1];
int im2col[4];
im2col[0] = indices[0];
im2col[1] = indices[2];
im2col[2] = indices[3];
int im2colOffset = im2col[0] * ${im2colStrides[0]} + im2col[1] * ${im2colStrides[1]} + im2col[2] * ${im2colStrides[2]};
int kernelOffset = indices[1] * ${adjustedKernelShape[1]};
float value = ${initValue};
for (int i = 0; i < ${sharedDim}; ++i) {
vec2 im2colCoords = offsetToCoords(im2colOffset, ${im2colWidth}, ${im2colHeight});
vec2 kernelCoords = offsetToCoords(kernelOffset, ${kWidth}, ${kHeight});
value += dot(${glsl.texture2D}(Im2Col, im2colCoords), ${glsl.texture2D}(K, kernelCoords));
++im2colOffset;
++kernelOffset;
}
${applyActivation}
return value;
}`;
return Object.assign(Object.assign({}, metadata), { output: { dims: outputShape, type: inputs[0].type, textureType: types_1.TextureType.unpacked }, shaderSource });
};
const createDotProductProgramInfoLoader = (inferenceHandler, inputs, outputShape, attributes) => {
const metadata = createDotProductProgramMetadata(inputs.length > 2, attributes);
return Object.assign(Object.assign({}, metadata), { get: () => createDotProductProgramInfo(inferenceHandler, metadata, inputs, outputShape, attributes) });
};
exports.createDotProductProgramInfoLoader = createDotProductProgramInfoLoader;
//# sourceMappingURL=dot-product.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"dot-product.js","sourceRoot":"","sources":["dot-product.ts"],"names":[],"mappings":"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"}

View File

@@ -0,0 +1,78 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
import {Tensor} from '../../../tensor';
import {ShapeUtil} from '../../../util';
import {getGlsl} from '../glsl-source';
import {WebGLInferenceHandler} from '../inference-handler';
import {ProgramInfo, ProgramInfoLoader, ProgramMetadata, TextureType} from '../types';
import {getActivationSnippet, InternalActivationAttributes} from './fuse-utils';
import {calculateIm2ColDims} from './im2col';
const createDotProductProgramMetadata = (hasBias: boolean, attributes: InternalActivationAttributes) => ({
name: 'ConvDotProduct',
inputNames: hasBias ? ['Im2Col', 'K', 'B'] : ['Im2Col', 'K'],
inputTypes: hasBias ? [TextureType.unpacked, TextureType.packedLastDimension, TextureType.unpacked] :
[TextureType.unpacked, TextureType.packedLastDimension],
cacheKey: attributes.activationCacheKey
});
const createDotProductProgramInfo =
(inferenceHandler: WebGLInferenceHandler, metadata: ProgramMetadata, inputs: readonly Tensor[],
outputShape: number[], attributes: InternalActivationAttributes): ProgramInfo => {
const xshape = inputs[0].dims;
const kshape = inputs[1].dims;
const adjustedKernelShape = [kshape[0], Math.ceil((xshape[1] * kshape[2] * kshape[3]) / 4)];
const im2colShape = calculateIm2ColDims(xshape, kshape, outputShape);
const [kWidth, kHeight] =
inferenceHandler.calculateTextureWidthAndHeight(adjustedKernelShape, TextureType.packedLastDimension);
const im2colStrides = ShapeUtil.computeStrides(im2colShape);
const [im2colWidth, im2colHeight] =
inferenceHandler.calculateTextureWidthAndHeight(im2colShape, TextureType.packedLastDimension);
const rank = outputShape.length;
const initValue = (inputs.length < 3) ? '0.0' : '_B(b)';
const sharedDim = Math.ceil(xshape[1] * kshape[2] * kshape[3] / 4);
const {activationFunction, applyActivation} = getActivationSnippet(attributes);
const glsl = getGlsl(inferenceHandler.session.backend.glContext.version);
const shaderSource = `
${activationFunction}
float process(int indices[${rank}]) {
int b[1];
b[0] = indices[1];
int im2col[4];
im2col[0] = indices[0];
im2col[1] = indices[2];
im2col[2] = indices[3];
int im2colOffset = im2col[0] * ${im2colStrides[0]} + im2col[1] * ${im2colStrides[1]} + im2col[2] * ${
im2colStrides[2]};
int kernelOffset = indices[1] * ${adjustedKernelShape[1]};
float value = ${initValue};
for (int i = 0; i < ${sharedDim}; ++i) {
vec2 im2colCoords = offsetToCoords(im2colOffset, ${im2colWidth}, ${im2colHeight});
vec2 kernelCoords = offsetToCoords(kernelOffset, ${kWidth}, ${kHeight});
value += dot(${glsl.texture2D}(Im2Col, im2colCoords), ${glsl.texture2D}(K, kernelCoords));
++im2colOffset;
++kernelOffset;
}
${applyActivation}
return value;
}`;
return {
...metadata,
output: {dims: outputShape, type: inputs[0].type, textureType: TextureType.unpacked},
shaderSource
};
};
export const createDotProductProgramInfoLoader =
(inferenceHandler: WebGLInferenceHandler, inputs: readonly Tensor[], outputShape: number[],
attributes: InternalActivationAttributes): ProgramInfoLoader => {
const metadata = createDotProductProgramMetadata(inputs.length > 2, attributes);
return {
...metadata,
get: () => createDotProductProgramInfo(inferenceHandler, metadata, inputs, outputShape, attributes)
};
};

View File

@@ -0,0 +1,31 @@
"use strict";
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseFlattenAttributes = exports.flatten = void 0;
const util_1 = require("../../../util");
const flatten = (inferenceHandler, inputs, axis) => {
validateInputs(inputs, axis);
const outputDims = util_1.ShapeUtil.flattenShape(inputs[0].dims, axis);
return [inferenceHandler.reshapeUnpacked(inputs[0], outputDims)];
};
exports.flatten = flatten;
const parseFlattenAttributes = (node) => node.attributes.getInt('axis', 1); // default axis is 1
exports.parseFlattenAttributes = parseFlattenAttributes;
const validateInputs = (inputs, axis) => {
if (!inputs || inputs.length !== 1) {
throw new Error('Flatten requires 1 input.');
}
const r = inputs[0].dims.length;
if (r === 0) {
throw new Error('scalar tensor is not supported.');
}
if (axis < -r || axis > r) {
throw new Error('Invalid axis');
}
// TODO: Support string type
if (inputs[0].type === 'string') {
throw new Error('string tensor is not supported.');
}
};
//# sourceMappingURL=flatten.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"flatten.js","sourceRoot":"","sources":["flatten.ts"],"names":[],"mappings":";AAAA,4DAA4D;AAC5D,kCAAkC;;;AAKlC,wCAAwC;AAGjC,MAAM,OAAO,GAChB,CAAC,gBAAuC,EAAE,MAAgB,EAAE,IAAY,EAAY,EAAE;IACpF,cAAc,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IAE7B,MAAM,UAAU,GAAG,gBAAS,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAChE,OAAO,CAAC,gBAAgB,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,CAAC;AACnE,CAAC,CAAC;AANO,QAAA,OAAO,WAMd;AAEC,MAAM,sBAAsB,GAAmC,CAAC,IAAgB,EAAU,EAAE,CAC/F,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAAE,oBAAoB;AAD/C,QAAA,sBAAsB,0BACG;AAEtC,MAAM,cAAc,GAAG,CAAC,MAAgB,EAAE,IAAY,EAAQ,EAAE;IAC9D,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE;QAClC,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAC;KAC9C;IAED,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC;IAChC,IAAI,CAAC,KAAK,CAAC,EAAE;QACX,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAC;KACpD;IAED,IAAI,IAAI,GAAG,CAAC,CAAC,IAAI,IAAI,GAAG,CAAC,EAAE;QACzB,MAAM,IAAI,KAAK,CAAC,cAAc,CAAC,CAAC;KACjC;IAED,4BAA4B;IAC5B,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,QAAQ,EAAE;QAC/B,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAC;KACpD;AACH,CAAC,CAAC"}

View File

@@ -0,0 +1,39 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
import {Graph} from '../../../graph';
import {OperatorImplementation, OperatorInitialization} from '../../../operators';
import {Tensor} from '../../../tensor';
import {ShapeUtil} from '../../../util';
import {WebGLInferenceHandler} from '../inference-handler';
export const flatten: OperatorImplementation<number> =
(inferenceHandler: WebGLInferenceHandler, inputs: Tensor[], axis: number): Tensor[] => {
validateInputs(inputs, axis);
const outputDims = ShapeUtil.flattenShape(inputs[0].dims, axis);
return [inferenceHandler.reshapeUnpacked(inputs[0], outputDims)];
};
export const parseFlattenAttributes: OperatorInitialization<number> = (node: Graph.Node): number =>
node.attributes.getInt('axis', 1); // default axis is 1
const validateInputs = (inputs: Tensor[], axis: number): void => {
if (!inputs || inputs.length !== 1) {
throw new Error('Flatten requires 1 input.');
}
const r = inputs[0].dims.length;
if (r === 0) {
throw new Error('scalar tensor is not supported.');
}
if (axis < -r || axis > r) {
throw new Error('Invalid axis');
}
// TODO: Support string type
if (inputs[0].type === 'string') {
throw new Error('string tensor is not supported.');
}
};

View File

@@ -0,0 +1,39 @@
"use strict";
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseInternalActivationAttributes = exports.getActivationSnippet = void 0;
const util_1 = require("../../../util");
const unary_op_1 = require("./unary-op");
function getActivationSnippet(attributes) {
let func;
switch (attributes.activation) {
case 'Relu':
func = (0, unary_op_1.glslRelu)();
break;
case 'Sigmoid':
func = (0, unary_op_1.glslSigmoid)();
break;
case 'Clip':
func = (0, unary_op_1.glslClip)(attributes.clipMin, attributes.clipMax);
break;
// TODO: adding other activations that can be fused.
default:
return { activationFunction: '', applyActivation: '' };
}
const activationName = func.name;
const activationFunction = func.body;
const applyActivation = `value = ${activationName}_(value);`;
return { activationFunction, applyActivation };
}
exports.getActivationSnippet = getActivationSnippet;
const parseInternalActivationAttributes = (attributes) => {
const activation = attributes.getString('activation', '');
if (activation === 'Clip') {
const [clipMin, clipMax] = attributes.getFloats('activation_params', [util_1.MIN_CLIP, util_1.MAX_CLIP]);
return { activation, clipMax, clipMin, activationCacheKey: `${activation}:${clipMin},${clipMax}` };
}
return { activation, activationCacheKey: activation };
};
exports.parseInternalActivationAttributes = parseInternalActivationAttributes;
//# sourceMappingURL=fuse-utils.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"fuse-utils.js","sourceRoot":"","sources":["fuse-utils.ts"],"names":[],"mappings":";AAAA,4DAA4D;AAC5D,kCAAkC;;;AAGlC,wCAAiD;AAGjD,yCAA2D;AAS3D,SAAgB,oBAAoB,CAAC,UAAwC;IAC3E,IAAI,IAAuB,CAAC;IAC5B,QAAQ,UAAU,CAAC,UAAU,EAAE;QAC7B,KAAK,MAAM;YACT,IAAI,GAAG,IAAA,mBAAQ,GAAE,CAAC;YAClB,MAAM;QACR,KAAK,SAAS;YACZ,IAAI,GAAG,IAAA,sBAAW,GAAE,CAAC;YACrB,MAAM;QACR,KAAK,MAAM;YACT,IAAI,GAAG,IAAA,mBAAQ,EAAC,UAAU,CAAC,OAAQ,EAAE,UAAU,CAAC,OAAQ,CAAC,CAAC;YAC1D,MAAM;QACR,oDAAoD;QACpD;YACE,OAAO,EAAC,kBAAkB,EAAE,EAAE,EAAE,eAAe,EAAE,EAAE,EAAC,CAAC;KACxD;IAED,MAAM,cAAc,GAAG,IAAI,CAAC,IAAI,CAAC;IACjC,MAAM,kBAAkB,GAAG,IAAI,CAAC,IAAI,CAAC;IACrC,MAAM,eAAe,GAAG,WAAW,cAAc,WAAW,CAAC;IAC7D,OAAO,EAAC,kBAAkB,EAAE,eAAe,EAAC,CAAC;AAC/C,CAAC;AArBD,oDAqBC;AAEM,MAAM,iCAAiC,GAAG,CAAC,UAAqB,EAAgC,EAAE;IACvG,MAAM,UAAU,GAAG,UAAU,CAAC,SAAS,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC;IAE1D,IAAI,UAAU,KAAK,MAAM,EAAE;QACzB,MAAM,CAAC,OAAO,EAAE,OAAO,CAAC,GAAG,UAAU,CAAC,SAAS,CAAC,mBAAmB,EAAE,CAAC,eAAQ,EAAE,eAAQ,CAAC,CAAC,CAAC;QAC3F,OAAO,EAAC,UAAU,EAAE,OAAO,EAAE,OAAO,EAAE,kBAAkB,EAAE,GAAG,UAAU,IAAI,OAAO,IAAI,OAAO,EAAE,EAAC,CAAC;KAClG;IACD,OAAO,EAAC,UAAU,EAAE,kBAAkB,EAAE,UAAU,EAAC,CAAC;AACtD,CAAC,CAAC;AARW,QAAA,iCAAiC,qCAQ5C"}

View File

@@ -0,0 +1,48 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
import {Attribute} from '../../../attribute';
import {MAX_CLIP, MIN_CLIP} from '../../../util';
import {GlslValueFunction} from '../glsl-definitions';
import {glslClip, glslRelu, glslSigmoid} from './unary-op';
export interface InternalActivationAttributes {
readonly activation: string;
readonly clipMin?: number;
readonly clipMax?: number;
readonly activationCacheKey: string;
}
export function getActivationSnippet(attributes: InternalActivationAttributes) {
let func: GlslValueFunction;
switch (attributes.activation) {
case 'Relu':
func = glslRelu();
break;
case 'Sigmoid':
func = glslSigmoid();
break;
case 'Clip':
func = glslClip(attributes.clipMin!, attributes.clipMax!);
break;
// TODO: adding other activations that can be fused.
default:
return {activationFunction: '', applyActivation: ''};
}
const activationName = func.name;
const activationFunction = func.body;
const applyActivation = `value = ${activationName}_(value);`;
return {activationFunction, applyActivation};
}
export const parseInternalActivationAttributes = (attributes: Attribute): InternalActivationAttributes => {
const activation = attributes.getString('activation', '');
if (activation === 'Clip') {
const [clipMin, clipMax] = attributes.getFloats('activation_params', [MIN_CLIP, MAX_CLIP]);
return {activation, clipMax, clipMin, activationCacheKey: `${activation}:${clipMin},${clipMax}`};
}
return {activation, activationCacheKey: activation};
};

View File

@@ -0,0 +1,87 @@
"use strict";
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseGatherAttributes = exports.gather = void 0;
const attribute_with_cache_key_1 = require("../../../attribute-with-cache-key");
const operators_1 = require("../../../operators");
const util_1 = require("../../../util");
const types_1 = require("../types");
const gather = (inferenceHandler, inputs, attributes) => {
validateInputs(inputs, attributes.axis);
const output = inferenceHandler.run(createGatherProgramInfoLoader(inferenceHandler, inputs, attributes), inputs);
return [output];
};
exports.gather = gather;
const parseGatherAttributes = (node) => (0, attribute_with_cache_key_1.createAttributeWithCacheKey)({ axis: node.attributes.getInt('axis', 0) });
exports.parseGatherAttributes = parseGatherAttributes;
const gatherProgramMetadata = {
name: 'Gather',
inputNames: ['A', 'B'],
inputTypes: [types_1.TextureType.unpacked, types_1.TextureType.unpacked],
};
const createGatherProgramInfo = (handler, metadata, inputs, axis) => {
const inputShape = inputs[0].dims.slice();
const indexDataShape = inputs[1].dims.slice();
const outputShape = new Array(inputShape.length + indexDataShape.length - 1);
axis = util_1.ShapeUtil.normalizeAxis(axis, inputShape.length);
const indexCopyOps = [];
for (let i = 0; i < outputShape.length; i++) {
// outputShape is divided into three parts: A, B, C
// |0 axis| axis + indexDataShape.length | end|
// | A | B | C |
//
// inputIdx: [A, inputs[1][B], C]
if (i < axis) { // A
outputShape[i] = inputShape[i];
indexCopyOps.push(`inputIdx[${i}] = outputIdx[${i}];`);
}
else {
if (i < axis + indexDataShape.length) { // B
outputShape[i] = indexDataShape[i - axis];
indexCopyOps.push(`indexDataIdx[${i - axis}] = outputIdx[${i}];`);
}
else { // C
outputShape[i] = inputShape[i - indexDataShape.length + 1]; // skip 1 for axis
indexCopyOps.push(`inputIdx[${i - indexDataShape.length + 1}] = outputIdx[${i}];`);
}
}
}
const orank = outputShape.length || 1;
const irank = inputShape.length;
const iDrank = indexDataShape.length || 1;
const shaderSource = `
float process(int outputIdx[${orank}]) {
int inputIdx[${irank}];
int indexDataIdx[${iDrank}];
indexDataIdx[0] = 0;
${indexCopyOps.join('\n ')}
int idx = int(_B(indexDataIdx));
inputIdx[${axis}] = idx < 0 ? idx + ${inputShape[axis]} : idx;
return _A(inputIdx);
}`;
return Object.assign(Object.assign({}, metadata), { output: { dims: outputShape, type: inputs[0].type, textureType: types_1.TextureType.unpacked }, shaderSource });
};
const createGatherProgramInfoLoader = (handler, inputs, attributes) => {
const metadata = Object.assign(Object.assign({}, gatherProgramMetadata), { cacheHint: attributes.cacheKey });
return Object.assign(Object.assign({}, metadata), { get: () => createGatherProgramInfo(handler, metadata, inputs, attributes.axis) });
};
const validateInputs = (inputs, axis) => {
if (!inputs || inputs.length !== 2) {
throw new Error('Gather requires 2 inputs.');
}
const tensorRank = inputs[0].dims.length;
if (tensorRank < 1) {
throw new Error('Invalid input shape.');
}
if (axis < -tensorRank || axis > tensorRank - 1) {
throw new Error('Invalid axis.');
}
if (operators_1.NUMBER_TYPES.indexOf(inputs[0].type) === -1) {
throw new Error('Invaid input type.');
}
if (inputs[1].type !== 'int32' && inputs[1].type !== 'int16') {
throw new Error('Invaid input type.');
}
};
//# sourceMappingURL=gather.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"gather.js","sourceRoot":"","sources":["gather.ts"],"names":[],"mappings":"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"}

View File

@@ -0,0 +1,103 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
import {AttributeWithCacheKey, createAttributeWithCacheKey} from '../../../attribute-with-cache-key';
import {Graph} from '../../../graph';
import {NUMBER_TYPES, OperatorImplementation, OperatorInitialization} from '../../../operators';
import {Tensor} from '../../../tensor';
import {ShapeUtil} from '../../../util';
import {WebGLInferenceHandler} from '../inference-handler';
import {ProgramInfo, ProgramInfoLoader, ProgramMetadata, TextureType} from '../types';
interface GatherAttributes extends AttributeWithCacheKey {
readonly axis: number;
}
export const gather: OperatorImplementation<GatherAttributes> =
(inferenceHandler: WebGLInferenceHandler, inputs: Tensor[], attributes: GatherAttributes): Tensor[] => {
validateInputs(inputs, attributes.axis);
const output = inferenceHandler.run(createGatherProgramInfoLoader(inferenceHandler, inputs, attributes), inputs);
return [output];
};
export const parseGatherAttributes: OperatorInitialization<GatherAttributes> = (node: Graph.Node): GatherAttributes =>
createAttributeWithCacheKey({axis: node.attributes.getInt('axis', 0)});
const gatherProgramMetadata = {
name: 'Gather',
inputNames: ['A', 'B'],
inputTypes: [TextureType.unpacked, TextureType.unpacked],
};
const createGatherProgramInfo =
(handler: WebGLInferenceHandler, metadata: ProgramMetadata, inputs: Tensor[], axis: number): ProgramInfo => {
const inputShape = inputs[0].dims.slice();
const indexDataShape = inputs[1].dims.slice();
const outputShape = new Array(inputShape.length + indexDataShape.length - 1);
axis = ShapeUtil.normalizeAxis(axis, inputShape.length);
const indexCopyOps: string[] = [];
for (let i = 0; i < outputShape.length; i++) {
// outputShape is divided into three parts: A, B, C
// |0 axis| axis + indexDataShape.length | end|
// | A | B | C |
//
// inputIdx: [A, inputs[1][B], C]
if (i < axis) { // A
outputShape[i] = inputShape[i];
indexCopyOps.push(`inputIdx[${i}] = outputIdx[${i}];`);
} else {
if (i < axis + indexDataShape.length) { // B
outputShape[i] = indexDataShape[i - axis];
indexCopyOps.push(`indexDataIdx[${i - axis}] = outputIdx[${i}];`);
} else { // C
outputShape[i] = inputShape[i - indexDataShape.length + 1]; // skip 1 for axis
indexCopyOps.push(`inputIdx[${i - indexDataShape.length + 1}] = outputIdx[${i}];`);
}
}
}
const orank = outputShape.length || 1;
const irank = inputShape.length;
const iDrank = indexDataShape.length || 1;
const shaderSource = `
float process(int outputIdx[${orank}]) {
int inputIdx[${irank}];
int indexDataIdx[${iDrank}];
indexDataIdx[0] = 0;
${indexCopyOps.join('\n ')}
int idx = int(_B(indexDataIdx));
inputIdx[${axis}] = idx < 0 ? idx + ${inputShape[axis]} : idx;
return _A(inputIdx);
}`;
return {
...metadata,
output: {dims: outputShape, type: inputs[0].type, textureType: TextureType.unpacked},
shaderSource
};
};
const createGatherProgramInfoLoader =
(handler: WebGLInferenceHandler, inputs: Tensor[], attributes: GatherAttributes): ProgramInfoLoader => {
const metadata = {...gatherProgramMetadata, cacheHint: attributes.cacheKey};
return {...metadata, get: () => createGatherProgramInfo(handler, metadata, inputs, attributes.axis)};
};
const validateInputs = (inputs: Tensor[], axis: number): void => {
if (!inputs || inputs.length !== 2) {
throw new Error('Gather requires 2 inputs.');
}
const tensorRank = inputs[0].dims.length;
if (tensorRank < 1) {
throw new Error('Invalid input shape.');
}
if (axis < -tensorRank || axis > tensorRank - 1) {
throw new Error('Invalid axis.');
}
if (NUMBER_TYPES.indexOf(inputs[0].type) === -1) {
throw new Error('Invaid input type.');
}
if (inputs[1].type !== 'int32' && inputs[1].type !== 'int16') {
throw new Error('Invaid input type.');
}
};

View File

@@ -0,0 +1,113 @@
"use strict";
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseGemmAttributesV11 = exports.parseGemmAttributesV7 = exports.gemm = void 0;
const attribute_with_cache_key_1 = require("../../../attribute-with-cache-key");
const util_1 = require("../../../util");
const types_1 = require("../types");
const gemm = (inferenceHandler, inputs, attributes) => {
validateInputs(inputs, attributes);
const output = inferenceHandler.run(createGemmProgramInfoLoader(inputs, attributes), inputs);
return [output];
};
exports.gemm = gemm;
const parseGemmAttributes = (node, isOptionalC) => {
const transA = node.attributes.getInt('transA', 0) !== 0;
const transB = node.attributes.getInt('transB', 0) !== 0;
const alpha = node.attributes.getFloat('alpha', 1.0);
const beta = node.attributes.getFloat('beta', 1.0);
return (0, attribute_with_cache_key_1.createAttributeWithCacheKey)({ transA, transB, alpha, beta, isOptionalC });
};
const parseGemmAttributesV7 = (node) => parseGemmAttributes(node, false);
exports.parseGemmAttributesV7 = parseGemmAttributesV7;
const parseGemmAttributesV11 = (node) => parseGemmAttributes(node, true);
exports.parseGemmAttributesV11 = parseGemmAttributesV11;
const createGemmProgramInfoLoader = (inputs, attributes) => {
const metadata = {
name: 'Gemm',
inputNames: inputs.length === 3 ? ['A', 'B', 'C'] : ['A', 'B'],
inputTypes: inputs.length === 3 ? [types_1.TextureType.unpacked, types_1.TextureType.unpacked, types_1.TextureType.unpacked] :
[types_1.TextureType.unpacked, types_1.TextureType.unpacked],
key: attributes.cacheKey
};
return Object.assign(Object.assign({}, metadata), { get: () => createGemmProgramInfo(metadata, inputs, attributes) });
};
const createGemmProgramInfo = (metadata, inputs, attributes) => {
const aShape = inputs[0].dims.slice();
const bShape = inputs[1].dims.slice();
const [M, N] = util_1.GemmUtil.getShapeOfGemmResult(aShape, attributes.transA, bShape, attributes.transB, inputs.length === 3 ? inputs[2].dims : undefined);
const outputShape = [M, N];
if (!outputShape) {
throw new Error('Can\'t use gemm on the given tensors');
}
let sharedDim = aShape[aShape.length - 1];
let line = '';
if (attributes.transA) {
sharedDim = aShape[0];
}
if (attributes.transA && attributes.transB) {
line = 'value += _A_T(a) * _B_T(b);';
}
else if (attributes.transA && !attributes.transB) {
line = 'value += _A_T(a) * _B(b);';
}
else if (!attributes.transA && attributes.transB) {
line = 'value += _A(a) * _B_T(b);';
}
else if (!attributes.transA && !attributes.transB) {
line = 'value += _A(a) * _B(b);';
}
const rank = outputShape.length;
const declareC = inputs.length === 3 ? `int c[${inputs[2].dims.length}];` : '';
const broadcastC = inputs.length === 3 ? 'bcastIndices_C(indices, c);' : '';
const calculateC = inputs.length === 3 ? 'value += beta * _C(c);' : '';
const shaderSource = `
float process(int indices[${rank}]) {
int a[${rank}];
int b[${rank}];
${declareC}
copyVec(indices, a);
copyVec(indices, b);
${broadcastC}
float value = 0.0;
for (int k=0; k<${sharedDim}; ++k) {
a[${rank - 1}] = k;
b[${rank - 2}] = k;
${line}
}
value = value * alpha;
${calculateC}
return value;
}`;
return Object.assign(Object.assign({}, metadata), { output: { dims: outputShape, type: inputs[0].type, textureType: types_1.TextureType.unpacked }, variables: [
{ name: 'alpha', type: 'float', data: attributes.alpha }, { name: 'beta', type: 'float', data: attributes.beta }
], shaderSource });
};
const validateInputs = (inputs, attributes) => {
if (!inputs) {
throw new Error('Input is missing');
}
if (attributes.isOptionalC && (inputs.length < 2 || inputs.length > 3)) {
throw new Error('Invaid input shape.');
}
if (!attributes.isOptionalC && inputs.length !== 3) {
throw new Error('Gemm requires 3 inputs');
}
// 'C' can be of dimensionality 1 or 2 only
if (inputs.length === 3 && inputs[2].dims.length !== 1 && inputs[2].dims.length !== 2) {
throw new Error('Invalid input shape of C');
}
if ((inputs[0].type !== 'float32' && inputs[0].type !== 'float64') ||
(inputs[1].type !== 'float32' && inputs[1].type !== 'float64') ||
(inputs.length === 3 && inputs[2].type !== 'float32' && inputs[2].type !== 'float64')) {
throw new Error('Invalid input type.');
}
if ((inputs[0].type !== inputs[1].type) || (inputs.length === 3 && inputs[0].type !== inputs[2].type)) {
throw new Error('Input types are mismatched');
}
};
//# sourceMappingURL=gemm.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"gemm.js","sourceRoot":"","sources":["gemm.ts"],"names":[],"mappings":"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"}

View File

@@ -0,0 +1,137 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
import {AttributeWithCacheKey, createAttributeWithCacheKey} from '../../../attribute-with-cache-key';
import {Graph} from '../../../graph';
import {OperatorImplementation, OperatorInitialization} from '../../../operators';
import {Tensor} from '../../../tensor';
import {GemmUtil} from '../../../util';
import {WebGLInferenceHandler} from '../inference-handler';
import {ProgramInfo, ProgramInfoLoader, ProgramMetadata, TextureType} from '../types';
export interface GemmAttributes extends AttributeWithCacheKey {
transA: boolean;
transB: boolean;
alpha: number;
beta: number;
isOptionalC: boolean; // in opset 11, C becomes optional
}
export const gemm: OperatorImplementation<GemmAttributes> =
(inferenceHandler: WebGLInferenceHandler, inputs: Tensor[], attributes: GemmAttributes): Tensor[] => {
validateInputs(inputs, attributes);
const output = inferenceHandler.run(createGemmProgramInfoLoader(inputs, attributes), inputs);
return [output];
};
const parseGemmAttributes = (node: Graph.Node, isOptionalC: boolean): GemmAttributes => {
const transA = node.attributes.getInt('transA', 0) !== 0;
const transB = node.attributes.getInt('transB', 0) !== 0;
const alpha = node.attributes.getFloat('alpha', 1.0);
const beta = node.attributes.getFloat('beta', 1.0);
return createAttributeWithCacheKey({transA, transB, alpha, beta, isOptionalC});
};
export const parseGemmAttributesV7: OperatorInitialization<GemmAttributes> = (node: Graph.Node): GemmAttributes =>
parseGemmAttributes(node, false);
export const parseGemmAttributesV11: OperatorInitialization<GemmAttributes> = (node: Graph.Node): GemmAttributes =>
parseGemmAttributes(node, true);
const createGemmProgramInfoLoader = (inputs: Tensor[], attributes: GemmAttributes): ProgramInfoLoader => {
const metadata = {
name: 'Gemm',
inputNames: inputs.length === 3 ? ['A', 'B', 'C'] : ['A', 'B'],
inputTypes: inputs.length === 3 ? [TextureType.unpacked, TextureType.unpacked, TextureType.unpacked] :
[TextureType.unpacked, TextureType.unpacked],
key: attributes.cacheKey
};
return {...metadata, get: () => createGemmProgramInfo(metadata, inputs, attributes)};
};
const createGemmProgramInfo =
(metadata: ProgramMetadata, inputs: Tensor[], attributes: GemmAttributes): ProgramInfo => {
const aShape = inputs[0].dims.slice();
const bShape = inputs[1].dims.slice();
const [M, N] = GemmUtil.getShapeOfGemmResult(
aShape, attributes.transA, bShape, attributes.transB, inputs.length === 3 ? inputs[2].dims : undefined);
const outputShape = [M, N];
if (!outputShape) {
throw new Error('Can\'t use gemm on the given tensors');
}
let sharedDim = aShape[aShape.length - 1];
let line = '';
if (attributes.transA) {
sharedDim = aShape[0];
}
if (attributes.transA && attributes.transB) {
line = 'value += _A_T(a) * _B_T(b);';
} else if (attributes.transA && !attributes.transB) {
line = 'value += _A_T(a) * _B(b);';
} else if (!attributes.transA && attributes.transB) {
line = 'value += _A(a) * _B_T(b);';
} else if (!attributes.transA && !attributes.transB) {
line = 'value += _A(a) * _B(b);';
}
const rank = outputShape.length;
const declareC = inputs.length === 3 ? `int c[${inputs[2].dims.length}];` : '';
const broadcastC = inputs.length === 3 ? 'bcastIndices_C(indices, c);' : '';
const calculateC = inputs.length === 3 ? 'value += beta * _C(c);' : '';
const shaderSource = `
float process(int indices[${rank}]) {
int a[${rank}];
int b[${rank}];
${declareC}
copyVec(indices, a);
copyVec(indices, b);
${broadcastC}
float value = 0.0;
for (int k=0; k<${sharedDim}; ++k) {
a[${rank - 1}] = k;
b[${rank - 2}] = k;
${line}
}
value = value * alpha;
${calculateC}
return value;
}`;
return {
...metadata,
output: {dims: outputShape, type: inputs[0].type, textureType: TextureType.unpacked},
variables: [
{name: 'alpha', type: 'float', data: attributes.alpha}, {name: 'beta', type: 'float', data: attributes.beta}
],
shaderSource
};
};
const validateInputs = (inputs: Tensor[], attributes: GemmAttributes): void => {
if (!inputs) {
throw new Error('Input is missing');
}
if (attributes.isOptionalC && (inputs.length < 2 || inputs.length > 3)) {
throw new Error('Invaid input shape.');
}
if (!attributes.isOptionalC && inputs.length !== 3) {
throw new Error('Gemm requires 3 inputs');
}
// 'C' can be of dimensionality 1 or 2 only
if (inputs.length === 3 && inputs[2].dims.length !== 1 && inputs[2].dims.length !== 2) {
throw new Error('Invalid input shape of C');
}
if ((inputs[0].type !== 'float32' && inputs[0].type !== 'float64') ||
(inputs[1].type !== 'float32' && inputs[1].type !== 'float64') ||
(inputs.length === 3 && inputs[2].type !== 'float32' && inputs[2].type !== 'float64')) {
throw new Error('Invalid input type.');
}
if ((inputs[0].type !== inputs[1].type) || (inputs.length === 3 && inputs[0].type !== inputs[2].type)) {
throw new Error('Input types are mismatched');
}
};

View File

@@ -0,0 +1,75 @@
"use strict";
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
Object.defineProperty(exports, "__esModule", { value: true });
exports.createPackedIm2ColProgramInfoLoader = void 0;
const glsl_source_1 = require("../glsl-source");
const types_1 = require("../types");
const packing_utils_1 = require("./packing-utils");
const createPackedIm2ColProgramMetadata = (cacheHint) => ({
name: 'Im2Col (packed)',
inputNames: ['A'],
inputTypes: [types_1.TextureType.packed],
cacheHint,
});
const createPackedIm2ColProgramInfo = (inferenceHandler, metadata, x, w, outputShape, attributes) => {
const xshape = x.dims;
const wshape = w.dims;
const rowDim = 2;
const colDim = 3;
const rank = outputShape.length;
const im2colShape = [wshape[1] * wshape[2] * wshape[3], outputShape[2] * outputShape[3]];
const kernelSize = wshape[2] * wshape[3];
const unpackChannel = (0, packing_utils_1.unpackFromChannel)();
const glsl = (0, glsl_source_1.getGlsl)(inferenceHandler.session.backend.glContext.version);
let unrolled = '';
for (let row = 0; row <= 1; row++) {
for (let col = 0; col <= 1; col++) {
unrolled += `
blockIndex = rc.x + ${col};
pos = rc.y + ${row};
if(blockIndex < ${im2colShape[1]} && pos < ${im2colShape[0]}) {
offsetY = int(blockIndex / (${outputShape[rank - 1]})) * ${attributes.strides[0]} -
${attributes.pads[0]};
d0 = offsetY + ${attributes.dilations[0]} * (imod(pos, ${kernelSize}) / ${wshape[2]});
if(d0 < ${xshape[rowDim]} && d0 >= 0) {
offsetX = imod(blockIndex, ${outputShape[rank - 1]}) * ${attributes.strides[1]} -
${attributes.pads[1]};
d1 = offsetX + ${attributes.dilations[1]} * imod(imod(pos, ${kernelSize}), ${wshape[2]});
if(d1 < ${xshape[colDim]} && d1 >= 0) {
ch = int(float(pos)/ ${kernelSize}.);
innerDims = vec2(d0, d1);
result[${row * 2 + col}] = getChannel(
getA(0, ch, int(innerDims.x),
int(innerDims.y)), innerDims);
}
}
}
`;
}
}
const shaderSource = `
${unpackChannel}
void main() {
ivec2 rc = getOutputCoords();
vec4 result = vec4(0.0);
int blockIndex, pos, offsetY, d0, offsetX, d1, ch;
vec2 innerDims;
${unrolled}
${glsl.output} = result;
}
`;
return Object.assign(Object.assign({}, metadata), { output: { dims: im2colShape, type: x.type, textureType: types_1.TextureType.packed }, shaderSource, hasMain: true });
};
const createPackedIm2ColProgramInfoLoader = (inferenceHandler, x, w, outputShape, attributes) => {
const metadata = createPackedIm2ColProgramMetadata(attributes.cacheKey);
return Object.assign(Object.assign({}, metadata), { get: () => createPackedIm2ColProgramInfo(inferenceHandler, metadata, x, w, outputShape, attributes) });
};
exports.createPackedIm2ColProgramInfoLoader = createPackedIm2ColProgramInfoLoader;
//# sourceMappingURL=im2col-pack.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"im2col-pack.js","sourceRoot":"","sources":["im2col-pack.ts"],"names":[],"mappings":";AAAA,4DAA4D;AAC5D,kCAAkC;;;AAGlC,gDAAuC;AAEvC,oCAAsF;AAGtF,mDAAkD;AAElD,MAAM,iCAAiC,GAAG,CAAC,SAAiB,EAAE,EAAE,CAAC,CAAC;IAChE,IAAI,EAAE,iBAAiB;IACvB,UAAU,EAAE,CAAC,GAAG,CAAC;IACjB,UAAU,EAAE,CAAC,mBAAW,CAAC,MAAM,CAAC;IAChC,SAAS;CACV,CAAC,CAAC;AAEH,MAAM,6BAA6B,GAC/B,CAAC,gBAAuC,EAAE,QAAyB,EAAE,CAAS,EAAE,CAAS,EACxF,WAA8B,EAAE,UAA0B,EAAe,EAAE;IAC1E,MAAM,MAAM,GAAG,CAAC,CAAC,IAAI,CAAC;IACtB,MAAM,MAAM,GAAG,CAAC,CAAC,IAAI,CAAC;IACtB,MAAM,MAAM,GAAG,CAAC,CAAC;IACjB,MAAM,MAAM,GAAG,CAAC,CAAC;IACjB,MAAM,IAAI,GAAG,WAAW,CAAC,MAAM,CAAC;IAChC,MAAM,WAAW,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,EAAE,WAAW,CAAC,CAAC,CAAC,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC;IACzF,MAAM,UAAU,GAAG,MAAM,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;IACzC,MAAM,aAAa,GAAG,IAAA,iCAAiB,GAAE,CAAC;IAC1C,MAAM,IAAI,GAAG,IAAA,qBAAO,EAAC,gBAAgB,CAAC,OAAO,CAAC,OAAO,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;IACzE,IAAI,QAAQ,GAAG,EAAE,CAAC;IAElB,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,IAAI,CAAC,EAAE,GAAG,EAAE,EAAE;QACjC,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,IAAI,CAAC,EAAE,GAAG,EAAE,EAAE;YACjC,QAAQ,IAAI;kCACY,GAAG;2BACV,GAAG;;8BAEA,WAAW,CAAC,CAAC,CAAC,aAAa,WAAW,CAAC,CAAC,CAAC;4CAC3B,WAAW,CAAC,IAAI,GAAG,CAAC,CAAC,QAAQ,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC;kBAC5E,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC;+BACL,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,iBAAiB,UAAU,OAAO,MAAM,CAAC,CAAC,CAAC;;wBAEzE,MAAM,CAAC,MAAM,CAAC;6CACO,WAAW,CAAC,IAAI,GAAG,CAAC,CAAC,OAAO,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC;oBAC1E,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC;iCACL,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,qBAAqB,UAAU,MAAM,MAAM,CAAC,CAAC,CAAC;;0BAE5E,MAAM,CAAC,MAAM,CAAC;;yCAEC,UAAU;;6BAEtB,GAAG,GAAG,CAAC,GAAG,GAAG;;;;;;;WAO/B,CAAC;SACH;KACF;IAED,MAAM,YAAY,GAAG;QACnB,aAAa;;;;;;;YAOT,QAAQ;YACR,IAAI,CAAC,MAAM;;aAEV,CAAC;IACR,uCACK,QAAQ,KACX,MAAM,EAAE,EAAC,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,WAAW,EAAE,mBAAW,CAAC,MAAM,EAAC,EAC1E,YAAY,EACZ,OAAO,EAAE,IAAI,IACb;AACJ,CAAC,CAAC;AAEC,MAAM,mCAAmC,GAC5C,CAAC,gBAAuC,EAAE,CAAS,EAAE,CAAS,EAAE,WAA8B,EAC7F,UAA0B,EAAqB,EAAE;IAChD,MAAM,QAAQ,GAAG,iCAAiC,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;IACxE,uCACK,QAAQ,KACX,GAAG,EAAE,GAAG,EAAE,CAAC,6BAA6B,CAAC,gBAAgB,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC,EAAE,WAAW,EAAE,UAAU,CAAC,IACnG;AACJ,CAAC,CAAC;AARO,QAAA,mCAAmC,uCAQ1C"}

View File

@@ -0,0 +1,92 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
import {Tensor} from '../../../tensor';
import {getGlsl} from '../glsl-source';
import {WebGLInferenceHandler} from '../inference-handler';
import {ProgramInfo, ProgramInfoLoader, ProgramMetadata, TextureType} from '../types';
import {ConvAttributes} from './conv';
import {unpackFromChannel} from './packing-utils';
const createPackedIm2ColProgramMetadata = (cacheHint: string) => ({
name: 'Im2Col (packed)',
inputNames: ['A'],
inputTypes: [TextureType.packed],
cacheHint,
});
const createPackedIm2ColProgramInfo =
(inferenceHandler: WebGLInferenceHandler, metadata: ProgramMetadata, x: Tensor, w: Tensor,
outputShape: readonly number[], attributes: ConvAttributes): ProgramInfo => {
const xshape = x.dims;
const wshape = w.dims;
const rowDim = 2;
const colDim = 3;
const rank = outputShape.length;
const im2colShape = [wshape[1] * wshape[2] * wshape[3], outputShape[2] * outputShape[3]];
const kernelSize = wshape[2] * wshape[3];
const unpackChannel = unpackFromChannel();
const glsl = getGlsl(inferenceHandler.session.backend.glContext.version);
let unrolled = '';
for (let row = 0; row <= 1; row++) {
for (let col = 0; col <= 1; col++) {
unrolled += `
blockIndex = rc.x + ${col};
pos = rc.y + ${row};
if(blockIndex < ${im2colShape[1]} && pos < ${im2colShape[0]}) {
offsetY = int(blockIndex / (${outputShape[rank - 1]})) * ${attributes.strides[0]} -
${attributes.pads[0]};
d0 = offsetY + ${attributes.dilations[0]} * (imod(pos, ${kernelSize}) / ${wshape[2]});
if(d0 < ${xshape[rowDim]} && d0 >= 0) {
offsetX = imod(blockIndex, ${outputShape[rank - 1]}) * ${attributes.strides[1]} -
${attributes.pads[1]};
d1 = offsetX + ${attributes.dilations[1]} * imod(imod(pos, ${kernelSize}), ${wshape[2]});
if(d1 < ${xshape[colDim]} && d1 >= 0) {
ch = int(float(pos)/ ${kernelSize}.);
innerDims = vec2(d0, d1);
result[${row * 2 + col}] = getChannel(
getA(0, ch, int(innerDims.x),
int(innerDims.y)), innerDims);
}
}
}
`;
}
}
const shaderSource = `
${unpackChannel}
void main() {
ivec2 rc = getOutputCoords();
vec4 result = vec4(0.0);
int blockIndex, pos, offsetY, d0, offsetX, d1, ch;
vec2 innerDims;
${unrolled}
${glsl.output} = result;
}
`;
return {
...metadata,
output: {dims: im2colShape, type: x.type, textureType: TextureType.packed},
shaderSource,
hasMain: true
};
};
export const createPackedIm2ColProgramInfoLoader =
(inferenceHandler: WebGLInferenceHandler, x: Tensor, w: Tensor, outputShape: readonly number[],
attributes: ConvAttributes): ProgramInfoLoader => {
const metadata = createPackedIm2ColProgramMetadata(attributes.cacheKey);
return {
...metadata,
get: () => createPackedIm2ColProgramInfo(inferenceHandler, metadata, x, w, outputShape, attributes)
};
};

View File

@@ -0,0 +1,73 @@
"use strict";
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
Object.defineProperty(exports, "__esModule", { value: true });
exports.calculateIm2ColDims = exports.createIm2ColProgramInfoLoader = void 0;
const types_1 = require("../types");
const createIm2ColProgramMetadata = (cacheHint) => ({
name: 'Im2Col',
inputNames: ['X'],
inputTypes: [types_1.TextureType.unpacked],
cacheHint,
});
const createIm2ColProgramInfo = (inferenceHandler, metadata, x, w, outputShape, attributes) => {
const xshape = x.dims;
const wshape = w.dims;
const rank = outputShape.length;
const im2colDims = (0, exports.calculateIm2ColDims)(xshape, wshape, outputShape, 4);
const shaderSource = `
const int XC = ${xshape[1]};
const int XH = ${xshape[2]};
const int XW = ${xshape[3]};
const int KH = ${attributes.kernelShape[0]};
const int KW = ${attributes.kernelShape[1]};
const int dilationH = ${attributes.dilations[0]};
const int dilationW = ${attributes.dilations[1]};
const int strideH = ${attributes.strides[0]};
const int strideW = ${attributes.strides[1]};
const int padH = ${attributes.pads[0]};
const int padW = ${attributes.pads[1]};
const int KHKW = KH*KW;
const int XCKHKW = XC * KHKW;
const int outputChannels = 4;
vec4 process(int indices[${rank}]) {
int b = indices[0]; // batch size
int oh = indices[1] * strideH - padH; //output height
int ow = indices[2] * strideW - padW; //output width
int p = indices[3] * outputChannels; //patch
vec4 value = vec4(0.0);
for(int i=0; i < outputChannels; ++i) {
if(p < XCKHKW) {
int patchC = p / KHKW;
int patchH = (p - patchC*KHKW) / KW;
int patchW = (p - patchC*KHKW) - patchH * KW;
int xh2 = oh + patchH * dilationH;
int xw2 = ow + patchW * dilationW;
int x[${xshape.length}];
x[0] = b;
x[1] = patchC;
x[2] = xh2;
x[3] = xw2;
if(xh2 >= 0 &&
xh2 < XH &&
xw2 >= 0 &&
xw2 < XW) {
value[i] = _X(x);
}
}
++p;
}
return value;
}
`;
return Object.assign(Object.assign({}, metadata), { output: { dims: im2colDims, type: x.type, textureType: types_1.TextureType.packedLastDimension }, shaderSource });
};
const createIm2ColProgramInfoLoader = (inferenceHandler, x, w, outputShape, attributes) => {
const metadata = createIm2ColProgramMetadata(attributes.cacheKey);
return Object.assign(Object.assign({}, metadata), { get: () => createIm2ColProgramInfo(inferenceHandler, metadata, x, w, outputShape, attributes) });
};
exports.createIm2ColProgramInfoLoader = createIm2ColProgramInfoLoader;
const calculateIm2ColDims = (inputShape, kernelShape, outputShape, channels = 4) => [outputShape[0], outputShape[2], outputShape[3],
Math.ceil(inputShape[1] * kernelShape[2] * kernelShape[3] / channels)];
exports.calculateIm2ColDims = calculateIm2ColDims;
//# sourceMappingURL=im2col.js.map

Some files were not shown because too many files have changed in this diff Show More