Федеральное агентство рф по образованию Государственное образовательное учреждение Высшего профессионального образования «Владимирский государственный университет»
Кафедра физики и прикладной математики
Лабораторная работа №1
«Модель однонейронной сети»
Выполнил: ст. гр. ПМИ-104 Андреев Д. В.
Принял: Горлов В.Н.
Владимир 2008
Цель работы:
Построить модель биологического нейрона, провести его обучение на основе дельта-правил для распознавания простого графического изображения, вводимого при работе с программой.
Постановка задачи:
Программа моделирует сеть, состоящую из одного слоя: входного, - который состоит из одного нейрона. Входы нейрона непосредственно связаны с точками изображения. Максимальный размер изображения – 100*100 точек (если задать число входов нейрона меньше 1000, то не все пиксели будут задействованы в качестве рецепторов).
Исходные данные для процесса обучения:
Число входов нейрона.
Значение порога.
Значение шага обучения.
Количество итераций.
Интерфейс: помимо окон, в которых можно изменять параметры, должны быть кнопки для выполнения следующих действий:
Сформировать нейронную сеть;
Выполнить заданное количество итераций обучения (“обучить”);
Запустить процесс распознавания изображения (“тестировать”);
Открыть форму для просмотра состояний скрытого слоя сети;
Стереть введенное изображение;
Получить информацию о программе.
Краткая теория:
Нейронные сети реализуют биологические процессы обработки информации и принятия человеком решений.
Из биологии: Нервная система человека состоит из нейронов, соединенных между собой нервными волокнами. Передача раздражений от кожи, ушей и глаз к мозгу, и процессы мышления происходят через передачу электрических импульсов между нейронами. Типы нервных волокон – дендриты (в большом количестве) для приема сигнала, и единственный аксон для передачи импульса.
Аксон контактирует с дендритами других нейронов через синапсы, которые влияют на силу импульса. Т.е., каждый синапс характеризуется определенным весом. Импульсы, поступившие к нейрону, суммируются. Если суммарный импульс превышает некоторый порог, нейрон формирует собственный импульс и передает его по аксону.
Математическая модель:
Текущее состояние нейрона определяется, как взвешенная сумма его входов: . Выход нейрона есть функция его состояния: y = f(s).Часто это пороговая функция: , где p – параметр, называемый порогом. |
|
Обучение НС:
Обучить НС, в сущности, это процесс настройки весов связей нейрона. Пусть есть некоторая база данных с примерами. Предъявляя образы на вход нейронной сети, мы получаем некоторый ответ. Вычисляя разность между желаемым (целевым) ответом и реальным ответом сети, мы получаем ошибку сети. Если ошибка достаточно мало процесс обучения останавливают, если нет, то изменяют веса ряда нейронов. Существует множество алгоритмов обучения, например, алгоритм дельта-правил.
Алгоритм «дельта-правила»
Задаем начальные малые значения весов.
Рассчитываем текущий выход сети Y.
Вычисляем d=T-Y, где T- целевое значение сети.
Если d=0, то веса не меняем, иначе w(t)[i]=w(t-1)[i]+d*x[i]*h, где h- шаг обучения.
Тестирование НС:
После того, как нейронная сеть обучена, мы можем применять ее для решения задачи. Важнейшая особенность человеческого мозга состоит в том, что, однажды обучившись определенному процессу, он может верно действовать и в тех ситуациях, в которых он не бывал в процессе обучения. Веса обученной нейронной сети хранят достаточно много информации, поэтому можно рассчитывать на правильный ответ и для нового варианта изображения.
Выполнение работы:
Работа начинается с запуска формы. Появляется следующее окно:
Она включает следующие элементы:
Область отображения bmp-файла;
Список bmp-файлов. Затем необходимо выбрать в списке один из bmp-файлов
Нажав кнопку “Результат” появляется окно, которое отображает четность/нечетность цифры, представленной на экране;
Кнопки “Добавить” и “Очистить” управляют изображением на экране.
Кнопка “Выход” закрывает форму приложения.
Листинг программы:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO;
namespace lab1
{
public partial class mainForm : Form
{
void BmpReadData(List<string> files, List<List<int>> all_x)
{
foreach (string file_name in files)
{
Bitmap bmp = new Bitmap(file_name);
List<int> x = new List<int>();
for (int i = 0; i < 100; i++)
for (int j = 0; j < 100; j++)
{
if (bmp.GetPixel(i, j).ToArgb() == Color.Black.ToArgb())
x.Add(1);
else
x.Add(0);
}
all_x.Add(x);
}
}
public mainForm()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
string[] files = { "0.bmp", "1.bmp", "2.bmp", "3.bmp", "4.bmp" };
res = new List<int>();
int i = 0;
foreach (string file_name in files)
{
listBoxPic.Items.Add(file_name);
res.Add(i % 2);
i++;
}
picBox.Image = Image.FromFile("no_image.bmp");
StatusBar.Text = "Для обучения нажмите \"обучить\"";
}
private void btnClear_Click(object sender, EventArgs e)
{
listBoxPic.Items.Clear();
res.Clear();
picBox.Image = Image.FromFile("no_image.bmp");
cmbBoxRes.SelectedIndex = -1;
}
//при выборе файлы отоборажаем картинку
private void listBoxPic_SelectedIndexChanged(object sender, EventArgs e)
{
toolStripProgressBar1.Value = 0;
if (listBoxPic.SelectedIndex == -1)
return;
picBox.Image = Image.FromFile(listBoxPic.Items[listBoxPic.SelectedIndex].ToString());
cmbBoxRes.SelectedIndex = res[listBoxPic.SelectedIndex];
}
private void cmbBoxRes_SelectedIndexChanged(object sender, EventArgs e)
{
if (listBoxPic.SelectedIndex == -1)
return;
res[listBoxPic.SelectedIndex] = cmbBoxRes.SelectedIndex;
}
//добавление файла в список
private void btnAdd_Click(object sender, EventArgs e)
{
openFileDialog.Filter = "bmp files (*.bmp)|*.bmp|All files (*.*)|*.*";
if (openFileDialog.ShowDialog() == DialogResult.OK)
{
string file_name = openFileDialog.FileName;
file_name = file_name.Substring(file_name.LastIndexOf("\\") + 1);
//проверяем расширение файла (необходимо чтобы было *.bmp)
if (!file_name.EndsWith("bmp"))
{
MessageBox.Show(
"Файл не является файлом *.bmp",
"Внимание",
MessageBoxButtons.OK,
MessageBoxIcon.Warning,
MessageBoxDefaultButton.Button2);
return;
}
//проверяем размеры изображения (необходимо 100*100)
Bitmap bmp = new Bitmap(file_name);
if (bmp.Width != 100 || bmp.Height != 100)
{
MessageBox.Show(
"Изображение должно быть размером 100х100",
"Внимание",
MessageBoxButtons.OK,
MessageBoxIcon.Warning,
MessageBoxDefaultButton.Button2);
return;
}
//проверяем, есть ли такой файл в списке
if (!listBoxPic.Items.Contains(file_name))
{
listBoxPic.Items.Add(file_name);
//по умолчанию новая цифра является четной
res.Add(0);
}
else
MessageBox.Show(
"Такой файл уже есть в списке",
"Внимание",
MessageBoxButtons.OK,
MessageBoxIcon.Warning,
MessageBoxDefaultButton.Button2);
}
}
//обучение нейронной сети
private void btnTraining_Click(object sender, EventArgs e)
{
toolStripProgressBar1.Value = 0;
//если ListBox пуст
if (listBoxPic.Items.Count == 0)
{
MessageBox.Show(
"Список файлов пуст",
"Внимание",
MessageBoxButtons.OK,
MessageBoxIcon.Warning,
MessageBoxDefaultButton.Button2);
return;
}
StatusBar.Text = "Обучение!";
Application.DoEvents();
//здесь храняться имена файлов
List<string> files = new List<string>();
for (int i = 0; i < listBoxPic.Items.Count; i++)
files.Add(listBoxPic.Items[i].ToString());
//здесь храняться все точки из изображений files
List<List<int>> all_x = new List<List<int>>();
BmpReadData(files, all_x);
//создаем нейрон
SingleNeiro n = new SingleNeiro(all_x[0].Count);
//проводим обучение
n.training(all_x, res, this);
//записываем весы в файл
n.WeightsToFile("w");
StatusBar.Text = "Обучение завершено!";
}
//определение четности цифры
private void btnRes_Click(object sender, EventArgs e)
{
//не выбран файл из списка
if (listBoxPic.SelectedIndex == -1)
{
MessageBox.Show(
"Не выбран файл для определения четности",
"Внимание",
MessageBoxButtons.OK,
MessageBoxIcon.Warning,
MessageBoxDefaultButton.Button2);
return;
}
SingleNeiro neuro = new SingleNeiro();
//проверка существования файла весов w или является ли он пустым
try
{
neuro.ReadWeigthsfromFile("w");
}
catch
{
MessageBox.Show(
"Файл весов w - не существует либо пуст\n Нужно обучить нейронную сеть",
"Внимание",
MessageBoxButtons.OK,
MessageBoxIcon.Warning,
MessageBoxDefaultButton.Button2);
return;
}
//читаем входы из изображения
neuro.ReadInputsFromBmpFile(listBoxPic.Items[listBoxPic.SelectedIndex].ToString());
txtRes.Text = "Цифра " + (neuro.Calculate() == 0 ? "четная" : "нечетная");
}
private void btnExit_Click(object sender, EventArgs e)
{
Application.Exit();
}
private void mnuItemDel_Click(object sender, EventArgs e)
{
listBoxPic.Items.Remove(listBoxPic.SelectedItem);
}
}
class SingleNeiro
{
private const double step = 0.8; //шаг обучения
private List<int> Inputs; //входы
private List<double> Weights; //веса
private double p = 3; //порог
public SingleNeiro()
{
Inputs = new List<int>();
Weights = new List<double>();
}
public SingleNeiro(int size)
{
Inputs = new List<int>();
Weights = new List<double>();
for (int i = 0; i < size; i++)
Weights.Add(0.5);
}
/// <summary>
/// рассчет четности цифры
/// </summary>
/// <returns></returns>
public int Calculate()
{
double sum = 0;
int idx = 0;
foreach (int bit in Inputs)
{
sum += bit * Weights[idx++];
}
return sum < p ? 0 : 1;
}
/// <summary>
/// изменяем весы пересчет весов
/// </summary>
/// <param name="popravka"></param>
public void ChangeWeight(int popravka)
{
for (int i = 0; i < Weights.Count; i++)
Weights[i] = Weights[i] + popravka * Inputs[i] * step;
}
/// <summary>
/// запись весов в файл
/// </summary>
/// <param name="name"></param>
public void WeightsToFile(string name)
{
StreamWriter fout = new StreamWriter(name);
foreach (double weight in Weights)
{
fout.WriteLine(weight);
}
fout.Close();
}
/// <summary>
/// функция для считывания весов из файла
/// </summary>
/// <param name="file_name"></param>
public void ReadWeigthsfromFile(string file_name)
{
StreamReader fin_w = new StreamReader(file_name);
string str = "";
while ((str = fin_w.ReadLine()) != null)
{
Weights.Add(double.Parse(str));
}
fin_w.Close();
}
/// <summary>
/// функция для считывания входов из графического изображения
/// </summary>
/// <param name="file_name"></param>
public void ReadInputsFromBmpFile(string file_name)
{
Bitmap bmp = new Bitmap(file_name);
for (int i = 0; i < 100; i++)
for (int j = 0; j < 100; j++)
{
if (bmp.GetPixel(i, j).ToArgb() == Color.Black.ToArgb())
Inputs.Add(1);
else
Inputs.Add(0);
}
}
/// <summary>
/// обучаем нейрон определять четность цифры
/// </summary>
/// <param name="all_x">образы цифр</param>
/// <param name="res">результаты четности для каждого из образов</param>
/// <param name="f1"></param>
public void training(List<List<int>> all_x, List<int> res,mainForm f1)
{
do
{
int idx = 0;
foreach (List<int> x in all_x)
{
//считываем входы
this.Inputs = x;
//определяем поправку, на которую изменяем весы
int offset = res[idx] - Calculate();
//до тех пор, пока не получим правильный результат
while (offset != 0)
{
if (f1.toolStripProgressBar1.Value + 5 > f1.toolStripProgressBar1.Maximum)
f1.toolStripProgressBar1.Maximum += 5;
f1.toolStripProgressBar1.Value += 5;
ChangeWeight(offset);
offset = res[idx] - Calculate();
}
idx++;
}
}
while (!TestTeaching(all_x, res));
f1.toolStripProgressBar1.Value = f1.toolStripProgressBar1.Maximum;
}
/// <summary>
/// проверка правильности четности цифры, выдаваемого нейронной сетью
/// </summary>
/// <param name="all_x"></param>
/// <param name="res"></param>
/// <returns></returns>
bool TestTeaching(List<List<int>> all_x, List<int> res)
{
int idx = 0;
foreach (List<int> x in all_x)
{
this.Inputs = x;
if (Calculate() != res[idx++])
return false;
}
return true;
}
}
}