Perceptrons

Ricardo Araujo
9 min readNov 12, 2020

--

O perceptron é um modelo classificador binário, proposto por Frank Rosenblatt no final da década de 1950 como um modelo matemático (simplificado, como todo modelo) de um neurônio. É a unidade básica de toda uma área denominada de abordagem conexionista para a Inteligência Artificial, em oposição a abordagem simbólica, baseadada em manipulação de símbolos por uma lógica, e atualmente melhor representada pelas redes neurais. Ainda que redes neurais modernas possuam partes que vão além do perceptron este ainda é, em diferentes formas, a unidade básica de representação destas redes.

No modelo de neurônio capturado pelo perceptron, sinais externos são capturados pelo neurônio por meio de dendritos e modulados pela sinapse. O neurônio “dispara”, isto é, emite sinal por meio do axônio, em função das suas entradas e dos pesos sinápticos. Estes últimos podem ser excitatórios, quando a presença de um sinal aumenta a probabilidade do neurônio disparar, ou inibitórios, quando a presença do sinal reduz a probabilidade de disparo. Este modelo possui apenas duas saídas possíveis, ativado ou não, e a saída é definida exclusivamente pela combinação de sinais na entrada e pesos sinápticos. Um diagrama clássico de um perceptron é como o abaixo.

Exemplo de perceptron com três entradas (x1, x2 e x3).

No diagrama acima, temos três entradas (x1, x2 e x3) que alimentam um somador. Este somador pondera as entradas por meio de pesos (w1, w2 e w3) e aceita uma entrada adicional constante, chamada bias, ponderada por um peso wb, cuja função ficará clara adiante. O resultado desta soma ponderada, s, alimenta uma função de ativação que mapeia s para o resultado final y. No perceptron clássico, a função de ativação é uma função degrau: s ≥ 0 “ativa” o neurônio, enquanto s < 0 o mantém desativado.

Os parâmetros do perceptron são seus pesos, que representam as sinapses em um neurônio. Ao alterarmos estes pesos, alteramos a função representada pelo perceptron — isto é, que padrões nas entradas são mapeados para ativações ou não do perceptron.

Como exemplo, podemos representar a função lógica AND usando um perceptron com duas entradas e bias. Assumimos que a função de ativação pode ter como saída os valores -1 (inativo) ou 1(ativo). Da mesma forma, as entradas podem apenas assumir estes mesmos valores. Isto é, queremos representar a tabela abaixo por meio de um perceptron:

A função AND e a incapacidade do Medium de lidar com tabelas.

Esta tabela é reproduzida por um perceptron se fizermos, por exemplo, w1 = 0,5; w2 = 0,5 e wb = -0,5.

Saídas de um perceptron com w1=w2=0,5 e wb=-0,5

Alterando os pesos, podemos representar diferentes funções. Logo, podemos treinar o modelo a partir de dados, ajustando os pesos para se ajustarem aos exemplos de treinamento. Observe no entanto que sem wb, não conseguimos aprender esta função (tente). O bias pode ser compreendido como alterando a função de ativação, deslocando o ponto onde esta ativa o perceptron de zero para outro valor, algo essencial para aprender esta função.

O bias tem o efeito equivalente a deslocar o valor para o qual o perceptron se ativa

A função do bias é ainda mais clara se compreendermos o que um perceptron representa. Em notação matemática, temos que:

s = w1*x1 + w2*x2 + … +wi*xi + wb

Ou, em notação vetorial:

s = w·x + wb

Onde w·x representa o produto escalar dos vetores w e x. E:

y = {1 se s≥0, 0 caso contrário}

Deve ficar claro que o perceptron nada mais é que o classificador linear visto anteriormente e, portanto, apenas é capaz de aprender problemas linearmente separáveis. Interessantemente, este fato apenas foi observado em 1969, no famoso livro Perceptrons por Minsky e Papert, reduzindo consideravelmente o entusiasmo existente neste modelo na época. O papel do bias deve também estar mais claro: ele possibilita que o hiperplano não passe pela origem.

A função AND e a reta separadora representada pelo perceptron

Assim, podemos utilizar quaisquer estratégias adotadas para o classificador linear para treinar um perceptron, já que eles são o mesmo modelo. Vamos ver duas destas estratégias.

Regra de Treinamento do Perceptron

A Regra de Treinamento do Perceptron é um algoritmo de treinamento iterativo, que considera um único exemplo em cada iteração. Suponha que desejamos aprender os padrões representados na tabela abaixo (e não nos importamos com a saída para outras entradas):

Agora usaremos 0 e 1 como saídas para o perceptron. t representa a saída desejada.
Representação gráfica da tabela acima

Suponha ainda, por simplicidade, que não temos bias no perceptron. Começamos inicializando os pesos com valores aleatórios (tipicamente pequenos, entre -1 e 1, mas isso não é uma exigência). Façamos w1=1,0 e w2=-0,8. Então, mostramos um exemplo para o perceptron e obtemos o resultado (dizemos que “propagamos” o exemplo). Vamos propagar o primeiro exemplo na tabela. Assuma que f é a função degrau.

y = f(1,0*1 + (-0,8)*2) = f(-0,6) = 0

Este não é o resultado desejado de acordo com a tabela. O diagrama abaixo mostra a reta definida por estes pesos. Claramente este não é um bom separador.

Separador resultante da inicialização aleatória dos pesos

Gostaríamos de alterar os pesos de forma que este exemplo seja corretamente classificado. Uma maneira de imediatamente fazer isso é tornar w = x. No entanto, se fizermos isso para cada exemplo, cada um “puxará” o separador para si, fazendo com o que o algoritmo oscile os pesos eternamente. Para evitar isso, a estratégia é fazer com que cada exemplo mova o separador em sua direção, mas não muito. Em adição, apenas queremos mover o separador quando este classifica incorretamente um exemplo. Unindo estas ideias, podemos atualizar cada peso wj ligado a entrada xj na iteração k com:

Na equação acima, wj(k-1) indica o peso anterior a atualização, η é uma constante chamada taxa de aprendizado, e η<1, (t-y) é o erro do modelo para o exemplo apresentado. A taxa de aprendizado e o erro são responsáveis por modular o quanto o peso se altera a cada iteração em direção a entrada. O erro aqui apenas pode ser -1, 0 ou +1, indicando se o peso deve ser alterado e a direção da alteração.

No caso acima, o primeiro exemplo propagado levou a uma saída incorreta. Vamos assumir η=0,05 e atualizar os pesos:

w1 = 1,0 + 0,05*(1–0)*1 = 1,05
w2 = 0,8 + 0,05*(1–0)*2 = 0,9

Agora procedemos mostrando outro exemplo e repetimos o processo. Cada passagem por todos exemplos é chamado de uma época. O algoritmo continua até que nenhum peso sofra alteração em toda uma época, quando dizemos que o modelo convergiu. A animação abaixo ilustra o processo, mostrando o separador definido pelos pesos (o vetor de pesos é ortogonal ao separador).

Regra de Treinamento do Perceptron operando como esperado

Para a Regra de Treinamento do Perceptron convergir, é necessário que η seja pequeno e que o problema seja linearmente separável. Enquanto podemos controlar o valor de η, não temos usualmente controle sobre a separabilidade do problema. Se o problema não for linearmente separável, os pesos nunca deixam de ser atualizados pois sempre há algum exemplo incorretamente classificado. A animação abaixo ilustra este processo.

Regra de Treinamento do Perceptron pode não convergir se o problema não é linearmente separável

Descida de Gradiente e Regra Delta

O segundo método de treinamento de perceptron utiliza descida de gradiente para permitir a convergência mesmo se o problema não for linearmente separável. Isto não significa, claro, que o separador resultante será capaz de separar os exemplos perfeitamente, mas que o algoritmo retornará um separador que procura minimizar o erro.

Para utilizar descida de gradiente, no lugar de tomarmos a saída y do perceptron, tomamos a saída s, a saída do somatório antes de passar pela função de ativação. Um perceptron sem função de ativação é comumente chamado de unidade linear ou Adaline (de Adaptive Linear). Definimos então o erro de um vetor de pesos como sendo o erro quadrático de cada exemplo no conjunto D de treinamento:

O erro é uma função dos pesos pois pesos diferentes levam a saídas diferentes e, portanto, erros diferentes. Ao contrário da Regra de Treinamento, o erro aqui é calculado sobre todos os exemplos de treinamento. A forma quadrática dá origem a uma parábola:

Exemplo de erro em função de um único peso

Observe como no gráfico acima há um mínimo bem definido. De fato, pela maneira com que definimos o erro e o uso de uma unidade linear, é garantido que há apenas um único mínimo global. Adicionalmente, observe também que o erro nunca chega em zero no exemplo acima. Isso sempre ocorrerá quando o problema não for linearmente separável.

Esta definição de erro permite agora a utilização de descida de gradiente para encontrar o mínimo da função. O procedimento inicia com pesos aleatórios e calculando o gradiente naquele ponto; atualiza-se os pesos segundo o gradiente e repete-se até que atinja-se o mínimo (ou um valor próximo o suficiente) ou um número máximo de iterações (épocas) seja atingido. A aplicação da descida de gradiente a um perceptron leva a uma forma fechada para a atualização de cada peso wj na época k, denominada Regra Delta:

A equação é muito semelhante a usada pela Regra de Treinamento. A diferença está no fato do erro ser calculado sobre todos os exemplos de treinamento e utilizar a saída linear. Novamente, η é a taxa de aprendizado e define a magnitude da atualização do peso. Este deve ser um valor baixo para garantir convergência, mas η muito baixo leva a uma convergência lenta. É comum adotar estratégias de escalonamento da taxa de aprendizado, iniciando com valores mais altos e reduzindo gradativamente. O gráfico abaixo ilustra a evolução do separador utilizando a Regra Delta.

A aplicação da Regra Delta garante a convergência mesmo quando o problema não é linearmente separável, para η baixo o suficiente.

Descida de Gradiente Estocástico (SGD)

Uma variante para a Regra Delta é atualizar os pesos utilizando apenas um subconjunto dos exemplos. Isso leva a uma descida de gradiente incremental, onde o gradiente é uma aproximação do gradiente “real” (que é calculado sobre todos os exemplos). A cada atualização, escolhe-se um conjunto (batch) diferente, podendo ser aleatoriamente, em sequência ou seguindo algum outro critério.

A grande vantagem de utilizar SGD é permitir o cálculo rápido do gradiente quando se tem muitos exemplos e não é possível armazenar todos em memória. Em um caso típico, com o uso de hardware especializado (como GPUs) para acelerar estes cálculos, não é usualmente possível colocar todos exemplos na memória especializada.

O uso de SGD pode tornar cada atualização de peso mais rápida, mas o custo é a necessidade de mais atualizações de pesos devido a convergência mais lenta do modelo. Porém, uma vantagem adicional é, devido ao ruído introduzido pela aproximação do gradiente, o SGD pode ser capaz de evitar mínimos locais quando a função de erro é complexa.

O uso de um sub-conjunto de exemplos para cálculo do gradiente é comumente chamado de aprendizado por mini-batch. O tamanho do mini-batch é um hiper-parâmetro adicional do treinamento do modelo, e é comum utilizar o maior mini-batch possível (i.e. que é possível carregar na memória).

No limite, pode-se utilizar um único exemplo por vez para atualizar os pesos. Isso leva a uma forma de atualização dos pesos ainda mais próxima da Regra de Treinamento, onde a única diferença é o uso da saída linear no lugar da saída da função de ativação:

SGD é a forma mais comum de descida de gradiente utilizada para treinamento de perceptrons e é também amplamente utilizada para treinar redes neurais.

--

--

Ricardo Araujo

Computer Science professor at UFPel. Machine Learning and Artificial Intelligence practitioner and researcher.