2017-05-29 9 views
1

Python 3を使用して単純な数値勾配チェックを実装しようとしていて、ニューラルネットワークにnumpyを使用しています。ニューラルネットワークの数値勾配チェックは、Python-numpyを使用した行列では動作しません。

単純な1D関数ではうまく機能しますが、パラメータの行列に適用すると失敗します。

私の推測では、コスト関数が行列に対してうまく計算されないか、数値勾配チェックのやり方が何とか間違っていると思います。

下記のコードを参照していただきありがとうございます。

import numpy as np 
import random 
import copy 

def gradcheck_naive(f, x): 
    """ Gradient check for a function f. 

    Arguments: 
    f -- a function that takes a single argument (x) and outputs the 
     cost (fx) and its gradients grad 
    x -- the point (numpy array) to check the gradient at 
    """ 
    rndstate = random.getstate() 
    random.setstate(rndstate) 
    fx, grad = f(x) # Evaluate function value at original point 
    #fx=cost 
    #grad=gradient 
    h = 1e-4   
    # Iterate over all indexes in x 
    it = np.nditer(x, flags=['multi_index'], op_flags=['readwrite']) 
    while not it.finished: 
     ix = it.multi_index #multi-index number 

     random.setstate(rndstate) 
     xp = copy.deepcopy(x) 
     xp[ix] += h 
     fxp, gradp = f(xp) 

     random.setstate(rndstate) 
     xn = copy.deepcopy(x) 
     xn[ix] -= h 
     fxn, gradn = f(xn) 
     numgrad = (fxp-fxn)/(2*h) 

     # Compare gradients 
     reldiff = abs(numgrad - grad[ix])/max(1, abs(numgrad), abs(grad[ix])) 
     if reldiff > 1e-5: 
      print ("Gradient check failed.") 
      print ("First gradient error found at index %s" % str(ix)) 
      print ("Your gradient: %f \t Numerical gradient: %f" % (
       grad[ix], numgrad)) 
      return 

     it.iternext() # Step to next dimension 

    print ("Gradient check passed!") 

#sanity check with 1D function 
exp_f = lambda x: (np.sum(np.exp(x)), np.exp(x)) 
gradcheck_naive(exp_f, np.random.randn(4,5)) #this works fine 

#sanity check with matrices 
#forward pass 
W = np.random.randn(5,10) 
x = np.random.randn(10,3) 
D = W.dot(x) 

#backpropagation pass 
gradx = W 

func_f = lambda x: (np.sum(W.dot(x)), gradx) 
gradcheck_naive(func_f, np.random.randn(10,3)) #this does not work (grad check fails) 

答えて

1

私はそれを理解しました。 (私の数学の先生はとても誇りに思っています...)

短い答えは、ドットの積と要素の賢明な製品を混ぜていたことです。

要素賢明な製品を使用して、勾配に等しいです:内積を使用する場合

W = np.array([[2,4],[3,5],[3,1]]) 
x = np.array([[1,7],[5,-1],[4,7]]) 
D = W*x #element-wise multiplication 

gradx = W 

func_f = lambda x: (np.sum(W*x), gradx) 
gradcheck_naive(func_f, np.random.randn(3,2)) 

、勾配は次のようになります。また、私は賢明な要素をどうやったのか不思議でした

W = np.array([[2,4],[3,5]])) 
x = np.array([[1,7],[5,-1],[5,1]]) 
D = x.dot(W) 

unitary = np.array([[1,1],[1,1],[1,1]]) 
gradx = unitary.dot(np.transpose(W)) 

func_f = lambda x: (np.sum(x.dot(W)), gradx) 
gradcheck_naive(func_f, np.random.randn(3,2)) 

製品は以下のように等しくない次元の行列で動作する:

x = np.random.randn(10) 
W = np.random.randn(3,10) 

D1 = x*W 
D2 = W*x 

D1 = D2(W = 3x10と同じ次元)と私の理解は、xがnumpyで3x10の行列になるようにブロードキャストされ、要素の賢明な乗算が可能です。

結論:疑問がある場合は、小さな行列で書き出して、エラーの原因を特定します。

+0

あなたはいい仕事をしました! – Aaron

関連する問題