Newsgroups: comp.ai.neural-nets
Path: cantaloupe.srv.cs.cmu.edu!rochester!udel!delmarva.com!news.internetMCI.com!newsfeed.internetmci.com!btnet!demon!peer-news.britain.eu.net!newsfeed.ed.ac.uk!dcs.ed.ac.uk!cnews
From: Ian Clarke <iic@dcs.ed.ac.uk>
Subject: Re: Programming a Neural Net
X-Nntp-Posting-Host: jura.dcs.ed.ac.uk
Content-Type: text/plain; charset=us-ascii
To: carrign@syd.au.swissbank.com
Message-ID: <30BF1DE5.1383@dcs.ed.ac.uk>
Sender: cnews@dcs.ed.ac.uk (UseNet News Admin)
Content-Transfer-Encoding: 7bit
Organization: Department of Computer Science, Edinburgh University
References: <1995Nov27.042430.21294@il.us.swissbank.com>
Mime-Version: 1.0
Date: Fri, 1 Dec 1995 15:23:17 GMT
X-Mailer: Mozilla 2.0b1J (X11; I; SunOS 5.4 sun4m)
Lines: 381

Here is a file which you can include into any program which allows you to
create and train a neural network.  Following it is a very simple program
which #includes the first one.  Neither are very portable, they will work
under Lattice C V5, but you should be able to fix them with some work.

cnntk1.c now follows...

/*
  The C Neural Network Toolkit - Include File
  (c) 1993,1994 Ian Clarke
  See 'legal.doc' in 'documnts.fld' folder for legal information
*/
#define train teach

/* NOTE: If your system does not have drand48(), simply replace it with
any
 function which returns a random number between 0 and 1 */

struct node
{
 float error,input,output,correct_output,threshold,change_in_threshold;
 short type;
};

const signed short input=-1;
const signed short hidden=0;
const signed short output=1;

struct connection
{
 short start,end;
 float weight,change_in_weight;
};


/* Procedure prototypes */

void run_net(struct node *nodes,struct connection *conns,int n,int c);
float af(float value);
void reset_net(struct node *nodes,struct connection *conns,int n,int c);
void teach_net(struct node *nodes,struct connection *conns,int n,int c
               ,float learning_rate);
float derror(float,float);
void scramble_net(struct node *nodes,struct connection *conns,int n,int
c);
void make_changes(struct node *nodes,struct connection *conns,int n,int
c);
/* This procedure causes the energy to flow from the bottom of
   the net to the top*/
   
void run_net(struct node nodes[],struct connection conns[],int n,int c)
{
 int x;

 for (x=0;x<n;x++)
 {
  nodes[x].input=0;
 };

 for (x=0;x<c;x++)
 {
  if
((nodes[conns[x].start].output==0)&(nodes[conns[x].start].type!=input))
  {
   nodes[conns[x].start].output=af(nodes[conns[x].start].input+nodes[conns[x].start].threshold);
  };
  nodes[conns[x].end].input+=nodes[conns[x].start].output*conns[x].weight;
  nodes[conns[x].end].output=0;
 };
 for(x=n-1;nodes[x].type==output;x--)
 {
  nodes[x].output=af(nodes[x].input+nodes[x].threshold);
 };
} 

/* This is the function used to determine the response of a node to
input*/

float af(float input)
{
 float output;
 output=(float) (1/(1+exp(-input)));
 return output;
}

/* Reset 'change_in_weight' and 'change_in_threshold' */

void reset_net(struct node nodes[],struct connection conns[],int n,int c)
{
 int counter;
 for (counter=0;counter<n;counter++)
 {
  nodes[counter].change_in_threshold=0;
 };
 for (counter=0;counter<=c-1;counter++)
 {
  conns[counter].change_in_weight=0;
 };
}

/* Teach net */

void teach_net(struct node nodes[],struct connection conns[],int n,int
c,float lr)
{
 int x;
 for(x=0;x<n;x++)
 {
  nodes[x].error=0;
 };
 for(x=c-1;x>-1;x--)
 {
  if (nodes[conns[x].end].type==output)
  {
   nodes[conns[x].end].error=nodes[conns[x].end].correct_output-
   nodes[conns[x].end].output;
  };
  nodes[conns[x].start].error+=conns[x].weight*
  derror(nodes[conns[x].end].error,nodes[conns[x].start].output);
 };
 for(x=0;x<c;x++)
 {
  conns[x].change_in_weight+=lr*nodes[conns[x].start].output*
  derror(nodes[conns[x].end].error,nodes[conns[x].end].output);
 };
 for(x=0;x<n;x++)
 {
  nodes[x].change_in_threshold+=derror(nodes[x].error,nodes[x].output);
 };
}

float derror(float error,float output)
{
 float otpt;
 otpt=error*output*(1-output);
 return otpt;
}

void make_changes(struct node nodes[],struct connection conns[],int n,int
c)
{
 int x;
 for(x=0;x<n;x++)
 {
  nodes[x].threshold+=nodes[x].change_in_threshold;
 };
 for(x=0;x<c;x++)
 {
  conns[x].weight+=conns[x].change_in_weight;
 };
}

void scramble_net(struct node nodes[],struct connection conns[],int n,int
c)
{
 int p;
 for(p=0;p<n;p++)
 {
  nodes[p].change_in_threshold=0;
  nodes[p].threshold=((int) drand48()*4)-2;
 };
 for(p=0;p<c;p++)
 {
  conns[p].change_in_weight=0;
  conns[p].weight=((int) drand48()*4)-2;
 };
}

...end

shapenet.c now follows...

#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include "cnntk1.c"

struct node nodes[12];
struct connection conns[27];

struct datastruct
{
 int shape;
 int size;
 int filled;
 int result;
} data[18];

int datas;

void main(void)
{
 /* Set up connections between nodes */
 
 int x,y,z=0,selection;
 for (x=0;x<8;x++)
 {
  for (y=8;y<11;y++)
  {
   conns[z].start=x;
   conns[z].end=y;
   z++;
  };
 };
 for (x=9;x<11;x++)
 {
  conns[z].start=x;
  conns[z].end=11;
 };
 
 /* Set up types of nodes */

 for (x=0;x<8;x++) nodes[x].type=input;
 for (x=8;x<11;x++) nodes[x].type=hidden;
 nodes[11].type=output;

 /* Set connection weights and node thresholds to arbitary values */

 scramble_net(nodes,conns,12,27);

 /* Display main menu */
 
 do
 {
  printf("   \033E"); /* Clear Screen */
  printf("   >>>Catagorisor - (c) 1993 Ian Clarke\n   Demonstration
of\n");
  printf("   The C Neural Network Toolkit - By Ian Clarke\n\n");
  printf("   1:Reset net\n");
  printf("   2:Create input data\n");
  printf("   3:Commence net training\n");
  printf("   4:Test net\n"); 
  printf("   5:Quit\n>>");
  selection=getchar();
  printf("   \033E");
  switch (selection)
  {
   case '1' : resetnet();break;
   case '2' : createdata();break;
   case '3' : trainnet();break;
   case '4' : testnet();break;
  };
 }
 while (selection!='5');
}

void resetnet(void)
{
 scramble_net(nodes,conns,12,27);
}

void createdata(void)
{
 int x;
 do
 {
  printf("   How many items of information are you going to give
me(Max:18)?\n>>");
  scanf("%d",&datas);
 } while((datas>18)||(datas<1));
 for (x=0;x<datas;x++)
 {
  printf("   \033EShape #%d\n",x+1);
  do
  {
   printf("   Please enter shape type:\n(1:Square 2:Triangle
3:Circle)>>");
   scanf("%d",&data[x].shape);
  } while ((data[x].shape>3)||(data[x].shape<1));
  do
  {
   printf("   Please enter size:\n(1:Small 2:Medium 3:Large)>>");
   scanf("%d",&data[x].size);
  } while ((data[x].size>3)||(data[x].size<1));
  do
  {
   printf("   Please enter whether filled or not:\n(1:Filled
2:Unfilled)>>");
   scanf("%d",&data[x].filled);
  } while ((data[x].filled>2)||(data[x].filled<1));
  do
  {
   printf("   Catagory A:1 or B:0?:\n(1:yes 0:No)>>");
   scanf("%d",&data[x].result);
  } while ((data[x].result>1)||(data[x].result<0));
 };
}
  
void trainnet(void)
{
 int x,y,counter=0;
 float error=0,previous_error,lr;
 lr=0.2;
 do
 {
  counter++;
  previous_error=error;
  error=0;
  for (x=0;(x<datas)&&kbhit()==0;x++)
  {
   for (y=0;y<8;y++)
   {
    if ((data[x].shape-1==y)||(data[x].size+2==y)||(data[x].filled+6==y))
    {
     nodes[y].output=1;
    }
    else
    {
     nodes[y].output=0;
    };
   };
   nodes[11].correct_output=(float) data[x].result;
   run_net(nodes,conns,12,27);
   teach_net(nodes,conns,12,27,lr);
   error+=fabs(nodes[11].output-nodes[11].correct_output);
  };
  make_changes(nodes,conns,12,27);
  reset_net(nodes,conns,12,27);
 if (previous_error>=error)
 {
  lr*=1.01;
 }
 else
 {
  lr*=0.9;
 }; 
 if (lr<0.0001)
 {
  lr=0.1;
 };
 printf("   Counter:%d  Error:%f LR:%f\n",counter,error/datas,lr);
 }
 while (kbhit()==0);
 printf("   Finished");
 lr=getchar();
} 

void testnet(void)
{
 int y;
 struct datastruct data;
 do
 {
  printf("   Please enter shape type:\n(1:Square 2:Triangle
3:Circle)>>");
  scanf("%d",&data.shape);
 } while ((data.shape>3)||(data.shape<1));
 do
 {
  printf("   Please enter size:\n(1:Small 2:Medium 3:Large)>>");
  scanf("%d",&data.size);
 } while ((data.size>3)||(data.size<1));
 do
 {
  printf("   Please enter whether filled or not:\n(1:Filled
2:Unfilled)>>");
  scanf("%d",&data.filled);
 } while ((data.filled>2)||(data.filled<1));
 for (y=0;y<8;y++)
 {
  if ((data.shape-1==y)||(data.size+2==y)||(data.filled+6==y))
  {
   nodes[y].output=1;
  }
  else
  {
   nodes[y].output=0;
  };
 };
 run_net(nodes,conns,12,27);
 printf("   Output is:%f\n",nodes[11].output);
 y=getchar();
}

...end

Good luck...
-- 
|IAN CLARKE        |"Then on the shore / of the wide world I stand|
|                  |alone, and think till love and fame to        |
|I.Clarke@ed.ac.uk |nothingness do sink" - John Keats             |
