Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Записка.doc
Скачиваний:
63
Добавлен:
09.02.2015
Размер:
360.96 Кб
Скачать

2.3. Структурная схема двухслойного персептрона с алгоритмом обратного распространения ошибки.

Персептрон представляет собой сеть, состоящую из нескольких последовательно соединенных слоев формальных нейронов Мак Каллока и Питтса. На низшем уровне иерархии находится входной слой, состоящий из сенсорных элементов, задачей которого является только прием и распространение по сети входной информации. Далее имеются один или, реже, несколько скрытых слоев. Каждый нейрон на скрытом слое имеет несколько входов, соединенных с выходами нейронов предыдущего слоя или непосредственно со входными сенсорами X1..Xn, и один выход. Нейрон характеризуется уникальным вектором весовых коэффициентов w. Веса всех нейронов слоя формируют матрицу, которую мы будем обозначать V или W (Приложения, чертёж 2).

Теперь конкретно нейронная сеть программы. На входе подаются вектора состоящие из:

  • Забитых и пропущенных шайб в последних матчах команды и также соперника (количество задано константой, LAST_MATCHES, можно менять в исходном коде);

  • Количество побед, ничьих и поражений той или иной команды;

  • Один сигнал - признак игры дома или в гостях.

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

а результаты игр заменяются на соответствующие им доли (также для обеих команд в отдельности), т.е. на входе сумма сигналов равно 3 или 3+OWNER_MATCH_FACTOR (величина сигнала игры на своем поле). Для каждого матча формируется два отдельных входных вектора - для хозяев и гостей. Сигналы складываются по весовой матрице и проходят через сигмоидальную функцию сжимающую выход в диапазон 0..1, затем это повторяется для следующего слоя сети и на выходе получается набор сигналов, принимающих значения от 0 до 1. Каждому кол-ву забитых шайб (кол-во выходов - константа MAX_GOALS) соответствует вектор из нулей и одной единицы. Выходной сигнал сравнивается с векторами и по наименьшему расстоянию (квадрату разности) определяется итоговое кол-во забитых командой шайб.

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

2.4. Описание основных модулей программы.

Разрабатываемая программа должная выполнять следящие функции:

  1. Добавления, удаления, редактирования турнирной таблицы и информации той или иной команды в отдельности;

  2. Просмотр турнирной таблицы и результата каждого матча той или иной команды в отдельности;

  3. Добавления нового матча, выбор скорости обучения и числа проходов;

  4. Обучения двухслойного персептрона с алгоритмом обратного распространения ошибки;

  5. Прогнозирования результатов того или иного хоккейного матча;

  6. Добавления с играного матча в БД с правильным результатом игры.

Обучения двухслойного персептрона с алгоритмом обратного распространения ошибки реализовано следующим образом:

procedure TFormMain.Learn;

var i,j,i0,i1,i2,l: Longint;

tmp: Real;

begin

temp:= StrToFloat(LabeledEditSpeed.Text);//скорость

//Задаем случайные веса;

for i0:= 1 to k0 do

for i1:= 0 to k1 do

W1[i0, i1]:= (random(100)-50)/1000;

for i1:= 0 to k1 do

for i2:= 0 to k2 do

W2[i1, i2]:= (random(100)-50)/2000;

l:= StrToInt(LabeledEditLearnCount.Text);//кол-во проходов

//обучение сети:

for i:= 1 to l do begin

j:= random(mCount)+1;//выбираем случайный образец

for i0:= 1 to k0 do

X[i0]:= Ims[j, i0];//формируем входной вектор

for i2:= 0 to k2 do//формируем выходной вектор

if(i2 = NetOuts[j]) then

T[i2]:= 1

else T[i2]:= 0;

NeuronOuts;//получаем выход нейронной сети в Y

if(NetOuts[j] <> d) then begin//если не совпадает с парвильным, то изменяем веса:

//Расчитываем ошибку выходного слоя

for i2:= 0 to k2 do

B2[i2]:= Y2[i2]*(1 - Y2[i2])*(T[i2] - Y2[i2]);

// Расчитываем ошибку входного слоя

for i1:= 0 to k1 do begin

tmp:= 0;

for i2:= 0 to k2 do

tmp:= tmp + B2[i2]*W2[i1, i2];

B1[i1]:= Y1[i1]*(1 - Y1[i1])*tmp;

end;

//Изменяем веса 1-го слоя

for i0:= 1 to k0 do

for i1:= 0 to k1 do

W1[i0, i1]:= W1[i0, i1] + temp*B1[i1]*X[i0];

//Изменение веса 2-го слоя

for i1:= 0 to k1 do

for i2:= 0 to k2 do

W2[i1, i2]:= W2[i1, i2] + temp*B2[i2]*Y1[i1];

end;

end;

//считаем кол-во обученных образцов:

i:= 0;

for j:= 1 to mCount do begin

for i0:= 1 to k0 do

X[i0]:= Ims[j, i0];

NeuronOuts;

if(NetOuts[j] = d) then inc(i);

end;

LabelResult.Caption:= IntToStr(i)+'/'+IntToStr(mCount);//выводим их в надпись на форме

end;

procedure TFormMain.FormNet;

var i,j,O,G,Oi,Gi: Longint;

TCodes: array[1..MAX_TEAMS] of Integer;//коды команд в таблице

begin

with DM.ADOTableTeams do begin

First;

tCount:= 0;//кол-во команд

while not Eof do begin

inc(tCount);

TCodes[tCount]:= FieldByName('Code').AsInteger;//коды команд

Next;

end;

end;

for i:= 1 to tCount do begin//по всем командам

for j:= 1 to LAST_MATCHES do begin//предварительно зануляем голы по последним матчам:

LastGoals[i,1,j]:= 0;

LastGoals[i,2,j]:= 0;

end;

for j:= 1 to 3 do//зануляем статистику команд:

TMs[i,j]:= 0;

end;

with DM.ADOTableAllMatches do begin

i:= 0;//счетчик матчей

Active:= True;

First;

while not Eof do begin//по всем состоявшимся матчам:

//коды хозяев и гостей:

OCode:= FieldByName('OwnerTeam').AsInteger;

GCode:= FieldByName('GuestTeam').AsInteger;

//номера в таблице:

Oi:= 1;

while(TCodes[Oi] <> OCode) do inc(Oi);

Gi:= 1;

while(TCodes[Gi] <> GCode) do inc(Gi);

//забитые голы:

O:= FieldByName('OwnerGoals').AsInteger;

G:= FieldByName('GuestGoals').AsInteger;

//добавляем отдельный обучающий набор для хозяев:

inc(i);

for j:= 1 to LAST_MATCHES do begin//записываем результаты последних 5-ти матчей команды и соперника:

Ims[i, j]:= LastGoals[ Oi, 1, j];

Ims[i, j+LAST_MATCHES]:= LastGoals[ Oi, 2, j];

Ims[i, j+2*LAST_MATCHES]:= LastGoals[ Gi, 1, j];

Ims[i, j+3*LAST_MATCHES]:= LastGoals[ Gi, 2, j];

end;

for j:= 1 to 3 do begin//добавляем статистику команды и ее соперника в турнире:

Ims[i, j+4*LAST_MATCHES]:= TMs[ Oi, j];

Ims[i, j+4*LAST_MATCHES+3]:= TMs[ Gi, j];

end;

Ims[i, k0]:= OWNER_MATCH_FACTOR;//на своем поле

NetOuts[i]:= O;//выход сети - номер нейрона (число забитых голов)

//аналогично добавляем отдельный обучающий набор для гостей:

inc(i);

for j:= 1 to LAST_MATCHES do begin

Ims[i, j]:= LastGoals[ Gi, 1, j];

Ims[i, j+LAST_MATCHES]:= LastGoals[ Gi, 2, j];

Ims[i, j+2*LAST_MATCHES]:= LastGoals[ Oi, 1, j];

Ims[i, j+3*LAST_MATCHES]:= LastGoals[ Oi, 2, j];

end;

for j:= 1 to 3 do begin

Ims[i, j+4*LAST_MATCHES]:= TMs[ Gi, j];

Ims[i, j+4*LAST_MATCHES+3]:= TMs[ Oi, j];

end;

Ims[i, k0]:= 0;//на чужом поле

NetOuts[i]:= G;

for j:= 1 to LAST_MATCHES-1 do begin//смещаем забитые голы на один матч:

LastGoals[ Gi, 1, j]:= LastGoals[ Gi, 1, j+1];

LastGoals[ Oi, 1, j]:= LastGoals[ Oi, 1, j+1];

LastGoals[ Gi, 2, j]:= LastGoals[ Gi, 2, j+1];

LastGoals[ Oi, 2, j]:= LastGoals[ Oi, 2, j+1];

end;

//и добавляем результаты последнего (текущего) для обучающих наборов будущих игр:

LastGoals[ Gi, 1, LAST_MATCHES]:= G;//забитые командой:

LastGoals[ Oi, 1, LAST_MATCHES]:= O;

LastGoals[ Gi, 2, LAST_MATCHES]:= O;//забитые команде соперниками:

LastGoals[ Oi, 2, LAST_MATCHES]:= G;

//добавляем результаты матча в текущую статистику команд:

if(O>G) then begin//победа хозяев:

TMs[ Oi, 1]:= TMs[ Oi, 1]+1;

TMs[ Gi, 3]:= TMs[ Gi, 3]+1;

end

else if(O=G) then begin//ничья:

TMs[ Oi, 2]:= TMs[ Oi, 2]+1;

TMs[ Gi, 2]:= TMs[ Gi, 2]+1;

end

else begin//победа гостей:

TMs[ Oi, 3]:= TMs[ Oi, 3]+1;

TMs[ Gi, 1]:= TMs[ Gi, 1]+1;

end;

Next;

end;

end;

mCount:= i;//}

//удаление малоинформативных (первых LAST_MATCHES) матчей:

i:= 1;

while(i <= mCount) do begin

if((Ims[i,L_GOALS2+1]+Ims[i,L_GOALS2+2]+Ims[i,L_GOALS2+3] < LAST_MATCHES)

or (Ims[i,L_GOALS2+4]+Ims[i,L_GOALS2+5]+Ims[i,L_GOALS2+6] < LAST_MATCHES)) then begin

for j:= 1 to k0 do

Ims[i, j]:= Ims[mCount, j];

NetOuts[i]:= NetOuts[mCount];

dec(mCount);

end

else inc(i);

end;//}

if (mCount > 0) then begin

Learn;

ButtonCalculate.Enabled:= True;

end

else ShowMessage('Нельзя обучить нейронную сеть: недостаточно сыгранных матчей у команд!');

end;

Прогнозирования результатов того или иного хоккейного матча осуществляется следующим образом:

procedure TFormMain.Prognosis;

var i,j,O,G: Longint;

Ims:array[1..2,1..k0] of real;

Outs: array[1..MAX_MATCHES] of Integer;

LastGoals: array[1..2,1..2,0..LAST_MATCHES+1] of Integer;

OwnerS,GuestS: String;

begin

with DM.ADOTableNewMatches do begin

First;

while not Eof do begin//прогнозы для всех новых матчей:

OwnerS:= FieldByName('OwnerTeam').AsString;

GuestS:= FieldByName('GuestTeam').AsString;

//формируем дла входных сигнала - для команды и соперника:

with DM.ADOTableTeamPointsEdit do begin//статистика турнира:

Active:= False;

Filtered:= True;

Filter:= 'Code = '+OwnerS;

Active:= True;

Ims[1, L_GOALS2+1]:= FieldByName('Win').AsInteger;

Ims[1, L_GOALS2+2]:= FieldByName('Draw').AsInteger;

Ims[1, L_GOALS2+3]:= FieldByName('Lost').AsInteger;

Ims[2, L_GOALS2+4]:= FieldByName('Win').AsInteger;

Ims[2, L_GOALS2+5]:= FieldByName('Draw').AsInteger;

Ims[2, L_GOALS2+6]:= FieldByName('Lost').AsInteger;

Active:= False;

Filter:= 'Code = '+GuestS;

Active:= True;

Ims[2, L_GOALS2+1]:= FieldByName('Win').AsInteger;

Ims[2, L_GOALS2+2]:= FieldByName('Draw').AsInteger;

Ims[2, L_GOALS2+3]:= FieldByName('Lost').AsInteger;

Ims[1, L_GOALS2+4]:= FieldByName('Win').AsInteger;

Ims[1, L_GOALS2+5]:= FieldByName('Draw').AsInteger;

Ims[1, L_GOALS2+6]:= FieldByName('Lost').AsInteger;

Active:= False;

end;

Ims[1, k0]:= OWNER_MATCH_FACTOR;

Ims[2, k0]:= 0;

with DM.ADOTableMatches do begin//голы последних матчей:

Active:= False;

Filtered:= True;

Filter:= 'OwnerTeam = '+OwnerS+' OR GuestTeam = '+OwnerS+'';//сначала голы хозяев (в новой игре)

Active:= True;

Last;

j:= LAST_MATCHES;

while(j > 0) do begin

O:= FieldByName('OwnerGoals').AsInteger;

G:= FieldByName('GuestGoals').AsInteger;

if(OwnerS = FieldByName('OwnerTeam').AsString) then begin

LastGoals[1,1,j]:= O;

LastGoals[1,2,j]:= G;

end

else begin

LastGoals[1,2,j]:= O;

LastGoals[1,1,j]:= G;

end;

Prior;

dec(j);

end;

Active:= False;

Filter:= 'OwnerTeam = '+GuestS+' OR GuestTeam = '+GuestS+'';//голы гостей (забитые и пропущенные)

Active:= True;

Last;

j:= LAST_MATCHES;

while(j > 0) do begin

O:= FieldByName('OwnerGoals').AsInteger;

G:= FieldByName('GuestGoals').AsInteger;

if(GuestS = FieldByName('OwnerTeam').AsString) then begin

LastGoals[2,1,j]:= O;

LastGoals[2,2,j]:= G;

end

else begin

LastGoals[2,2,j]:= O;

LastGoals[2,1,j]:= G;

end;

Prior;

dec(j);

end;

Active:= False;

end;

for j:= 1 to LAST_MATCHES do begin//заносим голы во входные образцы:

Ims[1, j]:= LastGoals[1,1,j];

Ims[1, j+LAST_MATCHES]:= LastGoals[1,2,j];

Ims[2, j]:= LastGoals[2,1,j];

Ims[2, j+LAST_MATCHES]:= LastGoals[2,2,j];

Ims[2, j+2*LAST_MATCHES]:= LastGoals[1,1,j];

Ims[2, j+3*LAST_MATCHES]:= LastGoals[1,2,j];

Ims[1, j+2*LAST_MATCHES]:= LastGoals[2,1,j];

Ims[1, j+3*LAST_MATCHES]:= LastGoals[2,2,j];

end;

Edit;

//расчитываем голы хозяев:

for j:= 1 to k0 do

X[j]:= Ims[1, j];

NeuronOuts;

FieldByName('OwnerGoals').AsInteger:= d;

//расчитываем голы гостей:

for j:= 1 to k0 do

X[j]:= Ims[2, j];

NeuronOuts;

FieldByName('GuestGoals').AsInteger:= d;

Post;

Next;

end;

end;