public function back(Deferred $prevGradient, Optimizer $optimizer) : Deferred
    {
        if (!$this->beta or !$this->gamma) {
            throw new RuntimeException('Layer has not been initilaized.');
        }

        if (!$this->stdInv or !$this->xHat) {
            throw new RuntimeException('Must perform forward pass before'
                . ' backpropagating.');
        }

        $dOut = $prevGradient->result();

        $dBeta = $dOut->sum();
        $dGamma = $dOut->multiply($this->xHat)->sum();

        $gamma = $this->gamma->w();

        $optimizer->step($this->beta, $dBeta);
        $optimizer->step($this->gamma, $dGamma);

        $stdInv = $this->stdInv;
        $xHat = $this->xHat;

        unset($this->stdInv, $this->xHat);

        return new Deferred(function () use ($dOut, $gamma, $stdInv, $xHat) {
            $dXHat = $dOut->multiply($gamma);

            $xHatSigma = $dXHat->multiply($xHat)->sum();

            $dXHatSigma = $dXHat->sum();

            return $dXHat->multiply($dOut->m())
                ->subtract($dXHatSigma)
                ->subtract($xHat->multiply($xHatSigma))
                ->multiply($stdInv->divide($dOut->m()));
        });
    }
public function back(Deferred $prevGradient, Optimizer $optimizer) : Deferred
    {
        if (!$this->beta or !$this->gamma) {
            throw new RuntimeException('Layer has not been initilaized.');
        }

        if (!$this->stdInv or !$this->xHat) {
            throw new RuntimeException('Must perform forward pass before'
                . ' backpropagating.');
        }

        $dOut = $prevGradient->result();

        $dBeta = $dOut->sum();
        $dGamma = $dOut->multiply($this->xHat)->sum();

        $gamma = $this->gamma->w();

        $optimizer->step($this->beta, $dBeta);
        $optimizer->step($this->gamma, $dGamma);

        $stdInv = $this->stdInv;
        $xHat = $this->xHat;

        unset($this->stdInv, $this->xHat);

        return new Deferred(function () use ($dOut, $gamma, $stdInv, $xHat) {
            $dXHat = $dOut->multiply($gamma);

            $xHatSigma = $dXHat->multiply($xHat)->sum();

            $dXHatSigma = $dXHat->sum();

            return $dXHat->multiply($dOut->m())
                ->subtract($dXHatSigma)
                ->subtract($xHat->multiply($xHatSigma))
                ->multiply($stdInv->divide($dOut->m()));
        });
    }
public function back ( Deferred $ prevGradient , Optimizer $ optimizer ) : Deferred { if ( ! $ this -> beta or ! $ this -> gamma ) { throw new RuntimeException ( 'Layer has not been initilaized.' ) ; } if ( ! $ this -> stdInv or ! $ this -> xHat ) { throw new RuntimeException ( 'Must perform forward pass before' . ' backpropagating.' ) ; } $ dOut = $ prevGradient -> result ( ) ; $ dBeta = $ dOut -> sum ( ) ; $ dGamma = $ dOut -> multiply ( $ this -> xHat ) -> sum ( ) ; $ gamma = $ this -> gamma -> w ( ) ; $ optimizer -> step ( $ this -> beta , $ dBeta ) ; $ optimizer -> step ( $ this -> gamma , $ dGamma ) ; $ stdInv = $ this -> stdInv ; $ xHat = $ this -> xHat ; unset ( $ this -> stdInv , $ this -> xHat ) ; return new Deferred ( function ( ) use ( $ dOut , $ gamma , $ stdInv , $ xHat ) { $ dXHat = $ dOut -> multiply ( $ gamma ) ; $ xHatSigma = $ dXHat -> multiply ( $ xHat ) -> sum ( ) ; $ dXHatSigma = $ dXHat -> sum ( ) ; return $ dXHat -> multiply ( $ dOut -> m ( ) ) -> subtract ( $ dXHatSigma ) -> subtract ( $ xHat -> multiply ( $ xHatSigma ) ) -> multiply ( $ stdInv -> divide ( $ dOut -> m ( ) ) ) ; } ) ; }
Calculate the errors and gradients of the layer and update the parameters.

@param \Rubix\ML\NeuralNet\Deferred $prevGradient
@param \Rubix\ML\NeuralNet\Optimizers\Optimizer $optimizer
@throws \RuntimeException
@return \Rubix\ML\NeuralNet\Deferred
Calculate the errors and gradients of the layer and update the parameters .