<jupyter_start><jupyter_text>**Super Resolution:**         The idea is to improve the quality of low quality images. There are different approaches used for this purpose.*   Bilinear Approach.*   K mean Approach.*   Model Prediction.*   Ground Truth.We will be using Model prediction using deep network to train a model to improve image quality.The first step is to preapare data. We will use google_images_download library for downloading images from internet and then we will use torch.Transform for transforming the downloaded images to lower size and to tensor data structure.Torch.Tensor is similar to multidimentional matrices in numpy, The advantagae is that it offer better performance in operations and the best part is that it offers GPU computation.  **Connecting My Google Drive...**The dataset will be downloaded and used from drive.<jupyter_code>from google.colab import drive
drive.mount('/content/gdrive')
%cd gdrive/My Drive/SuperResolution_DL_Project
!pip install google_images_download<jupyter_output>Collecting google_images_download
  Downloading https://files.pythonhosted.org/packages/18/ed/0319d30c48f3653802da8e6dcfefcea6370157d10d566ef6807cceb5ec4d/google_images_download-2.8.0.tar.gz
Collecting selenium
[?25l  Downloading https://files.pythonhosted.org/packages/80/d6/4294f0b4bce4de0abf13e17190289f9d0613b0a44e5dd6a7f5ca98459853/selenium-3.141.0-py2.py3-none-any.whl (904kB)
[K     |████████████████████████████████| 911kB 4.0MB/s 
[?25hRequirement already satisfied: urllib3 in /usr/local/lib/python3.6/dist-packages (from selenium->google_images_download) (1.24.3)
Building wheels for collected packages: google-images-download
  Building wheel for google-images-download (setup.py) ... [?25l[?25hdone
  Created wheel for google-images-download: filename=google_images_download-2.8.0-py2.py3-none-any.whl size=14550 sha256=c253d99a0a835a3c23fdb9f67ae5104b93a3c3edc0c3013fb72d3b23c839810b
  Stored in directory: /root/.cache/pip/wheels/1f/28/ad/f56e7061e1d2a9a1affe2f9c649c2570cb9198dd2[...]<jupyter_text>**Downloading Data...**The following script will download 160 images to train set and 40 to test set.<jupyter_code>from google_images_download import google_images_download   #importing the library

response = google_images_download.googleimagesdownload()   #class instantiation

keywordString = "car,bike,cat,dog,chair,table,tree,book"

arguments_train = {"keywords": keywordString, "limit": 20, "exact_size": "1024,786",
             "output_directory": "Images", "image_directory": "train", "print_urls": True}   #creating list of arguments

arguments_test = {"keywords": keywordString, "limit": 25, "offset": 20, "exact_size": "1024,786",
             "output_directory": "Images", "image_directory": "test", "print_urls": True}   #creating list of arguments


paths = response.download(arguments_train)
print(paths)
paths = response.download(arguments_test)
print(paths)<jupyter_output><empty_output><jupyter_text>**The Above code Uploaded apprx 150 files to Images/train folder. And apprx 40 to Images/Test folder in drive** **Now we will prepare the dataset for our model. We will divide the dataset into train and test set and transform the images using torch.transform**<jupyter_code>import torch.utils.data as data
from os import listdir
from os.path import join
from PIL import Image
from torchvision.transforms import Compose, CenterCrop, ToTensor, Resize


def is_image_file(filename):
    return any(filename.endswith(extension) for extension in [".png", ".jpg", ".jpeg"])


def load_img(filepath):
    img = Image.open(filepath).convert('YCbCr')
    y, _, _ = img.split()
    return y


class DatasetFromFolder(data.Dataset):
    def __init__(self, image_dir, input_transform=None, target_transform=None):
        super(DatasetFromFolder, self).__init__()
        self.image_filenames = [join(image_dir, x) for x in listdir(image_dir) if is_image_file(x)]

        self.input_transform = input_transform
        self.target_transform = target_transform

    def __getitem__(self, index):
        input = load_img(self.image_filenames[index])
        target = input.copy()
        if self.input_transform:
            input = self.input_transform(input)
        if self.target_transform:
            target = self.target_transform(target)

        return input, target

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

def calculate_valid_crop_size(crop_size, upscale_factor):
    return crop_size - (crop_size % upscale_factor)


def input_transform(crop_size, upscale_factor):
    return Compose([
        CenterCrop(crop_size),
        Resize(crop_size // upscale_factor),
        ToTensor(),
    ])


def target_transform(crop_size):
    return Compose([
        CenterCrop(crop_size),
        ToTensor(),
    ])


def get_training_set(upscale_factor):
    root_dir = "Images"
    train_dir = join(root_dir, "train")
    crop_size = calculate_valid_crop_size(256, upscale_factor)

    return DatasetFromFolder(train_dir,
                             input_transform=input_transform(crop_size, upscale_factor),
                             target_transform=target_transform(crop_size))


def get_test_set(upscale_factor):
    root_dir = "Images"
    test_dir = join(root_dir, "test")
    crop_size = calculate_valid_crop_size(256, upscale_factor)

    return DatasetFromFolder(test_dir,
                             input_transform=input_transform(crop_size, upscale_factor),
                             target_transform=target_transform(crop_size))<jupyter_output><empty_output><jupyter_text>**Now we will define our model...**<jupyter_code>import torch
import torch.nn as nn
import torch.nn.init as init


class Net(nn.Module):
    def __init__(self, upscale_factor):
        super(Net, self).__init__()

        self.relu = nn.ReLU()
        self.conv1 = nn.Conv2d(1, 64, (5, 5), (1, 1), (2, 2))
        self.conv2 = nn.Conv2d(64, 64, (3, 3), (1, 1), (1, 1))
        self.conv3 = nn.Conv2d(64, 32, (3, 3), (1, 1), (1, 1))
        self.conv4 = nn.Conv2d(32, upscale_factor ** 2, (3, 3), (1, 1), (1, 1))
        self.pixel_shuffle = nn.PixelShuffle(upscale_factor)

        self._initialize_weights()

    def forward(self, x):
        x = self.relu(self.conv1(x))
        x = self.relu(self.conv2(x))
        x = self.relu(self.conv3(x))
        x = self.pixel_shuffle(self.conv4(x))
        return x

    def _initialize_weights(self):
        init.orthogonal_(self.conv1.weight, init.calculate_gain('relu'))
        init.orthogonal_(self.conv2.weight, init.calculate_gain('relu'))
        init.orthogonal_(self.conv3.weight, init.calculate_gain('relu'))
        init.orthogonal_(self.conv4.weight)<jupyter_output><empty_output><jupyter_text>**Now Comes The Main Part. Here we will be training our Model for the above prepared dataset****Make cuda = True below to use GPU...**<jupyter_code>cuda = True;

from __future__ import print_function
import argparse
from math import log10

import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader

upscale_factor = 3;
train_batch_size = 24;
test_batch_size = 10;
threads = 4;
epochs_count=30;
lr = 0.01
seed = 123;

if cuda and not torch.cuda.is_available():
    raise Exception("No GPU found")

torch.manual_seed(seed)

device = torch.device("cuda" if cuda else "cpu")

print('Loading datasets...')

train_set = get_training_set(upscale_factor)
test_set = get_test_set(upscale_factor)
training_data_loader = DataLoader(dataset=train_set, num_workers=threads, batch_size=train_batch_size, shuffle=True)
testing_data_loader = DataLoader(dataset=test_set, num_workers=threads, batch_size=test_batch_size, shuffle=False)

print('Building model...')
model = Net(upscale_factor).to(device)
criterion = nn.MSELoss()

optimizer = optim.Adam(model.parameters(), lr)


def train(epoch):
    epoch_loss = 0
    for iteration, batch in enumerate(training_data_loader, 1):
        input, target = batch[0].to(device), batch[1].to(device)

        optimizer.zero_grad()
        loss = criterion(model(input), target)
        epoch_loss += loss.item()
        loss.backward()
        optimizer.step()

        print("===> Epoch[{}]({}/{}): Loss: {:.4f}".format(epoch, iteration, len(training_data_loader), loss.item()))

    print("===> Epoch {} Complete: Avg. Loss: {:.4f}".format(epoch, epoch_loss / len(training_data_loader)))


def test():
    avg_psnr = 0
    with torch.no_grad():
        for batch in testing_data_loader:
            input, target = batch[0].to(device), batch[1].to(device)

            prediction = model(input)
            mse = criterion(prediction, target)
            psnr = 10 * log10(1 / mse.item())
            avg_psnr += psnr
    print("===> Avg. PSNR: {:.4f} dB".format(avg_psnr / len(testing_data_loader)))


def checkpoint(epoch):
    model_out_path = "model_epoch_{}.pth".format(epoch)
    torch.save(model, model_out_path)
    print("Checkpoint saved to {}".format(model_out_path))

for epoch in range(1, epochs_count + 1):
    train(epoch)
    test()
    checkpoint(epoch)<jupyter_output>Loading datasets...
Building model...
===> Epoch[1](1/6): Loss: 0.5630
===> Epoch[1](2/6): Loss: 33.4124
===> Epoch[1](3/6): Loss: 0.1108
===> Epoch[1](4/6): Loss: 0.3287
===> Epoch[1](5/6): Loss: 0.3053
===> Epoch[1](6/6): Loss: 0.1043
===> Epoch 1 Complete: Avg. Loss: 5.8041
===> Avg. PSNR: 11.6346 dB
Checkpoint saved to model_epoch_1.pth<jupyter_text>**As we have successfully trained our model. Now we will test it. First I will downscale an image.**<jupyter_code>from matplotlib import pyplot as plt
from skimage.io import imread, imshow, imsave
from skimage.transform import rescale
import cv2
import numpy as np 
img = imread('test.jpg')
img_rescaled = rescale(img, scale=(0.2, 0.2))

plt.subplot(121), imshow(img)
plt.title('Original Image')

plt.subplot(122), imshow(img_rescaled)
plt.title('Rescaled Image')

imsave('testImg.jpg', img_rescaled)
plt.show()<jupyter_output><empty_output><jupyter_text>1.   **Now we will use the epoch file and test the above downscaled image.** I Ran the model for 30 epochs I will use that file.2.   **Set cuda = True to use GPU...**3.   **Provide input image name from folder...**4.  **The output image will be saved as out.jpg in main folder...**<jupyter_code>from __future__ import print_function
import torch
from PIL import Image
from torchvision.transforms import ToTensor
import numpy as np

cuda = True
input_image = "testImg.jpg"
output_filename = "out.jpg"
model_file = "model_epoch_30.pth"

img = Image.open(input_image).convert('YCbCr')
y, cb, cr = img.split()

model = torch.load(model_file)
img_to_tensor = ToTensor()
input = img_to_tensor(y).view(1, -1, y.size[1], y.size[0])

if cuda:
    model = model.cuda()
    input = input.cuda()

out = model(input)
out = out.cpu()
out_img_y = out[0].detach().numpy()
out_img_y *= 255.0
out_img_y = out_img_y.clip(0, 255)
out_img_y = Image.fromarray(np.uint8(out_img_y[0]), mode='L')

out_img_cb = cb.resize(out_img_y.size, Image.BICUBIC)
out_img_cr = cr.resize(out_img_y.size, Image.BICUBIC)
out_img = Image.merge('YCbCr', [out_img_y, out_img_cb, out_img_cr]).convert('RGB')

out_img.save(output_filename)
print('output image saved to ', output_filename)

from matplotlib import pyplot as plt
from skimage.io import imread, imshow, imsave
from skimage.transform import rescale, resize
import cv2

img1 = imread('orange.jpg')
img2 = imread('out.jpg')

plt.subplot(121), imshow(img1)
plt.title('Before Image')

plt.subplot(122), imshow(img2)
plt.title('After Image')<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.1223643276875216, 'fraction_numerical': 0.03629450397511234, 'mean_word_length': 4.311151904543369, 'pattern_counts': {'":': 13, '<': 27, '<?xml version=': 0, '>': 39, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 26, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '7', 'dir': 'jupyter-structured-clean-dedup', 'id': '319209', 'license': 'Unlicense', 'n_tokens_mistral': 4189, 'n_tokens_neox': 3907, 'n_words': 940, 'path': 'SuperResolution.ipynb', 'repo_name': 'bilal-aslam/SuperResolution', 'size': '11572'}