Tensorflow Data cardinality is ambigous with multiple inputs - python

I have a model with two inputs for text classification with additional input 'subject' of text. One of my inputs is for text - it gets vectorized by a vectorization layer. The other is 'subject' as int. These are concatenated later. In my code below, x_train_text is simply a list of texts. x_train_subject is a list of integers. These two and y_train_int has same sizes. However, even though the sizes are the same(4499), I get the following error:
ValueError: Data cardinality is ambiguous:
x sizes: 2
y sizes: 4499
Make sure all arrays contain the same number of samples.
CODE:
MAX_TOKENS_NUM = 5000 # Maximum vocab size.
MAX_SEQUENCE_LEN = 40 # Sequence length to pad the outputs to.
EMBEDDING_DIMS = 100
text_input = tf.keras.Input(shape=(1,), dtype=tf.string)
subject_input = tf.keras.Input(shape=(1,), dtype=tf.int32)
text_layer = vectorize_layer(text_input)
text_layer = tf.keras.layers.Embedding(MAX_TOKENS_NUM + 1, EMBEDDING_DIMS)(text_layer)
text_layer = tf.keras.layers.GlobalAveragePooling1D()(text_layer)
subject_layer = tf.keras.layers.CategoryEncoding(
num_tokens=len(subjects), output_mode='one_hot', sparse=False
)(subject_input)
concatenated = tf.keras.layers.Concatenate(axis=1)([text_layer, subject_layer])
output = tf.keras.layers.Dense(len(labels))(concatenated)
model = tf.keras.models.Model(inputs=[text_input, subject_input], outputs=output)
model.summary()
model.compile(loss=losses.SparseCategoricalCrossentropy(from_logits=True),
optimizer='adam',
metrics=tf.metrics.SparseCategoricalAccuracy())
FIT FUNCTION :
epochs = 100
history = model.fit(
[x_train_text,x_train_subject],
y=y_train_int,
epochs=epochs)
What could be the solution?

When I changed the fit function to receive inputs as Pandas.DataFrame.values as below it works.
FIT FUNCTION :
epochs = 100
history = model.fit(
[pd.DataFrame(x_train_text).values,pd.DataFrame(x_train_subject).values],
y=pd.DataFrame(y_train_int).values,
epochs=epochs)

Related

ValueError: `decode_predictions` expects a batch of predictions (i.e. a 2D array of shape (samples, 1000)). Found array with shape: (1, 26)

I am using a model trained by myself to translate braille digits into plain text. As you can see this is a classification problem with 26 classes, one for each letter in the alphabet.
This is the dataset that I used to train my model: https://www.kaggle.com/datasets/shanks0465/braille-character-dataset
This is how I am generating my training and validation set:
os.mkdir('./images/')
alpha = 'a'
for i in range(0, 26):
os.mkdir('./images/' + alpha)
alpha = chr(ord(alpha) + 1)
rootdir = "C:\\Users\\ffernandez\\Downloads\\capstoneProject\\Braille Dataset\\Braille Dataset\\"
for file in os.listdir(rootdir):
letter = file[0]
copyfile(rootdir+file, './images/' + letter + '/' + file)
The resulting folder looks like this:
folder structure
And this is how I create the train and validation split:
datagen = ImageDataGenerator(rotation_range=20,
shear_range=10,
validation_split=0.2)
train_generator = datagen.flow_from_directory('./images/',
target_size=(28,28),
subset='training')
val_generator = datagen.flow_from_directory('./images/',
target_size=(28,28),
subset='validation')
Finally this is the code corresponding to the design, compilation and training of the model:
K.clear_session()
model_ckpt = ModelCheckpoint('BrailleNet.h5',save_best_only=True)
reduce_lr = ReduceLROnPlateau(patience=8,verbose=0)
early_stop = EarlyStopping(patience=15,verbose=1)
entry = L.Input(shape=(28,28,3))
x = L.SeparableConv2D(64,(3,3),activation='relu')(entry)
x = L.MaxPooling2D((2,2))(x)
x = L.SeparableConv2D(128,(3,3),activation='relu')(x)
x = L.MaxPooling2D((2,2))(x)
x = L.SeparableConv2D(256,(2,2),activation='relu')(x)
x = L.GlobalMaxPooling2D()(x)
x = L.Dense(256)(x)
x = L.LeakyReLU()(x)
x = L.Dense(64,kernel_regularizer=l2(2e-4))(x)
x = L.LeakyReLU()(x)
x = L.Dense(26,activation='softmax')(x)
model = Model(entry,x)
model.compile(loss='categorical_crossentropy',optimizer='adam',metrics=['accuracy'])
history = model.fit_generator(train_generator,validation_data=val_generator,epochs=666,
callbacks=[model_ckpt,reduce_lr,early_stop],verbose=0)
Then this is the code for testing an image of the letter 'a' in braille has the same size as the training and validation set (28x28):
img_path = "./test/a1.JPG10whs.jpg"
img = plt.imread(img_path)
img_array = tf.keras.utils.img_to_array(img)
img_batch = np.expand_dims(img_array, axis=0)
img_preprocessed = tf.keras.applications.resnet50.preprocess_input(img_batch)
prediction = model.predict(img_preprocessed)
print(tf.keras.applications.imagenet_utils.decode_predictions(prediction, top=3)[0])
Just when I execute that last line of code this error appears:
ValueError: decode_predictions expects a batch of predictions (i.e. a 2D array of shape (samples, 1000)). Found array with shape: (1, 26)
A similar question I found here on stackoverflow (ValueError: `decode_predictions` expects a batch of predictions (i.e. a 2D array of shape (samples, 1000)). Found array with shape: (1, 7)).
I've seen that using "decode_predictions" only makes sense if your model outputs the ImageNet classes (1000-dimensional) but if I can't use "decode_predictions" I don't know how to get my predictions.
My desired output would be like:
prediction = model.predict(img_preprocessed)
print(prediction)
output: 'a'
Any hint or suggestion on how to solve this issue is highly appreciated.
If we take a look at what the prediction object acually is we can see that it has 26 values. These values are the propabiity for each letter that the model predicts:
So we need a way to map the prediction value to the respective letter.
A simple way to do this could to create a list of all the 26 possible letters and search the max value in the prediction array. Example:
#Create prediction labels from a-z
alpha="a"
labels=["a"]
for i in range(0, 25):
alpha = chr(ord(alpha) + 1)
labels.append(alpha)
#Search the max value in prediction
labels[np.argmax(prediction)]
The output should be the character with the highest probability:

Tensorflow getting ' ValueError: Exception encountered when calling layer "normalization" Dimensions must be equal'

I am following Tensorflow’s regression tutorial and have created a multivariable linear regression and deep neural network however, when I am trying to collect the test set in test_results, I get the following error:
ValueError: Exception encountered when calling layer "normalization" (type Normalization).
Dimensions must be equal, but are 7 and 8 for '{{node sequential/normalization/sub}} = Sub[T=DT_FL Dimensions must be equal, but are 7 and Dimensions must be equal, but are 7 and 8 for '{{node sequential/normalization/sub}} = Sub[T=DT_FLOAT](sequential/Cast, sequential/normalizati
on/sub/y)' with input shapes: [?,7], [1,8].
Call arguments received by layer "normalization" (type Normalization):
• inputs=tf.Tensor(shape=(None, 7), dtype=float32)
Here is the some of code for the linear regression,starting from splitting labels, the error appears on the last line, test_results[‘linear_model’] = linear_model.evaluate(test_features, test_labels, verbose = 0) However, I am able to generate the error plots and everything seems to work fine otherwise, so I’m not entirely sure what the error is with getting test results.
Any help would be much appreciated!
#Split labels
train_features = train_dataset.copy()
test_features = test_dataset.copy()
train_labels = train_features.pop('HCO3')
test_labels = test_features.pop('HCO3')
train_features = np.asarray(train_dataset.copy()).astype('float32')
#print(train_features.tail())
#Normalization
normalizer = tf.keras.layers.Normalization(axis=-1)
normalizer.adapt(np.array(train_features))
first = np.array(train_features[:1])
linear_model = tf.keras.Sequential([
normalizer,
layers.Dense(units=1)
])
#Compilation
linear_model.compile(
optimizer=tf.keras.optimizers.Adam(learning_rate=0.1),
loss='mean_absolute_error'
)
history = linear_model.fit(
train_features,
train_labels,
epochs=100,
# Suppress logging.
verbose=0,
# Calculate validation results on 20% of the training data.
validation_split = 0.2)
#Track error for later
test_results = {}
test_results['linear_model'] = linear_model.evaluate(test_features, test_labels, verbose = 0)
You lost the outcome column in the dataframe because of pop. Try extracting that column using
train_labels = train_features['HC03']
test_labels = test_features['HC03']

Having trouble with Keras One Hot Encoding Memory Error

I am trying to build a word level lstm model using keras and for that I need to create one hot encoding for words to feed in the model. I have around 32360 words around 130,000 lines. Each time I attempt to run my model I run into a memory error.
I believe the issue is the size of the dataset. I have been researching this for a couple of days now and it seems the solution is to either: create a generator where I do the one hot encoding and then load my data in batches or to reduce the number of lines I attempt to feed into the model. I cannot quite figure out the generator piece.
The error I get is:
MemoryError: Unable to allocate 143. GiB for an array with shape
(1184643, 32360) and data type int32
Is the generator the correct way to go? Is there any way to solve this otherwise? My code is below:
vocab_size = len(tokenizer.word_index)+1
seq = []
for item in corpus:
seq_list = tokenizer.texts_to_sequences([item])[0]
for i in range(1, len(seq_list)):
n_gram = seq_list[:i+1]
seq.append(n_gram)
max_seq_size = max([len(s) for s in seq])
seq = np.array(pad_sequences(seq, maxlen=max_seq_size, padding='pre'))
input_sequences, labels = seq[:,:-1], seq[:,-1]
one_hot_labels = to_categorical(labels, num_classes=vocab_size, dtype='int32')
n_units = 256
embedding_size = 100
text_in = Input(shape = (None,))
x = Embedding(vocab_size, embedding_size)(text_in)
x = LSTM(n_units)(x)
x = Dropout(0.2)(x)
text_out = Dense(vocab_size, activation = 'softmax')(x)
model = Model(text_in, text_out)
model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
filepath="new_model_weights/weights-{epoch:02d}.hdf5"
checkpoint = ModelCheckpoint(filepath,
monitor='accuracy',
verbose=1,
save_best_only=False,
save_weights_only=False,
mode='auto',
save_freq='epoch')
callbacks_list = [checkpoint]
epochs = 50
batch_size = 10
history = model.fit(input_sequences, one_hot_labels, epochs=epochs, batch_size=batch_size, callbacks=callbacks_list, verbose=1)

How to use Grid Search when there are multiple inputs, including a matrix?

I am trying to tune the neuron model, but since the inputs are multiple and in different shapes, it seems impossible to stack it together.
There are two types of inputs when I make the model.
one of them is:
cats = [train.time_signature,train.key,train.mode_cat,train.loudness_cat,train.tempo_cat,train.duration_cat]
The shape of them are all (7678,)
another input is:
num_train
The shape of it is (7678,30), which is a matrix
When fitting the Keras model, it's okay to just concatenate them together as a training set:
final_model.fit([cats,num_train],train.genre_cat,batch_size=50,epochs=1000,verbose=1,validation_split=.1)
However, when I use the GridSearch, it doesn't allow me to the same input as I did in the model.
grid_result = grid.fit([cats,num_train],train.genre_cat)
It shows error :ValueError: Found input variables with inconsistent numbers of samples: [2, 7678], which means the num_train is not allowed because I got the other 30 samples on index 1.
Is there anything that I can deal with this problem? Thanks.
Reference:
Grid Search for Keras with multiple inputs
https://github.com/keras-team/keras/issues/2748
I think that the trick is always the same: make one single input which is the concatenation of the multiple inputs.
In this particular case, we have N inputs of dim (n_sample,1) and one input of dim (n_sample,30). The new concatenated input will have dimensions (n_sample, n_stacked_columns).
we make the separation of the columns inside the model
n_sample = 100
x1 = np.random.uniform(0,1, (n_sample,1)) # (n_sample,1)
x2 = np.random.uniform(0,1, (n_sample,1)) # (n_sample,1)
x3 = np.random.uniform(0,1, (n_sample,1)) # (n_sample,1)
x = np.random.uniform(0,1, (n_sample,30)) # (n_sample,30)
X = np.column_stack([x1,x2,x3,x]) # (n_sample,1+1+1+30)
y = np.random.uniform(0,1, n_sample)
inp = Input((X.shape[-1],))
inp1 = Lambda(lambda x: tf.expand_dims(x[:,0],-1))(inp) # (None,1)
inp2 = Lambda(lambda x: tf.expand_dims(x[:,1],-1))(inp) # (None,1)
inp3 = Lambda(lambda x: tf.expand_dims(x[:,2],-1))(inp) # (None,1)
inp_matrix = Lambda(lambda x: x[:,3:])(inp) # (None,30)
d1 = Dense(8)(inp1)
d2 = Dense(8)(inp2)
d3 = Dense(8)(inp3)
d_matrix = Dense(8)(inp_matrix)
concat = Concatenate()([d1,d2,d3,d_matrix])
out = Dense(1)(concat)
model = Model(inp, out)
model.compile('adam','mse')
model.fit(X,y, epochs=3)

Sequence-to-sequence classification with variable sequence lengths in Keras

I would like to train an LSTM or GRU network in TensorFlow/Keras to continuously recognize whether a user is walking or not based on input from motion sensors (accelerometer and gyroscope). I have 50 input sequences with lengths varying from 581 to 5629 time steps and 6 features and 50 corresponding output sequences of boolean values. My problem is that I don't know how to feed the training data to the fit() method.
I know approximately what I need to do: I'd like to train with 5 batches of 10 sequences each, and for each batch I have to pad all but the longest sequence so all 10 sequences have the same lengths and apply masking. I just don't know how to build the data structures. I know that I can make one big 3D tensor of size (50,5629,6) and that works, but it's painfully slow, so I'd really like to make the sequence length of each batch as small as possible.
Here's the problem in code:
import tensorflow as tf
import numpy as np
# Load data from file
x_list, y_list = loadSequences("train.csv")
# x_list is now a list of arrays (n,6) of float64, where n is the timesteps
# and 6 is the number of features, sorted by increasing sequence lengths.
# y_list is a list of arrays (n,1) of Boolean.
x_train = # WHAT DO I WRITE HERE?
y_train = # AND HERE?
model = tf.keras.models.Sequential([
tf.keras.layers.Masking(),
tf.keras.layers.LSTM(32, return_sequences=True),
tf.keras.layers.Dense(2, activation=tf.nn.softmax)
])
model.compile(optimizer='adam',
loss='sparse_categorical_crossentropy',
metrics=['accuracy'])
model.fit(x_train, y_train, batch_size=10, epochs=100)
You can do some thing like this
use generator function take a look at this link fit_generator look for fit_generator method.
def data_generater(batch_size):
print("reading data")
training_file = 'data_location', 'r')
# assuming data is in json format so feels free to change accordingly
training_set = json.loads(training_file.read())
training_file.close()
batch_i = 0 # Counter inside the current batch vector
batch_x = [] # The current batch's x data
batch_y = [] # The current batch's y data
while True:
for obj in training_set:
batch_x.append(your input sequences one by one)
if obj['val'] == True:
batch_y.append([1])
elif obj['val'] == False:
batch_y.append([0])
batch_i += 1
if batch_i == batch_size:
# Ready to yield the batch
# pad input to max length in the batch
batch_x = pad_txt_data(batch_x)
yield batch_x, np.array(batch_y)
batch_x = []
batch_y = []
batch_i = 0
def pad_txt_data(arr):
# expecting arr to be in the shape of (10, m, 6)
paded_arr = []
prefered_len = len(max(arr, key=len))
# Now pad all your sequences to preferred length in the batch(arr)
return np.array(paded_arr)
and in the model
model = keras.Sequential()
model.add(keras.layers.Masking(mask_value=0., input_shape=(None,6)))
model.add(keras.layers.LSTM(32))
model.add(keras.layers.Dense(1, activation="softmax"))
model.compile(optimizer="Adam", loss='categorical_crossentropy', metrics=['categorical_accuracy'])
model.fit_generator(data_generater(10), steps_per_epoch=5, epochs=10)
Batch_size, steps_per_epoch, epoch can be different.
Generally
steps_per_epoch = (number of sequences/batch_size)
Note: Form reading your description your task appears to be Binary classification problem not like an Sequence to sequence problem. A good example for sequence to sequence is a language translation. Just google around you will find what i mean.
And if you really want to see the difference in training times I suggest using a GPU if available and CuDNNLSTM.
In case it helps someone, here's how I ended up implementing a solution:
import tensorflow as tf
import numpy as np
# Load data from file
x_list, y_list = loadSequences("train.csv")
# x_list is now a list of arrays (m,n) of float64, where m is the timesteps
# and n is the number of features.
# y_list is a list of arrays (m,1) of Boolean.
assert len(x_list) == len(y_list)
num_sequences = len(x_list)
num_features = len(x_list[0][0])
batch_size = 10
batches_per_epoch = 5
assert batch_size * batches_per_epoch == num_sequences
def train_generator():
# Sort by length so the number of timesteps in each batch is minimized
x_list.sort(key=len)
y_list.sort(key=len)
# Generate batches
while True:
for b in range(batches_per_epoch):
longest_index = (b + 1) * batch_size - 1
timesteps = len(x_list[longest_index])
x_train = np.zeros((batch_size, timesteps, num_features))
y_train = np.zeros((batch_size, timesteps, 1))
for i in range(batch_size):
li = b * batch_size + i
x_train[i, 0:len(x_list[li]), :] = x_list[li]
y_train[i, 0:len(y_list[li]), 0] = y_list[li]
yield x_train, y_train
model = tf.keras.models.Sequential([
tf.keras.layers.Masking(mask_value=0., input_shape=(None,num_features)),
tf.keras.layers.LSTM(32, return_sequences=True),
tf.keras.layers.Dense(2, activation=tf.nn.softmax)
])
model.compile(optimizer='adam',
loss='sparse_categorical_crossentropy',
metrics=['accuracy'])
model.fit_generator(train_generator(), steps_per_epoch=batches_per_epoch, epochs=100)

Categories