Программирование нейронной сети - Самоорганизующейся карты Кохонена - C#
Формулировка задачи:
Пробую реализовать нейронную сеть Кохонена на C# на простом примере - распознавания образов, а конкретно 6 цифр: 0, 1, 2, 3, 4, 5.
Одно из описаний алгоритма работы сети Кохонена представлено здесь: http://gorbachenko.self-organization...nizing_map.pdf
Реализую сеть следующим образом:
Описываю 2 класса:
- класс описания нейрона, который содержит такие параметры как: порядковый номер нейрона, массив его весов. При создании экцемпляра класса, необходимо конструктору указать, соответственно, порядковый номер нейрона и количество входов (весов). Веса будут назначены случайным образом в диапазоне от 0.0 до 1.0.
- класс описания сети Кохонена, включающей в себя количество входов, массив нейронов (экземпляров первого класса).
Как я уже писал ранее, для начала, я хочу отладить нейронную сеть на распознавании образов (картинок) изображений, соответствующих 6-ти цифрам. Размер каждого изображения 45*45 Для этого, я беру изображения каждой цифры и преобразую их в вектор (массив) длинной 2045.
Далее, создаю структуру необученной нейронной сети:
NeuroNet net = new NeuroNet(inputNeurons, outputNeurons);
Исполняю функцию обучения:
Study(ref net, InputVector);
Выдаю результат:
В результате я вывожу на каждой итерации Евклидово расстояние между каждым нейроном, соответствующим своему входному вектору. Так я хочу, увидеть, действительно ли веса нейроном подстроились согласно входным векторам.
Но результаты выводятся несоответствующие ожиданиям. Когда происходит подстройка весов определенно нейрона, сильно искажаются ранее подстроенные веса других нейронов. Я полагаю, что проблема может быть либо в какой-то части реализации алгоритма обучения, либо конкретно в функции соседства hc.
Привожу код проекта:
Файл проекта находится во вложении. Готовые библиотеки не хочу использовать, так как хочу понять как самому реализовать.
Очень прошу, те кто знакомы с нейронными сетями, укажите, пожалуйста, на ошибку.
for (int i = 0; i < outputNeurons; i++) { currentPicture = new Bitmap(System.Drawing.Image.FromFile(AppDomain.CurrentDomain.BaseDirectory + i.ToString() + ".png", true)); InputVector[i] = ImageToVector(currentPicture); }
for (int i = 0; i < 6; i++) { textBox1.Text += "При подаче на вход " + i + "-го образца, Ответ: " + Test(net, InputVector[i]).ToString() + Environment.NewLine; }
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; namespace SOM { public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void button1_Click(object sender, EventArgs e) { textBox1.Clear(); Bitmap currentPicture = new Bitmap(System.Drawing.Image.FromFile("0.png", true)); int inputNeurons = currentPicture.Size.Height * currentPicture.Size.Width; int outputNeurons = 6; double[][] InputVector = new double[outputNeurons][]; for (int i = 0; i < outputNeurons; i++) { currentPicture = new Bitmap(System.Drawing.Image.FromFile(AppDomain.CurrentDomain.BaseDirectory + i.ToString() + ".png", true)); InputVector[i] = ImageToVector(currentPicture); } NeuroNet net = new NeuroNet(inputNeurons, outputNeurons); Study(ref net, InputVector); for (int i = 0; i < 6; i++) { textBox1.Text += "При подаче на вход " + i + "-го образца, Ответ: " + Test(net, InputVector[i]).ToString() + Environment.NewLine; } } private double[] ImageToVector(Bitmap img) { int Size = img.Size.Height*img.Size.Width; double[] vector = new double[Size]; int i = 0; for (int x = 0; x < img.Size.Width; x++) { for (int y = 0; y < img.Size.Height; y++) { Color pixel = img.GetPixel(x,y); Byte lum = (Byte)((pixel.R * 77 + pixel.G * 151 + pixel.B * 28) >> 8); vector[i++] = 1.0f - lum / 255.0f; } } return vector; } private int Test(NeuroNet net, double[] InputVector) { double MinDistance = EuclideanDistance(net.neurons[0], InputVector); int BMUIndex = 0; for (int i = 1; i < net.neurons.Count; i++) { double tmp_ED = EuclideanDistance(net.neurons[i], InputVector); if (tmp_ED < MinDistance) { BMUIndex = i; MinDistance = tmp_ED; } } return BMUIndex; } private void Study(ref NeuroNet net, double[][] InputVector) { int c; for (int k = 0; k < 6; k++) // цикл, в котором предъявляем сети входные вектора - InputVector { double MinDistance = EuclideanDistance(net.neurons[0], InputVector[k]); int BMUIndex = 0; for (int i = 1; i < net.neurons.Count; i++) { double tmp_ED = EuclideanDistance(net.neurons[i], InputVector[k]); //находим Евклидово расстояние между i-ым нейроном и k-ым входным вектором if (tmp_ED < MinDistance) // если Евклидово расстояние минимально, то это нейрон-победитель { BMUIndex = i; // индекс нейрона-победителя MinDistance = tmp_ED; } } for (int i = 0; i < net.neurons.Count; i++) { for (int g = 0; g < InputVector[k].Length; g++) { double hfunc = hc(k, net.neurons[BMUIndex].weights[g], net.neurons[i].weights[g]); double normfunc = normLearningRate(k); net.neurons[i].weights[g] = net.neurons[i].weights[g] + hfunc * normfunc * (InputVector[k][g] - net.neurons[i].weights[g]); if (i > 0 && g > 282) c = 0; } } double Error = EuclideanDistance(net.neurons[BMUIndex], InputVector[k]); for (int y = 0; y < 6; y++) { textBox1.Text += "Евклидово расстояние " + y + "-го нейрона между " + y + "-м входным вектором на " + k + "-ой итерации: " + EuclideanDistance(net.neurons[y], InputVector[y]) + Environment.NewLine; } textBox1.Text += Environment.NewLine; } } private double hc(int k, double winnerCoordinate, double Coordinate) { double dist = Distance(winnerCoordinate, Coordinate); double s = sigma(k); return Math.Exp(-dist / 2 * Sqr(sigma(k))); } private double sigma(int k) { //return -0.01 * k + 2; return 1 * Math.Exp(-k / 5); //double nf = 1000 / Math.Log(2025); //return Math.Exp(-k / nf) * 2025; } private double normLearningRate(int k) { return 0.1 * Math.Exp(-k / 1000); } private double EuclideanDistance(Neuron neuron, double[] InputVector) { double Sum = 0; for (int i = 0; i < InputVector.Length; i++) { Sum += Sqr(InputVector[i] - neuron.weights[i]); } return Math.Sqrt(Sum); } private double Distance(double winnerCoordinate, double Coordinate) { return Math.Sqrt(Sqr(winnerCoordinate - Coordinate)); } private double Sqr(double value) { return value * value; } } public class NeuroNet { public int inputs = 0; public List<Neuron> neurons; public NeuroNet(int inputs_, int neurons_) { neurons = new List<Neuron>(); inputs = inputs_; for (int i = 0; i < neurons_; i++) { Neuron neuron = new Neuron(i, inputs_); neurons.Add(neuron); } } } public class Neuron { public int number = 0; public List<double> weights; public Neuron(int number_, int inputs_) { weights = new List<double>(); number = number_; Random rand = new Random(); for (int i = 0; i < inputs_; i++) { weights.Add(rand.NextDouble()); } } } }
Решение задачи: «Программирование нейронной сети - Самоорганизующейся карты Кохонена»
textual
Листинг программы
private double hc(int k, double winnerCoordinate, double Coordinate) { double dist = Distance(winnerCoordinate, Coordinate); double s = sigma(k); return Math.Exp(-dist*dist / (2 * Sqr(sigma(k)))); }
ИИ поможет Вам:
- решить любую задачу по программированию
- объяснить код
- расставить комментарии в коде
- и т.д