Tutorial: converting a NeurEco Regression model to a Keras model#

NeurEco Tabular offers the user the possibility to convert a model to a keras model to be used with TensorFlow.

Note

  • This feature is only available for the python API.

  • This feature requires an existing installation of TensorFlow 2.x and keras.

he following section will use the test case Energy consumption. This test case is delivered with the NeurEco installation package.

The first step will be to load the data and build a model:

import numpy as np
from NeurEco import NeurEcoTabular as Tabular

''' Load the training data '''
 print("Loading the training data".center(60, "*"))
 x_train = np.genfromtxt("x_train.csv", delimiter=";", skip_header=True)
 y_train = np.genfromtxt("y_train.csv", delimiter=";", skip_header=True)
 y_train = np.reshape(y_train, (-1, 1))
 ''' create a NeurEco Object to build the model'''
 print("Creating the NeurEco builder".center(60, "*"))
 builder = Tabular.Regressor()

 ''' Building the NeurEco Model '''
 builder.build(input_data=x_train, output_data=y_train,
               # the rest of these parameters are optional
               write_model_to="./EnergyConsumptionModel/EnergyConsumption.ednn",
               checkpoint_address="./EnergyConsumptionModel/EnergyConsumption.checkpoint",
               valid_percentage=33.33,
               inputs_shifting="min_centered",
               inputs_scaling="max_centered")

 ''' Delete the builder from memory'''
 print("Deleting the NeurEco builder".center(60, "*"))
 builder.delete()

Once the build is done, and the model is saved, let’s convert it to a keras model. To do so, we first need to import the proper library:

from NeurEco import NeurEco2Keras

Once that’s done, we will convert the ednn model to a keras model, and we will print out its summary:

neureco_model_path = "./EnergyConsumptionModel/EnergyConsumption.ednn"
keras_model = NeurEco2Keras.neureco2keras(neureco_model_path)
keras_model.summary()
Model: "EnergyConsumption_NeurEco_Keras_Model"
_________________________________________________________________
Layer (type)                 Output Shape              Param #
=================================================================
input (InputLayer)           [(None, 5)]               0
_________________________________________________________________
tf_op_layer_centeredInputs ( [(None, 5)]               0
_________________________________________________________________
tf_op_layer_normalizedInputs [(None, 5)]               0
_________________________________________________________________
adagos_gemm (AdagosGemm)     (None, 8)                 48
_________________________________________________________________
tf_op_layer_x1TensorActivati [(None, 8)]               0
_________________________________________________________________
adagos_gemm_1 (AdagosGemm)   (None, 1)                 9
_________________________________________________________________
tf_op_layer_outputDescaled ( [(None, 1)]               0
_________________________________________________________________
tf_op_layer_output (TensorFl [(None, 1)]               0
=================================================================
Total params: 57
Trainable params: 57
Non-trainable params: 0
_________________________________________________________________

Note

The number of links (NeurEco model) is slightly different than the number of trainable parameters (keras model). This is because the keras models are naturally fully connected, and some of the weights are present in the keras model although they are not needed (they have a value of 0).

At this stage, we can evaluate the two models (NeurEco and Keras), and see the difference between them:

x_test = np.genfromtxt("x_test.csv", delimiter=";")[1:, :]

''' evaluate the model using neureco '''
neureco_model = Tabular.Regressor()
neureco_model.load(neureco_model_path)
neureco_output = neureco_model.evaluate(x_test)

''' evaluate the model using keras '''
keras_output = keras_model.predict(x_test.astype("float32"))

''' compare the models results '''
error = np.linalg.norm(keras_output - neureco_output) / np.linalg.norm(neureco_output)
print("Error between the models:", error)
Error between the models: 1.6618171240269623e-07

The keras model can be saved and restored for later use. For example, we can save it as a h5 model to the disk:

import tensorflow as tf
keras_model.save("./EnergyConsumptionModel/EnergyConsumption.h5")

We can now reload it from the disk. However, a custom class is needed to perform the load. This class is called AdagosGemm and is in the library NeurEco2Keras. To load the model simply run:

import tensorflow as tf
reloaded_keras_model = tf.keras.models.load_model("./EnergyConsumptionModel/EnergyConsumption.h5",
                                                  custom_objects={'AdagosGemm': NeurEco2Keras.AdagosGemm})

If the user doesn’t have the possibility to import NeurEco2keras in its production environment, simply copy and paste the following class:

class AdagosGemm(tf.keras.layers.Layer):
   def __init__(self, w_init, b_init, alpha, beta, w_name, b_name, comp=False, name=None, **kwargs):
        super(AdagosGemm, self).__init__(name=name)
        self.trainable = not comp
        self.w_init = w_init
        self.b_init = b_init
        self.alpha = alpha
        self.beta = beta
        self.w_name = w_name
        self.b_name = b_name
        self.w = None
        self.b = None

   def get_config(self):
        config = super().get_config()
        config.update({"trainable": self.trainable,
                       "w_init": self.w_init,
                       "b_init": self.b_init,
                       "alpha": self.alpha,
                       "beta": self.beta,
                       "w_name": self.w_name,
                       "b_name": self.b_name,
                       "w": self.w.numpy(),
                       "b": self.b.numpy()})
        return config

   def build(self, input_shape):
        self.w = self.add_weight(shape=self.w_init,
                                 name=self.w_name, trainable=self.trainable)
        self.b = self.add_weight(shape=self.b_init,
                                 name=self.b_name, trainable=self.trainable)
        self.built = True

   def call(self, a):
        return self.alpha * tf.matmul(a, self.w) + self.beta * self.b

To load the model in this case, we will change the custom object to this class:

import tensorflow as tf
reloaded_keras_model = tf.keras.models.load_model("./EnergyConsumptionModel/EnergyConsumption.h5",
                                                  custom_objects={'AdagosGemm': AdagosGemm})

We can evaluate the reloaded model on the testing data, and compare it to the neureco_outputs obtained previously:

''' evaluate the model using keras '''
reloaded_keras_output = reloaded_keras_model.predict(x_test.astype("float32"))

''' compare the models results '''
error = np.linalg.norm(reloaded_keras_output - neureco_output) / np.linalg.norm(neureco_output)
print("Error between the models (NeurEco and reloaded):", error)
Error between the models (NeurEco and reloaded): 1.6618171240269623e-07