"backends/v2/src/queue.rs" did not exist on "12590fdccebb34f39fb85b7dae29b80fade2b6b0"
optimization_oca.h 8.52 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// Copyright (C) 2010  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_OPTIMIZATIoN_OCA_H__
#define DLIB_OPTIMIZATIoN_OCA_H__

#include "optimization_oca_abstract.h"

#include "../matrix.h"
#include "optimization_solve_qp_using_smo.h"
#include <list>

// ----------------------------------------------------------------------------------------

namespace dlib
{
    template <typename matrix_type>
    class oca_problem
    {
    public:
        typedef typename matrix_type::type scalar_type;

        virtual ~oca_problem() {}

Davis King's avatar
Davis King committed
24
        virtual bool r_has_lower_bound (
25
26
27
            scalar_type& 
        ) const { return false; }

28
29
30
31
32
33
34
        virtual bool optimization_status (
            scalar_type ,
            scalar_type ,
            unsigned long,
            unsigned long
        ) const = 0;

Davis King's avatar
Davis King committed
35
        virtual scalar_type get_c (
36
37
        ) const = 0;

Davis King's avatar
Davis King committed
38
        virtual long get_num_dimensions (
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
        ) const = 0;

        virtual void get_risk (
            matrix_type& current_solution,
            scalar_type& risk_value,
            matrix_type& risk_subgradient
        ) const = 0;

    };

// ----------------------------------------------------------------------------------------

    class oca
    {
    public:

        oca () 
        {
57
58
            sub_eps = 1e-2;
            sub_max_iter = 200000;
59

60
            inactive_thresh = 10;
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
        }

        void set_subproblem_epsilon (
            double eps_
        ) { sub_eps = eps_; }

        double get_subproblem_epsilon (
        ) const { return sub_eps; }

        void set_subproblem_max_iterations (
            unsigned long sub_max_iter_
        ) 
        { 
            // make sure requires clause is not broken
            DLIB_ASSERT(sub_max_iter_ > 0,
                "\t void oca::set_subproblem_max_iterations"
                << "\n\t max iterations must be greater than 0"
                << "\n\t sub_max_iter_: " << sub_max_iter_
                << "\n\t this: " << this
                );

            sub_max_iter = sub_max_iter_; 
        }

        unsigned long get_subproblem_max_iterations (
        ) const { return sub_max_iter; }

        void set_inactive_plane_threshold (
            unsigned long inactive_thresh_
        ) 
        { 
            // make sure requires clause is not broken
            DLIB_ASSERT(inactive_thresh_ > 0,
                "\t void oca::set_inactive_plane_threshold"
                << "\n\t inactive threshold must be greater than 0"
                << "\n\t inactive_thresh_: " << inactive_thresh_
                << "\n\t this: " << this
                );

            inactive_thresh = inactive_thresh_; 
        }

        unsigned long get_inactive_plane_threshold (
        ) const { return inactive_thresh; }

        template <
            typename matrix_type
            >
Davis King's avatar
Davis King committed
109
        typename matrix_type::type operator() (
110
111
112
113
            const oca_problem<matrix_type>& problem,
            matrix_type& w
        ) const
        {
Davis King's avatar
Davis King committed
114
            // make sure requires clause is not broken
Davis King's avatar
Davis King committed
115
            DLIB_ASSERT(problem.get_c() > 0 &&
Davis King's avatar
Davis King committed
116
117
118
                        problem.get_num_dimensions() > 0,
                "\t void oca::operator()"
                << "\n\t The oca_problem is invalid"
Davis King's avatar
Davis King committed
119
                << "\n\t problem.get_c():              " << problem.get_c() 
Davis King's avatar
Davis King committed
120
121
122
123
                << "\n\t problem.get_num_dimensions(): " << problem.get_num_dimensions() 
                << "\n\t this: " << this
                );

124
125
126
            typedef typename matrix_type::type scalar_type;
            typedef typename matrix_type::layout_type layout_type;
            typedef typename matrix_type::mem_manager_type mem_manager_type;
Davis King's avatar
Davis King committed
127
            typedef matrix_type vect_type;
128

Davis King's avatar
Davis King committed
129
            const scalar_type C = problem.get_c();
130
131
132
133
134
135

            std::list<vect_type> planes;
            std::vector<scalar_type> bs, miss_count;

            vect_type temp, alpha, w_cur;

Davis King's avatar
Davis King committed
136
            w.set_size(problem.get_num_dimensions(), 1);
137
138
139
140
141
142
143
144
145
146
147
148
            w = 0;
            w_cur = w;

            // The best objective value seen so far.   Note also
            // that w always contains the best solution seen so far.
            scalar_type best_obj = std::numeric_limits<scalar_type>::max();

            // This will hold the cutting plane objective value.  This value is
            // a lower bound on the true optimal objective value.
            scalar_type cp_obj = 0;

            scalar_type R_lower_bound;
Davis King's avatar
Davis King committed
149
            if (problem.r_has_lower_bound(R_lower_bound))
150
151
152
153
154
155
156
157
158
159
            {
                // The flat lower bounding plane is always good to have if we know
                // what it is.
                bs.push_back(R_lower_bound);
                planes.push_back(zeros_matrix<scalar_type>(w.size(),1));
                miss_count.push_back(0);
            }

            matrix<scalar_type,0,0,mem_manager_type, layout_type> K;

160
161
            unsigned long counter = 0;
            while (true)
162
            {
163
                ++counter;
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198

                // add the next cutting plane
                scalar_type cur_risk;
                planes.resize(planes.size()+1);
                problem.get_risk(w_cur, cur_risk, planes.back());
                bs.push_back(cur_risk - dot(w_cur,planes.back()));
                miss_count.push_back(0);

                // Check the objective value at w_cur and see if it is better than
                // the best seen so far.
                const scalar_type cur_obj = 0.5*trans(w_cur)*w_cur + C*cur_risk;
                if (cur_obj < best_obj)
                {
                    best_obj = cur_obj;
                    w = w_cur;
                }


                // compute kernel matrix for all the planes
                K.set_size(planes.size(), planes.size());
                long rr = 0;
                for (typename std::list<vect_type>::iterator r = planes.begin(); r != planes.end(); ++r)
                {
                    long cc = rr;
                    for (typename std::list<vect_type>::iterator c = r; c != planes.end(); ++c)
                    {
                        K(rr,cc) = dot(*r, *c);
                        K(cc,rr) = K(rr,cc);
                        ++cc;
                    }
                    ++rr;
                }

                alpha = uniform_matrix<scalar_type>(planes.size(),1, C/planes.size());

199
200
201
202
203
204
205
                // solve the cutting plane subproblem for the next w_cur.   We solve it to an
                // accuracy that is related to how big the error gap is
                scalar_type eps = std::min<scalar_type>(sub_eps, 0.1*(best_obj-cp_obj)) ;
                // just a sanaty check
                if (eps < 1e-7)
                    eps = 1e-7;
                solve_qp_using_smo(K, vector_to_matrix(bs), alpha, eps, sub_max_iter); 
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228

                // construct the w_cur that minimized the subproblem.
                w_cur = 0;
                rr = 0;
                for (typename std::list<vect_type>::iterator i = planes.begin(); i != planes.end(); ++i)
                {
                    if (alpha(rr) != 0)
                    {
                        w_cur -= alpha(rr)*(*i);
                        miss_count[rr] = 0;
                    }
                    else
                    {
                        miss_count[rr] += 1;
                    }
                    ++rr;
                }

                // Compute the lower bound on the true objective given to us by the cutting 
                // plane subproblem.
                cp_obj = -0.5*trans(w_cur)*w_cur + trans(alpha)*vector_to_matrix(bs);

                // report current status
229
230
                if (problem.optimization_status(best_obj, best_obj - cp_obj, planes.size(), counter))
                    break;
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245

                // If it has been a while since a cutting plane was an active constraint then
                // we should throw it away.
                while (max(vector_to_matrix(miss_count)) >= inactive_thresh)
                {
                    long idx = index_of_max(vector_to_matrix(miss_count));
                    typename std::list<vect_type>::iterator i0 = planes.begin();
                    advance(i0, idx);
                    planes.erase(i0);
                    bs.erase(bs.begin()+idx);
                    miss_count.erase(miss_count.begin()+idx);
                }

            }

Davis King's avatar
Davis King committed
246
            return best_obj;
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
        }

    private:

        double sub_eps;

        unsigned long sub_max_iter;

        unsigned long inactive_thresh;
    };
}

// ----------------------------------------------------------------------------------------

#endif // DLIB_OPTIMIZATIoN_OCA_H__