$upper) { throw new InvalidArgumentException('Lower bound cannot be' . ' reater than the upper bound.'); } if ($losses < 1) { throw new InvalidArgumentException('The number of steps per' . " cycle must be greater than 0, $losses given."); } if ($decay <= 0.0 or $decay >= 1.0) { throw new InvalidArgumentException('Decay must be between' . " 0 and 1, $decay given."); } $this->lower = $lower; $this->upper = $upper; $this->range = $upper - $lower; $this->losses = $losses; $this->decay = $decay; } /** * 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 { $cycle = floor(1 + $this->t / (2 * $this->losses)); $x = abs($this->t / $this->losses - 2 * $cycle + 1); $scale = $this->decay ** $this->t; $rate = $this->lower + $this->range * max(0, 1 - $x) * $scale; ++$this->t; return $gradient->multiply($rate); } /** * Return the string representation of the object. * * @internal * * @return string */ public function __toString() : string { return "Cyclical (lower: {$this->lower}, upper: {$this->upper}," . " steps: {$this->losses}, decay: {$this->decay})"; } }