AI-MXNet

 view release on metacpan or  search on metacpan

lib/AI/MXNet/Module/Base.pm  view on Meta::CPAN

        - forward(data_batch): forward operation.
        - backward(out_grads=): backward operation.
        - update(): update parameters according to installed optimizer.
        - get_outputs(): get outputs of the previous forward operation.
        - get_input_grads(): get the gradients with respect to the inputs computed
        in the previous backward operation.
        - update_metric(metric, labels): update performance metric for the previous forward
        computed results.

    - other properties (mostly for backward compatability)
        - symbol: the underlying symbolic graph for this module (if any)
        This property is not necessarily constant. For example, for AI::MXNet::Module::Bucketing,
        this property is simply the *current* symbol being used. For other modules,
        this value might not be well defined.

    When those intermediate-level API are implemented properly, the following
    high-level API will be automatically available for a module:

        - fit: train the module parameters on a data set
        - predict: run prediction on a data set and collect outputs
        - score: run prediction on a data set and evaluate performance
=cut

has 'logger'            => (is => 'rw', default => sub { AI::MXNet::Logging->get_logger });
has '_symbol'           => (is => 'rw', init_arg => 'symbol', isa => 'AI::MXNet::Symbol');
has [
    qw/binded for_training inputs_need_grad
    params_initialized optimizer_initialized/
]                       => (is => 'rw', isa => 'Bool', init_arg => undef, default => 0);

################################################################################
# High Level API
################################################################################

=head2 forward_backward

    A convenient function that calls both forward and backward.
=cut

method forward_backward(AI::MXNet::DataBatch $data_batch)
{
    $self->forward($data_batch, is_train => 1);
    $self->backward();
}

=head2 score

    Run prediction on eval_data and evaluate the performance according to
    eval_metric.

    Parameters
    ----------
    $eval_data   : AI::MXNet::DataIter
    $eval_metric : AI::MXNet::EvalMetric
    :$num_batch= : Maybe[Int]
        Number of batches to run. Default is undef, indicating run until the AI::MXNet::DataIter
        finishes.
    :$batch_end_callback= : Maybe[Callback]
        Could also be a array ref of functions.
    :$reset=1 : Bool
        Default 1, indicating whether we should reset $eval_data before starting
        evaluating.
    $epoch=0 : Int
        Default is 0. For compatibility, this will be passed to callbacks (if any). During
        training, this will correspond to the training epoch number.
=cut

method score(
    AI::MXNet::DataIter                 $eval_data,
    EvalMetric                          $eval_metric,
    Maybe[Int]                          :$num_batch=,
    Maybe[Callback]|ArrayRef[Callback]  :$batch_end_callback=,
    Maybe[Callback]|ArrayRef[Callback]  :$score_end_callback=,
    Bool                                :$reset=1,
    Int                                 :$epoch=0
)
{
    assert($self->binded and $self->params_initialized);
    $eval_data->reset if $reset;
    if(not blessed $eval_metric or not $eval_metric->isa('AI::MXNet::EvalMetric'))
    {
        $eval_metric = AI::MXNet::Metric->create($eval_metric);
    }

    $eval_metric->reset();
    my $actual_num_batch = 0;
    my $nbatch = 0;
    while(my $eval_batch = <$eval_data>)
    {
        last if (defined $num_batch and $nbatch == $num_batch);
        $self->forward($eval_batch, is_train => 0);
        $self->update_metric($eval_metric, $eval_batch->label);

        if (defined $batch_end_callback)
        {
            my $batch_end_params = AI::MXNet::BatchEndParam->new(
                epoch  => $epoch,
                nbatch => $nbatch,
                eval_metric => $eval_metric
            );
            for my $callback (@{ _as_list($batch_end_callback) })
            {
                &{$callback}($batch_end_params);
            }
        }
        $actual_num_batch++;
        $nbatch++
    }
    if($score_end_callback)
    {
        my $params = AI::MXNet::BatchEndParam->new(
            epoch  => $epoch,
            nbatch => $actual_num_batch,
            eval_metric => $eval_metric,
        );
        for my $callback (@{ _as_list($score_end_callback) })
        {
            &{callback}($params);
        }
    }
    return $eval_metric->get_name_value;
}

=head2  iter_predict

    Iterate over predictions.

    Parameters
    ----------
    $eval_data : AI::MXNet::DataIter
    :$num_batch= : Maybe[Int]
        Default is undef, indicating running all the batches in the data iterator.
    :$reset=1 : bool
        Default is 1, indicating whether we should reset the data iter before start
        doing prediction.
=cut

method iter_predict(AI::MXNet::DataIter $eval_data, Maybe[Int] :$num_batch=, Bool :$reset=1)
{
    assert($self->binded and $self->params_initialized);
    if($reset)
    {
        $eval_data->reset;
    }
    my $nbatch = 0;
    my @out;
    while(my $eval_batch = <$eval_data>)
    {
        last if defined $num_batch and $nbatch == $num_batch;
        $self->forward($eval_batch, is_train => 0);
        my $pad = $eval_batch->pad;
        my $outputs = [
            map { $_->slice([0, $_->shape->[0] - ($pad//0) - 1]) } @{ $self->get_outputs() }
        ];
        push @out, [$outputs, $nbatch, $eval_batch];
        $nbatch++;
    }
    return @out;
}

=head2 predict

    Run prediction and collect the outputs.

    Parameters
    ----------
    $eval_data  : AI::MXNet::DataIter
    :$num_batch= : Maybe[Int]
        Default is undef, indicating running all the batches in the data iterator.
    :$merge_batches=1 : Bool
        Default is 1.
    :$reset=1 : Bool
        Default is 1, indicating whether we should reset the data iter before start
        doing prediction.
    :$always_output_list=0 : Bool
    Default is 0, see the doc for return values.

    Returns
    -------
    When $merge_batches is 1 (by default), the return value will be an array ref
    [$out1, $out2, $out3] where each element is concatenation of the outputs for
    all the mini-batches. If $always_output_list` also is 0 (by default),
    then in the case of a single output, $out1 is returned in stead of [$out1].

    When $merge_batches is 0, the return value will be a nested array ref like
    [[$out1_batch1, $out2_batch1], [$out1_batch2], ...]. This mode is useful because
    in some cases (e.g. bucketing), the module does not necessarily produce the same
    number of outputs.

    The objects in the results are AI::MXNet::NDArray`s. If you need to work with pdl array,
    just call ->aspdl() on each AI::MXNet::NDArray.
=cut

method predict(
    AI::MXNet::DataIter $eval_data,
    Maybe[Int] :$num_batch=, Bool :$merge_batches=1, Bool :$reset=1, Bool :$always_output_list=0
)
{
    assert($self->binded and $self->params_initialized);
    $eval_data->reset() if $reset;

    my @output_list;
    my $nbatch = 0;
    while(my $eval_batch = <$eval_data>)
    {
        last if defined $num_batch and $nbatch == $num_batch;
        $self->forward($eval_batch, is_train => 0);
        my $pad = $eval_batch->pad;
        my $outputs = [map { $_->slice([0, $_->shape->[0]-($pad//0)-1])->copy } @{ $self->get_outputs }];
        push @output_list, $outputs;
    }
    return () unless @output_list;
    if($merge_batches)
    {
        my $num_outputs = @{ $output_list[0] };
        for my $out (@output_list)
        {
            unless(@{ $out } == $num_outputs)
            {
                confess('Cannot merge batches, as num of outputs is not the same '
                       .'in mini-batches. Maybe bucketing is used?');
            }
        }
        my @output_list2;
        for my $i (0..$num_outputs-1)
        {
            push @output_list2,
                 AI::MXNet::NDArray->concatenate([map { $_->[$i] } @output_list]);
        }
        if($num_outputs == 1 and not $always_output_list)
        {
            return $output_list2[0];
        }
        return @output_list2;
    }
    return @output_list;
}

=head2 fit

    Train the module parameters.

    Parameters
    ----------
    $train_data : AI::MXNet::DataIter
    :$eval_data= : Maybe[AI::MXNet::DataIter]
        If not undef, it will be used as a validation set to evaluate the performance
        after each epoch.
    :$eval_metric='acc' : str or AI::MXNet::EvalMetric subclass object.
        Default is 'accuracy'. The performance measure used to display during training.
        Other possible predefined metrics are:
        'ce' (CrossEntropy), 'f1', 'mae', 'mse', 'rmse', 'top_k_accuracy'
    :$epoch_end_callback= : Maybe[Callback]|ArrayRef[Callback] function or array ref of functions.
        Each callback will be called with the current $epoch, $symbol, $arg_params
        and $aux_params.
    :$batch_end_callback= : Maybe[Callback]|ArrayRef[Callback] function or array ref of functions.
        Each callback will be called with a AI::MXNet::BatchEndParam.
    :$kvstore='local' : str or AI::MXNet::KVStore
        Default is 'local'.
    :$optimizer : str or AI::MXNet::Optimizer
        Default is 'sgd'
    :$optimizer_params : hash ref
        Default { learning_rate => 0.01 }.
        The parameters for the optimizer constructor.
    :$eval_end_callback= : Maybe[Callback]|ArrayRef[Callback] function or array ref of functions
        These will be called at the end of each full evaluation, with the metrics over
        the entire evaluation set.
    :$eval_batch_end_callback : Maybe[Callback]|ArrayRef[Callback] function or array ref of functions
        These will be called at the end of each minibatch during evaluation
    :$initializer= : Initializer
        Will be called to initialize the module parameters if not already initialized.
    :$arg_params= : hash ref
        Default undef, if not undef, must be an existing parameters from a trained
        model or loaded from a checkpoint (previously saved model). In this case,
        the value here will be used to initialize the module parameters, unless they
        are already initialized by the user via a call to init_params or fit.
        $arg_params have higher priority than the $initializer.
    :$aux_params= : hash ref
        Default is undef. This is similar to the $arg_params, except for auxiliary states.
    :$allow_missing=0 : Bool
        Default is 0. Indicates whether we allow missing parameters when $arg_params
        and $aux_params are not undefined. If this is 1, then the missing parameters
        will be initialized via the $initializer.
    :$force_rebind=0 : Bool
        Default is 0. Whether to force rebinding the executors if already binded.
    :$force_init=0 : Bool
        Default is 0. Indicates whether we should force initialization even if the
        parameters are already initialized.
    :$begin_epoch=0 : Int
        Default is 0. Indicates the starting epoch. Usually, if we are resuming from a
        checkpoint saved at a previous training phase at epoch N, then we should specify
        this value as N+1.
    :$num_epoch : Int
        Number of epochs for the training.
=cut


method fit(
    AI::MXNet::DataIter                 $train_data,
    Maybe[AI::MXNet::DataIter]         :$eval_data=,
    EvalMetric                         :$eval_metric='acc',
    Maybe[Callback]|ArrayRef[Callback] :$epoch_end_callback=,
    Maybe[Callback]|ArrayRef[Callback] :$batch_end_callback=,
    Str                                :$kvstore='local',
    Optimizer                          :$optimizer='sgd',
    HashRef                            :$optimizer_params={ learning_rate => 0.01 },
    Maybe[Callback]|ArrayRef[Callback] :$eval_end_callback=,
    Maybe[Callback]|ArrayRef[Callback] :$eval_batch_end_callback=,
    AI::MXNet::Initializer             :$initializer=AI::MXNet::Initializer->Uniform(scale => 0.01),
    Maybe[HashRef[AI::MXNet::NDArray]] :$arg_params=,
    Maybe[HashRef[AI::MXNet::NDArray]] :$aux_params=,
    Bool                               :$allow_missing=0,
    Bool                               :$force_rebind=0,
    Bool                               :$force_init=0,
    Int                                :$begin_epoch=0,
    Int                                :$num_epoch,
    Maybe[EvalMetric]                  :$validation_metric=,
    Maybe[AI::MXNet::Monitor]          :$monitor=
)
{
    $self->bind(
        data_shapes  => $train_data->provide_data,
        label_shapes => $train_data->provide_label,
        for_training => 1,
        force_rebind => $force_rebind
    );
    if($monitor)
    {
        $self->install_monitor($monitor);
    }
    $self->init_params(
        initializer   => $initializer,
        arg_params    => $arg_params,
        aux_params    => $aux_params,
        allow_missing => $allow_missing,
        force_init    => $force_init
    );
    $self->init_optimizer(
        kvstore          => $kvstore,
        optimizer        => $optimizer,
        optimizer_params => $optimizer_params
    );

    if(not defined $validation_metric)
    {
        $validation_metric = $eval_metric;
    }
    $eval_metric = AI::MXNet::Metric->create($eval_metric)
        unless blessed $eval_metric;



( run in 0.714 second using v1.01-cache-2.11-cpan-39bf76dae61 )