SSD-VGG-512 Trained on PASCAL VOC2007, PASCAL VOC2012 and MS-COCO Data

Contributed by: Julian W. Francis

Detect and localize objects in an image

Released in 2016, this model discretizes the output space of bounding boxes into a set of default boxes. At the time of prediction, scores are generated for each object and multiple feature maps with different resolutions are used to make predictions for objects of various sizes. This model processes images at 59 FPS on a NVIDIA Titan X.

Number of layers: 157 | Parameter count: 29,432,700 | Trained size: 119 MB |

Training Set Information

Performance

Examples

Resource retrieval

Get the pre-trained net:

In[1]:=
NetModel["SSD-VGG-512 Trained on PASCAL VOC2007, PASCAL VOC2012 and \
MS-COCO Data" ]
Out[1]=

Evaluation function

Write an evaluation function to scale the result to the input image size and suppress the least probable detections:

In[2]:=
nonMaxSuppression[overlapThreshold_][detection_] := Module[{boxes, confidence}, Fold[{list, new} |-> If[NoneTrue[list[[All, 1]], iou[#, new[[1]]] > overlapThreshold &], Append[list, new], list], Sequence @@ TakeDrop[Reverse@SortBy[detection, Last], 1]]]

iou := iou = With[{c = Compile[{{box1, _Real, 2}, {box2, _Real, 2}}, Module[{area1, area2, x1, y1, x2, y2, w, h, int}, area1 = (box1[[2, 1]] - box1[[1, 1]]) (box1[[2, 2]] - box1[[1, 2]]);
       area2 = (box2[[2, 1]] - box2[[1, 1]]) (box2[[2, 2]] - box2[[1, 2]]);
       x1 = Max[box1[[1, 1]], box2[[1, 1]]];
       y1 = Max[box1[[1, 2]], box2[[1, 2]]];
       x2 = Min[box1[[2, 1]], box2[[2, 1]]];
       y2 = Min[box1[[2, 2]], box2[[2, 2]]];
       w = Max[0., x2 - x1];
       h = Max[0., y2 - y1];
       int = w*h;
       int/(area1 + area2 - int)], RuntimeAttributes -> {Listable}, Parallelization -> True, RuntimeOptions -> "Speed"]}, c @@ Replace[{##}, Rectangle -> List, Infinity, Heads -> True] &]

Define the label list for this model. Integers in the model's output correspond to elements in the label list:

In[3]:=
labels = {"aeroplane", "bicycle", "bird", "boat", "bottle", "bus", "car", "cat", "chair", "cow", "diningtable",
      "dog", "horse", "motorbike", "person", "pottedplant", "sheep", "sofa", "train", "tvmonitor"};
In[4]:=
netevaluate[img_Image, detectionThreshold_ : .5, overlapThreshold_ : .45] := Module[{netOutputDecoder, net},
  netOutputDecoder[imageDims_, threshold_ : .5][netOutput_] := Module[{detections = Position[netOutput["ClassProb"], x_ /; x > threshold]}, If[Length[detections] > 0, Transpose[{Rectangle @@@ Round@Transpose[
          Transpose[
            Extract[netOutput["Boxes"], detections[[All, 1 ;; 1]]], {2, 3, 1}]*
           imageDims/{512, 512}, {3, 1, 2}], Extract[labels, detections[[All, 2 ;; 2]]],
       Extract[netOutput["ClassProb"], detections]}],
     {}
     ]
    ];
  net = NetModel[
    "SSD-VGG-512 Trained on PASCAL VOC2007, PASCAL VOC2012 and \
MS-COCO Data" ];
  (Flatten[
      nonMaxSuppression[overlapThreshold] /@ GatherBy[#, #[[2]] &], 1] &)@netOutputDecoder[ImageDimensions[img], detectionThreshold]@(net@(ImageResize[#, {512, 512}] &)@img)
  ]

Basic usage

Obtain the detected bounding boxes with their corresponding classes and confidences for a given image:

In[5]:=
(* Evaluate this cell to get the example input *) CloudGet["https://www.wolframcloud.com/obj/8204b435-5a13-43eb-ae14-6a15f2268293"]
In[6]:=
detection = netevaluate[testImage]
Out[6]=

Inspect which classes are detected:

In[7]:=
classes = DeleteDuplicates@detection[[All, 2]]
Out[7]=

Visualize the detection:

In[8]:=
HighlightImage[testImage, MapThread[{White, Inset[Style[#2, Black, FontSize -> Scaled[1/12], Background -> GrayLevel[1, .6]], Last[#1], {Right, Top}], #1} &,
   Transpose@detection]]
Out[8]=

Network result

The network computes 24,564 bounding boxes and the probability that the objects in each box are of any given class:

In[9]:=
res = NetModel[
   "SSD-VGG-512 Trained on PASCAL VOC2007, PASCAL VOC2012 and MS-COCO \
Data" ][testImage]
Out[9]=
In[10]:=
Dimensions /@ res
Out[10]=

Visualize all the boxes predicted by the net scaled by their “objectness” measures:

In[11]:=
rectangles = Rectangle @@@ res["Boxes"];
In[12]:=
Graphics[
 MapThread[{EdgeForm[Opacity[#1 + .01]], #2} &, {Total[
    res["ClassProb"], {2}], rectangles}],
 BaseStyle -> {FaceForm[], EdgeForm[{Thin, Black}]}
 ]
Out[12]=

Visualize all the boxes scaled by the probability that they contain a bus:

In[13]:=
idx = Position[labels, "bus"][[1, 1]]
Out[13]=
In[14]:=
Graphics[
 MapThread[{EdgeForm[Opacity[#1 + .01]], #2} &, {res["ClassProb"][[
    All, idx]], rectangles}],
 BaseStyle -> {FaceForm[], EdgeForm[{Thin, Black}]}
 ]
Out[14]=

Superimpose the bus prediction on top of the scaled input received by the net:

In[15]:=
HighlightImage[ImageResize[testImage, {512, 512}], Graphics[MapThread[{EdgeForm[{Opacity[#1 + .01]}], #2} &, {res[
      "ClassProb"][[All, idx]], rectangles}]], BaseStyle -> {FaceForm[], EdgeForm[{Thin, Red}]}]
Out[15]=

Advanced visualization

Write a function to apply a custom styling to the result of the detection:

In[16]:=
styleDetection[
  detection_] := {RandomColor[], {#[[1]], Text[Style[#[[2]], White, 12], {20, 20} + #[[1, 1]], Background -> Black]} & /@ #} & /@ GatherBy[detection, #[[2]] &]
In[17]:=
HighlightImage[testImage, styleDetection[netevaluate[testImage]]]
Out[17]=

Net information

Inspect the number of parameters of all arrays in the net:

In[18]:=
NetInformation[
 NetModel["SSD-VGG-512 Trained on PASCAL VOC2007, PASCAL VOC2012 and \
MS-COCO Data" ], "ArraysElementCounts"]
Out[18]=

Obtain the total number of parameters:

In[19]:=
NetInformation[
 NetModel["SSD-VGG-512 Trained on PASCAL VOC2007, PASCAL VOC2012 and \
MS-COCO Data" ], "ArraysTotalElementCount"]
Out[19]=

Obtain the layer type counts:

In[20]:=
NetInformation[
 NetModel["SSD-VGG-512 Trained on PASCAL VOC2007, PASCAL VOC2012 and \
MS-COCO Data" ], "LayerTypeCounts"]
Out[20]=

Display the summary graphic:

In[21]:=
NetInformation[
 NetModel["SSD-VGG-512 Trained on PASCAL VOC2007, PASCAL VOC2012 and \
MS-COCO Data" ], "SummaryGraphic"]
Out[21]=

Export to MXNet

Export the net into a format that can be opened in MXNet:

In[22]:=
jsonPath = Export[FileNameJoin[{$TemporaryDirectory, "net.json"}], NetModel["SSD-VGG-512 Trained on PASCAL VOC2007, PASCAL VOC2012 and \
MS-COCO Data" ], "MXNet"]
Out[22]=

Export also creates a net.params file containing parameters:

In[23]:=
paramPath = FileNameJoin[{DirectoryName[jsonPath], "net.params"}]
Out[23]=

Get the size of the parameter file:

In[24]:=
FileByteCount[paramPath]
Out[24]=

The size is similar to the byte count of the resource object:

In[25]:=
ResourceObject[
  "SSD-VGG-512 Trained on PASCAL VOC2007, PASCAL VOC2012 and MS-COCO \
Data" ]["ByteCount"]
Out[25]=

Requirements

Wolfram Language 11.3 (March 2018) or above

Resource History

Reference