[英]Issue with gradient calculation in a Neural Network (stuck at 7% error in MNIST)
嗨,我在使用numpy在python中實現神經網絡時檢查梯度的計算遇到問題。 我正在使用mnist
數據集嘗試並嘗試使用小批量梯度下降。
我已經檢查了數學並在紙面上看起來不錯,所以也許您可以給我提示這里發生了什么:
編輯:一個答案讓我意識到,成本函數的確計算錯誤。 但是,這不能解釋漸變問題,因為它是使用back_prop計算的。 我使用rmsprop
,30個歷元和100個批次的minibatch gradient
下降法在隱藏層中使用300個單位得到%7的錯誤率。 ( learning_rate
= 0.001,由於rmsprop而較小)。
每個輸入具有768個功能,因此對於100個樣本,我有一個矩陣。 Mnist
有10個班級。
X = NoSamplesxFeatures = 100x768
Y = NoSamplesxClasses = 100x10
完全訓練后,我正在使用一個隱藏層神經網絡,其中隱藏層大小為300。 我還有一個問題是我是否應該使用softmax輸出函數來計算錯誤...我認為不是。 但是,對於所有這些我都是新手,顯然,對我來說似乎很奇怪。
(注意:我知道代碼很丑陋,但這是我在壓力下完成的第一個Python / Numpy代碼,請多多包涵)
這是back_prof和激活:
def sigmoid(z):
return np.true_divide(1,1 + np.exp(-z) )
#not calculated really - this the fake version to make it faster.
def sigmoid_prime(a):
return (a)*(1 - a)
def _back_prop(self,W,X,labels,f=sigmoid,fprime=sigmoid_prime,lam=0.001):
"""
Calculate the partial derivates of the cost function using backpropagation.
"""
#Weight for first layer and hidden layer
Wl1,bl1,Wl2,bl2 = self._extract_weights(W)
# get the forward prop value
layers_outputs = self._forward_prop(W,X,f)
#from a number make a binary vector, for mnist 1x10 with all 0 but the number.
y = self.make_1_of_c_encoding(labels)
num_samples = X.shape[0] # layers_outputs[-1].shape[0]
# Dot product return Numsamples (N) x Outputs (No CLasses)
# Y is NxNo Clases
# Layers output to
big_delta = np.zeros(Wl2.size + bl2.size + Wl1.size + bl1.size)
big_delta_wl1, big_delta_bl1, big_delta_wl2, big_delta_bl2 = self._extract_weights(big_delta)
# calculate the gradient for each training sample in the batch and accumulate it
for i,x in enumerate(X):
# Error with respect the output
dE_dy = layers_outputs[-1][i,:] - y[i,:]
# bias hidden layer
big_delta_bl2 += dE_dy
# get the error for the hiddlen layer
dE_dz_out = dE_dy * fprime(layers_outputs[-1][i,:])
#and for the input layer
dE_dhl = dE_dy.dot(Wl2.T)
#bias input layer
big_delta_bl1 += dE_dhl
small_delta_hl = dE_dhl*fprime(layers_outputs[-2][i,:])
#here calculate the gradient for the weights in the hidden and first layer
big_delta_wl2 += np.outer(layers_outputs[-2][i,:],dE_dz_out)
big_delta_wl1 += np.outer(x,small_delta_hl)
# divide by number of samples in the batch (should be done here)?
big_delta_wl2 = np.true_divide(big_delta_wl2,num_samples) + lam*Wl2*2
big_delta_bl2 = np.true_divide(big_delta_bl2,num_samples)
big_delta_wl1 = np.true_divide(big_delta_wl1,num_samples) + lam*Wl1*2
big_delta_bl1 = np.true_divide(big_delta_bl1,num_samples)
# return
return np.concatenate([big_delta_wl1.ravel(),
big_delta_bl1,
big_delta_wl2.ravel(),
big_delta_bl2.reshape(big_delta_bl2.size)])
現在feed_forward:
def _forward_prop(self,W,X,transfer_func=sigmoid):
"""
Return the output of the net a Numsamples (N) x Outputs (No CLasses)
# an array containing the size of the output of all of the laye of the neural net
"""
# Hidden layer DxHLS
weights_L1,bias_L1,weights_L2,bias_L2 = self._extract_weights(W)
# Output layer HLSxOUT
# A_2 = N x HLS
A_2 = transfer_func(np.dot(X,weights_L1) + bias_L1 )
# A_3 = N x Outputs
A_3 = transfer_func(np.dot(A_2,weights_L2) + bias_L2)
# output layer
return [A_2,A_3]
以及用於梯度檢查的成本函數:
def cost_function(self,W,X,labels,reg=0.001):
"""
reg: regularization term
No weight decay term - lets leave it for later
"""
outputs = self._forward_prop(W,X,sigmoid)[-1] #take the last layer out
sample_size = X.shape[0]
y = self.make_1_of_c_encoding(labels)
e1 = np.sum((outputs - y)**2, axis=1))*0.5
#error = e1.sum(axis=1)
error = e1.sum()/sample_size + 0.5*reg*(np.square(W)).sum()
return error
運行梯度檢查時會得到什么樣的結果? 通常,您可以通過查看梯度的輸出與梯度檢查產生的輸出來弄清實現錯誤的性質。
此外,對於諸如MNIST之類的分類任務,平方誤差通常不是一個好的選擇,我建議使用簡單的S型頂層或softmax。 對於S形,您要使用的交叉熵函數為:
L(h,Y) = -Y*log(h) - (1-Y)*log(1-h)
對於softmax
L(h,Y) = -sum(Y*log(h))
其中Y是作為1x10向量給出的目標,h是您的預測值,但可以輕松擴展到任意批量。
在這兩種情況下,頂層增量僅變為:
delta = h - Y
頂層漸變變為:
grad = dot(delta, A_in)
其中A_in是上一層的頂層輸入。
雖然我無法理解反向傳播例程,但我從您的代碼中懷疑梯度誤差是由於您在使用平方誤差以及計算時未正確計算頂級dE / dw_l2而導致的fprime輸入錯誤。
使用平方誤差時,頂層增量應為:
delta = (h - Y) * fprime(Z_l2)
這里Z_l2是第2層傳遞函數的輸入。類似地,在計算較低層的fprime時,您想使用傳遞函數的輸入(即dot(X,weights_L1)+ bias_L1)
希望能有所幫助。
編輯:作為使用平方交叉誤差上的交叉熵誤差的補充理由,我建議查找Geoffrey Hinton關於線性分類方法的講座: www.cs.toronto.edu/~hinton/csc2515/notes/lec3.ppt
EDIT2:我使用RMSPROP在MNIST數據集上使用不同的參數和1個隱藏層對神經網絡的實現在本地運行了一些測試。 結果如下:
Test1
Epochs: 30
Hidden Size: 300
Learn Rate: 0.001
Lambda: 0.001
Train Method: RMSPROP with decrements=0.5 and increments=1.3
Train Error: 6.1%
Test Error: 6.9%
Test2
Epochs: 30
Hidden Size: 300
Learn Rate: 0.001
Lambda: 0.000002
Train Method: RMSPROP with decrements=0.5 and increments=1.3
Train Error: 4.5%
Test Error: 5.7%
看來,如果將lambda參數減小幾個數量級,您最終將獲得更好的性能。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.