Low accuracy after training a CNN - python

I try to train a CNN model that classifies the handwritten digit using Keras, but I am getting low accuracy in the training (lower than 10%) and a big error.
I tried a simple neural network without concolutions and it didn't work as well.
This is my code.
import tensorflow as tf
from tensorflow import keras
import numpy as np
import matplotlib.pyplot as plt
(x_train, y_train), (x_test, y_test) = keras.datasets.mnist.load_data()
#Explore data
print(y_train[12])
print(np.shape(x_train))
print(np.shape(x_test))
#we have 60000 imae for the training and 10000 for testing
# Scaling data
x_train = x_train/255
y_train = y_train/255
#reshape the data
x_train = x_train.reshape(60000,28,28,1)
x_test = x_test.reshape(10000,28,28,1)
y_train = y_train.reshape(60000,1)
y_test = y_test.reshape(10000,1)
#Create a model
model = keras.Sequential([
keras.layers.Conv2D(64,(3,3),(1,1),padding = "same",input_shape=(28,28,1)),
keras.layers.MaxPooling2D(pool_size = (2,2),padding = "valid"),
keras.layers.Conv2D(32,(3,3),(1,1),padding = "same"),
keras.layers.MaxPooling2D(pool_size = (2,2),padding = "valid"),
keras.layers.Flatten(),
keras.layers.Dense(128,activation = "relu"),
keras.layers.Dense(10,activation = "softmax")])
model.compile(optimizer = "adam",
loss = "sparse_categorical_crossentropy",
metrics = ['accuracy'])
model.fit(x_train,y_train,epochs=10)
test_loss,test_acc = model.evaluate(x_test,y_test)
print("\ntest accuracy:",test_acc)
Could anyone advice me on how to improve my model?

Your problem is here:
x_train = x_train/255
y_train = y_train/255 # makes no sense
You should have rescaled x_test, not y_train.
x_train = x_train/255
x_test = x_test/255
That was probably just a typo from your part. Change these lines and you'll have 95%+ accuracy.

You model have some scaling problem and try to use tf 2.0
x_train /= 255
x_test /= 255
you don't need to scale all data of test
as you have done :
x_train = x_train/255
y_train = y_train/255
Afterwards, we can transform the labels into a one-hot encoding
from tensorflow.keras.utils import to_categorical
y_train = to_categorical(y_train, 10)
y_test = to_categorical(y_test, 10)
which helps in the :
loss='categorical_crossentropy',
The Sequential API allows us to stack layers on top of each other. The only downside is that we cannot have multiple outputs or inputs when using these models. Nevertheless, we can create a Sequential object and use the add() function to add layers to our model.
Try to use more API that make your model more smooth and accurate as using add function is present on Tf 2.0
As we can give Conv2D 4 time to make smooth :
seq_model.add(Conv2D(filters=32, kernel_size=(5,5), activation='relu',
input_shape=x_train.shape[1:]))
seq_model.add(Conv2D(filters=32, kernel_size=(5,5), activation='relu'))
seq_model.add(Conv2D(filters=64, kernel_size=(3, 3), activation='relu'))
seq_model.add(Conv2D(filters=64, kernel_size=(3, 3), activation='relu'))
in the code you can use dropout :
seq_model.add(Dropout(rate=0.25))
Full model :
%tensorflow_version 2.x
from tensorflow.keras.datasets import mnist
(x_train, y_train), (x_test, y_test) = mnist.load_data()
x_train = x_train.astype('float32')
x_test = x_test.astype('float32')
x_train /= 255
x_test /= 255
x_train = x_train.reshape(x_train.shape[0], 28, 28, 1)
x_test = x_test.reshape(x_test.shape[0], 28, 28, 1)
from tensorflow.keras.utils import to_categorical
y_train = to_categorical(y_train, 10)
y_test = to_categorical(y_test, 10)
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Conv2D, MaxPool2D, Dense, Flatten, Dropout
seq_model = Sequential()
seq_model.add(Conv2D(filters=32, kernel_size=(5,5), activation='relu',
input_shape=x_train.shape[1:]))
seq_model.add(Conv2D(filters=32, kernel_size=(5,5), activation='relu'))
seq_model.add(MaxPool2D(pool_size=(2, 2)))
seq_model.add(Dropout(rate=0.25))
seq_model.add(Conv2D(filters=64, kernel_size=(3, 3), activation='relu'))
seq_model.add(Conv2D(filters=64, kernel_size=(3, 3), activation='relu'))
seq_model.add(MaxPool2D(pool_size=(2, 2)))
seq_model.add(Dropout(rate=0.25))
seq_model.add(Flatten())
seq_model.add(Dense(256, activation='relu'))
seq_model.add(Dropout(rate=0.5))
seq_model.add(Dense(10, activation='softmax'))
seq_model.compile(
loss='categorical_crossentropy',
optimizer='adam',
metrics=['accuracy']
)
epochsz = 3 # number of epch
batch_sizez = 32 # the batch size ,can be 64 , 128 so other
seq_model.fit(x_train,y_train, batch_size=batch_sizez, epochs=epochsz)
Result :
Train on 60000 samples
Epoch 1/3
60000/60000 [==============================] - 186s 3ms/sample - loss: 0.1379 - accuracy: 0.9588
Epoch 2/3
60000/60000 [==============================] - 187s 3ms/sample - loss: 0.0677 - accuracy: 0.9804
Epoch 3/3
60000/60000 [==============================] - 187s 3ms/sample - loss: 0.0540 - accuracy: 0.9840

Related

How to extract the image names and labels in the training set after completing the active learning loop and write them to a CSV file?

I am using the Keras script at https://modal-python.readthedocs.io/en/latest/content/examples/Keras_integration.html to perform active learning for a binary classification task. After completing the active learning loop, how do we extract the image names and labels in the training set that gives the optimal test performance and write them to a CSV file?
from tensorflow import keras
import numpy as np
from tensorflow.keras.datasets import mnist
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Dropout, Flatten, Conv2D, MaxPooling2D
from tensorflow.keras.wrappers.scikit_learn import KerasClassifier
from modAL.models import ActiveLearner
from modAL.uncertainty import entropy_sampling
# build function for the Keras' scikit-learn API
def create_keras_model():
model = Sequential()
model.add(Conv2D(32, kernel_size=(3, 3), activation='relu', input_shape=(28, 28, 1)))
model.add(Conv2D(64, (3, 3), activation='relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.25))
model.add(Flatten())
model.add(Dense(128, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(10, activation='softmax'))
model.compile(loss='categorical_crossentropy', optimizer='adadelta', metrics=['accuracy'])
return model
# create the classifier
classifier = KerasClassifier(create_keras_model)
# read training data
(X_train, y_train), (X_test, y_test) = mnist.load_data()
X_train = X_train.reshape(60000, 28, 28, 1).astype('float32') / 255
X_test = X_test.reshape(10000, 28, 28, 1).astype('float32') / 255
y_train = keras.utils.to_categorical(y_train, 10)
y_test = keras.utils.to_categorical(y_test, 10)
# assemble initial data
n_initial = 1000
initial_idx = np.random.choice(range(len(X_train)), size=n_initial, replace=False)
X_initial = X_train[initial_idx]
y_initial = y_train[initial_idx]
# generate the pool
# remove the initial data from the training dataset
X_pool = np.delete(X_train, initial_idx, axis=0)
y_pool = np.delete(y_train, initial_idx, axis=0)
"""
Training the ActiveLearner
"""
# initialize ActiveLearner
learner = ActiveLearner(
estimator=classifier,
X_training=X_initial, y_training=y_initial,
verbose=1
)
# the active learning loop
n_queries = 100
for idx in range(n_queries):
query_idx, query_instance = learner.query(X_pool, n_instances=100, verbose=0)
print(query_idx)
learner.teach(
X=X_pool[query_idx], y=y_pool[query_idx], only_new=True,
verbose=1
)
# remove queried instance from pool
X_pool = np.delete(X_pool, query_idx, axis=0)
y_pool = np.delete(y_pool, query_idx, axis=0)
# the final accuracy score
print(learner.score(X_test, y_test, verbose=1))

I need help finding the correct input shape for my 2 dimensional CNN model

I am trying to build a CNN model for a 2d data. I have 1000 rows with 26 cols. this is the code I have, I have tried numerous combinations for my input shape but I cannot figure out what i am doing wrong.
# CNN
# The known number of output classes.
num_classes = 10
# label encoding
encoder = LabelEncoder()
y_train = encoder.fit_transform(y_train)
y_test = encoder.fit_transform(y_test)
# one hot encoding
y_train = keras.utils.np_utils.to_categorical(y_train, num_classes)
y_test = keras.utils.np_utils.to_categorical(y_test, num_classes)
print(X_train.shape)
print(X_test.shape)
# reshape 2D to 3D
x_train = X_train.reshape(670, 26, 1)
x_test = X_test.reshape(330, 26, 1)
print(x_train.shape)
print(x_test.shape)
# build CNN model
model2 = models.Sequential()
model2.add(layers.Conv1D(64, kernel_size=2, input_shape=(26, 1), activation='relu')) # convolution
model2.add(layers.MaxPool1D(pool_size=2)) # pooling
model2.add(layers.Flatten()) # flatten
model2.add(layers.Dense(128, activation='relu')) # fc
2.add(layers.Dense(num_classes, activation='softmax'))
# model compile
model2.compile(loss="categorical_crossentropy",
optimizer=adam,
metrics=['accuracy'])
# model.summary()
batch_size = 128
epochs = 5000
model = model.fit(x_train, y_train,
batch_size=batch_size,
epochs=epochs,
verbose=2,
callbacks=early_stopping,
validation_split=0.1,
)
This gives:
Error:ValueError: Input 0 of layer sequential is incompatible with the layer: expected axis -1 of input shape to have value 26 but received input with shape (None, 26, 1)
Your implementation would work perfectly if you load the data correctly and fit the label encoder on Train only, then transform Train & Test set!
df = pd.read_csv('data.csv')
train, test = train_test_split(df, test_size=0.33)
y_train, X_train = train.iloc[:,-1].values, train.iloc[:,1:-1].values
y_test, X_test = test.iloc[:,-1].values, test.iloc[:,1:-1].values
print(X_test.shape, X_train.shape, y_test.shape, y_train.shape)
# CNN
# The known number of output classes.
num_classes = 10
# label encoding
encoder = LabelEncoder()
y_train = encoder.fit_transform(y_train)
y_test = encoder.transform(y_test)
# one hot encoding
y_train = to_categorical(y_train, num_classes)
y_test = to_categorical(y_test, num_classes)
print(X_train.shape)
print(X_test.shape)
# reshape 2D to 3D
x_train = X_train.reshape(670, 26, 1)
x_test = X_test.reshape(330, 26, 1)
print(x_train.shape)
print(x_test.shape)
# build CNN model
model2 = models.Sequential()
model2.add(layers.Conv1D(64, kernel_size=2, input_shape=(26, 1), activation='relu')) # convolution
model2.add(layers.MaxPool1D(pool_size=2)) # pooling
model2.add(layers.Flatten()) # flatten
model2.add(layers.Dense(128, activation='relu')) # fc
model2.add(layers.Dense(num_classes, activation='softmax'))
# model compile
model2.compile(loss="categorical_crossentropy",
optimizer=Adam(),
metrics=['accuracy'])
# model.summary()
batch_size = 128
epochs = 5000
model = model2.fit(x_train, y_train,
batch_size=batch_size,
epochs=epochs,
verbose=2,
callbacks=EarlyStopping(),
validation_split=0.1,
)
output:
(330, 26) (670, 26) (330,) (670,)
(670, 26)
(330, 26)
(670, 26, 1)
(330, 26, 1)
Epoch 1/5000
5/5 - 0s - loss: 244.5596 - accuracy: 0.0829 - val_loss: 151.6749 - val_accuracy: 0.1045

ValueError: Input arrays should have the same number of samples as target arrays. Found 60000 input samples and 10000 target samples

I'm trying to train my Deep Neural Network to recognize handwritten
numbers but I keep getting the error stated previously in the title It
gives me an error saying: ValueError: Input arrays should have the
same number of samples as target arrays. Found 60000 input samples and
10000 target samples. How can i fix this? (i already tried
train_test_split and transport but nothing worked)
# Imports
import keras
from keras.datasets import mnist
from keras.models import Sequential
from keras.layers import Dense
from keras.utils import to_categorical
# Configuration options
feature_vector_length = 784
num_classes = 60000
# Load the data
(X_train, Y_train), (X_test, Y_test) = mnist.load_data()
# Reshape the data - MLPs do not understand such things as '2D'.
# Reshape to 28 x 28 pixels = 784 features
X_train = X_train.reshape(X_train.shape[0], feature_vector_length)
X_test = X_test.reshape(X_test.shape[0], feature_vector_length)
# Convert into greyscale
X_train = X_train.astype('float32')
X_test = X_test.astype('float32')
X_train /= 255
X_test /= 255
# Convert target classes to categorical ones
Y_train = to_categorical(Y_train, num_classes)
Y_test = to_categorical(Y_test, num_classes)
# Load the data
(X_train, Y_train), (X_test, Y_test) = mnist.load_data()
# Visualize one sample
import matplotlib.pyplot as plt
plt.imshow(X_train[0], cmap='Greys')
plt.show()
# Set the input shape
input_shape = (feature_vector_length,)
print(f'Feature shape: {input_shape}')
# Create the model
# Using sigmoid instead of relu function
model = Sequential()
model.add(Flatten())
model.add(Dense(350, input_shape=input_shape, activation="sigmoid",
kernel_initializer=init))
model.add(Dense(50, activation="sigmoid", kernel_initializer=init))
model.add(Dense(num_classes, activation="sigmoid",
kernel_initializer=init))
# Configure the model and start training
model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=
['accuracy'])
model.fit(X_train, Y_train, epochs=10, batch_size=250, verbose=1,
validation_split=0.2)
# Test the model after training
test_results = model.evaluate(X_test, Y_test, verbose=1)
print(f'Test results - Loss: {test_results[0]} - Accuracy:
{test_results[1]}%')
If you want a solution to your problem, here it is:
# Imports
import keras
from keras.datasets import mnist
from keras.models import Sequential
from keras.layers import Dense, Flatten
from keras.utils import to_categorical
# Configuration options
feature_vector_length = 784
num_classes = 10
# Load the data
(X_train, Y_train), (X_test, Y_test) = mnist.load_data()
# Reshape the data - MLPs do not understand such things as '2D'.
# Reshape to 28 x 28 pixels = 784 features
# X_train = X_train.reshape(X_train.shape[0], feature_vector_length)
# X_test = X_test.reshape(X_test.shape[0], feature_vector_length)
# Convert into greyscale
X_train = X_train.astype('float32')
X_test = X_test.astype('float32')
X_train /= 255
X_test /= 255
# Convert target classes to categorical ones
Y_train = to_categorical(Y_train, num_classes)
Y_test = to_categorical(Y_test, num_classes)
# Create the model
# Using sigmoid instead of relu function
model = Sequential()
model.add(Flatten())
model.add(Dense(350, input_shape=input_shape, activation="relu"))
model.add(Dense(50, activation="relu"))
model.add(Dense(num_classes, activation="softmax"))
# Configure the model and start training
model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=
['accuracy'])
model.fit(X_train, Y_train, epochs=10, batch_size=250, verbose=1,
validation_split=0.2)
# Test the model after training
test_results = model.evaluate(X_test, Y_test, verbose=1)
But you should really do some research and understand what every line in your code is supposed to do and what every parameter means. For example, the choice of sigmoid activation function being wrong, especially in the final layer is the very first thing to understand. That's one of the many things that you should do research about. Then there is:
understanding why and when to reshape your data,
what is the purpose of flatten layer
and most importantly, understand what is num_classes and why it is 10 and not 1000 or 60000

Keras AttributeError: 'module' object has no attribute '_TensorLike'

I am practicing using Keras to build a Convolution Neural Network. I decided to follow along this tutorial: http://adventuresinmachinelearning.com/keras-tutorial-cnn-11-lines/
However when attempting to convolve my model I run into the following error:
AttributeError: 'module' object has no attribute '_TensorLike'
The following is my code to look at.
from __future__ import print_function
import keras
from keras.datasets import mnist
from keras.layers import Dense, Flatten
from keras.layers import Conv2D, MaxPooling2D
from keras.models import Sequential
import matplotlib.pylab as plt
batch_size = 128
num_classes = 10
epochs = 10
# input image dimensions
img_x, img_y = 28, 28
# load the MNIST data set, which already splits into train and test sets for us
(x_train, y_train), (x_test, y_test) = mnist.load_data()
# reshape the data into a 4D tensor - (sample_number, x_img_size, y_img_size, num_channels)
# because the MNIST is greyscale, we only have a single channel - RGB colour images would have 3
x_train = x_train.reshape(x_train.shape[0], img_x, img_y, 1)
x_test = x_test.reshape(x_test.shape[0], img_x, img_y, 1)
input_shape = (img_x, img_y, 1)
# convert the data to the right type
x_train = x_train.astype('float32')
x_test = x_test.astype('float32')
x_train /= 255
x_test /= 255
print('x_train shape:', x_train.shape)
print(x_train.shape[0], 'train samples')
print(x_test.shape[0], 'test samples')
# convert class vectors to binary class matrices - this is for use in the
# categorical_crossentropy loss below
y_train = keras.utils.to_categorical(y_train, num_classes)
y_test = keras.utils.to_categorical(y_test, num_classes)
model = Sequential()
model.add(Conv2D(32, kernel_size=(5, 5), strides=(1, 1),
activation='relu',
input_shape=input_shape))
model.add(MaxPooling2D(pool_size=(2, 2), strides=(2, 2)))
model.add(Conv2D(64, (5, 5), activation='relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Flatten())
model.add(Dense(1000, activation='relu'))
model.add(Dense(num_classes, activation='softmax'))
model.compile(loss=keras.losses.categorical_crossentropy,
optimizer=keras.optimizers.Adam(),
metrics=['accuracy'])
class AccuracyHistory(keras.callbacks.Callback):
def on_train_begin(self, logs={}):
self.acc = []
def on_epoch_end(self, batch, logs={}):
self.acc.append(logs.get('acc'))
history = AccuracyHistory()
model.fit(x_train, y_train,
batch_size=batch_size,
epochs=epochs,
verbose=1,
validation_data=(x_test, y_test),
callbacks=[history])
score = model.evaluate(x_test, y_test, verbose=0)
print('Test loss:', score[0])
print('Test accuracy:', score[1])
plt.plot(range(1, 11), history.acc)
plt.xlabel('Epochs')
plt.ylabel('Accuracy')
plt.show()
I have installed keras and upgraded it to the latest version (2.2.0). I have also installed tensorflow and upgraded it as well and have python version 3.4. My input shape is a (28,28,1) tensor (the 1 because these images are greyscale). Can someone please help me because I am quite lost
This is caused by some misalignment between Keras and TensorFlow.
It is fixed on keras>=2.4.3. Optionally you can also move to tf.Keras (TensorFlow's implementation of Keras)
tf.Keras documentation: https://www.tensorflow.org/api_docs/python/tf/keras

Using Keras with HDF5Matrix with labels only

I believe that this is my first question in Stack Overflow, so I apologize in advance if I don't follow all guidelines.
I recently started to use Keras for deep learning, and since I work with HDF5 files using h5py to manage large datasets, I searched for a way to train models using keras on very large HDF5 files. I found out that the most common way would be to use HDF5Matrix found in keras.utils.io_utils.
I modified one of Keras examples (mnist.cnn) as following:
'''Trains a simple convnet on the MNIST dataset.
Gets to 99.25% test accuracy after 12 epochs
(there is still a lot of margin for parameter tuning).
16 seconds per epoch on a GRID K520 GPU.
'''
from __future__ import print_function
import keras
from keras.datasets import mnist
from keras.models import Sequential
from keras.layers import Dense, Dropout, Flatten
from keras.layers import Conv2D, MaxPooling2D
from keras import backend as K
# My Imports
from os.path import exists
import h5py
from keras.utils.io_utils import HDF5Matrix
batch_size = 128
num_classes = 10
epochs = 12
# input image dimensions
img_rows, img_cols = 28, 28
# the data, shuffled and split between train and test sets
(x_train, y_train), (x_test, y_test) = mnist.load_data()
if K.image_data_format() == 'channels_first':
x_train = x_train.reshape(x_train.shape[0], 1, img_rows, img_cols)
x_test = x_test.reshape(x_test.shape[0], 1, img_rows, img_cols)
input_shape = (1, img_rows, img_cols)
else:
x_train = x_train.reshape(x_train.shape[0], img_rows, img_cols, 1)
x_test = x_test.reshape(x_test.shape[0], img_rows, img_cols, 1)
input_shape = (img_rows, img_cols, 1)
x_train = x_train.astype('float32')
x_test = x_test.astype('float32')
x_train /= 255
x_test /= 255
print('x_train shape:', x_train.shape)
print(x_train.shape[0], 'train samples')
print(x_test.shape[0], 'test samples')
# convert class vectors to binary class matrices
y_train = keras.utils.to_categorical(y_train, num_classes)
y_test = keras.utils.to_categorical(y_test, num_classes)
#-----------------------------------HDF5 files creation---------------------------------------
sample_file_name = "x.hdf5"
solution_file_name = "y.hdf5"
train_name = "train"
test_name = "test"
#Create dataset
if (not exists(sample_file_name)) and (not exists(solution_file_name)):
samples_file = h5py.File(sample_file_name,mode='a')
solutions_file = h5py.File(solution_file_name,mode='a')
samples_train = samples_file.create_dataset(train_name,data=x_train)
samples_test = samples_file.create_dataset(test_name, data=x_test)
solution_train = solutions_file.create_dataset(train_name, data=y_train)
solution_test = solutions_file.create_dataset(test_name, data=y_test)
samples_file.flush()
samples_file.close()
solutions_file.flush()
solutions_file.close()
x_train = HDF5Matrix(sample_file_name,train_name)
x_test = HDF5Matrix(sample_file_name,test_name)
y_train = HDF5Matrix(solution_file_name,train_name)
y_test = HDF5Matrix(solution_file_name,test_name)
#---------------------------------------------------------------------------------------------
model = Sequential()
model.add(Conv2D(32, kernel_size=(3, 3),
activation='relu',
input_shape=input_shape))
model.add(Conv2D(64, (3, 3), activation='relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.25))
model.add(Flatten())
model.add(Dense(128, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(num_classes, activation='softmax'))
model.compile(loss=keras.losses.categorical_crossentropy,
optimizer=keras.optimizers.Adadelta(),
metrics=['accuracy'])
# If using HDF5Matrix one needs to disable shuffle
model.fit(x_train, y_train,
batch_size=batch_size,
epochs=epochs,
verbose=1,
validation_data=(x_test, y_test),
shuffle=False)
score = model.evaluate(x_test, y_test, verbose=0)
print('Test loss:', score[0])
print('Test accuracy:', score[1])
However, there is something that concerns me. In segmentation problems \ multi-class problems, where the number of classes is very large, saving the solutions in categorical format is very wasteful. Moreover, doing that means that once you add a new class, the entire dataset should be changed accordingly.
That's why I thought using the normalizer feature of HDF5Matrix as following:
'''Trains a simple convnet on the MNIST dataset.
Gets to 99.25% test accuracy after 12 epochs
(there is still a lot of margin for parameter tuning).
16 seconds per epoch on a GRID K520 GPU.
'''
from __future__ import print_function
import keras
from keras.datasets import mnist
from keras.models import Sequential
from keras.layers import Dense, Dropout, Flatten
from keras.layers import Conv2D, MaxPooling2D
from keras import backend as K
# My Imports
from os.path import exists
import h5py
from keras.utils.io_utils import HDF5Matrix
batch_size = 128
num_classes = 10
epochs = 12
# input image dimensions
img_rows, img_cols = 28, 28
# the data, shuffled and split between train and test sets
(x_train, y_train), (x_test, y_test) = mnist.load_data()
if K.image_data_format() == 'channels_first':
x_train = x_train.reshape(x_train.shape[0], 1, img_rows, img_cols)
x_test = x_test.reshape(x_test.shape[0], 1, img_rows, img_cols)
input_shape = (1, img_rows, img_cols)
else:
x_train = x_train.reshape(x_train.shape[0], img_rows, img_cols, 1)
x_test = x_test.reshape(x_test.shape[0], img_rows, img_cols, 1)
input_shape = (img_rows, img_cols, 1)
x_train = x_train.astype('float32')
x_test = x_test.astype('float32')
x_train /= 255
x_test /= 255
print('x_train shape:', x_train.shape)
print(x_train.shape[0], 'train samples')
print(x_test.shape[0], 'test samples')
#-----------------------------------HDF5 files creation---------------------------------------
sample_file_name = "x.hdf5"
solution_file_name = "y.hdf5"
train_name = "train"
test_name = "test"
#Create dataset
if (not exists(sample_file_name)) and (not exists(solution_file_name)):
samples_file = h5py.File(sample_file_name,mode='a')
solutions_file = h5py.File(solution_file_name,mode='a')
samples_train = samples_file.create_dataset(train_name,data=x_train)
samples_test = samples_file.create_dataset(test_name, data=x_test)
solution_train = solutions_file.create_dataset(train_name, data=y_train)
solution_test = solutions_file.create_dataset(test_name, data=y_test)
samples_file.flush()
samples_file.close()
solutions_file.flush()
solutions_file.close()
x_train = HDF5Matrix(sample_file_name,train_name)
x_test = HDF5Matrix(sample_file_name,test_name)
y_train = HDF5Matrix(solution_file_name,train_name,normalizer=lambda solution: keras.utils.to_categorical(solution,num_classes))
y_test = HDF5Matrix(solution_file_name,test_name,normalizer=lambda solution: keras.utils.to_categorical(solution,num_classes))
#---------------------------------------------------------------------------------------------
model = Sequential()
model.add(Conv2D(32, kernel_size=(3, 3),
activation='relu',
input_shape=input_shape))
model.add(Conv2D(64, (3, 3), activation='relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.25))
model.add(Flatten())
model.add(Dense(128, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(num_classes, activation='softmax'))
model.compile(loss=keras.losses.categorical_crossentropy,
optimizer=keras.optimizers.Adadelta(),
metrics=['accuracy'])
# If using HDF5Matrix one needs to disable shuffle
model.fit(x_train, y_train,
batch_size=batch_size,
epochs=epochs,
verbose=1,
validation_data=(x_test, y_test),
shuffle=False)
score = model.evaluate(x_test, y_test, verbose=0)
print('Test loss:', score[0])
print('Test accuracy:', score[1])
However, this yields an error implying that the shape of the solution should match, and normalizer shouldn't be used that way:
ValueError: Error when checking target: expected dense_2 to have 2, but got array with shape (60000, 1, 10)
So, is there a way to save the data in HDF5 (and if not possible, using some other format), and use Keras in a manner that saves the labels (and not the categorical vector) without turning it into a regression problem?
You are getting this error because of these lines.
Keras checks input shapes before training. The problem is that HDF5Matrix will return the pre-normalized shape if you call .shape, then Keras will believe you have a (60000,) array for y_train and a (10000,) for y_test.
However, when accessing a slice of the matrix, the normalizer is applied so that for example y_train[5:7].shape does have the final expected shape: (2, 10).
This is mainly because the normalizer isn't really expected to change the shape, but Keras could indeed handle this case.
You can fix it by using fit_generator instead of fit so that training only sees normalized data:
def generator(features, labels, size):
while True:
start, end = 0, size
while end < len(features):
s = slice(start, end)
# you can actually do the normalization here if you want
yield features[s], labels[s]
start, end = end, end + size
model.fit_generator(
generator(x_train, y_train, batch_size),
steps_per_epoch=len(x_train) // batch_size,
epochs=1,
verbose=1,
validation_data=generator(x_test, y_test, batch_size),
validation_steps=len(x_test) // batch_size,
shuffle=False)
Note that you could do any kind of normalization inside the generator function and that will be transparent to Keras. And you can use different batch sizes for train and validation.
Also, you have to change the evaluation in the same way:
score = model.evaluate_generator(
generator(x_test, y_test, batch_size),
steps=len(x_test) // batch_size)
I think your solution with the normalizer is a good idea, by the way.

Categories