Está en la página 1de 11

Cmo implementar el algoritmo del Perceptron desde cero en Python

El algoritmo Perceptron es el tipo ms simple de red neuronal artificial.

Es un modelo de una sola neurona que puede utilizarse para problemas de


clasificacin de dos clases y proporciona la base para desarrollar redes mucho
ms grandes.

Luego de la implementacin del algoritmo de Perceptron desde cero con


Python, le permitir conocer:

Cmo entrenar los pesos de la red para el Perceptron.


Cmo hacer predicciones con el Perceptron.
Cmo implementar el algoritmo Perceptron para un problema de
clasificacin real.

Empecemos:
Descripcin: En esta seccin se ofrece una breve introduccin al algoritmo
Perceptron y al conjunto de datos Sonar al que posteriormente lo aplicaremos.

Algoritmo Perceptron: El Perceptron se inspira en el procesamiento de la


informacin de una sola clula neural llamada neurona.

Una neurona acepta seales de entrada a travs de sus dendritas, que pasan la
seal elctrica hasta el cuerpo celular.

De manera similar, el Perceptron recibe seales de entrada a partir de


ejemplos de datos de entrenamiento que ponderamos y combinamos en una
ecuacin lineal llamada activacin.

activation = sum(weight_i * x_i) + bias

La activacin se transforma entonces en un valor de salida o prediccin


utilizando una funcin de transferencia, tal como la funcin de transferencia
escalonada.

prediction = 1.0 if activation >= 0.0 else 0.0

De esta manera, el Perceptron es un algoritmo de clasificacin para problemas


con dos clases (0 y 1) donde se puede usar una ecuacin lineal (hiperplano)
para separar las dos clases.
Est estrechamente relacionado con la regresin lineal y la regresin logstica
que hacen predicciones de manera similar (por ejemplo, una suma ponderada
de insumos).

Los pesos del algoritmo de Perceptron se deben estimar a partir de los datos de
entrenamiento usando un descenso de gradiente estocstico.

Pendiente del gradiente estocstico

Gradient Descent es el proceso de minimizar una funcin siguiendo los


gradientes de la funcin de coste.

Esto implica conocer la forma del coste, as como la derivada, de modo que
desde un punto dado conozca el gradiente y pueda moverse en esa direccin,
p. Cuesta abajo hacia el valor mnimo.

En el aprendizaje de mquina, podemos utilizar una tcnica que evala y


actualiza las ponderaciones de cada iteracin llamada descenso de gradiente
estocstico para minimizar el error de un modelo en nuestros datos de
entrenamiento.

La forma en que funciona este algoritmo de optimizacin es que cada instancia


de entrenamiento se muestra al modelo uno a la vez. El modelo hace una
prediccin para una instancia de entrenamiento, se calcula el error y se
actualiza el modelo para reducir el error para la siguiente prediccin.

Este procedimiento se puede usar para encontrar el conjunto de pesos en un


modelo que resulte con el menor error para el modelo con los datos de
entrenamiento.

Para el algoritmo de Perceptron, cada iteracin los pesos (w) se actualizan


usando la ecuacin:

w = w + learning_rate * (expected - predicted) * x

Donde: w es el peso optimizado, learning_rate es una tasa de


aprendizaje que debe configurar (por ejemplo, 0,01), (esperado - previsto)
es el error de prediccin para el modelo en los datos de entrenamiento
atribuido al peso y x es el valor de entrada.

Juego de datos Sonar

El conjunto de datos que usaremos para las respectivas pruebas es el conjunto


de datos Sonar.
Este es un conjunto de datos que describe sonar chirp, el cual se devuelve en
diferentes servicios. Las 60 variables de entrada representan la fuerza de los
retornos en ngulos diferentes. Es un problema de clasificacin binaria que
requiere un modelo para diferenciar las rocas de los cilindros metlicos.

Es un conjunto de datos bien comprendido. Todas las variables son continuas y


generalmente estn en el rango de 0 a 1. Como tal no tendremos que
normalizar los datos de entrada, que a menudo es una buena prctica con el
algoritmo del Perceptron. La variable de salida es una cadena "M" para la mina
y "R" para la roca, que tendr que convertirse en enteros 1 y 0.

Al predecir la clase con la mayor cantidad de observaciones en el conjunto de


datos (M o minas), el Algoritmo de Reglas Cero puede alcanzar una precisin
del 53%.

Puede obtener ms informacin sobre este conjunto de datos en el repositorio


UCI de Aprendizaje de Mquinas. Puede descargar el dataset de forma gratuita
y colocarlo en su directorio de trabajo con el nombre de archivo sonar.all-
data.csv.

La presente actividad experimental se divide en tres partes:

Creacin de las predicciones.


Estimacin de los Pesos de la red de entrenamiento.
Modelado del conjunto de datos Sonar.

Estos pasos le darn la base para implementar y aplicar el algoritmo


Perceptron a su propia clasificacin de problemas de modelado predictivo.

1. Creacin de las predicciones

El primer paso es desarrollar una funcin que pueda hacer predicciones.

Esto ser necesario tanto en la evaluacin de los valores de los pesos


seleccionados en el descenso del gradiente estocstico, y despus de que
finaliza el modelo y si deseamos empezar a crear otras predicciones sobre los
datos de la prueba o sobre los nuevos datos.

A continuacin se muestra una funcin denominada predict () que predice un


valor de salida para una fila dado un conjunto de pesos.

El primer peso es siempre el bias (umbral), ya que es independiente y no es


responsable de un valor de entrada especfico.
# Make a prediction with weights
def predict(row, weights):
activation = weights[0]
for i in range(len(row)-1):
activation += weights[i + 1] * row[i]
return 1.0 if activation >= 0.0 else 0.0

Podemos crear un pequeo conjunto de datos para probar su funcin de


prediccin.

X1 X2 Y
2.7810836 2.550537003 0
1.465489372 2.362125076 0
3.396561688 4.400293529 0
1.38807019 1.850220317 0
3.06407232 3.005305973 0
7.627531214 2.759262235 1
5.332441248 2.088626775 1
6.922596716 1.77106367 1
8.675418651 -0.242068655 1
7.673756466 3.508563011 1

Tambin podemos usar pesos previamente preparados para hacer predicciones


para este conjunto de datos.

Poniendo todo esto juntos podemos probar nuestra funcin de prediccin () a


continuacin.
# Make a prediction with weights
def predict(row, weights):
activation = weights[0]
for i in range(len(row)-1):
activation += weights[i + 1] * row[i]
return 1.0 if activation >= 0.0 else 0.0

# test predictions
dataset = [[2.7810836,2.550537003,0],
[1.465489372,2.362125076,0],
[3.396561688,4.400293529,0],
[1.38807019,1.850220317,0],
[3.06407232,3.005305973,0],
[7.627531214,2.759262235,1],
[5.332441248,2.088626775,1],
[6.922596716,1.77106367,1],
[8.675418651,-0.242068655,1],
[7.673756466,3.508563011,1]]
weights = [-0.1, 0.20653640140000007, -0.23418117710000003]
for row in dataset:
prediction = predict(row, weights)
print("Expected=%d, Predicted=%d" % (row[-1], prediction))

Hay dos valores de entrada (X1 y X2) y tres valores de peso (polarizacin(bias),
w1 y w2). La ecuacin de activacin que hemos modelado para este problema
es:

activation = (w1 * X1) + (w2 * X2) + bias


O, con los valores de peso especficos que elegimos a mano como:

activation = (0.206 * X1) + (-0.234 * X2) + -0.1

Ejecutando esta funcin obtendremos predicciones que coincidan con los


valores esperados de salida (Y).

Expected=0, Predicted=0
Expected=0, Predicted=0
Expected=0, Predicted=0
Expected=0, Predicted=0
Expected=0, Predicted=0
Expected=1, Predicted=1
Expected=1, Predicted=1
Expected=1, Predicted=1
Expected=1, Predicted=1
Expected=1, Predicted=1

Ahora estamos listos para implementar un descenso de gradiente estocstico


para optimizar sus valores de peso.

2. Estimacin de los Pesos de la red de entrenamiento

Podemos estimar los valores de peso para nuestros datos de entrenamiento


usando un descenso de gradiente estocstico.

El descenso del gradiente estocstico requiere dos parmetros:

Tasa de Aprendizaje: Se utiliza para limitar la cantidad de cada peso que se


corrige cada vez que se actualiza.
Epochs: El nmero de veces que se ejecuta a travs de los datos de
entrenamiento mientras se actualiza el peso.

Estos, junto con los datos de entrenamiento sern los argumentos a la funcin.

Hay 3 bucles que necesitamos realizar en la funcin:

Bucle en cada poca.


Bucle sobre cada fila en los datos de entrenamiento para una poca.
Bucle sobre cada peso y actualizarlo para una fila en una poca.

Es importante, actualizar cada peso para cada fila en los datos de


entrenamiento, cada poca.

Los pesos se actualizan en base al error del modelo realizado. El error se


calcula como la diferencia entre el valor de salida esperado y la prediccin
hecha con los pesos seleccionados.
Hay un peso para cada atributo de entrada, y stos se actualizan de manera
coherente, por ejemplo:

w(t+1)= w(t) + learning_rate * (expected(t) - predicted(t)) * x(t)

El umbral (bias) se actualiza de manera similar, excepto que no tiene una


entrada, ya que no est asociado con un valor de entrada especfico:

bias(t+1) = bias(t) + learning_rate * (expected(t) - predicted(t))

Ahora podemos juntar todo esto. A continuacin se muestra una funcin


denominada train_weights () que calcula los valores de ponderacin para un
conjunto de datos de entrenamiento usando un descenso de gradiente
estocstico.

# Estimate Perceptron weights using stochastic gradient descent


def train_weights(train, l_rate, n_epoch):
weights = [0.0 for i in range(len(train[0]))]
for epoch in range(n_epoch):
sum_error = 0.0
for row in train:
prediction = predict(row, weights)
error = row[-1] - prediction
sum_error += error**2
weights[0] = weights[0] + l_rate * error
for i in range(len(row)-1):
weights[i + 1] = weights[i + 1] + l_rate * error * row[i]
print('>epoch=%d, lrate=%.3f, error=%.3f' % (epoch, l_rate, sum_error))
return weights

Se puede ver que tambin hacemos un seguimiento de la suma del error


cuadrado (un valor positivo) cada poca para que podamos imprimir un
mensaje positivo para cada bucle externo.

Podemos probar esta funcin con el mismo conjunto de datos artificial desde
arriba.

# Make a prediction with weights


def predict(row, weights):
activation = weights[0]
for i in range(len(row)-1):
activation += weights[i + 1] * row[i]
return 1.0 if activation >= 0.0 else 0.0

# Estimate Perceptron weights using stochastic gradient descent


def train_weights(train, l_rate, n_epoch):
weights = [0.0 for i in range(len(train[0]))]
for epoch in range(n_epoch):
sum_error = 0.0
for row in train:
prediction = predict(row, weights)
error = row[-1] - prediction
sum_error += error**2
weights[0] = weights[0] + l_rate * error
for i in range(len(row)-1):
weights[i + 1] = weights[i + 1] + l_rate * error * row[i]
print( ' >epoch=%d, lrate=%.3f, error=%.3f ' % (epoch, l_rate, sum_error))
return weights

# Calculate weights
dataset = [[2.7810836,2.550537003,0],
[1.465489372,2.362125076,0],
[3.396561688,4.400293529,0],
[1.38807019,1.850220317,0],
[3.06407232,3.005305973,0],
[7.627531214,2.759262235,1],
[5.332441248,2.088626775,1],
[6.922596716,1.77106367,1],
[8.675418651,-0.242068655,1],
[7.673756466,3.508563011,1]]
l_rate = 0.1
n_epoch = 5
weights = train_weights(dataset, l_rate, n_epoch)
print(weights)

Utilizamos una tasa de aprendizaje de 0.1 y entrenamos el modelo para slo 5


pocas, o 5 exposiciones de los pesos a todo el conjunto de datos de
formacin.

Al Ejecutar el ejemplo se imprime un mensaje cada poca con el error de


cuadrado de suma para esa poca y el conjunto final de pesos.

>epoch=0, lrate=0.100, error=2.000


>epoch=1, lrate=0.100, error=1.000
>epoch=2, lrate=0.100, error=0.000
>epoch=3, lrate=0.100, error=0.000
>epoch=4, lrate=0.100, error=0.000
[-0.1, 0.20653640140000007, -0.23418117710000003]

Usted puede ver cmo el problema es aprendido muy rpidamente por


el algoritmo.

Ahora, apliquemos este algoritmo en un conjunto de datos real.

3. Modelado del conjunto de datos Sonar

En esta seccin, vamos a entrenar un modelo de Perceptron usando el


descenso de gradiente estocstico en el conjunto de datos Sonar.

El ejemplo supone que una copia CSV del conjunto de datos est en el
directorio de trabajo actual con el nombre de archivo sonar.all-data.csv.

Se carga primero el conjunto de datos, los valores de cadena se convierten a


numricos y la columna de salida se convierte de cadenas a valores enteros de
0 a 1. Esto se logra con las funciones de ayuda load_csv (), str_column_to_float
() y str_column_to_int () para cargar y preparar el conjunto de datos.

Usaremos la validacin cruzada k-fold para estimar el rendimiento del modelo


aprendido en datos no vistos. Esto significa que vamos a construir y evaluar k
modelos y estimar el rendimiento como el error medio del modelo. La precisin
de la clasificacin se utilizar para evaluar cada modelo. Estos
comportamientos se proporcionan en las funciones auxiliares
cross_validation_split (), accuracy_metric () y evaluate_algorithm ().

Utilizaremos las funciones predict () y train_weights () creadas anteriormente


para entrenar el modelo y una nueva funcin perceptron () para unirlas.

A continuacin se muestra el ejemplo completo.


# Perceptron Algorithm on the Sonar Dataset
from random import seed
from random import randrange
from csv import reader

# Load a CSV file


def load_csv(filename):
dataset = list()
with open(filename, 'r') as file:
csv_reader = reader(file)
for row in csv_reader:
if not row:
continue
dataset.append(row)
return dataset

# Convert string column to float


def str_column_to_float(dataset, column):
for row in dataset:
row[column] = float(row[column].strip())

# Convert string column to integer


def str_column_to_int(dataset, column):
class_values = [row[column] for row in dataset]
unique = set(class_values)
lookup = dict()
for i, value in enumerate(unique):
lookup[value] = i
for row in dataset:
row[column] = lookup[row[column]]
return lookup

# Split a dataset into k folds


def cross_validation_split(dataset, n_folds):
dataset_split = list()
dataset_copy = list(dataset)
fold_size = len(dataset) / n_folds
for i in range(n_folds):
fold = list()
while len(fold) < fold_size:
index = randrange(len(dataset_copy))
fold.append(dataset_copy.pop(index))
dataset_split.append(fold)
return dataset_split

# Calculate accuracy percentage


def accuracy_metric(actual, predicted):
correct = 0
for i in range(len(actual)):
if actual[i] == predicted[i]:
correct += 1
return correct / float(len(actual)) * 100.0

# Evaluate an algorithm using a cross validation split


def evaluate_algorithm(dataset, algorithm, n_folds, *args):
folds = cross_validation_split(dataset, n_folds)
scores = list()
for fold in folds:
train_set = list(folds)
train_set.remove(fold)
train_set = sum(train_set, [])
test_set = list()
for row in fold:
row_copy = list(row)
test_set.append(row_copy)
row_copy[-1] = None
predicted = algorithm(train_set, test_set, *args)
actual = [row[-1] for row in fold]
accuracy = accuracy_metric(actual, predicted)
scores.append(accuracy)
return scores

# Make a prediction with weights


def predict(row, weights):
activation = weights[0]
for i in range(len(row)-1):
activation += weights[i + 1] * row[i]
return 1.0 if activation >= 0.0 else 0.0

# Estimate Perceptron weights using stochastic gradient descent


def train_weights(train, l_rate, n_epoch):
weights = [0.0 for i in range(len(train[0]))]
for epoch in range(n_epoch):
for row in train:
prediction = predict(row, weights)
error = row[-1] - prediction
weights[0] = weights[0] + l_rate * error
for i in range(len(row)-1):
weights[i + 1] = weights[i + 1] + l_rate * error * row[i]
return weights

# Perceptron Algorithm With Stochastic Gradient Descent


def perceptron(train, test, l_rate, n_epoch):
predictions = list()
weights = train_weights(train, l_rate, n_epoch)
for row in test:
prediction = predict(row, weights)
predictions.append(prediction)
return(predictions)

# Test the Perceptron algorithm on the sonar dataset


seed(1)
# load and prepare data
filename = 'sonar.all-data.csv'
dataset = load_csv(filename)
for i in range(len(dataset[0])-1):
str_column_to_float(dataset, i)
# convert string class to integers
str_column_to_int(dataset, len(dataset[0])-1)
# evaluate algorithm
n_folds = 3
l_rate = 0.01
n_epoch = 500
scores = evaluate_algorithm(dataset, perceptron, n_folds, l_rate, n_epoch)
print('Scores: %s' % scores)
print('Mean Accuracy: %.3f%%' % (sum(scores)/float(len(scores))))

Se utiliz un valor de k de 3 para la validacin cruzada, con lo que cada


plegado 208/3 = 69,3 o un poco menos de 70 registros para ser evaluados en
cada iteracin. Se seleccion una tasa de aprendizaje de 0,1 y 500 pocas de
entrenamiento con un poco de experimentacin.

Es importante probar nuestras propias configuraciones y ver si se puede vencer


la puntuacin alcanzada en la experimentacin.

Al ejecutar este ejemplo se imprime las puntuaciones para cada uno de los 3
pliegues de validacin cruzada y luego imprime la precisin de la clasificacin
media.

Podemos ver que la precisin es de aproximadamente el 73%, ms alta que el


valor de la lnea base de poco ms del 50% si slo predijimos la clase
mayoritaria usando el Algoritmo de Reglas Cero.

Scores (Puntuaciones): [73.91304347826086, 78.26086956521739, 68.11594202898551]


Mean Accuracy (Precisin Media): 73.430%

Extensiones

En esta seccin se enumeran las extensiones de la presente experimentacin


que quizs desee explorar.

Sintonice el ejemplo. Sintonice la tasa de aprendizaje, el nmero de


pocas e incluso el mtodo de preparacin de datos para obtener una
puntuacin mejorada en el conjunto de datos.
Batch Stochastic Gradient Descent. Cambiar el algoritmo de descenso
de gradiente estocstico para acumular actualizaciones a travs de cada
poca y slo actualizar los pesos en un lote al final de la poca.
Problemas de regresin adicionales. Aplicar la tcnica a otros
problemas de clasificacin en el repositorio de aprendizaje de mquina UCI.

Es importante explorar alguna de estas extensiones?, y comentando las


mismas en base a los siguiente:
Revisin: En esta experimentacin, descubri cmo implementar el algoritmo
de Perceptron usando un descenso de gradiente estocstico desde cero con
Python.

Aprendi:
Cmo hacer predicciones para un problema de clasificacin binaria.
Cmo optimizar un conjunto de pesos usando un descenso de gradiente
estocstico.
Cmo aplicar la tcnica a un problema de modelado predictivo de
clasificacin real.

También podría gustarte