L'algoritmo Perceptron è il tipo più semplice di rete neurale artificiale.
Se non conosci la storia del Perceptron, Clicca qui.
È un modello di un singolo neurone che può essere utilizzato per problemi di classificazione a due classi e fornisce le basi per lo sviluppo successivo di reti molto più grandi.
In questo tutorial scoprirai come implementare l'algoritmo Perceptron da zero con Python.
Dopo aver completato questo tutorial, saprai:
Come addestrare i pesi di rete per il Perceptron.
Come fare previsioni con il Perceptron.
Come implementare l'algoritmo Perceptron per un problema di classificazione del mondo reale.
Adesso vediamo come implementare l'algoritmo di Perceptron da zero in Python.
Indice:
Descrizione
Questa sezione fornisce una breve introduzione all'algoritmo di Perceptron e al dataset del Sonar a cui lo applicheremo in seguito.
Algoritmo di Perceptron
Il Perceptron si ispira all'elaborazione delle informazioni di una singola cellula neurale chiamata neurone.
Un neurone accetta segnali in ingresso tramite i suoi dendriti, che trasmettono il segnale elettrico al corpo cellulare.
In modo simile, il Perceptron riceve segnali di input da esempi di dati di allenamento che pesiamo e combinati in un'equazione lineare chiamata attivazione.
activation = sum(weight_i * x_i) + bias
L'attivazione viene quindi trasformata in un valore di output o previsione utilizzando una funzione di trasferimento, come la funzione di trasferimento a gradini.
prediction = 1.0 if activation >= 0.0 else 0.0
In questo modo, il Perceptron è un algoritmo di classificazione per problemi con due classi (0 e 1) in cui è possibile utilizzare un'equazione lineare (simile o iperpiano) per separare le due classi.
È strettamente correlato alla regressione lineare e logistica che fanno previsioni in modo simile (ad esempio una somma ponderata di input).
I pesi dell'algoritmo Perceptron devono essere stimati dai dati di allenamento utilizzando la discesa del gradiente stocastico.
Discesa stocastica del gradiente
Gradient Descent è il processo di minimizzazione di una funzione seguendo i gradienti della funzione di costo.
Ciò implica conoscere la forma del costo oltre che la derivata in modo che da un dato punto si conosca la pendenza e ci si possa muovere in quella direzione, ad esempio in discesa verso il valore minimo.
Nell'apprendimento automatico, possiamo utilizzare una tecnica che valuta e aggiorna i pesi ogni iterazione chiamata discesa del gradiente stocastico per ridurre al minimo l'errore di un modello sui nostri dati di addestramento.
Il modo in cui funziona questo algoritmo di ottimizzazione è che ogni istanza di addestramento viene mostrata al modello una alla volta. Il modello effettua una previsione per un'istanza di addestramento, l'errore viene calcolato e il modello viene aggiornato per ridurre l'errore per la previsione successiva.
Questa procedura può essere utilizzata per trovare l'insieme di pesi in un modello che risulta nell'errore più piccolo per il modello sui dati di addestramento.
Per l'algoritmo di Perceptron, ad ogni iterazione i pesi ( w ) vengono aggiornati utilizzando l'equazione:
w = w + learning_rate * (expected - predicted) * x
Dove w è il peso in fase di ottimizzazione, learning_rate è un tasso di apprendimento che è necessario configurare (ad esempio 0,01), (previsto - previsto) è l'errore di previsione per il modello sui dati di addestramento attribuito al peso e x è il valore di input.
Set di dati del sonar
Il set di dati che useremo in questo tutorial è il set di dati Sonar.
Questo è un set di dati che descrive i ritorni del sensore del sonar che rimbalzano su diversi servizi. Le 60 variabili di input sono la forza dei rendimenti a diverse angolazioni. È un problema di classificazione binaria che richiede un modello per differenziare le rocce dai cilindri di metallo.
È un set di dati ben compreso. Tutte le variabili sono continue e generalmente nell'intervallo da 0 a 1. Pertanto non dovremo normalizzare i dati di input, il che è spesso una buona pratica con l'algoritmo Perceptron.
Puoi saperne di più su questo set di dati nel repository UCI Machine Learning . È possibile scaricare gratuitamente il set di dati e inserirlo nella directory di lavoro con il nome file sonar.all-data.csv .
Tutorial
Questo tutorial è suddiviso in 3 parti:
Fare previsioni.
Allenamento pesi del Perceptron.
Modellazione del set di dati del sonar.
Questi passaggi forniranno le basi per implementare e applicare l'algoritmo Perceptron ai propri problemi di modellazione predittiva di classificazione.
1. Fare previsioni
Il primo passo è sviluppare una funzione che possa fare previsioni.
Ciò sarà necessario sia nella valutazione dei valori dei pesi candidati nella discesa del gradiente stocastico, sia dopo che il modello è stato finalizzato e si desidera iniziare a fare previsioni su dati di test o nuovi dati.
Di seguito è riportata una funzione denominata prediction () che prevede un valore di output per una riga dato un insieme di pesi.
Il primo peso è sempre il bias in quanto è autonomo e non è responsabile di un valore di input specifico.
# Facciamo la previsione utilizzando i Pesi(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
Possiamo escogitare un piccolo set di dati per testare la nostra funzione di previsione.
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
Possiamo anche utilizzare pesi preparati in precedenza per fare previsioni per questo set di dati.
Mettendo tutto insieme possiamo testare la nostra funzione predict() di seguito.
# Facciamo la previsione utilizzando i Pesi(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 Predizione
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("Aspettato=%d, Previsto=%d" % (row[-1], prediction))
Sono disponibili due valori di input ( X1 e X2 ) e tre valori di peso ( bias , w1 e w2 ). L'equazione di attivazione che abbiamo modellato per questo problema è:
activation = (w1 * X1) + (w2 * X2) + bias
Oppure, con i valori di peso specifico abbiamo scelto manualmente come:
activation = (0.206 * X1) + (-0.234 * X2) + -0.1
Eseguendo questa funzione otteniamo previsioni che corrispondono ai valori di output attesi ( 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
Ora siamo pronti per implementare la discesa del gradiente stocastico per ottimizzare i nostri valori di peso.
2. Training Network Weights
Possiamo stimare i valori di peso per i nostri dati di allenamento utilizzando la discesa del gradiente stocastico.
La discesa del gradiente stocastico richiede due parametri:
Tasso di apprendimento : utilizzato per limitare la quantità di correzione di ogni peso ogni volta che viene aggiornato.
Epoche : il numero di volte per eseguire i dati di allenamento durante l'aggiornamento del peso.
Questi, insieme ai dati di addestramento, saranno gli argomenti della funzione.
Ci sono 3 loop che dobbiamo eseguire nella funzione:
Ripeti ogni Epoche.
Ripeti ogni riga nei dati di addestramento per un'Epoche.
Fai un giro su ogni peso e aggiornalo per una riga in un'Epoche.
Come puoi vedere, aggiorniamo ogni peso per ogni riga nei dati di allenamento, ogni Epoche.
I pesi vengono aggiornati in base all'errore commesso dal modello. L'errore viene calcolato come la differenza tra il valore di output atteso e la previsione effettuata con i pesi candidati.
C'è un peso per ogni attributo di input e questi vengono aggiornati in modo coerente, ad esempio:
w(t+1)= w(t) + learning_rate * (expected(t) - predicted(t)) * x(t)
Il bias viene aggiornato in modo simile, tranne che senza un input in quanto non è associato a un valore di input specifico:
bias(t+1) = bias(t) + learning_rate * (expected(t) - predicted(t))
Ora possiamo mettere insieme tutto questo. Di seguito è riportata una funzione denominata train_weights () che calcola i valori di peso per un set di dati di allenamento utilizzando la discesa del gradiente stocastico.
# Stimiamo i pesi del Perceptron usando la discesa del gradiente stocastico
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
Puoi vedere che teniamo anche traccia della somma dell'errore al quadrato (un valore positivo) ogni epoca in modo da poter stampare un bel messaggio ogni ciclo esterno. Possiamo testare questa funzione sullo stesso piccolo set di dati artificioso dall'alto.
# Facciamo la previsione utilizzando i Pesi(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
# Stimiamo i pesi del Perceptron usando la discesa del gradiente stocastico
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
# Calcoliamo i Pesi per le previsioni
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)
Usiamo un tasso di apprendimento di 0,1 e addestriamo il modello solo per 5 epoche o 5 esposizioni dei pesi all'intero set di dati di addestramento.
L'esecuzione dell'esempio stampa un messaggio ogni epoche con la somma al quadrato dell'errore per quell'epoche e il set finale di pesi.
>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]
Puoi vedere come il problema viene appreso molto rapidamente dall'algoritmo.
Ora, applichiamo questo algoritmo su un set di dati reale.
3. Modellazione del dataset del sonar
In questa sezione, addestreremo un modello Perceptron utilizzando la discesa del gradiente stocastico sul set di dati del Sonar.
L'esempio presuppone che una copia CSV del set di dati si trovi nella directory di lavoro corrente con il nome file sonar.all-data.csv .
Il set di dati viene prima caricato, i valori di stringa convertiti in numerici e la colonna di output viene convertita da stringhe a valori interi da 0 a 1. Ciò si ottiene con le funzioni di supporto load_csv () , str_column_to_float () e str_column_to_int () per caricare e preparare il set di dati.
Useremo la validazione incrociata k-fold per stimare le prestazioni del modello appreso su dati invisibili. Ciò significa che costruiremo e valuteremo k modelli e stimeremo le prestazioni come errore medio del modello. L'accuratezza della classificazione verrà utilizzata per valutare ogni modello. Questi comportamenti sono forniti nella cross_validation_split () , accuracy_metric () e evaluate_algorithm () funzioni di supporto.
Useremo le funzioni prediction () e train_weights () create sopra per addestrare il modello e una nuova funzione perceptron () per legarli insieme.
Di seguito è riportato l'esempio completo.
# Implementiamo l'algoritmo Perceptron su un set di dati
from random import seed
from random import randrange
from csv import reader
# Carico il CSV
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
# Converto colonne da stringhe a Float
def str_column_to_float(dataset, column):
for row in dataset:
row[column] = float(row[column].strip())
# Converto colonne da stringhe a Intere
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
# Divido il dataset in k "sottogruppi"
def cross_validation_split(dataset, n_folds):
dataset_split = list()
dataset_copy = list(dataset)
fold_size = int(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
# Valutiamo l'accuratezza del modello
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
# Valuto l'algoritmo usando il 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
# Facciamo
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
# Stimiamo i pesi del Perceptron usando la discesa del gradiente stocastico
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 con 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)
# carico e preparo dati
filename = 'sonar.all-data.csv'
dataset = load_csv(filename)
for i in range(len(dataset[0])-1):
str_column_to_float(dataset, i)
# converto string class a integers
str_column_to_int(dataset, len(dataset[0])-1)
# VIA !!!
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))))
Un valore k di 3 è stato utilizzato per la convalida incrociata, dando a ciascuna piega 208/3 = 69,3 o poco meno di 70 record da valutare a ogni iterazione. Un tasso di apprendimento di 0,1 e 500 epoche di formazione sono stati scelti con un po 'di sperimentazione.
Puoi provare le tue configurazioni e vedere se riesci a battere il mio punteggio.
L'esecuzione di questo esempio stampa i punteggi per ciascuna delle 3 pieghe di convalida incrociata, quindi stampa l'accuratezza della classificazione media.
Possiamo vedere che la precisione è di circa il 72%, superiore al valore di base di poco più del 50% se prevedessimo solo la classe di maggioranza utilizzando l'algoritmo della regola zero.
Scores: [76.81159420289855, 69.56521739130434, 72.46376811594203]
Mean Accuracy: 72.947%
Estensioni
Questa sezione elenca le estensioni di questo tutorial che potresti voler considerare di esplorare.
Sintonizza l'esempio . Regola la velocità di apprendimento, il numero di epoche e persino il metodo di preparazione dei dati per ottenere un punteggio migliore sul set di dati.
Discesa gradiente stocastica in batch . Modificare l'algoritmo di discesa del gradiente stocastico per accumulare gli aggiornamenti in ogni epoca e aggiornare i pesi in un batch solo alla fine dell'epoca.
Ulteriori problemi di regressione . Applicare la tecnica ad altri problemi di classificazione nel repository di machine learning UCI.
Hai esplorato qualcuna di queste estensioni? Fatemelo sapere nei commenti qui sotto.
Revisione
In questo tutorial, hai scoperto come implementare l'algoritmo Perceptron utilizzando la discesa del gradiente stocastico da zero con Python.
Hai imparato.
Come fare previsioni per un problema di classificazione binaria.
Come ottimizzare un insieme di pesi utilizzando la discesa del gradiente stocastico.
Come applicare la tecnica a un problema di modellazione predittiva di classificazione reale.
Hai qualche domanda? Fai la tua domanda nei commenti qui sotto e faremo del nostro meglio per rispondere.
Comments