I am building a deep learning model with Sentinel-2 satellite imagery as the input dataset. The dataset can be labeled as being either natural (1) or anthropogenic (0). I am using PyTorch, with a ResNet18 model, and BCEWithLogitsLoss as a loss function.
I have tried following several solutions found online, including feeding the model with a dataset of only natural (label = 1) images, but every time the model will only predict the label 0.
The same code, with loss = CrossEntropyLoss() and output classes = 2, will predict more correct results, up to 99% accuracy.
Where am I going wrong?
I am new here, so apologies in advance if I made any mistakes! Please, let me know if I need to provide additional code.
Thank you :)
Dataset class:
class CustomDataset(Dataset):
def __init__(self, csv_file, Data_Folder, transform = None, datasplitcat = None, bands = None):
self.data = pd.read_csv(csv_file, sep = ",", skiprows=None)
if datasplitcat:
self.data = self.data[self.data['datasplit'] == datasplitcat]
self.data = self.data.reset_index(drop=True, inplace=False)
self.image_paths = self.data['file']
self.image_folder = Data_Folder
self.target_values = self.data['label']
self.transform = transform
self.bands = bands
def __len__(self):
return len(self.image_paths)
def __getitem__(self, idx):
# IMAGES #
image_name = self.image_paths[idx]
image_path = os.path.join(self.image_folder, image_name)
image = tiff.imread(image_path)
# Choose Number of Bands
image = image[:, :, self.bands]
# Float transformation
image = image.astype('float32')
# Normalization
image = image[:,:,:]/8000
# Transformation
if self.transform:
image = self.transform(image)
# LABELS #
label = int(self.target_values[idx])
label = np.array(label).astype('int64')
label = torch.tensor(label, dtype=torch.long)
label = label.view(-1)
return image, label
Loss implementation:
for batch in train_loader:
optimizer.zero_grad()
inputs, targets = batch
inputs, targets = inputs.to(device), targets.to(device)
# Forward pass
outputs = model(inputs)
targets = targets.view(-1, 1)
targets = torch.tensor(targets, dtype=torch.float32).to(device)
# Compute loss
loss = loss_fn(outputs, targets)
total_loss += loss.item()
# Backward pass and optimization
loss.backward()
optimizer.step()
Model code:
class ResNet18(nn.Module):
def __init__(self, num_classes, band, pt_value):
super(ResNet18, self).__init__()
resnet = resnet18(pretrained = pt_value) # Use pre-trained ResNet50
# Modify the first convolutional layer to accept variable input channels
if band != 3:
resnet.conv1 = nn.Conv2d(band, 64, kernel_size=(7, 7), stride=(2, 2), padding=(3, 3), bias=False)
self.features = nn.Sequential(*list(resnet.children())[:-2])
self.pool = nn.AdaptiveAvgPool2d(1)
self.fc1 = nn.Linear(512, 64)
self.fc2 = nn.Linear(64, 1)
def forward(self, x):
x = self.features(x)
x = self.pool(x)
x = x.view(x.size(0), -1)
x = relu(self.fc1(x))
x = self.fc2(x)
return x