# ---
# jupyter:
#   jupytext:
#     text_representation:
#       extension: .py
#       format_name: light
#       format_version: '1.5'
#       jupytext_version: 1.14.4
#   kernelspec:
#     display_name: Python 3 (ipykernel)
#     language: python
#     name: python3
# ---

# + [markdown] id="view-in-github" colab_type="text"
# <a href="https://colab.research.google.com/github/kishkath/Data_Structures-Hashing-/blob/main/Copy_of_Book3_fitgenerator.ipynb" target="_parent"><img src="https://colab.research.google.com/assets/colab-badge.svg" alt="Open In Colab"/></a>

# + [markdown] id="R7QEBylzjfhX"
#
#
# <img align="left" width="800" src="https://pyimagesearch.com/wp-content/uploads/2018/12/keras_fit_generator_illustration.png">
#

# + id="JdAig2LEfd2q"


# + [markdown] id="TdVu7bFxjOJU"
# ## Uncomment below cells and run all of them

# + id="6SXxlMnzFCMA" colab={"base_uri": "https://localhost:8080/"} outputId="000993f7-400a-4954-e884-5fe8586c94d8"
# ! pip install kaggle

# + id="ULlYlIaGFCJN"
# ! mkdir ~/.kaggle

# + [markdown] id="4o948yf1jQOl"
# ### From Kaggle website from your account page generate API Token then download and store the kaggle.json file into the same directory of this notebook.

# + id="0NKB1GD4FCHY"
# ! cp kaggle.json ~/.kaggle/

# + id="421u9brnFCFd"
# ! chmod 600 ~/.kaggle/kaggle.json

# + [markdown] id="K_elGLdqjSaY"
# # # ### copy the API command for the dataset you want to download from kaggle dataset page

# + id="A5DPMo_rFCDk" colab={"base_uri": "https://localhost:8080/"} outputId="8520a5ef-788a-4a30-9666-43749a9b4315"
# !kaggle datasets download -d andrewmvd/animal-faces

# + id="BDSz2ELvFCBy" colab={"base_uri": "https://localhost:8080/"} outputId="fe627b1b-136c-40b8-e3fe-18f954d75c14"
# ! unzip animal-faces.zip

# + [markdown] id="vZMLiWc5PHcG"
# # The keras deep learning libraries has functions to fit model
#
# 1. .fit
# 2. .fit_generator
#
#
#

# + [markdown] id="NeM7g_30PHXL"
# # What is difference between keras fit and fit_generator?
#
#
# Both the functions perform on same task, but how they do it is completely different.
#
# let us disccus each function with example and understand their working.
#
#
# ## fit_geneartor
#
#
# For small and simple dataset we can use .fit function because the dataset do not require any data augmentation.
#
# However, in real life this is not the case. The dataset we get are often complex and challenging with a large size. Thus is fiting it into the memory is difficult.
#
# The dataset also require to be augmented to prevent overfitting of the model and increase the ability of our model to generalize
#
#
#
# In those cases we need to use Keras .fit_generator
# function
#
#
# First step is to initialize the number of epochs we are going to train our neural network along with the batch size.
#
# Then we initialize a object named gen which is a keras ImageDatagenerator object that will be used to perform data augmentation i.e randomly rotating, shifting, chaning brightness, etc
#
#
# Each new batch of data is randomly adjusted according to the parameters supplied to ImageDataGenerator.
#
#
# Now we need to use keras .fit_generator function to train our neural network 
#
#
#
#

# + id="no6Wg1e4E8V0"
# importing all the necessary for example: tensorflow, ImageDataGenerator, etc
import os 
import cv2
import random
import numpy as np 
import pandas as pd
import matplotlib.pyplot as plt 
import seaborn as sns 
import tensorflow as tf 
from tensorflow import keras 
from keras.preprocessing.image import ImageDataGenerator as gen




# + id="PKF9ozLhIDbj"
# create a function for plotting images with parameter image array

  # create a subplot of 9 images using fig, axes
  
  # flatten the axes 
  
  # loop through image array and axes simultaneously using zip function
  
    # show image using imshow()
    
  
  # tighten the layout to avoid white space between images
  
  # display the subplot 

def plotting(image_arr):
  fig,axes = plt.subplot(3,3,figsize=(9,9))
  axes = axes.flatten() 

  for img,ax in zip(image_arr,axes):
    ax.imshow(img)
    ax.axis('off')
  plt.tight_layout() 
  plt.show()
  


# + [markdown] id="_Nob9B90bVmn"
# # 1. Read Image
#
# Read the images from the dataset  directory 

# + colab={"base_uri": "https://localhost:8080/"} id="ZbqOFn3gI2iD" outputId="3ca02b88-29e0-47df-8fb4-9478ed4d98e7"
# chose a random image from directory using random.choice(os.listdir(image_folder path))

path = r'/content/afhq/train/dog'
random_img = random.choice(os.listdir(path))

# print the chosen image
print(random_img)

# + id="fc6zgnxHI3rO" colab={"base_uri": "https://localhost:8080/"} outputId="cf8a867f-88f8-4936-b687-bb75a7582653"
# create a image path varibale to store concatenation of image folder path + chosen image name 

random_imgpath = path+'/'+random_img
print("image Path: ",random_imgpath)

# + [markdown] id="PqAjNadjbYWQ"
# # 2. Plot the sample image chosen
#
# just plot the image chosen in above cells using matplotlib

# + colab={"base_uri": "https://localhost:8080/", "height": 286} id="U4muIpTtI5gM" outputId="cbbf0cd5-bfdb-43b8-f6bc-0c22930bde45"
# read image from path and expand dims with axis 0 and store the result in image named variable

image = np.expand_dims(cv2.imread(random_imgpath),0)
#print(image.shape)
# 4 dimensional required set
# plot the image using plt.imshow()
plt.imshow(image[0])

# + id="PNo57Dp4IpEC"
# set train data path in a variable named train_path

train_path = "/content/afhq/train"

# + id="BzXFeMprII9A"
''' 
create a variable with reference to ImageDataGenerator with following parameters:
gen = ImageDataGenerator(
    rotation_range= integer value, 
    width_shift_range= float value, 
    height_shift_range= float vaue,
    zoom_range= float value, 
    channel_shift_range= integer, 
    brightness_range=  [min smaller than 1, max grater than 1],
    horizontal_flip= boolean,
    vertical_flip= boolean)
'''

generate = keras.preprocessing.image.ImageDataGenerator(rotation_range=2,width_shift_range=1.3,height_shift_range=1.8,zoom_range=1.9,channel_shift_range=3,
                              brightness_range=[0.3,0.9],horizontal_flip=True,vertical_flip=True)
image_size = 244 
batch_size = 48 

# image size variable named IMAGE_SIZE with size value

# batch size variable named BATCH_SIZE with size value



# + id="5GTf3ceJoEhC"


# + [markdown] id="72jJvPVMkDF1"
#
# # Using flow_from_directory function
#
# 1. The directory must be set to the path where your 'n' classes of folders are present.
# 2. The target_size is the size of your input images, every image will be resized to this size.
# 3. color_mode: if the image is either black and white or grayscale set 'grayscale' or if the image has three color channels, set 'rgb'.
# 4. batch_size: No. of images to be yielded from the generator per batch.
# 5. class_mode: Set 'binary' if you have only two classes to predict, if not set to'categorical'. in case if you're developing an Autoencoder system, both input and the output would probably be the same image, for this case set to 'input'.
# 6. shuffle: Set True if you want to shuffle the order of the image that is being yielded, else set False.
# 7. seed: Random seed for applying random image augmentation and shuffling the order of the image.

# + [markdown] id="-EKNKYEucFH4"
# # Train generator
#
# Using ImageDatagenerator function flow_from_directory on training data directory we can generate training data with data augmentation.

# + colab={"base_uri": "https://localhost:8080/"} id="5TV2RkLgcDW6" outputId="c63d1a5b-541c-4151-bfb8-318ca027d065"

'''create a variable with reference to ImageDataGenerator with following parameters:
train_generator = gen.flow_from_directory(
    train_path, 
    target_size=(IMAGE_SIZE,IMAGE_SIZE), 
    subset='training',
    batch_size= BATCH_SIZE,
    color_mode = 'rgb',
    shuffle=boolean,
    class_mode=  'categorical' or 'binary',
    seed= integer value)
'''

train_generated = generate.flow_from_directory(train_path,target_size=(image_size,image_size),subset='training',batch_size=batch_size,color_mode='rgb',shuffle=True,class_mode = 'categorical',seed = 42)




# + [markdown] id="eTBf0OgmbyIQ"
# # ploting the generated images above flow_from_directory method

# + colab={"base_uri": "https://localhost:8080/", "height": 719} id="jm8DgGNUIHqN" outputId="7fae3f04-9502-4a0b-e88c-2e7d4bdaa352"
# create two variables x,y which will store values returned by train_generator.next() 

x,y = train_generated.next() 

fig = plt.figure(figsize=(20,12))

# create figure

row = 3 
cols =3 

for i in range(9):
  fig.add_subplot(row,cols,i+1) 
  image = x[i].astype(np.uint8)
  label = y[i] 
  plt.imshow(image) 
  plt.title(label)
  plt.axis('off')
plt.show() 

# create loop in range 9 or your choice

  # add a subplot to figure of size you want
  
  # create a image named variable to store ith value of x astype np.uint8
  
  # create a label named variable to store ith value of y astype np.uint8
  
  # plot the image using imshow
  
  # add the title as actual label to image


# show the image


# + id="aP8UU-THJ555"
# set valid data path in a variable named valid_path
val_path = "/content/afhq/val"

# + [markdown] id="j2rlj_7ecK4f"
# # Valid generator
#
# Using ImageDatagenerator function flow_from_directory on training data directory we can generate training data with data augmentation.

# + colab={"base_uri": "https://localhost:8080/"} id="alr4ElihIkRg" outputId="11291a51-3bed-4c05-ab2f-b6f2b93bba2b"

'''create a variable with reference to ImageDataGenerator with following parameters:

valid_generator = gen.flow_from_directory(
valid_path, 
target_size=(IMAGE_SIZE,IMAGE_SIZE),
shuffle= boolean,
class_mode='categorical' or 'binary')
'''

val_generator = generate.flow_from_directory(val_path,target_size=(image_size,image_size),shuffle=True,class_mode='categorical')




# + [markdown] id="HxdVhGTUcNuc"
# # Building model

# + [markdown] id="E25E1umPdQOt"
# # To train faster we will be using Transer Learning with
#
# ## MobileNetV2 Model
#
# MobileNet is a CNN architecture model for Image Classification and Mobile Vision. As compared to other models, running or applying transfer learning using  MobileNet consumes very less omputation power. Thus it can be used on devices such as Mobile devices, embedded systems and computers wthout GPU or low specification.
# It runs well on browser as browser have computational limitation.
#

# + id="NJLdVT5ALpt-" colab={"base_uri": "https://localhost:8080/"} outputId="3f29182e-841a-4ffa-8cf5-24d463fa5fb7"
# create a variable name base_model with MobileNetV2 model from tensorflow application library
# weight: imagnet

# input shape : 224,224,3

base_model = keras.applications.MobileNetV2(input_shape=(224,224,3),include_top=False,weights="imagenet")



# set base model trainable to False
base_model.trainable=False

# + id="N-5YOncMLq_V"
# create a variable and store number of classes i.e 3 classes in this case

classes = ['cat','dog','wild']

# + id="JkqPHS7mLtDn"
# define inputs using tensorflow Input --> 224,224,3

# set the inputs to base_model

x = base_model(inps)

# Add GlobalAveragePooling2D layer to base_model

x = keras.layers.GlobalAveragePooling2D()(x)

# define initializer for model i.e GlorotUniform for uniform distribution of tensor data

initializer = tf.keras.initializers.GlorotUniform()

# create a variable to store activation, use any sigmoid, softmax (softmax recommended)

var = "softmax"

# Define a Dense layer

output = keras.layers.Dense(3)(x)


# Create a model using the layers created

model = keras.Model(inps,output)


# + [markdown] id="KN8kDJgCdV6M"
# # Note:
# The last layer has 10 number of classes unit. So the output(predicted labels) will be 10 floating points as the actual label is a single integer number.
#
# For the last layer, the activation function can be: 
# 1. None
# 2. sigmoid
# 3. softmax
#
# When there is no activation function used inthe model's last layer, we need to set from_logits=True in cross-entropy loss function during compiling model. This loss function will apply sigmoid transformation on predicted label values

# + colab={"base_uri": "https://localhost:8080/"} id="9V_rncsSgCCA" outputId="f3ede566-88a4-43ca-c429-2cdfcd008a21"
model.summary()

# + [markdown] id="QxLH6abPdZ1w"
# ### Let's see the model summary

# + colab={"base_uri": "https://localhost:8080/"} id="HZS8q0JDLzBN" outputId="eca9f642-0631-43fd-e444-14f9cbb7ff95"
# visualize modle summary
model.summary()

# + [markdown] id="Wf10goLediHF"
# ## Compile the model
#
# Compile the model before training it. Since there are 3 classes, use the tf.keras.losses.CategoricalCrossEntropy() loss with from_logits=True (if activation function is not mentioned while creating model)

# + id="hHzPymR0ddog"
# Compile the model by passing loss, optimizer and metrics

model.compile(optimizer=keras.optimizers.Adam(learning_rate=0.0001),loss= keras.losses.CategoricalCrossentropy(from_logits=True),metrics=['accuracy'])

# + [markdown] id="LmE5h-Qva6w4"
#
# # How fit_generator works exactly?
#
# In the background, keras fit_generaor uses following process on the data while training a model:
#   1. Keras calls the genrator function passed to fit_generator i.e gen.flow_from_directory in our case.
#   2. The generator returns the batch of size mentioned while generating image to the fit_generator.
#   3. The .fit_generator function accepts the batch of image data, perform backpropagation and updates the weights in our model.
#   4. This process is repeated until we have reached the desired number of epochs.

# + [markdown] id="3r5zE2dRa07f"
# ## Why do we need steps_per_epoch?
#
# The keras data genrator is meant to loop infinitely i.e it should never return or exit.
#
# Since the function is intended to loop infinitely, Keras has no ability to determine when one epoch starts and a new epoch begins.
#
# Therefore, we compute the steps_per_epoch
# value as the total number of training data points divided by the batch size. Once Keras hits this step count it knows that it's a new epoch.
#

# + colab={"base_uri": "https://localhost:8080/"} id="6QTwWDXbKA9c" outputId="135433ab-6dc5-47e9-9419-6c8193b70f24"

# create a variable name step_size_train and set value as train_generator.n// train_generator.batch_size

step_size_train = train_generated.n //train_generated.batch_size

# create a variable name step_size_valid and set value as valid_generator.n// train_generator.batch_size

step_size_val  = val_generator.n//train_generated.batch_size

print('train: ',step_size_train,' val: ',step_size_valid)

#fit model using fit_generator function by passing following paarameters:
model.fit_generator(generator = train_generated,
                    steps_per_epoch = step_size_train,
                    validation_data = val_generator,
                    validation_steps=step_size_val,
                    epochs=5)




# + colab={"base_uri": "https://localhost:8080/"} id="Rjr6PHAqoo7O" outputId="0f341073-e038-40ad-854e-c493d6da9a1f"




step_size_valid  = val_generator.n//train_generated.batch_size
print(step_size_valid)

# + [markdown] id="FIlpLJFxfgJn"
# # Summary
#
# In this assignement you learned the differences between Keras fit and fitgenerator functions used to train a deep neural network.
#
# .fit is used when there is no need for data augmentation and teh whole data can be used to fit in memory.
#
# Whereas, 
# .fit_generator should be used when data augmenetation to be applied or data is too large to store in memory or whenever there is need for converting image dataset in to baches of images

# + [markdown] id="QWLNveojmfs9"
# ![link text](http://recyclefloridatoday.org/wp-content/uploads/2020/07/Congratulations-1.jpg)

# + [markdown] id="muaF2swfmlT8"
# # Please fill the below feedback form about this assignment
#
# https://forms.zohopublic.in/cloudyml/form/CloudyMLDeepLearningFeedbackForm/formperma/VCFbldnXAnbcgAIl0lWv2blgHdSldheO4RfktMdgK7s

StarcoderdataJupyterScriptsDedupFiltered