GCC Code Coverage Report


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