7254f7b4d1
Build / Build (macos-latest) (push) Has been cancelled
Build / Build (ubuntu-latest) (push) Has been cancelled
Build / Build (windows-latest) (push) Has been cancelled
Build / Analyze (javascript) (push) Has been cancelled
Build / Analyze (python) (push) Has been cancelled
404 lines
14 KiB
JavaScript
404 lines
14 KiB
JavaScript
import * as flatbuffers from './flatbuffers.js';
|
|
|
|
const espdl = {};
|
|
|
|
espdl.ModelFactory = class {
|
|
|
|
async match(context) {
|
|
const identifier = context.identifier;
|
|
const extension = identifier.lastIndexOf('.') > 0 ? identifier.split('.').pop().toLowerCase() : '';
|
|
if (extension === 'espdl') {
|
|
const stream = context.stream;
|
|
if (stream && stream.length >= 16) {
|
|
const buffer = stream.peek(16);
|
|
const header = String.fromCharCode(...buffer.slice(0, 4));
|
|
if (header === 'EDL2') {
|
|
return context.set('espdl.binary', null);
|
|
}
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
async open(context) {
|
|
espdl.schema = await context.require('./espdl-schema');
|
|
espdl.schema = espdl.schema.espdl;
|
|
const stream = context.stream;
|
|
const reader = flatbuffers.BinaryReader.open(stream, 16);
|
|
let model = null;
|
|
try {
|
|
model = espdl.schema.Model.create(reader);
|
|
} catch (error) {
|
|
const message = error && error.message ? error.message : error.toString();
|
|
throw new espdl.Error(`File format is not espdl.Model (${message.replace(/\.$/, '')}).`);
|
|
}
|
|
const metadata = await espdl.Metadata.open(context);
|
|
return new espdl.Model(metadata, model, stream);
|
|
}
|
|
};
|
|
|
|
espdl.Model = class {
|
|
|
|
constructor(metadata, model, stream) {
|
|
this.format = `ESP-DL v${model.ir_version}`;
|
|
this.description = model.doc_string || '';
|
|
this.modules = [];
|
|
this.metadata = [];
|
|
if (model.metadata_props) {
|
|
for (const prop of model.metadata_props) {
|
|
this.metadata.push(new espdl.Argument(prop.key, prop.value));
|
|
}
|
|
}
|
|
if (model.graph) {
|
|
const graph = new espdl.Graph(metadata, model.graph, model, stream);
|
|
this.modules.push(graph);
|
|
}
|
|
}
|
|
};
|
|
|
|
espdl.Graph = class {
|
|
|
|
constructor(metadata, graph) {
|
|
this.name = graph.name || '';
|
|
this.inputs = [];
|
|
this.outputs = [];
|
|
this.nodes = [];
|
|
this.signatures = [];
|
|
const context = new espdl.Context(graph);
|
|
if (graph.node) {
|
|
for (let i = 0; i < graph.node.length; i++) {
|
|
const node = graph.node[i];
|
|
const nodeObj = new espdl.Node(metadata, context, node, i.toString());
|
|
this.nodes.push(nodeObj);
|
|
}
|
|
}
|
|
if (graph.input) {
|
|
for (let i = 0; i < graph.input.length; i++) {
|
|
const valueInfo = graph.input[i];
|
|
const tensor = context.initializer(valueInfo.name);
|
|
if (!tensor) {
|
|
const value = context.value(valueInfo.name);
|
|
const values = value ? [value] : [];
|
|
const argument = new espdl.Argument(valueInfo.name, values);
|
|
this.inputs.push(argument);
|
|
}
|
|
}
|
|
}
|
|
if (graph.output) {
|
|
for (let i = 0; i < graph.output.length; i++) {
|
|
const valueInfo = graph.output[i];
|
|
const value = context.value(valueInfo.name);
|
|
const values = value ? [value] : [];
|
|
const argument = new espdl.Argument(valueInfo.name, values);
|
|
this.outputs.push(argument);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
espdl.Argument = class {
|
|
|
|
constructor(name, value, type, visible) {
|
|
this.name = name;
|
|
this.value = value;
|
|
this.type = type || null;
|
|
this.visible = visible !== false;
|
|
}
|
|
};
|
|
|
|
espdl.Value = class {
|
|
|
|
constructor(name, type, initializer) {
|
|
this.name = name;
|
|
this.type = type || null;
|
|
this.initializer = initializer || null;
|
|
}
|
|
};
|
|
|
|
espdl.Node = class {
|
|
|
|
constructor(metadata, context, node, identifier) {
|
|
this.name = node.name || '';
|
|
this.identifier = identifier;
|
|
this.type = null;
|
|
if (metadata) {
|
|
this.type = metadata.type('espdl', node.op_type);
|
|
}
|
|
if (!this.type) {
|
|
this.type = { name: node.op_type };
|
|
}
|
|
this.inputs = [];
|
|
this.outputs = [];
|
|
this.attributes = [];
|
|
if (node.input) {
|
|
for (let i = 0; i < node.input.length;) {
|
|
const inputMeta = this.type && Array.isArray(this.type.inputs) && i < this.type.inputs.length ? this.type.inputs[i] : { name: i.toString() };
|
|
const count = inputMeta.list ? node.input.length - i : 1;
|
|
const list = node.input.slice(i, i + count);
|
|
const values = list.map((inputName) => {
|
|
if (!inputName) {
|
|
return null;
|
|
}
|
|
return context.value(inputName);
|
|
}).filter((v) => v);
|
|
const argument = new espdl.Argument(inputMeta.name, values);
|
|
this.inputs.push(argument);
|
|
i += count;
|
|
}
|
|
}
|
|
if (node.output) {
|
|
for (let i = 0; i < node.output.length;) {
|
|
const outputMeta = this.type && Array.isArray(this.type.outputs) && i < this.type.outputs.length ? this.type.outputs[i] : { name: i.toString() };
|
|
const count = outputMeta.list ? node.output.length - i : 1;
|
|
const list = node.output.slice(i, i + count);
|
|
const values = list.map((outputName) => {
|
|
if (!outputName) {
|
|
return null;
|
|
}
|
|
return context.value(outputName);
|
|
}).filter((v) => v);
|
|
const argument = new espdl.Argument(outputMeta.name, values);
|
|
this.outputs.push(argument);
|
|
i += count;
|
|
}
|
|
}
|
|
if (node.attribute) {
|
|
for (const attr of node.attribute) {
|
|
const name = attr.name || '';
|
|
let value = null;
|
|
let type = null;
|
|
switch (attr.attr_type) {
|
|
case espdl.schema.AttributeType.FLOAT:
|
|
value = attr.f ? attr.f.f : 0;
|
|
type = 'float32';
|
|
break;
|
|
case espdl.schema.AttributeType.INT:
|
|
value = attr.i ? Number(attr.i.i) : 0;
|
|
type = 'int64';
|
|
break;
|
|
case espdl.schema.AttributeType.STRING:
|
|
value = attr.s ? new TextDecoder('utf-8').decode(attr.s) : '';
|
|
type = 'string';
|
|
break;
|
|
case espdl.schema.AttributeType.TENSOR:
|
|
value = attr.t ? new espdl.Tensor(0, attr.t) : null;
|
|
type = 'tensor';
|
|
break;
|
|
case espdl.schema.AttributeType.FLOATS:
|
|
value = attr.floats ? Array.from(attr.floats) : [];
|
|
type = 'float32[]';
|
|
break;
|
|
case espdl.schema.AttributeType.INTS:
|
|
value = attr.ints ? Array.from(attr.ints).map((i) => Number(i)) : [];
|
|
type = 'int64[]';
|
|
break;
|
|
case espdl.schema.AttributeType.STRINGS:
|
|
value = attr.strings ? attr.strings.map((s) => new TextDecoder('utf-8').decode(s)) : [];
|
|
type = 'string[]';
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
const attribute = new espdl.Argument(name, value, type);
|
|
this.attributes.push(attribute);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
espdl.Tensor = class {
|
|
|
|
constructor(index, tensor) {
|
|
this.identifier = index.toString();
|
|
this.name = tensor.name || '';
|
|
this.type = new espdl.TensorType(tensor);
|
|
this.category = '';
|
|
this.encoding = this.type.dataType === 'string' ? '|' : '<';
|
|
this.values = null;
|
|
if (tensor.float_data && tensor.float_data.length > 0) {
|
|
this.values = new Float32Array(tensor.float_data);
|
|
} else if (tensor.int32_data && tensor.int32_data.length > 0) {
|
|
this.values = new Int32Array(tensor.int32_data);
|
|
} else if (tensor.int64_data && tensor.int64_data.length > 0) {
|
|
this.values = new BigInt64Array(tensor.int64_data);
|
|
} else if (tensor.string_data && tensor.string_data.length > 0) {
|
|
this.values = tensor.string_data;
|
|
} else if (tensor.raw_data && tensor.raw_data.length > 0) {
|
|
const length = tensor.raw_data.length * 16;
|
|
const data = new Uint8Array(length);
|
|
for (let i = 0; i < tensor.raw_data.length; i++) {
|
|
data.set(tensor.raw_data[i].bytes, i * 16);
|
|
}
|
|
this.values = data;
|
|
}
|
|
}
|
|
};
|
|
|
|
espdl.TensorType = class {
|
|
|
|
constructor(tensor) {
|
|
let dataType = '';
|
|
if (tensor.value_info_type === undefined) {
|
|
dataType = tensor.data_type;
|
|
this.shape = new espdl.TensorShape(tensor.dims ? Array.from(tensor.dims).map((d) => Number(d)) : []);
|
|
} else {
|
|
const value = tensor.value_info_type.value;
|
|
dataType = value ? value.elem_type : undefined;
|
|
let shape = [];
|
|
const dim = value && value.shape && value.shape.dim;
|
|
if (dim && dim.length > 0) {
|
|
shape = dim.map((d) => {
|
|
if (d && d.value) {
|
|
if (d.value.dim_type === 1) {
|
|
return Number(d.value.dim_value);
|
|
} else if (d.value.dim_type === 2) {
|
|
return d.value.dim_param || '?';
|
|
}
|
|
}
|
|
return '?';
|
|
});
|
|
}
|
|
this.shape = new espdl.TensorShape(shape);
|
|
}
|
|
switch (dataType) {
|
|
case espdl.schema.TensorDataType.FLOAT: this.dataType = 'float32'; break;
|
|
case espdl.schema.TensorDataType.DOUBLE: this.dataType = 'float64'; break;
|
|
case espdl.schema.TensorDataType.BOOL: this.dataType = 'boolean'; break;
|
|
default: this.dataType = espdl.schema.TensorDataType[dataType] ? espdl.schema.TensorDataType[dataType].toLowerCase() : '?'; break;
|
|
}
|
|
}
|
|
|
|
toString() {
|
|
return this.dataType + this.shape.toString();
|
|
}
|
|
};
|
|
|
|
espdl.TensorShape = class {
|
|
|
|
constructor(dimensions) {
|
|
this.dimensions = dimensions;
|
|
}
|
|
|
|
toString() {
|
|
if (!this.dimensions || this.dimensions.length === 0) {
|
|
return '';
|
|
}
|
|
return `[${this.dimensions.map((dimension) => dimension.toString()).join(',')}]`;
|
|
}
|
|
};
|
|
|
|
espdl.Metadata = class {
|
|
|
|
static async open(context) {
|
|
if (!espdl.Metadata._metadata) {
|
|
let data = null;
|
|
try {
|
|
data = await context.asset('espdl-metadata.json');
|
|
} catch {
|
|
// continue regardless of error
|
|
}
|
|
espdl.Metadata._metadata = new espdl.Metadata(data);
|
|
}
|
|
return espdl.Metadata._metadata;
|
|
}
|
|
|
|
constructor(data) {
|
|
this._types = new Map();
|
|
if (data) {
|
|
const types = JSON.parse(data);
|
|
for (const type of types) {
|
|
if (!this._types.has(type.module)) {
|
|
this._types.set(type.module, new Map());
|
|
}
|
|
const types = this._types.get(type.module);
|
|
if (!types.has(type.name)) {
|
|
types.set(type.name, []);
|
|
}
|
|
types.get(type.name).push(type);
|
|
}
|
|
}
|
|
}
|
|
|
|
type(domain, name) {
|
|
domain = domain || 'espdl';
|
|
let current = null;
|
|
if (this._types.has(domain)) {
|
|
const types = this._types.get(domain);
|
|
if (types.has(name)) {
|
|
for (const type of types.get(name)) {
|
|
if (!current || type.version > current.version) {
|
|
current = type;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return current;
|
|
}
|
|
};
|
|
|
|
espdl.Context = class {
|
|
|
|
constructor(graph) {
|
|
this._initializers = new Map();
|
|
this._values = new Map();
|
|
if (graph.initializer) {
|
|
for (let i = 0; i < graph.initializer.length; i++) {
|
|
const tensor = graph.initializer[i];
|
|
const name = tensor.name || '';
|
|
if (name) {
|
|
const initializer = new espdl.Tensor(i, tensor);
|
|
this._initializers.set(name, initializer);
|
|
this._values.set(name, new espdl.Value(name, initializer.type, initializer));
|
|
}
|
|
}
|
|
}
|
|
if (graph.input) {
|
|
for (const valueInfo of graph.input) {
|
|
const name = valueInfo.name || '';
|
|
if (name && !this._values.has(name)) {
|
|
const type = valueInfo.value_info_type ? new espdl.TensorType(valueInfo) : null;
|
|
this._values.set(name, new espdl.Value(name, type, null));
|
|
}
|
|
}
|
|
}
|
|
if (graph.output) {
|
|
for (const valueInfo of graph.output) {
|
|
const name = valueInfo.name || '';
|
|
if (name && !this._values.has(name)) {
|
|
const type = valueInfo.value_info_type ? new espdl.TensorType(valueInfo) : null;
|
|
this._values.set(name, new espdl.Value(name, type, null));
|
|
}
|
|
}
|
|
}
|
|
if (graph.value_info) {
|
|
for (const valueInfo of graph.value_info) {
|
|
const name = valueInfo.name || '';
|
|
if (name && !this._values.has(name)) {
|
|
const type = valueInfo.value_info_type ? new espdl.TensorType(valueInfo) : null;
|
|
this._values.set(name, new espdl.Value(name, type, null));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
value(name) {
|
|
if (!this._values.has(name)) {
|
|
this._values.set(name, new espdl.Value(name, null, null));
|
|
}
|
|
return this._values.get(name);
|
|
}
|
|
|
|
initializer(name) {
|
|
return this._initializers.get(name) || null;
|
|
}
|
|
};
|
|
|
|
espdl.Error = class extends Error {
|
|
|
|
constructor(message) {
|
|
super(message);
|
|
this.name = 'Error loading ESP-DL model.';
|
|
}
|
|
};
|
|
|
|
export const ModelFactory = espdl.ModelFactory; |