Files
2026-07-13 13:30:25 +08:00

102 lines
3.1 KiB
Python
Executable File

import numpy as np
from prml.nn.optimizer.optimizer import Optimizer
class Eve(Optimizer):
"""
Eve optimizer
initialization
m1 = 0 (initial 1st moment of gradient)
m2 = 0 (initial 2nd moment of gradient)
n_iter = 0
update rule
n_iter += 1
learning
"""
def __init__(self,
network,
learning_rate=0.001,
beta1=0.9,
beta2=0.999,
beta3=0.999,
lower_threshold=0.1,
upper_threshold=10.,
epsilon=1e-8):
"""
construct Eve optimizer
Parameters
----------
network : Network
neural network to be optmized
learning_rate : float
beta1 : float
exponential decay rate for the 1st moment
beta2 : float
exponential decay rate for the 2nd moment
beta3 : float
exponential decay rate for computing relative change
lower_threshold : float
lower threshold for relative change
upper_threshold : float
upper threshold for relative change
epsilon : float
small constant to be added to denominator for numerical stability
Attributes
----------
n_iter : int
number of iterations performed
moment1 : dict
1st moment of each parameter
moment2 : dict
2nd moment of each parameter
"""
super().__init__(network, learning_rate)
self.beta1 = beta1
self.beta2 = beta2
self.beta3 = beta3
self.lower_threshold = lower_threshold
self.upper_threshold = upper_threshold
self.epsilon = epsilon
self.moment1 = {}
self.moment2 = {}
self.f = 1.
self.d = 1.
for key, param in self.params.items():
self.moment1[key] = np.zeros(param.shape)
self.moment2[key] = np.zeros(param.shape)
def update(self, loss):
loss = float(loss)
self.increment_iteration()
if self.n_iter > 1:
if loss > self.f:
delta = self.lower_threshold + 1
Delta = self.upper_threshold + 1
else:
delta = 1 / (self.upper_threshold + 1)
Delta = 1 / (self.lower_threshold + 1)
c = min(max(delta, loss / self.f), Delta)
f = c * self.f
r = abs(f - self.f) / min(f, self.f)
self.d = self.beta3 * self.d * (1 - self.beta3) * r
self.f = f
else:
self.f = loss
self.d = 1
lr = (
self.learning_rate
* (1 - self.beta2 ** self.n_iter) ** 0.5
/ (1 - self.beta1 ** self.n_iter)
)
for key, param in self.params.items():
m1 = self.moment1[key]
m2 = self.moment2[key]
m1 += (1 - self.beta1) * (param.grad - m1)
m2 += (1 - self.beta2) * (param.grad ** 2 - m2)
param.value -= lr * m1 / (self.d * np.sqrt(m2) + self.epsilon)