File size: 18,772 Bytes
9375c9a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
<html><!-- Created using the cpp_pretty_printer from the dlib C++ library.  See http://dlib.net for updates. --><head><title>dlib C++ Library - dnn_introduction3_ex.cpp</title></head><body bgcolor='white'><pre>
<font color='#009900'>// The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt
</font><font color='#009900'>/*
    This is an example illustrating the use of the deep learning tools from the
    dlib C++ Library.  I'm assuming you have already read the <a href="dnn_introduction_ex.cpp.html">dnn_introduction_ex.cpp</a> and
    the <a href="dnn_introduction2_ex.cpp.html">dnn_introduction2_ex.cpp</a> examples.  So in this example program I'm going to go
    over a transfer learning example, which includes:
        - Defining a layer visitor to modify the some network parameters for fine-tuning
        - Using pretrained layers of a network for another task
*/</font>

<font color='#0000FF'>#include</font> <font color='#5555FF'>&lt;</font>dlib<font color='#5555FF'>/</font>dnn.h<font color='#5555FF'>&gt;</font>
<font color='#0000FF'>#include</font> <font color='#5555FF'>&lt;</font>iostream<font color='#5555FF'>&gt;</font>

<font color='#009900'>// This header file includes a generic definition of the most common ResNet architectures
</font><font color='#0000FF'>#include</font> "<a style='text-decoration:none' href='resnet.h.html'>resnet.h</a>"

<font color='#0000FF'>using</font> <font color='#0000FF'>namespace</font> std;
<font color='#0000FF'>using</font> <font color='#0000FF'>namespace</font> dlib;

<font color='#009900'>// In this simple example we will show how to load a pretrained network and use it for a
</font><font color='#009900'>// different task.  In particular, we will load a ResNet50 trained on ImageNet, adjust
</font><font color='#009900'>// some of its parameters and use it as a pretrained backbone for some metric learning
</font><font color='#009900'>// task.
</font>
<font color='#009900'>// Let's start by defining a network that will use the ResNet50 backbone from resnet.h
</font><font color='#0000FF'>namespace</font> model
<b>{</b>
    <font color='#0000FF'>template</font><font color='#5555FF'>&lt;</font><font color='#0000FF'>template</font><font color='#5555FF'>&lt;</font><font color='#0000FF'>typename</font><font color='#5555FF'>&gt;</font> <font color='#0000FF'>class</font> <b><a name='BN'></a>BN</b><font color='#5555FF'>&gt;</font>
    <font color='#0000FF'>using</font> net_type <font color='#5555FF'>=</font> loss_metric<font color='#5555FF'>&lt;</font>
        fc_no_bias<font color='#5555FF'>&lt;</font><font color='#979000'>128</font>,
        avg_pool_everything<font color='#5555FF'>&lt;</font>
        <font color='#0000FF'>typename</font> resnet::def<font color='#5555FF'>&lt;</font>BN<font color='#5555FF'>&gt;</font>::<font color='#0000FF'>template</font> backbone_50<font color='#5555FF'>&lt;</font>
        input_rgb_image
        <font color='#5555FF'>&gt;</font><font color='#5555FF'>&gt;</font><font color='#5555FF'>&gt;</font><font color='#5555FF'>&gt;</font>;

    <font color='#0000FF'>using</font> train <font color='#5555FF'>=</font> net_type<font color='#5555FF'>&lt;</font>bn_con<font color='#5555FF'>&gt;</font>;
    <font color='#0000FF'>using</font> infer <font color='#5555FF'>=</font> net_type<font color='#5555FF'>&lt;</font>affine<font color='#5555FF'>&gt;</font>;
<b>}</b>

<font color='#009900'>// Next, we define a layer visitor that will modify the weight decay of a network.  The
</font><font color='#009900'>// main interest of this class is to show how one can define custom visitors that modify
</font><font color='#009900'>// some network parameters.
</font><font color='#0000FF'>class</font> <b><a name='visitor_weight_decay_multiplier'></a>visitor_weight_decay_multiplier</b>
<b>{</b>
<font color='#0000FF'>public</font>:

    <b><a name='visitor_weight_decay_multiplier'></a>visitor_weight_decay_multiplier</b><font face='Lucida Console'>(</font><font color='#0000FF'><u>double</u></font> new_weight_decay_multiplier_<font face='Lucida Console'>)</font> :
        new_weight_decay_multiplier<font face='Lucida Console'>(</font>new_weight_decay_multiplier_<font face='Lucida Console'>)</font> <b>{</b><b>}</b>

    <font color='#0000FF'>template</font> <font color='#5555FF'>&lt;</font><font color='#0000FF'>typename</font> layer<font color='#5555FF'>&gt;</font>
    <font color='#0000FF'><u>void</u></font> <b><a name='operator'></a>operator</b><font face='Lucida Console'>(</font><font face='Lucida Console'>)</font><font face='Lucida Console'>(</font>layer<font color='#5555FF'>&amp;</font> l<font face='Lucida Console'>)</font> <font color='#0000FF'>const</font>
    <b>{</b>
        <font color='#BB00BB'>set_weight_decay_multiplier</font><font face='Lucida Console'>(</font>l, new_weight_decay_multiplier<font face='Lucida Console'>)</font>;
    <b>}</b>

<font color='#0000FF'>private</font>:

    <font color='#0000FF'><u>double</u></font> new_weight_decay_multiplier;
<b>}</b>;


<font color='#0000FF'><u>int</u></font> <b><a name='main'></a>main</b><font face='Lucida Console'>(</font><font face='Lucida Console'>)</font> <font color='#0000FF'>try</font>
<b>{</b>
    <font color='#009900'>// Let's instantiate our network in train mode.
</font>    model::train net;

    <font color='#009900'>// We create a new scope so that resources from the loaded network are freed
</font>    <font color='#009900'>// automatically when leaving the scope.
</font>    <b>{</b>
        <font color='#009900'>// Now, let's define the classic ResNet50 network and load the pretrained model on
</font>        <font color='#009900'>// ImageNet.
</font>        resnet::train_50 resnet50;
        std::vector<font color='#5555FF'>&lt;</font>string<font color='#5555FF'>&gt;</font> labels;
        <font color='#BB00BB'>deserialize</font><font face='Lucida Console'>(</font>"<font color='#CC0000'>resnet50_1000_imagenet_classifier.dnn</font>"<font face='Lucida Console'>)</font> <font color='#5555FF'>&gt;</font><font color='#5555FF'>&gt;</font> resnet50 <font color='#5555FF'>&gt;</font><font color='#5555FF'>&gt;</font> labels;

        <font color='#009900'>// For transfer learning, we are only interested in the ResNet50's backbone, which
</font>        <font color='#009900'>// lays below the loss and the fc layers, so we can extract it as:
</font>        <font color='#0000FF'>auto</font> backbone <font color='#5555FF'>=</font> std::<font color='#BB00BB'>move</font><font face='Lucida Console'>(</font>resnet50.<font color='#BB00BB'>subnet</font><font face='Lucida Console'>(</font><font face='Lucida Console'>)</font>.<font color='#BB00BB'>subnet</font><font face='Lucida Console'>(</font><font face='Lucida Console'>)</font><font face='Lucida Console'>)</font>;

        <font color='#009900'>// We can now assign ResNet50's backbone to our network skipping the different
</font>        <font color='#009900'>// layers, in our case, the loss layer and the fc layer:
</font>        net.<font color='#BB00BB'>subnet</font><font face='Lucida Console'>(</font><font face='Lucida Console'>)</font>.<font color='#BB00BB'>subnet</font><font face='Lucida Console'>(</font><font face='Lucida Console'>)</font> <font color='#5555FF'>=</font> backbone;

        <font color='#009900'>// An alternative way to use the pretrained network on a different
</font>        <font color='#009900'>// network is to extract the relevant part of the network (we remove
</font>        <font color='#009900'>// loss and fc layers), stack the new layers on top of it and assign
</font>        <font color='#009900'>// the network.
</font>        <font color='#0000FF'>using</font> net_type <font color='#5555FF'>=</font> loss_metric<font color='#5555FF'>&lt;</font>fc_no_bias<font color='#5555FF'>&lt;</font><font color='#979000'>128</font>, <font color='#BB00BB'>decltype</font><font face='Lucida Console'>(</font>backbone<font face='Lucida Console'>)</font><font color='#5555FF'>&gt;</font><font color='#5555FF'>&gt;</font>;
        net_type net2;
        net2.<font color='#BB00BB'>subnet</font><font face='Lucida Console'>(</font><font face='Lucida Console'>)</font>.<font color='#BB00BB'>subnet</font><font face='Lucida Console'>(</font><font face='Lucida Console'>)</font> <font color='#5555FF'>=</font> backbone;
    <b>}</b>

    <font color='#009900'>// We can use the visit_layers function to modify the weight decay of the entire
</font>    <font color='#009900'>// network:
</font>    <font color='#BB00BB'>visit_computational_layers</font><font face='Lucida Console'>(</font>net, <font color='#BB00BB'>visitor_weight_decay_multiplier</font><font face='Lucida Console'>(</font><font color='#979000'>0.001</font><font face='Lucida Console'>)</font><font face='Lucida Console'>)</font>;

    <font color='#009900'>// We can also use predefined visitors to affect the learning rate of the whole
</font>    <font color='#009900'>// network.
</font>    <font color='#BB00BB'>set_all_learning_rate_multipliers</font><font face='Lucida Console'>(</font>net, <font color='#979000'>0.5</font><font face='Lucida Console'>)</font>;

    <font color='#009900'>// Modifying the learning rates of a network is a common practice for fine tuning, for
</font>    <font color='#009900'>// this reason it is already provided. However, it is implemented internally using a
</font>    <font color='#009900'>// visitor that is very similar to the one defined in this example.
</font>
    <font color='#009900'>// Usually, we want to freeze the network, except for the top layers:
</font>    <font color='#BB00BB'>visit_computational_layers</font><font face='Lucida Console'>(</font>net.<font color='#BB00BB'>subnet</font><font face='Lucida Console'>(</font><font face='Lucida Console'>)</font>.<font color='#BB00BB'>subnet</font><font face='Lucida Console'>(</font><font face='Lucida Console'>)</font>, <font color='#BB00BB'>visitor_weight_decay_multiplier</font><font face='Lucida Console'>(</font><font color='#979000'>0</font><font face='Lucida Console'>)</font><font face='Lucida Console'>)</font>;
    <font color='#BB00BB'>set_all_learning_rate_multipliers</font><font face='Lucida Console'>(</font>net.<font color='#BB00BB'>subnet</font><font face='Lucida Console'>(</font><font face='Lucida Console'>)</font>.<font color='#BB00BB'>subnet</font><font face='Lucida Console'>(</font><font face='Lucida Console'>)</font>, <font color='#979000'>0</font><font face='Lucida Console'>)</font>;

    <font color='#009900'>// Alternatively, we can use the visit_layers_range to modify only a specific set of
</font>    <font color='#009900'>// layers:
</font>    visit_computational_layers_range<font color='#5555FF'>&lt;</font><font color='#979000'>0</font>, <font color='#979000'>2</font><font color='#5555FF'>&gt;</font><font face='Lucida Console'>(</font>net, <font color='#BB00BB'>visitor_weight_decay_multiplier</font><font face='Lucida Console'>(</font><font color='#979000'>1</font><font face='Lucida Console'>)</font><font face='Lucida Console'>)</font>;

    <font color='#009900'>// Sometimes we might want to set the learning rate differently throughout the network.
</font>    <font color='#009900'>// Here we show how to use adjust the learning rate at the different ResNet50's
</font>    <font color='#009900'>// convolutional blocks:
</font>    set_learning_rate_multipliers_range<font color='#5555FF'>&lt;</font>  <font color='#979000'>0</font>,   <font color='#979000'>2</font><font color='#5555FF'>&gt;</font><font face='Lucida Console'>(</font>net, <font color='#979000'>1</font><font face='Lucida Console'>)</font>;
    set_learning_rate_multipliers_range<font color='#5555FF'>&lt;</font>  <font color='#979000'>2</font>,  <font color='#979000'>38</font><font color='#5555FF'>&gt;</font><font face='Lucida Console'>(</font>net, <font color='#979000'>0.1</font><font face='Lucida Console'>)</font>;
    set_learning_rate_multipliers_range<font color='#5555FF'>&lt;</font> <font color='#979000'>38</font>, <font color='#979000'>107</font><font color='#5555FF'>&gt;</font><font face='Lucida Console'>(</font>net, <font color='#979000'>0.01</font><font face='Lucida Console'>)</font>;
    set_learning_rate_multipliers_range<font color='#5555FF'>&lt;</font><font color='#979000'>107</font>, <font color='#979000'>154</font><font color='#5555FF'>&gt;</font><font face='Lucida Console'>(</font>net, <font color='#979000'>0.001</font><font face='Lucida Console'>)</font>;
    set_learning_rate_multipliers_range<font color='#5555FF'>&lt;</font><font color='#979000'>154</font>, <font color='#979000'>193</font><font color='#5555FF'>&gt;</font><font face='Lucida Console'>(</font>net, <font color='#979000'>0.0001</font><font face='Lucida Console'>)</font>;

    <font color='#009900'>// Finally, we can check the results by printing the network.  But before, if we
</font>    <font color='#009900'>// forward an image through the network, we will see tensors shape at every layer.
</font>    matrix<font color='#5555FF'>&lt;</font>rgb_pixel<font color='#5555FF'>&gt;</font> <font color='#BB00BB'>image</font><font face='Lucida Console'>(</font><font color='#979000'>224</font>, <font color='#979000'>224</font><font face='Lucida Console'>)</font>;
    <font color='#BB00BB'>assign_all_pixels</font><font face='Lucida Console'>(</font>image, <font color='#BB00BB'>rgb_pixel</font><font face='Lucida Console'>(</font><font color='#979000'>0</font>, <font color='#979000'>0</font>, <font color='#979000'>0</font><font face='Lucida Console'>)</font><font face='Lucida Console'>)</font>;
    std::vector<font color='#5555FF'>&lt;</font>matrix<font color='#5555FF'>&lt;</font>rgb_pixel<font color='#5555FF'>&gt;</font><font color='#5555FF'>&gt;</font> <font color='#BB00BB'>minibatch</font><font face='Lucida Console'>(</font><font color='#979000'>1</font>, image<font face='Lucida Console'>)</font>;
    resizable_tensor input;
    net.<font color='#BB00BB'>to_tensor</font><font face='Lucida Console'>(</font>minibatch.<font color='#BB00BB'>begin</font><font face='Lucida Console'>(</font><font face='Lucida Console'>)</font>, minibatch.<font color='#BB00BB'>end</font><font face='Lucida Console'>(</font><font face='Lucida Console'>)</font>, input<font face='Lucida Console'>)</font>;
    net.<font color='#BB00BB'>forward</font><font face='Lucida Console'>(</font>input<font face='Lucida Console'>)</font>;
    cout <font color='#5555FF'>&lt;</font><font color='#5555FF'>&lt;</font> net <font color='#5555FF'>&lt;</font><font color='#5555FF'>&lt;</font> endl;
    cout <font color='#5555FF'>&lt;</font><font color='#5555FF'>&lt;</font> "<font color='#CC0000'>input size=(</font>" <font color='#5555FF'>&lt;</font><font color='#5555FF'>&lt;</font>
       "<font color='#CC0000'>num:</font>" <font color='#5555FF'>&lt;</font><font color='#5555FF'>&lt;</font> input.<font color='#BB00BB'>num_samples</font><font face='Lucida Console'>(</font><font face='Lucida Console'>)</font> <font color='#5555FF'>&lt;</font><font color='#5555FF'>&lt;</font> "<font color='#CC0000'>, </font>" <font color='#5555FF'>&lt;</font><font color='#5555FF'>&lt;</font>
       "<font color='#CC0000'>k:</font>" <font color='#5555FF'>&lt;</font><font color='#5555FF'>&lt;</font> input.<font color='#BB00BB'>k</font><font face='Lucida Console'>(</font><font face='Lucida Console'>)</font> <font color='#5555FF'>&lt;</font><font color='#5555FF'>&lt;</font> "<font color='#CC0000'>, </font>" <font color='#5555FF'>&lt;</font><font color='#5555FF'>&lt;</font>
       "<font color='#CC0000'>nr:</font>" <font color='#5555FF'>&lt;</font><font color='#5555FF'>&lt;</font> input.<font color='#BB00BB'>nr</font><font face='Lucida Console'>(</font><font face='Lucida Console'>)</font> <font color='#5555FF'>&lt;</font><font color='#5555FF'>&lt;</font> "<font color='#CC0000'>, </font>"
       "<font color='#CC0000'>nc:</font>" <font color='#5555FF'>&lt;</font><font color='#5555FF'>&lt;</font> input.<font color='#BB00BB'>nc</font><font face='Lucida Console'>(</font><font face='Lucida Console'>)</font> <font color='#5555FF'>&lt;</font><font color='#5555FF'>&lt;</font> "<font color='#CC0000'>)</font>" <font color='#5555FF'>&lt;</font><font color='#5555FF'>&lt;</font> endl;

    <font color='#009900'>// We can also print the number of parameters of the network:
</font>    cout <font color='#5555FF'>&lt;</font><font color='#5555FF'>&lt;</font> "<font color='#CC0000'>number of network parameters: </font>" <font color='#5555FF'>&lt;</font><font color='#5555FF'>&lt;</font> <font color='#BB00BB'>count_parameters</font><font face='Lucida Console'>(</font>net<font face='Lucida Console'>)</font> <font color='#5555FF'>&lt;</font><font color='#5555FF'>&lt;</font> endl;

    <font color='#009900'>// From this point on, we can fine-tune the new network using this pretrained backbone
</font>    <font color='#009900'>// on another task, such as the one showed in <a href="dnn_metric_learning_on_images_ex.cpp.html">dnn_metric_learning_on_images_ex.cpp</a>.
</font>
    <font color='#0000FF'>return</font> EXIT_SUCCESS;
<b>}</b>
<font color='#0000FF'>catch</font> <font face='Lucida Console'>(</font><font color='#0000FF'>const</font> serialization_error<font color='#5555FF'>&amp;</font> e<font face='Lucida Console'>)</font>
<b>{</b>
    cout <font color='#5555FF'>&lt;</font><font color='#5555FF'>&lt;</font> e.<font color='#BB00BB'>what</font><font face='Lucida Console'>(</font><font face='Lucida Console'>)</font> <font color='#5555FF'>&lt;</font><font color='#5555FF'>&lt;</font> endl;
    cout <font color='#5555FF'>&lt;</font><font color='#5555FF'>&lt;</font> "<font color='#CC0000'>You need to download a copy of the file resnet50_1000_imagenet_classifier.dnn</font>" <font color='#5555FF'>&lt;</font><font color='#5555FF'>&lt;</font> endl;
    cout <font color='#5555FF'>&lt;</font><font color='#5555FF'>&lt;</font> "<font color='#CC0000'>available at http://dlib.net/files/resnet50_1000_imagenet_classifier.dnn.bz2</font>" <font color='#5555FF'>&lt;</font><font color='#5555FF'>&lt;</font> endl;
    cout <font color='#5555FF'>&lt;</font><font color='#5555FF'>&lt;</font> endl;
    <font color='#0000FF'>return</font> EXIT_FAILURE;
<b>}</b>
<font color='#0000FF'>catch</font> <font face='Lucida Console'>(</font><font color='#0000FF'>const</font> exception<font color='#5555FF'>&amp;</font> e<font face='Lucida Console'>)</font>
<b>{</b>
    cout <font color='#5555FF'>&lt;</font><font color='#5555FF'>&lt;</font> e.<font color='#BB00BB'>what</font><font face='Lucida Console'>(</font><font face='Lucida Console'>)</font> <font color='#5555FF'>&lt;</font><font color='#5555FF'>&lt;</font> endl;
    <font color='#0000FF'>return</font> EXIT_FAILURE;
<b>}</b>

</pre></body></html>