2
0
Эх сурвалжийг харах

TensorFlow type and attribute documentation.

Lutz Roeder 8 жил өмнө
parent
commit
2a36085529

Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 3 - 3
src/onnx-operator.json


Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 0 - 3843
src/tf-operator.json


BIN
src/tf-operator.pb


+ 287 - 2
src/tflite.js

@@ -53,7 +53,10 @@ tflite.BuiltinOperator = {
   CALL: 31,
   CUSTOM: 32,
   EMBEDDING_LOOKUP_SPARSE: 33,
-  PAD: 34
+  PAD: 34,
+  UNIDIRECTIONAL_SEQUENCE_RNN: 35,
+  GATHER: 36,
+  BATCH_TO_SPACE_ND: 37
 };
 
 /**
@@ -82,7 +85,9 @@ tflite.BuiltinOptions = {
   SpaceToDepthOptions: 19,
   EmbeddingLookupSparseOptions: 20,
   MulOptions: 21,
-  PadOptions: 22
+  PadOptions: 22,
+  GatherOptions: 23,
+  BatchToSpaceNDOptions: 24
 };
 
 /**
@@ -2391,6 +2396,219 @@ tflite.ReshapeOptions.endReshapeOptions = function(builder) {
   return offset;
 };
 
+/**
+ * @constructor
+ */
+tflite.BatchToSpaceNDOptions = function() {
+  /**
+   * @type {flatbuffers.ByteBuffer}
+   */
+  this.bb = null;
+
+  /**
+   * @type {number}
+   */
+  this.bb_pos = 0;
+};
+
+/**
+ * @param {number} i
+ * @param {flatbuffers.ByteBuffer} bb
+ * @returns {tflite.BatchToSpaceNDOptions}
+ */
+tflite.BatchToSpaceNDOptions.prototype.__init = function(i, bb) {
+  this.bb_pos = i;
+  this.bb = bb;
+  return this;
+};
+
+/**
+ * @param {flatbuffers.ByteBuffer} bb
+ * @param {tflite.BatchToSpaceNDOptions=} obj
+ * @returns {tflite.BatchToSpaceNDOptions}
+ */
+tflite.BatchToSpaceNDOptions.getRootAsBatchToSpaceNDOptions = function(bb, obj) {
+  return (obj || new tflite.BatchToSpaceNDOptions).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+};
+
+/**
+ * @param {number} index
+ * @returns {number}
+ */
+tflite.BatchToSpaceNDOptions.prototype.blockShape = function(index) {
+  var offset = this.bb.__offset(this.bb_pos, 4);
+  return offset ? this.bb.readInt32(this.bb.__vector(this.bb_pos + offset) + index * 4) : 0;
+};
+
+/**
+ * @returns {number}
+ */
+tflite.BatchToSpaceNDOptions.prototype.blockShapeLength = function() {
+  var offset = this.bb.__offset(this.bb_pos, 4);
+  return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @returns {Int32Array}
+ */
+tflite.BatchToSpaceNDOptions.prototype.blockShapeArray = function() {
+  var offset = this.bb.__offset(this.bb_pos, 4);
+  return offset ? new Int32Array(this.bb.bytes().buffer, this.bb.bytes().byteOffset + this.bb.__vector(this.bb_pos + offset), this.bb.__vector_len(this.bb_pos + offset)) : null;
+};
+
+/**
+ * @param {number} index
+ * @returns {number}
+ */
+tflite.BatchToSpaceNDOptions.prototype.beforeCrops = function(index) {
+  var offset = this.bb.__offset(this.bb_pos, 6);
+  return offset ? this.bb.readInt32(this.bb.__vector(this.bb_pos + offset) + index * 4) : 0;
+};
+
+/**
+ * @returns {number}
+ */
+tflite.BatchToSpaceNDOptions.prototype.beforeCropsLength = function() {
+  var offset = this.bb.__offset(this.bb_pos, 6);
+  return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @returns {Int32Array}
+ */
+tflite.BatchToSpaceNDOptions.prototype.beforeCropsArray = function() {
+  var offset = this.bb.__offset(this.bb_pos, 6);
+  return offset ? new Int32Array(this.bb.bytes().buffer, this.bb.bytes().byteOffset + this.bb.__vector(this.bb_pos + offset), this.bb.__vector_len(this.bb_pos + offset)) : null;
+};
+
+/**
+ * @param {number} index
+ * @returns {number}
+ */
+tflite.BatchToSpaceNDOptions.prototype.afterCrops = function(index) {
+  var offset = this.bb.__offset(this.bb_pos, 8);
+  return offset ? this.bb.readInt32(this.bb.__vector(this.bb_pos + offset) + index * 4) : 0;
+};
+
+/**
+ * @returns {number}
+ */
+tflite.BatchToSpaceNDOptions.prototype.afterCropsLength = function() {
+  var offset = this.bb.__offset(this.bb_pos, 8);
+  return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @returns {Int32Array}
+ */
+tflite.BatchToSpaceNDOptions.prototype.afterCropsArray = function() {
+  var offset = this.bb.__offset(this.bb_pos, 8);
+  return offset ? new Int32Array(this.bb.bytes().buffer, this.bb.bytes().byteOffset + this.bb.__vector(this.bb_pos + offset), this.bb.__vector_len(this.bb_pos + offset)) : null;
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ */
+tflite.BatchToSpaceNDOptions.startBatchToSpaceNDOptions = function(builder) {
+  builder.startObject(3);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} blockShapeOffset
+ */
+tflite.BatchToSpaceNDOptions.addBlockShape = function(builder, blockShapeOffset) {
+  builder.addFieldOffset(0, blockShapeOffset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {Array.<number>} data
+ * @returns {flatbuffers.Offset}
+ */
+tflite.BatchToSpaceNDOptions.createBlockShapeVector = function(builder, data) {
+  builder.startVector(4, data.length, 4);
+  for (var i = data.length - 1; i >= 0; i--) {
+    builder.addInt32(data[i]);
+  }
+  return builder.endVector();
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} numElems
+ */
+tflite.BatchToSpaceNDOptions.startBlockShapeVector = function(builder, numElems) {
+  builder.startVector(4, numElems, 4);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} beforeCropsOffset
+ */
+tflite.BatchToSpaceNDOptions.addBeforeCrops = function(builder, beforeCropsOffset) {
+  builder.addFieldOffset(1, beforeCropsOffset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {Array.<number>} data
+ * @returns {flatbuffers.Offset}
+ */
+tflite.BatchToSpaceNDOptions.createBeforeCropsVector = function(builder, data) {
+  builder.startVector(4, data.length, 4);
+  for (var i = data.length - 1; i >= 0; i--) {
+    builder.addInt32(data[i]);
+  }
+  return builder.endVector();
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} numElems
+ */
+tflite.BatchToSpaceNDOptions.startBeforeCropsVector = function(builder, numElems) {
+  builder.startVector(4, numElems, 4);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} afterCropsOffset
+ */
+tflite.BatchToSpaceNDOptions.addAfterCrops = function(builder, afterCropsOffset) {
+  builder.addFieldOffset(2, afterCropsOffset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {Array.<number>} data
+ * @returns {flatbuffers.Offset}
+ */
+tflite.BatchToSpaceNDOptions.createAfterCropsVector = function(builder, data) {
+  builder.startVector(4, data.length, 4);
+  for (var i = data.length - 1; i >= 0; i--) {
+    builder.addInt32(data[i]);
+  }
+  return builder.endVector();
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} numElems
+ */
+tflite.BatchToSpaceNDOptions.startAfterCropsVector = function(builder, numElems) {
+  builder.startVector(4, numElems, 4);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @returns {flatbuffers.Offset}
+ */
+tflite.BatchToSpaceNDOptions.endBatchToSpaceNDOptions = function(builder) {
+  var offset = builder.endObject();
+  return offset;
+};
+
 /**
  * @constructor
  */
@@ -2624,6 +2842,73 @@ tflite.EmbeddingLookupSparseOptions.endEmbeddingLookupSparseOptions = function(b
   return offset;
 };
 
+/**
+ * @constructor
+ */
+tflite.GatherOptions = function() {
+  /**
+   * @type {flatbuffers.ByteBuffer}
+   */
+  this.bb = null;
+
+  /**
+   * @type {number}
+   */
+  this.bb_pos = 0;
+};
+
+/**
+ * @param {number} i
+ * @param {flatbuffers.ByteBuffer} bb
+ * @returns {tflite.GatherOptions}
+ */
+tflite.GatherOptions.prototype.__init = function(i, bb) {
+  this.bb_pos = i;
+  this.bb = bb;
+  return this;
+};
+
+/**
+ * @param {flatbuffers.ByteBuffer} bb
+ * @param {tflite.GatherOptions=} obj
+ * @returns {tflite.GatherOptions}
+ */
+tflite.GatherOptions.getRootAsGatherOptions = function(bb, obj) {
+  return (obj || new tflite.GatherOptions).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+};
+
+/**
+ * @returns {number}
+ */
+tflite.GatherOptions.prototype.axis = function() {
+  var offset = this.bb.__offset(this.bb_pos, 4);
+  return offset ? this.bb.readInt32(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ */
+tflite.GatherOptions.startGatherOptions = function(builder) {
+  builder.startObject(1);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} axis
+ */
+tflite.GatherOptions.addAxis = function(builder, axis) {
+  builder.addFieldInt32(0, axis, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @returns {flatbuffers.Offset}
+ */
+tflite.GatherOptions.endGatherOptions = function(builder) {
+  var offset = builder.endObject();
+  return offset;
+};
+
 /**
  * @constructor
  */

+ 32 - 10
src/view-onnx.js

@@ -20,8 +20,8 @@ class OnnxModel {
             this._graph = new OnnxGraph(this, this._model.graph, 0);
             this._activeGraph = this._graph;
 
-            if (!OnnxModel.operatorMetadata) {
-                OnnxModel.operatorMetadata = new OnnxOperatorMetadata(this.hostService);
+            if (!OnnxOperatorMetadata.operatorMetadata) {
+                OnnxOperatorMetadata.operatorMetadata = new OnnxOperatorMetadata(this.hostService);
             }
         }
         catch (err) {
@@ -216,7 +216,7 @@ class OnnxNode {
     }
 
     get documentation() {
-        return OnnxModel.operatorMetadata.getOperatorDocumentation(this.operator);
+        return OnnxOperatorMetadata.operatorMetadata.getOperatorDocumentation(this.operator);
     }
 
     get domain() {
@@ -228,7 +228,7 @@ class OnnxNode {
         this._node.input.forEach((input, index) => {
             results.push({
                 'id': input,
-                'name': OnnxModel.operatorMetadata.getInputName(this.operator, index),
+                'name': OnnxOperatorMetadata.operatorMetadata.getInputName(this.operator, index),
                 'type': ''
             });
         });
@@ -240,7 +240,7 @@ class OnnxNode {
         this._node.output.forEach((output, index) => {
             results.push({
                 id: output,
-                name: OnnxModel.operatorMetadata.getOutputName(this.operator, index),
+                name: OnnxOperatorMetadata.operatorMetadata.getOutputName(this.operator, index),
                 type: ''
             });
         });
@@ -253,7 +253,7 @@ class OnnxNode {
         if (node.attribute && node.attribute.length > 0) {
             result = [];
             node.attribute.forEach((attribute) => { 
-                result.push(new OnnxAttribute(attribute));
+                result.push(new OnnxAttribute(this, attribute));
             });
         }
         return result;
@@ -261,7 +261,8 @@ class OnnxNode {
 }
 
 class OnnxAttribute {
-    constructor(attribute) {
+    constructor(node, attribute) {
+        this._node = node;
         this._attribute = attribute;
     }
 
@@ -281,7 +282,7 @@ class OnnxAttribute {
         else if (this._attribute.hasOwnProperty('t')) {
             return OnnxTensor.formatTensorType(this._attribute.t);
         }
-        return '';
+        return OnnxOperatorMetadata.operatorMetadata.getAttributeType(this._node.operator, this._attribute.name);
     }
 
     get value() {
@@ -619,7 +620,7 @@ class OnnxOperatorMetadata {
                 } 
             }
         }
-        return "(" + index.toString() + ")";
+        return '(' + index.toString() + ')';
     }
 
     getOutputName(operator, index) {
@@ -638,7 +639,28 @@ class OnnxOperatorMetadata {
                 } 
             }
         }
-        return "(" + index.toString() + ")";
+        return '(' + index.toString() + ')';
+    }
+
+    getAttributeType(operator, name) {
+        var schema = this.map[operator];
+        if (schema) {
+            var attributeMap = schema.attributeMap;
+            if (!attributeMap) {
+                attributeMap = {};
+                if (schema.attributes) {
+                    schema.attributes.forEach((attribute) => {
+                        attributeMap[attribute.name] = attribute;
+                    });
+                }
+                schema.attributeMap = attributeMap;
+            }
+            var attributeEntry = attributeMap[name];
+            if (attributeEntry) { 
+                return attributeEntry.type;
+            }
+        }
+        return '';
     }
 
     getOperatorDocumentation(operator) {

+ 13 - 6
src/view-template.js

@@ -16,8 +16,8 @@ var itemsTemplate = `
 {{#if quantization}}
 <pre>{{{quantization}}}</pre>
 {{/if}}
-{{#if doc}}
-{{{doc}}}
+{{#if description}}
+{{{description}}}
 {{/if}}
 <pre>{{{value}}}</pre>
 </div>
@@ -54,7 +54,7 @@ var operatorTemplate = `
 <h2>Attributes</h2>
 <dl>
 {{#attributes}}
-<dt>{{{name}}}: <tt>{{{type}}}</tt></dt>
+<dt>{{{name}}}{{#if type}}: <tt>{{{type}}}</tt>{{/if}}</dt>
 <dd>{{{description}}}</dd>
 {{/attributes}}
 </dl>
@@ -65,7 +65,7 @@ var operatorTemplate = `
 <dl>
 {{/if}}
 {{#inputs}}
-<dt>{{{name}}}: <tt>{{{type}}}</tt> {{#if option}}({{{option}}}){{/if}}</dt>
+<dt>{{{name}}}{{#if type}}: <tt>{{{type}}}</tt>{{/if}} {{#if option}}({{{option}}}){{/if}}</dt>
 <dd>{{{description}}}</dd>
 {{/inputs}}
 </dl>
@@ -75,7 +75,7 @@ var operatorTemplate = `
 <dl>
 {{/if}}
 {{#outputs}}
-<dt>{{{name}}}: <tt>{{{type}}}</tt> {{#if option}}({{{option}}}){{/if}}</dt>
+<dt>{{{name}}}{{#if type}}: <tt>{{{type}}}</tt>{{/if}} {{#if option}}({{{option}}}){{/if}}</dt>
 <dd>{{{description}}}</dd>
 {{/outputs}}
 </dl>
@@ -174,6 +174,8 @@ var summaryTemplate = `
 var nodeTemplate = `
 <style type='text/css'>
 .details h1 { font-weight: 600; font-size: 14px; line-height: 1.25; border-bottom: 1px solid #eaecef; padding-bottom: 0.3em; margin-top: 0; margin-bottom: 16px; }
+.details h2 { font-weight: 600; font-size: 12px; line-height: 1.25; margin-bottom: 16px; border-bottom: 1px solid #eaecef; }
+.details h3 { font-weight: 600; font-size: 12px; line-height: 1.25; }
 .details .items { font-family: 'Open Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 12px; line-height: 1.5; margin: 0; }
 .details .item { margin-bottom: 20px; }
 .details .item b { font-weight: 600; }
@@ -182,6 +184,9 @@ var nodeTemplate = `
 </style>
 <div class='details'>
 <div class='items'>
+{{#if operator}}
+<h1>{{{operator}}}</h1>
+{{/if}}
 {{#if name}}
 <div class='item'><b>name</b><br><pre>{{{name}}}</pre></div>
 {{/if}}
@@ -192,8 +197,9 @@ var nodeTemplate = `
 <div class='item'><b>domain</b><br><pre>{{{domain}}}</pre></div>
 {{/if}}
 </div>
+
 {{#if attributes}}
-<h1>Attributes</h1>
+<h2>Attributes</h2>
 {{/if}}
 <div class='items'>
 {{#attributes}}
@@ -206,5 +212,6 @@ var nodeTemplate = `
 </div>
 {{/attributes}}
 </div>
+
 </div>
 `;

+ 158 - 76
src/view-tf.js

@@ -270,6 +270,10 @@ class TensorFlowNode {
         this._node = node;
     }
 
+    get graph() {
+        return this._graph;
+    }
+
     get operator() {
         return this._node.op;
     }
@@ -347,9 +351,9 @@ class TensorFlowNode {
         var result = [];
         if (node.attr) {
             Object.keys(node.attr).forEach((name) => {
-                var hidden = (name == '_output_shapes' || name == 'T');
+                var hidden = (name == '_output_shapes'); //   || name == 'T');
                 var value = node.attr[name];
-                result.push(new TensorFlowAttribute(name, value, hidden));
+                result.push(new TensorFlowAttribute(this, name, value, hidden));
             });
         }
         return result;
@@ -357,7 +361,8 @@ class TensorFlowNode {
 }
 
 class TensorFlowAttribute { 
-    constructor(name, value, hidden) {
+    constructor(node, name, value, hidden) {
+        this._node = node;
         this._name = name;
         this._value = value;
         if (hidden) {
@@ -373,36 +378,48 @@ class TensorFlowAttribute {
         if (this._value.hasOwnProperty('tensor')) {
             return TensorFlowTensor.formatTensorType(this._value.tensor);
         }
+        var graphMetadata = this._node.graph.metadata;
+        if (graphMetadata) {
+            return graphMetadata.getAttributeType(this._node.operator, this._name);
+        }
         return '';
     }
 
     get value() {
-        if (this._value.hasOwnProperty('type')) {
-            return TensorFlowTensor.formatDataType(this._value.type);
+        var item = TensorFlowAttribute.formatAttributeValue(this._value);
+        if (Array.isArray(item)) {
+            return item.join(', ');
         }
-        else if (this._value.hasOwnProperty('i')) {
-            return this._value.i.toString();
+        return item;
+    }
+
+    static formatAttributeValue(value) {
+        if (value.hasOwnProperty('type')) {
+            return TensorFlowTensor.formatDataType(value.type);
         }
-        else if (this._value.hasOwnProperty('f')) {
-            return this._value.f.toString();
+        else if (value.hasOwnProperty('i')) {
+            return value.i.toString();
         }
-        else if (this._value.hasOwnProperty('b')) {
-            return this._value.b.toString();
+        else if (value.hasOwnProperty('f')) {
+            return value.f.toString();
         }
-        else if (this._value.hasOwnProperty('shape')) {
-            return TensorFlowTensor.formatTensorShape(this._value.shape);;
+        else if (value.hasOwnProperty('b')) {
+            return value.b.toString();
         }
-        else if (this._value.hasOwnProperty('s')) {
-            if (this._value.s.filter(c => c <= 32 && c >= 128).length == 0) {
-                return '"' + String.fromCharCode.apply(null, this._value.s) + '"';
+        else if (value.hasOwnProperty('shape')) {
+            return TensorFlowTensor.formatTensorShape(value.shape);;
+        }
+        else if (value.hasOwnProperty('s')) {
+            if (value.s.filter(c => c <= 32 && c >= 128).length == 0) {
+                return '"' + String.fromCharCode.apply(null, value.s) + '"';
             }
-            return this._value.s.map(v => v.toString()).join(', ');           
+            return value.s.map(v => v.toString()).join(', ');           
         }
-        else if (this._value.hasOwnProperty('tensor')) {
-            return new TensorFlowTensor(this._value.tensor).value;
+        else if (value.hasOwnProperty('tensor')) {
+            return new TensorFlowTensor(value.tensor).value;
         }
-        else if (this._value.hasOwnProperty('list')) {
-            var list = this._value.list;
+        else if (value.hasOwnProperty('list')) {
+            var list = value.list;
             if (list.s && list.s.length > 0) {
                 if (list.s.length > 65536) {
                     return "Too large to render.";
@@ -412,31 +429,31 @@ class TensorFlowAttribute {
                         return '"' + String.fromCharCode.apply(null, s) + '"';
                     }
                     return s.map(v => v.toString()).join(', ');    
-                }).join(', ');
+                });
             }
             else if (list.i && list.i.length > 0) {
                 if (list.i.length > 65536) {
                     return "Too large to render.";
                 }
-                return list.i.map((v) => v.toString()).join(', ');
+                return list.i.map((v) => v.toString());
             }
             else if (list.f && list.f.length > 0) {
                 if (list.f.length > 65536) {
                     return "Too large to render.";
                 }
-                return list.f.map((v) => v.toString()).join(', ');
+                return list.f.map((v) => v.toString());
             }
             else if (list.type && list.type.length > 0) {
                 if (list.type.length > 65536) {
                     return "Too large to render.";
                 }
-                return list.type.map((type) => TensorFlowTensor.formatDataType(type)).join(', ');
+                return list.type.map((type) => TensorFlowTensor.formatDataType(type));
             }
             else if (list.shape && list.shape.length > 0) {
                 if (list.shape.length > 65536) {
                     return "Too large to render.";
                 }
-                return list.shape.map((shape) => TensorFlowTensor.formatTensorShape(shape)).join(', ');
+                return list.shape.map((shape) => TensorFlowTensor.formatTensorShape(shape));
             }
         }
         debugger;
@@ -483,16 +500,21 @@ class TensorFlowTensor {
         if (!this._tensor.dtype) {
             return 'Tensor has no data type.';
         }
-        if (!this._tensor.tensorShape) {
+        if (!this._tensor.tensorShape || !this._tensor.tensorShape.dim) {
             return 'Tensor has no dimensions.';
         }
 
+        this._size = 1;
+        this._tensor.tensorShape.dim.forEach((dim) => {
+            this._size = this._size * (dim.size ? dim.size : 0);
+        });
+
         switch (this._tensor.dtype) {
             case tensorflow.DataType.DT_FLOAT:
                 if (this._tensor.tensorContent && this._tensor.tensorContent.length > 0) {
                     this._rawData = new DataView(this._tensor.tensorContent.buffer, this._tensor.tensorContent.byteOffset, this._tensor.tensorContent.byteLength)
                 }
-                else if (this._tensor.floatVal && this._tensor.floatVal.length > 0) {
+                else if (this._tensor.floatVal && this._tensor.floatVal.length == this._size) {
                     this._data = this._tensor.floatVal;
                 }
                 else {
@@ -503,7 +525,7 @@ class TensorFlowTensor {
                 if (this._tensor.tensorContent && this._tensor.tensorContent.length > 0) {
                     this._rawData = new DataView(this._tensor.tensorContent.buffer, this._tensor.tensorContent.byteOffset, this._tensor.tensorContent.byteLength)
                 }
-                else if (this._tensor.intVal && this._tensor.intVal.length > 0) {
+                else if (this._tensor.intVal && this._tensor.intVal.length == this._size) {
                     this._data = this._tensor.intVal;
                 }
                 else {
@@ -514,7 +536,7 @@ class TensorFlowTensor {
                 if (this._tensor.tensorContent && this._tensor.tensorContent.length > 0) {
                     return 'Tensor data type is not implemented.';
                 }
-                else if (this._tensor.stringVal && this._tensor.stringVal.length > 0) {
+                else if (this._tensor.stringVal && this._tensor.stringVal.length == this._size) {
                     this._data = this._tensor.stringVal;
                 }
                 else {
@@ -530,6 +552,7 @@ class TensorFlowTensor {
         this._count = 0;
         this._utf8Decoder = window.TextDecoder ? new TextDecoder('utf-8') : null;
         var result = this.read(0);
+        delete this._size;
         delete this._index;
         delete this._count;
         delete this._data;
@@ -649,27 +672,21 @@ class TensorFlowOperatorMetadata {
 
     constructor(hostService) {
         this._map = {};
-        hostService.request('/tf-operator.json', (err, data) => {
+        hostService.request('/tf-operator.pb', (err, data) => {
             if (err != null) {
-                // TODO error
             }
             else {
-                var items = JSON.parse(data);
-                if (items) {
-                    items.forEach((item) => {
-                        if (item.name && item.schema)
-                        {
-                            var name = item.name;
-                            var schema = item.schema;
-                            this._map[name] = schema;
-                        }
+                var operators = tensorflow.OpList.decode(data);
+                if (operators.op) {
+                    operators.op.forEach((opDef) => {
+                        this._map[opDef.name] = opDef;
                     });
                 }
             }
         });
     }
 
-    getSchema(operator) {
+    getOpDef(operator) {
         return this._map[operator];
     }
 }
@@ -680,23 +697,13 @@ class TensorFlowGraphOperatorMetadata {
         this._map = {};
         if (metaInfoDef && metaInfoDef.strippedOpList && metaInfoDef.strippedOpList.op) {
             metaInfoDef.strippedOpList.op.forEach((opDef) => {
-                var schema = { inputs: [], outputs: [], attributes: [] };
-                opDef.inputArg.forEach(function (inputArg) {
-                    schema.inputs.push({ name: inputArg.name, typeStr: inputArg.typeAttr });
-                });
-                opDef.outputArg.forEach(function (outputArg) {
-                    schema.outputs.push({ name: outputArg.name, typeStr: outputArg.typeAttr });
-                });
-                opDef.attr.forEach(function (attr) {
-                    schema.attributes.push({ name: attr.name, type: attr.type });
-                });
                 this._map[opDef.name] = schema;
             });
         }
     }
 
-    getSchema(operator) {
-        var schema = TensorFlowModel.operatorMetadata.getSchema(operator);
+    getOpDef(operator) {
+        var schema = TensorFlowModel.operatorMetadata.getOpDef(operator);
         if (!schema) {
             schema = this._map[operator];
         }
@@ -704,9 +711,9 @@ class TensorFlowGraphOperatorMetadata {
     }
 
     getInputName(operator, index) {
-        var schema = this.getSchema(operator);
-        if (schema) {
-            var inputs = schema.inputs;
+        var opDef = this.getOpDef(operator);
+        if (opDef) {
+            var inputs = opDef.inputArg;
             if (inputs && index < inputs.length) {
                 var input = inputs[index];
                 if (input) {
@@ -721,9 +728,9 @@ class TensorFlowGraphOperatorMetadata {
     }
 
     getOutputName(operator, index) {
-        var schema = this.getSchema(operator);
-        if (schema) {
-            var outputs = schema.outputs;
+        var opDef = this.getOpDef(operator);
+        if (opDef) {
+            var outputs = opDef.outputArg;
             if (outputs && index < outputs.length) {
                 var output = outputs[index];
                 if (output) {
@@ -737,30 +744,105 @@ class TensorFlowGraphOperatorMetadata {
         return '(' + index.toString() + ')';
     }
 
+    getAttributeType(operator, name) {
+        var opDef = this.getOpDef(operator);
+        if (opDef) {
+            var attributeMap = opDef.attributeMap;
+            if (!attributeMap) {
+                attributeMap = {};
+                if (opDef.attr) {
+                    opDef.attr.forEach((attr) => {
+                        attributeMap[attr.name] = attr;
+                    });
+                }
+                opDef.attributeMap = attributeMap;
+            }
+            var attributeEntry = attributeMap[name];
+            if (attributeEntry) { 
+                return attributeEntry.type;
+            }
+        }        
+        return '';
+    }
+
     getOperatorDocumentation(operator) {
-        var schema = this.getSchema(operator);
-        if (schema) {
-            schema = Object.assign({}, schema);
+        var schema = {};
+        var opDef = this.getOpDef(operator);
+        if (opDef) {
             schema.name = operator;
-            if (schema.summary) {
-                schema.summary = marked(schema.summary);
+            if (opDef.summary) {
+                schema.summary = marked(opDef.summary);
             }
-            if (schema.description) {
-                schema.description = marked(schema.description);
+            if (opDef.description) {
+                schema.description = marked(opDef.description);
             }
-            if (schema.inputs) {
-                schema.inputs.forEach((input) => {
-                    input.description = marked(input.description);
+            if (opDef.inputArg) {
+                schema.inputs = [];
+                opDef.inputArg.forEach((inputArg) => {
+                    var input = {};
+                    input.name = inputArg.name;
+                    if (inputArg.type) {
+                        input.type = inputArg.type;
+                    }
+                    else if (inputArg.typeAttr) {
+                        input.type = inputArg.typeAttr;
+                    }
+                    else if (inputArg.typeListAttr) {
+                        input.type = inputArg.typeListAttr;
+                    }
+                    if (inputArg.description) {
+                        input.description = marked(inputArg.description);
+                    }
+                    schema.inputs.push(input);
                 });
             }
-            if (schema.outputs) {
-                schema.outputs.forEach((output) => {
-                    output.description = marked(output.description);
+            if (opDef.outputArg) {
+                schema.outputs = [];
+                opDef.outputArg.forEach((outputArg) => {
+                    var output = {};
+                    output.name = outputArg.name;
+                    if (outputArg.type) {
+                        output.type = outputArg.type;
+                    }
+                    else if (outputArg.typeAttr) {
+                        output.type = outputArg.typeAttr;
+                    }
+                    else if (outputArg.typeListAttr) {
+                        output.type = outputArg.typeListAttr;
+                    }
+                    if (outputArg.description) {
+                        output.description = marked(outputArg.description);
+                    }
+                    schema.outputs.push(output);
                 });
             }
-            if (schema.attributes) {
-                schema.attributes.forEach((attribute) => {
-                    attribute.description = marked(attribute.description);
+            if (opDef.attr) {
+                schema.attributes = [];
+                opDef.attr.forEach((attr) => {
+                    var attribute = {};
+                    attribute.name = attr.name;
+                    if (attr.type) {
+                        attribute.type = attr.type;
+                    }
+                    var description = attr.description;
+                    if (attr.allowedValues) {
+                        var allowedValues = TensorFlowAttribute.formatAttributeValue(attr.allowedValues);
+                        allowedValues = Array.isArray(allowedValues) ? allowedValues : [ allowedValues ];
+                        allowedValues = allowedValues.map((item) => '`' + item + '`').join(', ');
+                        allowedValues = 'Must be one of the following: ' + allowedValues + '.';
+                        description = description ? (allowedValues + ' ' + description) : allowedValues;
+                    }
+                    if (attr.defaultValue) {
+                        var defaultValue = TensorFlowAttribute.formatAttributeValue(attr.defaultValue);
+                        defaultValue = Array.isArray(defaultValue) ? defaultValue : [ defaultValue ];
+                        defaultValue = defaultValue.map((item) => '`' + item + '`').join(', ');
+                        defaultValue = 'Defaults to ' + defaultValue + '.';
+                        description = description ? (defaultValue + ' ' + description) : defaultValue;
+                    }
+                    if (description) {
+                        attribute.description = marked(description);
+                    }
+                    schema.attributes.push(attribute);
                 });
             }
             var template = Handlebars.compile(operatorTemplate, 'utf-8');

+ 2 - 1
src/view.js

@@ -104,7 +104,8 @@ function updateGraph(model) {
     var svg = dagreD3.d3.select(svgElement);
 
     var g = new dagreD3.graphlib.Graph();
-     g.setGraph({ });
+    g.setGraph({ });
+    // g.setGraph({ align: 'DR' });
     // g.setGraph({ ranker: 'network-simplex' });
     // g.setGraph({ ranker: 'tight-tree' });
     // g.setGraph({ ranker: 'longest-path' });

+ 8 - 64
tools/tf-operator-json.py

@@ -1,70 +1,14 @@
 #!/usr/bin/env python
 
-from __future__ import unicode_literals
-
-import json
-import io
-import sys
-
 from tensorflow.core.framework import op_def_pb2
 from google.protobuf import text_format
 
-ops_file = '../third_party/tensorflow/tensorflow/core/ops/ops.pbtxt';
-ops_list = op_def_pb2.OpList()
-
-json_file = '../src/tf-operator.json'
-
-with open(ops_file) as text_file:
-    text = text_file.read()
-    text_format.Merge(text, ops_list)
-
-json_root = []
-
-for schema in ops_list.op:
-    json_schema = {}
-
-    if schema.summary:
-        json_schema['summary'] = schema.summary
-    if schema.description:
-        json_schema['description'] = schema.description
-    if schema.input_arg:
-        json_schema['inputs'] = []
-        for input_arg in schema.input_arg:
-            json_schema['inputs'].append({
-                'name': input_arg.name,
-                'type': input_arg.type,
-                'description': input_arg.description,
-                'type_attr': input_arg.type_attr
-            })
-    if schema.output_arg:
-        json_schema['outputs'] = []
-        for output_arg in schema.output_arg:
-            json_schema['outputs'].append({
-                'name': output_arg.name,
-                'type': output_arg.type,
-                'description': output_arg.description,
-                'type_attr': output_arg.type_attr
-            })
-    if schema.attr:
-        json_schema['attributes'] = []
-        for attr in schema.attr:
-            json_schema['attributes'].append({
-                'name': attr.name,
-                'type': attr.type,
-                'description': attr.description
-            })
-    json_root.append({
-        'name': schema.name,
-        'schema': json_schema
-    })
-
-with io.open(json_file, 'w', newline='') as fout:
-    json_root = json.dumps(json_root, sort_keys=True, indent=2)
-    for line in json_root.splitlines():
-        line = line.rstrip()
-        if sys.version_info[0] < 3:
-            line = unicode(line)
-        fout.write(line)
-        fout.write('\n')
-
+input_file = '../third_party/tensorflow/tensorflow/core/ops/ops.pbtxt';
+output_file = '../src/tf-operator.pb'
 
+with open(input_file) as input_handle:
+    ops_list = op_def_pb2.OpList()
+    text_format.Merge(input_handle.read(), ops_list)
+    data = ops_list.SerializeToString()
+    with open(output_file, 'wb') as output_handle:
+        output_handle.write(data)

Энэ ялгаанд хэт олон файл өөрчлөгдсөн тул зарим файлыг харуулаагүй болно