Adam(parameters: list[Variable], lr: float = 0.001, beta1: float = 0.9, beta2: float = 0.999, eps: float = 1e-08, weight_decay: float = 0.0)
Adam optimiser (Kingma & Ba, 2015).
Parameters
parameters : list of Variable
lr : step size (α)
beta1 : first-moment decay (default 0.9)
beta2 : second-moment decay (default 0.999)
eps : numerical stability term (default 1e-8)
weight_decay : L2 regularisation coefficient
Source code in MiniTorch/optim/adam.py
| def __init__(
self,
parameters: list[Variable],
lr: float = 1e-3,
beta1: float = 0.9,
beta2: float = 0.999,
eps: float = 1e-8,
weight_decay: float = 0.0,
) -> None:
self.parameters = parameters
self.lr = lr
self.beta1 = beta1
self.beta2 = beta2
self.eps = eps
self.weight_decay = weight_decay
self.t: int = 0
self._m: list[np.ndarray] = [np.zeros_like(p.data) for p in parameters]
self._v: list[np.ndarray] = [np.zeros_like(p.data) for p in parameters]
self._scratch: list[np.ndarray] = [
np.empty_like(p.data) for p in parameters
]
|
step
Source code in MiniTorch/optim/adam.py
| def step(self) -> None:
self.t += 1
lr_t = (
self.lr
* math.sqrt(1 - self.beta2 ** self.t)
/ (1 - self.beta1 ** self.t)
)
for i, p in enumerate(self.parameters):
if p.grad is None:
continue
g: np.ndarray = p.grad.data # type: ignore[assignment]
if self.weight_decay != 0:
g = g + self.weight_decay * p.data # type: ignore[operator]
first_moment = self._m[i]
second_moment = self._v[i]
scratch = self._scratch[i]
first_moment *= self.beta1
first_moment += (1 - self.beta1) * g
second_moment *= self.beta2
np.multiply(g, g, out=scratch)
second_moment += (1 - self.beta2) * scratch
np.sqrt(second_moment, out=scratch)
scratch += self.eps
np.divide(first_moment, scratch, out=scratch)
scratch *= lr_t
p.data -= scratch # type: ignore[operator]
|
zero_grad
Source code in MiniTorch/optim/adam.py
| def zero_grad(self) -> None:
for p in self.parameters:
p.clear_grad()
|