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))
- 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()
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)
- 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].
In [ ]:
In [ ]: