Пользовательский CNN не имеет отчета о классификации

#python #deep-learning #neural-network #pytorch

#python #глубокое обучение #нейронная сеть #pytorch

Вопрос:

Я создаю модель для прогнозирования набора данных, и моя точность действительно хороша, но я хотел бы проверить это с помощью отчета о классификации, но я действительно не уверен, как это вписать в мой код. Я изначально не думал об этом, но у меня проблемы. Может кто-нибудь помочь? Обычно, как мы можем сгенерировать отчет о классификации для пользовательской модели?

 lb = joblib.load('/content/drive/MyDrive/Colab_Notebooks/outputs/lb.pkl')

class CustomCNN(nn.Module):
    def __init__(self):
        super(CustomCNN, self).__init__()
        self.conv1 = nn.Conv2d(3, 16, 5)
        self.conv2 = nn.Conv2d(16, 32, 5)
        self.conv3 = nn.Conv2d(32, 64, 3)
        self.conv4 = nn.Conv2d(64, 128, 5)
        self.fc1 = nn.Linear(128, 256)
        self.fc2 = nn.Linear(256, len(lb.classes_))
        self.pool = nn.MaxPool2d(2, 2)
    def forward(self, x):
        x = self.pool(F.relu(self.conv1(x)))
        x = self.pool(F.relu(self.conv2(x)))
        x = self.pool(F.relu(self.conv3(x)))
        x = self.pool(F.relu(self.conv4(x)))
        bs, _, _, _ = x.shape
        x = F.adaptive_avg_pool2d(x, 1).reshape(bs, -1)
        x = F.relu(self.fc1(x))
        x = self.fc2(x)
        return x

# learning_parameters
lr = 1e-3
batch_size = 32
device = 'cuda' if torch.cuda.is_available() else 'cpu'

print(f"Computation device: {device}n")


# read the data.csv file and get the image paths and labels
df = pd.read_csv('/content/drive/MyDrive/Colab_Notebooks/input/data.csv')
X = df.image_path.values # image paths
y = df.target.values # targets
(xtrain, xtest, ytrain, ytest) = train_test_split(X, y,
    test_size=0.10, random_state=42)
print(f"Training instances: {len(xtrain)}")
print(f"Validation instances: {len(xtest)}")


class ImageDataset(Dataset):
    def __init__(self, images, labels=None, tfms=None):
        self.X = images
        self.y = labels
        # apply augmentations
        if tfms == 0:  # if validating
            self.aug = albumentations.Compose([
                albumentations.Resize(224, 224, always_apply=True),
            ])
        else:  # if training
            self.aug = albumentations.Compose([
                albumentations.Resize(224, 224, always_apply=True),
                albumentations.HorizontalFlip(p=0.5),
                albumentations.ShiftScaleRotate(
                    shift_limit=0.3,
                    scale_limit=0.3,
                    rotate_limit=15,
                    p=0.5
                ),
            ])

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

    def __getitem__(self, i):
        image = Image.open(self.X[i])
        image = image.convert('RGB')
        image = self.aug(image=np.array(image))['image']
        image = np.transpose(image, (2, 0, 1)).astype(np.float32)
        label = self.y[i]
        return (torch.tensor(image, dtype=torch.float), torch.tensor(label, dtype=torch.long))

train_data = ImageDataset(xtrain, ytrain, tfms=1)
test_data = ImageDataset(xtest, ytest, tfms=0)
# dataloaders
trainloader = DataLoader(train_data, batch_size=batch_size, shuffle=True)
testloader = DataLoader(test_data, batch_size=batch_size, shuffle=False)

model = CustomCNN().to(device)
print(model)
# total parameters and trainable parameters
total_params = sum(p.numel() for p in model.parameters())
print(f"{total_params:,} total parameters.")
total_trainable_params = sum(
    p.numel() for p in model.parameters() if p.requires_grad)
print(f"{total_trainable_params:,} training parameters.")

# optimizer
optimizer = optim.Adam(model.parameters(), lr=lr)
# loss function
criterion = nn.CrossEntropyLoss()
scheduler = torch.optim.lr_scheduler.ReduceLROnPlateau(
    optimizer,
    mode='min',
    patience=5,
    factor=0.5,
    min_lr=1e-6,
    verbose=True
)


# validation function
def validate(model, test_dataloader):
    print('Validating')
    model.eval()
    val_running_loss = 0.0
    val_running_correct = 0
    with torch.no_grad():
        for i, data in tqdm(enumerate(test_dataloader), total=int(len(test_data) / test_dataloader.batch_size)):
            data, target = data[0].to(device), data[1].to(device)
            outputs = model(data)
            loss = criterion(outputs, target)

            val_running_loss  = loss.item()
            _, preds = torch.max(outputs.data, 1)
            val_running_correct  = (preds == target).sum().item()

        val_loss = val_running_loss / len(test_dataloader.dataset)
        val_accuracy = 100. * val_running_correct / len(test_dataloader.dataset)
        print(f'Val Loss: {val_loss:.4f}, Val Acc: {val_accuracy:.2f}')

        return val_loss, val_accuracy


# training function
def fit(model, train_dataloader):
    print('Training')
    model.train()
    train_running_loss = 0.0
    train_running_correct = 0
    for i, data in tqdm(enumerate(train_dataloader), total=int(len(train_data) / train_dataloader.batch_size)):
        data, target = data[0].to(device), data[1].to(device)
        optimizer.zero_grad()
        outputs = model(data)
        loss = criterion(outputs, target)
        train_running_loss  = loss.item()
        _, preds = torch.max(outputs.data, 1)
        train_running_correct  = (preds == target).sum().item()
        loss.backward()
        optimizer.step()

    train_loss = train_running_loss / len(train_dataloader.dataset)
    train_accuracy = 100. * train_running_correct / len(train_dataloader.dataset)

    print(f"Train Loss: {train_loss:.4f}, Train Acc: {train_accuracy:.2f}")
 

—Я пытался включить сюда отчет о классификации, но да, в моем пользовательском CNN нет отчета о классификации! приведенная ниже часть с комментариями была моей попыткой посмотреть, смогу ли я сгенерировать отчет, но я получаю сообщение об ошибке.

 '''    
    predictions = model.predict(x=xtest.astype("float32"), batch_size=32)
    print(classification_report(ytest.argmax(axis=1),
      predictions.argmax(axis=1), target_names=lb.classes_))
    return train_loss, train_accuracy
'''  

train_loss, train_accuracy = [], []
val_loss, val_accuracy = [], []
start = time.time()
for epoch in range(5):
    print(f"Epoch {epoch   1} of {epoch   1}")
    train_epoch_loss, train_epoch_accuracy = fit(model, trainloader)
    val_epoch_loss, val_epoch_accuracy = validate(model, testloader)
    train_loss.append(train_epoch_loss)
    train_accuracy.append(train_epoch_accuracy)
    val_loss.append(val_epoch_loss)
    val_accuracy.append(val_epoch_accuracy)
    scheduler.step(val_epoch_loss)
end = time.time()

print(f"{(end - start) / 60:.3f} minutes")



##
# accuracy plots
plt.figure(figsize=(10, 7))
plt.plot(train_accuracy, color='green', label='train accuracy')
plt.plot(val_accuracy, color='blue', label='validataion accuracy')
plt.xlabel('Epochs')
plt.ylabel('Accuracy')
plt.legend()
plt.savefig('/content/drive/MyDrive/Colab_Notebooks/outputs/accuracy.png')
plt.show()

# loss plots
plt.figure(figsize=(10, 7))
plt.plot(train_loss, color='orange', label='train loss')
plt.plot(val_loss, color='red', label='validataion loss')
plt.xlabel('Epochs')
plt.ylabel('Loss')
plt.legend()
plt.savefig('/content/drive/MyDrive/Colab_Notebooks/outputs/loss.png')
plt.show()

# serialize the model to disk
print('Saving model...')
torch.save(model.state_dict(), '/content/drive/MyDrive/Colab_Notebooks/outputs/sports.pth')

print('TRAINING COMPLETE')
 

Ошибка:

 --------------------------------------------------------------------------
ModuleAttributeError                      Traceback (most recent call last)
<ipython-input-5-ad111802746a> in <module>()
    157 for epoch in range(5):
    158     print(f"Epoch {epoch   1} of {epoch   1}")
--> 159     train_epoch_loss, train_epoch_accuracy = fit(model, trainloader)
    160     val_epoch_loss, val_epoch_accuracy = validate(model, testloader)
    161     train_loss.append(train_epoch_loss)

1 frames
/usr/local/lib/python3.6/dist-packages/torch/nn/modules/module.py in __getattr__(self, name)
    777                 return modules[name]
    778         raise ModuleAttributeError("'{}' object has no attribute '{}'".format(
--> 779             type(self).__name__, name))
    780 
    781     def __setattr__(self, name: str, value: Union[Tensor, 'Module']) -> None:

ModuleAttributeError: 'CustomCNN' object has no attribute 'predict'
 

Комментарии:

1. это похоже на pytorch, а не на tensorflow

2. @Nicolas мой плохой, неправильный тег, я это исправил.

3. «predictions = model.predict(x = xtest.astype(«float32″), batch_size = 32)» Закомментирован ли этот раздел?

4. да, потому что я не буду работать, я получаю сообщение об ошибке выше, если я попытаюсь таким образом показать отчет о классификации. В основном это была моя попытка.

Ответ №1:

Я думаю, вы делаете это неправильно в этой строке

 predictions = model.predict(x=xtest.astype("float32"), batch_size=32)
 

Поскольку ваша модель находится в pytorch и наследует nn.module, вам не нужно явно вызывать .predict для получения прогнозов, потому что они не .predict работают. .predict функция доступна в tensorflow keras.

Вы можете просто передать значение в model model(data) , как в приведенной ниже строке

 predictions = []
real_labels = []
for x, y in test_dataloader:
    x = x.to(device).float()
    out_class = model(x)
    label = out_class.cpu().data.numpy().argmax()
    predictions.append(label)
    real_labels.append(y)
 

Для вычисления classification_report вы можете сделать следующее

  • Установите библиотеку seqeval
     pip install seqeval
     
  • Затем выполните следующие действия
     from seqeval.metrics import classification_report
    
    predictions = [ predictions ]
    real_labels = [ real_labels ]
    
    print(classification_report( predictions, real_labels ))
     

Убедитесь, что формат predictions массива и real_labels список списка подобны [ [ class_1, class_2, ... ] ] вот почему я добавил extra [ ] перед переходом в функцию `classification_report’

Он напечатает отчет примерно так, как показано ниже

                 precision    recall  f1-score   support

         ACT       0.00      0.00      0.00         0
    CITATION       0.47      0.82      0.60        11
     SECTION       0.17      1.00      0.29         1

   micro avg       0.38      0.83      0.53        12
   macro avg       0.21      0.61      0.30        12
weighted avg       0.45      0.83      0.57        12
 

где ACT CITATION и SECTION являются классами или метками в моем случае.

Редактировать

Увидев ваш комментарий, я предполагаю, что вы не понимаете, куда следует поместить приведенный выше код, поэтому в вопросе вы прокомментировали некоторые строки

 '''    
   predictions = model.predict(x=xtest.astype("float32"),   batch_size=32)
print(classification_report(ytest.argmax(axis=1),
  predictions.argmax(axis=1), target_names=lb.classes_))
return train_loss, train_accuracy
''' 
 

Из-за этих строк (после раскомментирования) вы получали ошибку. Потому что вы написали model.predict .

Просто удалите эти строки и мои строки после всех построений перед этой строкой # serialize the model to disk

Комментарии:

1. Просто небольшая вещь: » вам не нужно явно вызывать .predict для получения прогнозов. » на самом деле nn.Module у s нет predict функции!

2. @coderina итак, приведенный выше код находится за пределами функции def fit или внутри нее?

3. @KSp код выходит за fit рамки функции… Я полагаю, вам нужен отчет о классификации после обучения модели … добавьте код, в котором вы пишете predictions = model.predict( ....

4. Но проблема в том, что у меня нет модели. предсказать в моем коде. Как вы можете видеть, что также говорит Иван.

5. Нет, нет … в приведенном выше коде вы прокомментировали некоторые строки predictions = model.predict (просто удалите эти строки и добавьте строки, которые я предложил.. Да, в модели pytorch нет функции .predict, есть только функция keras, я уже написал это в своем ответе