Browse Source

Operator documentation formatting

Lutz Roeder 8 years ago
parent
commit
e153b4df03
10 changed files with 453 additions and 603 deletions
  1. 1 1
      README.md
  2. 74 445
      src/onnx-operator.json
  3. 260 130
      src/tf-operator.json
  4. 33 5
      src/view-onnx.js
  5. 4 4
      src/view-template.js
  6. 39 4
      src/view-tf.js
  7. 15 4
      tools/onnx-generate
  8. 6 4
      tools/onnx-operator-json.py
  9. 17 4
      tools/tf-generate
  10. 4 2
      tools/tf-operator-json.py

+ 1 - 1
README.md

@@ -21,7 +21,7 @@ Netron is a viewer for [ONNX](http://onnx.ai) neural network models.
 
 ## Download Models
 
-Below are a few model files you can download and open in Netron:
+Below are a few model files you can download and open:
 
 **ONNX Models**
 

File diff suppressed because it is too large
+ 74 - 445
src/onnx-operator.json


File diff suppressed because it is too large
+ 260 - 130
src/tf-operator.json


+ 33 - 5
src/view-onnx.js

@@ -13,11 +13,13 @@ class OnnxModel {
 
             this._model = onnx.ModelProto.decode(buffer);
 
-            if (this._model.graph) {
-                this._graph = new OnnxGraph(this, this._model.graph, 0);
-                this._activeGraph = this._graph;
+            if (!this._model.graph) {
+                throw 'Model does not contain a graph.';
             }
 
+            this._graph = new OnnxGraph(this, this._model.graph, 0);
+            this._activeGraph = this._graph;
+
             if (!OnnxModel.operatorMetadata) {
                 OnnxModel.operatorMetadata = new OnnxOperatorMetadata(this.hostService);
             }
@@ -664,8 +666,7 @@ class OnnxOperatorMetadata {
                             }
                             else {
                                 var text = lines.join('');
-                                text = text.replace(/\`\`(.*?)\`\`/gm, (match, content) => '<code>' + content + '</code>');
-                                text = text.replace(/\`(.*?)\`/gm, (match, content) => '<code>' + content + '</code>');
+                                text = this.markdown(text);
                                 output.push('<p>' + text + '</p>');
                             }
                         }
@@ -678,6 +679,27 @@ class OnnxOperatorMetadata {
             var formatRange = (value) => {
                 return (value == 2147483647) ? '&#8734;' : value.toString();
             };
+            if (schema.attributes) {
+                schema.attributes.forEach((attribute) => {
+                    if (attribute.description) {
+                        attribute.description = this.markdown(attribute.description);
+                    }
+                });
+            }
+            if (schema.inputs) {
+                schema.inputs.forEach((input) => {
+                    if (input.description) {
+                        input.description = this.markdown(input.description);
+                    }
+                });
+            }
+            if (schema.outputs) {
+                schema.outputs.forEach((output) => {
+                    if (output.description) {
+                        output.description = this.markdown(output.description);
+                    }
+                });
+            }
             if (schema.min_input != schema.max_input) {
                 schema.inputs_range = formatRange(schema.min_input) + ' - ' + formatRange(schema.max_input);
             }
@@ -696,4 +718,10 @@ class OnnxOperatorMetadata {
         }
         return "";
     }
+
+    markdown(text) {
+        text = text.replace(/\`\`(.*?)\`\`/gm, (match, content) => '<code>' + content + '</code>');
+        text = text.replace(/\`(.*?)\`/gm, (match, content) => '<code>' + content + '</code>');
+        return text;
+    }
 }

+ 4 - 4
src/view-template.js

@@ -54,7 +54,7 @@ var operatorTemplate = `
 <h2>Attributes</h2>
 <dl>
 {{#attributes}}
-<dt><tt>{{{name}}}</tt> : {{{type}}}</dt>
+<dt>{{{name}}}: <tt>{{{type}}}</tt></dt>
 <dd>{{{description}}}</dd>
 {{/attributes}}
 </dl>
@@ -65,7 +65,7 @@ var operatorTemplate = `
 <dl>
 {{/if}}
 {{#inputs}}
-<dt><tt>{{{name}}}</tt> {{#if option}}({{{option}}}){{/if}}: {{{typeStr}}}</dt>
+<dt>{{{name}}}: <tt>{{{type}}}</tt> {{#if option}}({{{option}}}){{/if}}</dt>
 <dd>{{{description}}}</dd>
 {{/inputs}}
 </dl>
@@ -75,7 +75,7 @@ var operatorTemplate = `
 <dl>
 {{/if}}
 {{#outputs}}
-<dt><tt>{{{name}}}</tt> {{#if option}}({{{option}}}){{/if}}: {{{typeStr}}}</dt>
+<dt>{{{name}}}: <tt>{{{type}}}</tt> {{#if option}}({{{option}}}){{/if}}</dt>
 <dd>{{{description}}}</dd>
 {{/outputs}}
 </dl>
@@ -84,7 +84,7 @@ var operatorTemplate = `
 <h2>Type Constraints</h2>
 <dl>
 {{#type_constraints}}
-<dt><tt>{{{type_param_str}}}</tt>: {{{allowed_type_strs_display}}}</dt>
+<dt>{{{type_param_str}}}: {{#allowed_type_strs}}<tt>{{this}}</tt>{{#unless @last}}, {{/unless}}{{/allowed_type_strs}}</dt>
 <dd>{{{description}}}</dd>
 {{/type_constraints}}
 </dl>

+ 39 - 4
src/view-tf.js

@@ -41,7 +41,7 @@ class TensorFlowModel {
 
                 this._model = new tensorflow.SavedModel();
                 this._model.metaGraphs.push(metaGraphDef);
-                this._graphs = [ new TensorFlowGraph(this._model, metaGraphDef) ];
+                this._graphs = [ new TensorFlowGraph(this._model, metaGraphDef, 0) ];
             }
 
             this._activeGraph = (this._graphs.length > 0) ? this._graphs[0] : null;
@@ -229,7 +229,7 @@ class TensorFlowGraph {
         var results = [];
         this._graph.graphDef.node.forEach((node) => {
             var id = node.name + ':0';
-            if (!this._initializerMap[id] && !this._inputMap[id]) {
+            if (!this._initializerMap[id] && !this._inputMap[id] && node.op != 'NoOp') {
                 results.push(new TensorFlowNode(this, node));
             }
         });
@@ -370,6 +370,9 @@ class TensorFlowAttribute {
     }
 
     get type() {
+        if (this._value.hasOwnProperty('tensor')) {
+            return TensorFlowTensor.formatTensorType(this._value.tensor);
+        }
         return '';
     }
 
@@ -395,6 +398,9 @@ class TensorFlowAttribute {
             }
             return this._value.s.map(v => v.toString()).join(', ');           
         }
+        else if (this._value.hasOwnProperty('tensor')) {
+            return new TensorFlowTensor(this._value.tensor).value;
+        }
         else if (this._value.hasOwnProperty('list')) {
             var list = this._value.list;
             if (list.s && list.s.length > 0) {
@@ -504,6 +510,17 @@ class TensorFlowTensor {
                     return 'Tensor data is empty.';
                 }
                 break;
+            case tensorflow.DataType.DT_STRING:
+                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) {
+                    this._data = this._tensor.stringVal;
+                }
+                else {
+                    return 'Tensor data is empty.';
+                }
+                break;
             default:
                 debugger;
                 return 'Tensor data type is not implemented.';
@@ -511,11 +528,13 @@ class TensorFlowTensor {
 
         this._index = 0;
         this._count = 0;
+        this._utf8Decoder = window.TextDecoder ? new TextDecoder('utf-8') : null;
         var result = this.read(0);
         delete this._index;
         delete this._count;
         delete this._data;
         delete this._rawData;
+        delete this._utf8Decoder;
 
         return JSON.stringify(result, null, 4);
     }
@@ -524,7 +543,7 @@ class TensorFlowTensor {
         var results = [];
         var dimensions = this._tensor.tensorShape.dim;
         if (dimensions.length == 0 && this._data.length == 1) {
-            return this._data[0];
+            return this.readDataValue();
         }
         var dim = dimensions[dimension];
         var size = dim.size;
@@ -535,7 +554,7 @@ class TensorFlowTensor {
                     return results;
                 }
                 if (this._data) {
-                    results.push(this._data[this._index++]);
+                    results.push(this.readDataValue());
                 }
                 else {
                     if (this._rawData) {
@@ -568,6 +587,19 @@ class TensorFlowTensor {
         return results;
     }
 
+    readDataValue() {
+        var value = this._data[this._index++];
+        if (this._tensor.dtype == tensorflow.DataType.DT_STRING) {
+            if (this._utf8Decoder) {
+                value = this._utf8Decoder.decode(value);
+            }
+            else {
+                value = String.fromCharCode.apply(null, textArray);
+            }
+        }
+        return value;
+    }
+
     static formatTensorType(tensor) {
         if (tensor.dtype) {
             var type = TensorFlowTensor.formatDataType(tensor.dtype);
@@ -603,6 +635,9 @@ class TensorFlowTensor {
             if (shape.dim.length == 0) {
                 return '';
             }
+            if (shape.dim.length == 1 && !shape.dim[0].size) {
+                return '[0]';
+            }
             return '[' + shape.dim.map((dim) => dim.size ? dim.size.toString() : '?').join(',') + ']';
         }
         debugger;

+ 15 - 4
tools/onnx-generate

@@ -2,10 +2,21 @@
 
 mkdir -p ../third_party
 
-pushd "../third_party" > /dev/null
-sudo rm -rf onnx
-git clone --recursive [email protected]:onnx/onnx.git
-popd > /dev/null
[email protected]:onnx/onnx.git
+
+if [ -d "../third_party/onnx" ]; then
+    pushd "../third_party/onnx" > /dev/null
+    echo "Fetch ${repository}..."
+    git fetch -p
+    echo "Reset ${repository}..."
+    git reset --hard origin/master
+    popd > /dev/null
+else
+    echo "Clone ${repository}..."
+    pushd "../third_party" > /dev/null
+    git clone --recursive ${repository}
+    popd > /dev/null
+fi
 
 export ONNX_ML=1
 

+ 6 - 4
tools/onnx-operator-json.py

@@ -56,8 +56,9 @@ def generate_json(schemas, json_file):
                     'name': input.name, 
                     'description': input.description,
                     'option': option,
-                    'typeStr': input.typeStr,
-                    'types': generate_json_types(input.types) })
+                    'type': input.typeStr
+                    #'types': generate_json_types(input.types) 
+                })
         json_schema['min_input'] = schema.min_input;
         json_schema['max_input'] = schema.max_input;
         if schema.outputs:
@@ -72,8 +73,9 @@ def generate_json(schemas, json_file):
                     'name': output.name, 
                     'description': output.description,
                     'option': option,
-                    'typeStr': output.typeStr,
-                    'types': generate_json_types(output.types) })
+                    'type': output.typeStr
+                    #'types': generate_json_types(output.types) 
+                })
         json_schema['min_output'] = schema.min_output;
         json_schema['max_output'] = schema.max_output;
         if schema.attributes:

+ 17 - 4
tools/tf-generate

@@ -1,9 +1,22 @@
 #!/bin/bash
 
-pushd "../third_party" > /dev/null
-sudo rm -rf tensorflow
-git clone --recursive [email protected]:tensorflow/tensorflow.git
-popd > /dev/null
+mkdir -p ../third_party
+
[email protected]:tensorflow/tensorflow.git
+
+if [ -d "../third_party/tensorflow" ]; then
+    pushd "../third_party/tensorflow" > /dev/null
+    echo "Fetch ${repository}..."
+    git fetch -p
+    echo "Reset ${repository}..."
+    git reset --hard origin/master
+    popd > /dev/null
+else
+    pushd "../third_party" > /dev/null
+    echo "Clone ${repository}..."
+    git clone --recursive ${repository}
+    popd > /dev/null
+fi
 
 echo "Generate '../src/tf.js'"
 ../node_modules/protobufjs/bin/pbjs -t static-module -w closure -r tf -o ../src/tf.js \

+ 4 - 2
tools/tf-operator-json.py

@@ -33,7 +33,8 @@ for schema in ops_list.op:
             json_schema['inputs'].append({
                 'name': input_arg.name,
                 'type': input_arg.type,
-                'description': input_arg.description
+                'description': input_arg.description,
+                'type_attr': input_arg.type_attr
             })
     if schema.output_arg:
         json_schema['outputs'] = []
@@ -41,7 +42,8 @@ for schema in ops_list.op:
             json_schema['outputs'].append({
                 'name': output_arg.name,
                 'type': output_arg.type,
-                'description': output_arg.description
+                'description': output_arg.description,
+                'type_attr': output_arg.type_attr
             })
     if schema.attr:
         json_schema['attributes'] = []

Some files were not shown because too many files changed in this diff