From 259e00b37f6995e2ba35d0103dbe472428d11668 Mon Sep 17 00:00:00 2001 From: leufen1 <l.leufen@fz-juelich.de> Date: Wed, 2 Mar 2022 15:04:35 +0100 Subject: [PATCH] new class CNNfromConfig to be able to configure CNN in much more detail --- mlair/model_modules/convolutional_networks.py | 118 ++++++++++++++++++ 1 file changed, 118 insertions(+) diff --git a/mlair/model_modules/convolutional_networks.py b/mlair/model_modules/convolutional_networks.py index a9621af4..8efe71a9 100644 --- a/mlair/model_modules/convolutional_networks.py +++ b/mlair/model_modules/convolutional_networks.py @@ -11,6 +11,124 @@ from mlair.model_modules.advanced_paddings import PadUtils, Padding2D, Symmetric import tensorflow.keras as keras +class CNNfromConfig(AbstractModelClass): + _activation = {"relu": keras.layers.ReLU, "tanh": partial(keras.layers.Activation, "tanh"), + "sigmoid": partial(keras.layers.Activation, "sigmoid"), + "linear": partial(keras.layers.Activation, "linear"), + "prelu": partial(keras.layers.PReLU, alpha_initializer=keras.initializers.constant(value=0.25)), + "leakyrelu": partial(keras.layers.LeakyReLU)} + _initializer = {"tanh": "glorot_uniform", "sigmoid": "glorot_uniform", "linear": "glorot_uniform", + "relu": keras.initializers.he_normal(), "selu": keras.initializers.lecun_normal(), + "prelu": keras.initializers.he_normal()} + _optimizer = {"adam": keras.optimizers.Adam, "sgd": keras.optimizers.SGD} + _regularizer = {"l1": keras.regularizers.l1, "l2": keras.regularizers.l2, "l1_l2": keras.regularizers.l1_l2} + _requirements = ["lr", "beta_1", "beta_2", "epsilon", "decay", "amsgrad", "momentum", "nesterov", "l1", "l2"] + + """ + Use this class like the following. Note that all keys must match the corresponding tf/keras keys of the layer + + ```python + input_shape = [(65,1,9)] + output_shape = [(4, )] + layer_configuration=[ + {"type": "Conv2D", "activation": "relu", "kernel_size": (1, 1), "filters": 8}, + {"type": "Dropout", "rate": 0.2}, + {"type": "Conv2D", "activation": "relu", "kernel_size": (5, 1), "filters": 16}, + {"type": "Dropout", "rate": 0.2}, + {"type": "MaxPooling2D", "pool_size": (8, 1), "strides": (1, 1)}, + {"type": "Conv2D", "activation": "relu", "kernel_size": (1, 1), "filters": 16}, + {"type": "Dropout", "rate": 0.2}, + {"type": "Conv2D", "activation": "relu", "kernel_size": (5, 1), "filters": 32}, + {"type": "Dropout", "rate": 0.2}, + {"type": "MaxPooling2D", "pool_size": (8, 1), "strides": (1, 1)}, + {"type": "Conv2D", "activation": "relu", "kernel_size": (1, 1), "filters": 32}, + {"type": "Dropout", "rate": 0.2}, + {"type": "Conv2D", "activation": "relu", "kernel_size": (5, 1), "filters": 64}, + {"type": "Dropout", "rate": 0.2}, + {"type": "MaxPooling2D", "pool_size": (8, 1), "strides": (1, 1)}, + {"type": "Conv2D", "activation": "relu", "kernel_size": (1, 1), "filters": 64}, + {"type": "Dropout", "rate": 0.2}, + {"type": "Flatten"}, + # {"type": "Dense", "units": 128, "activation": "relu"} + ] + model = CNNfromConfig(input_shape, output_shape, layer_configuration) + ``` + + """ + + def __init__(self, input_shape: list, output_shape: list, layer_configuration: list, **kwargs): + + assert len(input_shape) == 1 + assert len(output_shape) == 1 + super().__init__(input_shape[0], output_shape[0]) + + self.conf = layer_configuration + activation_output = kwargs.pop("activation_output", "linear") + self.activation_output = self._activation.get(activation_output) + self.activation_output_name = activation_output + self.kwargs = kwargs + + # apply to model + + self.set_model() + self.set_compile_options() + self.set_custom_objects(loss=custom_loss([keras.losses.mean_squared_error, var_loss]), var_loss=var_loss) + + def set_model(self): + x_input = keras.layers.Input(shape=self._input_shape) + x_in = x_input + + for layer_opts in self.conf: + print(layer_opts) + layer, layer_kwargs, follow_up_layer = self._extract_layer_conf(layer_opts) + x_in = layer(**layer_kwargs)(x_in) + if follow_up_layer is not None: + x_in = follow_up_layer()(x_in) + + x_in = keras.layers.Dense(self._output_shape)(x_in) + out = self.activation_output(name=f"{self.activation_output_name}_output")(x_in) + self.model = keras.Model(inputs=x_input, outputs=[out]) + print(self.model.summary()) + + def _set_regularizer(self, regularizer, **kwargs): + if regularizer is None or (isinstance(regularizer, str) and regularizer.lower() == "none"): + return None + try: + reg_name = regularizer.lower() + reg = self._regularizer.get(reg_name) + reg_kwargs = {} + if reg_name in ["l1", "l2"]: + reg_kwargs = select_from_dict(kwargs, reg_name, remove_none=True) + if reg_name in reg_kwargs: + reg_kwargs["l"] = reg_kwargs.pop(reg_name) + elif reg_name == "l1_l2": + reg_kwargs = select_from_dict(kwargs, ["l1", "l2"], remove_none=True) + return reg(**reg_kwargs) + except KeyError: + raise AttributeError(f"Given regularizer {regularizer} is not supported in this model class.") + + def set_compile_options(self): + # self.compile_options = {"loss": [custom_loss([keras.losses.mean_squared_error, var_loss])], + # "metrics": ["mse", "mae", var_loss]} + self.compile_options = {"loss": [keras.losses.mean_squared_error], + "metrics": ["mse", "mae", var_loss]} + + def _extract_layer_conf(self, layer_opts): + follow_up_layer = None + layer_type = layer_opts.pop("type") + layer = getattr(keras.layers, layer_type, None) + activation_type = layer_opts.pop("activation", None) + if activation_type is not None: + activation = self._activation.get(activation_type) + kernel_initializer = self._initializer.get(activation_type, "glorot_uniform") + layer_opts["kernel_initializer"] = kernel_initializer + follow_up_layer = activation + regularizer_type = layer_opts.pop("kernel_regularizer", None) + if regularizer_type is not None: + layer_opts["kernel_regularizer"] = self._set_regularizer(regularizer_type, **self.kwargs) + return layer, layer_opts, follow_up_layer + + class CNN(AbstractModelClass): # pragma: no cover _activation = {"relu": keras.layers.ReLU, "tanh": partial(keras.layers.Activation, "tanh"), -- GitLab