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

295 lines
11 KiB
JavaScript

const armnn = {};
armnn.ModelFactory = class {
async match(context) {
const identifier = context.identifier;
const extension = identifier.lastIndexOf('.') > 0 ? identifier.split('.').pop().toLowerCase() : '';
if (extension === 'armnn') {
const reader = await context.peek('flatbuffers.binary');
if (reader) {
return context.set('armnn.flatbuffers', reader);
}
}
if (extension === 'json') {
const obj = await context.peek('json');
if (obj && obj.layers && obj.inputIds && obj.outputIds) {
return context.set('armnn.flatbuffers.json', obj);
}
}
return null;
}
async open(context) {
armnn.schema = await context.require('./armnn-schema');
armnn.schema = armnn.schema.armnnSerializer;
let model = null;
switch (context.type) {
case 'armnn.flatbuffers': {
try {
const reader = await context.read('flatbuffers.binary');
model = armnn.schema.SerializedGraph.create(reader);
} catch (error) {
const message = error && error.message ? error.message : error.toString();
throw new armnn.Error(`File format is not armnn.SerializedGraph (${message.replace(/\.$/, '')}).`);
}
break;
}
case 'armnn.flatbuffers.json': {
try {
const reader = await context.read('flatbuffers.text');
model = armnn.schema.SerializedGraph.createText(reader);
} catch (error) {
const message = error && error.message ? error.message : error.toString();
throw new armnn.Error(`File text format is not armnn.SerializedGraph (${message.replace(/\.$/, '')}).`);
}
break;
}
default: {
throw new armnn.Error(`Unsupported Arm NN format '${context.type}'.`);
}
}
const metadata = await context.metadata('armnn-metadata.json');
return new armnn.Model(metadata, model);
}
};
armnn.Model = class {
constructor(metadata, model) {
this.format = 'Arm NN';
this.modules = [new armnn.Graph(metadata, model)];
}
};
armnn.Graph = class {
constructor(metadata, graph) {
this.name = '';
this.nodes = [];
this.inputs = [];
this.outputs = [];
const counts = new Map();
for (const layer of graph.layers) {
const base = armnn.Node.getBase(layer);
for (const slot of base.inputSlots) {
const name = `${slot.connection.sourceLayerIndex}:${slot.connection.outputSlotIndex}`;
counts.set(name, counts.has(name) ? counts.get(name) + 1 : 1);
}
}
const values = new Map();
const value = (layerIndex, slotIndex, tensor) => {
const name = `${layerIndex}:${slotIndex}`;
if (!values.has(name)) {
const layer = graph.layers[layerIndex];
const base = layerIndex < graph.layers.length ? armnn.Node.getBase(layer) : null;
const tensorInfo = base && slotIndex < base.outputSlots.length ? base.outputSlots[slotIndex].tensorInfo : null;
values.set(name, new armnn.Value(name, tensorInfo, tensor));
}
return values.get(name);
};
const layers = graph.layers.filter((layer) => {
const base = armnn.Node.getBase(layer);
if (base.layerType === armnn.schema.LayerType.Constant && base.outputSlots.length === 1 && layer.layer.input) {
const [slot] = base.outputSlots;
const name = `${base.index}:${slot.index}`;
if (counts.get(name) === 1) {
const tensor = new armnn.Tensor(layer.layer.input, 'Constant');
value(base.index, slot.index, tensor);
return false;
}
}
return true;
});
for (const layer of layers) {
const base = armnn.Node.getBase(layer);
for (const slot of base.inputSlots) {
value(slot.connection.sourceLayerIndex, slot.connection.outputSlotIndex);
}
}
for (const layer of layers) {
const base = armnn.Node.getBase(layer);
switch (base.layerType) {
case armnn.schema.LayerType.Input: {
const name = base ? base.layerName : '';
for (const slot of base.outputSlots) {
const argument = new armnn.Argument(name, [value(base.index, slot.index)]);
this.inputs.push(argument);
}
break;
}
case armnn.schema.LayerType.Output: {
const base = armnn.Node.getBase(layer);
const name = base ? base.layerName : '';
for (const slot of base.inputSlots) {
const argument = new armnn.Argument(name, [value(slot.connection.sourceLayerIndex, slot.connection.outputSlotIndex)]);
this.outputs.push(argument);
}
break;
}
default:
this.nodes.push(new armnn.Node(metadata, layer, value));
break;
}
}
}
};
armnn.Node = class {
constructor(metadata, layer, value) {
const name = layer.layer.constructor.name;
const type = metadata.type(name);
this.type = type ? { ...type } : { name };
this.type.name = this.type.name.replace(/Layer$/, '');
this.name = '';
this.outputs = [];
this.inputs = [];
this.attributes = [];
const inputSchemas = (this.type && this.type.inputs) ? [...this.type.inputs] : [{ name: 'input' }];
const outputSchemas = (this.type && this.type.outputs) ? [...this.type.outputs] : [{ name: 'output' }];
const base = armnn.Node.getBase(layer);
if (base) {
this.name = base.layerName;
const inputs = [...base.inputSlots];
while (inputs.length > 0) {
const schema = inputSchemas.length > 0 ? inputSchemas.shift() : { name: '?' };
const count = schema.list ? inputs.length : 1;
const argument = new armnn.Argument(schema.name, inputs.splice(0, count).map((inputSlot) => {
return value(inputSlot.connection.sourceLayerIndex, inputSlot.connection.outputSlotIndex);
}));
this.inputs.push(argument);
}
const outputs = [...base.outputSlots];
while (outputs.length > 0) {
const schema = outputSchemas.length > 0 ? outputSchemas.shift() : { name: '?' };
const count = schema.list ? outputs.length : 1;
this.outputs.push(new armnn.Argument(schema.name, outputs.splice(0, count).map((outputSlot) => {
return value(base.index, outputSlot.index);
})));
}
}
if (layer.layer) {
if (layer.layer.descriptor && this.type.attributes) {
for (const [key, obj] of Object.entries(layer.layer.descriptor)) {
const schema = metadata.attribute(name, key);
const type = schema ? schema.type : null;
let value = ArrayBuffer.isView(obj) ? Array.from(obj) : obj;
const enumType = armnn.schema[type];
if (enumType) {
value = enumType[value] || value;
}
const attribute = new armnn.Argument(key, value, type);
this.attributes.push(attribute);
}
}
for (const [name, tensor] of Object.entries(layer.layer).filter(([, value]) => value instanceof armnn.schema.ConstTensor)) {
const value = new armnn.Value('', tensor.info, new armnn.Tensor(tensor));
const argument = new armnn.Argument(name, [value]);
this.inputs.push(argument);
}
}
}
static getBase(layer) {
return layer.layer.base.base ? layer.layer.base.base : layer.layer.base;
}
static makeKey(layer_id, index) {
return `${layer_id}_${index}`;
}
};
armnn.Argument = class {
constructor(name, value, type = null) {
this.name = name;
this.value = value;
this.type = type;
}
};
armnn.Value = class {
constructor(name, tensorInfo, initializer) {
if (typeof name !== 'string') {
throw new armnn.Error(`Invalid value identifier '${JSON.stringify(name)}'.`);
}
this.name = name;
this.type = new armnn.TensorType(tensorInfo);
this.initializer = initializer;
if (tensorInfo.quantizationScale !== 0 ||
tensorInfo.quantizationOffset !== 0 ||
tensorInfo.quantizationScales.length > 0 ||
tensorInfo.quantizationDim !== 0) {
this.quantization = {
type: 'linear',
dimension: tensorInfo.quantizationDim,
scale: [tensorInfo.quantizationScale],
offset: [tensorInfo.quantizationOffset]
};
}
}
};
armnn.Tensor = class {
constructor(tensor, category = '') {
this.type = new armnn.TensorType(tensor.info);
this.category = category;
const data = tensor.data.data.slice(0);
this.values = new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
}
};
armnn.TensorType = class {
constructor(tensorInfo) {
const dataType = tensorInfo.dataType;
switch (dataType) {
case 0: this.dataType = 'float16'; break;
case 1: this.dataType = 'float32'; break;
case 2: this.dataType = 'quint8'; break; // QuantisedAsymm8
case 3: this.dataType = 'int32'; break;
case 4: this.dataType = 'boolean'; break;
case 5: this.dataType = 'qint16'; break; // QuantisedSymm16
case 6: this.dataType = 'quint8'; break; // QAsymmU8
case 7: this.dataType = 'qint16'; break; // QSymmS16
case 8: this.dataType = 'qint8'; break; // QAsymmS8
case 9: this.dataType = 'qint8'; break; // QSymmS8
default:
throw new armnn.Error(`Unsupported data type '${JSON.stringify(dataType)}'.`);
}
this.shape = new armnn.TensorShape(tensorInfo.dimensions);
}
toString() {
return this.dataType + this.shape.toString();
}
};
armnn.TensorShape = class {
constructor(dimensions) {
this.dimensions = Array.from(dimensions);
}
toString() {
if (!this.dimensions || this.dimensions.length === 0) {
return '';
}
return `[${this.dimensions.map((dimension) => dimension.toString()).join(',')}]`;
}
};
armnn.Error = class extends Error {
constructor(message) {
super(message);
this.name = 'Error loading Arm NN model.';
}
};
export const ModelFactory = armnn.ModelFactory;