Using Lime for a LSTM

200 views Asked by At

Hey Stackoverflow Community,

I am trying to apply the XAI-Tool Lime on my LSTM-Model. I am doing a forecasting task in the energy sector. The data is a CSV-file, therefore I had to change the shape of the data from a 2d table to a 3d, so I can use it for the LSTM-Model. So I try to clean up the data a little bit, deleting some variables which are most of the time "nan", to get a better performence.

The Model is working fine, the loss isn't the best, but I didn't tune any hyperparameters yet - so this is all good.

import os
import random
import pandas as pd
from pandas import DataFrame
from pandas import concat
import numpy as np
import tensorflow as tf 
import matplotlib.pyplot as pyplot
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error
from sklearn.metrics import make_scorer
from sklearn.model_selection import RandomizedSearchCV
from keras.wrappers.scikit_learn import KerasRegressor
from keras.models import Sequential
from keras.layers import Dense, Dropout
from keras.layers import LSTM
import warnings

warnings.filterwarnings("ignore")


f = open(os.path.expanduser("/Users/x/Turbine_Data.csv"))
df = pd.read_csv(f)

df.rename(columns={'Unnamed: 0': "Index"}, inplace=True)
df = df.set_index("Index")

df = df.drop(["WTG","Blade1PitchAngle","Blade2PitchAngle","Blade3PitchAngle","ControlBoxTemperature"], axis = 1)
df = df.dropna(subset=["WindSpeed"])
threshold = 3
df = df.dropna(thresh=df.shape[1] - threshold)
df = df.interpolate(method='linear', limit_direction='forward', axis=0)
nan_counts = df.isna().sum()

#print(nan_counts)
print(df.head(3))

def series_to_supervised(data, n_in=1, n_out=1, dropnan=True):
 n_vars = 1 if type(data) is list else data.shape[1]
 df = DataFrame(data)
 cols, names = list(), list()
 for i in range(n_in, 0, -1):
     cols.append(df.shift(i))
     names += [('var%d(t-%d)' % (j+1, i)) for j in range(n_vars)]
 for i in range(0, n_out):
     cols.append(df.shift(-i))
     if i == 0:
         names += [('var%d(t)' % (j+1)) for j in range(n_vars)]
     else:
         names += [('var%d(t+%d)' % (j+1, i)) for j in range(n_vars)]
 agg = concat(cols, axis=1)
 agg.columns = names
 if dropnan:
     agg.dropna(inplace=True)
 return agg
 
values = df.values
values = values.astype('float32')
df = series_to_supervised(values, 1, 1)
df.drop(df.columns[[17,18,19,20,21,22,23,24,25,26,27,28,29,30,31]], axis=1, inplace=True)

#print(df.head())

df = df.values
inputs, outputs = df[:, :-1], df[:, -1]
inputs_train, inputs_val, outputs_train, outputs_val = train_test_split(inputs,outputs,test_size=.2,random_state=42)
inputs_train = inputs_train.reshape((inputs_train.shape[0], 1, inputs_train.shape[1]))
inputs_val = inputs_val.reshape((inputs_val.shape[0], 1, inputs_val.shape[1]))
print(inputs_train.shape, outputs_train.shape, inputs_val.shape, outputs_val.shape)

def custom_scorer(estimator, X, y):
    predictions = estimator.predict(X)
    mse = mean_squared_error(y, predictions)
    return -mse

def create_lstm_model(units=150, learning_rate=0.001, batch_size=16, epochs=70):
    model = Sequential()
    model.add(LSTM(units, input_shape=(inputs_train.shape[1], inputs_train.shape[2]), return_sequences=True))
    model.add(Dropout(0.2))
    model.add(LSTM(50))
    model.add(Dropout(0.2))
    model.add(Dense(1))
    optimizer = tf.keras.optimizers.Adam(learning_rate=0.001)
    model.compile(loss='mae', optimizer=optimizer)
    return model

param_grid = {
    'units': [100, 150],
    'learning_rate': [0.0005, 0.001, 0.01],
    'batch_size': [16, 64, 96, 128],
    'epochs': [50, 60, 70, 80, 90, 100]
}

model = KerasRegressor(build_fn=create_lstm_model, verbose=0)

#RANDOM SEARCH FOR FINDING BEST HYPERPARAMETERS
#random_search = RandomizedSearchCV(estimator=keras_regressor, param_distributions=param_grid, n_iter=100, cv=2, scoring=make_scorer(custom_scorer), verbose=2, random_state=42)
#random_search.fit(inputs_train, outputs_train)
#print(random_search.best_params_)

#model = random_search.best_estimator_
m = model.fit(inputs_train, outputs_train, epochs=60, batch_size=16, validation_data=(inputs_val, outputs_val), verbose=2, shuffle=False)


pyplot.plot(m.history['loss'], label='train')
pyplot.plot(m.history['val_loss'], label='test')
pyplot.legend()
pyplot.show()

Coming to my problem. I used Lime before to explain Regression Task, which worked fine. But I did not managed to apply LIME on the LSTM.

I might know, where the problem is. LSTM is using a 3D array, in my case e.g. (49285, 1, 16) for the input_train data. But LIME does expect a 2D array. I already tried to reshape my data, nothing works fine. The Doc of Lime did not help me out at all and I did not find any good example how to use LIME on a LSTM.

I tried this:

from lime.lime_tabular import LimeTabularExplainer
explainer = LimeTabularExplainer(training_data=inputs_train, mode="regression")

instance_idx = 0

input_instance = inputs_val[instance_idx].reshape((1, inputs_val.shape[1]))
predictions = model.predict(input_instance)
explanation = explainer.explain_instance(input_instance[0], model.predict)
explanation.show_in_notebook()

Do you have any idea how to get LIME working ? And you have any idea what's the major problem is? I am fully self taught, therefore some parts of my code might be a little filthy. I would be very grateful for tips and suggestions.

Thanks

Leo

0

There are 0 answers