Coverage for source/model/model_blue_prints/vggception_cnn_blue_print.py: 95%

63 statements  

« prev     ^ index     » next       coverage.py v7.8.0, created at 2025-08-25 21:18 +0000

1# model/model_blue_prints/vggception_cnn_blue_print.py 

2 

3# global imports 

4import math 

5from tensorflow.keras import layers, Model 

6from typing import Optional 

7 

8# local imports 

9from source.model import BluePrintBase, ModelAdapterBase, TFModelAdapter, \ 

10 Vgg16Block, XceptionBlock 

11 

12class VGGceptionCnnBluePrint(BluePrintBase): 

13 """ 

14 Blueprint for creating a hybrid CNN architecture combining VGG and Xception patterns. 

15 

16 This class implements a model blueprint that constructs a neural network with a 

17 combined architecture inspired by VGG16 and Xception networks. It's designed to 

18 process both spatial and non-spatial features by separating the input vector 

19 and processing them through different network components before combining them. 

20 """ 

21 

22 def __init__(self, number_of_filters: int = 32, cnn_squeezing_coeff: int = 2, 

23 dense_squeezing_coeff: int = 2, dense_repetition_coeff: int = 1, 

24 filters_number_coeff: int = 2, should_apply_2d_convolution: bool = True) -> None: 

25 """ 

26 Initializes the VGGceptionCnnBluePrint with the specified configuration parameters. 

27 

28 Parameters: 

29 number_of_filters (int): Initial number of convolutional filters. 

30 cnn_squeezing_coeff (int): Factor by which CNN dimensions are reduced. 

31 dense_squeezing_coeff (int): Factor by which dense layer sizes are reduced. 

32 dense_repetition_coeff (int): Number of dense layers of the same size to use. 

33 filters_number_coeff (int): Factor by which filter count increases in convolutional layers. 

34 should_apply_2d_convolution (bool): Whether to apply 2D convolution in the CNN blocks. 

35 """ 

36 

37 self.__number_of_filters = number_of_filters 

38 self.__cnn_squeezing_coeff = cnn_squeezing_coeff 

39 self.__dense_squeezing_coeff = dense_squeezing_coeff 

40 self.__dense_repetition_coeff = dense_repetition_coeff 

41 self.__filters_number_coeff = filters_number_coeff 

42 self.__should_apply_2d_convolution = should_apply_2d_convolution 

43 if should_apply_2d_convolution: 

44 self.__vgg16_kernels = [(3, 3), (3, 3), (2, 2)] 

45 self.__xception_kernels = [(3, 3), (3, 3), (3, 3), (1, 1)] 

46 else: 

47 self.__vgg16_kernels = [(3, 1), (3, 1), (2, 1)] 

48 self.__xception_kernels = [(3, 1), (3, 1), (3, 1), (1, 1)] 

49 

50 def instantiate_model(self, input_shape: tuple[int, int], output_length: int, spatial_data_shape: tuple[int, int], 

51 number_of_filters: Optional[int] = None, cnn_squeezing_coeff: Optional[int] = None, 

52 dense_squeezing_coeff: Optional[int] = None, dense_repetition_coeff: Optional[int] = None, 

53 filters_number_coeff: Optional[int] = None) -> ModelAdapterBase: 

54 """ 

55 Creates and returns a hybrid VGG-Xception CNN model according to specified parameters. 

56 

57 The method constructs a neural network that: 

58 1. Separates the input into spatial and non-spatial components 

59 2. Processes the spatial data through VGG16 and Xception blocks 

60 3. Flattens the CNN output and concatenates with non-spatial features 

61 4. Passes the combined features through a series of dense layers 

62 5. Produces a softmax output for classification 

63 

64 Parameters: 

65 input_shape (tuple[int, int]): Shape of the input tensor 

66 output_length (int): Number of output classes/actions 

67 spatial_data_shape (tuple[int, int]): Rows and columns to reshape spatial data 

68 number_of_filters (int): Initial number of convolutional filters 

69 cnn_squeezing_coeff (int): Factor by which CNN dimensions are reduced 

70 dense_squeezing_coeff (int): Factor by which dense layer sizes are reduced 

71 dense_repetition_coeff (int): Number of dense layers of the same size to use 

72 filters_number_coeff (int): Factor by which filter count increases in convolutional layers 

73 

74 Returns: 

75 Model: Keras model implementing the hybrid VGG-Xception architecture to be compiled further. 

76 """ 

77 

78 if number_of_filters is None: 

79 number_of_filters = self.__number_of_filters 

80 if cnn_squeezing_coeff is None: 

81 cnn_squeezing_coeff = self.__cnn_squeezing_coeff 

82 if dense_squeezing_coeff is None: 

83 dense_squeezing_coeff = self.__dense_squeezing_coeff 

84 if dense_repetition_coeff is None: 

85 dense_repetition_coeff = self.__dense_repetition_coeff 

86 if filters_number_coeff is None: 

87 filters_number_coeff = self.__filters_number_coeff 

88 

89 if self.__should_apply_2d_convolution: 

90 xception_steps = [(cnn_squeezing_coeff, cnn_squeezing_coeff), 

91 (cnn_squeezing_coeff, cnn_squeezing_coeff)] 

92 else: 

93 xception_steps = [(cnn_squeezing_coeff, 1), (cnn_squeezing_coeff, 1)] 

94 

95 spatial_data_rows, spatial_data_cols = spatial_data_shape 

96 spatial_data_length = spatial_data_rows * spatial_data_cols 

97 

98 input_vector = layers.Input((1, input_shape[0])) 

99 reshaped_input_vector = layers.Reshape((input_shape[0],))(input_vector) 

100 spatial_part = layers.Lambda(lambda x: x[:, :spatial_data_length])(reshaped_input_vector) 

101 non_spatial_part = layers.Lambda(lambda x: x[:, spatial_data_length:])(reshaped_input_vector) 

102 reshaped_spatial_part = layers.Reshape((spatial_data_rows, spatial_data_cols, 1))(spatial_part) 

103 

104 cnn_part = Vgg16Block(self.__vgg16_kernels, 

105 [number_of_filters, number_of_filters])(reshaped_spatial_part) 

106 cnn_part = layers.BatchNormalization()(cnn_part) 

107 

108 nr_of_xceptions_blocks = int(math.ceil(math.log(spatial_data_rows // 2, cnn_squeezing_coeff))) 

109 for _ in range(nr_of_xceptions_blocks): 

110 number_of_filters *= filters_number_coeff 

111 cnn_part = XceptionBlock(self.__xception_kernels, 

112 [number_of_filters, number_of_filters, number_of_filters], 

113 xception_steps)(cnn_part) 

114 cnn_part = layers.BatchNormalization()(cnn_part) 

115 

116 flatten_cnn_part = layers.Flatten()(cnn_part) 

117 concatenated_parts = layers.Concatenate()([flatten_cnn_part, non_spatial_part]) 

118 

119 closest_smaller_power_of_coeff = int(math.pow(dense_squeezing_coeff, 

120 int(math.log(concatenated_parts.shape[-1], 

121 dense_squeezing_coeff)))) 

122 dense = layers.Dense(closest_smaller_power_of_coeff, activation = 'relu')(concatenated_parts) 

123 dense = layers.BatchNormalization()(dense) 

124 

125 number_of_nodes = closest_smaller_power_of_coeff // dense_squeezing_coeff 

126 nr_of_dense_layers = int(math.log(closest_smaller_power_of_coeff, dense_squeezing_coeff)) 

127 for _ in range(nr_of_dense_layers): 

128 for _ in range(dense_repetition_coeff): 

129 dense = layers.Dense(number_of_nodes, activation = 'relu')(dense) 

130 dense = layers.BatchNormalization()(dense) 

131 number_of_nodes //= dense_squeezing_coeff 

132 if int(math.log(number_of_nodes, 10)) == int(math.log(output_length, 10)) + 1: 

133 dense = layers.Dropout(0.3)(dense) 

134 elif int(math.log(number_of_nodes, 10)) == int(math.log(output_length, 10)): 

135 break 

136 

137 output = layers.Dense(output_length, activation = 'softmax')(dense) 

138 

139 return TFModelAdapter(Model(inputs = input_vector, outputs = output))