[comp.ai] IEEE ASSP April 1987 on Neural Networks

del@homxc.UUCP (09/26/87)

I found the article very interesting and decided to code the hamming
classification neural network. I thought the comp.ai would be
interested. I think I found a bug in the article's description of the
routine (see code).

It should be portable to any C compiler.
_______________________cut here______________________
/* ham.c
 * c version of the hamming net
 * david leasure
 * 9/25/87
 *
 * this routine is a hamming classification network
 * described in IEEE ASSP April 1987 by Richard P. Lippmann pg. 9
 * correcting for a presumed bug in the presented routine
 * the bug is the value set for THETA by Lippmann. When THETA is
 * N / 2 it so overwhelms the outputs from the lower net that only 0
 * activation values are passed up from the threshold function.
 * I have chosen to set epsilon to 1 / 2M and to not have an upper
 * limit on the threshold function so no saturation occurs
 *
 * the program is somewhat inefficient because of the use of
 * data storage for maxnet (t[k,l] in lippman's) and for output[t,M]
 * but they could be useful in a simulator of this network which allowed
 * things to be fiddled with.
 * the code could be improved by not encoding the size and values
 * of the node matrices directly, too, reading them instead from files
 * and/or a user interface.
 *
 * if you improve the code, please send me the diff's
 * david e. leasure
 * ihnp4!homxc!del or del@homxc.att.com
 */

/* EMACS_MODES: tabstop=4 c */

#include <stdio.h>
#include <ctype.h>

/* number of bits per exemplar (7x5) */
#define N 35

/*number of exemplars */
#define M 10

/* presentation (r,c) */
#define rows 7
#define cols 5

/* define maximum number of iterations before convergence */
#define MAX_ITERATION 20

/* define the exemplary training data */
/* should be replaced later with a read routine */

static int exemplars[M][N] = {
/* 0 */
-1,1,1,1,-1,
1,-1,-1,-1,1,
1,-1,-1,-1,1,
1,-1,-1,-1,1,
1,-1,-1,-1,1,
1,-1,-1,-1,1,
-1,1,1,1,-1,
/* 1 */
-1,-1,-1,-1,1,
-1,-1,-1,1,1,
-1,-1,-1,-1,1,
-1,-1,-1,-1,1,
-1,-1,-1,-1,1,
-1,-1,-1,-1,1,
-1,-1,-1,-1,1,
/* 2 */
-1,1,1,1,-1,
1,-1,-1,-1,1,
-1,-1,-1,-1,1,
-1,-1,-1,1,-1,
-1,-1,1,-1,-1,
-1,1,-1,-1,-1,
1,1,1,1,1,
/* 3 */
1,1,1,1,1,
-1,-1,-1,1,-1,
-1,-1,1,-1,-1,
-1,1,1,1,-1,
-1,-1,-1,-1,1,
1,-1,-1,-1,1,
-1,1,1,1,-1,
/* 4 */
-1,-1,-1,1,-1,
-1,-1,1,1,-1,
-1,1,-1,1,-1,
1,-1,-1,1,-1,
1,1,1,1,1,
-1,-1,-1,1,-1,
-1,-1,-1,1,-1,
/* 5 */
1,1,1,1,1,
1,-1,-1,-1,-1,
1,1,1,1,-1,
-1,-1,-1,-1,1,
-1,-1,-1,-1,1,
1,-1,-1,-1,1,
-1,1,1,1,-1,
/* 6 */
-1,-1,1,1,-1,
-1,1,-1,-1,-1,
1,-1,-1,-1,-1,
1,1,1,1,-1,
1,-1,-1,-1,1,
1,-1,-1,-1,1,
-1,1,1,1,-1,
/* 7 */
1,1,1,1,1,
-1,-1,-1,-1,1,
-1,-1,-1,1,-1,
-1,-1,-1,1,-1,
-1,-1,1,-1,-1,
-1,-1,1,-1,-1,
-1,-1,1,-1,-1,
/* 8 */
-1,1,1,1,-1,
1,-1,-1,-1,1,
1,-1,-1,-1,1,
-1,1,1,1,-1,
1,-1,-1,-1,1,
1,-1,-1,-1,1,
-1,1,1,1,-1,
/* 9 */
-1,1,1,1,-1,
1,-1,-1,-1,1,
1,-1,-1,-1,1,
-1,1,1,1,1,
-1,-1,-1,-1,1,
-1,-1,-1,1,-1,
-1,1,1,-1,-1};

static float w[N][M];           /* weights of lower subnet */
static float maxnet[M][M];      /* weights of maxnet */
/* input pattern */
static int x[N] =
	{/* altered 5 with 4 flipped bits */
	1,1,1,1,-1,
	1,-1,-1,-1,-1,
	-1,1,1,1,-1,
	-1,-1,-1,-1,1,
	-1,1,-1,-1,1,
	1,-1,-1,-1,1,
	-1,1,1,-1,-1};

/* input vector */
static output[MAX_ITERATION][M]; /* output at time t matrix */

#define THETA  0.0 /* N / 2.0 */
#define EPSILON 1.0 / (2.0 * M)

/* INIT_LOWER 
 * initialize the weight matrix for the lower network
 */
int init_lower()
{
	int i, j;

	for (i=0; i<N; i++) {
		for (j=0; j<M; j++) {
			w[i][j] = exemplars[j][i]/2.0;
		}
	}
}

/* INIT_UPPER
 * init the weight matrix for the upper maxnet
 */
int init_upper()
{
	int k, l;

	for (k=0; k<M; k++) {
		for (l=0; l<M; l++) {
			if (k==l)
				maxnet[k][l] = 1.0;
			else
				maxnet[k][l] =  -1.0 / 20.0;
		}
	}
}


/* INIT_SUM 
 * the code to perform the summation of the weight/input value products
 * for each output, i.e. (sum(i=0..N-1) w[i][j]*x[i]) - THETA
*/
float init_sum(j)
	int j;
{
	int i;
	float sum;

	sum = 0;
	for (i=0; i<N; i++) {
		sum = sum + (w[i][j] * x[i]);
	}
	return(sum - THETA);
}

/* CONVERGE_SUM(J,T)
 * perform the sum for the maxnet output calculation
 * i.e., output[j](t) - epsilon * sum(k<>j where j,k=0..M)output[k](t)
 */
float converge_sum(j,t)
	int j,t;
{
	int k, sum;

	sum = 0;
	for (k=0; k<M; k++)
		if (k != j)     sum = sum + output[t][k];
	sum = output[t][j] - EPSILON * sum;
	return(sum);
}

/* F_THRESH(ALPHA)
 * implement a simple threshold logic nonlinearity
 * I have chosen not to give it a saturation cutoff
 */
float f_thresh(alpha)
	float alpha;
{
	if (alpha <= 0.0)
		return(0.0);
	else
		return(alpha);
}




/* INIT_UNKNOWN()
 * apply the input to the lower net and derive state 0 of the maxnet
 */
int init_unknown()
{
	int j;

	for (j=0; j<M; j++) {
		output[0][j] = f_thresh(init_sum(j));
	}
}

/* CONVERGE()
 * perform up to MAX_ITERATIONs of the convergence function
 * answer found when only one of the maxnet outputs is high
 * that output indexes the exemplars for the correct pattern
 */
int converge()
{
	int t, count, j, winner;

	count = 2; /* prime the pump */
	winner = -1; /* start with "no winner" */

	for (t=1; t<MAX_ITERATION && count>1; t++) {
		count = 0;
		for (j=0; j<M; j++) {
			if ((output[t][j] = f_thresh(converge_sum(j,t - 1))) > 0) {
				winner = j;
				count++;
			}
		}
	}
	if (count != 1)
		winner = -1; /* error condition not supposed to occur */
	return(winner);
}

/* SHOW_EXEMPLAR(EX)
 * print the exemplar(ex) using .'s for -1 and *'s for +1
 * break the lines so the pattern is correctly seen
 */
int show_exemplar(ex)
	int ex[];
{
	int c, i;

	c = 0;
	for (i=0; i<N; i++) {
		if (ex[i] < 0) {
			printf(".");
		}
		else {
			printf("*");
		}
		if (++c == cols) {
			printf("\n");
			c = 0;
		}
	}
	printf("\n");
}

/* SHOW_EXEMPLARS()
 * show all the exemplars
 */
int show_exemplars()
{
	int j;


	for (j=0; j<M; j++) {
		printf("Exemplar %d:\n",j);
		show_exemplar(&exemplars[j][0]);
	}
	printf("\n");
}


main()
{
	int winner;

	printf("Hamming Neural Net Example\n\n");

	/*
	show_exemplars(); 
	*/

	init_lower();	
	init_upper();   
	init_unknown();
	winner = converge();
	if (winner >= 0) {
		printf("The winner is %d.\n", winner);
		printf("\nInput pattern:\n");
		show_exemplar(&x[0]);
		printf("\n\nExemplar:\n");
		show_exemplar(&exemplars[winner][0]);
		printf("\n");
	}
	else { /* according to lippmann, this should never happen */
		printf("Something's wrong. No winner.\n");
	}
	exit(0);
}
-- 
David E. Leasure - AT&T Bell Laboratories - (201) 615-5307