How do I use a .pickle file to predict an image?
I have trained a CNN model in PyTorch to detect skin diseases in 6 different classes. My model came out with an accuracy of 92% and I saved it in a .pickle file. I wish to use this model for predictions but I don't know how to do so. If anyone can aid me in the necessary steps, I will be grateful. I have tried using Streamlit but apparently, Streamlit does not work anymore so I am opting for an offline solution where I can just upload an image and the model will give me a prediction of such.
Here is the code for my model. I used a pre-trained ResNet18 model and trained it on the Skin Cancer MNIST: HAM10000 dataset from Kaggle.
def set_parameter_requires_grad(model, feature_extracting):
    if feature_extracting:
        for param in model.parameters():
            param.requires_grad = False

def initialize_model(model_name, num_classes, feature_extract, use_pretrained=True):
    # Initialize these variables which will be set in this if statement. Each of these
    #   variables is model specific.
    model_ft = None
    input_size = 0

    if model_name == &quot;resnet&quot;:
        &quot;&quot;&quot; Resnet18, resnet34, resnet50, resnet101
        &quot;&quot;&quot;
        model_ft = models.resnet18(pretrained=use_pretrained)
        set_parameter_requires_grad(model_ft, feature_extract)
        num_ftrs = model_ft.fc.in_features
        model_ft.fc = nn.Linear(num_ftrs, num_classes)
        input_size = 224


    elif model_name == &quot;vgg&quot;:
        &quot;&quot;&quot; VGG11_bn
        &quot;&quot;&quot;
        model_ft = models.vgg11_bn(pretrained=use_pretrained)
        set_parameter_requires_grad(model_ft, feature_extract)
        num_ftrs = model_ft.classifier[6].in_features
        model_ft.classifier[6] = nn.Linear(num_ftrs,num_classes)
        input_size = 224


    elif model_name == &quot;densenet&quot;:
        &quot;&quot;&quot; Densenet121
        &quot;&quot;&quot;
        model_ft = models.densenet121(pretrained=use_pretrained)
        set_parameter_requires_grad(model_ft, feature_extract)
        num_ftrs = model_ft.classifier.in_features
        model_ft.classifier = nn.Linear(num_ftrs, num_classes)
        input_size = 224

    elif model_name == &quot;inception&quot;:
        &quot;&quot;&quot; Inception v3
        &quot;&quot;&quot;
        model_ft = models.inception_v3(pretrained=use_pretrained)
        set_parameter_requires_grad(model_ft, feature_extract)
        # Handle the auxilary net
        num_ftrs = model_ft.AuxLogits.fc.in_features
        model_ft.AuxLogits.fc = nn.Linear(num_ftrs, num_classes)
        # Handle the primary net
        num_ftrs = model_ft.fc.in_features
        model_ft.fc = nn.Linear(num_ftrs,num_classes)
        input_size = 299

    else:
        print(&quot;Invalid model name, exiting...&quot;)
        exit()
    return model_ft, input_size

# resnet,vgg,densenet,inception
model_name = 'resnet'
num_classes = 7
feature_extract = False
# Initialize the model for this run
model_ft, input_size = initialize_model(model_name, num_classes, feature_extract, use_pretrained=True)
# Define the device:
device = torch.device('cuda:0')
# Put the model on the device:
model = model_ft.to(device)

# norm_mean = (0.49139968, 0.48215827, 0.44653124)
# norm_std = (0.24703233, 0.24348505, 0.26158768)
# define the transformation of the train images.
train_transform = transforms.Compose([transforms.Resize((input_size,input_size)),transforms.RandomHorizontalFlip(),
                                      transforms.RandomVerticalFlip(),transforms.RandomRotation(20),
                                      transforms.ColorJitter(brightness=0.1, contrast=0.1, hue=0.1),
                                        transforms.ToTensor(), transforms.Normalize(norm_mean, norm_std)])
# define the transformation of the val images.
val_transform = transforms.Compose([transforms.Resize((input_size,input_size)), transforms.ToTensor(),
                                    transforms.Normalize(norm_mean, norm_std)])

# Define a pytorch dataloader for this dataset
class HAM10000(Dataset):
    def __init__(self, df, transform=None):
        self.df = df
        self.transform = transform

    def __len__(self):
        return len(self.df)

    def __getitem__(self, index):
        # Load data and get label
        X = Image.open(self.df['path'][index])
        y = torch.tensor(int(self.df['cell_type_idx'][index]))

        if self.transform:
            X = self.transform(X)

        return X, y

# Define the training set using the table train_df and using our defined transitions (train_transform)
training_set = HAM10000(df_train, transform=train_transform)
train_loader = DataLoader(training_set, batch_size=64, shuffle=True, num_workers=4)
# Same for the validation set:
validation_set = HAM10000(df_val, transform=train_transform)
val_loader = DataLoader(validation_set, batch_size=64, shuffle=False, num_workers=4)

# we use Adam optimizer, use cross entropy loss as our loss function
optimizer = optim.Adam(model.parameters(), lr=1e-5)
criterion = nn.CrossEntropyLoss().to(device)

Here are the training process and the save file.
class AverageMeter(object):
    def __init__(self):
        self.reset()

    def reset(self):
        self.val = 0
        self.avg = 0
        self.sum = 0
        self.count = 0

    def update(self, val, n=1):
        self.val = val
        self.sum += val * n
        self.count += n
        self.avg = self.sum / self.count

total_loss_train, total_acc_train = [],[]
def train(train_loader, model, criterion, optimizer, epoch):
    model.train()
    train_loss = AverageMeter()
    train_acc = AverageMeter()
    curr_iter = (epoch - 1) * len(train_loader)
    for i, data in enumerate(train_loader):
        images, labels = data
        N = images.size(0)
        # print('image shape:',images.size(0), 'label shape',labels.size(0))
        images = Variable(images).to(device)
        labels = Variable(labels).to(device)

        optimizer.zero_grad()
        outputs = model(images)

        loss = criterion(outputs, labels)
        loss.backward()
        optimizer.step()
        prediction = outputs.max(1, keepdim=True)[1]
        train_acc.update(prediction.eq(labels.view_as(prediction)).sum().item()/N)
        train_loss.update(loss.item())
        curr_iter += 1
        if (i + 1) % 100 == 0:
            print('[epoch %d], [iter %d / %d], [train loss %.5f], [train acc %.5f]' % (
                epoch, i + 1, len(train_loader), train_loss.avg, train_acc.avg))
            total_loss_train.append(train_loss.avg)
            total_acc_train.append(train_acc.avg)
    return train_loss.avg, train_acc.avg

def validate(val_loader, model, criterion, optimizer, epoch):
    model.eval()
    val_loss = AverageMeter()
    val_acc = AverageMeter()
    with torch.no_grad():
        for i, data in enumerate(val_loader):
            images, labels = data
            N = images.size(0)
            images = Variable(images).to(device)
            labels = Variable(labels).to(device)

            outputs = model(images)
            prediction = outputs.max(1, keepdim=True)[1]

            val_acc.update(prediction.eq(labels.view_as(prediction)).sum().item()/N)

            val_loss.update(criterion(outputs, labels).item())

    print('------------------------------------------------------------')
    print('[epoch %d], [val loss %.5f], [val acc %.5f]' % (epoch, val_loss.avg, val_acc.avg))
    print('------------------------------------------------------------')
    return val_loss.avg, val_acc.avg



if os.path.exists(&quot;Tested_model2.pickle&quot;):
  print(&quot;Loading Trained Model&quot;)
  model = pickle.load(open(&quot;Tested_model2.pickle&quot;, &quot;rb&quot;))
  print(model)
else:
  print(&quot;Training New Model.&quot;)
  print(&quot;Training begins.&quot;)
  print(&quot;********************************************************&quot;)
  epoch_num = 25
  load_model = True
  best_val_acc = 0
  total_loss_val, total_acc_val = [],[]
  for epoch in range(1, epoch_num+1):
    loss_train, acc_train = train(train_loader, model, criterion, optimizer, epoch)
    loss_val, acc_val = validate(val_loader, model, criterion, optimizer, epoch)
    total_loss_val.append(loss_val)
    total_acc_val.append(acc_val)
    if acc_val &gt; best_val_acc:
        best_val_acc = acc_val
        print('*****************************************************')
        print('best record: [epoch %d], [val loss %.5f], [val acc %.5f]' % (epoch, loss_val, acc_val))
        print('*****************************************************')

with open (&quot;Tested_model2.pickle&quot;, &quot;wb&quot;) as file:
  pickle.dump(model, file)

To put it simply, I wanna know how to use the pickle file for predictions.
Edit: I added the evaluation part in the following, please help me to understand how can I proceed further with this code.
model.eval()
y_label = []
y_predict = []
with torch.no_grad():
    for i, data in enumerate(val_loader):
        images, labels = data
        N = images.size(0)
        images = Variable(images).to(device)
        outputs = model(images)
        prediction = outputs.max(1, keepdim=True)[1]
        y_label.extend(labels.cpu().numpy())
        y_predict.extend(np.squeeze(prediction.cpu().numpy().T))

Also, This is the code that I previously used to load and make predictions, however I did not get to know whether the code is correct or not or the method is right.
%%writefile app.py
import streamlit as st
import torch 

st.set_option('deprecation.showfileUploaderEncoding', False)
@st.cache(allow_output_mutation=True)

def load_model():
  model = pickle.load(open(&quot;Trained_Model_part2.pickle&quot;, &quot;rb&quot;))
  return mdoel

model = load_model()
st.write(&quot;&quot;&quot;
         #Classification of skin disease
         &quot;&quot;&quot;)

file = st.file_uploader(&quot;Please upload the image of the affected area.&quot;, type = [&quot;jpg&quot;, &quot;png&quot;])

import cv2
from PIL import Image, ImageOps
import numpy as np

def import_and_predict(image_data, model):
  size = (224, 224)
  image = ImageOps.fit(image_data, size, Image.ANTIALIAS)
  img = np.asarray(image)
  image_reshape = img[np.newaxis,...]
  prediction = model.predict(img_reshape)

  return prediction

if file is None:
  st.text(&quot;Please upload an image file.&quot;)
else:
  image = Image.open(file)
  st.image(image, use_column_width = True)
  predictions = import_and_predict(image, model)
  class_names = [&quot;Melanocytic nevi&quot;, &quot;Melanoma&quot;, &quot;Benign keratosis-like lesions&quot;, &quot;Basal cell carcinoma&quot;, &quot;Actinic keratoses&quot;, &quot;Vascular lesions&quot;, &quot;Dermatofibroma&quot;]
  string = &quot;It is: &quot; + class_names[np.argmax(predictions)]
  st.success(string)

This uses streamlit and the loader is the previous pickle file loader which will be replaced by a .pth loader. I want to know what changes do I have to make so the code will ask for an image input or look for an image in the specific folder and deliver a prediction. Thank you.

I'll show you how to save and load pytorch model parameters properly (you should use the .pt extension):
To save the model do this (once every epoch or after training):
torch.save(model.state_dict(), &quot;your/path/model_file.pt&quot;)

All the model parameters are now loaded into &quot;your/path/model_file.pt&quot;.
To load the model now you will need the model class (class YourModel(nn.Module): ...) and the parameters:
model = YourModel()
model.load_state_dict(torch.load(&quot;your/path/model_file.pt&quot;))

The model is now initialized with the trianed parameters and ready to use. For example like this:
model = YourModel()
model.load_state_dict(torch.load(&quot;your/path/model_file.pt&quot;))

# set to evaluation mode
model.eval()

# load an image
sample = get_sample()

# reshape sample to (batch-size x width x height) but batch-size is 1 because you probably want to predict just one image at a time in real-life usage
sample = torch.reshape(1, sample.size(0), sample.size(1))

prediction = model(sample)

Edit to answer the question in the comments:
To load a trained pytorch model you need the file in which the models parameter is saved and the model structure itself. The model structure is just the python code of a pytorch module class. You havent build the model youself therefore you dont have the direct model code but in your case it should be model_ft. It's just the python class holding all the layers. So the model class is like the skeletton and the parameters like the flesh or something.
When you would create a model class completly yourself and load the trained weights into it it would look like this for example:

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

# the model (skeleton class)
class YourModel(nn.Module):
    def __init__(self):
        super(YourModel, self).__init__()

        self.dense1 = nn.Linear(128, 64)
        self.dense2 = nn.Linear(64, 2)

    def forward(self, x):
        x = F.relu(self.dense1(x))
        x = torch.sigmoid(self.dense2(x))

        return x

# . . .
# train model and save it to model.pt
# . . .

# load &quot;empty&quot; model
model = YourModel()

# load trained paramters/weights into the model
model.load_state_dict(torch.load(&quot;/path/model.pt&quot;))

So as I said, in your case it the model class should be model_ft.
