2016-04-06 6 views
2

をSGD。目標は、solver.step()を実行した後に重みの更新を一致させることと、手動で重みを更新することによるものです。 使用MNISTデータを次のようにカフェのPythonのマニュアルは、私が代わりに<code>solver.step()</code>機能を使用してのカフェのpythonで、手動でのpythonで重みを更新するために、SGD機能を実装しようとしています

セットアップがあります。 solber.prototxtのランダムシードをrandom_seed: 52として設定します。 momentum: 0.0base_lr: 0.01lr_policy: "fixed"を確認してください。上記はSGD更新方程式を単純に実装することができるように行われています(勢い、正則化などはありません)。式は単純です: - :

のTest1: 前方伝播および後方を計算するカフェの前方の()と後方()を使用 W_t + 1 = W_tムー* W_t_diff

以下は二つの試験です伝搬。私は5回の反復のためにこれを実行

 solver.net.layers[k].blobs[0].data[...] -= solver.net.layers[k].blobs[0].diff 
     solver.net.layers[k].blobs[1].data[...] -= solver.net.layers[k].blobs[1].diff 

:私は重みを含む層毎 :として

for k in weight_layer_idx: 
     solver.net.layers[k].blobs[0].diff[...] *= lr # weights 
     solver.net.layers[k].blobs[1].diff[...] *= lr # biases 

次に、重量/バイアスを更新します。

試験2:実行中のcaffeのsolver.step(5)

ここで、2回のテストが2回の繰り返しの後に正確に同じウェイトを返すようになると期待しています。

Iは、上記の各試験後の重み値を保存し、二つの試験により重みベクトルとの間のノルム差を計算し、私は彼らが、ビット正確でないことがわかります。私は行方不明になるかもしれない何かを見つけられますか?続い

は参考のため全体のコードである:

import caffe 
caffe.set_device(0) 
caffe.set_mode_gpu() 
import numpy as np 

niter = 5 
solver = None 
solver = caffe.SGDSolver('solver.prototxt') 

# Automatic SGD: TEST2 
solver.step(niter) 
# save the weights to compare later 
w_solver_step = copy(solver.net.layers[1].blobs[0].data.astype('float64')) 
b_solver_step = copy(solver.net.layers[1].blobs[1].data.astype('float64')) 

# Manual SGD: TEST1 
solver = None 
solver = caffe.SGDSolver('solver.prototxt') 
lr = 0.01 
momentum = 0. 

# Get layer types 
layer_types = [] 
for ll in solver.net.layers: 
    layer_types.append(ll.type) 

# Get the indices of layers that have weights in them 
weight_layer_idx = [idx for idx,l in enumerate(layer_types) if 'Convolution' in l or 'InnerProduct' in l] 

for it in range(1, niter+1): 
    solver.net.forward() # fprop 
    solver.net.backward() # bprop 
    for k in weight_layer_idx: 
     solver.net.layers[k].blobs[0].diff[...] *= lr 
     solver.net.layers[k].blobs[1].diff[...] *= lr 
     solver.net.layers[k].blobs[0].data[...] -= solver.net.layers[k].blobs[0].diff 
     solver.net.layers[k].blobs[1].data[...] -= solver.net.layers[k].blobs[1].diff 

# save the weights to compare later 
w_fwdbwd_update = copy(solver.net.layers[1].blobs[0].data.astype('float64')) 
b_fwdbwd_update = copy(solver.net.layers[1].blobs[1].data.astype('float64')) 

# Compare 
print "after iter", niter, ": weight diff: ", np.linalg.norm(w_solver_step - w_fwdbwd_update), "and bias diff:", np.linalg.norm(b_solver_step - b_fwdbwd_update) 

二つの試験を用いて重みを比較し、最後の行が生成する:私はこの差が0.0

ことを期待したように

after iter 5 : weight diff: 0.000203027766144 and bias diff: 1.78390789051e-05

アイデア?

+0

あなたはsolver.prototxtゼロに[ 'weight_decay'](http://stackoverflow.com/q/32177764/1714410)を設定することがありますか? – Shai

+1

はい、以前言及していなかったが、 'weight_decay:0.0'が設定されています。何が起こっているかは、これらの2つのテストを1回だけ実行すると、すべてのレイヤーから正確に一致するウェイトベクトルが取得されますが、その後の繰り返しは取得されません。 – Aniket

+0

勾配の勢いがあるかもしれません。勢いを0に設定してみてください。 – mkuse

答えて

4

ほとんどの場合、各更新後に差分をゼロに設定するだけです。 Caffeはこれを自動的に実行して、バッチ蓄積を実装する機会を与えます(1回の重量更新で複数のバッチにグラデーションを適用します。これは、あなたのメモリが所望のバッチサイズに十分に大きくない場合に役立ちます)。別の可能な問題はcudnnの使用であってもよい

、畳み込みの実装は、非決定論的である(又は正確にカフェで使用するように設定されている方法)。 一般的に、これは問題ありませんが、あなたのケースでは毎回わずかに異なる結果が出るため、異なる重量が発生します。 cudnnでcaffeをコンパイルした場合は、テスト中に起こらないようにcpuにモードを設定するだけで済みます。

また、ソルバーパラメータは重量の更新に影響します。

  • lr_policy:あなたが述べたように、あなたが知っておくべき0
  • weight_decay:0
  • RANDOM_SEED:52#または任意の他の定数

  • 勢い "固定"ネットでは、学習率乗数を使用しないように注意してください。たいてい、バイアスはウェイトの2倍の速さで学習されますが、これは実装した動作ではありません。だから、層の定義の1にそれらを設定してくださいする必要があります。

    param { 
        lr_mult: 1 # weight lr multiplier 
        } 
    param { 
        lr_mult: 1 # bias lr multiplier 
        } 
    

    なく、少なくとも最後に、あなたのコードは勢い、重量崩壊とlr_multと同じようにどのように見えるかをここでの例。 CPUモードでは、これは予想される出力(なしの違い)を生成します。

    import caffe 
    caffe.set_device(0) 
    caffe.set_mode_cpu() 
    import numpy as np 
    
    niter = 5 
    solver = None 
    solver = caffe.SGDSolver('solver.prototxt') 
    
    # Automatic SGD: TEST2 
    solver.step(niter) 
    # save the weights to compare later 
    w_solver_step = solver.net.layers[1].blobs[0].data.copy() 
    b_solver_step = solver.net.layers[1].blobs[1].data.copy() 
    
    # Manual SGD: TEST1 
    solver = None 
    solver = caffe.SGDSolver('solver.prototxt') 
    base_lr = 0.01 
    momentum = 0.9 
    weight_decay = 0.0005 
    lr_w_mult = 1 
    lr_b_mult = 2 
    
    momentum_hist = {} 
    for layer in solver.net.params: 
        m_w = np.zeros_like(solver.net.params[layer][0].data) 
        m_b = np.zeros_like(solver.net.params[layer][1].data) 
        momentum_hist[layer] = [m_w, m_b] 
    
    for i in range(niter): 
        solver.net.forward() 
        solver.net.backward() 
        for layer in solver.net.params: 
         momentum_hist[layer][0] = momentum_hist[layer][0] * momentum + (solver.net.params[layer][0].diff + weight_decay * 
                     solver.net.params[layer][0].data) * base_lr * lr_w_mult 
         momentum_hist[layer][1] = momentum_hist[layer][1] * momentum + (solver.net.params[layer][1].diff + weight_decay * 
                     solver.net.params[layer][1].data) * base_lr * lr_b_mult 
         solver.net.params[layer][0].data[...] -= momentum_hist[layer][0] 
         solver.net.params[layer][1].data[...] -= momentum_hist[layer][1] 
         solver.net.params[layer][0].diff[...] *= 0 
         solver.net.params[layer][1].diff[...] *= 0 
    
    # save the weights to compare later 
    w_fwdbwd_update = solver.net.layers[1].blobs[0].data.copy() 
    b_fwdbwd_update = solver.net.layers[1].blobs[1].data.copy() 
    
    # Compare 
    print "after iter", niter, ": weight diff: ", np.linalg.norm(w_solver_step - w_fwdbwd_update), "and bias diff:", np.linalg.norm(b_solver_step - b_fwdbwd_update) 
    
  • 関連する問題