AI-TensorFlow-Libtensorflow

 view release on metacpan or  search on metacpan

lib/AI/TensorFlow/Libtensorflow/ImportGraphDefResults.pm  view on Meta::CPAN

	arg TF_ImportGraphDefResults => 'results',
] => 'void' );

$ffi->attach( [ 'ImportGraphDefResultsReturnOutputs' => 'ReturnOutputs' ] => [
	arg TF_ImportGraphDefResults => 'results',
	arg 'int*' => 'num_outputs',
	arg 'opaque*' => { id => 'outputs', type => 'TF_Output_struct_array*' },
] => 'void' => sub {
	my ($xs, $results) = @_;
	my $num_outputs;
	my $outputs_array = undef;
	$xs->($results, \$num_outputs, \$outputs_array);
	return [] if $num_outputs == 0;

	my $sizeof_output = $ffi->sizeof('TF_Output');
	window(my $outputs_packed, $outputs_array, $sizeof_output * $num_outputs );
	# due to unpack, these are copies (no longer owned by $results)
	my @outputs = map bless(\$_, "AI::TensorFlow::Libtensorflow::Output"),
		unpack "(a${sizeof_output})*", $outputs_packed;
	return \@outputs;
});

$ffi->attach( [ 'ImportGraphDefResultsReturnOperations' => 'ReturnOperations' ] => [
	arg TF_ImportGraphDefResults => 'results',
	arg 'int*' => 'num_opers',
	arg 'opaque*' => { id => 'opers', type => 'TF_Operation_array*' },
] => 'void' => sub {
	my ($xs, $results) = @_;
	my $num_opers;
	my $opers_array = undef;
	$xs->($results, \$num_opers, \$opers_array);
	return [] if $num_opers == 0;

	my $opers_array_base_packed = buffer_to_scalar($opers_array,
		$ffi->sizeof('opaque') * $num_opers );
	my @opers = map {
		$ffi->cast('opaque', 'TF_Operation', $_ )
	} unpack "(@{[ AI::TensorFlow::Libtensorflow::Lib::_pointer_incantation ]})*", $opers_array_base_packed;
	return \@opers;
} );

lib/AI/TensorFlow/Libtensorflow/Lib/FFIType/Variant/PackableMaybeArrayRef.pm  view on Meta::CPAN

package AI::TensorFlow::Libtensorflow::Lib::FFIType::Variant::PackableMaybeArrayRef;
# ABSTRACT: Maybe[ArrayRef] to pack()'ed scalar argument with size argument (as int) (size is -1 if undef)
$AI::TensorFlow::Libtensorflow::Lib::FFIType::Variant::PackableMaybeArrayRef::VERSION = '0.0.7';
use strict;
use warnings;
use FFI::Platypus::Buffer qw(scalar_to_buffer buffer_to_scalar);
use FFI::Platypus::API qw( arguments_set_pointer arguments_set_sint32 );

use Package::Variant;
use Module::Runtime 'module_notional_filename';

sub make_variant {

lib/AI/TensorFlow/Libtensorflow/Lib/FFIType/Variant/PackableMaybeArrayRef.pm  view on Meta::CPAN

		if( defined $value ) {
			die "Value must be an ArrayRef" unless ref $value eq 'ARRAY';
			my $data = pack  $arguments{pack_type} . '*', @$value;
			my $n    = scalar @$value;
			my ($pointer, $size) = scalar_to_buffer($data);

			push @stack, [ \$data, $pointer, $size ];
			arguments_set_pointer( $i  , $pointer);
			arguments_set_sint32(  $i+1, $n);
		} else {
			my $data = undef;
			my $n    = -1;
			my ($pointer, $size) = (0, 0);
			push @stack, [ \$data, $pointer, $size ];
			arguments_set_pointer( $i  , $pointer);
			arguments_set_sint32(  $i+1, $n);
		}
	};

	my $perl_to_native_post = install perl_to_native_post => sub {
		my ($data_ref, $pointer, $size) = @{ pop @stack };

lib/AI/TensorFlow/Libtensorflow/Lib/FFIType/Variant/PackableMaybeArrayRef.pm  view on Meta::CPAN

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

AI::TensorFlow::Libtensorflow::Lib::FFIType::Variant::PackableMaybeArrayRef - Maybe[ArrayRef] to pack()'ed scalar argument with size argument (as int) (size is -1 if undef)

=head1 AUTHOR

Zakariyya Mughal <zmughal@cpan.org>

=head1 COPYRIGHT AND LICENSE

This software is Copyright (c) 2022-2023 by Auto-Parallel Technologies, Inc.

This is free software, licensed under:

lib/AI/TensorFlow/Libtensorflow/Lib/_Alloc.pm  view on Meta::CPAN

use FFI::Platypus::Buffer qw(buffer_to_scalar window);
use Sub::Quote qw(quote_sub);

use Feature::Compat::Defer;

# If _aligned_alloc() implementation needs the size to be a multiple of the
# alignment.
our $_ALIGNED_ALLOC_ALIGNMENT_MULTIPLE = 0;

my $ffi = FFI::Platypus->new;
$ffi->lib(undef);
if( $ffi->find_symbol('aligned_alloc') ) {
	# C11 aligned_alloc()
	# NOTE: C11 aligned_alloc not available on Windows.
	# void *aligned_alloc(size_t alignment, size_t size);
	$ffi->attach( [ 'aligned_alloc' => '_aligned_alloc' ] =>
		[ 'size_t', 'size_t' ] => 'opaque' );
	*_aligned_free = *free;
	$_ALIGNED_ALLOC_ALIGNMENT_MULTIPLE = 1;
} else {
	# Pure Perl _aligned_alloc()

lib/AI/TensorFlow/Libtensorflow/Manual/CAPI.pod  view on Meta::CPAN

  Fills in `funcs` with the TF_Function* registered in `g`.
  `funcs` must point to an array of TF_Function* of length at least
  `max_func`. In usual usage, max_func should be set to the result of
  TF_GraphNumFunctions(g). In this case, all the functions registered in
  `g` will be returned. Else, an unspecified subset.
  
  If successful, returns the number of TF_Function* successfully set in
  `funcs` and sets status to OK. The caller takes ownership of
  all the returned TF_Functions. They must be deleted with TF_DeleteFunction.
  On error, returns 0, sets status to the encountered error, and the contents
  of funcs will be undefined.

=back

  /* From <tensorflow/c/c_api.h> */
  TF_CAPI_EXPORT extern int TF_GraphGetFunctions(TF_Graph* g, TF_Function** funcs,
                                                 int max_func, TF_Status* status);

=head2 TF_OperationToNodeDef

=over 2

lib/AI/TensorFlow/Libtensorflow/Manual/CAPI.pod  view on Meta::CPAN

=back

  /* From <tensorflow/c/tf_shape.h> */
  TF_CAPI_EXPORT extern int TF_ShapeDims(const TF_Shape* shape);

=head2 TF_ShapeDimSize

=over 2

  Returns the `d`th dimension of `shape`. If `shape` has unknown rank,
  invoking this function is undefined behavior. Returns -1 if dimension is
  unknown.

=back

  /* From <tensorflow/c/tf_shape.h> */
  TF_CAPI_EXPORT extern int64_t TF_ShapeDimSize(const TF_Shape* shape, int d);

=head2 TF_DeleteShape

=over 2

lib/AI/TensorFlow/Libtensorflow/Manual/CAPI.pod  view on Meta::CPAN

    (1) If attr_type == TF_ATTR_STRING
        then total_size is the cumulative byte size
        of all the strings in the list.
    (3) If attr_type == TF_ATTR_SHAPE
        then total_size is the number of dimensions
        of the shape valued attribute, or -1
        if its rank is unknown.
    (4) If attr_type == TF_ATTR_SHAPE
        then total_size is the cumulative number
        of dimensions of all shapes in the list.
    (5) Otherwise, total_size is undefined.

=back

  /* From <tensorflow/c/kernels.h> */
  TF_CAPI_EXPORT extern void TF_OpKernelConstruction_GetAttrSize(
      TF_OpKernelConstruction* ctx, const char* attr_name, int32_t* list_size,
      int32_t* total_size, TF_Status* status);

=head2 TF_OpKernelConstruction_GetAttrType

lib/AI/TensorFlow/Libtensorflow/Manual/CAPI.pod  view on Meta::CPAN

=back

  /* From <tensorflow/c/c_api_experimental.h> */
  TF_CAPI_EXPORT extern const char* TF_GetNumberAttrForOpListInput(
      const char* op_name, int input_index, TF_Status* status);

=head2 TF_OpIsStateful

=over 2

  Returns 1 if the op is stateful, 0 otherwise. The return value is undefined
  if the status is not ok.

=back

  /* From <tensorflow/c/c_api_experimental.h> */
  TF_CAPI_EXPORT extern int TF_OpIsStateful(const char* op_type,
                                            TF_Status* status);

=head2 TF_InitMain

lib/AI/TensorFlow/Libtensorflow/Manual/Notebook/InferenceUsingTFHubCenterNetObjDetect.pod  view on Meta::CPAN


use PDL;
use AI::TensorFlow::Libtensorflow::DataType qw(FLOAT UINT8);

use FFI::Platypus::Memory qw(memcpy);
use FFI::Platypus::Buffer qw(scalar_to_pointer);

sub FloatPDLTOTFTensor {
    my ($p) = @_;
    return AI::TensorFlow::Libtensorflow::Tensor->New(
        FLOAT, [ reverse $p->dims ], $p->get_dataref, sub { undef $p }
    );
}

sub FloatTFTensorToPDL {
    my ($t) = @_;

    my $pdl = zeros(float,reverse( map $t->Dim($_), 0..$t->NumDims-1 ) );

    memcpy scalar_to_pointer( ${$pdl->get_dataref} ),
        scalar_to_pointer( ${$t->Data} ),
        $t->ByteSize;
    $pdl->upd_data;

    $pdl;
}

sub Uint8PDLTOTFTensor {
    my ($p) = @_;
    return AI::TensorFlow::Libtensorflow::Tensor->New(
        UINT8, [ reverse $p->dims ], $p->get_dataref, sub { undef $p }
    );
}

sub Uint8TFTensorToPDL {
    my ($t) = @_;

    my $pdl = zeros(byte,reverse( map $t->Dim($_), 0..$t->NumDims-1 ) );

    memcpy scalar_to_pointer( ${$pdl->get_dataref} ),
        scalar_to_pointer( ${$t->Data} ),

lib/AI/TensorFlow/Libtensorflow/Manual/Notebook/InferenceUsingTFHubCenterNetObjDetect.pod  view on Meta::CPAN

        qw(--signature_def) => 'serving_default'
    ) == 0 or die "Could not run saved_model_cli";
} else {
    say "Install the tensorflow Python package to get the `saved_model_cli` command.";
}

my $opt = AI::TensorFlow::Libtensorflow::SessionOptions->New;

my $graph = AI::TensorFlow::Libtensorflow::Graph->New;
my $session = AI::TensorFlow::Libtensorflow::Session->LoadFromSavedModel(
    $opt, undef, $model_base, \@tags, $graph, undef, $s
);
AssertOK($s);

my %ops = (
    in  => {
        op   =>  $graph->OperationByName('serving_default_input_tensor'),
        dict => {
            input_tensor => 0,
        }
    },

lib/AI/TensorFlow/Libtensorflow/Manual/Notebook/InferenceUsingTFHubCenterNetObjDetect.pod  view on Meta::CPAN

p $pdl_image_batched;
p $t;

my $RunSession = sub {
    my ($session, $t) = @_;
    my @outputs_t;

    my @keys = keys %{ $outputs{out} };
    my @values = $outputs{out}->@{ @keys };
    $session->Run(
        undef,
        [ values %{$outputs{in} } ], [$t],
        \@values, \@outputs_t,
        undef,
        undef,
        $s
    );
    AssertOK($s);

    return { mesh \@keys, \@outputs_t };
};

undef;

my $tftensor_output_by_name = $RunSession->($session, $t);

my %pdl_output_by_name = map {
    $_ => FloatTFTensorToPDL( $tftensor_output_by_name->{$_} )
} keys $tftensor_output_by_name->%*;

undef;

my $min_score_thresh = 0.30;

my $which_detect = which( $pdl_output_by_name{detection_scores} > $min_score_thresh );

my %subset;

$subset{detection_boxes}   = $pdl_output_by_name{detection_boxes}->dice('X', $which_detect);
$subset{detection_classes} = $pdl_output_by_name{detection_classes}->dice($which_detect);
$subset{detection_scores}  = $pdl_output_by_name{detection_scores}->dice($which_detect);

lib/AI/TensorFlow/Libtensorflow/Manual/Notebook/InferenceUsingTFHubCenterNetObjDetect.pod  view on Meta::CPAN


$gp->close;

IPerl->png( bytestream => path($plot_output_path)->slurp_raw ) if IN_IPERL;

use Filesys::DiskUsage qw/du/;

my $total = du( { 'human-readable' => 1, dereference => 1 },
    $model_archive_path, $model_base );

say "Disk space usage: $total"; undef;

__END__

=pod

=encoding UTF-8

=head1 NAME

AI::TensorFlow::Libtensorflow::Manual::Notebook::InferenceUsingTFHubCenterNetObjDetect - Using TensorFlow to do object detection using a pre-trained model

lib/AI/TensorFlow/Libtensorflow/Manual/Notebook/InferenceUsingTFHubCenterNetObjDetect.pod  view on Meta::CPAN


  use PDL;
  use AI::TensorFlow::Libtensorflow::DataType qw(FLOAT UINT8);
  
  use FFI::Platypus::Memory qw(memcpy);
  use FFI::Platypus::Buffer qw(scalar_to_pointer);
  
  sub FloatPDLTOTFTensor {
      my ($p) = @_;
      return AI::TensorFlow::Libtensorflow::Tensor->New(
          FLOAT, [ reverse $p->dims ], $p->get_dataref, sub { undef $p }
      );
  }
  
  sub FloatTFTensorToPDL {
      my ($t) = @_;
  
      my $pdl = zeros(float,reverse( map $t->Dim($_), 0..$t->NumDims-1 ) );
  
      memcpy scalar_to_pointer( ${$pdl->get_dataref} ),
          scalar_to_pointer( ${$t->Data} ),
          $t->ByteSize;
      $pdl->upd_data;
  
      $pdl;
  }
  
  sub Uint8PDLTOTFTensor {
      my ($p) = @_;
      return AI::TensorFlow::Libtensorflow::Tensor->New(
          UINT8, [ reverse $p->dims ], $p->get_dataref, sub { undef $p }
      );
  }
  
  sub Uint8TFTensorToPDL {
      my ($t) = @_;
  
      my $pdl = zeros(byte,reverse( map $t->Dim($_), 0..$t->NumDims-1 ) );
  
      memcpy scalar_to_pointer( ${$pdl->get_dataref} ),
          scalar_to_pointer( ${$t->Data} ),

lib/AI/TensorFlow/Libtensorflow/Manual/Notebook/InferenceUsingTFHubCenterNetObjDetect.pod  view on Meta::CPAN

=back

Note that the above documentation has two errors: both C<num_detections> and C<detection_classes> are not of type C<tf.int>, but are actually C<tf.float32>.

Now we can load the model from that folder with the tag set C<[ 'serve' ]> by using the C<LoadFromSavedModel> constructor to create a C<::Graph> and a C<::Session> for that graph.

  my $opt = AI::TensorFlow::Libtensorflow::SessionOptions->New;
  
  my $graph = AI::TensorFlow::Libtensorflow::Graph->New;
  my $session = AI::TensorFlow::Libtensorflow::Session->LoadFromSavedModel(
      $opt, undef, $model_base, \@tags, $graph, undef, $s
  );
  AssertOK($s);

So let's use the names from the C<saved_model_cli> output to create our C<::Output> C<ArrayRef>s.

  my %ops = (
      in  => {
          op   =>  $graph->OperationByName('serving_default_input_tensor'),
          dict => {
              input_tensor => 0,

lib/AI/TensorFlow/Libtensorflow/Manual/Notebook/InferenceUsingTFHubCenterNetObjDetect.pod  view on Meta::CPAN


We can use the C<Run> method to run the session and get the multiple output C<TFTensor>s. The following uses the names in C<$outputs> mapping to help process the multiple outputs more easily.

  my $RunSession = sub {
      my ($session, $t) = @_;
      my @outputs_t;
  
      my @keys = keys %{ $outputs{out} };
      my @values = $outputs{out}->@{ @keys };
      $session->Run(
          undef,
          [ values %{$outputs{in} } ], [$t],
          \@values, \@outputs_t,
          undef,
          undef,
          $s
      );
      AssertOK($s);
  
      return { mesh \@keys, \@outputs_t };
  };
  
  undef;



  my $tftensor_output_by_name = $RunSession->($session, $t);
  
  my %pdl_output_by_name = map {
      $_ => FloatTFTensorToPDL( $tftensor_output_by_name->{$_} )
  } keys $tftensor_output_by_name->%*;
  
  undef;

=head2 Results summary

Then we use a score threshold to select the objects of interest.

  my $min_score_thresh = 0.30;
  
  my $which_detect = which( $pdl_output_by_name{detection_scores} > $min_score_thresh );
  
  my %subset;

lib/AI/TensorFlow/Libtensorflow/Manual/Notebook/InferenceUsingTFHubCenterNetObjDetect.pod  view on Meta::CPAN

  
  IPerl->png( bytestream => path($plot_output_path)->slurp_raw ) if IN_IPERL;

=head1 RESOURCE USAGE

  use Filesys::DiskUsage qw/du/;
  
  my $total = du( { 'human-readable' => 1, dereference => 1 },
      $model_archive_path, $model_base );
  
  say "Disk space usage: $total"; undef;

=head1 CPANFILE

  requires 'AI::TensorFlow::Libtensorflow';
  requires 'AI::TensorFlow::Libtensorflow::DataType';
  requires 'Archive::Extract';
  requires 'Data::Printer';
  requires 'Data::Printer::Filter::PDL';
  requires 'FFI::Platypus::Buffer';
  requires 'FFI::Platypus::Memory';

lib/AI/TensorFlow/Libtensorflow/Manual/Notebook/InferenceUsingTFHubEnformerGeneExprPredModel.pod  view on Meta::CPAN


use PDL;
use AI::TensorFlow::Libtensorflow::DataType qw(FLOAT);

use FFI::Platypus::Memory qw(memcpy);
use FFI::Platypus::Buffer qw(scalar_to_pointer);

sub FloatPDLTOTFTensor {
    my ($p) = @_;
    return AI::TensorFlow::Libtensorflow::Tensor->New(
        FLOAT, [ reverse $p->dims ], $p->get_dataref, sub { undef $p }
    );
}

sub FloatTFTensorToPDL {
    my ($t) = @_;

    my $pdl = zeros(float,reverse( map $t->Dim($_), 0..$t->NumDims-1 ) );

    memcpy scalar_to_pointer( ${$pdl->get_dataref} ),
        scalar_to_pointer( ${$t->Data} ),

lib/AI/TensorFlow/Libtensorflow/Manual/Notebook/InferenceUsingTFHubEnformerGeneExprPredModel.pod  view on Meta::CPAN

say "";

say "First 5:";
say $df->head(5);

my $opt = AI::TensorFlow::Libtensorflow::SessionOptions->New;

my @tags = ( 'serve' );
my $graph = AI::TensorFlow::Libtensorflow::Graph->New;
my $session = AI::TensorFlow::Libtensorflow::Session->LoadFromSavedModel(
    $opt, undef, $new_model_base, \@tags, $graph, undef, $s
);
AssertOK($s);

my %puts = (
    ## Inputs
    inputs_args_0 =>
        AI::TensorFlow::Libtensorflow::Output->New({
            oper => $graph->OperationByName('serving_default_args_0'),
            index => 0,
        }),

lib/AI/TensorFlow/Libtensorflow/Manual/Notebook/InferenceUsingTFHubEnformerGeneExprPredModel.pod  view on Meta::CPAN

    }),
);

p %puts;

my $predict_on_batch = sub {
    my ($session, $t) = @_;
    my @outputs_t;

    $session->Run(
        undef,
        [$puts{inputs_args_0}], [$t],
        [$puts{outputs_human}], \@outputs_t,
        undef,
        undef,
        $s
    );
    AssertOK($s);

    return $outputs_t[0];
};

undef;

use PDL;

our $SHOW_ENCODER = 1;

sub one_hot_dna {
    my ($seq) = @_;

    my $from_alphabet = "NACGT";
    my $to_alphabet   = pack "C*", 0..length($from_alphabet)-1;

lib/AI/TensorFlow/Libtensorflow/Manual/Notebook/InferenceUsingTFHubEnformerGeneExprPredModel.pod  view on Meta::CPAN

    for(0..5) {
        my $base = $test_interval->length;
        my $to = $base + $_;
        _debug_resize $test_interval, $to, "$base -> $to (+ $_)";
    }
    say "";
}

}

undef;

use Bio::DB::HTS::Faidx;

my $hg_db = Bio::DB::HTS::Faidx->new( $hg_bgz_path );

sub extract_sequence {
    my ($db, $interval) = @_;

    my $chrom_length = $db->length($interval->seq_id);

lib/AI/TensorFlow/Libtensorflow/Manual/Notebook/InferenceUsingTFHubEnformerGeneExprPredModel.pod  view on Meta::CPAN

say "Resized interval: $resized_interval with length @{[ $resized_interval->length ]}";

die "resize() is not working properly!" unless $resized_interval->length == $model_sequence_length;

my $seq = extract_sequence( $hg_db, $resized_interval );

say "Resized sequence is ", seq_info($seq);

my $sequence_one_hot = one_hot_dna( $seq )->dummy(-1);

say $sequence_one_hot->info; undef;

use Devel::Timer;
my $t = Devel::Timer->new;

$t->mark('prediction of sequence');

my $predictions = $predict_on_batch->( $session, FloatPDLTOTFTensor( $sequence_one_hot ) );

$t->mark('End of prediction of sequence');

p $predictions;

$t->mark('END');
$t->report();

my $predictions_p = FloatTFTensorToPDL($predictions)->slice(',,(0)');
say $predictions_p->info; undef;

my @tracks = (
    [ 'DNASE:CD14-positive monocyte female' =>   41 => $predictions_p->slice('(41)') ],
    [ 'DNASE:keratinocyte female'           =>   42 => $predictions_p->slice('(42)') ],
    [ 'CHIP:H3K27ac:keratinocyte female'    =>  706 => $predictions_p->slice('(706)')],
    [ 'CAGE:Keratinocyte - epidermal'       => 4799 => log10(1 + $predictions_p->slice('(4799)')) ],
);

use PDL::Graphics::Gnuplot;

lib/AI/TensorFlow/Libtensorflow/Manual/Notebook/InferenceUsingTFHubEnformerGeneExprPredModel.pod  view on Meta::CPAN


my $clinvar_tbi_path = "${clinvar_path}.tbi";
unless( -f $clinvar_tbi_path ) {
    system( qw(tabix), $clinvar_path );
}
my $v = Bio::DB::HTS::VCF->new( filename => $clinvar_path );
$v->num_variants

COMMENT

undef;

use Filesys::DiskUsage qw/du/;

my $total = du( { 'human-readable' => 1, dereference => 1 },
    $model_archive_path, $model_base, $new_model_base,

    $targets_path,

    $hg_gz_path,
    $hg_bgz_path, $hg_bgz_fai_path,

    $clinvar_path,

    $plot_output_path,
);

say "Disk space usage: $total"; undef;

__END__

=pod

=encoding UTF-8

=head1 NAME

AI::TensorFlow::Libtensorflow::Manual::Notebook::InferenceUsingTFHubEnformerGeneExprPredModel - Using TensorFlow to do gene expression prediction using a pre-trained model

lib/AI/TensorFlow/Libtensorflow/Manual/Notebook/InferenceUsingTFHubEnformerGeneExprPredModel.pod  view on Meta::CPAN


  use PDL;
  use AI::TensorFlow::Libtensorflow::DataType qw(FLOAT);
  
  use FFI::Platypus::Memory qw(memcpy);
  use FFI::Platypus::Buffer qw(scalar_to_pointer);
  
  sub FloatPDLTOTFTensor {
      my ($p) = @_;
      return AI::TensorFlow::Libtensorflow::Tensor->New(
          FLOAT, [ reverse $p->dims ], $p->get_dataref, sub { undef $p }
      );
  }
  
  sub FloatTFTensorToPDL {
      my ($t) = @_;
  
      my $pdl = zeros(float,reverse( map $t->Dim($_), 0..$t->NumDims-1 ) );
  
      memcpy scalar_to_pointer( ${$pdl->get_dataref} ),
          scalar_to_pointer( ${$t->Data} ),

lib/AI/TensorFlow/Libtensorflow/Manual/Notebook/InferenceUsingTFHubEnformerGeneExprPredModel.pod  view on Meta::CPAN


=head2 Load the model

Let's now load the model in Perl and get the inputs and outputs into a data structure by name.

  my $opt = AI::TensorFlow::Libtensorflow::SessionOptions->New;
  
  my @tags = ( 'serve' );
  my $graph = AI::TensorFlow::Libtensorflow::Graph->New;
  my $session = AI::TensorFlow::Libtensorflow::Session->LoadFromSavedModel(
      $opt, undef, $new_model_base, \@tags, $graph, undef, $s
  );
  AssertOK($s);
  
  my %puts = (
      ## Inputs
      inputs_args_0 =>
          AI::TensorFlow::Libtensorflow::Output->New({
              oper => $graph->OperationByName('serving_default_args_0'),
              index => 0,
          }),

lib/AI/TensorFlow/Libtensorflow/Manual/Notebook/InferenceUsingTFHubEnformerGeneExprPredModel.pod  view on Meta::CPAN

</span><span style="color: #33ccff;">}</span><span style="">
</span></code></pre></span>

We need a helper to simplify running the session and getting just the predictions that we want.

  my $predict_on_batch = sub {
      my ($session, $t) = @_;
      my @outputs_t;
  
      $session->Run(
          undef,
          [$puts{inputs_args_0}], [$t],
          [$puts{outputs_human}], \@outputs_t,
          undef,
          undef,
          $s
      );
      AssertOK($s);
  
      return $outputs_t[0];
  };
  
  undef;

=head2 Encoding the data

The model specifies that the way to get a sequence of DNA bases into a C<TFTensor> is to use L<one-hot encoding|https://en.wikipedia.org/wiki/One-hot#Machine_learning_and_statistics> in the order C<ACGT>.

This means that the bases are represented as vectors of length 4:

| base | vector encoding |
|------|-----------------|
| A    | C<[1 0 0 0]>     |

lib/AI/TensorFlow/Libtensorflow/Manual/Notebook/InferenceUsingTFHubEnformerGeneExprPredModel.pod  view on Meta::CPAN

      for(0..5) {
          my $base = $test_interval->length;
          my $to = $base + $_;
          _debug_resize $test_interval, $to, "$base -> $to (+ $_)";
      }
      say "";
  }
  
  }
  
  undef;

B<STREAM (STDOUT)>:

  Testing interval resizing:
  
  Testing interval chr11:4..8 with length 5
  -----
  Interval: chr11:4..8 -> chr11:4..8, length  5 : 5 -> 5 (+ 0)
  Interval: chr11:4..8 -> chr11:3..8, length  6 : 5 -> 6 (+ 1)
  Interval: chr11:4..8 -> chr11:3..9, length  7 : 5 -> 7 (+ 2)

lib/AI/TensorFlow/Libtensorflow/Manual/Notebook/InferenceUsingTFHubEnformerGeneExprPredModel.pod  view on Meta::CPAN

  Resized sequence is ACTAGTTCTA...GGCCCAAATC (length 393216)

B<RESULT>:

  1

To prepare the input we have to one-hot encode this resized sequence and give it a dummy dimension at the end to indicate that it is is a batch with a single sequence. Then we can turn the PDL ndarray into a C<TFTensor> and pass it to our prediction ...

  my $sequence_one_hot = one_hot_dna( $seq )->dummy(-1);
  
  say $sequence_one_hot->info; undef;

B<STREAM (STDOUT)>:

  PDL: Float D [4,393216,1]


  use Devel::Timer;
  my $t = Devel::Timer->new;
  
  $t->mark('prediction of sequence');

lib/AI/TensorFlow/Libtensorflow/Manual/Notebook/InferenceUsingTFHubEnformerGeneExprPredModel.pod  view on Meta::CPAN

01 -&gt; 02  14.5634  100.00%  prediction of sequence -&gt; End of prediction of sequence
02 -&gt; 03  0.0007   0.00%  End of prediction of sequence -&gt; END
00 -&gt; 01  0.0000   0.00%  INIT -&gt; prediction of sequence
</span></code></pre></span>

=end html

Now we turn the C<TFTensor> output into a PDL ndarray.

  my $predictions_p = FloatTFTensorToPDL($predictions)->slice(',,(0)');
  say $predictions_p->info; undef;

B<STREAM (STDOUT)>:

  PDL: Float D [5313,896]

=head2 Plot predicted tracks

These predictions can be plotted 

  my @tracks = (

lib/AI/TensorFlow/Libtensorflow/Manual/Notebook/InferenceUsingTFHubEnformerGeneExprPredModel.pod  view on Meta::CPAN

  
  my $clinvar_tbi_path = "${clinvar_path}.tbi";
  unless( -f $clinvar_tbi_path ) {
      system( qw(tabix), $clinvar_path );
  }
  my $v = Bio::DB::HTS::VCF->new( filename => $clinvar_path );
  $v->num_variants
  
  COMMENT
  
  undef;

=head1 RESOURCE USAGE

  use Filesys::DiskUsage qw/du/;
  
  my $total = du( { 'human-readable' => 1, dereference => 1 },
      $model_archive_path, $model_base, $new_model_base,
  
      $targets_path,
  
      $hg_gz_path,
      $hg_bgz_path, $hg_bgz_fai_path,
  
      $clinvar_path,
  
      $plot_output_path,
  );
  
  say "Disk space usage: $total"; undef;

B<STREAM (STDOUT)>:

  Disk space usage: 4.66G

=head1 CPANFILE

  requires 'AI::TensorFlow::Libtensorflow';
  requires 'AI::TensorFlow::Libtensorflow::DataType';
  requires 'Archive::Extract';

lib/AI/TensorFlow/Libtensorflow/Manual/Notebook/InferenceUsingTFHubMobileNetV2Model.pod  view on Meta::CPAN


use PDL;
use AI::TensorFlow::Libtensorflow::DataType qw(FLOAT);

use FFI::Platypus::Memory qw(memcpy);
use FFI::Platypus::Buffer qw(scalar_to_pointer);

sub FloatPDLTOTFTensor {
    my ($p) = @_;
    return AI::TensorFlow::Libtensorflow::Tensor->New(
        FLOAT, [ reverse $p->dims ], $p->get_dataref, sub { undef $p }
    );
}

sub FloatTFTensorToPDL {
    my ($t) = @_;

    my $pdl = zeros(float,reverse( map $t->Dim($_), 0..$t->NumDims-1 ) );

    memcpy scalar_to_pointer( ${$pdl->get_dataref} ),
        scalar_to_pointer( ${$t->Data} ),

lib/AI/TensorFlow/Libtensorflow/Manual/Notebook/InferenceUsingTFHubMobileNetV2Model.pod  view on Meta::CPAN

        qw(--signature_def) => 'serving_default'
    ) == 0 or die "Could not run saved_model_cli";
} else {
    say "Install the tensorflow Python package to get the `saved_model_cli` command.";
}

my $opt = AI::TensorFlow::Libtensorflow::SessionOptions->New;

my $graph = AI::TensorFlow::Libtensorflow::Graph->New;
my $session = AI::TensorFlow::Libtensorflow::Session->LoadFromSavedModel(
    $opt, undef, $model_base, \@tags, $graph, undef, $s
);
AssertOK($s);

my %ops = (
    in  => $graph->OperationByName('serving_default_inputs'),
    out => $graph->OperationByName('StatefulPartitionedCall'),
);

die "Could not get all operations" unless List::Util::all(sub { defined }, values %ops);

lib/AI/TensorFlow/Libtensorflow/Manual/Notebook/InferenceUsingTFHubMobileNetV2Model.pod  view on Meta::CPAN

my $t = FloatPDLTOTFTensor($pdl_image_batched);

p $pdl_image_batched;
p $t;

my $RunSession = sub {
    my ($session, $t) = @_;
    my @outputs_t;

    $session->Run(
        undef,
        $outputs{in}, [$t],
        $outputs{out}, \@outputs_t,
        undef,
        undef,
        $s
    );
    AssertOK($s);

    return $outputs_t[0];
};

say "Warming up the model";
use PDL::GSL::RNG;
my $rng = PDL::GSL::RNG->new('default');

lib/AI/TensorFlow/Libtensorflow/Manual/Notebook/InferenceUsingTFHubMobileNetV2Model.pod  view on Meta::CPAN


my $p_approx_batched = $probabilities_batched->sumover->approx(1, 1e-5);
p $p_approx_batched;
say "All probabilities sum up to approximately 1" if $p_approx_batched->all->sclr;

use Filesys::DiskUsage qw/du/;

my $total = du( { 'human-readable' => 1, dereference => 1 },
    $model_archive_path, $model_base, $labels_path );

say "Disk space usage: $total"; undef;

my @solid_channel_uris = (
    'https://upload.wikimedia.org/wikipedia/commons/thumb/6/62/Solid_red.svg/480px-Solid_red.svg.png',
    'https://upload.wikimedia.org/wikipedia/commons/thumb/1/1d/Green_00FF00_9x9.svg/480px-Green_00FF00_9x9.svg.png',
    'https://upload.wikimedia.org/wikipedia/commons/thumb/f/ff/Solid_blue.svg/480px-Solid_blue.svg.png',
);
undef;

__END__

=pod

=encoding UTF-8

=head1 NAME

AI::TensorFlow::Libtensorflow::Manual::Notebook::InferenceUsingTFHubMobileNetV2Model - Using TensorFlow to do image classification using a pre-trained model

lib/AI/TensorFlow/Libtensorflow/Manual/Notebook/InferenceUsingTFHubMobileNetV2Model.pod  view on Meta::CPAN


  use PDL;
  use AI::TensorFlow::Libtensorflow::DataType qw(FLOAT);
  
  use FFI::Platypus::Memory qw(memcpy);
  use FFI::Platypus::Buffer qw(scalar_to_pointer);
  
  sub FloatPDLTOTFTensor {
      my ($p) = @_;
      return AI::TensorFlow::Libtensorflow::Tensor->New(
          FLOAT, [ reverse $p->dims ], $p->get_dataref, sub { undef $p }
      );
  }
  
  sub FloatTFTensorToPDL {
      my ($t) = @_;
  
      my $pdl = zeros(float,reverse( map $t->Dim($_), 0..$t->NumDims-1 ) );
  
      memcpy scalar_to_pointer( ${$pdl->get_dataref} ),
          scalar_to_pointer( ${$t->Data} ),

lib/AI/TensorFlow/Libtensorflow/Manual/Notebook/InferenceUsingTFHubMobileNetV2Model.pod  view on Meta::CPAN

For the C<input>, we have C<(-1, 224, 224, 3)> which is a L<common input image specification for TensorFlow Hub|https://www.tensorflow.org/hub/common_signatures/images#input>. This is known as C<channels_last> (or C<NHWC>) layout where the TensorFlow...

For the C<output>, we have C<(-1, 1001)> which is C<[batch_size, num_classes]> where the elements are scores that the image received for that ImageNet class.

Now we can load the model from that folder with the tag set C<[ 'serve' ]> by using the C<LoadFromSavedModel> constructor to create a C<::Graph> and a C<::Session> for that graph.

  my $opt = AI::TensorFlow::Libtensorflow::SessionOptions->New;
  
  my $graph = AI::TensorFlow::Libtensorflow::Graph->New;
  my $session = AI::TensorFlow::Libtensorflow::Session->LoadFromSavedModel(
      $opt, undef, $model_base, \@tags, $graph, undef, $s
  );
  AssertOK($s);

So let's use the names from the C<saved_model_cli> output to create our C<::Output> C<ArrayRef>s.

  my %ops = (
      in  => $graph->OperationByName('serving_default_inputs'),
      out => $graph->OperationByName('StatefulPartitionedCall'),
  );
  

lib/AI/TensorFlow/Libtensorflow/Manual/Notebook/InferenceUsingTFHubMobileNetV2Model.pod  view on Meta::CPAN


We can use the C<Run> method to run the session and get the output C<TFTensor>.

First, we send a single random input to warm up the model.

  my $RunSession = sub {
      my ($session, $t) = @_;
      my @outputs_t;
  
      $session->Run(
          undef,
          $outputs{in}, [$t],
          $outputs{out}, \@outputs_t,
          undef,
          undef,
          $s
      );
      AssertOK($s);
  
      return $outputs_t[0];
  };
  
  say "Warming up the model";
  use PDL::GSL::RNG;
  my $rng = PDL::GSL::RNG->new('default');

lib/AI/TensorFlow/Libtensorflow/Manual/Notebook/InferenceUsingTFHubMobileNetV2Model.pod  view on Meta::CPAN


  1

=head1 RESOURCE USAGE

  use Filesys::DiskUsage qw/du/;
  
  my $total = du( { 'human-readable' => 1, dereference => 1 },
      $model_archive_path, $model_base, $labels_path );
  
  say "Disk space usage: $total"; undef;

B<STREAM (STDOUT)>:

  Disk space usage: 27.45M

=head1 DEBUGGING

The following images can be used to test the C<load_image_to_pdl> function.

  my @solid_channel_uris = (
      'https://upload.wikimedia.org/wikipedia/commons/thumb/6/62/Solid_red.svg/480px-Solid_red.svg.png',
      'https://upload.wikimedia.org/wikipedia/commons/thumb/1/1d/Green_00FF00_9x9.svg/480px-Green_00FF00_9x9.svg.png',
      'https://upload.wikimedia.org/wikipedia/commons/thumb/f/ff/Solid_blue.svg/480px-Solid_blue.svg.png',
  );
  undef;

=head1 CPANFILE

  requires 'AI::TensorFlow::Libtensorflow';
  requires 'AI::TensorFlow::Libtensorflow::DataType';
  requires 'Archive::Extract';
  requires 'Data::Printer';
  requires 'Data::Printer::Filter::PDL';
  requires 'FFI::Platypus::Buffer';
  requires 'FFI::Platypus::Memory';

lib/AI/TensorFlow/Libtensorflow/Output.pm  view on Meta::CPAN

	RecordArrayRef( 'OutputArrayPtrSz',
		record_module => __PACKAGE__, with_size => 1,
	),
	=> 'TF_Output_array_sz');

use overload
	'""' => \&_op_stringify;

sub _op_stringify {
	join ":", (
		( defined $_[0]->_oper ? $_[0]->oper->Name : '<undefined operation>' ),
		( defined $_[0]->index ? $_[0]->index      : '<no index>'            )
	);
}

sub _data_printer {
	my ($self, $ddp) = @_;

	my %data = (
		oper  => $self->oper,
		index => $self->index,

lib/AI/TensorFlow/Libtensorflow/Session.pm  view on Meta::CPAN

	}
);

sub _process_target_opers_args {
	my ($target_opers) = @_;
	my @target_opers_args = defined $target_opers
		? do {
			my $target_opers_a = AI::TensorFlow::Libtensorflow::Operation->_as_array( @$target_opers );
			( $target_opers_a, $target_opers_a->count )
		}
		: ( undef, 0 );

	return @target_opers_args;
}

$ffi->attach([ 'SessionPRunSetup' => 'PRunSetup' ] => [
    arg TF_Session => 'session',
    # Input names
    arg TF_Output_struct_array => 'inputs',
    arg int => 'ninputs',
    # Output names

lib/AI/TensorFlow/Libtensorflow/Session.pm  view on Meta::CPAN

Status.

=back

B<Returns>

=over 4

=item Maybe[TFSession]

A new execution session with the associated graph, or C<undef> on
error.

=back

B<C API>: L<< C<TF_NewSession>|AI::TensorFlow::Libtensorflow::Manual::CAPI/TF_NewSession >>

=head2 LoadFromSavedModel

B<C API>: L<< C<TF_LoadSessionFromSavedModel>|AI::TensorFlow::Libtensorflow::Manual::CAPI/TF_LoadSessionFromSavedModel >>

lib/AI/TensorFlow/Libtensorflow/Tensor.pm  view on Meta::CPAN

=back

Creates a C<TFTensor> from a data buffer C<$data> with the given specification
of data type C<$dtype> and dimensions C<$dims>.

  # Create a buffer containing 0 through 8 single-precision
  # floating-point data.
  my $data = pack("f*",  0..8);

  $t = Tensor->New(
    FLOAT, [3,3], \$data, sub { undef $data }, undef
  );

  ok $t, 'Created 3-by-3 float TFTensor';

Implementation note: if C<$dtype> is not a
L<STRING|AI::TensorFlow::Libtensorflow::DataType/STRING>
or
L<RESOURCE|AI::TensorFlow::Libtensorflow::DataType/RESOURCE>,
then the pointer for C<$data> is checked to see if meets the
TensorFlow's alignment preferences. If it does not, the

lib/AI/TensorFlow/Libtensorflow/Tensor.pm  view on Meta::CPAN


Data buffer for the contents of the C<TFTensor>.

=item CodeRef $deallocator

A callback used to deallocate C<$data> which is passed the
parameters C<<
  $deallocator->( opaque $pointer, size_t $size, opaque $deallocator_arg)
>>.

=item Ref $deallocator_arg [optional, default: C<undef>]

Argument that is passed to the C<$deallocator> callback.

=back

B<Returns>

=over 4

=item L<TFTensor|AI::TensorFlow::Libtensorflow::Lib::Types/TFTensor>

lib/AI/TensorFlow/Libtensorflow/Tensor.pm  view on Meta::CPAN


=head2 MaybeMove

B<Returns>

=over 4

=item Maybe[TFTensor]

Deletes the C<TFTensor> and returns a new C<TFTensor> with the
same content if possible. Returns C<undef> and leaves the
C<TFTensor> untouched if not.

=back

B<C API>: L<< C<TF_TensorMaybeMove>|AI::TensorFlow::Libtensorflow::Manual::CAPI/TF_TensorMaybeMove >>

=head2 IsAligned

B<C API>: L<< C<TF_TensorIsAligned>|AI::TensorFlow::Libtensorflow::Manual::CAPI/TF_TensorIsAligned >>

maint/inc/Pod/Elemental/Transformer/TF_CAPI.pm  view on Meta::CPAN

use Moose;
use Pod::Elemental::Transformer 0.101620;
with 'Pod::Elemental::Transformer';

use Pod::Elemental::Element::Pod5::Command;

use namespace::autoclean;

has command_name => (
  is  => 'ro',
  init_arg => undef,
);

sub transform_node {
  my ($self, $node) = @_;

  for my $i (reverse(0 .. $#{ $node->children })) {
    my $para = $node->children->[ $i ];
    next unless $self->__is_xformable($para);
    my @replacements = $self->_expand( $para );
    splice @{ $node->children }, $i, 1, @replacements;

maint/inc/Pod/Elemental/Transformer/TF_Sig.pm  view on Meta::CPAN

  ) {
    $prefix = Pod::Elemental::Element::Pod5::Ordinary->new({
      content => "B<@{[ $region_types{$para->format_name} ]}>",
    });
  }

  my @replacements;
  if( $is_list_type ) {
    @replacements = $orig->($self, $para);
  } else {
    undef $prefix;
    push @replacements, Pod::Elemental::Element::Pod5::Ordinary
      ->new( { content => do { my $v = <<EOF; chomp $v; $v } });
=over 2

C<<<
@{[ join("\n", map { $_->content } $para->children->@*) ]}
>>>

=back
EOF

maint/process-capi.pl  view on Meta::CPAN

	};

	method check_types() {
		my @data = $self->typedef_struct_data->@*;
		my %types = map { $_ => 1 } AI::TensorFlow::Libtensorflow::Lib->ffi->types;
		my %part;
		@part{qw(todo done)} = part { exists $types{$_} } uniq map { $_->{name} } @data;
		use DDP; p %part;
	}

	method check_functions($first_arg = undef) {
		my $functions = AI::TensorFlow::Libtensorflow::Lib->ffi->_attached_functions;
		my @dupes = map { $_->[0]{c} }
			grep { @$_ != 1 } values $functions->%*;
		die "Duplicated functions @dupes" if @dupes;

		my @data = $self->fdecl_data->@*;

		say <<~STATS;
		Statistics:
		==========

t/05_session_run.t  view on Meta::CPAN

		-0.4809832, -0.3770838, 0.1743573, 0.7720509, -0.4064746, 0.0116595, 0.0051413, 0.9135732, 0.7197526, -0.0400658, 0.1180671, -0.6829428,
		-0.4810135, -0.3772099, 0.1745346, 0.7719303, -0.4066443, 0.0114614, 0.0051195, 0.9135003, 0.7196983, -0.0400035, 0.1178188, -0.6830465,
		-0.4809143, -0.3773398, 0.1746384, 0.7719052, -0.4067171, 0.0111654, 0.0054433, 0.9134697, 0.7192584, -0.0399981, 0.1177435, -0.6835230,
		-0.4808300, -0.3774327, 0.1748246, 0.7718700, -0.4070232, 0.0109549, 0.0059128, 0.9133330, 0.7188759, -0.0398740, 0.1181437, -0.6838635,
		-0.4807833, -0.3775733, 0.1748378, 0.7718275, -0.4073670, 0.0107582, 0.0062978, 0.9131795, 0.7187147, -0.0394935, 0.1184392, -0.6840039,
	);
	$p_data->reshape(1,5,12);

	my $input_tensor = AI::TensorFlow::Libtensorflow::Tensor->New(
		FLOAT, [ $p_data->dims ], $p_data->get_dataref,
		sub { undef $p_data }
	);


	my $output_op = Output->New({
		oper => $graph->OperationByName( 'output_node0'),
		index => 0 } );
	die "Can not init output op" unless $output_op;

	my $status = AI::TensorFlow::Libtensorflow::Status->New;
	my $options = AI::TensorFlow::Libtensorflow::SessionOptions->New;
	my $session = AI::TensorFlow::Libtensorflow::Session->New($graph, $options, $status);
	die "Could not create session" unless $status->GetCode == AI::TensorFlow::Libtensorflow::Status::OK;

	my @output_values;
	my $target_op_a = undef;
	$session->Run(
		undef,
		[$input_op ], [$input_tensor],
		[$output_op], \@output_values,
		undef,
		undef,
		$status
	);

	die "run failed" unless $status->GetCode == AI::TensorFlow::Libtensorflow::Status::OK;

	my $output_tensor = $output_values[0];
	my $output_pdl = zeros(float,( map $output_tensor->Dim($_), 0..$output_tensor->NumDims-1) );

	memcpy scalar_to_pointer( ${$output_pdl->get_dataref} ),
		scalar_to_pointer( ${$output_tensor->Data} ),

t/lib/TF_Utils.pm  view on Meta::CPAN

	$self->_targets( \@data );
  }

  sub Run {
	my ($self, $s) = @_;
	if( @{ $self->_inputs } != @{ $self->_input_values } ) {
		die "Call SetInputs() before Run()";
	}

	$self->session->Run(
		undef,
		$self->_inputs, $self->_input_values,
		$self->_outputs, $self->_output_values,
		$self->_targets,
		undef,
		$s
	);
  }

  sub output_tensor { my ($self, $i) = @_; $self->_output_values->[$i] }
}

sub BinaryOpHelper {
	my ($op_name, $l, $r,
		$graph, $s, $name,

t/upstream/CAPI/003_Tensor.t  view on Meta::CPAN

	# It should not be called in this case because aligned_alloc() is used.
	ok ! $deallocator_called, 'deallocator not called yet';

	is $t->Type, 'FLOAT', 'FLOAT TF_Tensor';
	is $t->NumDims, 2, '2D TF_Tensor';
	is $t->Dim(0), $dims[0], 'dim 0';
	is $t->Dim(1), $dims[1], 'dim 1';
	is $t->ByteSize, $num_bytes, 'bytes';
	is scalar_to_pointer(${$t->Data}), scalar_to_pointer($values),
		'data at same pointer address';
	undef $t;
	ok $deallocator_called, 'deallocated';
};

done_testing;

t/upstream/CAPI/004_MalformedTensor.t  view on Meta::CPAN


use Test2::V0;
use lib 't/lib';
use TF_TestQuiet;
use aliased 'AI::TensorFlow::Libtensorflow';
use aliased 'AI::TensorFlow::Libtensorflow::Tensor';
use AI::TensorFlow::Libtensorflow::DataType qw(FLOAT);

subtest "(CAPI, MalformedTensor)" => sub {
	my $noop_dealloc = sub {};
	my $t = Tensor->New(FLOAT, [], \undef, $noop_dealloc);
	ok ! defined $t, 'No data passed in so no tensor created';
};

done_testing;

t/upstream/CAPI/006_MaybeMove.t  view on Meta::CPAN

		my $pointer = shift;
		AI::TensorFlow::Libtensorflow::Lib::_Alloc->_tf_aligned_free($pointer);
		$deallocator_called = 1;
	});
	ok !$deallocator_called, 'not deallocated';

	my $o = $t->MaybeMove;

	is $o, U(), 'it is unsafe to move memory TF might not own';

	undef $t;
	ok $deallocator_called, 'deallocated'
};

done_testing;

t/upstream/CAPI/014_SetShape.t  view on Meta::CPAN

	my $feed_out_0 = Output->New({ oper => $feed, index => 0 });

	my $num_dims;

	note 'Fetch the shape, it should be completely unknown';
	$num_dims = $graph->GetTensorNumDims($feed_out_0, $s);
	TF_Utils::AssertStatusOK($s);
	is $num_dims, -1, 'Dims are unknown';

	note 'Set the shape to be unknown, expect no change';
	$graph->SetTensorShape($feed_out_0, undef, $s);
	$num_dims = $graph->GetTensorNumDims($feed_out_0, $s);
	TF_Utils::AssertStatusOK($s);
	is $num_dims, -1, 'Dims are still unknown';

	note 'Set the shape to be 2 x Unknown';
	my $dims = [2, -1];
	$graph->SetTensorShape( $feed_out_0, $dims, $s);
	TF_Utils::AssertStatusOK($s);

	note 'Fetch the shape and validate it is 2 by -1.';

t/upstream/CAPI/014_SetShape.t  view on Meta::CPAN


	note 'Fetch and see that the new value is returned.';
	$returned_dims = $graph->GetTensorShape( $feed_out_0, $s );
	TF_Utils::AssertStatusOK($s);
	is $returned_dims, $dims, "Got shape [ @$dims ]";

	note q{
		Try to set 'unknown' with unknown rank on the shape and see that
		it doesn't change.
	};
	$graph->SetTensorShape($feed_out_0, undef, $s);
	TF_Utils::AssertStatusOK($s);
	$num_dims = $graph->GetTensorNumDims( $feed_out_0, $s );
	$returned_dims = $graph->GetTensorShape( $feed_out_0, $s );
	TF_Utils::AssertStatusOK($s);
	is $num_dims, 2, 'unchanged numdims';
	is $returned_dims, [2,3], 'dims still [2 3]';

	note q{
		Try to set 'unknown' with same rank on the shape and see that
		it doesn't change.

t/upstream/CAPI/018_ImportGraphDef.t  view on Meta::CPAN

	TF_Utils::Neg( $oper, $graph, $s );
	TF_Utils::AssertStatusOK($s);
	ok $graph->OperationByName( 'neg' ), 'got neg operation from graph';

	note 'Export to a GraphDef.';
	my $graph_def = AI::TensorFlow::Libtensorflow::Buffer->New;
	$graph->ToGraphDef( $graph_def, $s );
	TF_Utils::AssertStatusOK($s);

	note 'Import it, with a prefix, in a fresh graph.';
	undef $graph;
	$graph = AI::TensorFlow::Libtensorflow::Graph->New;
	my $opts = AI::TensorFlow::Libtensorflow::ImportGraphDefOptions->New;
	$opts->SetPrefix('imported');
	$graph->ImportGraphDef($graph_def, $opts, $s);
	TF_Utils::AssertStatusOK($s);

	ok my $scalar = $graph->OperationByName('imported/scalar'), 'imported/scalar';
	ok my $feed = $graph->OperationByName('imported/feed'), 'imported/feed';
	ok my $neg = $graph->OperationByName('imported/neg'), 'imported/neg';

t/upstream/CAPI/018_ImportGraphDef.t  view on Meta::CPAN

	is $scalar, $empty_control_outputs, 'scalar control outputs';

	is $feed, $empty_control_inputs, 'feed control inputs';
	is $feed, $empty_control_outputs, 'feed control outputs';

	is $neg, $empty_control_inputs, 'neg control inputs';
	is $neg, $empty_control_outputs, 'neg control outputs';

	note q|Import it again, with an input mapping, return outputs, and a return
	operation, into the same graph.|;
	undef $opts;
	$opts = AI::TensorFlow::Libtensorflow::ImportGraphDefOptions->New;
	$opts->SetPrefix('imported2');
	$opts->AddInputMapping( 'scalar', 0, $TFOutput->coerce([$scalar=>0]));
	$opts->AddReturnOutput('feed', 0);
	$opts->AddReturnOutput('scalar', 0);
	is $opts->NumReturnOutputs, 2, 'num return outputs';
	$opts->AddReturnOperation('scalar');
	is $opts->NumReturnOperations, 1, 'num return operations';
	my $results = $graph->ImportGraphDefWithResults( $graph_def, $opts, $s );
	TF_Utils::AssertStatusOK($s);

t/upstream/CAPI/018_ImportGraphDef.t  view on Meta::CPAN

	note 'Check return operation';
	my $return_opers = $results->ReturnOperations;
	is $return_opers, array {
		item 0 => object {
			# not remapped
			call Name => $scalar2->Name;
		};
		end;
	}, 'return opers';

	undef $results;

	note 'Import again, with control dependencies, into the same graph.';
	undef $opts;
	$opts = AI::TensorFlow::Libtensorflow::ImportGraphDefOptions->New;
	$opts->SetPrefix("imported3");
	$opts->AddControlDependency($feed);
	$opts->AddControlDependency($feed2);
	$graph->ImportGraphDef($graph_def, $opts, $s);
	TF_Utils::AssertStatusOK($s);

	ok my $scalar3 = $graph->OperationByName("imported3/scalar"), "imported3/scalar";
	ok my $feed3 = $graph->OperationByName("imported3/feed"), "imported3/feed";
	ok my $neg3 = $graph->OperationByName("imported3/neg"), "imported3/neg";

t/upstream/CAPI/018_ImportGraphDef.t  view on Meta::CPAN

		end;
	}, 'scalar3 control inputs';

	is $feed3->GetControlInputs, array {
		item 0 => object { call Name => $feed->Name  };
		item 1 => object { call Name => $feed2->Name };
		end;
	}, 'feed3 control inputs';

	note 'Export to a graph def so we can import a graph with control dependencies';
	undef $graph_def;
	$graph_def = AI::TensorFlow::Libtensorflow::Buffer->New;
	$graph->ToGraphDef( $graph_def, $s );
	TF_Utils::AssertStatusOK($s);

	note 'Import again, with remapped control dependency, into the same graph';
	undef $opts;
	$opts = AI::TensorFlow::Libtensorflow::ImportGraphDefOptions->New;
	$opts->SetPrefix("imported4");
	$opts->RemapControlDependency("imported/feed", $feed );
	$graph->ImportGraphDef($graph_def, $opts, $s);
	TF_Utils::AssertStatusOK($s);

	ok my $scalar4 = $graph->OperationByName("imported4/imported3/scalar"),
		"imported4/imported3/scalar";
	ok my $feed4 = $graph->OperationByName("imported4/imported2/feed"),
		"imported4/imported2/feed";

	note q|Check that imported `imported3/scalar` has remapped control dep from
	original graph and imported control dep|;
	is $scalar4->GetControlInputs, array {
		item object { call Name => $feed->Name  };
		item object { call Name => $feed4->Name };
		end;
	}, 'scalar4 control inputs';

	undef $opts;
	undef $graph_def;

	note 'Can add nodes to the imported graph without trouble.';
	TF_Utils::Add( $feed, $scalar, $graph, $s );
	TF_Utils::AssertStatusOK($s);
};

done_testing;

t/upstream/CAPI/019_ImportGraphDef_WithReturnOutputs.t  view on Meta::CPAN

	TF_Utils::Neg( $oper, $graph, $s );
	TF_Utils::AssertStatusOK($s);
	ok $graph->OperationByName("neg"), "get neg";

	note 'Export to a GraphDef.';
	my $graph_def = AI::TensorFlow::Libtensorflow::Buffer->New;
	$graph->ToGraphDef( $graph_def, $s );
	TF_Utils::AssertStatusOK($s);

	note 'Import it in a fresh graph with return outputs.';
	undef $graph;
	$graph = AI::TensorFlow::Libtensorflow::Graph->New;
	my $opts = AI::TensorFlow::Libtensorflow::ImportGraphDefOptions->New;
	$opts->AddReturnOutput('feed', 0);
	$opts->AddReturnOutput('scalar', 0);
	is $opts->NumReturnOutputs, 2, '2 return outputs';
	my $return_outputs = $graph->ImportGraphDefWithReturnOutputs(
		$graph_def, $opts, $s
	);
	TF_Utils::AssertStatusOK($s);

t/upstream/CAPI/020_ImportGraphDef_MissingUnusedInputMappings.t  view on Meta::CPAN

	TF_Utils::Neg( $oper, $graph, $s );
	TF_Utils::AssertStatusOK($s);
	ok $graph->OperationByName('neg'), 'neg';

	note 'Export to a GraphDef.';
	my $graph_def = AI::TensorFlow::Libtensorflow::Buffer->New;
	$graph->ToGraphDef( $graph_def, $s );
	TF_Utils::AssertStatusOK($s);

	note 'Import it in a fresh graph.';
	undef $graph;
	$graph = AI::TensorFlow::Libtensorflow::Graph->New;
	my $opts = AI::TensorFlow::Libtensorflow::ImportGraphDefOptions->New;
	$graph->ImportGraphDef($graph_def, $opts, $s);
	TF_Utils::AssertStatusOK($s);

	my $scalar = $graph->OperationByName('scalar');

	note 'Import it in a fresh graph with an unused input mapping.';
	undef $opts;
	$opts = AI::TensorFlow::Libtensorflow::ImportGraphDefOptions->New;
	$opts->SetPrefix("imported");
	$opts->AddInputMapping("scalar", 0, $TFOutput->coerce([$scalar, 0]));
	$opts->AddInputMapping("fake", 0, $TFOutput->coerce([$scalar, 0]));
	my $results = $graph->ImportGraphDefWithResults($graph_def, $opts, $s);
	TF_Utils::AssertStatusOK($s);

	note 'Check unused input mappings';
	is my $srcs = $results->MissingUnusedInputMappings, array {
		item [ 'fake', 0 ];

t/upstream/CAPI/026_SessionPRun.t  view on Meta::CPAN

	note q{Setup a session and a partial run handle.  The partial run will allow
	computation of A + 2 + B in two phases (calls to TF_SessionPRun):
	1. Feed A and get (A+2)
	2. Feed B and get (A+2)+B};
	my $opts = AI::TensorFlow::Libtensorflow::SessionOptions->New;
	my $sess = AI::TensorFlow::Libtensorflow::Session->New($graph, $opts, $s);

	my @feeds = $TFOutput->map([ $op_a => 0 ], [$op_b => 0]);
	my @fetches = $TFOutput->map([$plus2 => 0], [$plusB => 0]);

	my $handle = $sess->PRunSetup( \@feeds, \@fetches, undef, $s);

	note 'Feed A and fetch A + 2.';
	my @feeds1 = $TFOutput->map( [$op_a => 0] );
	my @fetches1 = $TFOutput->map( [$plus2 => 0] );
	my @feedValues1 = ( TF_Utils::Int32Tensor(1) );
	my @fetchValues1;
	$sess->PRun( $handle,
		\@feeds1, \@feedValues1,
		\@fetches1, \@fetchValues1,
		undef,
		$s );
	TF_Utils::AssertStatusOK($s);
	is unpack("l", ${ $fetchValues1[0]->Data }), 3,
		'(A := 1) + Const(2) = 3';
	undef @feedValues1;
	undef @fetchValues1;

	note 'Feed B and fetch (A + 2) + B.';
	my @feeds2 = $TFOutput->map( [$op_b => 0] );
	my @fetches2 = $TFOutput->map( [$plusB => 0] );
	my @feedValues2 = ( TF_Utils::Int32Tensor(4) );
	my @fetchValues2;
	$sess->PRun($handle,
		\@feeds2, \@feedValues2,
		\@fetches2, \@fetchValues2,
		undef,
		$s);
	TF_Utils::AssertStatusOK($s);
	is unpack("l", ${ $fetchValues2[0]->Data }), 7,
		'( (A := 1) + Const(2) ) + ( B := 4 ) = 7';

	undef $handle;
	$sess->Close($s);
	TF_Utils::AssertStatusOK($s);
	undef $graph;
	undef $s;
};

done_testing;

t/upstream/CAPI/030_SavedModelNullArgsAreValid.t  view on Meta::CPAN

		"tensorflow", "cc", "saved_model", "testdata",
			"half_plus_two", "00000123"
	);
	my $opt = AI::TensorFlow::Libtensorflow::SessionOptions->New;
	my $s = AI::TensorFlow::Libtensorflow::Status->New;
	my @tags = ('serve');
	my $graph = AI::TensorFlow::Libtensorflow::Graph->New;

	note 'NULL run_options and meta_graph_def should work.';
	is my $session = AI::TensorFlow::Libtensorflow::Session->LoadFromSavedModel(
		$opt, undef, "$saved_model_dir", \@tags, $graph, undef, $s
	), D();
	TF_Utils::AssertStatusOK($s);
	$session->Close($s);
	TF_Utils::AssertStatusOK($s);
	undef $session;
};

done_testing;

t/upstream/CAPI/032_TestBitcastFrom_Reshape.t  view on Meta::CPAN


subtest "(CAPI, TestBitcastFrom_Reshape)" => sub {
	my @dims = (2, 3);
	is my $t_a = AI::TensorFlow::Libtensorflow::Tensor->Allocate(
		UINT64, \@dims
	), object {
		call ElementCount => 6;
		call ByteSize     => 6 * UINT64->Size;
	}, '2x3 TFTensor';
	is my $t_b = AI::TensorFlow::Libtensorflow::Tensor->Allocate(
		UINT64, undef
	), object {
		call ElementCount => 1;
		call ByteSize     => UINT64->Size;
	}, 'scalar TFTensor';

	my @new_dims = (3, 2);
	my $status = AI::TensorFlow::Libtensorflow::Status->New;
	$t_a->BitcastFrom( UINT64, $t_b, \@new_dims, $status );
	TF_Utils::AssertStatusOK($status);

t/upstream/CAPI/037_TestTensorNonScalarBytesAllocateDelete.t  view on Meta::CPAN

		my $data_i = $ffi->cast('opaque', 'TF_TString', $data_i_ptr );
		$data_i->Init;
		$data_i->{owner} = $t; # do not want to free the pointer
		# The following input string length is large enough to make sure that
		# copy to tstring in large mode.
		$data_i->Copy(
			"This is the " . ($i + 1) . "th. data element\n"
		);
	}

	undef $t;

	pass 'Created TF_STRING tensor and deallocated';
};

done_testing;



( run in 3.307 seconds using v1.01-cache-2.11-cpan-d80b1682f3f )