Willino Blog

Sono un ingegnere informatico, appassionato di fotografia, chitarra acustica, micologia e Tennis Tavolo. In questo blog cercherò di raccontare eventi ed esperienze che in qualche modo potrebbero risultare utili a tutti.

venerdì 23 gennaio 2009

Addenstramento di un neurone artificiale

Posto il codice da me creato per addestrare un robot a due neuroni a navigare lungo un corridoio usando cone sensori soltanto due baffi a contatto.
Ogni neurone controlla lo stato di uno dei due motori del robot (uno per la ruona sx e uno per la ruota dx).
Fare riferimento a percettrone per un piccolo cenno di teoria.

unit IA1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, Buttons, Grids;

{

-----------------------------------
Esercizio personale
-----------------------------------
ROBOTICA MOBILE
-----------------------------------
Università Degli Studi di Palermo
Ingegneria Informatica
William Pristia
-----------------------------------

Addenstramento di un percettrone per la navigazione di un robot munito di due sensori a baffo.

E' stato scelto un campione di 3 vettori di input con tre diverse risposte della rete
Un valore di soglia di -0.001
un tasso di apprendimento di 0.3

}

Type
TWeight = Real;
TWeightsVector = Array Of TWeight;
TInputsVector = TWeightsVector;
TThreshold = Real;
TPerceptron = Class;

TOnStepEvent = Procedure (Sender : TPerceptron;
Const Step : Integer;
Const WeightsVector : TWeightsVector;
Const OutPutValue : TThreshold) Of Object;

TQueryInputsVectorEvent = Procedure (Sender : TPerceptron;
Var Vector : TInputsVector) Of Object;

TQueryOutputValueEvent = Procedure (Sender : TPerceptron; Var
Output : TThreshold) Of Object;

TQueryCoefficientOfLearning = Procedure (Sender : TPerceptron;
Var Coefficient : TThreshold) Of Object;

TPerceptron = Class
Private
fCurrentStep : Integer;
fInitialWeightsVector,
fPredWeightsVector : TWeightsVector;
fVectorSize: Integer;
fActive: Boolean;
fThreshold,
fInitialCoefficientOfLearning: TThreshold;
fCoefficientOfLearning: TThreshold;
fSteps: Integer;
fOnQueryInputsVector: TQueryInputsVectorEvent;
fOnQueryOutputValue: TQueryOutputValueEvent;
fOnQueryCoefficientOfLearning: TQueryCoefficientOfLearning;
fOnStep: TOnStepEvent; // coefficiente di apprendimento
Procedure ClearVectors;
procedure SetVectorSize(const Value: Integer);
Protected
// Funzione di eccitazione.
// la classe base implementa il percettrone classico con la funzione uguale a Sgn(X)
Function ExcitationFunction(Value : Real) : Real; Virtual;
// Funzione di aggiornamento costante di apprendimento
Procedure UpdateCoefficientOfLearning; Virtual;
Procedure UpdateInputsVector; Virtual;
Procedure UpdateOutputValue; Virtual;
Procedure InitWeightsVector; Dynamic;
Procedure BeginTraining; Dynamic;
Procedure StopTraining; Dynamic;
Public

InputsVector : TInputsVector; // vettore di ingresso
WeightsVector : TWeightsVector; // Vettore dei pesi
OutPutValue : TThreshold; // valore atteso di uscita (ecco perchè con apprendimento supervisionato)

Class Function ScalarProduct(aReal : TThreshold;
aVector : TInputsVector) : Real;
Class Function WeightedSum(aWeightsVector : TWeightsVector;
aInputsVector : TInputsVector) : Real;

Constructor Create; Virtual;
Destructor Destroy; Override;
Procedure TrainsThisStep; Virtual;
Procedure RunTraining;

Property Active : Boolean
Read fActive;
Property Steps : Integer
Read fSteps
Write fSteps;
Property VectorSize : Integer
Read fVectorSize
Write SetVectorSize; // Numero componenti dei vettori
Property CoefficientOfLearning : TThreshold
Read fCoefficientOfLearning
Write fCoefficientOfLearning;
Property Threshold : TThreshold
Read fThreshold
Write fThreshold; // Valore di soglia
Property CurrentStep : Integer
Read fCurrentStep;

Property InitialWeightsVector : TWeightsVector
Read fInitialWeightsVector;
Property InitialCoefficientOfLearning : TThreshold
Read fInitialCoefficientOfLearning
Write fInitialCoefficientOfLearning;

// Eventi associati alla richiesta dei vettori di input e del valore di output
Property OnQueryInputsVector : TQueryInputsVectorEvent
Read fOnQueryInputsVector
Write fOnQueryInputsVector;
Property OnQueryOutputValue : TQueryOutputValueEvent
Read fOnQueryOutputValue
Write fOnQueryOutputValue;
// Eventi associati alla richiesta di aggiornamento della costante di apprendimento
Property OnQueryCoefficientOfLearning : TQueryCoefficientOfLearning
Read fOnQueryCoefficientOfLearning
Write fOnQueryCoefficientOfLearning;
// Eventi associati alla computazione di un passo di apprendimento
Property OnStep : TOnStepEvent
Read fOnStep
Write fOnStep;
End;

TEngine = Class(TPerceptron)
Public
Constructor Create; Override;
Procedure UpdateInputsVector; Override;
End;

TForm3 = class(TForm)
BitBtn1: TBitBtn;
sg: TStringGrid;
procedure BitBtn1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
Procedure UpdateLeftEngineOutputValue(Sender : TPerceptron;
Var Output : TThreshold);
Procedure UpdateRightEngineOutputValue(Sender : TPerceptron;
Var Output : TThreshold);
Procedure Step(Sender : TPerceptron;
Const Step : Integer;
Const WeightsVector : TWeightsVector;
Const OutPutValue : TThreshold);
end;


Procedure MakeRandomInput(Var Vector : TInputsVector);

var
Form3: TForm3;

implementation

Uses
Math;

{$R *.dfm}

Procedure MakeRandomInput(Var Vector : TInputsVector);
Var
I : Integer;
Begin
for I:=Low(Vector) to High(Vector) Do
Begin
Randomize;
// Inizializzazione normalizzata a 1 :
//
// / x \ (y)
// | ------- | * (-1)
// \ 1000 /
//
// con x e y casuali
Vector[I]:=((Random(1000)+1)/1000) * (Power(-1,Random(1000)));
End;
End;

{ TPerceptron }

procedure TPerceptron.BeginTraining;
begin
fActive:=True;
fCurrentStep:=0;
InitWeightsVector;
fCoefficientOfLearning:=fInitialCoefficientOfLearning;
end;

procedure TPerceptron.ClearVectors;
Var
I : Integer;
begin
For I:=0 To Pred(fVectorSize) Do
Begin
fInitialWeightsVector[I]:=0;
fPredWeightsVector[I]:=0;
WeightsVector[I]:=0;
End;
end;

constructor TPerceptron.Create;
begin
fActive:=False;
fSteps:=5;
fVectorSize:=0;
ClearVectors;
SetLength(InputsVector,fVectorSize);
FillChar(InputsVector,Length(InputsVector),0);
fThreshold:=0;
fInitialCoefficientOfLearning:=0; // un valore classico
end;

destructor TPerceptron.Destroy;
begin
SetLength(fPredWeightsVector,0);
fPredWeightsVector:=Nil;
SetLength(WeightsVector,0);
WeightsVector:=Nil;
inherited;
end;

function TPerceptron.ExcitationFunction(Value: Real): Real;
begin
If (Value-fThreshold)>0 Then
Result:=1
Else
Result:=0;
end;

procedure TPerceptron.InitWeightsVector;
Var
I : Integer;
begin
If fVectorSize>0 Then
Begin
ClearVectors;
For I:=0 To Pred(fVectorSize) Do
Begin
Randomize;
// Inizializzazione normalizzata a 1 :
//
// / x \ (y)
// | ------- | * (-1)
// \ 1000 /
//
// con x e y casuali
fInitialWeightsVector[I] :=((Random(1000)+1)/1000) * (Power(-1,Random(1000)));
WeightsVector[I]:=fInitialWeightsVector[I];
End;
End;
end;

procedure TPerceptron.RunTraining;
Var
I : Integer;
begin
BeginTraining;
For I:=1 To fSteps Do
Begin
fCurrentStep:=I;
UpdateInputsVector;
UpdateOutputValue;
TrainsThisStep;
If I
UpdateCoefficientOfLearning;
End;
StopTraining;
end;

class function TPerceptron.ScalarProduct(aReal: TThreshold;
aVector: TInputsVector): Real;
Var
I : Integer;
begin
// prodotto scalare per reale dell'errore per il vettore di input
Result:=0;
For I:=Low(aVector) To high(aVector) Do
Result:=Result+(aReal*aVector[I]);
end;

procedure TPerceptron.SetVectorSize(const Value: Integer);
begin
fVectorSize := Value;
SetLength(fPredWeightsVector,Value);
SetLength(fInitialWeightsVector,Value);
SetLength(WeightsVector,Value);
SetLength(InputsVector,Value);
end;


procedure TPerceptron.StopTraining;
begin
fActive:=False;
end;

procedure TPerceptron.TrainsThisStep;
Var
I : Integer;
lScalar, // prodotto scalare del vettore degli input per l'errore
lError, // errore (valore atteso - valore reale)
lSum : TThreshold; // somma pesata
lResult : Real; // valore reale
begin
// Calcolo dell'input netto (somma pesata)
lSum:=WeightedSum(WeightsVector,InputsVector);

// si sottopone l'input netto o potenziale (a meno della soglia)
// alla funzione di attivazione (uscita del neurone)
lResult:=ExcitationFunction(lSum);

//Aggiornamento vettore pesi
For I:=0 To Pred(fVectorSize) Do
Begin
// Calcolo dell'errore
lError:=OutPutValue - lResult;

// prodotto scalare per reale dell'errore per il vettore di input
lScalar:=ScalarProduct(lError,InputsVector);

// Aggiornamento del vettore dei pesi
WeightsVector[I]:=fPredWeightsVector[I] + (fCoefficientOfLearning * lScalar);
fPredWeightsVector[I]:=WeightsVector[I];
If Assigned(fOnStep) Then fOnStep(Self,fCurrentStep,WeightsVector,OutputValue);
End;
end;

procedure TPerceptron.UpdateCoefficientOfLearning;
begin
If Assigned(fOnQueryCoefficientOfLearning) Then
fOnQueryCoefficientOfLearning(Self,fCoefficientOfLearning);
end;

procedure TPerceptron.UpdateInputsVector;
begin
If Assigned(fOnQueryInputsVector) Then
fOnQueryInputsVector(Self,InputsVector);
end;

procedure TPerceptron.UpdateOutputValue;
begin
If Assigned(fOnQueryOutputValue) Then
fOnQueryOutputValue(Self,OutputValue);
end;

class function TPerceptron.WeightedSum(aWeightsVector: TWeightsVector;
aInputsVector: TInputsVector): Real;
Var
I : Integer;
begin
Result:=0;
If Length(aWeightsVector)=Length(aWeightsVector) Then
For I:=Low(aWeightsVector) To High(aWeightsVector) Do
Result:=Result+(aWeightsVector[I] * aInputsVector[I]);
end;

{ TEngine }

constructor TEngine.Create;
begin
inherited;
Steps:=3;
VectorSize:=2;
Threshold:=-0.001;
InitialCoefficientOfLearning:=0.3;
end;

procedure TEngine.UpdateInputsVector;
begin
Case CurrentStep Of
1 : Begin
InputsVector[0]:=0;
InputsVector[1]:=0;
End;
2 : Begin
InputsVector[0]:=0;
InputsVector[1]:=1;
End;
3 : Begin
InputsVector[0]:=1;
InputsVector[1]:=0;
End;
End;
end;

{TForm3}

procedure TForm3.Step(Sender: TPerceptron;
Const Step : Integer;
const WeightsVector: TWeightsVector;
const OutPutValue: TThreshold);
Var
I : Integer;
begin
For I:=0 To Pred(Sender.VectorSize) Do
Begin
sg.Cells[I,Step-1]:=FloatToStr(Sender.WeightsVector[I]);
End;
end;

procedure TForm3.UpdateLeftEngineOutputValue;
begin
Case Sender.CurrentStep Of
1 : Output:=1;
2 : Output:=1;
3 : Output:=-1;
End;
end;

procedure TForm3.UpdateRightEngineOutputValue;
begin
Case Sender.CurrentStep Of
1 : Output:=1;
2 : Output:=-1;
3 : Output:=1;
End;
end;

procedure TForm3.BitBtn1Click(Sender: TObject);
Var
A : TEngine;
I : Integer;
begin
sg.rowCount:=3;
sg.ColCount:=2;

A:=TEngine.Create;
A.OnQueryOutputValue:=UpdateLeftEngineOutputValue;
A.OnStep:=Step;
A.RunTraining;
{ For I:=0 To Pred(A.VectorSize) Do
Begin
sg.Cells[I,0]:=FloatToStr(A.InitialWeightsVector[I]);
sg.Cells[I,1]:=FloatToStr(A.WeightsVector[I]);
End;}
A.Free;
end;


end.

Nessun commento:

ANSA.it - Top News