lightning/tests/metrics/test_classification.py

228 lines
6.2 KiB
Python
Raw Normal View History

Native torch metrics (#1488) * Create metric.py * Create utils.py * Create __init__.py * Create __init__.py * Create __init__.py * add tests for metric utils * add tests for metric utils * add docstrings for metrics utils * add docstrings for metrics utils * add function to recursively apply other function to collection * add function to recursively apply other function to collection * add tests for this function * add tests for this function * add tests for this function * update test * update test * Update pytorch_lightning/metrics/metric.py Co-Authored-By: Jirka Borovec <Borda@users.noreply.github.com> * update metric name * remove example docs * fix tests * fix tests * add metric tests * fix to tensor conversion * fix to tensor conversion * fix apply to collection * fix apply to collection * Update pytorch_lightning/metrics/metric.py Co-Authored-By: Jirka Borovec <Borda@users.noreply.github.com> * remove tests from init * remove tests from init * add missing type annotations * rename utils to convertors * rename utils to convertors * rename utils to convertors * rename utils to convertors * Update pytorch_lightning/metrics/convertors.py Co-Authored-By: Jirka Borovec <Borda@users.noreply.github.com> * Update pytorch_lightning/metrics/convertors.py Co-Authored-By: Jirka Borovec <Borda@users.noreply.github.com> * Update pytorch_lightning/metrics/convertors.py Co-Authored-By: Jirka Borovec <Borda@users.noreply.github.com> * Update pytorch_lightning/metrics/convertors.py Co-Authored-By: Jirka Borovec <Borda@users.noreply.github.com> * Update pytorch_lightning/metrics/convertors.py Co-Authored-By: Jirka Borovec <Borda@users.noreply.github.com> * Update pytorch_lightning/metrics/convertors.py Co-Authored-By: Jirka Borovec <Borda@users.noreply.github.com> * Update pytorch_lightning/metrics/metric.py Co-Authored-By: Jirka Borovec <Borda@users.noreply.github.com> * Update tests/utilities/test_apply_to_collection.py Co-Authored-By: Jirka Borovec <Borda@users.noreply.github.com> * Update tests/utilities/test_apply_to_collection.py Co-Authored-By: Jirka Borovec <Borda@users.noreply.github.com> * Update tests/utilities/test_apply_to_collection.py Co-Authored-By: Jirka Borovec <Borda@users.noreply.github.com> * Update tests/utilities/test_apply_to_collection.py Co-Authored-By: Jirka Borovec <Borda@users.noreply.github.com> * Update tests/metrics/convertors.py Co-Authored-By: Jirka Borovec <Borda@users.noreply.github.com> * Update tests/metrics/convertors.py Co-Authored-By: Jirka Borovec <Borda@users.noreply.github.com> * Apply suggestions from code review Co-Authored-By: Jirka Borovec <Borda@users.noreply.github.com> * Apply suggestions from code review Co-Authored-By: Jirka Borovec <Borda@users.noreply.github.com> * Apply suggestions from code review Co-Authored-By: Jirka Borovec <Borda@users.noreply.github.com> * add doctest example * rename file and fix imports * rename file and fix imports * added parametrized test * added parametrized test * replace lambda with inlined function * rename apply_to_collection to apply_func * rename apply_to_collection to apply_func * rename apply_to_collection to apply_func * Separated class description from init args * Apply suggestions from code review Co-Authored-By: Jirka Borovec <Borda@users.noreply.github.com> * adjust random values * suppress output when seeding * remove gpu from doctest * Add requested changes and add ellipsis for doctest * Add requested changes and add ellipsis for doctest * Add requested changes and add ellipsis for doctest * forgot to push these files... * forgot to push these files... * forgot to push these files... * add explicit check for dtype to convert to * add explicit check for dtype to convert to * fix ddp tests * fix ddp tests * fix ddp tests * remove explicit ddp destruction * remove explicit ddp destruction * New metric classes (#1326) * Create metrics package * Create metric.py * Create utils.py * Create __init__.py * add tests for metric utils * add docstrings for metrics utils * add function to recursively apply other function to collection * add tests for this function * update test * Update pytorch_lightning/metrics/metric.py Co-Authored-By: Jirka Borovec <Borda@users.noreply.github.com> * update metric name * remove example docs * fix tests * add metric tests * fix to tensor conversion * fix apply to collection * Update CHANGELOG.md * Update pytorch_lightning/metrics/metric.py Co-Authored-By: Jirka Borovec <Borda@users.noreply.github.com> * remove tests from init * add missing type annotations * rename utils to convertors * Create metrics.rst * Update index.rst * Update index.rst * Update pytorch_lightning/metrics/convertors.py Co-Authored-By: Jirka Borovec <Borda@users.noreply.github.com> * Update pytorch_lightning/metrics/convertors.py Co-Authored-By: Jirka Borovec <Borda@users.noreply.github.com> * Update pytorch_lightning/metrics/convertors.py Co-Authored-By: Jirka Borovec <Borda@users.noreply.github.com> * Update pytorch_lightning/metrics/metric.py Co-Authored-By: Jirka Borovec <Borda@users.noreply.github.com> * Update tests/utilities/test_apply_to_collection.py Co-Authored-By: Jirka Borovec <Borda@users.noreply.github.com> * Update tests/utilities/test_apply_to_collection.py Co-Authored-By: Jirka Borovec <Borda@users.noreply.github.com> * Update tests/metrics/convertors.py Co-Authored-By: Jirka Borovec <Borda@users.noreply.github.com> * Apply suggestions from code review Co-Authored-By: Jirka Borovec <Borda@users.noreply.github.com> * add doctest example * rename file and fix imports * added parametrized test * replace lambda with inlined function * rename apply_to_collection to apply_func * Separated class description from init args * Apply suggestions from code review Co-Authored-By: Jirka Borovec <Borda@users.noreply.github.com> * adjust random values * suppress output when seeding * remove gpu from doctest * Add requested changes and add ellipsis for doctest * forgot to push these files... * add explicit check for dtype to convert to * fix ddp tests * remove explicit ddp destruction Co-authored-by: Jirka Borovec <Borda@users.noreply.github.com> * add function to reduce tensors (similar to reduction in torch.nn) * add functionals of reduction metrics * add functionals of reduction metrics * add more metrics * pep8 fixes * rename * rename * add reduction tests * add first classification tests * bugfixes * bugfixes * add more unit tests * fix roc score metric * fix tests * solve tests * fix docs * Update CHANGELOG.md * remove binaries * solve changes from rebase * add eos * test auc independently * fix formatting * docs * docs * chlog * move * function descriptions * Add documentation to native metrics (#2144) * add docs * add docs * Apply suggestions from code review * formatting * add docs Co-authored-by: Jirka Borovec <Borda@users.noreply.github.com> Co-authored-by: Jirka <jirka@pytorchlightning.ai> * Rename tests/metrics/test_classification.py to tests/metrics/functional/test_classification.py * Rename tests/metrics/test_reduction.py to tests/metrics/functional/test_reduction.py * Add module interface for classification metrics * add basic tests for classification metrics' module interface * pep8 * add additional converters * add additional base class * change baseclass for some metrics * update classification tests * update converter tests * update metric tests * Apply suggestions from code review * tests-params * tests-params * imports * pep8 * tests-params * formatting * fix test_metrics * typo * formatting * fix dice tests * fix decorator order * fix tests * seed * dice test * formatting * try freeze test * formatting * fix tests * try spawn * formatting * fix Co-authored-by: Jirka Borovec <Borda@users.noreply.github.com> Co-authored-by: J. Borovec <jirka.borovec@seznam.cz> Co-authored-by: Xavier Sumba <c.uent@hotmail.com> Co-authored-by: Jirka <jirka@pytorchlightning.ai> Co-authored-by: Nicki Skafte <nugginea@gmail.com>
2020-06-13 12:47:25 +00:00
# NOTE: This file only tests if modules with arguments are running fine.
# The actual metric implementation is tested in functional/test_classification.py
# Especially reduction and reducing across processes won't be tested here!
import pytest
import torch
from pytorch_lightning.metrics.classification import (
Accuracy,
ConfusionMatrix,
PrecisionRecall,
Precision,
Recall,
AveragePrecision,
AUROC,
FBeta,
F1,
ROC,
MulticlassROC,
MulticlassPrecisionRecall,
DiceCoefficient,
)
@pytest.fixture
def random():
torch.manual_seed(0)
@pytest.mark.parametrize('num_classes', [1, None])
def test_accuracy(num_classes):
acc = Accuracy(num_classes=num_classes)
assert acc.name == 'accuracy'
result = acc(pred=torch.tensor([[0, 1, 1], [1, 0, 1]]),
target=torch.tensor([[0, 0, 1], [1, 0, 1]]))
assert isinstance(result, torch.Tensor)
@pytest.mark.parametrize('normalize', [False, True])
def test_confusion_matrix(normalize):
conf_matrix = ConfusionMatrix(normalize=normalize)
assert conf_matrix.name == 'confusion_matrix'
target = (torch.arange(120) % 3).view(-1, 1)
pred = target.clone()
cm = conf_matrix(pred, target)
assert isinstance(cm, torch.Tensor)
@pytest.mark.parametrize('pos_label', [1, 2.])
def test_precision_recall(pos_label):
pred, target = torch.tensor([1, 2, 3, 4]), torch.tensor([1, 0, 0, 1])
pr_curve = PrecisionRecall(pos_label=pos_label)
assert pr_curve.name == 'precision_recall_curve'
pr = pr_curve(pred=pred, target=target, sample_weight=[0.1, 0.2, 0.3, 0.4])
assert isinstance(pr, tuple)
assert len(pr) == 3
for tmp in pr:
assert isinstance(tmp, torch.Tensor)
@pytest.mark.parametrize('num_classes', [1, None])
def test_precision(num_classes):
precision = Precision(num_classes=num_classes)
assert precision.name == 'precision'
pred, target = torch.tensor([1, 2, 3, 4]), torch.tensor([1, 0, 0, 1])
prec = precision(pred=pred, target=target)
assert isinstance(prec, torch.Tensor)
@pytest.mark.parametrize('num_classes', [1, None])
def test_recall(num_classes):
recall = Recall(num_classes=num_classes)
assert recall.name == 'recall'
pred, target = torch.tensor([1, 2, 3, 4]), torch.tensor([1, 0, 0, 1])
rec = recall(pred=pred, target=target)
assert isinstance(rec, torch.Tensor)
@pytest.mark.parametrize('pos_label', [1, 2])
def test_average_precision(pos_label):
pred, target = torch.tensor([1, 2, 3, 4]), torch.tensor([1, 2, 0, 1])
avg_prec = AveragePrecision(pos_label=pos_label)
assert avg_prec.name == 'AP'
ap = avg_prec(pred=pred, target=target, sample_weight=[0.1, 0.2, 0.3, 0.4])
assert isinstance(ap, torch.Tensor)
@pytest.mark.parametrize('pos_label', [1, 2])
def test_auroc(pos_label):
pred, target = torch.tensor([1, 2, 3, 4]), torch.tensor([1, 2, 0, 1])
auroc = AUROC(pos_label=pos_label)
assert auroc.name == 'auroc'
area = auroc(pred=pred, target=target, sample_weight=[0.1, 0.2, 0.3, 0.4])
assert isinstance(area, torch.Tensor)
@pytest.mark.parametrize(['beta', 'num_classes'], [
pytest.param(0., 1),
pytest.param(0.5, 1),
pytest.param(1., 1),
pytest.param(2., 1),
pytest.param(0., None),
pytest.param(0.5, None),
pytest.param(1., None),
pytest.param(2., None)
])
def test_fbeta(beta, num_classes):
fbeta = FBeta(beta=beta, num_classes=num_classes)
assert fbeta.name == 'fbeta'
score = fbeta(pred=torch.tensor([[0, 1, 1], [1, 0, 1]]),
target=torch.tensor([[0, 0, 1], [1, 0, 1]]))
assert isinstance(score, torch.Tensor)
@pytest.mark.parametrize('num_classes', [1, None])
def test_f1(num_classes):
f1 = F1(num_classes=num_classes)
assert f1.name == 'f1'
score = f1(pred=torch.tensor([[0, 1, 1], [1, 0, 1]]),
target=torch.tensor([[0, 0, 1], [1, 0, 1]]))
assert isinstance(score, torch.Tensor)
@pytest.mark.parametrize('pos_label', [1, 2])
def test_roc(pos_label):
pred, target = torch.tensor([1, 2, 3, 4]), torch.tensor([1, 2, 4, 3])
roc = ROC(pos_label=pos_label)
assert roc.name == 'roc'
res = roc(pred=pred, target=target, sample_weight=[0.1, 0.2, 0.3, 0.4])
assert isinstance(res, tuple)
assert len(res) == 3
for tmp in res:
assert isinstance(tmp, torch.Tensor)
@pytest.mark.parametrize('num_classes', [4, None])
def test_multiclass_roc(num_classes):
pred = torch.tensor([[0.85, 0.05, 0.05, 0.05],
[0.05, 0.85, 0.05, 0.05],
[0.05, 0.05, 0.85, 0.05],
[0.05, 0.05, 0.05, 0.85]])
target = torch.tensor([0, 1, 3, 2])
multi_roc = MulticlassROC(num_classes=num_classes)
assert multi_roc.name == 'multiclass_roc'
res = multi_roc(pred, target)
assert isinstance(res, tuple)
if num_classes is not None:
assert len(res) == num_classes
for tmp in res:
assert isinstance(tmp, tuple)
assert len(tmp) == 3
for _tmp in tmp:
assert isinstance(_tmp, torch.Tensor)
@pytest.mark.parametrize('num_classes', [4, None])
def test_multiclass_pr(num_classes):
pred = torch.tensor([[0.85, 0.05, 0.05, 0.05],
[0.05, 0.85, 0.05, 0.05],
[0.05, 0.05, 0.85, 0.05],
[0.05, 0.05, 0.05, 0.85]])
target = torch.tensor([0, 1, 3, 2])
multi_pr = MulticlassPrecisionRecall(num_classes=num_classes)
assert multi_pr.name == 'multiclass_precision_recall_curve'
pr = multi_pr(pred, target)
assert isinstance(pr, tuple)
if num_classes is not None:
assert len(pr) == num_classes
for tmp in pr:
assert isinstance(tmp, tuple)
assert len(tmp) == 3
for _tmp in tmp:
assert isinstance(_tmp, torch.Tensor)
@pytest.mark.parametrize('include_background', [True, False])
def test_dice_coefficient(include_background):
dice_coeff = DiceCoefficient(include_background=include_background)
assert dice_coeff.name == 'dice'
dice = dice_coeff(torch.randint(0, 1, (10, 25, 25)),
torch.randint(0, 1, (10, 25, 25)))
assert isinstance(dice, torch.Tensor)