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

# + id="aEW8FsaTRaOo"
import numpy as np

import torch
from torch import nn
from torch import optim
import torch.nn.functional as F
import torch.utils.data as utils
from torchvision import datasets, transforms
from torch.utils.data.sampler import SubsetRandomSampler
import os
import platform
import pickle

# + id="bJAZFldDTQRz"
from google.colab import drive
drive.mount('/content/drive')

# + id="dtBf2_UXTPVs"
# !rm -r DLAV-2022
# !git clone https://github.com/vita-epfl/DLAV-2022.git
path = os.getcwd() + '/DLAV-2022/homeworks/hw2/test_batch'

# + id="QB1xSP9nUZGQ"
# Set the variable to the location of the trained model
model_path = './cifar10_vgg11bn_CUDA.ckpt'


# + id="QEIcPZ4hT7fY"
class ConvNet(nn.Module):
    def __init__(self, n_input_channels=3, n_output=10):
        super().__init__()
        ################################################################################
        # TODO:                                                                        #
        # Define 2 or more different layers of the neural network                      #
        ################################################################################
        # use the VGG11bn model which 8 convolution layers and 3 full connect layers
        # '?' denotes the batch size, which is 64 in our default setting from func above
        # network:[64, 'M', 128, 'M', 256, 256, 'M', 512, 512, 'M', 512, 512, 'M'],
        self.features = nn.Sequential(
                # 1. 64
                nn.Conv2d(3, 64, kernel_size=3, padding=1),         # (  3,32,32) => ( 64,32,32)
                nn.BatchNorm2d(64),
                nn.ReLU(inplace=True),
                nn.MaxPool2d(kernel_size=2, stride=2),              # ( 64,32,32) => ( 64,16,16)
                # 2. 128 conv
                nn.Conv2d(64, 128, kernel_size=3, padding=1),       # ( 64,16,16) => (128,16,16)
                nn.BatchNorm2d(128),
                nn.ReLU(inplace=True),
                nn.MaxPool2d(kernel_size=2, stride=2),              # (128,16,16) => (128, 8, 8)
                # 3. 256 conv
                nn.Conv2d(128, 256, kernel_size=3, padding=1),      # (128, 8, 8) => (256, 8, 8)
                nn.BatchNorm2d(256),
                nn.ReLU(inplace=True),
                # 4. 256
                nn.Conv2d(256, 256, kernel_size=3, padding=1),      # (256, 8, 8) => (256, 8, 8)
                nn.BatchNorm2d(256),
                nn.ReLU(inplace=True),
                nn.MaxPool2d(kernel_size=2, stride=2),              # (256, 8, 8) => (256, 4, 4)
                # 5. 512
                nn.Conv2d(256, 512, kernel_size=3, padding=1),      # (512, 4, 4) => (512, 4, 4)
                nn.BatchNorm2d(512),
                nn.ReLU(inplace=True),                
                # 6. 512
                nn.Conv2d(512, 512, kernel_size=3, padding=1),      # (512, 4, 4) => (512, 4, 4)
                nn.BatchNorm2d(512),
                nn.ReLU(inplace=True),  
                nn.MaxPool2d(kernel_size=2, stride=2),              # (512, 4, 4) => (512, 2, 2)
                # 7. 512
                nn.Conv2d(512, 512, kernel_size=3, padding=1),      # (512, 2, 2) => (512, 2, 2)
                nn.BatchNorm2d(512),
                nn.ReLU(inplace=True),  
                # 8. 512
                nn.Conv2d(512, 512, kernel_size=3, padding=1),      # (512, 2, 2) => (512, 2, 2)
                nn.BatchNorm2d(512),
                nn.ReLU(inplace=True),  
                nn.MaxPool2d(kernel_size=2, stride=2),              # (512, 2, 2) => (512, 1, 1)
        )
        self.classifier = nn.Sequential(
                # 9. Linear
                nn.Dropout(),
                nn.Linear(512, 512),                                # (512, 1, 1) => flatten => (512,)
                nn.ReLU(True),
                # 10. linear
                nn.Dropout(),
                nn.Linear(512, 512),                                # (512,) => (512,)
                nn.ReLU(True),
                # 11. linear
                nn.Linear(512, 10),                                 # (512,) => (10,)
        )
        ################################################################################
        #                              END OF YOUR CODE                                #
        ################################################################################
    
    def forward(self, x):
        ################################################################################
        # TODO:                                                                        #
        # Set up the forward pass that the input data will go through.                 #
        # A good activation function betweent the layers is a ReLu function.           #
        #                                                                              #
        # Note that the output of the last convolution layer should be flattened       #
        # before being inputted to the fully connected layer. We can flatten           #
        # Tensor `x` with `x.view`.                                                    #
        ################################################################################
        x = self.features(x)
        x = x.view(x.size(0), -1)
        x = self.classifier(x)
        ################################################################################
        #                              END OF YOUR CODE                                #
        ################################################################################
        
        return x
    
    def predict(self, x):
        logits = self.forward(x)
        return F.softmax(logits)


# + id="p5v7OgpDR4m2"
def predict_usingCNN(X):
    #########################################################################
    # TODO:                                                                 #
    # - Load your saved model                                               #
    # - Do the operation required to get the predictions                    #
    # - Return predictions in a numpy array                                 #
    # Note: For the predictions, you have to return the index of the max    #
    # value                                                                 #
    #########################################################################
    # CUDA setting
    device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
    net = ConvNet().to(device)
    # Load my optimized model
    checkpoint = torch.load(model_path, map_location=torch.device(device))

    net.load_state_dict(checkpoint)
    # prediction/inference
    with torch.no_grad():
        X = X.to(device)
        outputs = net(X)
        _, predicted = torch.max(outputs.data, 1)
        # _, predicted = torch.max(F.softmax(outputs,dim=1).data, 1)
        # cannot turn a CUDA tensor to numpy, so move to CPU first
        y_pred = predicted.to('cpu').numpy()
    #########################################################################
    #                       END OF YOUR CODE                                #
    #########################################################################
    return y_pred
   


# + id="IGqVw4U3Sy21"
## Read DATA
def load_pickle(f):
    version = platform.python_version_tuple()
    if version[0] == '2':
        return  pickle.load(f)
    elif version[0] == '3':
        return  pickle.load(f, encoding='latin1')
    raise ValueError("invalid python version: {}".format(version))

def load_CIFAR_batch(filename):
  """ load single batch of cifar """
  with open(filename, 'rb') as f:
    datadict = load_pickle(f)
    X = datadict['data']
    Y = datadict['labels']
    X = X.reshape(10000, 3, 32, 32).astype("float")
    Y = np.array(Y)
    return X, Y
test_filename = path
X,Y = load_CIFAR_batch(test_filename)

# + id="qiRBbv7fR-DB"
# Data Manipulation
mean_pytorch = np.array([0.4914, 0.4822, 0.4465])
std_pytorch = np.array([0.2023, 0.1994, 0.2010])
X_pytorch = np.divide(np.subtract( X/255 , mean_pytorch[np.newaxis, :,np.newaxis,np.newaxis]), std_pytorch[np.newaxis, :,np.newaxis,np.newaxis])

# Run Prediction and Evaluation
prediction_cnn = predict_usingCNN(torch.from_numpy(X_pytorch).float())
acc_cnn = sum(prediction_cnn == Y)/len(X_pytorch)
print("CNN Accuracy= %f"%(acc_cnn))
# -

# I found that the accuracy on the final test data is a little higher than the accuracy when i was tranning on the validation data. 
#
# I check the code in the `CNN_Exercise.ipynb`, and i suppose is the way we calculate the validation accuracy, because the last bach of every epoch is usually not the normal size (The number of samples in the data set is not divisible by the batch size) but our way to calulate the accuracy is using accumulated batch accuracy dividied by its batch size in which the last batch in one epoch will be smaller than the normal batch size, and than accumulating the averaged batch accuracy , and lastly divided by its step. 
#
# So the last batch in every epoch will heavily affect (`lead to underestimation`) the calculation of final accuracy in our validation.

StarcoderdataJupyterScriptsDedupFiltered