Introduction to ADAM

Hello! Today, we will explore the ADAM (Adaptive Moment Estimation) algorithm. This advanced optimization algorithm is a favorite among machine learning practitioners as it combines the advantages of two other extensions of Stochastic Gradient Descent (SGD): Root Mean Square Propagation (RMSprop) and Adaptive Gradient Algorithm (AdaGrad). Our primary focus today is understanding ADAM, and we will also build it from scratch in Python to optimize multivariable functions.

Understanding ADAM

Before we dive into ADAM, let us recall that classic gradient descent methods like SGD and even sophisticated versions like Momentum and RMSProp have some limitations. These limitations relate to sensitivity to learning rates, the issue of vanishing gradients, and the absence of individual adaptive learning rates for different parameters.

ADAM, a promising choice for an optimization algorithm, combines the merits of RMSProp and AdaGrad. It maintains a per-parameter learning rate adapted based on the average of recent magnitudes of the gradients for the weights (similar to RMSProp) and the average of recent gradients (like Momentum). This mechanism enables the algorithm to traverse quickly over the low gradient regions and slow down near the optimal points.

ADAM Mathematically
ADAM in Python Code

Let's now consolidate the ADAM concept into Python code. We will define an ADAM function, which takes the gradients, the decay rates beta1 and beta2, a numerical constant epsilon, the learning rate, and previous estimates of m and v (initialized to 0) as input and returns the updated parameters, along with the updated m and v.

def ADAM(beta1, beta2, epsilon, grad, m_prev, v_prev, learning_rate):
    # Update biased first-moment estimate
    m = beta1 * m_prev + (1 - beta1) * grad

    # Update biased second raw moment estimate
    v = beta2 * v_prev + (1 - beta2) * np.power(grad, 2)

    # Calculate updates
    updates = learning_rate * m / (np.sqrt(v) + epsilon)
    return updates, m, v

v and m are initialized with zeros and therefore they are biased towards zero at the start of the optimization, especially when the decay rates are small (beta1 and beta2 close to 1).

To counteract these biases, Adam also usually includes the correction terms m_hat and v_hat. These terms adjust m and v by an amount that lessens as the number of time steps increases:

m_hat = m / (1 - np.power(beta1, epoch+1))  # Correcting the bias for the first moment
v_hat = v / (1 - np.power(beta2, epoch+1))  # Correcting the bias for the second moment

updates = learning_rate * m_hat / (np.sqrt(v_hat) + epsilon)
return updates, m, v

Note that we still return plain m and v.

Sign up
Join the 1M+ learners on CodeSignal
Be a part of our community of 1M+ users who develop and demonstrate their skills on CodeSignal