Форум программистов, компьютерный форум, киберфорум
C# .NET
Войти
Регистрация
Восстановить пароль
 
Рейтинг 4.51/119: Рейтинг темы: голосов - 119, средняя оценка - 4.51
0 / 0 / 0
Регистрация: 09.11.2013
Сообщений: 11
1

Программирование нейронной сети - Самоорганизующейся карты Кохонена

09.11.2013, 18:29. Просмотров 23624. Ответов 9


Пробую реализовать нейронную сеть Кохонена на C# на простом примере - распознавания образов, а конкретно 6 цифр: 0, 1, 2, 3, 4, 5.
Одно из описаний алгоритма работы сети Кохонена представлено здесь: http://gorbachenko.self-organi... ng_map.pdf

Реализую сеть следующим образом:
Описываю 2 класса:
- класс описания нейрона, который содержит такие параметры как: порядковый номер нейрона, массив его весов. При создании экцемпляра класса, необходимо конструктору указать, соответственно, порядковый номер нейрона и количество входов (весов). Веса будут назначены случайным образом в диапазоне от 0.0 до 1.0.
- класс описания сети Кохонена, включающей в себя количество входов, массив нейронов (экземпляров первого класса).

Как я уже писал ранее, для начала, я хочу отладить нейронную сеть на распознавании образов (картинок) изображений, соответствующих 6-ти цифрам. Размер каждого изображения 45*45 Для этого, я беру изображения каждой цифры и преобразую их в вектор (массив) длинной 2045.

C#
1
2
3
4
5
6
            
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);
Выдаю результат:
C#
1
2
3
4
            for (int i = 0; i < 6; i++)
            {
                textBox1.Text += "При подаче на вход " + i + "-го образца, Ответ: " + Test(net, InputVector[i]).ToString() + Environment.NewLine;
            }
В результате я вывожу на каждой итерации Евклидово расстояние между каждым нейроном, соответствующим своему входному вектору. Так я хочу, увидеть, действительно ли веса нейроном подстроились согласно входным векторам.

Но результаты выводятся несоответствующие ожиданиям. Когда происходит подстройка весов определенно нейрона, сильно искажаются ранее подстроенные веса других нейронов. Я полагаю, что проблема может быть либо в какой-то части реализации алгоритма обучения, либо конкретно в функции соседства hc.

Привожу код проекта:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
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());
            }
 
        }
    }
}
Файл проекта находится во вложении. Готовые библиотеки не хочу использовать, так как хочу понять как самому реализовать.

Очень прошу, те кто знакомы с нейронными сетями, укажите, пожалуйста, на ошибку.
0
Вложения
Тип файла: zip SOM.ZIP (52.9 Кб, 535 просмотров)
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
09.11.2013, 18:29
Ответы с готовыми решениями:

Не работает процедура обучения нейронной сети
Здравствуйте! Я написал свой класс нейронной сети, но обучение по алгоритму обратного...

Обучение нейронной сети и правильность ее концепции
Решил создать &quot;реалистичную&quot; самообучающуюся нейронную сеть. Концепция : создается Х нейронов,...

Создание нейронной сети для подбора растений в аквариум
Здравствуйте. Кто сталкивался, скиньте пример создания нейронной сети для задачи типа: &quot;Подбор...

Принятие решений нейронной сети в игре крестики нолики
Собственно есть нейронная сеть(слизанная с хабра), там нейронная сеть была предназначена для...

9
Master of Orion
Эксперт .NET
6079 / 4935 / 905
Регистрация: 10.07.2011
Сообщений: 14,522
Записей в блоге: 5
10.11.2013, 14:30 2
ColdDeath, если вам не помогут, то поищите по форуму (тут были по нейронным сетям топики, даже вполне хорошие), вот еще пара статей, может помогут:

http://habrahabr.ru/post/143129/

http://habrahabr.ru/post/143668/
0
0 / 0 / 0
Регистрация: 09.11.2013
Сообщений: 11
10.11.2013, 17:14  [ТС] 3
Статьи посмотрел, не подходят. В одной просто про нейронные сети в общем виде, а в другой про Кохонена, но по сути она таковой не является.
0
0 / 0 / 1
Регистрация: 12.11.2014
Сообщений: 109
12.11.2014, 22:30 4
http://www.twirpx.com/file/214887/
0
16 / 16 / 8
Регистрация: 18.03.2014
Сообщений: 268
02.02.2015, 17:09 5
Просто решил написать ^_^
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
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) // Eсли Евклидово расстояние минимально, то это нейрон-победитель
                    {
                        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]);
                        net.neurons[i].weights[g] = net.neurons[i].weights[g] + hfunc * normfunc * (InputVector[i][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());
            }
 
        }
    }
}
2
0 / 0 / 0
Регистрация: 27.03.2015
Сообщений: 1
27.03.2015, 15:04 6
C++
1
net.neurons[i].weights[g] = net.neurons[i].weights[g] + hfunc * normfunc * (InputVector[i][g] - net.neurons[i].weights[g]); // Вроде так работает
Если не ошибаюсь, то в исходном варианте было все правильно. Т.е. нужно брать именно тот входной вектор, на котором основывается обучение, т.е.

C++
1
net.neurons[i].weights[g] = net.neurons[i].weights[g] + hfunc * normfunc * (InputVector[k][g] - net.neurons[i].weights[g]);
А ошибки могут быть уже в самой формуле соседства... но не здесь.
0
16 / 16 / 8
Регистрация: 18.03.2014
Сообщений: 268
03.04.2015, 13:46 7
qu1ze, я не спец в этом, но как по мне главное это работает.
0
0 / 0 / 0
Регистрация: 28.09.2015
Сообщений: 1
29.09.2015, 01:16 8
Функция соседства написана неправильно, вот правильный вариант:
C#
1
2
3
4
5
6
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))));
        }
0
aquaMakc
29.09.2015, 11:22
  #9

Не по теме:

r0m1k, ))) и не важно, что последнее сообщение было полтора года назад

0
0 / 0 / 0
Регистрация: 16.05.2018
Сообщений: 1
11.12.2018, 21:28 10
ColdDeath, здравствуйте, у меня возник вопрос ,откуда в методе :

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;
}
взялась 1 после return?
я так полагаю это сигма нулевое,но как вы его нашли и почему лямда равна 5?
0
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
11.12.2018, 21:28

Заказываю контрольные, курсовые, дипломные и любые другие студенческие работы здесь или здесь.

Карты Кохонена для восстановления изображений
Здравствуйте! Попалась на глаза статья, где описывалась нейросеть для восстановления фрагментов...

Обучение нейронной сети encog
Здравствуйте. Скачал нейронную сеть. Пример обучения запускается. Работающий пример объявления...

Нет метода Main в примере нейронной сети
Начал изучать нейросети, а параллельно с#(есть начальная база, Которую дали в...

Разработка нейронной сети в matlab и интеграция с C#
Здравствуйте. Подскажите, пожалуйста, я в matlab разработал нейронную сеть, затем сохранил её в...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
10
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2021, vBulletin Solutions, Inc.