AI-MXNet-Gluon-ModelZoo

 view release on metacpan or  search on metacpan

Changes  view on Meta::CPAN

Revision history for Perl extension AI::MXNet::Gluon::ModelZoo

1.33    Thu Oct  4 13:25:56 PDT 2018
        - Fixed kwalitee issues.

1.32    Sun Aug  5 14:25:31 PDT 2018
        - Updated vgg16/19 models

1.3     Tue Jul 10 21:19:13 PDT 2018
        - Initial release

MANIFEST  view on Meta::CPAN

Changes
examples/image_classification.pl
lib/AI/MXNet/Gluon/ModelZoo.pm
lib/AI/MXNet/Gluon/ModelZoo/ModelStore.pm
lib/AI/MXNet/Gluon/ModelZoo/Vision.pm
lib/AI/MXNet/Gluon/ModelZoo/Vision/AlexNet.pm
lib/AI/MXNet/Gluon/ModelZoo/Vision/DenseNet.pm
lib/AI/MXNet/Gluon/ModelZoo/Vision/Inception.pm
lib/AI/MXNet/Gluon/ModelZoo/Vision/MobileNet.pm
lib/AI/MXNet/Gluon/ModelZoo/Vision/ResNet.pm
lib/AI/MXNet/Gluon/ModelZoo/Vision/SqueezeNet.pm
lib/AI/MXNet/Gluon/ModelZoo/Vision/VGG.pm
Makefile.PL
MANIFEST
META.json
META.yml
README
t/AI-MXNet-Gluon-ModelZoo.t
t/test_gluon_model_zoo.t

META.json  view on Meta::CPAN

{
   "abstract" : "Perl interface to MXNet Gluon ModelZoo",
   "author" : [
      "Sergey Kolychev <sergeykolychev.github@gmail.com>"
   ],
   "dynamic_config" : 0,
   "generated_by" : "ExtUtils::MakeMaker version 7.24, CPAN::Meta::Converter version 2.143240",
   "license" : [
      "apache_2_0"
   ],
   "meta-spec" : {
      "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec",
      "version" : "2"
   },
   "name" : "AI-MXNet-Gluon-ModelZoo",
   "no_index" : {
      "directory" : [
         "t",
         "inc"
      ]
   },
   "prereqs" : {
      "build" : {
         "requires" : {}
      },
      "configure" : {
         "requires" : {
            "ExtUtils::MakeMaker" : "6.30"
         }
      },
      "runtime" : {
         "requires" : {
            "AI::MXNet" : "1.31",
            "AI::MXNet::Gluon::Contrib" : "1.3",
            "IO::Uncompress::Unzip" : "0"
         }
      },
      "test" : {
         "requires" : {}
      }
   },
   "release_status" : "stable",
   "version" : "1.33"
}

META.yml  view on Meta::CPAN

---
abstract: 'Perl interface to MXNet Gluon ModelZoo'
author:
  - 'Sergey Kolychev <sergeykolychev.github@gmail.com>'
build_requires: {}
configure_requires:
  ExtUtils::MakeMaker: '6.30'
dynamic_config: 0
generated_by: 'ExtUtils::MakeMaker version 7.24, CPAN::Meta::Converter version 2.143240'
license: apache
meta-spec:
  url: http://module-build.sourceforge.net/META-spec-v1.4.html
  version: '1.4'
name: AI-MXNet-Gluon-ModelZoo
no_index:
  directory:
    - t
    - inc
requires:
  AI::MXNet: '1.31'
  AI::MXNet::Gluon::Contrib: '1.3'
  IO::Uncompress::Unzip: '0'
version: '1.33'

Makefile.PL  view on Meta::CPAN

# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License.  You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied.  See the License for the
# specific language governing permissions and limitations
# under the License.

use strict;
use warnings;

use 5.014000;

use ExtUtils::MakeMaker 6.30;



my %WriteMakefileArgs = (
  "ABSTRACT" => "Perl interface to MXNet Gluon ModelZoo",
  "AUTHOR" => "Sergey Kolychev <sergeykolychev.github\@gmail.com>",
  "BUILD_REQUIRES" => {},
  "CONFIGURE_REQUIRES" => {
    "ExtUtils::MakeMaker" => "6.30"
  },
  "DISTNAME" => "AI-MXNet-Gluon-ModelZoo",
  "EXE_FILES" => [],
  "LICENSE" => "apache_2_0",
  "NAME" => "AI::MXNet::Gluon::ModelZoo",
  "PREREQ_PM" => {
    "AI::MXNet" => "1.31",
    "AI::MXNet::Gluon::Contrib" => "1.3",
    "IO::Uncompress::Unzip" => "0"
  },
  "TEST_REQUIRES" => {},
  "VERSION" => "1.33",
  "test" => {
    "TESTS" => "t/*.t"
  }
);


my %FallbackPrereqs = (
  "AI::MXNet" => "1.31",
  "AI::MXNet::Gluon::Contrib" => "1.3",
  "IO::Uncompress::Unzip" => "0"
);


unless ( eval { ExtUtils::MakeMaker->VERSION(6.63_03) } ) {
  delete $WriteMakefileArgs{TEST_REQUIRES};
  delete $WriteMakefileArgs{BUILD_REQUIRES};
  $WriteMakefileArgs{PREREQ_PM} = \%FallbackPrereqs;
}

delete $WriteMakefileArgs{CONFIGURE_REQUIRES}
  unless eval { ExtUtils::MakeMaker->VERSION(6.52) };

WriteMakefile(%WriteMakefileArgs);

README  view on Meta::CPAN

This archive contains the distribution AI-MXNet-Gluon-ModelZoo,
version 1.33:

  Perl interface to MXNet Gluon ModelZoo, a collection of pretrained machine learning models for computer vision.

This library is licensed under Apache 2.0 license https://www.apache.org/licenses/LICENSE-2.0

examples/image_classification.pl  view on Meta::CPAN

#!/usr/bin/env perl
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License.  You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied.  See the License for the
# specific language governing permissions and limitations
# under the License.

use strict;
use warnings;
use AI::MXNet::Gluon::ModelZoo 'get_model';
use AI::MXNet::Gluon::Utils 'download';
use Getopt::Long qw(HelpMessage);

GetOptions(
    ## my Pembroke Welsh Corgi Kyuubi, enjoing Solar eclipse of August 21, 2017
    'image=s' => \(my $image = 'http://apache-mxnet.s3-accelerate.dualstack.amazonaws.com/'.
                               'gluon/dataset/kyuubi.jpg'),
    'model=s' => \(my $model = 'resnet152_v2'),
    'help'    => sub { HelpMessage(0) },
) or HelpMessage(1);

## get a pretrained model (download parameters file if necessary)
my $net = get_model($model, pretrained => 1);

## ImageNet classes
my $fname = download('http://data.mxnet.io/models/imagenet/synset.txt');
my @text_labels = map { chomp; s/^\S+\s+//; $_ } IO::File->new($fname)->getlines;

## get the image from the disk or net
if($image =~ /^https/)
{
    eval { require IO::Socket::SSL; };
    die "Need to have IO::Socket::SSL installed for https images" if $@;
}
$image = $image =~ /^https?/ ? download($image) : $image;

# Following the conventional way of preprocessing ImageNet data:
# Resize the short edge into 256 pixes,
# And then perform a center crop to obtain a 224-by-224 image.
# The following code uses the image processing functions provided 
# in the AI::MXNet::Image module.

$image = mx->image->imread($image);
$image = mx->image->resize_short($image, $model =~ /inception/ ? 330 : 256);
($image) = mx->image->center_crop($image, [($model =~ /inception/ ? 299 : 224)x2]);

## CV that is used to read image is column major (as PDL)
$image = $image->transpose([2,0,1])->expand_dims(axis=>0);

## normalizing the image
my $rgb_mean = nd->array([0.485, 0.456, 0.406])->reshape([1,3,1,1]);
my $rgb_std = nd->array([0.229, 0.224, 0.225])->reshape([1,3,1,1]);
$image = ($image->astype('float32') / 255 - $rgb_mean) / $rgb_std;

# Now we can recognize the object in the image.
# We perform an additional softmax on the output to obtain probability scores.
# And then print the top-5 recognized objects.
my $prob = $net->($image)->softmax;
for my $idx (@{ $prob->topk(k=>5)->at(0) })
{
    my $i = $idx->asscalar;
    printf(
        "With prob = %.5f, it contains %s\n",
        $prob->at(0)->at($i)->asscalar, $text_labels[$i]
    );
}

lib/AI/MXNet/Gluon/ModelZoo.pm  view on Meta::CPAN

# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License.  You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied.  See the License for the
# specific language governing permissions and limitations
# under the License.

package AI::MXNet::Gluon::ModelZoo;
use strict;
use warnings;
use AI::MXNet qw(mx);
use AI::MXNet::Gluon qw(gluon);
use AI::MXNet::Gluon::NN qw(nn);
use AI::MXNet::Gluon::Contrib;
use AI::MXNet::Gluon::ModelZoo::Vision;
use Exporter;
use base qw(Exporter);
@AI::MXNet::Gluon::ModelZoo::EXPORT_OK = qw(get_model);
our $VERSION = '1.33';

=head1 NAME

    AI::MXNet::Gluon::ModelZoo - A collection of pretrained MXNet Gluon models
=cut

=head1 SYNOPSIS

    ## run forward prediction on random data
    use AI::MXNet::Gluon::ModelZoo qw(get_model);
    my $alexnet = get_model('alexnet', pretrained => 1);
    my $out = $alexnet->(mx->nd->random->uniform(shape=>[1, 3, 224, 224]));
    print $out->aspdl;
=cut

=head1 DESCRIPTION

    This module houses a collection of pretrained models (the parameters are hosted on public mxnet servers).
    https://mxnet.incubator.apache.org/api/python/gluon/model_zoo.html
    See examples/image_classification.pl for the example of real time image classification
    using a pretrained model from the ModelZoo
=cut

our %models = qw/
    resnet18_v1 resnet18_v1
    resnet34_v1 resnet34_v1
    resnet50_v1 resnet50_v1
    resnet101_v1 resnet101_v1
    resnet152_v1 resnet152_v1
    resnet18_v2 resnet18_v2
    resnet34_v2 resnet34_v2
    resnet50_v2 resnet50_v2
    resnet101_v2 resnet101_v2
    resnet152_v2 resnet152_v2
    vgg11 vgg11
    vgg13 vgg13
    vgg16 vgg16
    vgg19 vgg19
    vgg11_bn vgg11_bn
    vgg13_bn vgg13_bn
    vgg16_bn vgg16_bn
    vgg19_bn vgg19_bn
    alexnet alexnet
    densenet121 densenet121
    densenet161 densenet161
    densenet169 densenet169
    densenet201 densenet201
    squeezenet1.0 squeezenet1_0
    squeezenet1.1 squeezenet1_1
    inceptionv3 inception_v3
    mobilenet1.0 mobilenet1_0
    mobilenet0.75 mobilenet0_75
    mobilenet0.5 mobilenet0_5
    mobilenet0.25 mobilenet0_25
    mobilenetv2_1.0 mobilenet_v2_1_0
    mobilenetv2_0.75 mobilenet_v2_0_75
    mobilenetv2_0.5 mobilenet_v2_0_5
    mobilenetv2_0.25 mobilenet_v2_0_25
/;


=head2 get_model

    Returns a pre-defined model by name

    Parameters
    ----------
    $name : Str
        Name of the model.
    :$pretrained : Bool
        Whether to load the pretrained weights for model.
    :$classes : Int
        Number of classes for the output layer.
    :$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.

    Returns
    -------
    HybridBlock
        The model.
=cut

sub get_model
{
    if(exists $models{lc $_[1]})
    {
        shift;
    }
    my ($name, %kwargs) = @_;
    $name = lc $name;
    Carp::confess(
        "Model $name is not present in the zoo\nValid models are:\n".
        join(', ', sort keys %models)."\n"
    ) unless exists $models{$name};
    my $sub = $models{$name};
    AI::MXNet::Gluon::ModelZoo::Vision->$sub(%kwargs);
}

sub vision { 'AI::MXNet::Gluon::ModelZoo::Vision' }

1;

=head1 AUTHOR

    Sergey Kolychev, <sergeykolychev.github@gmail.com>

=head1 COPYRIGHT & LICENSE

    This library is licensed under Apache 2.0 license L<https://www.apache.org/licenses/LICENSE-2.0>

=cut

lib/AI/MXNet/Gluon/ModelZoo/ModelStore.pm  view on Meta::CPAN

# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License.  You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied.  See the License for the
# specific language governing permissions and limitations
# under the License.

package AI::MXNet::Gluon::ModelZoo::ModelStore;
use strict;
use warnings;
use AI::MXNet::Function::Parameters;

=head1 NAME

    AI::MXNet::Gluon::ModelZoo::ModelStore - Model zoo for pre-trained models.
=cut

use AI::MXNet::Gluon::Utils qw(download check_sha1);
use IO::Uncompress::Unzip qw(unzip);
use File::Path qw(make_path);

my %_model_sha1 = map { $_->[1] => $_->[0] } (
    ['44335d1f0046b328243b32a26a4fbd62d9057b45', 'alexnet'],
    ['f27dbf2dbd5ce9a80b102d89c7483342cd33cb31', 'densenet121'],
    ['b6c8a95717e3e761bd88d145f4d0a214aaa515dc', 'densenet161'],
    ['2603f878403c6aa5a71a124c4a3307143d6820e9', 'densenet169'],
    ['1cdbc116bc3a1b65832b18cf53e1cb8e7da017eb', 'densenet201'],
    ['ed47ec45a937b656fcc94dabde85495bbef5ba1f', 'inceptionv3'],
    ['9f83e440996887baf91a6aff1cccc1c903a64274', 'mobilenet0.25'],
    ['8e9d539cc66aa5efa71c4b6af983b936ab8701c3', 'mobilenet0.5'],
    ['529b2c7f4934e6cb851155b22c96c9ab0a7c4dc2', 'mobilenet0.75'],
    ['6b8c5106c730e8750bcd82ceb75220a3351157cd', 'mobilenet1.0'],
    ['36da4ff1867abccd32b29592d79fc753bca5a215', 'mobilenetv2_1.0'],
    ['e2be7b72a79fe4a750d1dd415afedf01c3ea818d', 'mobilenetv2_0.75'],
    ['aabd26cd335379fcb72ae6c8fac45a70eab11785', 'mobilenetv2_0.5'],
    ['ae8f9392789b04822cbb1d98c27283fc5f8aa0a7', 'mobilenetv2_0.25'],
    ['a0666292f0a30ff61f857b0b66efc0228eb6a54b', 'resnet18_v1'],
    ['48216ba99a8b1005d75c0f3a0c422301a0473233', 'resnet34_v1'],
    ['0aee57f96768c0a2d5b23a6ec91eb08dfb0a45ce', 'resnet50_v1'],
    ['d988c13d6159779e907140a638c56f229634cb02', 'resnet101_v1'],
    ['671c637a14387ab9e2654eafd0d493d86b1c8579', 'resnet152_v1'],
    ['a81db45fd7b7a2d12ab97cd88ef0a5ac48b8f657', 'resnet18_v2'],
    ['9d6b80bbc35169de6b6edecffdd6047c56fdd322', 'resnet34_v2'],
    ['ecdde35339c1aadbec4f547857078e734a76fb49', 'resnet50_v2'],
    ['18e93e4f48947e002547f50eabbcc9c83e516aa6', 'resnet101_v2'],
    ['f2695542de38cf7e71ed58f02893d82bb409415e', 'resnet152_v2'],
    ['264ba4970a0cc87a4f15c96e25246a1307caf523', 'squeezenet1.0'],
    ['33ba0f93753c83d86e1eb397f38a667eaf2e9376', 'squeezenet1.1'],
    ['dd221b160977f36a53f464cb54648d227c707a05', 'vgg11'],
    ['ee79a8098a91fbe05b7a973fed2017a6117723a8', 'vgg11_bn'],
    ['6bc5de58a05a5e2e7f493e2d75a580d83efde38c', 'vgg13'],
    ['7d97a06c3c7a1aecc88b6e7385c2b373a249e95e', 'vgg13_bn'],
    ['e660d4569ccb679ec68f1fd3cce07a387252a90a', 'vgg16'],
    ['7f01cf050d357127a73826045c245041b0df7363', 'vgg16_bn'],
    ['ad2f660d101905472b83590b59708b71ea22b2e5', 'vgg19'],
    ['f360b758e856f1074a85abd5fd873ed1d98297c3', 'vgg19_bn']
);

my $apache_repo_url = 'http://apache-mxnet.s3-accelerate.dualstack.amazonaws.com/';
my $_url_format = '%sgluon/models/%s.zip';

func short_hash($name)
{
    Carp::confess("model $name is not available in model zoo") unless exists $_model_sha1{$name};
    return substr($_model_sha1{$name}, 0, 8);
}

=head2 get_model_file

    Return location for the pretrained on local file system.

    This function will download from online model zoo when model cannot be found or has mismatch.
    The root directory will be created if it doesn't exist.

    Parameters
    ----------
    $name : Str
        Name of the model.
    :$root : Str, default '~/.mxnet/models'
        Location for keeping the model parameters.

    Returns
    -------
    $file_path
        Path to the requested pretrained model file.
=cut

method get_model_file(Str $name, Str :$root='~/.mxnet/models')
{
    my $file_name = "$name-".short_hash($name);
    $root =~ s/~/$ENV{HOME}/;
    my $file_path = "$root/$file_name.params";
    my $sha1_hash = $_model_sha1{$name};
    if(-f $file_path)
    {
        if(check_sha1($file_path, $sha1_hash))
        {
            return $file_path;
        }
        else
        {
            warn("Mismatch in the content of model file detected. Downloading again.\n");
        }
    }
    else
    {
        warn("Model file is not found. Downloading.\n");
    }

    if(not -d $root)
    {
        make_path($root);
    }

    my $zip_file_path = "$root/$file_name.zip";
    my $repo_url = $ENV{MXNET_GLUON_REPO}//$apache_repo_url;
    if($repo_url !~ /\/$/)
    {
        $repo_url .= '/';
    }
    download(
        sprintf($_url_format, $repo_url, $file_name),
        path=>$zip_file_path,
        overwrite=>1
    );
    unzip($zip_file_path, $file_path);
    unlink $zip_file_path;
    if(check_sha1($file_path, $sha1_hash))
    {
        return $file_path;
    }
    else
    {
        Carp::confess("Downloaded file $file_path has different hash. Please try again.");
    }
}

=head2 purge

    Purge all pretrained model files in local file store.

    Parameters
    ----------
    root : str, default '~/.mxnet/models'
        Location for keeping the model parameters.
=cut

method purge(Str $root='~/.mxnet/models')
{
    $root =~ s/~/$ENV{HOME}/;
    map { unlink } glob("$root/*.params");
}

1;

lib/AI/MXNet/Gluon/ModelZoo/Vision.pm  view on Meta::CPAN

# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License.  You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied.  See the License for the
# specific language governing permissions and limitations
# under the License.

package AI::MXNet::Gluon::ModelZoo::Vision;
use strict;
use warnings;
use AI::MXNet::Gluon::ModelZoo::ModelStore;
use AI::MXNet::Gluon::ModelZoo::Vision::AlexNet;
use AI::MXNet::Gluon::ModelZoo::Vision::DenseNet;
use AI::MXNet::Gluon::ModelZoo::Vision::Inception;
use AI::MXNet::Gluon::ModelZoo::Vision::MobileNet;
use AI::MXNet::Gluon::ModelZoo::Vision::ResNet;
use AI::MXNet::Gluon::ModelZoo::Vision::SqueezeNet;
use AI::MXNet::Gluon::ModelZoo::Vision::VGG;

sub import
{
    my ($class, $short_name) = @_;
    if($short_name)
    {
        $short_name =~ s/[^\w:]//g;
        if(length $short_name)
        {
            my $short_name_package =<<"EOP";
            package $short_name;
            \@${short_name}::ISA = ('AI::MXNet::Gluon::ModelZoo::Vision');
            1;
EOP
            eval $short_name_package;
        }
    }
}

1;

lib/AI/MXNet/Gluon/ModelZoo/Vision/AlexNet.pm  view on Meta::CPAN

# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License.  You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied.  See the License for the
# specific language governing permissions and limitations
# under the License.

package AI::MXNet::Gluon::ModelZoo::Vision::AlexNet;
use strict;
use warnings;
use AI::MXNet::Function::Parameters;
use AI::MXNet::Gluon::Mouse;
extends 'AI::MXNet::Gluon::HybridBlock';

=head1 NAME

    AI::MXNet::Gluon::ModelZoo::Vision::AlexNet - AlexNet model from the `"One weird trick..."
=cut

=head1 DESCRIPTION

    AlexNet model from the "One weird trick..." <https://arxiv.org/abs/1404.5997> paper.

    Parameters
    ----------
    classes : Int, default 1000
        Number of classes for the output layer.
=cut
has 'classes' => (is => 'ro', isa => 'Int', default => 1000);
method python_constructor_arguments() { ['classes'] }

sub BUILD
{
    my $self = shift;
    $self->name_scope(sub {
        $self->features(nn->HybridSequential(prefix=>''));
        $self->features->name_scope(sub {
            $self->features->add(nn->Conv2D(64, kernel_size=>11, strides=>4,
                                            padding=>2, activation=>'relu'));
            $self->features->add(nn->MaxPool2D(pool_size=>3, strides=>2));
            $self->features->add(nn->Conv2D(192, kernel_size=>5, padding=>2,
                                            activation=>'relu'));
            $self->features->add(nn->MaxPool2D(pool_size=>3, strides=>2));
            $self->features->add(nn->Conv2D(384, kernel_size=>3, padding=>1,
                                            activation=>'relu'));
            $self->features->add(nn->Conv2D(256, kernel_size=>3, padding=>1,
                                            activation=>'relu'));
            $self->features->add(nn->Conv2D(256, kernel_size=>3, padding=>1,
                                            activation=>'relu'));
            $self->features->add(nn->MaxPool2D(pool_size=>3, strides=>2));
            $self->features->add(nn->Flatten());
            $self->features->add(nn->Dense(4096, activation=>'relu'));
            $self->features->add(nn->Dropout(0.5));
            $self->features->add(nn->Dense(4096, activation=>'relu'));
            $self->features->add(nn->Dropout(0.5));
        });
        $self->output(nn->Dense($self->classes));
    });
}

method hybrid_forward(GluonClass $F, GluonInput $x)
{
    $x = $self->features->($x);
    $x = $self->output->($x);
    return $x;
}

package AI::MXNet::Gluon::ModelZoo::Vision;

=head2 alexnet

    AlexNet model from the `"One weird trick..." <https://arxiv.org/abs/1404.5997> paper.

    Parameters
    ----------
    :$pretrained : Bool, default 0
        Whether to load the pretrained weights for model.
    :$ctx : AI::MXNet::Context, default AI::MXNet::Context->cpu
        The context in which to load the pretrained weights.
    :$root : Str, default '~/.mxnet/models'
        Location for keeping the model parameters.
=cut

method alexnet(
    Bool :$pretrained=0,
    AI::MXNet::Context :$ctx=AI::MXNet::Context->cpu(),
    Str :$root='~/.mxnet/models',
    Int :$classes=1000
)
{
    my $net = AI::MXNet::Gluon::ModelZoo::Vision::AlexNet->new($classes);
    if($pretrained)
    {
        $net->load_parameters(
            AI::MXNet::Gluon::ModelZoo::ModelStore->get_model_file(
                'alexnet',
                root=>$root
            ),
            ctx=>$ctx
        );
    }
    return $net;
}

1;

lib/AI/MXNet/Gluon/ModelZoo/Vision/DenseNet.pm  view on Meta::CPAN

# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License.  You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied.  See the License for the
# specific language governing permissions and limitations
# under the License.

package AI::MXNet::Gluon::ModelZoo::Vision::DenseNet;
use strict;
use warnings;
use AI::MXNet::Base;
use AI::MXNet::Function::Parameters;
use AI::MXNet::Gluon::Mouse;
extends 'AI::MXNet::Gluon::HybridBlock';

func _make_dense_block($num_layers, $bn_size, $growth_rate, $dropout, $stage_index)
{
    my $out = nn->HybridSequential(prefix=>"stage${stage_index}_");
    $out->name_scope(sub {
        for(1..$num_layers)
        {
            $out->add(_make_dense_layer($growth_rate, $bn_size, $dropout));
        }
    });
    return $out;
}

func _make_dense_layer($growth_rate, $bn_size, $dropout)
{
    my $new_features = nn->HybridSequential(prefix=>'');
    $new_features->add(nn->BatchNorm());
    $new_features->add(nn->Activation('relu'));
    $new_features->add(nn->Conv2D($bn_size * $growth_rate, kernel_size=>1, use_bias=>0));
    $new_features->add(nn->BatchNorm());
    $new_features->add(nn->Activation('relu'));
    $new_features->add(nn->Conv2D($growth_rate, kernel_size=>3, padding=>1, use_bias=>0));
    if($dropout)
    {
        $new_features->add(nn->Dropout($dropout));
    }

    my $out = nn->HybridConcurrent(axis=>1, prefix=>'');
    $out->add(nn->Identity());
    $out->add($new_features);

    return $out;
}

func _make_transition($num_output_features)
{
    my $out = nn->HybridSequential(prefix=>'');
    $out->add(nn->BatchNorm());
    $out->add(nn->Activation('relu'));
    $out->add(nn->Conv2D($num_output_features, kernel_size=>1, use_bias=>0));
    $out->add(nn->AvgPool2D(pool_size=>2, strides=>2));
    return $out;
}

=head1 NAME

    AI::MXNet::Gluon::ModelZoo::Vision::DenseNet - Densenet-BC model from the "Densely Connected Convolutional Networks"
=cut

=head1 DESCRIPTION

    Densenet-BC model from the "Densely Connected Convolutional Networks" <https://arxiv.org/pdf/1608.06993.pdf> paper.

    Parameters
    ----------
    num_init_features : Int
        Number of filters to learn in the first convolution layer.
    growth_rate : Int
        Number of filters to add each layer (`k` in the paper).
    block_config : array ref of Int
        List of integers for numbers of layers in each pooling block.
    bn_size : Int, default 4
        Multiplicative factor for number of bottle neck layers.
        (i.e. bn_size * k features in the bottleneck layer)
    dropout : float, default 0
        Rate of dropout after each dense layer.
    classes : int, default 1000
        Number of classification classes.
=cut
has [qw/num_init_features
        growth_rate/] => (is => 'ro', isa => 'Int', required => 1);
has 'block_config'    => (is => 'ro', isa => 'ArrayRef[Int]', required => 1);
has 'bn_size'         => (is => 'ro', isa => 'Int', default => 4);
has 'dropout'         => (is => 'ro', isa => 'Num', default => 0);
has 'classes'         => (is => 'ro', isa => 'Int', default => 1000);
method python_constructor_arguments(){ [qw/num_init_features growth_rate block_config bn_size dropout classes/] }

sub BUILD
{
    my $self = shift;
    $self->name_scope(sub {
        $self->features(nn->HybridSequential(prefix=>''));
        $self->features->add(
            nn->Conv2D(
                $self->num_init_features, kernel_size=>7,
                strides=>2, padding=>3, use_bias=>0
            )
        );
        $self->features->add(nn->BatchNorm());
        $self->features->add(nn->Activation('relu'));
        $self->features->add(nn->MaxPool2D(pool_size=>3, strides=>2, padding=>1));
        # Add dense blocks
        my $num_features = $self->num_init_features;
        for(enumerate($self->block_config))
        {
            my ($i, $num_layers) = @$_;
            $self->features->add(_make_dense_block($num_layers, $self->bn_size, $self->growth_rate, $self->dropout, $i+1));
            $num_features += $num_layers * $self->growth_rate;
            if($i != @{ $self->block_config } - 1)
            {
                $self->features->add(_make_transition(int($num_features/2)));
                $num_features = int($num_features/2);
            }
        }
        $self->features->add(nn->BatchNorm());
        $self->features->add(nn->Activation('relu'));
        $self->features->add(nn->AvgPool2D(pool_size=>7));
        $self->features->add(nn->Flatten());

        $self->output(nn->Dense($self->classes));
    });
}

method hybrid_forward(GluonClass $F, GluonInput $x)
{
    $x = $self->features->($x);
    $x = $self->output->($x);
    return $x;
}

package AI::MXNet::Gluon::ModelZoo::Vision;

my %densenet_spec = (
    121 => [64, 32, [6, 12, 24, 16]],
    161 => [96, 48, [6, 12, 36, 24]],
    169 => [64, 32, [6, 12, 32, 32]],
    201 => [64, 32, [6, 12, 48, 32]]
);

=head2 get_densenet

    Densenet-BC model from the
    "Densely Connected Convolutional Networks" <https://arxiv.org/pdf/1608.06993.pdf> paper.

    Parameters
    ----------
    $num_layers : Int
        Number of layers for the variant of densenet. Options are 121, 161, 169, 201.
    :$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

method get_densenet(
    Int $num_layers, Bool :$pretrained=0, :$ctx=AI::MXNet::Context->cpu(),
    :$root='~/.mxnet/models',
    Int :$bn_size=4,
    Num :$dropout=0,
    Int :$classes=1000
)
{
    my ($num_init_features, $growth_rate, $block_config) = @{ $densenet_spec{$num_layers} };
    my $net = AI::MXNet::Gluon::ModelZoo::Vision::DenseNet->new(
        $num_init_features, $growth_rate, $block_config,
        $bn_size, $dropout, $classes
    );
    if($pretrained)
    {
        $net->load_parameters(
            AI::MXNet::Gluon::ModelZoo::ModelStore->get_model_file(
                "densenet$num_layers",
                root=>$root
            ),
            ctx=>$ctx
        );
    }
    return $net;
}

=head2 densenet121

    Densenet-BC 121-layer model from the
    "Densely Connected Convolutional Networks" <https://arxiv.org/pdf/1608.06993.pdf> paper.

    Parameters
    ----------
    :$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

method densenet121(%kwargs)
{
    return __PACKAGE__->get_densenet(121, %kwargs)
}

=head2 densenet161

    Densenet-BC 161-layer model from the
    "Densely Connected Convolutional Networks" <https://arxiv.org/pdf/1608.06993.pdf> paper.

    Parameters
    ----------
    :$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

method densenet161(%kwargs)
{
    return __PACKAGE__->get_densenet(161, %kwargs)
}

=head2 densenet169

    Densenet-BC 169-layer model from the
    "Densely Connected Convolutional Networks" <https://arxiv.org/pdf/1608.06993.pdf> paper.

    Parameters
    ----------
    :$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

method densenet169(%kwargs)
{
    return __PACKAGE__->get_densenet(169, %kwargs)
}

=head2 densenet201

    Densenet-BC 201-layer model from the
    "Densely Connected Convolutional Networks" <https://arxiv.org/pdf/1608.06993.pdf> paper.

    Parameters
    ----------
    :$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

method densenet201(%kwargs)
{
    return __PACKAGE__->get_densenet(201, %kwargs)
}

1;

lib/AI/MXNet/Gluon/ModelZoo/Vision/Inception.pm  view on Meta::CPAN

# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License.  You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied.  See the License for the
# specific language governing permissions and limitations
# under the License.

package AI::MXNet::Gluon::ModelZoo::Vision::Inception::V3;
use strict;
use warnings;
use AI::MXNet::Base;
use AI::MXNet::Function::Parameters;
use AI::MXNet::Gluon::Mouse;
extends 'AI::MXNet::Gluon::HybridBlock';

func _make_basic_conv(%kwargs)
{
    my $out = nn->HybridSequential(prefix=>'');
    $out->add(nn->Conv2D(use_bias=>0, %kwargs));
    $out->add(nn->BatchNorm(epsilon=>0.001));
    $out->add(nn->Activation('relu'));
    return $out;
}

func _make_branch($use_pool, @conv_settings)
{
    my $out = nn->HybridSequential(prefix=>'');
    if($use_pool eq 'avg')
    {
        $out->add(nn->AvgPool2D(pool_size=>3, strides=>1, padding=>1));
    }
    elsif($use_pool eq 'max')
    {
        $out->add(nn->MaxPool2D(pool_size=>3, strides=>2));
    }
    my @setting_names = ('channels', 'kernel_size', 'strides', 'padding');
    for my $setting (@conv_settings)
    {
        my %kwargs;
        for(enumerate($setting))
        {
            my ($i, $value) = @$_;
            if(defined $value)
            {
                $kwargs{ $setting_names[$i] } = $value;
            }
        }
        $out->add(_make_basic_conv(%kwargs));
    }
    return $out;
}

func _make_A($pool_features, $prefix)
{
    my $out = nn->HybridConcurrent(axis=>1, prefix=>$prefix);
    $out->name_scope(sub {
        $out->add(_make_branch('', [64, 1, undef, undef]));
        $out->add(_make_branch(
            '',
            [48, 1, undef, undef],
            [64, 5, undef, 2]
        ));
        $out->add(_make_branch(
            '',
            [64, 1, undef, undef],
            [96, 3, undef, 1],
            [96, 3, undef, 1]
        ));
        $out->add(_make_branch('avg', [$pool_features, 1, undef, undef]));
    });
    return $out;
}

func _make_B($prefix)
{
    my $out = nn->HybridConcurrent(axis=>1, prefix=>$prefix);
    $out->name_scope(sub {
        $out->add(_make_branch('', [384, 3, 2, undef]));
        $out->add(_make_branch(
            '',
            [64, 1, undef, undef],
            [96, 3, undef, 1],
            [96, 3, 2, undef]
        ));
        $out->add(_make_branch('max'));
    });
    return $out;
}

func _make_C($channels_7x7, $prefix)
{
    my $out = nn->HybridConcurrent(axis=>1, prefix=>$prefix);
    $out->name_scope(sub {
        $out->add(_make_branch('', [192, 1, undef, undef]));
        $out->add(_make_branch(
            '',
            [$channels_7x7, 1, undef, undef],
            [$channels_7x7, [1, 7], undef, [0, 3]],
            [192, [7, 1], undef, [3, 0]]
        ));
        $out->add(_make_branch(
            '',
            [$channels_7x7, 1, undef, undef],
            [$channels_7x7, [7, 1], undef, [3, 0]],
            [$channels_7x7, [1, 7], undef, [0, 3]],
            [$channels_7x7, [7, 1], undef, [3, 0]],
            [192, [1, 7], undef, [0, 3]]
        ));
        $out->add(_make_branch(
            'avg',
            [192, 1, undef, undef]
        ));
    });
    return $out;
}

func _make_D($prefix)
{
    my $out = nn->HybridConcurrent(axis=>1, prefix=>$prefix);
    $out->name_scope(sub {
        $out->add(_make_branch(
            '',
            [192, 1, undef, undef],
            [320, 3, 2, undef]
        ));
        $out->add(_make_branch(
            '',
            [192, 1, undef, undef],
            [192, [1, 7], undef, [0, 3]],
            [192, [7, 1], undef, [3, 0]],
            [192, 3, 2, undef]
        ));
        $out->add(_make_branch('max'));
    });
    return $out;
}

func _make_E($prefix)
{
    my $out = nn->HybridConcurrent(axis=>1, prefix=>$prefix);
    $out->name_scope(sub {
        $out->add(_make_branch('', [320, 1, undef, undef]));

        my $branch_3x3 = nn->HybridSequential(prefix=>'');
        $out->add($branch_3x3);
        $branch_3x3->add(_make_branch(
            '',
            [384, 1, undef, undef]
        ));
        my $branch_3x3_split = nn->HybridConcurrent(axis=>1, prefix=>'');
        $branch_3x3_split->add(_make_branch('', [384, [1, 3], undef, [0, 1]]));
        $branch_3x3_split->add(_make_branch('', [384, [3, 1], undef, [1, 0]]));
        $branch_3x3->add($branch_3x3_split);

        my $branch_3x3dbl = nn->HybridSequential(prefix=>'');
        $out->add($branch_3x3dbl);
        $branch_3x3dbl->add(_make_branch(
            '',
            [448, 1, undef, undef],
            [384, 3, undef, 1]
        ));
        my $branch_3x3dbl_split = nn->HybridConcurrent(axis=>1, prefix=>'');
        $branch_3x3dbl->add($branch_3x3dbl_split);
        $branch_3x3dbl_split->add(_make_branch('', [384, [1, 3], undef, [0, 1]]));
        $branch_3x3dbl_split->add(_make_branch('', [384, [3, 1], undef, [1, 0]]));

        $out->add(_make_branch('avg', [192, 1, undef, undef]));
    });
    return $out;
}

func make_aux($classes)
{
    my $out = nn->HybridSequential(prefix=>'');
    $out->add(nn->AvgPool2D(pool_size=>5, strides=>3));
    $out->add(_make_basic_conv(channels=>128, kernel_size=>1));
    $out->add(_make_basic_conv(channels=>768, kernel_size=>5));
    $out->add(nn->Flatten());
    $out->add(nn->Dense($classes));
    return $out;
}

=head1 NAME

    AI::MXNet::Gluon::ModelZoo::Vision::Inception::V3 - Inception v3 model.
=cut

=head1 DESCRIPTION

    Inception v3 model from
    "Rethinking the Inception Architecture for Computer Vision"
    <http://arxiv.org/abs/1512.00567> paper.

    Parameters
    ----------
    classes : Int, default 1000
        Number of classification classes.
=cut

has 'classes' => (is => 'ro', isa => 'Int', default => 1000);
method python_constructor_arguments(){ ['classes'] }

sub BUILD
{
    my $self = shift;
    $self->name_scope(sub {
        $self->features(nn->HybridSequential(prefix=>''));
        $self->features->add(_make_basic_conv(channels=>32, kernel_size=>3, strides=>2));
        $self->features->add(_make_basic_conv(channels=>32, kernel_size=>3));
        $self->features->add(_make_basic_conv(channels=>64, kernel_size=>3, padding=>1));
        $self->features->add(nn->MaxPool2D(pool_size=>3, strides=>2));
        $self->features->add(_make_basic_conv(channels=>80, kernel_size=>1));
        $self->features->add(_make_basic_conv(channels=>192, kernel_size=>3));
        $self->features->add(nn->MaxPool2D(pool_size=>3, strides=>2));
        $self->features->add(_make_A(32, 'A1_'));
        $self->features->add(_make_A(64, 'A2_'));
        $self->features->add(_make_A(64, 'A3_'));
        $self->features->add(_make_B('B_'));
        $self->features->add(_make_C(128, 'C1_'));
        $self->features->add(_make_C(160, 'C2_'));
        $self->features->add(_make_C(160, 'C3_'));
        $self->features->add(_make_C(192, 'C4_'));
        $self->features->add(_make_D('D_'));
        $self->features->add(_make_E('E1_'));
        $self->features->add(_make_E('E2_'));
        $self->features->add(nn->AvgPool2D(pool_size=>8));
        $self->features->add(nn->Dropout(0.5));

        $self->output(nn->Dense($self->classes));
    });
}

method hybrid_forward(GluonClass $F, GluonInput $x)
{
    $x = $self->features->($x);
    $x = $self->output->($x);
    return $x;
}

package AI::MXNet::Gluon::ModelZoo::Vision;

=head2 inception_v3

    Inception v3 model from
    "Rethinking the Inception Architecture for Computer Vision"
    <http://arxiv.org/abs/1512.00567> paper.

    Parameters
    ----------
    :$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

method inception_v3(
    Bool :$pretrained=0, AI::MXNet::Context :$ctx=AI::MXNet::Context->cpu(),
    Str :$root='~/.mxnet/models', Int :$classes=1000
)
{
    my $net = AI::MXNet::Gluon::ModelZoo::Vision::Inception::V3->new($classes);
    if($pretrained)
    {
        $net->load_parameters(
            AI::MXNet::Gluon::ModelZoo::ModelStore->get_model_file(
                "inceptionv3",
                root=>$root
            ),
            ctx=>$ctx
        );
    }
    return $net;
}

1;

lib/AI/MXNet/Gluon/ModelZoo/Vision/MobileNet.pm  view on Meta::CPAN

# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License.  You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied.  See the License for the
# specific language governing permissions and limitations
# under the License.

use strict;
use warnings;
use AI::MXNet::Function::Parameters;
package AI::MXNet::Gluon::ModelZoo::Vision::MobileNet::RELU6;
use AI::MXNet::Gluon::Mouse;
extends 'AI::MXNet::Gluon::HybridBlock';

method hybrid_forward(GluonClass $F, GluonInput $x)
{
    return $F->clip($x, a_min => 0, a_max => 6, name=>"relu6");
}

package AI::MXNet::Gluon::ModelZoo::Vision::MobileNet::LinearBottleneck;
use AI::MXNet::Gluon::Mouse;
extends 'AI::MXNet::Gluon::HybridBlock';
has [qw/in_channels channels t stride/] => (is => 'ro', isa => 'Int', required => 1);
method python_constructor_arguments(){ [qw/in_channels channels t stride/] }

=head1 NAME

    AI::MXNet::Gluon::ModelZoo::Vision::MobileNet::LinearBottleneck - LinearBottleneck used in MobileNetV2 model
=cut

=head1 DESCRIPTION

    LinearBottleneck used in MobileNetV2 model from the
    "Inverted Residuals and Linear Bottlenecks:
      Mobile Networks for Classification, Detection and Segmentation"
    <https://arxiv.org/abs/1801.04381> paper.

    Parameters
    ----------
    in_channels : Int
        Number of input channels.
    channels : Int
        Number of output channels.
    t : Int
        Layer expansion ratio.
    stride : Int
        stride
=cut

func _add_conv(
    $out, $channels, :$kernel=1, :$stride=1, :$pad=0,
    :$num_group=1, :$active=1, :$relu6=0
)
{
    $out->add(nn->Conv2D($channels, $kernel, $stride, $pad, groups=>$num_group, use_bias=>0));
    $out->add(nn->BatchNorm(scale=>1));
    if($active)
    {
        $out->add($relu6 ? AI::MXNet::Gluon::ModelZoo::Vision::MobileNet::RELU6->new : nn->Activation('relu'));
    }
}

sub BUILD
{
    my $self = shift;
    $self->use_shortcut($self->stride == 1 and $self->in_channels == $self->channels);
    $self->name_scope(sub {
        $self->out(nn->HybridSequential());
        _add_conv($self->out, $self->in_channels * $self->t, relu6=>1);
        _add_conv(
            $self->out, $self->in_channels * $self->t, kernel=>3, stride=>$self->stride,
            pad=>1, num_group=>$self->in_channels * $self->t, relu6=>1
        );
        _add_conv($self->out, $self->channels, active=>0, relu6=>1);
    });
}

method hybrid_forward($F, $x)
{
    my $out = $self->out->($x);
    if($self->use_shortcut)
    {
        $out = $F->elemwise_add($out, $x);
    }
    return $out;
}

package AI::MXNet::Gluon::ModelZoo::Vision::MobileNet;
use AI::MXNet::Gluon::Mouse;
use AI::MXNet::Base;
extends 'AI::MXNet::Gluon::HybridBlock';
has 'multiplier' => (is => 'ro', isa => 'Num', default => 1);
has 'classes'    => (is => 'ro', isa => 'Int', default => 1000);
method python_constructor_arguments(){ [qw/multiplier classes/] }

=head1 NAME

    AI::MXNet::Gluon::ModelZoo::Vision::MobileNet - MobileNet model from the
        "MobileNets: Efficient Convolutional Neural Networks for Mobile Vision Applications"
=cut

=head1 DESCRIPTION

    MobileNet model from the
    "MobileNets: Efficient Convolutional Neural Networks for Mobile Vision Applications"
    <https://arxiv.org/abs/1704.04861> paper.

    Parameters
    ----------
    multiplier : Num, default 1.0
        The width multiplier for controling the model size. Only multipliers that are no
        less than 0.25 are supported. The actual number of channels is equal to the original
        channel size multiplied by this multiplier.
    classes : Int, default 1000
        Number of classes for the output layer.
=cut

func _add_conv(
    $out, :$channels=1, :$kernel=1, :$stride=1, :$pad=0,
    :$num_group=1, :$active=1, :$relu6=0
)
{
    $out->add(nn->Conv2D($channels, $kernel, $stride, $pad, groups=>$num_group, use_bias=>0));
    $out->add(nn->BatchNorm(scale=>1));
    if($active)
    {
        $out->add($relu6 ? AI::MXNet::Gluon::ModelZoo::Vision::MobileNet::RELU6->new : nn->Activation('relu'));
    }
}


func _add_conv_dw($out, :$dw_channels=, :$channels=, :$stride=, :$relu6=0)
{
    _add_conv($out, channels=>$dw_channels, kernel=>3, stride=>$stride,
              pad=>1, num_group=>$dw_channels, relu6=>$relu6);
    _add_conv($out, channels=>$channels, relu6=>$relu6);
}

sub BUILD
{
    my $self = shift;
    $self->name_scope(sub {
        $self->features(nn->HybridSequential(prefix=>''));
        $self->features->name_scope(sub {
            _add_conv($self->features, channels=>int(32 * $self->multiplier), kernel=>3, pad=>1, stride=>2);
            my $dw_channels = [map { int($_ * $self->multiplier) } (32, 64, (128)x2, (256)x2, (512)x6, 1024)];
            my $channels = [map { int($_ * $self->multiplier) } (64, (128)x2, (256)x2, (512)x6, (1024)x2)];
            my $strides = [(1, 2)x3, (1)x5, 2, 1];
            for(zip($dw_channels, $channels, $strides))
            {
                my ($dwc, $c, $s) = @$_;
                _add_conv_dw($self->features, dw_channels=>$dwc, channels=>$c, stride=>$s);
            }
            $self->features->add(nn->GlobalAvgPool2D());
            $self->features->add(nn->Flatten());
        });
        $self->output(nn->Dense($self->classes));
    });
}

method hybrid_forward(GluonClass $F, GluonInput $x)
{
    $x = $self->features->($x);
    $x = $self->output->($x);
    return $x;
}

package AI::MXNet::Gluon::ModelZoo::Vision::MobileNetV2;
use AI::MXNet::Gluon::Mouse;
use AI::MXNet::Base;
extends 'AI::MXNet::Gluon::HybridBlock';
has 'multiplier' => (is => 'ro', isa => 'Num', default => 1);
has 'classes'    => (is => 'ro', isa => 'Int', default => 1000);
method python_constructor_arguments(){ [qw/multiplier classes/] }

=head1 NAME

    AI::MXNet::Gluon::ModelZoo::Vision::MobileNetV2 - MobileNet model from the
        "Inverted Residuals and Linear Bottlenecks: Mobile Networks for Classification, Detection and Segmentation"
=cut

=head1 DESCRIPTION

    MobileNetV2 model from the
    "Inverted Residuals and Linear Bottlenecks:
      Mobile Networks for Classification, Detection and Segmentation"
    <https://arxiv.org/abs/1801.04381> paper.

    Parameters
    ----------
    multiplier : Num, default 1.0
        The width multiplier for controling the model size. Only multipliers that are no
        less than 0.25 are supported. The actual number of channels is equal to the original
        channel size multiplied by this multiplier.
    classes : Int, default 1000
        Number of classes for the output layer.
=cut

func _add_conv(
    $out, $channels, :$kernel=1, :$stride=1, :$pad=0,
    :$num_group=1, :$active=1, :$relu6=0
)
{
    $out->add(nn->Conv2D($channels, $kernel, $stride, $pad, groups=>$num_group, use_bias=>0));
    $out->add(nn->BatchNorm(scale=>1));
    if($active)
    {
        $out->add($relu6 ? AI::MXNet::Gluon::ModelZoo::Vision::MobileNet::RELU6->new : nn->Activation('relu'));
    }
}

sub BUILD
{
    my $self = shift;
    $self->name_scope(sub {
        $self->features(nn->HybridSequential(prefix=>'features_'));
        $self->features->name_scope(sub {
            _add_conv(
                $self->features, int(32 * $self->multiplier), kernel=>3,
                stride=>2, pad=>1, relu6=>1
            );

            my $in_channels_group = [map { int($_ * $self->multiplier) } (32, 16, (24)x2, (32)x3, (64)x4, (96)x3, (160)x3)];
            my $channels_group = [map { int($_ * $self->multiplier) } (16, (24)x2, (32)x3, (64)x4, (96)x3, (160)x3, 320)];
            my $ts = [1, (6)x16];
            my $strides = [(1, 2)x2, 1, 1, 2, (1)x6, 2, (1)x3];

            for(zip($in_channels_group, $channels_group, $ts, $strides))
            {
                my ($in_c, $c, $t, $s) = @$_;
                $self->features->add(
                    AI::MXNet::Gluon::ModelZoo::Vision::MobileNet::LinearBottleneck->new(
                        in_channels=>$in_c, channels=>$c,
                        t=>$t, stride=>$s
                    )
                );
            }

            my $last_channels = $self->multiplier > 1 ? int(1280 * $self->multiplier) : 1280;
            _add_conv($self->features, $last_channels, relu6=>1);
            $self->features->add(nn->GlobalAvgPool2D());
        });

        $self->output(nn->HybridSequential(prefix=>'output_'));
        $self->output->name_scope(sub {
            $self->output->add(
                nn->Conv2D($self->classes, 1, use_bias=>0, prefix=>'pred_'),
                nn->Flatten()
            );
        });
    });
}

method hybrid_forward(GluonClass $F, GluonInput $x)
{
    $x = $self->features->($x);
    $x = $self->output->($x);
    return $x;
}

package AI::MXNet::Gluon::ModelZoo::Vision;

=head2 get_mobilenet

    MobileNet model from the
    "MobileNets: Efficient Convolutional Neural Networks for Mobile Vision Applications"
    <https://arxiv.org/abs/1704.04861> paper.

    Parameters
    ----------
    $multiplier : Num
        The width multiplier for controling the model size. Only multipliers that are no
        less than 0.25 are supported. The actual number of channels is equal to the original
        channel size multiplied by this multiplier.
    :$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

method get_mobilenet(
    Num $multiplier, Bool :$pretrained=0, AI::MXNet::Context :$ctx=AI::MXNet::Context->cpu(),
    Str :$root='~/.mxnet/models'
)
{
    my $net = AI::MXNet::Gluon::ModelZoo::Vision::MobileNet->new($multiplier);
    if($pretrained)
    {
        my $version_suffix = sprintf("%.2f", $multiplier);
        if($version_suffix eq '1.00' or $version_suffix eq '0.50')
        {
            $version_suffix =~ s/.$//;
        }
        $net->load_parameters(
            AI::MXNet::Gluon::ModelZoo::ModelStore->get_model_file(
                "mobilenet$version_suffix",
                root=>$root
            ),
            ctx=>$ctx
        );
    }
    return $net;
}

=head2 get_mobilenet_v2

    MobileNetV2 model from the
    "Inverted Residuals and Linear Bottlenecks:
      Mobile Networks for Classification, Detection and Segmentation"
    <https://arxiv.org/abs/1801.04381> paper.

    Parameters
    ----------
    $multiplier : Num
        The width multiplier for controling the model size. Only multipliers that are no
        less than 0.25 are supported. The actual number of channels is equal to the original
        channel size multiplied by this multiplier.
    :$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

method get_mobilenet_v2(
    Num $multiplier, Bool :$pretrained=0, AI::MXNet::Context :$ctx=AI::MXNet::Context->cpu(),
    Str :$root='~/.mxnet/models'
)
{
    my $net = AI::MXNet::Gluon::ModelZoo::Vision::MobileNetV2->new($multiplier);
    if($pretrained)
    {
        my $version_suffix = sprintf("%.2f", $multiplier);
        if($version_suffix eq '1.00' or $version_suffix eq '0.50')
        {
            $version_suffix =~ s/.$//;
        }
        $net->load_parameters(
            AI::MXNet::Gluon::ModelZoo::ModelStore->get_model_file(
                "mobilenetv2_$version_suffix",
                root=>$root
            ),
            ctx=>$ctx
        );
    }
    return $net;
}

=head2 mobilenet1_0

    MobileNet model from the
    "MobileNets: Efficient Convolutional Neural Networks for Mobile Vision Applications"
    <https://arxiv.org/abs/1704.04861> paper, with width multiplier 1.0.

    Parameters
    ----------
    :$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.
=cut

method mobilenet1_0(%kwargs)
{
    return __PACKAGE__->get_mobilenet(1.0, %kwargs);
}

=head2 mobilenet_v2_1_0

    MobileNetV2 model from the
    "Inverted Residuals and Linear Bottlenecks:
      Mobile Networks for Classification, Detection and Segmentation"
    <https://arxiv.org/abs/1801.04381> paper.

    Parameters
    ----------
    :$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.
=cut

method mobilenet_v2_1_0(%kwargs)
{
    return __PACKAGE__->get_mobilenet_v2(1.0, %kwargs);
}

=head2 mobilenet0_75

    MobileNet model from the
    "MobileNets: Efficient Convolutional Neural Networks for Mobile Vision Applications"
    <https://arxiv.org/abs/1704.04861> paper, with width multiplier 0.75.

    Parameters
    ----------
    :$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.
=cut

method mobilenet0_75(%kwargs)
{
    return __PACKAGE__->get_mobilenet(0.75, %kwargs);
}

=head2 mobilenet_v2_0_75

    MobileNetV2 model from the
    "Inverted Residuals and Linear Bottlenecks:
      Mobile Networks for Classification, Detection and Segmentation"
    <https://arxiv.org/abs/1801.04381> paper.

    Parameters
    ----------
    :$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.
=cut

method mobilenet_v2_0_75(%kwargs)
{
    return __PACKAGE__->get_mobilenet_v2(0.75, %kwargs);
}

=head2 mobilenet0_5

    MobileNet model from the
    "MobileNets: Efficient Convolutional Neural Networks for Mobile Vision Applications"
    <https://arxiv.org/abs/1704.04861> paper, with width multiplier 0.5.

    Parameters
    ----------
    :$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.
=cut

method mobilenet0_5(%kwargs)
{
    return __PACKAGE__->get_mobilenet(0.5, %kwargs);
}

=head2 mobilenet_v2_0_5

    MobileNetV2 model from the
    "Inverted Residuals and Linear Bottlenecks:
      Mobile Networks for Classification, Detection and Segmentation"
    <https://arxiv.org/abs/1801.04381> paper.

    Parameters
    ----------
    :$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.
=cut

method mobilenet_v2_0_5(%kwargs)
{
    return __PACKAGE__->get_mobilenet_v2(0.5, %kwargs);
}

=head2 mobilenet0_25

    MobileNet model from the
    "MobileNets: Efficient Convolutional Neural Networks for Mobile Vision Applications"
    <https://arxiv.org/abs/1704.04861> paper, with width multiplier 0.25.

    Parameters
    ----------
    :$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.
=cut

method mobilenet0_25(%kwargs)
{
    return __PACKAGE__->get_mobilenet(0.25, %kwargs);
}

=head2 mobilenet_v2_0_25

    MobileNetV2 model from the
    "Inverted Residuals and Linear Bottlenecks:
      Mobile Networks for Classification, Detection and Segmentation"
    <https://arxiv.org/abs/1801.04381> paper.

    Parameters
    ----------
    :$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.
=cut

method mobilenet_v2_0_25(%kwargs)
{
    return __PACKAGE__->get_mobilenet_v2(0.25, %kwargs);
}

1;

lib/AI/MXNet/Gluon/ModelZoo/Vision/ResNet.pm  view on Meta::CPAN

# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License.  You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied.  See the License for the
# specific language governing permissions and limitations
# under the License.

use strict;
use warnings;
use AI::MXNet::Function::Parameters;

package AI::MXNet::Gluon::ModelZoo::Vision::ResNet::BasicBlockV1;
use AI::MXNet::Gluon::Mouse;
extends 'AI::MXNet::Gluon::HybridBlock';

=head1 NAME 

    AI::MXNet::Gluon::ModelZoo::Vision::ResNet::BasicBlockV1 - BasicBlock V1 from `"Deep Residual Learning for Image Recognition"
=cut

=head1 DESCRIPTION

    BasicBlock V1 from `"Deep Residual Learning for Image Recognition"
    <http://arxiv.org/abs/1512.03385>`_ paper.
    This is used for ResNet V1 for 18, 34 layers.

    Parameters
    ----------
    channels : Int
        Number of output channels.
    stride : Int
        Stride size.
    downsample : Bool, default 0
        Whether to downsample the input.
    in_channels : Int, default 0
        Number of input channels. Default is 0, to infer from the graph.
=cut

has ['channels',
      'stride']   => (is => 'ro', isa => 'Int', required => 1);
has 'downsample' => (is => 'rw', default => 0);
has 'in_channels' => (is => 'ro', isa => 'Int', default => 0);
method python_constructor_arguments() { [qw/channels stride downsample/] }
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;
    $self->body(nn->HybridSequential(prefix=>''));
    $self->body->add(_conv3x3($self->channels, $self->stride, $self->in_channels));
    $self->body->add(nn->BatchNorm());
    $self->body->add(nn->Activation('relu'));
    $self->body->add(_conv3x3($self->channels, 1, $self->channels));
    $self->body->add(nn->BatchNorm());
    if($self->downsample)
    {
        $self->downsample(nn->HybridSequential(prefix=>''));
        $self->downsample->add(
            nn->Conv2D($self->channels, kernel_size=>1, strides=>$self->stride,
                       use_bias=>0, in_channels=>$self->in_channels)
        );
        $self->downsample->add(nn->BatchNorm());
    }
    else
    {
        $self->downsample(undef);
    }
}

method hybrid_forward(GluonClass $F, GluonInput $x)
{
    my $residual = $x;
    $x = $self->body->($x);
    if(defined $self->downsample)
    {
        $residual = $self->downsample->($residual);
    }
    $x = $F->Activation($residual+$x, act_type=>'relu');
    return $x;
}

package AI::MXNet::Gluon::ModelZoo::Vision::ResNet::BottleneckV1;
use AI::MXNet::Gluon::Mouse;
extends 'AI::MXNet::Gluon::HybridBlock';

=head1 NAME

    AI::MXNet::Gluon::ModelZoo::Vision::ResNet::BottleneckV1 - Bottleneck V1 from "Deep Residual Learning for Image Recognition"
=cut

=head1 DESCRIPTION

    Bottleneck V1 from "Deep Residual Learning for Image Recognition"
    <http://arxiv.org/abs/1512.03385> paper.
    This is used for ResNet V1 for 50, 101, 152 layers.

    Parameters
    ----------
    channels : int
        Number of output channels.
    stride : int
        Stride size.
    downsample : bool, default False
        Whether to downsample the input.
    in_channels : int, default 0
        Number of input channels. Default is 0, to infer from the graph.
=cut

has ['channels',
      'stride']   => (is => 'ro', isa => 'Int', required => 1);
has 'downsample'  => (is => 'rw', default => 0);
has 'in_channels' => (is => 'ro', isa => 'Int', default => 0);
method python_constructor_arguments() { [qw/channels stride downsample/] }
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;
    $self->body(nn->HybridSequential(prefix=>''));
    $self->body->add(nn->Conv2D(int($self->channels/4), kernel_size=>1, strides=>$self->stride));
    $self->body->add(nn->BatchNorm());
    $self->body->add(nn->Activation('relu'));
    $self->body->add(_conv3x3(int($self->channels/4), 1, int($self->channels/4)));
    $self->body->add(nn->BatchNorm());
    $self->body->add(nn->Activation('relu'));
    $self->body->add(nn->Conv2D($self->channels, kernel_size=>1, strides=>1));
    $self->body->add(nn->BatchNorm());
    if($self->downsample)
    {
        $self->downsample(nn->HybridSequential(prefix=>''));
        $self->downsample->add(
            nn->Conv2D($self->channels, kernel_size=>1, strides=>$self->stride,
                       use_bias=>0, in_channels=>$self->in_channels)
        );
        $self->downsample->add(nn->BatchNorm());
    }
    else
    {
        $self->downsample(undef);
    }
}

method hybrid_forward(GluonClass $F, GluonInput $x)
{
    my $residual = $x;
    $x = $self->body->($x);
    if(defined $self->downsample)
    {
        $residual = $self->downsample->($residual);
    }
    $x = $F->Activation($residual+$x, act_type=>'relu');
    return $x;
}

package AI::MXNet::Gluon::ModelZoo::Vision::ResNet::BasicBlockV2;
use AI::MXNet::Gluon::Mouse;
extends 'AI::MXNet::Gluon::HybridBlock';

=head1 NAME 

    AI::MXNet::Gluon::ModelZoo::Vision::ResNet::BasicBlockV2 - BasicBlock V2 from "Identity Mappings in Deep Residual Networks"
=cut

=head1 DESCRIPTION

    Bottleneck V2 from "Identity Mappings in Deep Residual Networks"
    <https://arxiv.org/abs/1603.05027> paper.
    This is used for ResNet V2 for 18, 34 layers.

    Parameters
    ----------
    channels : Int
        Number of output channels.
    stride : Int
        Stride size.
    downsample : Bool, default 0
        Whether to downsample the input.
    in_channels : Int, default 0
        Number of input channels. Default is 0, to infer from the graph.
=cut

has ['channels',
      'stride']   => (is => 'ro', isa => 'Int', required => 1);
has 'downsample' => (is => 'rw', default => 0);
has 'in_channels' => (is => 'ro', isa => 'Int', default => 0);
method python_constructor_arguments() { [qw/channels stride downsample/] }
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;
    $self->bn1(nn->BatchNorm());
    $self->conv1(_conv3x3($self->channels, $self->stride, $self->in_channels));
    $self->bn2(nn->BatchNorm());
    $self->conv2(_conv3x3($self->channels, 1, $self->channels));
    if($self->downsample)
    {
        $self->downsample(
            nn->Conv2D($self->channels, kernel_size=>1, strides=>$self->stride,
                       use_bias=>0, in_channels=>$self->in_channels)
        );
    }
    else
    {
        $self->downsample(undef);
    }
}

method hybrid_forward(GluonClass $F, GluonInput $x)
{
    my $residual = $x;
    $x = $self->bn1->($x);
    $x = $F->Activation($x, act_type=>'relu');
    if(defined $self->downsample)
    {
        $residual = $self->downsample->($x);
    }
    $x = $self->conv1->($x);

    $x = $self->bn2->($x);
    $x = $F->Activation($x, act_type=>'relu');
    $x = $self->conv2->($x);

    return $x + $residual;
}


package AI::MXNet::Gluon::ModelZoo::Vision::ResNet::BottleneckV2;
use AI::MXNet::Gluon::Mouse;
extends 'AI::MXNet::Gluon::HybridBlock';

=head1 NAME

    AI::MXNet::Gluon::ModelZoo::Vision::ResNet::BottleneckV2 - Bottleneck V2 from "Identity Mappings in Deep Residual Networks"
=cut

=head1 DESCRIPTION

    Bottleneck V2 from "Identity Mappings in Deep Residual Networks"
    <https://arxiv.org/abs/1603.05027> paper.
    This is used for ResNet V2 for 50, 101, 152 layers.

    Parameters
    ----------
    channels : int
        Number of output channels.
    stride : int
        Stride size.
    downsample : bool, default False
        Whether to downsample the input.
    in_channels : int, default 0
        Number of input channels. Default is 0, to infer from the graph.
=cut

has ['channels',
      'stride']   => (is => 'ro', isa => 'Int', required => 1);
has 'downsample' => (is => 'rw', default => 0);
has 'in_channels' => (is => 'ro', isa => 'Int', default => 0);
method python_constructor_arguments() { [qw/channels stride downsample/] }
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;
    $self->bn1(nn->BatchNorm());
    $self->conv1(nn->Conv2D(int($self->channels/4), kernel_size=>1, strides=>1, use_bias=>0));
    $self->bn2(nn->BatchNorm());
    $self->conv2(_conv3x3(int($self->channels/4), $self->stride, int($self->channels/4)));
    $self->bn3(nn->BatchNorm());
    $self->conv3(nn->Conv2D($self->channels, kernel_size=>1, strides=>1, use_bias=>0));
    if($self->downsample)
    {
        $self->downsample(
            nn->Conv2D($self->channels, kernel_size=>1, strides=>$self->stride,
                       use_bias=>0, in_channels=>$self->in_channels)
        );
    }
    else
    {
        $self->downsample(undef);
    }
}

method hybrid_forward(GluonClass $F, GluonInput $x)
{
    my $residual = $x;
    $x = $self->bn1->($x);
    $x = $F->Activation($x, act_type=>'relu');
    if(defined $self->downsample)
    {
        $residual = $self->downsample->($x);
    }
    $x = $self->conv1->($x);

    $x = $self->bn2->($x);
    $x = $F->Activation($x, act_type=>'relu');
    $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;
    my $block_class = $resnet_block_versions[$version-1]{$block_type};
    my $net = $resnet_class->new(
        $block_class, $layers, $channels,
        (defined($classes) ? (classes => $classes) : ()),
        (defined($thumbnail) ? (thumbnail => $thumbnail) : ())
    );
    if($pretrained)
    {
        $net->load_parameters(
            AI::MXNet::Gluon::ModelZoo::ModelStore->get_model_file(
                "resnet${num_layers}_v$version",
                root=>$root
            ),
            ctx=>$ctx
        );
    }
    return $net;
}

=head2 resnet18_v1

    ResNet-18 V1 model from "Deep Residual Learning for Image Recognition"
    <http://arxiv.org/abs/1512.03385> paper.

    Parameters
    ----------
    :$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

method resnet18_v1(%kwargs)
{
    return __PACKAGE__->get_resnet(1, 18, %kwargs);
}

=head2 resnet34_v1

    ResNet-34 V1 model from "Deep Residual Learning for Image Recognition"
    <http://arxiv.org/abs/1512.03385> paper.

    Parameters
    ----------
    :$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

method resnet34_v1(%kwargs)
{
    return __PACKAGE__->get_resnet(1, 34, %kwargs);
}

=head2 resnet50_v1

    ResNet-50 V1 model from "Deep Residual Learning for Image Recognition"
    <http://arxiv.org/abs/1512.03385> paper.

    Parameters
    ----------
    :$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

method resnet50_v1(%kwargs)
{
    return __PACKAGE__->get_resnet(1, 50, %kwargs);
}

=head2 resnet101_v1

    ResNet-101 V1 model from "Deep Residual Learning for Image Recognition"
    <http://arxiv.org/abs/1512.03385> paper.

    Parameters
    ----------
    :$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

method resnet101_v1(%kwargs)
{
    return __PACKAGE__->get_resnet(1, 101, %kwargs);
}

=head2 resnet152_v1

    ResNet-152 V1 model from "Deep Residual Learning for Image Recognition"
    <http://arxiv.org/abs/1512.03385> paper.

    Parameters
    ----------
    :$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

method resnet152_v1(%kwargs)
{
    return __PACKAGE__->get_resnet(1, 152, %kwargs);
}

=head2 resnet18_v2

    ResNet-18 V2 model from "Identity Mappings in Deep Residual Networks"
    <https://arxiv.org/abs/1603.05027> paper.

    Parameters
    ----------
    :$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

method resnet18_v2(%kwargs)
{
    return __PACKAGE__->get_resnet(2, 18, %kwargs);
}

=head2 resnet34_v2

    ResNet-34 V2 model from "Identity Mappings in Deep Residual Networks"
    <https://arxiv.org/abs/1603.05027> paper.

    Parameters
    ----------
    :$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

method resnet34_v2(%kwargs)
{
    return __PACKAGE__->get_resnet(2, 34, %kwargs);
}

=head2 resnet50_v2

    ResNet-50 V2 model from "Identity Mappings in Deep Residual Networks"
    <https://arxiv.org/abs/1603.05027> paper.

    Parameters
    ----------
    :$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

method resnet50_v2(%kwargs)
{
    return __PACKAGE__->get_resnet(2, 50, %kwargs);
}

=head2 resnet101_v2

    ResNet-101 V2 model from "Identity Mappings in Deep Residual Networks"
    <https://arxiv.org/abs/1603.05027> paper.

    Parameters
    ----------
    :$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

method resnet101_v2(%kwargs)
{
    return __PACKAGE__->get_resnet(2, 101, %kwargs);
}

=head2 resnet152_v2

    ResNet-152 V2 model from "Identity Mappings in Deep Residual Networks"
    <https://arxiv.org/abs/1603.05027> paper.

    Parameters
    ----------
    :$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

method resnet152_v2(%kwargs)
{
    return __PACKAGE__->get_resnet(2, 152, %kwargs);
}

1;

lib/AI/MXNet/Gluon/ModelZoo/Vision/SqueezeNet.pm  view on Meta::CPAN

# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License.  You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied.  See the License for the
# specific language governing permissions and limitations
# under the License.

package AI::MXNet::Gluon::ModelZoo::Vision::SqueezeNet;
use strict;
use warnings;
use AI::MXNet::Function::Parameters;
use AI::MXNet::Gluon::Mouse;
use AI::MXNet::Types;
extends 'AI::MXNet::Gluon::HybridBlock';

func _make_fire($squeeze_channels, $expand1x1_channels, $expand3x3_channels)
{
    my $out = nn->HybridSequential(prefix=>'');
    $out->add(_make_fire_conv($squeeze_channels, 1));

    my $paths = nn->HybridConcurrent(axis=>1, prefix=>'');
    $paths->add(_make_fire_conv($expand1x1_channels, 1));
    $paths->add(_make_fire_conv($expand3x3_channels, 3, 1));
    $out->add($paths);

    return $out;
}

func _make_fire_conv($channels, $kernel_size, $padding=0)
{
    my $out = nn->HybridSequential(prefix=>'');
    $out->add(nn->Conv2D($channels, $kernel_size, padding=>$padding));
    $out->add(nn->Activation('relu'));
    return $out;
}

=head1 NAME

    AI::MXNet::Gluon::ModelZoo::Vision::SqueezeNet - SqueezeNet model from the "SqueezeNet: AlexNet-level accuracy with 50x fewer parameters and <0.5MB model size"
=cut

=head1 DESCRIPTION

    SqueezeNet model from the "SqueezeNet: AlexNet-level accuracy with 50x fewer parameters
    and <0.5MB model size" <https://arxiv.org/abs/1602.07360> paper.
    SqueezeNet 1.1 model from the official SqueezeNet repo
    <https://github.com/DeepScale/SqueezeNet/tree/master/SqueezeNet_v1.1>.
    SqueezeNet 1.1 has 2.4x less computation and slightly fewer parameters
    than SqueezeNet 1.0, without sacrificing accuracy.

    Parameters
    ----------
    version : Str
        Version of squeezenet. Options are '1.0', '1.1'.
    classes : Int, default 1000
        Number of classification classes.
=cut

has 'version' => (is => 'ro', isa => enum([qw[1.0 1.1]]), required => 1);
has 'classes' => (is => 'ro', isa => 'Int', default => 1000);
method python_constructor_arguments() { [qw/version classes/] }

sub BUILD
{
    my $self = shift;
    $self->name_scope(sub {
        $self->features(nn->HybridSequential(prefix=>''));
        if($self->version eq '1.0')
        {
            $self->features->add(nn->Conv2D(96, kernel_size=>7, strides=>2));
            $self->features->add(nn->Activation('relu'));
            $self->features->add(nn->MaxPool2D(pool_size=>3, strides=>2, ceil_mode=>1));
            $self->features->add(_make_fire(16, 64, 64));
            $self->features->add(_make_fire(16, 64, 64));
            $self->features->add(_make_fire(32, 128, 128));
            $self->features->add(nn->MaxPool2D(pool_size=>3, strides=>2, ceil_mode=>1));
            $self->features->add(_make_fire(32, 128, 128));
            $self->features->add(_make_fire(48, 192, 192));
            $self->features->add(_make_fire(48, 192, 192));
            $self->features->add(_make_fire(64, 256, 256));
            $self->features->add(nn->MaxPool2D(pool_size=>3, strides=>2, ceil_mode=>1));
            $self->features->add(_make_fire(64, 256, 256));
        }
        else
        {
            $self->features->add(nn->Conv2D(64, kernel_size=>3, strides=>2));
            $self->features->add(nn->Activation('relu'));
            $self->features->add(nn->MaxPool2D(pool_size=>3, strides=>2, ceil_mode=>1));
            $self->features->add(_make_fire(16, 64, 64));
            $self->features->add(_make_fire(16, 64, 64));
            $self->features->add(nn->MaxPool2D(pool_size=>3, strides=>2, ceil_mode=>1));
            $self->features->add(_make_fire(32, 128, 128));
            $self->features->add(_make_fire(32, 128, 128));
            $self->features->add(nn->MaxPool2D(pool_size=>3, strides=>2, ceil_mode=>1));
            $self->features->add(_make_fire(48, 192, 192));
            $self->features->add(_make_fire(48, 192, 192));
            $self->features->add(_make_fire(64, 256, 256));
            $self->features->add(_make_fire(64, 256, 256));
        }
        $self->features->add(nn->Dropout(0.5));

        $self->output(nn->HybridSequential(prefix=>''));
        $self->output->add(nn->Conv2D($self->classes, kernel_size=>1));
        $self->output->add(nn->Activation('relu'));
        $self->output->add(nn->AvgPool2D(13));
        $self->output->add(nn->Flatten());
    });
}

method hybrid_forward(GluonClass $F, GluonInput $x)
{
    $x = $self->features->($x);
    $x = $self->output->($x);
    return $x;
}


package AI::MXNet::Gluon::ModelZoo::Vision;

=head2 get_squeezenet

    SqueezeNet model from the "SqueezeNet: AlexNet-level accuracy with 50x fewer parameters
    and <0.5MB model size" <https://arxiv.org/abs/1602.07360> paper.
    SqueezeNet 1.1 model from the official SqueezeNet repo
    <https://github.com/DeepScale/SqueezeNet/tree/master/SqueezeNet_v1.1>.
    SqueezeNet 1.1 has 2.4x less computation and slightly fewer parameters
    than SqueezeNet 1.0, without sacrificing accuracy.

    Parameters
    ----------
    $version : Str
        Version of squeezenet. Options are '1.0', '1.1'.
    :$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

method get_squeezenet(
    Str $version, Bool :$pretrained=0, AI::MXNet::Context :$ctx=AI::MXNet::Context->cpu(),
    Str :$root='~/.mxnet/models', Int :$classes=1000
)
{
    my $net = AI::MXNet::Gluon::ModelZoo::Vision::SqueezeNet->new($version, $classes);
    if($pretrained)
    {
        $net->load_parameters(
            AI::MXNet::Gluon::ModelZoo::ModelStore->get_model_file(
                "squeezenet$version",
                root=>$root
            ),
            ctx=>$ctx
        );
    }
    return $net;
}

=head2 squeezenet1_0

    SqueezeNet 1.0 model from the "SqueezeNet: AlexNet-level accuracy with 50x fewer parameters
    and <0.5MB model size" <https://arxiv.org/abs/1602.07360> paper.

    Parameters
    ----------
    :$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

method squeezenet1_0(%kwargs)
{
    return __PACKAGE__->get_squeezenet('1.0', %kwargs);
}

=head2 squeezenet1_1

    SqueezeNet 1.1 model from the official SqueezeNet repo
    <https://github.com/DeepScale/SqueezeNet/tree/master/SqueezeNet_v1.1>.
    SqueezeNet 1.1 has 2.4x less computation and slightly fewer parameters
    than SqueezeNet 1.0, without sacrificing accuracy.

    Parameters
    ----------
    :$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

method squeezenet1_1(%kwargs)
{
    return __PACKAGE__->get_squeezenet('1.1', %kwargs);
}

1;

lib/AI/MXNet/Gluon/ModelZoo/Vision/VGG.pm  view on Meta::CPAN

# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License.  You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied.  See the License for the
# specific language governing permissions and limitations
# under the License.

use strict;
use warnings;
use AI::MXNet::Function::Parameters;
package AI::MXNet::Gluon::ModelZoo::Vision::VGG;
use AI::MXNet::Gluon::Mouse;
extends 'AI::MXNet::Gluon::HybridBlock';
use AI::MXNet::Base;

=head1 NAME 

    AI::MXNet::Gluon::ModelZoo::Vision::VGG - VGG model from the "Very Deep Convolutional Networks for Large-Scale Image Recognition"
=cut

=head1 DESCRIPTION

    VGG model from the "Very Deep Convolutional Networks for Large-Scale Image Recognition"
    <https://arxiv.org/abs/1409.1556> paper.

    Parameters
    ----------
    layers : array ref of Int
        Numbers of layers in each feature block.
    filters : array ref of Int
        Numbers of filters in each feature block. List length should match the layers.
    classes : Int, default 1000
        Number of classification classes.
    batch_norm : Bool, default 0
        Use batch normalization.
=cut
method python_constructor_arguments() { [qw/layers filters classes batch_norm/] }
has ['layers',
     'filters']   => (is => 'ro', isa => 'ArrayRef[Int]', required => 1);
has  'classes'    => (is => 'ro', isa => 'Int', default => 1000);
has  'batch_norm' => (is => 'ro', isa => 'Bool', default => 0);

sub BUILD
{
    my $self = shift;
    assert(@{ $self->layers } == @{ $self->filters });
    $self->name_scope(sub {
        $self->features($self->_make_features());
        $self->features->add(nn->Dense(4096, activation=>'relu',
                                       weight_initializer=>'normal',
                                       bias_initializer=>'zeros'));
        $self->features->add(nn->Dropout(rate=>0.5));
        $self->features->add(nn->Dense(4096, activation=>'relu',
                                       weight_initializer=>'normal',
                                       bias_initializer=>'zeros'));
        $self->features->add(nn->Dropout(rate=>0.5));
        $self->output(nn->Dense($self->classes,
                                   weight_initializer=>'normal',
                                   bias_initializer=>'zeros'));
    });
}

method _make_features()
{
    my $featurizer = nn->HybridSequential(prefix=>'');
    for(enumerate($self->layers))
    {
        my ($i, $num) = @$_;
        for(0..$num-1)
        {
            $featurizer->add(
                nn->Conv2D(
                    $self->filters->[$i], kernel_size => 3, padding => 1,
                    weight_initializer => mx->init->Xavier(
                        rnd_type    => 'gaussian',
                        factor_type => 'out',
                        magnitude   => 2
                    ),
                    bias_initializer=>'zeros'
                )
            );
            if($self->batch_norm)
            {
                $featurizer->add(nn->BatchNorm());
            }
            $featurizer->add(nn->Activation('relu'));
        }
        $featurizer->add(nn->MaxPool2D(strides=>2));
    }
    return $featurizer;
}

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 %vgg_spec = (
    11 => [[1, 1, 2, 2, 2], [64, 128, 256, 512, 512]],
    13 => [[2, 2, 2, 2, 2], [64, 128, 256, 512, 512]],
    16 => [[2, 2, 3, 3, 3], [64, 128, 256, 512, 512]],
    19 => [[2, 2, 4, 4, 4], [64, 128, 256, 512, 512]]
);

=head2 get_vgg

    VGG model from the "Very Deep Convolutional Networks for Large-Scale Image Recognition"
    <https://arxiv.org/abs/1409.1556> paper.

    Parameters
    ----------
    $num_layers : Int
        Number of layers for the variant of densenet. Options are 11, 13, 16, 19.
    :$pretrained : Bool, default 0
        Whether to load the pretrained weights for model.
    :$ctx : AI::MXNet::Context, default AI::MXNet::Context->cpu
        The context in which to load the pretrained weights.
    :$root : Str, default '~/.mxnet/models'
        Location for keeping the model parameters.
=cut

method get_vgg(
    Int $num_layers, Bool :$pretrained=0, AI::MXNet::Context :$ctx=AI::MXNet::Context->cpu(),
    Str :$root='~/.mxnet/models', Int :$classes=1000, Bool :$batch_norm=0
)
{
    my ($layers, $filters) = @{ $vgg_spec{$num_layers} };
    my $net = AI::MXNet::Gluon::ModelZoo::Vision::VGG->new($layers, $filters, $classes, $batch_norm);
    if($pretrained)
    {
        $net->load_parameters(
            AI::MXNet::Gluon::ModelZoo::ModelStore->get_model_file(
                "vgg$num_layers".($batch_norm ? '_bn' : ''),
                root=>$root
            ),
            ctx=>$ctx
        );
    }
    return $net;
}

=head2 vgg11

    VGG-11 model from the "Very Deep Convolutional Networks for Large-Scale Image Recognition"
    <https://arxiv.org/abs/1409.1556> paper.

    Parameters
    ----------
    :$pretrained : Bool, default 0
        Whether to load the pretrained weights for model.
    :$ctx : AI::MXNet::Context, default AI::MXNet::Context->cpu
        The context in which to load the pretrained weights.
    :$root : Str, default '~/.mxnet/models'
        Location for keeping the model parameters.
=cut

method vgg11(%kwargs)
{
    return __PACKAGE__->get_vgg(11, %kwargs);
}

=head2 vgg13

    VGG-13 model from the "Very Deep Convolutional Networks for Large-Scale Image Recognition"
    <https://arxiv.org/abs/1409.1556> paper.

    Parameters
    ----------
    :$pretrained : Bool, default 0
        Whether to load the pretrained weights for model.
    :$ctx : AI::MXNet::Context, default AI::MXNet::Context->cpu
        The context in which to load the pretrained weights.
    :$root : Str, default '~/.mxnet/models'
        Location for keeping the model parameters.
=cut

method vgg13(%kwargs)
{
    return __PACKAGE__->get_vgg(13, %kwargs);
}

=head2 vgg16

    VGG-16 model from the "Very Deep Convolutional Networks for Large-Scale Image Recognition"
    <https://arxiv.org/abs/1409.1556> paper.

    Parameters
    ----------
    :$pretrained : Bool, default 0
        Whether to load the pretrained weights for model.
    :$ctx : AI::MXNet::Context, default AI::MXNet::Context->cpu
        The context in which to load the pretrained weights.
    :$root : Str, default '~/.mxnet/models'
        Location for keeping the model parameters.
=cut

method vgg16(%kwargs)
{
    return __PACKAGE__->get_vgg(16, %kwargs);
}

=head2 vgg19

    VGG-19 model from the "Very Deep Convolutional Networks for Large-Scale Image Recognition"
    <https://arxiv.org/abs/1409.1556> paper.

    Parameters
    ----------
    :$pretrained : Bool, default 0
        Whether to load the pretrained weights for model.
    :$ctx : AI::MXNet::Context, default AI::MXNet::Context->cpu
        The context in which to load the pretrained weights.
    :$root : Str, default '~/.mxnet/models'
        Location for keeping the model parameters.
=cut

method vgg19(%kwargs)
{
    return __PACKAGE__->get_vgg(19, %kwargs);
}

=head2 vgg11_bn

    VGG-11 model with batch normalization from the "Very Deep Convolutional Networks for Large-Scale Image Recognition"
    <https://arxiv.org/abs/1409.1556> paper.

    Parameters
    ----------
    :$pretrained : Bool, default 0
        Whether to load the pretrained weights for model.
    :$ctx : AI::MXNet::Context, default AI::MXNet::Context->cpu
        The context in which to load the pretrained weights.
    :$root : Str, default '~/.mxnet/models'
        Location for keeping the model parameters.
=cut

method vgg11_bn(%kwargs)
{
    $kwargs{batch_norm} = 1;
    return __PACKAGE__->get_vgg(11, %kwargs);
}

=head2 vgg13_bn

    VGG-13 model with batch normalization from the "Very Deep Convolutional Networks for Large-Scale Image Recognition"
    <https://arxiv.org/abs/1409.1556> paper.

    Parameters
    ----------
    :$pretrained : Bool, default 0
        Whether to load the pretrained weights for model.
    :$ctx : AI::MXNet::Context, default AI::MXNet::Context->cpu
        The context in which to load the pretrained weights.
    :$root : Str, default '~/.mxnet/models'
        Location for keeping the model parameters.
=cut

method vgg13_bn(%kwargs)
{
    $kwargs{batch_norm} = 1;
    return __PACKAGE__->get_vgg(13, %kwargs);
}

=head2 vgg16_bn

    VGG-16 model with batch normalization from the "Very Deep Convolutional Networks for Large-Scale Image Recognition"
    <https://arxiv.org/abs/1409.1556> paper.

    Parameters
    ----------
    :$pretrained : Bool, default 0
        Whether to load the pretrained weights for model.
    :$ctx : AI::MXNet::Context, default AI::MXNet::Context->cpu
        The context in which to load the pretrained weights.
    :$root : Str, default '~/.mxnet/models'
        Location for keeping the model parameters.
=cut

method vgg16_bn(%kwargs)
{
    $kwargs{batch_norm} = 1;
    return __PACKAGE__->get_vgg(16, %kwargs);
}

=head2 vgg19_bn

    VGG-19 model with batch normalization from the "Very Deep Convolutional Networks for Large-Scale Image Recognition"
    <https://arxiv.org/abs/1409.1556> paper.

    Parameters
    ----------
    :$pretrained : Bool, default 0
        Whether to load the pretrained weights for model.
    :$ctx : AI::MXNet::Context, default AI::MXNet::Context->cpu
        The context in which to load the pretrained weights.
    :$root : Str, default '~/.mxnet/models'
        Location for keeping the model parameters.
=cut

method vgg19_bn(%kwargs)
{
    $kwargs{batch_norm} = 1;
    return __PACKAGE__->get_vgg(19, %kwargs);
}

1;

t/AI-MXNet-Gluon-ModelZoo.t  view on Meta::CPAN

# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License.  You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied.  See the License for the
# specific language governing permissions and limitations
# under the License.

use strict;
use warnings;
use Test::More tests => 1;
BEGIN { use_ok('AI::MXNet::Gluon::ModelZoo') };

t/test_gluon_model_zoo.t  view on Meta::CPAN

# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License.  You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied.  See the License for the
# specific language governing permissions and limitations
# under the License.

use strict;
use warnings;
use AI::MXNet::Gluon::ModelZoo qw(get_model);
use Test::More tests => 34;

sub test_models
{
    my @all_models = ('resnet34_v1', 'resnet18_v1', 'resnet50_v1', 'resnet101_v1', 'resnet152_v1',
                  'resnet18_v2', 'resnet34_v2', 'resnet50_v2', 'resnet101_v2', 'resnet152_v2',
                  'vgg11', 'vgg13', 'vgg16', 'vgg19',
                  'vgg11_bn', 'vgg13_bn', 'vgg16_bn', 'vgg19_bn',
                  'alexnet', 'inceptionv3',
                  'densenet121', 'densenet161', 'densenet169', 'densenet201',
                  'squeezenet1.0', 'squeezenet1.1',
                  'mobilenet1.0', 'mobilenet0.75', 'mobilenet0.5', 'mobilenet0.25',
                  'mobilenetv2_1.0', 'mobilenetv2_0.75', 'mobilenetv2_0.5', 'mobilenetv2_0.25');
    my %pretrained_to_test = ('squeezenet1.1' => 1);

    for my $model_name (@all_models)
    {
            my $test_pretrain = exists $pretrained_to_test{ $model_name };
            my $model = get_model($model_name, pretrained=>$test_pretrain, root=>'model/');
            my $data_shape = $model_name !~ /inception/ ? [2, 3, 224, 224] : [2, 3, 299, 299];
            if(not $test_pretrain)
            {
                $model->collect_params()->initialize();
            }
            $model->hybridize();
            $model->(mx->nd->random->uniform(shape=>$data_shape))->wait_to_read;
            ok(1, "forward for $model_name");
    }
}

test_models();

 view all matches for this distribution
 view release on metacpan -  search on metacpan

( run in 2.803 seconds using v1.00-cache-2.02-grep-82fe00e-cpan-cec75d87357c )