Browse Source

Add UFF prototype (#511)

Lutz Roeder 5 years ago
parent
commit
f764c0d061
8 changed files with 1504 additions and 15 deletions
  1. 2 0
      electron-builder.yml
  2. 2 6
      src/app.js
  3. 2 0
      src/hdf5.js
  4. 1 1
      src/index.html
  5. 127 0
      src/uff-metadata.json
  6. 916 0
      src/uff-proto.js
  7. 371 8
      src/uff.js
  8. 83 0
      tools/uff.proto

+ 2 - 0
electron-builder.yml

@@ -57,6 +57,8 @@ fileAssociations:
     ext: tfl
   - name: "Tengine"
     ext: tmfile
+  - name: "UFF Model"
+    ext: uff
 afterSign: "./setup/notarize.js"
 publish:
   - provider: github

+ 2 - 6
src/app.js

@@ -123,14 +123,10 @@ class Application {
                     'h5', 'hd5', 'hdf5', 'json', 'keras',
                     'mlmodel',
                     'caffemodel',
-                    'model', 'dnn', 'cmf',
-                    'mar', 'params',
-                    'mnn',
+                    'model', 'dnn', 'cmf', 'mar', 'params',
                     'meta',
                     'tflite', 'lite', 'tfl', 'bin',
-                    'armnn',
-                    'param', 'ncnn',
-                    'nn',
+                    'armnn', 'param', 'ncnn', 'mnn', 'nn', 'uff', 'uff.txt',
                     'tmfile',
                     'pt', 'pth', 't7',
                     'pkl', 'joblib',

+ 2 - 0
src/hdf5.js

@@ -862,6 +862,8 @@ hdf5.Datatype = class {
                 return 'string';
             case 5: // opaque
                 return 'uint8[]';
+            case 8: // enumerated
+                return 'enumeration[' + (this._flags & 0xffff).toString() + ']';
             case 9: // variable-length
                 if ((this._flags & 0x0f) == 1) { // type
                     return 'char[]';

+ 1 - 1
src/index.html

@@ -280,7 +280,7 @@ body { overflow: hidden; margin: 0; width: 100vw; height: 100vh; font-family: -a
     <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="download-button" class="center download-button">Download App</button>
-    <input type="file" id="open-file-dialog" class="open-file-dialog" multiple="false" accept=".onnx, .pb, .meta, .tflite, .lite, .tfl, .bin, .keras, .h5, .hd5, .hdf5, .json, .model, .mar, .params, .param, .armnn, .mnn, .ncnn, .nn, .dnn, .cmf, .mlmodel, .caffemodel, .pbtxt, .prototxt, .pkl, .pt, .pth, .t7, .joblib, .cfg, .xml">
+    <input type="file" id="open-file-dialog" class="open-file-dialog" multiple="false" accept=".onnx, .pb, .meta, .tflite, .lite, .tfl, .bin, .keras, .h5, .hd5, .hdf5, .json, .model, .mar, .params, .param, .armnn, .mnn, .ncnn, .nn, .uff, .dnn, .cmf, .mlmodel, .caffemodel, .pbtxt, .prototxt, .pkl, .pt, .pth, .t7, .joblib, .cfg, .xml">
     <!-- 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>

+ 127 - 0
src/uff-metadata.json

@@ -1,2 +1,129 @@
 [
+  {
+    "name": "Activation",
+    "schema": {
+      "category": "Activation",
+      "inputs": [
+        { "name": "input" }
+      ]
+    }
+  },
+  {
+    "name": "Binary",
+    "schema": {
+      "inputs": [
+        { "name": "x" },
+        { "name": "y" }
+      ]
+    }
+  },
+  {
+    "name": "Unary",
+    "schema": {
+      "inputs": [
+        { "name": "input" }
+      ]
+    }
+  },
+  {
+    "name": "Conv",
+    "schema": {
+      "category": "Layer",
+      "inputs": [
+        { "name": "input" },
+        { "name": "kernel" }
+      ]
+    }
+  },
+  {
+    "name": "FullyConnected",
+    "schema": {
+      "category": "Layer",
+      "inputs": [
+        { "name": "input" },
+        { "name": "weights" }
+      ]
+    }
+  },
+  {
+    "name": "Reshape",
+    "schema": {
+      "category": "Shape",
+      "inputs": [
+        { "name": "input" },
+        { "name": "shape" }
+      ]
+    }
+  },
+  {
+    "name": "StridedSlice",
+    "schema": {
+      "category": "Tensor",
+      "inputs": [
+        { "name": "input" },
+        { "name": "begin" },
+        { "name": "end" },
+        { "name": "strides" }
+      ]
+    }
+  },
+  {
+    "name": "Squeeze",
+    "schema": {
+      "category": "Transform"
+    }
+  },
+  {
+    "name": "BatchNorm",
+    "schema": {
+      "category": "Normalization",
+      "inputs": [
+        { "name": "input" },
+        { "name": "gamma" },
+        { "name": "beta" },
+        { "name": "moving_mean" },
+        { "name": "moving_variance" }
+      ]
+    }
+  },
+  {
+    "name": "Pool",
+    "schema": {
+      "category": "Pool",
+      "inputs": [
+        { "name": "input" }
+      ]
+    }
+  },
+  {
+    "name": "_MaxPool",
+    "schema": {
+      "category": "Pool",
+      "inputs": [
+        { "name": "input" }
+      ]
+    }
+  },
+  {
+    "name": "Concat",
+    "schema": {
+      "category": "Tensor"
+    }
+  },
+  {
+    "name": "Flatten",
+    "schema": {
+      "category": "Shape"
+    }
+  },
+  {
+    "name": "GatherV2",
+    "schema": {
+      "category": "Data",
+      "inputs": [
+        { "name": "input" },
+        { "name": "indices" }
+      ]
+    }
+  }
 ]

+ 916 - 0
src/uff-proto.js

@@ -13,6 +13,9 @@
         uff.MetaGraph = (function() {
     
             function MetaGraph(properties) {
+                this.descriptors = [];
+                this.graphs = [];
+                this.referenced_data = [];
                 if (properties)
                     for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
                         if (properties[keys[i]] != null)
@@ -21,6 +24,9 @@
     
             MetaGraph.prototype.version = $util.Long ? $util.Long.fromBits(0,0,false) : 0;
             MetaGraph.prototype.descriptor_core_version = $util.Long ? $util.Long.fromBits(0,0,false) : 0;
+            MetaGraph.prototype.descriptors = $util.emptyArray;
+            MetaGraph.prototype.graphs = $util.emptyArray;
+            MetaGraph.prototype.referenced_data = $util.emptyArray;
     
             MetaGraph.decode = function decode(reader, length) {
                 if (!(reader instanceof $Reader))
@@ -35,6 +41,21 @@
                     case 2:
                         message.descriptor_core_version = reader.int64();
                         break;
+                    case 3:
+                        if (!(message.descriptors && message.descriptors.length))
+                            message.descriptors = [];
+                        message.descriptors.push($root.uff.Descriptor.decode(reader, reader.uint32()));
+                        break;
+                    case 4:
+                        if (!(message.graphs && message.graphs.length))
+                            message.graphs = [];
+                        message.graphs.push($root.uff.Graph.decode(reader, reader.uint32()));
+                        break;
+                    case 5:
+                        if (!(message.referenced_data && message.referenced_data.length))
+                            message.referenced_data = [];
+                        message.referenced_data.push($root.uff.KeyValuePair.decode(reader, reader.uint32()));
+                        break;
                     default:
                         reader.skipType(tag & 7);
                         break;
@@ -55,6 +76,21 @@
                     case "descriptor_core_version":
                         message.descriptor_core_version = reader.int64();
                         break;
+                    case "descriptors":
+                        if (!(message.descriptors && message.descriptors.length))
+                            message.descriptors = [];
+                        message.descriptors.push($root.uff.Descriptor.decodeText(reader, true));
+                        break;
+                    case "graphs":
+                        if (!(message.graphs && message.graphs.length))
+                            message.graphs = [];
+                        message.graphs.push($root.uff.Graph.decodeText(reader, true));
+                        break;
+                    case "referenced_data":
+                        if (!(message.referenced_data && message.referenced_data.length))
+                            message.referenced_data = [];
+                        message.referenced_data.push($root.uff.KeyValuePair.decodeText(reader, true));
+                        break;
                     default:
                         reader.field(tag, message);
                         break;
@@ -66,6 +102,886 @@
             return MetaGraph;
         })();
     
+        uff.Descriptor = (function() {
+    
+            function Descriptor(properties) {
+                if (properties)
+                    for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                        if (properties[keys[i]] != null)
+                            this[keys[i]] = properties[keys[i]];
+            }
+    
+            Descriptor.prototype.id = "";
+            Descriptor.prototype.version = $util.Long ? $util.Long.fromBits(0,0,false) : 0;
+    
+            Descriptor.decode = function decode(reader, length) {
+                if (!(reader instanceof $Reader))
+                    reader = $Reader.create(reader);
+                var end = length === undefined ? reader.len : reader.pos + length, message = new $root.uff.Descriptor();
+                while (reader.pos < end) {
+                    var tag = reader.uint32();
+                    switch (tag >>> 3) {
+                    case 1:
+                        message.id = reader.string();
+                        break;
+                    case 2:
+                        message.version = reader.int64();
+                        break;
+                    default:
+                        reader.skipType(tag & 7);
+                        break;
+                    }
+                }
+                if (!message.hasOwnProperty("id"))
+                    throw $util.ProtocolError("missing required 'id'", { instance: message });
+                if (!message.hasOwnProperty("version"))
+                    throw $util.ProtocolError("missing required 'version'", { instance: message });
+                return message;
+            };
+    
+            Descriptor.decodeText = function decodeText(reader) {
+                var message = new $root.uff.Descriptor();
+                reader.start();
+                while (!reader.end()) {
+                    var tag = reader.tag();
+                    switch (tag) {
+                    case "id":
+                        message.id = reader.string();
+                        break;
+                    case "version":
+                        message.version = reader.int64();
+                        break;
+                    default:
+                        reader.field(tag, message);
+                        break;
+                    }
+                }
+                if (!message.hasOwnProperty("id"))
+                    throw $util.ProtocolError("missing required 'id'", { instance: message });
+                if (!message.hasOwnProperty("version"))
+                    throw $util.ProtocolError("missing required 'version'", { instance: message });
+                return message;
+            };
+    
+            return Descriptor;
+        })();
+    
+        uff.Graph = (function() {
+    
+            function Graph(properties) {
+                this.nodes = [];
+                if (properties)
+                    for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                        if (properties[keys[i]] != null)
+                            this[keys[i]] = properties[keys[i]];
+            }
+    
+            Graph.prototype.id = "";
+            Graph.prototype.nodes = $util.emptyArray;
+    
+            Graph.decode = function decode(reader, length) {
+                if (!(reader instanceof $Reader))
+                    reader = $Reader.create(reader);
+                var end = length === undefined ? reader.len : reader.pos + length, message = new $root.uff.Graph();
+                while (reader.pos < end) {
+                    var tag = reader.uint32();
+                    switch (tag >>> 3) {
+                    case 1:
+                        message.id = reader.string();
+                        break;
+                    case 2:
+                        if (!(message.nodes && message.nodes.length))
+                            message.nodes = [];
+                        message.nodes.push($root.uff.Node.decode(reader, reader.uint32()));
+                        break;
+                    default:
+                        reader.skipType(tag & 7);
+                        break;
+                    }
+                }
+                return message;
+            };
+    
+            Graph.decodeText = function decodeText(reader) {
+                var message = new $root.uff.Graph();
+                reader.start();
+                while (!reader.end()) {
+                    var tag = reader.tag();
+                    switch (tag) {
+                    case "id":
+                        message.id = reader.string();
+                        break;
+                    case "nodes":
+                        if (!(message.nodes && message.nodes.length))
+                            message.nodes = [];
+                        message.nodes.push($root.uff.Node.decodeText(reader, true));
+                        break;
+                    default:
+                        reader.field(tag, message);
+                        break;
+                    }
+                }
+                return message;
+            };
+    
+            return Graph;
+        })();
+    
+        uff.Node = (function() {
+    
+            function Node(properties) {
+                this.inputs = [];
+                this.fields = [];
+                this.extra_fields = [];
+                if (properties)
+                    for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                        if (properties[keys[i]] != null)
+                            this[keys[i]] = properties[keys[i]];
+            }
+    
+            Node.prototype.id = "";
+            Node.prototype.inputs = $util.emptyArray;
+            Node.prototype.operation = "";
+            Node.prototype.fields = $util.emptyArray;
+            Node.prototype.extra_fields = $util.emptyArray;
+    
+            Node.decode = function decode(reader, length) {
+                if (!(reader instanceof $Reader))
+                    reader = $Reader.create(reader);
+                var end = length === undefined ? reader.len : reader.pos + length, message = new $root.uff.Node();
+                while (reader.pos < end) {
+                    var tag = reader.uint32();
+                    switch (tag >>> 3) {
+                    case 1:
+                        message.id = reader.string();
+                        break;
+                    case 2:
+                        if (!(message.inputs && message.inputs.length))
+                            message.inputs = [];
+                        message.inputs.push(reader.string());
+                        break;
+                    case 3:
+                        message.operation = reader.string();
+                        break;
+                    case 4:
+                        if (!(message.fields && message.fields.length))
+                            message.fields = [];
+                        message.fields.push($root.uff.KeyValuePair.decode(reader, reader.uint32()));
+                        break;
+                    case 5:
+                        if (!(message.extra_fields && message.extra_fields.length))
+                            message.extra_fields = [];
+                        message.extra_fields.push($root.uff.KeyValuePair.decode(reader, reader.uint32()));
+                        break;
+                    default:
+                        reader.skipType(tag & 7);
+                        break;
+                    }
+                }
+                if (!message.hasOwnProperty("id"))
+                    throw $util.ProtocolError("missing required 'id'", { instance: message });
+                if (!message.hasOwnProperty("operation"))
+                    throw $util.ProtocolError("missing required 'operation'", { instance: message });
+                return message;
+            };
+    
+            Node.decodeText = function decodeText(reader) {
+                var message = new $root.uff.Node();
+                reader.start();
+                while (!reader.end()) {
+                    var tag = reader.tag();
+                    switch (tag) {
+                    case "id":
+                        message.id = reader.string();
+                        break;
+                    case "inputs":
+                        if (!(message.inputs && message.inputs.length))
+                            message.inputs = [];
+                        if (reader.first())
+                            while (!reader.last()) {
+                                message.inputs.push(reader.string());
+                                reader.next();
+                            }
+                        else
+                            message.inputs.push(reader.string());
+                        break;
+                    case "operation":
+                        message.operation = reader.string();
+                        break;
+                    case "fields":
+                        if (!(message.fields && message.fields.length))
+                            message.fields = [];
+                        message.fields.push($root.uff.KeyValuePair.decodeText(reader, true));
+                        break;
+                    case "extra_fields":
+                        if (!(message.extra_fields && message.extra_fields.length))
+                            message.extra_fields = [];
+                        message.extra_fields.push($root.uff.KeyValuePair.decodeText(reader, true));
+                        break;
+                    default:
+                        reader.field(tag, message);
+                        break;
+                    }
+                }
+                if (!message.hasOwnProperty("id"))
+                    throw $util.ProtocolError("missing required 'id'", { instance: message });
+                if (!message.hasOwnProperty("operation"))
+                    throw $util.ProtocolError("missing required 'operation'", { instance: message });
+                return message;
+            };
+    
+            return Node;
+        })();
+    
+        uff.KeyValuePair = (function() {
+    
+            function KeyValuePair(properties) {
+                if (properties)
+                    for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                        if (properties[keys[i]] != null)
+                            this[keys[i]] = properties[keys[i]];
+            }
+    
+            KeyValuePair.prototype.key = "";
+            KeyValuePair.prototype.value = null;
+    
+            KeyValuePair.decode = function decode(reader, length) {
+                if (!(reader instanceof $Reader))
+                    reader = $Reader.create(reader);
+                var end = length === undefined ? reader.len : reader.pos + length, message = new $root.uff.KeyValuePair();
+                while (reader.pos < end) {
+                    var tag = reader.uint32();
+                    switch (tag >>> 3) {
+                    case 1:
+                        message.key = reader.string();
+                        break;
+                    case 2:
+                        message.value = $root.uff.Value.decode(reader, reader.uint32());
+                        break;
+                    default:
+                        reader.skipType(tag & 7);
+                        break;
+                    }
+                }
+                if (!message.hasOwnProperty("key"))
+                    throw $util.ProtocolError("missing required 'key'", { instance: message });
+                if (!message.hasOwnProperty("value"))
+                    throw $util.ProtocolError("missing required 'value'", { instance: message });
+                return message;
+            };
+    
+            KeyValuePair.decodeText = function decodeText(reader) {
+                var message = new $root.uff.KeyValuePair();
+                reader.start();
+                while (!reader.end()) {
+                    var tag = reader.tag();
+                    switch (tag) {
+                    case "key":
+                        message.key = reader.string();
+                        break;
+                    case "value":
+                        message.value = $root.uff.Value.decodeText(reader, true);
+                        break;
+                    default:
+                        reader.field(tag, message);
+                        break;
+                    }
+                }
+                if (!message.hasOwnProperty("key"))
+                    throw $util.ProtocolError("missing required 'key'", { instance: message });
+                if (!message.hasOwnProperty("value"))
+                    throw $util.ProtocolError("missing required 'value'", { instance: message });
+                return message;
+            };
+    
+            return KeyValuePair;
+        })();
+    
+        uff.Value = (function() {
+    
+            function Value(properties) {
+                if (properties)
+                    for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                        if (properties[keys[i]] != null)
+                            this[keys[i]] = properties[keys[i]];
+            }
+    
+            Value.prototype.s = "";
+            Value.prototype.s_list = null;
+            Value.prototype.d = 0;
+            Value.prototype.d_list = null;
+            Value.prototype.b = false;
+            Value.prototype.b_list = false;
+            Value.prototype.i = $util.Long ? $util.Long.fromBits(0,0,false) : 0;
+            Value.prototype.i_list = null;
+            Value.prototype.blob = $util.newBuffer([]);
+            Value.prototype.ref = "";
+            Value.prototype.dtype = 65544;
+            Value.prototype.dtype_list = null;
+            Value.prototype.dim_orders = null;
+            Value.prototype.dim_orders_list = null;
+    
+            var $oneOfFields;
+    
+            Object.defineProperty(Value.prototype, "type", {
+                get: $util.oneOfGetter($oneOfFields = ["s", "s_list", "d", "d_list", "b", "b_list", "i", "i_list", "blob", "ref", "dtype", "dtype_list", "dim_orders", "dim_orders_list"]),
+                set: $util.oneOfSetter($oneOfFields)
+            });
+    
+            Value.decode = function decode(reader, length) {
+                if (!(reader instanceof $Reader))
+                    reader = $Reader.create(reader);
+                var end = length === undefined ? reader.len : reader.pos + length, message = new $root.uff.Value();
+                while (reader.pos < end) {
+                    var tag = reader.uint32();
+                    switch (tag >>> 3) {
+                    case 1:
+                        message.s = reader.string();
+                        break;
+                    case 2:
+                        message.s_list = $root.uff.ListString.decode(reader, reader.uint32());
+                        break;
+                    case 3:
+                        message.d = reader.double();
+                        break;
+                    case 4:
+                        message.d_list = $root.uff.ListDouble.decode(reader, reader.uint32());
+                        break;
+                    case 5:
+                        message.b = reader.bool();
+                        break;
+                    case 6:
+                        message.b_list = reader.bool();
+                        break;
+                    case 7:
+                        message.i = reader.int64();
+                        break;
+                    case 8:
+                        message.i_list = $root.uff.ListInt.decode(reader, reader.uint32());
+                        break;
+                    case 9:
+                        message.blob = reader.bytes();
+                        break;
+                    case 100:
+                        message.ref = reader.string();
+                        break;
+                    case 101:
+                        message.dtype = reader.int32();
+                        break;
+                    case 102:
+                        message.dtype_list = $root.uff.ListDataType.decode(reader, reader.uint32());
+                        break;
+                    case 103:
+                        message.dim_orders = $root.uff.DimOrders.decode(reader, reader.uint32());
+                        break;
+                    case 104:
+                        message.dim_orders_list = $root.uff.ListDimOrders.decode(reader, reader.uint32());
+                        break;
+                    default:
+                        reader.skipType(tag & 7);
+                        break;
+                    }
+                }
+                return message;
+            };
+    
+            Value.decodeText = function decodeText(reader) {
+                var message = new $root.uff.Value();
+                reader.start();
+                while (!reader.end()) {
+                    var tag = reader.tag();
+                    switch (tag) {
+                    case "s":
+                        message.s = reader.string();
+                        break;
+                    case "s_list":
+                        message.s_list = $root.uff.ListString.decodeText(reader, true);
+                        break;
+                    case "d":
+                        message.d = reader.double();
+                        break;
+                    case "d_list":
+                        message.d_list = $root.uff.ListDouble.decodeText(reader, true);
+                        break;
+                    case "b":
+                        message.b = reader.bool();
+                        break;
+                    case "b_list":
+                        message.b_list = reader.bool();
+                        break;
+                    case "i":
+                        message.i = reader.int64();
+                        break;
+                    case "i_list":
+                        message.i_list = $root.uff.ListInt.decodeText(reader, true);
+                        break;
+                    case "blob":
+                        message.blob = reader.bytes();
+                        break;
+                    case "ref":
+                        message.ref = reader.string();
+                        break;
+                    case "dtype":
+                        message.dtype = reader.enum($root.uff.DataType);
+                        break;
+                    case "dtype_list":
+                        message.dtype_list = $root.uff.ListDataType.decodeText(reader, true);
+                        break;
+                    case "dim_orders":
+                        message.dim_orders = $root.uff.DimOrders.decodeText(reader, true);
+                        break;
+                    case "dim_orders_list":
+                        message.dim_orders_list = $root.uff.ListDimOrders.decodeText(reader, true);
+                        break;
+                    default:
+                        reader.field(tag, message);
+                        break;
+                    }
+                }
+                return message;
+            };
+    
+            return Value;
+        })();
+    
+        uff.DataType = (function() {
+            var valuesById = {}, values = Object.create(valuesById);
+            values[valuesById[65544] = "DT_INT8"] = 65544;
+            values[valuesById[65552] = "DT_INT16"] = 65552;
+            values[valuesById[65568] = "DT_INT32"] = 65568;
+            values[valuesById[65600] = "DT_INT64"] = 65600;
+            values[valuesById[131088] = "DT_FLOAT16"] = 131088;
+            values[valuesById[131104] = "DT_FLOAT32"] = 131104;
+            return values;
+        })();
+    
+        uff.DimOrder = (function() {
+    
+            function DimOrder(properties) {
+                if (properties)
+                    for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                        if (properties[keys[i]] != null)
+                            this[keys[i]] = properties[keys[i]];
+            }
+    
+            DimOrder.prototype.key = $util.Long ? $util.Long.fromBits(0,0,false) : 0;
+            DimOrder.prototype.value = null;
+    
+            DimOrder.decode = function decode(reader, length) {
+                if (!(reader instanceof $Reader))
+                    reader = $Reader.create(reader);
+                var end = length === undefined ? reader.len : reader.pos + length, message = new $root.uff.DimOrder();
+                while (reader.pos < end) {
+                    var tag = reader.uint32();
+                    switch (tag >>> 3) {
+                    case 1:
+                        message.key = reader.int64();
+                        break;
+                    case 2:
+                        message.value = $root.uff.ListInt.decode(reader, reader.uint32());
+                        break;
+                    default:
+                        reader.skipType(tag & 7);
+                        break;
+                    }
+                }
+                if (!message.hasOwnProperty("key"))
+                    throw $util.ProtocolError("missing required 'key'", { instance: message });
+                if (!message.hasOwnProperty("value"))
+                    throw $util.ProtocolError("missing required 'value'", { instance: message });
+                return message;
+            };
+    
+            DimOrder.decodeText = function decodeText(reader) {
+                var message = new $root.uff.DimOrder();
+                reader.start();
+                while (!reader.end()) {
+                    var tag = reader.tag();
+                    switch (tag) {
+                    case "key":
+                        message.key = reader.int64();
+                        break;
+                    case "value":
+                        message.value = $root.uff.ListInt.decodeText(reader, true);
+                        break;
+                    default:
+                        reader.field(tag, message);
+                        break;
+                    }
+                }
+                if (!message.hasOwnProperty("key"))
+                    throw $util.ProtocolError("missing required 'key'", { instance: message });
+                if (!message.hasOwnProperty("value"))
+                    throw $util.ProtocolError("missing required 'value'", { instance: message });
+                return message;
+            };
+    
+            return DimOrder;
+        })();
+    
+        uff.DimOrders = (function() {
+    
+            function DimOrders(properties) {
+                this.orders = [];
+                if (properties)
+                    for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                        if (properties[keys[i]] != null)
+                            this[keys[i]] = properties[keys[i]];
+            }
+    
+            DimOrders.prototype.orders = $util.emptyArray;
+    
+            DimOrders.decode = function decode(reader, length) {
+                if (!(reader instanceof $Reader))
+                    reader = $Reader.create(reader);
+                var end = length === undefined ? reader.len : reader.pos + length, message = new $root.uff.DimOrders();
+                while (reader.pos < end) {
+                    var tag = reader.uint32();
+                    switch (tag >>> 3) {
+                    case 1:
+                        if (!(message.orders && message.orders.length))
+                            message.orders = [];
+                        message.orders.push($root.uff.DimOrder.decode(reader, reader.uint32()));
+                        break;
+                    default:
+                        reader.skipType(tag & 7);
+                        break;
+                    }
+                }
+                return message;
+            };
+    
+            DimOrders.decodeText = function decodeText(reader) {
+                var message = new $root.uff.DimOrders();
+                reader.start();
+                while (!reader.end()) {
+                    var tag = reader.tag();
+                    switch (tag) {
+                    case "orders":
+                        if (!(message.orders && message.orders.length))
+                            message.orders = [];
+                        message.orders.push($root.uff.DimOrder.decodeText(reader, true));
+                        break;
+                    default:
+                        reader.field(tag, message);
+                        break;
+                    }
+                }
+                return message;
+            };
+    
+            return DimOrders;
+        })();
+    
+        uff.ListString = (function() {
+    
+            function ListString(properties) {
+                this.val = [];
+                if (properties)
+                    for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                        if (properties[keys[i]] != null)
+                            this[keys[i]] = properties[keys[i]];
+            }
+    
+            ListString.prototype.val = $util.emptyArray;
+    
+            ListString.decode = function decode(reader, length) {
+                if (!(reader instanceof $Reader))
+                    reader = $Reader.create(reader);
+                var end = length === undefined ? reader.len : reader.pos + length, message = new $root.uff.ListString();
+                while (reader.pos < end) {
+                    var tag = reader.uint32();
+                    switch (tag >>> 3) {
+                    case 1:
+                        if (!(message.val && message.val.length))
+                            message.val = [];
+                        message.val.push(reader.string());
+                        break;
+                    default:
+                        reader.skipType(tag & 7);
+                        break;
+                    }
+                }
+                return message;
+            };
+    
+            ListString.decodeText = function decodeText(reader) {
+                var message = new $root.uff.ListString();
+                reader.start();
+                while (!reader.end()) {
+                    var tag = reader.tag();
+                    switch (tag) {
+                    case "val":
+                        if (!(message.val && message.val.length))
+                            message.val = [];
+                        if (reader.first())
+                            while (!reader.last()) {
+                                message.val.push(reader.string());
+                                reader.next();
+                            }
+                        else
+                            message.val.push(reader.string());
+                        break;
+                    default:
+                        reader.field(tag, message);
+                        break;
+                    }
+                }
+                return message;
+            };
+    
+            return ListString;
+        })();
+    
+        uff.ListInt = (function() {
+    
+            function ListInt(properties) {
+                this.val = [];
+                if (properties)
+                    for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                        if (properties[keys[i]] != null)
+                            this[keys[i]] = properties[keys[i]];
+            }
+    
+            ListInt.prototype.val = $util.emptyArray;
+    
+            ListInt.decode = function decode(reader, length) {
+                if (!(reader instanceof $Reader))
+                    reader = $Reader.create(reader);
+                var end = length === undefined ? reader.len : reader.pos + length, message = new $root.uff.ListInt();
+                while (reader.pos < end) {
+                    var tag = reader.uint32();
+                    switch (tag >>> 3) {
+                    case 1:
+                        if (!(message.val && message.val.length))
+                            message.val = [];
+                        if ((tag & 7) === 2) {
+                            var end2 = reader.uint32() + reader.pos;
+                            while (reader.pos < end2)
+                                message.val.push(reader.int64());
+                        } else
+                            message.val.push(reader.int64());
+                        break;
+                    default:
+                        reader.skipType(tag & 7);
+                        break;
+                    }
+                }
+                return message;
+            };
+    
+            ListInt.decodeText = function decodeText(reader) {
+                var message = new $root.uff.ListInt();
+                reader.start();
+                while (!reader.end()) {
+                    var tag = reader.tag();
+                    switch (tag) {
+                    case "val":
+                        if (!(message.val && message.val.length))
+                            message.val = [];
+                        if (reader.first())
+                            while (!reader.last()) {
+                                message.val.push(reader.int64());
+                                reader.next();
+                            }
+                        else
+                            message.val.push(reader.int64());
+                        break;
+                    default:
+                        reader.field(tag, message);
+                        break;
+                    }
+                }
+                return message;
+            };
+    
+            return ListInt;
+        })();
+    
+        uff.ListDouble = (function() {
+    
+            function ListDouble(properties) {
+                this.val = [];
+                if (properties)
+                    for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                        if (properties[keys[i]] != null)
+                            this[keys[i]] = properties[keys[i]];
+            }
+    
+            ListDouble.prototype.val = $util.emptyArray;
+    
+            ListDouble.decode = function decode(reader, length) {
+                if (!(reader instanceof $Reader))
+                    reader = $Reader.create(reader);
+                var end = length === undefined ? reader.len : reader.pos + length, message = new $root.uff.ListDouble();
+                while (reader.pos < end) {
+                    var tag = reader.uint32();
+                    switch (tag >>> 3) {
+                    case 1:
+                        if (!(message.val && message.val.length))
+                            message.val = [];
+                        if ((tag & 7) === 2) {
+                            var end2 = reader.uint32() + reader.pos;
+                            while (reader.pos < end2)
+                                message.val.push(reader.double());
+                        } else
+                            message.val.push(reader.double());
+                        break;
+                    default:
+                        reader.skipType(tag & 7);
+                        break;
+                    }
+                }
+                return message;
+            };
+    
+            ListDouble.decodeText = function decodeText(reader) {
+                var message = new $root.uff.ListDouble();
+                reader.start();
+                while (!reader.end()) {
+                    var tag = reader.tag();
+                    switch (tag) {
+                    case "val":
+                        if (!(message.val && message.val.length))
+                            message.val = [];
+                        if (reader.first())
+                            while (!reader.last()) {
+                                message.val.push(reader.double());
+                                reader.next();
+                            }
+                        else
+                            message.val.push(reader.double());
+                        break;
+                    default:
+                        reader.field(tag, message);
+                        break;
+                    }
+                }
+                return message;
+            };
+    
+            return ListDouble;
+        })();
+    
+        uff.ListDataType = (function() {
+    
+            function ListDataType(properties) {
+                this.val = [];
+                if (properties)
+                    for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                        if (properties[keys[i]] != null)
+                            this[keys[i]] = properties[keys[i]];
+            }
+    
+            ListDataType.prototype.val = $util.emptyArray;
+    
+            ListDataType.decode = function decode(reader, length) {
+                if (!(reader instanceof $Reader))
+                    reader = $Reader.create(reader);
+                var end = length === undefined ? reader.len : reader.pos + length, message = new $root.uff.ListDataType();
+                while (reader.pos < end) {
+                    var tag = reader.uint32();
+                    switch (tag >>> 3) {
+                    case 1:
+                        if (!(message.val && message.val.length))
+                            message.val = [];
+                        if ((tag & 7) === 2) {
+                            var end2 = reader.uint32() + reader.pos;
+                            while (reader.pos < end2)
+                                message.val.push(reader.int32());
+                        } else
+                            message.val.push(reader.int32());
+                        break;
+                    default:
+                        reader.skipType(tag & 7);
+                        break;
+                    }
+                }
+                return message;
+            };
+    
+            ListDataType.decodeText = function decodeText(reader) {
+                var message = new $root.uff.ListDataType();
+                reader.start();
+                while (!reader.end()) {
+                    var tag = reader.tag();
+                    switch (tag) {
+                    case "val":
+                        if (!(message.val && message.val.length))
+                            message.val = [];
+                        if (reader.first())
+                            while (!reader.last()) {
+                                message.val.push(reader.enum($root.uff.DataType));
+                                reader.next();
+                            }
+                        else
+                            message.val.push(reader.enum($root.uff.DataType));
+                        break;
+                    default:
+                        reader.field(tag, message);
+                        break;
+                    }
+                }
+                return message;
+            };
+    
+            return ListDataType;
+        })();
+    
+        uff.ListDimOrders = (function() {
+    
+            function ListDimOrders(properties) {
+                this.val = [];
+                if (properties)
+                    for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                        if (properties[keys[i]] != null)
+                            this[keys[i]] = properties[keys[i]];
+            }
+    
+            ListDimOrders.prototype.val = $util.emptyArray;
+    
+            ListDimOrders.decode = function decode(reader, length) {
+                if (!(reader instanceof $Reader))
+                    reader = $Reader.create(reader);
+                var end = length === undefined ? reader.len : reader.pos + length, message = new $root.uff.ListDimOrders();
+                while (reader.pos < end) {
+                    var tag = reader.uint32();
+                    switch (tag >>> 3) {
+                    case 1:
+                        if (!(message.val && message.val.length))
+                            message.val = [];
+                        message.val.push($root.uff.DimOrders.decode(reader, reader.uint32()));
+                        break;
+                    default:
+                        reader.skipType(tag & 7);
+                        break;
+                    }
+                }
+                return message;
+            };
+    
+            ListDimOrders.decodeText = function decodeText(reader) {
+                var message = new $root.uff.ListDimOrders();
+                reader.start();
+                while (!reader.end()) {
+                    var tag = reader.tag();
+                    switch (tag) {
+                    case "val":
+                        if (!(message.val && message.val.length))
+                            message.val = [];
+                        message.val.push($root.uff.DimOrders.decodeText(reader, true));
+                        break;
+                    default:
+                        reader.field(tag, message);
+                        break;
+                    }
+                }
+                return message;
+            };
+    
+            return ListDimOrders;
+        })();
+    
         return uff;
     })();
 

+ 371 - 8
src/uff.js

@@ -43,13 +43,6 @@ uff.ModelFactory = class {
                 try {
                     uff.proto = protobuf.roots.uff.uff;
                     const reader = prototxt.TextReader.create(context.text);
-                    const field = reader.field;
-                    reader.field = (token, module) => {
-                        if (token === 'descriptors' || token === 'graphs' || token == 'referenced_data') {
-                            return reader.skip();
-                        }
-                        return field(token, module);
-                    };
                     meta_graph = uff.proto.MetaGraph.decodeText(reader);
                 }
                 catch (error) {
@@ -82,8 +75,18 @@ uff.ModelFactory = class {
 uff.Model = class {
 
     constructor(metadata, meta_graph) {
-        meta_graph.graphs = meta_graph.graphs || [];
         this._version = meta_graph.version;
+        this._imports = meta_graph.descriptors.map((descriptor) => descriptor.id + ' v' + descriptor.version.toString()).join(', ');
+        const references = new Map(meta_graph.referenced_data.map((item) => [ item.key, item.value ]));
+        for (const graph of meta_graph.graphs) {
+            for (const node of graph.nodes) {
+                for (const field of node.fields) {
+                    if (field.value.type === 'ref' && references.has(field.value.ref)) {
+                        field.value = references.get(field.value.ref);
+                    }
+                }
+            }
+        }
         this._graphs = meta_graph.graphs.map((graph) => new uff.Graph(metadata, graph));
     }
 
@@ -107,6 +110,52 @@ uff.Graph = class {
         this._inputs = [];
         this._outputs = [];
         this._nodes = [];
+
+        const args = new Map();
+        const inputCountMap = new Map();
+        for (const node of graph.nodes) {
+            for (const input of node.inputs) {
+                inputCountMap.set(input, inputCountMap.has(input) ? inputCountMap.get(input) + 1 : 1);
+                args.set(input, new uff.Argument(input));
+            }
+            if (!args.has(node.id)) {
+                args.set(node.id, new uff.Argument(node.id));
+            }
+        }
+        for (let i = graph.nodes.length - 1; i >= 0; i--) {
+            const node = graph.nodes[i];
+            if (node.operation === 'Const' && node.inputs.length === 0 && inputCountMap.get(node.id) === 1) {
+                const fields = {};
+                for (const field of node.fields) {
+                    fields[field.key] = field.value;
+                }
+                if (fields.dtype && fields.shape && fields.values) {
+                    const tensor = new uff.Tensor(fields.dtype, fields.shape, fields.values);
+                    args.set(node.id, new uff.Argument(node.id, tensor.type, tensor));
+                    graph.nodes.splice(i, 1);
+                }
+            }
+            if (node.operation === 'Input' && node.inputs.length === 0) {
+                const fields = {};
+                for (const field of node.fields) {
+                    fields[field.key] = field.value;
+                }
+                const type = fields.dtype && fields.shape ? new uff.TensorType(fields.dtype, fields.shape) : null;
+                args.set(node.id, new uff.Argument(node.id, type, null));
+            }
+        }
+
+        for (const node of graph.nodes) {
+            if (node.operation === 'Input') {
+                this._inputs.push(new uff.Parameter(node.id, [ args.get(node.id) ]));
+                continue;
+            }
+            if (node.operation === 'MarkOutput' && node.inputs.length === 1) {
+                this._outputs.push(new uff.Parameter(node.id, [ args.get(node.inputs[0]) ]));
+                continue;
+            }
+            this._nodes.push(new uff.Node(metadata, node, args));
+        }
     }
 
     get name() {
@@ -126,6 +175,320 @@ uff.Graph = class {
     }
 };
 
+uff.Parameter = class {
+
+    constructor(name, args) {
+        this._name = name;
+        this._arguments = args;
+    }
+
+    get name() {
+        return this._name;
+    }
+
+    get visible() {
+        return true;
+    }
+
+    get arguments() {
+        return this._arguments;
+    }
+};
+
+uff.Argument = class {
+
+    constructor(name, type, initializer) {
+        if (typeof name !== 'string') {
+            throw new uff.Error("Invalid argument identifier '" + JSON.stringify(name) + "'.");
+        }
+        this._name = name;
+        this._type = type || null;
+        this._initializer = initializer || null;
+    }
+
+    get name() {
+        return this._name;
+    }
+
+    get type() {
+        return this._type;
+    }
+
+    get initializer() {
+        return this._initializer;
+    }
+};
+
+uff.Node = class {
+
+    constructor(metadata, node, args) {
+        this._name = node.id;
+        this._operation = node.operation;
+        this._metadata = metadata.type(node.operation);
+        this._attributes = [];
+        this._inputs = [];
+        this._outputs = [];
+
+        const schema = metadata.type(node.operation);
+        if (node.inputs && node.inputs.length > 0) {
+            let inputIndex = 0;
+            if (schema && schema.inputs) {
+                for (const inputSchema of schema.inputs) {
+                    if (inputIndex < node.inputs.length || inputSchema.option != 'optional') {
+                        const inputCount = (inputSchema.option == 'variadic') ? (node.input.length - inputIndex) : 1;
+                        const inputArguments = node.inputs.slice(inputIndex, inputIndex + inputCount).map((id) => {
+                            return args.get(id);
+                        });
+                        inputIndex += inputCount;
+                        this._inputs.push(new uff.Parameter(inputSchema.name, inputArguments));
+                    }
+                }
+            }
+            this._inputs = this._inputs.concat(node.inputs.slice(inputIndex).map((id, index) => {
+                const inputName = ((inputIndex + index) == 0) ? 'input' : (inputIndex + index).toString();
+                return new uff.Parameter(inputName, [ args.get(id) ]);
+            }));
+        }
+
+        this._outputs.push(new uff.Parameter('output', [
+            args.get(node.id)
+        ]));
+
+        for (const field of node.fields) {
+            this._attributes.push(new uff.Attribute(metadata.attribute(this._operation, field.key), field.key, field.value));
+        }
+    }
+
+    get name() {
+        return this._name;
+    }
+
+    get type() {
+        return this._operation;
+    }
+
+    get metadata() {
+        return this._metadata;
+    }
+
+    get inputs() {
+        return this._inputs;
+    }
+
+    get outputs() {
+        return this._outputs;
+    }
+
+    get attributes() {
+        return this._attributes;
+    }
+};
+
+uff.Attribute = class {
+
+    constructor(metadata, name, value) {
+        this._name = name;
+        switch(value.type) {
+            case 's':  this._value = value.s; break;
+            case 'i':  this._value = value.i; break;
+            case 'd':  this._value = value.d; break;
+            case 'b':  this._value = value.b; break;
+            case 'i_list':  this._value = value.i_list.val; break;
+            case 'd_list':  this._value = value.d_list.val; break;
+            case 'dtype': this._value = new uff.TensorType(value, null).dataType; break;
+            case 'dim_orders_list': this._value = value.dim_orders_list.val; break;
+            default: throw new uff.Error("Unknown attribute format '" + JSON.stringify(value.type) + "'.");
+        }
+    }
+
+    get name() {
+        return this._name;
+    }
+
+    get value() {
+        return this._value;
+    }
+};
+
+uff.Tensor = class {
+
+    constructor(dataType, shape, values) {
+        this._type = new uff.TensorType(dataType, shape);
+        switch (values.type) {
+            case 'blob': this._data = values.blob; break;
+            default: throw new uff.Error("Unknown values format '" + JSON.stringify(values.type) + "'.");
+        }
+    }
+
+    get kind() {
+        return 'Const';
+    }
+
+    get type() {
+        return this._type;
+    }
+
+    get state() {
+        return this._context().state;
+    }
+
+    get value() {
+        const context = this._context();
+        if (context.state) {
+            return null;
+        }
+        context.limit = Number.MAX_SAFE_INTEGER;
+        return this._decode(context, 0);
+    }
+
+    toString() {
+        const context = this._context();
+        if (context.state) {
+            return '';
+        }
+        context.limit = 10000;
+        const value = this._decode(context, 0);
+        return JSON.stringify(value, null, 4);
+    }
+
+    _context() {
+        const context = {};
+        context.state = null;
+        context.index = 0;
+        context.count = 0;
+
+        if (this._data == null) {
+            context.state = 'Tensor data is empty.';
+            return context;
+        }
+        if (this._data.length > 8 &&
+            this._data[0] === 0x28 && this._data[1] === 0x2e && this._data[2] === 0x2e && this._data[3] === 0x2e &&
+            this._data[this._data.length - 1] === 0x29 && this._data[this._data.length - 2] === 0x2e && this._data[this._data.length - 3] === 0x2e && this._data[this._data.length - 4] === 0x2e) {
+            context.state = 'Tensor data is empty.';
+            return context;
+        }
+
+        context.dataType = this._type.dataType;
+        context.shape = this._type.shape.dimensions;
+        context.data = new DataView(this._data.buffer, this._data.byteOffset, this._data.byteLength);
+        return context;
+    }
+
+    _decode(context, dimension) {
+        const shape = (context.shape.length == 0) ? [ 1 ] : context.shape;
+        const size = shape[dimension];
+        const results = [];
+        if (dimension == shape.length - 1) {
+            for (let i = 0; i < size; i++) {
+                if (context.count > context.limit) {
+                    results.push('...');
+                    return results;
+                }
+                switch (context.dataType) {
+                    case 'int8':
+                        results.push(context.data.getInt8(context.index));
+                        context.index += 1;
+                        context.count++;
+                        break;
+                    case 'int16':
+                        results.push(context.data.getInt16(context.index));
+                        context.index += 2;
+                        context.count++;
+                        break;
+                    case 'int32':
+                        results.push(context.data.getInt32(context.index, true));
+                        context.index += 4;
+                        context.count++;
+                        break;
+                    case 'int64':
+                        results.push(new long.Long(context.data.getUint32(context.index, true), context.data.getUint32(context.index + 4, true), false));
+                        context.index += 8;
+                        context.count++;
+                        break;
+                    case 'float16':
+                        results.push(context.data.getFloat16(context.index, true));
+                        context.index += 2;
+                        context.count++;
+                        break;
+                    case 'float32':
+                        results.push(context.data.getFloat32(context.index, true));
+                        context.index += 4;
+                        context.count++;
+                        break;
+                    default:
+                        break;
+                }
+            }
+        }
+        else {
+            for (let j = 0; j < size; j++) {
+                if (context.count > context.limit) {
+                    results.push('...');
+                    return results;
+                }
+                results.push(this._decode(context, dimension + 1));
+            }
+        }
+        if (context.shape.length == 0) {
+            return results[0];
+        }
+        return results;
+    }
+};
+
+uff.TensorType = class {
+
+    constructor(dataType, shape) {
+        if (dataType.type !== 'dtype') {
+            throw new uff.Error("Unknown data type format '" + JSON.stringify(dataType.type) + "'.");
+        }
+        switch (dataType.dtype) {
+            case uff.proto.DataType.DT_INT8: this._dataType = 'int8'; break;
+            case uff.proto.DataType.DT_INT16: this._dataType = 'int16'; break;
+            case uff.proto.DataType.DT_INT32: this._dataType = 'int32'; break;
+            case uff.proto.DataType.DT_INT64: this._dataType = 'int64'; break;
+            case uff.proto.DataType.DT_FLOAT16: this._dataType = 'float16'; break;
+            case uff.proto.DataType.DT_FLOAT32: this._dataType = 'float32'; break;
+            default:
+                throw new uff.Error("Unknown data type '" + JSON.stringify(dataType) + "'.");
+        }
+        this._shape = shape ? new uff.TensorShape(shape) : null;
+    }
+
+    get dataType() {
+        return this._dataType;
+    }
+
+    get shape() {
+        return this._shape;
+    }
+
+    toString() {
+        return this.dataType + this._shape.toString();
+    }
+};
+
+uff.TensorShape = class {
+
+    constructor(shape) {
+        if (shape.type !== 'i_list') {
+            throw new uff.Error("Unknown shape format '" + JSON.stringify(shape.type) + "'.");
+        }
+        this._dimensions = shape.i_list.val;
+    }
+
+    get dimensions() {
+        return this._dimensions;
+    }
+
+    toString() {
+        if (!this._dimensions || this._dimensions.length == 0) {
+            return '';
+        }
+        return '[' + this._dimensions.join(',') + ']';
+    }
+};
+
 uff.Metadata = class {
 
     static open(host) {

+ 83 - 0
tools/uff.proto

@@ -6,4 +6,87 @@ package uff;
 message MetaGraph {
     optional int64 version = 1;
     optional int64 descriptor_core_version = 2;
+    repeated Descriptor descriptors = 3;
+    repeated Graph graphs = 4;
+    repeated KeyValuePair referenced_data = 5;
+}
+
+message Descriptor {
+    required string id = 1;
+    required int64 version = 2;
+}
+
+message Graph {
+    optional string id = 1;
+    repeated Node nodes = 2;
+}
+
+message Node {
+    required string id = 1;
+    repeated string inputs = 2;
+    required string operation = 3;
+    repeated KeyValuePair fields = 4;
+    repeated KeyValuePair extra_fields = 5;
+}
+
+message KeyValuePair {
+    required string key = 1;
+    required Value value = 2;
+}
+
+message Value {
+    oneof type {
+        string s = 1;
+        ListString s_list = 2;
+        double d = 3;
+        ListDouble d_list = 4;
+        bool b = 5;
+        bool b_list = 6;
+        int64 i = 7;
+        ListInt i_list = 8;
+        bytes blob = 9;
+        string ref = 100;
+        DataType dtype = 101;
+        ListDataType dtype_list = 102;
+        DimOrders dim_orders = 103;
+        ListDimOrders dim_orders_list = 104;
+    }
+}
+
+enum DataType {
+    DT_INT8 = 0x10008;
+    DT_INT16 = 0x10010;
+    DT_INT32 = 0x10020;
+    DT_INT64 = 0x10040;
+    DT_FLOAT16 = 0x20010;
+    DT_FLOAT32 = 0x20020;
+}
+
+message DimOrder {
+    required int64 key = 1;
+    required ListInt value = 2;
+}
+
+message DimOrders {
+    repeated DimOrder orders = 1;
+}
+
+message ListString {
+    repeated string val = 1;
+}
+
+message ListInt {
+    repeated int64 val = 1;
+}
+
+message ListDouble {
+    repeated double val = 1;
+}
+
+message ListDataType {
+    repeated DataType val = 1;
+}
+
+message ListDimOrders {
+    repeated DimOrders val = 1;
 }