This is an automated email from the ASF dual-hosted git repository. jxie pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/incubator-mxnet.git
The following commit(s) were added to refs/heads/master by this push: new f674bc4 1) Fixes for ImageIter (#7357) f674bc4 is described below commit f674bc40dbdb834919a37bd12af3003d7a427307 Author: Sergey Kolychev <sergeykolychev.git...@gmail.com> AuthorDate: Wed Aug 9 13:20:04 2017 -0700 1) Fixes for ImageIter (#7357) 2) Convolutional RNN 3) Improved Visualization 4) PearsonCorrelation metric 5) Fixed tests. --- perl-package/AI-MXNet/Changes | 3 + perl-package/AI-MXNet/MANIFEST | 1 - perl-package/AI-MXNet/META.json | 4 +- perl-package/AI-MXNet/META.yml | 4 +- perl-package/AI-MXNet/Makefile.PL | 4 +- perl-package/AI-MXNet/README | 2 +- perl-package/AI-MXNet/lib/AI/MXNet.pm | 2 +- perl-package/AI-MXNet/lib/AI/MXNet/Base.pm | 2 +- perl-package/AI-MXNet/lib/AI/MXNet/Image.pm | 8 +- perl-package/AI-MXNet/lib/AI/MXNet/Metric.pm | 50 ++++ perl-package/AI-MXNet/lib/AI/MXNet/Module.pm | 8 - perl-package/AI-MXNet/lib/AI/MXNet/RNN.pm | 3 + perl-package/AI-MXNet/lib/AI/MXNet/RNN/Cell.pm | 307 ++++++++++++++++++++- perl-package/AI-MXNet/lib/AI/MXNet/Symbol.pm | 2 +- perl-package/AI-MXNet/lib/AI/MXNet/Types.pm | 4 +- .../AI-MXNet/lib/AI/MXNet/Visualization.pm | 8 + perl-package/AI-MXNet/t/test_model_parallel.t | 74 +++++ perl-package/AI-MXNet/t/test_rnn.t | 62 ++++- perl-package/AI-MXNetCAPI/Changes | 3 + perl-package/AI-MXNetCAPI/META.json | 2 +- perl-package/AI-MXNetCAPI/META.yml | 2 +- perl-package/AI-MXNetCAPI/README | 2 +- perl-package/AI-MXNetCAPI/lib/AI/MXNetCAPI.pm | 2 +- perl-package/AI-MXNetCAPI/mxnet.i | 7 + 24 files changed, 537 insertions(+), 29 deletions(-) diff --git a/perl-package/AI-MXNet/Changes b/perl-package/AI-MXNet/Changes index 5d5c5a2..f8ecc75 100644 --- a/perl-package/AI-MXNet/Changes +++ b/perl-package/AI-MXNet/Changes @@ -1,5 +1,8 @@ Revision history for Perl extension AI::MXNet +1.0102 Sun Aug 6 16:55:08 PDT 2017 + - bugfixes in Image.pm, updated tests, added PearsonCorrelation metric, added Convolutional RNN modules. + 1.0101 Sun Jul 2 17:16:01 PDT 2017 - reworked CachedOp, two new optimizers, auto module reshape, using strings to index the kvstore. diff --git a/perl-package/AI-MXNet/MANIFEST b/perl-package/AI-MXNet/MANIFEST index 7a6d78b..48cb31d 100644 --- a/perl-package/AI-MXNet/MANIFEST +++ b/perl-package/AI-MXNet/MANIFEST @@ -10,7 +10,6 @@ examples/cudnn_lstm_bucketing.pl Makefile.PL Changes META.json -t/test_autograd.t t/test_recordio.t t/test_random.t t/test_init.t diff --git a/perl-package/AI-MXNet/META.json b/perl-package/AI-MXNet/META.json index 5454592..692f1dd 100644 --- a/perl-package/AI-MXNet/META.json +++ b/perl-package/AI-MXNet/META.json @@ -30,7 +30,7 @@ }, "runtime" : { "requires" : { - "AI::MXNetCAPI" : "1.0101", + "AI::MXNetCAPI" : "1.0102", "AI::NNVMCAPI" : "1.01", "Function::Parameters" : "1.0705", "GraphViz" : "2.14", @@ -43,5 +43,5 @@ } }, "release_status" : "stable", - "version" : "1.0101" + "version" : "1.0102" } diff --git a/perl-package/AI-MXNet/META.yml b/perl-package/AI-MXNet/META.yml index 8c09c96..5b92018 100644 --- a/perl-package/AI-MXNet/META.yml +++ b/perl-package/AI-MXNet/META.yml @@ -17,10 +17,10 @@ no_index: - t - inc requires: - AI::MXNetCAPI: '1.0101' + AI::MXNetCAPI: '1.0102' AI::NNVMCAPI: '1.01' Function::Parameters: '1.0705' GraphViz: '2.14' Mouse: v2.1.0 PDL: '2.007' -version: '1.0101' +version: '1.0102' diff --git a/perl-package/AI-MXNet/Makefile.PL b/perl-package/AI-MXNet/Makefile.PL index 990176d..2c9bda8 100644 --- a/perl-package/AI-MXNet/Makefile.PL +++ b/perl-package/AI-MXNet/Makefile.PL @@ -19,7 +19,7 @@ my %WriteMakefileArgs = ( "LICENSE" => "apache_2_0", "NAME" => "AI::MXNet", "PREREQ_PM" => { - "AI::MXNetCAPI" => "1.0101", + "AI::MXNetCAPI" => "1.0102", "AI::NNVMCAPI" => "1.01", "Function::Parameters" => "1.0705", "Mouse" => "v2.1.0", @@ -35,7 +35,7 @@ my %WriteMakefileArgs = ( my %FallbackPrereqs = ( - "AI::MXNetCAPI" => "1.0101", + "AI::MXNetCAPI" => "1.0102", "AI::NNVMCAPI" => "1.01", "Function::Parameters" => "1.0705", "Mouse" => "v2.1.0", diff --git a/perl-package/AI-MXNet/README b/perl-package/AI-MXNet/README index f275d08..86b6cf1 100644 --- a/perl-package/AI-MXNet/README +++ b/perl-package/AI-MXNet/README @@ -1,5 +1,5 @@ This archive contains the distribution AI-MXNet, -version 1.0101: +version 1.0102: Perl interface to MXNet machine learning library diff --git a/perl-package/AI-MXNet/lib/AI/MXNet.pm b/perl-package/AI-MXNet/lib/AI/MXNet.pm index 1d21253..40e84a6 100644 --- a/perl-package/AI-MXNet/lib/AI/MXNet.pm +++ b/perl-package/AI-MXNet/lib/AI/MXNet.pm @@ -46,7 +46,7 @@ use AI::MXNet::Image; use AI::MXNet::Contrib; use AI::MXNet::Contrib::AutoGrad; use AI::MXNet::CachedOp; -our $VERSION = '1.0101'; +our $VERSION = '1.0102'; sub import { diff --git a/perl-package/AI-MXNet/lib/AI/MXNet/Base.pm b/perl-package/AI-MXNet/lib/AI/MXNet/Base.pm index d5ff0dd..0c42fa9 100644 --- a/perl-package/AI-MXNet/lib/AI/MXNet/Base.pm +++ b/perl-package/AI-MXNet/lib/AI/MXNet/Base.pm @@ -20,7 +20,7 @@ use strict; use warnings; use PDL; use PDL::Types qw(); -use AI::MXNetCAPI 1.0101; +use AI::MXNetCAPI 1.0102; use AI::NNVMCAPI 1.01; use AI::MXNet::Types; use Time::HiRes; diff --git a/perl-package/AI-MXNet/lib/AI/MXNet/Image.pm b/perl-package/AI-MXNet/lib/AI/MXNet/Image.pm index b996b02..18ef42a 100644 --- a/perl-package/AI-MXNet/lib/AI/MXNet/Image.pm +++ b/perl-package/AI-MXNet/lib/AI/MXNet/Image.pm @@ -764,7 +764,7 @@ sub BUILD { chomp($line); my @line = split(/\t/, $line); - my $label = AI::MXNet::NDArray->array([@line[1..@line-1]]); + my $label = AI::MXNet::NDArray->array([@line[1..@line-2]]); my $key = $line[0]; $imglist{$key} = [$label, $line[-1]]; push @imgkeys, $key; @@ -838,6 +838,10 @@ sub BUILD { $self->aug_list(AI::MXNet::Image->CreateAugmenter(data_shape => $self->data_shape, %{ $self->kwargs//{} })); } + else + { + $self->aug_list([]); + } $self->cur(0); $self->reset(); } @@ -877,7 +881,7 @@ method next_sample() } else { - my ($label, $fname) = $self->imglist->{$idx}; + my ($label, $fname) = @{ $self->imglist->{$idx} }; if(not defined $self->imgrec) { open(F, $self->path_root . "/$fname") or confess("can't open $fname $!"); diff --git a/perl-package/AI-MXNet/lib/AI/MXNet/Metric.pm b/perl-package/AI-MXNet/lib/AI/MXNet/Metric.pm index 6504481..c3a3183 100644 --- a/perl-package/AI-MXNet/lib/AI/MXNet/Metric.pm +++ b/perl-package/AI-MXNet/lib/AI/MXNet/Metric.pm @@ -510,6 +510,55 @@ method update(ArrayRef[AI::MXNet::NDArray] $labels, ArrayRef[AI::MXNet::NDArray] }, $labels, $preds); } +package AI::MXNet::PearsonCorrelation; +use Mouse; +use AI::MXNet::Base; +extends 'AI::MXNet::EvalMetric'; +has '+name' => (default => 'pearson-correlation'); + +=head1 NAME + + AI::MXNet::PearsonCorrelation +=cut + +=head1 DESCRIPTION + + Computes Pearson correlation. + + Parameters + ---------- + name : str + Name of this metric instance for display. + + Examples + -------- + >>> $predicts = [mx->nd->array([[0.3, 0.7], [0, 1.], [0.4, 0.6]])] + >>> $labels = [mx->nd->array([[1, 0], [0, 1], [0, 1]])] + >>> $pr = mx->metric->PearsonCorrelation() + >>> $pr->update($labels, $predicts) + >>> print pr->get() + ('pearson-correlation', '0.421637061887229') +=cut + +method update(ArrayRef[AI::MXNet::NDArray] $labels, ArrayRef[AI::MXNet::NDArray] $preds) +{ + AI::MXNet::Metric::check_label_shapes($labels, $preds); + zip(sub { + my ($label, $pred) = @_; + AI::MXNet::Metric::check_label_shapes($label, $pred); + $label = $label->aspdl->flat; + $pred = $pred->aspdl->flat; + my ($label_mean, $label_stdv) = ($label->stats)[0, 6]; + my ($pred_mean, $pred_stdv) = ($pred->stats)[0, 6]; + $self->sum_metric( + $self->sum_metric + + + ((($label-$label_mean)*($pred-$pred_mean))->sum/$label->nelem)/(($label_stdv*$pred_stdv)->at(0)) + ); + $self->num_inst($self->num_inst + 1); + }, $labels, $preds); +} + =head1 DESCRIPTION Custom evaluation metric that takes a sub ref. @@ -574,6 +623,7 @@ my %metrics = qw/ top_k_accuracy AI::MXNet::TopKAccuracy Perplexity AI::MXNet::Perplexity perplexity AI::MXNet::Perplexity + pearsonr AI::MXNet::PearsonCorrelation /; method create(Metric|ArrayRef[Metric] $metric, %kwargs) diff --git a/perl-package/AI-MXNet/lib/AI/MXNet/Module.pm b/perl-package/AI-MXNet/lib/AI/MXNet/Module.pm index 967a511..3e4d938 100644 --- a/perl-package/AI-MXNet/lib/AI/MXNet/Module.pm +++ b/perl-package/AI-MXNet/lib/AI/MXNet/Module.pm @@ -796,14 +796,6 @@ method forward( ) { assert($self->binded and $self->params_initialized); - # If starting to do the inference, force rebind the module. - if($self->label_shapes and not $data_batch->label) - { - confess( - "If you are trying to do inference, rebind module ". - "with 'force_rebind=True' and 'for_training=False'" - ); - } my @curr_data_shapes = map { $_->shape } @{ $self->data_shapes }; my @new_data_shapes = map { $_->shape } @{ $data_batch->data }; diff --git a/perl-package/AI-MXNet/lib/AI/MXNet/RNN.pm b/perl-package/AI-MXNet/lib/AI/MXNet/RNN.pm index 1ccab31..07e72a7 100644 --- a/perl-package/AI-MXNet/lib/AI/MXNet/RNN.pm +++ b/perl-package/AI-MXNet/lib/AI/MXNet/RNN.pm @@ -166,6 +166,9 @@ method SequentialRNNCell(@args) { AI::MXNet::RNN::SequentialCell->new(@args) } method BidirectionalCell(@args) { AI::MXNet::RNN::BidirectionalCell->new(@args) } method DropoutCell(@args) { AI::MXNet::RNN::DropoutCell->new(@args) } method ZoneoutCell(@args) { AI::MXNet::RNN::ZoneoutCell->new(@args) } +method ConvRNNCell(@args) { AI::MXNet::RNN::ConvCell->new(@args) } +method ConvLSTMCell(@args) { AI::MXNet::RNN::ConvLSTMCell->new(@args) } +method ConvGRUCell(@args) { AI::MXNet::RNN::ConvGRUCell->new(@args) } method ResidualCell(@args) { AI::MXNet::RNN::ResidualCell->new(@args) } method encode_sentences(@args) { AI::MXNet::RNN::IO->encode_sentences(@args) } method BucketSentenceIter(@args) diff --git a/perl-package/AI-MXNet/lib/AI/MXNet/RNN/Cell.pm b/perl-package/AI-MXNet/lib/AI/MXNet/RNN/Cell.pm index 0221a90..08c3094 100644 --- a/perl-package/AI-MXNet/lib/AI/MXNet/RNN/Cell.pm +++ b/perl-package/AI-MXNet/lib/AI/MXNet/RNN/Cell.pm @@ -766,7 +766,7 @@ has '_dropout' => (is => 'ro', isa => 'Num', init_arg => 'dropout', has '_get_next_state' => (is => 'ro', isa => 'Bool', init_arg => 'get_next_state', default => 0); has '_bidirectional' => (is => 'ro', isa => 'Bool', init_arg => 'bidirectional', default => 0); has 'forget_bias' => (is => 'ro', isa => 'Num', default => 1); -has 'initializer' => (is => 'rw', isa => 'Maybe[AI::MXNet::Initializer]'); +has 'initializer' => (is => 'rw', isa => 'Maybe[Initializer]'); has '_mode' => ( is => 'ro', isa => enum([qw/rnn_relu rnn_tanh lstm gru/]), @@ -1429,6 +1429,309 @@ method unroll( return($outputs, $states); } +package AI::MXNet::RNN::ConvCell::Base; +use Mouse; +use AI::MXNet::Base; +extends 'AI::MXNet::RNN::Cell::Base'; + +=head1 NAME + + AI::MXNet::RNN::Conv::Base +=cut + +=head1 DESCRIPTION + + Abstract base class for Convolutional RNN cells + +=cut + +has '_h2h_kernel' => (is => 'ro', isa => 'Shape', init_arg => 'h2h_kernel'); +has '_h2h_dilate' => (is => 'ro', isa => 'Shape', init_arg => 'h2h_dilate'); +has '_h2h_pad' => (is => 'rw', isa => 'Shape', init_arg => undef); +has '_i2h_kernel' => (is => 'ro', isa => 'Shape', init_arg => 'i2h_kernel'); +has '_i2h_stride' => (is => 'ro', isa => 'Shape', init_arg => 'i2h_stride'); +has '_i2h_dilate' => (is => 'ro', isa => 'Shape', init_arg => 'i2h_dilate'); +has '_i2h_pad' => (is => 'ro', isa => 'Shape', init_arg => 'i2h_pad'); +has '_num_hidden' => (is => 'ro', isa => 'DimSize', init_arg => 'num_hidden'); +has '_input_shape' => (is => 'ro', isa => 'Shape', init_arg => 'input_shape'); +has '_conv_layout' => (is => 'ro', isa => 'Str', init_arg => 'conv_layout', default => 'NCHW'); +has '_activation' => (is => 'ro', init_arg => 'activation'); +has '_state_shape' => (is => 'rw', init_arg => undef); +has [qw/i2h_weight_initializer h2h_weight_initializer + i2h_bias_initializer h2h_bias_initializer/] => (is => 'rw', isa => 'Maybe[Initializer]'); + +sub BUILD +{ + my $self = shift; + assert ( + ($self->_h2h_kernel->[0] % 2 == 1 and $self->_h2h_kernel->[1] % 2 == 1), + "Only support odd numbers, got h2h_kernel= (@{[ $self->_h2h_kernel ]})" + ); + $self->_h2h_pad([ + int($self->_h2h_dilate->[0] * ($self->_h2h_kernel->[0] - 1) / 2), + int($self->_h2h_dilate->[1] * ($self->_h2h_kernel->[1] - 1) / 2) + ]); + # Infer state shape + my $data = AI::MXNet::Symbol->Variable('data'); + my $state_shape = AI::MXNet::Symbol->Convolution( + data => $data, + num_filter => $self->_num_hidden, + kernel => $self->_i2h_kernel, + stride => $self->_i2h_stride, + pad => $self->_i2h_pad, + dilate => $self->_i2h_dilate, + layout => $self->_conv_layout + ); + $state_shape = ($state_shape->infer_shape(data=>$self->_input_shape))[1]->[0]; + $state_shape->[0] = 0; + $self->_state_shape($state_shape); +} + +method state_info() +{ + return [ + { shape => $self->_state_shape, __layout__ => $self->_conv_layout }, + { shape => $self->_state_shape, __layout__ => $self->_conv_layout } + ]; +} + +method call($inputs, $states) +{ + confess("AI::MXNet::RNN::ConvCell::Base is abstract class for convolutional RNN"); +} + +package AI::MXNet::RNN::ConvCell; +use Mouse; +extends 'AI::MXNet::RNN::ConvCell::Base'; + +=head1 NAME + + AI::MXNet::RNN::ConvCell +=cut + +=head1 DESCRIPTION + + Convolutional RNN cells + + Parameters + ---------- + input_shape : array ref of int + Shape of input in single timestep. + num_hidden : int + Number of units in output symbol. + h2h_kernel : array ref of int, default (3, 3) + Kernel of Convolution operator in state-to-state transitions. + h2h_dilate : array ref of int, default (1, 1) + Dilation of Convolution operator in state-to-state transitions. + i2h_kernel : array ref of int, default (3, 3) + Kernel of Convolution operator in input-to-state transitions. + i2h_stride : array ref of int, default (1, 1) + Stride of Convolution operator in input-to-state transitions. + i2h_pad : array ref of int, default (1, 1) + Pad of Convolution operator in input-to-state transitions. + i2h_dilate : array ref of int, default (1, 1) + Dilation of Convolution operator in input-to-state transitions. + activation : str or Symbol, + default functools.partial(symbol.LeakyReLU, act_type='leaky', slope=0.2) + Type of activation function. + prefix : str, default 'ConvRNN_' + Prefix for name of layers (and name of weight if params is None). + params : RNNParams, default None + Container for weight sharing between cells. Created if None. + conv_layout : str, , default 'NCHW' + Layout of ConvolutionOp +=cut + +has '+_h2h_kernel' => (default => sub { [3, 3] }); +has '+_h2h_dilate' => (default => sub { [1, 1] }); +has '+_i2h_kernel' => (default => sub { [3, 3] }); +has '+_i2h_stride' => (default => sub { [1, 1] }); +has '+_i2h_dilate' => (default => sub { [1, 1] }); +has '+_i2h_pad' => (default => sub { [1, 1] }); +has '+_prefix' => (default => 'ConvRNN_'); +has '+_activation' => (default => sub { sub { AI::MXNet::Symbol->LeakyReLU(@_, act_type => 'leaky', slope => 0.2) } }); +has '+i2h_bias_initializer' => (default => 'zeros'); +has '+h2h_bias_initializer' => (default => 'zeros'); +has 'forget_bias' => (is => 'ro', isa => 'Num'); +has [qw/_iW _iB + _hW _hB/] => (is => 'rw', init_arg => undef); + + +sub BUILD +{ + my $self = shift; + $self->_iW($self->_params->get('i2h_weight', init => $self->i2h_weight_initializer)); + $self->_hW($self->_params->get('h2h_weight', init => $self->h2h_weight_initializer)); + $self->_iB( + $self->params->get( + 'i2h_bias', + (defined($self->forget_bias and not defined $self->i2h_bias_initializer) + ? (init => AI::MXNet::LSTMBias->new(forget_bias => $self->forget_bias)) + : (init => $self->i2h_bias_initializer) + ) + ) + ); + $self->_hB($self->_params->get('h2h_bias', init => $self->h2h_bias_initializer)); +} + +method _num_gates() +{ + scalar(@{ $self->_gate_names() }); +} + +method _gate_names() +{ + return [''] +} + +method _conv_forward($inputs, $states, $name) +{ + my $i2h = AI::MXNet::Symbol->Convolution( + name => "${name}i2h", + data => $inputs, + num_filter => $self->_num_hidden*$self->_num_gates(), + kernel => $self->_i2h_kernel, + stride => $self->_i2h_stride, + pad => $self->_i2h_pad, + dilate => $self->_i2h_dilate, + weight => $self->_iW, + bias => $self->_iB + ); + my $h2h = AI::MXNet::Symbol->Convolution( + name => "${name}h2h", + data => @{ $states }[0], + num_filter => $self->_num_hidden*$self->_num_gates(), + kernel => $self->_h2h_kernel, + stride => [1, 1], + pad => $self->_h2h_pad, + dilate => $self->_h2h_dilate, + weight => $self->_hW, + bias => $self->_hB + ); + return ($i2h, $h2h); +} + +method call(AI::MXNet::Symbol $inputs, AI::MXNet::Symbol|ArrayRef[AI::MXNet::Symbol] $states) +{ + $self->_counter($self->_counter + 1); + my $name = sprintf('%st%d_', $self->_prefix, $self->_counter); + my ($i2h, $h2h) = $self->_conv_forward($inputs, $states, $name); + my $output = $self->_get_activation($i2h + $h2h, $self->_activation, name => "${name}out"); + return ($output, [$output]); +} + +package AI::MXNet::RNN::ConvLSTMCell; +use Mouse; +extends 'AI::MXNet::RNN::ConvCell'; +has '+forget_bias' => (default => 1); +has '+_prefix' => (default => 'ConvLSTM_'); + +=head1 NAME + + AI::MXNet::RNN::ConvLSTMCell +=cut + +=head1 DESCRIPTION + + Convolutional LSTM network cell. + + Reference: + Xingjian et al. NIPS2015 +=cut + +method _gate_names() +{ + return ['_i', '_f', '_c', '_o']; +} + +method call(AI::MXNet::Symbol $inputs, AI::MXNet::Symbol|ArrayRef[AI::MXNet::Symbol] $states) +{ + $self->_counter($self->_counter + 1); + my $name = sprintf('%st%d_', $self->_prefix, $self->_counter); + my ($i2h, $h2h) = $self->_conv_forward($inputs, $states, $name); + my $gates = $i2h + $h2h; + my @slice_gates = @{ AI::MXNet::Symbol->SliceChannel( + $gates, + num_outputs => 4, + axis => index($self->_conv_layout, 'C'), + name => "${name}slice" + ) }; + my $in_gate = AI::MXNet::Symbol->Activation( + $slice_gates[0], + act_type => "sigmoid", + name => "${name}i" + ); + my $forget_gate = AI::MXNet::Symbol->Activation( + $slice_gates[1], + act_type => "sigmoid", + name => "${name}f" + ); + my $in_transform = $self->_get_activation( + $slice_gates[2], + $self->_activation, + name => "${name}c" + ); + my $out_gate = AI::MXNet::Symbol->Activation( + $slice_gates[3], + act_type => "sigmoid", + name => "${name}o" + ); + my $next_c = AI::MXNet::Symbol->_plus( + $forget_gate * @{$states}[1], + $in_gate * $in_transform, + name => "${name}state" + ); + my $next_h = AI::MXNet::Symbol->_mul( + $out_gate, $self->_get_activation($next_c, $self->_activation), + name => "${name}out" + ); + return ($next_h, [$next_h, $next_c]); +} + +package AI::MXNet::RNN::ConvGRUCell; +use Mouse; +extends 'AI::MXNet::RNN::ConvCell'; +has '+_prefix' => (default => 'ConvGRU_'); + +=head1 NAME + + AI::MXNet::RNN::ConvGRUCell +=cut + +=head1 DESCRIPTION + + Convolutional GRU network cell. +=cut + +method _gate_names() +{ + return ['_r', '_z', '_o']; +} + +method call(AI::MXNet::Symbol $inputs, AI::MXNet::Symbol|ArrayRef[AI::MXNet::Symbol] $states) +{ + $self->_counter($self->_counter + 1); + my $name = sprintf('%st%d_', $self->_prefix, $self->_counter); + my ($i2h, $h2h) = $self->_conv_forward($inputs, $states, $name); + my ($i2h_r, $i2h_z, $h2h_r, $h2h_z); + ($i2h_r, $i2h_z, $i2h) = @{ AI::MXNet::Symbol->SliceChannel($i2h, num_outputs => 3, name => "${name}_i2h_slice") }; + ($h2h_r, $h2h_z, $h2h) = @{ AI::MXNet::Symbol->SliceChannel($h2h, num_outputs => 3, name => "${name}_h2h_slice") }; + my $reset_gate = AI::MXNet::Symbol->Activation( + $i2h_r + $h2h_r, act_type => "sigmoid", + name => "${name}_r_act" + ); + my $update_gate = AI::MXNet::Symbol->Activation( + $i2h_z + $h2h_z, act_type => "sigmoid", + name => "${name}_z_act" + ); + my $next_h_tmp = $self->_get_activation($i2h + $reset_gate * $h2h, $self->_activation, name => "${name}_h_act"); + my $next_h = AI::MXNet::Symbol->_plus( + (1 - $update_gate) * $next_h_tmp, $update_gate * @{$states}[0], + name => "${name}out" + ); + return ($next_h, [$next_h]); +} + package AI::MXNet::RNN::ModifierCell; use Mouse; use AI::MXNet::Base; @@ -1593,7 +1896,7 @@ method call(AI::MXNet::Symbol $inputs, SymbolOrArrayOfSymbols $states) p => $p ); }; - my $prev_output = $self->prev_output || AI::MXNet::Symbol->zeros(shape => [0, 0]); + my $prev_output = $self->prev_output // AI::MXNet::Symbol->zeros(shape => [0, 0]); my $output = $p_outputs != 0 ? AI::MXNet::Symbol->where( &{$mask}($p_outputs, $next_output), diff --git a/perl-package/AI-MXNet/lib/AI/MXNet/Symbol.pm b/perl-package/AI-MXNet/lib/AI/MXNet/Symbol.pm index a5298c7..eed6e93 100644 --- a/perl-package/AI-MXNet/lib/AI/MXNet/Symbol.pm +++ b/perl-package/AI-MXNet/lib/AI/MXNet/Symbol.pm @@ -1232,7 +1232,7 @@ method Variable( Maybe[Num] :$lr_mult=, Maybe[Num] :$wd_mult=, Maybe[Dtype] :$dtype=, - Maybe[AI::MXNet::Initializer] :$init=, + Maybe[Initializer] :$init=, HashRef[Str] :$kwargs={}, Maybe[Str] :$__layout__= ) diff --git a/perl-package/AI-MXNet/lib/AI/MXNet/Types.pm b/perl-package/AI-MXNet/lib/AI/MXNet/Types.pm index e48ae3c..b4ec7e9 100644 --- a/perl-package/AI-MXNet/lib/AI/MXNet/Types.pm +++ b/perl-package/AI-MXNet/lib/AI/MXNet/Types.pm @@ -34,6 +34,7 @@ class_type 'AI::MXNet::Callback'; class_type 'AI::MXNet::EvalMetric'; class_type 'AI::MXNet::DataParallelExecutorGroup'; class_type 'AI::MXNet::Optimizer'; +class_type 'AI::MXNet::Initializer'; class_type 'AI::MXNet::InitDesc'; class_type 'AI::MXNet::IRHeader'; subtype "AcceptableInput" => as "Num|PDL|PDL::Matrix|AI::MXNet::NDArray|AI::MXNet::NDArray::Slice|ArrayRef"; @@ -55,6 +56,7 @@ subtype "NameShape" => as "ArrayRef" => where { subtype "Callback" => as "CodeRef|ArrayRef[Coderef]|AI::MXNet::Callback|ArrayRef[AI::MXNet::Callback]"; subtype "EvalMetric" => as "AI::MXNet::EvalMetric|Str|CodeRef"; subtype "Optimizer" => as "AI::MXNet::Optimizer|Str"; -subtype "Activation" => as "AI::MXNet::Symbol|Str"; +subtype "Initializer" => as "AI::MXNet::Initializer|Str"; +subtype "Activation" => as "AI::MXNet::Symbol|Str|CodeRef"; subtype "SymbolOrArrayOfSymbols" => as "AI::MXNet::Symbol|ArrayRef[AI::MXNet::Symbol]"; subtype "NameShapeOrDataDesc" => as "NameShape|AI::MXNet::DataDesc"; diff --git a/perl-package/AI-MXNet/lib/AI/MXNet/Visualization.pm b/perl-package/AI-MXNet/lib/AI/MXNet/Visualization.pm index 4cdc135..e28cd65 100644 --- a/perl-package/AI-MXNet/lib/AI/MXNet/Visualization.pm +++ b/perl-package/AI-MXNet/lib/AI/MXNet/Visualization.pm @@ -371,6 +371,7 @@ method plot_network( } $dot->graph->add_node($name, label => $label, %attr); }; + # add edges for my $node (@{ $nodes }) { @@ -395,6 +396,13 @@ method plot_network( { my $key = $input_name; $key .= '_output' if $input_node->{op} ne 'null'; + if($input_node->{op} ne 'null' and exists $input_node->{attr}) + { + if(ref $input_node->{attr} eq 'HASH' and exists $input_node->{attr}{num_outputs}) + { + $key .= ($input_node->{attr}{num_outputs} - 1); + } + } my $end = @{ $shape_dict{$key} }; $attr{label} = join('x', @{ $shape_dict{$key} }[1..$end-1]); } diff --git a/perl-package/AI-MXNet/t/test_model_parallel.t b/perl-package/AI-MXNet/t/test_model_parallel.t new file mode 100644 index 0000000..6a8aba7 --- /dev/null +++ b/perl-package/AI-MXNet/t/test_model_parallel.t @@ -0,0 +1,74 @@ +use strict; +use warnings; +use Test::More tests => 4; +use AI::MXNet qw(mx); +use AI::MXNet::TestUtils qw(reldiff); +use AI::MXNet::Base; + +sub test_chain +{ + my $ctx1 = mx->cpu(0); + my $ctx2 = mx->cpu(1); + my $n = 2; + my $data1 = mx->sym->Variable('data1'); + my $data2 = mx->sym->Variable('data2'); + my $data3 = mx->sym->Variable('data2'); + my $net; + { + local($mx::AttrScope) = mx->AttrScope(ctx_group=>'dev1'); + $net = $data1 + $data2; + $net = $net * 3; + } + { + local($mx::AttrScope) = mx->AttrScope(ctx_group=>'dev2'); + $net = $net + $data3; + } + + my $arr = []; + my $arr_grad = []; + my $shape = [4, 5]; + { + local($mx::Context) = $ctx1; + for (0..$n-1) + { + push @$arr, mx->nd->empty($shape); + push @$arr_grad, mx->nd->empty($shape); + } + } + { + local($mx::Context) = $ctx2; + push @$arr, mx->nd->empty($shape); + push @$arr_grad, mx->nd->empty($shape); + } + + my $exec1 = $net->bind( + ctx => $ctx1, + args => $arr, + args_grad => $arr_grad, + group2ctx => { dev1 => $ctx1, dev2 => $ctx2 } + ); + $arr->[0] .= 1; + $arr->[1] .= 2; + $arr->[2] .= 3; + my $arr2 = [map { $_->copyto($ctx1) } @$arr]; + my $arr_grad2 = [map { $_->copyto($ctx1) } @$arr_grad]; + my $exec2 = $net->bind( + ctx => $ctx1, + args => $arr2, + args_grad => $arr_grad2 + ); + + $exec1->forward(1); + $exec2->forward(1); + ok(reldiff($exec1->outputs->[0]->aspdl, $exec2->outputs->[0]->aspdl) < 1e-6); + my $out_grad = mx->nd->empty($shape, ctx => $ctx1); + $out_grad .= 1; + $exec1->backward([$out_grad]); + $exec2->backward([$out_grad->copyto($ctx1)]); + zip(sub { + my ($a, $b) = @_; + ok(reldiff($a->aspdl, $b->aspdl) < 1e-6); + }, $arr_grad, $arr_grad2); +} + +test_chain(); diff --git a/perl-package/AI-MXNet/t/test_rnn.t b/perl-package/AI-MXNet/t/test_rnn.t index 77332b1..76242c0 100644 --- a/perl-package/AI-MXNet/t/test_rnn.t +++ b/perl-package/AI-MXNet/t/test_rnn.t @@ -3,7 +3,7 @@ use warnings; use AI::MXNet qw(mx); use AI::MXNet::TestUtils qw(same); use PDL; -use Test::More tests => 45; +use Test::More tests => 54; sub test_rnn { @@ -201,6 +201,63 @@ sub test_zoneout is_deeply($outs, [[10, 100], [10, 100], [10, 100]]); } +sub test_convrnn +{ + my $cell = mx->rnn->ConvRNNCell(input_shape => [1, 3, 16, 10], num_hidden=>10, + h2h_kernel=>[3, 3], h2h_dilate=>[1, 1], + i2h_kernel=>[3, 3], i2h_stride=>[1, 1], + i2h_pad=>[1, 1], i2h_dilate=>[1, 1], + prefix=>'rnn_'); + my $inputs = [map { mx->sym->Variable("rnn_t${_}_data") } 0..2]; + my ($outputs) = $cell->unroll(3, inputs => $inputs); + $outputs = mx->sym->Group($outputs); + is_deeply( + [sort keys %{ $cell->params->_params }], + ['rnn_h2h_bias', 'rnn_h2h_weight', 'rnn_i2h_bias', 'rnn_i2h_weight'] + ); + is_deeply($outputs->list_outputs(), ['rnn_t0_out_output', 'rnn_t1_out_output', 'rnn_t2_out_output']); + my (undef, $outs) = $outputs->infer_shape(rnn_t0_data=>[1, 3, 16, 10], rnn_t1_data=>[1, 3, 16, 10], rnn_t2_data=>[1, 3, 16, 10]); + is_deeply($outs, [[1, 10, 16, 10], [1, 10, 16, 10], [1, 10, 16, 10]]); +} + +sub test_convlstm +{ + my $cell = mx->rnn->ConvLSTMCell(input_shape => [1, 3, 16, 10], num_hidden=>10, + h2h_kernel=>[3, 3], h2h_dilate=>[1, 1], + i2h_kernel=>[3, 3], i2h_stride=>[1, 1], + i2h_pad=>[1, 1], i2h_dilate=>[1, 1], + prefix=>'rnn_', forget_bias => 1); + my $inputs = [map { mx->sym->Variable("rnn_t${_}_data") } 0..2]; + my ($outputs) = $cell->unroll(3, inputs => $inputs); + $outputs = mx->sym->Group($outputs); + is_deeply( + [sort keys %{ $cell->params->_params }], + ['rnn_h2h_bias', 'rnn_h2h_weight', 'rnn_i2h_bias', 'rnn_i2h_weight'] + ); + is_deeply($outputs->list_outputs(), ['rnn_t0_out_output', 'rnn_t1_out_output', 'rnn_t2_out_output']); + my (undef, $outs) = $outputs->infer_shape(rnn_t0_data=>[1, 3, 16, 10], rnn_t1_data=>[1, 3, 16, 10], rnn_t2_data=>[1, 3, 16, 10]); + is_deeply($outs, [[1, 10, 16, 10], [1, 10, 16, 10], [1, 10, 16, 10]]); +} + +sub test_convgru +{ + my $cell = mx->rnn->ConvGRUCell(input_shape => [1, 3, 16, 10], num_hidden=>10, + h2h_kernel=>[3, 3], h2h_dilate=>[1, 1], + i2h_kernel=>[3, 3], i2h_stride=>[1, 1], + i2h_pad=>[1, 1], i2h_dilate=>[1, 1], + prefix=>'rnn_', forget_bias => 1); + my $inputs = [map { mx->sym->Variable("rnn_t${_}_data") } 0..2]; + my ($outputs) = $cell->unroll(3, inputs => $inputs); + $outputs = mx->sym->Group($outputs); + is_deeply( + [sort keys %{ $cell->params->_params }], + ['rnn_h2h_bias', 'rnn_h2h_weight', 'rnn_i2h_bias', 'rnn_i2h_weight'] + ); + is_deeply($outputs->list_outputs(), ['rnn_t0_out_output', 'rnn_t1_out_output', 'rnn_t2_out_output']); + my (undef, $outs) = $outputs->infer_shape(rnn_t0_data=>[1, 3, 16, 10], rnn_t1_data=>[1, 3, 16, 10], rnn_t2_data=>[1, 3, 16, 10]); + is_deeply($outs, [[1, 10, 16, 10], [1, 10, 16, 10], [1, 10, 16, 10]]); +} + test_rnn(); test_lstm(); test_lstm_forget_bias(); @@ -211,3 +268,6 @@ test_stack(); test_bidirectional(); test_unfuse(); test_zoneout(); +test_convrnn(); +test_convlstm(); +test_convgru(); diff --git a/perl-package/AI-MXNetCAPI/Changes b/perl-package/AI-MXNetCAPI/Changes index 17595b4..1a6356c 100644 --- a/perl-package/AI-MXNetCAPI/Changes +++ b/perl-package/AI-MXNetCAPI/Changes @@ -1,5 +1,8 @@ Revision history for Perl extension AI::MXNetCAPI +1.0102 Sun Aug 6 16:55:08 PDT 2017 + - updated autograd calls. + 1.0101 Sun Jul 2 17:16:01 PDT 2017 - refactored CachedOp, using strings to index the kvstore. diff --git a/perl-package/AI-MXNetCAPI/META.json b/perl-package/AI-MXNetCAPI/META.json index a79b1e0..a6d65fd 100644 --- a/perl-package/AI-MXNetCAPI/META.json +++ b/perl-package/AI-MXNetCAPI/META.json @@ -37,5 +37,5 @@ } }, "release_status" : "stable", - "version" : "1.0101" + "version" : "1.0102" } diff --git a/perl-package/AI-MXNetCAPI/META.yml b/perl-package/AI-MXNetCAPI/META.yml index 84b7801..0e3bb53 100644 --- a/perl-package/AI-MXNetCAPI/META.yml +++ b/perl-package/AI-MXNetCAPI/META.yml @@ -19,4 +19,4 @@ no_index: - inc requires: Test::More: '0' -version: '1.0101' +version: '1.0102' diff --git a/perl-package/AI-MXNetCAPI/README b/perl-package/AI-MXNetCAPI/README index 07df0c3..5c53146 100644 --- a/perl-package/AI-MXNetCAPI/README +++ b/perl-package/AI-MXNetCAPI/README @@ -1,4 +1,4 @@ -AI-MXNetCAPI version 1.0101 +AI-MXNetCAPI version 1.0102 ===================== Swig interface to MXNet c api. diff --git a/perl-package/AI-MXNetCAPI/lib/AI/MXNetCAPI.pm b/perl-package/AI-MXNetCAPI/lib/AI/MXNetCAPI.pm index f092057..0a93d71 100644 --- a/perl-package/AI-MXNetCAPI/lib/AI/MXNetCAPI.pm +++ b/perl-package/AI-MXNetCAPI/lib/AI/MXNetCAPI.pm @@ -18,7 +18,7 @@ package AI::MXNetCAPI; use base qw(DynaLoader); bootstrap AI::MXNetCAPI; -our $VERSION = '1.0101'; +our $VERSION = '1.0102'; 1; __END__ diff --git a/perl-package/AI-MXNetCAPI/mxnet.i b/perl-package/AI-MXNetCAPI/mxnet.i index bf00e68..fd1a471 100644 --- a/perl-package/AI-MXNetCAPI/mxnet.i +++ b/perl-package/AI-MXNetCAPI/mxnet.i @@ -459,6 +459,13 @@ int MXNDArrayGetContext(NDArrayHandle handle, int *out, int *out); /*! + * \brief return gradient buffer attached to this NDArray + * \param handle NDArray handle + * \return 0 when success, -1 when failure happens + */ +int MXNDArrayGetGrad(NDArrayHandle handle, NDArrayHandle *out); + +/*! * \brief detach and ndarray from computation graph by clearing entry_ * \param handle NDArray handle * \return 0 when success, -1 when failure happens -- To stop receiving notification emails like this one, please contact ['"comm...@mxnet.apache.org" <comm...@mxnet.apache.org>'].