Coverage for source/model/model_building_blocks/xception_block.py: 100%
25 statements
« prev ^ index » next coverage.py v7.8.0, created at 2025-07-30 20:59 +0000
« prev ^ index » next coverage.py v7.8.0, created at 2025-07-30 20:59 +0000
1# model/model_building_blocks/vgg16_block.py
3# global imports
4import tensorflow as tf
5from tensorflow.keras.layers import Activation, Add, BatchNormalization, Conv2D, MaxPooling2D, SeparableConv2D
7# local imports
9class XceptionBlock:
10 """
11 Class implementing an Xception block compatible with the TensorFlow API. This block implements
12 depthwise separable convolutions followed by max pooling and a residual connection, as seen in
13 the Xception architecture.
15 Diagram:
17 ::
19 Input Tensor --> +-----------------------+ +----------------------+ +--------------------+ +-----+
20 | | SeparableConv2D | | SeparableConv2D | | MaxPooling2D | | Add |
21 | | Filters: N1 |-->| Filters: N2 |-->| Pool Size: K3xK3 |-->| |
22 | | Kernel Size: K1xK1 | | Kernel Size: K2xK2 | | Stride: S1xS1 | | |
23 | +-----------------------+ +----------------------+ +--------------------+ | |
24 | | |
25 +----------> +-----------------------+ | |
26 | Conv2D | | |
27 | Filters: N3 | | |
28 | Kernel Size: K4xK4 |------------------------------------------------------>| |
29 | Stride: S2xS2 | | |
30 | | +-----+ --> Output Tensor
31 +-----------------------+
32 """
34 def __init__(self, kernels: tuple[tuple[int, int], tuple[int, int], tuple[int, int], tuple[int, int]],
35 filters: tuple[int, int, int], steps: tuple[tuple[int, int], tuple[int, int]]) -> None:
36 """
37 Class constructor.
39 Parameters:
40 kernels (tuple[tuple[int, int], tuple[int, int], tuple[int, int], tuple[int, int]]):
41 Sizes of all kernels used within this block.
42 filters (tuple[int, int, int]): Number of filters used in the convolutional layers.
43 steps (tuple[tuple[int, int], tuple[int, int]]): Strides for the max pooling and
44 convolutional layers.
45 """
47 self.__separable_conv_2d_1_kernel_size: tuple[int, int] = kernels[0]
48 self.__separable_conv_2d_2_kernel_size: tuple[int, int] = kernels[1]
49 self.__max_pooling_2d_kernel_size: tuple[int, int] = kernels[2]
50 self.__conv_2d_kernel_size: tuple[int, int] = kernels[3]
51 self.__separable_conv_2d_1_nr_of_filters: int = filters[0]
52 self.__separable_conv_2d_2_nr_of_filters: int = filters[1]
53 self.__conv_2d_nr_of_filters: int = filters[2]
54 self.__max_pooling_2d_step: tuple[int, int] = steps[0]
55 self.__conv_2d_step: tuple[int, int] = steps[1]
57 def __call__(self, input_tensor: tf.Tensor) -> tf.Tensor:
58 """
59 Applies depthwise separable convolutions with max pooling, and a residual connection to
60 the input tensor.
62 Parameters:
63 input_tensor (tf.Tensor): Input tensor to which the transformations should be applied.
65 Returns:
66 tf.Tensor: Output tensor after the transformations have been applied.
67 """
69 # Depthwise separable convolution
70 x_1 = SeparableConv2D(self.__separable_conv_2d_1_nr_of_filters,
71 self.__separable_conv_2d_1_kernel_size,
72 padding = 'same', use_bias = False)(input_tensor)
73 x_1 = BatchNormalization()(x_1)
74 x_1 = Activation('relu')(x_1)
75 x_1 = SeparableConv2D(self.__separable_conv_2d_2_nr_of_filters,
76 self.__separable_conv_2d_2_kernel_size,
77 padding = 'same', use_bias = False)(x_1)
78 x_1 = BatchNormalization()(x_1)
79 x_1 = Activation('relu')(x_1)
80 x_1 = MaxPooling2D(self.__max_pooling_2d_kernel_size, strides=self.__max_pooling_2d_step, padding = 'same')(x_1)
82 # Residual connection
83 x_2 = Conv2D(self.__conv_2d_nr_of_filters, self.__conv_2d_kernel_size, strides = self.__conv_2d_step,
84 padding = 'same', use_bias = False)(input_tensor)
85 x_2 = BatchNormalization()(x_2)
87 output_tensor = Add()([x_1, x_2])
89 return output_tensor