|
|
@@ -56,23 +56,29 @@ kmodel.Graph = class {
|
|
|
index++;
|
|
|
}
|
|
|
for (const layer of model.layers) {
|
|
|
- if (layer.type.name === 'INPUT') {
|
|
|
- for (const input of layer.outputs) {
|
|
|
- this._inputs.push(new kmodel.Parameter('input', input.arguments.map((argument) => {
|
|
|
- return new kmodel.Argument(argument.name);
|
|
|
- })));
|
|
|
+ switch (layer.type.name) {
|
|
|
+ case 'INPUT':
|
|
|
+ case 'input': {
|
|
|
+ for (const input of layer.outputs) {
|
|
|
+ this._inputs.push(new kmodel.Parameter('input', input.arguments.map((argument) => {
|
|
|
+ return new kmodel.Argument(argument.name);
|
|
|
+ })));
|
|
|
+ }
|
|
|
+ break;
|
|
|
}
|
|
|
- continue;
|
|
|
- }
|
|
|
- if (layer.type.name === 'OUTPUT') {
|
|
|
- for (const output of layer.inputs) {
|
|
|
- this._outputs.push(new kmodel.Parameter(output.name, output.arguments.map((argument) => {
|
|
|
- return new kmodel.Argument(argument.name);
|
|
|
- })));
|
|
|
+ case 'OUTPUT':
|
|
|
+ case 'output': {
|
|
|
+ for (const output of layer.inputs) {
|
|
|
+ this._outputs.push(new kmodel.Parameter(output.name, output.arguments.map((argument) => {
|
|
|
+ return new kmodel.Argument(argument.name);
|
|
|
+ })));
|
|
|
+ }
|
|
|
+ break;
|
|
|
}
|
|
|
- continue;
|
|
|
+ default:
|
|
|
+ this._nodes.push(new kmodel.Node(layer));
|
|
|
+ break;
|
|
|
}
|
|
|
- this._nodes.push(new kmodel.Node(layer));
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -186,7 +192,86 @@ kmodel.Tensor = class {
|
|
|
}
|
|
|
|
|
|
get state() {
|
|
|
- return 'Tensor data not implemented.';
|
|
|
+ return this._context().state;
|
|
|
+ }
|
|
|
+
|
|
|
+ get value() {
|
|
|
+ const context = this._context();
|
|
|
+ if (context.state) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ context.limit = Number.MAX_SAFE_INTEGER;
|
|
|
+ return this._decode(context, 0);
|
|
|
+ }
|
|
|
+
|
|
|
+ toString() {
|
|
|
+ const context = this._context();
|
|
|
+ if (context.state) {
|
|
|
+ return '';
|
|
|
+ }
|
|
|
+ context.limit = 10000;
|
|
|
+ const value = this._decode(context, 0);
|
|
|
+ return JSON.stringify(value, null, 4);
|
|
|
+ }
|
|
|
+
|
|
|
+ _context() {
|
|
|
+ const context = {};
|
|
|
+ context.state = null;
|
|
|
+ context.index = 0;
|
|
|
+ context.count = 0;
|
|
|
+ if (this._data == null || this._data.length === 0) {
|
|
|
+ context.state = 'Tensor data is empty.';
|
|
|
+ return context;
|
|
|
+ }
|
|
|
+ const dataType = this.type.dataType;
|
|
|
+ const shape = this.type.shape.dimensions;
|
|
|
+ if (dataType !== 'uint8' && dataType !== 'float32') {
|
|
|
+ context.state = "Tensor data type '" + dataType + "' is not implemented.";
|
|
|
+ return context;
|
|
|
+ }
|
|
|
+ context.dataType = dataType;
|
|
|
+ context.shape = shape;
|
|
|
+ context.data = new DataView(this._data.buffer, this._data.byteOffset, this._data.byteLength);
|
|
|
+ return context;
|
|
|
+ }
|
|
|
+
|
|
|
+ _decode(context, dimension) {
|
|
|
+ const shape = (context.shape.length == 0) ? [ 1 ] : context.shape;
|
|
|
+ const size = shape[dimension];
|
|
|
+ const results = [];
|
|
|
+ if (dimension == shape.length - 1) {
|
|
|
+ for (let i = 0; i < size; i++) {
|
|
|
+ if (context.count > context.limit) {
|
|
|
+ results.push('...');
|
|
|
+ return results;
|
|
|
+ }
|
|
|
+ switch (context.dataType) {
|
|
|
+ case 'uint8':
|
|
|
+ results.push(context.data.getUint8(context.index));
|
|
|
+ context.index += 1;
|
|
|
+ context.count++;
|
|
|
+ break;
|
|
|
+ case 'float32':
|
|
|
+ results.push(context.data.getFloat32(context.index, true));
|
|
|
+ context.index += 4;
|
|
|
+ context.count++;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ for (let j = 0; j < size; j++) {
|
|
|
+ if (context.count > context.limit) {
|
|
|
+ results.push('...');
|
|
|
+ return results;
|
|
|
+ }
|
|
|
+ results.push(this._decode(context, dimension + 1));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (context.shape.length == 0) {
|
|
|
+ return results[0];
|
|
|
+ }
|
|
|
+ return results;
|
|
|
}
|
|
|
};
|
|
|
|
|
|
@@ -211,7 +296,7 @@ kmodel.Node = class {
|
|
|
}
|
|
|
for (const input of layer.inputs || []) {
|
|
|
this._inputs.push(new kmodel.Parameter(input.name, input.arguments.map((argument) => {
|
|
|
- const type = argument.shape ? new kmodel.TensorType(argument.data_type || '?', argument.shape) : null;
|
|
|
+ const type = argument.shape ? new kmodel.TensorType(argument.datatype || '?', argument.shape) : null;
|
|
|
const tensor = argument.data ? new kmodel.Tensor(type, argument.data) : null;
|
|
|
return new kmodel.Argument(argument.name, type, tensor);
|
|
|
})));
|
|
|
@@ -333,12 +418,6 @@ kmodel.Reader = class {
|
|
|
}
|
|
|
return obj;
|
|
|
};
|
|
|
- reader.mem_address = function(memory_type, name) {
|
|
|
- const mem_address = this.uint32();
|
|
|
- const argument = { name: memory_type + ':' + mem_address.toString() };
|
|
|
- const parameter = { name: name, arguments: [ argument ] };
|
|
|
- return [ parameter ];
|
|
|
- };
|
|
|
switch (this._version) {
|
|
|
case 3: {
|
|
|
reader.kpu_model_header_t = function() {
|
|
|
@@ -353,7 +432,7 @@ kmodel.Reader = class {
|
|
|
};
|
|
|
reader.kpu_model_output_t = function(name) {
|
|
|
return {
|
|
|
- address: this.mem_address('main', name),
|
|
|
+ address: [ this.parameter(name) ],
|
|
|
size: reader.uint32()
|
|
|
};
|
|
|
};
|
|
|
@@ -363,6 +442,15 @@ kmodel.Reader = class {
|
|
|
body_size: reader.uint32()
|
|
|
};
|
|
|
};
|
|
|
+ reader.argument = function(memory_type) {
|
|
|
+ memory_type = memory_type || 'main';
|
|
|
+ const address = this.uint32();
|
|
|
+ return { name: memory_type + ':' + address.toString() };
|
|
|
+ };
|
|
|
+ reader.parameter = function(name, memory_type) {
|
|
|
+ const argument = this.argument(memory_type);
|
|
|
+ return { name: name, arguments: [ argument ] };
|
|
|
+ };
|
|
|
const model_header = reader.kpu_model_header_t();
|
|
|
this._layers = new Array(model_header.layers_length);
|
|
|
const outputs = new Array(model_header.output_count);
|
|
|
@@ -386,8 +474,8 @@ kmodel.Reader = class {
|
|
|
register( 4, 'QUANTIZED_GLOBAL_MAX_POOL2D', 'Pool');
|
|
|
register( 5, 'GLOBAL_AVERAGE_POOL2D', 'Pool', (layer, reader) => {
|
|
|
layer.flags = reader.uint32();
|
|
|
- layer.inputs = reader.mem_address('main', 'inputs');
|
|
|
- layer.outputs = reader.mem_address('main', 'outputs');
|
|
|
+ layer.inputs = [ reader.parameter('input') ];
|
|
|
+ layer.outputs = [ reader.parameter('output') ];
|
|
|
layer.kernel_size = reader.uint32();
|
|
|
layer.channels = reader.uint32();
|
|
|
});
|
|
|
@@ -395,8 +483,8 @@ kmodel.Reader = class {
|
|
|
register( 7, 'MAX_POOL2D', 'Pool');
|
|
|
register( 8, 'QUANTIZED_MAX_POOL2D', 'Pool', (layer, reader) => {
|
|
|
layer.flags = reader.uint32();
|
|
|
- layer.inputs = reader.mem_address('main', 'inputs');
|
|
|
- layer.outputs = reader.mem_address('main', 'outputs');
|
|
|
+ layer.inputs = [ reader.parameter('input') ];
|
|
|
+ layer.outputs = [ reader.parameter('output') ];
|
|
|
layer.inputs[0].arguments[0].shape = [ reader.uint32(), reader.uint32(), reader.uint32() ];
|
|
|
layer.outputs[0].arguments[0].shape = [ reader.uint32(), reader.uint32(), reader.uint32() ];
|
|
|
layer.kernel = [ reader.uint32(), reader.uint32() ];
|
|
|
@@ -407,16 +495,16 @@ kmodel.Reader = class {
|
|
|
register( 10, 'QUANTIZED_AVERAGE_POOL2D', 'Pool');
|
|
|
register( 11, 'QUANTIZE', '', (layer, reader) => {
|
|
|
layer.flags = reader.uint32();
|
|
|
- layer.inputs = reader.mem_address('main', 'inputs');
|
|
|
- layer.outputs = reader.mem_address('main', 'outputs');
|
|
|
+ layer.inputs = [ reader.parameter('input') ];
|
|
|
+ layer.outputs = [ reader.parameter('output') ];
|
|
|
layer.count = reader.uint32();
|
|
|
layer.scale = reader.float32();
|
|
|
layer.bias = reader.float32();
|
|
|
});
|
|
|
register( 12, 'DEQUANTIZE', '', (layer, reader) => {
|
|
|
layer.flags = reader.uint32();
|
|
|
- layer.inputs = reader.mem_address('main', 'inputs');
|
|
|
- layer.outputs = reader.mem_address('main', 'outputs');
|
|
|
+ layer.inputs = [ reader.parameter('input') ];
|
|
|
+ layer.outputs = [ reader.parameter('output') ];
|
|
|
layer.count = reader.uint32();
|
|
|
layer.scale = reader.float32();
|
|
|
layer.bias = reader.float32();
|
|
|
@@ -425,13 +513,13 @@ kmodel.Reader = class {
|
|
|
register( 14, 'L2_NORMALIZATION', 'Normalization');
|
|
|
register( 15, 'SOFTMAX', 'Activation', (layer, reader) => {
|
|
|
layer.flags = reader.uint32();
|
|
|
- layer.inputs = reader.mem_address('main', 'inputs');
|
|
|
- layer.outputs = reader.mem_address('main', 'outputs');
|
|
|
+ layer.inputs = [ reader.parameter('input') ];
|
|
|
+ layer.outputs = [ reader.parameter('output') ];
|
|
|
layer.channels = reader.uint32();
|
|
|
});
|
|
|
register( 16, 'CONCAT', 'Tensor', (layer, reader) => {
|
|
|
layer.flags = reader.uint32();
|
|
|
- layer.outputs = reader.mem_address('main', 'outputs');
|
|
|
+ layer.outputs = [ reader.parameter('output') ];
|
|
|
layer.inputs_mem = new Array(reader.uint32());
|
|
|
for (let i = 0; i < layer.inputs_mem.length; i++) {
|
|
|
layer.inputs_mem[i] = {
|
|
|
@@ -442,7 +530,7 @@ kmodel.Reader = class {
|
|
|
});
|
|
|
register( 17, 'QUANTIZED_CONCAT', 'Tensor', (layer, reader) => {
|
|
|
layer.flags = reader.uint32();
|
|
|
- layer.outputs = reader.mem_address('main', 'outputs');
|
|
|
+ layer.outputs = [ reader.parameter('output') ];
|
|
|
layer.inputs_mem = new Array(reader.uint32());
|
|
|
for (let i = 0; i < layer.inputs_mem.length; i++) {
|
|
|
layer.inputs_mem[i] = {
|
|
|
@@ -453,8 +541,8 @@ kmodel.Reader = class {
|
|
|
});
|
|
|
register( 18, 'FULLY_CONNECTED', 'Layer', (layer, reader) => {
|
|
|
layer.flags = reader.uint32();
|
|
|
- layer.inputs = reader.mem_address('main', 'inputs');
|
|
|
- layer.outputs = reader.mem_address('main', 'outputs');
|
|
|
+ layer.inputs = [ reader.parameter('input') ];
|
|
|
+ layer.outputs = [ reader.parameter('output') ];
|
|
|
layer.in_channels = reader.uint32();
|
|
|
layer.out_channels = reader.uint32();
|
|
|
const act = reader.uint32();
|
|
|
@@ -469,22 +557,22 @@ kmodel.Reader = class {
|
|
|
}
|
|
|
layer.chain = [ { type: activations[act] } ];
|
|
|
}
|
|
|
- layer.inputs.push({ name: 'weights', arguments: [ { name: '', data_type: 'float32', shape: [ layer.in_channels, layer.out_channels ], data: reader.read(4 * layer.in_channels * layer.out_channels) } ] });
|
|
|
- layer.inputs.push({ name: 'bias', arguments: [ { name: '', data_type: 'float32', shape: [ layer.out_channels ], data: reader.read(4 * layer.out_channels) } ] });
|
|
|
+ layer.inputs.push({ name: 'weights', arguments: [ { name: '', datatype: 'float32', shape: [ layer.in_channels, layer.out_channels ], data: reader.read(4 * layer.in_channels * layer.out_channels) } ] });
|
|
|
+ layer.inputs.push({ name: 'bias', arguments: [ { name: '', datatype: 'float32', shape: [ layer.out_channels ], data: reader.read(4 * layer.out_channels) } ] });
|
|
|
});
|
|
|
register( 19, 'QUANTIZED_FULLY_CONNECTED', 'Layer');
|
|
|
register( 20, 'TENSORFLOW_FLATTEN', 'Shape', (layer, reader) => {
|
|
|
layer.flags = reader.uint32();
|
|
|
- layer.inputs = reader.mem_address('main', 'inputs');
|
|
|
- layer.outputs = reader.mem_address('main', 'outputs');
|
|
|
+ layer.inputs = [ reader.parameter('input') ];
|
|
|
+ layer.outputs = [ reader.parameter('output') ];
|
|
|
const shape = [ reader.uint32(), reader.uint32(), reader.uint32() ];
|
|
|
layer.inputs[0].arguments[0].shape = shape;
|
|
|
layer.outputs[0].arguments[0].shape = shape;
|
|
|
});
|
|
|
register( 21, 'QUANTIZED_TENSORFLOW_FLATTEN', 'Shape', (layer, reader) => {
|
|
|
layer.flags = reader.uint32();
|
|
|
- layer.inputs = reader.mem_address('main', 'inputs');
|
|
|
- layer.outputs = reader.mem_address('main', 'outputs');
|
|
|
+ layer.inputs = [ reader.parameter('input') ];
|
|
|
+ layer.outputs = [ reader.parameter('output') ];
|
|
|
const shape = [ reader.uint32(), reader.uint32(), reader.uint32() ];
|
|
|
layer.inputs[0].arguments[0].shape = shape;
|
|
|
layer.outputs[0].arguments[0].shape = shape;
|
|
|
@@ -495,16 +583,17 @@ kmodel.Reader = class {
|
|
|
register( 1003, 'RESHAPE', 'Shape');
|
|
|
register(10240, 'K210_CONV', 'Layer', (layer, reader) => {
|
|
|
layer.flags = reader.uint32();
|
|
|
- layer.outputs = reader.mem_address('main', 'outputs');
|
|
|
+ layer.outputs = [ reader.parameter('output') ];
|
|
|
const layer_offset = reader.uint32();
|
|
|
const weights_offset = reader.uint32();
|
|
|
const bn_offset = reader.uint32();
|
|
|
const act_offset = reader.uint32();
|
|
|
reader.seek(layer_offset);
|
|
|
layer.interrupt_enabe = reader.uint64_bits({ int_en: 0, ram_flag: 1, full_add: 2, depth_wise_layer: 3 });
|
|
|
- layer.inputs = reader.mem_address('kpu', 'inputs');
|
|
|
- const outputs = reader.mem_address('kpu', 'outputs');
|
|
|
- layer.outputs = layer.flags & 1 ? layer.outputs : outputs;
|
|
|
+ layer.inputs = [ reader.parameter('input', 'kpu') ];
|
|
|
+ const outputs = [ reader.parameter('output', 'kpu') ];
|
|
|
+ layer.outputs[0].arguments.push(outputs[0].arguments[0]);
|
|
|
+ // layer.outputs = layer.flags & 1 ? layer.outputs : outputs;
|
|
|
layer.image_channel_num = reader.uint64_bits({ i_ch_num: 0, o_ch_num: 32, o_ch_num_coef: 48 });
|
|
|
layer.image_size = reader.uint64_bits({ i_row_wid: 0, i_col_high: 10, o_row_wid: 32, o_col_high : 42 });
|
|
|
layer.kernel_pool_type_cfg = reader.uint64_bits({ kernel_type: 0, pad_type: 3, pool_type: 4, first_stride: 8, bypass_conv: 9, load_para: 10, dma_burst_size: 16, pad_value: 24, bwsx_base_addr: 32 });
|
|
|
@@ -515,26 +604,65 @@ kmodel.Reader = class {
|
|
|
layer.conv_value = reader.uint64_bits({ shr_w: 0, shr_x: 4, arg_w: 8, arg_x: 32 });
|
|
|
layer.conv_value2 = reader.uint64_bits({ arg_add: 0 });
|
|
|
layer.dma_parameter = reader.uint64_bits({ send_data_out: 0, channel_byte_num: 16, dma_total_byte: 32 });
|
|
|
- reader.seek(weights_offset);
|
|
|
+ layer.chain = [];
|
|
|
+ const ic = layer.image_channel_num.i_ch_num + 1;
|
|
|
+ const oc = layer.image_channel_num.o_ch_num + 1;
|
|
|
+ const filter = [ 1, 3 ][layer.kernel_pool_type_cfg.kernel_type];
|
|
|
+ const weights_shape = layer.interrupt_enabe.depth_wise_layer ? [ oc, filter, filter ] : [ ic, oc, filter, filter ];
|
|
|
+ const weights_size = weights_shape.reduce((a, b) => a * b);
|
|
|
reader.seek(bn_offset);
|
|
|
+ const batch_norm = {
|
|
|
+ type: { name: 'BATCH_NORM', category: 'Normalization' },
|
|
|
+ weights: []
|
|
|
+ };
|
|
|
+ batch_norm.weights = new Array(oc);
|
|
|
+ for (let i = 0; i < oc; i++) {
|
|
|
+ batch_norm.weights[i] = reader.uint64_bits({ norm_mul: 0, norm_add: 24, norm_shift: 56, reserved: 60 });
|
|
|
+ delete batch_norm.weights[i].reserved;
|
|
|
+ }
|
|
|
+ layer.chain.push(batch_norm);
|
|
|
reader.seek(act_offset);
|
|
|
+ const activation = {};
|
|
|
+ activation.type = { name: 'ACTIVATION', category: 'Activation' };
|
|
|
+ activation.activate_para = new Array(16);
|
|
|
+ for (let i = 0; i < 16; i++) {
|
|
|
+ activation.activate_para[i] = reader.uint64_bits({ shift_number: 0, y_mul: 8, x_start: 24, reserved: 60 });
|
|
|
+ delete activation.activate_para[i].reserved;
|
|
|
+ }
|
|
|
+ for (let i = 0; i < 16; i++) {
|
|
|
+ activation.activate_para[i].bias = reader.int8();
|
|
|
+ }
|
|
|
+ layer.chain.push(activation);
|
|
|
+ reader.seek(weights_offset);
|
|
|
+ layer.inputs.push({
|
|
|
+ name: 'weights',
|
|
|
+ arguments: [ {
|
|
|
+ name: 'const',
|
|
|
+ datatype: 'uint8',
|
|
|
+ shape: weights_shape,
|
|
|
+ data: reader.read(weights_size)
|
|
|
+ } ]
|
|
|
+ });
|
|
|
+ delete layer.kernel_pool_type_cfg.bwsx_base_addr;
|
|
|
+ delete layer.kernel_calc_type_cfg.active_addr;
|
|
|
+ delete layer.kernel_load_cfg.para_start_addr;
|
|
|
});
|
|
|
register(10241, 'K210_ADD_PADDING', '', (layer, reader) => {
|
|
|
layer.flags = reader.uint32();
|
|
|
- layer.inputs = reader.mem_address('main', 'inputs');
|
|
|
- layer.outputs = reader.mem_address('kpu', 'outputs');
|
|
|
+ layer.inputs = [ reader.parameter('input') ];
|
|
|
+ layer.outputs = [ reader.parameter('output', 'kpu') ];
|
|
|
layer.channels = reader.uint32();
|
|
|
});
|
|
|
register(10242, 'K210_REMOVE_PADDING', '', (layer, reader) => {
|
|
|
layer.flags = reader.uint32();
|
|
|
- layer.inputs = reader.mem_address('main', 'inputs');
|
|
|
- layer.outputs = reader.mem_address('main', 'outputs');
|
|
|
+ layer.inputs = [ reader.parameter('input') ];
|
|
|
+ layer.outputs = [ reader.parameter('output') ];
|
|
|
layer.channels = reader.uint32();
|
|
|
});
|
|
|
register(10243, 'K210_UPLOAD', '', (layer, reader) => {
|
|
|
layer.flags = reader.uint32();
|
|
|
- layer.inputs = reader.mem_address('main', 'inputs');
|
|
|
- layer.outputs = reader.mem_address('kpu', 'outputs');
|
|
|
+ layer.inputs = [ reader.parameter('input') ];
|
|
|
+ layer.outputs = [ reader.parameter('output', 'kpu') ];
|
|
|
const shape = [ reader.uint32(), reader.uint32(), reader.uint32() ];
|
|
|
layer.inputs[0].arguments[0].shape = shape;
|
|
|
layer.outputs[0].arguments[0].shape = shape;
|
|
|
@@ -555,14 +683,14 @@ kmodel.Reader = class {
|
|
|
// console.log(JSON.stringify(Object.fromEntries(Object.entries(layer).filter((entry) => !(entry[1] instanceof Uint8Array))), null, 2));
|
|
|
}
|
|
|
if (this._layers.length > 0) {
|
|
|
- this._layers.push({
|
|
|
- type: { name: 'INPUT' },
|
|
|
- outputs: this._layers[0].inputs
|
|
|
+ this._layers.unshift({
|
|
|
+ type: { name: 'input' },
|
|
|
+ outputs: [ this._layers[0].inputs[0] ]
|
|
|
});
|
|
|
}
|
|
|
for (const output of outputs) {
|
|
|
this._layers.push({
|
|
|
- type: { name: 'OUTPUT' },
|
|
|
+ type: { name: 'output' },
|
|
|
inputs: output.address
|
|
|
});
|
|
|
}
|
|
|
@@ -579,18 +707,32 @@ kmodel.Reader = class {
|
|
|
outputs: reader.uint32(),
|
|
|
reserved0: reader.uint32(),
|
|
|
};
|
|
|
+ reader.memory_type_t = function() {
|
|
|
+ const value = this.uint32();
|
|
|
+ return [ 'const', 'main', 'kpu' ][value];
|
|
|
+ };
|
|
|
+ reader.datatype_t = function() {
|
|
|
+ const value = this.uint32();
|
|
|
+ return [ 'float32', 'uint8' ][value];
|
|
|
+ };
|
|
|
reader.memory_range = function() {
|
|
|
return {
|
|
|
- memory_type: this.uint32(), // 0=const, 1=main, 2=k210_kpu
|
|
|
- datatype: this.uint32(), // 0=float32, 1=uint8
|
|
|
+ memory_type: this.memory_type_t(),
|
|
|
+ datatype: this.datatype_t(),
|
|
|
start: this.uint32(),
|
|
|
size: this.uint32()
|
|
|
};
|
|
|
};
|
|
|
reader.argument = function() {
|
|
|
const memory = this.memory_range();
|
|
|
- const type = [ 'const', 'main', 'kpu' ][memory.memory_type];
|
|
|
- return { name: type + ':' + memory.start.toString() };
|
|
|
+ const value = {
|
|
|
+ name: memory.memory_type + ':' + memory.start.toString(),
|
|
|
+ datatype: memory.datatype
|
|
|
+ };
|
|
|
+ if (memory.memory_type === 'const') {
|
|
|
+ value.data = constants.slice(memory.start, memory.start + memory.size);
|
|
|
+ }
|
|
|
+ return value;
|
|
|
};
|
|
|
reader.parameter = function(name) {
|
|
|
const argument = this.argument();
|
|
|
@@ -599,8 +741,11 @@ kmodel.Reader = class {
|
|
|
reader.runtime_shape_t = function() {
|
|
|
return [ reader.uint32(), reader.uint32(), reader.uint32(), reader.uint32() ];
|
|
|
};
|
|
|
+ reader.padding = function() {
|
|
|
+ return { before: reader.int32(), after: reader.int32() };
|
|
|
+ };
|
|
|
reader.runtime_paddings_t = function() {
|
|
|
- return [ reader.int32(), reader.int32(), reader.int32(), reader.int32(), reader.int32(), reader.int32(), reader.int32(), reader.int32() ];
|
|
|
+ return [ this.padding(), this.padding(), this.padding(), this.padding() ];
|
|
|
};
|
|
|
reader.scalar = function() {
|
|
|
return {
|
|
|
@@ -613,9 +758,11 @@ kmodel.Reader = class {
|
|
|
value.activate_para = new Array(16);
|
|
|
for (let i = 0; i < 16; i++) {
|
|
|
value.activate_para[i] = this.uint64_bits({ shift_number: 0, y_mul: 8, x_start: 24, reserved: 60 });
|
|
|
+ delete value.activate_para[i].reserved;
|
|
|
+ }
|
|
|
+ for (let i = 0; i < 16; i++) {
|
|
|
+ value.activate_para[i].bias = reader.int8();
|
|
|
}
|
|
|
- value.activate_para_bias0 = reader.read(8);
|
|
|
- value.activate_para_bias1 = reader.read(8);
|
|
|
return value;
|
|
|
};
|
|
|
reader.unary_op_t = function() {
|
|
|
@@ -630,18 +777,18 @@ kmodel.Reader = class {
|
|
|
const value = reader.uint32();
|
|
|
return [ 'mean', 'min', 'max', 'sum' ][value];
|
|
|
};
|
|
|
- this._inputs = new Array(model_header.inputs);
|
|
|
- for (let i = 0; i < this._inputs.length; i++) {
|
|
|
- this._inputs[i] = reader.memory_range();
|
|
|
+ const inputs = new Array(model_header.inputs);
|
|
|
+ for (let i = 0; i < inputs.length; i++) {
|
|
|
+ inputs[i] = reader.parameter('input' + (i == 0 ? '' : (i + 1).toString()));
|
|
|
}
|
|
|
- for (let i = 0; i < this._inputs.length; i++) {
|
|
|
- this._inputs[i].shape = reader.runtime_shape_t();
|
|
|
+ for (let i = 0; i < inputs.length; i++) {
|
|
|
+ inputs[i].arguments[0].shape = reader.runtime_shape_t();
|
|
|
}
|
|
|
- this._outputs = new Array(model_header.outputs);
|
|
|
- for (let i = 0; i < this._outputs.length; i++) {
|
|
|
- this._outputs[i] = reader.memory_range();
|
|
|
+ const outputs = new Array(model_header.outputs);
|
|
|
+ for (let i = 0; i < outputs.length; i++) {
|
|
|
+ outputs[i] = reader.parameter('output' + (i == 0 ? '' : (i + 1).toString()));
|
|
|
}
|
|
|
- this._constants = reader.read(model_header.constants);
|
|
|
+ const constants = reader.read(model_header.constants);
|
|
|
this._layers = new Array(model_header.nodes);
|
|
|
for (let i = 0; i < this._layers.length; i++) {
|
|
|
this._layers[i] = {
|
|
|
@@ -687,7 +834,13 @@ kmodel.Reader = class {
|
|
|
layer.a_cols = reader.int32();
|
|
|
layer.b_cols = reader.int32();
|
|
|
layer.fused_activation = [ reader.float32(), reader.float32() ];
|
|
|
- // xtl::span<const float> bias;
|
|
|
+ const bias = reader.read(4 * layer.b_cols);
|
|
|
+ if (!bias.every((value) => value === 0)) {
|
|
|
+ layer.inputs.push({
|
|
|
+ name: 'bias',
|
|
|
+ arguments: [ { name: 'const', datatype: 'float32', shape: [ layer.b_cols ], data: bias } ]
|
|
|
+ });
|
|
|
+ }
|
|
|
});
|
|
|
register( 0x05, 'pad', 'Shape', (layer, reader) => {
|
|
|
layer.inputs = [ reader.parameter('input') ];
|
|
|
@@ -710,8 +863,26 @@ kmodel.Reader = class {
|
|
|
layer.outputs[0].arguments[0].shape = reader.runtime_shape_t();
|
|
|
layer.init_value = reader.float32();
|
|
|
});
|
|
|
- register( 0x08, 'reduce_window2d');
|
|
|
- register( 0x09, 'memory_copy', '');
|
|
|
+ register( 0x08, 'reduce_window2d', '', (layer, reader) => {
|
|
|
+ layer.inputs = [ reader.parameter('input') ];
|
|
|
+ layer.outputs = [ reader.parameter('output') ];
|
|
|
+ layer.reduce_op = reader.reduce_op_t();
|
|
|
+ layer.inputs[0].arguments[0].shape = reader.runtime_shape_t();
|
|
|
+ layer.padding_h = reader.padding();
|
|
|
+ layer.padding_w = reader.padding();
|
|
|
+ layer.filter_h = reader.int32();
|
|
|
+ layer.filter_w = reader.int32();
|
|
|
+ layer.stride_h = reader.int32();
|
|
|
+ layer.stride_w = reader.int32();
|
|
|
+ layer.dilation_h = reader.int32();
|
|
|
+ layer.dilation_w = reader.int32();
|
|
|
+ layer.init_value = reader.float32();
|
|
|
+ layer.fused_activation = [ reader.float32(), reader.float32() ];
|
|
|
+ });
|
|
|
+ register( 0x09, 'memory_copy', '', (layer, reader) => {
|
|
|
+ layer.inputs = [ reader.parameter('input') ];
|
|
|
+ layer.outputs = [ reader.parameter('output') ];
|
|
|
+ });
|
|
|
register( 0x0A, 'resize_image', '');
|
|
|
register( 0x0B, 'softmax', 'Activation');
|
|
|
register( 0x0C, 'transpose', 'Transform', (layer, reader) => {
|
|
|
@@ -766,8 +937,10 @@ kmodel.Reader = class {
|
|
|
layer.batches = reader.int32();
|
|
|
layer.reserved0 = reader.int32();
|
|
|
layer.interrupt_enabe = reader.uint64_bits({ int_en: 0, ram_flag: 1, full_add: 2, depth_wise_layer: 3 });
|
|
|
- layer.inputs = reader.mem_address('kpu', 'inputs'); // image_src_addr
|
|
|
- const outputs = reader.mem_address('kpu', 'output'); // image_dst_addr
|
|
|
+ const image_src_addr = reader.uint32();
|
|
|
+ const image_dst_addr = reader.uint32();
|
|
|
+ layer.inputs = [ { name: 'input', arguments: [ { name: 'kpu:' + image_src_addr.toString() } ] } ];
|
|
|
+ const outputs = [ { name: 'output', arguments: [ { name: 'kpu:' + image_dst_addr.toString() } ] } ];
|
|
|
layer.outputs[0].arguments.push(outputs[0].arguments[0]);
|
|
|
// layer.outputs = layer.flags & 1 ? layer.outputs : outputs;
|
|
|
layer.image_channel_num = reader.uint64_bits({ i_ch_num: 0, o_ch_num: 32, o_ch_num_coef: 48 });
|
|
|
@@ -784,16 +957,18 @@ kmodel.Reader = class {
|
|
|
const ic = layer.image_channel_num.i_ch_num + 1;
|
|
|
const oc = layer.image_channel_num.o_ch_num + 1;
|
|
|
const filter = [ 1, 3 ][layer.kernel_pool_type_cfg.kernel_type];
|
|
|
- const weights_size = layer.interrupt_enabe.depth_wise_layer ? oc * filter * filter : ic * oc * filter * filter;
|
|
|
+ const weights_shape = layer.interrupt_enabe.depth_wise_layer ? [ oc, filter, filter ] : [ ic, oc, filter, filter ];
|
|
|
+ const weights_size = weights_shape.reduce((a, b) => a * b);
|
|
|
reader.skip(layer.kernel_pool_type_cfg.bwsx_base_addr);
|
|
|
delete layer.kernel_pool_type_cfg.bwsx_base_addr;
|
|
|
const batch_norm = {
|
|
|
- type: { name: 'batchnorm', category: 'Normalization' },
|
|
|
+ type: { name: 'batch_norm', category: 'Normalization' },
|
|
|
weights: []
|
|
|
};
|
|
|
batch_norm.weights = new Array(oc);
|
|
|
for (let i = 0; i < oc; i++) {
|
|
|
- batch_norm.weights[i] = reader.uint64_bits({ norm_mul: 0, norm_add: 24, norm_shift: 56, reserverd: 60 });
|
|
|
+ batch_norm.weights[i] = reader.uint64_bits({ norm_mul: 0, norm_add: 24, norm_shift: 56, reserved: 60 });
|
|
|
+ delete batch_norm.weights[i].reserved;
|
|
|
}
|
|
|
layer.chain.push(batch_norm);
|
|
|
reader.skip(layer.kernel_calc_type_cfg.active_addr);
|
|
|
@@ -803,7 +978,15 @@ kmodel.Reader = class {
|
|
|
layer.chain.push(activation);
|
|
|
reader.skip(layer.kernel_load_cfg.para_start_addr);
|
|
|
delete layer.kernel_load_cfg.para_start_addr;
|
|
|
- layer.weights = reader.read(weights_size);
|
|
|
+ layer.inputs.push({
|
|
|
+ name: 'weights',
|
|
|
+ arguments: [ {
|
|
|
+ name: 'const',
|
|
|
+ datatype: 'uint8',
|
|
|
+ shape: weights_shape,
|
|
|
+ data: reader.read(weights_size)
|
|
|
+ } ]
|
|
|
+ });
|
|
|
});
|
|
|
for (const layer of this._layers) {
|
|
|
const type = types.get(layer.opcode);
|
|
|
@@ -826,6 +1009,18 @@ kmodel.Reader = class {
|
|
|
// console.log(JSON.stringify(Object.fromEntries(Object.entries(layer).filter((entry) => !(entry[1] instanceof Uint8Array))), null, 2));
|
|
|
delete layer.opcode;
|
|
|
}
|
|
|
+ for (const input of inputs) {
|
|
|
+ this._layers.unshift({
|
|
|
+ type: { name: 'INPUT' },
|
|
|
+ outputs: [ input ]
|
|
|
+ });
|
|
|
+ }
|
|
|
+ for (const output of outputs) {
|
|
|
+ this._layers.push({
|
|
|
+ type: { name: 'OUTPUT' },
|
|
|
+ inputs: [ output ]
|
|
|
+ });
|
|
|
+ }
|
|
|
break;
|
|
|
}
|
|
|
case 5: {
|