AI-MXNet-Gluon-ModelZoo
view release on metacpan or search on metacpan
lib/AI/MXNet/Gluon/ModelZoo/Vision/ResNet.pm view on Meta::CPAN
$x = $self->conv2->($x);
$x = $self->bn3->($x);
$x = $F->Activation($x, act_type=>'relu');
$x = $self->conv3->($x);
return $x + $residual;
}
# Nets
package AI::MXNet::Gluon::ModelZoo::Vision::ResNet::V1;
use AI::MXNet::Gluon::Mouse;
extends 'AI::MXNet::Gluon::HybridBlock';
use AI::MXNet::Base;
=head1 NAME
AI::MXNet::Gluon::ModelZoo::Vision::ResNet::V1 - ResNet V1 model from "Deep Residual Learning for Image Recognition"
=cut
=head1 DESCRIPTION
ResNet V1 model from from "Deep Residual Learning for Image Recognition"
<http://arxiv.org/abs/1512.03385> paper.
Parameters
----------
block : AI::MXNet::Gluon::HybridBlock
Class for the residual block. Options are AI::MXNet::Gluon::ModelZoo::Vision::ResNet::BasicBlockV1,
AI::MXNet::Gluon::ModelZoo::Vision::ResNet::BottleneckV1.
layers : array ref of Int
Numbers of layers in each block
channels : array ref of Int
Numbers of channels in each block. Length should be one larger than layers list.
classes : int, default 1000
Number of classification classes.
thumbnail : bool, default 0
Enable thumbnail.
=cut
has 'block' => (is => 'ro', isa => 'Str', required => 1);
has ['layers',
'channels'] => (is => 'ro', isa => 'ArrayRef[Int]', required => 1);
has 'classes' => (is => 'ro', isa => 'Int', default => 1000);
has 'thumbnail' => (is => 'ro', isa => 'Bool', default => 0);
method python_constructor_arguments() { [qw/block layers channels classes thumbnail/] }
func _conv3x3($channels, $stride, $in_channels)
{
return nn->Conv2D(
$channels, kernel_size=>3, strides=>$stride, padding=>1,
use_bias=>0, in_channels=>$in_channels
);
}
sub BUILD
{
my $self = shift;
assert(@{ $self->layers } == (@{ $self->channels } - 1));
$self->name_scope(sub {
$self->features(nn->HybridSequential(prefix=>''));
if($self->thumbnail)
{
$self->features->add(_conv3x3($self->channels->[0], 1, 0));
}
else
{
$self->features->add(nn->Conv2D($self->channels->[0], 7, 2, 3, use_bias=>0));
$self->features->add(nn->BatchNorm());
$self->features->add(nn->Activation('relu'));
$self->features->add(nn->MaxPool2D(3, 2, 1));
}
for(enumerate($self->layers))
{
my ($i, $num_layer) = @$_;
my $stride = $i == 0 ? 1 : 2;
$self->features->add(
$self->_make_layer(
$self->block, $num_layer, $self->channels->[$i+1],
$stride, $i+1, in_channels=>$self->channels->[$i]
)
);
}
$self->features->add(nn->GlobalAvgPool2D());
$self->output(nn->Dense($self->classes, in_units=>$self->channels->[-1]));
});
}
method _make_layer($block, $layers, $channels, $stride, $stage_index, :$in_channels=0)
{
my $layer = nn->HybridSequential(prefix=>"stage${stage_index}_");
$layer->name_scope(sub {
$layer->add(
$block->new(
$channels, $stride, $channels != $in_channels, in_channels=>$in_channels,
prefix=>''
)
);
for(1..$layers-1)
{
$layer->add($block->new($channels, 1, 0, in_channels=>$channels, prefix=>''));
}
});
return $layer;
}
method hybrid_forward(GluonClass $F, GluonInput $x)
{
$x = $self->features->($x);
$x = $self->output->($x);
return $x;
}
package AI::MXNet::Gluon::ModelZoo::Vision::ResNet::V2;
use AI::MXNet::Gluon::Mouse;
extends 'AI::MXNet::Gluon::HybridBlock';
use AI::MXNet::Base;
=head1 NAME
AI::MXNet::Gluon::ModelZoo::Vision::ResNet::V2 - ResNet V2 model from "Identity Mappings in Deep Residual Networks"
=cut
=head1 DESCRIPTION
ResNet V2 model from "Identity Mappings in Deep Residual Networks"
<https://arxiv.org/abs/1603.05027> paper.
Parameters
----------
block : AI::MXNet::Gluon::HybridBlock
Class for the residual block. Options are AI::MXNet::Gluon::ModelZoo::Vision::ResNet::BasicBlockV2,
AI::MXNet::Gluon::ModelZoo::Vision::ResNet::BottleneckV2.
layers : array ref of Int
Numbers of layers in each block
channels : array ref of Int
Numbers of channels in each block. Length should be one larger than layers list.
classes : int, default 1000
Number of classification classes.
thumbnail : bool, default 0
Enable thumbnail.
=cut
has 'block' => (is => 'ro', isa => 'Str', required => 1);
has ['layers',
'channels'] => (is => 'ro', isa => 'ArrayRef[Int]', required => 1);
has 'classes' => (is => 'ro', isa => 'Int', default => 1000);
has 'thumbnail' => (is => 'ro', isa => 'Bool', default => 0);
method python_constructor_arguments() { [qw/block layers channels classes thumbnail/] }
func _conv3x3($channels, $stride, $in_channels)
{
return nn->Conv2D(
$channels, kernel_size=>3, strides=>$stride, padding=>1,
use_bias=>0, in_channels=>$in_channels
);
}
sub BUILD
{
my $self = shift;
assert(@{ $self->layers } == (@{ $self->channels } - 1));
$self->name_scope(sub {
$self->features(nn->HybridSequential(prefix=>''));
$self->features->add(nn->BatchNorm(scale=>0, center=>0));
if($self->thumbnail)
{
$self->features->add(_conv3x3($self->channels->[0], 1, 0));
}
else
{
$self->features->add(nn->Conv2D($self->channels->[0], 7, 2, 3, use_bias=>0));
$self->features->add(nn->BatchNorm());
$self->features->add(nn->Activation('relu'));
$self->features->add(nn->MaxPool2D(3, 2, 1));
}
my $in_channels = $self->channels->[0];
for(enumerate($self->layers))
{
my ($i, $num_layer) = @$_;
my $stride = $i == 0 ? 1 : 2;
$self->features->add(
$self->_make_layer(
$self->block, $num_layer, $self->channels->[$i+1],
$stride, $i+1, in_channels=>$in_channels
)
);
$in_channels = $self->channels->[$i+1];
}
$self->features->add(nn->BatchNorm());
$self->features->add(nn->Activation('relu'));
$self->features->add(nn->GlobalAvgPool2D());
$self->features->add(nn->Flatten());
$self->output(nn->Dense($self->classes, in_units=>$in_channels));
});
}
method _make_layer($block, $layers, $channels, $stride, $stage_index, :$in_channels=0)
{
my $layer = nn->HybridSequential(prefix=>"stage${stage_index}_");
$layer->name_scope(sub {
$layer->add(
$block->new(
$channels, $stride, $channels != $in_channels, in_channels=>$in_channels,
prefix=>''
)
);
for(1..$layers-1)
{
$layer->add($block->new($channels, 1, 0, in_channels=>$channels, prefix=>''));
}
});
return $layer;
}
method hybrid_forward(GluonClass $F, GluonInput $x)
{
$x = $self->features->($x);
$x = $self->output->($x);
return $x;
}
package AI::MXNet::Gluon::ModelZoo::Vision;
# Specification
my %resnet_spec = (
18 => ['basic_block', [2, 2, 2, 2], [64, 64, 128, 256, 512]],
34 => ['basic_block', [3, 4, 6, 3], [64, 64, 128, 256, 512]],
50 => ['bottle_neck', [3, 4, 6, 3], [64, 256, 512, 1024, 2048]],
101 => ['bottle_neck', [3, 4, 23, 3], [64, 256, 512, 1024, 2048]],
152 => ['bottle_neck', [3, 8, 36, 3], [64, 256, 512, 1024, 2048]]
);
my @resnet_net_versions = qw(AI::MXNet::Gluon::ModelZoo::Vision::ResNet::V1 AI::MXNet::Gluon::ModelZoo::Vision::ResNet::V2);
my @resnet_block_versions = (
{
basic_block => 'AI::MXNet::Gluon::ModelZoo::Vision::ResNet::BasicBlockV1',
bottle_neck => 'AI::MXNet::Gluon::ModelZoo::Vision::ResNet::BottleneckV1'
},
{
basic_block => 'AI::MXNet::Gluon::ModelZoo::Vision::ResNet::BasicBlockV2',
bottle_neck => 'AI::MXNet::Gluon::ModelZoo::Vision::ResNet::BottleneckV2'
},
);
=head2 get_resnet
ResNet V1 model from "Deep Residual Learning for Image Recognition"
<http://arxiv.org/abs/1512.03385> paper.
ResNet V2 model from "Identity Mappings in Deep Residual Networks"
<https://arxiv.org/abs/1603.05027> paper.
Parameters
----------
$version : Int
Version of ResNet. Options are 1, 2.
$num_layers : Int
Numbers of layers. Options are 18, 34, 50, 101, 152.
:$pretrained : Bool, default 0
Whether to load the pretrained weights for model.
:$ctx : AI::MXNet::Context, default CPU
The context in which to load the pretrained weights.
:$root : Str, default '~/.mxnet/models'
Location for keeping the model parameters.
=cut
# Constructor
method get_resnet(
Int $version, Int $num_layers, Bool :$pretrained=0,
AI::MXNet::Context :$ctx=AI::MXNet::Context->cpu(),
Str :$root='~/.mxnet/models',
Maybe[Int] :$classes=,
Maybe[Bool] :$thumbnail=
)
{
my ($block_type, $layers, $channels) = @{ $resnet_spec{$num_layers} };
my $resnet_class = $resnet_net_versions[$version-1];
confess("invalid resnet $version [$version], can be 1,2") unless $resnet_class;
( run in 1.227 second using v1.01-cache-2.11-cpan-39bf76dae61 )