Приклад 1.
Для прикладу напишемо невелику програму, яка буде розпізнавати прості зображення, скажімо, букви російської мови на растрових зображеннях. Домовимося, що в початковому стані наша система буде мати «порожню» пам'ять, тобто отакий новонароджений мозок, готовий до бою. Для того щоб змусити її коректно працювати, нам потрібно буде витратити час на навчання.
Отже,
виходячи з поставленого завдання –
кількість варіантів виходу дорівнює
кількості букв в алфавіті -> 33. Далі,
визначимося зі вхідними даними - будемо
подавати на вхід бітовий масив 30х30 у
вигляді растрового зображення:
У підсумку - потрібно створити 33 нейрона, у кожного з яких буде 30х30 = 900 входів.
Створимо клас для нашого нейрона:
type
Neuron = class
name: string; / / Тут назву нейрона - буква, з якою він асоціюється
Input: array [0 .. 29,0 .. 29] of integer; / / Тут вхідний масив 30х30
output: integer; / / Сюди результат
memory: array [0 .. 29,0 .. 29] of integer; // Тут будемо зберігати досвід про попередній досвід
end;
Створимо масив нейронів, по кількості букв:
For i: = 0 to 32 do begin
neuro_web [i]: = Neuron.Create;
neuro_web [i]. output: = 0;
neuro_web [i]. name: = chr (Ord ('A') + i); / / Букви від А до Я
end;
«Пам'ять» нейромережі будемо зберігати їх у растрових зображеннях 30х30.
Ось наприклад, пам'ять нейрона «К» після прогону програми за різними шрифтами:
Як видно, самі насичені області відповідають пік селям, що найбільш часто зустрічаються.
Будемо завантажувати «пам'ять» у кожен нейрон при його створенні:
p: = TBitmap.Create;
p.LoadFromFile (ExtractFilePath (Application.ExeName) + '\ res\' + neuro_web [i]. name + '. bmp')
На початку роботи ненавченої програми, пам'ять кожного нейрона буде білою плямою 30х30.
Розпізнавати нейрон буде наступним чином:
- Беремо 1-й піксель
- Порівнюємо його з 1- м пікселем в пам'яті (там лежить значення 0 .. 255)
- Порівнюємо різницю з якимсь порогом
- Якщо різниця менше порога - вважаємо, що в даній точці буква схожа на лежачу в пам'яті, додаємо +1 до ваги нейрона.
І так по всіх пікселям.
В кінці розпізнавання у нас буде набір нейронів, кожен з яких вважає, що він прав на скількись відсотків. Ці відсотки - і є вага нейрона. Чим більше вага, тим імовірніше, що саме цей нейрон прав.
Тепер будемо згодовувати програмі довільне зображення і пробігати кожним нейроном по ньому:
for x: = 0 to 29 do
for y: = 0 to 29 do begin
n: = neuro_web [i]. memory [x, y];
m: = neuro_web [i]. input [x, y];
if ((abs (m-n) <120)) then / / Поріг різниці кольору
if m <250 then neuro_web [i]. weight: = neuro_web [i]. weight +1; / / Крім того, не будемо враховувати білі пікселі, щоб не отримувати зайвих балів в терезах
if m <> 0 then begin
if m <250 then n: = round ((n + (n + m) / 2) / 2);
neuro_web [i]. memory [x, y]: = n; end
else if n <> 0 then
if m <250 then n: = round ((n + (n + m) / 2) / 2);
neuro_web [i]. memory [x, y]: = n;
end;
якого вага більша:
if neuro_web [i]. weight> max then begin
max: = neuro_web [i]. weight;
max_n: = i;
end;
Саме по ось цьому значенню max_n, програма і скаже нам, що, на її думку, ми їй підсунули.
По початку це буде не завжди вірно, тому потрібно зробити алгоритм навчання.
s: = InputBox ('Enter the letter', 'програма вважає, що це буква' + neuro_web [max_n]. name, neuro_web [max_n]. name);
for i: = 0 to 32 do begin / / Пробігаємо по нейронам
if neuro_web [i]. name = s then begin / / В потрібному нейроні оновлюємо пам'ять
for x: = 0 to 29 do begin
for y: = 0 to 29 do begin
p.Canvas.Pixels [x, y]: = RGB (neuro_web [i]. memory [x, y], neuro_web [i]. memory [x, y], neuro_web [i]. memory [x, y]) ; / / Записуємо нове значення пікселя пам'яті
end;
end;
p.SaveToFile (ExtractFilePath (Application.ExeName) + '\ res \' + neuro_web [i]. name + '. bmp');
Саме оновлення пам'яті будемо робити так: n: = round (n + (n + m) / 2);
Тобто якщо дана точка в пам'яті нейрона відсутня, але вчитель говорить, що вона є в цій букві - ми її запам'ятовуємо, але не повністю, а тільки наполовину. З подальшим навчанням, ступінь впливу даного уроку буде збільшуватися.
Ось
декілька ітерацій для літери Г:
Почнемо навчання.
Відкриваємо зображення букв і терпляче вказуємо програмі на її помилки:
Через деякий час програма почне стабільно визначати навіть не знайомі їй раніше літери.
unit neuro;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls, StdCtrls, ExtDlgs, XPMan;
type
Neuron = class
name: string;
input: array[0..29,0..29] of integer;
output:integer;
weight:integer;
memory:array[0..29,0..29] of integer;
end;
type
TForm1 = class(TForm)
Image1: TImage;
ListBox1: TListBox;
Button1: TButton;
ListBox2: TListBox;
Button2: TButton;
Panel1: TPanel;
Panel2: TPanel;
Button3: TButton;
OpenPictureDialog1: TOpenPictureDialog;
XPManifest1: TXPManifest;
procedure FormCreate(Sender: TObject);
procedure ListBox1Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure ListBox1DblClick(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
neuro_web:array[0..32] of Neuron;
img:array[0..29,0..29] of integer;
implementation
{$R *.dfm}
procedure GetAllFiles( Path: string; Lb: TListBox );
var
sRec: TSearchRec;
isFound: boolean;
begin
isFound := FindFirst( Path + '\*.bmp', faAnyFile, sRec ) = 0;
while isFound do
begin
if ( sRec.Name <> '.' ) and ( sRec.Name <> '..' ) then
begin
if ( sRec.Attr and faDirectory ) = faDirectory then
GetAllFiles( Path + '\' + sRec.Name, Lb );
Lb.Items.Add( sRec.Name );
end;
Application.ProcessMessages;
isFound := FindNext( sRec ) = 0;
end;
FindClose( sRec );
end;
procedure start();
var x,y,i,l:integer;
p:TBitmap;
c:TColor;
begin
for i:=0 to 32 do begin
neuro_web[i].weight:=0;
neuro_web[i].output:=50;
neuro_web[i].name:=chr(Ord('А')+i);
p:=TBitmap.Create;
p.LoadFromFile(ExtractFilePath(Application.ExeName)+'\res\'+neuro_web[i].name+'.bmp');
for x:=0 to 29 do
for y:=0 to 29 do begin
c:=p.Canvas.Pixels[x,y];
l:=round((GetRValue(c)+GetGValue(c)+GetBValue(c))/3);
neuro_web[i].memory[x,y]:=l;
end;
end;
p.Free;
end;
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
procedure recognize();
var x,y,i,n,m,max,max_n:integer;
c:TColor;
p:TBitmap;
s:string;
r:Trect ;
begin
Form1.ListBox2.Clear;
max:=0;
max_n:=0;
r.Left:=0;
r.Right:=30;
r.Top:=0;
r.Bottom:=30;
for x:=0 to 29 do
for y:=0 to 29 do begin
c:=Form1.Image1.Canvas.Pixels[x,y];
i:=round((GetRValue(c)+GetGValue(c)+GetBValue(c))/3);
if i<100 then i:=0 else i:=255;
img[x,y]:=i ;
end;
for i:=0 to 32 do
for x:=0 to 29 do
for y:=0 to 29 do
neuro_web[i].input[x,y]:=img[x,y];
for i:=0 to 32 do begin
p:=TBitmap.Create;
p.Width:=30;
p.Height:=30;
for x:=0 to 29 do
for y:=0 to 29 do begin
n:=neuro_web[i].memory[x,y];
m:=neuro_web[i].input[x,y];
if ((abs(m-n)<120)) then
if m<250 then neuro_web[i].weight:=neuro_web[i].weight+1;
if m<>0 then begin
if m<250 then n:=round((n+(n+m)/2)/2);
neuro_web[i].memory[x,y]:=n; end
else if n<>0 then
if m<250 then n:=round((n+(n+m)/2)/2);
neuro_web[i].memory[x,y]:=n;
end;
Form1.ListBox2.Items.Add(chr(Ord('А')+i)+' = '+IntToStr(neuro_web[i].weight));
if neuro_web[i].weight>max then begin
max:=neuro_web[i].weight;
max_n:=i;
end;
end;
s:=InputBox('Enter the letter', 'Программа считает, что найдена буква '+neuro_web[max_n].name, neuro_web[max_n].name);
for i:=0 to 32 do begin
if neuro_web[i].name=s then begin
p.Canvas.TextOut(10,10,'asa');
p.Canvas.Brush.Color:=clWhite;
p.Canvas.Pen.Color:=clWhite;
p.Canvas.FillRect(r);
p.Canvas.Brush.Color:=clBlack;
p.Canvas.Pen.Color:=clBlack;
p.SaveToFile('aa.bmp');
for x:=0 to 29 do begin
for y:=0 to 29 do begin
p.Canvas.Pixels[x,y]:=RGB(neuro_web[i].memory[x,y],neuro_web[i].memory[x,y],neuro_web[i].memory[x,y]);
end;
end;
p.SaveToFile(ExtractFilePath(Application.ExeName)+'\res\'+neuro_web[i].name+'.bmp');
end;
end;
max:=0;
start();
end;
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
procedure TForm1.FormCreate(Sender: TObject);
var i:integer;
begin
GetAllFiles( ExtractFilePath(Application.ExeName)+'\img', listbox1 );
for i:=0 to 32 do
neuro_web[i]:=Neuron.Create;
start();
end;
procedure TForm1.ListBox1Click(Sender: TObject);
begin
Image1.Picture.LoadFromFile( ExtractFilePath(Application.ExeName)+'\res\'+ListBox1.Items.Strings[Listbox1.ItemIndex]);
end;
procedure TForm1.Button3Click(Sender: TObject);
begin
recognize();
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
If OpenPictureDialog1.Execute then
Image1.Picture.LoadFromFile(OpenPictureDialog1.FileName);
recognize();
end;
procedure TForm1.ListBox1DblClick(Sender: TObject);
begin
Button1.Click;
end;
end.
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;
using System.IO;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
public int[,] input = new int[3, 5];
Web NW1;
private void button1_Click(object sender, EventArgs e)
{
listBox1.Items.Clear();
button2.Enabled = true;
openFileDialog1.Title = "Укажите тестируемый файл";
openFileDialog1.ShowDialog();
pictureBox1.Image = Image.FromFile(openFileDialog1.FileName);
Bitmap im = pictureBox1.Image as Bitmap;
for (var i = 0; i <= 5; i++) listBox1.Items.Add(" ");
for (var x = 0; x <= 2; x++)
{
for (var y = 0; y <= 4; y++)
{
// listBox1.Items.Add(Convert.ToString(im.GetPixel(x, y).R));
int n = (im.GetPixel(x, y).R);
if (n >= 250) n = 0;
else n = 1;
listBox1.Items[y] = listBox1.Items[y] + " " + Convert.ToString(n);
input[x, y] = n;
//if (n == 0) input[x, y] = 1;
}
}
recognize();
}
public void recognize()
{
NW1.mul_w();
NW1.Sum();
if (NW1.Rez()) listBox1.Items.Add(" - True, Sum = "+Convert.ToString(NW1.sum));
else listBox1.Items.Add( " - False, Sum = "+Convert.ToString(NW1.sum));
}
class Web
{
public int[,] mul;
public int[,] weight;
public int[,] input;
public int limit = 9;
public int sum ;
public Web(int sizex, int sizey,int[,] inP)
{
weight = new int[sizex, sizey];
mul = new int[sizex, sizey];
input = new int[sizex, sizey];
input = inP;
}
public void mul_w()
{
for (int x = 0; x <= 2; x++)
{
for (int y = 0; y <= 4; y++)
{
mul[x, y] = input[x,y]*weight[x,y];
}
}
}
public void Sum()
{
sum = 0;
for (int x = 0; x <= 2; x++)
{
for (int y = 0; y <= 4; y++)
{
sum += mul[x, y];
}
}
}
public bool Rez()
{
if (sum >= limit)
return true;
else return false;
}
public void incW(int[,] inP)
{
for (int x = 0; x <= 2; x++)
{
for (int y = 0; y <= 4; y++)
{
weight[x, y] += inP[x, y];
}
}
}
public void decW(int[,] inP)
{
for (int x = 0; x <= 2; x++)
{
for (int y = 0; y <= 4; y++)
{
weight[x, y] -= inP[x, y];
}
}
}
}
private void Form1_Load(object sender, EventArgs e)
{
NW1 = new Web(3, 5,input);
openFileDialog1.Title = "Укажите файл весов";
openFileDialog1.ShowDialog();
string s = openFileDialog1.FileName;
StreamReader sr = File.OpenText(s);
string line;
string[] s1;
int k = 0;
while ((line = sr.ReadLine()) != null)
{
s1 = line.Split(' ');
for (int i = 0; i < s1.Length; i++)
{
listBox1.Items.Add("");
if (k < 5)
{
NW1.weight[i, k] = Convert.ToInt32(s1[i]);
listBox1.Items[k] += Convert.ToString(NW1.weight[i, k]);
}
}
k++;
}
sr.Close();
}
private void button2_Click(object sender, EventArgs e)
{
button2.Enabled = false;
if (NW1.Rez() == false)
NW1.incW(input);
else NW1.decW(input);
//Запись
string s="";
string[] s1 = new string[5];
System.IO.File.Delete("w.txt");
FileStream FS = new FileStream("w.txt", FileMode.OpenOrCreate);
StreamWriter SW = new StreamWriter(FS);
for (int y = 0; y <= 4; y++)
{
s = Convert.ToString(NW1.weight[0, y]) + " " + Convert.ToString(NW1.weight[1, y]) + " " + Convert.ToString(NW1.weight[2, y]) ;
s1[y] = s;
SW.WriteLine(s);
}
SW.Close();
}
}
}
