TensorFlow訓練神經網絡cost一直為0


問題描述

這幾天在用TensorFlow搭建一個神經網絡來做一個binary classifier,搭建一個典型的神經網絡的基本思路是:

  • 定義神經網絡的layers(層)以及初始化每一層的參數
  • 然后迭代:
    • 前向傳播(Forward propagation)
    • 計算cost(Compute cost)
    • 反向傳播(Backward propagation)
    • 更新參數(Update parameters)
  • 使用訓練好的參數去做預測

在訓練的時候發現了一個很奇怪的現象:每一次迭代所有的cost都為0。一開始以為是參數初始化出了問題,花了好多時間在上面。后來仔細研究了一下發現是最后一層的輸出函數用錯了,我用的是tf.nn.softmax_cross_entropy_with_logits來計算cost。 我們知道softmax一般是用來做multiclass classifier的,也就是輸出的類別要大於兩個。對於一個binary classifier而言,很明顯我們要用sigmoid函數也就是tf.nn.sigmoid_cross_entropy_with_logits來計算cost,於是問題解決。

為什么?

那么為什么在binary classifier中使用了softmax之后cost就一直是0呢?我們先來看一下softmax的公式:

s(z)j=ezjKk=1ezks(z)j=ezj∑k=1Kezk

  • binary classifier的output是一維的(one-dimension 0/1),那么如果只有一個元素,那么s(z)就永遠等於1,不管z的值是多少。
  • 恆定輸出1之后,我們結合交叉熵的計算公式可知:
    • 如果true label是0,那么 -0*log(1) = 0
    • 如果true label是1,那么 -1*log(1) = 0

Tensorflow函數:tf.nn.softmax_cross_entropy_with_logits 講解

 

首先把Tensorflow英文API搬過來:

tf.nn.softmax_cross_entropy_with_logits(_sentinel=None, labels=None, logits=None, dim=-1, name=None)

 

Computes softmax cross entropy between logits and labels.

Measures the probability error in discrete classification tasks in which the classes are mutually exclusive (each entry is in exactly one class). For example, each CIFAR-10 image is labeled with one and only one label: an image can be a dog or a truck, but not both.

NOTE: While the classes are mutually exclusive, their probabilities need not be. All that is required is that each row oflabels is a valid probability distribution. If they are not, the computation of the gradient will be incorrect.

If using exclusive labels (wherein one and only one class is true at a time), seesparse_softmax_cross_entropy_with_logits.

WARNING: This op expects unscaled logits, since it performs a softmax on logits internally for efficiency. Do not call this op with the output of softmax, as it will produce incorrect results.

logits and labels must have the same shape [batch_size, num_classes] and the same dtype (either float16,float32, or float64).

Note that to avoid confusion, it is required to pass only named arguments to this function.

Args:

  • _sentinel: Used to prevent positional parameters. Internal, do not use.
  • labels: Each row labels[i] must be a valid probability distribution.
  • logits: Unscaled log probabilities.
  • dim: The class dimension. Defaulted to -1 which is the last dimension.
  • name: A name for the operation (optional).
這個函數至少需要兩個參數:labels, logits.

labels:為神經網絡期望的輸出

logits:為神經網絡最后一層的輸出

警告:這個函數內部自動計算softmax,然后再計算交叉熵代價函數,也就是說logits必須是沒有經過tf.nn.softmax函數處理的數據,否則導致訓練結果有問題。建議編程序時使用這個函數,而不必自己編寫交叉熵代價函數。

下面是兩層CNN識別mnist的softmax回歸實驗:

 

[python]  view plain  copy
 
  1.   
[python]  view plain  copy
 
  1.   
[python]  view plain  copy
 
  1. #coding=utf-8  
  2. import tensorflow as tf  
  3. from tensorflow.examples.tutorials.mnist import input_data  
  4. mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)  
  5.   
  6. def compute_accuracy(v_xs,v_ys):  
  7.     global prediction  
  8.     y_pre=sess.run(prediction,feed_dict={xs:v_xs,keep_prob:1}) #這里的keep_prob是保留概率,即我們要保留的RELU的結果所占比例  
  9.     correct_prediction=tf.equal(tf.argmax(y_pre,1),tf.argmax(v_ys,1))  
  10.     accuracy=tf.reduce_mean(tf.cast(correct_prediction,tf.float32))  
  11.     result=sess.run(accuracy,feed_dict={xs:v_xs,ys:v_ys,keep_prob:1})  
  12.     return result  
  13.   
  14. def weight_variable(shape):  
  15.     inital=tf.truncated_normal(shape,stddev=0.1)     #stddev爲標準差  
  16.     return tf.Variable(inital)  
  17.   
  18. def bias_variable(shape):  
  19.     inital=tf.constant(0.1,shape=shape)  
  20.     return tf.Variable(inital)  
  21.   
  22. def conv2d(x,W):    #x爲像素值,W爲權值  
  23.     #strides[1,x_movement,y_movement,1]  
  24.     #must have strides[0]=strides[3]=1  
  25.     #padding=????  
  26.     return tf.nn.conv2d(x,W,strides=[1,1,1,1],padding='SAME')#  
  27.   
  28. def max_pool_2x2(x):  
  29.     # strides[1,x_movement,y_movement,1]  
  30.     return tf.nn.max_pool(x,ksize=[1,2,2,1],strides=[1,2,2,1],padding='SAME')#ksize二三維為池化窗口  
  31.   
  32. #define placeholder for inputs to network  
  33. xs=tf.placeholder(tf.float32,[None,784])/255  
  34. ys=tf.placeholder(tf.float32,[None,10])  
  35. keep_prob=tf.placeholder(tf.float32)  
  36. x_image=tf.reshape(xs, [-1,28,28,1]) #-1為這個維度不確定,變成一個4維的矩陣,最后為最里面的維數  
  37. #print x_image.shape                 #最后這個1理解為輸入的channel,因為為黑白色所以為1  
  38.   
  39. ##conv1 layer##  
  40. W_conv1=weight_variable([5,5,1,32]) #patch 5x5,in size 1 是image的厚度,outsize 32 是提取的特征的維數  
  41. b_conv1=bias_variable([32])  
  42. h_conv1=tf.nn.relu(conv2d(x_image,W_conv1)+b_conv1)# output size 28x28x32 因為padding='SAME'  
  43. h_pool1=max_pool_2x2(h_conv1)      #output size 14x14x32  
  44.   
  45. ##conv2 layer##  
  46. W_conv2=weight_variable([5,5,32,64]) #patch 5x5,in size 32 是conv1的厚度,outsize 64 是提取的特征的維數  
  47. b_conv2=bias_variable([64])  
  48. h_conv2=tf.nn.relu(conv2d(h_pool1,W_conv2)+b_conv2)# output size 14x14x64 因為padding='SAME'  
  49. h_pool2=max_pool_2x2(h_conv2)      #output size 7x7x64  
  50.   
  51. ##func1 layer##  
  52. W_fc1=weight_variable([7*7*64,1024])  
  53. b_fc1=bias_variable([1024])  
  54. #[n_samples,7,7,64]->>[n_samples,7*7*64]  
  55. h_pool2_flat=tf.reshape(h_pool2,[-1,7*7*64])  
  56. h_fc1=tf.nn.relu(tf.matmul(h_pool2_flat,W_fc1)+b_fc1)  
  57. h_fc1_drop=tf.nn.dropout(h_fc1,keep_prob)  #防止過擬合  
  58.   
  59. ##func2 layer##  
  60. W_fc2=weight_variable([1024,10])  
  61. b_fc2=bias_variable([10])  
  62. #prediction=tf.nn.softmax(tf.matmul(h_fc1_drop,W_fc2)+b_fc2)  
  63. prediction=tf.matmul(h_fc1_drop,W_fc2)+b_fc2  
[python]  view plain  copy
 
  1. #h_fc1_drop=tf.nn.dropout(h_fc1,keep_prob)  #防止過擬合  
  2.   
  3. #the errro between prediction and real data  
  4.   
  5. #cross_entropy = tf.reduce_mean(-tf.reduce_sum(ys*tf.log(prediction),reduction_indices=[1]))  
[python]  view plain  copy
 
  1. cross_entropy = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=ys, logits=prediction)  
  2. train_step = tf.train.AdamOptimizer(1e-4).minimize(cross_entropy)  
  3. sess=tf.Session()  
  4. sess.run(tf.global_variables_initializer())  
  5.   
  6. for i in range(1000):  
  7.     batch_xs,batch_ys=mnist.train.next_batch(100)  
  8.     sess.run(train_step,feed_dict={xs:batch_xs,ys:batch_ys,keep_prob:0.5})  
  9.     if i%50 ==0:  
  10.         accuracy = 0  
  11.         for j in range(10):  
  12.             test_batch = mnist.test.next_batch(1000)  
  13.             acc_forone=compute_accuracy(test_batch[0], test_batch[1])  
  14.             #print 'once=%f' %(acc_forone)  
  15.             accuracy=acc_forone+accuracy  
  16.         print '測試結果:batch:%g,准確率:%f' %(i,accuracy/10)  

 
           
實驗結果為:

 

 

[python]  view plain  copy
 
  1. 測試結果:batch:0,准確率:0.090000  
  2. 測試結果:batch:50,准確率:0.788600  
  3. 測試結果:batch:100,准確率:0.880200  
  4. 測試結果:batch:150,准確率:0.904600  
  5. 測試結果:batch:200,准確率:0.927500  
  6. 測試結果:batch:250,准確率:0.929800  
  7. 測試結果:batch:300,准確率:0.939600  
  8. 測試結果:batch:350,准確率:0.942100  
  9. 測試結果:batch:400,准確率:0.950600  
  10. 測試結果:batch:450,准確率:0.950700  
  11. 測試結果:batch:500,准確率:0.956700  
  12. 測試結果:batch:550,准確率:0.956000  
  13. 測試結果:batch:600,准確率:0.957100  
  14. 測試結果:batch:650,准確率:0.958400  
  15. 測試結果:batch:700,准確率:0.961500  
  16. 測試結果:batch:750,准確率:0.963800  
  17. 測試結果:batch:800,准確率:0.965000  
  18. 測試結果:batch:850,准確率:0.966300  
  19. 測試結果:batch:900,准確率:0.967800  
  20. 測試結果:batch:950,准確率:0.967700  

迭代次數沒有太多,否則准確率還會提高。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM