Trying to train a Resnet50 model from it's pre trained form but once it hits the code of training it, it throws this error ValueError: Shapes (None, 5) and (None, 1000) are incompatible I can't figure out what am I doing wrong here?
I have 5 classes dataset so that's why I am using categorical_crossentropy as the loss.
Full code is here:
# This is in for loop until labels.append
#load the image, pre-process it, and store it in the data list
image = cv2.imread(imagePath)
image = cv2.resize(image, (224, 224))
image = img_to_array(image)
data.append(image)
# extract the class label from the image path and update the
# labels list
label = imagePath.split(os.path.sep)[-2]
labels.append(label)
print("[INFO] ...reading the images completed", "+ Label class extracted.")
# scale the raw pixel intensities to the range [0, 1]
data = np.array(data, dtype="float") / 255.0
labels = np.array(labels)
print("[INFO] data matrix: {:.2f}MB".format(
data.nbytes / (1024 * 1000.0)))
# binarize the labels
lb = LabelBinarizer()
labels = lb.fit_transform(labels)
# partition the data into training and testing splits using 80% of
# the data for training and the remaining 20% for testing
(trainX, testX, trainY, testY) = train_test_split(data, labels, test_size=0.2, random_state=42)
model = ResNet50()
model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
print("[INFO] Model compilation completed.")
# train the network
print("[INFO] training network...")
H = model.fit(trainX, trainY, batch_size=BS,
validation_data=(testX, testY),
steps_per_epoch=len(trainX) // BS,
epochs=EPOCHS, verbose=1)
Try adding a layer with the proper number of categories for your task:
base = ResNet50(include_top=False, pooling='avg')
out = K.layers.Dense(5, activation='softmax')
model = K.Model(inputs=base.input, outputs=out(base.output))
You have used the fully connected layers of the pre-trained ResNet, you need to create your appropriate classification layers suitable for your task.
from tensorflow.keras.layers import GlobalAveragePooling2D
from tensorflow.keras import Model
model = ResNet50(include_top=False)
f_flat = GlobalAveragePooling2D()(model.output)
fc = Dense(units=2048,activation="relu")(f_flat)
logit = Dense(units=5, activation="softmax")(fc)
model = Model(model.inputs,logit)
Related
I need help with some Machine Learning code of mine.
I am using the base of a pretrained model by google and adding the last flattening and output layers of my own.
After training the model and saving it, I commented out the training part of the code and loaded and used the saved model.
my code:
import tensorflow as tf
from tensorflow import keras
import numpy as np
import matplotlib.pyplot as plt
import tensorflow_datasets as tfds
tfds.disable_progress_bar()
class_names = ['cat','dog']
#load the images
(raw_train, raw_validation, raw_test), metadata = tfds.load(
'cats_vs_dogs',
split=['train[:80%]', 'train[80%:90%]', 'train[90%:]'],
with_info=True,
as_supervised=True,
)
get_label_name = metadata.features['label'].int2str
#function to resize image
IMG_SIZE=160
def format_example(image, label):
image = tf.cast(image, tf.float32) #cast to convert integer values in pixels to float32
image = (image/127.5) - 1
image = tf.image.resize(image, (IMG_SIZE, IMG_SIZE))
return image,label
#.map is to apply a function to all raw images
train = raw_train.map(format_example)
validation = raw_validation.map(format_example)
test = raw_test.map(format_example)
BATCH_SIZE = 32
SHUFFLE_BUFFER_SIZE = 1000
train_batches = train.shuffle(SHUFFLE_BUFFER_SIZE).batch(BATCH_SIZE)
validation_batches = validation.batch(BATCH_SIZE)
test_batches = test.batch(BATCH_SIZE)
IMG_SHAPE = (IMG_SIZE, IMG_SIZE, 3)
#Create base model from pretrained model MobileNetV2
base_model = tf.keras.applications.MobileNetV2(input_shape=IMG_SHAPE,
include_top=False,
weights='imagenet')
#freezing the base (preventing any more training)
base_model.trainable = False
#Flattening it down
global_average_layer = tf.keras.layers.GlobalAveragePooling2D()
#Adding dense layer of only 1 neuron as only 2 possibilities(cat/dog)
prediction_layer = keras.layers.Dense(1)
model = tf.keras.Sequential([
base_model,
global_average_layer,
prediction_layer
])
#slow learning rate since it is a pretrained model
base_learning_rate = 0.0001
#Compiling the model
model.compile(optimizer=tf.keras.optimizers.RMSprop(lr=base_learning_rate),
loss=tf.keras.losses.BinaryCrossentropy(from_logits=True),
metrics=['accuracy'])
initial_epochs = 3
validation_steps=20
loss0,accuracy0 = model.evaluate(validation_batches, steps = validation_steps)
print('training...')
history = model.fit(train_batches,
epochs=initial_epochs,
validation_data = validation_batches)
acc = history.history['accuracy']
print(acc)
model.save("dogs_vs_cats.h5")
model = tf.keras.models.load_model('dogs_vs_cats.h5', compile=True)
print('predicting... ')
prediction = model.predict(test, verbose=1)
print(prediction)
I am getting the following error:
ValueError: Input 0 of layer "sequential" is incompatible with the layer: expected shape=(None, 160, 160, 3), found shape=(160, 160, 3)
Do I understand correctly that you get this error only after you comment training code and run lines starting from model = tf.keras.models.load_model('dogs_vs_cats.h5', compile=True)? If yes, I think that you have a mistake in this line:
prediction = model.predict(test, verbose=1)
You use test with 3D-images, but not batched test_batches with 4D-images, this is why you obtain an error with 3D/4D shapes.
I am working on a small project where i wanted to classify some images by training them within a convolutional network, with a pretrained VGG16 network.
These are the steps i took:
#Setting Conditions
img_size = (180,180)
batch_size = 600
num_classes = len(class_names)
#Using Keras built in preprocessing method which facilitates the preprocessing instead of having to do it manually.
train_ds = tf.keras.preprocessing.image_dataset_from_directory(
"Data/Train",
validation_split = 0.2,
subset = "training",
seed = 1337, # creating a seed so t
image_size = img_size,
batch_size = batch_size,
)
valid_ds = tf.keras.preprocessing.image_dataset_from_directory(
"Data/Train",
validation_split = 0.2,
subset = "validation",
seed = 1337, # creating a seed so t
image_size = img_size,
batch_size = batch_size,
)
BUILDING MODEL
#Creating Model
model = Sequential()
#ADDING The VGG16 Pre trained network
model.add(VGG16(pooling ='avg',weights="imagenet", include_top=False))
#adding a dense layer
model.add(Dense(num_classes,activation = 'softmax'))
#Setting the trainable parameter for VGG16 to false, as we want to use this pretrained network, and train the new images.
model.layers[0].trainable = False
#The compile() method: specifying a loss, metrics, and an optimizer To train a model with fit(), #you need to specify a loss function, an optimizer, and optionally, some metrics to monitor.
#You pass these to the model as arguments to the compile() method
model.compile(optimizer = 'adam',loss = 'categorical_crossentropy', metrics =['accuracy'])
epoch_train = len(train_ds)
opoch_val = len(valid_ds)
numbers_epochs = 2
fit_model = model.fit(train_ds, steps_per_epoch = epoch_train,verbose = 1, validation_data = valid_ds, validation_steps = opoch_val,)
When i try to fit the model, i get the following error:
ValueError: Shapes (None, 1) and (None, 43) are incompatible
If there is an expert out there to call out what i did wrong or what steps i skipped... I would be very greatful!
You need to set label_mode='categorical in image_dataset_from_directory if you plan to train your model with categorical_crossentropy. By default, the image_dataset_from_directory method assumes that the labels are encoded as integers (label_mode='int'), meaning you should being using the sparse_categorical_crossentropy loss. Here is a working example:
import tensorflow as tf
import pathlib
import matplotlib.pyplot as plt
dataset_url = "https://storage.googleapis.com/download.tensorflow.org/example_images/flower_photos.tgz"
data_dir = tf.keras.utils.get_file('flower_photos', origin=dataset_url, untar=True)
data_dir = pathlib.Path(data_dir)
batch_size = 32
num_classes = 5
train_ds = tf.keras.utils.image_dataset_from_directory(data_dir, shuffle=True, batch_size=batch_size, label_mode='categorical')
model = tf.keras.Sequential()
model.add(tf.keras.applications.VGG16(pooling ='avg',weights="imagenet", include_top=False))
model.add(tf.keras.layers.Dense(num_classes, activation = 'softmax'))
model.layers[0].trainable = False
model.compile(optimizer = 'adam',loss = 'categorical_crossentropy', metrics =['accuracy'])
numbers_epochs = 2
fit_model = model.fit(train_ds, epochs=numbers_epochs)
I've loaded in my train and validation sets from CIFAR10 like so:
train = tfds.load('cifar10', split='train[:90%]', shuffle_files=True)
validation = tfds.load('cifar10', split='train[-10%:]', shuffle_files=True)
I've created the architecture for my CNN
model = ...
Now I'm trying to use model.fit() to train my model but I don't know how to seperate out the 'image' and 'label' from my objects. Train and Validation look like this:
print(train) # same layout as the validation set
<_OptionsDataset shapes: {id: (), image: (32, 32, 3), label: ()}, types: {id: tf.string, image: tf.uint8, label: tf.int64}>
My naive approach would be this but those OptionsDatasets are not subscript-able.
history = model.fit(train['image'], train['label'], epochs=100, batch_size=64, validation_data=(validation['image'], test['label'], verbose=0)
We can do this as follows
import tensorflow as tf
import tensorflow_datasets as tfds
def normalize(img, label):
img = tf.cast(img, tf.float32) / 255.
return (img, label)
ds = tfds.load('mnist', split='train', as_supervised=True)
ds = ds.shuffle(1024).batch(32).prefetch(tf.data.experimental.AUTOTUNE)
ds = ds.map(normalize)
for i in ds.take(1):
print(i[0].shape, i[1].shape)
# (32, 28, 28, 1) (32,)
Use as_supervised=True for returning an image, label as tuple
Use .map() for applying preprocessing funciton or even augmentation.
Model
# declare input shape
input = tf.keras.Input(shape=(28,28,1))
# Block 1
x = tf.keras.layers.Conv2D(32, 3, strides=2, activation="relu")(input)
# Now that we apply global max pooling.
gap = tf.keras.layers.GlobalMaxPooling2D()(x)
# Finally, we add a classification layer.
output = tf.keras.layers.Dense(10, activation='softmax')(gap)
# bind all
func_model = tf.keras.Model(input, output)
Compile and Run
print('\nFunctional API')
func_model.compile(
metrics=['accuracy'],
loss= 'sparse_categorical_crossentropy', # labels are integer (not one-hot)
optimizer = tf.keras.optimizers.Adam()
)
func_model.fit(ds)
# 1875/1875 [==============================] - 15s 7ms/step - loss: 2.1782 - accuracy: 0.2280
Tensorflow knows how to handle the tfds objects. So in your case you can just do
history = model.fit(train, epochs=100, batch_size=64, validation_data=(validation, verbose=0)
No need to split out the labels from the images. But if you really want to you can do the following
labels = []
for image, label in tfds.as_numpy(train):
labels.append(label)
I'm trying to create model for facial emotion recognition.
My dataset is from "kaggle face recognition" (or sth like this).
Set is in *.csv file emotion+pixels (as a string eg. "3, pixel pixel pixel...") and I'm preprocessing it by this method:
def resizeImages(x):
x = x.astype('float32')
x = x / 255.0
return x
def loadData():
print("Data loading START")
rawData = pd.read_csv("../data/data.csv")
pixels = rawData['pixels'].tolist()
images = []
for each in pixels:
image = [int(pixel) for pixel in each.split()]
image = np.asarray(image).reshape(width, height)
images.append(image.astype('float32'))
images = np.asarray(images)
images = np.expand_dims(images, -1)
images = np.repeat(images, 3, axis=3)
emotions = pd.get_dummies(rawData['emotion'])
print(emotions)
images = resizeImages(images)
print("Data loading DONE")
return images, emotions
My model is made like this:
#Constants
width, height, depth = 48, 48, 3
numOfClasses = 7
epochs = 10
batch_size = 50
#Loading Data
from Model.DataProcess import loadData
pixels, emotions = loadData()
#Spliting Data
from sklearn.model_selection import train_test_split
xtrain, xtest, ytrain, ytest = train_test_split(pixels, emotions, test_size = 0.2)
#Loading VGG16 Model
from keras.applications.vgg16 import VGG16
vgg16model = VGG16(include_top=False, weights='imagenet',
input_shape=(width, height, depth), pooling='avg')
#Frezzing layers at VGG16 model - not trainable
for layer in vgg16model.layers:
layer.trainable = False
#Creating final classifier
from keras.models import Sequential
from keras.layers import Dropout, Dense
myModel = Sequential([
vgg16model,
Dense(256, input_shape=(512,), activation="relu"),
Dense(256, input_shape=(256,), activation="relu"),
Dropout(0.25),
Dense(128, input_shape=(256,)),
Dense(output_dim=numOfClasses, activation="softmax")
])
myModel.summary()
#Creating optimizer
from keras.optimizers import Adamax
adamax = Adamax()
myModel.compile(loss='categorical_crossentropy',
optimizer=adamax,
metrics=['accuracy'])
#Fiting model
history = myModel.fit(
xtrain, ytrain,
epochs=epochs,
validation_data=(xtest, ytest),
callbacks = callbacks
)
Am I doing something wrong, couse after a bunch op epchos my loss is still about 1.5 and accuracy is nearly 0.4
I want to use bottlenecks for transfer learning using InceptionV3 in Keras.
I've used some of the tips on creating, loading and using bottlenecks from
https://blog.keras.io/building-powerful-image-classification-models-using-very-little-data.html
My problem is that I don't know how to use a bottleneck (numpy array) as input to an InceptionV3 with a new top layer.
I get the following error:
ValueError: Error when checking input: expected input_3 to have shape
(None, None, None, 3) but got array with shape (248, 8, 8, 2048)
248 refers to the total number of images in this case.
I know that this line is wrong, but I dont't know how to correct it:
model = Model(inputs=base_model.input, outputs=predictions)
What is the correct way to input the bottleneck into InceptionV3?
Creating the InceptionV3 bottlenecks:
def create_bottlenecks():
datagen = ImageDataGenerator(rescale=1. / 255)
model = InceptionV3(include_top=False, weights='imagenet')
# Generate bottlenecks for all training images
generator = datagen.flow_from_directory(
train_data_dir,
target_size=(img_width, img_height),
batch_size=batch_size,
class_mode=None,
shuffle=False)
nb_train_samples = len(generator.filenames)
bottlenecks_train = model.predict_generator(generator, int(math.ceil(nb_train_samples / float(batch_size))), verbose=1)
np.save(open(train_bottlenecks_file, 'w'), bottlenecks_train)
# Generate bottlenecks for all validation images
generator = datagen.flow_from_directory(
validation_data_dir,
target_size=(img_width, img_height),
batch_size=batch_size,
class_mode=None,
shuffle=False)
nb_validation_samples = len(generator.filenames)
bottlenecks_validation = model.predict_generator(generator, int(math.ceil(nb_validation_samples / float(batch_size))), verbose=1)
np.save(open(validation_bottlenecks_file, 'w'), bottlenecks_validation)
Loading the bottlenecks:
def load_bottlenecks(src_dir, bottleneck_file):
datagen = ImageDataGenerator(rescale=1. / 255)
generator = datagen.flow_from_directory(
src_dir,
target_size=(img_width, img_height),
batch_size=batch_size,
class_mode='categorical',
shuffle=False)
num_classes = len(generator.class_indices)
# load the bottleneck features saved earlier
bottleneck_data = np.load(bottleneck_file)
# get the class lebels for the training data, in the original order
bottleneck_class_labels = generator.classes
# convert the training labels to categorical vectors
bottleneck_class_labels = to_categorical(bottleneck_class_labels, num_classes=num_classes)
return bottleneck_data, bottleneck_class_labels
Starting training:
def start_training():
global nb_train_samples, nb_validation_samples
create_bottlenecks()
train_data, train_labels = load_bottlenecks(train_data_dir, train_bottlenecks_file)
validation_data, validation_labels = load_bottlenecks(validation_data_dir, validation_bottlenecks_file)
nb_train_samples = len(train_data)
nb_validation_samples = len(validation_data)
base_model = InceptionV3(weights='imagenet', include_top=False)
# add a global spatial average pooling layer
x = base_model.output
x = GlobalAveragePooling2D()(x)
# let's add a fully-connected layer
x = Dense(1024, activation='relu')(x)
# and a logistic layer -- let's say we have 2 classes
predictions = Dense(2, activation='softmax')(x)
# What is the correct input? Obviously not base_model.input.
model = Model(inputs=base_model.input, outputs=predictions)
# first: train only the top layers (which were randomly initialized)
# i.e. freeze all convolutional InceptionV3 layers
for layer in base_model.layers:
layer.trainable = False
model.compile(optimizer=optimizers.SGD(lr=0.01, momentum=0.9), loss='categorical_crossentropy', metrics=['accuracy'])
# train the model on the new data for a few epochs
history = model.fit(train_data, train_labels,
epochs=epochs,
batch_size=batch_size,
validation_data=(validation_data, validation_labels),
)
Any help would be appreciated!
This error happens when you try to train your model with input data in a different shape from the shape your model supports.
Your model supports (None, None, None, 3), meaning:
Any number of images
Any height
Any width
3 channels
So, you must make sure that train_data (and validation_data) matches this shape.
The system is telling that train_data.shape = (248,8,8,2048)
I see that train_data comes from load_botlenecks. Is it really supposed to be coming from there? What is train data supposed to be? An image? Something else? What is a bottleneck?
Your model starts in the Inception model, and the Inception model takes images.
But if bottlenecks are already results of the Inception model, and you want to feed only bottlenecks, then the Inception model should not participate of anything at all.
Start from:
inputTensor = Input((8,8,2048)) #Use (None,None,2048) if bottlenecks vary in size
x = GlobalAveragePooling2D()(inputTensor)
.....
Create the model with:
model = Model(inputTensor, predictions)
The idea is:
Inception model: Image -> Inception -> Bottlenecks
Your model: Bottlenecks -> Model -> Labels
The combination of the two models is only necessary when you don't have the bottlenecks preloaded, but you have your own images for which you want to predict the bottlenecks first. (Of course you can work with separate models as well)
Then you're going to input only images (the bottlenecks will be created by Inception and passed to your model, everything internally):
Combined model: Image -> Inception ->(bottlenecks)-> Model -> Labels
For that:
inputImage = Input((None,None,3))
bottleNecks = base_model(inputImage)
predictions = model(bottleNecks)
fullModel = Model(inputImage, predictions)