Skip to content

Commit 4a0397d

Browse files
committed
testing testing
1 parent 51ad92f commit 4a0397d

File tree

9 files changed

+138
-3
lines changed

9 files changed

+138
-3
lines changed

docs/source/data_functional.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ The corruption functions are modelled after
55
D. Hendrycks and T. Dietterich: *Benchmarking Neural Network Robustness to Common Corruptions and Perturbations* (ICLR 2019)
66
and the code provided by their authors in https://github.com/hendrycks/robustness/ but our implementation is expected to differ in details from theirs.
77

8+
It is important to use 0..1-values image tensors as inputs.
9+
This means that you need to do the normalization after applying these.
10+
In the traditional default PyTorch/TorchVision pipeline, images are normalized in the dataset, which may be too early. In our examples, we like to move the normalization to the beginning of the model itself or in a separate augmentation model.
11+
812

913
.. automodule:: torchdrift.data.functional
1014
:imported-members:

test/README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
I run the following from the torchdrift repository:
2+
3+
```python
4+
PYTHONPATH=. pytest-3 --cov-report term --cov=torchdrift test/ -v
5+
```

test/conftest.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
2+
import os
3+
os.environ['NUMBA_DISABLE_JIT'] = '1'

test/test_corruption_functions.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import pytest
2+
import torchdrift
3+
import torch
4+
import scipy.ndimage
5+
6+
# these tests could be made more specific, eventually
7+
8+
def test_gaussian_noise():
9+
a = torch.rand(4, 3, 32, 32)
10+
b = torch.rand(1, 3, 200, 200)
11+
a1 = torchdrift.data.functional.gaussian_noise(a)
12+
b1 = torchdrift.data.functional.gaussian_noise(b)
13+
assert (a1 == a1.clamp(min=0, max=1)).all()
14+
assert (a-a1).std() < (b-b1).std()
15+
16+
def test_shot_noise():
17+
a = torch.rand(4, 3, 100, 100)
18+
a1 = torchdrift.data.functional.shot_noise(a, severity=4)
19+
a2 = torchdrift.data.functional.gaussian_noise(a, severity=4)
20+
assert (a1-a).abs().max() < (a2-a).abs().max()
21+
22+
def test_impulse_noise():
23+
a = torch.rand(4, 3, 100, 100)/2+0.25
24+
a1 = torchdrift.data.functional.impulse_noise(a, severity=4)
25+
assert a1.min().abs() + (1 - a1.max()).abs() < 1e-6
26+
27+
def test_speckle_noise():
28+
a = torch.rand(4, 3, 100, 100)/2+0.25
29+
a1 = torchdrift.data.functional.speckle_noise(a, severity=4)
30+
assert a1.min().abs() + (1 - a1.max()).abs() < 1e-6
31+
32+
def test_gaussian_blur():
33+
a = torch.rand(1, 3, 300, 300)
34+
a1 = torchdrift.data.functional.gaussian_blur(a, severity=5)
35+
a2 = scipy.ndimage.gaussian_filter(a, [0, 0, 6, 6])
36+
assert ((a1-a2)[:,:, 32:-32, 32:-32]).max().abs() < 1e-2
37+
38+
39+
if __name__ == "__main__":
40+
pytest.main([__file__])

test/test_detectors.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import pytest
2+
import torchdrift
3+
import torch
4+
import sklearn.decomposition
5+
6+
def test_detector():
7+
x = torch.randn(5, 5)
8+
d = torchdrift.detectors.Detector()
9+
d.fit(x)
10+
with pytest.raises(NotImplementedError):
11+
d(x)
12+
13+
def _test_detector_class(cls):
14+
torch.manual_seed(1234)
15+
d = cls()
16+
d2 = cls(return_p_value=True)
17+
x = torch.randn(5, 5)
18+
y = torch.randn(5, 5) + 1.0
19+
d.fit(x)
20+
d2.fit(x)
21+
assert (d(x).item() < d(y).item())
22+
assert d.compute_p_value(x) > 0.80
23+
assert d.compute_p_value(y) < 0.05
24+
assert d.compute_p_value(y) == d2(y)
25+
26+
def test_ksdetector():
27+
_test_detector_class(torchdrift.detectors.KSDriftDetector)
28+
29+
def test_mmddetector():
30+
_test_detector_class(torchdrift.detectors.KernelMMDDriftDetector)
31+
32+
if __name__ == "__main__":
33+
pytest.main([__file__])

test/test_utils.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import pytest
2+
import torchdrift
3+
import torch
4+
import torch.utils.data
5+
6+
class TensorDataModule:
7+
def __init__(self, *args):
8+
self.ds = torch.utils.data.TensorDataset(*args)
9+
10+
def default_dataloader(self, batch_size=None, num_samples=None, shuffle=True):
11+
dataset = self.ds
12+
if batch_size is None:
13+
batch_size = self.val_batch_size
14+
replacement = num_samples is not None
15+
if shuffle:
16+
sampler = torch.utils.data.RandomSampler(dataset, replacement=replacement, num_samples=num_samples)
17+
else:
18+
sampler = None
19+
return torch.utils.data.DataLoader(dataset, batch_size=batch_size, sampler=sampler)
20+
21+
def test_fit():
22+
dm_ref = TensorDataModule(torch.randn(500, 5))
23+
d = torchdrift.detectors.KernelMMDDriftDetector()
24+
torchdrift.utils.fit(
25+
dm_ref.default_dataloader(batch_size=10), torch.nn.Identity(),
26+
[torch.nn.Identity(), d],
27+
num_batches=3,
28+
device='cpu')
29+
30+
def test_experiment():
31+
torch.manual_seed(1234)
32+
d = torchdrift.detectors.KernelMMDDriftDetector()
33+
dm_ref = TensorDataModule(torch.randn(500, 5))
34+
dm_x = TensorDataModule(torch.randn(500, 5))
35+
dm_y = TensorDataModule(torch.randn(500, 5) + 1)
36+
experiment = torchdrift.utils.DriftDetectionExperiment(
37+
d, torch.nn.Linear(5, 5),
38+
)
39+
experiment.post_training(torch.utils.data.DataLoader(dm_ref.ds, batch_size=100))
40+
experiment.evaluate(dm_x, dm_y)
41+
experiment = torchdrift.utils.DriftDetectionExperiment(
42+
d, torch.nn.Linear(5, 5), ood_ratio=0.9, sample_size=10
43+
)
44+
experiment.post_training(torch.utils.data.DataLoader(dm_ref.ds, batch_size=100))
45+
experiment.evaluate(dm_x, dm_y)
46+
47+
if __name__ == "__main__":
48+
pytest.main([__file__])

torchdrift/data/functional/corruption_functions.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ def interpolate_severity(img, cifar, imagenet, severity):
6262
def gaussian_noise(x: Tensor, severity: int = 1) -> Tensor:
6363
"""Applys gaussian noise."""
6464
cifar_std = [0.04, 0.06, 0.08, 0.09, 0.10]
65-
imagent_std = [0.08, 0.12, 0.18, 0.26, 0.38]
65+
imagenet_std = [0.08, 0.12, 0.18, 0.26, 0.38]
6666
std = interpolate_severity(x, cifar_std, imagenet_std, severity)
6767
return (x + torch.randn_like(x) * std).clamp(min=0.0, max=1.0)
6868

torchdrift/detectors/ks.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
try:
99
import numba
1010
njit = numba.jit(nopython=True, fastmath=True)
11-
except ImportError:
11+
except ImportError: # pragma: no cover
1212
njit = lambda x: x
1313

1414

torchdrift/utils/fit.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,9 @@ def fit(
3636
nb = len(dl)
3737
if num_batches is not None:
3838
nb = min(nb, num_batches)
39-
for i, (b, _) in tqdm.tqdm(zip(range(nb), dl), total=nb):
39+
for i, b in tqdm.tqdm(zip(range(nb), dl), total=nb):
40+
if not isinstance(b, torch.Tensor):
41+
b = b[0]
4042
with torch.no_grad():
4143
all_outputs.append(feature_extractor(b.to(device)))
4244
all_outputs = torch.cat(all_outputs, dim=0)

0 commit comments

Comments
 (0)