소스 검색

Update kmodel.js

Lutz Roeder 4 년 전
부모
커밋
78ba987b66
1개의 변경된 파일267개의 추가작업 그리고 59개의 파일을 삭제
  1. 267 59
      source/kmodel.js

+ 267 - 59
source/kmodel.js

@@ -37,6 +37,23 @@ kmodel.Graph = class {
     constructor(model) {
         this._inputs = [];
         this._outputs = [];
+        const scopes = new Map();
+        let index = 0;
+        for (const layer of model.layers) {
+            for (const input of layer.inputs || []) {
+                for (const argument of input.arguments) {
+                    argument.name = scopes.has(argument.name) ? scopes.get(argument.name) : argument.name;
+                }
+            }
+            for (const output of layer.outputs || []) {
+                for (const argument of output.arguments) {
+                    const value = scopes.has(argument.name) ? argument.name + '#' + index.toString() : argument.name;
+                    scopes.set(argument.name, value); // custom argument id
+                    argument.name = value;
+                }
+            }
+            index++;
+        }
         this._nodes = model.layers.map((layer) => new kmodel.Node(layer));
     }
 
@@ -53,21 +70,141 @@ kmodel.Graph = class {
     }
 };
 
+kmodel.Parameter = class {
+
+    constructor(name, args) {
+        this._name = name;
+        this._arguments = args;
+    }
+
+    get name() {
+        return this._name;
+    }
+
+    get visible() {
+        return true;
+    }
+
+    get arguments() {
+        return this._arguments;
+    }
+};
+
+kmodel.Argument = class {
+
+    constructor(name, type, initializer) {
+        if (typeof name !== 'string') {
+            throw new kmodel.Error("Invalid argument identifier '" + JSON.stringify(name) + "'.");
+        }
+        this._name = name;
+        this._type = type;
+        this._initializer = initializer;
+    }
+
+    get name() {
+        return this._name;
+    }
+
+    get type() {
+        if (this._initializer) {
+            return this._initializer.type;
+        }
+        return this._type;
+    }
+
+    get initializer() {
+        return this._initializer;
+    }
+};
+
+kmodel.TensorType = class {
+
+    constructor(dataType, shape) {
+        this._dataType = dataType;
+        this._shape = new kmodel.TensorShape(shape);
+    }
+
+    get dataType() {
+        return this._dataType;
+    }
+
+    get shape() {
+        return this._shape;
+    }
+
+    toString() {
+        return this._dataType + this._shape.toString();
+    }
+};
+
+kmodel.TensorShape = class {
+
+    constructor(shape) {
+        this._shape = shape;
+    }
+
+    get dimensions() {
+        return this._shape;
+    }
+
+    toString() {
+        if (this._shape && Array.isArray(this._shape) && this._shape.length > 0) {
+            return '[' + this._shape.map((dim) => dim ? dim.toString() : '?').join(',') + ']';
+        }
+        return '';
+    }
+};
+
+kmodel.Tensor = class {
+
+    constructor(type, data) {
+        this._type = type;
+        this._data = data;
+    }
+
+    get type() {
+        return this._type;
+    }
+
+    get state() {
+        return 'Tensor data not implemented.';
+    }
+};
+
 kmodel.Node = class {
 
     constructor(layer) {
-        this._location = layer.location;
+        this._location = layer.location !== undefined ? layer.location.toString() : layer.location;
         this._type = layer.type;
+        this._inputs = [];
+        this._outputs = [];
+        this._chain = [];
         this._attributes = [];
+        this._chain = [];
         for (const entry of Object.entries(layer)) {
             const name = entry[0];
-            if (name === 'type' || name === 'location' || name === 'params') {
+            if (name === 'type' || name === 'location' || name === 'inputs' || name === 'outputs') {
                 continue;
             }
             const value = entry[1];
             const attribute = new kmodel.Attribute(name, value);
             this._attributes.push(attribute);
         }
+        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 tensor = argument.data ? new kmodel.Tensor(type, argument.data) : null;
+                return new kmodel.Argument(argument.name, type, tensor);
+            })));
+        }
+        for (const output of layer.outputs || []) {
+            this._outputs.push(new kmodel.Parameter(output.name, output.arguments.map((argument) => {
+                return new kmodel.Argument(argument.name);
+            })));
+        }
+        for (const chain of layer.chain || []) {
+            this._chain.push(new kmodel.Node(chain));
+        }
     }
 
     get location() {
@@ -83,16 +220,20 @@ kmodel.Node = class {
     }
 
     get inputs() {
-        return [];
+        return this._inputs;
     }
 
     get outputs() {
-        return [];
+        return this._outputs;
     }
 
     get attributes() {
         return this._attributes;
     }
+
+    get chain() {
+        return this._chain;
+    }
 };
 
 kmodel.Attribute = class {
@@ -154,28 +295,64 @@ kmodel.Reader = class {
             };
             switch (this._version) {
                 case 3: {
-                    const model_header = {
-                        flags: reader.uint32(),
-                        arch: reader.uint32(),
-                        layers_length: reader.uint32(),
-                        max_start_address: reader.uint32(),
-                        main_mem_usage: reader.uint32(),
-                        output_count: reader.uint32()
+                    reader.kpu_model_header_t = function() {
+                        return {
+                            flags: reader.uint32(),
+                            arch: reader.uint32(),
+                            layers_length: reader.uint32(),
+                            max_start_address: reader.uint32(),
+                            main_mem_usage: reader.uint32(),
+                            output_count: reader.uint32()
+                        };
                     };
-                    this._layers = new Array(model_header.layers_length);
-                    this._outputs = new Array(model_header.output_count);
-                    for (let i = 0; i < this._outputs.length; i++) {
-                        this._outputs[i] = {
+                    reader.kpu_model_output_t = function() {
+                        return {
                             address: reader.uint32(),
                             size: reader.uint32()
                         };
-                    }
-                    for (let i = 0; i < this._layers.length; i++) {
-                        this._layers[i] = {
-                            location: i,
+                    };
+                    reader.kpu_model_layer_header_t = function() {
+                        return {
                             type: reader.uint32(),
                             body_size: reader.uint32()
                         };
+                    };
+                    reader.mem_address = function(memory, name) {
+                        const mem_address = this.uint32();
+                        const argument = { name: memory + ':' + mem_address.toString() };
+                        const parameter = { name: name, arguments: [ argument ] };
+                        return [ parameter ];
+                    };
+                    reader.kpu_layer_config_field = function(fields) {
+                        const buffer = reader.read(8);
+                        fields = Object.entries(fields);
+                        fields.push([ null, Math.min(64, fields[fields.length - 1][1] + 56)]);
+                        const obj = {};
+                        for (let i = 0; i < fields.length - 1; i++) {
+                            const key = fields[i][0];
+                            let value = 0;
+                            let position = fields[i][1];
+                            const end = fields[i + 1][1];
+                            while (position < end) {
+                                const offset = (position / 8) >> 0;
+                                const start = (position & 7);
+                                const count = Math.min((offset + 1) * 8, end) - position;
+                                value = value | ((buffer[offset] >>> start) & ((1 << count) - 1)) << (position - fields[i][1]);
+                                position += count;
+                            }
+                            obj[key] = value;
+                        }
+                        return obj;
+                    };
+                    const model_header = reader.kpu_model_header_t();
+                    this._layers = new Array(model_header.layers_length);
+                    this._outputs = new Array(model_header.output_count);
+                    for (let i = 0; i < this._outputs.length; i++) {
+                        this._outputs[i] = reader.kpu_model_output_t();
+                    }
+                    for (let i = 0; i < this._layers.length; i++) {
+                        this._layers[i] = reader.kpu_model_layer_header_t();
+                        this._layers[i].location = i;
                     }
                     let offset = reader.position;
                     for (const layer of this._layers) {
@@ -190,8 +367,8 @@ kmodel.Reader = class {
                     register(    4, 'QUANTIZED_GLOBAL_MAX_POOL2D', 'Pool');
                     register(    5, 'GLOBAL_AVERAGE_POOL2D', 'Pool', (layer, reader) => {
                         layer.flags = reader.uint32();
-                        layer.main_mem_in_address = reader.uint32();
-                        layer.main_mem_out_address = reader.uint32();
+                        layer.inputs = reader.mem_address('main', 'inputs');
+                        layer.outputs = reader.mem_address('main', 'outputs');
                         layer.kernel_size = reader.uint32();
                         layer.channels = reader.uint32();
                     });
@@ -199,8 +376,8 @@ kmodel.Reader = class {
                     register(    7, 'MAX_POOL2D', 'Pool');
                     register(    8, 'QUANTIZED_MAX_POOL2D', 'Pool', (layer, reader) => {
                         layer.flags = reader.uint32();
-                        layer.main_mem_in_address = reader.uint32();
-                        layer.main_mem_out_address = reader.uint32();
+                        layer.inputs = reader.mem_address('main', 'inputs');
+                        layer.outputs = reader.mem_address('main', 'outputs');
                         layer.in_shape = [ reader.uint32(), reader.uint32(), reader.uint32() ];
                         layer.out_shape = [ reader.uint32(), reader.uint32(), reader.uint32() ];
                         layer.kernel = [ reader.uint32(), reader.uint32() ];
@@ -211,16 +388,16 @@ kmodel.Reader = class {
                     register(   10, 'QUANTIZED_AVERAGE_POOL2D', 'Pool');
                     register(   11, 'QUANTIZE', '', (layer, reader) => {
                         layer.flags = reader.uint32();
-                        layer.main_mem_in_address = reader.uint32();
-                        layer.mem_out_address = reader.uint32();
+                        layer.inputs = reader.mem_address('main', 'inputs');
+                        layer.outputs = reader.mem_address('main', 'outputs');
                         layer.count = reader.uint32();
                         layer.scale = reader.float32();
                         layer.bias = reader.float32();
                     });
                     register(   12, 'DEQUANTIZE', '', (layer, reader) => {
                         layer.flags = reader.uint32();
-                        layer.main_mem_in_address = reader.uint32();
-                        layer.mem_out_address = reader.uint32();
+                        layer.inputs = reader.mem_address('main', 'inputs');
+                        layer.outputs = reader.mem_address('main', 'outputs');
                         layer.count = reader.uint32();
                         layer.scale = reader.float32();
                         layer.bias = reader.float32();
@@ -229,13 +406,13 @@ kmodel.Reader = class {
                     register(   14, 'L2_NORMALIZATION', 'Normalization');
                     register(   15, 'SOFTMAX', 'Activation', (layer, reader) => {
                         layer.flags = reader.uint32();
-                        layer.main_mem_in_address = reader.uint32();
-                        layer.main_mem_out_address = reader.uint32();
+                        layer.inputs = reader.mem_address('main', 'inputs');
+                        layer.outputs = reader.mem_address('main', 'outputs');
                         layer.channels = reader.uint32();
                     });
                     register(   16, 'CONCAT', 'Tensor', (layer, reader) => {
                         layer.flags = reader.uint32();
-                        layer.main_mem_out_address = reader.uint32();
+                        layer.outputs = reader.mem_address('main', 'outputs');
                         layer.inputs_mem = new Array(reader.uint32());
                         for (let i = 0; i < layer.inputs_mem.length; i++) {
                             layer.inputs_mem[i] = {
@@ -246,7 +423,7 @@ kmodel.Reader = class {
                     });
                     register(   17, 'QUANTIZED_CONCAT', 'Tensor', (layer, reader) => {
                         layer.flags = reader.uint32();
-                        layer.main_mem_out_address = reader.uint32();
+                        layer.outputs = reader.mem_address('main', 'outputs');
                         layer.inputs_mem = new Array(reader.uint32());
                         for (let i = 0; i < layer.inputs_mem.length; i++) {
                             layer.inputs_mem[i] = {
@@ -257,28 +434,41 @@ kmodel.Reader = class {
                     });
                     register(   18, 'FULLY_CONNECTED', 'Layer', (layer, reader) => {
                         layer.flags = reader.uint32();
-                        layer.main_mem_in_address = reader.uint32();
-                        layer.main_mem_out_address = reader.uint32();
+                        layer.inputs = reader.mem_address('main', 'inputs');
+                        layer.outputs = reader.mem_address('main', 'outputs');
                         layer.in_channels = reader.uint32();
                         layer.out_channels = reader.uint32();
-                        layer.act = reader.uint32(); // {'linear':0, 'relu':1, 'relu6':2}
-                        layer.params = {
-                            weights: reader.read(4 * layer.in_channels * layer.out_channels),
-                            bias: reader.read(4 * layer.out_channels)
-                        };
+                        const act = reader.uint32();
+                        const activations = [
+                            { name: 'LINEAR', category: 'Activation' },
+                            { name: 'RELU', category: 'Activation' },
+                            { name: 'RELU6', category: 'Activation' },
+                        ];
+                        if (act !== 0) {
+                            if (act > activations.length) {
+                                throw new kmodel.Error("Unsupported FULLY_CONNECTED activation '" + act.toString() + "'.");
+                            }
+                            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) } ] });
                     });
                     register(   19, 'QUANTIZED_FULLY_CONNECTED', 'Layer');
                     register(   20, 'TENSORFLOW_FLATTEN', 'Shape', (layer, reader) => {
                         layer.flags = reader.uint32();
-                        layer.main_mem_in_address = reader.uint32();
-                        layer.main_mem_out_address = reader.uint32();
-                        layer.shape = [ reader.uint32(), reader.uint32(), reader.uint32() ];
+                        layer.inputs = reader.mem_address('main', 'inputs');
+                        layer.outputs = reader.mem_address('main', 'outputs');
+                        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.main_mem_in_address = reader.uint32();
-                        layer.main_mem_out_address = reader.uint32();
-                        layer.shape = [ reader.uint32(), reader.uint32(), reader.uint32() ];
+                        layer.inputs = reader.mem_address('main', 'inputs');
+                        layer.outputs = reader.mem_address('main', 'outputs');
+                        const shape = [ reader.uint32(), reader.uint32(), reader.uint32() ];
+                        layer.inputs[0].arguments[0].shape = shape;
+                        layer.outputs[0].arguments[0].shape = shape;
                     });
                     register( 1000, 'CONV', 'Layer');
                     register( 1001, 'DWCONV', 'Layer');
@@ -286,29 +476,49 @@ kmodel.Reader = class {
                     register( 1003, 'RESHAPE', 'Shape');
                     register(10240, 'K210_CONV', 'Layer', (layer, reader) => {
                         layer.flags = reader.uint32();
-                        layer.main_mem_out_address = reader.uint32();
-                        /* const layer_offset = */ reader.uint32();
-                        /* const weights_offset = */ reader.uint32();
-                        /* const bn_offset = */ reader.uint32();
-                        /* const act_offset = */ reader.uint32();
+                        layer.outputs = reader.mem_address('main', 'outputs');
+                        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.kpu_layer_config_field({ 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.image_channel_num = reader.kpu_layer_config_field({ i_ch_num: 0, o_ch_num: 32, o_ch_num_coef: 48 });
+                        layer.image_size =  reader.kpu_layer_config_field({ i_row_wid: 0, i_col_high: 10, o_row_wid: 32, o_col_high : 42 });
+                        layer.kernel_pool_type_cfg = reader.kpu_layer_config_field({ 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 });
+                        layer.kernel_load_cfg = reader.kpu_layer_config_field({ load_coor: 0, load_time: 1, para_size: 15, para_start_addr: 32 });
+                        layer.kernel_offset = reader.kpu_layer_config_field({ coef_column_offset: 0, coef_row_offset: 4 });
+                        layer.kernel_calc_type_cfg = reader.kpu_layer_config_field({ channel_switch_addr: 0, row_switch_addr: 16, coef_size: 20, coef_group: 28, load_act: 31, active_addr: 32 });
+                        layer.write_back_cfg = reader.kpu_layer_config_field({ wb_channel_switch_addr: 0, wb_row_switch_addr: 16, wb_group: 20 });
+                        layer.conv_value = reader.kpu_layer_config_field({ shr_w: 0, shr_x: 4, arg_w: 8, arg_x: 32 });
+                        layer.conv_value2 = reader.kpu_layer_config_field({ arg_add: 0 });
+                        layer.dma_parameter = reader.kpu_layer_config_field({ send_data_out: 0, channel_byte_num: 16, dma_total_byte: 32 });
+                        reader.seek(weights_offset);
+                        reader.seek(bn_offset);
+                        reader.seek(act_offset);
                     });
                     register(10241, 'K210_ADD_PADDING', '', (layer, reader) => {
                         layer.flags = reader.uint32();
-                        layer.main_mem_in_address = reader.uint32();
-                        layer.kpu_mem_out_address = reader.uint32();
+                        layer.inputs = reader.mem_address('main', 'inputs');
+                        layer.outputs = reader.mem_address('kpu', 'outputs');
                         layer.channels = reader.uint32();
                     });
                     register(10242, 'K210_REMOVE_PADDING', '', (layer, reader) => {
                         layer.flags = reader.uint32();
-                        layer.main_mem_in_address = reader.uint32();
-                        layer.kpu_mem_out_address = reader.uint32();
+                        layer.inputs = reader.mem_address('main', 'inputs');
+                        layer.outputs = reader.mem_address(layer.flags & 1 ? 'main' : 'kpu', 'outputs');
                         layer.channels = reader.uint32();
                     });
                     register(10243, 'K210_UPLOAD', '', (layer, reader) => {
                         layer.flags = reader.uint32();
-                        layer.main_mem_in_address = reader.uint32();
-                        layer.kpu_mem_out_address = reader.uint32();
-                        layer.shape = [ reader.uint32(), reader.uint32(), reader.uint32() ];
+                        layer.inputs = reader.mem_address('main', 'inputs');
+                        layer.outputs = reader.mem_address('kpu', 'outputs');
+                        const shape = [ reader.uint32(), reader.uint32(), reader.uint32() ];
+                        layer.inputs[0].arguments[0].shape = shape;
+                        layer.outputs[0].arguments[0].shape = shape;
                     });
                     for (const layer of this._layers) {
                         const type = types.get(layer.type);
@@ -323,9 +533,6 @@ kmodel.Reader = class {
                         type.callback(layer, reader);
                         delete layer.offset;
                         delete layer.body_size;
-                        if (reader.position != (layer.offset + layer.body_size)) {
-                            // debugger;
-                        }
                         // console.log(JSON.stringify(Object.fromEntries(Object.entries(layer).filter((entry) => !(entry[1] instanceof Uint8Array))), null, 2));
                     }
                     break;
@@ -367,6 +574,7 @@ kmodel.Reader = class {
                     this._layers = new Array(model_header.nodes);
                     for (let i = 0; i < this._layers.length; i++) {
                         this._layers[i] = {
+                            location: i,
                             op_code: reader.uint32(),
                             body_size: reader.uint32()
                         };