Pytorch precision and recall error: The `target` has to be an integer tensor

Viewed 247

I have this pytorch code (full code is the 'graph level tasks: graph classification' from here:

class GraphLevelGNN(pl.LightningModule):
    
    def __init__(self, **model_kwargs):
        super().__init__()
        # Saving hyperparameters
        self.save_hyperparameters()
        
        self.model = GraphGNNModel(**model_kwargs)
        self.loss_module = nn.BCEWithLogitsLoss() #if self.hparams.c_out == 1 else nn.CrossEntropyLoss()
    def forward(self, data, mode="train"):
        x, edge_index, batch_idx = data.x, data.edge_index, data.batch
        x = self.model(x, edge_index, batch_idx)
        x = x.squeeze(dim=-1)
        
        if self.hparams.c_out == 1:
            preds = (x > 0).float()
            data.y = data.y.float()
        else:
            preds = x.argmax(dim=-1)
        loss = self.loss_module(x, data.y)
        acc = (preds == data.y).sum().float() / preds.shape[0]
        precision_and_recall = precision_recall(preds,data.y,average='macro',num_classes=2)
        return loss, acc, precision_and_recall

    def configure_optimizers(self):
        optimizer = optim.SGD(self.parameters(),lr=0.1) # High lr because of small dataset and small model
        return optimizer

    def training_step(self, batch, batch_idx):
        loss, acc,precision_and_recall = self.forward(batch, mode="train")
        self.log('train_loss', loss)
        self.log('train_acc', acc)
        self.log('train_precision',precision_and_recall)
        return loss

    def validation_step(self, batch, batch_idx):
        _, acc = self.forward(batch, mode="val")
        self.log('val_acc', acc)

    def test_step(self, batch, batch_idx):
        _, acc = self.forward(batch, mode="test")
        self.log('test_acc', acc)

If I remove the references to precision and recall, the code works as expected and will print out test_acc.

When i add in that I also want to monitor precision and recall (i.e. exactly as in code above), I receive the error:

  precision_and_recall = precision_recall(preds,data.y,average='macro',num_classes=2)
  File "/root/miniconda3/lib/python3.7/site-packages/torchmetrics/functional/classification/precision_recall.py", line 546, in precision_recall
    ignore_index=ignore_index,
  File "/root/miniconda3/lib/python3.7/site-packages/torchmetrics/functional/classification/stat_scores.py", line 161, in _stat_scores_update
    ignore_index=ignore_index,
  File "/root/miniconda3/lib/python3.7/site-packages/torchmetrics/utilities/checks.py", line 417, in _input_format_classification
    ignore_index=ignore_index,
  File "/root/miniconda3/lib/python3.7/site-packages/torchmetrics/utilities/checks.py", line 268, in _check_classification_inputs
    _basic_input_validation(preds, target, threshold, multiclass, ignore_index)
  File "/root/miniconda3/lib/python3.7/site-packages/torchmetrics/utilities/checks.py", line 47, in _basic_input_validation
    raise ValueError("The `target` has to be an integer tensor.")
ValueError: The `target` has to be an integer tensor.

I guess this is saying that the target needs to be an integer for precision and recall, but a float for accuracy, whereas I would like to return both?

Could someone show me how to get around this and edit this code to return both accuracy and precision and recall?

1 Answers

Before passing it to the precision_recall function, you can just change the datatype of your target values. They appear to be float but the required type is integer. That makes sense as labels are categorical.

Assuming data.y is a numpy array, you can do:

precision_and_recall = precision_recall(preds,data.y.astype(np.longlong),average='macro',num_classes=2)
Related