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

import torch
import torchvision
from torchvision import datasets,models,transforms
from torch import nn,optim
import numpy as np
import pandas as pd 
import time
import os
import matplotlib.pyplot as plt
import cv2
import glob
from torch.utils.data import DataLoader
import random

#using the inception network
model = models.inception_v3(pretrained=True)

# +
#Image augmentation for the train set
train_transform = transforms.Compose([transforms.RandomRotation(30),
                                     transforms.RandomResizedCrop(299),  #the inception network takes in 299*299 image size
                                     transforms.RandomHorizontalFlip(),
                                     transforms.ToTensor(),
                                     transforms.Normalize([0.485,0.456,0.406],[0.229,0.224,0.225])])

#Image augmentation for the test set
valid_transform = transforms.Compose([transforms.Resize(299),    #the inception network takes in 299*299 image size
                                      transforms.CenterCrop(299), 
                                     transforms.ToTensor(),
                                     transforms.Normalize([0.485,0.456,0.406],[0.229,0.224,0.225])])

data_dir = r"D:\Data\Flower Classification\flower_data"         #the path for the data

#Load the images from their files
train_data = datasets.ImageFolder(data_dir+"/train",transform=train_transform)
valid_data = datasets.ImageFolder(data_dir+"/valid",transform=valid_transform)

train_loader = DataLoader(train_data,batch_size=16,shuffle=True)
valid_loader = DataLoader(valid_data,batch_size=16,shuffle=True)


# -

def get_unique_data():
    each_label = []
    each_image = []
    for image,label in train_data:
        if label not in each_label:
            each_image.append(image)
            each_label.append(label)
    return each_image,each_label


#printing all the classes
#ploting each type of flower we have
unique_images,unique_labels=get_unique_data()
grid=torchvision.utils.make_grid(unique_images,nrow=20, padding=2)
plt.figure(figsize=(15,15))
plt.imshow(np.transpose(grid,(1,2,0)))
print('labels:',unique_labels)

# +
#check whether we can use the gpu or not 
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
print(device)

# updating all the parameters take much time but it improve the model's accuracy 
for param in model.parameters():
    param.requires_grad = True   
    
#connect the network with our fc layer
model.AuxLogits.fc = nn.Linear(model.AuxLogits.fc.in_features,102)
model.fc = nn.Linear(model.fc.in_features,102)  # 102 class we have in the dataset


critireon = nn.CrossEntropyLoss()   #the loss function crossentropy since its a classification problem
optimizer = optim.SGD(model.parameters(),lr=0.001,momentum=0.9)   # defining the optimizer 
model.to(device)


# -

def train_model(model, criterion, optimizer, num_epochs=10):
    start = time.time()
    i=0
    best_model_wts = model.state_dict()
    best_acc = 0.0
    loss_over_time_train = []
    loss_over_time_valid = []
    acc_over_time_train = []
    acc_over_time_valid = []

    for epoch in range(num_epochs):
        print('Epoch {}/{}'.format(epoch+1, num_epochs))
        

        # Each epoch has a training and validation phase
        for phase in ['train', 'valid']:
            if phase == 'train':
                model.train()
                dataloader=train_loader# Set model to training mode
            else:
                model.eval()
                dataloader=valid_loader# Set model to evaluate mode

            running_loss = 0.0
            running_corrects = 0

            # Iterate over data.
            for data in dataloader:
                # get the inputs
                inputs, labels = data

                inputs=inputs.to(device)
                labels=labels.to(device)
        
                # zero the parameter gradients
                optimizer.zero_grad()

                # forward
                with torch.set_grad_enabled(phase == 'train'):
                    if phase == 'train':
                        outputs,aux_outputs = model(inputs)
                        loss1 = criterion(outputs,labels)
                        loss2 = criterion(aux_outputs,labels)
                        loss = loss1 + 0.4*loss2
                    else:
                        outputs = model(inputs)
                        loss = criterion(outputs, labels)
                    
                    _, preds = torch.max(outputs, 1)

                # backward + optimize only if in training phase
                    if phase == 'train':
                        loss.backward()
                        optimizer.step()

                # calculating the loss and accuracy
                running_loss  += loss.item()*inputs.size(0)
                running_corrects += torch.sum(preds == labels.data)
                
            if phase=="train":
                epoch_loss = running_loss / len(train_data)
                loss_over_time_train.append(epoch_loss)
                epoch_acc = running_corrects.double() / len(train_data)
                acc_over_time_train.append(epoch_acc)
    
                
            else:
                epoch_loss = running_loss / len(valid_data)
                loss_over_time_valid.append(epoch_loss)
                epoch_acc = running_corrects.double() / len(valid_data)
                acc_over_time_valid.append(epoch_acc)

            print('{} Loss: {:.4f} Acc: {:.4f}'.format(
                phase, epoch_loss, epoch_acc))
            

            if phase == 'valid' and epoch_acc > best_acc:
                best_acc = epoch_acc
                best_model_wts =model.state_dict()
            
        print('-' * 60)
                
    time_elapsed = time.time() - start
    print('Training complete in {:.0f}m {:.0f}s'.format(
        time_elapsed // 60, time_elapsed % 60))
    print('Best val Acc: {:4f}'.format(best_acc))

    # load best model weights
    model.load_state_dict(best_model_wts)
    loss = {"train":loss_over_time_train,"val":loss_over_time_valid}
    acc = {"train":acc_over_time_train,"val":acc_over_time_valid}
    return model,loss,acc

#training the model
num_epochs = 20
model_trained,loss,acc = train_model(model,critireon,optimizer,num_epochs)

#the model's directory
model_dir = r"D:\Trained_models\Pytorch\Flower_Classification"
#the model's name
model_name = r"\flower_classification 2.pt"
#saving the best trained model
# torch.save(model.state_dict(),model_dir+model_name)

model.load_state_dict(torch.load(r"D:\Trained_models\Pytorch\Flower_Classification\flower_classification 2.pt"))
model.eval()         # converting the model to evaluate mode

import json
data=json.loads(open(r'D:\Data\Flower Classification\cat_to_name.json').read())    #loading flower names 

#preparing the test set to load
test_data = transforms.Compose([
        transforms.Resize(299),            #the inception's input size 299
        transforms.CenterCrop(299),
        transforms.ToTensor(),
        transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
    ])
test_data = datasets.ImageFolder(r"D:\Data\Flower Classification"+r"\test set",transform=test_data)
test_loader = DataLoader(test_data,batch_size=16,shuffle=False,num_workers=4)


#getting the name of the predicted class
def send_name(image_id):
    for im_id in data.keys():
        if im_id == str(image_id):
            name = data[im_id]
            return name


#storing every image name 
image_names = []
for i in test_loader.dataset.imgs:
    image_names.append(i[0].split('\\')[-1])

#predicting flower types 
output = []
flower_name = []
for inputs, labels in test_loader:
    inputs = inputs.to(device)
    outputs = model(inputs)
    _, predicted = torch.max(outputs, 1)
    for i in predicted:
        flower_name.append(send_name(int(i)))
        output.append(int(i))

#using pandas dataframe to show the predictions
df = pd.DataFrame()
df['image_name'] = image_names
df['class'] = output
df['flower_name'] = flower_name

#displaying the predictios
with pd.option_context('display.max_rows', None, 'display.max_columns', None):  
    print(df)



StarcoderdataJupyterScriptsDedupFiltered