2017-05-03 16 views
3

我正在嘗試爲Keras(link)實現彈性反向傳播優化程序,但是具有挑戰性的部分是能夠根據每個參數的相應梯度是否爲正值來執行更新,負數或零。我編寫了下面的代碼作爲實現Rprop優化器的開始。但是,我似乎無法找到單獨訪問參數的方法。循環遍歷params(如下面的代碼所示)在每次迭代時返回p, g, g_old, s, wChangeOld,它們都是矩陣。Keras - 執行Rprop算法的問題

有沒有一種方法可以迭代各個參數並更新它們?如果我可以根據其漸變的符號對參數向量進行索引,它也可以工作。謝謝!

class Rprop(Optimizer): 
    def __init__(self, init_step=0.01, **kwargs): 
     super(Rprop, self).__init__(**kwargs) 
     self.init_step = K.variable(init_step, name='init_step') 
     self.iterations = K.variable(0., name='iterations') 

     self.posStep = 1.2 
     self.negStep = 0.5 
     self.minStep = 1e-6 
     self.maxStep = 50. 

    def get_updates(self, params, constraints, loss): 
     grads = self.get_gradients(loss, params) 
     self.updates = [K.update_add(self.iterations, 1)] 

     shapes = [K.get_variable_shape(p) for p in params] 
     stepList = [K.ones(shape)*self.init_step for shape in shapes] 
     wChangeOldList = [K.zeros(shape) for shape in shapes] 
     grads_old = [K.zeros(shape) for shape in shapes] 

     self.weights = stepList + grads_old + wChangeOldList 
     self.updates = [] 

     for p, g, g_old, s, wChangeOld in zip(params, grads, grads_old, 
                    stepList, wChangeOldList): 
      change = K.sign(g * g_old) 

      if change > 0: 
       s_new = K.minimum(s * self.posStep, self.maxStep) 
       wChange = s_new * K.sign(g) 
       g_new = g 

      elif change < 0: 
       s_new = K.maximum(s * self.posStep, self.maxStep) 
       wChange = - wChangeOld 
       g_new = 0 

      else: 
       s_new = s 
       wChange = s_new * K.sign(g) 
       g_new = p 

      self.updates.append(K.update(g_old, g_new)) 
      self.updates.append(K.update(wChangeOld, wChange)) 
      self.updates.append(K.update(s, s_new)) 

      new_p = p - wChange 

      # Apply constraints 
      if p in constraints: 
       c = constraints[p] 
       new_p = c(new_p) 

      self.updates.append(K.update(p, new_p)) 
     return self.updates 

    def get_config(self): 
     config = {'init_step': float(K.get_value(self.init_step))} 
     base_config = super(Rprop, self).get_config() 
     return dict(list(base_config.items()) + list(config.items())) 
+0

你不需要K.switch(K.equal(其他城市,0),......),而不是在這裏,如果/ elif的/別的嗎? – gkcn

回答

0

我在Keras尋找RProp算法,並發現了這個問題。我冒昧地將您的代碼調整到我的目的,並立即將其發回。到目前爲止,它似乎工作得很好,但我沒有廣泛地測試它。

聲明:我對keras很新,但對theano(和塊)有很多經驗。此外,我只用theano作爲後端測試了這一點,但沒有測試tensorflow。

class RProp(Optimizer): 
    def __init__(self, init_alpha=1e-3, scale_up=1.2, scale_down=0.5, min_alpha=1e-6, max_alpha=50., **kwargs): 
     super(RProp, self).__init__(**kwargs) 
     self.init_alpha = K.variable(init_alpha, name='init_alpha') 
     self.scale_up = K.variable(scale_up, name='scale_up') 
     self.scale_down = K.variable(scale_down, name='scale_down') 
     self.min_alpha = K.variable(min_alpha, name='min_alpha') 
     self.max_alpha = K.variable(max_alpha, name='max_alpha') 

    def get_updates(self, params, constraints, loss): 
     grads = self.get_gradients(loss, params) 
     shapes = [K.get_variable_shape(p) for p in params] 
     alphas = [K.variable(numpy.ones(shape) * self.init_alpha) for shape in shapes] 
     old_grads = [K.zeros(shape) for shape in shapes] 
     self.weights = alphas + old_grads 
     self.updates = [] 

     for param, grad, old_grad, alpha in zip(params, grads, old_grads, alphas): 
      new_alpha = K.switch(
       K.greater(grad * old_grad, 0), 
       K.minimum(alpha * self.scale_up, self.max_alpha), 
       K.maximum(alpha * self.scale_down, self.min_alpha) 
      ) 
      new_param = param - K.sign(grad) * new_alpha 
      # Apply constraints 
      if param in constraints: 
       c = constraints[param] 
       new_param = c(new_param) 
      self.updates.append(K.update(param, new_param)) 
      self.updates.append(K.update(alpha, new_alpha)) 
      self.updates.append(K.update(old_grad, grad)) 

     return self.updates 

    def get_config(self): 
     config = { 
      'init_alpha': float(K.get_value(self.init_alpha)), 
      'scale_up': float(K.get_value(self.scale_up)), 
      'scale_down': float(K.get_value(self.scale_down)), 
      'min_alpha': float(K.get_value(self.min_alpha)), 
      'max_alpha': float(K.get_value(self.max_alpha)), 
     } 
     base_config = super(RProp, self).get_config() 
     return dict(list(base_config.items()) + list(config.items())) 

重要提示:

  • RPROP通常不包括在是有原因的機器學習庫:除非你用全批學習它不會在所有的工作。如果你有一個小的訓練集,全批次學習只是有用的。
  • Adam(Keras builtin)優於此RProp算法。也許是因爲這只是它是如何,或者也許是因爲我犯了一個錯誤:)

你的代碼的一些意見(指原來的變量名):

  • wChange永遠不會通過重複使用,所以你不需要將它們存儲在永久變量中。
  • change > 0不符合您的想法,因爲change是張量變量。你想要的是一個元素明智的比較,用K.switch()代替。
  • 您使用了maxStep兩次,而不是在另一次使用minStep
  • change爲零的情況可以忽略不計,因爲在實踐中幾乎不會發生這種情況。
  • g_new = 0g_new = p都是完全假的,應該是g_new = g,就像在第一個if分支一樣。
0

我是新來的keras和Pyhton,但我修改了上面的代碼爲我的目的了一下。 由於使用全批次學習和偏導數,這是非常快速和簡單的算法。在我的測試中,它超越了所有其他反向傳播算法,包括Adam。我用Tensorflow和CNTK作爲後端進行了測試。

修改RPROP不重回溯: https://pdfs.semanticscholar.org/df9c/6a3843d54a28138a596acc85a96367a064c2.pdf

class iRprop_(Optimizer): 
def __init__(self, init_alpha=0.01, scale_up=1.2, scale_down=0.5, min_alpha=0.00001, max_alpha=50., **kwargs): 
    super(iRprop_, self).__init__(**kwargs) 
    self.init_alpha = K.variable(init_alpha, name='init_alpha') 
    self.scale_up = K.variable(scale_up, name='scale_up') 
    self.scale_down = K.variable(scale_down, name='scale_down') 
    self.min_alpha = K.variable(min_alpha, name='min_alpha') 
    self.max_alpha = K.variable(max_alpha, name='max_alpha') 

def get_updates(self, params, loss): 
    grads = self.get_gradients(loss, params) 
    shapes = [K.get_variable_shape(p) for p in params] 
    alphas = [K.variable(K.ones(shape) * self.init_alpha) for shape in shapes] 
    old_grads = [K.zeros(shape) for shape in shapes] 
    self.weights = alphas + old_grads 
    self.updates = [] 

    for p, grad, old_grad, alpha in zip(params, grads, old_grads, alphas): 
     grad = K.sign(grad) 
     new_alpha = K.switch(
      K.greater(grad * old_grad, 0), 
      K.minimum(alpha * self.scale_up, self.max_alpha), 
      K.switch(K.less(grad * old_grad, 0),K.maximum(alpha * self.scale_down, self.min_alpha),alpha)  
     ) 

     grad = K.switch(K.less(grad * old_grad, 0),K.zeros_like(grad),grad) 
     new_p = p - grad * new_alpha 

     # Apply constraints. 
     if getattr(p, 'constraint', None) is not None: 
      new_p = p.constraint(new_p) 
     self.updates.append(K.update(p, new_p)) 
     self.updates.append(K.update(alpha, new_alpha)) 
     self.updates.append(K.update(old_grad, grad)) 

    return self.updates 

def get_config(self): 
    config = { 
     'init_alpha': float(K.get_value(self.init_alpha)), 
     'scale_up': float(K.get_value(self.scale_up)), 
     'scale_down': float(K.get_value(self.scale_down)), 
     'min_alpha': float(K.get_value(self.min_alpha)), 
     'max_alpha': float(K.get_value(self.max_alpha)), 
    } 
    base_config = super(iRprop_, self).get_config() 
    return dict(list(base_config.items()) + list(config.items())) 
+0

我試過使用它。但我得到的錯誤:TypeError:get_updates()只需要3個參數(給出4) –