Модераторы: Rickert
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Программирование нейронной сети - Самоорганизующей 
:(
    Опции темы
ColdDeath
Дата 9.11.2013, 17:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 18
Регистрация: 3.8.2009

Репутация: нет
Всего: нет



Пробую реализовать нейронную сеть Кохонена на C# на простом примере - распознавания образов, а конкретно 6 цифр: 0, 1, 2, 3, 4, 5.
Одно из описаний алгоритма работы сети Кохонена представлено здесь: http://gorbachenko.self-organization.ru/ar...anizing_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());
            }

        }
    }
}


Файл проекта находится во вложении. Готовые библиотеки не хочу использовать, так как хочу понять как самому реализовать.

Очень прошу, те кто знакомы с нейронными сетями, укажите, пожалуйста, на ошибку.
PM MAIL   Вверх
Агрох
Дата 10.12.2013, 09:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 176
Регистрация: 6.4.2013
Где: Москва

Репутация: нет
Всего: 6



Лень читать про сети Кохонена, поэтому просто спрошу:

Являются ли они обучаемыми без учителя?

Насколько я помню, для обучения любой сети требуется обучающая группа и контрольная группа. В вашем случае это хотя бы по 5 картинок обучающей группы, с немного отличающимися друг от друга изображениями всех цифр и ещё по 1-2 в контрольной группе, так же немного отличных друг от друга и от соответствующих картинок из группы для обучения. Если этого нет, то вы сможете в лучшем случае обучить сеть распознавать по одному конкретному изображению каждой цифры. Шаг влево, шаг вправо и уже не распознается. Например, при наличии "мусора" в изображении, или если изображение будет сдвинуто (не ровно по центру, как при обучении, а чуть чуть левее). Самыми проблемными в вашем примере являются цифры 2, 3, 5, которые могут распознаваться непредсказуемо, т.е. цифра 2 иногда будет распознаваться как 5 или 3 и наоборот.
--------------------
Putin here, Putin there, Putin almost everywhere!
PM MAIL   Вверх
prog2013
Дата 11.12.2013, 22:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 7
Регистрация: 16.11.2013

Репутация: нет
Всего: нет



> Когда происходит подстройка весов определенно нейрона, сильно искажаются ранее подстроенные веса других нейронов...

Я тоже скажу лишь как теоретик, в целом они и должны меняться. Они же в коллективе работают - в этом суть нейронных сетей. Вопрос лишь нет ли ошибки в программе.
PM   Вверх
Mirkes
Дата 6.3.2014, 18:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 586
Регистрация: 18.8.2011
Где: Красноярск

Репутация: нет
Всего: 17



Тема еще жива?
Если автор откликнется, могу попробовать помочь.


--------------------
Mirkes
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Программирование игр, графики и искуственного интеллекта"
Rickert

НА ЗЛОБУ ДНЯ: Дорогие посетители, прошу обратить внимание что новые темы касающиеся новых вопросов создаются кнопкой "Новая тема" а не "Ответить"! Любые оффтопиковые вопросы, заданные в текущих тематических темах будут удалены а их авторы, при рецедиве, забанены.

  • Литературу, связанную с программированием графики, обсуждаем здесь
  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы связанные с программированием графики и мультимедии на языках С++ и Delphi
  • Вопросы по реализации алгоритмов рассматриваются здесь

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Rickert.

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Программирование игр, графики и искусственного интеллекта | Следующая тема »


 




[ Время генерации скрипта: 0.0612 ]   [ Использовано запросов: 20 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.