Files
wehub-resource-sync 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
chore: import upstream snapshot with attribution
2026-07-13 12:37:45 +08:00

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;