import os
from keras.preprocessing.image import ImageDataGenerator
from keras.models import Sequential
from keras.layers import Convolution2D, MaxPooling2D
from keras.layers import Activation, Dropout, Flatten, Dense
img_width, img_height = 64, 64
train_data_dir = 'data/train'
validation_data_dir = 'data/validation'
nb_train_samples = sum([len(files) for files in os.walk(train_data_dir)])
nb_validation_samples = sum([len(files) for files in os.walk(validation_data_dir)])
nb_epoch = 10
model = Sequential()
model.add(Dense(4096, input_dim = 4096, init='normal', activation='relu'))
model.add(Dense(4,init='normal',activation='softmax'))
model.compile(loss='categorical_crossentropy',
optimizer='adam',
metrics=['accuracy'])
train_datagen = ImageDataGenerator(
rescale=1./255,
)
test_datagen = ImageDataGenerator(rescale=1./255)
train_generator = train_datagen.flow_from_directory(
train_data_dir,
color_mode="grayscale",
target_size=(img_width, img_height),
batch_size=1,
class_mode=None)
validation_generator = test_datagen.flow_from_directory(
validation_data_dir,
color_mode="grayscale",
target_size=(img_width, img_height),
batch_size=1,
class_mode=None)
model.fit_generator(
train_generator,
samples_per_epoch=nb_train_samples,
nb_epoch=nb_epoch,
validation_data=validation_generator,
nb_val_samples=nb_validation_samples)
Everything runs fine until the model.fit_generator() in the coding above. Then it pop out errors like the the followed.
Traceback (most recent call last):
File "C:/Users/Sam/PycharmProjects/MLP/Testing Code without CNN.py", line 55, in <module>
nb_val_samples=nb_validation_samples)
File "C:\Python27\lib\site-packages\keras\models.py", line 874, in fit_generator
pickle_safe=pickle_safe)
File "C:\Python27\lib\site-packages\keras\engine\training.py", line 1427, in fit_generator
'or (x, y). Found: ' + str(generator_output))
Exception: output of generator should be a tuple (x, y, sample_weight) or (x, y). Found: [[[[ 0.19215688]
The problem should be caused by data dimension mismatch. ImageDataGenerator actually loads image files and put into numpy array in shape of (num_image_channel, image_height, image_width). But your first layer is a densely connected layer, which is looking for input data in the shape of 1D array, or 2D array with a number of samples. So essentially you are missing your input layer, which takes the input in the right shape.
Change the following line of code
model.add(Dense(4096, input_dim = 4096, init='normal', activation='relu'))
to
model.add(Reshape((img_width*img_height*img_channel), input_shape=(img_channel, img_height, img_width)))
model.add(Dense(4096, init='normal', activation='relu'))
You have to define img_channel, which is the number of channels in your images. The above code also assumes that your are using dim_ordering of th. If you are using tf input dimension ordering, you would have to change the input reshape layer to
model.add(Reshape((img_width*img_height*img_channel), input_shape=(img_height, img_width, img_channel)))
--- Old answer --
You probably have put training data and validation data into subfolders under train and validation, which isn't supported by Keras. All training data should be in one single folder, same for the validation data.
Please refer to this Keras tutorial for more details.
I am not 100% sure what you are trying to achieve but if you are trying a binary classification of pictures, try setting class_mode to binary. From the documentation:
class_mode: one of "categorical", "binary", "sparse" or None. Default:
"categorical". Determines the type of label arrays that are returned:
"categorical" will be 2D one-hot encoded labels, "binary" will be 1D
binary labels, "sparse" will be 1D integer labels.
The error message is a bit confusing but if you look at the source code, it becomes clearer:
if not hasattr(generator_output, '__len__'):
_stop.set()
raise Exception('output of generator should be a tuple '
'(x, y, sample_weight) '
'or (x, y). Found: ' + str(generator_output))
Related
I want to classify 40 types of car logos. I used softmax and sparse_categorical_crossentropy but error still occurs. What's wrong with this code?
ValueError: Error when checking target: expected dense_8 to have
shape (1,) but got array with shape (40,)
My code:
from keras.models import Sequential
from keras.layers import Conv2D
from keras.layers import MaxPooling2D
from keras.layers import Flatten
from keras.layers import Dense
import keras
classifier=Sequential()
classifier.add(Conv2D(32,3,3,input_shape=(50,50,3),activation='relu'))
classifier.add(MaxPooling2D(pool_size=(2,2)))
classifier.add(Flatten())
classifier.add(Dense(output_dim=128,activation='relu'))
classifier.add(Dense(output_dim=40,activation='softmax'))
loss_fn = keras.losses.SparseCategoricalCrossentropy()
classifier.compile(optimizer='adam',loss='sparse_categorical_crossentropy',metrics=['accuracy'])
from keras.preprocessing.image import ImageDataGenerator
train_datagen = ImageDataGenerator(
rescale=1./255,
shear_range=0.2,
zoom_range=0.2,
horizontal_flip=True)
test_datagen = ImageDataGenerator(rescale=1./255)
train_generator = train_datagen.flow_from_directory(
'dataset/train_set',
target_size=(50, 50),
batch_size=32,
class_mode='categorical')
validation_generator = test_datagen.flow_from_directory(
'dataset/test_set',
target_size=(50, 50),
batch_size=32,
class_mode='categorical')
classifier.fit(
train_generator,
steps_per_epoch=2000,
epochs=50,
validation_data=validation_generator,
validation_steps=800)
You are using the sparse_categorical_crossentropy however in your code part it is not mentioned how you have encoded the labels. If the levels are already one hot encoded then use categorical_crossentropy loss as sparse_categorical_crossentropy loss needs integer labels and does the one-hot encoding internally.
However it depends on the how your training dataset is which I do not see in the question here
just starting out with ML, and wanted to create my own CNN to detect orientation of images with faces. I followed a tutorial to accept input images of 64x64x1, and here is my code:
from keras.models import Model
from keras.layers import Input
from keras.layers import Dense
from keras.layers import Flatten
from keras.layers.convolutional import Conv2D
from keras.layers.pooling import MaxPooling2D
from keras.preprocessing.image import ImageDataGenerator
datagen = ImageDataGenerator()
train_it = datagen.flow_from_directory('firstThousandTransformed/', class_mode='categorical', batch_size=64, color_mode="grayscale")
val_it = datagen.flow_from_directory('validation/', class_mode='categorical', batch_size=64, color_mode="grayscale")
imageInput = Input(shape=(64,64,1))
conv1 = Conv2D(32, kernel_size=4, activation='relu')(imageInput)
pool1 = MaxPooling2D(pool_size=(2, 2))(conv1)
conv2 = Conv2D(16, kernel_size=4, activation='relu')(pool1)
pool2 = MaxPooling2D(pool_size=(2, 2))(conv2)
flat = Flatten()(pool2)
hidden1 = Dense(10, activation='relu')(flat)
output = Dense(4, activation='sigmoid')(hidden1)
model = Model(inputs=imageInput, outputs=output)
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
print(model.summary())
model.fit(train_it, steps_per_epoch=16, validation_data=val_it, validation_steps=8)
However, I get this error when I try to run:
Input to reshape is a tensor with 3810304 values, but the requested
shape requires a multiple of 2704 [[node model/flatten/Reshape
(defined at c:\Users\cdues\Desktop\kerasTutorial\orentationTry.py:33)
]] [Op:__inference_train_function_836]
Below is my model summary:
I need some help understanding what a Tensor shape is and where my code has gone wrong here. Just working through the tutorial with Keras, I didn't encounter Tensor shape and now I am sort of lost. Sorry for the basic question, can yall help a noobie out? Thanks!
Try using the target_size argument while calling flow_from_directory.
train_it = datagen.flow_from_directory('firstThousandTransformed/',
class_mode='categorical',
batch_size=64,
color_mode='grayscale',
target_size=(64,64))
val_it = datagen.flow_from_directory('validation/',
class_mode='categorical',
batch_size=64,
color_mode='grayscale',
target_size=(64,64))
This way you can reshape the images from the directories before feeding to the model.
First in ImageDataGenerator there is a parameter called rescale. Typically with pixel values in the range 0 to 255 rescale is set to 1/255 so pixel value fall in the range from 0 to 1. I recommend you use that. Documentation for ImageDataGenerator is here.. In flow from directory you can specify the image size with parameter target_size: Tuple of integers (height, width), default: (256, 256). Documentation is at location specified earlier. In your model you have 4 nodes in your output layer. This implies you are classifying images into one of 4 classes. If that is the case in model.compile you should use categorical cross entropy as the loss. Change the activation function in your output layer to softmax.
I'm writing a CNN classifier for 20 classes. As mentioned in the title, this is the error i get when i try to fit my model.
I've already checked this answer: Error, but i have already (i think) set the categorical conversion.
Here's my code:
1) Imagegenerator:
apply_data_augmentation = True
if apply_data_augmentation:
train_datagen = ImageDataGenerator(rotation_range=10, #Training data generator + validation split (20%)
width_shift_range=10,
height_shift_range=10,
zoom_range=0.3,
horizontal_flip=True,
vertical_flip=True,
fill_mode='constant',
cval=0,
rescale=1./255,
validation_split=0.2)
else:
train_datagen = ImageDataGenerator(rescale=1./255)
2) Getting data:
dataset_dir = os.path.join(cwd, 'Classification_Dataset')
bs = 8
# img shape
img_h = 28
img_w = 28
num_classes=20
decide_class_indices = False
if decide_class_indices:
classes = ['airplane', # 0
'bear', # 1
'calculator', # 2
'computer-monitor', # 3
'fireworks', # 4
'galaxy', # 5
'grand-piano', # 6
'kangaroo', # 7
'laptop', # 8
'lightbulb', # 9
'lightning', # 10
'mountain-bike', # 11
'owl', # 12
'school-bus', # 13
'sheet-music', # 14
'skyscraper', # 15
'sword', # 16
't-shirt', # 17
'waterfall', # 18
'wine-bottle'] # 19
else:
classes=None
print(classes)
# Training
training_dir = os.path.join(dataset_dir, 'training')
train_generator = train_datagen.flow_from_directory(
training_dir,
target_size=(img_h, img_w),
batch_size=bs,
class_mode='categorical',
classes=classes,
subset='training',
shuffle=True,
seed=SEED) # set as training data
validation_generator = train_datagen.flow_from_directory(
training_dir, # same directory as training data
target_size=(img_h, img_w),
batch_size=bs,
class_mode='categorical',
classes=classes,
subset='validation',
shuffle=False,
seed=SEED) # set as validation data
print(train_generator)
3) Model + fit:
from keras.datasets import mnist
import matplotlib.pyplot as plt
import numpy as np
from keras import Sequential
from keras.layers import Conv2D, AveragePooling2D, Flatten, Dense, Dropout
from keras.callbacks import EarlyStopping
model = Sequential()
model.add(Conv2D(filters=6, kernel_size=(3, 3), activation='relu', input_shape=(28,28,3)))
model.add(AveragePooling2D())
model.add(Conv2D(filters=16, kernel_size=(3, 3), activation='relu'))
model.add(AveragePooling2D())
model.add(Flatten())
model.add(Dense(units=120, activation='relu'))
model.add(Dropout(0.3))
model.add(Dense(units=100, activation='relu'))
model.add(Dropout(0.3))
model.add(Dense(units=20, activation='softmax'))
model.compile(optimizer='adam',
loss='sparse_categorical_crossentropy',
metrics=['accuracy'])
nb_epochs = 5
model.fit_generator(
train_generator,
steps_per_epoch = train_generator.samples // bs,
validation_data = validation_generator,
validation_steps = validation_generator.samples // bs,
epochs = nb_epochs)
I checked all the possible problems mentioned in many questions (such as missing flatten layers, categorical conversion, non matching inputs, ) but (at least to me) everything seems fine.
I can't understand where's the problem.
Your flow_from_directory function with class_mode='categorical' generates one-hot encoded 2D labels (Ref) whereas sparse_categorical_crossentropy expects integer value. You have two ways to fix the issue:
1. Change the loss function to categorical_crossentropy when you compile your model
2. Change the label to sparse mode by using class_mode='sparse' in the flow_from_directory function
In a nutshell, when your label is an integer value (representing class) use sparse_categorical_crossentropy and when label is one-hot encoded use categorical_crossentropy as loss function.
I use keras and import VGG16 network with imagenet weights to classify male/female photos.
Strcture of directories is:
split_1/train/male/*.jpg
split_1/train/female/*.jpg
split_1/val/female/*.jpg
split_1/val/male/*.jpg
I tried most of the solutions I found over the internet but none of them worked:
changing batch_size
changing optimizers
changing class_mode/loss function
setting every layer to trainable
copying every layer from VGG to my sequential
import numpy as np
from keras.preprocessing.image import ImageDataGenerator
from keras.models import Sequential
from keras.layers import Dropout, Flatten, Dense
from keras import applications
[...]
img_width, img_height = 224, 224
top_model_weights_path = "%s_retry2.h5" % split
train_data_dir = "%s/train" % split
validation_data_dir = "%s/val" % split
batch_size = 48
nb_train_samples = 4000
nb_validation_samples = ( 299 // batch_size ) * batch_size
epochs = 5
def train_top_model():
datagen = ImageDataGenerator(
horizontal_flip=True,
shear_range=0.2,
rescale=1. / 255)
vdatagen = ImageDataGenerator(rescale=1./255)
traingen = datagen.flow_from_directory(
train_data_dir,
target_size=(img_width, img_height),
batch_size=batch_size,
class_mode='categorical',
follow_links=True,
shuffle=True)
valgen = vdatagen.flow_from_directory(
validation_data_dir,
target_size=(img_width, img_height),
batch_size=batch_size,
class_mode='categorical',
follow_links=True,
shuffle=True)
vgg_model = applications.VGG16(input_shape=(224,224,3), weights="imagenet", include_top=False)
model = Sequential()
model.add(vgg_model)
model.add(Flatten())
model.add(Dense(2, activation='softmax'))
model.compile(optimizer="rmsprop", loss='categorical_crossentropy', metrics=['accuracy'])
history = model.fit_generator(traingen,
epochs=epochs,
steps_per_epoch=nb_train_samples // batch_size,
validation_data=valgen,
validation_steps=nb_validation_samples // batch_size)
It reports actual amount of images so it finds the jpgs properly.
Accuracy in val keeps being "random" and the same (~50%) during entire training.
Try reducing the learning rate, it may be the case where your model is overshooting the minima every time and hence not able to converge.
If any kind of hyper parameter tuning doesn't work then you need to fix your data but i think male/female classification data shouldn't be that tough to learn for a CNN model with pre-trained weights.
How Many sample do you have per class???
It seems that you don't have enough data to fine tune these large scale parameters that VGG16 has. (138 million if you trainable all the layers)
I suggest :
1. for gender classification problem, Try to use an official dataset such as IMDB-WIKI
2. If you wanna use your own data first collect more label sample and after that augment all of them
3. finally, Use state of the art CNN architectures such as Xception (you can load imagenet pre-traind of xception in keras) freeze 20 first layers and fune tune others
With VGG 16 using Keras, I'm trying to run a three class classification problem and here is the code:
import numpy as np
from keras.preprocessing.image import ImageDataGenerator
from keras.models import Sequential
from keras.layers import Dropout, Flatten, Dense
from keras import applications
from keras.optimizers import SGD
from keras import backend as K
K.set_image_dim_ordering('tf')
img_width, img_height = 48, 48
top_model_weights_path = 'vgg16_1.h5'
train_data_dir = 'data6/train'
validation_data_dir = 'data6/validation'
nb_train_samples = 400
nb_validation_samples = 100
epochs = 10
batch_size = 32
def save_bottlebeck_features():
datagen = ImageDataGenerator(rescale=1. / 255)
model = applications.VGG16(include_top=False, weights='imagenet', input_shape=(48, 48, 3))
generator = datagen.flow_from_directory(
train_data_dir,
target_size=(img_width, img_height),
batch_size=batch_size,
class_mode='categorical',
shuffle=False)
bottleneck_features_train = model.predict_generator(
generator, nb_train_samples // batch_size)
np.save(open('bottleneck_features_train', 'wb'),bottleneck_features_train)
generator = datagen.flow_from_directory(
validation_data_dir,
target_size=(img_width, img_height),
batch_size=batch_size,
class_mode='categorical',
shuffle=False)
bottleneck_features_validation = model.predict_generator(
generator, nb_validation_samples // batch_size)
np.save(open('bottleneck_features_validation', 'wb'),bottleneck_features_validation)
def train_top_model():
train_data = np.load(open('bottleneck_features_train', 'rb'))
train_labels = np.array(([0]*(nb_train_samples // 3) + [1]*(nb_train_samples // 3) +
[2]*(nb_train_samples // 3)))
validation_data = np.load(open('bottleneck_features_validation', 'rb'))
validation_labels = np.array([0]*(nb_validation_samples // 3) + [1]*(nb_validation_samples // 3) +
[2]*(nb_validation_samples // 3))
model = Sequential()
model.add(Flatten(input_shape=train_data.shape[1:]))
model.add(Dense(128, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(3, activation='softmax'))
sgd = SGD(lr=1e-2, decay=0.00371, momentum=0.9, nesterov=False)
model.compile(optimizer=sgd,
loss='categorical_crossentropy', metrics=['accuracy'])
model.fit(train_data, train_labels,
epochs=epochs,
batch_size=batch_size,
validation_data=(validation_data, validation_labels))
model.save_weights(top_model_weights_path)
save_bottlebeck_features()
train_top_model()
Running the code, I'm getting the error:
Error when checking target: expected dense_20 to have shape (None, 3) but got
array with shape (1200, 1)
Kindly let me know what changes I have to make to the code to make it function. I'm using Anaconda with Python 3.5.2, running on a windows machine.
Your training output is shaped like (None, 1) --- Or (1200, 1), where there are 1200 samples, all samples with only one dimension (each sample is a number)
But your model ends with Dense(3), which will output things like (None, 3). That is: each sample has 3 numbers.
If you think your training data is correct, you must adjust your model.
A suggestion is add one more Dense(1) layer. With a "sigmoid" activation if the result is between 0 and 1, or a "tanh" if the result is between -1 and 1.
Always use model.summary() to check what dimensions your model have.