Skip to content

Commit 197e84a

Browse files
committed
Introducing locally connected 1d layers
1 parent d516437 commit 197e84a

File tree

7 files changed

+411
-6
lines changed

7 files changed

+411
-6
lines changed

CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ add_library(neural-fortran
3636
src/nf/nf_layer_constructors_submodule.f90
3737
src/nf/nf_layer.f90
3838
src/nf/nf_layer_submodule.f90
39+
src/nf/nf_locally_connected_1d.f90
40+
src/nf/nf_locally_connected_1d_submodule.f90
3941
src/nf/nf_loss.f90
4042
src/nf/nf_loss_submodule.f90
4143
src/nf/nf_maxpool2d_layer.f90

example/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
foreach(execid
22
cnn_mnist
3+
cnn_mnist_1d
34
dense_mnist
45
get_set_network_params
56
network_parameters

example/cnn_mnist.f90

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ program cnn_mnist
1212
real, allocatable :: validation_images(:,:), validation_labels(:)
1313
real, allocatable :: testing_images(:,:), testing_labels(:)
1414
integer :: n
15-
integer, parameter :: num_epochs = 10
15+
integer, parameter :: num_epochs = 20
1616

1717
call load_mnist(training_images, training_labels, &
1818
validation_images, validation_labels, &
@@ -35,9 +35,9 @@ program cnn_mnist
3535
call net % train( &
3636
training_images, &
3737
label_digits(training_labels), &
38-
batch_size=128, &
38+
batch_size=16, &
3939
epochs=1, &
40-
optimizer=sgd(learning_rate=3.) &
40+
optimizer=sgd(learning_rate=0.003) &
4141
)
4242

4343
print '(a,i2,a,f5.2,a)', 'Epoch ', n, ' done, Accuracy: ', accuracy( &

example/cnn_mnist_1d.f90

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
program cnn_mnist
2+
3+
use nf, only: network, sgd, &
4+
input, conv2d, maxpool2d, flatten, dense, reshape, locally_connected_1d, &
5+
load_mnist, label_digits, softmax, relu
6+
7+
implicit none
8+
9+
type(network) :: net
10+
11+
real, allocatable :: training_images(:,:), training_labels(:)
12+
real, allocatable :: validation_images(:,:), validation_labels(:)
13+
real, allocatable :: testing_images(:,:), testing_labels(:)
14+
integer :: n
15+
integer, parameter :: num_epochs = 10
16+
17+
call load_mnist(training_images, training_labels, &
18+
validation_images, validation_labels, &
19+
testing_images, testing_labels)
20+
21+
net = network([ &
22+
input(784), &
23+
reshape([1,28,28]), &
24+
conv2d(filters=8, kernel_size=3, activation=relu()), &
25+
maxpool2d(pool_size=2), &
26+
conv2d(filters=16, kernel_size=3, activation=relu()), &
27+
maxpool2d(pool_size=2), &
28+
dense(10, activation=softmax()) &
29+
])
30+
31+
call net % print_info()
32+
33+
epochs: do n = 1, num_epochs
34+
35+
call net % train( &
36+
training_images, &
37+
label_digits(training_labels), &
38+
batch_size=16, &
39+
epochs=1, &
40+
optimizer=sgd(learning_rate=1) &
41+
)
42+
43+
print '(a,i2,a,f5.2,a)', 'Epoch ', n, ' done, Accuracy: ', accuracy( &
44+
net, validation_images, label_digits(validation_labels)) * 100, ' %'
45+
46+
end do epochs
47+
48+
print '(a,f5.2,a)', 'Testing accuracy: ', &
49+
accuracy(net, testing_images, label_digits(testing_labels)) * 100, '%'
50+
51+
contains
52+
53+
real function accuracy(net, x, y)
54+
type(network), intent(in out) :: net
55+
real, intent(in) :: x(:,:), y(:,:)
56+
integer :: i, good
57+
good = 0
58+
do i = 1, size(x, dim=2)
59+
if (all(maxloc(net % predict(x(:,i))) == maxloc(y(:,i)))) then
60+
good = good + 1
61+
end if
62+
end do
63+
accuracy = real(good) / size(x, dim=2)
64+
end function accuracy
65+
66+
end program cnn_mnist
67+

src/nf/nf_datasets_mnist_submodule.f90

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,9 @@ module subroutine load_mnist(training_images, training_labels, &
5050
real, allocatable, intent(in out), optional :: testing_labels(:)
5151

5252
integer, parameter :: dtype = 4, image_size = 784
53-
integer, parameter :: num_training_images = 50000
54-
integer, parameter :: num_validation_images = 10000
55-
integer, parameter :: num_testing_images = 10000
53+
integer, parameter :: num_training_images = 500
54+
integer, parameter :: num_validation_images = 100
55+
integer, parameter :: num_testing_images = 100
5656
logical :: file_exists
5757

5858
! Check if MNIST data is present and download it if not.

src/nf/nf_locally_connected_1d.f90

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
module nf_locally_connected_1d_layer
2+
!! This module provides a locally connected 1d layer type.
3+
4+
use nf_activation, only: activation_function
5+
use nf_base_layer, only: base_layer
6+
implicit none
7+
8+
private
9+
public :: locally_connected_1d_layer
10+
11+
type, extends(base_layer) :: locally_connected_1d_layer
12+
! For a 1D layer, we assume an input shape of [channels, input_length]
13+
integer :: channels ! number of input channels
14+
integer :: input_length ! length of the 1D input
15+
integer :: output_length ! computed as input_length - kernel_size + 1
16+
integer :: kernel_size ! size of the 1D window
17+
integer :: filters ! number of filters (output channels)
18+
19+
! Parameters (unshared weights)
20+
! Kernel shape: (filters, output_length, channels, kernel_size)
21+
real, allocatable :: kernel(:,:,:,:)
22+
! Biases shape: (filters, output_length)
23+
real, allocatable :: biases(:,:)
24+
25+
! Forward-pass arrays
26+
! Pre-activation values: shape (filters, output_length)
27+
real, allocatable :: z(:,:)
28+
! Activated output: shape (filters, output_length)
29+
real, allocatable :: output(:,:)
30+
31+
! Gradients for backpropagation
32+
! Gradient for kernel, same shape as kernel
33+
real, allocatable :: dw(:,:,:,:)
34+
! Gradient for biases, same shape as biases
35+
real, allocatable :: db(:,:)
36+
! Gradient with respect to the input, shape (channels, input_length)
37+
real, allocatable :: gradient(:,:)
38+
39+
! Activation function
40+
class(activation_function), allocatable :: activation
41+
contains
42+
procedure :: forward
43+
procedure :: backward
44+
procedure :: get_gradients
45+
procedure :: get_num_params
46+
procedure :: get_params
47+
procedure :: init
48+
procedure :: set_params
49+
end type locally_connected_1d_layer
50+
51+
interface locally_connected_1d_layer
52+
module function locally_connected_1d_layer_cons(filters, kernel_size, activation) result(res)
53+
!! Constructor for the locally connected 1d layer.
54+
integer, intent(in) :: filters
55+
integer, intent(in) :: kernel_size
56+
class(activation_function), intent(in):: activation
57+
type(locally_connected_1d_layer) :: res
58+
end function locally_connected_1d_layer_cons
59+
end interface locally_connected_1d_layer
60+
61+
interface
62+
module subroutine init(self, input_shape)
63+
!! Initialize the layer data structures.
64+
!! input_shape: integer array of length 2, where
65+
!! input_shape(1) = number of channels
66+
!! input_shape(2) = input length
67+
class(locally_connected_1d_layer), intent(inout) :: self
68+
integer, intent(in) :: input_shape(:)
69+
end subroutine init
70+
71+
pure module subroutine forward(self, input)
72+
!! Apply the forward pass.
73+
!! Input shape: (channels, input_length)
74+
class(locally_connected_1d_layer), intent(inout) :: self
75+
real, intent(in) :: input(:,:)
76+
end subroutine forward
77+
78+
pure module subroutine backward(self, input, gradient)
79+
!! Apply the backward pass.
80+
!! input: shape (channels, input_length)
81+
!! gradient: gradient w.r.t. output, shape (filters, output_length)
82+
class(locally_connected_1d_layer), intent(inout) :: self
83+
real, intent(in) :: input(:,:)
84+
real, intent(in) :: gradient(:,:)
85+
end subroutine backward
86+
87+
pure module function get_num_params(self) result(num_params)
88+
!! Get the total number of parameters (kernel + biases)
89+
class(locally_connected_1d_layer), intent(in) :: self
90+
integer :: num_params
91+
end function get_num_params
92+
93+
module function get_params(self) result(params)
94+
!! Return a flattened vector of parameters (kernel then biases).
95+
class(locally_connected_1d_layer), intent(in), target :: self
96+
real, allocatable :: params(:)
97+
end function get_params
98+
99+
module function get_gradients(self) result(gradients)
100+
!! Return a flattened vector of gradients (dw then db).
101+
class(locally_connected_1d_layer), intent(in), target :: self
102+
real, allocatable :: gradients(:)
103+
end function get_gradients
104+
105+
module subroutine set_params(self, params)
106+
!! Set the parameters from a flattened vector.
107+
class(locally_connected_1d_layer), intent(inout) :: self
108+
real, intent(in) :: params(:)
109+
end subroutine set_params
110+
end interface
111+
112+
end module nf_locally_connected_1d_layer

0 commit comments

Comments
 (0)