Source code for arsenal.maths.stepsize
"""
Adaptive stepsize algorithms
"""
import numpy as np
__author__ = 'Tim Vieira (http://timvieira.github.io)'
[docs]def norm_clip(x, C):
"Rescale x (in place) so that ||x|| <= C."
z = np.linalg.norm(x)
if z > C:
x[:] *= C/z
[docs]def ewma(x, y, alpha):
"Exponentially weighted moving average (`x` is updated in place)."
x[:] *= (1-alpha)
x[:] += alpha*y
[docs]class adagrad(object):
"""
Adagrad
"""
def __init__(self, x, damping = 1e-4):
self.x = x
self.G = np.zeros_like(x) + damping
self.i = 0
self.D = None
def __call__(self, g, learning_rate=1.0):
# Update parameters
self.G += g*g
self.D = learning_rate/np.sqrt(self.G)
self.x[:] -= g * self.D
self.i += 1
[docs]class sgd(object):
"""
Simple sgd
"""
def __init__(self, x):
self.x = x
self.i = 0
def __call__(self, g, learning_rate=1.0):
self.x[:] -= g * learning_rate
self.i += 1
[docs]class adam(object):
"""
Adam as described in http://arxiv.org/pdf/1412.6980.pdf.
"""
def __init__(self, x):
self.x = x
self.m = np.zeros_like(x)
self.v = np.zeros_like(x)
self.i = 1
self.D = None
def __call__(self, g, learning_rate=0.01, b1 = 0.1, b2 = 0.01, lam=1e-4, damping=1e-4):
i = self.i
b1t = 1 - (1-b1)*(lam**i) # b1t -> 1 over time
# Update first moment estimate
ewma(self.m, g, b1t)
# Update second moment estimate
ewma(self.v, g*g, b2)
# Bias correction.
mhat = self.m / (1 - (1-b1)**i)
vhat = self.v / (1 - (1-b2)**i)
# Take step
self.x[:] -= learning_rate*mhat/(np.sqrt(vhat) + damping)
self.i += 1
[docs]class sgd_momentum(object):
def __init__(self, x):
self.velocity = np.zeros(len(x))
self.x = x
def __call__(self, g, mass=0.9, learning_rate=0.1):
self.velocity[:] = mass * self.velocity - (1.0 - mass) * g
self.x[:] += learning_rate * self.velocity