view release on metacpan or search on metacpan
examples/char_lstm.pl view on Meta::CPAN
$stack->add($cell);
}
my $data = mx->sym->Variable('data');
my $label = mx->sym->Variable('softmax_label');
my $embed = mx->sym->Embedding(
data => $data, input_dim => scalar(keys %vocabulary),
output_dim => $num_embed, name => 'embed'
);
$stack->reset;
my ($outputs, $states) = $stack->unroll($seq_size, inputs => $embed, merge_outputs => 1);
my $pred = mx->sym->Reshape($outputs, shape => [-1, $num_hidden*(1+($bidirectional ? 1 : 0))]);
$pred = mx->sym->FullyConnected(data => $pred, num_hidden => $data_iter->vocab_size, name => 'pred');
$label = mx->sym->Reshape($label, shape => [-1]);
my $net = mx->sym->SoftmaxOutput(data => $pred, label => $label, name => 'softmax');
my $contexts;
if(defined $gpus)
{
$contexts = [map { mx->gpu($_) } split(/,/, $gpus)];
}
examples/cudnn_lstm_bucketing.pl view on Meta::CPAN
$cell = mx->rnn->FusedRNNCell(
$num_hidden, mode => 'lstm', num_layers => $num_layers,
bidirectional => $bidirectional, dropout => $dropout
);
}
my $sym_gen = sub { my $seq_len = shift;
my $data = mx->sym->Variable('data');
my $label = mx->sym->Variable('softmax_label');
my $embed = mx->sym->Embedding(data=>$data, input_dim=>scalar(keys %$vocab), output_dim=>$num_embed,name=>'embed');
my ($output) = $cell->unroll($seq_len, inputs=>$embed, merge_outputs=>1, layout=>'TNC');
my $pred = mx->sym->Reshape($output, shape=>[-1, $num_hidden*(1+$bidirectional)]);
$pred = mx->sym->FullyConnected(data=>$pred, num_hidden=>scalar(keys %$vocab), name=>'pred');
$label = mx->sym->Reshape($label, shape=>[-1]);
$pred = mx->sym->SoftmaxOutput(data=>$pred, label=>$label, name=>'softmax');
return ($pred, ['data'], ['softmax_label']);
};
my $contexts;
if(defined $gpus)
{
examples/cudnn_lstm_bucketing.pl view on Meta::CPAN
}
my $sym_gen = sub {
my $seq_len = shift;
my $data = mx->sym->Variable('data');
my $label = mx->sym->Variable('softmax_label');
my $embed = mx->sym->Embedding(
data => $data, input_dim => scalar(keys %$vocab),
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*(1+$bidirectional)]);
$pred = mx->sym->FullyConnected(data => $pred, num_hidden => scalar(keys %$vocab), name => 'pred');
$label = mx->sym->Reshape($label, shape => [-1]);
$pred = mx->sym->SoftmaxOutput(data => $pred, label => $label, name => 'softmax');
return ($pred, ['data'], ['softmax_label']);
};
my $contexts;
if($gpus)
{
$contexts = [map { mx->gpu($_) } split(/,/, $gpus)];
examples/lstm_bucketing.pl view on Meta::CPAN
my $sym_gen = sub {
my $seq_len = shift;
my $data = mx->sym->Variable('data');
my $label = mx->sym->Variable('softmax_label');
my $embed = mx->sym->Embedding(
data => $data, input_dim => scalar(keys %$vocabulary),
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 => scalar(keys %$vocabulary), name => 'pred');
$label = mx->sym->Reshape($label, shape => [-1]);
$pred = mx->sym->SoftmaxOutput(data => $pred, label => $label, name => 'softmax');
return ($pred, ['data'], ['softmax_label']);
};
my $contexts;
if(defined $gpus)
{
lib/AI/MXNet/Executor/Group.pm view on Meta::CPAN
}
# Load label into sliced arrays
func _load_label($batch, $targets, $major_axis)
{
_load_general($batch->label, $targets, $major_axis);
}
# Merge outputs that live on multiple context into one, so that they look
# like living on one context.
func _merge_multi_context($outputs, $major_axis)
{
my @rets;
zip(sub {
my ($tensors, $axis) = @_;
if($axis >= 0)
{
if(@$tensors == 1)
{
push @rets, $tensors->[0];
}
lib/AI/MXNet/Executor/Group.pm view on Meta::CPAN
# first one, without checking they are actually the same
push @rets, $tensors->[0];
}
}, $outputs, $major_axis);
return \@rets;
}
## TODO
## this class is here because of https://github.com/gfx/p5-Mouse/pull/67
## once 2.4.7 version of Mouse in Ubuntu for affected Perl version
## these accessors should be merged into main class
package AI::MXNet::DataParallelExecutorGroup::_private;
use Mouse;
has [qw/output_layouts label_layouts arg_names aux_names
batch_size slices execs data_arrays
label_arrays param_arrays grad_arrays aux_arrays
data_layouts shared_data_arrays input_grad_arrays
_default_execs state_arrays/
] => (is => 'rw', init_arg => undef);
package AI::MXNet::DataParallelExecutorGroup;
lib/AI/MXNet/Executor/Group.pm view on Meta::CPAN
}, $self->param_names, $self->_p->param_arrays);
zip(sub {
my ($name, $block) = @_;
my $weight = sum(map { $_->copyto(AI::MXNet::Context->cpu) } @{ $block }) / @{ $block };
$weight->astype($aux_params->{$name}->dtype)->copyto($aux_params->{$name});
}, $self->_p->aux_names, $self->_p->aux_arrays);
}
method get_states($merge_multi_context=1)
{
assert((not $merge_multi_context), "merge_multi_context=True is not supported for get_states yet.");
return $self->_p->state_arrays;
}
method set_states($states, $value)
{
if(defined $states)
{
assert((not defined $value), "Only one of states & value can be specified.");
AI::MXNet::Executor::Group::_load_general($states, $self->_p->state_arrays, [(0)x@{ $states }]);
}
lib/AI/MXNet/Executor/Group.pm view on Meta::CPAN
}, $self->symbol->list_outputs, \@shapes, $self->_p->output_layouts);
return \@concat_shapes;
}
=head2 get_outputs
Gets outputs of the previous forward computation.
Parameters
----------
merge_multi_context : bool
Default is 1. In the case when data-parallelism is used, the outputs
will be collected from multiple devices. A 1 value indicates that we
should merge the collected results so that they look like from a single
executor.
Returns
-------
If merge_multi_context is 1, it is [$out1, $out2]. Otherwise, it
is [[$out1_dev1, $out1_dev2], [$out2_dev1, $out2_dev2]]. All the output
elements are `AI::MXNet::NDArray`.
=cut
method get_outputs(Bool $merge_multi_context=1)
{
my $outputs;
for my $i (0..@{ $self->_p->execs->[0]->outputs }-1)
{
my @tmp;
for my $exec (@{ $self->_p->execs })
{
push @tmp, $exec->outputs->[$i];
}
push @$outputs, \@tmp;
}
if($merge_multi_context)
{
$outputs = AI::MXNet::Executor::Group::_merge_multi_context($outputs, $self->_p->output_layouts);
}
return $outputs;
}
=head2 get_input_grads
Get the gradients with respect to the inputs of the module.
Parameters
----------
merge_multi_context : bool
Default is 1. In the case when data-parallelism is used, the outputs
will be collected from multiple devices. A 1 value indicates that we
should merge the collected results so that they look like from a single
executor.
Returns
-------
If merge_multi_context is 1, it is [$grad1, $grad2]. Otherwise, it
is [[$grad1_dev1, $grad1_dev2], [$grad2_dev1, $grad2_dev2]]. All the output
elements are AI::MXNet::NDArray.
=cut
method get_input_grads(Bool $merge_multi_context=1)
{
confess("assert \$self->inputs_need_grad") unless $self->inputs_need_grad;
if($merge_multi_context)
{
return AI::MXNet::Executor::Group::_merge_multi_context($self->_p->input_grad_arrays, $self->_p->data_layouts);
}
return $self->_p->input_grad_arrays;
}
=head2 backward
Run backward on all devices. A backward should be called after
a call to the forward function. Backward cannot be called unless
$self->for_training is 1.
lib/AI/MXNet/Module.pm view on Meta::CPAN
## TODO
## this class is here because of https://github.com/gfx/p5-Mouse/pull/67
## once 2.4.7 version of Mouse in Ubuntu for affected Perl version
## these accessors should be merged into main class
package AI::MXNet::Module::Private;
use Mouse;
has [qw/_param_names _fixed_param_names
_aux_names _data_names _label_names _state_names
_output_names _arg_params _aux_params
_params_dirty _optimizer _kvstore
_update_on_kvstore _updater _work_load_list
_preload_opt_states _exec_group
_data_shapes _label_shapes _context _grad_req/
lib/AI/MXNet/Module.pm view on Meta::CPAN
$self->_p->_exec_group->_p->param_arrays,
$self->_p->_exec_group->_p->grad_arrays,
$self->_p->_updater,
scalar(@{ $self->_p->_context}),
$self->_p->_kvstore,
$self->_p->_exec_group->param_names
);
}
}
method get_outputs(Bool $merge_multi_context=1)
{
assert($self->binded and $self->params_initialized);
return $self->_p->_exec_group->get_outputs($merge_multi_context);
}
method get_input_grads(Bool $merge_multi_context=1)
{
assert($self->binded and $self->params_initialized and $self->inputs_need_grad);
return $self->_p->_exec_group->get_input_grads($merge_multi_context);
}
method get_states(Bool $merge_multi_context=1)
{
assert($self->binded and $self->params_initialized);
return $self->_p->_exec_group->get_states($merge_multi_context);
}
method set_states(:$states=, :$value=)
{
assert($self->binded and $self->params_initialized);
return $self->_p->_exec_group->set_states($states, $value);
}
method update_metric(
AI::MXNet::EvalMetric $eval_metric,
lib/AI/MXNet/Module/Base.pm view on Meta::CPAN
=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)
lib/AI/MXNet/Module/Base.pm view on Meta::CPAN
}
$self->set_params(\%arg_params, \%aux_params);
}
=head2 get_states
The states from all devices
Parameters
----------
$merge_multi_context=1 : Bool
Default is true (1). In the case when data-parallelism is used, the states
will be collected from multiple devices. A true value indicate that we
should merge the collected results so that they look like from a single
executor.
Returns
-------
If $merge_multi_context is 1, it is like [$out1, $out2]. Otherwise, it
is like [[$out1_dev1, $out1_dev2], [$out2_dev1, $out2_dev2]]. All the output
elements are AI::MXNet::NDArray.
=cut
method get_states(Bool $merge_multi_context=1)
{
assert($self->binded and $self->params_initialized);
assert(not $merge_multi_context);
return [];
}
=head2 set_states
Set value for states. You can specify either $states or $value, not both.
Parameters
----------
$states= : Maybe[ArrayRef[ArrayRef[AI::MXNet::NDArray]]]
lib/AI/MXNet/Module/Base.pm view on Meta::CPAN
{
confess("NotImplemented")
}
=head2 get_outputs
The outputs of the previous forward computation.
Parameters
----------
$merge_multi_context=1 : Bool
=cut
method get_outputs(Bool $merge_multi_context=1) { confess("NotImplemented") }
=head2 get_input_grads
The gradients to the inputs, computed in the previous backward computation.
Parameters
----------
$merge_multi_context=1 : Bool
=cut
method get_input_grads(Bool $merge_multi_context=1) { confess("NotImplemented") }
=head2 update
Update parameters according to the installed optimizer and the gradients computed
in the previous forward-backward batch.
=cut
method update() { confess("NotImplemented") }
=head2 update_metric
lib/AI/MXNet/Module/Bucketing.pm view on Meta::CPAN
my $sym_gen = sub {
my $seq_len = shift;
my $data = mx->sym->Variable('data');
my $label = mx->sym->Variable('softmax_label');
my $embed = mx->sym->Embedding(
data => $data, input_dim => scalar(keys %$vocabulary),
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 => scalar(keys %$vocabulary), name => 'pred');
$label = mx->sym->Reshape($label, shape => [-1]);
$pred = mx->sym->SoftmaxOutput(data => $pred, label => $label, name => 'softmax');
return ($pred, ['data'], ['softmax_label']);
};
my $contexts;
if(defined $gpus)
{
lib/AI/MXNet/Module/Bucketing.pm view on Meta::CPAN
arg_params => $arg_params,
aux_params => $aux_params,
allow_missing => $allow_missing,
force_init => $force_init,
allow_extra => $allow_extra
);
$self->_params_dirty(0);
$self->params_initialized(1);
}
method get_states(Bool $merge_multi_context=1)
{
assert($self->binded and $self->params_initialized);
$self->_curr_module->get_states($merge_multi_context);
}
method set_states(:$states=, :$value=)
{
assert($self->binded and $self->params_initialized);
$self->_curr_module->set_states(states => $states, value => $value);
}
=head2 bind
lib/AI/MXNet/Module/Bucketing.pm view on Meta::CPAN
$self->_curr_module->backward($out_grads);
}
method update()
{
assert($self->binded and $self->params_initialized and $self->optimizer_initialized);
$self->_params_dirty(1);
$self->_curr_module->update;
}
method get_outputs(Bool $merge_multi_context=1)
{
assert($self->binded and $self->params_initialized);
return $self->_curr_module->get_outputs($merge_multi_context);
}
method get_input_grads(Bool $merge_multi_context=1)
{
assert($self->binded and $self->params_initialized and $self->inputs_need_grad);
return $self->_curr_module->get_input_grads($merge_multi_context);
}
method update_metric(
AI::MXNet::EvalMetric $eval_metric,
ArrayRef[AI::MXNet::NDArray] $labels
)
{
assert($self->binded and $self->params_initialized);
$self->_curr_module->update_metric($eval_metric, $labels);
}
lib/AI/MXNet/RNN/Cell.pm view on Meta::CPAN
:$begin_state : array ref of Symbol
input states. Created by begin_state()
or output state of another cell. Created
from begin_state() if undef.
:$input_prefix : str
prefix for automatically created input
placehodlers.
:$layout : str
layout of input symbol. Only used if the input
is a single Symbol.
:$merge_outputs : Bool
If 0, returns outputs as an array ref of Symbols.
If 1, concatenates the output across the time steps
and returns a single symbol with the shape
[$batch_size, $length, ...) if the layout equal to 'NTC',
or [$length, $batch_size, ...) if the layout equal tp 'TNC'.
If undef, output whatever is faster
Returns
-------
$outputs : array ref of Symbol or Symbol
lib/AI/MXNet/RNN/Cell.pm view on Meta::CPAN
has the same structure as begin_state()
=cut
method unroll(
Int $length,
Maybe[AI::MXNet::Symbol|ArrayRef[AI::MXNet::Symbol]] :$inputs=,
Maybe[AI::MXNet::Symbol|ArrayRef[AI::MXNet::Symbol]] :$begin_state=,
Str :$input_prefix='',
Str :$layout='NTC',
Maybe[Bool] :$merge_outputs=
)
{
$self->reset;
my $axis = index($layout, 'T');
if(not defined $inputs)
{
$inputs = [
map { AI::MXNet::Symbol->Variable("${input_prefix}t${_}_data") } (0..$length-1)
];
}
lib/AI/MXNet/RNN/Cell.pm view on Meta::CPAN
my @inputs = @{ $inputs };
for my $i (0..$length-1)
{
my $output;
($output, $states) = &{$self}(
$inputs[$i],
$states
);
push @$outputs, $output;
}
if($merge_outputs)
{
@$outputs = map { AI::MXNet::Symbol->expand_dims($_, axis => $axis) } @$outputs;
$outputs = AI::MXNet::Symbol->Concat(@$outputs, dim => $axis);
}
return($outputs, $states);
}
method _get_activation($inputs, $activation, @kwargs)
{
if(not ref $activation)
lib/AI/MXNet/RNN/Cell.pm view on Meta::CPAN
{
confess("AI::MXNet::RNN::FusedCell cannot be stepped. Please use unroll");
}
method unroll(
Int $length,
Maybe[AI::MXNet::Symbol|ArrayRef[AI::MXNet::Symbol]] :$inputs=,
Maybe[AI::MXNet::Symbol|ArrayRef[AI::MXNet::Symbol]] :$begin_state=,
Str :$input_prefix='',
Str :$layout='NTC',
Maybe[Bool] :$merge_outputs=
)
{
$self->reset;
my $axis = index($layout, 'T');
$inputs //= AI::MXNet::Symbol->Variable("${input_prefix}data");
if(blessed($inputs))
{
assert(
(@{ $inputs->list_outputs() } == 1),
"unroll doesn't allow grouped symbol as input. Please "
lib/AI/MXNet/RNN/Cell.pm view on Meta::CPAN
$rnn[1]->_set_attr(%attr);
$rnn[2]->_set_attr(%attr);
($outputs, $states) = ($rnn[0], [$rnn[1], $rnn[2]]);
}
else
{
my @rnn = @{ $rnn };
$rnn[1]->_set_attr(%attr);
($outputs, $states) = ($rnn[0], [$rnn[1]]);
}
if(defined $merge_outputs and not $merge_outputs)
{
AI::MXNet::Logging->warning(
"Call RNN::FusedCell->unroll with merge_outputs=1 "
."for faster speed"
);
$outputs = [@ {
AI::MXNet::Symbol->SliceChannel(
$outputs,
axis => 0,
num_outputs => $length,
squeeze_axis => 1
)
}];
lib/AI/MXNet/RNN/Cell.pm view on Meta::CPAN
}
return ($inputs, [map { @$_} @next_states]);
}
method unroll(
Int $length,
Maybe[AI::MXNet::Symbol|ArrayRef[AI::MXNet::Symbol]] :$inputs=,
Maybe[AI::MXNet::Symbol|ArrayRef[AI::MXNet::Symbol]] :$begin_state=,
Str :$input_prefix='',
Str :$layout='NTC',
Maybe[Bool] :$merge_outputs=
)
{
my $num_cells = @{ $self->_cells };
$begin_state //= $self->begin_state;
my $p = 0;
my $states;
my @next_states;
enumerate(sub {
my ($i, $cell) = @_;
my $n = @{ $cell->state_info };
$states = [@{$begin_state}[$p..$p+$n-1]];
$p += $n;
($inputs, $states) = $cell->unroll(
$length,
inputs => $inputs,
input_prefix => $input_prefix,
begin_state => $states,
layout => $layout,
merge_outputs => ($i < $num_cells-1) ? undef : $merge_outputs
);
push @next_states, $states;
}, $self->_cells);
return ($inputs, [map { @{ $_ } } @next_states]);
}
package AI::MXNet::RNN::BidirectionalCell;
use Mouse;
use AI::MXNet::Base;
extends 'AI::MXNet::RNN::Cell::Base';
lib/AI/MXNet/RNN/Cell.pm view on Meta::CPAN
);
return $self->_cells_begin_state($self->_cells, @kwargs);
}
method unroll(
Int $length,
Maybe[AI::MXNet::Symbol|ArrayRef[AI::MXNet::Symbol]] :$inputs=,
Maybe[AI::MXNet::Symbol|ArrayRef[AI::MXNet::Symbol]] :$begin_state=,
Str :$input_prefix='',
Str :$layout='NTC',
Maybe[Bool] :$merge_outputs=
)
{
my $axis = index($layout, 'T');
if(not defined $inputs)
{
$inputs = [
map { AI::MXNet::Symbol->Variable("${input_prefix}t${_}_data") } (0..$length-1)
];
}
lib/AI/MXNet/RNN/Cell.pm view on Meta::CPAN
{
assert(@$inputs == $length);
}
$begin_state //= $self->begin_state;
my $states = $begin_state;
my ($l_cell, $r_cell) = @{ $self->_cells };
my ($l_outputs, $l_states) = $l_cell->unroll(
$length, inputs => $inputs,
begin_state => [@{$states}[0..@{$l_cell->state_info}-1]],
layout => $layout,
merge_outputs => $merge_outputs
);
my ($r_outputs, $r_states) = $r_cell->unroll(
$length, inputs => [reverse @{$inputs}],
begin_state => [@{$states}[@{$l_cell->state_info}..@{$states}-1]],
layout => $layout,
merge_outputs => $merge_outputs
);
if(not defined $merge_outputs)
{
$merge_outputs = (
blessed $l_outputs and $l_outputs->isa('AI::MXNet::Symbol')
and
blessed $r_outputs and $r_outputs->isa('AI::MXNet::Symbol')
);
if(not $merge_outputs)
{
if(blessed $l_outputs and $l_outputs->isa('AI::MXNet::Symbol'))
{
$l_outputs = [
@{ AI::MXNet::Symbol->SliceChannel(
$l_outputs, axis => $axis,
num_outputs => $length,
squeeze_axis => 1
) }
];
lib/AI/MXNet/RNN/Cell.pm view on Meta::CPAN
$r_outputs = [
@{ AI::MXNet::Symbol->SliceChannel(
$r_outputs, axis => $axis,
num_outputs => $length,
squeeze_axis => 1
) }
];
}
}
}
if($merge_outputs)
{
$l_outputs = [@{ $l_outputs }];
$r_outputs = [@{ AI::MXNet::Symbol->reverse(blessed $r_outputs ? $r_outputs : @{ $r_outputs }, axis=>$axis) }];
}
else
{
$r_outputs = [reverse(@{ $r_outputs })];
}
my $outputs = [];
zip(sub {
my ($i, $l_o, $r_o) = @_;
push @$outputs, AI::MXNet::Symbol->Concat(
$l_o, $r_o, dim=>(1+($merge_outputs?1:0)),
name => $merge_outputs
? sprintf('%sout', $self->_output_prefix)
: sprintf('%st%d', $self->_output_prefix, $i)
);
}, [0..@{ $l_outputs }-1], [@{ $l_outputs }], [@{ $r_outputs }]);
if($merge_outputs)
{
$outputs = @{ $outputs }[0];
}
$states = [$l_states, $r_states];
return($outputs, $states);
}
package AI::MXNet::RNN::ConvCell::Base;
use Mouse;
use AI::MXNet::Base;
lib/AI/MXNet/RNN/Cell.pm view on Meta::CPAN
$output = AI::MXNet::Symbol->elemwise_add($output, $inputs, name => $output->name.'_plus_residual');
return ($output, $states)
}
method unroll(
Int $length,
Maybe[AI::MXNet::Symbol|ArrayRef[AI::MXNet::Symbol]] :$inputs=,
Maybe[AI::MXNet::Symbol|ArrayRef[AI::MXNet::Symbol]] :$begin_state=,
Str :$input_prefix='',
Str :$layout='NTC',
Maybe[Bool] :$merge_outputs=
)
{
$self->reset;
$self->base_cell->_modified(0);
my ($outputs, $states) = $self->base_cell->unroll($length, inputs=>$inputs, begin_state=>$begin_state,
layout=>$layout, merge_outputs=>$merge_outputs);
$self->base_cell->_modified(1);
$merge_outputs //= (blessed($outputs) and $outputs->isa('AI::MXNet::Symbol'));
($inputs) = _normalize_sequence($length, $inputs, $layout, $merge_outputs);
if($merge_outputs)
{
$outputs = AI::MXNet::Symbol->elemwise_add($outputs, $inputs, name => $outputs->name . "_plus_residual");
}
else
{
my @temp;
zip(sub {
my ($output_sym, $input_sym) = @_;
push @temp, AI::MXNet::Symbol->elemwise_add($output_sym, $input_sym,
name=>$output_sym->name."_plus_residual");
}, [@{ $outputs }], [@{ $inputs }]);
$outputs = \@temp;
}
return ($outputs, $states);
}
func _normalize_sequence($length, $inputs, $layout, $merge, $in_layout=)
{
assert((defined $inputs),
"unroll(inputs=>undef) has been deprecated. ".
"Please create input variables outside unroll."
);
my $axis = index($layout, 'T');
my $in_axis = defined $in_layout ? index($in_layout, 'T') : $axis;
if(blessed($inputs))
{
if(not $merge)
{
assert(
(@{ $inputs->list_outputs() } == 1),
"unroll doesn't allow grouped symbol as input. Please "
."convert to list first or let unroll handle splitting"
);
$inputs = [ @{ AI::MXNet::Symbol->split(
$inputs,
axis => $in_axis,
num_outputs => $length,
squeeze_axis => 1
) }];
}
}
else
{
assert(not defined $length or @$inputs == $length);
if($merge)
{
$inputs = [map { AI::MXNet::Symbol->expand_dims($_, axis=>$axis) } @{ $inputs }];
$inputs = AI::MXNet::Symbol->Concat(@{ $inputs }, dim=>$axis);
$in_axis = $axis;
}
}
if(blessed($inputs) and $axis != $in_axis)
{
$inputs = AI::MXNet::Symbol->swapaxes($inputs, dim0=>$axis, dim1=>$in_axis);
t/test_module.t view on Meta::CPAN
my $seq_len = shift;
my $data = mx->sym->Variable('data');
my $label = mx->sym->Variable('softmax_label');
my $embed = mx->sym->Embedding(data=>$data, input_dim=>$vocab_dim,
output_dim=>$num_embedding, name=>'embed');
my $stack = mx->rnn->SequentialRNNCell();
for my $i (0..$num_layer-1)
{
$stack->add(mx->rnn->LSTMCell(num_hidden=>$num_hidden, prefix=>"lstm_l${i}_"));
}
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=>$vocab_dim, name=>'pred');
$label = mx->sym->Reshape($label, shape=>[-1]);
$pred = mx->sym->SoftmaxOutput(data=>$pred, label=>$label, name=>'softmax');
return ($pred, ['data'], ['softmax_label']);
};
my $create_bucketing_module = sub { my $key = shift;
t/test_module.t view on Meta::CPAN
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) = @_;
t/test_rnn.t view on Meta::CPAN
sub test_lstm_forget_bias
{
my $forget_bias = 2;
my $stack = mx->rnn->SequentialRNNCell();
$stack->add(mx->rnn->LSTMCell(100, forget_bias=>$forget_bias, prefix=>'l0_'));
$stack->add(mx->rnn->LSTMCell(100, forget_bias=>$forget_bias, prefix=>'l1_'));
my $dshape = [32, 1, 200];
my $data = mx->sym->Variable('data');
my ($sym) = $stack->unroll(1, inputs => $data, merge_outputs => 1);
my $mod = mx->mod->Module($sym, context => mx->cpu(0));
$mod->bind(data_shapes=>[['data', $dshape]]);
$mod->init_params();
my ($bias_argument) = grep { /i2h_bias$/ } @{ $sym->list_arguments };
my $f = zeros(100);
my $expected_bias = $f->glue(0, $forget_bias * ones(100), zeros(200));
ok(
((($mod->get_params())[0]->{$bias_argument}->aspdl - $expected_bias)->abs < 1e-07)->all
);
t/test_rnn.t view on Meta::CPAN
sub test_residual_bidirectional
{
my $cell = mx->rnn->ResidualCell(
mx->rnn->BidirectionalCell(
mx->rnn->GRUCell(25, prefix=>'rnn_l_'),
mx->rnn->GRUCell(25, prefix=>'rnn_r_')
)
);
my $inputs = [map { mx->sym->Variable("rnn_t${_}_data") } 0..1];
my ($outputs) = $cell->unroll(2, inputs => $inputs, merge_outputs=>0);
$outputs = mx->sym->Group($outputs);
is_deeply(
[sort keys %{ $cell->params->_params }],
['rnn_l_h2h_bias', 'rnn_l_h2h_weight', 'rnn_l_i2h_bias', 'rnn_l_i2h_weight',
'rnn_r_h2h_bias', 'rnn_r_h2h_weight', 'rnn_r_i2h_bias', 'rnn_r_i2h_weight']
);
is_deeply(
$outputs->list_outputs,
['bi_t0_plus_residual_output', 'bi_t1_plus_residual_output']
);