Coverage for source/model/model_building_blocks/xception_block.py: 100%

25 statements  

« prev     ^ index     » next       coverage.py v7.8.0, created at 2025-08-01 20:51 +0000

1# model/model_building_blocks/vgg16_block.py 

2 

3# global imports 

4import tensorflow as tf 

5from tensorflow.keras.layers import Activation, Add, BatchNormalization, Conv2D, MaxPooling2D, SeparableConv2D 

6 

7# local imports 

8 

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. 

14 

15 Diagram: 

16 

17 :: 

18 

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 """ 

33 

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. 

38 

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 """ 

46 

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] 

56 

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. 

61 

62 Parameters: 

63 input_tensor (tf.Tensor): Input tensor to which the transformations should be applied. 

64 

65 Returns: 

66 tf.Tensor: Output tensor after the transformations have been applied. 

67 """ 

68 

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) 

81 

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) 

86 

87 output_tensor = Add()([x_1, x_2]) 

88 

89 return output_tensor