GCC Code Coverage Report


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