automatic commit
[folded-ctf.git] / parsing_pool.cc
1 /*
2  *  folded-ctf is an implementation of the folded hierarchy of
3  *  classifiers for object detection, developed by Francois Fleuret
4  *  and Donald Geman.
5  *
6  *  Copyright (c) 2008 Idiap Research Institute, http://www.idiap.ch/
7  *  Written by Francois Fleuret <francois.fleuret@idiap.ch>
8  *
9  *  This file is part of folded-ctf.
10  *
11  *  folded-ctf is free software: you can redistribute it and/or modify
12  *  it under the terms of the GNU General Public License as published
13  *  by the Free Software Foundation, either version 3 of the License,
14  *  or (at your option) any later version.
15  *
16  *  folded-ctf is distributed in the hope that it will be useful, but
17  *  WITHOUT ANY WARRANTY; without even the implied warranty of
18  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19  *  General Public License for more details.
20  *
21  *  You should have received a copy of the GNU General Public License
22  *  along with folded-ctf.  If not, see <http://www.gnu.org/licenses/>.
23  *
24  */
25
26 #include "parsing_pool.h"
27 #include "tools.h"
28
29 ParsingPool::ParsingPool(LabelledImagePool *image_pool, PoseCellHierarchy *hierarchy, scalar_t proportion_negative_cells) {
30   _nb_images = image_pool->nb_images();
31   _parsings = new Parsing *[_nb_images];
32
33   _nb_cells = 0;
34   _nb_positive_cells = 0;
35   _nb_negative_cells = 0;
36   for(int i = 0; i < _nb_images; i++) {
37     _parsings[i] = new Parsing(image_pool, hierarchy, proportion_negative_cells, i);
38     _nb_cells += _parsings[i]->nb_cells();
39     _nb_positive_cells += _parsings[i]->nb_positive_cells();
40     _nb_negative_cells += _parsings[i]->nb_negative_cells();
41   }
42   (*global.log_stream) << "ParsingPool initialized" << endl;
43   (*global.log_stream) << "  _nb_cells = " << _nb_cells << endl;
44   (*global.log_stream) << "  _nb_positive_cells = " << _nb_positive_cells << endl;
45   (*global.log_stream) << "  _nb_negative_cells = " << _nb_negative_cells << endl;
46 }
47
48 ParsingPool::~ParsingPool() {
49   for(int i = 0; i < _nb_images; i++)
50     delete _parsings[i];
51   delete[] _parsings;
52 }
53
54 void ParsingPool::down_one_level(LossMachine *loss_machine, PoseCellHierarchy *hierarchy, int level) {
55   scalar_t *labels = new scalar_t[_nb_cells];
56   scalar_t *tmp_responses = new scalar_t[_nb_cells];
57
58   int c;
59
60   { ////////////////////////////////////////////////////////////////////
61     // Sanity check
62     scalar_t l = 0;
63     for(int i = 0; i < _nb_images; i++) {
64       for(int d = 0; d < _parsings[i]->nb_cells(); d++) {
65         if(_parsings[i]->label(d) != 0) {
66           l += exp( - _parsings[i]->label(d) * _parsings[i]->response(d));
67         }
68       }
69     }
70     (*global.log_stream) << "* INITIAL LOSS IS " << l << endl;
71   } ////////////////////////////////////////////////////////////////////
72
73   // Put the negative samples with their current responses, and all
74   // others to 0
75
76   c = 0;
77   for(int i = 0; i < _nb_images; i++) {
78     for(int d = 0; d < _parsings[i]->nb_cells(); d++) {
79       if(_parsings[i]->label(d) < 0) {
80         labels[c] = -1;
81         tmp_responses[c] = _parsings[i]->response(d);
82       } else {
83         labels[c] = 0;
84         tmp_responses[c] = 0;
85       }
86       c++;
87     }
88   }
89
90   // Sub-sample among the negative ones
91
92   int *sample_nb_occurences = new int[_nb_cells];
93   scalar_t *sample_responses = new scalar_t[_nb_cells];
94
95   loss_machine->subsample(_nb_cells, labels, tmp_responses,
96                           _nb_negative_cells, sample_nb_occurences, sample_responses,
97                           1);
98
99   c = 0;
100   for(int i = 0; i < _nb_images; i++) {
101     for(int d = 0; d < _parsings[i]->nb_cells(); d++) {
102       if(_parsings[i]->label(d) > 0) {
103         sample_nb_occurences[c + d] = 1;
104         sample_responses[c + d] = _parsings[i]->response(d);
105       }
106     }
107
108     int d = c + _parsings[i]->nb_cells();
109
110     _parsings[i]->down_one_level(hierarchy, level, sample_nb_occurences + c, sample_responses + c);
111
112     c = d;
113   }
114
115   { ////////////////////////////////////////////////////////////////////
116     // Sanity check
117     scalar_t l = 0;
118     for(int i = 0; i < _nb_images; i++) {
119       for(int d = 0; d < _parsings[i]->nb_cells(); d++) {
120         if(_parsings[i]->label(d) != 0) {
121           l += exp( - _parsings[i]->label(d) * _parsings[i]->response(d));
122         }
123       }
124     }
125     (*global.log_stream) << "* FINAL LOSS IS " << l << endl;
126   } ////////////////////////////////////////////////////////////////////
127
128   delete[] sample_responses;
129   delete[] sample_nb_occurences;
130
131   delete[] labels;
132   delete[] tmp_responses;
133 }
134
135 void ParsingPool::update_cell_responses(PiFeatureFamily *pi_feature_family,
136                                         Classifier *classifier) {
137   for(int i = 0; i < _nb_images; i++) {
138     _parsings[i]->update_cell_responses(pi_feature_family, classifier);
139   }
140 }
141
142 void ParsingPool::weighted_sampling(LossMachine *loss_machine,
143                                     PiFeatureFamily *pi_feature_family,
144                                     SampleSet *sample_set,
145                                     scalar_t *responses) {
146
147   int nb_negatives_to_sample = sample_set->nb_samples() - _nb_positive_cells;
148
149   ASSERT(nb_negatives_to_sample > 0);
150
151   scalar_t *labels = new scalar_t[_nb_cells];
152   scalar_t *tmp_responses = new scalar_t[_nb_cells];
153
154   int c, s;
155
156   // Put the negative samples with their current responses, and all
157   // others to 0
158
159   c = 0;
160   for(int i = 0; i < _nb_images; i++) {
161     for(int d = 0; d < _parsings[i]->nb_cells(); d++) {
162       if(_parsings[i]->label(d) < 0) {
163         labels[c] = -1;
164         tmp_responses[c] = _parsings[i]->response(d);
165       } else {
166         labels[c] = 0;
167         tmp_responses[c] = 0;
168       }
169       c++;
170     }
171   }
172
173   // Sub-sample among the negative ones
174
175   int *sample_nb_occurences = new int[_nb_cells];
176   scalar_t *sample_responses = new scalar_t[_nb_cells];
177
178   loss_machine->subsample(_nb_cells, labels, tmp_responses,
179                           nb_negatives_to_sample, sample_nb_occurences, sample_responses,
180                           0);
181
182   for(int k = 0; k < _nb_cells; k++) {
183     if(sample_nb_occurences[k] > 0) {
184       ASSERT(sample_nb_occurences[k] == 1);
185       labels[k] = -1.0;
186       tmp_responses[k] = sample_responses[k];
187     } else {
188       labels[k] = 0;
189     }
190   }
191
192   delete[] sample_responses;
193   delete[] sample_nb_occurences;
194
195   // Put the positive ones
196
197   c = 0;
198   for(int i = 0; i < _nb_images; i++) {
199     for(int d = 0; d < _parsings[i]->nb_cells(); d++) {
200       if(_parsings[i]->label(d) > 0) {
201         labels[c] = 1;
202         tmp_responses[c] = _parsings[i]->response(d);
203       }
204       c++;
205     }
206   }
207
208   // Here we have the responses for the sub-sampled in tmp_responses,
209   // and we have labels[n] set to zero for non-sampled samples
210
211   s = 0;
212   c = 0;
213
214   for(int i = 0; i < _nb_images; i++) {
215
216     int *to_collect = new int[_parsings[i]->nb_cells()];
217
218     for(int d = 0; d < _parsings[i]->nb_cells(); d++) {
219       to_collect[d] = (labels[c + d] != 0);
220     }
221
222     _parsings[i]->collect_samples(sample_set, pi_feature_family, s, to_collect);
223
224     for(int d = 0; d < _parsings[i]->nb_cells(); d++) {
225       if(to_collect[d]) {
226         responses[s++] = tmp_responses[c + d];
227       }
228     }
229
230     delete[] to_collect;
231
232     c += _parsings[i]->nb_cells();
233   }
234
235   delete[] tmp_responses;
236   delete[] labels;
237 }
238
239 void ParsingPool::write_roc(ofstream *out) {
240   int nb_negatives = nb_negative_cells();
241   int nb_positives = nb_positive_cells();
242
243   scalar_t *pos_responses = new scalar_t[nb_positives];
244   scalar_t *neg_responses = new scalar_t[nb_negatives];
245   int np = 0, nn = 0;
246   for(int i = 0; i < _nb_images; i++) {
247     for(int c = 0; c < _parsings[i]->nb_cells(); c++) {
248       if(_parsings[i]->label(c) > 0)
249         pos_responses[np++] = _parsings[i]->response(c);
250       else if(_parsings[i]->label(c) < 0)
251         neg_responses[nn++] = _parsings[i]->response(c);
252     }
253   }
254
255   ASSERT(nn == nb_negatives && np == nb_positives);
256
257   print_roc_small_pos(out,
258                       nb_positives, pos_responses,
259                       nb_negatives, neg_responses,
260                       1.0);
261
262   delete[] pos_responses;
263   delete[] neg_responses;
264 }