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-23 15:55 +0000
« prev ^ index » next coverage.py v7.8.0, created at 2025-08-23 15:55 +0000
1# model/model_blue_prints/vggception_cnn_blue_print.py
3# global imports
4import math
5from tensorflow.keras import layers, Model
6from typing import Optional
8# local imports
9from source.model import BluePrintBase, ModelAdapterBase, TFModelAdapter, \
10 Vgg16Block, XceptionBlock
12class VGGceptionCnnBluePrint(BluePrintBase):
13 """
14 Blueprint for creating a hybrid CNN architecture combining VGG and Xception patterns.
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 """
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.
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 """
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)]
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.
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
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
74 Returns:
75 Model: Keras model implementing the hybrid VGG-Xception architecture to be compiled further.
76 """
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
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)]
95 spatial_data_rows, spatial_data_cols = spatial_data_shape
96 spatial_data_length = spatial_data_rows * spatial_data_cols
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)
104 cnn_part = Vgg16Block(self.__vgg16_kernels,
105 [number_of_filters, number_of_filters])(reshaped_spatial_part)
106 cnn_part = layers.BatchNormalization()(cnn_part)
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)
116 flatten_cnn_part = layers.Flatten()(cnn_part)
117 concatenated_parts = layers.Concatenate()([flatten_cnn_part, non_spatial_part])
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)
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
137 output = layers.Dense(output_length, activation='softmax')(dense)
139 return TFModelAdapter(Model(inputs = input_vector, outputs = output))