Image-CCV
view release on metacpan or search on metacpan
ccv-src/lib/ccv_dpm.c view on Meta::CPAN
FILE* w = fopen(dir, "w+");
if (!w)
return;
fprintf(w, "%d %d\n", negative_cache_size, negv->rnum);
int i;
for (i = 0; i < negv->rnum; i++)
{
ccv_dpm_feature_vector_t* v = *(ccv_dpm_feature_vector_t**)ccv_array_get(negv, i);
_ccv_dpm_write_feature_vector(w, v);
}
fclose(w);
}
static int _ccv_dpm_read_negative_feature_vectors(ccv_array_t** _negv, int _negative_cache_size, const char* dir)
{
FILE* r = fopen(dir, "r");
if (!r)
return -1;
int negative_cache_size, negnum;
fscanf(r, "%d %d", &negative_cache_size, &negnum);
assert(negative_cache_size == _negative_cache_size);
ccv_array_t* negv = *_negv = ccv_array_new(sizeof(ccv_dpm_feature_vector_t*), negnum, 0);
int i;
for (i = 0; i < negnum; i++)
{
ccv_dpm_feature_vector_t* v = _ccv_dpm_read_feature_vector(r);
assert(v);
ccv_array_push(negv, &v);
}
fclose(r);
return 0;
}
static void _ccv_dpm_adjust_model_constant(ccv_dpm_mixture_model_t* model, int k, ccv_dpm_feature_vector_t** posv, int posnum, double percentile)
{
int i, j;
double* scores = (double*)ccmalloc(posnum * sizeof(double));
j = 0;
for (i = 0; i < posnum; i++)
if (posv[i] && posv[i]->id == k)
{
scores[j] = _ccv_dpm_vector_score(model, posv[i]);
j++;
}
_ccv_dpm_score_qsort(scores, j, 0);
float adjust = scores[ccv_clamp((int)(percentile * j), 0, j - 1)];
// adjust to percentile
model->root[k].beta -= adjust;
PRINT(CCV_CLI_INFO, " - tune model %d constant for %f\n", k + 1, -adjust);
ccfree(scores);
}
static void _ccv_dpm_check_params(ccv_dpm_new_param_t params)
{
assert(params.components > 0);
assert(params.parts > 0);
assert(params.grayscale == 0 || params.grayscale == 1);
assert(params.symmetric == 0 || params.symmetric == 1);
assert(params.min_area > 100);
assert(params.max_area > params.min_area);
assert(params.iterations >= 0);
assert(params.data_minings >= 0);
assert(params.relabels >= 0);
assert(params.negative_cache_size > 0);
assert(params.include_overlap > 0.1);
assert(params.alpha > 0 && params.alpha < 1);
assert(params.alpha_ratio > 0 && params.alpha_ratio < 1);
assert(params.C > 0);
assert(params.balance > 0);
assert(params.percentile_breakdown > 0 && params.percentile_breakdown <= 1);
assert(params.detector.interval > 0);
}
#define MINI_BATCH (10)
#define REGQ (100)
static ccv_dpm_mixture_model_t* _ccv_dpm_optimize_root_mixture_model(gsl_rng* rng, ccv_dpm_mixture_model_t* model, ccv_array_t** posex, ccv_array_t** negex, int relabels, double balance, double C, double previous_alpha, double alpha_ratio, int iterat...
{
int i, j, k, t, c;
for (i = 0; i < model->count - 1; i++)
assert(posex[i]->rnum == posex[i + 1]->rnum && negex[i]->rnum == negex[i + 1]->rnum);
int posnum = posex[0]->rnum;
int negnum = negex[0]->rnum;
int* label = (int*)ccmalloc(sizeof(int) * (posnum + negnum));
int* order = (int*)ccmalloc(sizeof(int) * (posnum + negnum));
double previous_positive_loss = 0, previous_negative_loss = 0, positive_loss = 0, negative_loss = 0, loss = 0;
double regz_rate = C;
for (c = 0; c < relabels; c++)
{
int* pos_prog = (int*)alloca(sizeof(int) * model->count);
memset(pos_prog, 0, sizeof(int) * model->count);
for (i = 0; i < posnum; i++)
{
int best = -1;
double best_score = -DBL_MAX;
for (k = 0; k < model->count; k++)
{
ccv_dpm_feature_vector_t* v = (ccv_dpm_feature_vector_t*)ccv_array_get(posex[k], i);
if (v->root.w == 0)
continue;
double score = _ccv_dpm_vector_score(model, v); // the loss for mini-batch method (computed on model)
if (score > best_score)
{
best = k;
best_score = score;
}
}
label[i] = best;
if (best >= 0)
++pos_prog[best];
}
PRINT(CCV_CLI_INFO, " - positive examples divided by components for root model optimizing : %d", pos_prog[0]);
for (i = 1; i < model->count; i++)
PRINT(CCV_CLI_INFO, ", %d", pos_prog[i]);
PRINT(CCV_CLI_INFO, "\n");
int* neg_prog = (int*)alloca(sizeof(int) * model->count);
memset(neg_prog, 0, sizeof(int) * model->count);
for (i = 0; i < negnum; i++)
{
int best = gsl_rng_uniform_int(rng, model->count);
label[i + posnum] = best;
++neg_prog[best];
}
PRINT(CCV_CLI_INFO, " - negative examples divided by components for root model optimizing : %d", neg_prog[0]);
for (i = 1; i < model->count; i++)
PRINT(CCV_CLI_INFO, ", %d", neg_prog[i]);
PRINT(CCV_CLI_INFO, "\n");
ccv_dpm_mixture_model_t* _model;
double alpha = previous_alpha;
previous_positive_loss = previous_negative_loss = 0;
for (t = 0; t < iterations; t++)
{
for (i = 0; i < posnum + negnum; i++)
order[i] = i;
gsl_ran_shuffle(rng, order, posnum + negnum, sizeof(int));
for (j = 0; j < model->count; j++)
{
double pos_weight = sqrt((double)neg_prog[j] / pos_prog[j] * balance); // positive weight
double neg_weight = sqrt((double)pos_prog[j] / neg_prog[j] / balance); // negative weight
_model = _ccv_dpm_model_copy(model);
int l = 0;
for (i = 0; i < posnum + negnum; i++)
{
k = order[i];
if (label[k] == j)
{
assert(label[k] < model->count);
if (k < posnum)
{
ccv_dpm_feature_vector_t* v = (ccv_dpm_feature_vector_t*)ccv_array_get(posex[label[k]], k);
assert(v->root.w);
double score = _ccv_dpm_vector_score(model, v); // the loss for mini-batch method (computed on model)
assert(!isnan(score));
assert(v->id == j);
if (score <= 1)
_ccv_dpm_stochastic_gradient_descent(_model, v, 1, alpha * pos_weight, regz_rate, symmetric);
} else {
ccv_dpm_feature_vector_t* v = (ccv_dpm_feature_vector_t*)ccv_array_get(negex[label[k]], k - posnum);
double score = _ccv_dpm_vector_score(model, v);
assert(!isnan(score));
assert(v->id == j);
if (score >= -1)
_ccv_dpm_stochastic_gradient_descent(_model, v, -1, alpha * neg_weight, regz_rate, symmetric);
}
++l;
if (l % REGQ == REGQ - 1)
_ccv_dpm_regularize_mixture_model(_model, j, 1.0 - pow(1.0 - alpha / (double)((pos_prog[j] + neg_prog[j]) * (!!symmetric + 1)), REGQ));
if (l % MINI_BATCH == MINI_BATCH - 1)
{
// mimicking mini-batch way of doing things
_ccv_dpm_mixture_model_cleanup(model);
ccfree(model);
model = _model;
_model = _ccv_dpm_model_copy(model);
}
}
}
_ccv_dpm_regularize_mixture_model(_model, j, 1.0 - pow(1.0 - alpha / (double)((pos_prog[j] + neg_prog[j]) * (!!symmetric + 1)), (((pos_prog[j] + neg_prog[j]) % REGQ) + 1) % (REGQ + 1)));
_ccv_dpm_mixture_model_cleanup(model);
ccfree(model);
model = _model;
}
// compute the loss
positive_loss = negative_loss = loss = 0;
int posvn = 0;
for (i = 0; i < posnum; i++)
{
if (label[i] < 0)
continue;
assert(label[i] < model->count);
ccv_dpm_feature_vector_t* v = (ccv_dpm_feature_vector_t*)ccv_array_get(posex[label[i]], i);
if (v->root.w)
{
double score = _ccv_dpm_vector_score(model, v);
assert(!isnan(score));
double hinge_loss = ccv_max(0, 1.0 - score);
positive_loss += hinge_loss;
double pos_weight = sqrt((double)neg_prog[v->id] / pos_prog[v->id] * balance); // positive weight
loss += pos_weight * hinge_loss;
++posvn;
}
}
for (i = 0; i < negnum; i++)
{
if (label[i + posnum] < 0)
continue;
assert(label[i + posnum] < model->count);
ccv_dpm_feature_vector_t* v = (ccv_dpm_feature_vector_t*)ccv_array_get(negex[label[i + posnum]], i);
double score = _ccv_dpm_vector_score(model, v);
assert(!isnan(score));
double hinge_loss = ccv_max(0, 1.0 + score);
negative_loss += hinge_loss;
double neg_weight = sqrt((double)pos_prog[v->id] / neg_prog[v->id] / balance); // negative weight
loss += neg_weight * hinge_loss;
}
loss = loss / (posvn + negnum);
positive_loss = positive_loss / posvn;
negative_loss = negative_loss / negnum;
FLUSH(CCV_CLI_INFO, " - with loss %.5lf (positive %.5lf, negative %.5f) at rate %.5lf %d | %d -- %d%%", loss, positive_loss, negative_loss, alpha, posvn, negnum, (t + 1) * 100 / iterations);
// check symmetric property of generated root feature
if (symmetric)
for (i = 0; i < model->count; i++)
{
ccv_dpm_root_classifier_t* root_classifier = model->root + i;
_ccv_dpm_check_root_classifier_symmetry(root_classifier->root.w);
}
if (fabs(previous_positive_loss - positive_loss) < 1e-5 &&
fabs(previous_negative_loss - negative_loss) < 1e-5)
{
PRINT(CCV_CLI_INFO, "\n - aborting iteration at %d because we didn't gain much", t + 1);
break;
}
previous_positive_loss = positive_loss;
previous_negative_loss = negative_loss;
alpha *= alpha_ratio; // it will decrease with each iteration
}
PRINT(CCV_CLI_INFO, "\n");
}
ccfree(order);
ccfree(label);
return model;
}
void ccv_dpm_mixture_model_new(char** posfiles, ccv_rect_t* bboxes, int posnum, char** bgfiles, int bgnum, int negnum, const char* dir, ccv_dpm_new_param_t params)
{
int t, d, c, i, j, k, p;
_ccv_dpm_check_params(params);
assert(params.negative_cache_size <= negnum && params.negative_cache_size > REGQ && params.negative_cache_size > MINI_BATCH);
PRINT(CCV_CLI_INFO, "with %d positive examples and %d negative examples\n"
"negative examples are are going to be collected from %d background images\n",
posnum, negnum, bgnum);
PRINT(CCV_CLI_INFO, "use symmetric property? %s\n", params.symmetric ? "yes" : "no");
PRINT(CCV_CLI_INFO, "use color? %s\n", params.grayscale ? "no" : "yes");
PRINT(CCV_CLI_INFO, "negative examples cache size : %d\n", params.negative_cache_size);
PRINT(CCV_CLI_INFO, "%d components and %d parts\n", params.components, params.parts);
PRINT(CCV_CLI_INFO, "expected %d root relabels, %d relabels, %d data minings and %d iterations\n", params.root_relabels, params.relabels, params.data_minings, params.iterations);
PRINT(CCV_CLI_INFO, "include overlap : %lf\n"
"alpha : %lf\n"
"alpha decreasing ratio : %lf\n"
"C : %lf\n"
"balance ratio : %lf\n"
"------------------------\n",
params.include_overlap, params.alpha, params.alpha_ratio, params.C, params.balance);
gsl_rng_env_setup();
gsl_rng* rng = gsl_rng_alloc(gsl_rng_default);
gsl_rng_set(rng, *(unsigned long int*)¶ms);
ccv_dpm_mixture_model_t* model = (ccv_dpm_mixture_model_t*)ccmalloc(sizeof(ccv_dpm_mixture_model_t));
memset(model, 0, sizeof(ccv_dpm_mixture_model_t));
struct feature_node* fn = (struct feature_node*)ccmalloc(sizeof(struct feature_node) * posnum);
for (i = 0; i < posnum; i++)
{
assert(bboxes[i].width > 0 && bboxes[i].height > 0);
fn[i].value = (float)bboxes[i].width / (float)bboxes[i].height;
fn[i].index = i;
}
char checkpoint[512];
char initcheckpoint[512];
sprintf(checkpoint, "%s/model", dir);
sprintf(initcheckpoint, "%s/init.model", dir);
_ccv_dpm_aspect_qsort(fn, posnum, 0);
double mean = 0;
for (i = 0; i < posnum; i++)
mean += fn[i].value;
mean /= posnum;
double variance = 0;
for (i = 0; i < posnum; i++)
variance += (fn[i].value - mean) * (fn[i].value - mean);
variance /= posnum;
PRINT(CCV_CLI_INFO, "global mean: %lf, & variance: %lf\ninterclass mean(variance):", mean, variance);
int* mnum = (int*)alloca(sizeof(int) * params.components);
int outnum = posnum, innum = 0;
for (i = 0; i < params.components; i++)
{
mnum[i] = (int)((double)outnum / (double)(params.components - i) + 0.5);
double mean = 0;
for (j = innum; j < innum + mnum[i]; j++)
mean += fn[j].value;
mean /= mnum[i];
double variance = 0;
for (j = innum; j < innum + mnum[i]; j++)
variance += (fn[j].value - mean) * (fn[j].value - mean);
variance /= mnum[i];
PRINT(CCV_CLI_INFO, " %lf(%lf)", mean, variance);
outnum -= mnum[i];
innum += mnum[i];
}
PRINT(CCV_CLI_INFO, "\n");
int* areas = (int*)ccmalloc(sizeof(int) * posnum);
for (i = 0; i < posnum; i++)
areas[i] = bboxes[i].width * bboxes[i].height;
_ccv_dpm_area_qsort(areas, posnum, 0);
// so even the object is 1/4 in size, we can still detect them (in detection phase, we start at 2x image)
int area = ccv_clamp(areas[(int)(posnum * 0.2 + 0.5)], params.min_area, params.max_area);
ccfree(areas);
innum = 0;
_ccv_dpm_read_checkpoint(model, checkpoint);
ccv-src/lib/ccv_dpm.c view on Meta::CPAN
for (i = 0; i < params.components; i++)
{
double aspect = 0;
for (j = innum; j < innum + mnum[i]; j++)
{
aspect += fn[j].value;
poslabels[fn[j].index] = i; // setup labels
}
aspect /= mnum[i];
cols[i] = ccv_max((int)(sqrtf(area / aspect) * aspect / CCV_DPM_WINDOW_SIZE + 0.5), 1);
rows[i] = ccv_max((int)(sqrtf(area / aspect) / CCV_DPM_WINDOW_SIZE + 0.5), 1);
if (i < params.components - 1)
PRINT(CCV_CLI_INFO, "%dx%d, ", cols[i], rows[i]);
else
PRINT(CCV_CLI_INFO, "%dx%d\n", cols[i], rows[i]);
fflush(stdout);
innum += mnum[i];
}
ccfree(fn);
int corrupted = 1;
for (i = 0; i < params.components; i++)
if (model->root[i].root.w)
{
PRINT(CCV_CLI_INFO, "skipping root mixture model initialization for model %d(%d)\n", i + 1, params.components);
corrupted = 0;
} else
break;
if (corrupted)
{
PRINT(CCV_CLI_INFO, "root mixture model initialization corrupted, reboot\n");
ccv_array_t** posex = (ccv_array_t**)alloca(sizeof(ccv_array_t*) * params.components);
for (i = 0; i < params.components; i++)
posex[i] = _ccv_dpm_summon_examples_by_rectangle(posfiles, bboxes, posnum, i, rows[i], cols[i], params.grayscale);
PRINT(CCV_CLI_INFO, "\n");
ccv_array_t** negex = (ccv_array_t**)alloca(sizeof(ccv_array_t*) * params.components);
_ccv_dpm_collect_examples_randomly(rng, negex, bgfiles, bgnum, negnum, params.components, rows, cols, params.grayscale);
PRINT(CCV_CLI_INFO, "\n");
int* neglabels = (int*)ccmalloc(sizeof(int) * negex[0]->rnum);
for (i = 0; i < negex[0]->rnum; i++)
neglabels[i] = gsl_rng_uniform_int(rng, params.components);
for (i = 0; i < params.components; i++)
{
ccv_dpm_root_classifier_t* root_classifier = model->root + i;
root_classifier->root.w = ccv_dense_matrix_new(rows[i], cols[i], CCV_32F | 31, 0, 0);
PRINT(CCV_CLI_INFO, "initializing root mixture model for model %d(%d)\n", i + 1, params.components);
_ccv_dpm_initialize_root_classifier(rng, root_classifier, i, mnum[i], poslabels, posex[i], neglabels, negex[i], params.C, params.symmetric, params.grayscale);
}
ccfree(neglabels);
ccfree(poslabels);
// check symmetric property of generated root feature
if (params.symmetric)
for (i = 0; i < params.components; i++)
{
ccv_dpm_root_classifier_t* root_classifier = model->root + i;
_ccv_dpm_check_root_classifier_symmetry(root_classifier->root.w);
}
if (params.components > 1)
{
/* TODO: coordinate-descent for lsvm */
PRINT(CCV_CLI_INFO, "optimizing root mixture model with coordinate-descent approach\n");
model = _ccv_dpm_optimize_root_mixture_model(rng, model, posex, negex, params.root_relabels, params.balance, params.C, params.alpha, params.alpha_ratio, params.iterations, params.symmetric);
} else {
PRINT(CCV_CLI_INFO, "components == 1, skipped coordinate-descent to optimize root mixture model\n");
}
for (i = 0; i < params.components; i++)
{
for (j = 0; j < posex[i]->rnum; j++)
_ccv_dpm_feature_vector_cleanup((ccv_dpm_feature_vector_t*)ccv_array_get(posex[i], j));
ccv_array_free(posex[i]);
for (j = 0; j < negex[i]->rnum; j++)
_ccv_dpm_feature_vector_cleanup((ccv_dpm_feature_vector_t*)ccv_array_get(negex[i], j));
ccv_array_free(negex[i]);
}
} else {
ccfree(poslabels);
}
_ccv_dpm_write_checkpoint(model, 0, checkpoint);
/* initialize part filter */
PRINT(CCV_CLI_INFO, "initializing part filters\n");
for (i = 0; i < params.components; i++)
{
if (model->root[i].count > 0)
{
PRINT(CCV_CLI_INFO, " - skipping part filters initialization for model %d(%d)\n", i + 1, params.components);
} else {
PRINT(CCV_CLI_INFO, " - initializing part filters for model %d(%d)\n", i + 1, params.components);
_ccv_dpm_initialize_part_classifiers(model->root + i, params.parts, params.symmetric);
_ccv_dpm_write_checkpoint(model, 0, checkpoint);
_ccv_dpm_write_checkpoint(model, 0, initcheckpoint);
}
}
_ccv_dpm_write_checkpoint(model, 0, checkpoint);
/* optimize both root filter and part filters with stochastic gradient descent */
PRINT(CCV_CLI_INFO, "optimizing root filter & part filters with stochastic gradient descent\n");
char gradient_progress_checkpoint[512];
sprintf(gradient_progress_checkpoint, "%s/gradient_descent_progress", dir);
char feature_vector_checkpoint[512];
sprintf(feature_vector_checkpoint, "%s/positive_vectors", dir);
char neg_vector_checkpoint[512];
sprintf(neg_vector_checkpoint, "%s/negative_vectors", dir);
ccv_dpm_feature_vector_t** posv = (ccv_dpm_feature_vector_t**)ccmalloc(posnum * sizeof(ccv_dpm_feature_vector_t*));
int* order = (int*)ccmalloc(sizeof(int) * (posnum + params.negative_cache_size + 64 /* the magical number for maximum negative examples collected per image */));
double previous_positive_loss = 0, previous_negative_loss = 0, positive_loss = 0, negative_loss = 0, loss = 0;
// need to re-weight for each examples
c = d = t = 0;
ccv_array_t* negv = 0;
if (0 == _ccv_dpm_read_negative_feature_vectors(&negv, params.negative_cache_size, neg_vector_checkpoint))
PRINT(CCV_CLI_INFO, " - read collected negative responses from last interrupted process\n");
_ccv_dpm_read_gradient_descent_progress(&c, &d, gradient_progress_checkpoint);
for (; c < params.relabels; c++)
{
double regz_rate = params.C;
ccv_dpm_mixture_model_t* _model;
if (0 == _ccv_dpm_read_positive_feature_vectors(posv, posnum, feature_vector_checkpoint))
{
PRINT(CCV_CLI_INFO, " - read collected positive responses from last interrupted process\n");
} else {
FLUSH(CCV_CLI_INFO, " - collecting responses from positive examples : 0%%");
for (i = 0; i < posnum; i++)
{
FLUSH(CCV_CLI_INFO, " - collecting responses from positive examples : %d%%", i * 100 / posnum);
ccv-src/lib/ccv_dpm.c view on Meta::CPAN
if (posv[i])
{
assert(posv[i]->id >= 0 && posv[i]->id < model->count);
++posvnum[posv[i]->id];
}
PRINT(CCV_CLI_INFO, " - positive examples divided by components : %d", posvnum[0]);
for (i = 1; i < model->count; i++)
PRINT(CCV_CLI_INFO, ", %d", posvnum[i]);
PRINT(CCV_CLI_INFO, "\n");
params.detector.threshold = 0;
for (; d < params.data_minings; d++)
{
// the cache is used up now, collect again
_ccv_dpm_write_gradient_descent_progress(c, d, gradient_progress_checkpoint);
double alpha = params.alpha;
if (negv)
{
ccv_array_t* av = ccv_array_new(sizeof(ccv_dpm_feature_vector_t*), 64, 0);
for (j = 0; j < negv->rnum; j++)
{
ccv_dpm_feature_vector_t* v = *(ccv_dpm_feature_vector_t**)ccv_array_get(negv, j);
double score = _ccv_dpm_vector_score(model, v);
assert(!isnan(score));
if (score >= -1)
ccv_array_push(av, &v);
else
_ccv_dpm_feature_vector_free(v);
}
ccv_array_free(negv);
negv = av;
} else {
negv = ccv_array_new(sizeof(ccv_dpm_feature_vector_t*), 64, 0);
}
FLUSH(CCV_CLI_INFO, " - collecting negative examples -- (0%%)");
if (negv->rnum < params.negative_cache_size)
_ccv_dpm_collect_from_background(negv, rng, bgfiles, bgnum, model, params, 0);
_ccv_dpm_write_negative_feature_vectors(negv, params.negative_cache_size, neg_vector_checkpoint);
FLUSH(CCV_CLI_INFO, " - collecting negative examples -- (100%%)\n");
int* negvnum = (int*)alloca(sizeof(int) * model->count);
memset(negvnum, 0, sizeof(int) * model->count);
for (i = 0; i < negv->rnum; i++)
{
ccv_dpm_feature_vector_t* v = *(ccv_dpm_feature_vector_t**)ccv_array_get(negv, i);
assert(v->id >= 0 && v->id < model->count);
++negvnum[v->id];
}
if (negv->rnum <= ccv_max(params.negative_cache_size / 2, ccv_max(REGQ, MINI_BATCH)))
{
for (i = 0; i < model->count; i++)
// we cannot get sufficient negatives, adjust constant and abort for next round
_ccv_dpm_adjust_model_constant(model, i, posv, posnum, params.percentile_breakdown);
continue;
}
PRINT(CCV_CLI_INFO, " - negative examples divided by components : %d", negvnum[0]);
for (i = 1; i < model->count; i++)
PRINT(CCV_CLI_INFO, ", %d", negvnum[i]);
PRINT(CCV_CLI_INFO, "\n");
previous_positive_loss = previous_negative_loss = 0;
uint64_t elapsed_time = _ccv_dpm_time_measure();
assert(negv->rnum < params.negative_cache_size + 64);
for (t = 0; t < params.iterations; t++)
{
for (p = 0; p < model->count; p++)
{
// if don't have enough negnum or posnum, aborting
if (negvnum[p] <= ccv_max(params.negative_cache_size / (model->count * 3), ccv_max(REGQ, MINI_BATCH)) ||
posvnum[p] <= ccv_max(REGQ, MINI_BATCH))
continue;
double pos_weight = sqrt((double)negvnum[p] / posvnum[p] * params.balance); // positive weight
double neg_weight = sqrt((double)posvnum[p] / negvnum[p] / params.balance); // negative weight
_model = _ccv_dpm_model_copy(model);
for (i = 0; i < posnum + negv->rnum; i++)
order[i] = i;
gsl_ran_shuffle(rng, order, posnum + negv->rnum, sizeof(int));
int l = 0;
for (i = 0; i < posnum + negv->rnum; i++)
{
k = order[i];
if (k < posnum)
{
if (posv[k] == 0 || posv[k]->id != p)
continue;
double score = _ccv_dpm_vector_score(model, posv[k]); // the loss for mini-batch method (computed on model)
assert(!isnan(score));
if (score <= 1)
_ccv_dpm_stochastic_gradient_descent(_model, posv[k], 1, alpha * pos_weight, regz_rate, params.symmetric);
} else {
ccv_dpm_feature_vector_t* v = *(ccv_dpm_feature_vector_t**)ccv_array_get(negv, k - posnum);
if (v->id != p)
continue;
double score = _ccv_dpm_vector_score(model, v);
assert(!isnan(score));
if (score >= -1)
_ccv_dpm_stochastic_gradient_descent(_model, v, -1, alpha * neg_weight, regz_rate, params.symmetric);
}
++l;
if (l % REGQ == REGQ - 1)
_ccv_dpm_regularize_mixture_model(_model, p, 1.0 - pow(1.0 - alpha / (double)((posvnum[p] + negvnum[p]) * (!!params.symmetric + 1)), REGQ));
if (l % MINI_BATCH == MINI_BATCH - 1)
{
// mimicking mini-batch way of doing things
_ccv_dpm_mixture_model_cleanup(model);
ccfree(model);
model = _model;
_model = _ccv_dpm_model_copy(model);
}
}
_ccv_dpm_regularize_mixture_model(_model, p, 1.0 - pow(1.0 - alpha / (double)((posvnum[p] + negvnum[p]) * (!!params.symmetric + 1)), (((posvnum[p] + negvnum[p]) % REGQ) + 1) % (REGQ + 1)));
_ccv_dpm_mixture_model_cleanup(model);
ccfree(model);
model = _model;
}
// compute the loss
int posvn = 0;
positive_loss = negative_loss = loss = 0;
for (i = 0; i < posnum; i++)
if (posv[i] != 0)
{
double score = _ccv_dpm_vector_score(model, posv[i]);
assert(!isnan(score));
double hinge_loss = ccv_max(0, 1.0 - score);
positive_loss += hinge_loss;
double pos_weight = sqrt((double)negvnum[posv[i]->id] / posvnum[posv[i]->id] * params.balance); // positive weight
loss += pos_weight * hinge_loss;
++posvn;
}
for (i = 0; i < negv->rnum; i++)
{
ccv_dpm_feature_vector_t* v = *(ccv_dpm_feature_vector_t**)ccv_array_get(negv, i);
double score = _ccv_dpm_vector_score(model, v);
assert(!isnan(score));
double hinge_loss = ccv_max(0, 1.0 + score);
negative_loss += hinge_loss;
double neg_weight = sqrt((double)posvnum[v->id] / negvnum[v->id] / params.balance); // negative weight
loss += neg_weight * hinge_loss;
}
loss = loss / (posvn + negv->rnum);
positive_loss = positive_loss / posvn;
negative_loss = negative_loss / negv->rnum;
FLUSH(CCV_CLI_INFO, " - with loss %.5lf (positive %.5lf, negative %.5f) at rate %.5lf %d | %d -- %d%%", loss, positive_loss, negative_loss, alpha, posvn, negv->rnum, (t + 1) * 100 / params.iterations);
// check symmetric property of generated root feature
if (params.symmetric)
for (i = 0; i < params.components; i++)
{
ccv_dpm_root_classifier_t* root_classifier = model->root + i;
_ccv_dpm_check_root_classifier_symmetry(root_classifier->root.w);
}
if (fabs(previous_positive_loss - positive_loss) < 1e-5 &&
fabs(previous_negative_loss - negative_loss) < 1e-5)
{
PRINT(CCV_CLI_INFO, "\n - aborting iteration at %d because we didn't gain much", t + 1);
break;
}
previous_positive_loss = positive_loss;
previous_negative_loss = negative_loss;
alpha *= params.alpha_ratio; // it will decrease with each iteration
}
_ccv_dpm_write_checkpoint(model, 0, checkpoint);
PRINT(CCV_CLI_INFO, "\n - data mining %d takes %.2lf seconds at loss %.5lf, %d more to go (%d of %d)\n", d + 1, (double)(_ccv_dpm_time_measure() - elapsed_time) / 1000000.0, loss, params.data_minings - d - 1, c + 1, params.relabels);
j = 0;
double* scores = (double*)ccmalloc(posnum * sizeof(double));
for (i = 0; i < posnum; i++)
if (posv[i])
{
scores[j] = _ccv_dpm_vector_score(model, posv[i]);
assert(!isnan(scores[j]));
j++;
}
_ccv_dpm_score_qsort(scores, j, 0);
ccfree(scores);
double breakdown;
PRINT(CCV_CLI_INFO, " - threshold breakdown by percentile");
for (breakdown = params.percentile_breakdown; breakdown < 1.0; breakdown += params.percentile_breakdown)
PRINT(CCV_CLI_INFO, " %0.2lf(%.1f%%)", scores[ccv_clamp((int)(breakdown * j), 0, j - 1)], (1.0 - breakdown) * 100);
PRINT(CCV_CLI_INFO, "\n");
char persist[512];
sprintf(persist, "%s/model.%d.%d", dir, c, d);
_ccv_dpm_write_checkpoint(model, 0, persist);
}
d = 0;
// if abort, means that we cannot find enough negative examples, try to adjust constant
for (i = 0; i < posnum; i++)
if (posv[i])
_ccv_dpm_feature_vector_free(posv[i]);
remove(feature_vector_checkpoint);
}
if (negv)
{
for (i = 0; i < negv->rnum; i++)
{
ccv_dpm_feature_vector_t* v = *(ccv_dpm_feature_vector_t**)ccv_array_get(negv, i);
_ccv_dpm_feature_vector_free(v);
}
ccv_array_free(negv);
}
remove(neg_vector_checkpoint);
ccfree(order);
ccfree(posv);
PRINT(CCV_CLI_INFO, "root rectangle prediction with linear regression\n");
_ccv_dpm_initialize_root_rectangle_estimator(model, posfiles, bboxes, posnum, params);
( run in 0.925 second using v1.01-cache-2.11-cpan-71847e10f99 )