home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
vis-ftp.cs.umass.edu
/
vis-ftp.cs.umass.edu.tar
/
vis-ftp.cs.umass.edu
/
pub
/
Software
/
ASCENDER
/
umass_foa.tar
/
mdt_NEW
/
mdtree
/
mdtree.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-01-27
|
16KB
|
590 lines
/* =============================================================
mdtree: Creates a multivatraite decision tree from the training
data in a feature file. The decision tree is then
converted to a lookup table, to be later used for
classification in the focus-of-attention routine.
Usage is as follows:
mdtree feature_file(input) lookup_table_file(output)
'feature_file' is the training data gathered by use of the
'mdtrain' routine.
Shashi Buluswar
Computer Vision Laboratory
Dept of Computer Science
University of Massachusetts
Amherst, MA 01003
Copyright 1995, University of Massachusetts - Amherst
=============================================================== */
#define MAIN
#include "mdtree.h"
/* inner_product returns the inner product of to vectors */
double inner_product (v1, v2)
LTU_vect v1, v2;
{
int i;
double x=0.0;
for (i=0; i<num_feat; i++) x = x + v1[i] * v2[i];
return x;
}
/* -----------------------------------------------------------------
Linear Threshold Unit (LTU) is a respresentation of the
Multivariate test. It is a binary test of the form
Transpose(inst)*wt >= 0, where inst is an instance description
(a pattern vector), consisting of a constant 1 and the n
features and wt is a vector of n+1 coefficients (weights).
if Transpose(inst)*wt >= 0 then the LTU infers that inst belongs
to class 1; otherwise inst belongs to class2.
----------------------------------------------------------------- */
int LTU (inst, wt)
LTU_vect inst, wt;
{
double lin_comb = 0.0;
lin_comb = inner_product (inst, wt);
if (lin_comb < 0) return 0;
else return 1;
}
/* -----------------------------------------------------------------
Xk: instance array
Wk_1: previous weight array
Wk: current weight array -- to be determined by RLS_train
Pk: covariance matrix
Pk_1: previous covariance matrix
----------------------------------------------------------------- */
void RLS_train (Xk, Wk_1, Wk, Yk)
LTU_vect Xk, Wk_1, Wk;
int Yk;
{
LTU_vect_sqr Pk, Pk_1;
LTU_vect Pk_1Xk, XkTPk_1, tmp_vect;
int i, j;
double scalar_value, sum_of_products;
if (loop == 1) {
/* initialize diagonal of covariance matrix */
for (i=0; i< num_feat; i++)
for (j=0; j< num_feat; j++)
if (i==j) Pk_1[i][j] = large_num;
else Pk_1[i][j] = 0.0;
}
/* RLS equations:
Pk = Pk_1 - Pk_1Xk [1 + XkTPk_1 * Xk] ^-1 XkTPk_1
Kk = PkXk
Wk = Wk_1 - Kk (XkTWk - Yk) */
/* Update Pk -- this is the first part of the RLS equation */
/* Multiply Pk_1 (the array p at time k-1) by Xk (X at time k) */
for (i=0; i<num_feat; i++) {
Pk_1Xk [i] = 0.0;
for (j=0; j<num_feat; j++)
Pk_1Xk [i] += Pk_1[i][j] * Xk[j];
}
/* Calculate the scalar value [1 + XkT_Pk_1Xk] ^ -1 */
scalar_value = 1.0;
for (i=0; i<num_feat; i++)
scalar_value += Pk_1Xk[i] * Xk[i];
scalar_value = 1.0/scalar_value;
/* Fold scalar_value into Pk_1Xk */
for (i=0; i<num_feat; i++) Pk_1Xk[i] *= scalar_value;
/* Multiply XkT (Xk transposed) by Pk_1 */
for (i=0; i<num_feat; i++)
{
XkTPk_1[i] = 0;
for (j=0; j<num_feat; j++)
XkTPk_1 [i] += Xk[j] * Pk_1[j][i];
}
/* Multiply Pk_1Xk by XkTPk_1 */
for (i=0; i<num_feat; i++)
for (j=0; j<num_feat; j++)
Pk[i][j] = Pk_1Xk[i] * XkTPk_1[j];
for (i=0; i<num_feat; i++)
for (j=0; j<num_feat; j++)
Pk[i][j] = Pk_1[i][j] - Pk[i][j];
/* second part of RLS equation */
/* Multiply XkT (Xktransposed) by Wk_1. The result is a
scalar_value. Subtract Yk. */
scalar_value = 0.0 - Yk;
for (i=0; i<num_feat; i++) scalar_value += Xk[i] * Wk_1[i];
/* Multiply Pk by Xk (= Kk) */
for (i=0; i<num_feat; i++) {
sum_of_products = 0.0;
for (j=0; j<num_feat; j++) {
sum_of_products += Pk[i][j] * Xk[j];
}
tmp_vect[i] = sum_of_products * scalar_value;
}
for (i=0; i<num_feat; i++) Wk[i] = Wk_1[i] - tmp_vect[i];
}
/* converged determines if the weight-training has converged, */
/* - returns 1 if converged */
/* - 0 otherwise */
/* note: convergence is tested by (estimate == actual +- fudge_factor */
int converged (vp, vc)
LTU_vect vp, vc;
{
int i, x=1;
double diff1, diff2;
for (i=0; i<num_feat; i++) {
diff1 = vc[i]-vp[i];
diff2 = vp[i]-vc[i];
if (diff1 > diff2) {
if (diff1 > small_num) x=0;
}
else
if (diff2 > small_num) x=0;
}
return x;
}
/* homogenous determines if a given set is homogeneous according to */
/* the known classification of the training instances */
int homogenous (set, size, class)
struct instance *set;
int size, *class;
{
int i=0, x=1;
*class = set[0].known_class;
for (i=0; i<size; i++)
if (!(set[i].known_class == *class)) {
x=0;
}
return x;
}
/* divide_set divides a given set according to the LTU-decided classification,
and creates two subsets */
void divide_set (super, size_super, sub0, size_sub0, sub1, size_sub1)
struct instance *super, *sub0, *sub1;
int size_super, *size_sub0, *size_sub1;
{
int i;
*size_sub0=0; *size_sub1=0;
for (i=0; i<size_super; i++) {
if (super[i].LTU_class == 0) {
sub0[*size_sub0] = super[i];
(*size_sub0)++;
}
else {
sub1[*size_sub1] = super[i];
(*size_sub1)++;
}
}
}
/* traverse-tree traverses any given binary tree in preorder */
void traverse_tree (tree_ptr)
struct tree_node *tree_ptr;
{
int i;
printf ("%d: ", tot_count);
for (i=0; i<num_feat; i++) printf ("%f, ", tree_ptr->weight_vect[i]);
printf ("class: %d\n", tree_ptr->node_class);
printf (" %d\n", tree_ptr->node_class);
tot_count++;
if (tree_ptr->neg != NULL) {
printf ("Negative: 0\n");
traverse_tree (tree_ptr->neg);
}
printf ("done with negative...\n");
if (tree_ptr->pos != NULL) {
printf ("Positive: 1\n");
traverse_tree (tree_ptr->pos);
}
printf ("done with positive...\n");
}
/* build_tree builds the decision tree recusively */
void build_tree (inst_set, set_size, tree_ptr)
struct instance *inst_set; /* the set of training instances */
int set_size; /* number of training instances */
struct tree_node *tree_ptr;
{
struct instance *sub0,
*sub1; /* subsets according to 0/1 class */
int size_sub0, size_sub1; /* size of sub_sets classified as 0 or 1 */
int class=0; /* classification 0/1 */
int i, j, k, x; /* temporary loop variables */
int conv=0; /* flag for convergence */
LTU_vect learned_weight_vec; /* learned weight vector after RLS-training */
LTU_vect prev_weight_vec; /* previos weight vector for RLS updating */
float tmp_float; /* tmp float for random # */
int num_zero, num_one;
/* -------------------------------------------------------------------------
find out if the set is homogenous according to known_class
if (set is homogenous), or (num_instances < 2*num_features) then do nothing
else (i.e. if the set is not homogenous then):
reset the covariance matrix (to large_num diagonal)
for each instance in the set
RLS_train the weight_vector (using the same covariance matrix)
LTU_classify the instances according to the learned weight vector
divide the set into two subsets according to the LTU_classification
call build_tree on each of the sub_sets
------------------------------------------------------------------------- */
x = homogenous (inst_set, set_size, &class); /* determine if set is homogenous */
if ((x == 1) || (set_size < min_set_size)) { /* if so, then do nothing */
tree_ptr->node_class = class;
}
else { /* if not, then ... */
printf ("set size: %d\n", set_size);
loop = 1; /* flag for resetting cov matrix */
/* init weight to random number */
for (k=0; k<num_feat; k++) {
tmp_float = random ();
prev_weight_vec[k] = tmp_float;
}
for (i=0; i<set_size; i++) { /* train for each instance */
conv=0;
while (conv == 0) {
RLS_train (inst_set[i].feat, prev_weight_vec, learned_weight_vec,
inst_set[i].known_class);
conv = converged (prev_weight_vec, learned_weight_vec);
loop ++; /* flag for *not* resetting cov mat */
for (k=0; k<num_feat; k++) prev_weight_vec[k] = learned_weight_vec[k];
/* pass on learned vector to next update */
}
}
tree_ptr->node_class = non_class;
for (i=0; i<num_feat; i++) (tree_ptr->weight_vect)[i] = learned_weight_vec[i];
for (i=0; i<set_size; i++) { /* classify each instance according to LTU */
inst_set[i].LTU_class = LTU (inst_set[i].feat, learned_weight_vec);
}
if ((sub0 = (struct instance *) malloc (set_size * sizeof (struct instance))) == NULL)
printf ("out of memory...\n");
if ((sub1 = (struct instance *) malloc (set_size * sizeof (struct instance))) == NULL)
printf ("out of memory...\n");
divide_set (inst_set, set_size, sub0, &size_sub0, sub1, &size_sub1);
if ((set_size==size_sub0) || (set_size==size_sub1)) {
num_zero=0; num_one=0;
for (j=0; j<set_size; j++){
if (inst_set[j].known_class==0) num_zero++;
else num_one++;
}
if (num_one > (num_zero/t_f_ratio)) tree_ptr->node_class = 1;
else tree_ptr->node_class = 0;
printf ("non-partitionable: 0=%d, 1=%d: %d\n", num_zero, num_one, tree_ptr->node_class);
}
else {
tree_ptr->pos = malloc (sizeof (struct tree_node));
tree_ptr->neg = malloc (sizeof (struct tree_node));
/* make sure the pointers in th struct is assigned NULL */
tree_ptr->pos->pos = NULL;
tree_ptr->pos->neg = NULL;
tree_ptr->neg->pos = NULL;
tree_ptr->neg->neg = NULL;
tree_ptr->pos->node_class = non_class;
for (i=0; i<num_feat; i++) tree_ptr->pos->weight_vect[i] = 0.0;
tree_ptr->neg->node_class = non_class;
for (i=0; i<num_feat; i++) tree_ptr->neg->weight_vect[i] = 0.0;
build_tree (sub0, size_sub0, tree_ptr->neg);
build_tree (sub1, size_sub1, tree_ptr->pos);
}
}
}
/* classify a given actual instance, given the instance's feature values,
and the decision-tree */
void classify (tree_ptr, inst_vect)
struct tree_node *tree_ptr;
LTU_vect inst_vect;
{
int x;
if (tree_ptr->node_class == non_class) {
x = LTU (inst_vect, tree_ptr->weight_vect);
if (x==1) {
classify (tree_ptr->pos, inst_vect);
}
else {
classify (tree_ptr->neg, inst_vect);
}
}
else {
LUT_ret_class = (tree_ptr->node_class);
/*return (tmpClass);*/
}
}
/* read data from input ascii file */
void read_actual_infile (file_name, size, data_array, idx)
char *file_name;
int size, idx;
short int data_array [num_feat][num_actual];
{
FILE *file_ptr;
int i=0, x;
double y;
printf ("%s %d\n", file_name, size);
if ((file_ptr = fopen (file_name, "r")) == NULL)
printf ("fopen error...\n");
else {
while ( (!feof (file_ptr)) && (i<size) ) {
fscanf (file_ptr, "%d", &x);
if (!feof(file_ptr)) {
y = x;
data_array [idx][i] = x;
i++;
}
}
}
printf ("# words: %d\n", i);
}
/*********************************************************************
* Count_instances(filename) *
* Counts the number of lines in filename *
*********************************************************************/
int count_instances(fname)
char *fname;
{
int count = 0;
char *dummy_string;
FILE *fp;
dummy_string = malloc(sizeof(char) * num_feat * 4);
if ((fp = fopen(fname,"r")) == NULL) {
fprintf(stderr, "Unable to open %s\n", fname);
return(-1);
}
while (fgets(dummy_string, (num_feat * 4), fp) != NULL)
count++;
free((void *) dummy_string);
fclose(fp);
return(count);
}
int bin2dec (bit_arr)
char bit_arr[CHAR_SIZE];
{
int dec_num, i;
dec_num=0;
for (i=(CHAR_SIZE-1); i>=0; i--) {
if (bit_arr[i] == '1') {
dec_num+= (pow(2,((CHAR_SIZE-1)-i)));
}
}
return(dec_num);
}
/*---------------------------------------------------------
Go through every combination of RGB (from RGB_min to RGB_max),
and classify the pixel at that value -- then store the
classification in the LUT. Finally, write the LUT out
to a file
------------------------------------------------------------*/
void write_LUT_to_file (tree_ptr, file_name)
struct tree_node *tree_ptr;
char *file_name;
{
int iR, iG, iB, bit_count=0;
FILE *LUT_file_ptr;
int ASCII_dec; /* decimal for ASCII char represented by 8 bits */
unsigned char ASCII_char; /* ASCII char represented by 8 bits */
double v[num_feat];
char tmp_c[1], bit_arr[CHAR_SIZE];
if ((LUT_file_ptr = fopen (file_name, "wb")) == NULL) {
printf ("fopen error...\n");
exit(-1);
}
else {
for (iR=RGB_min; iR<RGB_max; iR++) { /* for each RGB pixel */
for (iG=RGB_min; iG<RGB_max; iG++) {
for (iB=RGB_min; iB<RGB_max; iB++) {
v[0]=1.0; /* assign instance vector */
v[1]=iR;
v[2]=iG;
v[3]=iB;
classify (tree_ptr, v); /* classify the vector as 1 or 0 */
sprintf (tmp_c, "%d", LUT_ret_class); /* convert a string of 8 bits */
bit_arr[bit_count]=tmp_c[0]; /* to a char */
bit_count++;
if ((bit_count%(CHAR_SIZE))==0) {
bit_count=0;
ASCII_dec = bin2dec(bit_arr);
ASCII_char = (unsigned char) ASCII_dec;
fprintf (LUT_file_ptr, "%c", ASCII_char);
}
/*fprintf (LUT_file_ptr, "%c", tmp_c[0]);*/
}
}
}
}
fclose (LUT_file_ptr);
}
void main (argc, argv)
int argc;
char *argv[];
{
int num_instances;
int i, j, temp;
struct instance *inst;
struct tree_node *tree_ptr;
FILE *input;
if (argc != 3) {
fprintf(stdout, "\nusage: mdt feature_file LUT_file\n");
exit (-1);
}
num_instances = count_instances(argv[1]);
if (num_instances == -1) {
fprintf(stderr, "\naborting training\n");
exit (-1);
}
inst = malloc(sizeof(struct instance) * num_instances);
if (inst == NULL) {
fprintf(stderr, "\nunable to allocate memory for %d instances\n", num_instances);
exit (-1);
}
input = fopen(argv[1],"r");
if (input == NULL) {
fprintf(stderr, "\nunable to open %s (second time)\n", argv[1]);
exit (-1);
}
for (i = 0; i < num_instances; i++) {
inst[i].feat[0] = 1;
if (fscanf(input, "%d", &temp) == EOF) {
fprintf(stderr, "\nNot enough instances?!\n");
exit (-1);
}
inst[i].known_class = temp;
for (j = 1; j < num_feat; j++) {
if (fscanf(input, "%d", &temp) == EOF) {
fprintf(stderr, "\nRan out of data?!\n");
exit (-1);
}
inst[i].feat[j] = temp;
}
}
printf ("building tree...\n");
tree_ptr = malloc (sizeof (struct tree_node)); /* build decision tree */
/* Make sure the pointers in the node are initialzed */
tree_ptr->pos = NULL;
tree_ptr->neg = NULL;
build_tree (inst, num_instances, tree_ptr);
printf ("\n\ndecision tree:\n\n"); /* print the decision tree */
traverse_tree (tree_ptr);
/* clasify each RGB combination and store in LUT;
write LUT to file LUT_file */
printf ("building LUT... %s\n", argv[2]);
write_LUT_to_file (tree_ptr, argv[2]) ;
printf ("done building LUT...\n");
}