Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 7 additions & 5 deletions example/concurrent-inferences.f90
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
program concurrent_inferences
!! This program demonstrates how to read a neural network from a JSON file
!! and use the network to perform concurrent inferences.
use inference_engine_m, only : inference_engine_t, tensor_t, infer
use inference_engine_m, only : inference_engine_t, tensor_t, infer, numerics_t
use sourcery_m, only : string_t, command_line_t, file_t
use assert_m, only : assert
use iso_fortran_env, only : int64, real64
Expand Down Expand Up @@ -40,10 +40,12 @@ program concurrent_inferences

block
integer(int64) t_start, t_finish, clock_rate
type(numerics_t) :: numerics
numerics = inference_engine%to_numerics()

print *,"Performing elemental inferences"
call system_clock(t_start, clock_rate)
outputs = inference_engine%infer(inputs) ! implicit allocation of outputs array
outputs = numerics%infer(inputs) ! implicit allocation of outputs array
call system_clock(t_finish)
print *,"Elemental inference time: ", real(t_finish - t_start, real64)/real(clock_rate, real64)

Expand All @@ -54,7 +56,7 @@ program concurrent_inferences
do k=1,lev
do j=1,lon
do i=1,lat
outputs(i,j,k) = inference_engine%infer(inputs(i,j,k))
outputs(i,j,k) = numerics%infer(inputs(i,j,k))
end do
end do
end do
Expand All @@ -64,15 +66,15 @@ program concurrent_inferences
print *,"Performing concurrent inference"
call system_clock(t_start)
do concurrent(i=1:lat, j=1:lon, k=1:lev)
outputs(i,j,k) = inference_engine%infer(inputs(i,j,k))
outputs(i,j,k) = numerics%infer(inputs(i,j,k))
end do
call system_clock(t_finish)
print *,"Concurrent inference time: ", real(t_finish - t_start, real64)/real(clock_rate, real64)

print *,"Performing concurrent inference with a non-type-bound inference procedure"
call system_clock(t_start)
do concurrent(i=1:lat, j=1:lon, k=1:lev)
outputs(i,j,k) = infer(inference_engine, inputs(i,j,k))
outputs(i,j,k) = infer(numerics, inputs(i,j,k))
end do
call system_clock(t_finish)
print *,"Concurrent inference time with non-type-bound procedure: ", real(t_finish - t_start, real64)/real(clock_rate, real64)
Expand Down
8 changes: 6 additions & 2 deletions example/write-read-infer.F90
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ program write_read_infer
!! perform inference. The network performs an identity mapping from any
!! non-negative inputs to the corresponding outputs using a RELU activation
!! function.
use inference_engine_m, only : inference_engine_t, relu_t, tensor_t
use inference_engine_m, only : inference_engine_t, relu_t, tensor_t, numerics_t
use sourcery_m, only : string_t, command_line_t, file_t
use kind_parameters_m, only : rkind
implicit none
Expand Down Expand Up @@ -82,7 +82,11 @@ subroutine write_read_query_infer(output_file_name)
print *, "Performing inference:"
inputs = tensor_t([2.,3.])
print *, "Inputs: ", inputs%values()
outputs = inference_engine%infer(inputs)
block
type(numerics_t) :: numerics
numerics = inference_engine%to_numerics()
outputs = numerics%infer(inputs)
end block
print *, "Actual outputs: ", outputs%values()
print *, "Correct outputs: ", inputs%values()
end subroutine write_read_query_infer
Expand Down
25 changes: 21 additions & 4 deletions src/inference_engine/inference_engine_m_.f90
Original file line number Diff line number Diff line change
Expand Up @@ -15,21 +15,21 @@ module inference_engine_m_
public :: inference_engine_t
public :: difference_t
public :: exchange_t
public :: infer
public :: numerics_t, infer

character(len=*), parameter :: key(*) = [character(len=len("usingSkipConnections")) :: &
"modelName", "modelAuthor", "compilationDate", "activationFunction", "usingSkipConnections"]

type inference_engine_t
!! Encapsulate the minimal information needed to perform inference
!! Encapsulate the information needed to perform inference
private
type(tensor_range_t) input_range_, output_range_
type(string_t) metadata_(size(key))
real(rkind), allocatable :: weights_(:,:,:), biases_(:,:)
integer, allocatable :: nodes_(:)
class(activation_strategy_t), allocatable :: activation_strategy_ ! Strategy Pattern facilitates elemental activation
contains
procedure :: infer
procedure :: to_numerics
procedure :: to_json
procedure :: map_to_input_range
procedure :: map_from_output_range
Expand All @@ -44,6 +44,17 @@ module inference_engine_m_
procedure :: to_exchange
end type

type numerics_t
!! Encapsulate the minimal information needed to perform inference
private
type(tensor_range_t) input_range_, output_range_
real(rkind), allocatable :: weights_(:,:,:), biases_(:,:)
integer, allocatable :: nodes_(:)
class(activation_strategy_t), allocatable :: activation_strategy_ ! Strategy Pattern facilitates elemental activation
contains
procedure :: infer
end type

type exchange_t
type(tensor_range_t) input_range_, output_range_
type(string_t) metadata_(size(key))
Expand Down Expand Up @@ -104,6 +115,12 @@ pure module function to_exchange(self) result(exchange)
type(exchange_t) exchange
end function

pure elemental module function to_numerics(self) result(numerics)
implicit none
class(inference_engine_t), intent(in) :: self
type(numerics_t) numerics
end function

impure elemental module function to_json(self) result(json_file)
implicit none
class(inference_engine_t), intent(in) :: self
Expand Down Expand Up @@ -131,7 +148,7 @@ elemental module subroutine assert_conformable_with(self, inference_engine)

elemental module function infer(self, inputs) result(outputs)
implicit none
class(inference_engine_t), intent(in) :: self
class(numerics_t), intent(in) :: self
type(tensor_t), intent(in) :: inputs
type(tensor_t) outputs
end function
Expand Down
25 changes: 20 additions & 5 deletions src/inference_engine/inference_engine_s.F90
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
integer, parameter :: input_layer = 0
integer k, l

call assert_consistency(self)
call numerics_consistency(self%weights_, self%biases_, self%nodes_, self%activation_strategy_)

associate(w => self%weights_, b => self%biases_, n => self%nodes_, output_layer => ubound(self%nodes_,1))

Expand Down Expand Up @@ -86,24 +86,30 @@
end procedure

pure subroutine inference_engine_consistency(self)

type(inference_engine_t), intent(in) :: self
call numerics_consistency(self%weights_, self%biases_, self%nodes_, self%activation_strategy_)
end subroutine

pure subroutine numerics_consistency(weights, biases, nodes, activation_strategy)
real(rkind), allocatable, intent(in) :: weights(:,:,:), biases(:,:)
integer, allocatable, intent(in) :: nodes(:)
class(activation_strategy_t), allocatable, intent(in) :: activation_strategy

integer, parameter :: input_layer=0

associate( &
all_allocated=>[allocated(self%weights_),allocated(self%biases_),allocated(self%nodes_),allocated(self%activation_strategy_)]&
all_allocated=>[allocated(weights),allocated(biases),allocated(nodes),allocated(activation_strategy)]&
)
call assert(all(all_allocated),"inference_engine_s(inference_engine_consistency): fully_allocated", &
intrinsic_array_t(all_allocated))
end associate

associate(max_width=>maxval(self%nodes_), component_dims=>[size(self%biases_,1), size(self%weights_,1), size(self%weights_,2)])
associate(max_width=>maxval(nodes), component_dims=>[size(biases,1), size(weights,1), size(weights,2)])
call assert(all(component_dims == max_width), "inference_engine_s(inference_engine_consistency): conformable arrays", &
intrinsic_array_t([max_width,component_dims]))
end associate

associate(input_subscript => lbound(self%nodes_,1))
associate(input_subscript => lbound(nodes,1))
call assert(input_subscript == input_layer, "inference_engine_s(inference_engine_consistency): n base subsscript", &
input_subscript)
end associate
Expand Down Expand Up @@ -390,6 +396,15 @@ function get_key_value(line) result(value_)
node_count = self%nodes_
end procedure

module procedure to_numerics
numerics%input_range_ = self%input_range_
numerics%output_range_ = self%output_range_
numerics%weights_ = self%weights_
numerics%biases_ = self%biases_
numerics%nodes_ = self%nodes_
numerics%activation_strategy_ = self%activation_strategy_
end procedure

module procedure to_json

type(string_t), allocatable :: lines(:)
Expand Down
2 changes: 1 addition & 1 deletion src/inference_engine_m.f90
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ module inference_engine_m
use differentiable_activation_strategy_m, only : differentiable_activation_strategy_t
use hyperparameters_m, only : hyperparameters_t
use input_output_pair_m, only : input_output_pair_t, shuffle
use inference_engine_m_, only : inference_engine_t, difference_t, infer
use inference_engine_m_, only : inference_engine_t, difference_t, numerics_t, infer
use kind_parameters_m, only : rkind
use mini_batch_m, only : mini_batch_t
use network_configuration_m, only : network_configuration_t
Expand Down
12 changes: 7 additions & 5 deletions test/asymmetric_engine_test_m.F90
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ module asymmetric_engine_test_m
test_t, test_result_t, vector_test_description_t, test_description_substring, string_t, vector_function_strategy_t

! Internal dependencies
use inference_engine_m, only : inference_engine_t, tensor_t
use inference_engine_m, only : inference_engine_t, tensor_t, numerics_t
use kind_parameters_m, only : rkind

implicit none
Expand Down Expand Up @@ -122,11 +122,13 @@ function xor_and_2nd_input_truth_table() result(test_passes)
block
real(rkind), parameter :: tolerance = 1.E-08_rkind, false = 0._rkind, true = 1._rkind
type(tensor_t) true_true, true_false, false_true, false_false
type(numerics_t) :: numerics
numerics = asymmetric%to_numerics()

true_true = asymmetric%infer(tensor_t([true,true]))
true_false = asymmetric%infer(tensor_t([true,false]))
false_true = asymmetric%infer(tensor_t([false,true]))
false_false = asymmetric%infer(tensor_t([false,false]))
true_true = numerics%infer(tensor_t([true,true]))
true_false = numerics%infer(tensor_t([true,false]))
false_true = numerics%infer(tensor_t([false,true]))
false_false = numerics%infer(tensor_t([false,false]))

associate( &
true_true_outputs => true_true%values(), &
Expand Down
10 changes: 7 additions & 3 deletions test/inference_engine_test_m.F90
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ module inference_engine_test_m
#endif

! Internal dependencies
use inference_engine_m, only : inference_engine_t, tensor_t, difference_t
use inference_engine_m, only : inference_engine_t, tensor_t, difference_t, numerics_t

implicit none

Expand Down Expand Up @@ -132,9 +132,11 @@ function elemental_infer_with_1_hidden_layer_xor_net() result(test_passes)
type(tensor_t), allocatable :: truth_table(:)
real(rkind), parameter :: tolerance = 1.E-08_rkind, false = 0._rkind, true = 1._rkind
integer i
type(numerics_t) :: numerics
numerics = inference_engine%to_numerics()

associate(array_of_inputs => [tensor_t([true,true]), tensor_t([true,false]), tensor_t([false,true]), tensor_t([false,false])])
truth_table = inference_engine%infer(array_of_inputs)
truth_table = numerics%infer(array_of_inputs)
end associate
test_passes = all( &
abs(truth_table(1)%values() - false) < tolerance .and. abs(truth_table(2)%values() - true) < tolerance .and. &
Expand All @@ -153,9 +155,11 @@ function elemental_infer_with_2_hidden_layer_xor_net() result(test_passes)
type(tensor_t), allocatable :: truth_table(:)
real(rkind), parameter :: tolerance = 1.E-08_rkind, false = 0._rkind, true = 1._rkind
integer i
type(numerics_t) :: numerics
numerics = inference_engine%to_numerics()

associate(array_of_inputs => [tensor_t([true,true]), tensor_t([true,false]), tensor_t([false,true]), tensor_t([false,false])])
truth_table = inference_engine%infer(array_of_inputs)
truth_table = numerics%infer(array_of_inputs)
end associate
test_passes = all( &
abs(truth_table(1)%values() - false) < tolerance .and. abs(truth_table(2)%values() - true) < tolerance .and. &
Expand Down