AI-MXNet
view release on metacpan or search on metacpan
lib/AI/MXNet/NDArray.pm view on Meta::CPAN
package AI::MXNet::NDArray;
=head1 NAME
AI::MXNet::NDArray - Multidimensional tensor object of MXNet.
=cut
use strict;
use warnings;
use AI::MXNet::Base;
use AI::MXNet::NDArray::Slice;
use AI::MXNet::Context;
use Mouse;
use AI::MXNet::Function::Parameters;
use overload
'""' => \&stringify,
'+' => \&add,
'+=' => \&iadd,
'-' => \&subtract,
'-=' => \&isubtract,
'*' => \&multiply,
'*=' => \&imultiply,
'/' => \÷,
'/=' => \&idivide,
'%' => \&modulo,
'%=' => \&imodulo,
'**' => \&power,
'==' => \&equal,
'!=' => \¬_equal,
'>' => \&greater,
'>=' => \&greater_equal,
'<' => \&lesser,
'<=' => \&lesser_equal,
'.=' => \&set,
'=' => sub { $_[0] };
extends 'AI::MXNet::NDArray::Base';
has 'writable' => (is => 'rw', isa => 'Int', default => 1, lazy => 1);
has 'handle' => (is => 'rw', isa => 'NDArrayHandle', required => 1);
sub DEMOLISH
{
check_call(AI::MXNetCAPI::NDArrayFree(shift->handle));
}
method STORABLE_freeze($cloning)
{
my $buf = check_call(AI::MXNetCAPI::NDArraySaveRawBytes($self->handle));
return ($buf,\ $self->writable);
}
method STORABLE_thaw($cloning, $buf, $writable)
{
my $handle = check_call(
AI::MXNetCAPI::NDArrayLoadFromRawBytes(
$buf, length($buf)
)
);
$self->handle($handle);
$self->writable($$writable);
}
method at(Index @indices)
{
confess("No idxs supplied") unless @indices;
my $shape = $self->shape;
my $dsize = @$shape;
my $isize = @indices;
confess("Dimensions size $dsize < indexes size $isize")
if $dsize < $isize;
confess("Dimensions size $dsize = indexes size $isize,
ndarray only supports either ->at on dimension 0
or full crop")
if $isize > 1 and $dsize != $isize;
my $i = 0;
zip(sub {
my ($idx, $dim_size) = @_;
confess("Dimension $i mismatch Idx: $idx >= Dim Size: $dim_size")
if $idx >= $dim_size or ($idx + $dim_size) < 0;
++$i;
}, \@indices, $shape);
$i = 0;
for my $v (@indices)
{
$v += $shape->[$i] if $v < 0;
++$i;
}
return $self->_at($indices[0]) if @indices == 1;
return $self->slice(@indices);
}
method slice(Slice @slices)
{
confess("No slices supplied") unless @slices;
my $shape = $self->shape;
my $dsize = @$shape;
my $isize = @slices;
confess("Dimensions size $dsize < slices size $isize")
if $dsize < $isize;
confess("Dimensions size $dsize != slices size $isize,
ndarray only supports either ->slice on dimension 0
or full crop")
if $isize > 1 and $dsize != $isize;
my $i = -1;
@slices = map {
++$i;
ref $_ ? (@$_ == 1 ? [$_->[0], $shape->[$i] - 1] : $_) : ($_ eq 'X' ? [0, $shape->[$i] - 1] : [$_, $_]);
} @slices;
zip(sub {
my ($slice, $dim_size) = @_;
my ($begin, $end, $stride) = @$slice;
confess("NDArray does not support slice strides != 1")
if ($stride//0) > 1;
confess("Dimension $i mismatch slice begin : $begin >= Dim Size: $dim_size")
if $begin >= $dim_size or ($begin + $dim_size) < 0;
confess("Dimension $i mismatch slice end : $end >= Dim Size: $dim_size")
lib/AI/MXNet/NDArray.pm view on Meta::CPAN
}
${$pdl->get_dataref} = $buf;
$pdl->upd_data;
return $pdl;
}
=head2 _slice
Returns sliced NDArray that shares memory with the current one.
Parameters
----------
start : int
Starting index of slice.
stop : int
Finishing index of slice.
=cut
method _slice (
Index $start,
Index $stop
)
{
confess("start $start > stop $stop") if $start > $stop;
my $handle = check_call(
AI::MXNetCAPI::NDArraySlice(
$self->handle,
$start,
$stop
)
);
return __PACKAGE__->new(handle => $handle, writable => $self->writable);
}
=head2 _at
Returns a sub NDArray that shares memory with current one.
Parameters
----------
idx : int
index of the sub array.
=cut
method _at(Index $idx)
{
my $handle = check_call(
AI::MXNetCAPI::NDArrayAt(
$self->handle, $idx >=0 ? $idx : $self->shape->[0] + $idx
)
);
return __PACKAGE__->new(handle => $handle, writable => $self->writable);
}
=head2 reshape
Returns a reshaped NDArray that shares the memory with current one.
One shape dimension can be -1. In this case, the value is inferred
from the length of the array and remaining dimensions.
Parameters
----------
new_shape : Shape
new shape of NDArray
=cut
method reshape(ArrayRef[Int] $new_shape)
{
my $i = -1;
my @inferred = map { $i++; $_ == -1 ? ($i) : () } @$new_shape;
assert((@inferred <= 1), 'Only one dimension can be inferred.');
if(@inferred)
{
$new_shape->[$inferred[0]] = product(@{ $self->shape })/product(map { abs($_) } @{ $new_shape });
}
my $handle = check_call(
AI::MXNetCAPI::NDArrayReshape(
$self->handle,
scalar(@$new_shape),
$new_shape
)
);
return __PACKAGE__->new(handle => $handle, writable => $self->writable);
}
=head2 ndim
Returns the number of dimensions of this array.
=cut
method ndim()
{
scalar(@{ $self->shape });
}
=head2 moveaxis
Moves the 'source' axis into the 'destination' position
while leaving the other axes in their original order
Parameters
----------
source : int
Original position of the axes to move.
destination : int
Destination position for each of the original axes.
Returns
-------
result :NDArray
Array with moved axes.
Examples
--------
> $X = mx->nd->array([[1, 2, 3],
[4, 5, 6]]);
> print Dumper($X->moveaxis(0, 1)->shape)
> [3, 2]
=cut
lib/AI/MXNet/NDArray.pm view on Meta::CPAN
- `/path-to/my-local-ndarray`
$data : array ref of NDArrays or hash ref of NDArrays
The data to be saved.
=cut
method save(Str $filename, ArrayRef[AI::MXNet::NDArray]|HashRef[AI::MXNet::NDArray] $data)
{
my $handles = [];
my $names = [];
if(ref $data eq 'HASH')
{
for my $name (keys %$data)
{
push @$names, $name;
push @$handles, $data->{ $name }->handle;
}
}
else
{
@$handles = map { $_->handle } @$data;
}
check_call(
AI::MXNetCAPI::NDArraySave(
$filename,
scalar(@$handles),
$handles,
$names
)
);
}
=head2 imdecode
Decode an image from string. Requires OpenCV to work.
Parameters
----------
$str_img : str
binary image data
:$clip_rect : iterable of 4 int
clip decoded image to rectangle (x0, y0, x1, y1)
:$out= : Maybe[NDArray]
output buffer. can be 3 dimensional (c, h, w) or 4 dimensional (n, c, h, w)
:$index : int
output decoded image to i-th slice of 4 dimensional buffer
:$channels=3 : int
number of channels to output. Decode to grey scale when channels = 1.
$mean= : Maybe[NDArray]
subtract mean from decode image before outputting.
=cut
method imdecode($str_img, ArrayRef[Int] :$clip_rect=[0, 0, 0, 0],
Maybe[AI::MXNet::NDArray] :$out=, Int :$index=0, Int :$channels=3, Maybe[AI::MXNet::NDArray] :$mean=)
{
return __PACKAGE__->_imdecode(
$mean//__PACKAGE__->_new_empty_handle(),
$index,
@$clip_rect,
$channels,
length($str_img),
{ str_img => $str_img, ($out ? (out => $out) : ()) }
);
}
=head2 _new_empty_handle
Returns a new empty handle.
Empty handle can be used to hold result
Returns
-------
a new empty ndarray handle
=cut
sub _new_empty_handle
{
my $hdl = check_call(AI::MXNetCAPI::NDArrayCreateNone());
return $hdl;
}
=head2 _new_alloc_handle
Returns a new handle with specified shape and context.
Empty handle is only used to hold results
Returns
-------
a new empty ndarray handle
=cut
func _new_alloc_handle($shape, $ctx, $delay_alloc, $dtype)
{
my $hdl = check_call(AI::MXNetCAPI::NDArrayCreateEx(
$shape,
scalar(@$shape),
$ctx->device_type_id,
$ctx->device_id,
$delay_alloc,
$dtype)
);
return $hdl;
}
=head2 waitall
Wait for all async operations to finish in MXNet.
This function is used for benchmarks only.
=cut
method waitall()
{
check_call(AI::MXNetCAPI::NDArrayWaitAll());
}
=head2 _fresh_grad
Parameters:
----------
( run in 0.549 second using v1.01-cache-2.11-cpan-39bf76dae61 )