(self)
return self.response
Setup the architecture for a Keras model.
        This function should be called after a model has been initialized with the setup (and optionally set_param_grid) methods.

        The architecture should define the layers, optimization and compilation parameters for a Keras sequential model.

        Since this SSE handles preprocessing the number of features will be inferenced from the training data.
        However, when using 3D or 4D data the input_shape needs to be specified in the first layer. 
        Note that this SSE does not support the keras input_dim argument. Please always use input_shape.

        The request should contain: model name, sort order, layer type, args, kwargs
        With a row for each layer, with a final row for compilation keyword arguments.
        
        Arguments should take the form of a comma separated string with the type of the value specified.
        Use the pipe | character to specify type: 'arg1=value1|str, arg2=value2|int, arg3=value3|bool'

        Sample input expected from the request:
        'DNN', 1, 'Dense', '12|int', 'activation=relu|str'
        'DNN', 2, 'Dropout', '0.25|float', ''
        'DNN', 3, 'Dense', '1|int', 'activation=sigmoid|str'
        'DNN', 4, 'Compilation', '', 'loss=binary_crossentropy|str, optimizer=adam|str, metrics=accuracy|list|str'

        If you want to specify parameters for the optimizer, you can add that as the second last row of the architecture:
        ...
        'DNN', 4, 'SGD', '', 'lr=0.01|float, clipvalue=0.5|float'
        'DNN', 5, 'Compilation', '', 'loss=binary_crossentropy|str, metrics=accuracy|str'     

        Layer wrappers can be used by including them in the layer type followed by a space:
        'DNN', 1, 'TimeDistributed Dense' ...
        ...
        For the Bidirectional wrapper the merge_mode parameter can be specified in the kwargs.  

        When using recurrent or convolutional layers you will need to pass a valid input_shape to reshape the data.
        Additionally, the feature definitions should include an 'identifier' variable that will be used for reshaping.
        E.g. The identifier is a date field and you want to use a LSTM with 10 time steps on a dataset with 20 features.
        'RNN', 1, 'LSTM', '64|int', 'input_shape=10;20|tuple|int, activation=relu|str'
        Note that you can pass None instead of 20 for the features, as the actual number of features will be calculated after 
        preprocessing the data.
Setup the architecture for a Keras model.
        This function should be called after a model has been initialized with the setup (and optionally set_param_grid) methods.
Setup the architecture for a Keras model . This function should be called after a model has been initialized with the setup ( and optionally set_param_grid ) methods .
def keras_setup(self):
        """
        Setup the architecture for a Keras model.
        This function should be called after a model has been initialized with the setup (and optionally set_param_grid) methods.

        The architecture should define the layers, optimization and compilation parameters for a Keras sequential model.

        Since this SSE handles preprocessing the number of features will be inferenced from the training data.
        However, when using 3D or 4D data the input_shape needs to be specified in the first layer. 
        Note that this SSE does not support the keras input_dim argument. Please always use input_shape.

        The request should contain: model name, sort order, layer type, args, kwargs
        With a row for each layer, with a final row for compilation keyword arguments.
        
        Arguments should take the form of a comma separated string with the type of the value specified.
        Use the pipe | character to specify type: 'arg1=value1|str, arg2=value2|int, arg3=value3|bool'

        Sample input expected from the request:
        'DNN', 1, 'Dense', '12|int', 'activation=relu|str'
        'DNN', 2, 'Dropout', '0.25|float', ''
        'DNN', 3, 'Dense', '1|int', 'activation=sigmoid|str'
        'DNN', 4, 'Compilation', '', 'loss=binary_crossentropy|str, optimizer=adam|str, metrics=accuracy|list|str'

        If you want to specify parameters for the optimizer, you can add that as the second last row of the architecture:
        ...
        'DNN', 4, 'SGD', '', 'lr=0.01|float, clipvalue=0.5|float'
        'DNN', 5, 'Compilation', '', 'loss=binary_crossentropy|str, metrics=accuracy|str'     

        Layer wrappers can be used by including them in the layer type followed by a space:
        'DNN', 1, 'TimeDistributed Dense' ...
        ...
        For the Bidirectional wrapper the merge_mode parameter can be specified in the kwargs.  

        When using recurrent or convolutional layers you will need to pass a valid input_shape to reshape the data.
        Additionally, the feature definitions should include an 'identifier' variable that will be used for reshaping.
        E.g. The identifier is a date field and you want to use a LSTM with 10 time steps on a dataset with 20 features.
        'RNN', 1, 'LSTM', '64|int', 'input_shape=10;20|tuple|int, activation=relu|str'
        Note that you can pass None instead of 20 for the features, as the actual number of features will be calculated after 
        preprocessing the data.

        """

        # Interpret the request data based on the expected row and column structure
        row_template = ['strData', 'numData', 'strData', 'strData', 'strData']
        col_headers = ['model_name', 'sort_order', 'layer_type', 'args', 'kwargs']
                
        # Create a Pandas Data Frame for the request data
        self.request_df = utils.request_df(self.request, row_template, col_headers)
               
        # Create a model that can be persisted to disk
        self.model = PersistentModel()
        
        # Get the model name from the request dataframe
        self.model.name = self.request_df.loc[0, 'model_name']
        
        # Get the model from cache or disk
        self._get_model()
        
        # Debug information is printed to the terminal and logs if the paramater debug = true
        if self.model.debug:
            self._print_log(3)

        # Set a flag which will let us know that this is a Keras model
        self.model.using_keras = True

        # Sort the layers, drop unnecessart columns and save the model architecture to a new data frame
        architecture = self.request_df.sort_values(by=['sort_order']).reset_index(drop=True).drop(labels=['model_name', 'sort_order'], axis = 1)

        # Convert args to a list and kwargs to a dictionary
        architecture['args'] = architecture['args'].apply(utils.get_args_by_type)
        architecture['kwargs'] = architecture['kwargs'].apply(utils.get_kwargs).apply(utils.get_kwargs_by_type) 

        # Add the architecture to the model
        self.model.architecture = architecture

        # Add the first layer's kwargs as a property for easy reference
        self.model.first_layer_kwargs = self.model.architecture.iloc[0, 2]

        # Debug information is printed to the terminal and logs if the paramater debug = true
        if self.model.debug:
            self._print_log(10)

        # Persist the model to disk
        self.model = self.model.save(self.model.name, self.path, overwrite=self.model.overwrite, compress=self.model.compress)
        
        # Update the cache to keep this model in memory
        self._update_cache()
              
        # Prepare the output
        message = [[self.model.name, 'Keras model architecture saved to disk',\
                    time.strftime('%X %x %Z', time.localtime(self.model.state_timestamp))]]
        self.response = pd.DataFrame(message, columns=['model_name', 'result', 'time_stamp'])
        
        # Send the reponse table description to Qlik
        self._send_table_description("setup")
        
        # Debug information is printed to the terminal and logs if the paramater debug = true
        if self.model.debug:
            self._print_log(4)
        
        # Finally send the response
        return self.response
def keras_setup ( self ) : # Interpret the request data based on the expected row and column structure row_template = [ 'strData' , 'numData' , 'strData' , 'strData' , 'strData' ] col_headers = [ 'model_name' , 'sort_order' , 'layer_type' , 'args' , 'kwargs' ] # Create a Pandas Data Frame for the request data self . request_df = utils . request_df ( self . request , row_template , col_headers ) # Create a model that can be persisted to disk self . model = PersistentModel ( ) # Get the model name from the request dataframe self . model . name = self . request_df . loc [ 0 , 'model_name' ] # Get the model from cache or disk self . _get_model ( ) # Debug information is printed to the terminal and logs if the paramater debug = true if self . model . debug : self . _print_log ( 3 ) # Set a flag which will let us know that this is a Keras model self . model . using_keras = True # Sort the layers, drop unnecessart columns and save the model architecture to a new data frame architecture = self . request_df . sort_values ( by = [ 'sort_order' ] ) . reset_index ( drop = True ) . drop ( labels = [ 'model_name' , 'sort_order' ] , axis = 1 ) # Convert args to a list and kwargs to a dictionary architecture [ 'args' ] = architecture [ 'args' ] . apply ( utils . get_args_by_type ) architecture [ 'kwargs' ] = architecture [ 'kwargs' ] . apply ( utils . get_kwargs ) . apply ( utils . get_kwargs_by_type ) # Add the architecture to the model self . model . architecture = architecture # Add the first layer's kwargs as a property for easy reference self . model . first_layer_kwargs = self . model . architecture . iloc [ 0 , 2 ] # Debug information is printed to the terminal and logs if the paramater debug = true if self . model . debug : self . _print_log ( 10 ) # Persist the model to disk self . model = self . model . save ( self . model . name , self . path , overwrite = self . model . overwrite , compress = self . model . compress ) # Update the cache to keep this model in memory self . _update_cache ( ) # Prepare the output message = [ [ self . model . name , 'Keras model architecture saved to disk' , time . strftime ( '%X %x %Z' , time . localtime ( self . model . state_timestamp ) ) ] ] self . response = pd . DataFrame ( message , columns = [ 'model_name' , 'result' , 'time_stamp' ] ) # Send the reponse table description to Qlik self . _send_table_description ( "setup" ) # Debug information is printed to the terminal and logs if the paramater debug = true if self . model . debug : self . _print_log ( 4 ) # Finally send the response return self . response