-
Notifications
You must be signed in to change notification settings - Fork 0
/
SOM.cs
209 lines (176 loc) · 8.6 KB
/
SOM.cs
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
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Kohonen_SOM
{
class SOM
{
private double[][] _inputs;
private double[,][] _weigthMap;//ağırlıkların tutulduğu harita
private double[,] _map;//en son işlem görüp konsolda gösterilecek olan harita
private List<double>[,] _commonIndexes;//her node un en çok eşleştiği input un index ini belirtmek için bir list matrisi
private int _attributeCount, _latticeLenght;
private Random _random = new Random();
public SOM(double[][] inputs,int latticeLength, int attributeCount)
{
_inputs = inputs;
_attributeCount = attributeCount;
_latticeLenght = latticeLength;
_weigthMap = new double[latticeLength, latticeLength][];
_map = new double[latticeLength, latticeLength];
//ağırlık matrisi 0-1 aralığında rastgele olarak dolduruluyor
InitializingWeights();
}
//ordering phase;
public void Run(double timeConstant2, double learningRate0, double effectiveWidth0)
{
//Ordering Phase(1000 iterasyon, learningRate(başlangıç) 0.1, learningRate alt sınırı 0.01, effectiveWidth 5);
TheAlgorithm(timeConstant2, learningRate0, effectiveWidth0, 0.01, false);
CreateAndShowTheMap();//o anda oluşan harita konsolda gösterilir
//Convergence Phase(50000 iterasyon, learningRate 0.01, learningRate alt sınırı 0, effectiveWidth 5);
TheAlgorithm(500*Math.Pow(_latticeLenght, 2), 0.01, effectiveWidth0, 0, true);
CreateAndShowTheMap();
}
private void TheAlgorithm(double timeConstant2, double learningRate0,
double effectiveWidth0, double lRLowerBound, bool convergence)
{
//her işlem öncesi node lara ait en çok tekrar eden index listeleri yenilenir(ordering-convergence)
_commonIndexes = new List<double>[_latticeLenght,_latticeLenght];
int iteration = 0;
double effectiveWidth = effectiveWidth0;
double learningRate = learningRate0;
double timeConstant1 = timeConstant2 / Math.Log10(effectiveWidth0);
int randomIndex;
while (iteration != timeConstant2)
{
//input vektörlerinden rastgele biri seçilir;
randomIndex = _random.Next(0, 500);
double[] inputVector = _inputs[randomIndex];
double minDistance = 10000, distance;
int winnerNeuronX = -1, winnerNeuronY = -1;//node un koordinatları
// kazanan node ve lokasyonu bulunur;
for (int i = 0; i < _latticeLenght; i++)
{
for (int j = 0; j < _latticeLenght; j++)
{
distance = EuclideanDistance(_weigthMap[i, j], inputVector);
if (distance < minDistance)
{
if (_commonIndexes[i, j] == null)// o node a ait commonIndexes listesi yok ise
{
_commonIndexes[i, j] = new List<double>();
}
minDistance = distance;
winnerNeuronX = i;
winnerNeuronY = j;
_commonIndexes[i, j].Add(randomIndex);/*kazanan node un koordinatlarına karşılık gelen
başka bir listedeki index e node un kazandığı input setinin bir göstergesi eklenir
(bu durumda o input setinin satır index i)*/
}
}
}
// haritadaki tüm node ların ağırlıkları hji ye bağlı olarak güncellenir;
double hji;
for (int i = 0; i < _latticeLenght; i++)
{
for (int j = 0; j < _latticeLenght; j++)
{
hji = Gaussian(winnerNeuronX, winnerNeuronY, i, j, effectiveWidth);
for (int k = 0; k < _weigthMap[i, j].Length; k++)
{
//haritada bulunan ij node unun ağırlık vektörü güncelleniyor;
_weigthMap[i, j][k] = _weigthMap[i, j][k] + learningRate * hji * (inputVector[k] - _weigthMap[i, j][k]);
}
}
}
//Iterasyon sonu işlemleri;
effectiveWidth = effectiveWidth0 * Math.Exp(-iteration / timeConstant1);
if (learningRate > lRLowerBound)//öğrenme hızı alt sınır kontrolü
{
learningRate = learningRate0 * Math.Exp(-iteration / timeConstant2);
}
iteration++;
}
if(convergence)
{
Console.WriteLine("-------------------------------------------------------------------------------------");
Console.WriteLine("Convergence Phase"+Environment.NewLine);
}
else
{
Console.WriteLine("Ordering Phase" + Environment.NewLine);
}
Console.WriteLine("LearningRate ve EffectiveWidth son değerleri: ");
Console.WriteLine("LearningRate = " + learningRate + " EffectiveWidth = " + effectiveWidth+Environment.NewLine);
Console.WriteLine("Harita: " + Environment.NewLine);
}
//hji değerini bulmak için Gaussian fonksiyonu kullanıldı;
private double Gaussian(int winnerX, int winnerY, int neuronX, int neuronY, double effectiveWidth)
{
double[] vector1 = { winnerX, winnerY };
double[] vector2 = { neuronX, neuronY };
double result = Math.Exp(-(Math.Pow(EuclideanDistance(vector1, vector2), 2) / (2 * Math.Pow(effectiveWidth, 2))));
return result;
}
private double EuclideanDistance(double[] vector1, double[] vector2)
{
double sum = 0;
for (int i = 0; i < vector1.Length; i++)
{
sum += Math.Pow(vector1[i] - vector2[i], 2);
}
double result = Math.Sqrt(sum);
return result;
}
//sonuç haritasını oluşturan ve konsolda gösteren metod;
private void CreateAndShowTheMap()
{
//harita oluşturulur;
for (int i = 0; i < _latticeLenght; i++)
{
for (int j = 0; j < _latticeLenght; j++)
{
if (_commonIndexes[i, j] != null)
{
//her node a karşılık gelen _commonIndexes[i,j] listesinin en çok tekrar eden değeri
//sonuç haritasının o indexlerdeki değeri olur;
_map[i, j] = _commonIndexes[i, j].GroupBy(item => item).
OrderByDescending(grp => grp.Count()).Select(grp => grp.Key).First();
}
else//o node da hiç eşleşme olmamış ise;
{
_map[i, j] = -1;
}
}
}
//harita konsola yazdırılır;
for (int i = 0; i < _latticeLenght; i++)
{
for (int j = 0; j < _latticeLenght; j++)
{
Console.Write(_map[i, j] + " ");
}
Console.WriteLine(Environment.NewLine);
}
}
//başlangıçta ağırlıklar 0-1 aralığında rastgele dağıtılır;
private void InitializingWeights()
{
for (int i = 0; i < _latticeLenght; i++)
{
for (int j = 0; j < _latticeLenght; j++)
{
double[] weightArray = new double[_attributeCount];
for (int k = 0; k < weightArray.Length; k++)
{
double randomWeight= _random.NextDouble();
weightArray[k] = randomWeight;
}
_weigthMap[i, j] = weightArray;
}
}
}
}
}