text_plain_output_1.png
from IPython.display import FileLink

from torch.utils.data import Dataset, DataLoader, SubsetRandomSampler

from torchvision import transforms

import datetime

import matplotlib.pyplot as plt

import numpy as np # linear algebra

import pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)

import torch

import torch.nn as nn

import torch.nn.functional as F

import torch.optim as optim

gpu_status = torch.cuda.is_available()

train_df = pd.read_csv('../input/plant-pathology-2020-fgvc7/train.csv')

def get_label(row):
    for c in train_df.columns[1:]:
        if row[c] == 1:
            return c
train_df_copy = train_df.copy()
train_df_copy['label'] = train_df_copy.apply(get_label, axis=1)

sample_img = train_df.iloc[1, 0]
sample_labels = train_df.iloc[1, :]
sample_labels = np.asarray(sample_labels)

class LeafDataset(Dataset):
    def __init__(self, df, transform=None):
        self.df = df
        self.transform = transform
    def __len__(self):
        return self.df.shape[0]
    def __getitem__(self, idx):
        img_src = '../input/plant-pathology-2020-fgvc7/images/' + self.df.loc[idx, 'image_id'] + '.jpg'
        image = PIL.Image.open(img_src).convert('RGB')
        if self.transform:
            image = self.transform(image)
        if self.df.shape[1] == 5:
            labels = self.df.loc[idx, ['healthy', 'multiple_diseases', 'rust', 'scab']].values
            labels = torch.from_numpy(labels.astype(np.uint8))
            labels = labels.unsqueeze(-1).long()
            labels = labels.numpy().tolist().index([1])
            labels = torch.from_numpy(np.asarray(labels))
            return (image, labels)
        else:
            return image

leaf_sample_dataset = LeafDataset(df=train_df, transform=None)
fig, ax = plt.subplots(1,3)

for i in range(3):
    img, label = leaf_sample_dataset[i]
    
    ax[i].imshow(img)
    print(type(img), img.size,label)

leaf_transform = transforms.Compose([transforms.Resize((512, 512)), transforms.CenterCrop((384, 384)), transforms.RandomAffine(degrees=15), transforms.RandomHorizontalFlip(p=0.4), transforms.RandomVerticalFlip(p=0.3), transforms.ToTensor(), transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])
leaf_train_dataset = LeafDataset(df=train_df, transform=leaf_transform)
leaf_train_loader = DataLoader(leaf_train_dataset, shuffle=True, batch_size=16)
images, labels = next(iter(leaf_train_loader))

dataset_size = len(leaf_train_dataset)
indices = list(range(dataset_size))
np.random.shuffle(indices)
split = int(np.floor(0.2 * dataset_size))
train_idx, val_idx = (indices[split:], indices[:split])
train_sampler = SubsetRandomSampler(train_idx)
valid_sampler = SubsetRandomSampler(val_idx)

leaf_train_loader = DataLoader(leaf_train_dataset, sampler=train_sampler, batch_size=64)
leaf_valid_loader = DataLoader(leaf_train_dataset, sampler=valid_sampler, batch_size=64)

test_df = pd.read_csv('../input/plant-pathology-2020-fgvc7/test.csv')

leaf_test_dataset = LeafDataset(df=test_df, transform=leaf_transform)
leaf_test_loader = DataLoader(leaf_test_dataset, batch_size=64)
test_images = next(iter(leaf_test_loader))

diagnosis = ['healthy', 'multiple_diseases', 'rust', 'scab']

train_images, train_labels = next(iter(leaf_train_loader))

fig = plt.figure(figsize=(25,4))
for idx in np.arange(8):
    ax = fig.add_subplot(2, 16/2, idx+1, xticks=[], yticks=[])
    plt.imshow(train_images[idx].numpy().transpose(1,2,0))
    ax.set_title(diagnosis[labels[idx]])

class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.conv1 = nn.Conv2d(3, 8, 3, padding=1)
        self.conv2 = nn.Conv2d(8, 16, 3, padding=1)
        self.conv3 = nn.Conv2d(16, 32, 3, padding=1)
        self.conv4 = nn.Conv2d(32, 64, 3, padding=1)
        self.conv5 = nn.Conv2d(64, 128, 3, padding=1)
        self.conv6 = nn.Conv2d(128, 256, 2, padding=1)
        self.conv7 = nn.Conv2d(256, 512, 2, padding=1)
        self.pool2 = nn.MaxPool2d(2, 2)
        self.fc1 = nn.Linear(12 * 12 * 512, 2048)
        self.fc2 = nn.Linear(2048, 4)
        self.dropout = nn.Dropout(0.2)
    def forward(self, x):
        x = F.relu(self.conv1(x))
        x = self.pool2(F.relu(self.conv2(x)))
        x = F.relu(self.conv3(x))
        x = self.pool2(F.relu(self.conv4(x)))
        x = self.pool2(F.relu(self.conv5(x)))
        x = self.pool2(F.relu(self.conv6(x)))
        x = self.pool2(F.relu(self.conv7(x)))
        x = x.view(-1, 12 * 12 * 512)
        x = self.dropout(x)
        x = F.relu(self.fc1(x))
        x = self.dropout(x)
        x = self.fc2(x)
        return x
model = Net()
if gpu_status:
    model.cuda()

criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=0.0008)

no_epochs = 40
valid_loss_min = np.Inf
curr_time = datetime.datetime.now()
curr_timestamp = str(datetime.datetime.now())
for epoch in range(1, no_epochs + 1):
    train_loss = 0.0
    valid_loss = 0.0
    model.train()
    for data, target in leaf_train_loader:
        if gpu_status:
            data = data.cuda()
            target = target.cuda()
        optimizer.zero_grad()
        output = model(data)
        loss = criterion(output, target)
        loss.backward()
        optimizer.step()
        train_loss += loss.item() * data.size(0)
    model.eval()
    for data, target in leaf_valid_loader:
        if gpu_status:
            data = data.cuda()
            target = target.cuda()
        output = model(data)
        loss = criterion(output, target)
        valid_loss += loss.item() * data.size(0)
    train_loss = train_loss / len(leaf_train_loader.dataset)
    valid_loss = valid_loss / len(leaf_valid_loader.dataset)
    if valid_loss < valid_loss_min:
        torch.save(model.state_dict(), 'Kaggle_kernel_model_apple_leaf' + curr_timestamp + '.pt')
        valid_loss_min = valid_loss

file_name = 'Kaggle_kernel_model_apple_leaf' + str(curr_timestamp)
model.load_state_dict(torch.load(file_name + '.pt'))

from IPython.display import FileLink
FileLink(file_name + '.pt')