[Python] PyTorch DeiT model keeps predicting one class no matter what

Discussão em 'Python' iniciado por Stack, Dezembro 19, 2024.

  1. Stack

    Stack Membro Participativo

    We are trying to fine-tune a custom model on an imported DeiT distilled patch16 384 pretrained model.

    Output:

    Cost at epoch 0 is 4.611058227040551
    Cost at epoch 1 is 0.9889081553979353
    test set accuracy
    Checking accuracy
    scores: tensor([[ 33.9686, 33.2787, -31.1509, ..., -25.5279, -36.7728, -24.9331],
    [ 33.9695, 33.2792, -31.1509, ..., -25.5264, -36.7719, -24.9356],
    [ 33.9690, 33.2784, -31.1496, ..., -25.5270, -36.7717, -24.9326],
    ...,
    [ 33.9692, 33.2780, -31.1487, ..., -25.5267, -36.7713, -24.9314],
    [ 33.9654, 33.2793, -31.1575, ..., -25.5372, -36.7818, -24.9307],
    [ 33.9687, 33.2778, -31.1490, ..., -25.5278, -36.7719, -24.9300]],
    device='cuda:0')
    predictions: tensor([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0], device='cuda:0')
    y: tensor([1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0,
    1, 1, 0, 1, 0, 1, 1, 1], device='cuda:0')

    ### many more prints later
    predictions: tensor([0, 0, 0, 0, 0, 0], device='cuda:0')
    y: tensor([0, 1, 1, 0, 1, 1], device='cuda:0')
    Got 80 / 198 with accuracy 40.40
    Precision: 0.1632
    Recall: 0.4040
    F1-Score: 0.2325


    The folder is structured as KneeOsteoarthritisXray with subfolders train, test, and val (ignoring val because we just want it to work) and each of those have subfolders 0 and 1 (0 is healthy, 1 has osteoarthritis) The model predicts only 0's and returns an accuracy equal to the amount of 0's in the dataset

    from sklearn.metrics import precision_score, recall_score, f1_score
    import os
    import numpy as np
    from PIL import Image
    from torch.utils.data import Dataset
    import torch
    import torch.nn as nn
    import torch.optim as optim
    import torch.nn.functional as F
    from torch.utils.data import DataLoader
    #import torchvision.transforms as transforms
    from torchvision import transforms
    import torchvision
    from transformers import DeiTForImageClassificationWithTeacher, DeiTImageProcessor

    transform = transforms.Compose([
    transforms.Grayscale(num_output_channels=3),
    transforms.ToTensor(),
    ])

    class myDataset(Dataset):
    def __init__(self, root_dir):
    self.root_dir = root_dir
    self.data = []

    for label in os.listdir(root_dir):
    label_dir = os.path.join(root_dir, label)
    if os.path.isdir(label_dir):
    for file in os.listdir(label_dir):
    self.data.append((os.path.join(label_dir, file), int(label)))

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

    def __getitem__(self, idx):
    img_path, label = self.data[idx]
    image = Image.open(img_path)
    #print(f'image before normalization: {image}') #DEBUG
    image = transform(image)
    #print(f'image after normalization to 0-1{image}') #DEBUG
    image_np = np.array(image)
    return image, label

    device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')

    learning_rate = 0.01
    batch_size = 32
    num_epochs = 32

    model_path = "/content/drive/MyDrive/datasets/PyTorchdeit-base-distilled-patch16-384/"
    model = DeiTForImageClassificationWithTeacher.from_pretrained(model_path)
    model.to(device)

    train_dataset = myDataset(root_dir="/content/drive/MyDrive/datasets/KneeOsteoarthritisXray/train")
    #val_dataset = myDataset(root_dir="/content/drive/MyDrive/datasets/KneeOsteoarthritisXray/val")
    test_dataset = myDataset(root_dir="/content/drive/MyDrive/datasets/KneeOsteoarthritisXray/test")

    train_loader = DataLoader(dataset=train_dataset, batch_size=batch_size, shuffle=True)
    #val_loader = DataLoader(dataset=val_dataset, batch_size=batch_size, shuffle=True)
    test_loader = DataLoader(dataset=test_dataset, batch_size=batch_size, shuffle=True)


    criterion = nn.CrossEntropyLoss()
    optimizer = optim.Adam(model.parameters(), lr=learning_rate)

    for epoch in range(num_epochs):
    losses = []

    for batch_idx, (data, targets) in enumerate(train_loader):
    data = data.to(device=device)
    targets = targets.to(device=device)

    scores = model(data)['logits']
    loss = criterion(scores, targets)
    losses.append(loss.item())

    optimizer.zero_grad()
    loss.backward()

    optimizer.step()

    print(f'Cost at epoch {epoch} is {(sum(losses)/len(losses))}')


    def check_accuracy(loader, model):
    print("Checking accuracy")
    num_correct = 0
    num_samples = 0
    all_labels = []
    all_preds = []

    model.eval()

    with torch.no_grad():
    for x, y in loader:
    x = x.to(device=device)
    y = y.to(device=device)

    scores = model(x)['logits']
    print(f'scores: {scores}')
    _, predictions = scores.max(1)
    print(f'predictions: {predictions}')
    print(f'y: {y}')

    all_labels.extend(y.cpu().numpy())
    all_preds.extend(predictions.cpu().numpy())

    num_correct += (predictions == y).sum() #.item()
    num_samples += predictions.size(0)

    print(f'Got {num_correct} / {num_samples} with accuracy {float(num_correct)/float(num_samples)*100:.2f}')

    precision = precision_score(all_labels, all_preds, average='weighted')
    recall = recall_score(all_labels, all_preds, average='weighted')
    f1 = f1_score(all_labels, all_preds, average='weighted')

    print(f'Precision: {precision:.4f}')
    print(f'Recall: {recall:.4f}')
    print(f'F1-Score: {f1:.4f}')

    model.train()

    print('test set accuracy')
    check_accuracy(test_loader, model)


    We don't think it's overfitting because we tried with unbalanced and balanced versions of the dataset, we tried overfitting a small dataset, and many other attempts.

    We checked out many many similar complaints and can't really get anything out of their code or solutions

    Continue reading...

Compartilhe esta Página