Github/kaggle 水果分类项目 前馈神经网络 gpu

#!/usr/bin/env python
# coding: utf-8
# https://github.com/kanchan1910/Fruit-Classification-using-Feedforward-Neural-Networks-in-PyTorch
# # **Fruit Classification using Feedforward Neural Networks in PyTorch**
# # **Project Link**
# https://www.kaggle.com/kanchanjeswani/kernel2c76114526
# 
# It contains the dataset of images containing fruits.
# In this notebook i am going to apply feedforward neural networks to classify the 131 classes of fruits

# In[1]:


# imports
import os
import torch
import torchvision
import tarfile
from torchvision.datasets.utils import download_url
from torch.utils.data import random_split


# In[2]:


project_name='FruitFeedforward'


# In[3]:


train_dataset_url="./train"
test_dataset_url="./test"


# In[4]:


# creating train and test folders
train_folder=os.listdir(train_dataset_url)
test_folder=os.listdir(test_dataset_url)


# In[5]:


# checking the number of classes in train and test folder
print("Train Class: ", len(train_folder))
print("Test Class: ", len(test_folder))


# In[6]:


# listing out names of each class of fruit present in train_folder
print(train_folder)


# In[7]:


# listing out names of each class of fruit present in test_folder
print(test_folder)


# In[8]:


# verifying some of the class images
plum_files = os.listdir(train_dataset_url + "/0")
print('No. of training examples for plum files:', len(plum_files))
print(plum_files[:5])


# In[9]:


# verifying some of the class images
banana_files = os.listdir(train_dataset_url + "/3")
print('No. of training examples for banana files:', len(banana_files))
print(banana_files[:5])


# In[10]:


# We can use the ImageFolder class from torchvision to load the data as PyTorch tenso


# In[11]:


#  importing libraries to change image into tensor dataset as pyTorch can't work on images
from torchvision.datasets import ImageFolder
from torchvision.transforms import ToTensor


# In[12]:


dataset = ImageFolder(train_dataset_url, transform=ToTensor())


# In[13]:


# Let's look at a sample element from the training dataset. Each element is a tuple, containing a image tensor and a label. 

img, label = dataset[0]
print(img.shape, label)
img


# In[14]:


# printing classes names of images
# The list of classes is stored in the .classes property of the dataset.

print(dataset.classes)


# In[15]:


# Matplotlib is an amazing visualization library in Python for 2D plots of arrays.
# One of the greatest benefits of visualization is that it allows us visual access to huge amounts of data in easily digestible visuals.
# Matplotlib consists of several plots like line, bar, scatter, histogram etc.


# In[16]:


import matplotlib.pyplot as plt


# In[17]:


# Let's look at a couple of images from the dataset.

def show_example(img, label):
    print('Label: ', dataset.classes[label], "("+str(label)+")")
    plt.imshow(img.permute(1, 2, 0))


# In[18]:


show_example(*dataset[0])


# In[20]:


show_example(*dataset[2000])


# In[23]:


show_example(*dataset[5463])


# In[24]:


# Training and Validation Datasets:
# While building real world machine learning models, it is quite common to split the dataset into 3 parts:

# Training set - used to train the model i.e. compute the loss and adjust the weights of the model using gradient descent.
# Validation set - used to evaluate the model while training, adjust hyperparameters (learning rate etc.) and pick the best version of the model.
# Test set - used to compare different models, or different types of modeling approaches, and report the final accuracy of the model. 
# Since there's no predefined validation set, we can set aside a small portion of the training set to be used as the validation set. 
# We'll use the random_split helper method from PyTorch to do this. To ensure that we always create the same validation set.
# we'll also set a seed for the random number generator


# In[25]:


# To ensure that we always create the same validation set, we'll also set a seed for the random number generator


# In[26]:


random_seed = 42
torch.manual_seed(random_seed);


# In[27]:


# let's print the lengths of train_ds and val_ds
val_size = 5000
train_size = len(dataset) - val_size

train_ds, val_ds = random_split(dataset, [train_size, val_size])
len(train_ds), len(val_ds)


# In[28]:


# We can now create data loaders for training and validation, to load the data in batches
from torch.utils.data.dataloader import DataLoader

batch_size=128 # The number of samples (data points) that would be passed through the network at a time.


# In[29]:


train_dl = DataLoader(train_ds, batch_size, shuffle=True, num_workers=4, pin_memory=True)
val_dl = DataLoader(val_ds, batch_size*2, num_workers=4, pin_memory=True)


# In[30]:


# We can look at batches of images from the dataset using the make_grid method from torchvision. 
# Each time the following code is run, we get a different bach, since the sampler shuffles the indices before creating batches.


# In[ ]:


from torchvision.utils import make_grid

def show_batch(dl):
    for images, labels in dl:
        fig, ax = plt.subplots(figsize=(12, 6))
        ax.set_xticks([]); ax.set_yticks([])
        ax.imshow(make_grid(images, nrow=16).permute(1, 2, 0))
        break


# In[ ]:


# let's view the grid of batches of images
show_batch(train_dl)


# In[ ]:


# As the sizes of our models and datasets increase, we need to use GPUs to train our models within a reasonable amount of time.
# GPUs contain hundreds of cores that are optimized for performing expensive matrix operations on floating point numbers in a short time
# This makes GPU(s) ideal for training deep neural networks with many layers.


# In[ ]:


# We can check if a GPU is available and the required NVIDIA CUDA drivers are installed using torch.cuda.is_available.


# In[ ]:


torch.cuda.is_available()


# In[ ]:


# Let's define a helper function to ensure that our code uses the GPU if available, and defaults to using the CPU if it isn't.

def get_default_device():
    """Pick GPU if available, else CPU"""
    if torch.cuda.is_available():
        return torch.device('cuda')
    else:
        return torch.device('cpu')
    
# Next, let's define a function that can move data and model to a chosen device.

def to_device(data, device):
    """Move tensor(s) to chosen device"""
    if isinstance(data, (list,tuple)):
        return [to_device(x, device) for x in data]
    return data.to(device, non_blocking=True)

# Finally, we define a DeviceDataLoader class to wrap our existing data loaders and move data to the selected device, as a batches are accessed. 
# All we need is an __iter__ method to retrieve batches of data, and an __len__ method to get the number of batches.

class DeviceDataLoader():
    """Wrap a dataloader to move data to a device"""
    def __init__(self, dl, device):
        self.dl = dl
        self.device = device
        
    def __iter__(self):
        """Yield a batch of data after moving it to device"""
        for b in self.dl: 
            yield to_device(b, self.device)

    def __len__(self):
        """Number of batches"""
        return len(self.dl)


# In[ ]:


# let's check our type of device
device = get_default_device()
device


# In[ ]:


import torch.nn as nn
import torch.nn.functional as F


# In[ ]:


# let's define our model

def accuracy(outputs, labels):
    _, preds = torch.max(outputs, dim=1)
    return torch.tensor(torch.sum(preds == labels).item() / len(preds))

class ImageClassificationBase(nn.Module):
    def training_step(self, batch):
        images, labels = batch 
        out = self(images)                  # Generate predictions
        loss = F.cross_entropy(out, labels) # Calculate loss
        # . A commonly used loss function for classification problems is the cross entropy.
        return loss
    
    def validation_step(self, batch):
        images, labels = batch 
        out = self(images)                    # Generate predictions
        loss = F.cross_entropy(out, labels)   # Calculate loss
        acc = accuracy(out, labels)           # Calculate accuracy
        return {'val_loss': loss.detach(), 'val_acc': acc}
        
    def validation_epoch_end(self, outputs):
        batch_losses = [x['val_loss'] for x in outputs]
        epoch_loss = torch.stack(batch_losses).mean()   # Combine losses
        batch_accs = [x['val_acc'] for x in outputs]
        epoch_acc = torch.stack(batch_accs).mean()      # Combine accuracies
        return {'val_loss': epoch_loss.item(), 'val_acc': epoch_acc.item()}
    
    def epoch_end(self, epoch, result):
        print("Epoch [{}], train_loss: {:.4f}, val_loss: {:.4f}, val_acc: {:.4f}".format(
            epoch, result['train_loss'], result['val_loss'], result['val_acc']))


# In[ ]:


input_size=3*100*100 # parameters
output_size=131


# In[ ]:


# NOW LET'S UNDERSTAND FEEDFORWARD NEURAL NETWORKS 


# In[ ]:


# Feedforward neural networks were among the first and most successful learning algorithms.
# They are also called deep networks, multi-layer perceptron (MLP), or simply neural networks. 
# As data travels through the network’s artificial mesh, each layer processes an aspect of the data, filters outliers, spots familiar entities and produces the final output


# In[ ]:


# NOW LET'S UNDERSTAND LAYERS OF FEEDFORWARD NEURAL NETWORKS 


# In[ ]:


# Input layer: This layer consists of the neurons that receive inputs and pass them on to the other layers. 
# The number of neurons in the input layer should be equal to the attributes or features in the dataset.
# Output layer: The output layer is the predicted feature and depends on the type of model you’re building.
# Hidden layer: In between the input and output layer, there are hidden layers based on the type of model. 
# Hidden layers contain a vast number of neurons which apply transformations to the inputs before passing them. 
# As the network is trained, the weights are updated to be more predictive. 





# In[ ]:


# Introducing a hidden layer and an activation function allows the model to learn more complex, multi-layered and non-linear relationships between the inputs and the targets.


# In[ ]:


class FruitFnnModel(ImageClassificationBase):
    def __init__(self):
        super().__init__()
        self.linear1=nn.Linear(input_size, 2048) # hidden layer
        self.linear2=nn.Linear(2048, 512) # hidden layer
        self.linear3=nn.Linear(512, 128)  # hidden layer
        self.linear4=nn.Linear(128, 64) #hidden layer
        self.linear5=nn.Linear(64, output_size) # output layer
        
    def forward(self, xb):
        # Flatten images into vectors
        out = xb.view(xb.size(0), -1)
        # Apply layers & activation functions
        out = self.linear1(out)
        out = F.relu(out)
        out = self.linear2(out)
        out = F.relu(out)
        out = self.linear3(out)
        out = F.relu(out)
        out = self.linear4(out)
        out = F.relu(out)
        out = self.linear5(out)
        # Get predictions using output layer
        return out


# In[ ]:


# TRAINING THE MODEL


# In[ ]:


# for epoch in range(num_epochs):
    # Training phase
    # for batch in train_loader:
        # Generate predictions
        # Calculate loss
        # Compute gradients
        # Update weights
        # Reset gradients
    
    # Validation phase
   #  for batch in val_loader:
        # Generate predictions
        # Calculate loss
        # Calculate metrics (accuracy etc.)
    # Calculate average validation loss & metrics
    
    # Log epoch, loss & metrics for inspection


# In[ ]:


@torch.no_grad()

# Here we are using torch.max() function, this function's default behaviour as you can guess by the name is to return maximum among the elements in the Tensor. 
# However, this function also helps get the maximum along a particular dimension, as a Tensor, instead of a single element.
# To specify the dimension (axis – in numpy), there is another optional keyword argument, called dim. This represents the direction that we take for the maximum.
# dim=0, (maximum along columns).
# dim=1 (maximum along rows).

def evaluate(model, val_loader):
    model.eval()
    outputs = [model.validation_step(batch) for batch in val_loader]
    return model.validation_epoch_end(outputs)

def fit(epochs, lr, model, train_loader, val_loader, opt_func=torch.optim.SGD):
    history = []
    optimizer = opt_func(model.parameters(), lr)
    for epoch in range(epochs):
        # Training Phase 
        model.train()
        train_losses = []
        for batch in train_loader:
            loss = model.training_step(batch) # extract loss
            train_losses.append(loss)
            loss.backward() # generate gradients
            optimizer.step() # All optimizers implement a step() method, that updates the parameters.
            optimizer.zero_grad() # Clears the gradients of all optimized torch.Tensor,because every time a variable is back propogated through,
            
            # the gradient will be accumulated instead of being replaced.
            
        # Validation phase
        result = evaluate(model, val_loader)
        result['train_loss'] = torch.stack(train_losses).mean().item() # combine losses
        model.epoch_end(epoch, result)
        history.append(result)
    return history


# In[ ]:


# We have defined an accuracy function which calculates the overall accuracy of the model on an entire batch of outputs, so that we can use it as a metric in fit


# In[ ]:


# Building Feed-Forward neural networks
Fnn_model = FruitFnnModel()
Fnn_model


# In[ ]:


# Printing out the tensor data of Feed Forward Neural Networks

for images, labels in train_dl:
    print('images.shape:', images.shape)
    out = Fnn_model(images)
    print('out.shape:', out.shape)
    print('out[0]:', out[0])
    break


# In[ ]:


# We can now wrap our data loaders using DeviceDataLoader.

Fnn_train_dl = DeviceDataLoader(train_dl, device)
Fnn_val_dl = DeviceDataLoader(val_dl, device)
to_device(Fnn_model, device);


# In[ ]:


# Before we train the model, we need to ensure that the data and the model's parameters (weights and biases) are on the same device (CPU or GPU). 
# We can reuse the to_device function to move the model's parameters to the right device.
Fnn_model = to_device(FruitFnnModel(), device)


# In[ ]:




# Let's see how the model performs on the validation set with the initial set of weights and biases.
evaluate(Fnn_model, Fnn_val_dl)


# In[ ]:


num_epochs = 15 # An epoch is one single pass of all the input data through the network.

# torch.optim is a package implementing various optimization algorithms
opt_func = torch.optim.Adam

# The amount of change to the model during each step of this search process, or the step size, is called the “learning rate” .
# It is the most important hyperparameter to tune for your neural network in order to achieve good performance on your problem.
# Learning rate controls how quickly or slowly a neural network model learns a problem.
lr = 0.001


# In[ ]:


# We are now ready to train the model. Let's train for 4 epochs and look at the results. 
Fnn_history = fit(num_epochs, lr, Fnn_model, Fnn_train_dl, Fnn_val_dl, opt_func)


# In[ ]:


# While the accuracy does continue to increase as we train for more epochs, the improvements get smaller with every epoch. 
# This is easier to see using a line graph.


# In[ ]:


def plot_accuracies(history):
    accuracies = [x['val_acc'] for x in history]
    plt.plot(accuracies, '-x')
    plt.xlabel('epoch')
    plt.ylabel('accuracy')
    plt.title('accuracy vs. number of epochs');


# In[ ]:


plot_accuracies(Fnn_history)


# In[ ]:


def plot_losses(history):
    train_losses = [x.get('train_loss') for x in history]
    val_losses = [x['val_loss'] for x in history]
    plt.plot(train_losses, '-bx')
    plt.plot(val_losses, '-rx')
    plt.xlabel('epoch')
    plt.ylabel('loss')
    plt.legend(['Training', 'Validation'])
    plt.title('Loss vs. No. of epochs : ');


# In[ ]:


plot_losses(Fnn_history)


# In[ ]:


# let's check our model's loss and accuracy last time.
evaluate(Fnn_model, Fnn_val_dl)


# In[ ]:


test_dataset = ImageFolder(test_dataset_url, transform=ToTensor())
len(test_dataset)


# In[ ]:


# NOW LET'S TEST OUR MODEL FOR INDIVIDUAL IMAGES.


# In[ ]:


# While we have been tracking the overall accuracy of a model so far, it's also a good idea to look at model's results on some sample images. 


# In[ ]:


def predict_image(img, model):
    # Convert to a batch of 1
    xb = to_device(img.unsqueeze(0), device)
    # Get predictions from model
    yb = model(xb)
    # Pick index with highest probability
    _, preds  = torch.max(yb, dim=1)
    # Retrieve the class label
    return dataset.classes[preds[0].item()]


# In[ ]:


img, label = test_dataset[6877]
plt.imshow(img.permute(1, 2, 0))
print('Label:', dataset.classes[label], ', Predicted:', predict_image(img, Fnn_model))


# In[ ]:


# CORRECT


# In[ ]:


img, label = test_dataset[1000]
plt.imshow(img.permute(1, 2, 0))
print('Label:', dataset.classes[label], ', Predicted:', predict_image(img, Fnn_model))


# In[ ]:


# CORRECT


# In[ ]:


img, label = test_dataset[5000]
plt.imshow(img.permute(1, 2, 0))
print('Label:', dataset.classes[label], ', Predicted:', predict_image(img, Fnn_model))


# In[ ]:


# CORRECT


# In[ ]:


img, label = test_dataset[400]
plt.imshow(img.permute(1, 2, 0))
print('Label:', dataset.classes[label], ', Predicted:', predict_image(img, Fnn_model))


# In[ ]:


# WRONG


# In[ ]:


img, label = test_dataset[309]
plt.imshow(img.permute(1, 2, 0))
print('Label:', dataset.classes[label], ', Predicted:', predict_image(img, Fnn_model))


# In[ ]:


# CORRECT


# In[ ]:


img, label = test_dataset[340]
plt.imshow(img.permute(1, 2, 0))
print('Label:', dataset.classes[label], ', Predicted:', predict_image(img, Fnn_model))


# In[ ]:


# CORRECT


# In[ ]:


img, label = test_dataset[2687]
plt.imshow(img.permute(1, 2, 0))
print('Label:', dataset.classes[label], ', Predicted:', predict_image(img, Fnn_model))


# In[ ]:


# CORRECT


# In[ ]:


img, label = test_dataset[2000]
plt.imshow(img.permute(1, 2, 0))
print('Label:', dataset.classes[label], ', Predicted:', predict_image(img, Fnn_model))


# In[ ]:


# CORRECT


# In[ ]:


img, label = test_dataset[2400]
plt.imshow(img.permute(1, 2, 0))
print('Label:', dataset.classes[label], ', Predicted:', predict_image(img, Fnn_model))


# In[ ]:


# CORRECT


# In[ ]:


img, label = test_dataset[len(test_dataset)-1]
plt.imshow(img.permute(1, 2, 0))
print('Label:', dataset.classes[label], ', Predicted:', predict_image(img, Fnn_model))


# In[ ]:


# WRONG


# In[ ]:


evaluate(Fnn_model, Fnn_val_dl)


# In[ ]:


# A state_dict is an integral entity if you are interested in saving or loading models from PyTorch.

torch.save(Fnn_model.state_dict(), 'Kanchan-FeedforwardNN-fruitclassif-fruit-Fnn.pth')

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值