|
25 Years of Programming
An open source source for C, C++, OWL, BASIC, MDB, XLS, DOT, and more... |
Home Projects Up Sitemap Search Blog Forum+Chat About Us Privacy Terms of Use Feedback FAQ Images Services Ads Donate Humor |
|
|
The "Visible Neural Network", programs for Microsoft Visual C++ .NET, Borland C/C++, ObjectWindows, and MSDOS (BGI graphics)This is a set of artificial neural network programs. The later versions are multilayer perceptron (MLP) backpropagation neural networks in which the number of layers and nodes are user-selectable.I call this the "Visible Neural Network" project because all the versions have color graphic displays that allow you to watch changes in the states of the network nodes and connections as they "think". There are screenshots below. The programs are intended as learning tools for those interested in working with the source code. They are not currently configured to solve useful problems. I wrote them to get hands-on experience working with neural net code to learn how it works. That evolved into a desire to write a neural net framework that would hopefuly be as simple as possible, straightforward and non-convoluted in its design, heavily commented to make its flow and workings understandable and to document why certain decisions were made, and extensible so it could potentially be adapted to useful applications. I think the latest Visual C++ version is the most understandable neural net framework of the open source ones I've seen online. That doesn't make it the best, and it is undoubtedly not the most powerful or flexible, but it has the most understandable source code to work with of the ones I've looked at. The four versions of the neural net program:By following links from here and in the table below, you can find all the program source code on web pages. For building the projects, the code is also provided in two zip download files. One zip (farther down this page) contains the code for all the Borland versions. A separate zip (follow the link in the next paragraph) has the Microsoft Visual C++ version.
Download all the Borland C/C++ neural network programsDownload neural.zip (about 89 KB) The zip contains all the Borland C++ versions (OWL and MSDOS), but not the Microsoft Visual C++ version. (Its zip file is available on its own project home page.) The zip file contains the code unique to the project, but also required are library files elsewhere on this site. Links to those files are in the web page source code listings that you can get to by following the links in the table below. The projects end up being rather large.
The project notes for these neural net programs are in a file called COMPLEX.DOC. It is available in several formats from the COMPLEX.DOC download page. If you want to review it first, there is a web page showing the Neural Net section of COMPLEX.DOC. If that web page looks like it will be interesting to you, you might want the entire COMPLEX.DOC file. It has discussions of neural nets throughout it. Screenshots:1) Before calculation begins, showing 5 input nodes, 3 hidden layers of 8 nodes each, and 1 output node. Node numbers are color coded by type (Sensory, Processor, Output).
2) During calculation. Connection colors encode levels of (output * connection strength). Nodes in this screenshot are shown as circles. If filled in, the node's net input is > 0; if empty, its input is <= 0. Display can be turned off for greater speed, or set to 2 other useful levels (or a third useless one).
3) This screenshot of the project nodes in the Borland C++ 4.0 IDE might help you set up the project:
If you are looking for a more powerful and flexible neural network program than this one and are knowledgeable enough not to be discouraged by a large assortment of options and settings, the Fast Artificial Neural Network Library (FANN) looks like the one I would choose due to its organization, commenting, and documentation. It is at http://sourceforge.net/. |
/* wneural.cpp WINDOWS target 4-24-2007
This is part of the WNeural project, Version 2.0.
Copyright (C)1995-99, 2007 Steven Whitney.
Initially published by http://25yearsofprogramming.com.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
Version 3 as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
(adapted from wlife2d.cpp)
A multilayer perceptron neural network that you can watch on the screen as it "thinks".
------
TO DO:
messagewindow is still probably best method for status reports,
but could alternatively write text info to aux (open it as a file) for viewing from Terminal.exe,
or use DDE to send status messages to an open MSWord temporary document
the way WAdapt.cpp does. (don't use OutputDebugString: you don't want event log output,
and don't use OpenComm, which is not Win32 portable).
you can en/disable output w/a toggle BOOL. unconditionally call OutputStatus(...),
which only within itself tests the member BOOL for whether to actually output anything.
--------------------
NOTES:
--draws directly to the window to avoid having to wait for Invalidate()
--This probably is a good candidate for Doc/View. The network is the document,
which would maintain its own running status text, to appear in a text view.
The graphic view would show the net, though its continual updating might be slow.
Then you could also have graph views (training times, node activity, or whatever).
FILES:
-- *.TRS Training set data, problems and solutions.
-- *.NET Node connection data for rebuilding a network from disk.
*/
#include <owl\owlpch.h>
#include <owl\chooseco.h>
#include <owl\opensave.h>
#include <owl\radiobut.h>
#include <owl\edit.h>
#include <owl\inputdia.h>
#include <classlib\arrays.h>
#include <math.h>
#pragma hdrstop
#include "c:\bcs\my.h"
#include "c:\bcs\library\stopwatc.h"
#include "c:\bcs\library\filearay.h"
#include "network.h"
#include "msgwind.h"
#include "wneural.rh"
#define IDHELP 998 // redefine a constant from bwcc.h, needed here
static const char AppName[] = "Neural Network";
//////////////////////////////////////////////////////////////////////////////
// SMessageWindow constructor
// derived from TDialog because with a base of TWindow, accelerators were intercepted.
// to keep the edit control the same size as the dialog, could resize it in the dialog's
// EvSize, by directly setting the TEdit's w,h attributes? (yes. see wshowfs.cpp)
// statuswindow.text scrolls, but the display of it doesn't. always top lines displayed.
// use ed->SetSelection()
SMessageWindow::SMessageWindow(TWindow* parent, TResId resid) : TDialog(parent, resid)
{
ed = new TEdit(this,IDC_TRANSEDIT,2001);
isopen = TRUE; // assumes autocreate is used
}
//----------------------------------------------------------------------------
// accept a string, add it to the text for the TEdit text, and redisplay.
// modified from serialco.cpp
// Always append /r/n. You cannot use endl. (for one thing, this isn't a stream)
// #error there is now LFtoCRLF() for the conversion. change wherever useful.
SMessageWindow& SMessageWindow::operator << (const string& s)
{
text += s; // text can be any length, but displayed info cannot,
int length = text.length();
if(length > 2000) // if it's now too long,
text = text.substr(length - 2000); // save only the latest 2000 chars
// #error use ed->SetText() or ed->SetSelection(-1,-1); ed->Insert()
if(isopen)
SetDlgItemText(IDC_TRANSEDIT,text.c_str()); // transfer it to the edit control
return(*this);
}
//----------------------------------------------------------------------------
// Remember the distinction between destroying the interface element and
// destroying the object. As long as the object hasn't been destroyed, nothing
// should get corrupted. << adds text to the string, which shows at the next Create().
void SMessageWindow::Destroy(int retValue)
{
TDialog::Destroy(retValue);
isopen = FALSE;
}
//----------------------------------------------------------------------------
BOOL SMessageWindow::Create()
{
BOOL retval = TDialog::Create(); // can only set text after it's open
if(text.length())
SetDlgItemText(IDC_TRANSEDIT,text.c_str()); // transfer it to the edit control
isopen = TRUE;
return(retval);
}
//----------------------------------------------------------------------------
// end class SMessageWindow
//////////////////////////////////////////////////////////////////////////////
// A window in which a neural net operates, and to which its graphics output is sent.
class SNeuralWindow : public TWindow
{
public:
SNeuralWindow(TWindow* parent = 0);
~SNeuralWindow();
BOOL IdleAction(long idlecount);
protected:
// pointers
NeuralNet* net;
SMessageWindow* statuswindow; // for ongoing status reports
// other variables
Stopwatch sw; // for timing things
long Iterations; // counts calls to net->Run() for training count/timing calculations
int INodes; // User normally wants to reuse these values.
int H1Nodes; // They are the node counts for each layer of the network.
int H2Nodes;
int H3Nodes;
int ONodes;
BOOL autocycle; // a master switch to force IdleAction to do nothing
// normal functions
void erasewindow(); // an immediate substitute for Invalidate()
void drawnodes(TDC& pdc, BOOL showconnect); // display the entire network graphically
void AssignNodeLocs(); // assign each Node its screen location.
// overridden virtuals
BOOL CanClose();
void Paint(TDC&, BOOL, TRect&);
// event handlers
void EvSize(UINT sizeType, TSize& size);
void EvRButtonDown(UINT, TPoint&);
void CmFileStart();
void CmFileExit() { GetApplication()->GetMainWindow()->CloseWindow(); }
void CmNetNew();
void CmNetLoad();
void CmNetSaveAs();
void CmTrainerLoad();
void CmViewPeekLevel();
void CmViewNodeNumbers();
void CmViewMessages();
void CmHelpIndex();
void CmHelpAbout();
DECLARE_RESPONSE_TABLE(SNeuralWindow);
};
DEFINE_RESPONSE_TABLE1(SNeuralWindow, TWindow)
EV_WM_SIZE,
EV_WM_RBUTTONDOWN,
EV_COMMAND(CM_FILESTART,CmFileStart),
EV_COMMAND(CM_FILEEXIT,CmFileExit),
EV_COMMAND(CM_NETNEW,CmNetNew),
EV_COMMAND(CM_NETLOAD,CmNetLoad),
EV_COMMAND(CM_NETSAVEAS,CmNetSaveAs),
EV_COMMAND(CM_TRAINERLOAD,CmTrainerLoad),
EV_COMMAND(CM_VIEWPEEKLEVEL,CmViewPeekLevel),
EV_COMMAND(CM_VIEWNODENUMBERS,CmViewNodeNumbers),
EV_COMMAND(CM_VIEWMESSAGES,CmViewMessages),
EV_COMMAND(CM_HELPINDEX,CmHelpIndex),
EV_COMMAND(CM_HELPABOUT,CmHelpAbout),
END_RESPONSE_TABLE;
//----------------------------------------------------------------------------
// constructor
SNeuralWindow::SNeuralWindow(TWindow* parent) : TWindow(parent)
{
SetBkgndColor(TColor::Black);
// initialize pointers
net = new NeuralNet();
// when minimized, the messagewindow has an empty icon.
statuswindow = new SMessageWindow(this,TResId(MESSAGESWINDOW));
statuswindow->EnableAutoCreate();
// initialize other variables
autocycle = FALSE;
Iterations = 0L;
INodes = 2; // User normally wants to reuse these values.
H1Nodes = 4;
H2Nodes = 0;
H3Nodes = 0;
ONodes = 1;
} //constructor
//----------------------------------------------------------------------------
// destructor
SNeuralWindow::~SNeuralWindow()
{
if(statuswindow)
delete statuswindow;
if(net)
delete net;
} //destructor
//----------------------------------------------------------------------------
void SNeuralWindow::EvSize(UINT /* sizeType */, TSize& /* size */)
{
AssignNodeLocs();
Invalidate(TRUE);
} //EvSize
//----------------------------------------------------------------------------
// Load a training set file.
// this is now redundant. CmTrainerLoad does the same thing.
void SNeuralWindow::CmFileStart()
{
CmTrainerLoad();
//erasewindow(); // #error remove if not needed
} //CmFileStart
//----------------------------------------------------------------------------
// fill the window with black. You frequently don't want to wait for Invalidate to work.
// I think this is no longer used.
void SNeuralWindow::erasewindow()
{
TRect clientrect = GetClientRect(); // current size of the display window
TClientDC dc(*this);
dc.FillRect(TRect(0,0,clientrect.Width(),clientrect.Height()),TBrush(TColor::Black));
} // erasewindow
//----------------------------------------------------------------------------
/* Assign each Node its location on the screen. Call it whenever a new net is created or
loaded or the screen is resized.
*/
void SNeuralWindow::AssignNodeLocs()
{
if(!net || !net->nw.GetItemsInContainer())
return;
int ystart = 16; // the top node is cut in half if it's 0, so what should it be?
int h = GetClientRect().Height() - ystart;
int w = GetClientRect().Width();
int dyin = h / max(net->Count(INPUT), 1); // spacing of nodes down the screen
int dyh1 = h / max(net->Count(HIDDEN,1), 1); // max prevents divide by zero
int dyh2 = h / max(net->Count(HIDDEN,2), 1);
int dyh3 = h / max(net->Count(HIDDEN,3), 1);
int dyout = h / max(net->Count(OUTPUT), 1);
int dxcolumns = (w - 30) / 4; // spacing of columns (by node type) across the screen
int dxfull = 20; // when a single column fills up, next column starts this many pixels to right
// #error not yet implemented.
// The screen display is mostly for small runs. At some point, there are
// too many nodes and you just can't display them well.
int lasttype = -1; // move over to next column when type changes
for(int i = 0 ; i < net->nw.GetItemsInContainer() ; i++)
{
Node* n = net->nw[i];
switch(n->Type)
{
case INPUT:
n->x = 10;
if(n->Type != lasttype)
n->y = ystart; // start at column top
else
n->y = net->nw[i-1]->y + dyin;
break;
case HIDDEN:
n->x = n->HiddenLayer * dxcolumns;
switch(n->HiddenLayer)
{
case 1:
if(n->Type != lasttype)
n->y = ystart; // start at column top
else
n->y = net->nw[i-1]->y + dyh1;
break;
case 2:
if(n->HiddenLayer != net->nw[i-1]->HiddenLayer)
n->y = ystart;
else
n->y = net->nw[i-1]->y + dyh2;
break;
case 3:
if(n->HiddenLayer != net->nw[i-1]->HiddenLayer)
n->y = ystart;
else
n->y = net->nw[i-1]->y + dyh3;
break;
}
break;
case OUTPUT:
n->x = w - 20;
if(n->Type != lasttype)
n->y = ystart; // start at column top
else
n->y = net->nw[i-1]->y + dyout;
break;
}
// This calculation for ->y was reliable, and if enabled replaces all the
// y calculations above. It also creates a more visually varied screen display.
//n->y = random(h);
lasttype = n->Type;
}
} // AssignNodeLocs
//----------------------------------------------------------------------------
// display the entire network graphically
void SNeuralWindow::drawnodes(TDC& dc, BOOL showconnect) // whether to show connections
{ // FALSE if just updating node fills
dc.SetBkColor(TColor::Black);
dc.SetMapMode(MM_TEXT);
TColor color;
int nwcount = net->nw.GetItemsInContainer();
for(int i = 0 ; i < nwcount ; i++)
{
Node* n = net->nw[i];
switch(n->Type) // set color for this node
{
case INPUT: color = TColor::LtRed; break;
case HIDDEN: color = TColor::LtGreen; break;
case OUTPUT: color = TColor::White; break;
}
if(net->shownodenumbers) // display as numbers
{
dc.SetTextColor(color);
dc.TextOut(n->x, n->y, tostring(i).c_str());
}
else // or display as circles. Much slower than using #s.
{
// if inputs positive, fills it in. Pen draws outline, Brush fills interior.
dc.SelectObject(TPen(color));
dc.SelectObject(TBrush((n->input > 0.) ? color : TColor::Black));
dc.Ellipse(n->x - 5, n->y - 5, n->x + 5, n->y + 5);
dc.RestorePen();
dc.RestoreBrush();
}
if(!showconnect)
continue;
// Now draw the connections into this node, colored according to
// (source node's output * the connection weight).
// To do so, it must draw the connections using inlist, so it
// draws the connections coming IN to this node.
int count = n->inlist.GetItemsInContainer();
for(int j = 0 ; j < count ; j++)
{
Node* source = n->inlist[j].from;
double output = source->output;
double weight = n->inlist[j].weight;
double total = output * weight;
/*#error unfinished.
This is the eventual coloration: they need to be scaled somehow
blue(0-255) = - more than 1.0
red(0-255) = - 0 to -1
green(0-255) = + 0 to 1
white(0-255) = + more than 1.0
*/
if(total < -1.0) color = TColor(0,0,255);
else if((total >= -1.0) && (total < 0.0)) color = TColor(255,0,0);
else if((total >= 0.0) && (total <= 1.0)) color = TColor(0,255,0);
else color = TColor(255,255,255);
dc.SelectObject(TPen(color));
dc.MoveTo(n->inlist[j].from->x, n->inlist[j].from->y);
dc.LineTo(n->x, n->y);
dc.RestorePen();
}
} // end for(all nodes in network)
} // drawnodes
//----------------------------------------------------------------------------
// might eventually be useful for something
void SNeuralWindow::EvRButtonDown(UINT modKeys, TPoint& point)
{
TWindow::EvRButtonDown(modKeys,point); // probably does nothing
Invalidate(TRUE); // for now, just force repainting
} //EvRButtonDown
//----------------------------------------------------------------------------
// toggle how to display the nodes (as #s or as dots)
void SNeuralWindow::CmViewNodeNumbers()
{
net->shownodenumbers = !net->shownodenumbers;
CheckMenuItem(GetApplication()->GetMainWindow()->GetMenu(),CM_VIEWNODENUMBERS,
MF_BYCOMMAND | (net->shownodenumbers ? MF_CHECKED : MF_UNCHECKED));
Invalidate(TRUE); // force a total redraw
} //CmViewNodeNumbers
//----------------------------------------------------------------------------
// set how often to redraw graphic node display
void SNeuralWindow::CmViewPeekLevel()
{
char buf[10];
ostrstream(buf,sizeof(buf)) << net->graphicon << ends;
if(TInputDialog(this,"Graphic Node Display Update Frequency",
"Enter 0 (fast) to 3 (slow): ", buf,sizeof(buf)).Execute() == IDOK)
{
int i = atoi(buf);
if((i >= 0) && (i <= 3))
net->graphicon = i;
}
} //CmViewPeekLevel
//----------------------------------------------------------------------------
void SNeuralWindow::CmViewMessages()
{
if(statuswindow->isopen)
statuswindow->Destroy();
else
statuswindow->Create();
CheckMenuItem(GetApplication()->GetMainWindow()->GetMenu(),CM_VIEWMESSAGES,
MF_BYCOMMAND | (statuswindow->isopen ? MF_CHECKED : MF_UNCHECKED));
} //CmViewMessages
//----------------------------------------------------------------------------
void SNeuralWindow::CmHelpIndex()
{
WinHelp("wneural.hlp",HELP_INDEX,0);
}
//----------------------------------------------------------------------------
/* rewire the network to our specifications */
void SNeuralWindow::CmNetNew()
{
char buf[80] = {0};
int i = INodes, j = H1Nodes, k = H2Nodes, l = H3Nodes, m = ONodes;
ostrstream(buf,sizeof(buf)) << INodes << " "
<< H1Nodes << " "
<< H2Nodes << " "
<< H3Nodes << " "
<< ONodes << ends;
if(TInputDialog(this,"Number of Nodes of to Create",
"Enter # of nodes in each layer:\n"
"Input (>0) Hidden1 (>=0) Hidden2 (>=0) Hidden3 (>=0) Output (>0)\n"
"If any hidden layer is 0, all subsequent hidden layers must be 0.",
buf,sizeof(buf)).Execute() == IDOK)
{
istrstream(buf) >> i >> j >> k >> l >> m;
if(net->CreateNetwork(i, j, k, l, m))
{
// User normally wants to reuse these values, so save them now that we know they're legal values.
INodes = i;
H1Nodes = j;
H2Nodes = k;
H3Nodes = l;
ONodes = m;
AssignNodeLocs();
autocycle = TRUE;
Iterations = 0L;
sw.reset(); // because cycling will start with the next IdleAction
sw.start();
}
else
MessageBox("Please review the rules for node counts and try again.",
"Cannot create specified network.",MB_OK);
}
Invalidate(TRUE); // erase the old display if present
} //CmNetNew
//----------------------------------------------------------------------------
// load a previously saved network architecture from disk
void SNeuralWindow::CmNetLoad()
{
// note this static would be shared by all class objects if you allow multiples
static TOpenSaveDialog::TData fd(OFN_FILEMUSTEXIST,
"Networks (*.NET)|*.NET|All Files (*.*)|*.*|",0,"","NET");
if((TFileOpenDialog(this,fd)).Execute() == IDOK)
{
if(net)
{
ifstream(fd.FileName) >> *net; // overwrite the net from the file
AssignNodeLocs();
Iterations = 0L;
autocycle = TRUE;
sw.reset(); // because cycling will start with the next IdleAction
sw.start();
}
}
} //CmNetLoad
//----------------------------------------------------------------------------
// save the current network to disk as a .NET file
void SNeuralWindow::CmNetSaveAs()
{
static TOpenSaveDialog::TData fd(OFN_OVERWRITEPROMPT | OFN_PATHMUSTEXIST,
"Networks (*.NET)|*.NET|All Files (*.*)|*.*|",0,"","NET");
if(TFileSaveDialog(this,fd).Execute() == IDOK)
ofstream(fd.FileName) << *net;
} //CmNetSaveAs
//----------------------------------------------------------------------------
// load training set from disk.
void SNeuralWindow::CmTrainerLoad()
{
static TOpenSaveDialog::TData fd(OFN_FILEMUSTEXIST,
"Training Sets (*.TRS)|*.TRS|All Files (*.*)|*.*|",0,"","TRS");
if((TFileOpenDialog(this,fd)).Execute() != IDOK) // if user cancelled
{
if(fd.Error) // check for error
MessageBox("Dialog box returned error.","Warning",MB_OK);
return; // and return
}
// user selected file(s), so process them
//#error this hasn't been modified to match the removal of MULTISELECT. Maybe no mods needed.
FileArray FileList; // accumulates the file names
FileList.AddDialogList(fd.FileName);
while(FileList.GetItemsInContainer()) // load the training files (there will be only 1)
{
string buf(FileList.GetNext()); // copy file name
buf.to_upper(); // toupper for error messages
if(!buf.contains(".TRS"))
{
buf += "\nFile extension must be .TRS";
MessageBox(buf.c_str(),"Cannot Load This File",MB_OK);
continue;
}
if(!net->LoadCases(buf.c_str()))
{
buf += "\nFile not found, corrupt, or training sets not unique.";
MessageBox(buf.c_str(),"File Error",MB_OK);
continue;
}
}
if(net->Cases.GetItemsInContainer())
{
Iterations = 0L;
autocycle = TRUE;
sw.reset(); // because cycling will start with the next IdleAction
sw.start();
}
else
MessageBox("No sets were successfully loaded.","Warning: Training data set empty",MB_OK);
} // CmTrainerLoad
//----------------------------------------------------------------------------
// show the "About" window
void SNeuralWindow::CmHelpAbout()
{
MessageBox("Copyright 1995-97, 2007 Steven Whitney",GetApplication()->GetName(),MB_OK);
}
//----------------------------------------------------------------------------
// allow saving network before shutdown
BOOL SNeuralWindow::CanClose()
{
BOOL status = TWindow::CanClose(); // processes children
if(status == FALSE)
return(FALSE);
if(net)
if(MessageBox("Save net to disk?","Network has changed",MB_YESNO) == IDYES)
CmNetSaveAs();
return(TRUE);
} //CanClose
//----------------------------------------------------------------------------
void SNeuralWindow::Paint(TDC& pdc, BOOL /* erase */, TRect& invalidarea) // OWLPG:37
{
// don't waste system time if !net or this isn't the active application, or is minimized
if(!net || IsIconic() || (GetActiveWindow() != GetApplication()->GetMainWindow()->HWindow))
return;
pdc.FillRect(invalidarea, TBrush(TColor::Black));
drawnodes(pdc, TRUE);
} //Paint
//----------------------------------------------------------------------------
BOOL SNeuralWindow::IdleAction(long /* idlecount */)
{
if(!autocycle || !net)
return(TRUE);
//putchar(7); // for testing whether it's cycling under all conditions (it is)
string statusmsg, errormsg;
int result = net->Run();
switch(result)
{
case 0: // processing is in progress. No problem.
Iterations++; // this counts the calls to Run(), and overstates actual iterations.
if((net->graphicon == 3) ||
((net->graphicon == 2) && net->CurrentCaseWasSolved()))
Invalidate(TRUE);
break;
case 1: // FINISHED because the network is fully trained (training run)
sw.stop();
statusmsg = string("Time: ") + tostring(sw.trialtime()) + " seconds."
+ " Trials: " + tostring(Iterations);
*statuswindow << string("Trained- ") << statusmsg << "\r\n";
MessageBox(statusmsg.c_str(),"Network is trained on all input Cases.",MB_OK);
autocycle = FALSE;
if(net->graphicon == 1)
Invalidate(TRUE);
break;
case 2: // FINISHED because all Cases in a REAL RUN have been processed.
sw.stop();
statusmsg = "The result data are in the output file.";
statusmsg += string("Time: ") + tostring(sw.trialtime()) + " seconds."
+ " Cases solved: " + tostring(Iterations);
*statuswindow << string("All Cases calculated- ") << statusmsg << "\r\n";
MessageBox(statusmsg.c_str(),"All dataset Cases have been processed.",MB_OK);
autocycle = FALSE;
break;
// errors
case -1:
errormsg = "The network is not created, contains no Nodes.";
break;
case -2:
errormsg = "There is no input dataset loaded. (Cases is empty).";
break;
case -3:
errormsg = "Network and dataset incompatible: Input nodes != Inputs.";
break;
case -4:
errormsg = "Network and dataset incompatible: Output nodes != Outputs.";
break;
}
if(errormsg.length())
{
errormsg += "\nWhen you resolve the problem, it will automatically try again.";
MessageBox(errormsg.c_str(),"Network cannot start processing because...",MB_OK);
autocycle = FALSE; // prevent displaying this message repeatedly.
}
/*
// set up window caption
string caption = string(GetApplication()->GetName()) + string(" - ");
if(Parent)
Parent->SetCaption(caption.c_str());
*/
return(TRUE); // always return true, or it won't get called again
}
//----------------------------------------------------------------------------
// end class SNeuralWindow
//////////////////////////////////////////////////////////////////////////////
// The application object
class TMyApp : public TApplication
{
public:
TMyApp(const char far *title) : TApplication(title) {} // title used in case of error
protected:
virtual BOOL IdleAction(long idlecount);
virtual void InitMainWindow()
{
TFrameWindow* frame = new TFrameWindow(0,GetName(),new SNeuralWindow);
frame->AssignMenu(TResId(MENU_1));
frame->Attr.AccelTable = TResId(MENU_1);
nCmdShow = SW_SHOWNORMAL;
SetMainWindow(frame);
}
};
//----------------------------------------------------------------------------
BOOL TMyApp::IdleAction(long /* idlecount */)
{
TApplication::IdleAction(0);
return TRUE;
}
//----------------------------------------------------------------------------
// end class TMyApp
//////////////////////////////////////////////////////////////////////////////
// OwlMain
int OwlMain(int /* argc */, char** /* argv */)
{
randomize();
string::set_case_sensitive(0);
string::set_paranoid_check(1);
// Run() calls: InitApplication(), InitInstance() { (which calls: InitMainWindow() },
// then displays main window.
TMyApp* myapp = new TMyApp(AppName);
int retval = myapp->Run();
delete myapp;
return(retval);
} //OwlMain
# $ K + Neural Net Help Contents
OverviewHID_OVERVIEW
File FormatsHID_FILEFORMATS
File Menu CommandsHID_FILEMENUCOMMANDS
Net Menu CommandsHID_NETMENUCOMMANDS
Trainer Menu CommandsHID_TRAINERMENUCOMMANDS
View Menu CommandsHID_VIEWMENUCOMMANDS
References and Further ReadingHID_FURTHERREADING
# $ K + Overview
Neural Net is a multilayer perceptron backpropagation (MLP) neural network. You can view a graphical display of the network as it thinks. Faster cycling means the training sets are being solved more readily.
In the graphic display, input nodes are RED, on left side of screen, hidden nodes are GREEN in center, and output nodes are WHITE at right. Flow is from input nodes through hidden nodes, to output nodes. Connection coloring indicates the (output of the output node * the weight of the connection). Coloration and boundaries can be specified in the source code file. Currently WHITE = highly stimulating GREEN = stimulating RED = inhibitory BLUE = highly inhibitory.
Neural Net (WNeural) Version 2.0 is a major rewrite, and is not compatible with Version 1.0 (which did not have a version number associated with it).
# $ K + File Formats
.TRS
Training set data, problems and solutions. A problem set consists of a list of inputs that constitute a problem, and a list of the outputs that constitute the correct answer for that problem. Format for each problem set is simply 2 lines, as below. A training set usually consists of multiple problems. The training set file has multiple sets of 2-line pairs:
input1 input2 input3... input values for problem 1
answer1 answer2... output values that are the correct answer for problem 1
input1 input2 input3... input values for problem 2
answer1 answer2... output values that are the correct answer for problem 2
etc.
A .TRS file with only 1 line can be used to test a network after it is trained. That is, the 1-line file contains only inputs, no correct answers, so the net will just accept the input and generate an answer.
.NET
Node connection data for rebuilding a network from disk, including how many of each type of node the network has (on line 1) and (on all following lines) information about the connections between the nodes.
Format:
inodecount h1count h2count h3count onodecount TOLERANCE\n
node# nodeBias nodeLearningRate\n
node# nodeBias nodeLearningRate\n
etc...
fromnode# tonode# weight\n
fromnode# tonode# weight\n
etc...
# $ K + File Menu Commands
Start
Begin training a network on a problem (training) set. You can use File|Start as your first action when entering the program. It always prompts you for the training set file(s) to use. If there is an existing network from a previous run, it will train that net on the problem set. If there is no previous net (the first run), you are prompted for some parameters to create one. If you wish to create a new network at a later time, use Net|NewHID_NETMENUCOMMANDS.
Exit
Terminate the program and exit to Windows.
# $ K + Net Menu Commands
New
Creates a new network, replacing any currently existing network (and losing it, if you have not saved it). You are prompted for the number of nodes to use in each of the network layers.
Whenever you create or load a new network or load a training set, the program checks to see if the two are compatible. If they are not, it displays the reason. If everything is ok, processing of the training set begins immediately.
Load
Create a new network from a disk file, using the numbers of nodes specified there and the specified connection data.
SaveAs
Save the current network to a disk file with the extension .NET.
The following menu items, if they still appear in the main window, are not functional and do nothing:
Add Connection
Delete Connection
RipOut Node
# $ K + Trainer Menu Commands
Load
Specify training set file(s) on which the network should be trained.
# $ K + View Menu Commands
Node #s
Toggles whether nodes are displayed as dots or as numbers. Numbers indicate node positions in the sequential order. (Nodes can only output to nodes later in the sequence than themselves.) Dots will flicker according to whether the summed input to that node is currently > 0 (dot filled in) or negative (dot empty). This significantly slows down processing.
Messages
Whether to show or hide the status report window.
Peek Level
How often to update the graphic display of the net:
0 no display FAST, but invisible
1 each time the last set is solved connection colors don't change, but new ones do appear
2 each time each set is solved a little slow, but the cycling shows up
3 every iteration of every set very SLOW
# $ K + For Further Reading
Books:
Choas Under Control, David Peak and Michael Frame
Complexity, M. Mitchell Waldrop
Magazine Articles:
Computer Programs:
/* library.cpp 3-4-99 Copyright (C)1999 Steven Whitney. Published under GNU GPL (General Public License) Version 3, with ABSOLUTELY NO WARRANTY. Initially published by http://25yearsofprogramming.com. The library for the WNEURAL project. This should be a project node. */ #include <owl\owlpch.h> #include <owl\chooseco.h> #include <owl\opensave.h> #include <owl\radiobut.h> #include <owl\edit.h> #include <owl\inputdia.h> #include <classlib\arrays.h> #include <math.h> #include <stdio.h> // for remaining putchar, gets calls #include "c:\bcs\my.h" #pragma hdrstop #include "c:\bcs\mylib.cpp" #include "c:\bcs\library\stopwatc.cpp" #include "c:\bcs\library\filearay.cpp" //////////////////////////////////////////////////////////////////////////////
/* msgwind.h 6-16-97
Copyright (C)1997 Steven Whitney.
Published under GNU GPL (General Public License) Version 3, with ABSOLUTELY NO WARRANTY.
Initially published by http://25yearsofprogramming.com.
This is part of the WNEURAL project.
SMessageWindow class declaration. The program's status reports go to a SMessageWindow.
*/
#ifndef __MSGWIND_H
#define __MSGWIND_H
#include <owl\owlpch.h>
#include <owl\edit.h>
#include "c:\bcs\my.h"
#pragma hdrstop
//////////////////////////////////////////////////////////////////////////////
// dialog box to replace EasyWin window. For status messages.
class SMessageWindow : public TDialog
{
public:
SMessageWindow(TWindow* parent, TResId resid); // constructor
SMessageWindow& operator << (const string&); // add a string to the text
BOOL isopen; // interface element currently displayed?
BOOL Create();
void Destroy(int retValue = IDCANCEL);
protected:
TEdit* ed;
string text;
};
//----------------------------------------------------------------------------
#endif // msgwind.h
/*
WNEURAL.RC is part of the WNEURAL project.
Copyright (C)1995-99 Steven Whitney.
Published under GNU GPL (General Public License) Version 3, with ABSOLUTELY NO WARRANTY.
Initially published by http://25yearsofprogramming.com.
produced by Borland Resource Workshop
*/
#include "wneural.rh"
MESSAGESWINDOW DIALOG 31, 66, 335, 231
STYLE WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX
CAPTION "Message Window"
FONT 8, "MS Sans Serif"
{
EDITTEXT IDC_TRANSEDIT, 0, 0, 335, 231, ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_WANTRETURN | NOT WS_TABSTOP | NOT WS_BORDER | WS_VSCROLL | WS_HSCROLL
}
IDD_INPUTDIALOG DIALOG 35, 50, 280, 133
STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | DS_SETFONT
FONT 8, "Helv"
{
LTEXT "", ID_PROMPT, 6, 6, 268, 78
EDITTEXT ID_INPUT, 9, 89, 261, 12, WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP | ES_AUTOHSCROLL
DEFPUSHBUTTON "&OK", IDOK, 102, 111, 40, 14
PUSHBUTTON "&Cancel", IDCANCEL, 148, 111, 40, 14
}
MENU_1 MENU
{
POPUP "&File"
{
MENUITEM "&Start...\tS", CM_FILESTART
MENUITEM "E&xit", CM_FILEEXIT
}
POPUP "&Net"
{
MENUITEM "&New\tN", CM_NETNEW
MENUITEM "&Load...", CM_NETLOAD
MENUITEM "&SaveAs...", CM_NETSAVEAS
MENUITEM SEPARATOR
MENUITEM "&Add Connection...\tA", CM_NETADDCONNECTION
MENUITEM "&Delete Connection...\tD", CM_NETDELETECONNECTION
MENUITEM SEPARATOR
MENUITEM "&Rip Out Node...\tR", CM_NETRIPNODE
}
POPUP "&Trainer"
{
MENUITEM "&Load...\tT", CM_TRAINERLOAD
}
POPUP "&View"
{
MENUITEM "&Node Numbers\t#", CM_VIEWNODENUMBERS, CHECKED
MENUITEM "&Messages\tM", CM_VIEWMESSAGES, CHECKED
MENUITEM SEPARATOR
MENUITEM "&Peek level...\tP", CM_VIEWPEEKLEVEL
}
POPUP "&Help"
{
MENUITEM "&Index\tF1", CM_HELPINDEX
MENUITEM "&Keyboard", CM_HELPKEYBOARD
MENUITEM "&Commands", CM_HELPCOMMANDS
MENUITEM "&Procedures", CM_HELPPROCEDURES
MENUITEM "&Using help", CM_HELPUSING_HELP
MENUITEM SEPARATOR
MENUITEM "&About...", CM_HELPABOUT
}
}
STRINGTABLE
{
CM_FILEEXIT, "Exit program"
CM_VIEWPEEKLEVEL, "How often to update graphic node display"
CM_NETLOAD, "Load previously saved network architecture"
CM_NETSAVEAS, "Save current network's architecture to a file"
CM_NETNEW, "Create a new randomly wired network"
CM_TRAINERLOAD, "Load a training set from disk"
CM_VIEWNODENUMBERS, "View nodes as numbers, or dots (slower)"
CM_FILESTART, "Start training the net on the training set"
}
MENU_1 ACCELERATORS
{
VK_F1, CM_HELPINDEX, VIRTKEY
"p", CM_VIEWPEEKLEVEL
"m", CM_VIEWMESSAGES
"t", CM_TRAINERLOAD
"#", CM_VIEWNODENUMBERS
"n", CM_NETNEW
"s", CM_FILESTART
"a", CM_NETADDCONNECTION
"d", CM_NETDELETECONNECTION
"r", CM_NETRIPNODE, ASCII
}
/* WNEURAL.RH is part of the WNEURAL project. Copyright (C)1995-99 Steven Whitney. Published under GNU GPL (General Public License) Version 3, with ABSOLUTELY NO WARRANTY. Initially published by http://25yearsofprogramming.com. produced by Borland Resource Workshop */ #include <owl\inputdia.rh> #define MENU_1 1 #define CM_NETRIPNODE 7 #define CM_NETDELETECONNECTION 6 #define CM_NETADDCONNECTION 5 #define CM_FILESTART 4 #define CM_VIEWNODENUMBERS 105 #define CM_TRAINERLOAD 104 #define CM_VIEWPEEKLEVEL 1 #define CM_NETNEW 3 #define CM_NETSAVEAS 103 #define CM_NETLOAD 102 #define CM_VIEWMESSAGES 2 #define CM_HELPABOUT 24348 #define CM_HELPUSING_HELP 24347 #define CM_HELPPROCEDURES 24346 #define CM_HELPCOMMANDS 24345 #define CM_HELPKEYBOARD 24344 #define CM_HELPINDEX 24343 #define CM_FILEEXIT 24342 #define MESSAGESWINDOW 3 #define IDC_TRANSEDIT 101
[OPTIONS] CONTENTS=HID_CONTENTS TITLE=Neural Net Help [CONFIG] BrowseButtons() [FILES] wneural.rtf
EXETYPE WINDOWS CODE PRELOAD MOVEABLE DISCARDABLE DATA PRELOAD MOVEABLE MULTIPLE HEAPSIZE 8000 STACKSIZE 8000
The next page (Network.cpp) has the source code for the classes that implement the neural network.
|
|
|
|