No notebook anterior, nós aprendemos intuitivamente como o perceptron aprende. De maneira geral, nós vamos atualizando os pesos e o bias sempre buscando diminuir uma função de custo. Nesse notebook, nós vamos ver como esse aprendizado realmente acontence, tanto na teoria quanto na prática. Também utilizaremos o Perceptron para resolver problemas de classificação e regressão.
Objetivos:
In [ ]:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from random import random
from sklearn.linear_model import LinearRegression
from sklearn.preprocessing import MinMaxScaler
from sklearn.datasets.samples_generator import make_blobs
%matplotlib inline
O tipo mais básico de Rede Neural Artificial é formada por apenas um neurônio, o Perceptron. Inicialmente, o Perceptron foi projetado para ser um classificador binário linear responsável por mapear uma ou mais entradas em uma saída desejada. Porém, também podemos utilizá-lo para resolver problemas de regressão linear. Ele foi projetado em 1957 por Frank Rosenblatt.
O perceptron é formado por:
Logo, o Perceptron é representado pela seguinte fórmula matemática:
$$\widehat{y}_i = f(\sum_i^D{x_iw_i} + b)$$Onde:
Observações importantes:
O Perceptron tem sua própria forma de aprendizado conforme definido no seu artigo original. Na verdade, a fórmula para atualização dos pesos e bias é bem simples:
$$w_i = w_i + \lambda(y_i - \widehat{y}_i)x_i$$
$$b_i = b_i + \lambda(y_i - \widehat{y}_i)$$
Onde $\lambda$ é a taxa de aprendizagem (learning rate).
Repare que $y_i - \widehat{y}_i$ significa calcular a diferença entre o valor esperado ($y_i$) e o valor predito ($\widehat{y}_i$). Supondo que estamos fazendo classificação binária de uma amostra $(x_i, y_i)$. Nesse caso, teremos duas possibilidades:
Repare, como dito lá em cima, que a atualização dos pesos e bias é feito a cada amostra, e não somente após ver todas as amostras do banco.
In [ ]:
x = np.array([[0, 0], [0, 1], [1, 0], [1, 1]])
#y = np.array([0, 1, 1, 1]) # porta OR
y = np.array([0, 0, 0, 1]).T # porta AND
print(x.shape, y.shape)
In [ ]:
In [ ]:
In [ ]:
x, y = make_blobs(n_samples=100, n_features=2, centers=2, random_state=1234)
print(x.shape, y.shape)
plt.scatter(x[:,0], x[:,1], c=y.ravel(), cmap='bwr')
In [ ]:
def plot_linear_classifier(x, y, w, b):
x1_min, x1_max = x[:,0].min(), x[:,0].max()
x2_min, x2_max = x[:,1].min(), x[:,1].max()
x1, x2 = np.meshgrid(np.linspace(x1_min-1, x1_max+1,100), np.linspace(x2_min-1, x2_max+1, 100))
x_mesh = np.array([x1.ravel(), x2.ravel()]).T
plt.scatter(x[:,0], x[:,1], c=y.ravel(), cmap='bwr')
y_mesh = np.dot(x_mesh, np.array(w).reshape(1, -1).T) + b
y_mesh = np.where(y_mesh <= 0, 0, 1)
plt.contourf(x1, x2, y_mesh.reshape(x1.shape), cmap='bwr', alpha=0.5)
plt.xlim(x1_min-1, x1_max+1)
plt.ylim(x2_min-1, x2_max+1)
In [ ]:
In [ ]:
Para transformar o Perceptron em um regressor linear, só o que temos de fazer é remover a função de ativação step, transformando-a em uma função de ativação linear.
Apesar dessa modificação, a fórmula de atualização dos pesos não sofre nenhuma alteração.
Vamos, então, implementar nosso perceptron para classificação em Python, Numpy, Keras e TensorFlow:
In [ ]:
df = pd.read_csv('data/medidas.csv')
print(df.shape)
df.head(10)
In [ ]:
x = df.Altura.values
y = df.Peso.values
plt.figure()
plt.scatter(x, y)
plt.xlabel('Altura')
plt.ylabel('Peso')
In [ ]:
print(x.shape, y.shape)
In [ ]:
x = x.reshape(-1, 1)
print(x.shape, y.shape)
Exercício: tentar estimar as learning_rates de w e b. Elas são diferentes por que nossos dados não estão na mesma escala!
In [ ]:
D = x.shape[1]
w = [2*random() - 1 for i in range(D)]
b = 2*random() - 1
for step in range(10001):
cost = 0
for x_n, y_n in zip(x, y):
# qual linha devemos remover para transformar o Perceptron num regressor?
y_pred = sum([x_i*w_i for x_i, w_i in zip(x_n, w)]) + b
y_pred = 1 if y_pred > 0 else 0
error = y_n - y_pred
w = [w_i + 1.0*error*x_i for x_i, w_i in zip(x_n, w)]
b = b + 1.0*error
cost += error**2
if step%1000 == 0:
print('step {0}: {1}'.format(step, cost))
print('w: ', w)
print('b: ', b)
In [ ]:
D = x.shape[1]
w = 2*np.random.random(size=D)-1
b = 2*np.random.random()-1
for step in range(10001):
cost = 0
for x_n, y_n in zip(x, y):
# qual linha devemos remover para transformar o Perceptron num regressor?
y_pred = np.dot(x_n, w) + b
y_pred = np.where(y_pred > 0, 1, 0)
error = y_n - y_pred
w = w + 1.0*np.dot(error, x_n)
b = b + 1.0*error
cost += error**2
if step%1000 == 0:
print('step {0}: {1}'.format(step, cost))
print('w: ', w)
print('b: ', b)
In [ ]:
minmax = MinMaxScaler(feature_range=(-1,1))
x = minmax.fit_transform(x.astype(np.float64))
print(x.min(), x.max())
In [ ]:
reg = LinearRegression()
reg.fit(x,y)
print('w: ', reg.coef_)
print('b: ', reg.intercept_)
In [ ]:
D = x.shape[1]
w = 2*np.random.random(size=D)-1
b = 2*np.random.random()-1
learning_rate = 1.0 # <- tente estimar a learning_rate
for step in range(1001):
cost = 0
for x_n, y_n in zip(x, y):
y_pred = np.dot(x_n, w) + b
error = y_n - y_pred
w = w + learning_rate*np.dot(error, x_n)
b = b + learning_rate*error
cost += error**2
if step%100 == 0:
print('step {0}: {1}'.format(step, cost))
print('w: ', w)
print('b: ', b)
In [ ]:
df = pd.read_csv('data/notas.csv')
print(df.shape)
df.head(10)
In [ ]:
plt.figure(figsize=(20, 4))
plt.subplot(1, 3, 1)
plt.scatter(df.prova1.values, df.final.values)
plt.xlabel('Prova 1')
plt.ylabel('Final')
plt.subplot(1, 3, 2)
plt.scatter(df.prova2.values, df.final.values)
plt.xlabel('Prova 2')
plt.ylabel('Final')
plt.subplot(1, 3, 3)
plt.scatter(df.prova3.values, df.final.values)
plt.xlabel('Prova 3')
plt.ylabel('Final')
In [ ]:
x = df[['prova1', 'prova2', 'prova3']].values
y = df['final'].values
print(x.shape, y.shape)
In [ ]:
minmax = MinMaxScaler(feature_range=(-1,1))
x = minmax.fit_transform(x.astype(np.float64))
In [ ]:
reg = LinearRegression()
reg.fit(x, y)
print('w: ', reg.coef_)
print('b: ', reg.intercept_)
In [ ]:
D = x.shape[1]
w = [2*random() - 1 for i in range(D)]
b = 2*random() - 1
learning_rate = 1.0 # <- tente estimar a learning_rate
for step in range(1): # <- tente estimar o número de passos
cost = 0
for x_n, y_n in zip(x, y):
y_pred = sum([x_i*w_i for x_i, w_i in zip(x_n, w)]) + b
error = y_n - y_pred
w = [w_i + learning_rate*error*x_i for x_i, w_i in zip(x_n, w)]
b = b + learning_rate*error
cost += error**2
if step%200 == 0:
print('step {0}: {1}'.format(step, cost))
print('w: ', w)
print('b: ', b)
In [ ]:
D = x.shape[1]
w = 2*np.random.random(size=D)-1
b = 2*np.random.random()-1
learning_rate = 1.0 # <- tente estimar a learning_rate
for step in range(1): # <- tente estimar o número de passos
cost = 0
for x_n, y_n in zip(x, y):
y_pred = np.dot(x_n, w) + b
error = y_n - y_pred
w = w + learning_rate*np.dot(error, x_n)
b = b + learning_rate*error
cost += error**2
if step%200 == 0:
print('step {0}: {1}'.format(step, cost))
print('w: ', w)
print('b: ', b)