|
|
@@ -1,32 +1,88 @@
|
|
|
|
|
|
var rknn = rknn || {};
|
|
|
+var base = base || require('./base');
|
|
|
+var flatbuffers = flatbuffers || require('./flatbuffers');
|
|
|
var json = json || require('./json');
|
|
|
|
|
|
rknn.ModelFactory = class {
|
|
|
|
|
|
match(context) {
|
|
|
- return rknn.Reader.open(context);
|
|
|
+ return rknn.Container.open(context);
|
|
|
}
|
|
|
|
|
|
open(context, match) {
|
|
|
- return context.metadata('rknn-metadata.json').then((metadata) => {
|
|
|
- const reader = match;
|
|
|
- return new rknn.Model(metadata, reader.model, reader.weights);
|
|
|
+ return context.require('./rknn-schema').then(() => {
|
|
|
+ rknn.schema = flatbuffers.get('rknn').rknn;
|
|
|
+ return context.metadata('rknn-metadata.json').then((metadata) => {
|
|
|
+ const container = match;
|
|
|
+ const type = container.type;
|
|
|
+ switch (type) {
|
|
|
+ case 'json': {
|
|
|
+ const buffer = container.value;
|
|
|
+ const reader = json.TextReader.open(buffer);
|
|
|
+ const model = reader.read();
|
|
|
+ return new rknn.Model(metadata, type, model, container.next);
|
|
|
+ }
|
|
|
+ case 'flatbuffers': {
|
|
|
+ const buffer = container.value;
|
|
|
+ const reader = flatbuffers.BinaryReader.open(buffer);
|
|
|
+ const model = rknn.schema.Model.create(reader);
|
|
|
+ return new rknn.Model(metadata, type, model, null);
|
|
|
+ }
|
|
|
+ case 'openvx': {
|
|
|
+ const buffer = container.value;
|
|
|
+ const model = new openvx.Model(buffer);
|
|
|
+ return new rknn.Model(metadata, type, model, null);
|
|
|
+ }
|
|
|
+ default: {
|
|
|
+ throw new rknn.Error("Unsupported RKNN format '" + container.type + "'.");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
});
|
|
|
}
|
|
|
};
|
|
|
|
|
|
rknn.Model = class {
|
|
|
|
|
|
- constructor(metadata, model, weights) {
|
|
|
- this._version = model.version;
|
|
|
- this._producer = model.ori_network_platform || model.network_platform || '';
|
|
|
- this._runtime = model.target_platform ? model.target_platform.join(',') : '';
|
|
|
- this._graphs = [ new rknn.Graph(metadata, model, weights) ];
|
|
|
+ constructor(metadata, type, model, next) {
|
|
|
+ switch (type) {
|
|
|
+ case 'json': {
|
|
|
+ this._format = 'RKNN v' + model.version.split('-').shift();
|
|
|
+ this._name = model.name || '';
|
|
|
+ this._producer = model.ori_network_platform || model.network_platform || '';
|
|
|
+ this._runtime = model.target_platform ? model.target_platform.join(',') : '';
|
|
|
+ this._graphs = [ new rknn.Graph(metadata, type, model.name || '', model, next) ];
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ case 'flatbuffers': {
|
|
|
+ const version = model.compiler.split('-').shift();
|
|
|
+ this._format = 'RKNN Lite' + (version ? ' v' + version : '');
|
|
|
+ this._runtime = model.runtime;
|
|
|
+ this._name = model.name || '';
|
|
|
+ this._graphs = model.graphs.map((graph) => new rknn.Graph(metadata, type, '', graph, null));
|
|
|
+ this._metadata = [];
|
|
|
+ this._metadata.push({ name: 'source', value: model.source });
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ case 'openvx': {
|
|
|
+ this._format = 'RKNN OpenVX';
|
|
|
+ this._name = model.name || '';
|
|
|
+ this._graphs = [ new rknn.Graph(metadata, type, '', model, next) ];
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ default: {
|
|
|
+ throw new rknn.Error("Unsupported RKNN model type '" + type + "'.");
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
get format() {
|
|
|
- return 'RKNN v' + this._version;
|
|
|
+ return this._format;
|
|
|
+ }
|
|
|
+
|
|
|
+ get name() {
|
|
|
+ return this._name;
|
|
|
}
|
|
|
|
|
|
get producer() {
|
|
|
@@ -37,6 +93,10 @@ rknn.Model = class {
|
|
|
return this._runtime;
|
|
|
}
|
|
|
|
|
|
+ get metadata() {
|
|
|
+ return this._metadata;
|
|
|
+ }
|
|
|
+
|
|
|
get graphs() {
|
|
|
return this._graphs;
|
|
|
}
|
|
|
@@ -44,79 +104,101 @@ rknn.Model = class {
|
|
|
|
|
|
rknn.Graph = class {
|
|
|
|
|
|
- constructor(metadata, model, weights) {
|
|
|
- this._name = model.name || '';
|
|
|
+ constructor(metadata, type, name, obj, next) {
|
|
|
+ this._name = name;
|
|
|
this._inputs = [];
|
|
|
this._outputs = [];
|
|
|
this._nodes = [];
|
|
|
-
|
|
|
- const args = new Map();
|
|
|
- for (const const_tensor of model.const_tensor) {
|
|
|
- const name = 'const_tensor:' + const_tensor.tensor_id.toString();
|
|
|
- const shape = new rknn.TensorShape(const_tensor.size);
|
|
|
- const type = new rknn.TensorType(const_tensor.dtype, shape);
|
|
|
- const tensor = new rknn.Tensor(type, const_tensor.offset, weights);
|
|
|
- const argument = new rknn.Argument(name, type, tensor);
|
|
|
- args.set(name, argument);
|
|
|
- }
|
|
|
- for (const virtual_tensor of model.virtual_tensor) {
|
|
|
- const name = virtual_tensor.node_id.toString() + ':' + virtual_tensor.output_port.toString();
|
|
|
- const argument = new rknn.Argument(name, null, null);
|
|
|
- args.set(name, argument);
|
|
|
- }
|
|
|
- for (const norm_tensor of model.norm_tensor) {
|
|
|
- const name = 'norm_tensor:' + norm_tensor.tensor_id.toString();
|
|
|
- const shape = new rknn.TensorShape(norm_tensor.size);
|
|
|
- const type = new rknn.TensorType(norm_tensor.dtype, shape);
|
|
|
- const argument = new rknn.Argument(name, type, null);
|
|
|
- args.set(name, argument);
|
|
|
- }
|
|
|
- const arg = (name) => {
|
|
|
- if (!args.has(name)) {
|
|
|
- const argument = new rknn.Argument(name, null, null);
|
|
|
- args.set(name, argument);
|
|
|
+ switch (type) {
|
|
|
+ case 'json': {
|
|
|
+ const model = obj;
|
|
|
+ const args = new Map();
|
|
|
+ for (const const_tensor of model.const_tensor) {
|
|
|
+ const name = 'const_tensor:' + const_tensor.tensor_id.toString();
|
|
|
+ const shape = new rknn.TensorShape(const_tensor.size);
|
|
|
+ const type = new rknn.TensorType(const_tensor.dtype, shape);
|
|
|
+ const tensor = new rknn.Tensor(type, const_tensor.offset, next.value);
|
|
|
+ const argument = new rknn.Argument(name, type, tensor);
|
|
|
+ args.set(name, argument);
|
|
|
+ }
|
|
|
+ for (const virtual_tensor of model.virtual_tensor) {
|
|
|
+ const name = virtual_tensor.node_id.toString() + ':' + virtual_tensor.output_port.toString();
|
|
|
+ const argument = new rknn.Argument(name, null, null);
|
|
|
+ args.set(name, argument);
|
|
|
+ }
|
|
|
+ for (const norm_tensor of model.norm_tensor) {
|
|
|
+ const name = 'norm_tensor:' + norm_tensor.tensor_id.toString();
|
|
|
+ const shape = new rknn.TensorShape(norm_tensor.size);
|
|
|
+ const type = new rknn.TensorType(norm_tensor.dtype, shape);
|
|
|
+ const argument = new rknn.Argument(name, type, null);
|
|
|
+ args.set(name, argument);
|
|
|
+ }
|
|
|
+ const arg = (name) => {
|
|
|
+ if (!args.has(name)) {
|
|
|
+ const argument = new rknn.Argument(name, null, null);
|
|
|
+ args.set(name, argument);
|
|
|
+ }
|
|
|
+ return args.get(name);
|
|
|
+ };
|
|
|
+ for (const node of model.nodes) {
|
|
|
+ node.input = [];
|
|
|
+ node.output = [];
|
|
|
+ }
|
|
|
+ for (const connection of model.connection) {
|
|
|
+ switch (connection.left) {
|
|
|
+ case 'input':
|
|
|
+ model.nodes[connection.node_id].input.push(connection);
|
|
|
+ if (connection.right_node) {
|
|
|
+ model.nodes[connection.right_node.node_id].output[connection.right_node.tensor_id] = connection;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case 'output':
|
|
|
+ model.nodes[connection.node_id].output.push(connection);
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ throw new rknn.Error("Unsupported left connection '" + connection.left + "'.");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ for (const graph of model.graph) {
|
|
|
+ const key = graph.right + ':' + graph.right_tensor_id.toString();
|
|
|
+ const argument = arg(key);
|
|
|
+ const name = graph.left + (graph.left_tensor_id === 0 ? '' : graph.left_tensor_id.toString());
|
|
|
+ const parameter = new rknn.Parameter(name, [ argument ]);
|
|
|
+ switch (graph.left) {
|
|
|
+ case 'input':
|
|
|
+ this._inputs.push(parameter);
|
|
|
+ break;
|
|
|
+ case 'output':
|
|
|
+ this._outputs.push(parameter);
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ throw new rknn.Error("Unsupported left graph connection '" + graph.left + "'.");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ this._nodes = model.nodes.map((node) => new rknn.Node(metadata, type, node, arg, next));
|
|
|
+ break;
|
|
|
}
|
|
|
- return args.get(name);
|
|
|
- };
|
|
|
-
|
|
|
- for (const node of model.nodes) {
|
|
|
- node.input = [];
|
|
|
- node.output = [];
|
|
|
- }
|
|
|
- for (const connection of model.connection) {
|
|
|
- switch (connection.left) {
|
|
|
- case 'input':
|
|
|
- model.nodes[connection.node_id].input.push(connection);
|
|
|
- if (connection.right_node) {
|
|
|
- model.nodes[connection.right_node.node_id].output[connection.right_node.tensor_id] = connection;
|
|
|
+ case 'flatbuffers': {
|
|
|
+ const graph = obj;
|
|
|
+ const args = graph.tensors.map((tensor) => new rknn.Argument(tensor.name));
|
|
|
+ const arg = (index) => {
|
|
|
+ if (index >= args.length) {
|
|
|
+ throw new rknn.Error("Invalid tensor index '" + index.toString() + "'.");
|
|
|
}
|
|
|
- break;
|
|
|
- case 'output':
|
|
|
- model.nodes[connection.node_id].output.push(connection);
|
|
|
- break;
|
|
|
- default:
|
|
|
- throw new rknn.Error("Unsupported left connection '" + connection.left + "'.");
|
|
|
+ return args[index];
|
|
|
+ };
|
|
|
+ this._nodes = graph.nodes.map((node) => new rknn.Node(metadata, type, node, arg, next));
|
|
|
+ break;
|
|
|
}
|
|
|
- }
|
|
|
-
|
|
|
- for (const graph of model.graph) {
|
|
|
- const key = graph.right + ':' + graph.right_tensor_id.toString();
|
|
|
- const argument = arg(key);
|
|
|
- const name = graph.left + (graph.left_tensor_id === 0 ? '' : graph.left_tensor_id.toString());
|
|
|
- const parameter = new rknn.Parameter(name, [ argument ]);
|
|
|
- switch (graph.left) {
|
|
|
- case 'input':
|
|
|
- this._inputs.push(parameter);
|
|
|
- break;
|
|
|
- case 'output':
|
|
|
- this._outputs.push(parameter);
|
|
|
- break;
|
|
|
- default:
|
|
|
- throw new rknn.Error("Unsupported left graph connection '" + graph.left + "'.");
|
|
|
+ case 'openvx': {
|
|
|
+ const model = obj;
|
|
|
+ this._nodes = model.nodes.map((node) => new rknn.Node(metadata, type, node, null, next));
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ default: {
|
|
|
+ throw new rknn.Error("Unsupported RKNN graph type '" + type + "'.");
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
- this._nodes = model.nodes.map((node) => new rknn.Node(metadata, node, arg));
|
|
|
}
|
|
|
|
|
|
get name() {
|
|
|
@@ -182,55 +264,98 @@ rknn.Argument = class {
|
|
|
|
|
|
rknn.Node = class {
|
|
|
|
|
|
- constructor(metadata, node, arg) {
|
|
|
- this._name = node.name || '';
|
|
|
- this._type = Object.assign({}, metadata.type(node.op) || { name: node.op });
|
|
|
- for (const prefix of [ 'VSI_NN_OP_', 'RKNN_OP_' ]) {
|
|
|
- this._type.name = this._type.name.startsWith(prefix) ? this._type.name.substring(prefix.length) : this._type.name;
|
|
|
- }
|
|
|
- this._inputs = [];
|
|
|
- this._outputs = [];
|
|
|
- this._attributes = [];
|
|
|
- node.input = node.input || [];
|
|
|
- for (let i = 0; i < node.input.length; ) {
|
|
|
- const input = this._type && this._type.inputs && i < this._type.inputs.length ? this._type.inputs[i] : { name: i === 0 ? 'input' : i.toString() };
|
|
|
- const count = input.list ? node.input.length - i : 1;
|
|
|
- const list = node.input.slice(i, i + count).map((input) => {
|
|
|
- if (input.right_tensor) {
|
|
|
- return arg(input.right_tensor.type + ':' + input.right_tensor.tensor_id.toString());
|
|
|
+ constructor(metadata, type, node, arg, next) {
|
|
|
+ switch (type) {
|
|
|
+ case 'json': {
|
|
|
+ this._name = node.name || '';
|
|
|
+ if (node.op === 'VSI_NN_OP_NBG' && next && next.type === 'openvx') {
|
|
|
+ const buffer = next.value;
|
|
|
+ const model = new openvx.Model(buffer);
|
|
|
+ this._type = new rknn.Graph(metadata, next.type, 'NBG', model, null);
|
|
|
}
|
|
|
- if (input.right_node) {
|
|
|
- return arg(input.right_node.node_id.toString() + ':' + input.right_node.tensor_id.toString());
|
|
|
+ else if (node.op === 'RKNN_OP_NNBG' && next && next.type === 'flatbuffers') {
|
|
|
+ const buffer = next.value;
|
|
|
+ const reader = flatbuffers.BinaryReader.open(buffer);
|
|
|
+ const model = rknn.schema.Model.create(reader);
|
|
|
+ this._type = new rknn.Graph(metadata, next.type, 'NNBG', model.graphs[0], null);
|
|
|
}
|
|
|
- throw new rknn.Error('Invalid input argument.');
|
|
|
- });
|
|
|
- this._inputs.push(new rknn.Parameter(input.name, list));
|
|
|
- i += count;
|
|
|
- }
|
|
|
- node.output = node.output || [];
|
|
|
- for (let i = 0; i < node.output.length; ) {
|
|
|
- const output = this._metadata && this._metadata.outputs && i < this._metadata.outputs.length ? this._metadata.outputs[i] : { name: i === 0 ? 'output' : i.toString() };
|
|
|
- const count = output.list ? node.output.length - i : 1;
|
|
|
- const list = node.output.slice(i, i + count).map((output) => {
|
|
|
- if (output.right_tensor) {
|
|
|
- return arg(output.right_tensor.type + ':' + output.right_tensor.tensor_id.toString());
|
|
|
+ else {
|
|
|
+ this._type = Object.assign({}, metadata.type(node.op) || { name: node.op });
|
|
|
+ for (const prefix of [ 'VSI_NN_OP_', 'RKNN_OP_' ]) {
|
|
|
+ this._type.name = this._type.name.startsWith(prefix) ? this._type.name.substring(prefix.length) : this._type.name;
|
|
|
+ }
|
|
|
}
|
|
|
- if (output.right_node) {
|
|
|
- return arg(output.right_node.node_id.toString() + ':' + output.right_node.tensor_id.toString());
|
|
|
+ this._inputs = [];
|
|
|
+ this._outputs = [];
|
|
|
+ this._attributes = [];
|
|
|
+ node.input = node.input || [];
|
|
|
+ for (let i = 0; i < node.input.length; ) {
|
|
|
+ const input = this._type && this._type.inputs && i < this._type.inputs.length ? this._type.inputs[i] : { name: i === 0 ? 'input' : i.toString() };
|
|
|
+ const count = input.list ? node.input.length - i : 1;
|
|
|
+ const list = node.input.slice(i, i + count).map((input) => {
|
|
|
+ if (input.right_tensor) {
|
|
|
+ return arg(input.right_tensor.type + ':' + input.right_tensor.tensor_id.toString());
|
|
|
+ }
|
|
|
+ if (input.right_node) {
|
|
|
+ return arg(input.right_node.node_id.toString() + ':' + input.right_node.tensor_id.toString());
|
|
|
+ }
|
|
|
+ throw new rknn.Error('Invalid input argument.');
|
|
|
+ });
|
|
|
+ this._inputs.push(new rknn.Parameter(input.name, list));
|
|
|
+ i += count;
|
|
|
}
|
|
|
- throw new rknn.Error('Invalid output argument.');
|
|
|
- });
|
|
|
- this._outputs.push(new rknn.Parameter(output.name, list));
|
|
|
- i += count;
|
|
|
- }
|
|
|
- if (node.nn) {
|
|
|
- const nn = node.nn;
|
|
|
- for (const key of Object.keys(nn)) {
|
|
|
- const params = nn[key];
|
|
|
- for (const name of Object.keys(params)) {
|
|
|
- const value = params[name];
|
|
|
- this._attributes.push(new rknn.Attribute(name, value));
|
|
|
+ node.output = node.output || [];
|
|
|
+ for (let i = 0; i < node.output.length; ) {
|
|
|
+ const output = this._metadata && this._metadata.outputs && i < this._metadata.outputs.length ? this._metadata.outputs[i] : { name: i === 0 ? 'output' : i.toString() };
|
|
|
+ const count = output.list ? node.output.length - i : 1;
|
|
|
+ const list = node.output.slice(i, i + count).map((output) => {
|
|
|
+ if (output.right_tensor) {
|
|
|
+ return arg(output.right_tensor.type + ':' + output.right_tensor.tensor_id.toString());
|
|
|
+ }
|
|
|
+ if (output.right_node) {
|
|
|
+ return arg(output.right_node.node_id.toString() + ':' + output.right_node.tensor_id.toString());
|
|
|
+ }
|
|
|
+ throw new rknn.Error('Invalid output argument.');
|
|
|
+ });
|
|
|
+ this._outputs.push(new rknn.Parameter(output.name, list));
|
|
|
+ i += count;
|
|
|
+ }
|
|
|
+ if (node.nn) {
|
|
|
+ const nn = node.nn;
|
|
|
+ for (const key of Object.keys(nn)) {
|
|
|
+ const params = nn[key];
|
|
|
+ for (const name of Object.keys(params)) {
|
|
|
+ const value = params[name];
|
|
|
+ this._attributes.push(new rknn.Attribute(name, value));
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ case 'flatbuffers': {
|
|
|
+ this._name = node.name;
|
|
|
+ this._type = metadata.type(node.type);
|
|
|
+ this._inputs = Array.from(node.inputs).map((input, index) => {
|
|
|
+ const argument = arg(input);
|
|
|
+ return new rknn.Parameter(index.toString(), [ argument ]);
|
|
|
+ });
|
|
|
+ this._outputs = Array.from(node.outputs).map((output, index) => {
|
|
|
+ const argument = arg(output);
|
|
|
+ return new rknn.Parameter(index.toString(), [ argument ]);
|
|
|
+ });
|
|
|
+ this._attributes = [];
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ case 'openvx': {
|
|
|
+ this._name = '';
|
|
|
+ this._type = metadata.type(node.type);
|
|
|
+ this._inputs = [];
|
|
|
+ this._outputs = [];
|
|
|
+ this._attributes = [];
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ default: {
|
|
|
+ throw new rknn.Error("Unsupported RKNN node type '" + type + "'.");
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
@@ -286,6 +411,7 @@ rknn.Tensor = class {
|
|
|
case 'float16': size = 2; break;
|
|
|
case 'float32': size = 4; break;
|
|
|
case 'float64': size = 8; break;
|
|
|
+ case 'vdata': size = 1; break;
|
|
|
default: throw new rknn.Error("Unsupported tensor data type '" + this._type.dataType + "'.");
|
|
|
}
|
|
|
const shape = type.shape.dimensions;
|
|
|
@@ -469,69 +595,173 @@ rknn.TensorShape = class {
|
|
|
}
|
|
|
};
|
|
|
|
|
|
-rknn.Reader = class {
|
|
|
+rknn.Container = class {
|
|
|
|
|
|
static open(context) {
|
|
|
const stream = context.stream;
|
|
|
- if (stream.length >= 8) {
|
|
|
- const buffer = stream.read(8);
|
|
|
- const decoder = new TextDecoder();
|
|
|
- const signature = decoder.decode(buffer);
|
|
|
- if (signature === 'RKNN\0\0\0\0' || signature === 'CYPTRKNN') {
|
|
|
- return new rknn.Reader(stream, signature);
|
|
|
- }
|
|
|
- }
|
|
|
- return null;
|
|
|
+ const container = new rknn.Container(stream, stream.length);
|
|
|
+ return container.type ? container : null;
|
|
|
}
|
|
|
|
|
|
- constructor(stream, signature) {
|
|
|
+ constructor(stream, length) {
|
|
|
this._stream = stream;
|
|
|
- this._signature = signature;
|
|
|
+ this._length = length;
|
|
|
+ this._type = '';
|
|
|
+ if ((stream.position + 16) <= this._length) {
|
|
|
+ const signature = [ 0x52, 0x4B, 0x4E, 0x4E ]; // RKNN
|
|
|
+ if (stream.peek(signature.length).every((value, index) => value === signature[index])) {
|
|
|
+ this._type = 'json';
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if ((stream.position + 16) <= this._length) {
|
|
|
+ const signature = [ 0x43, 0x59, 0x50, 0x54, 0x52, 0x4B, 0x4E, 0x4E ]; // RKNN
|
|
|
+ if (stream.peek(signature.length).every((value, index) => value === signature[index])) {
|
|
|
+ this._type = 'crypt';
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if ((stream.position + 8) <= this._length) {
|
|
|
+ const signature = [ 0x52, 0x4B, 0x4E, 0x4E ]; // RKNN
|
|
|
+ if (stream.peek(8).subarray(4, 8).every((value, index) => value === signature[index])) {
|
|
|
+ this._type = 'flatbuffers';
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if ((stream.position + 8) <= this._length) {
|
|
|
+ const signature = [ 0x56, 0x50, 0x4D, 0x4E ]; // VPMN
|
|
|
+ if (stream.peek(signature.length).every((value, index) => value === signature[index])) {
|
|
|
+ this._type = 'openvx';
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- get version() {
|
|
|
- this._decode();
|
|
|
- return this._version;
|
|
|
+ get type() {
|
|
|
+ return this._type;
|
|
|
}
|
|
|
|
|
|
- get weights() {
|
|
|
- this._decode();
|
|
|
- return this._weights;
|
|
|
+ get value() {
|
|
|
+ this.read();
|
|
|
+ return this._value;
|
|
|
}
|
|
|
|
|
|
- get model() {
|
|
|
- this._decode();
|
|
|
- return this._model;
|
|
|
+ get next() {
|
|
|
+ this.read();
|
|
|
+ return this._next;
|
|
|
}
|
|
|
|
|
|
- _decode() {
|
|
|
+ read() {
|
|
|
if (this._stream) {
|
|
|
- if (this._signature === 'CYPTRKNN') {
|
|
|
- throw new rknn.Error('Invalid file content. File contains undocumented encrypted RKNN data.');
|
|
|
+ const stream = this._stream;
|
|
|
+ delete this._stream;
|
|
|
+ switch (this._type) {
|
|
|
+ case 'crypt': {
|
|
|
+ throw new rknn.Error('Invalid file content. File contains undocumented encrypted RKNN data.');
|
|
|
+ }
|
|
|
+ case 'json': {
|
|
|
+ const uint64 = () => {
|
|
|
+ const buffer = stream.read(8);
|
|
|
+ const reader = new base.BinaryReader(buffer);
|
|
|
+ return reader.uint64();
|
|
|
+ };
|
|
|
+ stream.skip(8);
|
|
|
+ const version = uint64();
|
|
|
+ const data_size = uint64();
|
|
|
+ switch (version) {
|
|
|
+ case 0x0001:
|
|
|
+ case 0x1001:
|
|
|
+ break;
|
|
|
+ case 0x0002:
|
|
|
+ if (data_size > 0) {
|
|
|
+ stream.skip(40);
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ throw new rknn.Error("Unsupported container version '" + version + "'.");
|
|
|
+ }
|
|
|
+ this._next = new rknn.Container(stream, data_size);
|
|
|
+ this._next.read();
|
|
|
+ const value_size = uint64(stream);
|
|
|
+ this._value = stream.read(value_size);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ case 'flatbuffers': {
|
|
|
+ this._value = stream.read(this._length);
|
|
|
+ this._next = null;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ case 'openvx': {
|
|
|
+ this._value = stream.read(this._length);
|
|
|
+ this._next = null;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ case '': {
|
|
|
+ this._value = stream.read(this._length);
|
|
|
+ this._next = null;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ default: {
|
|
|
+ throw new rknn.Error("Unsupported container type '" + this._format + "'.");
|
|
|
+ }
|
|
|
}
|
|
|
- this._version = this._uint64();
|
|
|
- const weights_size = this._uint64();
|
|
|
- if (this._version > 1) {
|
|
|
- this._stream.read(40);
|
|
|
+ }
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+var openvx = openvx || {};
|
|
|
+
|
|
|
+openvx.Model = class {
|
|
|
+
|
|
|
+ constructor(buffer) {
|
|
|
+ const reader = new openvx.BinaryReader(buffer);
|
|
|
+ reader.skip(4); // signature
|
|
|
+ const major = reader.uint16();
|
|
|
+ /* const minor = */ reader.uint16();
|
|
|
+ reader.skip(4);
|
|
|
+ this._name = reader.string(64);
|
|
|
+ this._nodes = new Array(reader.uint32());
|
|
|
+ if (major > 3) {
|
|
|
+ reader.skip(296);
|
|
|
+ }
|
|
|
+ else if (major > 1) {
|
|
|
+ reader.skip(288);
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ reader.skip(32);
|
|
|
+ }
|
|
|
+ /* const inputOffset = */ reader.uint32();
|
|
|
+ /* const inputSize = */ reader.uint32();
|
|
|
+ /* const outputOffset = */ reader.uint32();
|
|
|
+ /* const outputSize = */ reader.uint32();
|
|
|
+ const nodeOffset = reader.uint32();
|
|
|
+ /* const nodeSize = */ reader.uint32();
|
|
|
+ reader.seek(nodeOffset);
|
|
|
+ for (let i = 0; i < this._nodes.length; i++) {
|
|
|
+ const type = reader.string(64);
|
|
|
+ const node = { type: type };
|
|
|
+ node.index = reader.uint32();
|
|
|
+ node.c = reader.uint32();
|
|
|
+ if (major > 3) {
|
|
|
+ node.d = reader.uint32();
|
|
|
}
|
|
|
- this._weights = this._stream.read(weights_size);
|
|
|
- const model_size = this._uint64();
|
|
|
- const model_buffer = this._stream.read(model_size);
|
|
|
- const reader = json.TextReader.open(model_buffer);
|
|
|
- this._model = reader.read();
|
|
|
- delete this._stream;
|
|
|
+ this._nodes[i] = node;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- _uint64() {
|
|
|
- const buffer = this._stream.read(8);
|
|
|
- const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength);
|
|
|
- return view.getUint64(0, true).toNumber();
|
|
|
+ get name() {
|
|
|
+ return this._name;
|
|
|
}
|
|
|
|
|
|
- _read() {
|
|
|
- const size = this._uint64();
|
|
|
- return this._stream.read(size);
|
|
|
+ get nodes() {
|
|
|
+ return this._nodes;
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+openvx.BinaryReader = class extends base.BinaryReader {
|
|
|
+
|
|
|
+ string(length) {
|
|
|
+ const buffer = this.read(length);
|
|
|
+ const index = buffer.indexOf(0);
|
|
|
+ const data = index === -1 ? buffer : buffer.subarray(0, index);
|
|
|
+ this._decoder = this._decoder || new TextDecoder('ascii');
|
|
|
+ return this._decoder.decode(data);
|
|
|
}
|
|
|
};
|
|
|
|