2016-04-12 20 views
13

私はnotMNISTデータセットのTensorFlow/Pythonにニューラルネットワーク分類子を書いています。私は隠されたレイヤーに正則化と脱落を実装しました。隠しレイヤーが1つしかない限り正常に動作しますが、精度を向上させるためにレイヤーを追加すると、ステップごとに損失関数が急速に増加し、NaNになります。ドロップアウトとL2正規化を一時的に無効にしました。私は2つ以上の層がある限り、同じ動作を得ます。私は自分のコードを最初から書き直していましたが(同じ柔軟性を持たせるためにいくつかのリファクタリングを行っていました)、同じ結果でした。レイヤの数とサイズはhidden_layer_specによって制御されます。私は何が欠けていますか?TensorFlowに複数のレイヤーを追加すると、損失関数が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`) 

答えて

17

これは、ディープラーニングの問題としてのコーディングの問題ではないことが分かります。余分なレイヤーではグラデーションがあまりにも不安定になり、損失関数がすぐにNaNになりました。これを解決する最善の方法はXavier initializationを使用することです。そうしないと、初期値の分散が高すぎて不安定になりがちです。また、学習率を下げることが役に立ちます。

+1

これはしばらく前のことでしたが、いくつかの正規化方法、具体的には[バッチ標準化](https://arxiv.org/pdf/1502.03167.pdf)を調べることもできます。あなたがそれをうまく使っていれば、BNは初期の体重分布などのネットワーク感度に役立ちます。 – Engineero

+0

'truncated_normal'の場合、' stddev = sqrt(2/N) 'を設定してみてください。ここで' N'は重み行列の行数です。あるいは 'stddev'を[lower value]に設定するだけです(https://discussions.udacity.com/t/problem-3-3-dropout-does-not-improve-test-accuarcy/46286/13)。ここでは、[例](http://www.ritchieng.com/machine-learning/deep-learning/tensorflow/regularization/)ですが、評価ステップでのドロップアウトなど、いくつかの間違いがあります。 – orodbhen

+0

実際、 'sqrt(2/N)'が由来するオリジナルの[paper](https://arxiv.org/pdf/1502.01852v1.pdf)です。 – orodbhen

8

私は同じ問題を抱えていましたが、バッチサイズと学習率が減りました。

+0

はい。私の学習率は0.5に固定されており、それを得るには0.06に下げる必要がありました。 – scipilot

関連する問題