In [1]:
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import torch 
from IPython.display import Image, display
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error
import matplotlib.pyplot as plt
import os

print("Library Versions:")
print('numpy:',np.__version__)
print('pandas:',pd.__version__)
print('torch:',torch.__version__)
Library Versions:
numpy: 2.2.3
pandas: 2.2.3
torch: 2.6.0
In [2]:
n_epochs = 100
verbose_option = True

Classification for Ship Detection¶

Load Ship Detection Dataset

In [3]:
import torch 
from torch.utils.data import Dataset, DataLoader
from torchvision.io import read_image
from torch.utils.data import random_split
from torchvision.transforms.functional import resize
from sklearn import preprocessing
import numpy as np
from pathlib import Path
import torchmetrics

ROOT_PATH = "/home/scs/jatho/public_html/AY25_SD312/class/99_ships/shipsnet"
LR = 1e-4
IMG_SIZE = [80]

tensor_size = IMG_SIZE[0]**2 * 3

def max_scaling(image):
    image = image / 255.0
    image = torch.Tensor(image)
    image = resize(image, size=IMG_SIZE)
    return image

def normalize_img(image):
    means = torch.Tensor([[[105.0385]],[[108.1886]],[[ 94.9558]]])
    stds = torch.Tensor([[[48.4294]],[[40.0104]],[[38.6445]]])
    image = torch.Tensor(image)
    image = resize(image, size=IMG_SIZE)
    image = image - means
    image = image / stds
    return image
In [4]:
#https://pytorch.org/tutorials/beginner/basics/data_tutorial.html
# This data loader excludes directories containing a specified substring
class ShipDataset(Dataset):

    def __init__(self, root_path, transform = None, skip_str = None):
        self.root_path = Path(root_path)
        self.skip_str = skip_str
        self.files = self._load_image_paths() #list(self.root_path.rglob("*/*"))
        #print(entry.parts[-1])
        self.classes = list(set([entry.parts[-1] 
                                 for entry in self.root_path.rglob("*") 
                                 if Path(entry).is_dir() and entry.parts[-1].isdigit()]))
        self.transform = transform

    def _load_image_paths(self):
        image_paths = []
        for dirpath, dirnames, filenames in os.walk(self.root_path):

            for filename in filenames:
                if filename.lower().endswith(('.png', '.jpg', '.jpeg')):
                    image_path = os.path.join(dirpath, filename)
                    if self.skip_str in image_path:
                        continue
                    else:
                        image_paths.append(Path(image_path))
            
        return image_paths

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

    def __getitem__(self, idx):
        image = read_image(str(self.files[idx]))
        label = int(self.files[idx].parts[-2])
        if self.transform:
            image = self.transform(image)
        return image, label
 
In [5]:
   
full_dataset1  = ShipDataset(ROOT_PATH, transform = None, skip_str = 'ipynb') #normalize_img
n_classes = len(full_dataset1.classes)
In [6]:
print(len(full_dataset1))
4000
In [7]:
train_dataset1, test_dataset1 = random_split(full_dataset1, [0.8, 0.2])

train_dataloader1 = DataLoader(train_dataset1, batch_size=len(train_dataset1))
test_dataloader1 = DataLoader(test_dataset1, batch_size=len(test_dataset1))
  1. Using PyTorch, pperform Maximum a Posterori (MAP) estimation for a non-linear Bernoulli prediction model for the binary classification dataset.
In [8]:
for images, label in test_dataloader1:
    images2=images[:15]
    # Convert to NumPy arrays and display using plt
    fig, axes = plt.subplots(3, 5, figsize=(15, 9))  # 3 rows and 5 columns
    for idx, ax in enumerate(axes.flat):  # Flatten axes to iterate over each subplot
        # Convert tensor to NumPy and permute to (H, W, C)
        img = images2[idx].permute(1, 2, 0).numpy()  # Assuming image is a tensor

        # Display the image with label
        if label[idx] == 1: 
            img_title = "ship" 
        else: 
            img_title = "not ship"
        ax.imshow(img)
        ax.set_title(img_title)
        ax.axis('off')  # Hide axis labels

    plt.tight_layout()
    plt.show()
No description has been provided for this image
In [9]:
full_dataset  = ShipDataset(ROOT_PATH, transform = normalize_img, skip_str = 'ipynb') #normalize_img
n_classes = len(full_dataset.classes)
In [10]:
train_dataset, test_dataset = random_split(full_dataset, [0.8, 0.2])

train_dataloader = DataLoader(train_dataset, batch_size=len(train_dataset))
test_dataloader = DataLoader(test_dataset, batch_size=len(test_dataset))

criterion = torch.nn.BCELoss(reduce='mean')
accuracy = torchmetrics.classification.BinaryAccuracy()
/home/scs/jatho/miniforge3/envs/ships/lib/python3.13/site-packages/torch/nn/_reduction.py:51: UserWarning: size_average and reduce args will be deprecated, please use reduction='mean' instead.
  warnings.warn(warning.format(ret))
In [11]:
def acc_cross_entropy(dataloader, model):
    for data, label in dataloader:
        p = model(data)
        nll_loss = criterion(p.squeeze(),label*1.0)
        loss = torch.sum(nll_loss + l2_coeff * model.L2reg()) #TODO: Write the MAP loss
        acc = accuracy(p.squeeze(), label)
        print(loss, acc)
In [12]:
class nn(torch.nn.Module):
    def __init__(self, inputSize, hiddenSize, outputSize):
        super(nn, self).__init__()
        self.layer1 = torch.nn.Linear(inputSize, hiddenSize)
        self.layer2 = torch.nn.Linear(hiddenSize, hiddenSize)
        self.layer3 = torch.nn.Linear(hiddenSize, outputSize)

    def forward(self, x):
        x = torch.flatten(x, start_dim=1)
        h1 = torch.nn.functional.relu(self.layer1(x))
        h2 = torch.nn.functional.relu(self.layer2(h1))
        return torch.sigmoid(self.layer3(h2))

    def L2reg(self): #computes the L2 penalty for this model
        l2reg_sum = 0
        for parameter in self.parameters():
            l2reg_sum = l2reg_sum + torch.sum(parameter ** 2) #sum of the parameters squared
        return l2reg_sum
In [13]:
model = nn(tensor_size, 200, 1)
optimizer = torch.optim.Adam(model.parameters(), lr=1e-4)
l2_coeff = 1e-5
In [14]:
print(model)
nn(
  (layer1): Linear(in_features=19200, out_features=200, bias=True)
  (layer2): Linear(in_features=200, out_features=200, bias=True)
  (layer3): Linear(in_features=200, out_features=1, bias=True)
)
In [15]:
for epoch in range(n_epochs):
    for data, label in train_dataloader:
        optimizer.zero_grad()
        p = model(data)
        nll_loss = criterion(p.squeeze(),label*1.0) 
        loss = torch.sum(nll_loss + l2_coeff * model.L2reg()) #MAP loss
        acc = accuracy(p.squeeze(), label)
        loss.backward()
        optimizer.step()
        if verbose_option: print(epoch, loss, acc)
0 tensor(0.6838, grad_fn=<SumBackward0>) tensor(0.6619)
1 tensor(0.5831, grad_fn=<SumBackward0>) tensor(0.7816)
2 tensor(0.5379, grad_fn=<SumBackward0>) tensor(0.7862)
3 tensor(0.5020, grad_fn=<SumBackward0>) tensor(0.8222)
4 tensor(0.4806, grad_fn=<SumBackward0>) tensor(0.8238)
5 tensor(0.4533, grad_fn=<SumBackward0>) tensor(0.8266)
6 tensor(0.4327, grad_fn=<SumBackward0>) tensor(0.8306)
7 tensor(0.4143, grad_fn=<SumBackward0>) tensor(0.8394)
8 tensor(0.3983, grad_fn=<SumBackward0>) tensor(0.8481)
9 tensor(0.3860, grad_fn=<SumBackward0>) tensor(0.8556)
10 tensor(0.3720, grad_fn=<SumBackward0>) tensor(0.8653)
11 tensor(0.3556, grad_fn=<SumBackward0>) tensor(0.8763)
12 tensor(0.3407, grad_fn=<SumBackward0>) tensor(0.8819)
13 tensor(0.3280, grad_fn=<SumBackward0>) tensor(0.8881)
14 tensor(0.3156, grad_fn=<SumBackward0>) tensor(0.8925)
15 tensor(0.3029, grad_fn=<SumBackward0>) tensor(0.8988)
16 tensor(0.2904, grad_fn=<SumBackward0>) tensor(0.9022)
17 tensor(0.2785, grad_fn=<SumBackward0>) tensor(0.9109)
18 tensor(0.2676, grad_fn=<SumBackward0>) tensor(0.9187)
19 tensor(0.2580, grad_fn=<SumBackward0>) tensor(0.9234)
20 tensor(0.2487, grad_fn=<SumBackward0>) tensor(0.9259)
21 tensor(0.2390, grad_fn=<SumBackward0>) tensor(0.9300)
22 tensor(0.2295, grad_fn=<SumBackward0>) tensor(0.9312)
23 tensor(0.2209, grad_fn=<SumBackward0>) tensor(0.9337)
24 tensor(0.2129, grad_fn=<SumBackward0>) tensor(0.9356)
25 tensor(0.2050, grad_fn=<SumBackward0>) tensor(0.9391)
26 tensor(0.1973, grad_fn=<SumBackward0>) tensor(0.9425)
27 tensor(0.1902, grad_fn=<SumBackward0>) tensor(0.9459)
28 tensor(0.1836, grad_fn=<SumBackward0>) tensor(0.9475)
29 tensor(0.1773, grad_fn=<SumBackward0>) tensor(0.9513)
30 tensor(0.1712, grad_fn=<SumBackward0>) tensor(0.9528)
31 tensor(0.1655, grad_fn=<SumBackward0>) tensor(0.9547)
32 tensor(0.1600, grad_fn=<SumBackward0>) tensor(0.9559)
33 tensor(0.1548, grad_fn=<SumBackward0>) tensor(0.9572)
34 tensor(0.1499, grad_fn=<SumBackward0>) tensor(0.9572)
35 tensor(0.1453, grad_fn=<SumBackward0>) tensor(0.9581)
36 tensor(0.1407, grad_fn=<SumBackward0>) tensor(0.9597)
37 tensor(0.1363, grad_fn=<SumBackward0>) tensor(0.9625)
38 tensor(0.1321, grad_fn=<SumBackward0>) tensor(0.9638)
39 tensor(0.1282, grad_fn=<SumBackward0>) tensor(0.9653)
40 tensor(0.1243, grad_fn=<SumBackward0>) tensor(0.9666)
41 tensor(0.1206, grad_fn=<SumBackward0>) tensor(0.9669)
42 tensor(0.1170, grad_fn=<SumBackward0>) tensor(0.9672)
43 tensor(0.1135, grad_fn=<SumBackward0>) tensor(0.9675)
44 tensor(0.1102, grad_fn=<SumBackward0>) tensor(0.9681)
45 tensor(0.1070, grad_fn=<SumBackward0>) tensor(0.9697)
46 tensor(0.1039, grad_fn=<SumBackward0>) tensor(0.9725)
47 tensor(0.1008, grad_fn=<SumBackward0>) tensor(0.9731)
48 tensor(0.0979, grad_fn=<SumBackward0>) tensor(0.9737)
49 tensor(0.0951, grad_fn=<SumBackward0>) tensor(0.9741)
50 tensor(0.0924, grad_fn=<SumBackward0>) tensor(0.9753)
51 tensor(0.0898, grad_fn=<SumBackward0>) tensor(0.9762)
52 tensor(0.0872, grad_fn=<SumBackward0>) tensor(0.9762)
53 tensor(0.0848, grad_fn=<SumBackward0>) tensor(0.9772)
54 tensor(0.0825, grad_fn=<SumBackward0>) tensor(0.9781)
55 tensor(0.0802, grad_fn=<SumBackward0>) tensor(0.9787)
56 tensor(0.0780, grad_fn=<SumBackward0>) tensor(0.9800)
57 tensor(0.0759, grad_fn=<SumBackward0>) tensor(0.9819)
58 tensor(0.0739, grad_fn=<SumBackward0>) tensor(0.9834)
59 tensor(0.0719, grad_fn=<SumBackward0>) tensor(0.9837)
60 tensor(0.0700, grad_fn=<SumBackward0>) tensor(0.9847)
61 tensor(0.0682, grad_fn=<SumBackward0>) tensor(0.9853)
62 tensor(0.0664, grad_fn=<SumBackward0>) tensor(0.9853)
63 tensor(0.0647, grad_fn=<SumBackward0>) tensor(0.9856)
64 tensor(0.0631, grad_fn=<SumBackward0>) tensor(0.9856)
65 tensor(0.0614, grad_fn=<SumBackward0>) tensor(0.9859)
66 tensor(0.0599, grad_fn=<SumBackward0>) tensor(0.9862)
67 tensor(0.0584, grad_fn=<SumBackward0>) tensor(0.9869)
68 tensor(0.0569, grad_fn=<SumBackward0>) tensor(0.9878)
69 tensor(0.0555, grad_fn=<SumBackward0>) tensor(0.9884)
70 tensor(0.0541, grad_fn=<SumBackward0>) tensor(0.9887)
71 tensor(0.0527, grad_fn=<SumBackward0>) tensor(0.9891)
72 tensor(0.0514, grad_fn=<SumBackward0>) tensor(0.9894)
73 tensor(0.0501, grad_fn=<SumBackward0>) tensor(0.9897)
74 tensor(0.0489, grad_fn=<SumBackward0>) tensor(0.9897)
75 tensor(0.0477, grad_fn=<SumBackward0>) tensor(0.9906)
76 tensor(0.0465, grad_fn=<SumBackward0>) tensor(0.9909)
77 tensor(0.0453, grad_fn=<SumBackward0>) tensor(0.9919)
78 tensor(0.0442, grad_fn=<SumBackward0>) tensor(0.9922)
79 tensor(0.0431, grad_fn=<SumBackward0>) tensor(0.9925)
80 tensor(0.0420, grad_fn=<SumBackward0>) tensor(0.9925)
81 tensor(0.0410, grad_fn=<SumBackward0>) tensor(0.9928)
82 tensor(0.0400, grad_fn=<SumBackward0>) tensor(0.9931)
83 tensor(0.0390, grad_fn=<SumBackward0>) tensor(0.9931)
84 tensor(0.0381, grad_fn=<SumBackward0>) tensor(0.9937)
85 tensor(0.0372, grad_fn=<SumBackward0>) tensor(0.9944)
86 tensor(0.0363, grad_fn=<SumBackward0>) tensor(0.9947)
87 tensor(0.0354, grad_fn=<SumBackward0>) tensor(0.9947)
88 tensor(0.0345, grad_fn=<SumBackward0>) tensor(0.9947)
89 tensor(0.0337, grad_fn=<SumBackward0>) tensor(0.9953)
90 tensor(0.0329, grad_fn=<SumBackward0>) tensor(0.9959)
91 tensor(0.0321, grad_fn=<SumBackward0>) tensor(0.9962)
92 tensor(0.0314, grad_fn=<SumBackward0>) tensor(0.9962)
93 tensor(0.0306, grad_fn=<SumBackward0>) tensor(0.9962)
94 tensor(0.0299, grad_fn=<SumBackward0>) tensor(0.9966)
95 tensor(0.0292, grad_fn=<SumBackward0>) tensor(0.9969)
96 tensor(0.0285, grad_fn=<SumBackward0>) tensor(0.9972)
97 tensor(0.0279, grad_fn=<SumBackward0>) tensor(0.9972)
98 tensor(0.0272, grad_fn=<SumBackward0>) tensor(0.9975)
99 tensor(0.0266, grad_fn=<SumBackward0>) tensor(0.9975)
  1. Compute the accuracy and cross entropy loss for the trained non-linear classification model for the test data.
In [14]:
for data, label in test_dataloader:
    p = model(data)
    nll_loss = criterion(p.squeeze(),label*1.0)
    loss = torch.sum(nll_loss + l2_coeff * model.L2reg()) #TODO: Write the MAP loss
    acc = accuracy(p.squeeze(), label)
    print(loss, acc)
tensor(0.1210, grad_fn=<SumBackward0>) tensor(0.9550)
In [16]:
for images, label in test_dataloader:
    images2=images[:15]
    preds = model(images)
    # Convert to NumPy arrays and display using plt
    fig, axes = plt.subplots(3, 5, figsize=(15, 9))  # 3 rows and 5 columns
    for idx, ax in enumerate(axes.flat):  # Flatten axes to iterate over each subplot
        # Convert tensor to NumPy and permute to (H, W, C)
        img = images2[idx].permute(1, 2, 0).numpy()  # Assuming image is a tensor
        #print(preds.squeeze())
        # Display the image with label
        if preds[idx] >= 0.5: 
            img_title = "ship" 
        else: 
            img_title = "not ship"
        ax.imshow(img)
        ax.set_title(img_title)
        ax.axis('off')  # Hide axis labels

    plt.tight_layout()
    plt.show()
Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers). Got range [-2.5290575..4.0379405].
Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers). Got range [-0.5170103..3.9603097].
Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers). Got range [-1.9792005..3.5721562].
Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers). Got range [-1.6939813..3.5204022].
Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers). Got range [-2.5790446..3.2694352].
Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers). Got range [-1.8102396..3.598033].
Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers). Got range [-0.74928653..3.856802].
Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers). Got range [-1.0856862..3.7532945].
Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers). Got range [-0.54227126..3.2616334].
Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers). Got range [-1.9396241..1.3620136].
Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers). Got range [-0.9045479..3.0139027].
Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers). Got range [-1.2044019..2.8445456].
Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers). Got range [-2.104168..3.096497].
Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers). Got range [-1.2793823..4.0120635].
Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers). Got range [-1.804246..3.4945254].
No description has been provided for this image
In [ ]:
 
In [ ]: