# --------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.
# --------------------------------------------------------------------------------------------
# - Generated by tools/entrypoint_compiler.py: do not edit by hand
"""
OnlineGradientDescentRegressor
"""

__all__ = ["OnlineGradientDescentRegressor"]


from ...core.loss.loss_factory import check_loss, create_loss
from ...entrypoints.trainers_onlinegradientdescentregressor import \
    trainers_onlinegradientdescentregressor
from ...utils.utils import trace
from ..base_pipeline_item import BasePipelineItem, DefaultSignatureWithRoles


class OnlineGradientDescentRegressor(
        BasePipelineItem,
        DefaultSignatureWithRoles):
    """

    Train a stochastic gradient descent model.

    .. remarks::
        Stochastic gradient descent uses a simple yet efficient iterative
        technique to fit model
        coefficients using error gradients for convex loss functions (see
        `Stochastic_gradient_descent
        <https://en.wikipedia.org/wiki/Stochastic_gradient_descent>`_).

        The ``OnlineGradientDescentRegressor`` implements the standard (non-
        batch) SGD, with a
        choice of loss functions, and an option to update the weight vector
        using the `average` of
        the vectors seen over time (``averaged`` argument is set to **True**
        by default).


        **Reference**

            `Stochastic_gradient_descent
            <https://en.wikipedia.org/wiki/Stochastic_gradient_descent>`_


    :param normalize: Specifies the type of automatic normalization used:

        * ``"Auto"``: if normalization is needed, it is performed
          automatically. This is the default choice.
        * ``"No"``: no normalization is performed.
        * ``"Yes"``: normalization is performed.
        * ``"Warn"``: if normalization is needed, a warning
          message is displayed, but normalization is not performed.

        Normalization rescales disparate data ranges to a standard scale.
        Feature
        scaling insures the distances between data points are proportional
        and
        enables various optimization methods such as gradient descent to
        converge
        much faster. If normalization is performed, a ``MaxMin`` normalizer
        is
        used. It normalizes values in an interval [a, b] where ``-1 <= a <=
        0``
        and ``0 <= b <= 1`` and ``b - a = 1``. This normalizer preserves
        sparsity by mapping zero to zero.

    :param caching: Whether trainer should cache input training data.

    :param loss: The default is :py:class:`'hinge' <nimbusml.loss.Hinge>`.
        Other choices are :py:class:`'exp' <nimbusml.loss.Exp>`,
        :py:class:`'log' <nimbusml.loss.Log>`, :py:class:`'smoothed_hinge'
        <nimbusml.loss.SmoothedHinge>`. For more information, please see
        :py:class:`'loss' <nimbusml.loss>`.

    :param learning_rate: Determines the size of the step taken in the
        direction of the gradient in each step of the learning process.  This
        determines how fast or slow the learner converges on the optimal
        solution. If the step size is too big, you might overshoot the optimal
        solution.  If the step size is too small, training takes longer to
        converge to the best solution.

    :param decrease_learning_rate: Decrease learning rate.

    :param l2_regularization: L2 Regularization Weight.

    :param number_of_iterations: Number of iterations.

    :param initial_weights_diameter: Sets the initial weights diameter that
        specifies the range from which values are drawn for the initial
        weights. These weights are initialized randomly from within this range.
        For example, if the diameter is specified to be ``d``, then the weights
        are uniformly distributed between ``-d/2`` and ``d/2``. The default
        value is ``0``, which specifies that all the  weights are set to zero.

    :param reset_weights_after_x_examples: Number of examples after which
        weights will be reset to the current average.

    :param lazy_update: Instead of updating averaged weights on every example,
        only update when loss is nonzero.

    :param recency_gain: Extra weight given to more recent updates
        (`do_lazy_updates`` must be **False**).

    :param recency_gain_multiplicative: Whether Recency Gain is multiplicative
        (vs. additive).

    :param averaged: Do averaging?.

    :param averaged_tolerance: The inexactness tolerance for averaging.

    :param initial_weights: Initial Weights and bias, comma-separated.

    :param shuffle: Whether to shuffle for each training iteration.

    :param params: Additional arguments sent to compute engine.

    .. seealso::
        :py:func:`FastLinearRegressor
        <nimbusml.linear_model.FastLinearRegressor>`,
        :py:func:`LightGbmRegressor <nimbusml.ensemble.LightGbmRegressor>`,
        :py:func:`FastForestRegressor <nimbusml.ensemble.FastForestRegressor>`,
        :py:func:`FastTreesRegressor <nimbusml.ensemble.FastTreesRegressor>`,
        :py:func:`GamRegressor <nimbusml.ensemble.GamRegressor>`.

    .. index:: models, stochastic, online, gradient, descent

    Example:
       .. literalinclude:: /../nimbusml/examples/OnlineGradientDescentRegressor.py
              :language: python
    """

    @trace
    def __init__(
            self,
            normalize='Auto',
            caching='Auto',
            loss='squared',
            learning_rate=0.1,
            decrease_learning_rate=True,
            l2_regularization=0.0,
            number_of_iterations=1,
            initial_weights_diameter=0.0,
            reset_weights_after_x_examples=None,
            lazy_update=True,
            recency_gain=0.0,
            recency_gain_multiplicative=False,
            averaged=True,
            averaged_tolerance=0.01,
            initial_weights=None,
            shuffle=True,
            **params):
        BasePipelineItem.__init__(
            self, type='regressor', **params)

        self.normalize = normalize
        self.caching = caching
        self.loss = loss
        check_loss(
            'RegressionLossFunction',
            self.__class__.__name__,
            self.loss)
        self.learning_rate = learning_rate
        self.decrease_learning_rate = decrease_learning_rate
        self.l2_regularization = l2_regularization
        self.number_of_iterations = number_of_iterations
        self.initial_weights_diameter = initial_weights_diameter
        self.reset_weights_after_x_examples = reset_weights_after_x_examples
        self.lazy_update = lazy_update
        self.recency_gain = recency_gain
        self.recency_gain_multiplicative = recency_gain_multiplicative
        self.averaged = averaged
        self.averaged_tolerance = averaged_tolerance
        self.initial_weights = initial_weights
        self.shuffle = shuffle

    @property
    def _entrypoint(self):
        return trainers_onlinegradientdescentregressor

    @trace
    def _get_node(self, **all_args):
        algo_args = dict(
            feature_column_name=self._getattr_role(
                'feature_column_name',
                all_args),
            label_column_name=self._getattr_role(
                'label_column_name',
                all_args),
            normalize_features=self.normalize,
            caching=self.caching,
            loss_function=create_loss(
                'RegressionLossFunction',
                self.__class__.__name__,
                self.loss),
            learning_rate=self.learning_rate,
            decrease_learning_rate=self.decrease_learning_rate,
            l2_regularization=self.l2_regularization,
            number_of_iterations=self.number_of_iterations,
            initial_weights_diameter=self.initial_weights_diameter,
            reset_weights_after_x_examples=self.reset_weights_after_x_examples,
            lazy_update=self.lazy_update,
            recency_gain=self.recency_gain,
            recency_gain_multiplicative=self.recency_gain_multiplicative,
            averaged=self.averaged,
            averaged_tolerance=self.averaged_tolerance,
            initial_weights=self.initial_weights,
            shuffle=self.shuffle)

        all_args.update(algo_args)
        return self._entrypoint(**all_args)
