= 1.0) { throw new InvalidArgumentException('Decay must be between' . " 0 and 1, $decay given."); } $this->rate = $rate; $this->decay = $decay; $this->lookahead = $lookahead; } /** * Warm the cache. * * @internal * * @param Parameter $param * @throws RuntimeException */ public function warm(Parameter $param) : void { $class = get_class($param->param()); if ($class === false) { throw new RuntimeException('Could not locate parameter class.'); } $this->cache[$param->id()] = $class::zeros(...$param->param()->shape()); } /** * Take a step of gradient descent for a given parameter. * * @internal * * @param Parameter $param * @param Tensor $gradient * @return Tensor */ public function step(Parameter $param, Tensor $gradient) : Tensor { $velocity = $this->cache[$param->id()]; $velocity = $gradient->multiply($this->rate) ->add($velocity->multiply(1.0 - $this->decay)); $this->cache[$param->id()] = $velocity; if ($this->lookahead) { $velocity = $gradient->multiply($this->rate) ->add($velocity->multiply(1.0 - $this->decay)); } return $velocity; } /** * Return the string representation of the object. * * @internal * * @return string */ public function __toString() : string { return "Momentum (rate: {$this->rate}, decay: {$this->decay}," . ' lookahead: ' . Params::toString($this->lookahead) . ')'; } }