2016-04-12 17 views
13

Sto scrivendo un classificatore di rete neurale in TensorFlow/Python per il set di dati notMNIST. Ho implementato la regolarizzazione l2 e il dropout sui livelli nascosti. Funziona bene finché c'è un solo livello nascosto, ma quando ho aggiunto più livelli (per migliorare l'accuratezza), la funzione di perdita aumenta rapidamente ad ogni passaggio, diventando NaN dal punto 5. Ho provato a disattivare temporaneamente la regolarizzazione Dropout e L2, ma Ho lo stesso comportamento finché ci sono 2+ livelli. Ho anche riscritto il mio codice da zero (facendo alcuni refactoring per renderlo più flessibile), ma con gli stessi risultati. Il numero e la dimensione dei livelli è controllato da hidden_layer_spec. Cosa mi manca?L'aggiunta di più livelli a TensorFlow fa sì che la funzione di perdita diventi Nan

#works for np.array([1024]) with about 96.1% accuracy 
hidden_layer_spec = np.array([1024, 300]) 
num_hidden_layers = hidden_layer_spec.shape[0] 
batch_size = 256 
beta = 0.0005 

epochs = 100 
stepsPerEpoch = float(train_dataset.shape[0])/batch_size 
num_steps = int(math.ceil(float(epochs) * stepsPerEpoch)) 

l2Graph = tf.Graph() 
with l2Graph.as_default(): 
    #with tf.device('/cpu:0'): 
     # Input data. For the training data, we use a placeholder that will be fed 
     # at run time with a training minibatch. 
     tf_train_dataset = tf.placeholder(tf.float32, 
             shape=(batch_size, image_size * image_size)) 
     tf_train_labels = tf.placeholder(tf.float32, shape=(batch_size, num_labels)) 
     tf_valid_dataset = tf.constant(valid_dataset) 
     tf_test_dataset = tf.constant(test_dataset) 

     weights = [] 
     biases = [] 
     for hi in range(0, num_hidden_layers + 1): 
     width = image_size * image_size if hi == 0 else hidden_layer_spec[hi - 1] 
     height = num_labels if hi == num_hidden_layers else hidden_layer_spec[hi] 
     weights.append(tf.Variable(tf.truncated_normal([width, height]), name = "w" + `hi + 1`)) 
     biases.append(tf.Variable(tf.zeros([height]), name = "b" + `hi + 1`)) 
     print(`width` + 'x' + `height`) 

     def logits(input, addDropoutLayer = False): 
     previous_layer = input 
     for hi in range(0, hidden_layer_spec.shape[0]): 
      previous_layer = tf.nn.relu(tf.matmul(previous_layer, weights[hi]) + biases[hi]) 
      if addDropoutLayer: 
      previous_layer = tf.nn.dropout(previous_layer, 0.5) 
     return tf.matmul(previous_layer, weights[num_hidden_layers]) + biases[num_hidden_layers] 

     # Training computation. 
     train_logits = logits(tf_train_dataset, True) 

     l2 = tf.nn.l2_loss(weights[0]) 
     for hi in range(1, len(weights)): 
     l2 = l2 + tf.nn.l2_loss(weights[0]) 
     loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(train_logits, tf_train_labels)) + beta * l2 

     # Optimizer. 
     global_step = tf.Variable(0) # count the number of steps taken. 
     learning_rate = tf.train.exponential_decay(0.5, global_step, int(stepsPerEpoch) * 2, 0.96, staircase = True) 
     optimizer = tf.train.GradientDescentOptimizer(learning_rate).minimize(loss, global_step=global_step) 

     # Predictions for the training, validation, and test data. 
     train_prediction = tf.nn.softmax(train_logits) 
     valid_prediction = tf.nn.softmax(logits(tf_valid_dataset)) 
     test_prediction = tf.nn.softmax(logits(tf_test_dataset)) 
     saver = tf.train.Saver() 

with tf.Session(graph=l2Graph) as session: 
    tf.initialize_all_variables().run() 
    print("Initialized") 
    for step in range(num_steps): 
    # Pick an offset within the training data, which has been randomized. 
    # Note: we could use better randomization across epochs. 
    offset = (step * batch_size) % (train_labels.shape[0] - batch_size) 
    # Generate a minibatch. 
    batch_data = train_dataset[offset:(offset + batch_size), :] 
    batch_labels = train_labels[offset:(offset + batch_size), :] 
    # Prepare a dictionary telling the session where to feed the minibatch. 
    # The key of the dictionary is the placeholder node of the graph to be fed, 
    # and the value is the numpy array to feed to it. 
    feed_dict = {tf_train_dataset : batch_data, tf_train_labels : batch_labels} 
    _, l, predictions = session.run(
     [optimizer, loss, train_prediction], feed_dict=feed_dict) 
    if (step % 500 == 0): 
     print("Minibatch loss at step %d: %f" % (step, l)) 
     print("Learning rate: " % learning_rate) 
     print("Minibatch accuracy: %.1f%%" % accuracy(predictions, batch_labels)) 
     print("Validation accuracy: %.1f%%" % accuracy(
     valid_prediction.eval(), valid_labels)) 
    print("Test accuracy: %.1f%%" % accuracy(test_prediction.eval(), test_labels)) 
    save_path = saver.save(session, "l2_degrade.ckpt") 
    print("Model save to " + `save_path`) 

risposta

17

Si è scoperto che questo non era tanto un problema di codifica quanto un problema di apprendimento approfondito. Il livello extra rendeva le sfumature troppo instabili e questo portava alla funzione di perdita che si tramutava rapidamente in NaN. Il modo migliore per risolvere questo problema è utilizzare Xavier initialization. Altrimenti, la varianza dei valori iniziali tenderà ad essere troppo alta, causando instabilità. Inoltre, ridurre il tasso di apprendimento può aiutare.

+1

Mi sono reso conto che era un po 'di tempo fa, ma potresti anche voler esaminare alcuni metodi di regolarizzazione, e in particolare in [normalizzazione batch] (https://arxiv.org/pdf/1502.03167.pdf). Se funziona funziona bene, ma BN aiuta con la sensibilità della rete alle distribuzioni di peso iniziali, tra le altre cose. – Engineero

+0

Per 'truncated_normal', provare a impostare' stddev = sqrt (2/N) ', dove' N' è il numero di righe nella matrice peso. O semplicemente imposta 'stddev' su [valore più basso] (https://discussions.udacity.com/t/problem-3-3-dropout-does-not-improve-test-accuarcy/46286/13). Ecco un [esempio] (http://www.ritchieng.com/machine-learning/deep-learning/tensorflow/regularization/), anche se ci sono alcuni errori, come includere il dropout nella fase di valutazione. – orodbhen

+0

In realtà, ecco l'originale [articolo] (https://arxiv.org/pdf/1502.01852v1.pdf) che deriva da 'sqrt (2/N)'. – orodbhen

8

Ho avuto lo stesso problema e ho ridotto le dimensioni del batch e il tasso di apprendimento ha funzionato per me.

+0

Sì. Il mio tasso di apprendimento era a 0,5 fisso e ho dovuto abbassarlo a 0,06 per farlo funzionare. – scipilot

Problemi correlati