GCC Code Coverage Report


Directory: src/athena/
File: athena_maxpool2d_layer.f90
Date: 2025-12-10 07:37:07
Exec Total Coverage
Lines: 0 0 100.0%
Functions: 0 0 -%
Branches: 0 0 -%

Line Branch Exec Source
1 module athena__maxpool2d_layer
2 !! Module containing implementation of a 2D max pooling layer
3 !!
4 !! This module implements 2D max pooling for downsampling spatial dimensions
5 !! by selecting maximum values within pooling windows.
6 !!
7 !! Mathematical operation:
8 !! output[i,j,k] = max_{m∈[0,pool_h), n∈[0,pool_w)} input[i*stride+m, j*stride+n, k]
9 !!
10 !! where:
11 !! (i,j) are output spatial coordinates
12 !! k is the channel index
13 !! (pool_h, pool_w) is the pooling window size
14 !! stride controls the step size
15 !!
16 !! Reduces spatial dimensions while preserving important features.
17 !! Shape: (width, height, channels) -> (width//stride, height//stride, channels)
18 use coreutils, only: real32, stop_program
19 use athena__base_layer, only: pool_layer_type, base_layer_type
20 use athena__pad2d_layer, only: pad2d_layer_type
21 use athena__misc_types, only: &
22 onnx_node_type, onnx_initialiser_type, onnx_tensor_type
23 use diffstruc, only: array_type
24 use athena__diffstruc_extd, only: maxpool2d
25 implicit none
26
27
28 private
29
30 public :: maxpool2d_layer_type
31 public :: read_maxpool2d_layer
32
33
34 type, extends(pool_layer_type) :: maxpool2d_layer_type
35 !! Type for 2D max pooling layer with overloaded procedures
36 contains
37 procedure, pass(this) :: set_hyperparams => set_hyperparams_maxpool2d
38 !! Set hyperparameters for 2D max pooling layer
39 procedure, pass(this) :: read => read_maxpool2d
40 !! Read 2D max pooling layer from file
41 procedure, pass(this) :: build_from_onnx => build_from_onnx_maxpool2d
42 !! Build 2D max pooling layer from ONNX node and initialiser
43
44 procedure, pass(this) :: forward => forward_maxpool2d
45 !! Forward propagation derived type handler
46
47 end type maxpool2d_layer_type
48
49 interface maxpool2d_layer_type
50 !! Interface for setting up the 2D max pooling layer
51 module function layer_setup( input_shape, &
52 pool_size, stride, padding, verbose ) result(layer)
53 !! Set up the 2D max pooling layer
54 integer, dimension(:), optional, intent(in) :: input_shape
55 !! Input shape
56 integer, dimension(..), optional, intent(in) :: pool_size
57 !! Pool size
58 integer, dimension(..), optional, intent(in) :: stride
59 !! Stride
60 character(*), optional, intent(in) :: padding
61 !! Padding
62 integer, optional, intent(in) :: verbose
63 !! Verbosity level
64 type(maxpool2d_layer_type) :: layer
65 !! Instance of the 2D max pooling layer
66 end function layer_setup
67 end interface maxpool2d_layer_type
68
69
70
71 contains
72
73 !!!#############################################################################
74 !!! set up layer
75 !!!#############################################################################
76 module function layer_setup( &
77 input_shape, &
78 pool_size, stride, padding, verbose) result(layer)
79 !! Set up the 2D max pooling layer
80 implicit none
81
82 ! Arguments
83 integer, dimension(:), optional, intent(in) :: input_shape
84 !! Input shape
85 integer, dimension(..), optional, intent(in) :: pool_size
86 !! Pool size
87 integer, dimension(..), optional, intent(in) :: stride
88 !! Stride
89 character(*), optional, intent(in) :: padding
90 !! Padding
91 integer, optional, intent(in) :: verbose
92 !! Verbosity level
93
94 type(maxpool2d_layer_type) :: layer
95 !! Instance of the 2D max pooling layer
96
97 ! Local variables
98 integer :: verbose_ = 0
99 !! Verbosity level
100 integer, dimension(2) :: pool_size_, stride_
101 !! Pool size and stride
102 character(len=20) :: padding_
103 !! Padding
104
105 if(present(verbose)) verbose_ = verbose
106
107
108 !---------------------------------------------------------------------------
109 ! Set up pool size
110 !---------------------------------------------------------------------------
111 if(present(pool_size))then
112 select rank(pool_size)
113 rank(0)
114 pool_size_ = pool_size
115 rank(1)
116 pool_size_(1) = pool_size(1)
117 if(size(pool_size,dim=1).eq.1)then
118 pool_size_(2) = pool_size(1)
119 elseif(size(pool_size,dim=1).eq.2)then
120 pool_size_(2) = pool_size(2)
121 end if
122 end select
123 else
124 pool_size_ = 2
125 end if
126
127
128 !---------------------------------------------------------------------------
129 ! Set up stride
130 !---------------------------------------------------------------------------
131 if(present(stride))then
132 select rank(stride)
133 rank(0)
134 stride_ = stride
135 rank(1)
136 stride_(1) = stride(1)
137 if(size(stride,dim=1).eq.1)then
138 stride_(2) = stride(1)
139 elseif(size(stride,dim=1).eq.2)then
140 stride_(2) = stride(2)
141 end if
142 end select
143 else
144 stride_ = 2
145 end if
146
147
148 !---------------------------------------------------------------------------
149 ! Set up padding
150 !---------------------------------------------------------------------------
151 if(present(padding))then
152 padding_ = padding
153 else
154 padding_ = "valid"
155 end if
156
157
158 !---------------------------------------------------------------------------
159 ! Set hyperparameters
160 !---------------------------------------------------------------------------
161 call layer%set_hyperparams( &
162 pool_size=pool_size_, stride=stride_, &
163 padding=padding_, verbose=verbose_ &
164 )
165
166
167 !---------------------------------------------------------------------------
168 ! Initialise layer shape
169 !---------------------------------------------------------------------------
170 if(present(input_shape)) call layer%init(input_shape=input_shape)
171
172 end function layer_setup
173 !###############################################################################
174
175
176 !###############################################################################
177 subroutine set_hyperparams_maxpool2d( &
178 this, pool_size, stride, padding, verbose &
179 )
180 !! Set hyperparameters for 2D max pooling layer
181 use coreutils, only: to_lower
182 implicit none
183
184 ! Arguments
185 class(maxpool2d_layer_type), intent(inout) :: this
186 !! Instance of the 2D max pooling layer
187 integer, dimension(2), intent(in) :: pool_size
188 !! Pool size
189 integer, dimension(2), intent(in) :: stride
190 !! Stride
191 character(*), optional, intent(in) :: padding
192 !! Padding
193 integer, optional, intent(in) :: verbose
194 !! Verbosity level
195
196 ! Local variables
197 character(len=20) :: padding_
198
199 this%name = "maxpool2d"
200 this%type = "pool"
201 this%subtype = "max"
202 this%input_rank = 3
203 this%output_rank = 3
204 if(allocated(this%pool)) deallocate(this%pool)
205 if(allocated(this%strd)) deallocate(this%strd)
206 allocate( &
207 this%pool(this%input_rank-1), &
208 this%strd(this%input_rank-1) &
209 )
210 this%pool = pool_size
211 this%strd = stride
212
213 ! Handle padding
214 if(present(padding))then
215 padding_ = trim(adjustl(padding))
216 else
217 padding_ = "valid"
218 end if
219
220 select case(trim(adjustl(to_lower(padding_))))
221 case("valid", "none", "")
222 case default
223 this%pad_layer = pad2d_layer_type( &
224 padding = [ (this%pool-1)/2 ], &
225 method = padding_ &
226 )
227 end select
228
229 end subroutine set_hyperparams_maxpool2d
230 !###############################################################################
231
232
233 !##############################################################################!
234 ! * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * !
235 !##############################################################################!
236
237
238 !###############################################################################
239 subroutine read_maxpool2d(this, unit, verbose)
240 !! Read 2D max pooling layer from file
241 use athena__tools_infile, only: assign_val, assign_vec
242 use coreutils, only: to_lower, to_upper, icount
243 implicit none
244
245 ! Arguments
246 class(maxpool2d_layer_type), intent(inout) :: this
247 !! Instance of the 2D max pooling layer
248 integer, intent(in) :: unit
249 !! File unit
250 integer, optional, intent(in) :: verbose
251 !! Verbosity level
252
253 ! Local variables
254 integer :: verbose_ = 0
255 !! Verbosity level
256 integer :: stat
257 !! File status
258 integer :: itmp1
259 !! Temporary integer
260 integer, dimension(2) :: pool_size, stride
261 !! Pool size and stride
262 integer, dimension(3) :: input_shape
263 !! Input shape
264 character(256) :: buffer, tag, err_msg
265 !! Buffer for reading lines, tag for identifying lines, error message
266
267
268 ! Initialise optional arguments
269 !---------------------------------------------------------------------------
270 if(present(verbose)) verbose_ = verbose
271
272
273 ! Loop over tags in layer card
274 !---------------------------------------------------------------------------
275 tag_loop: do
276
277 ! Check for end of file
278 !------------------------------------------------------------------------
279 read(unit,'(A)',iostat=stat) buffer
280 if(stat.ne.0)then
281 write(err_msg,'("file encountered error (EoF?) before END ",A)') &
282 to_upper(this%name)
283 call stop_program(err_msg)
284 return
285 end if
286 if(trim(adjustl(buffer)).eq."") cycle tag_loop
287
288 ! Check for end of layer card
289 !------------------------------------------------------------------------
290 if(trim(adjustl(buffer)).eq."END "//to_upper(trim(this%name)))then
291 backspace(unit)
292 exit tag_loop
293 end if
294
295 tag=trim(adjustl(buffer))
296 if(scan(buffer,"=").ne.0) tag=trim(tag(:scan(tag,"=")-1))
297
298 ! Read parameters from save file
299 !------------------------------------------------------------------------
300 select case(trim(tag))
301 case("INPUT_SHAPE")
302 call assign_vec(buffer, input_shape, itmp1)
303 case("POOL_SIZE")
304 call assign_vec(buffer, pool_size, itmp1)
305 case("STRIDE")
306 call assign_vec(buffer, stride, itmp1)
307 case default
308 ! Don't look for "e" due to scientific notation of numbers
309 ! ... i.e. exponent (E+00)
310 if(scan(to_lower(trim(adjustl(buffer))),&
311 'abcdfghijklmnopqrstuvwxyz').eq.0)then
312 cycle tag_loop
313 elseif(tag(:3).eq.'END')then
314 cycle tag_loop
315 end if
316 write(err_msg,'("Unrecognised line in input file: ",A)') &
317 trim(adjustl(buffer))
318 call stop_program(err_msg)
319 return
320 end select
321 end do tag_loop
322
323
324 ! Set hyperparameters and initialise layer
325 !---------------------------------------------------------------------------
326 call this%set_hyperparams(pool_size=pool_size, stride=stride)
327 call this%init(input_shape = input_shape)
328
329
330 ! Check for end of layer card
331 !---------------------------------------------------------------------------
332 read(unit,'(A)') buffer
333 if(trim(adjustl(buffer)).ne."END "//to_upper(trim(this%name)))then
334 write(0,*) trim(adjustl(buffer))
335 write(err_msg,'("END ",A," not where expected")') to_upper(this%name)
336 call stop_program(err_msg)
337 return
338 end if
339
340 end subroutine read_maxpool2d
341 !###############################################################################
342
343
344 !###############################################################################
345 function read_maxpool2d_layer(unit, verbose) result(layer)
346 !! Read 2D max pooling layer from file and return layer
347 implicit none
348
349 ! Arguments
350 integer, intent(in) :: unit
351 !! File unit
352 integer, optional, intent(in) :: verbose
353 !! Verbosity level
354 class(base_layer_type), allocatable :: layer
355 !! Instance of the 2D max pooling layer
356
357 ! Local variables
358 integer :: verbose_ = 0
359 !! Verbosity level
360
361 if(present(verbose)) verbose_ = verbose
362 allocate(layer, source=maxpool2d_layer_type())
363 call layer%read(unit, verbose=verbose_)
364
365 end function read_maxpool2d_layer
366 !###############################################################################
367
368
369 !###############################################################################
370 subroutine build_from_onnx_maxpool2d( &
371 this, node, initialisers, value_info, verbose &
372 )
373 !! Read ONNX attributes for 2D max pooling layer
374 implicit none
375
376 ! Arguments
377 class(maxpool2d_layer_type), intent(inout) :: this
378 !! Instance of the 2D max pooling layer
379 type(onnx_node_type), intent(in) :: node
380 !! ONNX node information
381 type(onnx_initialiser_type), dimension(:), intent(in) :: initialisers
382 !! ONNX initialiser information
383 type(onnx_tensor_type), dimension(:), intent(in) :: value_info
384 !! ONNX value info
385 integer, intent(in) :: verbose
386 !! Verbosity level
387
388 ! Local variables
389 integer :: verbose_ = 0
390 !! Verbosity level
391 integer :: i
392 !! Loop index and temporary integer
393 integer, dimension(2) :: stride, pool_size, padding
394 !! Stride, kernel size, and padding
395 character(256) :: val
396 !! Attribute value
397 character(20) :: padding_method
398 !! Padding method
399
400 ! Set default values
401 padding = 0
402
403 do i = 1, size(node%attributes)
404 val = node%attributes(i)%val
405 select case(trim(adjustl(node%attributes(i)%name)))
406 case("kernel_shape")
407 read(val,*) pool_size
408 case("strides")
409 read(val,*) stride
410 case("pads")
411 read(val,*) padding
412 case default
413 ! Do nothing
414 write(0,*) "WARNING: Unrecognised attribute in ONNX MAXPOOL2D ", &
415 "layer: ", trim(adjustl(node%attributes(i)%name))
416 end select
417 end do
418
419
420 ! Check size of initialisers is zero
421 if(size(initialisers).ne.0)then
422 write(0,*) "WARNING: initialisers not used for ONNX MAXPOOL2D layer"
423 end if
424
425 ! Convert integer padding to character method
426 if(any(padding.gt.0))then
427 padding_method = "constant"
428 else
429 padding_method = "valid"
430 end if
431
432 call this%set_hyperparams( &
433 stride = stride, &
434 pool_size = pool_size, &
435 padding = padding_method &
436 )
437
438 end subroutine build_from_onnx_maxpool2d
439 !###############################################################################
440
441
442 !##############################################################################!
443 ! * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * !
444 !##############################################################################!
445
446
447 !###############################################################################
448 subroutine forward_maxpool2d(this, input)
449 !! Forward propagation
450 implicit none
451
452 ! Arguments
453 class(maxpool2d_layer_type), intent(inout) :: this
454 !! Instance of the 2D max pooling layer
455 class(array_type), dimension(:,:), intent(in) :: input
456 !! Input values
457
458 ! Local variables
459 type(array_type), pointer :: ptr
460 !! Pointer array
461
462
463 call this%output(1,1)%zero_grad()
464 select case(allocated(this%pad_layer))
465 case(.true.)
466 call this%pad_layer%forward(input)
467 ptr => maxpool2d(this%pad_layer%output(1,1), this%pool, this%strd)
468 case default
469 ptr => maxpool2d(input(1,1), this%pool, this%strd)
470 end select
471 call this%output(1,1)%assign_and_deallocate_source(ptr)
472 this%output(1,1)%is_temporary = .false.
473
474 end subroutine forward_maxpool2d
475 !###############################################################################
476
477 end module athena__maxpool2d_layer
478