1 # Custom deep learning layers support {#tutorial_dnn_custom_layers}
4 Deep learning is a fast growing area. The new approaches to build neural networks
5 usually introduce new types of layers. They could be modifications of existing
6 ones or implement outstanding researching ideas.
8 OpenCV gives an opportunity to import and run networks from different deep learning
9 frameworks. There are a number of the most popular layers. However you can face
10 a problem that your network cannot be imported using OpenCV because of unimplemented layers.
12 The first solution is to create a feature request at https://github.com/opencv/opencv/issues
13 mentioning details such a source of model and type of new layer. A new layer could
14 be implemented if OpenCV community shares this need.
16 The second way is to define a **custom layer** so OpenCV's deep learning engine
17 will know how to use it. This tutorial is dedicated to show you a process of deep
18 learning models import customization.
20 ## Define a custom layer in C++
21 Deep learning layer is a building block of network's pipeline.
22 It has connections to **input blobs** and produces results to **output blobs**.
23 There are trained **weights** and **hyper-parameters**.
24 Layers' names, types, weights and hyper-parameters are stored in files are generated by
25 native frameworks during training. If OpenCV mets unknown layer type it throws an
26 exception trying to read a model:
29 Unspecified error: Can't create layer "layer_name" of type "MyType" in function getLayerInstance
32 To import the model correctly you have to derive a class from cv::dnn::Layer with
33 the following methods:
35 @snippet dnn/custom_layers.hpp A custom layer interface
37 And register it before the import:
39 @snippet dnn/custom_layers.hpp Register a custom layer
41 @note `MyType` is a type of unimplemented layer from the thrown exception.
43 Let's see what all the methods do:
47 @snippet dnn/custom_layers.hpp MyLayer::MyLayer
49 Retrieves hyper-parameters from cv::dnn::LayerParams. If your layer has trainable
50 weights they will be already stored in the Layer's member cv::dnn::Layer::blobs.
52 - A static method `create`
54 @snippet dnn/custom_layers.hpp MyLayer::create
56 This method should create an instance of you layer and return cv::Ptr with it.
58 - Output blobs' shape computation
60 @snippet dnn/custom_layers.hpp MyLayer::getMemoryShapes
62 Returns layer's output shapes depends on input shapes. You may request an extra
63 memory using `internals`.
67 @snippet dnn/custom_layers.hpp MyLayer::forward
69 Implement a layer's logic here. Compute outputs for given inputs.
71 @note OpenCV manages memory allocated for layers. In the most cases the same memory
72 can be reused between layers. So your `forward` implementation should not rely that
73 the second invocation of `forward` will has the same data at `outputs` and `internals`.
75 - Optional `finalize` method
77 @snippet dnn/custom_layers.hpp MyLayer::finalize
79 The chain of methods are the following: OpenCV deep learning engine calls `create`
80 method once then it calls `getMemoryShapes` for an every created layer then you
81 can make some preparations depends on known input dimensions at cv::dnn::Layer::finalize.
82 After network was initialized only `forward` method is called for an every network's input.
84 @note Varying input blobs' sizes such height or width or batch size you make OpenCV
85 reallocate all the internal memory. That leads efficiency gaps. Try to initialize
86 and deploy models using a fixed batch size and image's dimensions.
88 ## Example: custom layer from Caffe
89 Let's create a custom layer `Interp` from https://github.com/cdmh/deeplab-public.
90 It's just a simple resize that takes an input blob of size `N x C x Hi x Wi` and returns
91 an output blob of size `N x C x Ho x Wo` where `N` is a batch size, `C` is a number of channels,
92 `Hi x Wi` and `Ho x Wo` are input and output `height x width` correspondingly.
93 This layer has no trainable weights but it has hyper-parameters to specify an output size.
109 This way our implementation can look like:
111 @snippet dnn/custom_layers.hpp InterpLayer
113 Next we need to register a new layer type and try to import the model.
115 @snippet dnn/custom_layers.hpp Register InterpLayer
117 ## Example: custom layer from TensorFlow
118 This is an example of how to import a network with [tf.image.resize_bilinear](https://www.tensorflow.org/versions/master/api_docs/python/tf/image/resize_bilinear)
119 operation. This is also a resize but with an implementation different from OpenCV's or `Interp` above.
121 Let's create a single layer network:
123 inp = tf.placeholder(tf.float32, [2, 3, 4, 5], 'input')
124 resized = tf.image.resize_bilinear(inp, size=[9, 8], name='resize_bilinear')
126 OpenCV sees that TensorFlow's graph in the following way:
140 name: "resize_bilinear/size"
158 tensor_content: "\t\000\000\000\010\000\000\000"
164 name: "resize_bilinear"
167 input: "resize_bilinear/size"
184 Custom layers import from TensorFlow is designed to put all layer's `attr` into
185 cv::dnn::LayerParams but input `Const` blobs into cv::dnn::Layer::blobs.
186 In our case resize's output shape will be stored in layer's `blobs[0]`.
188 @snippet dnn/custom_layers.hpp ResizeBilinearLayer
190 Next we register a layer and try to import the model.
192 @snippet dnn/custom_layers.hpp Register ResizeBilinearLayer
194 ## Define a custom layer in Python
195 The following example shows how to customize OpenCV's layers in Python.
197 Let's consider [Holistically-Nested Edge Detection](https://arxiv.org/abs/1504.06375)
198 deep learning model. That was trained with one and only difference comparing to
199 a current version of [Caffe framework](http://caffe.berkeleyvision.org/). `Crop`
200 layers that receive two input blobs and crop the first one to match spatial dimensions
201 of the second one used to crop from the center. Nowadays Caffe's layer does it
202 from the top-left corner. So using the latest version of Caffe or OpenCV you'll
203 get shifted results with filled borders.
205 Next we're going to replace OpenCV's `Crop` layer that makes top-left cropping by
208 - Create a class with `getMemoryShapes` and `forward` methods
210 @snippet dnn/edge_detection.py CropLayer
212 @note Both methods should return lists.
214 - Register a new layer.
216 @snippet dnn/edge_detection.py Register
218 That's it! We've replaced an implemented OpenCV's layer to a custom one.
219 You may find a full script in the [source code](https://github.com/opencv/opencv/tree/3.4/samples/dnn/edge_detection.py).
223 <td>![](js_tutorials/js_assets/lena.jpg)</td>
224 <td>![](images/lena_hed.jpg)</td>