Bladeren bron

Update view.js

Lutz Roeder 2 jaren geleden
bovenliggende
commit
bf7c950cda
23 gewijzigde bestanden met toevoegingen van 1220 en 1247 verwijderingen
  1. 4 8
      source/acuity.js
  2. 2 1
      source/bigdl.js
  3. 2 1
      source/circle.js
  4. 2 5
      source/dl4j.js
  5. 8 6
      source/dlc.js
  6. 5 3
      source/gguf.js
  7. 11 7
      source/hailo.js
  8. 3 3
      source/keras.js
  9. 726 726
      source/kmodel.js
  10. 2 5
      source/mxnet.js
  11. 2 5
      source/ncnn.js
  12. 2 5
      source/nnef.js
  13. 5 3
      source/om.js
  14. 2 5
      source/openvino.js
  15. 55 60
      source/paddle.js
  16. 40 40
      source/pytorch.js
  17. 8 6
      source/rknn.js
  18. 274 274
      source/tengine.js
  19. 39 39
      source/tensorrt.js
  20. 2 5
      source/tf.js
  21. 2 1
      source/tflite.js
  22. 20 35
      source/view.js
  23. 4 4
      source/weka.js

+ 4 - 8
source/acuity.js

@@ -4,15 +4,11 @@ const acuity = {};
 acuity.ModelFactory = class {
 
     match(context) {
-        const extension = context.identifier.split('.').pop().toLowerCase();
-        if (extension === 'json') {
-            const obj = context.peek('json');
-            if (obj && obj.MetaData && obj.Layers) {
-                context.type = 'acuity';
-                context.target = obj;
-            }
+        const obj = context.peek('json');
+        if (obj && obj.MetaData && obj.Layers) {
+            context.type = 'acuity';
+            context.target = obj;
         }
-        return null;
     }
 
     async open(context) {

+ 2 - 1
source/bigdl.js

@@ -9,7 +9,8 @@ bigdl.ModelFactory = class {
 
     match(context) {
         const tags = context.tags('pb');
-        if (tags.has(2) && tags.has(7) && tags.has(8) && tags.has(9) && tags.has(10) && tags.has(11) && tags.has(12)) {
+        if (tags.has(2) && tags.has(7) && tags.has(8) &&
+            tags.has(9) && tags.has(10) && tags.has(11) && tags.has(12)) {
             context.type = 'bigdl';
         }
     }

+ 2 - 1
source/circle.js

@@ -16,6 +16,7 @@ circle.ModelFactory = class {
         const obj = context.peek('json');
         if (obj && obj.subgraphs && obj.operator_codes) {
             context.type = 'circle.flatbuffers.json';
+            context.target = obj;
             return;
         }
     }
@@ -28,7 +29,7 @@ circle.ModelFactory = class {
         switch (context.type) {
             case 'circle.flatbuffers.json': {
                 try {
-                    const obj = context.peek('json');
+                    const obj = context.target;
                     const reader = new flatbuffers.TextReader(obj);
                     model = circle.schema.Model.createText(reader);
                 } catch (error) {

+ 2 - 5
source/dl4j.js

@@ -27,11 +27,8 @@ dl4j.ModelFactory = class {
         }
     }
 
-    filter(context, name) {
-        if (context.type === 'dl4j.configuration' && (name === 'dl4j.coefficients' || name === 'openvino.bin')) {
-            return false;
-        }
-        return true;
+    filter(context, type) {
+        return context.type !== 'dl4j.configuration' || (type !== 'dl4j.coefficients' && type !== 'openvino.bin');
     }
 
     async open(context) {

+ 8 - 6
source/dlc.js

@@ -7,8 +7,11 @@ const dlc = {};
 dlc.ModelFactory = class {
 
     match(context) {
-        context.target = dlc.Container.open(context);
-        context.type = context.target ? context.target.name : null;
+        const container = dlc.Container.open(context);
+        if (container) {
+            context.type = 'dlc';
+            context.target = container;
+        }
     }
 
     async open(context) {
@@ -274,8 +277,7 @@ dlc.Container = class {
     }
 
     constructor(context, model, params, metadata) {
-        this.name = 'dlc';
-        this._context = context;
+        this.context = context;
         this._model = model;
         this._params = params;
         this._metadata = metadata;
@@ -291,7 +293,7 @@ dlc.Container = class {
         if (this._metadata === undefined) {
             this._metadata = await this._fetch('dlc.metadata');
         }
-        delete this._context;
+        delete this.context;
         this.graphs = [];
         this.metadata = new Map();
         if (this._model) {
@@ -601,7 +603,7 @@ dlc.Container = class {
 
     async _fetch(name) {
         try {
-            const context = await this._context.fetch(name);
+            const context = await this.context.fetch(name);
             return context.stream;
         } catch (error) {
             return null;

+ 5 - 3
source/gguf.js

@@ -6,8 +6,11 @@ const gguf = {};
 gguf.ModelFactory = class {
 
     match(context) {
-        context.target = gguf.Reader.open(context.stream);
-        context.type = context.target ? context.target.name : null;
+        const reader = gguf.Reader.open(context.stream);
+        if (reader) {
+            context.type = 'gguf';
+            context.target = reader;
+        }
     }
 
     async open(context) {
@@ -195,7 +198,6 @@ gguf.Reader = class {
     }
 
     constructor(stream) {
-        this.name = 'gguf';
         this.stream = stream;
         const QK_K = 256;
         gguf.Reader.GGML_QUANT_SIZES = gguf.Reader.GGML_QUANT_SIZES || new Map([

+ 11 - 7
source/hailo.js

@@ -5,15 +5,18 @@ const hailo = {};
 hailo.ModelFactory = class {
 
     match(context) {
-        context.target = hailo.Container.open(context);
-        context.type = context.target ? context.target.name : null;
+        const container = hailo.Container.open(context);
+        if (container) {
+            context.type = container.type;
+            context.target = container;
+        }
     }
 
-    filter(context, name) {
-        if (context.type === 'hailo.metadata' && (name.startsWith('hailo.') || name === 'npz')) {
+    filter(context, type) {
+        if (context.type === 'hailo.metadata' && (type === 'hailo.configuration' || type === 'npz')) {
             return false;
         }
-        if (context.type === 'hailo.configuration' && name === 'npz') {
+        if (context.type === 'hailo.configuration' && type === 'npz') {
             return false;
         }
         return true;
@@ -265,7 +268,7 @@ hailo.Container = class {
     }
 
     constructor(context, basename, configuration, metadata) {
-        this.name = metadata ? 'hailo.metadata' : configuration ? 'hailo.configuration' : 'hailo';
+        this.type = metadata ? 'hailo.metadata' : configuration ? 'hailo.configuration' : 'hailo';
         this.context = context;
         this.basename = basename;
         this.configuration = configuration;
@@ -307,7 +310,8 @@ hailo.Container = class {
             if (entries && entries.size > 0) {
                 const inputs = new Set([
                     'kernel', 'bias',
-                    'input_activation_bits', 'output_activation_bits', 'weight_bits', 'bias_decomposition'
+                    'input_activation_bits', 'output_activation_bits',
+                    'weight_bits', 'bias_decomposition'
                 ]);
                 for (const [name, value] of entries) {
                     const key = name.split('.').slice(0, -1).join('.');

+ 3 - 3
source/keras.js

@@ -74,11 +74,11 @@ keras.ModelFactory = class {
         }
     }
 
-    filter(context, name) {
-        if (context.type === 'keras.metadata.json' && (name === 'keras.config.json' || name === 'keras.model.weights.h5' || name === 'keras.model.weights.npz')) {
+    filter(context, type) {
+        if (context.type === 'keras.metadata.json' && (type === 'keras.config.json' || type === 'keras.model.weights.h5' || type === 'keras.model.weights.npz')) {
             return false;
         }
-        if (context.type === 'keras.config.json' && (name === 'keras.model.weights.h5' || name === 'keras.model.weights.npz')) {
+        if (context.type === 'keras.config.json' && (type === 'keras.model.weights.h5' || type === 'keras.model.weights.npz')) {
             return false;
         }
         return true;

+ 726 - 726
source/kmodel.js

@@ -6,8 +6,11 @@ const kmodel = {};
 kmodel.ModelFactory = class {
 
     match(context) {
-        context.target = kmodel.Reader.open(context.stream);
-        context.type = context.target ? context.target.name : context.target;
+        const reader = kmodel.Reader.open(context.stream);
+        if (reader) {
+            context.type = 'kmodel';
+            context.target = reader;
+        }
     }
 
     async open(context) {
@@ -251,771 +254,768 @@ kmodel.Reader = class {
     }
 
     constructor(stream, version) {
-        this.name = 'kmodel';
         this.stream = stream;
         this.version = version;
         this.modules = [];
     }
 
     read() {
-        if (this.stream) {
-            if (this.version < 3 || this.version > 5) {
-                throw new kmodel.Error(`Unsupported model version '${this.version}'.`);
-            }
-            const types = new Map();
-            const register = (type, name, category, callback) => {
-                types.set(type, { type: { name: name, category: category || '' }, callback: callback });
-            };
-            switch (this.version) {
-                case 3: {
-                    const reader = new kmodel.BinaryReader.v3(this.stream);
-                    const model_header = reader.kpu_model_header_t();
-                    const layers = new Array(model_header.layers_length);
-                    const outputs = new Array(model_header.output_count);
-                    for (let i = 0; i < model_header.output_count; i++) {
-                        outputs[i] = reader.kpu_model_output_t(`output${i > 0 ? i.toString() : ''}`);
-                    }
-                    for (let i = 0; i < layers.length; i++) {
-                        layers[i] = reader.kpu_model_layer_header_t();
-                        layers[i].location = i;
+        if (this.version < 3 || this.version > 5) {
+            throw new kmodel.Error(`Unsupported model version '${this.version}'.`);
+        }
+        const types = new Map();
+        const register = (type, name, category, callback) => {
+            types.set(type, { type: { name: name, category: category || '' }, callback: callback });
+        };
+        switch (this.version) {
+            case 3: {
+                const reader = new kmodel.BinaryReader.v3(this.stream);
+                const model_header = reader.kpu_model_header_t();
+                const layers = new Array(model_header.layers_length);
+                const outputs = new Array(model_header.output_count);
+                for (let i = 0; i < model_header.output_count; i++) {
+                    outputs[i] = reader.kpu_model_output_t(`output${i > 0 ? i.toString() : ''}`);
+                }
+                for (let i = 0; i < layers.length; i++) {
+                    layers[i] = reader.kpu_model_layer_header_t();
+                    layers[i].location = i;
+                }
+                let offset = reader.position;
+                for (const layer of layers) {
+                    layer.offset = offset;
+                    offset += layer.body_size;
+                }
+                /* eslint-disable space-in-parens */
+                register(   -1, 'DUMMY');
+                register(    0, 'INVALID');
+                register(    1, 'ADD');
+                register(    2, 'QUANTIZED_ADD');
+                register(    3, 'GLOBAL_MAX_POOL2D', 'Pool');
+                register(    4, 'QUANTIZED_GLOBAL_MAX_POOL2D', 'Pool');
+                register(    5, 'GLOBAL_AVERAGE_POOL2D', 'Pool', (layer, reader) => {
+                    layer.flags = reader.uint32();
+                    layer.inputs = [ reader.parameter('input') ];
+                    layer.outputs = [ reader.parameter('output') ];
+                    layer.kernel_size = reader.uint32();
+                    layer.channels = reader.uint32();
+                });
+                register(    6, 'QUANTIZED_GLOBAL_AVERAGE_POOL2D', 'Pool');
+                register(    7, 'MAX_POOL2D', 'Pool');
+                register(    8, 'QUANTIZED_MAX_POOL2D', 'Pool', (layer, reader) => {
+                    layer.flags = reader.uint32();
+                    layer.inputs = [ reader.parameter('input') ];
+                    layer.outputs = [ reader.parameter('output') ];
+                    layer.inputs[0].value[0].shape = [ reader.uint32(), reader.uint32(), reader.uint32() ];
+                    layer.outputs[0].value[0].shape = [ reader.uint32(), reader.uint32(), reader.uint32() ];
+                    layer.kernel = [ reader.uint32(), reader.uint32() ];
+                    layer.stride = [ reader.uint32(), reader.uint32() ];
+                    layer.padding = [ reader.uint32(), reader.uint32() ];
+                });
+                register(    9, 'AVERAGE_POOL2D', 'Pool');
+                register(   10, 'QUANTIZED_AVERAGE_POOL2D', 'Pool');
+                register(   11, 'QUANTIZE', '', (layer, reader) => {
+                    layer.flags = reader.uint32();
+                    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.parameter('input') ];
+                    layer.outputs = [ reader.parameter('output') ];
+                    layer.count = reader.uint32();
+                    layer.scale = reader.float32();
+                    layer.bias = reader.float32();
+                });
+                register(   13, 'REQUANTIZE', '', (layer, reader) => {
+                    layer.flags = reader.uint32();
+                    layer.inputs = [ reader.parameter('input') ];
+                    layer.outputs = [ reader.parameter('output') ];
+                    layer.count = reader.uint32();
+                    layer.table = reader.read(256);
+                });
+                register(   14, 'L2_NORMALIZATION', 'Normalization');
+                register(   15, 'SOFTMAX', 'Activation', (layer, reader) => {
+                    layer.flags = reader.uint32();
+                    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.parameter('output') ];
+                    layer.inputs_mem = new Array(reader.uint32());
+                    for (let i = 0; i < layer.inputs_mem.length; i++) {
+                        layer.inputs_mem[i] = {
+                            start: reader.uint32(),
+                            end: reader.uint32()
+                        };
                     }
-                    let offset = reader.position;
-                    for (const layer of layers) {
-                        layer.offset = offset;
-                        offset += layer.body_size;
+                });
+                register(   17, 'QUANTIZED_CONCAT', 'Tensor', (layer, reader) => {
+                    layer.flags = reader.uint32();
+                    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] = {
+                            start: reader.uint32(),
+                            end: reader.uint32()
+                        };
                     }
-                    /* eslint-disable space-in-parens */
-                    register(   -1, 'DUMMY');
-                    register(    0, 'INVALID');
-                    register(    1, 'ADD');
-                    register(    2, 'QUANTIZED_ADD');
-                    register(    3, 'GLOBAL_MAX_POOL2D', 'Pool');
-                    register(    4, 'QUANTIZED_GLOBAL_MAX_POOL2D', 'Pool');
-                    register(    5, 'GLOBAL_AVERAGE_POOL2D', 'Pool', (layer, reader) => {
-                        layer.flags = reader.uint32();
-                        layer.inputs = [ reader.parameter('input') ];
-                        layer.outputs = [ reader.parameter('output') ];
-                        layer.kernel_size = reader.uint32();
-                        layer.channels = reader.uint32();
-                    });
-                    register(    6, 'QUANTIZED_GLOBAL_AVERAGE_POOL2D', 'Pool');
-                    register(    7, 'MAX_POOL2D', 'Pool');
-                    register(    8, 'QUANTIZED_MAX_POOL2D', 'Pool', (layer, reader) => {
-                        layer.flags = reader.uint32();
-                        layer.inputs = [ reader.parameter('input') ];
-                        layer.outputs = [ reader.parameter('output') ];
-                        layer.inputs[0].value[0].shape = [ reader.uint32(), reader.uint32(), reader.uint32() ];
-                        layer.outputs[0].value[0].shape = [ reader.uint32(), reader.uint32(), reader.uint32() ];
-                        layer.kernel = [ reader.uint32(), reader.uint32() ];
-                        layer.stride = [ reader.uint32(), reader.uint32() ];
-                        layer.padding = [ reader.uint32(), reader.uint32() ];
-                    });
-                    register(    9, 'AVERAGE_POOL2D', 'Pool');
-                    register(   10, 'QUANTIZED_AVERAGE_POOL2D', 'Pool');
-                    register(   11, 'QUANTIZE', '', (layer, reader) => {
-                        layer.flags = reader.uint32();
-                        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.parameter('input') ];
-                        layer.outputs = [ reader.parameter('output') ];
-                        layer.count = reader.uint32();
-                        layer.scale = reader.float32();
-                        layer.bias = reader.float32();
-                    });
-                    register(   13, 'REQUANTIZE', '', (layer, reader) => {
-                        layer.flags = reader.uint32();
-                        layer.inputs = [ reader.parameter('input') ];
-                        layer.outputs = [ reader.parameter('output') ];
-                        layer.count = reader.uint32();
-                        layer.table = reader.read(256);
-                    });
-                    register(   14, 'L2_NORMALIZATION', 'Normalization');
-                    register(   15, 'SOFTMAX', 'Activation', (layer, reader) => {
-                        layer.flags = reader.uint32();
-                        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.parameter('output') ];
-                        layer.inputs_mem = new Array(reader.uint32());
-                        for (let i = 0; i < layer.inputs_mem.length; i++) {
-                            layer.inputs_mem[i] = {
-                                start: reader.uint32(),
-                                end: reader.uint32()
-                            };
-                        }
-                    });
-                    register(   17, 'QUANTIZED_CONCAT', 'Tensor', (layer, reader) => {
-                        layer.flags = reader.uint32();
-                        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] = {
-                                start: reader.uint32(),
-                                end: reader.uint32()
-                            };
+                });
+                register(   18, 'FULLY_CONNECTED', 'Layer', (layer, reader) => {
+                    layer.flags = reader.uint32();
+                    layer.inputs = [ reader.parameter('input') ];
+                    layer.outputs = [ reader.parameter('output') ];
+                    layer.in_channels = reader.uint32();
+                    layer.out_channels = reader.uint32();
+                    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}'.`);
                         }
+                        layer.chain = [ { type: activations[act] } ];
+                    }
+                    layer.inputs.push({ name: 'weights', value: [ { 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', value: [ { 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.parameter('input') ];
+                    layer.outputs = [ reader.parameter('output') ];
+                    const shape = [ reader.uint32(), reader.uint32(), reader.uint32() ];
+                    layer.inputs[0].value[0].shape = shape;
+                    layer.outputs[0].value[0].shape = shape;
+                });
+                register(   21, 'QUANTIZED_TENSORFLOW_FLATTEN', 'Shape', (layer, reader) => {
+                    layer.flags = reader.uint32();
+                    layer.inputs = [ reader.parameter('input') ];
+                    layer.outputs = [ reader.parameter('output') ];
+                    const shape = [ reader.uint32(), reader.uint32(), reader.uint32() ];
+                    layer.inputs[0].value[0].shape = shape;
+                    layer.outputs[0].value[0].shape = shape;
+                });
+                register(   22, 'RESIZE_NEAREST_NEIGHBOR', '', (layer, reader) => {
+                    layer.flags = reader.uint32();
+                    layer.inputs = [ reader.parameter('input') ];
+                    layer.outputs = [ reader.parameter('output') ];
+                    layer.inputs[0].value[0].shape = [ reader.uint32(), reader.uint32(), reader.uint32() ];
+                    layer.out_width = reader.uint32();
+                    layer.out_height = reader.uint32();
+                    layer.align_corners = reader.uint32();
+                });
+                register(   23, 'QUANTIZED_RESIZE_NEAREST_NEIGHBOR', '', (layer, reader) => {
+                    layer.flags = reader.uint32();
+                    layer.inputs = [ reader.parameter('input') ];
+                    layer.outputs = [ reader.parameter('output') ];
+                    layer.inputs[0].value[0].shape = [ reader.uint32(), reader.uint32(), reader.uint32() ];
+                    layer.out_width = reader.uint32();
+                    layer.out_height = reader.uint32();
+                    layer.align_corners = reader.uint32();
+                });
+                register( 1000, 'CONV', 'Layer');
+                register( 1001, 'DWCONV', 'Layer');
+                register( 1002, 'QUANTIZED_RESHAPE', 'Shape');
+                register( 1003, 'RESHAPE', 'Shape');
+                register(10240, 'K210_CONV', 'Layer', (layer, reader) => {
+                    layer.flags = reader.uint32();
+                    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.parameter('input', 'kpu') ];
+                    const outputs = [ reader.parameter('output', 'kpu') ];
+                    layer.outputs[0].value.push(outputs[0].value[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 });
+                    layer.kernel_load_cfg = reader.uint64_bits({ load_coor: 0, load_time: 1, para_size: 15, para_start_addr: 32 });
+                    layer.kernel_offset = reader.uint64_bits({ coef_column_offset: 0, coef_row_offset: 4 });
+                    layer.kernel_calc_type_cfg = reader.uint64_bits({ 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.uint64_bits({ wb_channel_switch_addr: 0, wb_row_switch_addr: 16, wb_group: 20 });
+                    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 });
+                    layer.chain = [];
+                    const ic = layer.image_channel_num.i_ch_num + 1;
+                    const oc = layer.image_channel_num.o_ch_num + 1;
+                    layer.outputs[0].value[0].shape = [ layer.image_size.o_row_wid + 1, layer.image_size.o_col_high + 1, oc ];
+                    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',
+                        value: [ {
+                            name: '',
+                            datatype: 'uint8',
+                            shape: weights_shape,
+                            data: reader.read(weights_size)
+                        } ]
                     });
-                    register(   18, 'FULLY_CONNECTED', 'Layer', (layer, reader) => {
-                        layer.flags = reader.uint32();
-                        layer.inputs = [ reader.parameter('input') ];
-                        layer.outputs = [ reader.parameter('output') ];
-                        layer.in_channels = reader.uint32();
-                        layer.out_channels = reader.uint32();
-                        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}'.`);
-                            }
-                            layer.chain = [ { type: activations[act] } ];
-                        }
-                        layer.inputs.push({ name: 'weights', value: [ { 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', value: [ { 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.parameter('input') ];
-                        layer.outputs = [ reader.parameter('output') ];
-                        const shape = [ reader.uint32(), reader.uint32(), reader.uint32() ];
-                        layer.inputs[0].value[0].shape = shape;
-                        layer.outputs[0].value[0].shape = shape;
+                    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.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.parameter('input') ];
+                    layer.outputs = [ reader.parameter('output') ];
+                    layer.channels = reader.uint32();
+                });
+                register(10243, 'K210_UPLOAD', '', (layer, reader) => {
+                    layer.flags = reader.uint32();
+                    layer.inputs = [ reader.parameter('input') ];
+                    layer.outputs = [ reader.parameter('output', 'kpu') ];
+                    const shape = [ reader.uint32(), reader.uint32(), reader.uint32() ];
+                    layer.inputs[0].value[0].shape = shape;
+                    layer.outputs[0].value[0].shape = shape;
+                });
+                /* eslint-enable space-in-parens */
+                for (const layer of layers) {
+                    const type = types.get(layer.type);
+                    if (!type) {
+                        throw new kmodel.Error(`Unsupported version '${this.version}' layer type '${layer.type}'.`);
+                    }
+                    if (!type.callback) {
+                        throw new kmodel.Error(`Unsupported version '${this.version}' layer '${type.type.name}'.`);
+                    }
+                    layer.type = type.type;
+                    reader.seek(layer.offset);
+                    type.callback(layer, reader);
+                    delete layer.offset;
+                    delete layer.body_size;
+                }
+                if (layers.length > 0) {
+                    layers.unshift({
+                        type: { name: 'input' },
+                        outputs: [ layers[0].inputs[0] ]
                     });
-                    register(   21, 'QUANTIZED_TENSORFLOW_FLATTEN', 'Shape', (layer, reader) => {
-                        layer.flags = reader.uint32();
-                        layer.inputs = [ reader.parameter('input') ];
-                        layer.outputs = [ reader.parameter('output') ];
-                        const shape = [ reader.uint32(), reader.uint32(), reader.uint32() ];
-                        layer.inputs[0].value[0].shape = shape;
-                        layer.outputs[0].value[0].shape = shape;
+                }
+                for (const output of outputs) {
+                    layers.push({
+                        type: { name: 'output' },
+                        inputs: output.address
                     });
-                    register(   22, 'RESIZE_NEAREST_NEIGHBOR', '', (layer, reader) => {
-                        layer.flags = reader.uint32();
-                        layer.inputs = [ reader.parameter('input') ];
-                        layer.outputs = [ reader.parameter('output') ];
-                        layer.inputs[0].value[0].shape = [ reader.uint32(), reader.uint32(), reader.uint32() ];
-                        layer.out_width = reader.uint32();
-                        layer.out_height = reader.uint32();
-                        layer.align_corners = reader.uint32();
+                }
+                this.modules.push({
+                    name: '',
+                    layers: layers
+                });
+                break;
+            }
+            case 4: {
+                const reader = new kmodel.BinaryReader.v4(this.stream);
+                const model_header = {
+                    flags: reader.uint32(),
+                    target: reader.uint32(), // 0=CPU, 1=K210
+                    constants: reader.uint32(),
+                    main_mem: reader.uint32(),
+                    nodes: reader.uint32(),
+                    inputs: reader.uint32(),
+                    outputs: reader.uint32(),
+                    reserved0: reader.uint32(),
+                };
+                const inputs = new Array(model_header.inputs);
+                for (let i = 0; i < inputs.length; i++) {
+                    inputs[i] = reader.parameter(`input${i == 0 ? '' : (i + 1)}`);
+                }
+                for (let i = 0; i < inputs.length; i++) {
+                    inputs[i].value[0].shape = reader.runtime_shape_t();
+                }
+                const outputs = new Array(model_header.outputs);
+                for (let i = 0; i < outputs.length; i++) {
+                    outputs[i] = reader.parameter(`output${i == 0 ? '' : (i + 1)}`);
+                }
+                reader.constants(model_header.constants);
+                const layers = new Array(model_header.nodes);
+                for (let i = 0; i < layers.length; i++) {
+                    layers[i] = {
+                        location: i,
+                        opcode: reader.uint32(),
+                        body_size: reader.uint32()
+                    };
+                }
+                let offset = reader.position;
+                for (const layer of layers) {
+                    layer.offset = offset;
+                    offset += layer.body_size;
+                }
+                /* eslint-disable space-in-parens */
+                register(  0x00, 'binary', '', (layer, reader) => {
+                    layer.inputs = [
+                        reader.parameter('a'),
+                        reader.parameter('b')
+                    ];
+                    layer.outputs = [ reader.parameter('outputs') ];
+                    layer.binary_op = reader.binary_op_t();
+                    layer.inputs[0].value[0].shape = reader.runtime_shape_t();
+                    layer.inputs[1].value[0].shape = reader.runtime_shape_t();
+                    layer.outputs[0].value[0].shape = reader.runtime_shape_t();
+                    layer.fused_activation = [ reader.float32(), reader.float32() ];
+                });
+                register(  0x01, 'concat', 'Tensor', (layer, reader) => {
+                    layer.outputs = [ reader.parameter('output') ];
+                    layer.inner_size = reader.uint32();
+                    layer.outer_size = reader.uint32();
+                    const inputs_count = reader.uint32();
+                    layer.inputs = [ { name: 'inputs', value: [] } ];
+                    for (let i = 0; i < inputs_count; i++) {
+                        layer.inputs[0].value[i] = reader.argument();
+                    }
+                    layer.dims = new Array(inputs_count);
+                    for (let i = 0; i < inputs_count; i++) {
+                        layer.dims[i] = reader.int32();
+                    }
+                });
+                register(  0x02, 'conv2d', 'Layer', (layer, reader) => {
+                    layer.inputs = [ reader.parameter('input') ];
+                    layer.outputs = [ reader.parameter('output') ];
+                    layer.inputs[0].value[0].shape = reader.runtime_shape_t();
+                    layer.groups = reader.int32();
+                    layer.out_channels = reader.int32();
+                    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.fused_activation = [ reader.float32(), reader.float32() ];
+                    const weights_shape = [ layer.out_channels, layer.inputs[0].value[0].shape[1] / layer.groups, layer.filter_h, layer.filter_w ];
+                    const weights_size = 4 * weights_shape.reduce((a, b) => a * b);
+                    layer.inputs.push({
+                        name: 'weights',
+                        value: [ {
+                            name: '',
+                            datatype: 'float32',
+                            shape: weights_shape,
+                            data: reader.read(weights_size)
+                        } ]
                     });
-                    register(   23, 'QUANTIZED_RESIZE_NEAREST_NEIGHBOR', '', (layer, reader) => {
-                        layer.flags = reader.uint32();
-                        layer.inputs = [ reader.parameter('input') ];
-                        layer.outputs = [ reader.parameter('output') ];
-                        layer.inputs[0].value[0].shape = [ reader.uint32(), reader.uint32(), reader.uint32() ];
-                        layer.out_width = reader.uint32();
-                        layer.out_height = reader.uint32();
-                        layer.align_corners = reader.uint32();
+                    const bias_shape = [ layer.out_channels ];
+                    const bias_size = 4 * layer.out_channels;
+                    layer.inputs.push({
+                        name: 'bias',
+                        value: [ {
+                            name: '',
+                            datatype: 'float32',
+                            shape: bias_shape,
+                            data: reader.read(bias_size)
+                        } ]
                     });
-                    register( 1000, 'CONV', 'Layer');
-                    register( 1001, 'DWCONV', 'Layer');
-                    register( 1002, 'QUANTIZED_RESHAPE', 'Shape');
-                    register( 1003, 'RESHAPE', 'Shape');
-                    register(10240, 'K210_CONV', 'Layer', (layer, reader) => {
-                        layer.flags = reader.uint32();
-                        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.parameter('input', 'kpu') ];
-                        const outputs = [ reader.parameter('output', 'kpu') ];
-                        layer.outputs[0].value.push(outputs[0].value[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 });
-                        layer.kernel_load_cfg = reader.uint64_bits({ load_coor: 0, load_time: 1, para_size: 15, para_start_addr: 32 });
-                        layer.kernel_offset = reader.uint64_bits({ coef_column_offset: 0, coef_row_offset: 4 });
-                        layer.kernel_calc_type_cfg = reader.uint64_bits({ 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.uint64_bits({ wb_channel_switch_addr: 0, wb_row_switch_addr: 16, wb_group: 20 });
-                        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 });
-                        layer.chain = [];
-                        const ic = layer.image_channel_num.i_ch_num + 1;
-                        const oc = layer.image_channel_num.o_ch_num + 1;
-                        layer.outputs[0].value[0].shape = [ layer.image_size.o_row_wid + 1, layer.image_size.o_col_high + 1, oc ];
-                        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);
+                });
+                register(  0x03, 'dequantize', '', (layer, reader) => {
+                    layer.inputs = [ reader.parameter('input') ];
+                    layer.outputs = [ reader.parameter('output') ];
+                    layer.zero_point = reader.int32();
+                    layer.scale = reader.float32();
+                });
+                register(  0x04, 'matmul', '', (layer, reader) => {
+                    layer.inputs = [
+                        reader.parameter('a'),
+                        reader.parameter('b'),
+                    ];
+                    layer.outputs = [ reader.parameter('output') ];
+                    layer.a_rows = reader.int32();
+                    layer.a_cols = reader.int32();
+                    layer.b_cols = reader.int32();
+                    layer.inputs[1].value[0].shape = [ layer.a_cols, layer.b_cols ];
+                    layer.fused_activation = [ reader.float32(), reader.float32() ];
+                    const bias = reader.read(4 * layer.b_cols);
+                    if (!bias.every((value) => value === 0)) {
                         layer.inputs.push({
-                            name: 'weights',
-                            value: [ {
-                                name: '',
-                                datatype: 'uint8',
-                                shape: weights_shape,
-                                data: reader.read(weights_size)
-                            } ]
+                            name: 'bias',
+                            value: [ { name: '', datatype: 'float32', shape: [ layer.b_cols ], data: bias } ]
                         });
-                        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.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.parameter('input') ];
-                        layer.outputs = [ reader.parameter('output') ];
-                        layer.channels = reader.uint32();
-                    });
-                    register(10243, 'K210_UPLOAD', '', (layer, reader) => {
-                        layer.flags = reader.uint32();
-                        layer.inputs = [ reader.parameter('input') ];
-                        layer.outputs = [ reader.parameter('output', 'kpu') ];
-                        const shape = [ reader.uint32(), reader.uint32(), reader.uint32() ];
-                        layer.inputs[0].value[0].shape = shape;
-                        layer.outputs[0].value[0].shape = shape;
-                    });
-                    /* eslint-enable space-in-parens */
-                    for (const layer of layers) {
-                        const type = types.get(layer.type);
-                        if (!type) {
-                            throw new kmodel.Error(`Unsupported version '${this.version}' layer type '${layer.type}'.`);
-                        }
-                        if (!type.callback) {
-                            throw new kmodel.Error(`Unsupported version '${this.version}' layer '${type.type.name}'.`);
-                        }
-                        layer.type = type.type;
-                        reader.seek(layer.offset);
-                        type.callback(layer, reader);
-                        delete layer.offset;
-                        delete layer.body_size;
                     }
-                    if (layers.length > 0) {
-                        layers.unshift({
-                            type: { name: 'input' },
-                            outputs: [ layers[0].inputs[0] ]
-                        });
+                });
+                register(  0x05, 'pad', 'Shape', (layer, reader) => {
+                    layer.inputs = [ reader.parameter('input') ];
+                    layer.outputs = [ reader.parameter('output') ];
+                    layer.inputs[0].value[0].shape = reader.runtime_shape_t();
+                    layer.paddings = reader.runtime_paddings_t();
+                    layer.pad_value = reader.scalar();
+                });
+                register(  0x06, 'quantize', '', (layer, reader) => {
+                    layer.inputs = [ reader.parameter('input') ];
+                    layer.outputs = [ reader.parameter('output') ];
+                    layer.zero_point = reader.int32();
+                    layer.scale = reader.float32();
+                });
+                register(  0x07, 'reduce', '', (layer, reader) => {
+                    layer.inputs = [ reader.parameter('input') ];
+                    layer.outputs = [ reader.parameter('output') ];
+                    layer.reduce_op = reader.reduce_op_t();
+                    layer.inputs[0].value[0].shape = reader.runtime_shape_t();
+                    layer.outputs[0].value[0].shape = reader.runtime_shape_t();
+                    layer.init_value = reader.float32();
+                });
+                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].value[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', '', (layer, reader) => {
+                    layer.inputs = [ reader.parameter('input') ];
+                    layer.outputs = [ reader.parameter('output') ];
+                    layer.reduce_op = reader.reduce_op_t();
+                    layer.inputs[0].value[0].shape = reader.runtime_shape_t();
+                    layer.out_h = reader.int32();
+                    layer.out_w = reader.int32();
+                    layer.mode = reader.image_resize_mode_t();
+                    layer.align_corners = reader.boolean();
+                });
+                register(  0x0B, 'softmax', 'Activation');
+                register(  0x0C, 'transpose', 'Transform', (layer, reader) => {
+                    layer.inputs = [ reader.parameter('input') ];
+                    layer.outputs = [ reader.parameter('output') ];
+                    layer.inputs[0].value[0].shape = reader.runtime_shape_t();
+                    layer.perm = reader.runtime_shape_t();
+                });
+                register(  0x0D, 'strided_slice', 'Tensor');
+                register(  0x0E, 'unary', '', (layer, reader) => {
+                    layer.inputs = [ reader.parameter('input') ];
+                    layer.outputs = [ reader.parameter('output') ];
+                    layer.unary_op = reader.unary_op_t();
+                });
+                register(  0x0F, 'quantized_conv2d', 'Layer', (layer, reader) => {
+                    layer.inputs = [ reader.parameter('input') ];
+                    layer.outputs = [ reader.parameter('output') ];
+                    layer.inputs[0].value[0].shape = reader.runtime_shape_t();
+                    layer.groups = reader.int32();
+                    layer.out_channels = reader.int32();
+                    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.input_offset = reader.int32();
+                    layer.filter_offset = reader.int32();
+                    layer.output_mul = reader.int32();
+                    layer.output_shift = reader.int32();
+                    layer.output_offset = reader.int32();
+                    const bias = reader.span('int32', [ layer.out_channels ]);
+                    if (bias) {
+                        layer.inputs.push({ name: 'bias', value: [ bias ] });
                     }
-                    for (const output of outputs) {
-                        layers.push({
-                            type: { name: 'output' },
-                            inputs: output.address
-                        });
+                    const weights = reader.span('uint8', [ layer.out_channels, layer.inputs[0].value[0].shape[1] / layer.groups, layer.filter_h, layer.filter_w]);
+                    if (weights) {
+                        layer.inputs.push({ name: 'weights', value: [ weights ] });
                     }
-                    this.modules.push({
-                        name: '',
-                        layers: layers
-                    });
-                    break;
-                }
-                case 4: {
-                    const reader = new kmodel.BinaryReader.v4(this.stream);
-                    const model_header = {
-                        flags: reader.uint32(),
-                        target: reader.uint32(), // 0=CPU, 1=K210
-                        constants: reader.uint32(),
-                        main_mem: reader.uint32(),
-                        nodes: reader.uint32(),
-                        inputs: reader.uint32(),
-                        outputs: reader.uint32(),
-                        reserved0: reader.uint32(),
+                });
+                register(  0x10, 'quantized_matmul', '', (layer, reader) => {
+                    layer.inputs = [
+                        reader.parameter('a'),
+                        reader.parameter('b'),
+                    ];
+                    layer.outputs = [ reader.parameter('output') ];
+                    layer.a_rows = reader.int32();
+                    layer.a_cols = reader.int32();
+                    layer.b_cols = reader.int32();
+                    layer.inputs[1].value[0].shape = [ layer.a_cols, layer.b_cols ];
+                    layer.input_a_offset = reader.int32();
+                    layer.input_b_offset = reader.int32();
+                    layer.output_mul = reader.int32();
+                    layer.output_shift = reader.int32();
+                    layer.output_offset = reader.int32();
+                    const bias = reader.span('int32', [ layer.b_cols ]);
+                    if (bias) {
+                        layer.inputs.push({ name: 'bias', value: [ bias ] });
+                    }
+                });
+                register(  0x11, 'quantized_binary', '', (layer, reader) => {
+                    layer.inputs = [
+                        reader.parameter('a'),
+                        reader.parameter('b')
+                    ];
+                    layer.outputs = [ reader.parameter('outputs') ];
+                    layer.binary_op = reader.binary_op_t();
+                    layer.inputs[0].value[0].shape = reader.runtime_shape_t();
+                    layer.inputs[1].value[0].shape = reader.runtime_shape_t();
+                    layer.outputs[0].value[0].shape = reader.runtime_shape_t();
+                    layer.input_a_offset = reader.int32();
+                    layer.input_a_mul = reader.int32();
+                    layer.input_a_shift = reader.int32();
+                    layer.input_b_offset = reader.int32();
+                    layer.input_b_mul = reader.int32();
+                    layer.input_b_shift = reader.int32();
+                    layer.output_offset = reader.int32();
+                    layer.output_mul = reader.int32();
+                    layer.output_shift = reader.int32();
+                });
+                register(  0x12, 'table_lookup1d', '', (layer, reader) => {
+                    layer.inputs = [ reader.parameter('input'), reader.parameter('table') ];
+                    layer.outputs = [ reader.parameter('output') ];
+                });
+                register(  0x13, 'conv2d_transpose', 'Layer');
+                register(  0x14, 'nnil_unary_method', '', (layer, reader, size) => {
+                    const position = reader.position;
+                    layer.inputs = [ reader.parameter('input') ];
+                    layer.outputs = [ reader.parameter('output') ];
+                    layer.body = reader.read(size - (reader.position - position));
+                });
+                register(0x1001, 'cpu_conv2d', 'Layer');
+                register(0x1002, 'cpu_depthwise_conv2d', 'Layer');
+                register(0x1003, 'cpu_reduce_window2d');
+                register(0x1004, 'cpu_quantized_conv2d', 'Layer');
+                register(0x1005, 'cpu_quantized_depthwise_conv2d', 'Layer');
+                register(0x2001, 'kpu_upload', '', (layer, reader) => {
+                    layer.inputs = [ reader.parameter('input') ];
+                    layer.outputs = [ reader.parameter('output') ];
+                    layer.inputs[0].value[0].shape = reader.runtime_shape_t();
+                });
+                register(0x2002, 'kpu_conv2d', 'Layer', (layer, reader) => {
+                    layer.outputs = [ reader.parameter('output') ];
+                    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 });
+                    const image_src_addr = reader.uint32();
+                    const image_dst_addr = reader.uint32();
+                    layer.inputs = [ { name: 'input', value: [ { name: `kpu:${image_src_addr}` } ] } ];
+                    const outputs = [ { name: 'output', value: [ { name: `kpu:${image_dst_addr}` } ] } ];
+                    layer.outputs[0].value.push(outputs[0].value[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 });
+                    layer.kernel_load_cfg = reader.uint64_bits({ load_coor: 0, load_time: 1, para_size: 15, para_start_addr: 32 });
+                    layer.kernel_offset = reader.uint64_bits({ coef_column_offset: 0, coef_row_offset: 4 });
+                    layer.kernel_calc_type_cfg = reader.uint64_bits({ 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.uint64_bits({ wb_channel_switch_addr: 0, wb_row_switch_addr: 16, wb_group: 20 });
+                    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, reserved: 1, channel_byte_num: 16, dma_total_byte: 32 });
+                    layer.chain = [];
+                    const ic = layer.image_channel_num.i_ch_num + 1;
+                    const oc = layer.image_channel_num.o_ch_num + 1;
+                    layer.outputs[0].value[0].shape = [ layer.image_size.o_row_wid + 1, layer.image_size.o_col_high + 1, oc ];
+                    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 ];
+                    reader.skip(layer.kernel_pool_type_cfg.bwsx_base_addr);
+                    delete layer.kernel_pool_type_cfg.bwsx_base_addr;
+                    const batch_norm = {
+                        type: { name: 'batch_norm', category: 'Normalization' },
+                        weights: []
                     };
-                    const inputs = new Array(model_header.inputs);
-                    for (let i = 0; i < inputs.length; i++) {
-                        inputs[i] = reader.parameter(`input${i == 0 ? '' : (i + 1)}`);
+                    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;
                     }
-                    for (let i = 0; i < inputs.length; i++) {
-                        inputs[i].value[0].shape = reader.runtime_shape_t();
+                    layer.chain.push(batch_norm);
+                    reader.skip(layer.kernel_calc_type_cfg.active_addr);
+                    delete layer.kernel_calc_type_cfg.active_addr;
+                    const activation = reader.kpu_activate_table_t();
+                    activation.type = { name: 'activation', category: 'Activation' };
+                    layer.chain.push(activation);
+                    reader.skip(layer.kernel_load_cfg.para_start_addr);
+                    delete layer.kernel_load_cfg.para_start_addr;
+                    const weights = reader.span('uint8', weights_shape);
+                    if (weights) {
+                        layer.inputs.push({ name: 'weights', value: [ weights ] });
                     }
-                    const outputs = new Array(model_header.outputs);
-                    for (let i = 0; i < outputs.length; i++) {
-                        outputs[i] = reader.parameter(`output${i == 0 ? '' : (i + 1)}`);
+                });
+                /* eslint-enable space-in-parens */
+                for (const layer of layers) {
+                    const type = types.get(layer.opcode);
+                    if (!type) {
+                        throw new kmodel.Error(`Unsupported version '${this.version}' layer type '${layer.type}'.`);
                     }
-                    reader.constants(model_header.constants);
-                    const layers = new Array(model_header.nodes);
-                    for (let i = 0; i < layers.length; i++) {
-                        layers[i] = {
-                            location: i,
-                            opcode: reader.uint32(),
-                            body_size: reader.uint32()
-                        };
+                    if (!type.callback) {
+                        throw new kmodel.Error(`Unsupported version '${this.version}' layer '${type.type.name}'.`);
                     }
-                    let offset = reader.position;
-                    for (const layer of layers) {
-                        layer.offset = offset;
-                        offset += layer.body_size;
+                    layer.type = type.type;
+                    reader.seek(layer.offset);
+                    if (type.callback) {
+                        type.callback(layer, reader, layer.body_size);
                     }
-                    /* eslint-disable space-in-parens */
-                    register(  0x00, 'binary', '', (layer, reader) => {
-                        layer.inputs = [
-                            reader.parameter('a'),
-                            reader.parameter('b')
-                        ];
-                        layer.outputs = [ reader.parameter('outputs') ];
-                        layer.binary_op = reader.binary_op_t();
-                        layer.inputs[0].value[0].shape = reader.runtime_shape_t();
-                        layer.inputs[1].value[0].shape = reader.runtime_shape_t();
-                        layer.outputs[0].value[0].shape = reader.runtime_shape_t();
-                        layer.fused_activation = [ reader.float32(), reader.float32() ];
-                    });
-                    register(  0x01, 'concat', 'Tensor', (layer, reader) => {
-                        layer.outputs = [ reader.parameter('output') ];
-                        layer.inner_size = reader.uint32();
-                        layer.outer_size = reader.uint32();
-                        const inputs_count = reader.uint32();
-                        layer.inputs = [ { name: 'inputs', value: [] } ];
-                        for (let i = 0; i < inputs_count; i++) {
-                            layer.inputs[0].value[i] = reader.argument();
-                        }
-                        layer.dims = new Array(inputs_count);
-                        for (let i = 0; i < inputs_count; i++) {
-                            layer.dims[i] = reader.int32();
-                        }
-                    });
-                    register(  0x02, 'conv2d', 'Layer', (layer, reader) => {
-                        layer.inputs = [ reader.parameter('input') ];
-                        layer.outputs = [ reader.parameter('output') ];
-                        layer.inputs[0].value[0].shape = reader.runtime_shape_t();
-                        layer.groups = reader.int32();
-                        layer.out_channels = reader.int32();
-                        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.fused_activation = [ reader.float32(), reader.float32() ];
-                        const weights_shape = [ layer.out_channels, layer.inputs[0].value[0].shape[1] / layer.groups, layer.filter_h, layer.filter_w ];
-                        const weights_size = 4 * weights_shape.reduce((a, b) => a * b);
-                        layer.inputs.push({
-                            name: 'weights',
-                            value: [ {
-                                name: '',
-                                datatype: 'float32',
-                                shape: weights_shape,
-                                data: reader.read(weights_size)
-                            } ]
-                        });
-                        const bias_shape = [ layer.out_channels ];
-                        const bias_size = 4 * layer.out_channels;
-                        layer.inputs.push({
-                            name: 'bias',
-                            value: [ {
-                                name: '',
-                                datatype: 'float32',
-                                shape: bias_shape,
-                                data: reader.read(bias_size)
-                            } ]
-                        });
-                    });
-                    register(  0x03, 'dequantize', '', (layer, reader) => {
-                        layer.inputs = [ reader.parameter('input') ];
-                        layer.outputs = [ reader.parameter('output') ];
-                        layer.zero_point = reader.int32();
-                        layer.scale = reader.float32();
-                    });
-                    register(  0x04, 'matmul', '', (layer, reader) => {
-                        layer.inputs = [
-                            reader.parameter('a'),
-                            reader.parameter('b'),
-                        ];
-                        layer.outputs = [ reader.parameter('output') ];
-                        layer.a_rows = reader.int32();
-                        layer.a_cols = reader.int32();
-                        layer.b_cols = reader.int32();
-                        layer.inputs[1].value[0].shape = [ layer.a_cols, layer.b_cols ];
-                        layer.fused_activation = [ reader.float32(), reader.float32() ];
-                        const bias = reader.read(4 * layer.b_cols);
-                        if (!bias.every((value) => value === 0)) {
-                            layer.inputs.push({
-                                name: 'bias',
-                                value: [ { name: '', datatype: 'float32', shape: [ layer.b_cols ], data: bias } ]
-                            });
-                        }
-                    });
-                    register(  0x05, 'pad', 'Shape', (layer, reader) => {
-                        layer.inputs = [ reader.parameter('input') ];
-                        layer.outputs = [ reader.parameter('output') ];
-                        layer.inputs[0].value[0].shape = reader.runtime_shape_t();
-                        layer.paddings = reader.runtime_paddings_t();
-                        layer.pad_value = reader.scalar();
-                    });
-                    register(  0x06, 'quantize', '', (layer, reader) => {
-                        layer.inputs = [ reader.parameter('input') ];
-                        layer.outputs = [ reader.parameter('output') ];
-                        layer.zero_point = reader.int32();
-                        layer.scale = reader.float32();
-                    });
-                    register(  0x07, 'reduce', '', (layer, reader) => {
-                        layer.inputs = [ reader.parameter('input') ];
-                        layer.outputs = [ reader.parameter('output') ];
-                        layer.reduce_op = reader.reduce_op_t();
-                        layer.inputs[0].value[0].shape = reader.runtime_shape_t();
-                        layer.outputs[0].value[0].shape = reader.runtime_shape_t();
-                        layer.init_value = reader.float32();
-                    });
-                    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].value[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', '', (layer, reader) => {
-                        layer.inputs = [ reader.parameter('input') ];
-                        layer.outputs = [ reader.parameter('output') ];
-                        layer.reduce_op = reader.reduce_op_t();
-                        layer.inputs[0].value[0].shape = reader.runtime_shape_t();
-                        layer.out_h = reader.int32();
-                        layer.out_w = reader.int32();
-                        layer.mode = reader.image_resize_mode_t();
-                        layer.align_corners = reader.boolean();
-                    });
-                    register(  0x0B, 'softmax', 'Activation');
-                    register(  0x0C, 'transpose', 'Transform', (layer, reader) => {
-                        layer.inputs = [ reader.parameter('input') ];
-                        layer.outputs = [ reader.parameter('output') ];
-                        layer.inputs[0].value[0].shape = reader.runtime_shape_t();
-                        layer.perm = reader.runtime_shape_t();
-                    });
-                    register(  0x0D, 'strided_slice', 'Tensor');
-                    register(  0x0E, 'unary', '', (layer, reader) => {
-                        layer.inputs = [ reader.parameter('input') ];
-                        layer.outputs = [ reader.parameter('output') ];
-                        layer.unary_op = reader.unary_op_t();
-                    });
-                    register(  0x0F, 'quantized_conv2d', 'Layer', (layer, reader) => {
-                        layer.inputs = [ reader.parameter('input') ];
-                        layer.outputs = [ reader.parameter('output') ];
-                        layer.inputs[0].value[0].shape = reader.runtime_shape_t();
-                        layer.groups = reader.int32();
-                        layer.out_channels = reader.int32();
-                        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.input_offset = reader.int32();
-                        layer.filter_offset = reader.int32();
-                        layer.output_mul = reader.int32();
-                        layer.output_shift = reader.int32();
-                        layer.output_offset = reader.int32();
-                        const bias = reader.span('int32', [ layer.out_channels ]);
-                        if (bias) {
-                            layer.inputs.push({ name: 'bias', value: [ bias ] });
-                        }
-                        const weights = reader.span('uint8', [ layer.out_channels, layer.inputs[0].value[0].shape[1] / layer.groups, layer.filter_h, layer.filter_w]);
-                        if (weights) {
-                            layer.inputs.push({ name: 'weights', value: [ weights ] });
-                        }
-                    });
-                    register(  0x10, 'quantized_matmul', '', (layer, reader) => {
-                        layer.inputs = [
-                            reader.parameter('a'),
-                            reader.parameter('b'),
-                        ];
-                        layer.outputs = [ reader.parameter('output') ];
-                        layer.a_rows = reader.int32();
-                        layer.a_cols = reader.int32();
-                        layer.b_cols = reader.int32();
-                        layer.inputs[1].value[0].shape = [ layer.a_cols, layer.b_cols ];
-                        layer.input_a_offset = reader.int32();
-                        layer.input_b_offset = reader.int32();
-                        layer.output_mul = reader.int32();
-                        layer.output_shift = reader.int32();
-                        layer.output_offset = reader.int32();
-                        const bias = reader.span('int32', [ layer.b_cols ]);
-                        if (bias) {
-                            layer.inputs.push({ name: 'bias', value: [ bias ] });
-                        }
-                    });
-                    register(  0x11, 'quantized_binary', '', (layer, reader) => {
-                        layer.inputs = [
-                            reader.parameter('a'),
-                            reader.parameter('b')
-                        ];
-                        layer.outputs = [ reader.parameter('outputs') ];
-                        layer.binary_op = reader.binary_op_t();
-                        layer.inputs[0].value[0].shape = reader.runtime_shape_t();
-                        layer.inputs[1].value[0].shape = reader.runtime_shape_t();
-                        layer.outputs[0].value[0].shape = reader.runtime_shape_t();
-                        layer.input_a_offset = reader.int32();
-                        layer.input_a_mul = reader.int32();
-                        layer.input_a_shift = reader.int32();
-                        layer.input_b_offset = reader.int32();
-                        layer.input_b_mul = reader.int32();
-                        layer.input_b_shift = reader.int32();
-                        layer.output_offset = reader.int32();
-                        layer.output_mul = reader.int32();
-                        layer.output_shift = reader.int32();
-                    });
-                    register(  0x12, 'table_lookup1d', '', (layer, reader) => {
-                        layer.inputs = [ reader.parameter('input'), reader.parameter('table') ];
-                        layer.outputs = [ reader.parameter('output') ];
-                    });
-                    register(  0x13, 'conv2d_transpose', 'Layer');
-                    register(  0x14, 'nnil_unary_method', '', (layer, reader, size) => {
-                        const position = reader.position;
-                        layer.inputs = [ reader.parameter('input') ];
-                        layer.outputs = [ reader.parameter('output') ];
-                        layer.body = reader.read(size - (reader.position - position));
-                    });
-                    register(0x1001, 'cpu_conv2d', 'Layer');
-                    register(0x1002, 'cpu_depthwise_conv2d', 'Layer');
-                    register(0x1003, 'cpu_reduce_window2d');
-                    register(0x1004, 'cpu_quantized_conv2d', 'Layer');
-                    register(0x1005, 'cpu_quantized_depthwise_conv2d', 'Layer');
-                    register(0x2001, 'kpu_upload', '', (layer, reader) => {
-                        layer.inputs = [ reader.parameter('input') ];
-                        layer.outputs = [ reader.parameter('output') ];
-                        layer.inputs[0].value[0].shape = reader.runtime_shape_t();
-                    });
-                    register(0x2002, 'kpu_conv2d', 'Layer', (layer, reader) => {
-                        layer.outputs = [ reader.parameter('output') ];
-                        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 });
-                        const image_src_addr = reader.uint32();
-                        const image_dst_addr = reader.uint32();
-                        layer.inputs = [ { name: 'input', value: [ { name: `kpu:${image_src_addr}` } ] } ];
-                        const outputs = [ { name: 'output', value: [ { name: `kpu:${image_dst_addr}` } ] } ];
-                        layer.outputs[0].value.push(outputs[0].value[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 });
-                        layer.kernel_load_cfg = reader.uint64_bits({ load_coor: 0, load_time: 1, para_size: 15, para_start_addr: 32 });
-                        layer.kernel_offset = reader.uint64_bits({ coef_column_offset: 0, coef_row_offset: 4 });
-                        layer.kernel_calc_type_cfg = reader.uint64_bits({ 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.uint64_bits({ wb_channel_switch_addr: 0, wb_row_switch_addr: 16, wb_group: 20 });
-                        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, reserved: 1, channel_byte_num: 16, dma_total_byte: 32 });
-                        layer.chain = [];
-                        const ic = layer.image_channel_num.i_ch_num + 1;
-                        const oc = layer.image_channel_num.o_ch_num + 1;
-                        layer.outputs[0].value[0].shape = [ layer.image_size.o_row_wid + 1, layer.image_size.o_col_high + 1, oc ];
-                        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 ];
-                        reader.skip(layer.kernel_pool_type_cfg.bwsx_base_addr);
-                        delete layer.kernel_pool_type_cfg.bwsx_base_addr;
-                        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.skip(layer.kernel_calc_type_cfg.active_addr);
-                        delete layer.kernel_calc_type_cfg.active_addr;
-                        const activation = reader.kpu_activate_table_t();
-                        activation.type = { name: 'activation', category: 'Activation' };
-                        layer.chain.push(activation);
-                        reader.skip(layer.kernel_load_cfg.para_start_addr);
-                        delete layer.kernel_load_cfg.para_start_addr;
-                        const weights = reader.span('uint8', weights_shape);
-                        if (weights) {
-                            layer.inputs.push({ name: 'weights', value: [ weights ] });
-                        }
+                    delete layer.offset;
+                    delete layer.body_size;
+                    delete layer.opcode;
+                }
+                for (const input of inputs) {
+                    layers.unshift({
+                        type: { name: 'INPUT' },
+                        outputs: [ input ]
                     });
-                    /* eslint-enable space-in-parens */
-                    for (const layer of layers) {
-                        const type = types.get(layer.opcode);
-                        if (!type) {
-                            throw new kmodel.Error(`Unsupported version '${this.version}' layer type '${layer.type}'.`);
-                        }
-                        if (!type.callback) {
-                            throw new kmodel.Error(`Unsupported version '${this.version}' layer '${type.type.name}'.`);
-                        }
-                        layer.type = type.type;
-                        reader.seek(layer.offset);
-                        if (type.callback) {
-                            type.callback(layer, reader, layer.body_size);
-                        }
-                        delete layer.offset;
-                        delete layer.body_size;
-                        delete layer.opcode;
-                    }
-                    for (const input of inputs) {
-                        layers.unshift({
-                            type: { name: 'INPUT' },
-                            outputs: [ input ]
-                        });
-                    }
-                    for (const output of outputs) {
-                        layers.push({
-                            type: { name: 'OUTPUT' },
-                            inputs: [ output ]
-                        });
-                    }
-                    this.modules.push({
-                        name: '',
-                        layers: layers
+                }
+                for (const output of outputs) {
+                    layers.push({
+                        type: { name: 'OUTPUT' },
+                        inputs: [ output ]
                     });
-                    break;
                 }
-                case 5: {
-                    const reader = new kmodel.BinaryReader.v5(this.stream);
-                    const model_header = reader.model_header();
-                    if (model_header.header_size < 32) {
-                        throw new kmodel.Error(`Invalid header size '${model_header.header_size}'.`);
+                this.modules.push({
+                    name: '',
+                    layers: layers
+                });
+                break;
+            }
+            case 5: {
+                const reader = new kmodel.BinaryReader.v5(this.stream);
+                const model_header = reader.model_header();
+                if (model_header.header_size < 32) {
+                    throw new kmodel.Error(`Invalid header size '${model_header.header_size}'.`);
+                }
+                if (model_header.header_size > reader.position) {
+                    reader.skip(model_header.header_size - reader.position);
+                }
+                delete model_header.header_size;
+                this.modules = new Array(model_header.modules);
+                for (let i = 0; i < this.modules.length; i++) {
+                    const start = reader.position;
+                    const module_header = reader.module_header();
+                    if (module_header.header_size > (reader.position - start)) {
+                        reader.skip(module_header.header_size - (reader.position - start));
                     }
-                    if (model_header.header_size > reader.position) {
-                        reader.skip(model_header.header_size - reader.position);
+                    const mempools = new Array(module_header.mempools);
+                    for (let i = 0; i < mempools.length; i++) {
+                        mempools[i] = reader.mempool_desc();
                     }
-                    delete model_header.header_size;
-                    this.modules = new Array(model_header.modules);
-                    for (let i = 0; i < this.modules.length; i++) {
-                        const start = reader.position;
-                        const module_header = reader.module_header();
-                        if (module_header.header_size > (reader.position - start)) {
-                            reader.skip(module_header.header_size - (reader.position - start));
+                    const shared_mempools = new Array(module_header.shared_mempools);
+                    for (let i = 0; i < shared_mempools.length; i++) {
+                        shared_mempools[i] = reader.mempool_desc();
+                    }
+                    const function_headers = new Array(module_header.functions);
+                    const functions = new Array(module_header.functions);
+                    for (let i = 0; i < functions.length; i++) {
+                        const position = reader.position;
+                        const function_header = reader.function_header();
+                        const header_size = reader.position - position;
+                        if (function_header.header_size > header_size) {
+                            reader.skip(function_header.header_size - header_size);
                         }
-                        const mempools = new Array(module_header.mempools);
-                        for (let i = 0; i < mempools.length; i++) {
-                            mempools[i] = reader.mempool_desc();
+                        const inputs = new Array(function_header.inputs);
+                        for (let i = 0; i < inputs.length; i++) {
+                            inputs[i] = reader.parameter(`input${i == 0 ? '' : (i + 1)}`);
                         }
-                        const shared_mempools = new Array(module_header.shared_mempools);
-                        for (let i = 0; i < shared_mempools.length; i++) {
-                            shared_mempools[i] = reader.mempool_desc();
+                        for (let i = 0; i < inputs.length; i++) {
+                            inputs[i].value[0].shape = reader.shape();
                         }
-                        const function_headers = new Array(module_header.functions);
-                        const functions = new Array(module_header.functions);
-                        for (let i = 0; i < functions.length; i++) {
-                            const position = reader.position;
-                            const function_header = reader.function_header();
-                            const header_size = reader.position - position;
-                            if (function_header.header_size > header_size) {
-                                reader.skip(function_header.header_size - header_size);
-                            }
-                            const inputs = new Array(function_header.inputs);
-                            for (let i = 0; i < inputs.length; i++) {
-                                inputs[i] = reader.parameter(`input${i == 0 ? '' : (i + 1)}`);
-                            }
-                            for (let i = 0; i < inputs.length; i++) {
-                                inputs[i].value[0].shape = reader.shape();
-                            }
-                            const outputs = new Array(function_header.outputs);
-                            for (let i = 0; i < outputs.length; i++) {
-                                outputs[i] = reader.parameter(`output${i == 0 ? '' : (i + 1)}`);
-                            }
-                            for (let i = 0; i < outputs.length; i++) {
-                                outputs[i].value[0].shape = reader.shape();
-                            }
-                            reader.align_position(8);
-                            const size = reader.size - position;
-                            if (function_header.size > size) {
-                                reader.skip(function_header.size - size);
-                            }
-                            function_headers[i] = function_header;
-                            functions[i] = {
-                                type: { name: 'Unknown' },
-                                inputs: inputs,
-                                outputs: outputs
-                            };
+                        const outputs = new Array(function_header.outputs);
+                        for (let i = 0; i < outputs.length; i++) {
+                            outputs[i] = reader.parameter(`output${i == 0 ? '' : (i + 1)}`);
                         }
-                        const sections = new Map();
-                        for (let i = 0; i < module_header.sections; i++) {
-                            const section_header = reader.section_header();
-                            reader.skip(section_header.body_start);
-                            const body = reader.read(section_header.body_size);
-                            const section = {
-                                reader: new base.BinaryReader(body),
-                                flags: section_header.flags
-                            };
-                            reader.align_position(8);
-                            sections.set(section_header.name, section);
+                        for (let i = 0; i < outputs.length; i++) {
+                            outputs[i].value[0].shape = reader.shape();
                         }
-                        for (let i = 0; i < function_headers.length; i++) {
-                            const function_header = function_headers[i];
-                            const reader = sections.get('.text').reader;
-                            reader.seek(function_header.entrypoint);
-                            function_header.text = reader.read(function_header.text_size);
-                            const layer = functions[i];
-                            switch (module_header.type) {
-                                case 'stackvm':
-                                    layer.type = { name: 'stackvm' };
-                                    break;
-                                case 'k210':
-                                    break;
-                                case 'k510':
-                                    break;
-                                default:
-                                    throw new kmodel.Error(`Unsupported module type '${module_header.type}'.`);
-                            }
+                        reader.align_position(8);
+                        const size = reader.size - position;
+                        if (function_header.size > size) {
+                            reader.skip(function_header.size - size);
                         }
-                        const name = this.modules.length > 1 ? i.toString() : '';
-                        this.modules[i] = {
-                            name: name,
-                            type: module_header.type,
-                            layers: functions
+                        function_headers[i] = function_header;
+                        functions[i] = {
+                            type: { name: 'Unknown' },
+                            inputs: inputs,
+                            outputs: outputs
                         };
                     }
-                    break;
-                }
-                default: {
-                    throw new kmodel.Error(`Unsupported model version '${this.version}'.`);
+                    const sections = new Map();
+                    for (let i = 0; i < module_header.sections; i++) {
+                        const section_header = reader.section_header();
+                        reader.skip(section_header.body_start);
+                        const body = reader.read(section_header.body_size);
+                        const section = {
+                            reader: new base.BinaryReader(body),
+                            flags: section_header.flags
+                        };
+                        reader.align_position(8);
+                        sections.set(section_header.name, section);
+                    }
+                    for (let i = 0; i < function_headers.length; i++) {
+                        const function_header = function_headers[i];
+                        const reader = sections.get('.text').reader;
+                        reader.seek(function_header.entrypoint);
+                        function_header.text = reader.read(function_header.text_size);
+                        const layer = functions[i];
+                        switch (module_header.type) {
+                            case 'stackvm':
+                                layer.type = { name: 'stackvm' };
+                                break;
+                            case 'k210':
+                                break;
+                            case 'k510':
+                                break;
+                            default:
+                                throw new kmodel.Error(`Unsupported module type '${module_header.type}'.`);
+                        }
+                    }
+                    const name = this.modules.length > 1 ? i.toString() : '';
+                    this.modules[i] = {
+                        name: name,
+                        type: module_header.type,
+                        layers: functions
+                    };
                 }
+                break;
+            }
+            default: {
+                throw new kmodel.Error(`Unsupported model version '${this.version}'.`);
             }
-            delete this.stream;
         }
+        delete this.stream;
     }
 };
 

+ 2 - 5
source/mxnet.js

@@ -27,11 +27,8 @@ mxnet.ModelFactory = class {
         }
     }
 
-    filter(context, name) {
-        if (context.type === 'mxnet.json' && name === 'mxnet.params') {
-            return false;
-        }
-        return true;
+    filter(context, type) {
+        return context.type !== 'mxnet.json' || type !== 'mxnet.params';
     }
 
     async open(context) {

+ 2 - 5
source/ncnn.js

@@ -56,11 +56,8 @@ ncnn.ModelFactory = class {
         }
     }
 
-    filter(context, name) {
-        if ((context.type === 'ncnn.model' || context.type === 'ncnn.model.bin') && name === 'ncnn.weights') {
-            return false;
-        }
-        return true;
+    filter(context, type) {
+        return (context.type !== 'ncnn.model' && context.type !== 'ncnn.model.bin') || type !== 'ncnn.weights';
     }
 
     async open(context) {

+ 2 - 5
source/nnef.js

@@ -27,11 +27,8 @@ nnef.ModelFactory = class {
         }
     }
 
-    filter(context, name) {
-        if (context.type === 'nnef.graph' && name === 'nnef.dat') {
-            return false;
-        }
-        return true;
+    filter(context, type) {
+        return context.type !== 'nnef.graph' || type !== 'nnef.dat';
     }
 
     async open(context) {

+ 5 - 3
source/om.js

@@ -10,8 +10,11 @@ const svp = {};
 om.ModelFactory = class {
 
     match(context) {
-        context.target = om.Container.open(context);
-        context.type = context.target ? context.target.name : null;
+        const container = om.Container.open(context);
+        if (container) {
+            context.type = 'om';
+            context.target = container;
+        }
     }
 
     async open(context) {
@@ -349,7 +352,6 @@ om.Container = class {
     }
 
     constructor(context, signature) {
-        this.name = 'om';
         this._context = context;
         this._signature = signature;
     }

+ 2 - 5
source/openvino.js

@@ -46,11 +46,8 @@ openvino.ModelFactory = class {
         }
     }
 
-    filter(context, name) {
-        if (context.type === 'openvino.xml' && name === 'openvino.bin') {
-            return false;
-        }
-        return true;
+    filter(context, type) {
+        return context.type !== 'openvino.xml' || type !== 'openvino.bin';
     }
 
     async open(context) {

+ 55 - 60
source/paddle.js

@@ -50,14 +50,11 @@ paddle.ModelFactory = class {
         }
     }
 
-    filter(context, name) {
-        if (context.type === 'paddle.pb' && name === 'paddle.params') {
+    filter(context, type) {
+        if (context.type === 'paddle.pb' && (type === 'paddle.params' || type === 'paddle.pickle')) {
             return false;
         }
-        if (context.type === 'paddle.naive.model' && name === 'paddle.naive.param') {
-            return false;
-        }
-        if (context.type === 'paddle.pb' && name === 'paddle.pickle') {
+        if (context.type === 'paddle.naive.model' && type === 'paddle.naive.param') {
             return false;
         }
         return true;
@@ -701,64 +698,62 @@ paddle.NaiveBuffer = class {
     }
 
     read() {
-        if (this.stream) {
-            const reader = new base.BinaryReader(this.stream);
-            if (this.meta_version >= 2) {
-                reader.skip(2);
+        const reader = new base.BinaryReader(this.stream);
+        if (this.meta_version >= 2) {
+            reader.skip(2);
+        }
+        const decoder = new TextDecoder();
+        const opt_version = reader.read(16);
+        const version = decoder.decode(opt_version.slice(0, opt_version.indexOf(0x00)));
+        this.format = `Paddle Lite${version && version.match(/^v\d+\.\d+.\d+$/) ? ` ${version}` : ''}`;
+        const topo_size = reader.uint64();
+        const openProgramDesc = (buffer) => {
+            const reader = flatbuffers.BinaryReader.open(buffer);
+            return paddle.schema.ProgramDesc.create(reader);
+        };
+        const openParamDesc = (buffer) => {
+            const reader = flatbuffers.BinaryReader.open(buffer);
+            return paddle.schema.ParamDesc.create(reader);
+        };
+        switch (this.meta_version) {
+            case -1: {
+                throw new paddle.Error('Paddle Lite naive buffer format is deprecated.');
             }
-            delete this.stream;
-            const decoder = new TextDecoder();
-            const opt_version = reader.read(16);
-            const version = decoder.decode(opt_version.slice(0, opt_version.indexOf(0x00)));
-            this.format = `Paddle Lite${version && version.match(/^v\d+\.\d+.\d+$/) ? ` ${version}` : ''}`;
-            const topo_size = reader.uint64();
-            const openProgramDesc = (buffer) => {
-                const reader = flatbuffers.BinaryReader.open(buffer);
-                return paddle.schema.ProgramDesc.create(reader);
-            };
-            const openParamDesc = (buffer) => {
-                const reader = flatbuffers.BinaryReader.open(buffer);
-                return paddle.schema.ParamDesc.create(reader);
-            };
-            switch (this.meta_version) {
-                case -1: {
-                    throw new paddle.Error('Paddle Lite naive buffer format is deprecated.');
-                }
-                case 0:
-                case 1: {
-                    throw new paddle.Error(`Paddle Lite meta format '${this.meta_version}' is deprecated.`);
-                }
-                case 2: {
-                    const topo_data = new Uint8Array(topo_size);
-                    topo_data.set(reader.read(topo_size), 0);
-                    this.model = openProgramDesc(topo_data);
-                    reader.uint16(); // version
-                    reader.uint16(); // meta_size
-                    const header_size = reader.uint16();
-                    const params_size = reader.uint16();
-                    reader.uint32(); // max_tensor_size
-                    reader.skip(header_size - 6);
-                    this.weights = new Map();
-                    for (let i = 0; i < params_size; i++) {
-                        const total_size = reader.uint32();
-                        const offset = reader.uint32();
-                        const param_bytes = total_size - offset;
-                        const param_data = reader.read(param_bytes);
-                        const desc = openParamDesc(param_data);
-                        const data = desc.variable.data;
-                        const data_type = desc.variable.data_type;
-                        const dim = desc.variable.dim;
-                        const type = paddle.Utility.createTensorType(data_type, dim);
-                        const tensor = new paddle.Tensor(type, data);
-                        this.weights.set(desc.name, tensor);
-                    }
-                    break;
-                }
-                default: {
-                    throw new paddle.Error(`Unsupported Paddle Lite naive buffer meta format '${this.meta_version}'.`);
+            case 0:
+            case 1: {
+                throw new paddle.Error(`Paddle Lite meta format '${this.meta_version}' is deprecated.`);
+            }
+            case 2: {
+                const topo_data = new Uint8Array(topo_size);
+                topo_data.set(reader.read(topo_size), 0);
+                this.model = openProgramDesc(topo_data);
+                reader.uint16(); // version
+                reader.uint16(); // meta_size
+                const header_size = reader.uint16();
+                const params_size = reader.uint16();
+                reader.uint32(); // max_tensor_size
+                reader.skip(header_size - 6);
+                this.weights = new Map();
+                for (let i = 0; i < params_size; i++) {
+                    const total_size = reader.uint32();
+                    const offset = reader.uint32();
+                    const param_bytes = total_size - offset;
+                    const param_data = reader.read(param_bytes);
+                    const desc = openParamDesc(param_data);
+                    const data = desc.variable.data;
+                    const data_type = desc.variable.data_type;
+                    const dim = desc.variable.dim;
+                    const type = paddle.Utility.createTensorType(data_type, dim);
+                    const tensor = new paddle.Tensor(type, data);
+                    this.weights.set(desc.name, tensor);
                 }
+                break;
+            }
+            default: {
+                throw new paddle.Error(`Unsupported Paddle Lite naive buffer meta format '${this.meta_version}'.`);
             }
         }
+        delete this.stream;
     }
 };
 

+ 40 - 40
source/pytorch.js

@@ -10,18 +10,15 @@ const pytorch = {};
 pytorch.ModelFactory = class {
 
     match(context) {
-        context.target = pytorch.Container.open(context);
-        context.type = context.target ? context.target.name : null;
+        const container = pytorch.Container.open(context);
+        if (container) {
+            context.type = container.type;
+            context.target = container;
+        }
     }
 
-    filter(context, name) {
-        if (context.type === 'pytorch.export' && name === 'pytorch.zip') {
-            return false;
-        }
-        if (context.type === 'pytorch.index' && name === 'pytorch.zip') {
-            return false;
-        }
-        return true;
+    filter(context, type) {
+        return (context.type !== 'pytorch.export' && context.type !== 'pytorch.index') || type !== 'pytorch.zip';
     }
 
     async open(context) {
@@ -800,7 +797,7 @@ pytorch.Container.Tar = class extends pytorch.Container {
 
     constructor(entries) {
         super();
-        this.name = 'pytorch.tar';
+        this.type = 'pytorch.tar';
         this.entries = entries;
     }
 
@@ -840,7 +837,7 @@ pytorch.Container.Pickle = class extends pytorch.Container {
 
     constructor(stream) {
         super();
-        this.name = 'pytorch.pickle';
+        this.type = 'pytorch.pickle';
         this.stream = stream;
     }
 
@@ -902,7 +899,7 @@ pytorch.Container.data_pkl = class extends pytorch.Container {
 
     constructor(type, data) {
         super();
-        this.name = 'pytorch.data_pkl';
+        this.type = 'pytorch.data_pkl';
         this._type = type;
         this._data = data;
     }
@@ -968,13 +965,13 @@ pytorch.Container.torch_utils = class extends pytorch.Container {
 
     constructor(obj) {
         super();
-        this.name = 'pytorch.torch_utils';
-        this._obj = obj;
+        this.type = 'pytorch.torch_utils';
+        this.obj = obj;
     }
 
     async read() {
-        this._modules = pytorch.Utility.find(this._obj);
-        delete this._obj;
+        this._modules = pytorch.Utility.find(this.obj);
+        delete this.obj;
     }
 
     get format() {
@@ -998,18 +995,18 @@ pytorch.Container.Mobile = class extends pytorch.Container {
 
     constructor(context) {
         super();
-        this.name = 'pytorch.mobile';
-        this._context = context;
+        this.type = 'pytorch.mobile';
+        this.context = context;
     }
 
     async read(metadata) {
-        await this._context.require('./pytorch-schema');
+        await this.context.require('./pytorch-schema');
         this._modules = new Map();
         const execution = new pytorch.jit.Execution(null, metadata);
         for (const event in this._events) {
             execution.on(event[0], event[1]);
         }
-        const stream = this._context.stream;
+        const stream = this.context.stream;
         const torch = execution.__import__('torch');
         const module = torch.jit.jit_module_from_flatbuffer(stream);
         const version = module._c._bytecode_version.toString();
@@ -1019,7 +1016,7 @@ pytorch.Container.Mobile = class extends pytorch.Container {
         } else {
             this._modules = pytorch.Utility.find(module);
         }
-        delete this._context;
+        delete this.context;
     }
 
     get format() {
@@ -1043,14 +1040,14 @@ pytorch.Container.ExecuTorch = class extends pytorch.Container {
 
     constructor(context) {
         super();
-        this.name = 'pytorch.executorch';
-        this._context = context;
+        this.type = 'pytorch.executorch';
+        this.context = context;
     }
 
     async read() {
-        await this._context.require('./pytorch-schema');
+        await this.context.require('./pytorch-schema');
         pytorch.executorch = flatbuffers.get('torch').executorch_flatbuffer;
-        const stream = this._context.stream;
+        const stream = this.context.stream;
         const reader = flatbuffers.BinaryReader.open(stream);
         /* const program = */ pytorch.executorch.Program.create(reader);
         throw new pytorch.Error('Invalid file content. File contains executorch.Program data.');
@@ -1100,7 +1097,7 @@ pytorch.Container.Zip = class extends pytorch.Container {
 
     constructor(entries, model) {
         super();
-        this.name = 'pytorch.zip';
+        this.type = 'pytorch.zip';
         // https://github.com/pytorch/pytorch/blob/master/torch/csrc/jit/docs/serialization.md
         this._entries = entries;
         this._model = model;
@@ -1167,8 +1164,8 @@ pytorch.Container.Index = class extends pytorch.Container {
 
     constructor(context, entries) {
         super();
-        this.name = 'pytorch.index';
-        this._context = context;
+        this.type = 'pytorch.index';
+        this.context = context;
         this._entries = entries;
         this._format = 'PyTorch';
     }
@@ -1177,7 +1174,7 @@ pytorch.Container.Index = class extends pytorch.Container {
         const weight_map = new Map(this._entries);
         const keys = new Set(weight_map.keys());
         const files = Array.from(new Set(weight_map.values()));
-        const contexts = await Promise.all(files.map((name) => this._context.fetch(name)));
+        const contexts = await Promise.all(files.map((name) => this.context.fetch(name)));
         const execution = new pytorch.jit.Execution(null, metadata);
         for (const event of this._events) {
             execution.on(event[0], event[1]);
@@ -1206,7 +1203,7 @@ pytorch.Container.Index = class extends pytorch.Container {
             }
         }
         this._modules = pytorch.Utility.findWeights(entries);
-        delete this._context;
+        delete this.context;
         delete this._entries;
     }
 
@@ -1231,9 +1228,9 @@ pytorch.Container.ExportedProgram = class extends pytorch.Container {
 
     constructor(context, serialized_exported_program) {
         super();
-        this.name = 'pytorch.export';
-        this._context = context;
-        this._serialized_exported_program = serialized_exported_program;
+        this.type = 'pytorch.export';
+        this.context = context;
+        this.serialized_exported_program = serialized_exported_program;
     }
 
     async read() {
@@ -1241,7 +1238,7 @@ pytorch.Container.ExportedProgram = class extends pytorch.Container {
         const serialized_state_dict = await this._fetch('serialized_state_dict.pt') || await this._fetch('serialized_state_dict.json');
         const serialized_constants = await this._fetch('serialized_constants.pt') || await this._fetch('serialized_constants.json');
         const f = new Map();
-        f.set('serialized_exported_program.json', this._serialized_exported_program);
+        f.set('serialized_exported_program.json', this.serialized_exported_program);
         f.set('serialized_state_dict.pt', serialized_state_dict);
         f.set('serialized_constants.pt', serialized_constants);
         const execution = new pytorch.Execution();
@@ -1249,9 +1246,9 @@ pytorch.Container.ExportedProgram = class extends pytorch.Container {
             execution.on(event[0], event[1]);
         }
         const torch = execution.__import__('torch');
-        if (this._serialized_exported_program.graph_module.graph.constants) {
+        if (this.serialized_exported_program.graph_module.graph.constants) {
             const zip = await import('./zip.js');
-            const constants = this._serialized_exported_program.graph_module.graph.constants;
+            const constants = this.serialized_exported_program.graph_module.graph.constants;
             for (const key of Object.keys(constants)) {
                 const value = constants[key];
                 const str = atob(value);
@@ -1263,6 +1260,8 @@ pytorch.Container.ExportedProgram = class extends pytorch.Container {
                 constants[key] = archive.entries;
             }
         }
+        delete this.serialized_exported_program;
+        delete this.context;
         /* const exported_program = */ torch._export.load(f);
         throw new pytorch.Error(`'torch.export' not supported.`);
     }
@@ -3308,8 +3307,8 @@ pytorch.Container.Package = class extends pytorch.Container {
 
     constructor(entries) {
         super();
-        this.name = 'pytorch.package';
-        this._entries = entries;
+        this.type = 'pytorch.package';
+        this.entries = entries;
     }
 
     async read() {
@@ -3318,7 +3317,7 @@ pytorch.Container.Package = class extends pytorch.Container {
             execution.on(event[0], event[1]);
         }
         const torch = execution.__import__('torch');
-        const reader = new torch.PyTorchFileReader(this._entries);
+        const reader = new torch.PyTorchFileReader(this.entries);
         const version = reader.version();
         this._format = pytorch.Utility.format('PyTorch Package', version);
         this._modules = new Map();
@@ -3355,6 +3354,7 @@ pytorch.Container.Package = class extends pytorch.Container {
                 this._modules.set(key, module);
             }
         }
+        delete this.entries;
     }
 
     get format() {

+ 8 - 6
source/rknn.js

@@ -9,8 +9,11 @@ const openvx = {};
 rknn.ModelFactory = class {
 
     match(context) {
-        context.target = rknn.Container.open(context);
-        context.type = context.target ? context.target.name : null;
+        const container = rknn.Container.open(context);
+        if (container) {
+            context.type = 'rknn';
+            context.target = container;
+        }
     }
 
     async open(context) {
@@ -524,14 +527,12 @@ rknn.Container = class extends Map {
 
     constructor(stream, entries) {
         super(entries);
-        this.name = 'rknn';
         this.stream = stream;
     }
 
     read() {
-        if (this.stream) {
-            const stream = this.stream;
-            delete this.stream;
+        const stream = this.stream;
+        if (stream) {
             const signature = rknn.Container.signature(stream);
             switch (signature) {
                 case 'rknn': {
@@ -584,6 +585,7 @@ rknn.Container = class extends Map {
                     break;
                 }
             }
+            delete this.stream;
         }
     }
 

+ 274 - 274
source/tengine.js

@@ -8,8 +8,11 @@ const tengine = {};
 tengine.ModelFactory = class {
 
     match(context) {
-        context.target = tengine.Reader.open(context.stream);
-        context.type = context.target ? context.target.name : null;
+        const reader = tengine.Reader.open(context.stream);
+        if (reader) {
+            context.type = 'tengine';
+            context.target = reader;
+        }
     }
 
     async open(context) {
@@ -251,296 +254,293 @@ tengine.Reader = class {
     }
 
     constructor(stream) {
-        this.name = 'tengine';
         this.stream = stream;
         // https://github.com/OAID/Tengine/wiki/The-format-of-tmfile
         // https://github.com/OAID/Tengine/blob/tengine-lite/source/serializer/tmfile/tm2_format.h
     }
 
     read() {
-        if (this.stream) {
-            const types = new Map();
-            const register = (index, version, name, params) => {
-                types.set(`${index}:${version}`, { name: name, params: params });
-            };
-            const operator = (index, version) => {
-                let current = version;
-                while (current >= 0) {
-                    if (types.has(`${index}:${current}`)) {
-                        break;
-                    }
-                    current--;
-                }
-                if (current >= 0) {
-                    const schema = types.get(`${index}:${current}`);
-                    if (current !== version) {
-                        types.set(`${index}:${version}`, schema);
-                    }
-                    return schema;
+        const types = new Map();
+        const register = (index, version, name, params) => {
+            types.set(`${index}:${version}`, { name: name, params: params });
+        };
+        const operator = (index, version) => {
+            let current = version;
+            while (current >= 0) {
+                if (types.has(`${index}:${current}`)) {
+                    break;
                 }
-                return null;
-            };
-            register(0, 0, 'Accuracy', []);
-            register(1, 0, 'BatchNormalization', [ 'f', 'f', 'i' ]);
-            register(2, 0, 'BilinearResize', [ 'f', 'f', 'i' ]);
-            register(3, 0, 'Concat', [ 'i' ]);
-            register(4, 0, 'Const', []);
-            register(5, 0, 'Convolution', [ 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i' ]);
-            register(6, 0, 'Deconvolution', [ 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i' ]);
-            register(7, 0, 'DetectionOutput', [ 'i', 'i', 'i', 'f', 'f' ]);
-            register(8, 0, 'DropOut', []);
-            register(9, 0, 'Eltwise', [ 'i', 'i' ]);
-            register(10, 0, 'Flatten', [ 'i' ]);
-            register(11, 0, 'FullyConnected', [ 'i' ]);
-            register(12, 0, 'INPUT', []);
-            register(13, 0, 'LRN', [ 'i', 'f', 'f', 'i', 'f' ]);
-            register(14, 0, 'Normalize', [ 'i', 'i' ]);
-            register(15, 0, 'Permute', [ 'i', 'i', 'i', 'i', 'i' ]);
-            register(16, 0, 'Pooling', [ 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i' ]);
-            register(17, 0, 'Prelu', []);
-            register(18, 0, 'PriorBox', [ 'f[]', 'f[]', 'f[]', 'f[]', 'i', 'i', 'i', 'i', 'i', 'f', 'f', 'f', 'i', 'i' ]);
-            register(19, 0, 'Region', [ 'i', 'i', 'i', 'i', 'f', 'f', 'f[]' ]);
-            register(20, 0, 'ReLU', [ 'f' ]);
-            register(21, 0, 'ReLU6', []);
-            register(22, 0, 'Reorg', [ 'i' ]);
-            register(23, 0, 'Reshape', [ 'i', 'i', 'i', 'i', 'i', 'i' ]);
-            // register(23, 0, 'Reshape', [ 'i', 'i', 'i[]' ]);
-            register(24, 0, 'RoiPooling', [ 'i', 'i', 'f' ]);
-            register(25, 0, 'RPN', [ 'f[]', 'f[]', 'i', 'i', 'i', 'i', 'i', 'f', 'anchors' ]);
-            register(26, 0, 'Scale', [ 'i', 'i', 'i' ]);
-            register(27, 0, 'Slice', [ 'i', 'i[]', 'i[]', 'i[]', 'i', 'i', 'i', 'i', 'i' ]);
-            register(28, 0, 'SoftMax', [ 'i' ]);
-            register(29, 0, 'Split', [ 'i', 'i', 'boolean', 'boolean', 'i[]' ]);
-            register(30, 0, 'DetectionPostProcess', [ 'i', 'i', 'f', 'f', 'i', 'f[]' ]);
-            register(31, 0, 'Gemm', [ 'f', 'f', 'i', 'i' ]);
-            register(32, 0, 'Generic', [ 'i', 'i', 'string' ]);
-            register(33, 0, 'Logistic', []);
-            register(34, 0, 'LSTM', [ 'f', 'f', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i' ]);
-            register(35, 0, 'RNN', [ 'f', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i' ]);
-            register(36, 0, 'TanH', []);
-            register(37, 0, 'Sigmoid', []);
-            register(38, 0, 'Squeeze', [ 'i', 'i', 'i', 'i' ]);
-            register(39, 0, 'FusedbnScaleRelu', []);
-            register(40, 0, 'Pad', [ 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'f' ]);
-            register(41, 0, 'StridedSlice', [ 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i' ]);
-            register(42, 0, 'ArgMax', [ 'i' ]);
-            register(43, 0, 'ArgMin', [ 'i' ]);
-            register(44, 0, 'TopKV2', [ 'i', 'i' ]);
-            register(45, 0, 'Reduction', [ 'i', 'i', 'i', 'i', 'i', 'i' ]);
-            register(46, 0, 'Max', []);
-            register(47, 0, 'Min', []);
-            register(48, 0, 'GRU', [ 'f', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i' ]);
-            register(49, 0, 'Addn', 'i');
-            register(50, 0, 'SwapAxis', [ 'i', 'i' ]);
-            register(51, 0, 'Upsample', [ 'f' ]);
-            register(52, 0, 'SpaceToBatchND', [ 'i', 'i', 'i', 'i', 'i', 'i' ]);
-            register(53, 0, 'BatchToSpaceND', [ 'i', 'i', 'i', 'i', 'i', 'i' ]);
-            register(54, 0, 'Resize', [ 'f', 'f', 'i' ]);
-            register(55, 0, 'ShuffleChannel', [ 'i' ]);
-            register(56, 0, 'Crop', [ 'i', 'i', 'i', 'i', 'i', 'i', 'boolean', 'i', 'i' ]);
-            register(57, 0, 'ROIAlign', [ 'i', 'i', 'f' ]);
-            register(58, 0, 'Psroipooling', [ 'i', 'i', 'f', 'i' ]);
-            register(59, 0, 'Unary', [ 'i' ]);
-            register(60, 0, 'Expanddims', [ 'i' ]);
-            register(61, 0, 'Bias', [ 'i' ]);
-            register(62, 0, 'Noop', []);
-            register(63, 0, 'Threshold', [ 'f' ]);
-            register(64, 0, 'Hardsigmoid', [ 'f', 'f' ]);
-            register(65, 0, 'Embed', [ 'f', 'f', 'f', 'f' ]);
-            register(66, 0, 'InstanceNorm', [ 'f' ]);
-            register(67, 0, 'MVN', [ 'i', 'i', 'f' ]);
-            register(68, 0, 'Absval', []);
-            register(69, 0, 'Cast', [ 'i', 'i' ]);
-            register(70, 0, 'HardSwish', [ 'f', 'f' ]);
-            register(71, 0, 'Interp', [ 'i', 'f', 'f', 'i', 'i' ]);
-            register(72, 0, 'SELU', [ 'f', 'f' ]);
-            register(73, 0, 'ELU', [ 'f' ]);
-            register(74, 0, 'BroadMul', []);
-            register(75, 0, 'Logical', [ 'i' ]);
-            register(76, 0, 'Gather', [ 'i', 'i' ]);
-            register(77, 0, 'Transpose', [ 'i[]' ]);
-            register(78, 0, 'Comparison', [ 'i' ]);
-            register(79, 0, 'SpaceToDepth', [ 'i' ]);
-            register(80, 0, 'DepthToSpace', [ 'i' ]);
-            register(81, 0, 'Reverse', []);
-            register(82, 0, 'SparseToDense', [ 'i','i','i' ]);
-            register(83, 0, 'Ceil', []);
-            register(84, 0, 'SquaredDifference', []);
-            register(85, 0, 'Round', []);
-            register(86, 0, 'ZerosLike', []);
-            register(87, 0, 'Clip', [ 'f','f' ]);
-            register(88, 0, 'Unsqueeze', [ 'i[]' ]);
-            register(89, 0, 'ReduceL2', [ 'i','i' ]);
-            register(90, 0, 'Mean', []);
-            register(91, 0, 'MatMul', []);
-            register(92, 0, 'Expand', ['i[]']);
-            register(93, 0, 'Scatter', ['i','boolean']);
-            register(94, 0, 'Shape', []);
-            register(95, 0, 'Where', []);
-            register(96, 0, 'Tile', ['i','i']);
-            register(97, 0, 'Mish', []);
-            register(98, 0, 'L2Pool', []);
-            register(99, 0, 'LogSoftmax', []);
-            register(100, 0, 'ReLU1', []);
-            register(101, 0, 'L2Normalization', []);
-            register(102, 0, 'PackModel', ['i','i']);
-            register(103, 0, 'Num', []);
-            const buffer = this.stream.peek();
-            const reader = new tengine.BinaryReader(buffer);
-            this._majorVersion = reader.uint16();
-            this._minorVersion = reader.uint16();
-            if (this._majorVersion !== 2) {
-                throw new tengine.Error(`Unsupported format version 'v${this._majorVersion}.${this._minorVersion}'.`);
+                current--;
             }
-            this._compileVersion = reader.uint16();
-            reader.skip(2); // struct align
-            reader.seek(reader.uint32()); // root table
-            this._originalFormat = reader.int32();
-            this._subFormat = reader.int32();
-            this.graphs = [];
-            const subgraphOffsets = reader.uint32s();
-            for (const subgraphOffset of subgraphOffsets) {
-                reader.seek(subgraphOffset);
-
-                const subgraph = {};
-                subgraph.id = reader.int32();
-                subgraph.graphLayout = reader.int32();
-                /*
-                if (graphLayout == 0) {
-                    return "NCHW";
+            if (current >= 0) {
+                const schema = types.get(`${index}:${current}`);
+                if (current !== version) {
+                    types.set(`${index}:${version}`, schema);
                 }
-                if (graphLayout == 1) {
-                    return "NHWC";
-                }
-                */
-                subgraph.originalLayout = reader.int32();
-                subgraph.inputs = reader.uint32s();
-                subgraph.outputs = reader.uint32s();
-                const nodeOffsets = reader.uint32s();
-                const tensorOffsets = reader.uint32s();
-                const bufferOffsets = reader.uint32s();
-                subgraph.name = reader.string();
-                subgraph.nodes = [];
-                subgraph.tensors = [];
-                this.graphs.push(subgraph);
-                // nodes
-                for (const nodeOffset of nodeOffsets) {
-                    reader.seek(nodeOffset);
-                    const node = {};
-                    node.id = reader.int32();
-                    node.inputs = reader.uint32s();
-                    node.outputs = reader.uint32s();
-                    const typeOffset = reader.int32();
-                    node.name = reader.string();
-                    const attributeOffsets = reader.uint32s();
-                    node.dynamicShape = reader.boolean();
-                    reader.seek(typeOffset);
-                    node.version = reader.int32();
-                    const index = reader.int32();
-                    const paramsOffset = reader.uint32();
-                    const schema = operator(index, node.version);
-                    node.type = schema ? schema.name : index.toString();
-                    const paramTypes = schema ? schema.params : [];
-                    node.params = [];
-                    if (paramsOffset) {
-                        reader.seek(paramsOffset);
-                        for (const paramType of paramTypes) {
-                            if (paramType !== 'boolean') {
-                                reader.align(4);
-                            }
-                            switch (paramType) {
-                                case 'i':
-                                    node.params.push(reader.int32());
-                                    break;
-                                case 'f':
-                                    node.params.push(reader.float32());
-                                    break;
-                                case 'i[]':
-                                    node.params.push(reader.int32s());
-                                    break;
-                                case 'f[]':
-                                    node.params.push(reader.float32s());
-                                    break;
-                                case 'boolean':
-                                    node.params.push(reader.boolean());
-                                    break;
-                                case 'string':
-                                    node.params.push(reader.string());
-                                    break;
-                                case 'anchors':
-                                    node.params.push(reader.anchors(4));
-                                    break;
-                                default:
-                                    throw new tengine.Error(`Unsupported param type '${paramType}' in '${node.type}'.`);
-                            }
+                return schema;
+            }
+            return null;
+        };
+        register(0, 0, 'Accuracy', []);
+        register(1, 0, 'BatchNormalization', [ 'f', 'f', 'i' ]);
+        register(2, 0, 'BilinearResize', [ 'f', 'f', 'i' ]);
+        register(3, 0, 'Concat', [ 'i' ]);
+        register(4, 0, 'Const', []);
+        register(5, 0, 'Convolution', [ 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i' ]);
+        register(6, 0, 'Deconvolution', [ 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i' ]);
+        register(7, 0, 'DetectionOutput', [ 'i', 'i', 'i', 'f', 'f' ]);
+        register(8, 0, 'DropOut', []);
+        register(9, 0, 'Eltwise', [ 'i', 'i' ]);
+        register(10, 0, 'Flatten', [ 'i' ]);
+        register(11, 0, 'FullyConnected', [ 'i' ]);
+        register(12, 0, 'INPUT', []);
+        register(13, 0, 'LRN', [ 'i', 'f', 'f', 'i', 'f' ]);
+        register(14, 0, 'Normalize', [ 'i', 'i' ]);
+        register(15, 0, 'Permute', [ 'i', 'i', 'i', 'i', 'i' ]);
+        register(16, 0, 'Pooling', [ 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i' ]);
+        register(17, 0, 'Prelu', []);
+        register(18, 0, 'PriorBox', [ 'f[]', 'f[]', 'f[]', 'f[]', 'i', 'i', 'i', 'i', 'i', 'f', 'f', 'f', 'i', 'i' ]);
+        register(19, 0, 'Region', [ 'i', 'i', 'i', 'i', 'f', 'f', 'f[]' ]);
+        register(20, 0, 'ReLU', [ 'f' ]);
+        register(21, 0, 'ReLU6', []);
+        register(22, 0, 'Reorg', [ 'i' ]);
+        register(23, 0, 'Reshape', [ 'i', 'i', 'i', 'i', 'i', 'i' ]);
+        // register(23, 0, 'Reshape', [ 'i', 'i', 'i[]' ]);
+        register(24, 0, 'RoiPooling', [ 'i', 'i', 'f' ]);
+        register(25, 0, 'RPN', [ 'f[]', 'f[]', 'i', 'i', 'i', 'i', 'i', 'f', 'anchors' ]);
+        register(26, 0, 'Scale', [ 'i', 'i', 'i' ]);
+        register(27, 0, 'Slice', [ 'i', 'i[]', 'i[]', 'i[]', 'i', 'i', 'i', 'i', 'i' ]);
+        register(28, 0, 'SoftMax', [ 'i' ]);
+        register(29, 0, 'Split', [ 'i', 'i', 'boolean', 'boolean', 'i[]' ]);
+        register(30, 0, 'DetectionPostProcess', [ 'i', 'i', 'f', 'f', 'i', 'f[]' ]);
+        register(31, 0, 'Gemm', [ 'f', 'f', 'i', 'i' ]);
+        register(32, 0, 'Generic', [ 'i', 'i', 'string' ]);
+        register(33, 0, 'Logistic', []);
+        register(34, 0, 'LSTM', [ 'f', 'f', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i' ]);
+        register(35, 0, 'RNN', [ 'f', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i' ]);
+        register(36, 0, 'TanH', []);
+        register(37, 0, 'Sigmoid', []);
+        register(38, 0, 'Squeeze', [ 'i', 'i', 'i', 'i' ]);
+        register(39, 0, 'FusedbnScaleRelu', []);
+        register(40, 0, 'Pad', [ 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'f' ]);
+        register(41, 0, 'StridedSlice', [ 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i' ]);
+        register(42, 0, 'ArgMax', [ 'i' ]);
+        register(43, 0, 'ArgMin', [ 'i' ]);
+        register(44, 0, 'TopKV2', [ 'i', 'i' ]);
+        register(45, 0, 'Reduction', [ 'i', 'i', 'i', 'i', 'i', 'i' ]);
+        register(46, 0, 'Max', []);
+        register(47, 0, 'Min', []);
+        register(48, 0, 'GRU', [ 'f', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i' ]);
+        register(49, 0, 'Addn', 'i');
+        register(50, 0, 'SwapAxis', [ 'i', 'i' ]);
+        register(51, 0, 'Upsample', [ 'f' ]);
+        register(52, 0, 'SpaceToBatchND', [ 'i', 'i', 'i', 'i', 'i', 'i' ]);
+        register(53, 0, 'BatchToSpaceND', [ 'i', 'i', 'i', 'i', 'i', 'i' ]);
+        register(54, 0, 'Resize', [ 'f', 'f', 'i' ]);
+        register(55, 0, 'ShuffleChannel', [ 'i' ]);
+        register(56, 0, 'Crop', [ 'i', 'i', 'i', 'i', 'i', 'i', 'boolean', 'i', 'i' ]);
+        register(57, 0, 'ROIAlign', [ 'i', 'i', 'f' ]);
+        register(58, 0, 'Psroipooling', [ 'i', 'i', 'f', 'i' ]);
+        register(59, 0, 'Unary', [ 'i' ]);
+        register(60, 0, 'Expanddims', [ 'i' ]);
+        register(61, 0, 'Bias', [ 'i' ]);
+        register(62, 0, 'Noop', []);
+        register(63, 0, 'Threshold', [ 'f' ]);
+        register(64, 0, 'Hardsigmoid', [ 'f', 'f' ]);
+        register(65, 0, 'Embed', [ 'f', 'f', 'f', 'f' ]);
+        register(66, 0, 'InstanceNorm', [ 'f' ]);
+        register(67, 0, 'MVN', [ 'i', 'i', 'f' ]);
+        register(68, 0, 'Absval', []);
+        register(69, 0, 'Cast', [ 'i', 'i' ]);
+        register(70, 0, 'HardSwish', [ 'f', 'f' ]);
+        register(71, 0, 'Interp', [ 'i', 'f', 'f', 'i', 'i' ]);
+        register(72, 0, 'SELU', [ 'f', 'f' ]);
+        register(73, 0, 'ELU', [ 'f' ]);
+        register(74, 0, 'BroadMul', []);
+        register(75, 0, 'Logical', [ 'i' ]);
+        register(76, 0, 'Gather', [ 'i', 'i' ]);
+        register(77, 0, 'Transpose', [ 'i[]' ]);
+        register(78, 0, 'Comparison', [ 'i' ]);
+        register(79, 0, 'SpaceToDepth', [ 'i' ]);
+        register(80, 0, 'DepthToSpace', [ 'i' ]);
+        register(81, 0, 'Reverse', []);
+        register(82, 0, 'SparseToDense', [ 'i','i','i' ]);
+        register(83, 0, 'Ceil', []);
+        register(84, 0, 'SquaredDifference', []);
+        register(85, 0, 'Round', []);
+        register(86, 0, 'ZerosLike', []);
+        register(87, 0, 'Clip', [ 'f','f' ]);
+        register(88, 0, 'Unsqueeze', [ 'i[]' ]);
+        register(89, 0, 'ReduceL2', [ 'i','i' ]);
+        register(90, 0, 'Mean', []);
+        register(91, 0, 'MatMul', []);
+        register(92, 0, 'Expand', ['i[]']);
+        register(93, 0, 'Scatter', ['i','boolean']);
+        register(94, 0, 'Shape', []);
+        register(95, 0, 'Where', []);
+        register(96, 0, 'Tile', ['i','i']);
+        register(97, 0, 'Mish', []);
+        register(98, 0, 'L2Pool', []);
+        register(99, 0, 'LogSoftmax', []);
+        register(100, 0, 'ReLU1', []);
+        register(101, 0, 'L2Normalization', []);
+        register(102, 0, 'PackModel', ['i','i']);
+        register(103, 0, 'Num', []);
+        const buffer = this.stream.peek();
+        const reader = new tengine.BinaryReader(buffer);
+        this._majorVersion = reader.uint16();
+        this._minorVersion = reader.uint16();
+        if (this._majorVersion !== 2) {
+            throw new tengine.Error(`Unsupported format version 'v${this._majorVersion}.${this._minorVersion}'.`);
+        }
+        this._compileVersion = reader.uint16();
+        reader.skip(2); // struct align
+        reader.seek(reader.uint32()); // root table
+        this._originalFormat = reader.int32();
+        this._subFormat = reader.int32();
+        this.graphs = [];
+        const subgraphOffsets = reader.uint32s();
+        for (const subgraphOffset of subgraphOffsets) {
+            reader.seek(subgraphOffset);
+
+            const subgraph = {};
+            subgraph.id = reader.int32();
+            subgraph.graphLayout = reader.int32();
+            /*
+            if (graphLayout == 0) {
+                return "NCHW";
+            }
+            if (graphLayout == 1) {
+                return "NHWC";
+            }
+            */
+            subgraph.originalLayout = reader.int32();
+            subgraph.inputs = reader.uint32s();
+            subgraph.outputs = reader.uint32s();
+            const nodeOffsets = reader.uint32s();
+            const tensorOffsets = reader.uint32s();
+            const bufferOffsets = reader.uint32s();
+            subgraph.name = reader.string();
+            subgraph.nodes = [];
+            subgraph.tensors = [];
+            this.graphs.push(subgraph);
+            // nodes
+            for (const nodeOffset of nodeOffsets) {
+                reader.seek(nodeOffset);
+                const node = {};
+                node.id = reader.int32();
+                node.inputs = reader.uint32s();
+                node.outputs = reader.uint32s();
+                const typeOffset = reader.int32();
+                node.name = reader.string();
+                const attributeOffsets = reader.uint32s();
+                node.dynamicShape = reader.boolean();
+                reader.seek(typeOffset);
+                node.version = reader.int32();
+                const index = reader.int32();
+                const paramsOffset = reader.uint32();
+                const schema = operator(index, node.version);
+                node.type = schema ? schema.name : index.toString();
+                const paramTypes = schema ? schema.params : [];
+                node.params = [];
+                if (paramsOffset) {
+                    reader.seek(paramsOffset);
+                    for (const paramType of paramTypes) {
+                        if (paramType !== 'boolean') {
+                            reader.align(4);
                         }
-                    }
-                    if (node.type === 'Slice') {
-                        node.params[6] = (this._originalFormat == 5) ? node.params[6] : 0;
-                    }
-                    node.attributes = attributeOffsets.map((attributeOffset) => {
-                        reader.seek(attributeOffset);
-                        const name = reader.string();
-                        const value = reader.string();
-                        const type = reader.int32();
-                        return { name: name, value: value, type: type };
-                    });
-                    subgraph.nodes.push(node);
-                }
-                // buffers
-                const buffers = bufferOffsets.map((bufferOffset) => {
-                    reader.seek(bufferOffset);
-                    const size = reader.uint32();
-                    const offset = reader.int32();
-                    if (offset !== 0) {
-                        reader.seek(offset);
-                        return reader.read(size);
-                    }
-                    return null;
-                });
-                // tensors
-                subgraph.tensors = tensorOffsets.map((tensorOffset) => {
-                    reader.seek(tensorOffset);
-                    const tensor = {};
-                    tensor.id = reader.int32();
-                    tensor.buffer = buffers[reader.int32()];
-                    tensor.dims = reader.int32s();
-                    tensor.name = reader.string();
-                    const quantparamsOffset = reader.int32();
-                    tensor.layout = reader.int32();
-                    tensor.type = reader.int32(); // ar = 1, const = 2, input = 3, vdep, unknown
-                    tensor.dataType = reader.int32();
-                    if (quantparamsOffset) {
-                        reader.seek(quantparamsOffset);
-                        tensor.quantparams = {
-                            zeroPoint: reader.int32(),
-                            scale: reader.float32(),
-                            width: reader.int32()
-                        };
-                    }
-                    return tensor;
-                });
-                for (const node of subgraph.nodes) {
-                    if (node.type === 'Convolution') {
-                        switch (subgraph.graphLayout) {
-                            case 0: // NCHW
-                                /* eslint-disable prefer-destructuring */
-                                node.params[6] = subgraph.tensors[node.inputs[1]].dims[1];
-                                /* eslint-enable prefer-destructuring */
+                        switch (paramType) {
+                            case 'i':
+                                node.params.push(reader.int32());
+                                break;
+                            case 'f':
+                                node.params.push(reader.float32());
+                                break;
+                            case 'i[]':
+                                node.params.push(reader.int32s());
                                 break;
-                            case 1: // NHWC
-                                /* eslint-disable prefer-destructuring */
-                                node.params[6] = subgraph.tensors[node.inputs[1]].dims[3];
-                                /* eslint-enable prefer-destructuring */
+                            case 'f[]':
+                                node.params.push(reader.float32s());
+                                break;
+                            case 'boolean':
+                                node.params.push(reader.boolean());
+                                break;
+                            case 'string':
+                                node.params.push(reader.string());
+                                break;
+                            case 'anchors':
+                                node.params.push(reader.anchors(4));
                                 break;
                             default:
-                                throw new tengine.Error(`Unsupported 'Convolution' layout '${subgraph.graphLayout}'.`);
+                                throw new tengine.Error(`Unsupported param type '${paramType}' in '${node.type}'.`);
                         }
                     }
                 }
+                if (node.type === 'Slice') {
+                    node.params[6] = (this._originalFormat == 5) ? node.params[6] : 0;
+                }
+                node.attributes = attributeOffsets.map((attributeOffset) => {
+                    reader.seek(attributeOffset);
+                    const name = reader.string();
+                    const value = reader.string();
+                    const type = reader.int32();
+                    return { name: name, value: value, type: type };
+                });
+                subgraph.nodes.push(node);
+            }
+            // buffers
+            const buffers = bufferOffsets.map((bufferOffset) => {
+                reader.seek(bufferOffset);
+                const size = reader.uint32();
+                const offset = reader.int32();
+                if (offset !== 0) {
+                    reader.seek(offset);
+                    return reader.read(size);
+                }
+                return null;
+            });
+            // tensors
+            subgraph.tensors = tensorOffsets.map((tensorOffset) => {
+                reader.seek(tensorOffset);
+                const tensor = {};
+                tensor.id = reader.int32();
+                tensor.buffer = buffers[reader.int32()];
+                tensor.dims = reader.int32s();
+                tensor.name = reader.string();
+                const quantparamsOffset = reader.int32();
+                tensor.layout = reader.int32();
+                tensor.type = reader.int32(); // ar = 1, const = 2, input = 3, vdep, unknown
+                tensor.dataType = reader.int32();
+                if (quantparamsOffset) {
+                    reader.seek(quantparamsOffset);
+                    tensor.quantparams = {
+                        zeroPoint: reader.int32(),
+                        scale: reader.float32(),
+                        width: reader.int32()
+                    };
+                }
+                return tensor;
+            });
+            for (const node of subgraph.nodes) {
+                if (node.type === 'Convolution') {
+                    switch (subgraph.graphLayout) {
+                        case 0: // NCHW
+                            /* eslint-disable prefer-destructuring */
+                            node.params[6] = subgraph.tensors[node.inputs[1]].dims[1];
+                            /* eslint-enable prefer-destructuring */
+                            break;
+                        case 1: // NHWC
+                            /* eslint-disable prefer-destructuring */
+                            node.params[6] = subgraph.tensors[node.inputs[1]].dims[3];
+                            /* eslint-enable prefer-destructuring */
+                            break;
+                        default:
+                            throw new tengine.Error(`Unsupported 'Convolution' layout '${subgraph.graphLayout}'.`);
+                    }
+                }
             }
-            delete this.stream;
         }
+        delete this.stream;
     }
 
     get version() {

+ 39 - 39
source/tensorrt.js

@@ -6,14 +6,13 @@ const tensorrt = {};
 tensorrt.ModelFactory = class {
 
     match(context) {
-        const stream = context.stream;
-        const engine = tensorrt.Engine.open(stream);
+        const engine = tensorrt.Engine.open(context);
         if (engine) {
             context.target = engine;
             context.type = 'tensorrt.engine';
             return;
         }
-        const container = tensorrt.Container.open(stream);
+        const container = tensorrt.Container.open(context);
         if (container) {
             context.target = container;
             context.type = 'tensorrt.container';
@@ -67,7 +66,8 @@ tensorrt.Graph = class {
 
 tensorrt.Engine = class {
 
-    static open(stream) {
+    static open(context) {
+        const stream = context.stream;
         if (stream && stream.length >= 24) {
             const signatures = [
                 [ 0x70, 0x74, 0x72, 0x74 ], // ptrt
@@ -76,58 +76,58 @@ tensorrt.Engine = class {
             const buffer = stream.peek(4);
             for (const signature of signatures) {
                 if (buffer.every((value, index) => value === signature[index])) {
-                    return new tensorrt.Engine(stream);
+                    return new tensorrt.Engine(context);
                 }
             }
         }
         return null;
     }
 
-    constructor(stream) {
-        this.stream = stream;
+    constructor(context) {
+        this.context = context;
         this.format = 'TensorRT Engine';
     }
 
     read() {
-        if (this.stream) {
-            const buffer = this.stream.peek(24);
-            delete this.stream;
-            const reader = new base.BinaryReader(buffer);
-            reader.skip(4);
-            const version = reader.uint32();
-            reader.uint32();
-            // let size = 0;
-            switch (version) {
-                case 0x0000:
-                case 0x002B: {
-                    reader.uint32();
-                    /* size = */ reader.uint64();
-                    break;
-                }
-                case 0x0057:
-                case 0x0059:
-                case 0x0060:
-                case 0x0061: {
-                    /* size = */ reader.uint64();
-                    reader.uint32();
-                    break;
-                }
-                default: {
-                    const content = Array.from(buffer).map((c) => (c < 16 ? '0' : '') + c.toString(16)).join('');
-                    throw new tensorrt.Error(`Unsupported TensorRT engine signature (${content.substring(8)}).`);
-                }
+        const stream = this.context.stream;
+        const buffer = stream.peek(24);
+        const reader = this.context.reader;
+        delete this.context;
+        reader.skip(4);
+        const version = reader.uint32();
+        reader.uint32();
+        // let size = 0;
+        switch (version) {
+            case 0x0000:
+            case 0x002B: {
+                reader.uint32();
+                /* size = */ reader.uint64();
+                break;
+            }
+            case 0x0057:
+            case 0x0059:
+            case 0x0060:
+            case 0x0061: {
+                /* size = */ reader.uint64();
+                reader.uint32();
+                break;
+            }
+            default: {
+                const content = Array.from(buffer).map((c) => (c < 16 ? '0' : '') + c.toString(16)).join('');
+                throw new tensorrt.Error(`Unsupported TensorRT engine signature (${content.substring(8)}).`);
             }
-            // const content = Array.from(buffer).map((c) => (c < 16 ? '0' : '') + c.toString(16)).join('');
-            // buffer = this._stream.read(24 + size);
-            // reader = new tensorrt.BinaryReader(buffer);
-            throw new tensorrt.Error('Invalid file content. File contains undocumented TensorRT engine data.');
         }
+        // const content = Array.from(buffer).map((c) => (c < 16 ? '0' : '') + c.toString(16)).join('');
+        // buffer = this._stream.read(24 + size);
+        // reader = new tensorrt.BinaryReader(buffer);
+        throw new tensorrt.Error('Invalid file content. File contains undocumented TensorRT engine data.');
     }
 };
 
 tensorrt.Container = class {
 
-    static open(stream) {
+    static open(context) {
+        const stream = context.stream;
         if (stream) {
             const buffer = stream.peek(Math.min(512, stream.length));
             if (buffer.length > 12 && buffer[6] === 0x00 && buffer[7] === 0x00) {

+ 2 - 5
source/tf.js

@@ -239,11 +239,8 @@ tf.ModelFactory = class {
         }
     }
 
-    filter(context, name) {
-        if (context.type === 'tf.bundle' && name === 'tf.data') {
-            return false;
-        }
-        return true;
+    filter(context, type) {
+        return context.type !== 'tf.bundle' || type !== 'tf.data';
     }
 
     async open(context) {

+ 2 - 1
source/tflite.js

@@ -30,6 +30,7 @@ tflite.ModelFactory = class {
         const obj = context.peek('json');
         if (obj && obj.subgraphs && obj.operator_codes) {
             context.type = 'tflite.flatbuffers.json';
+            context.target = obj;
             return;
         }
     }
@@ -42,7 +43,7 @@ tflite.ModelFactory = class {
         switch (context.type) {
             case 'tflite.flatbuffers.json': {
                 try {
-                    const obj = context.peek('json');
+                    const obj = context.target;
                     const reader = new flatbuffers.TextReader(obj);
                     model = tflite.schema.Model.createText(reader);
                 } catch (error) {

+ 20 - 35
source/view.js

@@ -5137,9 +5137,7 @@ view.Context = class {
                 case 'bson': {
                     const reader = json.BinaryReader.open(this._stream);
                     if (reader) {
-                        const obj = reader.read();
-                        this._content.set('bson', obj);
-                        return obj;
+                        return reader.read();
                     }
                     throw new view.Error('Invalid BSON content.');
                 }
@@ -5619,12 +5617,12 @@ view.ModelFactoryService = class {
                     }
                     return model;
                 } catch (error) {
+                    delete context.type;
+                    delete context.target;
                     if (context.stream && context.stream.position !== 0) {
                         context.stream.seek(0);
                     }
                     errors.push(error);
-                    context.type = null;
-                    context.target = null;
                 }
             }
         }
@@ -5647,38 +5645,24 @@ view.ModelFactoryService = class {
                 const folder = rotate(map).filter(equals).map(at(0)).join('/');
                 return folder.length === 0 ? folder : `${folder}/`;
             };
-            const list = Array.from(entries).map(([name, stream]) => {
-                return { name: name, stream: stream };
-            });
-            const files = list.filter((entry) => {
-                if (entry.name.endsWith('/')) {
-                    return false;
-                }
-                if (entry.name.split('/').pop().startsWith('.')) {
-                    return false;
-                }
-                if (!entry.name.startsWith('./') && entry.name.startsWith('.')) {
-                    return false;
-                }
-                return true;
-            });
-            const folder = rootFolder(files.map((entry) => entry.name));
+            const files = Array.from(entries).filter(([name]) => !(name.endsWith('/') || name.split('/').pop().startsWith('.') || (!name.startsWith('./') && name.startsWith('.'))));
+            const folder = rootFolder(files.map(([name]) => name));
             const filter = async (queue, entries) => {
                 entries = new Map(Array.from(entries)
                     .filter(([path]) => path.startsWith(folder))
                     .map(([path, stream]) => [ path.substring(folder.length), stream ]));
                 const entryContext = new view.EntryContext(this._host, entries);
                 let matches = [];
-                for (const entry of queue) {
-                    const identifier = entry.name.substring(folder.length);
-                    const context = new view.Context(entryContext, identifier, entry.stream);
+                for (const [name, stream] of queue) {
+                    const identifier = name.substring(folder.length);
+                    const context = new view.Context(entryContext, identifier, stream);
                     const modules = this._filter(context);
                     for (const module of modules) {
                         /* eslint-disable no-await-in-loop */
                         const factory = await this._require(module);
                         /* eslint-enable no-await-in-loop */
                         factory.match(context);
-                        context.target = null;
+                        delete context.target;
                         if (context.type) {
                             matches = matches.filter((match) => !factory.filter || factory.filter(context, match.type));
                             if (matches.every((match) => !match.factory.filter || match.factory.filter(match, context.type))) {
@@ -5689,22 +5673,23 @@ view.ModelFactoryService = class {
                         }
                     }
                 }
-                if (matches.length === 0) {
-                    return null;
-                }
                 if (matches.length > 1) {
                     const content = matches.map((context) => context.type).join(',');
                     throw new view.ArchiveError(`Archive contains multiple model files '${content}'.`);
                 }
-                const match = matches.shift();
-                match.type = null;
-                return match;
+                if (matches.length > 0) {
+                    const match = matches.shift();
+                    delete match.type;
+                    delete match.factory;
+                    return match;
+                }
+                return null;
             };
-            const queue = files.slice(0).filter((entry) => entry.name.substring(folder.length).indexOf('/') < 0);
-            const context = await filter(queue, entries);
+            const queue = files.filter(([name]) => name.substring(folder.length).indexOf('/') < 0);
+            let context = await filter(queue, entries);
             if (!context) {
-                const queue = files.slice(0).filter((entry) => entry.name.substring(folder.length).indexOf('/') >= 0);
-                return await filter(queue, entries);
+                const queue = files.filter(([name]) => name.substring(folder.length).indexOf('/') >= 0);
+                context = await filter(queue, entries);
             }
             return context;
         } catch (error) {

+ 4 - 4
source/weka.js

@@ -10,12 +10,13 @@ weka.ModelFactory = class {
         try {
             const stream = context.stream;
             if (stream.length >= 5) {
-                const signature = [ 0xac, 0xed ];
-                if (stream.peek(2).every((value, index) => value === signature[index])) {
+                const buffer = stream.peek(2);
+                if (buffer[0] === 0xAC && buffer[1] === 0xED) {
                     const reader = new java.io.InputObjectStream(stream);
                     const obj = reader.read();
                     if (obj && obj.$class && obj.$class.name) {
                         context.type = 'weka';
+                        context.target = obj;
                     }
                 }
             }
@@ -25,8 +26,7 @@ weka.ModelFactory = class {
     }
 
     async open(context) {
-        const reader = new java.io.InputObjectStream(context.stream);
-        const obj = reader.read();
+        const obj = context.target;
         throw new weka.Error(`Unsupported type '${obj.$class.name}'.`);
     }
 };