Perceptron
O perceptron é um tipo de rede neural artificial inventada em 1958 por Frank Rosenblatt no Cornell Aeronautical Laboratory.[1][2] Ele pode ser visto como o tipo mais simples de rede neural feedforward: um classificador linear.[1][2]
Definição
O perceptron é um classificador binário que mapeia sua entrada (um vetor de valor real) para um valor de saída (uma valor binário simples) através da matriz.
Onde é um vetor de peso real e é o produto escalar (que computa uma soma com pesos) e é o viés (do inglês "bias"), um termo constante que não depende de qualquer valor de entrada.
Implementação em Python
''' Este projeto esta disponivel no GiHub de Marcos castro de Sousa Implementação da rede neural Perceptron w = w + N * (d(k) - y) * x(k) ''' import random, copy class Perceptron: def __init__(self, amostras, saidas, taxa_aprendizado=0.1, epocas=1000, limiar=-1): self.amostras = amostras # todas as amostras self.saidas = saidas # saídas respectivas de cada amostra self.taxa_aprendizado = taxa_aprendizado # taxa de aprendizado (entre 0 e 1) self.epocas = epocas # número de épocas self.limiar = limiar # limiar self.num_amostras = len(amostras) # quantidade de amostras self.num_amostra = len(amostras[0]) # quantidade de elementos por amostra self.pesos = [] # vetor de pesos # função para treinar a rede def treinar(self): # adiciona -1 para cada uma das amostras for amostra in self.amostras: amostra.insert(0, -1) # inicia o vetor de pesos com valores aleatórios for i in range(self.num_amostra): self.pesos.append(random.random()) # insere o limiar no vetor de pesos self.pesos.insert(0, self.limiar) # inicia o contador de epocas num_epocas = 0 while True: erro = False # o erro inicialmente inexiste # para todas as amostras de treinamento for i in range(self.num_amostras): u = 0 ''' realiza o somatório, o limite (self.amostra + 1) é porque foi inserido o -1 para cada amostra ''' for j in range(self.num_amostra + 1): u += self.pesos[j] * self.amostras[i][j] # obtém a saída da rede utilizando a função de ativação y = self.sinal(u) # verifica se a saída da rede é diferente da saída desejada if y != self.saidas[i]: # calcula o erro: subtração entre a saída desejada e a saída da rede erro_aux = self.saidas[i] - y # faz o ajuste dos pesos para cada elemento da amostra for j in range(self.num_amostra + 1): self.pesos[j] = self.pesos[j] + self.taxa_aprendizado * erro_aux * self.amostras[i][j] erro = True # ainda existe erro # incrementa o número de épocas num_epocas += 1 # critério de parada é pelo número de épocas ou se não existir erro if num_epocas > self.epocas or not erro: break # função utilizada para testar a rede # recebe uma amostra a ser classificada e os nomes das classes # utiliza a função sinal, se é -1 então é classe1, senão é classe2 def testar(self, amostra, classe1, classe2): # insere o -1 amostra.insert(0, -1) # utiliza o vetor de pesos que foi ajustado na fase de treinamento u = 0 for i in range(self.num_amostra + 1): u += self.pesos[i] * amostra[i] # calcula a saída da rede y = self.sinal(u) # verifica a qual classe pertence if y == -1: print('A amostra pertence a classe %s' % classe1) else: print('A amostra pertence a classe %s' % classe2) # função de ativação: degrau bipolar (sinal) def sinal(self, u): return 1 if u >= 0 else -1 print('\nA ou B?\n') # amostras: um total de 4 amostras amostras = [[0.1, 0.4, 0.7], [0.3, 0.7, 0.2], [0.6, 0.9, 0.8], [0.5, 0.7, 0.1]] # saídas desejadas de cada amostra saidas = [1, -1, -1, 1] # conjunto de amostras de testes testes = copy.deepcopy(amostras) # cria uma rede Perceptron rede = Perceptron(amostras=amostras, saidas=saidas, taxa_aprendizado=0.1, epocas=1000) # treina a rede rede.treinar() # testando a rede for teste in testes: rede.testar(teste, 'A', 'B')
Implementação em C#
using System; using System.Linq; namespace perceptron { public class Perceptron { static readonly double[] w = new double[3]; private readonly int[,] _matrizAprendizado = new int[4, 3]; private double _net; Perceptron() { //tabela AND _matrizAprendizado[0, 0] = 0; _matrizAprendizado[0, 1] = 0; _matrizAprendizado[0, 2] = 0; _matrizAprendizado[1, 0] = 0; _matrizAprendizado[1, 1] = 1; _matrizAprendizado[1, 2] = 0; _matrizAprendizado[2, 0] = 1; _matrizAprendizado[2, 1] = 0; _matrizAprendizado[2, 2] = 0; _matrizAprendizado[3, 0] = 1; _matrizAprendizado[3, 1] = 1; _matrizAprendizado[3, 2] = 1; w[0] = 0; w[1] = 0; w[2] = 0; } public static void Main(string[] args) { //pesos antes do treinamento w.ToList().ForEach(x => Console.WriteLine(x + ",")); Console.WriteLine("\n"); //efetua-se o treinamento da rede new Perceptron().Treinar(); Console.WriteLine("\n"); //pesos ajustados após treinamento w.ToList().ForEach(x => Console.WriteLine(x + ",")); //dados de entrada para rede treinada, 0 e 0 resulta em 0 (tabela and) -1 corresponde ao BIAS int[] amostra1 = { 0, 1, -1 }; // 0 e 1 -> 0 Classe B int[] amostra2 = { 1, 0, -1 }; // 1 e 0 -> 0 Classe B int[] amostra3 = { 0, 0, -1 }; // 0 e 0 -> 0 Classe B int[] amostra4 = { 1, 1, -1 }; // 1 e 1 -> 1 Classe A ClassificarAmostra(amostra1); ClassificarAmostra(amostra2); ClassificarAmostra(amostra3); ClassificarAmostra(amostra4); Console.ReadKey(); } public static void ClassificarAmostra(int[] amostra) { //pesos encontrados após o treinamento int[] pesos = { 2, 1, 3 }; //aplicação da separação dos dados linearmente após aprendizado var u = amostra.Select((t, k) => pesos[k] * t).Sum(); var y = LimiarAtivacao(u); Console.WriteLine(y > 0 ? "Amostra da classe A >= 0" : "HelloWorld < 0"); } private static int LimiarAtivacao(double u) { return (u >= 0) ? 1 : 0; } int Executar(int x1, int x2) { _net = (x1 * w[0]) + (x2 * w[1]) + ((-1) * w[2]); return (_net >= 0) ? 1 : 0; } public void Treinar() { var treinou = true; for (var i = 0; i < _matrizAprendizado.GetLength(0); i++) { var saida = Executar(_matrizAprendizado[i, 0], _matrizAprendizado[i, 1]); if (saida != _matrizAprendizado[i, 2]) { CorrigirPeso(i, saida); treinou = false; } } if (!treinou) Treinar(); } void CorrigirPeso(int i, int saida) { w[0] = w[0] + (1 * (_matrizAprendizado[i, 2] - saida) * _matrizAprendizado[i, 0]); w[1] = w[1] + (1 * (_matrizAprendizado[i, 2] - saida) * _matrizAprendizado[i, 1]); w[2] = w[2] + (1 * (_matrizAprendizado[i, 2] - saida) * (-1)); } } }
Implementação em Ruby
# # Classe PERCEPTRON responsável para aprendizado e resolução da tabela AND # class Perceptron def initialize # pesos sinápticos [0] entrada 1, [1] entrada 2, [3]BIAS @w = [] # variável responsável pelo somatório(rede). @net = 0 # variavél responsável pelo número máximo de épocas @epocasMax = 30 # variável responsável pela contagem das épocas durante o treinamento @count = 0 # declara o vetor da matriz de aprendizado @matriz_aprendizado = [] self.inicia_matriz end def inicia_matriz # Primeiro valor @matriz_aprendizado[0] = [] @matriz_aprendizado[0][0] = 0; # entrada 1 @matriz_aprendizado[0][1] = 0; # entrada 2 @matriz_aprendizado[0][2] = 0; # valor esperado # Segundo Valor @matriz_aprendizado[1] = [] @matriz_aprendizado[1][0] = 0; # entrada 1 @matriz_aprendizado[1][1] = 1; # entrada 2 @matriz_aprendizado[1][2] = 0; # valor esperado # terceiro valor @matriz_aprendizado[2] = [] @matriz_aprendizado[2][0] = 1; # entrada 1 @matriz_aprendizado[2][1] = 0; # entrada 2 @matriz_aprendizado[2][2] = 0; # valor esperado # quarto valor @matriz_aprendizado[3] = [] @matriz_aprendizado[3][0] = 1; # entrada 1 @matriz_aprendizado[3][1] = 1; # entrada 2 @matriz_aprendizado[3][2] = 1; # valor esperado # inicialização dos pesos sinápticos # Peso sináptico para primeira entrada. @w[0] = 0; # Peso sináptico para segunda entrada. @w[1] = 0; # Peso sináptico para o BIAS @w[2] = 0; end # Método responsávelpelo somatório e a função de ativação. def executar(x1, x2) # Somatório (NET) @net = (x1 * @w[0]) + (x2 * @w[1]) + ((-1) * @w[2]); # Função de Ativação return 1 if (@net >= 0) return 0; end # Método para treinamento da rede def treinar() # variavel utilizada responsável pelo controlede treinamento recebefalso treinou = true; # varável responsável para receber o valor da saída (y) saida = nil; # laço usado para fazer todas as entradas @matriz_aprendizado.length.times do |i| # A saída recebe o resultado da rede que no caso é 1 ou 0 saida = self.executar(@matriz_aprendizado[i][0], @matriz_aprendizado[i][1]); if (saida != @matriz_aprendizado[i][2]) # Caso a saída seja diferente do valor esperado # os pesos sinápticos serão corrigidos self.corrigirPeso(i, saida); # a variavél responsável pelo controlede treinamento recebe falso treinou = false; end end # acrescenta uma época @count+=1; # teste se houve algum erro duranteo treinamento e o número de epocas #é menor qe o definido if(not treinou and (@count < @epocasMax)) # chamada recursiva do método self.treinar(); end end # fim do método para treinamento # Método para a correção de pesos def corrigirPeso(i, saida) @w[0] = @w[0] + (1 * (@matriz_aprendizado[i][2] - saida) * @matriz_aprendizado[i][0]); @w[1] = @w[1] + (1 * (@matriz_aprendizado[i][2] - saida) * @matriz_aprendizado[i][1]); @w[2] = @w[2] + (1 * (@matriz_aprendizado[i][2] - saida) * (-1)); end end
Implementação em Java
/* * Classe PERCEPTRON responsável para aprendizado e resolução da tabela AND */ public class Perceptron { // pesos sinápticos [0] entrada 1, [1] entrada 2, [3]BIAS private double[] w = new double[3]; // variável responsável pelo somatório(rede). private double NET = 0; // variavél responsável pelo número máximo de épocas private final int epocasMax = 30; // variável responsável pela contagem das épocas durante o treinamento private int count = 0; // declara o vetor da matriz de aprendizado private int[][] matrizAprendizado = new int[4][3]; // MÉTODO DE RETORNO DO CONTADOR public int getCount(){ return this.count; } // metodo de inicialização inicia o vetor da matriz de aprendizado Perceptron() { // Primeiro valor this.matrizAprendizado[0][0] = 0; // entrada 1 this.matrizAprendizado[0][1] = 0; // entrada 2 this.matrizAprendizado[0][2] = 0; // valor esperado // Segundo Valor this.matrizAprendizado[1][0] = 0; // entrada 1 this.matrizAprendizado[1][1] = 1; // entrada 2 this.matrizAprendizado[1][2] = 0; // valor esperado // terceiro valor this.matrizAprendizado[2][0] = 1; // entrada 1 this.matrizAprendizado[2][1] = 0; // entrada 2 this.matrizAprendizado[2][2] = 0; // valor esperado // quarto valor this.matrizAprendizado[3][0] = 1; // entrada 1 this.matrizAprendizado[3][1] = 1; // entrada 2 this.matrizAprendizado[3][2] = 1; // valor esperado // inicialização dos pesos sinápticos // Peso sináptico para primeira entrada. w[0] = 0; // Peso sináptico para segunda entrada. w[1] = 0; // Peso sináptico para o BIAS w[2]= 0; } // Método responsávelpelo somatório e a função de ativação. int executar(int x1, int x2) { // Somatório (NET) NET = (x1 * w[0]) + (x2 * w[1]) + ((-1) * w[2]); // Função de Ativação if (NET >= 0) { return 1; } return 0; } // Método para treinamento da rede public void treinar() { // variavel utilizada responsável pelo controlede treinamento recebefalso boolean treinou= true; // varável responsável para receber o valor da saída (y) int saida; // laço usado para fazer todas as entradas for (int i = 0; i < matrizAprendizado.length; i++) { // A saída recebe o resultado da rede que no caso é 1 ou 0 saida = executar(matrizAprendizado[i][0], matrizAprendizado[i][1]); if (saida != matrizAprendizado[i][2]) { // Caso a saída seja diferente do valor esperado // os pesos sinápticos serão corrigidos corrigirPeso(i, saida); // a variavél responsável pelo controlede treinamento recebe falso treinou = false; } } // acrescenta uma época this.count++; // teste se houve algum erro duranteo treinamento e o número de epocas //é menor qe o definido if((treinou == false) && (this.count < this.epocasMax)) { // chamada recursiva do método treinar(); } } // fim do método para treinamento // Método para a correção de pesos void corrigirPeso(int i, int saida) { w[0] = w[0] + (1 * (matrizAprendizado[i][2] - saida) * matrizAprendizado[i][0]); w[1] = w[1] + (1 * (matrizAprendizado[i][2] - saida) * matrizAprendizado[i][1]); w[2] = w[2] + (1 * (matrizAprendizado[i][2] - saida) * (-1)); }}
Referências
- ↑ a b Freund, Yoav; Schapire, Robert E. (1999). «Large Margin Classification: Using the Perceptron Algorithm» (PDF). UC San Diego. 37 (3): 2. Consultado em 23 de junho de 2020
- ↑ a b Lefkowitz, Melanie (25 de setembro de 2019). «Professor's perceptron paved the way for AI – 60 years too soon». Cornell Chronicle (em inglês). Consultado em 23 de junho de 2020