Skip to content

Commit

Permalink
a "wow" error in ccv_dense_matrix_renew
Browse files Browse the repository at this point in the history
ccv_dense_matrix_renew is an old function. It meant to check whether
the pass-in matrix is on specification, if it is, sign it and return,
if it is not, create/retrieve a new one based on the signature and
return. However, I made a huge mistake by not check if signature is
empty or not, and by the signature generation process, it will generate
a non-empty signature for pass-in empty ones, and using this one
to retrieve matrix from cache. Since I don't use that much
empty-signature matrix myself, the problem hasn't surfaced until
when I have to regularly ccv_make_matrix_mutable/immutable for
dpm implementations.
  • Loading branch information
liuliu committed May 12, 2012
1 parent e2c8f02 commit de220a1
Show file tree
Hide file tree
Showing 4 changed files with 152 additions and 27 deletions.
100 changes: 100 additions & 0 deletions bin/dpmcreate.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
#include "ccv.h"
#include <ctype.h>

void exit_with_help()
{
printf(
"USAGE: dpmcreate positive_set_file background_set_file negative_number model_components model_parts output [change_to_directory]\n"
"DESCRIPTION:\n"
"- positive_set_file: text file contains a list of positive files in format:\n"
"- <file name> x y width height \\newline\n"
"- background_set_file: text file contains a list of image files that don't contain any target objects\n"
"- negative_number: the number of negative examples we should collect from background files to initialize SVM\n"
"- model_components: the number of root filters in our mixture model\n"
"- model_parts: the number of part filters for each root filter\n"
"- output: the output model file\n"
"- change_to_directory: change the base directory so that the program can read images from there\n"
);
exit(-1);
}

int main(int argc, char** argv)
{
if (argc != 7 && argc != 8)
exit_with_help();
ccv_enable_cache(512 * 1024 * 1024);
FILE* r0 = fopen(argv[1], "r");
FILE* r1 = fopen(argv[2], "r");
char* file = (char*)malloc(1024);
int x, y, width, height;
int capacity = 32, size = 0;
char** posfiles = (char**)ccmalloc(sizeof(char*) * capacity);
ccv_rect_t* bboxes = (ccv_rect_t*)ccmalloc(sizeof(ccv_rect_t) * capacity);
int dirlen = (argc == 8) ? strlen(argv[7]) + 1 : 0;
while (fscanf(r0, "%s %d %d %d %d", file, &x, &y, &width, &height) != EOF)
{
posfiles[size] = (char*)ccmalloc(1024);
if (argc == 8)
{
strncpy(posfiles[size], argv[7], 1024);
posfiles[size][dirlen - 1] = '/';
}
strncpy(posfiles[size] + dirlen, file, 1024 - dirlen);
bboxes[size] = ccv_rect(x, y, width, height);
++size;
if (size >= capacity)
{
capacity *= 2;
posfiles = (char**)ccrealloc(posfiles, sizeof(char*) * capacity);
bboxes = (ccv_rect_t*)ccrealloc(bboxes, sizeof(ccv_rect_t) * capacity);
}
}
int posnum = size;
fclose(r0);
size_t len = 1024;
ssize_t read;
capacity = 32, size = 0;
char** bgfiles = (char**)ccmalloc(sizeof(char*) * capacity);
while ((read = getline(&file, &len, r1)) != -1)
{
while(read > 1 && isspace(file[read - 1]))
read--;
file[read] = 0;
bgfiles[size] = (char*)ccmalloc(1024);
if (argc == 8)
{
strncpy(bgfiles[size], argv[7], 1024);
bgfiles[size][dirlen - 1] = '/';
}
strncpy(bgfiles[size] + dirlen, file, 1024 - dirlen);
++size;
if (size >= capacity)
{
capacity *= 2;
bgfiles = (char**)ccrealloc(bgfiles, sizeof(char*) * capacity);
}
}
fclose(r1);
int bgnum = size;
int negnum = atoi(argv[3]);
int components = atoi(argv[4]);
int parts = atoi(argv[5]);
free(file);
ccv_dpm_param_t detector = { .interval = 8, .min_neighbors = 2, .flags = 0, .threshold = 0.0 };
ccv_dpm_new_param_t params = { .components = components,
.detector = detector,
.parts = parts,
.min_area = 3000,
.max_area = 5000,
.symmetric = 1,
.alpha = 0.1,
.iterations = 1000,
.C = 0.02,
.grayscale = 0 };
ccv_dpm_mixture_model_new(posfiles, bboxes, posnum, bgfiles, bgnum, negnum, argv[6], params);
free(posfiles);
free(bboxes);
free(bgfiles);
ccv_disable_cache();
return 0;
}
60 changes: 42 additions & 18 deletions lib/ccv_dpm.c
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,8 @@ static CCV_IMPLEMENT_QSORT(_ccv_dpm_area_qsort, int, less_than)
static void _ccv_dpm_write_checkpoint(ccv_dpm_mixture_model_t* model, const char* dir)
{
FILE* w = fopen(dir, "w+");
if (!w)
return;
fprintf(w, ",\n");
int i, j, x, y, ch, count = 0;
for (i = 0; i < model->count; i++)
Expand Down Expand Up @@ -155,7 +157,7 @@ static void _ccv_dpm_write_checkpoint(ccv_dpm_mixture_model_t* model, const char
ccv_dpm_part_classifier_t* part_classifier = root_classifier->part + j;
fprintf(w, "%d %d %d\n", part_classifier->x, part_classifier->y, part_classifier->z);
fprintf(w, "%la %la %la %la\n", part_classifier->dx, part_classifier->dy, part_classifier->dxx, part_classifier->dyy);
fprintf(w, "%d %d\n", part_classifier->w->rows, part_classifier->w->cols);
fprintf(w, "%d %d %d\n", part_classifier->w->rows, part_classifier->w->cols, part_classifier->counterpart);
ch = CCV_GET_CHANNEL(part_classifier->w->type);
for (y = 0; y < part_classifier->w->rows; y++)
{
Expand All @@ -171,7 +173,7 @@ static void _ccv_dpm_write_checkpoint(ccv_dpm_mixture_model_t* model, const char
static void _ccv_dpm_read_checkpoint(ccv_dpm_mixture_model_t* model, const char* dir)
{
FILE* r = fopen(dir, "r");
if (r == 0)
if (!r)
return;
int count;
char flag;
Expand All @@ -196,7 +198,7 @@ static void _ccv_dpm_read_checkpoint(ccv_dpm_mixture_model_t* model, const char*
{
fscanf(r, "%d %d %d", &part_classifier[j].x, &part_classifier[j].y, &part_classifier[j].z);
fscanf(r, "%lf %lf %lf %lf", &part_classifier[j].dx, &part_classifier[j].dy, &part_classifier[j].dxx, &part_classifier[j].dyy);
fscanf(r, "%d %d", &rows, &cols);
fscanf(r, "%d %d %d", &rows, &cols, &part_classifier[j].counterpart);
part_classifier[j].w = ccv_dense_matrix_new(rows, cols, CCV_32F | 31, ccmalloc(ccv_compute_dense_matrix_size(rows, cols, CCV_32F | 31)), 0);
for (k = 0; k < rows * cols * 31; k++)
fscanf(r, "%f", &part_classifier[j].w->data.f32[k]);
Expand Down Expand Up @@ -262,8 +264,8 @@ static void _ccv_dpm_initialize_root_classifier(gsl_rng* rng, ccv_dpm_root_class
int rows = root_classifier->root.w->rows;
printf(" - creating initial model %d at %dx%d\n", label + 1, cols, rows);
struct problem prob;
prob.n = 31 * cols * rows + 1;
prob.bias = 1.0;
prob.n = symmetric ? 31 * cols2c * rows + 1 : 31 * cols * rows + 1;
prob.bias = symmetric ? 0.5 : 1.0; // for symmetric, since we only pass half features in, need to set bias to be half too
prob.y = (int*)malloc(sizeof(int) * (cnum + negnum) * (!!symmetric + 1));
prob.x = (struct feature_node**)malloc(sizeof(struct feature_node*) * (cnum + negnum) * (!!symmetric + 1));
printf(" - generating positive examples ");
Expand Down Expand Up @@ -406,7 +408,7 @@ static void _ccv_dpm_initialize_root_classifier(gsl_rng* rng, ccv_dpm_root_class
j = 0;
for (y = 0; y < rows; y++)
{
for (x = 0; x < cols; x++)
for (x = 0; x < cols2c; x++)
for (k = 0; k < 31; k++)
{
features[j].index = j + 1;
Expand Down Expand Up @@ -468,9 +470,11 @@ static void _ccv_dpm_initialize_root_classifier(gsl_rng* rng, ccv_dpm_root_class
{
for (x = 0; x < cols2c; x++)
for (k = 0; k < 31; k++)
wptr[(cols - 1 - x) * 31 + _ccv_dpm_sym_lut[k]] = wptr[x * 31 + k] = linear->w[y * cols2c * 31 + k];
wptr[(cols - 1 - x) * 31 + _ccv_dpm_sym_lut[k]] = wptr[x * 31 + k] = linear->w[(y * cols2c + x) * 31 + k];
wptr += cols * 31;
}
// since for symmetric, lsvm only computed half features, to compensate that, we doubled the constant.
root_classifier->beta = linear->w[31 * rows * cols2c] * 2.0;
} else {
for (j = 0; j < 31 * rows * cols; j++)
root_classifier->root.w->data.f32[j] = linear->w[j];
Expand All @@ -497,7 +501,7 @@ static void _ccv_dpm_initialize_part_classifiers(ccv_dpm_root_classifier_t* root
{
ccv_dpm_part_classifier_t* part_classifier = root_classifier->part + i;
int dx = 0, dy = 0, dw = 0, dh = 0, sym = 0;
double dsum = -DBL_MAX;
double dsum = -1.0; // absolute value, thus, -1.0 is enough
#define slice_and_update_if_needed(y, x, l, n, s) \
{ \
ccv_dense_matrix_t* slice = 0; \
Expand Down Expand Up @@ -532,7 +536,7 @@ static void _ccv_dpm_initialize_part_classifiers(ccv_dpm_root_classifier_t* root
if (i < parts - 1) // have 2 locations
{
for (y = 0; y < w->rows - j + 1; y++)
for (x = 0; x <= (w->rows - k - k / 2 /* to avoid overlapping by half */ - 1) / 2; x++)
for (x = 0; x <= w->cols / 2 - k /* to avoid overlapping */; x++)
slice_and_update_if_needed(y, x, j, k, 1);
}
} else {
Expand All @@ -551,6 +555,7 @@ static void _ccv_dpm_initialize_part_classifiers(ccv_dpm_root_classifier_t* root
part_classifier->z = 1;
part_classifier->w = 0;
ccv_slice(w, (ccv_matrix_t**)&part_classifier->w, 0, dy, dx, dh, dw);
ccv_make_matrix_immutable(part_classifier->w);
/* clean up the region we selected */
float* w_ptr = (float*)ccv_get_dense_matrix_cell_by(CCV_32F | 31, w, dy, dx, 0);
for (y = 0; y < dh; y++)
Expand All @@ -573,6 +578,7 @@ static void _ccv_dpm_initialize_part_classifiers(ccv_dpm_root_classifier_t* root
part_classifier[1].z = 1;
part_classifier[1].w = 0;
ccv_slice(w, (ccv_matrix_t**)&part_classifier[1].w, 0, dy, dx, dh, dw);
ccv_make_matrix_immutable(part_classifier[1].w);
/* clean up the region we selected */
float* w_ptr = (float*)ccv_get_dense_matrix_cell_by(CCV_32F | 31, w, dy, dx, 0);
for (y = 0; y < dh; y++)
Expand All @@ -598,6 +604,22 @@ typedef struct {
ccv_dpm_part_classifier_t* part;
} ccv_dpm_feature_vector_t;

static void _ccv_dpm_write_feature_vectors(ccv_dpm_feature_vector_t** vectors, int n, const char* dir)
{
FILE* w = fopen(dir, "w+");
if (!w)
return;
fprintf(w, "%d\n", n);
int i, j, x, y;
for (i = 0; i < n; i++)
{
ccv_dpm_feature_vector_t* vector = vectors[i];
fprintf(w, "%d %d\n", vector->id, vector->count);
fprintf(w, "%d %d\n", vector->root.w->rows, vector->root.w->cols);
}
fclose(w);
}

static void _ccv_dpm_initialize_feature_vector_on_pattern(ccv_dpm_feature_vector_t* vector, ccv_dpm_root_classifier_t* root, int id)
{
int i;
Expand Down Expand Up @@ -905,6 +927,8 @@ void ccv_dpm_mixture_model_new(char** posfiles, ccv_rect_t* bboxes, int posnum,
fn[i].value = (float)bboxes[i].width / (float)bboxes[i].height;
fn[i].index = i;
}
char checkpoint[1024];
sprintf(checkpoint, "%s/model", dir);
_ccv_dpm_aspect_qsort(fn, posnum, 0);
double mean = 0;
for (i = 0; i < posnum; i++)
Expand Down Expand Up @@ -941,7 +965,7 @@ void ccv_dpm_mixture_model_new(char** posfiles, ccv_rect_t* bboxes, int posnum,
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, dir);
_ccv_dpm_read_checkpoint(model, checkpoint);
if (model->count <= 0)
{
/* initialize root mixture model with liblinear */
Expand Down Expand Up @@ -983,7 +1007,7 @@ void ccv_dpm_mixture_model_new(char** posfiles, ccv_rect_t* bboxes, int posnum,
root_classifier->root.w = ccv_dense_matrix_new(rows[i], cols[i], CCV_32F | 31, 0, 0);
printf("initializing root mixture model for model %d(%d)\n", i + 1, params.components);
_ccv_dpm_initialize_root_classifier(rng, root_classifier, i, mnum[i], labels, posfiles, bboxes, posnum, bgfiles, bgnum, negnum, params.symmetric, params.grayscale);
_ccv_dpm_write_checkpoint(model, dir);
_ccv_dpm_write_checkpoint(model, checkpoint);
}
ccfree(fn);
ccfree(labels);
Expand Down Expand Up @@ -1011,21 +1035,21 @@ void ccv_dpm_mixture_model_new(char** posfiles, ccv_rect_t* bboxes, int posnum,
} else {
printf(" - 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, dir);
_ccv_dpm_write_checkpoint(model, checkpoint);
}
}
_ccv_dpm_write_checkpoint(model, dir);
_ccv_dpm_write_checkpoint(model, checkpoint);
/* optimize both root filter and part filters with stochastic gradient descent */
printf("optimizing root filter & part filters with stochastic gradient descent\n");
ccv_dpm_feature_vector_t** posv = (ccv_dpm_feature_vector_t**)ccmalloc(sizeof(ccv_dpm_feature_vector_t*) * posnum);
ccv_dpm_feature_vector_t** negv = (ccv_dpm_feature_vector_t**)ccmalloc(sizeof(ccv_dpm_feature_vector_t*) * negnum);
for (t = 0; t < params.iterations; t++)
{
unsigned int elapsed_time = _ccv_dpm_time_measure();
j = 0;
i = j = 0;
printf(" - collecting best responses from positive examples : 0%%");
fflush(stdout);
for (i = 0; i < posnum; i++)
for (; i < posnum; i++)
{
printf("\b\b\b%2d%%", i * 100 / posnum);
fflush(stdout);
Expand All @@ -1041,10 +1065,10 @@ void ccv_dpm_mixture_model_new(char** posfiles, ccv_rect_t* bboxes, int posnum,
}
printf("\b\b\b100%%\n");
int posvn = j;
j = 0;
i = j = 0;
printf(" - collecting responses above threshold 0 from background examples : 0%%");
fflush(stdout);
for (i = 0; i < bgnum; i++)
for (; i < bgnum; i++)
{
printf("\b\b\b%2d%%", i * 100 / bgnum);
fflush(stdout);
Expand Down Expand Up @@ -1365,7 +1389,7 @@ ccv_dpm_mixture_model_t* ccv_load_dpm_mixture_model(const char* directory)
{
fscanf(r, "%d %d %d", &part_classifier[j].x, &part_classifier[j].y, &part_classifier[j].z);
fscanf(r, "%lf %lf %lf %lf", &part_classifier[j].dx, &part_classifier[j].dy, &part_classifier[j].dxx, &part_classifier[j].dyy);
fscanf(r, "%d %d", &rows, &cols);
fscanf(r, "%d %d %d", &rows, &cols, &part_classifier[j].counterpart);
part_classifier[j].w = ccv_dense_matrix_new(rows, cols, CCV_32F | 31, ccmalloc(ccv_compute_dense_matrix_size(rows, cols, CCV_32F | 31)), 0);
size += ccv_compute_dense_matrix_size(rows, cols, CCV_32F | 31);
for (k = 0; k < rows * cols * 31; k++)
Expand Down
3 changes: 2 additions & 1 deletion lib/ccv_memory.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ ccv_dense_matrix_t* ccv_dense_matrix_renew(ccv_dense_matrix_t* x, int rows, int
assert(x->rows == rows && x->cols == cols && (CCV_GET_DATA_TYPE(x->type) & types) && (CCV_GET_CHANNEL(x->type) == CCV_GET_CHANNEL(types)));
prefer_type = CCV_GET_DATA_TYPE(x->type) | CCV_GET_CHANNEL(x->type);
}
sig = ccv_matrix_generate_signature((const char*)&prefer_type, sizeof(int), sig, 0);
if (sig != 0)
sig = ccv_matrix_generate_signature((const char*)&prefer_type, sizeof(int), sig, 0);
if (x == 0)
{
x = ccv_dense_matrix_new(rows, cols, prefer_type, 0, sig);
Expand Down
Loading

0 comments on commit de220a1

Please sign in to comment.