/// <summary> /// Normalizuje wektor na przedział [0,ceiling] /// </summary> /// <param name="ceiling"> /// Górna granica przedziału /// </param> private void normalizeRange(LearningExample ex, double ceiling, int width, int height) { // Pętla mająca na celu znalezienie minimów i maksimów double min = Double.MaxValue; double max = Double.MinValue; for (int i = 0; i < width; i++) { for (int j = 0; j < height; j++) { int index = i * height + j; if (ex.Example[index] < min) min = ex.Example[index]; if (ex.Example[index] > max) max = ex.Example[index]; } } // Górna granica przedziału double ceil = max - min; // Mnożnik - dzielimy przez górną część otrzymując przedział [0,1], // a następnie mnożymy razy 256 żeby wartości były z całego zakresu // skali szarości double mult = ceiling / ceil; modifyEx(ex, min, mult, width, height); }
/// <summary> /// Tworzy nową klasyfikację /// </summary> /// <param name="perceptrons"> /// Lista perceptronów /// </param> /// <param name="example"> /// Przykład /// </param> public Classification(List<Perceptron> perceptrons, LearningExample example) { classifications = new List<double>(); LearningExample e = example; // Kolejne współrzędne są klasyfikacjami odpowiednich perceptronów foreach (Perceptron p in perceptrons) { classifications.Add(p.outputFunction(e.Example)); } }
/// <summary> /// Modyfikuje wartości wektora w celu normalizacji /// </summary> private void modifyEx(LearningExample ex, double min, double mult, int width, int height) { for (int i = 0; i < width; i++) { for (int j = 0; j < height; j++) { int index = i * height + j; ex.Example[index] = (ex.Example[index] - min) * mult; } } }
/// <summary> /// Algorytm redukcji składowych głównych /// </summary> internal void reduction(List<LearningExample> exampleList) { try { Dispatcher.Invoke(OnReductionStarted, this, new EventArgs()); List<LearningExample> list = new List<LearningExample>(exampleList); int dimension = exampleList[0].Example.Dimension; List<PerceptronLib.Vector> principalComponents = new List<PerceptronLib.Vector>(outputDimension); for (int i = 0; i < outputDimension; i++) { #if DEBUG printLine("i = " + i); #endif principalComponents.Add(ojLearn(list).Weights); PerceptronLib.Vector w = principalComponents[i]; //printLine("Składowa główna: " + w[0] + ", " + w[1] + ", " + w[2] + ", " + w[3]); //printLine("Składowa główna: długość = " + w.Length); List<LearningExample> nextList = new List<LearningExample>(); foreach (LearningExample ex in list) { PerceptronLib.Vector x = ex.Example; double val = w * w; double activation = w * x; PerceptronLib.Vector nextExVector = new PerceptronLib.Vector(dimension); nextExVector = x - w * (activation / val); nextExVector.normalizeWeights(); LearningExample nextEx = new LearningExample(nextExVector, 0); nextList.Add(nextEx); } list = nextList; } saveImages(principalComponents, examplesWidth, examplesHeight); Dispatcher.Invoke(OnReductionFinished, this, new EventArgs()); } catch (Exception ex) { printLine(ex.Message + " [ " + ex.StackTrace + " ]"); } }
/// <summary> /// Zapisuje utworzone obrazy na dysku /// </summary> private void saveImages(List<PerceptronLib.Vector> vectors, int width, int height) { try { //if (File.Exists(getDataBaseFileName()) == false) //{ // printLine("Plik bazy danych nie istnieje"); // return; //} // Otwiera plik bazy danych i nadpisuje go FileStream stream = new System.IO.FileStream(getDataBaseFileName(), FileMode.Create, System.IO.FileAccess.Write); EigenFacesDB db = new EigenFacesDB(vectors); BinaryFormatter formatter = new BinaryFormatter(); printLine("Zapisywanie wyników..."); int dimension = examples[0].Example.Dimension; for (int l = 0; l < examples.Count; l++) { LearningExample ex = examples[l]; // Tworzy nowy element bazy danych EigenNode node = new EigenNode("Przykład" + (l + 1)); PerceptronLib.Vector v = new PerceptronLib.Vector(dimension); //printLine("outputDim = " + outputDimension + ", vectors.count = " + vectors.Count); for (int k = 0; k < outputDimension; k++) { PerceptronLib.Vector p = vectors[k]; Bitmap img = new Bitmap(examplesWidth, examplesHeight); if (l == 0) { Bitmap eigenImg = new Bitmap(examplesWidth, examplesHeight); LearningExample eigenEx = new LearningExample(vectors[k], 0); normalizeRange(eigenEx, 256.0F, width, height); for (int i = 0; i < width; i++) { for (int j = 0; j < height; j++) { int index = i * height + j; byte color = (byte)(eigenEx.Example[index]); System.Drawing.Color c = System.Drawing.Color.FromArgb(255, color, color, color); eigenImg.SetPixel(i, j, c); } } eigenImg.Save("eigenVector-" + (k + 1) + ".jpg"); } double val = p * p; double activation = p * ex.Example; node.Coordinates.Add(activation); v += p * (activation / val); LearningExample newEx = new LearningExample(v, 0); normalizeRange(newEx, 256.0F, width, height); for (int i = 0; i < width; i++) { for (int j = 0; j < height; j++) { int index = i * height + j; byte color = (byte)(newEx.Example[index]); System.Drawing.Color c = System.Drawing.Color.FromArgb(255, color, color, color); img.SetPixel(i, j, c); } } img.Save("output" + (l + 1) + "-" + (k + 1) + ".jpg"); } db.add(node); } //foreach (EigenNode n in nodes) //{ // printLine("n.coordinates: " + n.Coordinates.Count); // db.add(n); //} printLine("Wymiar zapisywanej bazy: " + db.Dimension); try { formatter.Serialize(stream, db); } catch (Exception ex) { printLine("Wujątek: " + ex.Message + " [ " + ex.StackTrace + " ]"); } stream.Close(); } catch (Exception ex) { printLine(ex.Message + " [ " + ex.StackTrace + " ] " + ex.GetType()); } }
/// <summary> /// Funkcja przeznaczona do badania poprawności klasyfikowania przykładów przez sieć /// </summary> /// <returns> /// Zwraca true, jeśli wszystkie przykłady uczące są dobrze klasyfikowane przez sieć /// </returns> private bool verify() { foreach (LearningExample e in examples) { LearningExample newExample = e; // Oblicza klasyfikacje kolejno wszystkich warstw for (int i = 0; i < layers.Count; i++) { newExample = new LearningExample(layers[i].compute(newExample), newExample.ExpectedDoubleValue); } // Zwrócić wartość true możemy tylko wtedy, gdy ostatnia warstwa zawiera // tylko jeden perceptron if (layers[layers.Count - 1].OutputDimension != 2) { return false; } // Klasyfikacja ostatniego perceptronu zgadza się z wartością oczekiwaną if (newExample.Example[1] != newExample.ExpectedDoubleValue) return false; } return true; }
/// <summary> /// Funkcja przeznaczona do klasyfikacji konkretnego przykładu /// </summary> /// <param name="example"> /// Przykład /// </param> /// <returns> /// Klasyfikacja podanego przykładu /// </returns> public Vector classify(LearningExample example) { LearningExample newExample = example; classificationExamples = new List<LearningExample>(layers.Count); // Przechodzi kolejno przez wszystkie warstwy sieci for (int i = 0; i < layers.Count; i++) { newExample = new LearningExample(layers[i].compute(newExample), example.ExpectedValue); classificationExamples.Add(newExample); } //System.Windows.MessageBox.Show(newExample.ToString()); return newExample.Example; }
/// <summary> /// Zdarzenie przechwytywane w momencie poruszania myszą na canvasie. /// Ma na celu pokacywanie, jak klasyfikowane są odpowiednie punkty na płaszczyźnie /// przez stworzoną sieć. /// </summary> private void canvas_MouseMove(object sender, MouseEventArgs e) { // Sprawdzamy, czy sieć została już utworzona if (isNetworkCreated) { Point p = e.GetPosition(canvas); // Tworzy wektor przeznaczony do przeliczenia PerceptronLib.Vector v = new PerceptronLib.Vector(3); v[0] = 1; v[1] = p.X - 100; v[2] = p.Y - 100; // Tworzy obiekt przykładu LearningExample ex = new LearningExample(v, 0); // Sprawdza, na jaki kolor należy pomalować prostokąt if (network.classify(ex)[1] == 1) { // Koloruje na czerwono classRect.Fill = new SolidColorBrush(Colors.Red); } else { // Koloruje na niebiesko classRect.Fill = new SolidColorBrush(Colors.Blue); } } }