2016-05-11 19 views
8

Il seguente codice è stato scritto per imparare la funzione XOR, ma circa la metà delle volte che la rete non apprende e la perdita dopo ogni epoca rimane la stessa.tflearn/tensorflow non apprende xor

train_f = [[0, 0], [0, 1], [1, 0], [1, 1]] 
train_c = [[0], [1], [1], [0]] 
test_f = train_f 
test_c = train_c 

import tensorflow as tf 
import tflearn 

X = [[0., 0.], [0., 1.], [1., 0.], [1., 1.]] 
Y_xor = [[0.], [1.], [1.], [0.]] 

# Graph definition 
with tf.Graph().as_default(): 
    # Building a network with 2 optimizers 
    net = tflearn.input_data(shape=[None, 2]) 
    # Nand operator definition 
    net = tflearn.fully_connected(net, 2, activation='relu') 
    net = tflearn.fully_connected(net, 2, activation='relu') 
    net = tflearn.fully_connected(net, 1, activation='sigmoid') 
    regressor = tflearn.regression(net, optimizer='adam', learning_rate=0.005, loss="mean_square",) 

    # Training 
    m = tflearn.DNN(regressor) 
    m.fit(X, Y_xor, n_epoch=256, snapshot_epoch=False) 

    # Testing 
    print("Testing XOR operator") 
    print("0 xor 0:", m.predict([[0., 0.]])) 
    print("0 xor 1:", m.predict([[0., 1.]])) 
    print("1 xor 0:", m.predict([[1., 0.]])) 
    print("1 xor 1:", m.predict([[1., 1.]])) 

A volte ottengo risultati corretti come questo:

Testing XOR operator 
0 xor 0: [[0.1487255096435547]] 
0 xor 1: [[0.9297153949737549]] 
1 xor 0: [[0.9354135394096375]] 
1 xor 1: [[0.1487255096435547]] 

Ma spesso questo:

Testing XOR operator 
0 xor 0: [[0.4999997615814209]] 
0 xor 1: [[0.5000002384185791]] 
1 xor 0: [[0.4999997615814209]] 
1 xor 1: [[0.5000001788139343]] 

La mia rete 2x2x1 dovrebbe essere in grado di eseguire XOR, e c'è anche una certa prova che suggerisce che questa rete dovrebbe sempre convergere http://www.ncbi.nlm.nih.gov/pubmed/12662805

Ho anche provato a cambiare i livelli relu in sigmoid, eseguire le iterazioni 2048 e creare reti 4x4x1 e 6x6x1, ma a volte lo stesso problema si verifica ancora.

Potrebbe esserci qualcosa di sbagliato nel modo in cui i pesi sono inizializzati? Come posso usare tflearn per avere una rete neurale per imparare la funzione xor?

+0

Prova semplice SGD (invece di Adam), gioca con il tasso di apprendimento ... – sascha

+0

Sfortunatamente, SGD non aiuta (con nessuna delle funzioni di attivazione) – rdezbolcom

risposta

7

Ho deciso di aggiungere un'altra risposta: ho fatto qualche ricerca in più e ho alcuni consigli sostanzialmente diversi da fornire.

Dopo aver scostato la carta this, mi sono reso conto che il motivo per cui non si vede la convergenza potrebbe avere a che fare con i pesi iniziali.Il documento fa riferimento specificamente ad alcune opere di Hirose et al (Hirose, Yamashita e Huiya 1991) che hanno scoperto che l'inizializzazione con una gamma limitata di pesi si traduce in una probabilità di convergenza molto bassa. Il "punto debole" sembrava essere un intervallo compreso tra 0,5 e 1 in media per convergere in modo affidabile.

Si scopre che tflearn utilizzerà automaticamente l'inizializzazione normale troncata con uno stddev di 0.02. Quindi i pesi hanno un range molto limitato. Ho scoperto che posso ottenere risultati ragionevolmente affidabili utilizzando l'inizializzazione uniforme casuale da -1.0 a 1.0.

Inoltre, per inciso risulta che hai aggiunto un terzo livello. XOR richiede solo un livello nascosto, quindi puoi rimuovere il secondo. Ecco il codice che funziona per me:

import tensorflow as tf 
import tflearn 

X = [[0., 0.], [0., 1.], [1., 0.], [1., 1.]] 
Y_xor = [[0.], [1.], [1.], [0.]] 

# Graph definition 
with tf.Graph().as_default(): 
    tnorm = tflearn.initializations.uniform(minval=-1.0, maxval=1.0) 
    net = tflearn.input_data(shape=[None, 2]) 
    net = tflearn.fully_connected(net, 2, activation='sigmoid', weights_init=tnorm) 
    net = tflearn.fully_connected(net, 1, activation='sigmoid', weights_init=tnorm) 
    regressor = tflearn.regression(net, optimizer='sgd', learning_rate=2., loss='mean_square') 

    # Training 
    m = tflearn.DNN(regressor) 
    m.fit(X, Y_xor, n_epoch=10000, snapshot_epoch=False) 

    # Testing 
    print("Testing XOR operator") 
    print("0 xor 0:", m.predict([[0., 0.]])) 
    print("0 xor 1:", m.predict([[0., 1.]])) 
    print("1 xor 0:", m.predict([[1., 0.]])) 
    print("1 xor 1:", m.predict([[1., 1.]])) 

Si noti che sto usando errore quadratico medio. Con mia sorpresa, sembra funzionare meglio per questo problema. L'entropia incrociata sembra far sì che l'ottimizzatore languisca in regioni relativamente piatte dello spazio problematico. Mi sarei aspettato il contrario; forse qualcuno più esperto di matematica sarà in grado di spiegarlo meglio.

+0

Grazie! Oltre a tutte le tue osservazioni utili, ho notato che hai cambiato il tasso di apprendimento dal mio 0.005 al 2.0. Senza questa modifica, la rete non converge. – rdezbolcom

+0

+5 Grazie mille! Sulla base di ciò che ho provato, senza impostare i pesi uniformi, tflearn praticamente non funziona per nessuna regressione non lineare. – Auxiliary

9

La rete con relu s (come è scritto nello snippet di codice) spesso non riesce ad allenarsi. Il motivo è che se l'input di relu è inferiore a zero, l'output è zero, e quindi il gradiente che ritorna è anch'esso zero.

Poiché si dispone di due livelli, ciascuno con solo due unità di rilancio, con l'inizializzazione casuale ciascuno di questi due strati ha il 25% di avere tutti i suoi neuroni che restituiscono zero, e quindi avere gradiente pari a zero => la rete neurale non impara affatto. In tale rete l'output dell'ultimo strato (prima del sigmoide finale) sarà zero, sigmoid di cui è 0,5 - esattamente ciò che si osserva nei tentativi su cui la rete non converge.

Poiché ogni livello ha il 25% di possibilità di fare questo danno, l'intera rete ha una probabilità totale di circa il 45% (1 - (1 - 0.25)^2) di non riuscire a allenarsi fin dall'inizio. C'è anche una probabilità non nulla che la rete non sia in uno stato simile all'inizio, ma che si trova ad avere un tale stato durante l'allenamento, aumentando ulteriormente la possibilità di divergenze.

Con quattro neuroni la possibilità sarà significativamente inferiore, ma non ancora pari a zero.

Ora, l'unica cosa a cui non posso rispondere è il motivo per cui la rete non converge quando si sostituisce relu con sigmoid - tale rete dovrebbe essere sempre in grado di apprendere "xor". La mia unica ipotesi è che tu abbia sostituito solo uno relu con sigmoid, non entrambi.

È possibile sostituire entrambi i relu s con sigmoid s e confermare che si osservano ancora divergenze?

+0

Grazie per la tua spiegazione! Vedo come relu sia problematico qui ma, se uso linear, sigmoid, softmax o tanh per tutti i livelli, si verifica lo stesso problema ... Per me, questo è particolarmente sorprendente nel caso di linear. – rdezbolcom

+1

In realtà, "lineare" è la meno sorprendente di tutte. Se hai un'attivazione "lineare" (in pratica, nessuna attivazione) tra due strati densi, questi due strati densi servono come uno. Tale rete "multistrato" non può apprendere nulla che la rete a livello singolo non possa apprendere e la rete a livello singolo non può apprendere XOR (in altre parole, con l'attivazione lineare la rete non dovrebbe mai convergere). Sigmoidi e tanh sono sconcertanti. Ci giocherò più tardi e cercherò di capire se riesco a capire il problema. – Ishamael

3

Oltre al consiglio di @ Ishamael, considerare l'utilizzo di una funzione di perdita diversa. L'errore quadratico medio non è generalmente una buona scelta per le attivazioni sigmoide perché il gradiente può ridursi troppo piccolo per essere utile per l'apprendimento a causa della saturazione.

+0

Ho giocato con varie altre funzioni di perdita ma questo non ha aiutato – rdezbolcom