Reputation: 8996
I have a sequence I am trying to classify, using a Keras LSTM with return_sequences=True. I have 'data' and 'labels' datasets both of which are the same shape - 2D matrices with rows by location and columns by time interval (cell values are my 'signal' feature). So an RNN w/ return_sequences=True seems like an intuitive approach.
After reshaping my data (X)
and labels (Y)
to 3D tensors of shape (rows, cols, 1)
, I call model.fit(X, Y)
but get the following error:
ValueError('Invalid shape for y')
It points me to the code for class KerasClassifier()'s fit method which checks that len(y.shape)==2
.
Ok so maybe I was supposed to reshape my 2D 'X'
to a 3D Tensor of shape (rows, cols, 1) but leave my labels as 2D for sklearn interface? But then when I try that I get another Keras error:
ValueError: Error when checking model target: expected lstm_17 to have 3 dimensions, but got array with shape (500, 2880)
...So how does one fit a Sklearn-style Keras RNN to return sequences? Different parts of Keras seem to demand that my target be both 2D and 3D. Or (more likely) I'm misunderstanding something.
... Here's a reproduceable code example:
from keras.layers import LSTM
from keras.wrappers.scikit_learn import KerasClassifier
# Raw Data/Targets
X = np.array([1,2,3,4,5,6,7,8,9,10,11,12]).reshape(3,4)
Y = np.array([1,0,1,1,0,1,0,1,0,1,0,1]).reshape(3,4)
# Convert X to 3D tensor per Keras doc for recurrent layers
X = X.reshape(X.shape[0], X.shape[1], 1)
# .fit() at bottom will throw an error whether or not this line is used to reshape Y
to reshape Y
Y = Y.reshape(Y.shape[0], Y.shape[1], 1)
# Define function to return compiled Keras Model (to pass to Sklearn API)
def keras_rnn(timesteps, num_features):
'''Function to return compiled Keras Classifier to pass to sklearn wrapper'''
model = Sequential()
model.add(LSTM(8, return_sequences=True, input_shape=(timesteps, num_features)))
model.add(LSTM(1, return_sequences=True, activation = 'sigmoid'))
model.compile(optimizer = 'RMSprop', loss = 'categorical_crossentropy')
return model
# Convert compiled Keras model to Scikit-learn-style classifier (compatible w/ sklearn model-tuning methods)
rnn_sklearn = KerasClassifier(build_fn=keras_rnn,
timesteps=4,
num_features=1)
# Fit RNN Model to Data, Target
rnn_sklearn.fit(X, Y)
ValueError: Invalid shape for y
Upvotes: 5
Views: 2159
Reputation: 11
This is something that I think is a feature of the KerasClassifier class. I ran into the same problem when I was using the class on a multi-step, multi-feature LSTM. For some reason, if I built the model through Keras and ran the fit() method after compile() the model will train normally with no errors. However, when I have the model created in a function and call that function with KerasClassifier, than I run into the error you have. Upon looking at the KerasClassifier class in the keras module (search for wrappers/scikit_learn.py) I found that 'y' had to be a specific shape or the function would raise an exception. This shape was a 2D 'y' tensor (n_samples, n_outputs) or a 1D 'y' tensor (n_samples) which was incompatible for what I was expecting. So I'm just going to use the model's fit() method instead of using the wrapper. Hope this helps.
BTW. My Keras version is 2.2.4 and Tensorflow is 1.15.0. This may not be applicable in the newer versions.
Upvotes: 1
Reputation: 137
This code work with Keras 2.0.2:
import numpy as np
from keras.models import Sequential
from keras.layers import LSTM, Flatten
from keras.wrappers.scikit_learn import KerasClassifier
# Raw Data/Targets
X = np.array([1,2,3,4,5,6,7,8,9,10,11,12]).reshape(3,4)
Y = np.array([1,0,1,1,0,1,0,1,0,1,0,1]).reshape(3,4)
# Convert X to 3D tensor per Keras doc for recurrent layers
X = X.reshape(X.shape[0], X.shape[1], 1)
# .fit() at bottom will throw an error whether or not this line is used to reshape Y to reshape Y
Y = Y.reshape(Y.shape[0], Y.shape[1], 1)
# Define function to return compiled Keras Model (to pass to Sklearn API)
def keras_rnn(timesteps, num_features):
'''Function to return compiled Keras Classifier to pass to sklearn wrapper'''
model = Sequential()
model.add(LSTM(8, return_sequences=True, input_shape=(timesteps, num_features)))
model.add(LSTM(1, return_sequences=True, activation = 'sigmoid'))
model.compile(optimizer = 'RMSprop', loss = 'binary_crossentropy')
return model
# Convert compiled Keras model to Scikit-learn-style classifier (compatible w/ sklearn model-tuning methods)
rnn_sklearn = KerasClassifier(build_fn=keras_rnn,
timesteps=4,
num_features=1)
# Fit RNN Model to Data, Target
rnn_sklearn.fit(X, Y)
Upvotes: 0