Hi,
I have being trying to train model on google Colab. The aim is to identify between different plant leaves such as strawberry, apple and Soybean etc.
Below is the code that I have so far.
from google.colab import drive
drive.mount('/content/drive/')
!ls -l "/content/drive/Othercomputers/My_MacBook_Pro/"
import tensorflow as tf
from tensorflow.keras.preprocessing.image import ImageDataGenerator
# path to 'train' and 'valid' directories
train_dir = '/content/drive/Othercomputers/My_MacBook_Pro/Strawberry/train'
validation_dir = '/content/drive/Othercomputers/My_MacBook_Pro/Strawberry/valid'
# Set up data generators without augmentation
train_datagen = ImageDataGenerator(rescale=1./255)
validation_datagen = ImageDataGenerator(rescale=1./255)
# The 'Strawberry__healthy' is the name of the subdirectory within 'train' and 'valid' and it represents the class name
train_generator = train_datagen.flow_from_directory(
train_dir,
target_size=(224, 224),
batch_size=32,
class_mode='categorical')
validation_generator = validation_datagen.flow_from_directory(
validation_dir,
target_size=(224, 224),
batch_size=32,
class_mode='categorical')
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import GlobalAveragePooling2D, Dense, Dropout
from tensorflow.keras.applications import MobileNetV2
from tensorflow.keras import regularizers
# Load MobileNetV2 pre-trained model
base_model = MobileNetV2(input_shape=(224, 224, 3), include_top=False, weights='imagenet')
# Freeze the base model weights
base_model.trainable = False
# Define the number of classes
num_classes = 2 # Update this based on your dataset
# Create the model
model = Sequential([
base_model,
GlobalAveragePooling2D(),
Dense(256, activation='relu', kernel_regularizer=regularizers.l2(0.01)), # L2 regularization
Dropout(0.5), # Dropout layer
Dense(num_classes, activation='softmax')
])
# Compile the model
model.compile(optimizer=tf.keras.optimizers.Adam(),
loss='categorical_crossentropy',
metrics=['accuracy'])
from tensorflow.keras.callbacks import EarlyStopping, ModelCheckpoint
epochs = 8
# Implement early stopping and model checkpointing
early_stopping = EarlyStopping(monitor='val_loss', patience=3, verbose=1, mode='min')
model_checkpoint = ModelCheckpoint('best_model.h5', monitor='val_accuracy', mode='max', save_best_only=True, verbose=1)
# Train the model without class weighting (since we removed data augmentation)
history = model.fit(
train_generator,
steps_per_epoch=train_generator.samples // train_generator.batch_size,
validation_data=validation_generator,
validation_steps=validation_generator.samples // validation_generator.batch_size,
epochs=epochs,
callbacks=[early_stopping, model_checkpoint]
)
# Load the best model after training
model.load_weights('best_model.h5')
# Evaluate model performance
print("Evaluating model...")
eval_result = model.evaluate(validation_generator)
print(f"Validation Loss: {eval_result[0]}, Validation Accuracy: {eval_result[1]}")
# Save the trained model in the recommended Keras format
model.save('my_strawberry_model.keras')
# Convert the model to TensorFlow Lite format for deployment on edge devices
converter = tf.lite.TFLiteConverter.from_keras_model(model)
tflite_model = converter.convert()
# Save the TensorFlow Lite model to disk
with open('my_strawberry_model.tflite', 'wb') as f:
f.write(tflite_model)
from google.colab import files
files.download('my_strawberry_model.keras') # Download the Keras model file
files.download('my_strawberry_model.tflite') # Download the TensorFlow Lite model file
output :
Mounted at /content/drive/
total 8
drwx------ 2 root root 4096 Dec 3 21:12 Soybean
drwx------ 2 root root 4096 Dec 26 11:43 Strawberry
Found 3640 images belonging to 2 classes. Found 910 images belonging to 2 classes. Downloading data from https://storage.googleapis.com/tensorflow/keras-applications/mobilenet_v2/mobilenet_v2_weights_tf_dim_ordering_tf_kernels_1.0_224_no_top.h5 9406464/9406464 [==============================] - 0s 0us/step
Epoch 1/8 113/113 [==============================] - ETA: 0s - loss: 1.6966 - accuracy: 0.9734 Epoch 1: val_accuracy improved from -inf to 0.99554, saving model to best_model.h5
/usr/local/lib/python3.10/dist-packages/keras/src/engine/training.py:3103: UserWarning: You are saving your model as an HDF5 file via `model.save()`. This file format is considered legacy. We recommend using instead the native Keras format, e.g. `model.save('my_model.keras')`. saving_api.save_model(
113/113 [==============================] - 605s 5s/step - loss: 1.6966 - accuracy: 0.9734 - val_loss: 0.5985 - val_accuracy: 0.9955
Epoch 2/8 113/113 [==============================] - ETA: 0s - loss: 0.3761 - accuracy: 0.9958 Epoch 2: val_accuracy did not improve from 0.99554 113/113 [==============================] - 208s 2s/step - loss: 0.3761 - accuracy: 0.9958 - val_loss: 0.2549 - val_accuracy: 0.9810
Epoch 3/8 113/113 [==============================] - ETA: 0s - loss: 0.1596 - accuracy: 0.9981 Epoch 3: val_accuracy did not improve from 0.99554 113/113 [==============================] - 258s 2s/step - loss: 0.1596 - accuracy: 0.9981 - val_loss: 0.1097 - val_accuracy: 0.9955
Epoch 4/8 113/113 [==============================] - ETA: 0s - loss: 0.0999 - accuracy: 0.9950 Epoch 4: val_accuracy improved from 0.99554 to 0.99888, saving model to best_model.h5 113/113 [==============================] - 218s 2s/step - loss: 0.0999 - accuracy: 0.9950 - val_loss: 0.0873 - val_accuracy: 0.9989
Epoch 5/8 113/113 [==============================] - ETA: 0s - loss: 0.0753 - accuracy: 0.9953 Epoch 5: val_accuracy did not improve from 0.99888 113/113 [==============================] - 252s 2s/step - loss: 0.0753 - accuracy: 0.9953 - val_loss: 0.0622 - val_accuracy: 0.9967
Epoch 6/8 113/113 [==============================] - ETA: 0s - loss: 0.0585 - accuracy: 0.9972 Epoch 6: val_accuracy did not improve from 0.99888 113/113 [==============================] - 250s 2s/step - loss: 0.0585 - accuracy: 0.9972 - val_loss: 0.0397 - val_accuracy: 0.9989
Epoch 7/8 113/113 [==============================] - ETA: 0s - loss: 0.0964 - accuracy: 0.9875 Epoch 7: val_accuracy did not improve from 0.99888 113/113 [==============================] - 222s 2s/step - loss: 0.0964 - accuracy: 0.9875 - val_loss: 0.0661 - val_accuracy: 0.9978
Epoch 8/8 113/113 [==============================] - ETA: 0s - loss: 0.0482 - accuracy: 0.9978 Epoch 8: val_accuracy did not improve from 0.99888 113/113 [==============================] - 253s 2s/step - loss: 0.0482 - accuracy: 0.9978 - val_loss: 0.0471 - val_accuracy: 0.9944 Evaluating model... 29/29 [==============================] - 44s 1s/step - loss: 0.0873 - accuracy: 0.9989 Validation Loss: 0.08727286010980606, Validation Accuracy: 0.9989010691642761
WARNING:absl:`mobilenetv2_1.00_224_input` is not a valid tf.function parameter name. Sanitizing to `mobilenetv2_1_00_224_input`. WARNING:absl:`mobilenetv2_1.00_224_input` is not a valid tf.function parameter name. Sanitizing to `mobilenetv2_1_00_224_input`. WARNING:absl:`mobilenetv2_1.00_224_input` is not a valid tf.function parameter name. Sanitizing to `mobilenetv2_1_00_224_input`.
I didn’t need to use data augumatation code as the pictures are already diverse(rotated, scaled, flipped etc )
I haven’t trained the model on Soybean yet as I want to fix is issue first before I train it on multiple plant species.
I get no errors when training the model as shown in the output. When I transfer the .tflite file to raspberry pi, the model identifies the picture of an animal with white background to be as “Strawberry” .
below is my python script and the output
FYI: I have changed the name of the tflite on my Raspberry Pi (my_strawberry_model_3.tflite) becuase I have generated model with same name before. but I assure you it is the right file.
import os
import numpy as np
import tflite_runtime.interpreter as tflite
from PIL import Image
# Function to preprocess the image
def preprocess_image(image_path):
img = Image.open(image_path).convert('RGB').resize((224, 224))
img_array = np.expand_dims(np.array(img, dtype=np.float32) / 255.0, axis=0)
return img_array
# Function to run inference
def run_inference(image_path, interpreter, input_details, output_details):
input_data = preprocess_image(image_path)
interpreter.set_tensor(input_details[0]['index'], input_data)
interpreter.invoke()
output_data = interpreter.get_tensor(output_details[0]['index'])
return output_data
# Load the TFLite model and allocate tensors
interpreter = tflite.Interpreter(model_path='my_strawberry_model_3.tflite')
#interpreter = tflite.Interpreter(model_path='my_soybean_model.tflite')
interpreter.allocate_tensors()
# Get input and output tensors
input_details = interpreter.get_input_details()
output_details = interpreter.get_output_details()
# Directory containing images to classify
directory_path = '/home/pi4/Desktop/fun_project/all_diff'
# Class names
class_names = ['Strawberry__healthy', 'Not_Strawberry']
#class_names = ['Soybean__healthy', 'Not_Soybean']
# Iterate over each image in the directory
for filename in os.listdir(directory_path):
if filename.lower().endswith(('.png', '.jpg', '.jpeg')): # Check for image files
image_path = os.path.join(directory_path, filename)
result = run_inference(image_path, interpreter, input_details, output_details)
predicted_class_index = np.argmax(result)
probabilities = result[0]
print(f"Image: {filename}")
print(f"Predicted class index: {predicted_class_index}")
print(f"Probabilities: {probabilities}")
print(f"Predicted class name: {class_names[predicted_class_index]}")
print("-" * 50) # Separator for readability
pi4@raspberrypi:~/Desktop/FYP $ python3 loop_plant_script.py
Image: donkey.jpg
Predicted class index: 0
Probabilities: [9.9951291e-01 4.8705883e-04]
Predicted class name: Strawberry__healthy
--------------------------------------------------
pi4@raspberrypi:~/Desktop/FYP $
Issue: it is obviously that a picture of animal should not be classed as “starwberry” . I am not sure what can I try out to make the model work.
Thanks in advance.