Browse Source

Paddle Lite support (#797)

Lutz Roeder 4 years ago
parent
commit
03a67af865
9 changed files with 938 additions and 237 deletions
  1. 4 2
      electron-builder.yml
  2. 1 1
      source/app.js
  3. 1 1
      source/index.html
  4. 0 38
      source/nb.js
  5. 533 0
      source/paddle-schema.js
  6. 378 177
      source/paddle.js
  7. 1 2
      source/view.js
  8. 15 16
      test/models.json
  9. 5 0
      tools/paddle

+ 4 - 2
electron-builder.yml

@@ -62,16 +62,18 @@ fileAssociations:
     ext: tfl
   - name: "Tengine"
     ext: tmfile
-  - name: "UFF Model"
-    ext: uff
   - name: "PaddlePaddle"
     ext: paddle
   - name: "PaddlePaddle"
     ext: pdmodel
   - name: "PaddlePaddle"
     ext: pdparams
+  - name: "Paddle Lite"
+    ext: nb
   - name: "RKNN"
     ext: rknn
+  - name: "UFF Model"
+    ext: uff
   - name: "xmodel"
     ext: xmodel
 afterSign: "./publish/notarize.js"

+ 1 - 1
source/app.js

@@ -164,7 +164,7 @@ class Application {
                     'mlmodel', 'mlpackage',
                     'caffemodel',
                     'model', 'dnn', 'cmf', 'mar', 'params',
-                    'pdmodel', 'pdparams',
+                    'pdmodel', 'pdparams', 'nb',
                     'meta',
                     'tflite', 'lite', 'tfl',
                     'armnn', 'mnn', 'nn', 'uff', 'uff.txt', 'rknn', 'xmodel',

+ 1 - 1
source/index.html

@@ -362,7 +362,7 @@ button { font-family: -apple-system, BlinkMacSystemFont, "Segoe WPC", "Segoe UI"
     <button id="consent-accept-button" class="center consent-accept-button">Accept</button>
     <button id="open-file-button" class="center open-file-button">Open Model&hellip;</button>
     <button id="github-button" class="center github-button">GitHub</button>
-    <input type="file" id="open-file-dialog" class="open-file-dialog" multiple="false" accept=".onnx, .pb, .meta, .tflite, .lite, .tfl, .keras, .h5, .hd5, .hdf5, .json, .model, .mar, .params, .param, .armnn, .mnn, .ncnn, .tnnproto, .tmfile, .ms, .om, .nn, .uff, .rknn, .xmodel, .paddle, .pdmodel, .pdparams, .dnn, .cmf, .mlmodel, .mlpackage, .caffemodel, .pbtxt, .prototxt, .pkl, .pt, .pth, .t7, .joblib, .cfg, .xml, .zip, .tar">
+    <input type="file" id="open-file-dialog" class="open-file-dialog" multiple="false" accept=".onnx, .pb, .meta, .tflite, .lite, .tfl, .keras, .h5, .hd5, .hdf5, .json, .model, .mar, .params, .param, .armnn, .mnn, .ncnn, .tnnproto, .tmfile, .ms, .om, .nn, .uff, .rknn, .xmodel, .paddle, .pdmodel, .pdparams, .nb, .dnn, .cmf, .mlmodel, .mlpackage, .caffemodel, .pbtxt, .prototxt, .pkl, .pt, .pth, .t7, .joblib, .cfg, .xml, .zip, .tar">
     <!-- Preload fonts to workaround Chrome SVG layout issue -->
     <div style="font-weight: normal; color: rgba(0, 0, 0, 0.01); user-select: none;">.</div>
     <div style="font-weight: bold; color: rgba(0, 0, 0, 0.01); user-select: none;">.</div>

+ 0 - 38
source/nb.js

@@ -1,38 +0,0 @@
-/* jshint esversion: 6 */
-
-// Experimental
-
-var nb = nb || {};
-var flatbuffers = flatbuffers || require('./flatbuffers');
-
-nb.ModelFactory = class {
-
-    match(context) {
-        if (context.stream) {
-            switch (context.identifier.toLowerCase()) {
-                case '__model__.nb':
-                    return 'paddlelite.model.naivebuffer';
-                case 'param.nb':
-                    return 'paddlelite.data.naivebuffer';
-            }
-        }
-        return '';
-    }
-
-    open(/* context, match */) {
-        throw new nb.Error('Invalid file content. File contains Paddle Lite naive buffer data.');
-    }
-};
-
-nb.Error = class extends Error {
-
-    constructor(message, context) {
-        super(message);
-        this.name = 'Error loading Paddle Lite model.';
-        this.context = context === false ? false : true;
-    }
-};
-
-if (typeof module !== 'undefined' && typeof module.exports === 'object') {
-    module.exports.ModelFactory = nb.ModelFactory;
-}

+ 533 - 0
source/paddle-schema.js

@@ -0,0 +1,533 @@
+var $root = flatbuffers.get('paddlelite');
+
+$root.paddle = $root.paddle || {};
+
+$root.paddle.lite = $root.paddle.lite || {};
+
+$root.paddle.lite.fbs = $root.paddle.lite.fbs || {};
+
+$root.paddle.lite.fbs.proto = $root.paddle.lite.fbs.proto || {};
+
+$root.paddle.lite.fbs.proto.AttrType = {
+    INT: 0,
+    FLOAT: 1,
+    STRING: 2,
+    INTS: 3,
+    FLOATS: 4,
+    STRINGS: 5,
+    BOOLEAN: 6,
+    BOOLEANS: 7,
+    BLOCK: 8,
+    LONG: 9,
+    BLOCKS: 10,
+    LONGS: 11
+};
+
+$root.paddle.lite.fbs.proto.Version = class Version {
+
+    static decode(reader, position) {
+        const $ = new $root.paddle.lite.fbs.proto.Version();
+        $.version = reader.int64_(position, 4, 0);
+        return $;
+    }
+
+    static decodeText(reader, json) {
+        const $ = new $root.paddle.lite.fbs.proto.Version();
+        $.version = reader.value(json.version, 0);
+        return $;
+    }
+};
+
+$root.paddle.lite.fbs.proto.OpDesc = class OpDesc {
+
+    static decode(reader, position) {
+        const $ = new $root.paddle.lite.fbs.proto.OpDesc();
+        $.type = reader.string_(position, 4, null);
+        $.inputs = reader.tableArray(position, 6, $root.paddle.lite.fbs.proto.OpDesc_.Var.decode);
+        $.outputs = reader.tableArray(position, 8, $root.paddle.lite.fbs.proto.OpDesc_.Var.decode);
+        $.attrs = reader.tableArray(position, 10, $root.paddle.lite.fbs.proto.OpDesc_.Attr.decode);
+        $.is_target = reader.bool_(position, 12, false);
+        return $;
+    }
+
+    static decodeText(reader, json) {
+        const $ = new $root.paddle.lite.fbs.proto.OpDesc();
+        $.type = reader.value(json.type, null);
+        $.inputs = reader.objectArray(json.inputs, $root.paddle.lite.fbs.proto.OpDesc_.Var.decodeText);
+        $.outputs = reader.objectArray(json.outputs, $root.paddle.lite.fbs.proto.OpDesc_.Var.decodeText);
+        $.attrs = reader.objectArray(json.attrs, $root.paddle.lite.fbs.proto.OpDesc_.Attr.decodeText);
+        $.is_target = reader.value(json.is_target, false);
+        return $;
+    }
+};
+
+$root.paddle.lite.fbs.proto.VarType = class VarType {
+
+    static decode(reader, position) {
+        const $ = new $root.paddle.lite.fbs.proto.VarType();
+        $.type = reader.int32_(position, 4, 0);
+        $.selected_rows = reader.table(position, 6, $root.paddle.lite.fbs.proto.VarType_.TensorDesc.decode);
+        $.lod_tensor = reader.table(position, 8, $root.paddle.lite.fbs.proto.VarType_.LoDTensorDesc.decode);
+        $.tensor_array = reader.table(position, 10, $root.paddle.lite.fbs.proto.VarType_.LoDTensorArrayDesc.decode);
+        $.reader = reader.table(position, 12, $root.paddle.lite.fbs.proto.VarType_.ReaderDesc.decode);
+        $.tuple = reader.table(position, 14, $root.paddle.lite.fbs.proto.VarType_.Tuple.decode);
+        return $;
+    }
+
+    static decodeText(reader, json) {
+        const $ = new $root.paddle.lite.fbs.proto.VarType();
+        $.type = $root.paddle.lite.fbs.proto.VarType_.Type[json.type];
+        $.selected_rows = reader.object(json.selected_rows, $root.paddle.lite.fbs.proto.VarType_.TensorDesc.decodeText);
+        $.lod_tensor = reader.object(json.lod_tensor, $root.paddle.lite.fbs.proto.VarType_.LoDTensorDesc.decodeText);
+        $.tensor_array = reader.object(json.tensor_array, $root.paddle.lite.fbs.proto.VarType_.LoDTensorArrayDesc.decodeText);
+        $.reader = reader.object(json.reader, $root.paddle.lite.fbs.proto.VarType_.ReaderDesc.decodeText);
+        $.tuple = reader.object(json.tuple, $root.paddle.lite.fbs.proto.VarType_.Tuple.decodeText);
+        return $;
+    }
+};
+
+$root.paddle.lite.fbs.proto.VarDesc = class VarDesc {
+
+    static decode(reader, position) {
+        const $ = new $root.paddle.lite.fbs.proto.VarDesc();
+        $.name = reader.string_(position, 4, null);
+        $.type = reader.table(position, 6, $root.paddle.lite.fbs.proto.VarType.decode);
+        $.persistable = reader.bool_(position, 8, false);
+        $.need_check_feed = reader.bool_(position, 10, false);
+        return $;
+    }
+
+    static decodeText(reader, json) {
+        const $ = new $root.paddle.lite.fbs.proto.VarDesc();
+        $.name = reader.value(json.name, null);
+        $.type = reader.object(json.type, $root.paddle.lite.fbs.proto.VarType.decodeText);
+        $.persistable = reader.value(json.persistable, false);
+        $.need_check_feed = reader.value(json.need_check_feed, false);
+        return $;
+    }
+};
+
+$root.paddle.lite.fbs.proto.BlockDesc = class BlockDesc {
+
+    static decode(reader, position) {
+        const $ = new $root.paddle.lite.fbs.proto.BlockDesc();
+        $.idx = reader.int32_(position, 4, 0);
+        $.parent_idx = reader.int32_(position, 6, 0);
+        $.vars = reader.tableArray(position, 8, $root.paddle.lite.fbs.proto.VarDesc.decode);
+        $.ops = reader.tableArray(position, 10, $root.paddle.lite.fbs.proto.OpDesc.decode);
+        $.forward_block_idx = reader.int32_(position, 12, -1);
+        return $;
+    }
+
+    static decodeText(reader, json) {
+        const $ = new $root.paddle.lite.fbs.proto.BlockDesc();
+        $.idx = reader.value(json.idx, 0);
+        $.parent_idx = reader.value(json.parent_idx, 0);
+        $.vars = reader.objectArray(json.vars, $root.paddle.lite.fbs.proto.VarDesc.decodeText);
+        $.ops = reader.objectArray(json.ops, $root.paddle.lite.fbs.proto.OpDesc.decodeText);
+        $.forward_block_idx = reader.value(json.forward_block_idx, -1);
+        return $;
+    }
+};
+
+$root.paddle.lite.fbs.proto.OpVersion = class OpVersion {
+
+    static decode(reader, position) {
+        const $ = new $root.paddle.lite.fbs.proto.OpVersion();
+        $.version = reader.int32_(position, 4, 0);
+        return $;
+    }
+
+    static decodeText(reader, json) {
+        const $ = new $root.paddle.lite.fbs.proto.OpVersion();
+        $.version = reader.value(json.version, 0);
+        return $;
+    }
+};
+
+$root.paddle.lite.fbs.proto.OpVersionMap = class OpVersionMap {
+
+    static decode(reader, position) {
+        const $ = new $root.paddle.lite.fbs.proto.OpVersionMap();
+        $.pair = reader.tableArray(position, 4, $root.paddle.lite.fbs.proto.OpVersionMap_.OpVersionPair.decode);
+        return $;
+    }
+
+    static decodeText(reader, json) {
+        const $ = new $root.paddle.lite.fbs.proto.OpVersionMap();
+        $.pair = reader.objectArray(json.pair, $root.paddle.lite.fbs.proto.OpVersionMap_.OpVersionPair.decodeText);
+        return $;
+    }
+};
+
+$root.paddle.lite.fbs.proto.ProgramDesc = class ProgramDesc {
+
+    static create(reader) {
+        return $root.paddle.lite.fbs.proto.ProgramDesc.decode(reader, reader.root);
+    }
+
+    static createText(reader) {
+        return $root.paddle.lite.fbs.proto.ProgramDesc.decodeText(reader, reader.root);
+    }
+
+    static decode(reader, position) {
+        const $ = new $root.paddle.lite.fbs.proto.ProgramDesc();
+        $.blocks = reader.tableArray(position, 4, $root.paddle.lite.fbs.proto.BlockDesc.decode);
+        $.version = reader.table(position, 6, $root.paddle.lite.fbs.proto.Version.decode);
+        $.op_version_map = reader.table(position, 8, $root.paddle.lite.fbs.proto.OpVersionMap.decode);
+        return $;
+    }
+
+    static decodeText(reader, json) {
+        const $ = new $root.paddle.lite.fbs.proto.ProgramDesc();
+        $.blocks = reader.objectArray(json.blocks, $root.paddle.lite.fbs.proto.BlockDesc.decodeText);
+        $.version = reader.object(json.version, $root.paddle.lite.fbs.proto.Version.decodeText);
+        $.op_version_map = reader.object(json.op_version_map, $root.paddle.lite.fbs.proto.OpVersionMap.decodeText);
+        return $;
+    }
+};
+
+$root.paddle.lite.fbs.proto.CombinedParamsDesc = class CombinedParamsDesc {
+
+    static create(reader) {
+        return $root.paddle.lite.fbs.proto.CombinedParamsDesc.decode(reader, reader.root);
+    }
+
+    static createText(reader) {
+        return $root.paddle.lite.fbs.proto.CombinedParamsDesc.decodeText(reader, reader.root);
+    }
+
+    static decode(reader, position) {
+        const $ = new $root.paddle.lite.fbs.proto.CombinedParamsDesc();
+        $.params = reader.tableArray(position, 4, $root.paddle.lite.fbs.proto.ParamDesc.decode);
+        return $;
+    }
+
+    static decodeText(reader, json) {
+        const $ = new $root.paddle.lite.fbs.proto.CombinedParamsDesc();
+        $.params = reader.objectArray(json.params, $root.paddle.lite.fbs.proto.ParamDesc.decodeText);
+        return $;
+    }
+};
+
+$root.paddle.lite.fbs.proto.ParamDesc = class ParamDesc {
+
+    static create(reader) {
+        return $root.paddle.lite.fbs.proto.ParamDesc.decode(reader, reader.root);
+    }
+
+    static createText(reader) {
+        return $root.paddle.lite.fbs.proto.ParamDesc.decodeText(reader, reader.root);
+    }
+
+    static decode(reader, position) {
+        const $ = new $root.paddle.lite.fbs.proto.ParamDesc();
+        $.version = reader.table(position, 4, $root.paddle.lite.fbs.proto.ParamDesc_.VersionDesc.decode);
+        $.name = reader.string_(position, 6, null);
+        $.variable = reader.union(position, 8, $root.paddle.lite.fbs.proto.ParamDesc_.VariableDesc.decode);
+        return $;
+    }
+
+    static decodeText(reader, json) {
+        const $ = new $root.paddle.lite.fbs.proto.ParamDesc();
+        $.version = reader.object(json.version, $root.paddle.lite.fbs.proto.ParamDesc_.VersionDesc.decodeText);
+        $.name = reader.value(json.name, null);
+        $.variable = $root.paddle.lite.fbs.proto.ParamDesc_.VariableDesc.decodeText(reader, json.variable, json.variable_type);
+        return $;
+    }
+};
+
+$root.paddle = $root.paddle || {};
+
+$root.paddle.lite = $root.paddle.lite || {};
+
+$root.paddle.lite.fbs = $root.paddle.lite.fbs || {};
+
+$root.paddle.lite.fbs.proto = $root.paddle.lite.fbs.proto || {};
+
+$root.paddle.lite.fbs.proto.VarType_ = $root.paddle.lite.fbs.proto.VarType_ || {};
+
+$root.paddle.lite.fbs.proto.VarType_.Type = {
+    BOOL: 0,
+    INT16: 1,
+    INT32: 2,
+    INT64: 3,
+    FP16: 4,
+    FP32: 5,
+    FP64: 6,
+    LOD_TENSOR: 7,
+    SELECTED_ROWS: 8,
+    FEED_MINIBATCH: 9,
+    FETCH_LIST: 10,
+    STEP_SCOPES: 11,
+    LOD_RANK_TABLE: 12,
+    LOD_TENSOR_ARRAY: 13,
+    PLACE_LIST: 14,
+    READER: 15,
+    RAW: 17,
+    TUPLE: 18,
+    SIZE_T: 19,
+    UINT8: 20,
+    INT8: 21
+};
+
+$root.paddle.lite.fbs.proto.VarType_.TensorDesc = class TensorDesc {
+
+    static decode(reader, position) {
+        const $ = new $root.paddle.lite.fbs.proto.VarType_.TensorDesc();
+        $.data_type = reader.int32_(position, 4, 0);
+        $.dims = reader.int64s_(position, 6);
+        return $;
+    }
+
+    static decodeText(reader, json) {
+        const $ = new $root.paddle.lite.fbs.proto.VarType_.TensorDesc();
+        $.data_type = $root.paddle.lite.fbs.proto.VarType_.Type[json.data_type];
+        $.dims = reader.array(json.dims);
+        return $;
+    }
+};
+
+$root.paddle.lite.fbs.proto.VarType_.LoDTensorDesc = class LoDTensorDesc {
+
+    static decode(reader, position) {
+        const $ = new $root.paddle.lite.fbs.proto.VarType_.LoDTensorDesc();
+        $.tensor = reader.table(position, 4, $root.paddle.lite.fbs.proto.VarType_.TensorDesc.decode);
+        $.lod_level = reader.int32_(position, 6, 0);
+        return $;
+    }
+
+    static decodeText(reader, json) {
+        const $ = new $root.paddle.lite.fbs.proto.VarType_.LoDTensorDesc();
+        $.tensor = reader.object(json.tensor, $root.paddle.lite.fbs.proto.VarType_.TensorDesc.decodeText);
+        $.lod_level = reader.value(json.lod_level, 0);
+        return $;
+    }
+};
+
+$root.paddle.lite.fbs.proto.VarType_.LoDTensorArrayDesc = class LoDTensorArrayDesc {
+
+    static decode(reader, position) {
+        const $ = new $root.paddle.lite.fbs.proto.VarType_.LoDTensorArrayDesc();
+        $.tensor = reader.table(position, 4, $root.paddle.lite.fbs.proto.VarType_.TensorDesc.decode);
+        $.lod_level = reader.int32_(position, 6, 0);
+        return $;
+    }
+
+    static decodeText(reader, json) {
+        const $ = new $root.paddle.lite.fbs.proto.VarType_.LoDTensorArrayDesc();
+        $.tensor = reader.object(json.tensor, $root.paddle.lite.fbs.proto.VarType_.TensorDesc.decodeText);
+        $.lod_level = reader.value(json.lod_level, 0);
+        return $;
+    }
+};
+
+$root.paddle.lite.fbs.proto.VarType_.ReaderDesc = class ReaderDesc {
+
+    static decode(reader, position) {
+        const $ = new $root.paddle.lite.fbs.proto.VarType_.ReaderDesc();
+        $.lod_tensor = reader.tableArray(position, 4, $root.paddle.lite.fbs.proto.VarType_.LoDTensorDesc.decode);
+        return $;
+    }
+
+    static decodeText(reader, json) {
+        const $ = new $root.paddle.lite.fbs.proto.VarType_.ReaderDesc();
+        $.lod_tensor = reader.objectArray(json.lod_tensor, $root.paddle.lite.fbs.proto.VarType_.LoDTensorDesc.decodeText);
+        return $;
+    }
+};
+
+$root.paddle.lite.fbs.proto.VarType_.Tuple = class Tuple {
+
+    static decode(reader, position) {
+        const $ = new $root.paddle.lite.fbs.proto.VarType_.Tuple();
+        $.element_type = reader.typedArray(position, 4, Int32Array);
+        return $;
+    }
+
+    static decodeText(reader, json) {
+        const $ = new $root.paddle.lite.fbs.proto.VarType_.Tuple();
+        $.element_type = reader.objectArray(json.element_type, $root.paddle.lite.fbs.proto.VarType_.Type.decodeText);
+        return $;
+    }
+};
+
+$root.paddle = $root.paddle || {};
+
+$root.paddle.lite = $root.paddle.lite || {};
+
+$root.paddle.lite.fbs = $root.paddle.lite.fbs || {};
+
+$root.paddle.lite.fbs.proto = $root.paddle.lite.fbs.proto || {};
+
+$root.paddle.lite.fbs.proto.CompatibleInfo_ = $root.paddle.lite.fbs.proto.CompatibleInfo_ || {};
+
+$root.paddle.lite.fbs.proto.CompatibleInfo_.Type = {
+    COMPATIBLE: 0,
+    DEFINITELY_NOT: 1,
+    POSSIBLE: 2,
+    BUG_FIX: 3,
+    PRECISION_CHANGE: 4
+};
+
+$root.paddle = $root.paddle || {};
+
+$root.paddle.lite = $root.paddle.lite || {};
+
+$root.paddle.lite.fbs = $root.paddle.lite.fbs || {};
+
+$root.paddle.lite.fbs.proto = $root.paddle.lite.fbs.proto || {};
+
+$root.paddle.lite.fbs.proto.OpDesc_ = $root.paddle.lite.fbs.proto.OpDesc_ || {};
+
+$root.paddle.lite.fbs.proto.OpDesc_.Attr = class Attr {
+
+    static decode(reader, position) {
+        const $ = new $root.paddle.lite.fbs.proto.OpDesc_.Attr();
+        $.name = reader.string_(position, 4, null);
+        $.type = reader.int32_(position, 6, 0);
+        $.i = reader.int32_(position, 8, 0);
+        $.f = reader.float32_(position, 10, 0);
+        $.s = reader.string_(position, 12, null);
+        $.ints = reader.typedArray(position, 14, Int32Array);
+        $.floats = reader.typedArray(position, 16, Float32Array);
+        $.strings = reader.strings_(position, 18);
+        $.b = reader.bool_(position, 20, false);
+        $.bools = reader.bools_(position, 22);
+        $.block_idx = reader.int32_(position, 24, 0);
+        $.l = reader.int64_(position, 26, 0);
+        $.blocks_idx = reader.typedArray(position, 28, Int32Array);
+        $.longs = reader.int64s_(position, 30);
+        return $;
+    }
+
+    static decodeText(reader, json) {
+        const $ = new $root.paddle.lite.fbs.proto.OpDesc_.Attr();
+        $.name = reader.value(json.name, null);
+        $.type = $root.paddle.lite.fbs.proto.AttrType[json.type];
+        $.i = reader.value(json.i, 0);
+        $.f = reader.value(json.f, 0);
+        $.s = reader.value(json.s, null);
+        $.ints = reader.typedArray(json.ints, Int32Array);
+        $.floats = reader.typedArray(json.floats, Float32Array);
+        $.strings = reader.array(json.strings);
+        $.b = reader.value(json.b, false);
+        $.bools = reader.array(json.bools);
+        $.block_idx = reader.value(json.block_idx, 0);
+        $.l = reader.value(json.l, 0);
+        $.blocks_idx = reader.typedArray(json.blocks_idx, Int32Array);
+        $.longs = reader.array(json.longs);
+        return $;
+    }
+};
+
+$root.paddle.lite.fbs.proto.OpDesc_.Var = class Var {
+
+    static decode(reader, position) {
+        const $ = new $root.paddle.lite.fbs.proto.OpDesc_.Var();
+        $.parameter = reader.string_(position, 4, null);
+        $.arguments = reader.strings_(position, 6);
+        return $;
+    }
+
+    static decodeText(reader, json) {
+        const $ = new $root.paddle.lite.fbs.proto.OpDesc_.Var();
+        $.parameter = reader.value(json.parameter, null);
+        $.arguments = reader.array(json.arguments);
+        return $;
+    }
+};
+
+$root.paddle = $root.paddle || {};
+
+$root.paddle.lite = $root.paddle.lite || {};
+
+$root.paddle.lite.fbs = $root.paddle.lite.fbs || {};
+
+$root.paddle.lite.fbs.proto = $root.paddle.lite.fbs.proto || {};
+
+$root.paddle.lite.fbs.proto.OpVersionMap_ = $root.paddle.lite.fbs.proto.OpVersionMap_ || {};
+
+$root.paddle.lite.fbs.proto.OpVersionMap_.OpVersionPair = class OpVersionPair {
+
+    static decode(reader, position) {
+        const $ = new $root.paddle.lite.fbs.proto.OpVersionMap_.OpVersionPair();
+        $.op_name = reader.string_(position, 4, null);
+        $.op_version = reader.table(position, 6, $root.paddle.lite.fbs.proto.OpVersion.decode);
+        return $;
+    }
+
+    static decodeText(reader, json) {
+        const $ = new $root.paddle.lite.fbs.proto.OpVersionMap_.OpVersionPair();
+        $.op_name = reader.value(json.op_name, null);
+        $.op_version = reader.object(json.op_version, $root.paddle.lite.fbs.proto.OpVersion.decodeText);
+        return $;
+    }
+};
+
+$root.paddle = $root.paddle || {};
+
+$root.paddle.lite = $root.paddle.lite || {};
+
+$root.paddle.lite.fbs = $root.paddle.lite.fbs || {};
+
+$root.paddle.lite.fbs.proto = $root.paddle.lite.fbs.proto || {};
+
+$root.paddle.lite.fbs.proto.ParamDesc_ = $root.paddle.lite.fbs.proto.ParamDesc_ || {};
+
+$root.paddle.lite.fbs.proto.ParamDesc_.LoDTensorDesc = class LoDTensorDesc {
+
+    static decode(reader, position) {
+        const $ = new $root.paddle.lite.fbs.proto.ParamDesc_.LoDTensorDesc();
+        $.lod_level = reader.int32_(position, 4, 0);
+        $.lod = reader.int64s_(position, 6);
+        $.dim = reader.int64s_(position, 8);
+        $.data_type = reader.int32_(position, 10, 0);
+        $.data = reader.typedArray(position, 12, Int8Array);
+        return $;
+    }
+
+    static decodeText(reader, json) {
+        const $ = new $root.paddle.lite.fbs.proto.ParamDesc_.LoDTensorDesc();
+        $.lod_level = reader.value(json.lod_level, 0);
+        $.lod = reader.array(json.lod);
+        $.dim = reader.array(json.dim);
+        $.data_type = $root.paddle.lite.fbs.proto.VarType_.Type[json.data_type];
+        $.data = reader.typedArray(json.data, Int8Array);
+        return $;
+    }
+};
+
+$root.paddle.lite.fbs.proto.ParamDesc_.VersionDesc = class VersionDesc {
+
+    static decode(reader, position) {
+        const $ = new $root.paddle.lite.fbs.proto.ParamDesc_.VersionDesc();
+        $.version = reader.int32_(position, 4, 0);
+        $.model_version = reader.int32_(position, 6, 0);
+        return $;
+    }
+
+    static decodeText(reader, json) {
+        const $ = new $root.paddle.lite.fbs.proto.ParamDesc_.VersionDesc();
+        $.version = reader.value(json.version, 0);
+        $.model_version = reader.value(json.model_version, 0);
+        return $;
+    }
+};
+
+$root.paddle.lite.fbs.proto.ParamDesc_.VariableDesc = class {
+
+    static decode(reader, position, type) {
+        switch (type) {
+            case 1: return $root.paddle.lite.fbs.proto.ParamDesc_.LoDTensorDesc.decode(reader, position);
+        }
+        return undefined;
+    }
+
+    static decodeText(reader, json, type) {
+        switch (type) {
+            case 'LoDTensorDesc': return $root.paddle.lite.fbs.proto.ParamDesc_.LoDTensorDesc.decodeText(reader, json);
+        }
+        return undefined;
+    }
+};

+ 378 - 177
source/paddle.js

@@ -1,6 +1,7 @@
 /* jshint esversion: 6 */
 
 var paddle = paddle || {};
+var flatbuffers = flatbuffers || require('./flatbuffers');
 var protobuf = protobuf || require('./protobuf');
 
 paddle.ModelFactory = class {
@@ -20,143 +21,147 @@ paddle.ModelFactory = class {
                 return 'paddle.pbtxt';
             }
         }
-        if (paddle.Container.open(context)) {
-            return 'paddle.container';
-        }
         const stream = context.stream;
         if (stream.length > 16 && stream.peek(16).every((value) => value === 0x00)) {
             return 'paddle.params';
         }
+        if (paddle.Weights.open(context)) {
+            return 'paddle.weights';
+        }
+        if (paddle.NaiveBuffer.open(context)) {
+            return 'paddle.naive';
+        }
         return undefined;
     }
 
     open(context, match) {
         return paddle.Metadata.open(context).then((metadata) => {
-            return context.require('./paddle-proto').then(() => {
-                paddle.proto = protobuf.get('paddle').paddle.framework.proto;
-                const identifier = context.identifier;
-                const parts = identifier.split('.');
-                const extension = parts.pop().toLowerCase();
-                const base = parts.join('.');
-                const openProgram = (stream, match) => {
-                    const program = {};
-                    program.format = 'PaddlePaddle';
-                    switch (match) {
-                        case 'paddle.pbtxt': {
-                            try {
-                                const reader = protobuf.TextReader.open(stream);
-                                program.desc = paddle.proto.ProgramDesc.decodeText(reader);
-                            }
-                            catch (error) {
-                                const message = error && error.message ? error.message : error.toString();
-                                throw new paddle.Error('File text format is not paddle.ProgramDesc (' + message.replace(/\.$/, '') + ').');
-                            }
-                            break;
-                        }
-                        case 'paddle.pb': {
-                            try {
-                                const reader = protobuf.BinaryReader.open(stream);
-                                program.desc = paddle.proto.ProgramDesc.decode(reader);
-                            }
-                            catch (error) {
-                                const message = error && error.message ? error.message : error.toString();
-                                throw new paddle.Error('File format is not paddle.ProgramDesc (' + message.replace(/\.$/, '') + ').');
-                            }
-                            break;
-                        }
-                        default: {
-                            throw new paddle.Error("Unknown Paddle format '" + match + "'.");
-                        }
-                    }
-                    const programDesc = program.desc;
-                    if (programDesc.version && programDesc.version.version && programDesc.version.version.toNumber) {
-                        const version = programDesc.version.version.toNumber();
-                        if (version > 0) {
-                            const list = [ Math.floor(version / 1000000) % 1000, Math.floor(version / 1000) % 1000, version % 1000 ];
-                            if (list.slice(-1).pop() === 0) {
-                                list.pop();
-                                if (list.slice(-1).pop() === 0) {
-                                    list.pop();
+            switch (match) {
+                case 'paddle.naive': {
+                    return context.require('./paddle-schema').then(() => {
+                        paddle.schema = flatbuffers.get('paddlelite').paddle.lite.fbs.proto;
+                        const file = paddle.NaiveBuffer.open(context);
+                        return new paddle.Model(metadata, file.format, file.model, file.weights);
+                    });
+                }
+                default: {
+                    return context.require('./paddle-proto').then(() => {
+                        paddle.proto = protobuf.get('paddle').paddle.framework.proto;
+                        const identifier = context.identifier;
+                        const parts = identifier.split('.');
+                        const extension = parts.pop().toLowerCase();
+                        const base = parts.join('.');
+                        const openProgram = (stream, match) => {
+                            const program = {};
+                            program.format = 'PaddlePaddle';
+                            switch (match) {
+                                case 'paddle.pbtxt': {
+                                    try {
+                                        const reader = protobuf.TextReader.open(stream);
+                                        program.desc = paddle.proto.ProgramDesc.decodeText(reader);
+                                    }
+                                    catch (error) {
+                                        const message = error && error.message ? error.message : error.toString();
+                                        throw new paddle.Error('File text format is not paddle.ProgramDesc (' + message.replace(/\.$/, '') + ').');
+                                    }
+                                    break;
+                                }
+                                case 'paddle.pb': {
+                                    try {
+                                        const reader = protobuf.BinaryReader.open(stream);
+                                        program.desc = paddle.proto.ProgramDesc.decode(reader);
+                                    }
+                                    catch (error) {
+                                        const message = error && error.message ? error.message : error.toString();
+                                        throw new paddle.Error('File format is not paddle.ProgramDesc (' + message.replace(/\.$/, '') + ').');
+                                    }
+                                    break;
+                                }
+                                default: {
+                                    throw new paddle.Error("Unknown Paddle format '" + match + "'.");
                                 }
                             }
-                            program.format += ' v' + list.map((item) => item.toString()).join('.');
-                        }
-                    }
-                    const variables = new Set();
-                    for (const block of programDesc.blocks) {
-                        const blockVars = new Set();
-                        for (const variable of block.vars) {
-                            if (variable.persistable && variable.type &&
-                                variable.type.type != paddle.proto.VarType.Type.FETCH_LIST &&
-                                variable.type.type != paddle.proto.VarType.Type.FEED_MINIBATCH) {
-                                blockVars.add(variable.name);
-                            }
-                        }
-                        for (const op of block.ops) {
-                            for (const input of op.inputs) {
-                                for (const argument of input.arguments) {
-                                    if (blockVars.has(argument)) {
-                                        variables.add(argument);
+                            const programDesc = program.desc;
+                            program.format += paddle.Utility.formatVersion(programDesc.version);
+                            const variables = new Set();
+                            for (const block of programDesc.blocks) {
+                                const blockVars = new Set();
+                                for (const variable of block.vars) {
+                                    if (variable.persistable && variable.type &&
+                                        variable.type.type != paddle.DataType.FETCH_LIST &&
+                                        variable.type.type != paddle.DataType.FEED_MINIBATCH) {
+                                        blockVars.add(variable.name);
+                                    }
+                                }
+                                for (const op of block.ops) {
+                                    for (const input of op.inputs) {
+                                        for (const argument of input.arguments) {
+                                            if (blockVars.has(argument)) {
+                                                variables.add(argument);
+                                            }
+                                        }
                                     }
                                 }
                             }
-                        }
-                    }
-                    program.vars = Array.from(variables).sort();
-                    return program;
-                };
-                const loadParams = (metadata, program, stream) => {
-                    const tensors = new Map();
-                    while (stream.position < stream.length) {
-                        tensors.set(program.vars.shift(), new paddle.Tensor(null, stream));
-                    }
-                    return new paddle.Model(metadata, program.format, program.desc, tensors);
-                };
-                switch (match) {
-                    case 'paddle.container': {
-                        const container = paddle.Container.open(context);
-                        return new paddle.Model(metadata, container.format, null, container.weights);
-                    }
-                    case 'paddle.params': {
-                        const file = identifier !== 'params' ? base + '.pdmodel' : 'model';
-                        return context.request(file, null).then((stream) => {
-                            const program = openProgram(stream, 'paddle.pb');
-                            return loadParams(metadata, program, context.stream);
-                        });
-                    }
-                    case 'paddle.pb':
-                    case 'paddle.pbtxt': {
-                        const program = openProgram(context.stream, match);
-                        const loadEntries = (context, program) => {
-                            const promises = program.vars.map((name) => context.request(name, null));
+                            program.vars = Array.from(variables).sort();
+                            return program;
+                        };
+                        const loadParams = (metadata, program, stream) => {
                             const tensors = new Map();
-                            return Promise.all(promises).then((streams) => {
-                                for (let i = 0; i < program.vars.length; i++) {
-                                    tensors.set(program.vars[i], new paddle.Tensor(null, streams[i]));
-                                }
-                                return new paddle.Model(metadata, program.format, program.desc, tensors);
-                            }).catch((/* err */) => {
-                                return new paddle.Model(metadata, program.format, program.desc, tensors);
-                            });
+                            while (stream.position < stream.length) {
+                                const tensor = paddle.Utility.openTensor(stream);
+                                tensors.set(program.vars.shift(), tensor);
+                            }
+                            return new paddle.Model(metadata, program.format, program.desc, tensors);
                         };
-                        if (extension === 'pdmodel') {
-                            return context.request(base + '.pdiparams', null).then((stream) => {
-                                return loadParams(metadata, program, stream);
-                            }).catch((/* err */) => {
-                                return loadEntries(context, program);
-                            });
-                        }
-                        if (identifier === 'model') {
-                            return context.request('params', null).then((stream) => {
-                                return loadParams(metadata, program, stream);
-                            }).catch((/* err */) => {
+                        switch (match) {
+                            case 'paddle.weights': {
+                                const container = paddle.Weights.open(context);
+                                return new paddle.Model(metadata, container.format, null, container.weights);
+                            }
+                            case 'paddle.params': {
+                                const file = identifier !== 'params' ? base + '.pdmodel' : 'model';
+                                return context.request(file, null).then((stream) => {
+                                    const program = openProgram(stream, 'paddle.pb');
+                                    return loadParams(metadata, program, context.stream);
+                                });
+                            }
+                            case 'paddle.pb':
+                            case 'paddle.pbtxt': {
+                                const program = openProgram(context.stream, match);
+                                const loadEntries = (context, program) => {
+                                    const promises = program.vars.map((name) => context.request(name, null));
+                                    const tensors = new Map();
+                                    return Promise.all(promises).then((streams) => {
+                                        for (let i = 0; i < program.vars.length; i++) {
+                                            const tensor = paddle.Utility.openTensor(streams[i]);
+                                            tensors.set(program.vars[i], tensor);
+                                        }
+                                        return new paddle.Model(metadata, program.format, program.desc, tensors);
+                                    }).catch((/* err */) => {
+                                        return new paddle.Model(metadata, program.format, program.desc, tensors);
+                                    });
+                                };
+                                if (extension === 'pdmodel') {
+                                    return context.request(base + '.pdiparams', null).then((stream) => {
+                                        return loadParams(metadata, program, stream);
+                                    }).catch((/* err */) => {
+                                        return loadEntries(context, program);
+                                    });
+                                }
+                                if (identifier === 'model') {
+                                    return context.request('params', null).then((stream) => {
+                                        return loadParams(metadata, program, stream);
+                                    }).catch((/* err */) => {
+                                        return loadEntries(context, program);
+                                    });
+                                }
                                 return loadEntries(context, program);
-                            });
+                            }
                         }
-                        return loadEntries(context, program);
-                    }
+                    });
                 }
-            });
+            }
         });
     }
 };
@@ -190,8 +195,8 @@ paddle.Graph = class {
 
             const args = new Map();
             for (const variable of block.vars) {
-                const type = variable.type && variable.type.type && variable.type.lod_tensor && variable.type.lod_tensor.tensor ? paddle.Utility.createTensorType(variable.type.lod_tensor.tensor) : null;
-                const tensor = variable.persistable && variable.type && variable.type.type != paddle.proto.VarType.Type.FETCH_LIST && variable.type.type != paddle.proto.VarType.Type.FEED_MINIBATCH ? (tensors.get(variable.name) || new paddle.Tensor(type)) : null;
+                const type = variable.type && variable.type.type && variable.type.lod_tensor && variable.type.lod_tensor.tensor ? paddle.Utility.createTensorType(variable.type.lod_tensor.tensor.data_type, variable.type.lod_tensor.tensor.dims) : null;
+                const tensor = variable.persistable && variable.type && variable.type.type != paddle.DataType.FETCH_LIST && variable.type.type != paddle.DataType.FEED_MINIBATCH ? (tensors.get(variable.name) || new paddle.Tensor(type)) : null;
                 args.set(variable.name, new paddle.Argument(variable.name, type, tensor));
             }
 
@@ -436,42 +441,42 @@ paddle.Attribute = class {
         this._name = attr.name;
         this._value = '?';
         switch (attr.type) {
-            case paddle.proto.AttrType.STRING:
+            case paddle.AttributeType.STRING:
                 this._type = 'string';
                 this._value = attr.s;
                 break;
-            case paddle.proto.AttrType.STRINGS:
+            case paddle.AttributeType.STRINGS:
                 this._type = 'string[]';
-                this._value = attr.strings;
+                this._value = Array.from(attr.strings);
                 break;
-            case paddle.proto.AttrType.BOOLEAN:
+            case paddle.AttributeType.BOOLEAN:
                 this._type = 'boolean';
                 this._value = attr.b;
                 break;
-            case paddle.proto.AttrType.BOOLEANS:
+            case paddle.AttributeType.BOOLEANS:
                 this._type = 'boolean[]';
-                this._value = attr.bools;
+                this._value = Array.from(attr.bools);
                 break;
-            case paddle.proto.AttrType.FLOAT:
+            case paddle.AttributeType.FLOAT:
                 this._type = 'float32';
                 this._value = attr.f;
                 break;
-            case paddle.proto.AttrType.FLOATS:
+            case paddle.AttributeType.FLOATS:
                 this._type = 'float[]';
-                this._value = attr.floats;
+                this._value = Array.from(attr.floats);
                 break;
-            case paddle.proto.AttrType.INT:
+            case paddle.AttributeType.INT:
                 this._type = 'int32';
                 this._value = attr.i;
                 break;
-            case paddle.proto.AttrType.INTS:
+            case paddle.AttributeType.INTS:
                 this._type = 'int32[]';
-                this._value = attr.ints;
+                this._value = Array.from(attr.ints);
                 break;
-            case paddle.proto.AttrType.LONG:
+            case paddle.AttributeType.LONG:
                 this._type = 'int64';
                 break;
-            case paddle.proto.AttrType.LONGS:
+            case paddle.AttributeType.LONGS:
                 this._type = 'int64[]';
                 break;
             default:
@@ -524,39 +529,10 @@ paddle.Attribute = class {
 
 paddle.Tensor = class {
 
-    constructor(type, data) {
+    constructor(type, data, kind) {
         this._type = type;
-        if (data && !Array.isArray(data)) {
-            if (data.__class__ && data.__class__.__module__ === 'numpy' && data.__class__.__name__ === 'ndarray') {
-                this._type = new paddle.TensorType(data.dtype.name, new paddle.TensorShape(data.shape));
-                this._data = data.data;
-                this._kind = 'NumPy Array';
-            }
-            else {
-                const uint32 = (stream) => {
-                    const buffer = stream.read(4);
-                    const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength);
-                    return view.getUint32(0, true);
-                };
-                const stream = data;
-                const signature = stream.read(16);
-                if (!signature.every((value) => value === 0x00)) {
-                    throw new paddle.Error('Invalid paddle.TensorDesc signature.');
-                }
-                const length = uint32(stream);
-                const buffer = stream.read(length);
-                const reader = protobuf.BinaryReader.open(buffer);
-                const tensorDesc = paddle.proto.VarType.TensorDesc.decode(reader);
-                const size = tensorDesc.dims.reduce((a, b) => a * b.toNumber(), 1);
-                let itemsize = 0;
-                switch (tensorDesc.data_type) {
-                    case paddle.proto.VarType.Type.FP32: itemsize = 4; break;
-                    default: throw new paddle.Error("Invalid inference params data type '" + tensorDesc.data_type + "'.");
-                }
-                this._type = paddle.Utility.createTensorType(tensorDesc);
-                this._data = stream.read(itemsize * size);
-            }
-        }
+        this._data = data;
+        this._kind = kind || '';
     }
 
     get kind() {
@@ -737,12 +713,12 @@ paddle.TensorShape = class {
 
 paddle.Utility = class {
 
-    static createTensorType(desc) {
+    static createTensorType(data_type, shape) {
         if (!paddle.Utility._dataTypes) {
-            const length = Math.max.apply(null, Object.values(paddle.proto.VarType.Type));
+            const length = Math.max.apply(null, Object.values(paddle.DataType));
             paddle.Utility._dataTypes = new Array(length);
-            for (const key of Object.keys(paddle.proto.VarType.Type)) {
-                const index = paddle.proto.VarType.Type[key];
+            for (const key of Object.keys(paddle.DataType)) {
+                const index = paddle.DataType[key];
                 let name = key.toLowerCase();
                 switch (name) {
                     case 'bool': name = 'boolean'; break;
@@ -754,24 +730,66 @@ paddle.Utility = class {
                 paddle.Utility._dataTypes[index] = name;
             }
         }
-        const dataType = desc.data_type < paddle.Utility._dataTypes.length ? paddle.Utility._dataTypes[desc.data_type] : '?';
-        return new paddle.TensorType(dataType, new paddle.TensorShape(desc.dims));
+        const dataType = data_type < paddle.Utility._dataTypes.length ? paddle.Utility._dataTypes[data_type] : '?';
+        return new paddle.TensorType(dataType, new paddle.TensorShape(shape));
+    }
+
+    static openTensor(stream) {
+        const uint32 = (stream) => {
+            const buffer = stream.read(4);
+            const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength);
+            return view.getUint32(0, true);
+        };
+        const signature = stream.read(16);
+        if (!signature.every((value) => value === 0x00)) {
+            throw new paddle.Error('Invalid paddle.TensorDesc signature.');
+        }
+        const length = uint32(stream);
+        const buffer = stream.read(length);
+        const reader = protobuf.BinaryReader.open(buffer);
+        const tensorDesc = paddle.proto.VarType.TensorDesc.decode(reader);
+        const size = tensorDesc.dims.reduce((a, b) => a * b.toNumber(), 1);
+        let itemsize = 0;
+        switch (tensorDesc.data_type) {
+            case paddle.DataType.FP32: itemsize = 4; break;
+            default: throw new paddle.Error("Invalid inference params data type '" + tensorDesc.data_type + "'.");
+        }
+        const type = paddle.Utility.createTensorType(tensorDesc.data_type, tensorDesc.dims);
+        const data = stream.read(itemsize * size);
+        return new paddle.Tensor(type, data);
+    }
+
+    static formatVersion(version) {
+        if (version && version.version && version.version.toNumber) {
+            const number = version.version.toNumber();
+            if (number > 0) {
+                const list = [ Math.floor(number / 1000000) % 1000, Math.floor(number / 1000) % 1000, number % 1000 ];
+                if (list.slice(-1).pop() === 0) {
+                    list.pop();
+                    if (list.slice(-1).pop() === 0) {
+                        list.pop();
+                    }
+                }
+                return ' v' + list.map((item) => item.toString()).join('.');
+            }
+        }
+        return '';
     }
 };
 
-paddle.Container = class {
+paddle.Weights = class {
 
     static open(context) {
         const extension = [ 'zip', 'tar' ].find((extension) => context.entries(extension).size > 0);
         if (extension) {
             const entries = new Map(Array.from(context.entries(extension)).filter((entry) => !entry[0].endsWith('/') && !entry[0].split('/').pop().startsWith('.')).slice());
             if (entries.size > 2 && Array.from(entries).every((entry) => entry[0].split('_').length > 0 && entry[1].peek(16).every((value) => value === 0x00))) {
-                return new paddle.Container('entries', entries);
+                return new paddle.Weights('entries', entries);
             }
         }
         const obj = context.open('pkl');
         if (obj && !Array.isArray(obj) && Object(obj) === obj) {
-            return new paddle.Container('pdparams', obj);
+            return new paddle.Weights('pdparams', obj);
         }
         return null;
     }
@@ -820,7 +838,7 @@ paddle.Container = class {
                         if (entry[0].startsWith(rootFolder)) {
                             const name = entry[0].substring(rootFolder.length);
                             const stream = entry[1];
-                            const tensor = new paddle.Tensor(null, stream);
+                            const tensor = paddle.Utility.openTensor(stream);
                             this._weights.set(name, tensor);
                         }
                     }
@@ -833,7 +851,10 @@ paddle.Container = class {
                         const value = this._data[key];
                         if (value && !Array.isArray(value) && value.__class__ && value.__class__.__module__ === 'numpy' && value.__class__.__name__ === 'ndarray') {
                             const name = map ? map[key] : key;
-                            this._weights.set(name, new paddle.Tensor(null, value));
+                            const type = new paddle.TensorType(value.dtype.name, new paddle.TensorShape(value.shape));
+                            const data = value.data;
+                            const tensor = new paddle.Tensor(type, data, 'NumPy Array');
+                            this._weights.set(name, tensor);
                         }
                     }
                     break;
@@ -844,6 +865,186 @@ paddle.Container = class {
     }
 };
 
+paddle.NaiveBuffer = class {
+
+    static open(context) {
+        const stream = context.stream;
+        if (stream.length > 4) {
+            const buffer = stream.peek();
+            const reader = new paddle.BinaryReader(buffer);
+            if (context.identifier === '__model__.nb' || context.identifier === 'param.nb') {
+                if (buffer[0] > 2 || buffer[1] !== 0x00 || buffer[2] !== 0x76 || buffer[2] !== 0x32) {
+                    return new paddle.NaiveBuffer(reader, -1);
+                }
+            }
+            const meta_version = reader.uint16();
+            if (meta_version <= 2) {
+                return new paddle.NaiveBuffer(reader, meta_version);
+            }
+        }
+        return null;
+    }
+
+    constructor(reader, meta_version) {
+        this.reader = reader;
+        this.meta_version = meta_version;
+    }
+
+    get format() {
+        this._read();
+        return 'Paddle Lite' + (this.opt_version ? ' ' + this.opt_version : '');
+    }
+
+    get model() {
+        this._read();
+        return this._model;
+    }
+
+    get weights() {
+        this._read();
+        return this._weights;
+    }
+
+    _read() {
+        if (this.reader) {
+            const reader = this.reader;
+            delete this.reader;
+            const decoder = new TextDecoder();
+            const opt_version = reader.read(16);
+            this.opt_version = decoder.decode(opt_version.slice(0, opt_version.indexOf(0x00)));
+            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.toString() + ' 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('Paddle Lite naive buffer meta format ' + this.meta_version.toString() + ' not supported.');
+                }
+            }
+        }
+    }
+};
+
+paddle.BinaryReader = class {
+
+    constructor(data) {
+        this._buffer = data instanceof Uint8Array ? data : data.peek();
+        this._position = 0;
+        this._dataView = new DataView(this._buffer.buffer, this._buffer.byteOffset, this._buffer.byteLength);
+    }
+
+    skip(offset) {
+        const position = this._position;
+        this._position += offset;
+        if (this._position > this._length) {
+            throw new Error('Expected ' + (this._position - this._length) + ' more bytes. The file might be corrupted. Unexpected end of file.');
+        }
+        return position;
+    }
+
+    read(size) {
+        const position = this._position;
+        this.skip(size);
+        return this._buffer.subarray(position, this._position);
+    }
+
+    uint16() {
+        const position = this.skip(2);
+        return this._dataView.getUint16(position, true);
+    }
+
+    uint32() {
+        const position = this.skip(4);
+        return this._dataView.getUint32(position, true);
+    }
+
+    uint64() {
+        const position = this.skip(8);
+        return this._dataView.getUint64(position, true).toNumber();
+    }
+};
+
+paddle.DataType = {
+    BOOL: 0,
+    INT16: 1,
+    INT32: 2,
+    INT64: 3,
+    FP16: 4,
+    FP32: 5,
+    FP64: 6,
+    LOD_TENSOR: 7,
+    SELECTED_ROWS: 8,
+    FEED_MINIBATCH: 9,
+    FETCH_LIST: 10,
+    STEP_SCOPES: 11,
+    LOD_RANK_TABLE: 12,
+    LOD_TENSOR_ARRAY: 13,
+    PLACE_LIST: 14,
+    READER: 15,
+    RAW: 17,
+    TUPLE: 18,
+    SIZE_T: 19,
+    UINT8: 20,
+    INT8: 21,
+    BF16: 22,
+    COMPLEX64: 23,
+    COMPLEX128: 24,
+};
+
+paddle.AttributeType = {
+    INT: 0,
+    FLOAT: 1,
+    STRING: 2,
+    INTS: 3,
+    FLOATS: 4,
+    STRINGS: 5,
+    BOOLEAN: 6,
+    BOOLEANS: 7,
+    BLOCK: 8,
+    LONG: 9,
+    BLOCKS: 10,
+    LONGS: 11,
+    FLOAT64S: 12
+};
+
 paddle.Metadata = class {
 
     static open(context) {

+ 1 - 2
source/view.js

@@ -1455,7 +1455,7 @@ view.ModelFactoryService = class {
         this.register('./sklearn', [ '.pkl', '.pickle', '.joblib', '.model', '.meta', '.pb', '.pt', '.h5', '.pkl.z', '.joblib.z' ]);
         this.register('./pickle', [ '.pkl', '.pickle', '.joblib', '.model', '.meta', '.pb', '.pt', '.h5', '.pkl.z', '.joblib.z' ]);
         this.register('./cntk', [ '.model', '.cntk', '.cmf', '.dnn' ]);
-        this.register('./paddle', [ '.pdmodel', '.pdparams', '.pdiparams', '.paddle', '__model__', '.__model__', '.pbtxt', '.txt', '.tar', '.tar.gz' ]);
+        this.register('./paddle', [ '.pdmodel', '.pdparams', '.pdiparams', '.paddle', '__model__', '.__model__', '.pbtxt', '.txt', '.tar', '.tar.gz', '.nb' ]);
         this.register('./bigdl', [ '.model', '.bigdl' ]);
         this.register('./darknet', [ '.cfg', '.model', '.txt', '.weights' ]);
         this.register('./weka', [ '.model' ]);
@@ -1478,7 +1478,6 @@ view.ModelFactoryService = class {
         this.register('./acuity', [ '.json' ]);
         this.register('./imgdnn', [ '.dnn', 'params', '.json' ]);
         this.register('./om', [ '.om', '.onnx', '.pb' ]);
-        this.register('./nb', [ '.nb' ]);
     }
 
     register(id, extensions) {

+ 15 - 16
test/models.json

@@ -2813,22 +2813,6 @@
     "format": "MXNet Model Archive v1.0",
     "link":   "https://github.com/lutzroeder/netron/issues/286"
   },
-  {
-    "type":   "nb",
-    "target": "lite_naive_model_opt.nb.tar.gz",
-    "source": "https://github.com/lutzroeder/netron/files/7084134/lite_naive_model_opt.nb.tar.gz",
-    "error":  "Invalid file content. File contains Paddle Lite naive buffer data.",
-    "format": "Paddle Lite",
-    "link":   "https://github.com/lutzroeder/netron/issues/797"
-  },
-  {
-    "type":   "nb",
-    "target": "mobilenet_v1_opt.nb.tar.gz",
-    "source": "https://github.com/lutzroeder/netron/files/7084157/mobilenet_v1_opt.nb.tar.gz",
-    "error":  "Invalid file content. File contains Paddle Lite naive buffer data.",
-    "format": "Paddle Lite",
-    "link":   "https://github.com/lutzroeder/netron/issues/797"
-  },
   {
     "type":   "nnabla",
     "target": "tecogan_model.h5",
@@ -4043,6 +4027,14 @@
     "format": "PaddlePaddle",
     "link":   "https://github.com/lutzroeder/netron/issues/552"
   },
+  {
+    "type":   "paddle",
+    "target": "lite_naive_model_opt.nb.tar.gz",
+    "source": "https://github.com/lutzroeder/netron/files/7084134/lite_naive_model_opt.nb.tar.gz",
+    "error":  "Paddle Lite naive buffer format is deprecated in '__model__.nb'.",
+    "format": "Paddle Lite",
+    "link":   "https://github.com/lutzroeder/netron/issues/797"
+  },
   {
     "type":   "paddle",
     "target": "PyramidBox_WiderFace.tar.gz",
@@ -4085,6 +4077,13 @@
     "format": "PaddlePaddle",
     "link":   "https://github.com/lutzroeder/netron/issues/198"
   },
+  {
+    "type":   "paddle",
+    "target": "squeezenet1.1.nb",
+    "source": "https://github.com/lutzroeder/netron/files/7272515/squeezenet1.1.nb.zip[squeezenet1.1.nb]",
+    "format": "Paddle Lite v2.9.1",
+    "link":   "https://github.com/lutzroeder/netron/issues/797"
+  },
   {
     "type":   "paddle",
     "target": "vgg_ilsvrc_16_fc_reduced.tar.gz",

+ 5 - 0
tools/paddle

@@ -6,18 +6,23 @@ pushd $(cd $(dirname ${0})/..; pwd) > /dev/null
 clean() {
     echo "paddle clean"
     rm -rf "./third_party/source/paddle"
+    rm -rf "./third_party/source/Paddle-Lite"
 }
 
 sync() {
     echo "paddle sync"
     mkdir -p "./third_party/source/paddle/paddle/fluid/framework"
     curl --silent --location --output "./third_party/source/paddle/paddle/fluid/framework/framework.proto" "https://github.com/PaddlePaddle/Paddle/blob/develop/paddle/fluid/framework/framework.proto?raw=true"
+    mkdir -p "./third_party/source/Paddle-Lite/lite/model_parser/flatbuffers"
+    curl --silent --location --output "./third_party/source/Paddle-Lite/lite/model_parser/flatbuffers/framework.fbs" "https://github.com/PaddlePaddle/Paddle-Lite/blob/develop/lite/model_parser/flatbuffers/framework.fbs?raw=true"
+    curl --silent --location --output "./third_party/source/Paddle-Lite/lite/model_parser/flatbuffers/param.fbs" "https://github.com/PaddlePaddle/Paddle-Lite/blob/develop/lite/model_parser/flatbuffers/param.fbs?raw=true"
 }
 
 schema() {
     echo "paddle schema"
     [[ $(grep -U $'\x0D' ./source/paddle-proto.js) ]] && crlf=1
     node ./tools/protoc.js --root paddle --text --out ./source/paddle-proto.js ./third_party/source/paddle/paddle/fluid/framework/framework.proto
+    node ./tools/flatc.js --text --root paddlelite --out ./source/paddle-schema.js ./third_party/source/Paddle-Lite/lite/model_parser/flatbuffers/param.fbs
     if [[ -n ${crlf} ]]; then
         unix2dos --quiet --newfile ./source/paddle-proto.js ./source/paddle-proto.js
     fi