I have working on a binary segmentation problem. 0 is for background and 1 is for my building class. When I trained my model loss get updated but accuracy and intersection over union does not change at all.
Epoch [1/10]
Train PxAcc: 0.9783, Train Loss: 0.0840, Train IoU: 0.4891,
Val PxAcc: 0.9391, Val Loss: 11.2002, Val IoU: 0.4695,
Epoch [2/10]
Train PxAcc: 0.9783, Train Loss: 0.0827, Train IoU: 0.4891,
Val PxAcc: 0.9391, Val Loss: 757.0062, Val IoU: 0.4695,
Epoch [3/10]
Train PxAcc: 0.9783, Train Loss: 0.3455, Train IoU: 0.4891,
Val PxAcc: 0.9391, Val Loss: 2.0062, Val IoU: 0.4695,
Here is my train and validate functions:
import torch
import numpy as np
from tqdm import tqdm
from metrics import px_acc, calc_mean_iou
def train(model, train_loader, criterion, optimizer, device):
model.train()
running_loss = 0.0
accuracy = 0.0
mean_iou = 0.0
all_preds = []
all_labels = []
for inputs, labels in tqdm(train_loader, desc="Training"):
inputs, labels = inputs.to(device), labels.to(device)
optimizer.zero_grad()
outputs = model(inputs)
output = outputs['out']
loss = criterion(output, labels)
loss.backward()
optimizer.step()
preds = torch.argmax(output, dim=1)
all_preds.extend(preds.cpu().numpy()) # Move to CPU before conversion to numpy
all_labels.extend(labels.cpu().numpy()) # Move to CPU before conversion to numpy
running_loss += loss.item()
# Calculate pixel accuracy
accuracy = px_acc(all_labels, all_preds)
mean_iou, iou_per_class = calc_mean_iou(all_labels, all_preds, num_classes= 2)
return accuracy, loss, mean_iou
def validate(model, val_loader, criterion, device):
model.eval()
running_loss = 0.0
accuracy = 0.0
mean_iou = 0.0
all_preds = []
all_labels = []
with torch.no_grad():
for inputs, labels in tqdm(val_loader, desc="Validation"):
inputs, labels = inputs.to(device), labels.to(device)
outputs = model(inputs)
output = outputs['out']
loss = criterion(output, labels)
running_loss += loss.item()
preds = torch.argmax(output, dim=1)
all_preds.extend(preds.cpu().numpy()) # Move to CPU before conversion to numpy
all_labels.extend(labels.cpu().numpy()) # Move to CPU before conversion to numpy
loss = running_loss / len(val_loader)
accuracy = px_acc(all_labels, all_preds)
mean_iou, iou_per_class = calc_mean_iou(all_labels, all_preds, num_classes= 2)
return accuracy, loss, mean_iou
Here is my metrics.py that includes intersection over union and pixel accuracy functions.
import numpy as np
def px_acc(y_true_list, y_pred_list):
# Initialize total correct predictions and total pixels
total_correct = 0
total_pixels = 0
# Iterate over the corresponding pairs of arrays in the lists
for y_true, y_pred in zip(y_true_list, y_pred_list):
total_correct += (y_true == y_pred).sum()
total_pixels += y_true.size
# Calculate pixel accuracy
acc = total_correct / total_pixels
return acc
def calc_mean_iou(y_true_list, y_pred_list, num_classes):
# Initialize confusion matrix
conf_matrix = np.zeros((num_classes, num_classes), dtype=np.float32)
# Populate the confusion matrix
for y_true, y_pred in zip(y_true_list, y_pred_list):
for i in range(num_classes):
for j in range(num_classes):
conf_matrix[i, j] += np.sum((y_true == i) & (y_pred == j))
# Calculate IoU per class
iou_per_class = []
for i in range(num_classes):
true_positives = conf_matrix[i, i]
false_positives = conf_matrix[:, i].sum() - true_positives
false_negatives = conf_matrix[i, :].sum() - true_positives
denom = true_positives + false_positives + false_negatives
iou = true_positives / denom if denom > 0 else 0
iou_per_class.append(iou)
# Calculate mean IoU
mean_iou = np.mean(iou_per_class)
return mean_iou, iou_per_class