2016-09-07 5 views
1

単純なリカレントニューラルネットワーク用のコードがいくつかありますが、私の更新段階に必要なコードの量を減らす方法があるかどうかを知りたいと思っています。私はそうしていたコード:#RMSProp下のすべての変数についてRMSPropのコード量を減らす方法はありますか

class RNN(object): 
    def__init___(self, data, hidden_size, eps=0.0001): 
     self.data = data 
     self.hidden_size = hidden_size 
     self.weights_hidden = np.random.rand(hidden_size, hidden_size) * 0.1 # W 
     self.weights_input = np.random.rand(hidden_size, len(data[0])) * 0.1 # U 
     self.weights_output = np.random.rand(len(data[0]), hidden_size) * 0.1 # V 
     self.bias_hidden = np.array([np.random.rand(hidden_size)]).T # b 
     self.bias_output = np.array([np.random.rand(len(data[0]))]).T # c 

     self.cache_w_hid, self.cache_w_in, self.cache_w_out = 0, 0, 0 
     self.cache_b_hid, self.cache_b_out = 0, 0 
     self.eps = eps 

    def train(self, seq_length, epochs, eta, decay_rate=0.9, learning_decay=0.0): 
     # Other stuff 
     self.update(seq, epoch, eta, decay_rate, learning_decay) 
     # Other Stuff 

    def update(self, seq, epoch, eta, decay_rate, learning_decay): 
     """Updates the network's weights and biases by applying gradient 
     descent using backpropagation through time and RMSPROP. 
     """ 
     delta_nabla_c, delta_nabla_b,\ 
     delta_nabla_V, delta_nabla_W, delta_nabla_U = self.backward_pass(seq) 

     eta = eta*np.exp(-epoch*learning_decay) 

     self.cache_w_hid += decay_rate * self.cache_w_hid \ 
          + (1 - decay_rate) * delta_nabla_W**2 
     self.weights_hidden -= eta * delta_nabla_W/(np.sqrt(self.cache_w_hid) + self.eps) 

     self.cache_w_in += decay_rate * self.cache_w_in \ 
          + (1 - decay_rate) * delta_nabla_U**2   
     self.weights_input -= eta * delta_nabla_U/(np.sqrt(self.cache_w_in) + self.eps) 

     self.cache_w_out += decay_rate * self.cache_w_out \ 
          + (1 - decay_rate) * delta_nabla_V**2 
     self.weights_output -= eta * delta_nabla_V/(np.sqrt(self.cache_w_out) + self.eps) 

     self.cache_b_hid += decay_rate * self.cache_b_hid \ 
          + (1 - decay_rate) * delta_nabla_b**2 
     self.bias_hidden -= eta * delta_nabla_b/(np.sqrt(self.cache_b_hid) + self.eps) 

     self.cache_b_out += decay_rate * self.cache_b_out \ 
          + (1 - decay_rate) * delta_nabla_c**2 
     self.bias_output -= eta * delta_nabla_c/(np.sqrt(self.cache_b_out) + self.eps) 

、すなわち、更新規則に従います:

cache = decay_rate * cache + (1 - decay_rate) * dx**2 
x += - learning_rate * dx/(np.sqrt(cache) + eps) 

私はself.weight_self.bias_が続き、これが書かれていたいcache_すべて宣言していますよりコンパクトに。私はzip()を使用して見ていたが、私はそれについてどうやって行くのか分からない。

+1

このコードはどこですか?スクリプト/モジュール、クラス、関数では? 'self'の使用はメソッドを示しますが、' cache_w_hid'のようなグローバルの使用はモジュールまたはクラスを指しています。 –

+0

私はあなたが何を意味するかあまりにも分かりません。私はこれを書いて、クラスがどのようにPythonで動作するかをよりよく理解するようにしました。コードのその部分がどこにあるのかを関数全体に含めるように投稿を更新しました。 'cache_'は' def update'にのみあり、クラス全体にはありません。 – Lukasz

+1

それは私の質問に完全に答えます。ありがとう。今すぐ答えよ。 –

答えて

1

あなたの質問から判断すると、ここでは他の種類の最適化よりも読みやすさ/優雅さを向上させようとしていると推測しています。

更新ルールを実装する関数を導入し、変数ごとに1回呼び出すことができます。ここでのトリックは、Pythonでは名前で属性にアクセスできるので、値の代わりにキャッシュと重み属性の名前を渡すことができます。これは、あなたが将来のパスのための値を更新できるようになる:

def update_rule(self, cache_attr, x_attr, decay_rate, learning_rate, dx): 
    cache = getattr(self, cache_attr) 
    cache = decay_rate * cache + (1 - decay_rate) * dx**2 
    setattr(self, cache_attr, cache) 

    x = getattr(self, x_attr) 
    x += - learning_rate * dx/(np.sqrt(cache) + self.eps) 
    setattr(self, x_attr, x) 

def update(self, seq, epoch, eta, decay_rate, learning_decay): 
    """Updates the network's weights and biases by applying gradient 
    descent using backpropagation through time and RMSPROP. 
    """ 
    delta_nabla_c, delta_nabla_b,\ 
    delta_nabla_V, delta_nabla_W, delta_nabla_U = self.backward_pass(seq) 

    eta = eta*np.exp(-epoch*learning_decay) 

    self.update_rule('cache_w_hid', 'weights_hidden', decay_rate, eta, delta_nabla_W) 
    self.update_rule('cache_w_in', 'weights_input', decay_rate, eta, delta_nabla_U) 
    self.update_rule('cache_w_out', 'weights_output', decay_rate, eta, delta_nabla_V) 
    self.update_rule('cache_b_hid', 'bias_hidden', decay_rate, eta, delta_nabla_b) 
    self.update_rule('cache_b_out', 'bias_output', decay_rate, eta, delta_nabla_c) 

実際には、追加のパラメータを保存して、基本的にupdateupdate_ruleを入れることで、民間の方法が何であるかを公開しないようすることができます。それが呼び出されたときに、あなたが持っていないので、これはdecay_ratelearning_rateに渡すために、update_ruleからupdateの名前空間を公開します:あなたが本当に望んでいた場合

def update(self, seq, epoch, eta, decay_rate, learning_decay): 
    """Updates the network's weights and biases by applying gradient 
    descent using backpropagation through time and RMSPROP. 
    """ 

    def update_rule(cache_attr, x_attr, dx): 
     cache = getattr(self, cache_attr) 
     cache = decay_rate * cache + (1 - decay_rate) * dx**2 
     setattr(self, cache_attr, cache) 

     x = getattr(self, x_attr) 
     x += - eta * dx/(np.sqrt(cache) + self.eps) 
     setattr(self, x_attr, x) 

    delta_nabla_c, delta_nabla_b,\ 
    delta_nabla_V, delta_nabla_W, delta_nabla_U = self.backward_pass(seq) 

    eta = eta*np.exp(-epoch*learning_decay) 

    update_rule('cache_w_hid', 'weights_hidden', delta_nabla_W) 
    update_rule('cache_w_in', 'weights_input', delta_nabla_U) 
    update_rule('cache_w_out', 'weights_output', delta_nabla_V) 
    update_rule('cache_b_hid', 'bias_hidden', delta_nabla_b) 
    update_rule('cache_b_out', 'bias_output', delta_nabla_c) 

最後に、あなたがupdate_ruleに電話を入れてzipを使用することができますループに入る。このバージョンでは、呼び出しの順序がself.backward_passによって返された値の順序と一致するように変更されていることに注意してください。個人的には、backward_passの結果に非常に敏感であるという事実に加えて、難読化され始めているため、本当に多くの更新がない限り、この最後のバージョンは使用しません。

def update(self, seq, epoch, eta, decay_rate, learning_decay): 
    """Updates the network's weights and biases by applying gradient 
    descent using backpropagation through time and RMSPROP. 
    """ 

    def update_rule(cache_attr, x_attr, dx): 
     cache = getattr(self, cache_attr) 
     cache = decay_rate * cache + (1 - decay_rate) * dx**2 
     setattr(self, cache_attr, cache) 

     x = getattr(self, x_attr) 
     x += - eta * dx/(np.sqrt(cache) + self.eps) 
     setattr(self, x_attr, x) 

    dx = self.backward_pass(seq) 

    eta = eta*np.exp(-epoch*learning_decay) 

    cache_attrs = ('cache_b_out', 'cache_b_hid', 'cache_w_out', 'cache_w_hid', 'cache_w_in') 
    x_attrs = ('bias_output', 'bias_hidden', 'weights_output', 'weights_hidden', 'weights_input') 

    for args in zip(cache_attrs, x_attrs, dx): 
     update_rule(*args) 
関連する問題