Pages

[Artigo]: Introduzindo Redes Neurais e Adaline

Sunday, December 21, 2008

Olá a todos,


Nesse post irei apresentar a outra rede neural direta e pioneira bastante conhecida além do Perceptron: A Adaline. Seguirei a mesma linha utilizada no tutorial anterior com implementações desenvolvidas em python.

Apresentando a Adaline

A Adaline (Adaptative Linear Neuron) foi desenvolvida por Widrow e Hoff em 1959. Foi criada anos depois do aparecimento do Perceptron e é um clássico modelo de neurônio que permite saídas tanto diretas quanto contínuas e pode ser usado para tarefas de classificação e regressão.

Para estas tarefas, o Adaline apresenta uma regra de aprendizado sofisticado, a Regra Delta, que se trata de um método de regressão linear que diminuía a cada exemplo a distância entre a saída obtida e a desejada através de adaptações graduais dos pesos do Perceptron.

Mas o que seria Regressão linear ?

A regressão consiste na busca por uma função que represente, de forma aproximada o comportamento apresentado pelo fenômeno em estudo. A forma mais conhecida de regressão é a linear, por exemplo, uma reta que minimiza o erro médio entre todos os valores considerados.

O gráfico abaixo ilustra um exemplo de um problema de regressão linear em duas dimensões. A busca pela "melhor" reta que melhor represente o conjunto de dados pode ser obtida através da rede Neural Adaline, o qual será explicado nos próximos tópicos.



Problema de regressão de linear

Treinamento

O Adaline é similar ao Perceptron, com diferença apenas pelo seu algoritmo de treinamento. Enquanto o Perceptron ajusta os pesos somente quando um padrão é classificado incorretamente, o Adaline utiliza a regra Delta para minimizar o erro médio (MSE) após cada padrão ser apresentado, ajustando os pesos proporcionalmente ao erro.

A regra Delta foi projetada para eliminar a deficiência do algoritmo de treinamento do perceptron quando são apresentados dados não linearmente separáveis. Ela simplesmente converge até um valor desejado aproximado, onde a função tem taxa de variação máxima. Para isso, ela utiliza de um algoritmo de gradiente descendente, com a intenção de diminuir o valor da função de erro. Este algoritmo pode ser visto como uma "caminhada" no domínio da função do erro , em que casa passo é feito no sentido oposto ao gradiente da função no ponto atual.

Imagine um ADALINE com apenas uma entrada x. Neste caso o neurônio terá apenas 2 pesos, w0 e w1. Logo, a função de erro será bidimensional. No figura abaixo é apresentado o
gráfico da função de erro para 50 padrões de treinamento criados aleatoriamente.


O algoritmo de treinamento do Adaline trabalha tentando minimizar o erro das saídas em relação aos valores desejados di pertencentes ao conjunto de treinamento. A função de custo a ser minimizada é a soma dos erros quadráticos descrita na equação:


Para uma condição inicial qualquer w(0)=wi deseja-se obter a direção do ajuste a ser aplicado no vetor de pesos de forma a caminhar em direção à solução ótima. Para a superfície de erro definida pela equação acima, a direção do ajuste no tempo t pode ser obtida pelo gradiente da função de custo no ponto w(t). Segundo esta regra, o ajuste deve ser feito em direção contrária ao vetor gradiente no ponto w(t). A figura abaixo ilustra o conceito apresentado acima. Os pesos iniciais começam a caminhar (convergir) em direção à solução ótima que seria quando o erro for o mínimo possível.



Baseado nesses conceitos a equação de atualização dos pesos pode ser definida por:

wi   wi +  (d - y)xi
b b +  (d - y)


Veremos agora através de implementação pelo código como esse algoritmo funciona. Utilizaremos o exemplo demonstrado na figura acima do problema de regressão linear, onde dado um conjunto de pontos, precisamos definir a melhor reta (y = ax + b) que represente esse que represente, de forma aproximada o comportamento apresentado pelo fenômeno estudado.

Para resolvermos esse problema nós precisamos de uma rede representada pela figura abaixo, da mesma maneira que o Perceptron com apenas algumas diferenças na saída do neurônio, onde a saída agora é passada por uma função de ativação linear em vez de uma função degrau (1 ou -1).

single layer perceptron


Como vocês podem observar, cada nó de entrada (input) está diretamente conectado ao nó de saída (output). Ajustando os valores dos pesos (weight) que conectam tais nós , a rede é capaz de aprender.

Veremos abaixo como isso funciona.

Um algoritmo simples

Segue o código-fonte relacionado ao neurônio. Há uma pequena diferença em relação ao Perceptron, em relação ao cálculo do erro global, que é realizado após o treinamento da rede e o surgimento de uma nova variável que é o limiar de erro (biasError), já que as saídas são contínuas no Adaline.




##################################################
# #
# Copyright 2008 -Marcel Pinheiro Caraciolo- #
# Email: caraciol@gmail.com #
# #
# -- Adaline Neural Net snippet code #
# -- Version: 0.1 - 12/12/2008 #
##################################################

#Snippet Neuron

from random import random

class Neuron:


def __init__(self,data,learningRate = 0.0000002, biasError = 0.01, bias = 1):
self._learning_rate = learningRate
#Threshold representing the bias (b of the equation y=ax+b)
self._biasError = biasError
self._bias = bias
self._input,self._output = data
#Randomise weights (Put one more entry for the weights vector to the bias).
self._weight = map(lambda x: x*random(), [0] * (len(self._input)+1))
#print self._weight
self._y = None
self._global_error = 1.0


def train(self,data):
self._input,self._output = data
#Append the bias into the input vector.
#bug in python @todo: FIX IT.
if len(self._input) == 1:
self._input.append(self._bias)

#Calculate output.
self._y = self._calculateOutput()
#Calculate error.
if self._error() > self._biasError:
#Update weights.
self._adjustWeight()



def calculateGlobalError(self,data):
self._input,self._output = data
#Append the bias into the input vector.
#bug in python @todo: FIX IT.
if len(self._input) == 1:
self._input.append(self._bias)
#Calculate output.
self._y = self._calculateOutput()
#Calculate the local error.
localError = abs(self._error())
if localError > self._biasError:
#Calculate the Global Error
self._global_error += localError

def execute(self,input):
self._input = input
#Calculate output.
self._y = self._calculateOutput()
return self._y

def _calculateOutput(self):
#return (self._weight[0] * self._input[0] + self._weight[1])
return sum(map(lambda x,y: x*y, self._input,self._weight))

def _error(self):
return self._output - self._y

def _adjustWeight(self):
self._weight = map(lambda x,y: x + (y*self._learning_rate*self._error()),self._weight,self._input)
#self._weight[0] += self._input[0] * self._learning_rate * self._error()
#self._weight[1] += self._learning_rate * self._error()

def getGlobalError(self):
return self._global_error

def getWeights(self):
return self._weight

def resetGlobalError(self):
self._global_error = 0.0


O código seguinte refere-se ao Adaline, que é o que irá apresentar os exemplos ao neurônio:


##################################################
# #
# Copyright 2008 -Marcel Pinheiro Caraciolo- #
# Email: caraciol@gmail.com #
# #
# -- Adaline Neural Net snippet code #
# -- Version: 0.1 - 28/12/2008 #
##################################################


#Snippet Adaline

from Neuron import *


class Adaline:

def __init__(self,inputs,iterations=100):
self._inputs = inputs
self._refresh_inputs = list(inputs)
self._iterations = iterations
self._iteration = 0
self._neuron = Neuron(self._getRandInput())
self._train()


def _train(self):
globalError = self._neuron.getGlobalError()
while self._iteration <= self._iterations and globalError != 0.0:
self._neuron.resetGlobalError()
self._refresh_inputs = list(self._inputs)
for i in range(len(self._refresh_inputs)):
self._neuron.train(self._getRandInput())
self._refresh_inputs = list(self._inputs)
for i in range(len(self._refresh_inputs)):
self._neuron.calculateGlobalError(self._getRandInput())
globalError = self._neuron.getGlobalError()/len(self._inputs)
print "Iteration %d Error: %f" % (self._iteration, globalError)
self._iteration += 1


def _getRandInput(self):
return self._refresh_inputs.pop()


def execute(self,input):
return self._neuron.execute(input)


def arange(self,start,stop=None,step=None):
if stop is None:
stop = float(start)
start = 0.0
if step is None:
step = 1.0
cur = float(start)
while cur <= stop:
yield cur
cur+=step

def getCoefficients(self):
return self._neuron.getWeights()



Execute as classes acima usando:


#main Logic

#Load sample input patterns

inputs = [ [[0.4],0.7], [[0.9],1.0], [[1.5],0.8], [[2.3],0.9],
[[2.9],1.4], [[3.1],2.1], [[3.7],2.4] ]


adaline = Adaline(inputs,351000)

#Display network generalization
print "Y = %f * x + %f " %(adaline.getCoefficients()[0],adaline.getCoefficients()[1])


A saída da rede após o treinamento é exibida conforme abaixo. Pode-se observar que o erro global vai reduzindo ao decorrer das iteraçôes. Embora não se tenha obtido um erro global igual 0.0, o treinamento foi interrompido pelo numero máximo de iterações que foi colocado como parâmetro (351000).



(...)
Iteration 350974 Error: 0.305201
Iteration 350975 Error: 0.305201
Iteration 350976 Error: 0.305201
Iteration 350977 Error: 0.305200
Iteration 350978 Error: 0.305200
Iteration 350979 Error: 0.305200
Iteration 350980 Error: 0.305200
Iteration 350981 Error: 0.305200
Iteration 350982 Error: 0.305200
Iteration 350983 Error: 0.305200
Iteration 350984 Error: 0.305200
Iteration 350985 Error: 0.305200
Iteration 350986 Error: 0.305199
Iteration 350987 Error: 0.305199
Iteration 350988 Error: 0.305199
Iteration 350989 Error: 0.305199
Iteration 350990 Error: 0.305199
Iteration 350991 Error: 0.305199
Iteration 350992 Error: 0.305199
Iteration 350993 Error: 0.305199
Iteration 350994 Error: 0.305199
Iteration 350995 Error: 0.305199
Iteration 350996 Error: 0.305198
Iteration 350997 Error: 0.305198
Iteration 350998 Error: 0.305198
Iteration 350999 Error: 0.305198
Iteration 351000 Error: 0.305198

Final Result:
Y = 0.531989 * x + 0.218829


Plotando o gráfico com a equação da reta obtida pelo treinamento da rede, observamos abaixo a reta (de cor marrom) que mais se aproxima do conjunto de valores de entrada da rede, provando a sua generalização e a capacidade de resolver problemas de regressão linear.



Download dos códigos aqui.

3 comments:

  1. WIZTECH Automation, Anna Nagar, Chennai, has earned reputation offering the best automation training in Chennai in the field of industrial automation. Flexible timings, hands-on-experience, 100% practical. The candidates are given enhanced job oriented practical training in all major brands of PLCs (AB, Keyence, ABB, GE-FANUC, OMRON, DELTA, SIEMENS, MITSUBISHI, SCHNEIDER, and MESSUNG)

    PLC training in chennai
    Automation training in chennai
    Best plc training in chennai
    PLC SCADA training in chennai
    Process automation training in chennai
    Final year eee projects in chennai
    VLSI training in chennai

    ReplyDelete
  2. Embedded system training: Wiztech Automation Provides Excellent training in embedded system training in Chennai - IEEE Projects - Mechanical projects in Chennai Wiztech provide 100% practical training, Individual focus, Free Accommodation, Placement for top companies. The study also includes standard microcontrollers such as Intel 8051, PIC, AVR, ARM, ARMCotex, Arduino etc.

    Embedded system training in chennai
    Embedded Course training in chennai
    Matlab training in chennai
    Android training in chennai
    LabVIEW training in chennai
    Arduino training in chennai
    Robotics training in chennai
    Oracle training in chennai
    Final year projects in chennai
    Mechanical projects in chennai
    ece projects in chennai

    ReplyDelete