Browse Source

Add ncnn test files (#296) (#860)

Lutz Roeder 4 years ago
parent
commit
d23ed691fe
3 changed files with 461 additions and 47 deletions
  1. 352 33
      source/ncnn-metadata.json
  2. 88 14
      source/ncnn.js
  3. 21 0
      test/models.json

+ 352 - 33
source/ncnn-metadata.json

@@ -39,7 +39,11 @@
   },
   {
     "name": "Cast",
-    "operator": 64
+    "operator": 64,
+    "attributes": [
+      { "name": "type_from", "type": "CastOpType", "default": 0 },
+      { "name": "type_to", "type": "CastOpType", "default": 0 }
+    ]
   },
   {
     "name": "Clip",
@@ -75,17 +79,78 @@
       { "name": "pad_left", "type": "int32", "default": 0 },
       { "name": "bias_term", "default": 0, "visible": false },
       { "name": "weight_data_size", "type": "int32", "default": 0, "visible": false },
-      { "name": "group", "type": "int32", "default": 0 },
+      { "name": "" },
       { "name": "int8_scale_term", "default": 0 },
       { "name": "activation_type", "default": 0 },
       { "name": "activation_params", "default": [] },
       { "name": "kernel_h", "type": "int32", "default": 0 },
       { "name": "dilation_h", "type": "int32", "default": 1 },
       { "name": "stride_h", "type": "int32", "default": 1 },
+      { "name": "pad_top", "type": "int32", "default": 0 },
+      { "name": "pad_right", "type": "int32", "default": 0 },
+      { "name": "pad_bottom", "type": "int32", "default": 0 },
+      { "name": "" },
+      { "name": "pad_value", "type": "float32", "default": 0 },
+      { "name": "dynamic_weight", "type": "int32", "default": 0 }
+    ]
+  },
+  {
+    "name": "Convolution1D",
+    "operator": 81,
+    "category": "Layer",
+    "attributes": [
+      { "name": "num_output", "type": "int32", "default": 0 },
+      { "name": "kernel_w", "type": "int32", "default": 0 },
+      { "name": "dilation_w", "type": "int32", "default": 1 },
+      { "name": "stride_w", "type": "int32", "default": 1 },
+      { "name": "pad_left", "type": "int32", "default": 0 },
+      { "name": "bias_term", "default": 0, "visible": false },
+      { "name": "weight_data_size", "type": "int32", "default": 0, "visible": false },
+      { "name": "" },
+      { "name": "" },
+      { "name": "activation_type", "default": 0 },
+      { "name": "activation_params", "default": [] },
+      { "name": "" },
+      { "name": "" },
+      { "name": "" },
+      { "name": "" },
       { "name": "pad_right", "type": "int32", "default": 0 },
+      { "name": "" },
+      { "name": "" },
+      { "name": "pad_value", "type": "float32", "default": 0 },
+      { "name": "dynamic_weight", "type": "int32", "default": 0 }
+    ]
+  },
+  {
+    "name": "Convolution3D",
+    "operator": 84,
+    "category": "Layer",
+    "attributes": [
+      { "name": "num_output", "type": "int32", "default": 0 },
+      { "name": "kernel_w", "type": "int32", "default": 0 },
+      { "name": "dilation_w", "type": "int32", "default": 1 },
+      { "name": "stride_w", "type": "int32", "default": 1 },
+      { "name": "pad_left", "type": "int32", "default": 0 },
+      { "name": "bias_term", "default": 0, "visible": false },
+      { "name": "weight_data_size", "type": "int32", "default": 0, "visible": false },
+      { "name": "" },
+      { "name": "" },
+      { "name": "activation_type", "default": 0 },
+      { "name": "activation_params", "default": [] },
+      { "name": "kernel_h", "type": "int32", "default": 0 },
+      { "name": "dilation_h", "type": "int32", "default": 1 },
+      { "name": "stride_h", "type": "int32", "default": 1 },
       { "name": "pad_top", "type": "int32", "default": 0 },
+      { "name": "pad_right", "type": "int32", "default": 0 },
       { "name": "pad_bottom", "type": "int32", "default": 0 },
-      { "name": "pad_value", "type": "float32", "default": 0 }
+      { "name": "pad_behind", "type": "int32", "default": 0 },
+      { "name": "pad_value", "type": "float32", "default": 0 },
+      { "name": "" },
+      { "name": "" },
+      { "name": "kernel_d", "type": "int32", "default": 0 },
+      { "name": "dilation_d", "type": "int32", "default": 1 },
+      { "name": "stride_d", "type": "int32", "default": 1 },
+      { "name": "pad_front", "type": "int32", "default": 0 }
     ]
   },
   {
@@ -107,10 +172,71 @@
       { "name": "kernel_h", "default": 0 },
       { "name": "dilation_h", "default": 1 },
       { "name": "stride_h", "default": 1 },
+      { "name": "pad_top", "type": "int32", "default": 0 },
       { "name": "pad_right", "type": "int32", "default": 0 },
+      { "name": "pad_bottom", "type": "int32", "default": 0 },
+      { "name": "" },
+      { "name": "pad_value", "type": "float32", "default": 0 },
+      { "name": "dynamic_weight", "type": "int32", "default": 0 }
+    ]
+  },
+  {
+    "name": "ConvolutionDepthWise1D",
+    "operator": 83,
+    "category": "Layer",
+    "attributes": [
+      { "name": "num_output", "default": 0 },
+      { "name": "kernel_w", "default": 0 },
+      { "name": "dilation_w", "default": 1 },
+      { "name": "stride_w", "default": 1 },
+      { "name": "pad_left", "default": 0 },
+      { "name": "bias_term", "default": 0, "visible": false },
+      { "name": "weight_data_size", "default": 0, "visible": false },
+      { "name": "group", "default": 0 },
+      { "name": "" },
+      { "name": "activation_type", "default": 0 },
+      { "name": "activation_params", "default": [] },
+      { "name": "" },
+      { "name": "" },
+      { "name": "" },
+      { "name": "" },
+      { "name": "pad_right", "type": "int32", "default": 0 },
+      { "name": "" },
+      { "name": "" },
+      { "name": "pad_value", "type": "float32", "default": 0 },
+      { "name": "dynamic_weight", "type": "int32", "default": 0 }
+    ]
+  },
+  {
+    "name": "ConvolutionDepthWise3D",
+    "operator": 85,
+    "category": "Layer",
+    "attributes": [
+      { "name": "num_output", "default": 0 },
+      { "name": "kernel_w", "default": 0 },
+      { "name": "dilation_w", "default": 1 },
+      { "name": "stride_w", "default": 1 },
+      { "name": "pad_left", "default": 0 },
+      { "name": "bias_term", "default": 0, "visible": false },
+      { "name": "weight_data_size", "default": 0, "visible": false },
+      { "name": "group", "default": 0 },
+      { "name": "" },
+      { "name": "activation_type", "default": 0 },
+      { "name": "activation_params", "default": [] },
+      { "name": "kernel_h", "default": 0 },
+      { "name": "dilation_h", "default": 1 },
+      { "name": "stride_h", "default": 1 },
       { "name": "pad_top", "type": "int32", "default": 0 },
+      { "name": "pad_right", "type": "int32", "default": 0 },
       { "name": "pad_bottom", "type": "int32", "default": 0 },
-      { "name": "pad_value", "type": "float32", "default": 0 }
+      { "name": "pad_behind", "type": "int32", "default": 0 },
+      { "name": "pad_value", "type": "float32", "default": 0 },
+      { "name": "" },
+      { "name": "" },
+      { "name": "kernel_d", "type": "int32", "default": 0 },
+      { "name": "dilation_d", "type": "int32", "default": 1 },
+      { "name": "stride_d", "type": "int32", "default": 1 },
+      { "name": "pad_front", "type": "int32", "default": 0 }
     ]
   },
   {
@@ -144,14 +270,22 @@
       { "name": "pad_w", "default": 0 },
       { "name": "bias_term", "default": 0, "visible": false },
       { "name": "weight_data_size", "default": 0, "visible": false },
-      { "name": "group", "default": 0 },
+      { "name": "" },
       { "name": "int8_scale_term", "default": 0 },
       { "name": "activation_type", "default": 0 },
       { "name": "activation_params", "default": [] },
       { "name": "kernel_h", "default": 0 },
       { "name": "dilation_h", "default": 1 },
       { "name": "stride_h", "default": 1 },
-      { "name": "pad_h", "default": 0 }
+      { "name": "pad_top", "default": 0 },
+      { "name": "pad_right", "default": 0 },
+      { "name": "" },
+      { "name": "pad_bottom", "default": 0 },
+      { "name": "" },
+      { "name": "output_pad_right", "default": 0 },
+      { "name": "output_pad_bottom", "default": 0 },
+      { "name": "output_w", "default": 0 },
+      { "name": "output_h", "default": 0 }
     ]
   },
   {
@@ -173,7 +307,15 @@
       { "name": "kernel_h", "default": 0 },
       { "name": "dilation_h", "default": 1 },
       { "name": "stride_h", "default": 1 },
-      { "name": "pad_h", "default": 0 }
+      { "name": "pad_top", "default": 0 },
+      { "name": "pad_right", "default": 0 },
+      { "name": "" },
+      { "name": "pad_bottom", "default": 0 },
+      { "name": "" },
+      { "name": "output_pad_right", "default": 0 },
+      { "name": "output_pad_bottom", "default": 0 },
+      { "name": "output_w", "default": 0 },
+      { "name": "output_h", "default": 0 }
     ]
   },
   {
@@ -182,7 +324,11 @@
   },
   {
     "name": "Dequantize",
-    "operator": 58
+    "operator": 58,
+    "attributes": [
+      { "name": "scale_data_size", "default": 1, "visible": false },
+      { "name": "bias_data_size", "default": 0, "visible": false }
+    ]
   },
   {
     "name": "DetectionOutput",
@@ -220,7 +366,11 @@
   },
   {
     "name": "ELU",
-    "operator": 11
+    "operator": 11,
+    "category": "Activation",
+    "attributes": [
+      { "name": "alpha", "type": "float32", "default": 0.1 }
+    ]
   },
   {
     "name": "Embed",
@@ -229,31 +379,53 @@
     "attributes": [
       { "name": "num_output", "default": 0 },
       { "name": "input_dim", "default": 0 },
-      { "name": "bias_term", "default": 0 },
-      { "name": "weight_data_size", "default": 0 }
+      { "name": "bias_term", "default": 0, "visible": false },
+      { "name": "weight_data_size", "default": 0, "visible": false }
     ]
   },
   {
     "name": "Exp",
-    "operator": 13
-  },
-  {
-    "name": "Exp",
-    "operator": 17
+    "operator": 13,
+    "attributes": [
+      { "name": "base", "type": "float32", "default": -1 },
+      { "name": "scale", "type": "float32", "default": 1 },
+      { "name": "shift", "type": "float32", "default": 0 }
+    ]
   },
   {
     "name": "ExpandDims",
-    "operator": 45
+    "operator": 45,
+    "category": "Shape",
+    "attributes": [
+      { "name": "expand_w", "default": 0 },
+      { "name": "expand_h", "default": 0 },
+      { "name": "expand_c", "default": 0 },
+      { "name": "axes", "default": [] }
+    ]
   },
   {
     "name": "Flatten",
     "operator": 14,
     "category": "Shape"
   },
+  {
+    "name": "GELU",
+    "operator": 80,
+    "category": "Activation",
+    "attributes": [
+      { "name": "fast_gelu", "type": "int32", "default": 0 }
+    ]
+  },
   {
     "name": "Gemm",
     "operator": 74,
-    "category": "Layer"
+    "category": "Layer",
+    "attributes": [
+      { "name": "alpha", "type": "float32", "default": 1 },
+      { "name": "beta", "type": "float32", "default": 1 },
+      { "name": "transA", "type": "int32", "default": 0 },
+      { "name": "transB", "type": "int32", "default": 0 }
+    ]
   },
   {
     "name": "GroupNorm",
@@ -309,7 +481,7 @@
       { "name": "" },
       { "name": "int8_scale_term", "default": 0 },
       { "name": "activation_type", "default": 0 },
-      { "name": "activation_params", "default": 0 }
+      { "name": "activation_params", "default": [] }
     ]
   },
   {
@@ -348,6 +520,15 @@
       { "name": "eps", "type": "float32", "default": 0.001 }
     ]
   },
+  {
+    "name": "Log",
+    "operator": 17,
+    "attributes": [
+      { "name": "base", "type": "float32", "default": -1 },
+      { "name": "scale", "type": "float32", "default": 1 },
+      { "name": "shift", "type": "float32", "default": 0 }
+    ]
+  },
   {
     "name": "LRN",
     "operator": 18,
@@ -376,7 +557,16 @@
     "attributes": [
       { "name": "w", "default": 0 },
       { "name": "h", "default": 0 },
-      { "name": "c", "default": 0 }
+      { "name": "c", "default": 0 },
+      { "name": "" },
+      { "name": "" },
+      { "name": "" },
+      { "name": "" },
+      { "name": "" },
+      { "name": "" },
+      { "name": "" },
+      { "name": "" },
+      { "name": "d", "default": 0 }
     ]
   },
   {
@@ -384,9 +574,25 @@
     "operator": 71,
     "category": "Activation"
   },
+  {
+    "name": "MultiHeadAttention",
+    "operator": 79,
+    "category": "Layer",
+    "attributes": [
+      { "name": "embed_dim", "default": 0 },
+      { "name": "num_head", "default": 1 },
+      { "name": "weight_data_size", "default": 0, "visible": false }
+    ]
+  },
   {
     "name": "MVN",
-    "operator": 20
+    "operator": 20,
+    "category": "Normalization",
+    "attributes": [
+      { "name": "normalize_variance", "default": 0 },
+      { "name": "across_channels", "default": 0 },
+      { "name": "eps", "type": "float32", "default": 0.0001 }
+    ]
   },
   {
     "name": "Noop",
@@ -411,7 +617,16 @@
   },
   {
     "name": "Packing",
-    "operator": 62
+    "operator": 62,
+    "category": "Shape",
+    "attributes": [
+      { "name": "out_elempack", "default": 1 },
+      { "name": "use_padding", "default": 0 },
+      { "name": "cast_type_from", "default": 0 },
+      { "name": "cast_type_to", "default": 0 },
+      { "name": "storage_type_from", "default": 0 },
+      { "name": "storage_type_to", "default": 0 }
+    ]
   },
   {
     "name": "Padding",
@@ -422,7 +637,7 @@
       { "name": "bottom", "default": 0 },
       { "name": "left", "default": 0 },
       { "name": "right", "default": 0 },
-      { "name": "type", "default": 0 },
+      { "name": "type", "type": "PaddingType", "default": 0 },
       { "name": "value", "type": "float32", "default": 0 },
       { "name": "per_channel_pad_data_size", "default": 0, "visible": false },
       { "name": "front", "default": 0 },
@@ -440,6 +655,7 @@
   {
     "name": "PixelShuffle",
     "operator": 69,
+    "category": "Shape",
     "attributes": [
       { "name": "upscale_factor", "default": 1 },
       { "name": "mode", "default": 0 }
@@ -471,9 +687,72 @@
       { "name": "out_h", "default": 0 }
     ]
   },
+  {
+    "name": "Pooling1D",
+    "operator": 82,
+    "category": "Pool",
+    "attributes": [
+      { "name": "pooling_type", "type": "PoolingType", "default": 0 },
+      { "name": "kernel_w", "default": 0 },
+      { "name": "stride_w", "default": 1 },
+      { "name": "pad_left", "default": 0 },
+      { "name": "global_pooling", "default": 0 },
+      { "name": "pad_mode", "default": 0 },
+      { "name": "avgpool_count_include_pad", "default": 0 },
+      { "name": "adaptive_pooling", "default": 0 },
+      { "name": "out_w", "default": 0 },
+      { "name": "" },
+      { "name": "" },
+      { "name": "" },
+      { "name": "" },
+      { "name": "" },
+      { "name": "pad_right", "default": 0 }
+    ]
+  },
+  {
+    "name": "Pooling3D",
+    "operator": 86,
+    "category": "Pool",
+    "attributes": [
+      { "name": "pooling_type", "type": "PoolingType", "default": 0 },
+      { "name": "kernel_w", "default": 0 },
+      { "name": "stride_w", "default": 1 },
+      { "name": "pad_left", "default": 0 },
+      { "name": "global_pooling", "default": 0 },
+      { "name": "pad_mode", "default": 0 },
+      { "name": "avgpool_count_include_pad", "default": 0 },
+      { "name": "adaptive_pooling", "default": 0 },
+      { "name": "out_w", "default": 0 },
+      { "name": "" },
+      { "name": "" },
+      { "name": "kernel_h", "default": 0 },
+      { "name": "stride_h", "default": 1 },
+      { "name": "pad_top", "default": 0 },
+      { "name": "pad_right", "default": 0 },
+      { "name": "pad_bottom", "default": 0 },
+      { "name": "pad_behind", "default": 0 },
+      { "name": "" },
+      { "name": "out_h", "default": 0 },
+      { "name": "" },
+      { "name": "" },
+      { "name": "kernel_d", "default": 0 },
+      { "name": "stride_d", "default": 1 },
+      { "name": "pad_front", "default": 0 },
+      { "name": "" },
+      { "name": "" },
+      { "name": "" },
+      { "name": "" },
+      { "name": "out_d", "default": 0 }
+    ]
+  },
   {
     "name": "Power",
-    "operator": 22
+    "operator": 22,
+    "attributes": [
+      { "name": "power", "type": "float32", "default": 1 },
+      { "name": "scale", "type": "float32", "default": 1 },
+      { "name": "shift", "type": "float32", "default": 0 }
+    ]
   },
   {
     "name": "PReLU",
@@ -513,11 +792,21 @@
   },
   {
     "name": "Quantize",
-    "operator": 57
+    "operator": 57,
+    "attributes": [
+      { "name": "scale_data_size", "default": 1, "visible": false }
+    ]
   },
   {
-    "name": "Reducation",
-    "operator": 25
+    "name": "Reduction",
+    "operator": 25,
+    "attributes": [
+      { "name": "op_type", "type": "ReductionOpType", "default": 0 },
+      { "name": "reduce_all", "type": "int32", "default": 1 },
+      { "name": "coeff", "type": "float32", "default": 1.0 },
+      { "name": "axes", "default": [] },
+      { "name": "keepdims", "type": "int32", "default": 0 }
+    ]
   },
   {
     "name": "ReLU",
@@ -534,6 +823,7 @@
   {
     "name": "Reorg",
     "operator": 55,
+    "category": "Shape",
     "attributes": [
       { "name": "stride", "default": 1 },
       { "name": "mode", "default": 0 }
@@ -541,7 +831,14 @@
   },
   {
     "name": "Requantize",
-    "operator": 63
+    "operator": 63,
+    "attributes": [
+      { "name": "scale_in_data_size", "default": 1, "visible": false },
+      { "name": "scale_out_data_size", "default": 1, "visible": false },
+      { "name": "bias_data_size", "default": 0, "visible": false },
+      { "name": "activation_type", "default": 0 },
+      { "name": "activation_params", "default": [] }
+    ]
   },
   {
     "name": "Reshape",
@@ -551,7 +848,15 @@
       { "name": "w", "default": -233 },
       { "name": "h", "default": -233 },
       { "name": "c", "default": -233 },
-      { "name": "permute", "default": 0 }
+      { "name": "permute", "default": 0 },
+      { "name": "" },
+      { "name": "" },
+      { "name": "" },
+      { "name": "" },
+      { "name": "" },
+      { "name": "" },
+      { "name": "" },
+      { "name": "d", "default": -233 }
     ]
   },
   {
@@ -593,6 +898,7 @@
   {
     "name": "ShuffleChannel",
     "operator": 52,
+    "category": "Shape",
     "attributes": [
       { "name": "group", "default": 1 },
       { "name": "reverse", "default": 0 }
@@ -610,6 +916,12 @@
     "attributes": [
       { "name": "slices", "default": [] },
       { "name": "axis", "default": 0 }
+    ],
+    "inputs": [
+      { "name": "input" }
+    ],
+    "outputs": [
+      { "name": "output", "option": "variadic" }
     ]
   },
   {
@@ -618,7 +930,7 @@
     "category": "Activation",
     "attributes": [
       { "name": "axis", "type": "int32", "default": 0 },
-      { "name": "fixbug0", "type": "int32", "default": 0 }
+      { "name": "fixbug0", "type": "int32", "default": 0, "visible": false }
     ]
   },
   {
@@ -644,7 +956,14 @@
   },
   {
     "name": "Squeeze",
-    "operator": 44
+    "operator": 44,
+    "category": "Shape",
+    "attributes": [
+      { "name": "squeeze_w", "default": 0 },
+      { "name": "squeeze_h", "default": 0 },
+      { "name": "squeeze_c", "default": 0 },
+      { "name": "axes", "default": [] }
+    ]
   },
   {
     "name": "StatisticsPooling",
@@ -673,7 +992,7 @@
     "name": "UnaryOp",
     "operator": 41,
     "attributes": [
-      { "name": "op_type", "type": "int32", "default": 0 }
+      { "name": "op_type", "type": "UnaryOpType", "default": 0 }
     ]
   },
   {
@@ -706,4 +1025,4 @@
       { "name": "input", "option": "variadic" }
     ]
   }
-]
+]

+ 88 - 14
source/ncnn.js

@@ -319,9 +319,9 @@ ncnn.Node = class {
             case 'Embed': {
                 const num_output = parseInt(attributes.get('0') || 0, 10);
                 const weight_data_size = parseInt(attributes.get('3') || 0, 10);
-                this._weight(blobReader, 'weight', [ weight_data_size ]);
+                this._weight(blobReader, 'weight', [ weight_data_size / num_output, num_output ]);
                 if (parseInt(attributes.get('2') || 0, 10) === 1) {
-                    this._weight(blobReader, 'bias', [ num_output], 'float32');
+                    this._weight(blobReader, 'bias', [ num_output ], 'float32');
                 }
                 attributes.get('3');
                 break;
@@ -343,25 +343,76 @@ ncnn.Node = class {
                 const kernel_w = parseInt(attributes.get('1') || 0, 10);
                 const kernel_h = parseInt(attributes.get('11') || kernel_w, 10);
                 const weight_data_size = parseInt(attributes.get('6') || 0, 10);
-                this._weight(blobReader, 'weight', [ num_output, weight_data_size / ( num_output * kernel_w * kernel_h), kernel_h, kernel_w ]);
+                this._weight(blobReader, 'weight', [ num_output, weight_data_size / (num_output * kernel_w * kernel_h), kernel_h, kernel_w ]);
                 if (parseInt(attributes.get('5') || 0, 10) === 1) {
                     this._weight(blobReader, 'bias', [ num_output ], 'float32');
                 }
                 attributes.delete('6');
                 break;
             }
-            case 'Dequantize': {
-                if (parseInt(attributes.get('1') || 0, 10) === 1) {
-                    const bias_data_size = parseInt(attributes.get('2') || 0, 10);
-                    this._weight(blobReader, 'bias', [ bias_data_size ], 'float32');
+            case 'Convolution1D':
+            case 'ConvolutionDepthWise1D': {
+                const activation_names = [ '', 'ReLU', 'LeakyReLU', 'Clip', 'Sigmoid', 'Mish', 'HardSwish' ];
+                const activation_type = parseInt(attributes.get('9') || 0, 10);
+                if (activation_type > 0 && activation_type < activation_names.length) {
+                    const layer = {
+                        type: activation_names[activation_type],
+                        attributes: new Map()
+                    };
+                    this._chain.push(new ncnn.Node(metadata, blobReader, layer, arg));
+                }
+                const num_output = parseInt(attributes.get('0') || 0, 10);
+                const kernel_w = parseInt(attributes.get('1') || 0, 10);
+                const weight_data_size = parseInt(attributes.get('6') || 0, 10);
+                this._weight(blobReader, 'weight', [ num_output, weight_data_size / (num_output * kernel_w), kernel_w ]);
+                if (parseInt(attributes.get('5') || 0, 10) === 1) {
+                    this._weight(blobReader, 'bias', [ num_output ], 'float32');
                 }
+                attributes.delete('6');
                 break;
             }
-            case 'Requantize': {
-                if (parseInt(attributes.get('2') || 0, 10) === 1) {
-                    const bias_data_size = parseInt(attributes.get('3') || 0, 10);
-                    this._weight(blobReader, 'bias', [ bias_data_size ], 'float32');
+            case 'Convolution3D':
+            case 'ConvolutionDepthWise3D': {
+                const activation_names = [ '', 'ReLU', 'LeakyReLU', 'Clip', 'Sigmoid', 'Mish', 'HardSwish' ];
+                const activation_type = parseInt(attributes.get('9') || 0, 10);
+                if (activation_type > 0 && activation_type < activation_names.length) {
+                    const layer = {
+                        type: activation_names[activation_type],
+                        attributes: new Map()
+                    };
+                    this._chain.push(new ncnn.Node(metadata, blobReader, layer, arg));
                 }
+                const num_output = parseInt(attributes.get('0') || 0, 10);
+                const kernel_w = parseInt(attributes.get('1') || 0, 10);
+                const kernel_h = parseInt(attributes.get('11') || kernel_w, 10);
+                const kernel_d = parseInt(attributes.get('21') || kernel_w, 10);
+                const weight_data_size = parseInt(attributes.get('6') || 0, 10);
+                this._weight(blobReader, 'weight', [ num_output, weight_data_size / (num_output * kernel_w * kernel_h * kernel_d), kernel_d, kernel_h, kernel_w ]);
+                if (parseInt(attributes.get('5') || 0, 10) === 1) {
+                    this._weight(blobReader, 'bias', [ num_output ], 'float32');
+                }
+                attributes.delete('6');
+                break;
+            }
+            case 'Quantize': {
+                const scale_data_size = parseInt(attributes.get('0') || 1, 10);
+                this._weight(blobReader, 'scale', [ scale_data_size ], 'float32');
+                break;
+            }
+            case 'Dequantize': {
+                const scale_data_size = parseInt(attributes.get('0') || 1, 10);
+                const bias_data_size = parseInt(attributes.get('1') || 0, 10);
+                this._weight(blobReader, 'scale', [ scale_data_size ], 'float32');
+                this._weight(blobReader, 'bias', [ bias_data_size ], 'float32');
+                break;
+            }
+            case 'Requantize': {
+                const scale_in_data_size = parseInt(attributes.get('0') || 1, 10);
+                const scale_out_data_size = parseInt(attributes.get('1') || 1, 10);
+                const bias_data_size = parseInt(attributes.get('2') || 0, 10);
+                this._weight(blobReader, 'scale_in', [ scale_in_data_size ], 'float32');
+                this._weight(blobReader, 'scale_out', [ scale_out_data_size ], 'float32');
+                this._weight(blobReader, 'bias', [ bias_data_size ], 'float32');
                 break;
             }
             case 'InstanceNorm': {
@@ -401,8 +452,12 @@ ncnn.Node = class {
             case 'MemoryData': {
                 const w = parseInt(attributes.get('0') || 0, 10);
                 const h = parseInt(attributes.get('1') || 0, 10);
+                const d = parseInt(attributes.get('11') || 0, 10);
                 const c = parseInt(attributes.get('2') || 0, 10);
-                if (c != 0) {
+                if (d != 0) {
+                    this._weight(blobReader, 'data', [ c, d, h, w ], 'float32');
+                }
+                else if (c != 0) {
                     this._weight(blobReader, 'data', [ c, h, w ], 'float32');
                 }
                 else if (h != 0) {
@@ -464,6 +519,21 @@ ncnn.Node = class {
                 attributes.delete('1');
                 break;
             }
+            case 'MultiHeadAttention': {
+                const embed_dim = parseInt(attributes.get('0') || 0, 10);
+                // const num_head = parseInt(attributes.get('1') || 0, 10);
+                // const weight_data_size = parseInt(attributes.get('2') || 0, 10);
+                this._weight(blobReader, 'weight_q', [ embed_dim, embed_dim ]);
+                this._weight(blobReader, 'bias_q', [ embed_dim ], 'float32');
+                this._weight(blobReader, 'weight_k', [ embed_dim, embed_dim ]);
+                this._weight(blobReader, 'bias_k', [ embed_dim ], 'float32');
+                this._weight(blobReader, 'weight_v', [ embed_dim, embed_dim ]);
+                this._weight(blobReader, 'bias_v', [ embed_dim ], 'float32');
+                this._weight(blobReader, 'weight_out', [ embed_dim, embed_dim ]);
+                this._weight(blobReader, 'bias_out', [ embed_dim ], 'float32');
+                attributes.delete('2');
+                break;
+            }
         }
 
         this._attributes = Array.from(attributes).map((attribute) => {
@@ -777,10 +847,14 @@ ncnn.Utility = class {
     static value(value, type) {
         ncnn.Utility._enum = ncnn.Utility._enum || new Map([
             [ 'BinaryOpType', [ 'Add', 'Sub', 'Mul', 'Div', 'Max', 'Min', 'Pow', 'RSub', 'RDiv' ] ],
+            [ 'CastOpType', [ 'Auto', 'Float32', 'Float16', 'Int8', 'BFloat16' ] ],
             [ 'EltwiseType', [ 'Prod', 'Sum', 'Max' ] ],
+            [ 'PaddingType', [ 'Constant', 'Replicate', 'Reflect' ] ],
             [ 'PoolingType', [ 'Max', 'Average' ] ],
             [ 'InterpResizeType', [ '', 'Nearest', 'Bilinear', 'Bicubic' ] ],
-            [ 'PermuteOrderType', [ 'WHC', 'HWC', 'WCH', 'CWH', 'HCW', 'CHW'] ]
+            [ 'PermuteOrderType', [ 'WH WHC WHDC', 'HW HWC HWDC', 'WCH WDHC', 'CWH DWHC', 'HCW HDWC', 'CHW DHWC', 'WHCD', 'HWCD', 'WCHD', 'CWHD', 'HCWD', 'CHWD', 'WDCH', 'DWCH', 'WCDH', 'CWDH', 'DCWH', 'CDWH', 'HDCW', 'DHCW', 'HCDW', 'CHDW', 'DCHW', 'CDHW' ] ],
+            [ 'ReductionOpType', [ 'Sum', 'ASum', 'SumSq', 'Mean', 'Max', 'Min', 'Prod', 'L1', 'L2', 'LogSum', 'LogSumExp' ] ],
+            [ 'UnaryOpType', [ 'Abs', 'Neg', 'Floor', 'Ceil', 'Square', 'Sqrt', 'Rsq', 'Exp', 'Log', 'Sin', 'Cos', 'Tan', 'ASin', 'ACos', 'ATan', 'Reciprocal', 'Tanh' ] ]
         ]);
         if (this._enum.has(type) && typeof value === 'string') {
             const index = parseInt(value, 10);
@@ -1024,4 +1098,4 @@ ncnn.Error = class extends Error {
 
 if (typeof module !== 'undefined' && typeof module.exports === 'object') {
     module.exports.ModelFactory = ncnn.ModelFactory;
-}
+}

+ 21 - 0
test/models.json

@@ -2976,6 +2976,27 @@
     "format": "ncnn",
     "link":   "https://github.com/lutzroeder/netron/issues/296"
   },
+  {
+    "type":   "ncnn",
+    "target": "test_nn_Conv1d.ncnn.param,test_nn_Conv1d.ncnn.bin",
+    "source": "https://github.com/lutzroeder/netron/files/7796942/ncnn-20211231.zip[test_nn_Conv3d.ncnn.param,test_nn_Conv3d.ncnn.bin]",
+    "format": "ncnn",
+    "link":   "https://github.com/lutzroeder/netron/issues/296"
+  },
+  {
+    "type":   "ncnn",
+    "target": "test_nn_Conv3d.ncnn.param,test_nn_Conv3d.ncnn.bin",
+    "source": "https://github.com/lutzroeder/netron/files/7796942/ncnn-20211231.zip[test_nn_Conv3d.ncnn.param,test_nn_Conv3d.ncnn.bin]",
+    "format": "ncnn",
+    "link":   "https://github.com/lutzroeder/netron/issues/296"
+  },
+  {
+    "type":   "ncnn",
+    "target": "test_nn_MultiheadAttention.ncnn.param,test_nn_MultiheadAttention.ncnn.bin",
+    "source": "https://github.com/lutzroeder/netron/files/7796942/ncnn-20211231.zip[test_nn_MultiheadAttention.ncnn.param,test_nn_MultiheadAttention.ncnn.bin]",
+    "format": "ncnn",
+    "link":   "https://github.com/lutzroeder/netron/issues/296"
+  },
   {
     "type":   "ncnn",
     "target": "vgg16.param",