// MultiLayerPerceptronDlg.cpp : implementation file
//
#include "stdafx.h"
#include "MultiLayerperceptron.h"
#include "MultiLayerPerceptronDlg.h"
#include ".\multilayerperceptrondlg.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
#define SAFE_DELETE(p) {if(p) {delete [] p; p = 0;}}
int totalIter = 0;
double* totalError = NULL;
HBRUSH brBlue = CreateSolidBrush(RGB(0,0,255));
HBRUSH brRed = CreateSolidBrush(RGB(255,0,0));
HPEN penWhite = CreatePen(PS_SOLID, 1, RGB(255,255,255));
// CAboutDlg dialog used for App About
class CAboutDlg : public CDialog
{
public:
CAboutDlg();
// Dialog Data
enum { IDD = IDD_ABOUTBOX };
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
// Implementation
protected:
DECLARE_MESSAGE_MAP()
};
CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
}
void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
END_MESSAGE_MAP()
// CMultiLayerPerceptronDlg dialog
CMultiLayerPerceptronDlg::CMultiLayerPerceptronDlg(CWnd* pParent /*=NULL*/)
: CDialog(CMultiLayerPerceptronDlg::IDD, pParent)
, m_dLearningRate(0.05)
, m_dMomentum(0.9)
, m_nIter(1000)
, m_dTargetError(0.03)
, m_bWritetoFile(FALSE)
, m_strErrorFile(_T("C:\\error.txt"))
{
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
m_hidSize[0] = 10;
m_hidSize[1] = 0;
m_hidSize[2] = 0;
for (int y = 0; y < 600; y++)
{
for (int x = 0; x < 800; x++)
{
m_fRedRatio[y][x] = -128;
}
}
}
void CMultiLayerPerceptronDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
DDX_Text(pDX, IDC_HIDDEN1, m_hidSize[0]);
DDX_Text(pDX, IDC_HIDDEN2, m_hidSize[1]);
DDX_Text(pDX, IDC_HIDDEN3, m_hidSize[2]);
DDX_Text(pDX, IDC_LR, m_dLearningRate);
DDX_Text(pDX, IDC_MOMENTUM, m_dMomentum);
DDX_Text(pDX, IDC_ITER, m_nIter);
DDX_Control(pDX, IDC_COLOR, m_cmbColor);
DDX_Text(pDX, IDC_TARGET_ERROR, m_dTargetError);
DDX_Check(pDX, IDC_WRITETOFILE, m_bWritetoFile);
DDX_Text(pDX, IDC_EDIT1, m_strErrorFile);
}
BEGIN_MESSAGE_MAP(CMultiLayerPerceptronDlg, CDialog)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
//}}AFX_MSG_MAP
ON_BN_CLICKED(IDC_INIT, OnBnClickedInit)
ON_BN_CLICKED(IDC_LEARN, OnBnClickedLearn)
ON_WM_LBUTTONDOWN()
ON_BN_CLICKED(IDC_CLEAR, OnBnClickedClear)
ON_BN_CLICKED(IDC_SHOW_ERROR, OnBnClickedShowError)
ON_BN_CLICKED(IDC_LOAD_WEIGHTS, OnBnClickedLoadWeights)
ON_BN_CLICKED(IDC_LOAD_WEIGHTS2, SaveWeights)
ON_BN_CLICKED(IDC_WRITETOFILE, OnBnClickedWritetofile)
END_MESSAGE_MAP()
// CMultiLayerPerceptronDlg message handlers
BOOL CMultiLayerPerceptronDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// Add "About..." menu item to system menu.
// IDM_ABOUTBOX must be in the system command range.
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);
CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != NULL)
{
CString strAboutMenu;
strAboutMenu.LoadString(IDS_ABOUTBOX);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
}
// Set the icon for this dialog. The framework does this automatically
// when the application's main window is not a dialog
SetIcon(m_hIcon, TRUE); // Set big icon
SetIcon(m_hIcon, FALSE); // Set small icon
m_ErrorDlg = new CErrorDlg(this);
m_ErrorDlg->Create(IDD_ERROR);
m_cmbColor.SetCurSel(0);
RECT rc;
GetDlgItem(IDC_SAMPLES)->GetClientRect(&rc);
double W = rc.right - rc.left;
double H = rc.bottom - rc.top;
//POINT blues[] = {{0,0},{W,H}};
POINT blues[] = {{W/2,2*H/3},{W/2,H/3},{W/3,H/2},{2*W/3,H/2},{5*W/12,7*H/12},{7*W/12,7*H/12},{5*W/12,5*H/12},{7*W/12,5*H/12}};
for (int i = 0; i < 8; i++)
{
m_BluePts.Add(blues[i]);
}
//POINT reds[] = {{0,H},{W,0}};
//POINT reds[] = {{5*W/12,7*H/12},{7*W/12,7*H/12},{5*W/12,5*H/12},{7*W/12,5*H/12}};
POINT reds[] = {{11*W/24,13*H/24},{13*W/24,13*H/24},{11*W/24,11*H/24},{13*W/24,11*H/24}};
m_RedPts.Add(reds[0]);m_RedPts.Add(reds[1]);m_RedPts.Add(reds[2]);m_RedPts.Add(reds[3]);
return TRUE; // return TRUE unless you set the focus to a control
}
void CMultiLayerPerceptronDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
if ((nID & 0xFFF0) == IDM_ABOUTBOX)
{
CAboutDlg dlgAbout;
dlgAbout.DoModal();
}
else
{
CDialog::OnSysCommand(nID, lParam);
}
}
// If you add a minimize button to your dialog, you will need the code below
// to draw the icon. For MFC applications using the document/view model,
// this is automatically done for you by the framework.
void CMultiLayerPerceptronDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // device context for painting
SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
// Center icon in client rectangle
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
// Draw the icon
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialog::OnPaint();
int i;
RECT rc;
CDC* pDC = GetDlgItem(IDC_SAMPLES)->GetDC();
pDC->SetBkMode(TRANSPARENT);
//Classified regions
for (int y = 0; y < 600; y++)
{
for (int x = 0; x < 800; x++)
{
if(m_fRedRatio[y][x] == -128)
continue;
int val = 255 - m_fRedRatio[y][x]*255;
if(m_fRedRatio[y][x] > 0)
{
SetPixel(pDC->m_hDC, x, y, RGB(255,val,val));
}
else //if(m_fRedRatio[y][x] < 0)
{
val = -(-255 - m_fRedRatio[y][x]*255);
SetPixel(pDC->m_hDC, x, y, RGB(val,val,255));
}
}
}
//Sample inputs from user
pDC->SelectObject(penWhite);
for (i = 0; i < m_RedPts.GetCount(); i++)
{
RECT rc = {m_RedPts[i].x-4, m_RedPts[i].y-4, m_RedPts[i].x+4, m_RedPts[i].y+4};
pDC->SelectObject(brRed);
//FillRect(pDC->m_hDC, &rc, brRed);
pDC->Rectangle(&rc);
}
for (i = 0; i < m_BluePts.GetCount(); i++)
{
RECT rc = {m_BluePts[i].x-4, m_BluePts[i].y-4, m_BluePts[i].x+4, m_BluePts[i].y+4};
pDC->SelectObject(brBlue);
//FillRect(pDC->m_hDC, &rc, brBlue);
pDC->Rectangle(&rc);
}
}
}
// The system calls this function to obtain the cursor to display while the user drags
// the minimized window.
HCURSOR CMultiLayerPerceptronDlg::OnQueryDragIcon()
{
return static_cast<HCURSOR>(m_hIcon);
}
void CMultiLayerPerceptronDlg::OnBnClickedInit()
{
for (int y = 0; y < 600; y++)
{
for (int x = 0; x < 800; x++)
{
m_fRedRatio[y][x] = -128;
}
}
Invalidate();
totalIter = 0;
m_ErrorDlg->m_errorGraph.SetData(0,0,0,0);
m_ErrorDlg->m_errorGraph.UpdateGraph();
initPerceptron();
GetDlgItem(IDC_LEARN)->EnableWindow(true);
GetDlgItem(IDC_LOAD_WEIGHTS)->EnableWindow(true);
GetDlgItem(IDC_SHOW_ERROR)->EnableWindow(true);
GetDlgItem(IDC_SAVE_WEIGHTS)->EnableWindow(true);
}
void CMultiLayerPerceptronDlg::initPerceptron()
{
UpdateData();
int nLayer,i,j,k;
perceptron = new Perceptron(n_in,n_out); // 2 inputs / 1 output
nLayer=0;
for(i=0;i<3;i++)
{
if (m_hidSize[i]!=0)
{
CString s;
s.Format(_T("H%d|"),i);
perceptron->addLayer(m_hidSize[i],s);
nLayer++;
}
}
for(j=0;j<nLayer;j++)
for(i=0;i<m_hidSize[j];i++) perceptron->biasConnect(j+1,i);
perceptron->biasConnect(nLayer+1,0); // for the output
if (nLayer==0)
{
// connect the inputs to the outputs
perceptron->connect(0,0,1,0);
perceptron->connect(0,1,1,0);
}
else
{
// connect the inputs to the first hidden layer
for(i=0;i<m_hidSize[0];i++)
for(j=0;j<n_in;j++)
perceptron->connect(0,j,1,i);
// Problem with third layer solved by Sebastien Baehni
// connect the hidden layers together
for(k=0;k<nLayer-1;k++)
for(i=0;i<m_hidSize[k];i++)
for(j=0;j<m_hidSize[k+1];j++)
perceptron->connect(k+1,i,k+2,j);
// connect the last hidden layer to the output
for(i=0;i<m_hidSize[nLayer-1];i++) perceptron->connect(nLayer,i,nLayer+1,0);
}
}
void CMultiLayerPerceptronDlg::learnPoints()
{
UpdateData();
setSamples();
// perceptron.printSamples();
Neuron::learningRate = m_dLearningRate;
SAFE_DELETE(totalError);
int scale = 1;
while ((m_nIter/scale) > 10000)
{
scale++;
}
//double* tmpError = new double[totalIter];
//memcpy( tmpError, totalError, (totalIter-m_nIter)*sizeof(double) );
totalError = new double[m_nIter/scale];
UpdateData();
FILE* fp = _wfopen(m_strErrorFile, _T("wt"));
double err = 0;
int i = 0;
for(i = 0;i < m_nIter; i++)
{
perceptron->learn(1);
if (i%scale==0)
{
SetDlgItemInt(IDC_COUNTER, i);
totalError[i/scale] = perceptron->currentError();
if(m_bWritetoFile)
fprintf(fp,"%f\n",totalError[i/scale]);
if(perceptron->currentError() < m_dTargetError)
break;
}
//err = perceptron->currentError();
//tmpError[i+totalIter-m_nIter] = err;
}
//m_ErrorDlg->m_errorGraph.SetData(0,tmpError,totalIter,false);
m_ErrorDlg->m_errorGraph.SetData(0,totalError,i/scale,false);
//m_ErrorDlg->ShowWindow(SW_NORMAL);
m_ErrorDlg->m_errorGraph.UpdateGraph();
fclose(fp);
//memcpy(totalError, tmpError, totalIter*sizeof(double));
//delete [] tmpError;
totalIter += i;
SetDlgItemInt(IDC_TOTAL_ITER, totalIter);
}
void CMultiLayerPerceptronDlg::OnBnClickedLearn()
{
learnPoints();
UpdateDisplay();
}
void CMultiLayerPerceptronDlg::OnLButtonDown(UINT nFlags, CPoint point)
{
UpdateData();
ClientToScreen(&point);
GetDlgItem(IDC_SAMPLES)->ScreenToClient(&point);
RECT clientrc;
GetDlgItem(IDC_SAMPLES)->GetClientRect(&clientrc);
if(!PtInRect(&clientrc, point))
return;
RECT rc = {point.x-4, point.y-4, point.x+4, point.y+4};
CDC* pDC = GetDlgItem(IDC_SAMPLES)->GetDC();
if(m_cmbColor.GetCurSel() == 0)
{
FillRect(pDC->m_hDC, &rc, brBlue);
m_BluePts.Add(point);
}
else
{
FillRect(pDC->m_hDC, &rc, brRed);
m_RedPts.Add(point);
}
CDialog::OnLButtonDown(nFlags, point);
}
void CMultiLayerPerceptronDlg::setSamples()
{
Samples iS,oS;
oS.nLenght = 1;
oS.samples[0] = 1.0;
iS.nLenght = 2;
RECT rc;
GetDlgItem(IDC_SAMPLES)->GetClientRect(&rc);
double W = rc.right - rc.left;
double H = rc.bottom - rc.top;
for (int i = 0; i < m_RedPts.GetCount(); i++)
{
iS.samples[0] = (double)m_RedPts[i].x/W;
iS.samples[1] = (H - (double)m_RedPts[i].y)/H;
perceptron->addSample(iS, oS);
}
oS.samples[0] = 0.0;
for (int i = 0; i < m_BluePts.GetCount(); i++)
{
iS.samples[0] = (double)m_BluePts[i].x/W;
iS.samples[1] = (H - (double)m_BluePts[i].y)/H;
perceptron->addSample(iS, oS);
}
}
void CMultiLayerPerceptronDlg::UpdateDisplay()
{
RECT rc;
GetDlgItem(IDC_SAMPLES)->GetClientRect(&rc);
double W = rc.right - rc.left;
double H = rc.bottom - rc.top;
Samples test = {{0.0,0.0},2};
int x = 0, y = 0;
CDC *pDc = GetDlgItem(IDC_SAMPLES)->GetDC();
pDc->SetBkMode(TRANSPARENT);
POINT point;
double result;
for (y = 0; y < H; y++)
{
for (x = 0; x < W; x++)
{
test.samples[0] = (double)x/W;
test.samples[1] = (double)y/H;
double result = perceptron->recognize(test).samples[0];
m_fRedRatio[(int)H-y][x] = (result-0.5)/0.5;//number between -1 and 1
/*if(perceptron->recognize(test).samples[0] > 0.5)
{
m_fRedRatio[(int)H-y][x] = 1;
}
else
{
m_fRedRatio[(int)H-y][x] = 0;
}*/
}
}
InvalidateRect(&rc,false);
};
void CMultiLayerPerceptronDlg::OnBnClickedClear()
{
m_RedPts.RemoveAll();
m_BluePts.RemoveAll();
for (int y = 0; y < 600; y++)
{
for (int x = 0; x < 800; x++)
{
m_fRedRatio[y][x] = -128;
}
}
Invalidate();
}
void CMultiLayerPerceptronDlg::OnBnClickedShowError()
{
m_ErrorDlg->ShowWindow(SW_NORMAL);
}
void CMultiLayerPerceptronDlg::OnBnClickedLoadWeights()
{
perceptron->LoadNet(_T("C:\\OCRNet.net"));
}
void CMultiLayerPerceptronDlg::SaveWeights()
{
perceptron->SaveNetwork(_T("C:\\OCRNet.net"));
}
void CMultiLayerPerceptronDlg::OnBnClickedWritetofile()
{
UpdateData();
GetDlgItem(IDC_EDIT1)->EnableWindow(m_bWritetoFile);
}