|
| 1 | +import numpy as np |
| 2 | + |
1 | 3 | import pytest
|
2 | 4 |
|
3 | 5 | import torch
|
4 | 6 | from torch import nn
|
5 | 7 | from torch.nn.modules.loss import _Loss as Loss
|
6 | 8 |
|
7 | 9 | from autoPyTorch.pipeline.components.training.losses import get_loss, losses
|
8 |
| -from autoPyTorch.utils.implementations import get_loss_weight_strategy |
| 10 | +from autoPyTorch.utils.implementations import ( |
| 11 | + LossWeightStrategyWeighted, |
| 12 | + LossWeightStrategyWeightedBinary, |
| 13 | + get_loss_weight_strategy, |
| 14 | +) |
9 | 15 |
|
10 | 16 |
|
11 | 17 | @pytest.mark.parametrize('output_type', ['multiclass',
|
@@ -66,3 +72,70 @@ def test_loss_dict():
|
66 | 72 | assert isinstance(loss['module'](), Loss)
|
67 | 73 | assert 'supported_output_types' in loss.keys()
|
68 | 74 | assert isinstance(loss['supported_output_types'], list)
|
| 75 | + |
| 76 | + |
| 77 | +@pytest.mark.parametrize('target,expected_weights', [ |
| 78 | + ( |
| 79 | + # Expected 4 classes where first one is majority one |
| 80 | + np.array([[1, 0, 0, 0], [1, 0, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]), |
| 81 | + # We reduce the contribution of the first class which has double elements |
| 82 | + np.array([0.5, 1., 1., 1.]), |
| 83 | + ), |
| 84 | + ( |
| 85 | + # Expected 2 classes -- multilable format |
| 86 | + np.array([[1, 0], [1, 0], [1, 0], [0, 1]]), |
| 87 | + # We reduce the contribution of the first class which 3 to 1 ratio |
| 88 | + np.array([2 / 3, 2]), |
| 89 | + ), |
| 90 | + ( |
| 91 | + # Expected 2 classes -- (-1, 1) format |
| 92 | + np.array([[1], [1], [1], [0]]), |
| 93 | + # We reduce the contribution of the second class, which has a 3 to 1 ratio |
| 94 | + np.array([2, 2 / 3]), |
| 95 | + ), |
| 96 | + ( |
| 97 | + # Expected 2 classes -- single column |
| 98 | + # We have to reduce the contribution of the second class with 5 to 1 ratio |
| 99 | + np.array([1, 1, 1, 1, 1, 0]), |
| 100 | + # We reduce the contribution of the first class which has double elements |
| 101 | + np.array([3, 6 / 10]), |
| 102 | + ), |
| 103 | +]) |
| 104 | +def test_lossweightstrategyweighted(target, expected_weights): |
| 105 | + weights = LossWeightStrategyWeighted()(target) |
| 106 | + np.testing.assert_array_equal(weights, expected_weights) |
| 107 | + assert nn.CrossEntropyLoss(weight=torch.Tensor(weights))( |
| 108 | + torch.zeros(target.shape[0], len(weights)).float(), |
| 109 | + torch.from_numpy(target.argmax(1)).long() if len(target.shape) > 1 |
| 110 | + else torch.from_numpy(target).long() |
| 111 | + ) > 0 |
| 112 | + |
| 113 | + |
| 114 | +@pytest.mark.parametrize('target,expected_weights', [ |
| 115 | + ( |
| 116 | + # Expected 2 classes -- multilable format |
| 117 | + np.array([[1, 0], [1, 0], [1, 0], [0, 1]]), |
| 118 | + # We reduce the contribution of the first class which 3 to 1 ratio |
| 119 | + np.array([1 / 3, 3]), |
| 120 | + ), |
| 121 | + ( |
| 122 | + # Expected 2 classes -- (-1, 1) format |
| 123 | + np.array([[1], [1], [1], [0]]), |
| 124 | + # We reduce the contribution of the second class, which has a 3 to 1 ratio |
| 125 | + np.array([1 / 3]), |
| 126 | + ), |
| 127 | + ( |
| 128 | + # Expected 2 classes -- single column |
| 129 | + # We have to reduce the contribution of the second class with 5 to 1 ratio |
| 130 | + np.array([1, 1, 1, 1, 1, 0]), |
| 131 | + # We reduce the contribution of the first class which has double elements |
| 132 | + np.array([0.2]), |
| 133 | + ), |
| 134 | +]) |
| 135 | +def test_lossweightstrategyweightedbinary(target, expected_weights): |
| 136 | + weights = LossWeightStrategyWeightedBinary()(target) |
| 137 | + np.testing.assert_array_equal(weights, expected_weights) |
| 138 | + assert nn.BCEWithLogitsLoss(pos_weight=torch.Tensor(weights))( |
| 139 | + torch.from_numpy(target).float(), |
| 140 | + torch.from_numpy(target).float(), |
| 141 | + ) > 0 |
0 commit comments