经过昨天晚上的努力,自己把最简单的单层神经网实现了,可是误差不收敛,会剧烈震荡,没搞定。今天早上修改了学习速率,结果就能收敛了,而且能识别部分手写字母。还有就是学习的部分收敛条件或者说是终止条件很纠结。
介于简单网络的识别效果,我觉得下一步应该改进训练样本的数量,现在每一类只有一个训练样本,出现分类错误的可能还是很高的。
下面是学习和识别部分的代码:
计算误差的函数
public double CalcError(double[] w, int[] v, int index )
{
double tmp = 0.0f;
for (int i = 0; i < NumInLayer + 1; i++)
{
tmp += w[i] * v[i];
}
tmp = index - tmp;
return tmp;
}
学习部分的函数
public void Learn(String name)
{
String mgrec = System.AppDomain.CurrentDomain.SetupInformation.ApplicationBase + "mgrec.txt";
StreamWriter sw = new StreamWriter(fileName, true);
StreamWriter sw_mg = new StreamWriter(mgrec, true);
String context = GetBMPContext(bmpDraw);
sw.WriteLine(name + " " + context);
sw_mg.WriteLine(name + " " + GetCurrentMouseGesture());
sw.Close();
sw_mg.Close();
//training the NN
int targetIndex = -1;
switch (name)
{
case "a":
targetIndex = 1;
break;
case "b":
targetIndex = 2;
break;
case "c":
targetIndex = 3;
break;
case "d":
targetIndex = 4;
break;
case "e":
targetIndex = 5;
break;
case "f":
targetIndex = 6;
break;
case "g":
targetIndex = 7;
break;
case "h":
targetIndex = 8;
break;
case "i":
targetIndex = 9;
break;
case "j":
targetIndex = 10;
break;
case "k":
targetIndex = 11;
break;
case "l":
targetIndex = 12;
break;
case "m":
targetIndex = 13;
break;
case "n":
targetIndex = 14;
break;
case "o":
targetIndex = 15;
break;
case "p":
targetIndex = 16;
break;
case "q":
targetIndex = 17;
break;
case "r":
targetIndex = 18;
break;
case "s":
targetIndex = 19;
break;
case "t":
targetIndex = 20;
break;
case "u":
targetIndex = 21;
break;
case "v":
targetIndex = 22;
break;
case "w":
targetIndex = 23;
break;
case "x":
targetIndex = 24;
break;
case "y":
targetIndex = 25;
break;
case "z":
targetIndex = 26;
break;
default:
break;
}
int[] v =new int[NumInLayer + 1];
double err = 10.0f;
double niu = 0.005;
double Epsilon = 1e-2;
double[] w = new double[NumInLayer + 1];
double[] dw = new double[NumInLayer + 1];
int iSeed = 9;
Random rm = new Random(iSeed);
v[0] = 1;
w[0] = rm.Next(-100, 100) / 200;
for (int i = 1; i < NumInLayer + 1; i++ )
{
int temp = rm.Next(-100, 100);
w[i] = temp / 200.0f;
v[i] =context[i - 1] - '0';
}
while (Math.Abs(err) >= Epsilon)
{
for (int i = 0; i < NumInLayer + 1; i++)
dw[i] = 0.0f;
err = CalcError(w, v, targetIndex);
for (int i = 0; i < NumInLayer + 1; i++)
dw[i] += niu * err * v[i];
for (int i = 0; i < NumInLayer + 1; i++)
w[i] += dw[i];
}
String ww = System.AppDomain.CurrentDomain.SetupInformation.ApplicationBase + "weight.txt";
StreamWriter sww = new StreamWriter(ww, true);
sww.WriteLine(name);
for (int i = 0; i < NumInLayer + 1; i++)
{
sww.WriteLine(w[i]);
}
sww.Close();
识别部分
public String Recognise()
{
String ww = System.AppDomain.CurrentDomain.SetupInformation.ApplicationBase + "weight.txt";
String context = GetBMPContext(bmpDraw);
String res = "";
StreamReader rww = new StreamReader(ww);
double[] w = new double[NumInLayer + 1];
double max = 0.0f;
int[] v = new int[NumInLayer + 1];
while (!rww.EndOfStream)
{
String tmp = rww.ReadLine();
double tmpres = 0.0f;
if (tmp[0] >= 'a' && tmp[0] <= 'z')
{
tmpres += w[0];
for (int i = 1; i < NumInLayer + 1; i++)
{
w[i] = Convert.ToDouble(rww.ReadLine());
v[i] = context[i - 1] - '0';
tmpres += w[i] * v[i];
}
if (tmpres >= max)
{
max = tmpres;
res = tmp;
}
}
}
Console.WriteLine(max);
if (res == "")
res = "denied";
return res;
}
下一步试试多层网络,多搞些训练样本,还有就是新的识别算法。目前的算法有一个突出的问题,当新实例与样本之间存在一个缩放与偏移,要想办法消除,或者采用别的算法。
工程已上传,有兴趣的可以自己试试。