-
Notifications
You must be signed in to change notification settings - Fork 100
Linear2d layer #197
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Linear2d layer #197
Changes from 36 commits
1fb279a
d997b6b
9919c01
43d1a1f
906f21b
e1b4695
0fe2ef0
957095d
eff36fe
b6f3c97
541d943
a27ec09
79abce3
2168ec9
9a13af3
0db76db
f28ecc0
9386aa3
07750db
b5a600a
dd1297e
e4cb526
86ec628
d40aebb
b803553
f1a01a6
b39e6da
1bec531
d01a174
141fe57
c4b8fc7
54d1bb0
9a4422f
7606d2c
7d271fe
539fde8
a97f141
bbfaf3c
4d28a0a
bfc69d5
119a6c8
6f33ebe
678b2c0
e78ef62
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,6 +2,7 @@ foreach(execid | |
| cnn_mnist | ||
| dense_mnist | ||
| get_set_network_params | ||
| linear2d | ||
| network_parameters | ||
| simple | ||
| sine | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| program linear2d_example | ||
|
|
||
| use nf, only: input, network, sgd, linear2d, mse, flatten | ||
| implicit none | ||
|
|
||
| type(network) :: net | ||
| real :: x(3, 4) = reshape( & | ||
| [0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2], & | ||
| [3, 4]) | ||
| real :: y(3) = [0.12, 0.1, 0.3] | ||
| integer, parameter :: num_iterations = 500 | ||
| integer :: n | ||
|
|
||
| net = network([ & | ||
| input(3, 4), & | ||
| linear2d(3, 4, 1), & | ||
| flatten() & | ||
| ]) | ||
|
|
||
| call net % print_info() | ||
|
|
||
| do n = 1, num_iterations | ||
| call net % forward(x) | ||
| call net % backward(y, mse()) | ||
| call net % update(optimizer=sgd(learning_rate=1.)) | ||
| print '(i4,3(3x,f8.6))', n, net % predict(x) | ||
| end do | ||
|
|
||
| end program linear2d_example | ||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -9,6 +9,7 @@ | |||||
| use nf_input3d_layer, only: input3d_layer | ||||||
| use nf_maxpool2d_layer, only: maxpool2d_layer | ||||||
| use nf_reshape_layer, only: reshape3d_layer | ||||||
| use nf_linear2d_layer, only: linear2d_layer | ||||||
| use nf_activation, only: activation_function, relu, sigmoid | ||||||
|
|
||||||
| implicit none | ||||||
|
|
@@ -71,6 +72,7 @@ module function flatten() result(res) | |||||
| end function flatten | ||||||
|
|
||||||
|
|
||||||
|
|
||||||
| module function input1d(layer_size) result(res) | ||||||
| integer, intent(in) :: layer_size | ||||||
| type(layer) :: res | ||||||
|
|
@@ -148,4 +150,13 @@ module function reshape(output_shape) result(res) | |||||
|
|
||||||
| end function reshape | ||||||
|
|
||||||
| module function linear2d(sequence_length, in_features, out_features) result(res) | ||||||
|
||||||
| module function linear2d(sequence_length, in_features, out_features) result(res) | |
| module function linear2d(out_features) result(res) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, makes sense
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It turns out that we cannot avoid passing sequence_length. We need it to determine the output shape. I think it's not a big deal and can be left like this
module function linear2d(sequence_length, out_features) result(res)
integer, intent(in) :: sequence_length, out_features
type(layer) :: res
res % name = 'linear2d'
res % layer_shape = [sequence_length, out_features]
allocate(res % p, source=linear2d_layer(out_features))
end function linear2dThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just gave it a try; unless I'm mistaken, I think it can work. See this commit: 678b2c0
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll try to explain; the process goes like this:
linear2d(out_features)constructs the genericlayerinstance which at this time does not yet know itslayer_shape.networkconstructor from an array of genericlayersloops over each layer in order and callslayer % init(prev_layer).- Inside
layer % initthe output shape of the previous layer is passed to the concretelinear2d_layer % init(input_shape)and inside the concreteinit, all parameters are now known (sequence_length,in_features,out_features. - After the concrete layer
initcall, back inside the genericlayer % init, we set the genericlayer % layer_shapeto be the same as the shape of the concretelinear2d_layer % output.
I hope this make sense and I'm sorry that it had to be so complicated. However, we are essentially hacking around Fortran's very limited generic features.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,79 @@ | ||
| module nf_linear2d_layer | ||
|
|
||
| use nf_activation, only: activation_function | ||
| use nf_base_layer, only: base_layer | ||
|
|
||
| implicit none | ||
|
|
||
| private | ||
| public :: linear2d_layer | ||
|
|
||
| type, extends(base_layer) :: linear2d_layer | ||
| integer :: sequence_length, in_features, out_features, batch_size | ||
|
|
||
| real, allocatable :: weights(:, :) | ||
| real, allocatable :: biases(:) | ||
| real, allocatable :: output(:, :) | ||
| real, allocatable :: gradient(:, :) ! input gradient | ||
| real, allocatable :: dw(:, :) ! weight gradients | ||
| real, allocatable :: db(:) ! bias gradients | ||
|
|
||
| contains | ||
|
|
||
| procedure :: backward | ||
| procedure :: forward | ||
| procedure :: init | ||
| procedure :: get_num_params | ||
| procedure :: get_params | ||
| procedure :: get_gradients | ||
| procedure :: set_params | ||
|
|
||
| end type linear2d_layer | ||
|
|
||
| interface linear2d_layer | ||
| module function linear2d_layer_cons(& | ||
| sequence_length, in_features, out_features& | ||
| ) result(res) | ||
| integer, intent(in) :: sequence_length, in_features, out_features | ||
| type(linear2d_layer) :: res | ||
| end function linear2d_layer_cons | ||
| end interface linear2d_layer | ||
|
|
||
| interface | ||
| pure module subroutine forward(self, input) | ||
| class(linear2d_layer), intent(in out) :: self | ||
| real, intent(in) :: input(:, :) | ||
| end subroutine forward | ||
|
|
||
| pure module subroutine backward(self, input, gradient) | ||
| class(linear2d_layer), intent(in out) :: self | ||
| real, intent(in) :: input(:, :) | ||
| real, intent(in) :: gradient(:, :) | ||
| end subroutine backward | ||
|
|
||
| module subroutine init(self, input_shape) | ||
| class(linear2d_layer), intent(in out) :: self | ||
| integer, intent(in) :: input_shape(:) | ||
| end subroutine init | ||
|
|
||
| pure module function get_num_params(self) result(num_params) | ||
| class(linear2d_layer), intent(in) :: self | ||
| integer :: num_params | ||
| end function get_num_params | ||
|
|
||
| module function get_params(self) result(params) | ||
| class(linear2d_layer), intent(in), target :: self | ||
| real, allocatable :: params(:) | ||
| end function get_params | ||
|
|
||
| module function get_gradients(self) result(gradients) | ||
| class(linear2d_layer), intent(in), target :: self | ||
| real, allocatable :: gradients(:) | ||
| end function get_gradients | ||
|
|
||
| module subroutine set_params(self, params) | ||
| class(linear2d_layer), intent(in out) :: self | ||
| real, intent(in), target :: params(:) | ||
| end subroutine set_params | ||
| end interface | ||
| end module nf_linear2d_layer |
Uh oh!
There was an error while loading. Please reload this page.