Skip to content

Instantly share code, notes, and snippets.

@fchollet
Last active July 23, 2024 16:32
Show Gist options
  • Save fchollet/7eb39b44eb9e16e59632d25fb3119975 to your computer and use it in GitHub Desktop.
Save fchollet/7eb39b44eb9e16e59632d25fb3119975 to your computer and use it in GitHub Desktop.
Fine-tuning a Keras model. Updated to the Keras 2.0 API.
'''This script goes along the blog post
"Building powerful image classification models using very little data"
from blog.keras.io.
It uses data that can be downloaded at:
https://www.kaggle.com/c/dogs-vs-cats/data
In our setup, we:
- created a data/ folder
- created train/ and validation/ subfolders inside data/
- created cats/ and dogs/ subfolders inside train/ and validation/
- put the cat pictures index 0-999 in data/train/cats
- put the cat pictures index 1000-1400 in data/validation/cats
- put the dogs pictures index 12500-13499 in data/train/dogs
- put the dog pictures index 13500-13900 in data/validation/dogs
So that we have 1000 training examples for each class, and 400 validation examples for each class.
In summary, this is our directory structure:
```
data/
train/
dogs/
dog001.jpg
dog002.jpg
...
cats/
cat001.jpg
cat002.jpg
...
validation/
dogs/
dog001.jpg
dog002.jpg
...
cats/
cat001.jpg
cat002.jpg
...
```
'''
from keras import applications
from keras.preprocessing.image import ImageDataGenerator
from keras import optimizers
from keras.models import Sequential
from keras.layers import Dropout, Flatten, Dense
# path to the model weights files.
weights_path = '../keras/examples/vgg16_weights.h5'
top_model_weights_path = 'fc_model.h5'
# dimensions of our images.
img_width, img_height = 150, 150
train_data_dir = 'cats_and_dogs_small/train'
validation_data_dir = 'cats_and_dogs_small/validation'
nb_train_samples = 2000
nb_validation_samples = 800
epochs = 50
batch_size = 16
# build the VGG16 network
model = applications.VGG16(weights='imagenet', include_top=False)
print('Model loaded.')
# build a classifier model to put on top of the convolutional model
top_model = Sequential()
top_model.add(Flatten(input_shape=model.output_shape[1:]))
top_model.add(Dense(256, activation='relu'))
top_model.add(Dropout(0.5))
top_model.add(Dense(1, activation='sigmoid'))
# note that it is necessary to start with a fully-trained
# classifier, including the top classifier,
# in order to successfully do fine-tuning
top_model.load_weights(top_model_weights_path)
# add the model on top of the convolutional base
model.add(top_model)
# set the first 25 layers (up to the last conv block)
# to non-trainable (weights will not be updated)
for layer in model.layers[:25]:
layer.trainable = False
# compile the model with a SGD/momentum optimizer
# and a very slow learning rate.
model.compile(loss='binary_crossentropy',
optimizer=optimizers.SGD(lr=1e-4, momentum=0.9),
metrics=['accuracy'])
# prepare data augmentation configuration
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(
train_data_dir,
target_size=(img_height, img_width),
batch_size=batch_size,
class_mode='binary')
validation_generator = test_datagen.flow_from_directory(
validation_data_dir,
target_size=(img_height, img_width),
batch_size=batch_size,
class_mode='binary')
# fine-tune the model
model.fit_generator(
train_generator,
samples_per_epoch=nb_train_samples,
epochs=epochs,
validation_data=validation_generator,
nb_val_samples=nb_validation_samples)
@savin333
Copy link

savin333 commented May 17, 2020

Fine tuned models' Prediction code

This codes were checked by myself. They all worked fine.

  1. If someone want to predict image classes in same model script where model were trained, here is the code :
img_width, img_height = 224, 224 
batch_size = 1 

datagen = ImageDataGenerator(rescale=1. / 255)

test_generator = datagen.flow_from_directory(  
         test_dir,  
         target_size=(img_width, img_height),
         batch_size=batch_size,  
         class_mode=None,  
         shuffle=False)  

test_generator.reset()
   
pred= model.predict_generator(test_generator, steps = no_of_images/batch_size)
predicted_class_indices=np.argmax(pred, axis =1 )
labels = (train_generator.class_indices)
labels = dict((v, k) for k, v in labels.items())
predictions = [labels[k] for k in predicted_class_indices]
print(predicted_class_indices)
print (labels)
print (predictions)

This code is inspired by stack overflow answer. click here

  1. If someone want to predict image classes in different script (separate from training script file), here is the code :
from tensorflow.python.keras.preprocessing.image import ImageDataGenerator
import json
import os
from tensorflow.keras.models import model_from_json
 
#Just give below lines parameters
best_weights = 'path to .h5 weight file'
model_json = 'path to saved model json file'
test_dir =  'path to test images'

img_width, img_height = 224, 224 
batch_size = 1
nb_img_samples = #no of testing images

with open(model_json, 'r') as json_file:
    json_savedModel= json_file.read()

model = tf.keras.models.model_from_json(json_savedModel)

model.summary()

model.load_weights(best_weights)

datagen = ImageDataGenerator(rescale=1. / 255)

test_generator = datagen.flow_from_directory(  
         folder_path,  
         target_size=(img_width, img_height),
         batch_size=batch_size,  
         class_mode=None,  
         shuffle=False)  

test_generator.reset()
   
pred= model.predict_generator(test_generator, steps = nb_img_samples/batch_size)
predicted_class_indices=np.argmax(pred,axis=1)
labels = {'cats': 0, 'dogs': 1} #if you have more classes, just add like this in correct order where your training folder order.
labels = dict((v,k) for k,v in labels.items())
predictions = [labels[k] for k in predicted_class_indices]
print(predicted_class_indices)
print (labels)
print (predictions) 

@allanchua101 only you have to edit this directorys path according to your drive file paths.

@lokoprof09
Copy link

lokoprof09 commented May 18, 2020 via email

@savin333
Copy link

@lokoprof09 you are welcome

@upcdz
Copy link

upcdz commented Apr 15, 2021

Hi, I get the following error when fine tuning with classifier_from_little_data_script_3.py . Any idea anyone please help.

Traceback (most recent call last):
File "classifier3.py", line 35, in
top_model.add(Dense(256, activation='relu'))
File "/home/zhang/ENTER/lib/python3.8/site-packages/tensorflow/python/training/tracking/base.py", line 456, in _method_wrapper
result = method(self, *args, **kwargs)
File "/home/zhang/ENTER/lib/python3.8/site-packages/tensorflow/python/keras/engine/sequential.py", line 213, in add
output_tensor = layer(self.outputs[0])
File "/home/zhang/ENTER/lib/python3.8/site-packages/tensorflow/python/keras/engine/base_layer.py", line 897, in call
self._maybe_build(inputs)
File "/home/zhang/ENTER/lib/python3.8/site-packages/tensorflow/python/keras/engine/base_layer.py", line 2416, in _maybe_build
self.build(input_shapes) # pylint:disable=not-callable
File "/home/zhang/ENTER/lib/python3.8/site-packages/tensorflow/python/keras/layers/core.py", line 1154, in build
raise ValueError('The last dimension of the inputs to Dense '
ValueError: The last dimension of the inputs to Dense should be defined. Found None.

@upcdz
Copy link

upcdz commented Apr 15, 2021

@fchollet I would really appreciate it if you can help me,

@EsraGuclu
Copy link

@upcdz

I got the same problem, the following line causes this error:

flatten = Flatten(name='flatten')(vgg16_output)

I changed this line with using GlobalAveragePooling2D(), then it worked.

flatten = GlobalAveragePooling2D()(vgg16_output)

@Gray-ly
Copy link

Gray-ly commented Aug 21, 2021

ValueError: The last dimension of the inputs to Dense should be defined. Found None.

@ashk3301
Copy link

ashk3301 commented Dec 1, 2022

Sorry, I got a error like that The shape of the input to "Flatten" is not fully defined (got (None, None, 512). Make sure to pass a complete "input_shape" or "batch_input_shape" argument to the first layer in your model.

I cannot find the weight file to download, '../keras/examples/vgg16_weights.h5' Thanks

@KennethYCK Hi! I am unable to understand how to get the input shape for my first layer. Can you help?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment