Программирование нейронной сети - Самоорганизующейся карты Кохонена - 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.
            
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;
            }
В результате я вывожу на каждой итерации Евклидово расстояние между каждым нейроном, соответствующим своему входному вектору. Так я хочу, увидеть, действительно ли веса нейроном подстроились согласно входным векторам. Но результаты выводятся несоответствующие ожиданиям. Когда происходит подстройка весов определенно нейрона, сильно искажаются ранее подстроенные веса других нейронов. Я полагаю, что проблема может быть либо в какой-то части реализации алгоритма обучения, либо конкретно в функции соседства hc. Привожу код проекта:
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))));
        }

ИИ поможет Вам:


  • решить любую задачу по программированию
  • объяснить код
  • расставить комментарии в коде
  • и т.д
Попробуйте бесплатно

Оцени полезность:

6   голосов , оценка 3.667 из 5
Похожие ответы