AI-MXNet

 view release on metacpan or  search on metacpan

t/test_module.t  view on Meta::CPAN

use strict;
use warnings;
use Test::More tests => 257;
use AI::MXNet qw(mx);
use AI::MXNet::Base;
use AI::MXNet::TestUtils qw(almost_equal enumerate same_array dies_like);
use Data::Dumper;

sub test_module_layout
{
    my $sym = mx->sym->Variable('data');
    $sym = mx->sym->Activation(data=>$sym, act_type=>'relu', __layout__=>'TNC');

    my $dshape = [3, 8, 7];
    my $mod = mx->mod->Module(
        $sym,
        data_names=>['data'],
        context=>[mx->cpu(0), mx->cpu(1)]
    );
    $mod->bind(
        data_shapes=>[mx->io->DataDesc('data', $dshape, layout=>'TNC')]
    );
    $mod->init_params();
    $mod->forward(
        mx->io->DataBatch(
            data=>[mx->nd->ones($dshape)]
        ),
        is_train => 1
    );
    $mod->backward([mx->nd->ones($dshape)]);
    is_deeply($mod->get_outputs()->[0]->shape, $dshape);

    my $hdshape = [3, 4, 7];
    for my $x (@{ $mod->get_outputs(0)->[0] })
    {
        is_deeply($x->shape, $hdshape);
    }
}

sub test_save_load
{
    my $dict_equ = sub {
        is_deeply([sort keys %$a], [sort keys %$b]);
        for my $k (keys %$a)
        {
            ok(($a->{$k}->aspdl == $b->{$k}->aspdl)->all);
        }
    };
    my $sym = mx->sym->Variable('data');
    $sym = mx->sym->FullyConnected($sym, num_hidden=>100);

    # single device
    my $mod = mx->mod->Module($sym, data_names=>['data']);
    $mod->bind(data_shapes=>[['data', [10, 10]]]);
    $mod->init_params();
    $mod->init_optimizer(optimizer_params=>{learning_rate => 0.1, momentum => 0.9});
    $mod->update();
    $mod->save_checkpoint('test', 0, 1);

    my $mod2 = mx->mod->Module->load('test', 0, 1, data_names=>['data']);
    $mod2->bind(data_shapes=>[['data', [10, 10]]]);
    $mod2->init_optimizer(optimizer_params=>{learning_rate => 0.1, momentum => 0.9});
    is($mod->_symbol->tojson(), $mod2->_symbol->tojson());
    $dict_equ->(($mod->get_params())[0], ($mod2->get_params())[0]);
    $dict_equ->($mod->_updater->states, $mod2->_updater->states);

t/test_module.t  view on Meta::CPAN


sub test_module_input_grads
{
    my $a = mx->sym->Variable('a', __layout__=>'NC');
    my $b = mx->sym->Variable('b', __layout__=>'NC');
    my $c = mx->sym->Variable('c', __layout__=>'NC');

    $c = $a + 2 * $b + 3 * $c;
    my $net = mx->mod->Module(
        $c, data_names=>['b', 'c', 'a'],
        context=>[mx->cpu(0), mx->cpu(1)]
    );
    $net->bind(
        data_shapes      => [['b', [5, 5]], ['c', [5, 5]], ['a', [5, 5]]],
        inputs_need_grad => 1
    );
    $net->init_params();

    $net->forward(
        mx->io->DataBatch(data => [
            mx->nd->ones([5, 5]),
            mx->nd->ones([5, 5]),
            mx->nd->ones([5, 5])
        ])
    );
    $net->backward([mx->nd->ones([5, 5])]);
    my $input_grads = $net->get_input_grads();
    my $b_grad = $input_grads->[0]->aspdl;
    my $c_grad = $input_grads->[1]->aspdl;
    my $a_grad = $input_grads->[2]->aspdl;
    ok(($a_grad == 1)->all);
    ok(($b_grad == 2)->all);
    ok(($c_grad == 3)->all);
}

sub test_executor_group
{
    my $get_rnn_sym = sub { my ($num_layers, $num_words, $num_hidden, $num_embed, $seq_len) = @_;
        my $stack = mx->rnn->SequentialRNNCell();
        for my $i (0..$num_layers-1)
        {
            $stack->add(mx->rnn->LSTMCell(num_hidden=>$num_hidden, prefix=>"lstm_l${i}_"));
        }
        my $data = mx->sym->Variable('data');
        my $label = mx->sym->Variable('softmax_label');
        my $embed = mx->sym->Embedding(data=>$data, input_dim=>$num_words,
                                 output_dim=>$num_embed, name=>'embed');

        $stack->reset();
        my ($outputs, $states) = $stack->unroll($seq_len, inputs=>$embed, merge_outputs=>1);

        my $pred = mx->sym->Reshape($outputs, shape=>[-1, $num_hidden]);
        $pred = mx->sym->FullyConnected(data=>$pred, num_hidden=>$num_words, name=>'pred');

        $label = mx->sym->Reshape($label, shape=>[-1]);
        $pred = mx->sym->SoftmaxOutput(data=>$pred, label=>$label, name=>'softmax');
        return $pred;
    };

    my $test_shared_exec_group = sub { my ($exec_grp_shared, $exec_grp_created, $shared_arg_names, $extra_args) = @_;
        # Test shared data arrays
        for my $i (0..@{ $exec_grp_shared->execs }-1)
        {
            # test same shared_data_arrays for two exec groups
            my $shared_data_array1 = $exec_grp_shared->shared_data_arrays->[$i];
            my $shared_data_array2 = $exec_grp_created->shared_data_arrays->[$i];
            if(defined $extra_args)
            {
                ok(keys(%$shared_data_array1) == @$extra_args);
            }
            ok(keys(%$shared_data_array1) == keys(%$shared_data_array2));
            while(my ($k, $v) = each %{ $shared_data_array1 })
            {
                if(defined $extra_args)
                {
                    ok(grep { $_ eq $k } @$extra_args);
                }
                ok(exists $shared_data_array2->{$k});
                ok(same_array($v, $shared_data_array2->{$k}));
            }
            # Test shared argument arrays and gradient arrays
            my $exec_shared  = $exec_grp_shared->execs->[$i];
            my $exec_created = $exec_grp_created->execs->[$i];
            if(defined $shared_arg_names)
            {
                # test shared arguments
                for my $arg_name (@$shared_arg_names)
                {
                    ok(exists $exec_created->arg_dict->{$arg_name});
                    ok(same_array($exec_shared->arg_dict->{$arg_name}, $exec_created->arg_dict->{$arg_name}));
                }
                # test shared argument gradients
                for my $arg_name (@$shared_arg_names)
                {
                    ok(exists $exec_created->grad_dict->{$arg_name});
                    ok(same_array($exec_shared->grad_dict->{$arg_name}, $exec_created->grad_dict->{$arg_name}));
                }
            }
            my $grad_req = $exec_grp_shared->grad_req;
            while(my ($arg_name, $grad) = each %{ $grad_req })
            {
                ok($grad eq $exec_grp_created->grad_req->{$arg_name});
            }
        }
    };
    my $contexts = [mx->cpu(0), mx->cpu(1)];
    my $workload = [(1) x scalar(@$contexts)];
    my $batch_size = 32;
    my $max_bucket_size = 80;
    my $num_words = 1000;
    my $num_hidden = 100;
    my $num_embed = 200;
    my $data_shapes = [['data', [$batch_size, $max_bucket_size]]];
    my $label_shapes = [['softmax_label', [$batch_size, $max_bucket_size]]];

    # generate an rnn sym with #layers=5
    my $sym = $get_rnn_sym->(3, $num_words, $num_hidden,
                      $num_embed, $max_bucket_size);
    my $arg_names1 = $sym->list_arguments();
    my $input_names = ['data', 'softmax_label'];
    my $shared_arg_names = [grep { !/^(?:data|softmax_label)$/ } @$arg_names1];
    my $exec_group1 = AI::MXNet::DataParallelExecutorGroup->new(
        symbol=>$sym, contexts=>$contexts,
        workload=>$workload, data_shapes=>$data_shapes,
        label_shapes=>$label_shapes, param_names=>$shared_arg_names,
        for_training=>1, inputs_need_grad=>0
    );
    # shared_data_arrays should only have input "data" and "softmax_label" arrays
    for my $i (0..@{$contexts}-1)
    {
        ok(keys(%{$exec_group1->shared_data_arrays->[$i]}) == @$input_names);
        for my $name (@$input_names)
        {
            ok(exists $exec_group1->shared_data_arrays->[$i]->{$name});
        }
    }
    # generate an rnn sym with #layers=5
    $sym = $get_rnn_sym->(5, $num_words, $num_hidden,
                      $num_embed, $max_bucket_size);
    my $arg_names2 = $sym->list_arguments();
    my $exec_group2 = AI::MXNet::DataParallelExecutorGroup->new(symbol=>$sym, contexts=>$contexts,

t/test_module.t  view on Meta::CPAN

    $mod->bind(data_shapes=>[['data1', $dshape1], ['data2', $dshape2]],
             label_shapes=>[['softmax_label', $lshape]]);
    $mod->init_params();
    $mod->init_optimizer(optimizer_params=>{learning_rate => 0.01});

    # Train with original data shapes
    my $data_batch = mx->io->DataBatch(data=>[mx->nd->random_uniform(0, 9, $dshape1),
                                       mx->nd->random_uniform(5, 15, $dshape2)],
                                 label=>[mx->nd->ones($lshape)]);
    $mod->forward($data_batch);
    is_deeply($mod->get_outputs->[0]->shape, [$lshape->[0], $num_class]);
    $mod->backward();
    $mod->update();

    # Train with different batch size
    $dshape1 = [3, 3, 64, 64];
    $dshape2 = [3, 3, 32, 32];
    $lshape = [3];
    $data_batch = mx->io->DataBatch(data=>[mx->nd->random_uniform(0, 9, $dshape1),
                                       mx->nd->random_uniform(5, 15, $dshape2)],
                                 label=>[mx->nd->ones($lshape)]);
    $mod->forward($data_batch);
    is_deeply($mod->get_outputs->[0]->shape, [$lshape->[0], $num_class]);
    $mod->backward();
    $mod->update();

    $dshape1 = [20, 3, 64, 64];
    $dshape2 = [20, 3, 32, 32];
    $lshape = [20];
    $data_batch = mx->io->DataBatch(data=>[mx->nd->random_uniform(3, 5, $dshape1),
                                       mx->nd->random_uniform(10, 25, $dshape2)],
                                 label=>[mx->nd->ones($lshape)]);
    $mod->forward($data_batch);
    is_deeply($mod->get_outputs->[0]->shape, [$lshape->[0], $num_class]);
    $mod->backward();
    $mod->update();

    #Train with both different batch size and data shapes
    $dshape1 = [20, 3, 120, 120];
    $dshape2 = [20, 3, 32, 64];
    $lshape = [20];
    $data_batch = mx->io->DataBatch(data=>[mx->nd->random_uniform(0, 9, $dshape1),
                                       mx->nd->random_uniform(5, 15, $dshape2)],
                                 label=>[mx->nd->ones($lshape)]);
    $mod->forward($data_batch);
    is_deeply($mod->get_outputs->[0]->shape, [$lshape->[0], $num_class]);
    $mod->backward();
    $mod->update();

    $dshape1 = [5, 3, 28, 40];
    $dshape2 = [5, 3, 24, 16];
    $lshape = [5];
    $data_batch = mx->io->DataBatch(data=>[mx->nd->random_uniform(0, 9, $dshape1),
                                       mx->nd->random_uniform(15, 25, $dshape2)],
                                 label=>[mx->nd->ones($lshape)]);
    $mod->forward($data_batch);
    is_deeply($mod->get_outputs->[0]->shape, [$lshape->[0], $num_class]);
    $mod->backward();
    $mod->update();

    #Test score
    my $dataset_shape1 = [30, 3, 30, 30];
    my $dataset_shape2 = [30, 3, 20, 40];
    my $labelset_shape = [30];

    my $eval_dataiter = mx->io->NDArrayIter(data=>[mx->nd->random_uniform(0, 9, $dataset_shape1),
                                            mx->nd->random_uniform(15, 25, $dataset_shape2)],
                                      label=>[mx->nd->ones($labelset_shape)],
                                      batch_size=>5);
    ok(keys %{ $mod->score($eval_dataiter, 'acc') } == 1);

    #Test prediction
    $dshape1 = [1, 3, 30, 30];
    $dshape2 = [1, 3, 20, 40];
    $dataset_shape1 = [10, 3, 30, 30];
    $dataset_shape2 = [10, 3, 20, 40];

    my $pred_dataiter = mx->io->NDArrayIter(data=>[mx->nd->random_uniform(0, 9, $dataset_shape1),
                                            mx->nd->random_uniform(15, 25, $dataset_shape2)]);
    $mod->bind(data_shapes=>[['data1', $dshape1], ['data2', $dshape2]],
             for_training=>0, force_rebind=>1);
    is_deeply($mod->predict($pred_dataiter)->shape, [10, $num_class]);

}

test_module_input_grads();
test_module_dtype();
test_monitor();
test_module_switch_bucket();
test_module_layout();
test_module_states();
test_module_reshape();
test_save_load();
test_executor_group();
test_module_set_params();
test_forward_reshape();



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