Skip to content

Commit d323175

Browse files
committed
Merge main
2 parents 5ae7e9d + 4ad75bc commit d323175

23 files changed

+404
-54
lines changed

CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ add_library(neural-fortran
3030
src/nf/nf_flatten_layer_submodule.f90
3131
src/nf/nf_input1d_layer.f90
3232
src/nf/nf_input1d_layer_submodule.f90
33+
src/nf/nf_input2d_layer.f90
34+
src/nf/nf_input2d_layer_submodule.f90
3335
src/nf/nf_input3d_layer.f90
3436
src/nf/nf_input3d_layer_submodule.f90
3537
src/nf/nf_layer_constructors.f90

LICENSE

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
MIT License
22

3-
Copyright (c) 2018-2024 neural-fortran contributors
3+
Copyright (c) 2018-2025 neural-fortran contributors
44

55
Permission is hereby granted, free of charge, to any person obtaining a copy
66
of this software and associated documentation files (the "Software"), to deal

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,12 @@ Read the paper [here](https://arxiv.org/abs/1902.06714).
2929

3030
| Layer type | Constructor name | Supported input layers | Rank of output array | Forward pass | Backward pass |
3131
|------------|------------------|------------------------|----------------------|--------------|---------------|
32-
| Input | `input` | n/a | 1, 3 | n/a | n/a |
32+
| Input | `input` | n/a | 1, 2, 3 | n/a | n/a |
3333
| Dense (fully-connected) | `dense` | `input1d`, `flatten` | 1 |||
3434
| Dropout | `dropout` | Any | 1 |||
3535
| Convolutional (2-d) | `conv2d` | `input3d`, `conv2d`, `maxpool2d`, `reshape` | 3 || ✅(*) |
3636
| Max-pooling (2-d) | `maxpool2d` | `input3d`, `conv2d`, `maxpool2d`, `reshape` | 3 |||
37-
| Flatten | `flatten` | `input3d`, `conv2d`, `maxpool2d`, `reshape` | 1 |||
37+
| Flatten | `flatten` | `input2d`, `input3d`, `conv2d`, `maxpool2d`, `reshape` | 1 |||
3838
| Reshape (1-d to 3-d) | `reshape` | `input1d`, `dense`, `flatten` | 3 |||
3939

4040
(*) See Issue [#145](https://github.com/modern-fortran/neural-fortran/issues/145) regarding non-converging CNN training on the MNIST dataset.

fpm.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ name = "neural-fortran"
22
version = "0.19.0"
33
license = "MIT"
44
author = "Milan Curcic"
5-
maintainer = "[email protected]"
5+
maintainer = "[email protected]"
66
copyright = "Copyright 2018-2025, neural-fortran contributors"
77

88
[preprocess]

src/nf/nf_flatten_layer.f90

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ module nf_flatten_layer
1818
integer, allocatable :: input_shape(:)
1919
integer :: output_size
2020

21-
real, allocatable :: gradient(:,:,:)
21+
real, allocatable :: gradient_2d(:,:)
22+
real, allocatable :: gradient_3d(:,:,:)
2223
real, allocatable :: output(:)
2324

2425
contains
@@ -40,23 +41,23 @@ end function flatten_layer_cons
4041
interface
4142

4243
pure module subroutine backward(self, input, gradient)
43-
!! Apply the backward pass to the flatten layer.
44-
!! This is a reshape operation from 1-d gradient to 3-d input.
44+
!! Apply the backward pass to the flatten layer for 2D and 3D input.
45+
!! This is a reshape operation from 1-d gradient to 2-d and 3-d input.
4546
class(flatten_layer), intent(in out) :: self
4647
!! Flatten layer instance
47-
real, intent(in) :: input(:,:,:)
48+
real, intent(in) :: input(..)
4849
!! Input from the previous layer
4950
real, intent(in) :: gradient(:)
5051
!! Gradient from the next layer
5152
end subroutine backward
5253

5354
pure module subroutine forward(self, input)
54-
!! Propagate forward the layer.
55+
!! Propagate forward the layer for 2D or 3D input.
5556
!! Calling this subroutine updates the values of a few data components
5657
!! of `flatten_layer` that are needed for the backward pass.
5758
class(flatten_layer), intent(in out) :: self
5859
!! Dense layer instance
59-
real, intent(in) :: input(:,:,:)
60+
real, intent(in) :: input(..)
6061
!! Input from the previous layer
6162
end subroutine forward
6263

src/nf/nf_flatten_layer_submodule.f90

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,30 @@ end function flatten_layer_cons
1717

1818
pure module subroutine backward(self, input, gradient)
1919
class(flatten_layer), intent(in out) :: self
20-
real, intent(in) :: input(:,:,:)
20+
real, intent(in) :: input(..)
2121
real, intent(in) :: gradient(:)
22-
self % gradient = reshape(gradient, shape(input))
22+
select rank(input)
23+
rank(2)
24+
self % gradient_2d = reshape(gradient, shape(input))
25+
rank(3)
26+
self % gradient_3d = reshape(gradient, shape(input))
27+
rank default
28+
error stop "Unsupported rank of input"
29+
end select
2330
end subroutine backward
2431

2532

2633
pure module subroutine forward(self, input)
2734
class(flatten_layer), intent(in out) :: self
28-
real, intent(in) :: input(:,:,:)
29-
self % output = pack(input, .true.)
35+
real, intent(in) :: input(..)
36+
select rank(input)
37+
rank(2)
38+
self % output = pack(input, .true.)
39+
rank(3)
40+
self % output = pack(input, .true.)
41+
rank default
42+
error stop "Unsupported rank of input"
43+
end select
3044
end subroutine forward
3145

3246

@@ -37,8 +51,13 @@ module subroutine init(self, input_shape)
3751
self % input_shape = input_shape
3852
self % output_size = product(input_shape)
3953

40-
allocate(self % gradient(input_shape(1), input_shape(2), input_shape(3)))
41-
self % gradient = 0
54+
if (size(input_shape) == 2) then
55+
allocate(self % gradient_2d(input_shape(1), input_shape(2)))
56+
self % gradient_2d = 0
57+
else if (size(input_shape) == 3) then
58+
allocate(self % gradient_3d(input_shape(1), input_shape(2), input_shape(3)))
59+
self % gradient_3d = 0
60+
end if
4261

4362
allocate(self % output(self % output_size))
4463
self % output = 0

src/nf/nf_input2d_layer.f90

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
module nf_input2d_layer
2+
3+
!! This module provides the `input2d_layer` type.
4+
5+
use nf_base_layer, only: base_layer
6+
implicit none
7+
8+
private
9+
public :: input2d_layer
10+
11+
type, extends(base_layer) :: input2d_layer
12+
real, allocatable :: output(:,:)
13+
contains
14+
procedure :: init
15+
procedure :: set
16+
end type input2d_layer
17+
18+
interface input2d_layer
19+
pure module function input2d_layer_cons(output_shape) result(res)
20+
!! Create a new instance of the 2-d input layer.
21+
!! Only used internally by the `layer % init` method.
22+
integer, intent(in) :: output_shape(2)
23+
!! Shape of the input layer
24+
type(input2d_layer) :: res
25+
!! 2-d input layer instance
26+
end function input2d_layer_cons
27+
end interface input2d_layer
28+
29+
interface
30+
31+
module subroutine init(self, input_shape)
32+
!! Only here to satisfy the language rules
33+
!! about deferred methods of abstract types.
34+
!! This method does nothing for this type and should not be called.
35+
class(input2d_layer), intent(in out) :: self
36+
integer, intent(in) :: input_shape(:)
37+
end subroutine init
38+
39+
pure module subroutine set(self, values)
40+
class(input2d_layer), intent(in out) :: self
41+
!! Layer instance
42+
real, intent(in) :: values(:,:)
43+
!! Values to set
44+
end subroutine set
45+
46+
end interface
47+
48+
end module nf_input2d_layer
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
submodule(nf_input2d_layer) nf_input2d_layer_submodule
2+
implicit none
3+
contains
4+
5+
pure module function input2d_layer_cons(output_shape) result(res)
6+
integer, intent(in) :: output_shape(2)
7+
type(input2d_layer) :: res
8+
allocate(res % output(output_shape(1), output_shape(2)))
9+
res % output = 0
10+
end function input2d_layer_cons
11+
12+
module subroutine init(self, input_shape)
13+
class(input2d_layer), intent(in out) :: self
14+
integer, intent(in) :: input_shape(:)
15+
end subroutine init
16+
17+
pure module subroutine set(self, values)
18+
class(input2d_layer), intent(in out) :: self
19+
real, intent(in) :: values(:,:)
20+
self % output = values
21+
end subroutine set
22+
23+
end submodule nf_input2d_layer_submodule

src/nf/nf_layer.f90

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,14 @@ module nf_layer
3535

3636
! Specific subroutines for different array ranks
3737
procedure, private :: backward_1d
38+
procedure, private :: backward_2d
3839
procedure, private :: backward_3d
3940
procedure, private :: get_output_1d
41+
procedure, private :: get_output_2d
4042
procedure, private :: get_output_3d
4143

42-
generic :: backward => backward_1d, backward_3d
43-
generic :: get_output => get_output_1d, get_output_3d
44+
generic :: backward => backward_1d, backward_2d, backward_3d
45+
generic :: get_output => get_output_1d, get_output_2d, get_output_3d
4446

4547
end type layer
4648

@@ -59,6 +61,19 @@ pure module subroutine backward_1d(self, previous, gradient)
5961
!! Array of gradient values from the next layer
6062
end subroutine backward_1d
6163

64+
pure module subroutine backward_2d(self, previous, gradient)
65+
!! Apply a backward pass on the layer.
66+
!! This changes the internal state of the layer.
67+
!! This is normally called internally by the `network % backward`
68+
!! method.
69+
class(layer), intent(in out) :: self
70+
!! Layer instance
71+
class(layer), intent(in) :: previous
72+
!! Previous layer instance
73+
real, intent(in) :: gradient(:, :)
74+
!! Array of gradient values from the next layer
75+
end subroutine backward_2d
76+
6277
pure module subroutine backward_3d(self, previous, gradient)
6378
!! Apply a backward pass on the layer.
6479
!! This changes the internal state of the layer.
@@ -95,6 +110,14 @@ pure module subroutine get_output_1d(self, output)
95110
!! Output values from this layer
96111
end subroutine get_output_1d
97112

113+
pure module subroutine get_output_2d(self, output)
114+
!! Returns the output values (activations) from this layer.
115+
class(layer), intent(in) :: self
116+
!! Layer instance
117+
real, allocatable, intent(out) :: output(:,:)
118+
!! Output values from this layer
119+
end subroutine get_output_2d
120+
98121
pure module subroutine get_output_3d(self, output)
99122
!! Returns the output values (activations) from a layer with a 3-d output
100123
!! (e.g. input3d, conv2d)

src/nf/nf_layer_constructors.f90

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,10 @@ module function input1d(layer_size) result(res)
3535
!! Resulting layer instance
3636
end function input1d
3737

38-
module function input3d(layer_shape) result(res)
39-
!! 3-d input layer constructor.
38+
module function input2d(dim1, dim2) result(res)
39+
!! 2-d input layer constructor.
4040
!!
41-
!! This layer is for inputting 3-d data to the network.
41+
!! This layer is for inputting 2-d data to the network.
4242
!! Currently, this layer must be followed by a conv2d layer.
4343
!! An input layer must be the first layer in the network.
4444
!!
@@ -50,10 +50,29 @@ module function input3d(layer_shape) result(res)
5050
!! ```
5151
!! use nf, only :: input, layer
5252
!! type(layer) :: input_layer
53-
!! input_layer = input([28, 28, 1])
53+
!! input_layer = input(28, 28)
54+
!! ```
55+
integer, intent(in) :: dim1, dim2
56+
!! First and second dimension sizes
57+
type(layer) :: res
58+
!! Resulting layer instance
59+
end function input2d
60+
61+
module function input3d(dim1, dim2, dim3) result(res)
62+
!! 3-d input layer constructor.
63+
!!
64+
!! This is a specific function that is available
65+
!! under a generic name `input`.
66+
!!
67+
!! Example:
68+
!!
69+
!! ```
70+
!! use nf, only :: input, layer
71+
!! type(layer) :: input_layer
72+
!! input_layer = input(28, 28, 1)
5473
!! ```
55-
integer, intent(in) :: layer_shape(3)
56-
!! Shape of the input layer
74+
integer, intent(in) :: dim1, dim2, dim3
75+
!! First, second and third dimension sizes
5776
type(layer) :: res
5877
!! Resulting layer instance
5978
end function input3d

0 commit comments

Comments
 (0)