How I Made A.I. To Detect Rotten Produce Using a CNN
By: Ashley C
Tags: Instacart, TensorFlow, Deep Learning, Machine Learning, Pytorch

Directories and Data Manipulation

TensorFlow

train_path = '/Users/ashleyc/Deeplearning/fresh_and_rotton/dataset/train'

test_path = '/Users/ashleyc/Deeplearning/fresh_and_rotton/dataset/test' BATCH_SIZE = 10 train_batches = ImageDataGenerator(

preprocessing_function=tf.keras.applications.vgg16.preprocess_input,

rescale=1/255.,

horizontal_flip=True,

vertical_flip=True ).flow_from_directory(

directory=train_path,

target_size=(20, 20),

classes=['freshapples', 'freshbananas', 'freshoranges', 'rottenapples', 'rottenbananas','rottenorganges'],

batch_size=BATCH_SIZE,

class_mode='categorical',

color_mode='rgb'

) test_batches = ImageDataGenerator(

preprocessing_function=tf.keras.applications.vgg16.preprocess_input, rescale=1/255.

).flow_from_directory(

directory=test_path,

target_size=(20, 20),

classes=['freshapples', 'freshbananas', 'freshoranges', 'rottenapples', 'rottenbananas','rottenorganges'],

batch_size=BATCH_SIZE,

class_mode='categorical',

color_mode='rgb',

shuffle=False

)

Alright, now let’s break this big chunk of text down.

train_path = '/Users/ashleyc/Deeplearning/fresh_and_rotton/dataset/train'

test_path = '/Users/ashleyc/Deeplearning/fresh_and_rotton/dataset/test'

The first step before we do any data manipulation, we need to initialize the directories.

BATCH_SIZE = 10

Our batch size refers to the number of items from the dataset our model is fed. I like to create variables for parameters that have numbers that might be changed within the model training purposes. This is because I only have to refer to a variable at the top of my code, rather than looking through my entire network to find this parameter.

train_batches = ImageDataGenerator(

preprocessing_function=tf.keras.applications.vgg16.preprocess_input,

rescale=1/255.,

horizontal_flip=True,

vertical_flip=True ).flow_from_directory(

directory=train_path,

target_size=(20, 20),

classes=['freshapples', 'freshbananas', 'freshoranges', 'rottenapples', 'rottenbananas','rottenorganges'],

batch_size=BATCH_SIZE,

class_mode='categorical',

color_mode='rgb'

) test_batches = ImageDataGenerator(

preprocessing_function=tf.keras.applications.vgg16.preprocess_input, rescale=1/255.

).flow_from_directory(

directory=test_path,

target_size=(20, 20),

classes=['freshapples', 'freshbananas', 'freshoranges', 'rottenapples', 'rottenbananas','rottenorganges'],

batch_size=BATCH_SIZE,

class_mode='categorical',

color_mode='rgb',

shuffle=False

)

We have two ImageDataGenerators, one for our training batches and one for our testing batches. The purposes of these generators are to perform data augmentations, which will then be fed into our CNN.

The training and testing batches almost have identical generators with the exception of a few added features that the training batches have. We will examine the training batch generator and differentiate the added features.

train_batches = ImageDataGenerator(

preprocessing_function=tf.keras.applications.vgg16.preprocess_input,

rescale=1/255.,

horizontal_flip=True,

vertical_flip=True ).flow_from_directory(

directory=train_path,

target_size=(20, 20),

classes=['freshapples', 'freshbananas', 'freshoranges', 'rottenapples', 'rottenbananas','rottenorganges'],

batch_size=BATCH_SIZE,

class_mode='categorical',

color_mode='rgb'

)

For our generator, we will use transfer learning. Essentially what transfer learning does is reuse a pre-trained model on a new problem, and the model will then exploit its knowledge from a prior task to improve generalization on a future task.

To define our transfer learning feature, we will use the preprocessing_function and use the vgg16 model.

reprocessing_function=tf.keras.applications.vgg16.preprocess_input,

Additionally, we need to rescale our image to 1/255., and this normalizes or input and transforms every pixel in the range 0,255 to 0,1. We do this to treat all the images in the same manner because different images have varying pixel ranges.

rescale=1/255.,

For our train_batches, we will apply a horizontal and vertical flip, but we will not do this for our testing data. When we feed in our testing data, we don’t want to augment it, we want to make sure the data is completely new in a sense. Keep in mind that for our test_batches, we need to set our shuffle to False.

horizontal_flip=True,

vertical_flip=True

On our ImageDataGenerator, we will need to call the flow_from_directory function. This method will take in a directory path and generate batches of augmented data.

.flow_from_directory(

directory=train_path,

target_size=(20, 20),

classes=['freshapples', 'freshbananas', 'freshoranges', 'rottenapples', 'rottenbananas','rottenorganges'],

batch_size=BATCH_SIZE,

class_mode='categorical',

color_mode='rgb'

)

Within our flow_from_directory function, we will define our directory, which we initialized earlier as “train_path”.

directory=train_path

Then we need to reshape our images using the target_size parameter to (20,20).

target_size=(20, 20)

After we will define our classes, and in this model we have six.

classes=['freshapples', 'freshbananas', 'freshoranges', 'rottenapples', 'rottenbananas','rottenorganges']

Once you define your classes in TensorFlow, if you do this correctly, you’ll see this as an output in your terminal:

Found 5501 images belonging to 6 classes.

Found 1384 images belonging to 6 classes.

If you see this, you have defined your classes successfully.

Now we will define our batch_size using the BATCH_SIZE variable we initialized earlier.

batch_size=BATCH_SIZE

We will use categorical for our class mode because we have data that falls into one of many categories. In this case, we are classifying fruits, but there are six categories that the data can fall under. Additionally, we will want to define our color_mode as RGB since our images are RGB.

class_mode='categorical',

color_mode='rgb'

PyTorch

fruit_train = '/Users/ashleyc/Deeplearning/fresh_and_rotton/dataset/train'

fruit_test = '/Users/ashleyc/Deeplearning/fresh_and_rotton/dataset/test'

data_dir = "/Users/ashleyc/Deeplearning/fresh_and_rotton/dataset"

data_transform = {'train':transforms.Compose([

transforms.Resize((224, 224)),

transforms.RandomHorizontalFlip(),

transforms.ToTensor(),

transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])

]), 'test':transforms.Compose([

transforms.Resize((224, 224)),

transforms.ToTensor(),

transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])

]) } image_datasets = {x: datasets.ImageFolder(os.path.join(data_dir, x), data_transform[x]) for x in ['train', 'test']}

data_loader = {x:torch.utils.data.DataLoader(image_datasets[x], shuffle=True, batch_size=124, num_workers=0) for x in ['train', 'test']}

class_names = image_datasets['train'].classes

Alright, let’s break this chunk down.

Firstly, let’s initialize our directories.

fruit_train = '/Users/ashleyc/Deeplearning/fresh_and_rotton/dataset/train'

fruit_test = '/Users/ashleyc/Deeplearning/fresh_and_rotton/dataset/test'

data_dir = "/Users/ashleyc/Deeplearning/fresh_and_rotton/dataset"

Next, we are going to do transformations and augmentations on our data. In the train part, I’m resizing my images to have a dimension of 224, 224, and I am also performing a random horizontal flip on the images. Note that we don’t flip our testing images. Lastly, we will need to convert our data into tensors, and then normalize it.

data_transform = {'train':transforms.Compose([

transforms.Resize((224, 224)),

transforms.RandomHorizontalFlip(),

transforms.ToTensor(),

transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])

]), 'test':transforms.Compose([

transforms.Resize((224, 224)),

transforms.ToTensor(),

transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])

]) }

In this image that belongs to the ‘rottenapples’ class, you can see how the image has been flipped.

Now we will apply the specific transformations to our training and testing data, and create a dataloader. Essentially a DataLoader will get data from a dataset and serve the data in batches.