# --------------------------------------------------------------------------------------------
# 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 learner 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: Learning rate.

    :param decrease_learning_rate: Decrease learning rate.

    :param l2_regularizer_weight: L2 Regularization Weight.

    :param num_iterations: Number of iterations.

    :param init_wts_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 do_lazy_updates: 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_multi: Whether Recency Gain is multiplicative vs.
        additive (`do_lazy_updates`` must be **False**).

    :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 streaming_cache_size: Size of cache when trained in Scope.

    :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_regularizer_weight=0.0,
            num_iterations=1,
            init_wts_diameter=0.0,
            reset_weights_after_x_examples=None,
            do_lazy_updates=True,
            recency_gain=0.0,
            recency_gain_multi=False,
            averaged=True,
            averaged_tolerance=0.01,
            initial_weights=None,
            shuffle=True,
            streaming_cache_size=1000000,
            **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_regularizer_weight = l2_regularizer_weight
        self.num_iterations = num_iterations
        self.init_wts_diameter = init_wts_diameter
        self.reset_weights_after_x_examples = reset_weights_after_x_examples
        self.do_lazy_updates = do_lazy_updates
        self.recency_gain = recency_gain
        self.recency_gain_multi = recency_gain_multi
        self.averaged = averaged
        self.averaged_tolerance = averaged_tolerance
        self.initial_weights = initial_weights
        self.shuffle = shuffle
        self.streaming_cache_size = streaming_cache_size

    @property
    def _entrypoint(self):
        return trainers_onlinegradientdescentregressor

    @trace
    def _get_node(self, **all_args):
        algo_args = dict(
            feature_column=self._getattr_role(
                'feature_column',
                all_args),
            label_column=self._getattr_role(
                'label_column',
                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_regularizer_weight=self.l2_regularizer_weight,
            num_iterations=self.num_iterations,
            init_wts_diameter=self.init_wts_diameter,
            reset_weights_after_x_examples=self.reset_weights_after_x_examples,
            do_lazy_updates=self.do_lazy_updates,
            recency_gain=self.recency_gain,
            recency_gain_multi=self.recency_gain_multi,
            averaged=self.averaged,
            averaged_tolerance=self.averaged_tolerance,
            initial_weights=self.initial_weights,
            shuffle=self.shuffle,
            streaming_cache_size=self.streaming_cache_size)

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