Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Мой бакалаврский опус.pdf
Скачиваний:
11
Добавлен:
27.03.2015
Размер:
1.29 Mб
Скачать

Заключение

Врезультате проведённой работы была создана и апробирована на конкретных примерах программная система, способная распознавать рукописные символы на изображениях, представленных в виде графических файлов в BMP-формате.

Тестирование программной системы проводилось на примерах изображений, содержащих как символы того же почерка, который использовался в процессе обучения, так

исимволы других почерков, которые классификатор (многослойный персептрон) ни разу не встречал среди объектов обучающей выборки. При этом система показала способность не только эффективно подстраиваться под конкретный почерк, но и обобщать свой опыт, решая поставленную задачу и на примерах изображений с начертаниями символов других почерков, которые не использовались в процессе обучения.

Входе реализации программной системы была усовершенствована традиционная версия BPE-алгоритма обучения многослойного персептрона (метод градиентного спуска был дополнен квазиньютоновскими методами со встроенными градиентными шагами), что позволило в ряде случаев увеличить скорость сходимости алгоритма и достижения требуемой точности обучения.

Благодаря разнообразным настройкам, предусмотренным в приложениях системы, их варьирование позволяет повысить эффективность выделения рукописного символа на изображении, а также обучения многослойного персептрона и, как следствие, улучшить качество классификации образов.

Кроме того, приложения разработанной программной системы отличаются высокой степенью гибкости, то есть способностью к модификации и усовершенствованию путём внесения незначительных изменений в их структуру. Такими изменениями, в частности, могут быть:

поддержка большего количества графических форматов входных изображений (gif, jpg и др.);

расширение набора фильтров, применяемых для выделения рукописных символов на изображениях;

извлечение дополнительных признаков, характеризующих рукописный символ;

добавление или выбор других методов оптимизации для их использования в алгоритме обучения многослойного персептрона.

44

Список литературы

1.Teuvo Kohonen. Automatic formation of topological maps of patterns in a self-organizing system. In Erkki Oja and Olli Simula, editors, Proc. 2SCIA, Scand. Conf. on Image Analysis, pages 214-220, Helsinki, Finland, 1981. Suomen Hahmontunnistustutkimuksen Seura r. y.

2.C.Cortes, V.Vapnik. Support Vector Networks, Machine Learning 20(3): 273-297, 1995.

3.Гонсалес, Р. Цифровая обработка изображений / Р. Гонсалес, Р. Вудс. – Москва:

Техносфера, 2005. – 1072 с.: ил. ISBN 5-94836-028-8.

4.Дуда, Р. Распознавание образов и анализ сцен / Р. Дуда, П. Харт. – М.: Мир, 1976. – 511 с.

5.Золотых, Н. Ю. Машинное обучение. Курс лекций. – Режим доступа: http://www.uic.unn.ru/~zny/ml/, свободный.

6.Горошкин, А. Н. Обработка и распознавание рукописного текста в системах электронного документооборота: автореф. дис ... канд. техн. наук: 05.13.01 / Горошкин Антон Николаевич. – Красноярск, 2008. – 22 с.

7.Галушкин А. И. Синтез многослойных систем распознавания образов. — М.: «Энергия», 1974.

8.Werbos P. J. Beyond regression: New tools for prediction and analysis in the behavioral sciences. Ph.D. thesis, Harvard University, Cambridge, MA, 1974.

9.Круглов, В.В. Искусственные нейронные сети. Теория и практика / В. В. Круглов, В. В. Борисов. – 2-е изд., стереотип. – М.: Горячая линия – Телеком, 2002. – 382 с.: ил. ISBN 5- 93517-031-0.

10.Комарцова, Л. Г. Нейрокомпьютеры. Учебное пособие для вузов / Л. Г. Комарцова, А. В.

Максимов. – 2-е изд. – М.: МГТУ им. Баумана, 2004. – 400 с.: ил. ISBN 5-7038-2554-7.

11.Хайкин, С. Нейронные сети: полный курс / С. Хайкин. – 2-е изд. М.: Издат. дом

«Вильямс», 2008. – 1104 с.: ил. ISBN 5-8459-0890-6.

12.Шапиро, Л. Компьютерное зрение / Л. Шапиро, Дж. Стокман. – Пер. с англ. – М.: БИНОМ. Лаборатория знаний, 2006. – 752 с.

13.Форсайт, Д. Компьютерное зрение. Современный подход / Д. Форсайт, Ж. Понс. – Пер. с англ. – М.: Издательский дом «Вильямс», 2004. – 928 с.

14.Рассел, С. Искусственный интеллект: современный подход (AIMA) / С. Рассел, П. Норвиг. – Пер. с англ. – М.: Издательский дом «Вильямс», 2006. – 1407 с.

15.Bradski G., Kaehler A. Learning OpenCV – Computer Vision with the OpenCV, 2008, p. 254.

16.Измаилов, А. Ф. Численные методы оптимизации / А.Ф. Измаилов, М.В. Солодов. – 2-е

изд., перераб. и доп. – М.: ФИЗМАТЛИТ, 2008. – 320 с.: ил. ISBN 978-5-9221-0975-8.

45

Приложение А. Исходные коды базовых компонентов программной системы

А.1. Классы для поддержки работы с растровыми изображениями

Листинг А.1: Трёхкомпонентный вектор для представления цвета в модели RGB

using System;

namespace Vectors

{

public class Vector

{

#region Public Fields

public float R; public float G; public float B;

#endregion

///<summary> Конструктор </summary>

public Vector(float r, float g, float b) {R = r; G = g; B = b;}

///<summary> Преобразование в массив </summary> public float[] ToArray() { return new float[] { R, G, B }; }

#region Properties

public float this[int index]

{

get

{

if (0 == index) return R;

else if (1 == index) return G; else return B;

}

set

{

if (0 == index) R = value; else if (1 == index) G = value; else B = value;

}

}

public static Vector Black { get { return new Vector(0, 0, 0); } }

public static Vector White { get { return new Vector(1f, 1f, 1f); } }

46

public float Intensity { get { return 0.299f * R + 0.587f * G + 0.114f * B; } }

#endregion

}

}

Листинг А.2: Полутоновое и бинарное растровые изображения

namespace Rasters

{

/// <summary> Полутоновое растровое изображение </summary> public class Raster

{

/// <summary> Массив пикселей растра. </summary> protected Vector[,] pixels = null;

public string FileName = "";

#region Constructors

public Raster() {}

/// <summary> Создает новый растр по заданной ширине и высоте. </summary> public Raster(int width, int height)

{

//создаем массив пикселей pixels = new Vector[width, height];

//присваиваем всем пикселям черный цвет for (int j = 0; j < height; j++)

for (int i = 0; i < width; i++) pixels[i, j] = Vector.Black;

}

/// <summary> Создает новый растр из заданного графического файла. </summary> public Raster(string filename)

{

//создаем объект Bitmap из файла

Bitmap bitmap = new Bitmap(filename);

//создаем массив пикселей

pixels = new Vector[bitmap.Width, bitmap.Height];

// копируем пикселей из объекта Bitmap в растр for (int j = 0; j < bitmap.Height; j++)

{

for (int i = 0; i < bitmap.Width; i++)

{

Color color = bitmap.GetPixel(i, j);

pixels[i, j] = new Vector(color.R / 255f, color.G / 255f, color.B / 255f);

47

}

}

}

#endregion

#region Public Methods

/// <summary> Конвертирование растра в объект Bitmap. </summary> public Bitmap ToBitmap()

{

// создаем новый объект Bitmap

Bitmap bitmap = new Bitmap(Width, Height);

// копируем содержимое растра for (int j = 0; j < Height; j++)

{

for (int i = 0; i < Width; i++)

{

bitmap.SetPixel(i, j, Color.FromArgb((int) (255 * pixels[i, j].R), (int) (255 * pixels[i, j].G), (int) (255 * pixels[i, j].B)));

}

}

return bitmap;

}

#endregion

#region Properties

/// <summary> Ширина растра. </summary>

public int Width { get { return pixels.GetLength(0); } }

/// <summary> Высота растра. </summary>

public int Height { get { return pixels.GetLength(1); } }

/// <summary> Обеспечение прямого доступа к пикселям растра. </summary> public Vector this[int i, int j]

{

get

{

if (i < 0) i = 0;

if (i > Width - 1) i = Width - 1; if (j < 0) j = 0;

if (j > Height - 1) j = Height - 1;

return pixels[i, j];

}

set

48

{

if (i > -1 && i < Width) if (j > -1 && j < Height) pixels[i, j] = value;

}

}

#endregion

}

/// <summary> Бинарное растровое изображение </summary> public class BinaryRaster: Raster

{

public Rectangle LimitingRectangle = new Rectangle(); // ограничивающий прямоугольник

#region Constructors

public BinaryRaster(Raster SourceRaster)

{

int width = SourceRaster.Width; int height = SourceRaster.Height;

pixels = new Vector[width, height];

for (int i = 0; i < width; i++) for (int j = 0; j < height; j++) this[i, j] = SourceRaster[i, j];

}

public BinaryRaster(int width, int height) : base(width, height) { }

#endregion

 

private double [] InputSignal = null;

// вектор входных сигналов

private TPoint CalcCenterPoint()

// подсчёт центра области

{

 

TPoint Result = new TPoint(0, 0); int N = 0; for (int i = 0; i<Width; i++)

for (int j = 0; j<Height; j++) if (this[i, j] == Vector.Black)

{ N++; Result.x += i; Result.y += j; } Result.x /= N; Result.y /= N;

return Result;

}

/// <summary> Вычисление центрального момента области </summary> public double GetCenterMoment(int i, int j)

{

TPoint CenterPoint = CalcCenterPoint();

double Sum = 0.0;

49

for (int m = 0; m<Width; m++) for (int n = 0; n<Height; n++) if (this[m, n] == Vector.Black)

{ Sum += Math.Pow(m - CenterPoint.x, i) * Math.Pow(n - CenterPoint.y, j); }

return Sum;

}

/// <summary> Нормализованный центральный момент области </summary> public double GetNormalizeCenterMoment (int i, int j)

{

double numerator = GetCenterMoment(i,j);

double denominator = Math.Pow(GetCenterMoment(0,0), i+j); return numerator/denominator;

}

#region Invariants Calculation Methods

public double GetInvariant_Elongation()

{

double m20 = GetNormalizeCenterMoment(2, 0); double m02 = GetNormalizeCenterMoment(0, 2); double m11 = GetNormalizeCenterMoment(1, 1);

double d = Math.Sqrt((m20 - m02) * (m20 - m02) + 4 * m11 * m11);

return (m20 + m02 + d) / (m20 + m02 - d);

}

public double GetInvariant_First()

{

double m20 = GetNormalizeCenterMoment(2, 0); double m02 = GetNormalizeCenterMoment(0, 2); return m20 + m02;

}

public double GetInvariant_Second()

{

double m20 = GetNormalizeCenterMoment(2, 0); double m02 = GetNormalizeCenterMoment(0, 2); double m11 = GetNormalizeCenterMoment(1, 1);

double result = (m20 - m02) * (m20 - m02) + 4 * m11 * m11;

return result;

}

public double GetInvariant_Third()

{

double m30 = GetNormalizeCenterMoment(3, 0); double m03 = GetNormalizeCenterMoment(0, 3); double m21 = GetNormalizeCenterMoment(2, 1);

50

double m12 = GetNormalizeCenterMoment(1, 2);

double result = (m30 - 3 * m12) * (m30 - 3 * m12) + (3 * m21 - m03) * (3 * m21 - m03);

return result;

}

public double GetInvariant_Fourth()

{

double m30 = GetNormalizeCenterMoment(3, 0); double m03 = GetNormalizeCenterMoment(0, 3); double m21 = GetNormalizeCenterMoment(2, 1); double m12 = GetNormalizeCenterMoment(1, 2);

double result = (m30+m12)*(m30+m12)+(m21+m03)*(m21+m03);

return result;

}

public double GetInvariant_Fifth()

{

double m30 = GetNormalizeCenterMoment(3, 0); double m03 = GetNormalizeCenterMoment(0, 3); double m21 = GetNormalizeCenterMoment(2, 1); double m12 = GetNormalizeCenterMoment(1, 2);

double result = (m30 - 3 * m12) * (m30 + m12) * (Math.Pow(m30 + m12, 2)-3 * Math.Pow(m21 + m03, 2))+ (3 * m21 - m03) * (m21 + m03) * (3*Math.Pow(m30 + m12, 2) - Math.Pow(m21 + m03, 2));

return result;

}

public double GetInvariant_Sixth()

{

double m20 = GetNormalizeCenterMoment(2, 0); double m02 = GetNormalizeCenterMoment(0, 2); double m30 = GetNormalizeCenterMoment(3, 0); double m03 = GetNormalizeCenterMoment(0, 3); double m11 = GetNormalizeCenterMoment(1, 1); double m21 = GetNormalizeCenterMoment(2, 1); double m12 = GetNormalizeCenterMoment(1, 2);

double result = (m20 + m02) * (Math.Pow(m30 + m12, 2) - 3 * Math.Pow(m21 + m03, 2)) - 4 * m11 * (m30 + m12) * (m03 + m21);

return result;

}

public double GetInvariant_Seventh()

{

double m30 = GetNormalizeCenterMoment(3, 0);

51

double m03 = GetNormalizeCenterMoment(0, 3); double m21 = GetNormalizeCenterMoment(2, 1); double m12 = GetNormalizeCenterMoment(1, 2);

double result = (3 * m21 - m03) * (m12 + m30) * (m30 + m12 * m12 - 3 * Math.Pow(m21 + m03, 2)) - (m30 - 3 * m12) * (m12 + m03) * (3 * Math.Pow(m30 + m12, 2) - Math.Pow(m21 + m03, 2));

return result;

}

#endregion

///<summary> Формирование признакового описания области </summary> public void InputSignalsForming(double [] Array)

{

Array[0] = GetInvariant_First(); Array[1] = GetInvariant_Second(); Array[2] = GetInvariant_Third(); Array[3] = GetInvariant_Fourth(); Array[4] = GetInvariant_Fifth(); Array[5] = GetInvariant_Sixth(); Array[6] = GetInvariant_Seventh();

}

//Направления поиска черных пикселей enum Direction { On_Width, On_Height };

private bool NoBlackPixels(int index, Direction direction)

{

switch (direction)

{

case Direction.On_Width:

{

for (int j = 0; j<Height; j++)

if (this[index, j] == Vector.Black) return false;

break;

}

case Direction.On_Height:

{

for (int i = 0; i<Width; i++)

if (this[i, index] == Vector.Black) return false;

break;

}

default: { break; }

}

52

return true;

}

// Вычисление ограничивающего прямоугольника для области на бинарном изображении public Rectangle GetLimitingRectangle()

{

int center_x = CalcCenterPoint().x; int center_y = CalcCenterPoint().y;

int i, j;

i = center_x; j = center_y;

while ((i>0)&&!NoBlackPixels(i, Direction.On_Width)) i--; while ((j>0)&&!NoBlackPixels(j, Direction.On_Height)) j--; TPoint LowPoint = new TPoint(i, j);

i = center_x; j = center_y;

while ((i<Width)&&!NoBlackPixels(i, Direction.On_Width)) i++; while ((j<Height)&&!NoBlackPixels(j, Direction.On_Height)) j++; TPoint HighPoint = new TPoint(i, j);

return new Rectangle(LowPoint.x, LowPoint.y, HighPoint.x - LowPoint.x, HighPoint.y - LowPoint.y);

}

// Формирование бинарного изображения из ограничивающего прямоугольника public BinaryRaster FromLimitingRectangle()

{

LimitingRectangle = GetLimitingRectangle();

BinaryRaster result = new BinaryRaster(LimitingRectangle.Width,

LimitingRectangle.Height);

for (int i = 0; i < LimitingRectangle.Width; i++) for (int j = 0; j < LimitingRectangle.Height; j++)

result[i, j] = this[LimitingRectangle.X + i, LimitingRectangle.Y + j]; return result;

}

}

/// <summary> Вспомогательная структура целочисленной точки </summary> struct TPoint

{

public int x; public int y;

public TPoint(int value_x, int value_y) { x = value_x; y = value_y; }

}

}

53

Листинг А.3: Фильтры, используемые для обработки растровых изображений

using System;

using System.Collections;

using System.ComponentModel;

using Rasters; using Vectors;

namespace Filters

{

/// <summary> Абстрактный фильтр для обработки изображения </summary> public abstract class ImageFilter

{

/// <summary> Метод, обрабатывающий заданный растр. </summary> public abstract Raster ProcessImage(Raster source, BackgroundWorker worker);

}

/// <summary> Медианный фильтр для шумоподавления </summary> public class MedianFilter: ImageFilter

{

int r; // радиус действия фильтра

public MedianFilter(int parameter) { r = parameter; }

public static void QuickSortColors(Vector [] A, int left, int right)

{

int i = left; int j = right;

int middle = (left + right) / 2; Vector a = A[middle];

do

{

while ((A[i].Intensity < a.Intensity) && (i < right)) i++; while ((a.Intensity < A[j].Intensity) && (j > left)) j--; if (i <= j)

{

Vector tmp = A[i]; A[i] = A[j]; A[j] = tmp; i++; j--;

}

}

while (i <= j);

if (left < j) QuickSortColors(A, left, j); if (i < right) QuickSortColors(A, i, right);

}

public override Raster ProcessImage(Raster source, BackgroundWorker worker)

{

Raster result = new Raster(source.Width, source.Height);

DateTime starttime = DateTime.Now;

54

for (int j = 0; j<source.Height; j++)

{

for (int i = 0; i<source.Width; i++)

{

int N = 0;

Vector [] environment = new Vector [(2*r+1)*(2*r+1)]; for (int l = -r; l <= r; l++)

for (int k = -r; k <= r; k++)

if ((i + k >= 0) && (i + k <= source.Width) && (j + l >= 0) && (j + l <= source.Height))

{

environment[(2 * r + 1) * (k + r) + l + r] = source[i + k, j + l]; N++;

}

else environment[(2 * r + 1) * (k + r) + l + r] = new Vector(-1.0f, -1.0f, -1.0f);

Vector[] array = new Vector[N]; int index = 0; for (int m = 0; m < (2 * r + 1) * (2 * r + 1); m++)

if (environment[m] != new Vector(-1.0f, -1.0f, -1.0f)) array[index++] = environment[m];

QuickSortColors(array, 0, N - 1);

result[i,j] = array[N/2];

}

worker.ReportProgress((int)(100 * (j + 1) / source.Height), DateTime.Now - starttime);

if (worker.CancellationPending) { result = source; break; }

}

return result;

}

}

/// <summary> Абстрактный фильтр адаптивной бинаризации </summary> public abstract class AdaptiveBinarizationFilter: ImageFilter

{

protected double offset = 0.0;

// смещение величины порога

protected int r = 1;

// радиус действия фильтра

public AdaptiveBinarizationFilter() {}

public AdaptiveBinarizationFilter(int value_r, double value_offset)

{

r = value_r; offset = value_offset;

}

public override Raster ProcessImage(Raster source, BackgroundWorker worker)

{

Raster result = new Raster(source.Width, source.Height);

55

double[,] Vicinity = new double[2 * r + 1, 2 * r + 1];

DateTime starttime = DateTime.Now;

for (int j = 0; j < source.Height; j++)

{

for (int i = 0; i < source.Width; i++)

{

for (int l = -r; l <= r; l++) for (int k = -r; k <= r; k++)

if ((i + k >= 0) && (j + l >= 0) && (i + k < source.Width) &&

(j + l < source.Height))

Vicinity[r + k, r + l] = source[i + k, j + l].Intensity; else Vicinity[r + k, r + l] = -1.0;

double T = CalcThreshold(Vicinity);

result[i, j] = (source[i, j].Intensity > T + offset) ? Vector.White : Vector.Black;

}

worker.ReportProgress((int)(100 * (j + 1) / source.Height), DateTime.Now - starttime);

if (worker.CancellationPending) { result = source; break; }

}

return result;

}

/// <summary> Вычисление порога для окрестности пиксела </summary> public abstract double CalcThreshold(double [,] Vicinity);

}

///<summary> Фильтр бинаризации изображения по константному порогу </summary> public class SimpleBinarizationFilter: ImageFilter

{

float T = 0.5f; // константный порог

public SimpleBinarizationFilter(float Value_T) {T = Value_T;}

public override Raster ProcessImage(Raster source, BackgroundWorker worker)

{

Raster result = new Raster(source.Width, source.Height); DateTime starttime = DateTime.Now;

for (int j=0; j<source.Height; j++)

{

for (int i=0; i<source.Width; i++)

{

result[i,j] = source[i,j].Intensity<T ? Vector.Black : Vector.White;

}

56

worker.ReportProgress((int)(100 * (j + 1) / source.Height), DateTime.Now - starttime);

if (worker.CancellationPending) { result = source; break; }

}

return result;

}

}

/// <summary> Фильтр бинаризации: порог - среднее значение яркости </summary> public class MeanBinarizationFilter: AdaptiveBinarizationFilter

{

public MeanBinarizationFilter(int value_r, double value_offset): base(value_r, value_offset) {}

public override double CalcThreshold(double[,] Vicinity)

{

double result = 0.00;

int width = Vicinity.GetLength(0); int height = Vicinity.GetLength(1); int N = 0;

for (int j = 0; j < height; j++) for (int i = 0; i < width; i++)

if (Vicinity[i, j] >= 0) { result += Vicinity[i, j]; N++; } return result / N;

}

}

/// <summary> Фильтр бинаризации: порог - медиана набора яркостей </summary> public class MedianBinarizationFilter: AdaptiveBinarizationFilter

{

public MedianBinarizationFilter(int value_r, double value_offset): base(value_r, value_offset) {}

public override double CalcThreshold(double[,] Array)

{

int height = Array.GetLength(0); int width = Array.GetLength(1); int N = width*height;

ArrayList Result = new ArrayList();

for (int i = 0; i < height; i++) for (int j = 0; j < width; j++)

if (Array[i, j] >= 0) Result.Add(Array[i, j]);

Result.Sort();

int MiddleIndex = Result.Count / 2;

return (double)Result[MiddleIndex];

}

}

57

///<summary> Фильтр бинаризации: порог - усреднённая сумма

///минимального и максимального значений яркости </summary> public class MinMaxBinarizationFilter: AdaptiveBinarizationFilter

{

public MinMaxBinarizationFilter(int value_r, double value_offset): base(value_r, value_offset) {}

private double Min(double [,] array)

{

double Result = System.Double.MaxValue;

int height = array.GetLength(1); int width = array.GetLength(0);

for (int j = 0; j<height; j++)

for (int i = 0; i<width; i++)

if ((array[i,j]>=0)&&(array[i,j]<Result)) Result = array[i,j];

return Result;

}

private double Max(double [,] array)

{

double Result = System.Double.MinValue;

int height = array.GetLength(1); int width = array.GetLength(0);

for (int j = 0; j<height; j++)

for (int i = 0; i<width; i++)

if (array[i,j]>Result) Result = array[i,j];

return Result;

}

public override double CalcThreshold(double[,] Array)

{

return (Min(Array)+Max(Array))/2;

}

}

/// <summary> Фильтр морфологического расширения </summary> public class MathMorphologyDilation: ImageFilter

{

bool [,] Mask = {{false, true, false}, {true, true, true}, {false, true, false}};

int width = 3, height = 3;

58

public MathMorphologyDilation(bool [,] Value_Mask)

{

height = Value_Mask.GetLength(1);

width = Value_Mask.GetLength(0); Mask = new bool[width, height]; for (int j = 0; j<height; j++)

for (int i = 0; i<width; i++) Mask[i,j] = Value_Mask[i,j];

}

public override Raster ProcessImage(Raster source, BackgroundWorker worker)

{

Raster result = new Raster(source.Width, source.Height); DateTime starttime = DateTime.Now;

for (int j=0; j<source.Height; j++)

{

for (int i = 0; i<source.Width; i++)

{

float MIN = 1.0f; Vector v = new Vector(-1.0f, -1.0f, -1.0f); for (int k = -width/2; k<=width/2; k++)

{

for (int l = -height/2; l<=height/2; l++)

if ((i + k >= 0) && (i + k < source.Width) && (j + l >= 0) && (j + l < source.Height))

if ((Mask[width/2+k, height/2+l])&&(source[i+k, j+l].Intensity<MIN))

{

v = source[i+k, j+l]; MIN = v.Intensity;

}

result[i, j] = v;

}

worker.ReportProgress((int)(100 * (j+1) / source.Height), DateTime.Now - starttime);

if (worker.CancellationPending) { result = source; break; }

}

return result;

}

}

}

59

А.2. Классы для поддержки функционирования многослойного персептрона

Листинг А.4: Пользовательские типы и структуры данных

// Структура для хранения параметров активационных функций public struct TParams

{

public double k, A, a; // набор параметров активационных функций

public TParams(double value_k, double value_A, double value_a)

{

k = value_k; A = value_A; a = value_a;

}

}

// типы слоёв персептрона

public enum LayerType {BURIED, HAPTIC, MOTOR};

// типы активационных функций

public enum ActivationFunctionType {Linear, Sigma, Tangent};

// методы оптимизации

public enum LearningMethod { Gradient_Descent, Davidon_Fletcher_Pauell, Broiden_Fletcher_Goldfarb_Shenno };

#region Types of functions

public sealed class TLinear

{

public static double Activation(TParams ob, double s) { return ob.k * s; } public static double Derivative(TParams ob, double s) { return ob.k; }

}

public sealed class TSigma

{

public static double Activation(TParams ob, double s) { return ob.A / (1 + Math.Exp(-ob.a * s)); } public static double Derivative(TParams ob, double s) { return ob.A * ob.a * Math.Exp(-ob.a * s)

/ Math.Pow(1 + Math.Exp(-ob.a * s), 2); }

}

public sealed class THyptan

{

public static double Activation(TParams ob, double s) { return ob.A * Math.Tanh(ob.a * s); } public static double Derivative(TParams ob, double s) { return ob.A * ob.a /

Math.Pow(Math.Cosh(ob.a * s), 2); }

}

60

public sealed class Zero

{

public static double Activation(TParams ob, double s) { return 0; } public static double Derivative(TParams ob, double s) { return 0; }

}

#endregion

//------------------------------------------------------------------------

public delegate double TFunction(TParams ob, double s);

//------------------------------------------------------------------------

 

public struct TTrainerTemplate

// структура трнировочного шаблона

{

 

public double [] InputSignalsVector;

// вектор входных сигналов

public double [] OutputSignalsVector;

// вектор выходных сигналов

public TTrainerTemplate(double [] Input, double [] Output)

{

InputSignalsVector = new double [Input.Length]; OutputSignalsVector = new double [Output.Length];

Input.CopyTo(InputSignalsVector, 0); Output.CopyTo(OutputSignalsVector, 0);

}

}

 

//------------------------------------------------------------------------

 

public struct TLayerProperties

// свойства слоя

{

 

public LayerType Type;

// тип слоя

public int NumberNeirons;

// число нейронов в слое

public ActivationFunctionType FunctionType;

// тип активационной функции нейронов слоя

public TLayerProperties(LayerType Value_Type, int Value_NumberNeirons, ActivationFunctionType Value_FunctionType)

{

Type = Value_Type;

NumberNeirons = Value_NumberNeirons; FunctionType = Value_FunctionType;

}

}

delegate double UnivariateFunction(double t);

61

Листинг А.5: Классы, инкапсулирующие информацию о нейроне и о слое нейронов

internal class TNeiron

 

// нейрон - базовый элемент сети

{

 

 

public TParams Params;

 

// параметры активационной функции

public TFunction ActivationFunction;

// активационная функция нейрона

public TFunction DerivativeFunction;

// производная активационной функции

public double threshold;

 

// порог активационной функции

public TNeiron()

 

// конструктор по умолчанию

{

 

 

Params = new TParams(1.0, 1.0, 1.0);

 

threshold = 0.0;

 

 

}

 

 

}

 

 

internal class TLayer

// слой нейронов

{

 

 

public TNeiron[] Neiron;

//массив нейронов

public LayerType flag;

//признак назначения слоя

private int quantity;

//число нейронов в слое

#region Constructors

 

 

public TLayer() {}

 

//конструктор по умолчанию

public TLayer(TLayerProperties Properties) //параметризованный конструктор

{

quantity = Properties.NumberNeirons;

Neiron = new TNeiron[quantity];

TFunction f_activation, f_derivative;

// Определяем тип активационной функции нейронов слоя и её производной

switch (Properties.FunctionType)

{

case ActivationFunctionType.Linear:

{

f_activation = new TFunction(TLinear.Activation); f_derivative = new TFunction(TLinear.Derivative); break;

}

case ActivationFunctionType.Sigma:

{

62

f_activation = new TFunction(TSigma.Activation); f_derivative = new TFunction(TSigma.Derivative); break;

}

case ActivationFunctionType.Tangent:

{

f_activation = new TFunction(THyptan.Activation); f_derivative = new TFunction(THyptan.Derivative); break;

}

default:

{

f_activation = new TFunction(Zero.Activation); f_derivative = new TFunction(Zero.Derivative); break;

}

}

for (int i = 0; i < quantity; i++)

{

Neiron[i] = new TNeiron(); Neiron[i].ActivationFunction = f_activation; Neiron[i].DerivativeFunction = f_derivative;

}

flag = Properties.Type;

}

public TLayer(LayerType Value_Type, int value_quantity)

{

quantity = value_quantity; Neiron = new TNeiron[quantity]; flag = Value_Type;

for (int i = 0; i<quantity; i++)

{

Neiron[i] = new TNeiron(); Neiron[i].ActivationFunction = null; Neiron[i].DerivativeFunction = null;

}

}

#endregion

#region Properties

public int Size { get { return quantity; } }

#endregion

}

63

Листинг А.6: Реализация класса многослойного персептрона

public class TPerceptron

// многослойный персетрон

{

 

private int N;

// размерность пространства входных сигналов

private int M;

// размерность пространства выходных сигналов

private int K;

// число скрытых слоёв

private TLayer [] Layer;

// набор слоёв, образующих нейронную сеть

private double [][,] SinapticWeight; /* массив синаптических весов

(первый индекс - номер слоя, второй - номер нейрона в этом слое,

а третий - номер нейрона в следующем слое) */

public TTrainerTemplate [] Template = null; // набор тренировочных шаблонов

#region Рабочие поля алгоритма обучения

// массив промежуточных выходных сигналов для всех тренировочных шаблонов private double [][][] OutputSignal;

private TVector SearchDirection = null; // направление убывания функции ошибки

public double t = 1.0;

// значение шагового множителя

#endregion

 

#region Параметры алгоритма обучения

 

public double accuracy = 0.001;

// точность обучения персептрона

public TInterval StepMultiplierDiapason; // диапазон значений шагового множителя

public int MaxNIterations = 10000;

// максимальное количество итераций

public LearningMethod Method;

// выбранный метод оптимизации

public static int CountIterations = 0;

// количество проведённых итераций

public static double MinError = 0.0;

// минимальное значение ошибки обучения

#endregion

 

// компонент для визуализации процесса обучения public BackgroundWorker LearningBackGroundWorker;

//поля для вывода информации о состоянии процесса обучения public Label LabelCount, LabelError;

//признак обученности-необученности персептрона

public bool IsLearned = false;

#region Методы настройки персептрона

64

/// <summary> Параметризованный конструктор персептрона </summary> public TPerceptron(int Value_N, TLayerProperties [] Properties, int Value_M)

{

K = Properties.Length;

//определяем число скрытых слоёв

N = Value_N; M = Value_M;

Layer = new TLayer[K + 2];

Layer[0] = new TLayer(LayerType.HAPTIC, N);

Layer[K + 1] = new TLayer(LayerType.MOTOR, M);

// Определяем свойства скрытых слоёв нейронов

for (int i = 1; i < K + 1; i++) Layer[i] = new TLayer(Properties[i - 1]);

// Выделяем память под массив синаптических весов

SinapticWeight = new double[K + 1][,];

for (int i = 1; i < K + 2; i++)

SinapticWeight[i - 1] = new double[Layer[i - 1].Size, Layer[i].Size];

}

/// <summary> Задание ативационных функций для моторного слоя </summary> public void Motor_DefineFunctions(ActivationFunctionType FunctionType)

{

TFunction f_activation, f_derivative;

switch (FunctionType)

{

case ActivationFunctionType.Linear:

{

f_activation = new TFunction(TLinear.Activation); f_derivative = new TFunction(TLinear.Derivative); break;

}

case ActivationFunctionType.Sigma:

{

f_activation = new TFunction(TSigma.Activation); f_derivative = new TFunction(TSigma.Derivative); break;

}

case ActivationFunctionType.Tangent:

{

f_activation = new TFunction(THyptan.Activation); f_derivative = new TFunction(THyptan.Derivative); break;

}

65

default:

{

f_activation = new TFunction(Zero.Activation); f_derivative = new TFunction(Zero.Derivative); break;

}

}

for (int i = 0; i < M; i++)

{

Layer[K + 1].Neiron[i].ActivationFunction = f_activation; Layer[K + 1].Neiron[i].DerivativeFunction = f_derivative;

}

}

public void SetLearningAlgoritmParameters(int MaxCount, TInterval t_Interval,

LearningMethod l_Method, double v_Accuracy)

{

MaxNIterations = MaxCount; StepMultiplierDiapason = t_Interval; Method = l_Method;

accuracy = v_Accuracy;

}

/// <summary> Инициализация значений весов и порогов </summary> public void Initialize()

{

Random Random = new Random();

for (int i = 1; i < K + 2; i++)

{

for (int j = 0; j < Layer[i - 1].Size; j++) for (int k = 0; k < Layer[i].Size; k++)

SinapticWeight[i - 1][j, k] = Random.NextDouble();

for (int j = 0; j < Layer[i].Size; j++) Layer[i].Neiron[j].threshold = Random.NextDouble();

}

}

#endregion

/// <summary> Выделение памяти под массив выходных сигналов </summary> public void GetMemoryForOutputSignals()

{

66

int Q = Template.Length;

OutputSignal = new double[Q][][];

for (int q = 0; q < Q; q++)

{

OutputSignal[q] = new double[K + 2][];

for (int k = 0; k < K + 2; k++) OutputSignal[q][k] = new double[Layer[k].Size];

}

}

public int GetCountIterations() { return CountIterations; }

public double GetMinError() { return MinError; }

#region ActivationFunctionArgument

///<summary> Вычисление аргумента активационной функции нейрона </summary> public double ActivationFunctionArgument(int q, int k, int i)

{

double Sum = 0.0;

for (int j = 0; j<Layer[k-1].Size; j++)

Sum += SinapticWeight[k-1][j,i]*OutputSignal[q][k-1][j];

return Sum - Layer[k].Neiron[i].threshold;

}

///<summary> Аргумент активационной функции с учётом направления поиска </summary> private double ActivationFunctionArgument(double t, int q, int k, int i)

{

double Sum = 0.0;

int Size = 0; for (int m = 0; m<k-1; m++) Size+=SinapticWeight[m].Length;

for (int j = 0; j < Layer[k - 1].Size; j++)

Sum += (SinapticWeight[k - 1][j, i] + t * SearchDirection.Array[Size + i + Layer[k].Size * j]) * OutputSignal[q][k - 1][j];

return Sum - Layer[k].Neiron[i].threshold;

}

/// <summary> В случае произвольного образа, поданного на вход персептрону </summary> private double ActivationFunctionArgument(double [][] OutputReactions, int k, int i)

{

double Sum = 0.0;

for (int j = 0; j < Layer[k - 1].Size; j++)

Sum += SinapticWeight[k - 1][j, i] * OutputReactions[k - 1][j]; return Sum - Layer[k].Neiron[i].threshold;

}

67

#endregion

#region CalcRealReactions

///<summary> вычисление фактических реакций персептрона

///на вектор входных сигналов q-ого шаблона </summary> private void CalcRealReactions(int q)

{

for (int i = 0; i<Layer[0].Size; i++)

OutputSignal[q][0][i] = Template[q].InputSignalsVector[i];

for (int k = 1; k < K + 2; k++)

{

for (int i = 0; i < Layer[k].Size; i++)

{

// находим аргумент активационной функции double s = ActivationFunctionArgument(q, k, i); TParams Params = Layer[k].Neiron[i].Params;

OutputSignal[q][k][i] = Layer[k].Neiron[i].ActivationFunction(Params, s);

}

}

}

///<summary> вычисление фактических реакций персептрона

///на вектор входных сигналов q-ого шаблона

///с учётом направления поиска </summary> private void CalcRealReactions(double t, int q)

{

for (int i = 0; i < Layer[0].Size; i++)

OutputSignal[q][0][i] = Template[q].InputSignalsVector[i];

for (int k = 1; k < K + 2; k++)

{

for (int i = 0; i < Layer[k].Size; i++)

{

//находим аргумент активационной функции double s = ActivationFunctionArgument(t, q, k, i);

TParams Params = Layer[k].Neiron[i].Params;

OutputSignal[q][k][i] = Layer[k].Neiron[i].ActivationFunction(Params, s);

}

}

}

///<summary> Вычисление выходных реакций персептрона

///по входным сигналам предъявленного образа </summary> public TVector GetOutputSignals(TVector Input)

{

TVector Output = new TVector(M);

double[][] OutputReactions = new double[K + 2][];

68

for (int k = 0; k < K + 2; k++)

{

OutputReactions[k] = new double[Layer[k].Size];

if (k == 0)

for (int i = 0; i < Layer[0].Size; i++) OutputReactions[0][i] = Input.Array[i];

else

for (int i = 0; i < Layer[k].Size; i++)

{

double s = ActivationFunctionArgument(OutputReactions, k, i); TParams Params = Layer[k].Neiron[i].Params;

OutputReactions[k][i] = Layer[k].Neiron[i].ActivationFunction(Params, s);

}

if (k == K + 1)

for (int i = 0; i < Layer[K + 1].Size; i++) Output.Array[i] = OutputReactions[K + 1][i];

}

return Output;

}

#endregion

#region LocalLearningError

/// <summary> Локальное значение функции ошибки </summary> public double LocalLearningError(int q)

{

TVector OutputVector = new TVector(OutputSignal[q][K + 1]);

TVector DesiredVector = new TVector(Template[q].OutputSignalsVector); double error = 0.5 * Math.Pow((OutputVector - DesiredVector).Norm(), 2); return error;

}

/// <summary> Локальное значение функции ошибки с учётом направления поиска

</summary>

private double LocalLearningError(double t, int q)

{

CalcRealReactions(t, q);

TVector OutputVector = new TVector(OutputSignal[q][K+1]);

TVector DesiredVector = new TVector(Template[q].OutputSignalsVector); double error = 0.5*Math.Pow((OutputVector - DesiredVector).Norm(), 2); return error;

}

#endregion

69

#region GlobalLearningError

/// <summary> Глобальная погрешность алгоритма обучения </summary> public double GlobalLearningError()

{

double error = 0.0;

int Q = Template.Length;

for (int q = 0; q<Q; q++) error += LocalLearningError(q); return error;

}

/// <summary> Глобальная погрешность алгоритма обучения с учётом направления поиска

</summary>

private double GlobalLearningError(double t)

{

double error = 0.0;

int Q = Template.Length;

for (int q = 0; q < Q; q++) error += LocalLearningError(t, q);

return error;

}

#endregion

/// <summary> Вычисление градиента функции ошибки </summary> public TVector CalcErrorGradient()

{

// Считаем размерность вектора градиента

int Sum_thresholds = 0, Sum_weights = 0;

for (int k = 1; k < K + 2; k++) Sum_thresholds += Layer[k].Size;

for (int k = 0; k < SinapticWeight.Length; k++) Sum_weights += SinapticWeight[k].Length; int Length = Sum_weights + Sum_thresholds;

TVector GradientVector = new TVector(Length);

int offset_weight = 0, offset_threshold = 0;

// отступ от конца вектора градиента

int Q = Template.Length;

 

double [][] delta = new double [Q][];

 

for (int k = K + 1; k > 0; k--)

 

{

 

if (k == K + 1)

// если текущий слой - моторный

for (int q = 0; q < Q; q++)

{

CalcRealReactions(q);

70

delta[q] = new double [Layer[K+1].Size];

for (int i = 0; i < Layer[K + 1].Size; i++)

{

TParams Params = Layer[K + 1].Neiron[i].Params;

delta[q][i] = (OutputSignal[q][K + 1][i] - Template[q].OutputSignalsVector[i]) *

Layer[K + 1].Neiron[i].DerivativeFunction(Params, ActivationFunctionArgument(q, K + 1, i));

}

}

else // если некоторый промежуточный слой

{

for (int q = 0; q < Q; q++)

{

double [] next_delta = new double[Layer[k].Size];

for (int i = 0; i < Layer[k].Size; i++)

{

double Summa = 0.0;

for (int j = 0; j < Layer[k + 1].Size; j++) Summa += SinapticWeight[k][i, j] * delta[q][j];

TParams Params = Layer[k].Neiron[i].Params;

next_delta[i] = Summa * Layer[k].Neiron[i].DerivativeFunction(Params, ActivationFunctionArgument(q, k, i));

}

delta[q] = next_delta;

}

}

offset_threshold += Layer[k].Size;

for (int i = 0; i < Layer[k].Size; i++) for (int q = 0; q < Q; q++)

GradientVector.Array[Length - offset_threshold + i] -= delta[q][i];

offset_weight += Layer[k - 1].Size * Layer[k].Size;

for (int i = 0; i < Layer[k - 1].Size; i++) for (int j = 0; j < Layer[k].Size; j++)

{

int index = Length - Sum_thresholds - offset_weight + Layer[k].Size * i + j; for (int q = 0; q < Q; q++)

GradientVector.Array[index] += delta[q][j] * OutputSignal[q][k - 1][i];

}

}

71

return GradientVector;

}

///<summary> Преобразование набора синаптических весов и

///порогов активационных функций в единый вектор </summary> public TVector ParametersToVector()

{

int Sum_weights = 0, Sum_thresholds = 0;

for (int k = 1; k<K+2; k++) Sum_thresholds += Layer[k].Size;

for (int k = 0; k < K + 1; k++) Sum_weights += SinapticWeight[k].Length;

int Length = Sum_weights + Sum_thresholds;

TVector result = new TVector(Length);

int offset = 0;

for (int k = 1; k<K+2; k++)

{

for (int i = 0; i<Layer[k-1].Size; i++) for (int j = 0; j<Layer[k].Size; j++)

result.Array[offset+Layer[k].Size*i+j] = SinapticWeight[k-1][i, j];

offset += Layer[k-1].Size*Layer[k].Size;

}

for (int k = 1; k<K+2; k++)

{

for (int i = 0; i<Layer[k].Size; i++) result.Array[offset+i] = Layer[k].Neiron[i].threshold; offset += Layer[k].Size;

}

return result;

}

private void NetworkParametersCorrection(TVector corrector)

{

int N_weights = 0;

for (int k = 0; k < K + 1; k++) N_weights += SinapticWeight[k].Length;

int offset_weight = 0, offset_threshold = N_weights;

// коррекция значений синаптических весов и порогов активационных функций

for (int k = 1; k < K + 2; k++)

{

for (int i = 0; i < Layer[k].Size; i++)

{

72

Layer[k].Neiron[i].threshold = corrector.Array[offset_threshold + i];

for (int j = 0; j < Layer[k - 1].Size; j++)

SinapticWeight[k - 1][j, i] = corrector.Array[offset_weight + i + j * Layer[k].Size];

}

offset_weight += SinapticWeight[k - 1].Length; offset_threshold += Layer[k].Size;

}

}

private double GetStepMultiplier()

{

UnivariateFunction f = new UnivariateFunction (GlobalLearningError); TInterval D = StepMultiplierDiapason; // переобозначение для удобства Task_of_optimization Task = new Task_of_optimization(f, D); PiyavskiyMethod Method = new PiyavskiyMethod(Task);

return Method.GetOptimalSolving().X;

}

#region Методы обучения многослойного персептрона

/// <summary> Метод наискорейшего градиентного спуска </summary> public void GradientMethodLearning()

{

Initialize(); // инициализация значений синаптических весов и порогов активационных функций

CountIterations = 0;

double MinGlobalError = Double.MaxValue; // минимальное значение погрешности

алгоритма обучения

 

double global_error = 0.0;

// глобальная погрешность алгоритма обучения

int Q = Template.Length;

// определяем число используемых для обучения

шаблонов

 

TVector v = null;

// набор параметров персептрона

for (int Count = 1; Count<=MaxNIterations; Count++)

{

TVector ErrorGradient = CalcErrorGradient(); // вычисляем градиент функции ошибки

SearchDirection = (-1) * ErrorGradient; // определяем направление убывания

UnivariateFunction f = new UnivariateFunction(GlobalLearningError);

TInterval D = new TInterval(0.001, 1.0); // переобозначение для удобства

Task_of_optimization Task = new Task_of_optimization (f, D);

73

PiyavskiyMethod Method = new PiyavskiyMethod (Task);

t = Method.GetOptimalSolving().X;

TVector Corrector = ParametersToVector() + t * SearchDirection;

NetworkParametersCorrection(Corrector);

CountIterations++;

CalcOutputSignals();

global_error = GlobalLearningError();

if (global_error < MinGlobalError) // условие коррекции погрешности

{

v = ParametersToVector(); MinGlobalError = global_error;

}

MinError = MinGlobalError;

if (MinGlobalError <= accuracy) // условие досрочного выхода из цикла

{

LearningBackGroundWorker.ReportProgress(100); break;

}

else LearningBackGroundWorker.ReportProgress(100 * Count / MaxNIterations);

if (LearningBackGroundWorker.CancellationPending)

{

NetworkParametersCorrection(v);

CalcOutputSignals(); return;

}

}

NetworkParametersCorrection(v);

CalcOutputSignals();

IsLearned = true;

}

public void CalcOutputSignals()

{

int Q = Template.Length;

for (int q = 0; q < Q; q++) CalcRealReactions(q);

}

74

/// <summary> Метод Давидона-Флетчера-Пауэлла </summary> public void DavidonFletcherPauellMethodLearning()

{

Initialize(); // первая инициализация параметров

CountIterations = 0;

TVector CurrentVector = ParametersToVector();

TVector CurrentGradVector = CalcErrorGradient();

TVector NextVector = null;

TVector NextGradVector = null;

// инициализация рабочих переменных

int Q = Template.Length;

double MinGlobalError = Double.MaxValue;

double global_error = 0.0;

TVector v = null;

TVector r = null; TVector s = null;

TSquarteMatrix Matrix = new TSquarteMatrix(CurrentVector.GetSize());

Matrix.Copying(Matrix.E);

for (int Count = 1; Count <= MaxNIterations; Count++)

{

SearchDirection = Matrix.ToSelection() * ((-1) * CurrentGradVector);

t = GetStepMultiplier();

NextVector = CurrentVector + t * SearchDirection;

NetworkParametersCorrection(NextVector);

NextGradVector = CalcErrorGradient();

r = NextVector - CurrentVector;

s = NextGradVector - CurrentGradVector;

//Итерационная формула пересчёта симметричных матриц

if ((Math.Abs(TVector.Dot(r, s)) >= 0.001) && (Math.Abs(TVector.Dot(Matrix * s, s)) >= 0.001))

75

Matrix = (Matrix.ToSelection() +

(1 / TVector.Dot(r, s)) * r.ToMatrix() * r.ToMatrix().Transpose().ToSelection() - (1 / TVector.Dot(Matrix * s, s)) * ((Matrix * s).ToMatrix().ToSelection() * (Matrix * s).ToMatrix().ToSelection().Transpose().ToSelection())).ToSquarte();

else Matrix.Copying(Matrix.E); // переходим к "градиентному" поведению метода

CurrentVector.Copying(NextVector);

CurrentGradVector.Copying(NextGradVector);

CalcOutputSignals();

CountIterations++;

global_error = GlobalLearningError();

if (global_error <= MinGlobalError) // условие коррекции погрешности

{

v = ParametersToVector(); MinGlobalError = global_error;

}

MinError = MinGlobalError;

if (MinGlobalError <= accuracy) // условие досрочного выхода из цикла

{

LearningBackGroundWorker.ReportProgress(100); break;

}

else LearningBackGroundWorker.ReportProgress(100 * Count / MaxNIterations);

if (LearningBackGroundWorker.CancellationPending)

{

NetworkParametersCorrection(v);

CalcOutputSignals();

return;

}

}

NetworkParametersCorrection(v);

CalcOutputSignals();

IsLearned = true;

}

76

/// <summary> Метод Бройдена-Флетчера-Гольдфарба-Шенно </summary> public void BroidenFletcherGoldfarbShennoMethodLearning()

{

Initialize(); // первая инициализация параметров

CountIterations = 0;

TVector CurrentVector = ParametersToVector();

TVector CurrentGradVector = CalcErrorGradient();

TVector NextVector = null;

TVector NextGradVector = null;

// инициализация рабочих переменных

int Q = Template.Length;

double MinGlobalError = Double.MaxValue;

double global_error = 0.0;

TVector v = null;

TVector r = null; TVector s = null;

TSquarteMatrix Matrix = new TSquarteMatrix(CurrentVector.GetSize());

Matrix.Copying(Matrix.E);

for (int Count = 1; Count<=MaxNIterations; Count++)

{

SearchDirection = Matrix.ToSelection() * ((-1) * CurrentGradVector);

t = GetStepMultiplier();

NextVector = CurrentVector + t * SearchDirection;

NetworkParametersCorrection(NextVector);

NextGradVector = CalcErrorGradient();

r = NextVector - CurrentVector;

s = NextGradVector - CurrentGradVector;

//Итерационная формула пересчёта симметричных матриц

if (Math.Abs(TVector.Dot(r, s)) >= 0.001)

Matrix = (Matrix.ToSelection() + (1 / TVector.Dot(r, s)) *

((r - Matrix.ToSelection() * s).ToMatrix() * r.ToMatrix().Transpose().ToSelection() +

77

r.ToMatrix() * (r - Matrix.ToSelection() * s).ToMatrix().Transpose().ToSelection()) - (TVector.Dot(r - Matrix.ToSelection() * s, s) / Math.Pow(TVector.Dot(r, s), 2)) *

TSquarteMatrix.FromVector(r).ToSelection()).ToSquarte();

else Matrix.Copying(Matrix.E); // переходим к "градиентному" поведению метода

CurrentVector.Copying(NextVector);

CurrentGradVector.Copying(NextGradVector);

CalcOutputSignals();

CountIterations++;

global_error = GlobalLearningError();

if (global_error <= MinGlobalError) // условие коррекции погрешности

{

v = ParametersToVector(); MinGlobalError = global_error;

}

MinError = MinGlobalError;

if (MinGlobalError <= accuracy) // условие досрочного выхода из цикла

{

LearningBackGroundWorker.ReportProgress(100); break;

}

else LearningBackGroundWorker.ReportProgress(100 * Count / MaxNIterations);

if (LearningBackGroundWorker.CancellationPending)

{

NetworkParametersCorrection(v);

CalcOutputSignals();

return;

}

}

NetworkParametersCorrection(v);

CalcOutputSignals();

}

#endregion

78

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]