| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866 |
- const openvino = {};
- openvino.ModelFactory = class {
- async match(context) {
- const identifier = context.identifier.toLowerCase();
- const extension = identifier.split('.').pop();
- if (/^.*\.ncnn\.bin$/.test(identifier) ||
- /^.*\.pnnx\.bin$/.test(identifier) ||
- /^.*pytorch_model.*\.bin$/.test(identifier) ||
- /^.*group.+-shard.+of.+\.bin$/.test(identifier) ||
- /^.*param\.bin$/.test(identifier)) {
- return null;
- }
- if (extension === 'bin') {
- const stream = context.stream;
- const length = Math.min(0x10000, stream.length);
- if (length >= 4) {
- let buffer = stream.peek(length);
- const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.length);
- const signature = view.getUint32(0, true);
- for (let i = 0; i < buffer.length - 4; i++) {
- const signature = view.getUint32(i, true);
- if (signature === 0xdeadbeef || // Core ML
- signature === 0x01306b47 || signature === 0x000d4b38 || signature === 0x0002c056) { // ncnn
- return null;
- }
- }
- const match = (pattern, identifier, buffer) => {
- if (pattern.identifier && typeof pattern.identifier === 'string' && identifier !== pattern.identifier) {
- return false;
- } else if (pattern.identifier && pattern.identifier instanceof RegExp && !pattern.identifier.test(identifier)) {
- return false;
- } else if (pattern.signature && !pattern.signature.every((value, index) => value === buffer[index])) {
- return false;
- }
- return true;
- };
- const include = [
- { identifier: 'googlenet-v1.bin', signature: [0x80, 0xD6, 0x50, 0xD7, 0xB0, 0xD7, 0xA5, 0x2D, 0xCA, 0x28, 0x49, 0x2A, 0x35, 0x31, 0x0A, 0x31] },
- { identifier: 'text-recognition-0012.bin', signature: [0x0B, 0x21, 0xC6, 0xBC, 0xD0, 0xBB, 0xC1, 0x3B] },
- ];
- if (include.some((pattern) => match(pattern, identifier, buffer))) {
- return context.set('openvino.bin');
- }
- const exclude = [
- { identifier: '__model__.bin' },
- { identifier: 'config.bin' },
- { identifier: 'model.bin' },
- { identifier: 'ncnn.bin' },
- { identifier: 'programs.bin' },
- { identifier: 'weights.bin' },
- { identifier: /stories\d+(m|k)\.bin$/ },
- { signature: [0x21, 0xA8, 0xEF, 0xBE, 0xAD, 0xDE] }
- ];
- if (exclude.some((pattern) => match(pattern, identifier, buffer))) {
- return null;
- }
- if (signature === 0x00000001) {
- return null;
- }
- const size = Math.min(buffer.length & 0xfffffffc, 128);
- buffer = buffer.subarray(0, size);
- if (Array.from(buffer).every((value) => value === 0)) {
- return context.set('openvino.bin');
- }
- const f32 = new Array(buffer.length >> 2);
- for (let i = 0; i < f32.length; i++) {
- f32[i] = view.getFloat32(i << 2, true);
- }
- const f16 = new Array(buffer.length >> 1);
- for (let i = 0; i < f16.length; i++) {
- f16[i] = view.getFloat16(i << 1, true);
- }
- const i32 = new Array(buffer.length >> 2);
- for (let i = 0; i < f32.length; i++) {
- i32[i] = view.getInt32(i << 2, true);
- }
- const validateFloat = (array) => array[0] !== 0 && array.every((x) => !Number.isNaN(x) && Number.isFinite(x)) &&
- (array.every((x) => x > -20.0 && x < 20.0 && (x >= 0 || x < -0.0000001) && (x <= 0 || x > 0.0000001)) ||
- array.every((x) => x > -100.0 && x < 100.0 && (x * 10) % 1 === 0));
- const validateInt = (array) => array.length > 32 &&
- array.slice(0, 32).every((x) => x === 0 || x === 1 || x === 2 || x === 0x7fffffff);
- if (validateFloat(f32) || validateFloat(f16) || validateInt(i32)) {
- return context.set('openvino.bin');
- }
- }
- return null;
- }
- const tags = await context.tags('xml');
- if (tags.has('net')) {
- return context.set('openvino.xml');
- }
- return null;
- }
- filter(context, match) {
- return context.type !== 'openvino.xml' || match.type !== 'openvino.bin';
- }
- async open(context) {
- const identifier = context.identifier;
- const base = identifier.substring(0, identifier.length - 4);
- let bin = null;
- switch (context.type) {
- case 'openvino.xml': {
- try {
- const file = `${base}.bin`;
- const content = await context.fetch(file);
- bin = content.stream.peek();
- } catch {
- // continue regardless of error
- }
- break;
- }
- case 'openvino.bin': {
- try {
- const file = `${base}.xml`;
- bin = context.stream.peek();
- context = await context.fetch(file, null);
- } catch (error) {
- const message = error && error.message ? error.message : error.toString();
- throw new openvino.Error(`Required OpenVINO model definition not found (${message.replace(/\.$/, '')}).`);
- }
- break;
- }
- default: {
- throw new openvino.Error(`Unsupported OpenVINO format '${context.type}'.`);
- }
- }
- let document = null;
- try {
- document = await context.read('xml');
- } catch (error) {
- const message = error && error.message ? error.message : error.toString();
- throw new openvino.Error(`File format is not OpenVINO XML (${message.replace(/\.$/, '')}).`);
- }
- if (!document.documentElement || document.documentElement.localName !== 'net') {
- throw new openvino.Error('File format is not OpenVINO IR.');
- }
- const element = document.documentElement;
- const metadata = await context.metadata('openvino-metadata.json');
- const object = (element) => {
- const obj = {};
- for (const attribute of element.attributes) {
- obj[attribute.localName] = attribute.value;
- }
- return obj;
- };
- const child = (parent, name) => {
- const elements = parent.getElementsByTagName(name);
- if (elements.length > 1) {
- throw new openvino.Error(`Element '${parent.localName}' has multiple '${name}' elements.`);
- }
- return elements.length > 0 ? elements[0] : null;
- };
- const children = (parent, name, element) => {
- const list = child(parent, name);
- return list ? list.getElementsByTagName(element) : [];
- };
- const edges = (parent, name) => {
- const map = {};
- for (const element of children(parent, name || 'edges', 'edge')) {
- const fromLayer = element.getAttribute('from-layer');
- const fromPort = element.getAttribute('from-port');
- const toLayer = element.getAttribute('to-layer');
- const toPort = element.getAttribute('to-port');
- map[`${toLayer}:${toPort}`] = `${fromLayer}:${fromPort}`;
- }
- return map;
- };
- const layers = (parent) => {
- const ports = (parent, name) => {
- return children(parent, name, 'port').map((element) => {
- const port = object(element);
- port.dims = element.getElementsByTagName('dim').map((dim) => parseInt(dim.textContent.trim(), 10));
- return port;
- });
- };
- return children(parent, 'layers', 'layer').map((element) => {
- const layer = object(element);
- layer.input = ports(element, 'input');
- layer.output = ports(element, 'output');
- const data = child(element, 'data');
- const blobs = child(element, 'blobs');
- layer.data = data ? object(data) : {};
- layer.blobs = blobs ? blobs.getElementsByTagName('*').map((blob) => {
- const obj = object(blob);
- obj.name = blob.localName;
- obj.offset = parseInt(obj.offset, 10);
- obj.size = parseInt(obj.size, 10);
- return obj;
- }) : [];
- if (layer.type === 'TensorIterator') {
- layer.back_edges = edges(element, 'back_edges');
- const body = child(element, 'body');
- if (body) {
- layer.body = {
- layers: layers(body),
- edges: edges(body)
- };
- }
- const port_map = child(element, 'port_map');
- if (port_map) {
- layer.port_map = { input: [], output: [] };
- for (const port of port_map.getElementsByTagName('*')) {
- const item = object(port);
- switch (port.localName) {
- case 'input': layer.port_map.input.push(item); break;
- case 'output': layer.port_map.output.push(item); break;
- default: throw new openvino.Error(`Unsupported port local name '${port.localName}'.`);
- }
- }
- }
- }
- return layer;
- });
- };
- const net = object(element);
- net.body = {
- layers: layers(element),
- edges: edges(element)
- };
- return new openvino.Model(metadata, net, bin);
- }
- };
- openvino.Model = class {
- constructor(metadata, net, bin) {
- this.name = net.name || '';
- this.modules = [new openvino.Graph(metadata, net, bin)];
- this.format = 'OpenVINO IR';
- }
- };
- openvino.Graph = class {
- constructor(metadata, net, bin) {
- this.name = net.name || '';
- this.nodes = [];
- this.inputs = [];
- this.outputs = [];
- const tensors = new Map();
- const values = new Map();
- values.map = (layer, precision, port, map) => {
- const id = `${layer}:${port.id}`;
- const name = map && map[id] ? map[id] : id;
- if (name === '') {
- throw new openvino.Error('Empty value name.');
- }
- const shape = port.dims.length === 0 ? null : new openvino.TensorShape(port.dims);
- if (!precision && values.has(name)) {
- const value = values.get(name);
- if (value.type && value.type.shape && value.type.shape.equals(shape)) {
- return value;
- }
- }
- const type = new openvino.TensorType(precision, shape);
- let tensor = null;
- if (tensors.has(id)) {
- const blob = tensors.get(id);
- const offset = blob.offset;
- const size = blob.size;
- const shape = new openvino.TensorShape(blob.shape);
- const type = new openvino.TensorType(blob.precision || precision, shape);
- const data = (bin && (offset + size) <= bin.length) ? bin.slice(offset, offset + size) : null;
- tensor = new openvino.Tensor(type, data, 'Const');
- }
- if (!values.has(name)) {
- values.set(name, new openvino.Value(name, type, tensor));
- } else if (type && !type.equals(values.get(name).type)) {
- throw new openvino.Error(`Duplicate value '${name}'.`);
- }
- return values.get(name);
- };
- const nodes = new Map();
- const constant = (layers, edges, back_edges) => {
- back_edges = back_edges || {};
- for (const layer of layers) {
- if (layer.type === 'Const' &&
- layer.input.length === 0 && layer.output.length === 1 && layer.blobs.length === 0 &&
- layer.data && layer.data.element_type !== undefined && layer.data.offset !== undefined && layer.data.size !== undefined) {
- let precision = null;
- switch (layer.data.element_type) {
- case 'f16': precision = 'FP16'; break;
- case 'f32': precision = 'FP32'; break;
- case 'f64': precision = 'FP64'; break;
- default: precision = layer.data.element_type.toUpperCase();
- }
- const shape = layer.data.shape;
- layer.blobs.push({
- name: 'value',
- precision,
- offset: parseInt(layer.data.offset, 10),
- size: parseInt(layer.data.size, 10),
- shape: shape ? shape.split(',').map((dim) => parseInt(dim.trim(), 10)) : null
- });
- layer.data = {};
- }
- if (layer.type === 'Const' && layer.blobs.length === 1 && !layer.blobs[0].shape &&
- layer.input.length === 0 && layer.output.length === 1 && layer.output[0].dims) {
- layer.blobs[0].shape = layer.output[0].dims;
- }
- }
- const constants = new Map();
- for (const layer of layers) {
- if (layer.type === 'Const' && layer.input.length === 0 && layer.output.length === 1) {
- const from = `${layer.id}:${layer.output[0].id}`;
- constants.set(from, { layer, counter: 0 });
- }
- }
- for (const from of Object.values(edges)) {
- if (constants.has(from)) {
- constants.get(from).counter++;
- }
- }
- if (back_edges) {
- for (const from of Object.values(back_edges)) {
- if (constants.has(from)) {
- constants.get(from).counter++;
- }
- }
- }
- for (const [name, value] of constants) {
- if (value.counter !== 1) {
- constants.delete(name);
- }
- }
- for (const layer of layers) {
- if (layer.blobs.length === 0) {
- for (let i = layer.input.length - 1; i >= 0; i--) {
- const input = layer.input[i];
- const to = `${layer.id}:${input.id}`;
- const from = edges[to] || back_edges[to];
- if (!constants.has(from)) {
- break;
- }
- const constLayer = constants.get(from).layer;
- if (constLayer && Array.isArray(constLayer.blobs) && constLayer.blobs.length > 0) {
- const [blob] = constLayer.blobs;
- if (blob) {
- blob.id = constLayer.name || constLayer.id;
- layer.input[i].blob = blob;
- constants.get(from).layer = null;
- constants.get(from).delete = true;
- }
- }
- }
- }
- }
- return layers.filter((layer) => {
- if (layer.type === 'Const' && layer.input.length === 0 && layer.output.length === 1) {
- const from = `${layer.id}:${layer.output[0].id}`;
- if (constants.has(from) && constants.get(from).delete) {
- return false;
- }
- }
- return true;
- });
- };
- const body = net.body;
- const body_layers = body && Array.isArray(body.layers) ? body.layers : [];
- const body_edges = body && body.edges ? body.edges : {};
- const layers = new Map(body_layers.map((entry) => [entry.id, entry]));
- const ports = new Map();
- if (Array.isArray(net.input)) {
- for (const input of net.input) {
- const value = values.map('', input.precision, input);
- const argument = new openvino.Argument(input.id, [value]);
- this.inputs.push(argument);
- ports.set(input.id, value);
- }
- }
- if (Array.isArray(net.output)) {
- for (const output of net.output) {
- const value = values.map('', output.precision, output);
- const argument = new openvino.Argument(output.id, [value]);
- this.outputs.push(argument);
- ports.set(output.id, value);
- }
- }
- for (const layer of body_layers) {
- for (const output of layer.output) {
- if (!output.precision) {
- output.precision = layer.precision;
- }
- }
- }
- if (net.port_map) {
- for (const input of net.port_map.input) {
- const external_port = net.input.find((v) => v.id === input.external_port_id);
- const layer = layers.get(input.internal_layer_id);
- if (input.internal_port_id === undefined) {
- input.internal_port_id = '';
- layer.input.push({
- id: input.internal_port_id,
- precision: layer.data.element_type,
- dims: layer.data.shape.split(',')
- });
- }
- const internal_port = layer.input.find((v) => v.id === input.internal_port_id);
- internal_port.precision = external_port.precision;
- }
- for (const output of net.port_map.output) {
- const external_port = net.output.find((v) => v.id === output.external_port_id);
- const layer = layers.get(output.internal_layer_id);
- if (output.internal_port_id === undefined) {
- output.internal_port_id = '';
- layer.output.push({
- id: output.internal_port_id,
- precision: external_port.precision,
- dims: external_port.dims
- });
- }
- }
- }
- const layer_list = constant(body_layers, body_edges);
- for (const layer of layer_list) {
- for (const input of layer.input) {
- if (input.blob) {
- tensors.set(`${layer.id}:${input.id}`, input.blob);
- }
- }
- }
- for (const layer of layer_list) {
- for (const output of layer.output) {
- values.map(layer.id, output.precision, output, null);
- }
- }
- for (const layer of layer_list) {
- const inputs = layer.input.map((input) => {
- const to = `${layer.id}:${input.id}`;
- if (body.edges[to]) {
- const output = body.edges[to] ? body.edges[to].split(':') : [];
- const [outputLayerId, outputId] = output;
- const outputLayer = layers.get(outputLayerId);
- if (outputLayer && outputId) {
- const output = outputLayer.output.find((output) => output.id === outputId);
- if (input && output) {
- input.precision = output.precision;
- }
- }
- }
- return values.map(layer.id, input.precision || layer.precision, input, body.edges);
- });
- const outputs = layer.output.map((output) => {
- let precision = null;
- if (output && output.precision) {
- precision = output.precision;
- } else if (layer && layer.precision) {
- precision = layer.precision;
- }
- return values.map(layer.id, precision, output, null);
- });
- const subgraph = Array.isArray(net.input) || Array.isArray(net.output);
- if (!subgraph && (layer.type === 'Input' || layer.type === 'Parameter')) {
- const name = layer.name || '';
- // precision is a part of OpenVINO IR layers of IR v6 and earlier
- // in IR v7 and newer the port is no longer an attribute of the layer but of each output port
- // IR input is not just a placeholder, it is conceptually the legitimate layer
- // in order not to break compatibility with the overall approach
- // with openvino.Argument for inputs and openvino.Node for outputs
- // input openvino.Node would be stored as an optional attribute of openvino.Parameter
- this.inputs.push(new openvino.Argument(name, outputs));
- } else {
- const node = new openvino.Node(metadata, layer, inputs, outputs, bin);
- nodes.set(layer.id, node);
- }
- }
- this.nodes = Array.from(nodes.values());
- if (net.port_map) {
- const createMapLayer = (obj) => {
- const data = {};
- for (const [name, value] of Object.entries(obj)) {
- if (name !== 'external_port_id' && name !== 'internal_layer_id' && name !== 'internal_port_id') {
- data[name] = value;
- }
- }
- return { type: '-', data };
- };
- for (const input of net.port_map.input) {
- const internal_port = layers.get(input.internal_layer_id).input.find((v) => v.id === input.internal_port_id);
- const inputs = [ports.get(input.external_port_id)];
- const outputs = [values.map(input.internal_layer_id, internal_port.precision, internal_port)];
- const layer = createMapLayer(input);
- this.nodes.push(new openvino.Node(metadata, layer, inputs, outputs));
- }
- for (const output of net.port_map.output) {
- const internal_port = layers.get(output.internal_layer_id).output.find((v) => v.id === output.internal_port_id);
- const inputs = [values.map(output.internal_layer_id, internal_port.precision, internal_port)];
- const outputs = [ports.get(output.external_port_id)];
- const layer = createMapLayer(output);
- this.nodes.push(new openvino.Node(metadata, layer, inputs, outputs));
- }
- }
- }
- };
- openvino.Node = class {
- constructor(metadata, layer, inputs, outputs, bin) {
- this.name = layer.name || '';
- this.inputs = [];
- this.outputs = [];
- this.attributes = [];
- const type = layer.type;
- this.type = metadata.type(type) || { name: type };
- for (let i = 0; i < inputs.length;) {
- let input = null;
- if (this.type && Array.isArray(this.type.inputs) && i < this.type.inputs.length) {
- input = this.type.inputs[i];
- } else if (inputs.length === 1) {
- input = { name: 'input' };
- } else {
- input = { name: i.toString() };
- }
- const count = input.type === 'Tensor[]' ? inputs.length - i : 1;
- const values = inputs.slice(i, i + count);
- const argument = new openvino.Argument(input.name, values);
- this.inputs.push(argument);
- i += count;
- }
- for (let i = 0; i < outputs.length;) {
- let output = null;
- if (this.type && Array.isArray(this.type.outputs) && i < this.type.outputs.length) {
- output = this.type.outputs[i];
- } else if (outputs.length === 1) {
- output = { name: 'output' };
- } else {
- output = { name: i.toString() };
- }
- const count = output.type === 'Tensor[]' ? outputs.length - i : 1;
- const values = outputs.slice(i, i + count);
- const argument = new openvino.Argument(output.name, values);
- this.outputs.push(argument);
- i += count;
- }
- const op = type;
- for (const [name, obj] of Object.entries(layer.data)) {
- const schema = metadata.attribute(op, name);
- let value = obj;
- let type = null;
- let visible = true;
- if (schema && schema.type !== undefined) {
- type = schema.type;
- switch (schema.type) {
- case '':
- case 'graph':
- case 'string':
- break;
- case 'boolean':
- if (obj === '1' || obj === 'true' || obj === 'True') {
- value = true;
- } else if (obj === '0' || obj === 'false' || obj === 'False') {
- value = false;
- } else {
- throw new openvino.Error(`Unsupported attribute boolean value '${obj}'.`);
- }
- break;
- case 'int32':
- case 'int64': {
- const intValue = Number.parseInt(obj, 10);
- value = Number.isNaN(obj - intValue) ? obj : intValue;
- break;
- }
- case 'float32':
- case 'float64': {
- const floatValue = Number.parseFloat(obj);
- value = Number.isNaN(obj - floatValue) ? obj : floatValue;
- break;
- }
- case 'int32[]':
- if (obj.length > 2) {
- let ints = [];
- for (const entry of obj.split(',')) {
- const item = entry.trim();
- const intValue = Number.parseInt(item, 10);
- if (Number.isNaN(item - intValue)) {
- ints = null;
- } else if (ints !== null) {
- ints.push(intValue);
- }
- }
- if (ints !== null) {
- value = ints;
- }
- }
- break;
- case 'float32[]':
- if (obj.length > 2) {
- let floats = [];
- for (const entry of obj.split(',')) {
- const item = entry.trim();
- const floatValue = Number.parseFloat(item);
- if (Number.isNaN(item - floatValue)) {
- floats = null;
- } else if (floats !== null) {
- floats.push(floatValue);
- }
- }
- if (floats !== null) {
- value = floats;
- }
- }
- break;
- default:
- throw new openvino.Error(`Unsupported attribute type '${schema.type}'.`);
- }
- }
- if (schema && schema.visible === false) {
- visible = false;
- } else if (schema && schema.default !== undefined) {
- const defaultValue = schema.default;
- if (value === defaultValue) {
- visible = false;
- } else if (Array.isArray(value) && Array.isArray(defaultValue)) {
- const repeat = defaultValue.length > 1 && defaultValue[defaultValue.length - 1] === null;
- if (value.every((item, index) => item === (repeat && index >= defaultValue.length - 1 ? defaultValue[defaultValue.length - 2] : defaultValue[index]))) {
- visible = false;
- }
- }
- }
- const attribute = new openvino.Argument(name, value, type, visible);
- this.attributes.push(attribute);
- }
- if (layer.type === 'TensorIterator') {
- const graph = new openvino.Graph(metadata, layer, null);
- const attribute = new openvino.Argument('body', graph, 'graph');
- this.attributes.push(attribute);
- }
- for (const blob of layer.blobs || []) {
- const name = blob.name;
- const offset = blob.offset;
- let data = (bin && (offset + blob.size) <= bin.length) ? bin.slice(offset, offset + blob.size) : null;
- let dimensions = blob.shape || null;
- const category = blob.kind || 'Blob';
- const id = blob.id || '';
- const precision = blob.precision || layer.precision;
- let itemSize = -1;
- switch (precision) {
- case 'BOOL': case 'BOOLEAN': itemSize = 1; break;
- case 'I1': case 'U1': itemSize = 0.125; break;
- case 'I2': case 'U2': itemSize = 0.25; break;
- case 'I4': case 'U4': itemSize = 0.5; break;
- case 'I8': case 'U8': itemSize = 1; break;
- case 'I16': case 'U16': case 'FP16': itemSize = 2; break;
- case 'I32': case 'U32': case 'FP32': itemSize = 4; break;
- case 'I64': case 'U64': case 'FP64': itemSize = 8; break;
- case 'F8E4M3': itemSize = 1; break;
- case 'BF16': itemSize = 2; break;
- default: throw new openvino.Error(`Unsupported data type size '${precision}'.`);
- }
- const weight = (name, precision, dimensions, data) => {
- const shape = dimensions ? new openvino.TensorShape(dimensions) : null;
- const type = new openvino.TensorType(precision, shape);
- const tensor = new openvino.Tensor(type, data, category);
- const value = new openvino.Value(id, null, tensor);
- this.inputs.push(new openvino.Argument(name, [value]));
- const size = Math.ceil(dimensions.reduce((a, b) => a * b, 1) * itemSize);
- if (data && data.length !== size) {
- return data.slice(size, data.length);
- }
- return null;
- };
- if (itemSize !== -1) {
- switch (`${type}:${name}`) {
- case 'FullyConnected:weights': {
- const outSize = parseInt(layer.data['out-size'], 10);
- dimensions = [layer.input[0].dims[1], outSize];
- break;
- }
- case 'FullyConnected:biases': {
- dimensions = [parseInt(layer.data['out-size'], 10)];
- break;
- }
- case 'Convolution:weights':
- case 'Deconvolution:weights': {
- const c = this.inputs[0].value[0].type.shape.dimensions[1];
- const group = parseInt(layer.data.group || '1', 10);
- const kernel = layer.data['kernel-x'] !== undefined && layer.data['kernel-y'] !== undefined ?
- [parseInt(layer.data['kernel-x'], 10), parseInt(layer.data['kernel-y'], 10)] :
- layer.data.kernel.split(',').map((v) => parseInt(v.trim(), 10));
- const n = parseInt(layer.data.output, 10);
- dimensions = [Math.floor(c / group), n].concat(kernel);
- break;
- }
- case 'LSTMCell:weights': {
- const input_size = inputs[0].type.shape.dimensions[1];
- const hidden_size = parseInt(layer.data.hidden_size, 10);
- data = weight('W', precision, [4 * hidden_size, input_size], data);
- data = weight('R', precision, [4 * hidden_size, hidden_size], data);
- break;
- }
- case 'LSTMCell:biases': {
- const hidden_size = parseInt(layer.data.hidden_size, 10);
- data = weight('B', precision, [4 * hidden_size], data);
- break;
- }
- case 'GRUCell:weights': {
- const input_size = inputs[0].type.shape.dimensions[1];
- const hidden_size = parseInt(layer.data.hidden_size, 10);
- data = weight('W', precision, [3 * hidden_size, input_size], data);
- data = weight('R', precision, [3 * hidden_size, hidden_size], data);
- break;
- }
- case 'GRUCell:biases': {
- const linear_before_reset = parseInt(layer.data.linear_before_reset, 10);
- const hidden_size = parseInt(layer.data.hidden_size, 10);
- dimensions = linear_before_reset ? [4 * hidden_size] : [3 * hidden_size];
- data = weight('B', precision, dimensions, data);
- break;
- }
- case 'Convolution:biases': {
- dimensions = [parseInt(layer.data.output, 10)];
- break;
- }
- case 'ScaleShift:weights':
- case 'ScaleShift:biases':
- case 'Normalize:weights': {
- dimensions = [layer.input[0].dims[1]];
- break;
- }
- case 'PReLU:weights': {
- dimensions = layer.data.channel_shared === '1' ? [1] : [layer.input[0].dims[1]];
- break;
- }
- case 'Const:custom': {
- if (this.outputs.length > 0 &&
- this.outputs[0].value.length > 0 &&
- this.outputs[0].value[0].type &&
- this.outputs[0].value[0].type.shape &&
- this.outputs[0].value[0].type.shape.dimensions) {
- dimensions = this.outputs[0].value[0].type.shape.dimensions;
- }
- break;
- }
- default: {
- break;
- }
- }
- }
- if (data) {
- weight(name, precision, dimensions, data);
- }
- }
- }
- };
- openvino.Argument = class {
- constructor(name, value, type = null, visible = true) {
- this.name = name;
- this.value = value;
- this.type = type;
- this.visible = visible;
- }
- };
- openvino.Value = class {
- constructor(name, type, initializer = null) {
- if (typeof name !== 'string') {
- throw new openvino.Error(`Invalid value identifier '${JSON.stringify(name)}'.`);
- }
- this.name = name;
- this.type = initializer ? initializer.type : type;
- this.initializer = initializer;
- }
- };
- openvino.Tensor = class {
- constructor(type, data, category) {
- this.type = type;
- this.values = data;
- this.category = category;
- }
- };
- openvino.TensorType = class {
- constructor(precision, shape) {
- precision = precision ? precision.toLowerCase() : precision;
- switch (precision) {
- case 'f4e2m1': this.dataType = 'float4e2m1'; break;
- case 'f8e4m3': this.dataType = 'float8e4m3'; break;
- case 'f8e5m2': this.dataType = 'float8e5m2'; break;
- case 'f8e8m0': this.dataType = 'float8e8m0'; break;
- case 'f16': this.dataType = 'float16'; break;
- case 'f32': this.dataType = 'float32'; break;
- case 'f64': this.dataType = 'float64'; break;
- case 'fp16': this.dataType = 'float16'; break;
- case 'fp32': this.dataType = 'float32'; break;
- case 'fp64': this.dataType = 'float64'; break;
- case 'bf16': this.dataType = 'bfloat16'; break;
- case 'nf4': this.dataType = 'nfloat4'; break;
- case 'i2': this.dataType = 'int2'; break;
- case 'i4': this.dataType = 'int4'; break;
- case 'i8': this.dataType = 'int8'; break;
- case 'i16': this.dataType = 'int16'; break;
- case 'i32': this.dataType = 'int32'; break;
- case 'i64': this.dataType = 'int64'; break;
- case 'u1': this.dataType = 'boolean'; break;
- case 'u2': this.dataType = 'uint2'; break;
- case 'u4': this.dataType = 'uint4'; break;
- case 'u8': this.dataType = 'uint8'; break;
- case 'u16': this.dataType = 'uint16'; break;
- case 'u32': this.dataType = 'uint32'; break;
- case 'u64': this.dataType = 'uint64'; break;
- case 'bool': this.dataType = 'boolean'; break;
- case 'boolean': this.dataType = 'boolean'; break;
- case 'bin': this.dataType = 'bit'; break;
- case 'string': this.dataType = 'string'; break;
- case 'dynamic': this.dataType = 'dynamic'; break;
- case 'unspecified': this.dataType = 'unspecified'; break;
- case '': this.dataType = '?'; break;
- case null: this.dataType = '?'; break;
- default: throw new openvino.Error(`Unsupported precision '${JSON.stringify(precision)}'.`);
- }
- this.shape = shape;
- }
- equals(obj) {
- return obj && this.dataType === obj.dataType &&
- ((this.shape === null && obj.shape === null) || this.shape && this.shape.equals(obj.shape));
- }
- toString() {
- if (this.shape === null) {
- return `${this.dataType}[?]`;
- }
- return this.dataType + this.shape.toString();
- }
- };
- openvino.TensorShape = class {
- constructor(dimensions) {
- this.dimensions = dimensions;
- }
- equals(obj) {
- return obj && Array.isArray(obj.dimensions) &&
- Array.isArray(this.dimensions) && this.dimensions.length === obj.dimensions.length
- && obj.dimensions.every((value, index) => this.dimensions[index] === value);
- }
- toString() {
- if (!this.dimensions || this.dimensions.length === 0) {
- return '';
- }
- return `[${this.dimensions.join(',')}]`;
- }
- };
- openvino.Error = class extends Error {
- constructor(message) {
- super(message);
- this.name = 'Error loading OpenVINO model.';
- }
- };
- export const ModelFactory = openvino.ModelFactory;
|