from abc import ABC
from abc import abstractmethod
from typing import Union
import numpy as np
import tensorflow
from tensorflow.keras import Input
from tensorflow.keras.backend import int_shape
from tensorflow.keras.layers import Activation
from tensorflow.keras.layers import Dense
from tensorflow.keras.layers import Dropout
[docs]class NetworkArchitecture(ABC):
def __init__(
self,
input_shapes: dict,
output_info: dict,
input_data_type="float32",
output_data_type="float32",
model_config: dict = {},
):
self.input_data_type = input_data_type
self.output_data_type = output_data_type
self.input_shapes = input_shapes
self.output_info = output_info
self.model_config = model_config
# self.inputs = self.make_inputs(input_shapes, input_data_type)
# self.outputs = self.make_outputs(output_info, output_data_type)
[docs] @staticmethod
def get_corrected_stride_size(
layer: tensorflow.keras.layers, stride_size: list, conv_size: list
):
"""
Ensure that the stride is never bigger than the actual input
In this way any network can keep working, indepedent of size
"""
input_shape = int_shape(layer)[1:-1]
stride_size = np.asarray(stride_size)
conv_size = np.asarray(conv_size)
stride_total_size = stride_size * conv_size
stride_size = np.floor(np.minimum(input_shape, stride_total_size) / conv_size)
# Ensure that stride_size is at least one
stride_size = np.maximum(stride_size, np.ones(len(stride_size)))
stride_size = stride_size.astype(np.int).tolist()
return stride_size
[docs] def make_dropout_layer(self, layer):
if "dropout" in self.model_config and self.model_config["dropout"] > 0:
out_layer = Dropout(self.model_config["dropout"])(layer)
else:
out_layer = layer
return out_layer
[docs] @abstractmethod
def make_outputs(self, output_info: dict, output_data_type: str) -> tensorflow.keras.layers:
"""Make the outputs"""
[docs] @abstractmethod
def create_model(self):
"""Here the code to create the actual model"""
[docs]class ClassificationNetworkArchitecture(NetworkArchitecture):
def __init__(
self,
input_shapes: dict,
output_info: dict,
input_data_type="float32",
output_data_type="float32",
model_config={},
):
super().__init__(input_shapes, output_info, input_data_type, output_data_type, model_config)
self.inputs = self.make_inputs(input_shapes, input_data_type)
self.outputs = self.make_outputs(output_info, output_data_type)
[docs] @staticmethod
def make_outputs(
output_info: dict,
output_data_type: str,
activation_type: str = "softmax",
squeeze_outputs: bool = True,
) -> dict:
outputs = {}
for i_output_name, i_output_classes in output_info.items():
outputs[i_output_name] = Dense(
i_output_classes, name=i_output_name, activation=activation_type, dtype="float32",
)
if squeeze_outputs and len(outputs) == 1:
outputs = list(outputs.values())[0]
return outputs