我试图从头开始在C#中使用反向传播实现神经网络,但是它不能正常工作。我使用this数据集进行学习。代码:
private void learningFunc()
{
string[] files;
System.IO.FileStream fs;
unsafe
{
for (int s = 0; s < letters; s++)
{
UpdateProgress(s);
expectedResult[s] = 1.0;
char symbol = (char)(s + 65);
files = System.IO.Directory.GetFiles(dataset_path + Convert.ToString(symbol));
foreach (string fileName in files.Take(500))
{
fs = new System.IO.FileStream(fileName, System.IO.FileMode.Open);
bmp = (Bitmap)System.Drawing.Bitmap.FromStream(fs);
fs.Close();
fs.Dispose();
BitmapData bData = bmp.LockBits(new Rectangle(0, 0, 28, 28), ImageLockMode.ReadWrite, bmp.PixelFormat);
byte* scan0 = (byte*)bData.Scan0.ToPointer();
//Bitmap bmp123 = new Bitmap(28, 28);
for (int i = 0; i < pixels; ++i)
{
byte* data = scan0 + i * 4;
l0[i] = data[0] / 255.0;
//bmp123.SetPixel(i %28, i / 28, Color.FromArgb((int)Math.Floor(l0[i] * 255), (int)Math.Floor(l0[i] * 255), (int)Math.Floor(l0[i] * 255)));
}
//pictureBox2.Image = bmp123;
bmp.UnlockBits(bData);
bmp.Dispose();
for (int i = 0; i < hidden_layer; ++i)
{
l1_in[i] = synapse0_bias[i];
for (int j = 0; j < pixels; ++j)
{
l1_in[i] += l0[j] * synapse0[j, i];
}
l1[i] = sigmoid(l1_in[i]);
}
for (int i = 0; i < letters; ++i)
{
l2_in[i] = synapse1_bias[i];
for (int j = 0; j < hidden_layer; ++j)
{
l2_in[i] += l1[j] * synapse1[j, i];
}
l2[i] = sigmoid(l2_in[i]);
l2_err[i] = (expectedResult[i] - l2[i]) * sigmoid_derivative(l2_in[i]);
}
for (int i = 0; i < letters; ++i)
{
for (int j = 0; j < hidden_layer; ++j)
{
synapse1_delta[j, i] = teaching_velocity * l2_err[i] * l1[j];
}
synapse1_bias_delta[i] = teaching_velocity * l2_err[i];
}
for (int i = 0; i < hidden_layer; ++i)
{
l1_err[i] = 0;
for (int j = 0; j < letters; ++j)
{
l1_err[i] += l2_err[j] * synapse1[i, j];
}
l1_err[i] = l1_err[i] * sigmoid_derivative(l1_in[i]);
}
for (int i = 0; i < hidden_layer; ++i)
{
for (int j = 0; j < pixels; ++j)
{
synapse0_delta[j, i] = teaching_velocity * l1_err[i] * l0[j];
}
synapse0_bias_delta[i] = teaching_velocity * l1_err[i];
}
for (int i = 0; i < letters; ++i)
{
for (int j = 0; j < hidden_layer; ++j)
{
synapse1[j, i] += synapse1_delta[j, i];
}
synapse1_bias[i] += synapse1_bias_delta[i];
}
for (int i = 0; i < hidden_layer; ++i)
{
for (int j = 0; j < pixels; ++j)
{
synapse0[j, i] += synapse0_delta[j, i];
}
synapse0_bias[i] += synapse0_bias_delta[i];
}
}
expectedResult[s] = 0.0;
}
}
System.IO.StreamWriter sw = new System.IO.StreamWriter("C:\\Users\\user\\Downloads\\az-handwritten-alphabets-in-csv-format\\A_Z Handwritten Data\\synapses.txt");
foreach (double syn in synapse0)
{
sw.WriteLine(syn);
}
sw.WriteLine("\r\n");
foreach (double syn in synapse1)
{
sw.WriteLine(syn + " ");
}
sw.Close();
sw.Dispose();
UpdateProgress(0);
//TeachButton.Enabled = true;
}
private double sigmoid(double x)
{
return 2.0 / (1 + Math.Exp(-x)) - 0.5;
}
private double sigmoid_derivative(double x)
{
return sigmoid(x) * (1 - sigmoid(x));
//return x * (1 - x);
}
private void RecognizeButton_Click(object sender, EventArgs e)
{
bmp = new Bitmap(pictureBox1.Image, new Size(28, 28));
for(int i=0; i<hidden_layer; i++)
{
hl_assumptions[i] = synapse0_bias[i];
for(int j=0; j<28; j++)
{
for(int k=0; k<28; k++)
{
hl_assumptions[i] += synapse0[j * 28 + k, i] * bmp.GetPixel(k, j).B / 255.0;
}
}
hl_assumptions[i] = sigmoid(hl_assumptions[i]);
}
for (int i = 0; i < letters; i++)
{
assumptions[i] = synapse1_bias[i];
for (int j = 0; j < hidden_layer; j++)
{
assumptions[i] += synapse1[j, i] * hl_assumptions[j];
}
assumptions[i] = sigmoid(assumptions[i]);
}
string textToOutput = "";
for(int i=0; i<letters; i++)
{
char symbol = (char)(65 + i);
textToOutput += symbol + ": " + assumptions[i].ToString() + "\r\n";
}
textBox1.Text = textToOutput;
bmp.Dispose();
}
完整的代码在这里: https://drive.google.com/open?id=1nOUYRgsHeiABNQfrTcmlp8SXINGBsmeO
我希望得到一个由26个元素组成的数组(每个元素对应一个字母),填充值介于-0.5到1.5之间,显示相似度,但是我总是使数组填充-0.5。我是机器学习的新手。预先感谢您的帮助!
P.S。该程序很可能在多线程和垃圾回收方面也有问题,但是在解决了这个问题之后,我将解决它们。