Procházet zdrojové kódy

Caffe tensor support

Lutz Roeder před 8 roky
rodič
revize
71e9f3b5de
3 změnil soubory, kde provedl 99 přidání a 12 odebrání
  1. 2 2
      README.md
  2. 80 1
      src/caffe-model.js
  3. 17 9
      src/caffe-operator.json

+ 2 - 2
README.md

@@ -3,9 +3,9 @@
 
 Netron is a viewer for neural network and machine learning models. 
 
-Netron supports **[ONNX](http://onnx.ai)** models (`.onnx`, `.pb`), **Keras** models (`.keras`, `.h5`) and **TensorFlow Lite** models (`.tflite`).
+Netron supports **[ONNX](http://onnx.ai)** (`.onnx`, `.pb`), **Keras** (`.keras`, `.h5`), **CoreML** (`.mlmodel`) and **TensorFlow Lite** (`.tflite`). 
 
-Netron has experimental support for **CoreML** models (`.mlmodel`) and **TensorFlow** models (`.pb`, `.meta`).
+Netron also has has experimental support for **Caffe** (`.caffemodel`) and **TensorFlow** (`.pb`, `.meta`).
 
 <p align='center'><a href='https://www.lutzroeder.com/ai'><img src='media/screenshot.png' width='800'></a></p>
 

+ 80 - 1
src/caffe-model.js

@@ -213,6 +213,7 @@ class CaffeNode {
             input.connections.forEach((connection) => {
                 if (connection.id instanceof CaffeTensor) {
                     connection.initializer = connection.id;
+                    connection.type = connection.initializer.type;
                     connection.id = '';
                 }
             });
@@ -283,7 +284,12 @@ class CaffeAttribute {
 
     constructor(owner, name, value) {
         this._owner = owner;
-        this._name = name;
+        this._name = '';
+        for (var i = 0; i < name.length; i++) {
+            var character = name[i];
+            var lowerCase = character.toLowerCase();
+            this._name += (character != lowerCase) ? ('_' + lowerCase) : character;
+        }
         this._value = value;
     }
 
@@ -304,6 +310,79 @@ class CaffeTensor {
 
     constructor(blob) {
         this._blob = blob;
+
+        if (blob.hasOwnProperty('num') && blob.hasOwnProperty('channels') &&
+            blob.hasOwnProperty('width') && blob.hasOwnProperty('height')) {
+            this._shape = [];
+            if (blob.num != 1) {
+                this._shape.push(blob.num);
+            }
+            if (blob.channels != 1) {
+                this._shape.push(blob.channels);
+            }
+            if (blob.width != 1) {
+                this._shape.push(blob.width);
+            }
+            if (blob.height != 1) {
+                this._shape.push(blob.height);
+            }
+        }
+        else if (blob.hasOwnProperty('shape')) {
+            this._shape = blob.shape.dim;
+        }
+
+        this._type = '?';
+        if (blob.data.length > 0) {
+            this._type = 'float';
+            this._data = blob.data;
+        }
+        else if (blob.doubleData.length > 0) {
+            this._type = 'double';
+            this._data = blob.doubleData;
+            debugger;
+        }
+    }
+
+    get type() {
+        return this._type + JSON.stringify(this._shape);
+    }
+
+    get value() {
+        if (this._data) {
+            this._index = 0;
+            this._count = 0;
+            var result = this.read(0);
+            delete this._index;
+            delete this._count;
+            return JSON.stringify(result, null, 4);
+        }
+        return '?';
+    }
+
+    read(dimension) {
+        var results = [];
+        var size = this._shape[dimension];
+        if (dimension == this._shape.length - 1) {
+            for (var i = 0; i < size; i++) {
+                if (this._count > 10000) {
+                    results.push('...');
+                    return results;
+                }
+                results.push(this._data[this._index]);
+                this._index++;
+                this._count++;
+            }
+        }
+        else {
+            for (var j = 0; j < size; j++) {
+                if (this._count > 10000) {
+                    results.push('...');
+                    return results;
+                }
+                results.push(this.read(dimension + 1));
+            }
+        }
+        return results;
     }
 }
 

+ 17 - 9
src/caffe-operator.json

@@ -12,11 +12,11 @@
         { "name": "output" }
       ],
       "attributes": [
-        { "name": "biasTerm", "hidden": true },
-        { "name": "weightFiller", "hidden": true },
-        { "name": "biasFiller", "hidden": true },
+        { "name": "bias_term", "hidden": true },
+        { "name": "weight_filler", "hidden": true },
+        { "name": "bias_filler", "hidden": true },
         { "name": "pad", "default": [] },
-        { "name": "kernelSize", "default": [] },
+        { "name": "kernel_size", "default": [] },
         { "name": "stride", "default": [] },
         { "name": "dilation", "default": [] }
       ]
@@ -35,9 +35,9 @@
         { "name": "output" }
       ],
       "attributes": [
-        { "name": "biasTerm", "hidden": true },
-        { "name": "weightFiller", "hidden": true },
-        { "name": "biasFiller", "hidden": true }
+        { "name": "bias_term", "hidden": true },
+        { "name": "weight_filler", "hidden": true },
+        { "name": "bias_filler", "hidden": true }
       ]
     }
   },
@@ -52,8 +52,8 @@
       ],
       "attributes": [
         { "name": "filler", "hidden": false },
-        { "name": "biasTerm", "hidden": false },
-        { "name": "biasFiller", "hidden": false }
+        { "name": "bias_term", "hidden": false },
+        { "name": "bias_filler", "hidden": false }
       ]
     }
   },
@@ -125,6 +125,14 @@
       ]  
     }
   },
+  {
+    "name": "Eltwise",
+    "schema": {
+      "inputs": [
+        { "name": "inputs", "option": "variadic" }
+      ]
+    }
+  },
   {
     "name": "Pooling",
     "schema": {