【问题标题】:Implementing the Rprop algorithm in Keras在 Keras 中实现 Rprop 算法
【发布时间】:2017-10-01 18:41:44
【问题描述】:

我正在尝试为 Keras (link) 实现弹性反向传播优化器,但具有挑战性的部分是能够根据其对应的梯度是正、负还是零对每个单独的参数执行更新。我编写了下面的代码作为实现 Rprop 优化器的开始。但是,我似乎找不到单独访问参数的方法。循环遍历params(如下面的代码)在每次迭代时返回p, g, g_old, s, wChangeOld,它们都是矩阵。

有没有一种方法可以迭代各个参数并更新它们?如果我可以根据其梯度的符号索引参数向量,它也会起作用。

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()))

【问题讨论】:

  • 这里不需要 K.switch(K.equal(change,0)...) 而不是 if/elif/else 吗?

标签: python tensorflow neural-network keras theano


【解决方案1】:

我也在 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 内置)优于此 RProp 算法。也许是因为事情就是这样,也许是因为我犯了一个错误:)

关于您的代码的一些 cmets(指您的原始变量名称):

  • wChange 从不跨迭代使用,因此您不需要将它们存储在永久变量中。
  • change &gt; 0 不会做你认为它做的事情,因为change 是一个张量变量。您需要的是逐元素比较,请改用 K.switch()
  • 您使用了两次maxStep,而不是另一次使用minStep
  • change 为零的情况可以忽略不计,因为这在实践中几乎从未发生过。
  • g_new = 0g_new = p 都是完全伪造的,应该是 g_new = g,就像第一个 if 分支一样。

【讨论】:

  • 你能解释一下如何使用这段代码吗?我应该将它添加到 Keras 的源代码中,还是将其包含在我自己的项目中。但这是一堂课,我该怎么办?非常感谢!
  • @HongCheng 不要将它添加到 Keras,而是将其添加到您自己的项目中。然后,当您构建模型后,请致电 mymodel.compile(optimizer=RProp(...), ...)。为了使其在保存后重新加载模型时也能正常工作,您可能还必须使用 custom_objects 参数到 load_model()
  • @jlh 我将文件(作为rprop.py)添加到存储所有.py 优化器的代码库中,我试图在我的模型中将它引用为optimizer=rprop 但我想我'我错过了一个实例化步骤,我该怎么办?谢谢!
【解决方案2】:

我是 keras 和 Python 的新手,但为了我的目的,我稍微修改了上面的代码。

由于使用了全批学习和偏导数,这是一种非常快速和简单的算法。在我的测试中,它优于所有其他反向传播算法,包括 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()))

【讨论】:

  • 我尝试使用它。但我收到错误:TypeError: get_updates() 恰好需要 3 个参数(给定 4 个)
猜你喜欢
  • 2014-09-26
  • 2020-11-09
  • 2020-09-29
  • 2017-03-07
  • 2017-06-28
  • 2019-07-03
  • 2017-09-30
  • 1970-01-01
  • 2022-06-14
相关资源
最近更新 更多