From 118f795dbe2850032cc29623b735a8da37eac661 Mon Sep 17 00:00:00 2001 From: Jeremie Vandenplas Date: Fri, 14 Jun 2024 12:23:54 -0400 Subject: [PATCH] Intrinsic `pack` replaced by pointers in `get_params` and `get_gradients` (#183) * Replace intrinsic pack by pointers * Dense layer: remove an avoidable reshape * conv2d: avoid intrinsics pack and reshape * replace a reshape by a pointer * clean conv2d_layer_submodule --------- Co-authored-by: Vandenplas, Jeremie Co-authored-by: milancurcic --- src/nf/nf_conv2d_layer.f90 | 8 +++--- src/nf/nf_conv2d_layer_submodule.f90 | 29 ++++++++++++------- src/nf/nf_dense_layer.f90 | 10 +++---- src/nf/nf_dense_layer_submodule.f90 | 43 ++++++++++++++++------------ src/nf/nf_layer.f90 | 4 +-- src/nf/nf_layer_submodule.f90 | 4 +-- src/nf/nf_network.f90 | 4 +-- src/nf/nf_network_submodule.f90 | 4 +-- 8 files changed, 60 insertions(+), 46 deletions(-) diff --git a/src/nf/nf_conv2d_layer.f90 b/src/nf/nf_conv2d_layer.f90 index 7b72980c..2f286030 100644 --- a/src/nf/nf_conv2d_layer.f90 +++ b/src/nf/nf_conv2d_layer.f90 @@ -89,19 +89,19 @@ pure module function get_num_params(self) result(num_params) !! Number of parameters end function get_num_params - pure module function get_params(self) result(params) + module function get_params(self) result(params) !! Return the parameters (weights and biases) of this layer. !! The parameters are ordered as weights first, biases second. - class(conv2d_layer), intent(in) :: self + class(conv2d_layer), intent(in), target :: self !! A `conv2d_layer` instance real, allocatable :: params(:) !! Parameters to get end function get_params - pure module function get_gradients(self) result(gradients) + module function get_gradients(self) result(gradients) !! Return the gradients of this layer. !! The gradients are ordered as weights first, biases second. - class(conv2d_layer), intent(in) :: self + class(conv2d_layer), intent(in), target :: self !! A `conv2d_layer` instance real, allocatable :: gradients(:) !! Gradients to get diff --git a/src/nf/nf_conv2d_layer_submodule.f90 b/src/nf/nf_conv2d_layer_submodule.f90 index b4804243..5f71084b 100644 --- a/src/nf/nf_conv2d_layer_submodule.f90 +++ b/src/nf/nf_conv2d_layer_submodule.f90 @@ -189,24 +189,32 @@ pure module function get_num_params(self) result(num_params) end function get_num_params - pure module function get_params(self) result(params) - class(conv2d_layer), intent(in) :: self + module function get_params(self) result(params) + class(conv2d_layer), intent(in), target :: self real, allocatable :: params(:) + real, pointer :: w_(:) => null() + + w_(1:size(self % kernel)) => self % kernel + params = [ & - pack(self % kernel, .true.), & + w_, & self % biases & ] end function get_params - pure module function get_gradients(self) result(gradients) - class(conv2d_layer), intent(in) :: self + module function get_gradients(self) result(gradients) + class(conv2d_layer), intent(in), target :: self real, allocatable :: gradients(:) + real, pointer :: dw_(:) => null() + + dw_(1:size(self % dw)) => self % dw + gradients = [ & - pack(self % dw, .true.), & + dw_, & self % db & ] @@ -219,7 +227,7 @@ module subroutine set_params(self, params) ! Check that the number of parameters is correct. if (size(params) /= self % get_num_params()) then - error stop 'conv2d % set_params: Number of parameters does not match' + error stop 'conv2d % set_params: Number of parameters does not match' end if ! Reshape the kernel. @@ -229,10 +237,9 @@ module subroutine set_params(self, params) ) ! Reshape the biases. - self % biases = reshape( & - params(product(shape(self % kernel)) + 1:), & - [self % filters] & - ) + associate(n => product(shape(self % kernel))) + self % biases = params(n + 1 : n + self % filters) + end associate end subroutine set_params diff --git a/src/nf/nf_dense_layer.f90 b/src/nf/nf_dense_layer.f90 index ae523ccb..c5735799 100644 --- a/src/nf/nf_dense_layer.f90 +++ b/src/nf/nf_dense_layer.f90 @@ -87,19 +87,19 @@ pure module function get_num_params(self) result(num_params) !! Number of parameters in this layer end function get_num_params - pure module function get_params(self) result(params) + module function get_params(self) result(params) !! Return the parameters (weights and biases) of this layer. !! The parameters are ordered as weights first, biases second. - class(dense_layer), intent(in) :: self + class(dense_layer), intent(in), target :: self !! Dense layer instance real, allocatable :: params(:) !! Parameters of this layer end function get_params - pure module function get_gradients(self) result(gradients) + module function get_gradients(self) result(gradients) !! Return the gradients of this layer. !! The gradients are ordered as weights first, biases second. - class(dense_layer), intent(in) :: self + class(dense_layer), intent(in), target :: self !! Dense layer instance real, allocatable :: gradients(:) !! Gradients of this layer @@ -110,7 +110,7 @@ module subroutine set_params(self, params) !! The parameters are ordered as weights first, biases second. class(dense_layer), intent(in out) :: self !! Dense layer instance - real, intent(in) :: params(:) + real, intent(in), target :: params(:) !! Parameters of this layer end subroutine set_params diff --git a/src/nf/nf_dense_layer_submodule.f90 b/src/nf/nf_dense_layer_submodule.f90 index 4be23e33..50d5b10d 100644 --- a/src/nf/nf_dense_layer_submodule.f90 +++ b/src/nf/nf_dense_layer_submodule.f90 @@ -61,24 +61,32 @@ pure module function get_num_params(self) result(num_params) end function get_num_params - pure module function get_params(self) result(params) - class(dense_layer), intent(in) :: self + module function get_params(self) result(params) + class(dense_layer), intent(in), target :: self real, allocatable :: params(:) + real, pointer :: w_(:) => null() + + w_(1:size(self % weights)) => self % weights + params = [ & - pack(self % weights, .true.), & + w_, & self % biases & ] end function get_params - pure module function get_gradients(self) result(gradients) - class(dense_layer), intent(in) :: self + module function get_gradients(self) result(gradients) + class(dense_layer), intent(in), target :: self real, allocatable :: gradients(:) + real, pointer :: dw_(:) => null() + + dw_(1:size(self % dw)) => self % dw + gradients = [ & - pack(self % dw, .true.), & + dw_, & self % db & ] @@ -87,24 +95,23 @@ end function get_gradients module subroutine set_params(self, params) class(dense_layer), intent(in out) :: self - real, intent(in) :: params(:) + real, intent(in), target :: params(:) + + real, pointer :: p_(:,:) => null() ! check if the number of parameters is correct if (size(params) /= self % get_num_params()) then error stop 'Error: number of parameters does not match' end if - ! reshape the weights - self % weights = reshape( & - params(:self % input_size * self % output_size), & - [self % input_size, self % output_size] & - ) - - ! reshape the biases - self % biases = reshape( & - params(self % input_size * self % output_size + 1:), & - [self % output_size] & - ) + associate(n => self % input_size * self % output_size) + ! reshape the weights + p_(1:self % input_size, 1:self % output_size) => params(1 : n) + self % weights = p_ + + ! reshape the biases + self % biases = params(n + 1 : n + self % output_size) + end associate end subroutine set_params diff --git a/src/nf/nf_layer.f90 b/src/nf/nf_layer.f90 index e9e90da8..ca5e9606 100644 --- a/src/nf/nf_layer.f90 +++ b/src/nf/nf_layer.f90 @@ -129,7 +129,7 @@ elemental module function get_num_params(self) result(num_params) !! Number of parameters in this layer end function get_num_params - pure module function get_params(self) result(params) + module function get_params(self) result(params) !! Returns the parameters of this layer. class(layer), intent(in) :: self !! Layer instance @@ -137,7 +137,7 @@ pure module function get_params(self) result(params) !! Parameters of this layer end function get_params - pure module function get_gradients(self) result(gradients) + module function get_gradients(self) result(gradients) !! Returns the gradients of this layer. class(layer), intent(in) :: self !! Layer instance diff --git a/src/nf/nf_layer_submodule.f90 b/src/nf/nf_layer_submodule.f90 index 07467643..c672581a 100644 --- a/src/nf/nf_layer_submodule.f90 +++ b/src/nf/nf_layer_submodule.f90 @@ -298,7 +298,7 @@ elemental module function get_num_params(self) result(num_params) end function get_num_params - pure module function get_params(self) result(params) + module function get_params(self) result(params) class(layer), intent(in) :: self real, allocatable :: params(:) @@ -323,7 +323,7 @@ pure module function get_params(self) result(params) end function get_params - pure module function get_gradients(self) result(gradients) + module function get_gradients(self) result(gradients) class(layer), intent(in) :: self real, allocatable :: gradients(:) diff --git a/src/nf/nf_network.f90 b/src/nf/nf_network.f90 index cf21f652..bcf10ae8 100644 --- a/src/nf/nf_network.f90 +++ b/src/nf/nf_network.f90 @@ -172,7 +172,7 @@ pure module integer function get_num_params(self) !! Network instance end function get_num_params - pure module function get_params(self) result(params) + module function get_params(self) result(params) !! Get the network parameters (weights and biases). class(network), intent(in) :: self !! Network instance @@ -180,7 +180,7 @@ pure module function get_params(self) result(params) !! Network parameters to get end function get_params - pure module function get_gradients(self) result(gradients) + module function get_gradients(self) result(gradients) class(network), intent(in) :: self !! Network instance real, allocatable :: gradients(:) diff --git a/src/nf/nf_network_submodule.f90 b/src/nf/nf_network_submodule.f90 index 3738b291..60fa8579 100644 --- a/src/nf/nf_network_submodule.f90 +++ b/src/nf/nf_network_submodule.f90 @@ -526,7 +526,7 @@ pure module function get_num_params(self) end function get_num_params - pure module function get_params(self) result(params) + module function get_params(self) result(params) class(network), intent(in) :: self real, allocatable :: params(:) integer :: n, nstart, nend @@ -546,7 +546,7 @@ pure module function get_params(self) result(params) end function get_params - pure module function get_gradients(self) result(gradients) + module function get_gradients(self) result(gradients) class(network), intent(in) :: self real, allocatable :: gradients(:) integer :: n, nstart, nend