Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix sonarcloud analysis issues #141

Merged
merged 4 commits into from
Jan 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
FROM python:3.8 AS xaitk_base

# install poetry and configure to install to pip environment
RUN pip install poetry \
&& poetry config virtualenvs.create false
ENV PATH=/root/.local/bin:${PATH}
RUN (curl -sSL 'https://install.python-poetry.org' | python3 -) \
&& poetry config virtualenvs.create false

WORKDIR /xaitk

Expand All @@ -11,5 +12,9 @@ COPY poetry.lock pyproject.toml /xaitk/
RUN poetry install --no-root

# install package
COPY . /xaitk/
COPY docs /xaitk/docs/
COPY scripts /xaitk/scripts/
COPY tests /xaitk/tests/
COPY xaitk_saliency /xaitk/xaitk_saliency
COPY .flake8 .mypy.ini CONTRIBUTING.md LICENSE.txt README.md /xaitk/
RUN poetry install
11 changes: 11 additions & 0 deletions docs/release_notes/pending_release.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,20 @@ Pending Release Notes
Updates / New Features
----------------------

Docker

* Update Dockerfile install of poetry, and make separate & specific directory
copies.

Utils

* Updated logging format of occlusion masking benchmark utility.

Fixes
-----

Tests

* Update various floating point equality comparisons to not use exact match.

* Fix random number usage from numpy to use `np.random.default_rng`.
7 changes: 5 additions & 2 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 8 additions & 8 deletions tests/impls/gen_classifier_conf_sal/test_occlusion_scoring.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,11 +58,11 @@ def test_1class_scores(self) -> None:
Test basic scoring with a single class for broadcasting sanity check.
"""
impl = OcclusionScoring()
np.random.seed(2)
rng = np.random.default_rng(2)
# Three Perturbation masks of height and width 10px for 1 class
image_confs_1_class_ = np.random.rand(1)
pertb_confs_1_class_ = np.random.rand(3, 1)
mask_confs_1_class_ = np.random.randint(low=0, high=2, size=(3, 10, 10), dtype='int')
image_confs_1_class_ = rng.standard_normal((1))
pertb_confs_1_class_ = rng.standard_normal((3, 1))
mask_confs_1_class_ = rng.integers(low=0, high=2, size=(3, 10, 10), dtype='int')

sal = impl.generate(image_confs_1_class_, pertb_confs_1_class_, mask_confs_1_class_)
assert sal.shape == (1, 10, 10)
Expand All @@ -85,10 +85,10 @@ def test_20class_scores(self) -> None:
Test scoring for 20 classes.
"""
impl = OcclusionScoring()
np.random.seed(2)
rng = np.random.default_rng(2)
# Three Perturbation masks of height and width 10px for 20 classes
image_confs_1_class_ = np.random.rand(20)
pertb_confs_1_class_ = np.random.rand(3, 20)
mask_confs_1_class_ = np.random.randint(low=0, high=2, size=(3, 10, 10), dtype='int')
image_confs_1_class_ = rng.standard_normal((20))
pertb_confs_1_class_ = rng.standard_normal((3, 20))
mask_confs_1_class_ = rng.integers(low=0, high=2, size=(3, 10, 10), dtype='int')
sal = impl.generate(image_confs_1_class_, pertb_confs_1_class_, mask_confs_1_class_)
assert sal.shape == (20, 10, 10)
40 changes: 20 additions & 20 deletions tests/impls/gen_descriptor_sim_sal/test_similarity_scoring.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,11 @@ def test_generate_mismatch_ref_descriptors(self) -> None:
Test that we appropriately error when the input reference descriptors
are not the same dimensionality.
"""
np.random.seed(0)
test_ref_descr = np.random.rand(16)
test_query_descrs = np.random.rand(5, 15) # Different than above
test_pert_descrs = np.random.rand(32, 16)
test_masks = np.random.rand(32, 16, 16)
rng = np.random.default_rng(seed=0)
test_ref_descr = rng.standard_normal(16)
test_query_descrs = rng.standard_normal((5, 15)) # Different than above
test_pert_descrs = rng.standard_normal((32, 16))
test_masks = rng.standard_normal((32, 16, 16))

impl = SimilarityScoring()

Expand All @@ -76,11 +76,11 @@ def test_generate_mismatched_perturbed(self) -> None:
Test that we appropriately error when the input perturbation
descriptors and mask arrays are not equal in first-dimension length.
"""
np.random.seed(0)
test_ref_descr = np.random.rand(16)
test_query_descrs = np.random.rand(1, 16)
test_pert_descrs = np.random.rand(32, 16)
test_masks = np.random.rand(30, 16, 16) # Different than above
rng = np.random.default_rng(seed=0)
test_ref_descr = rng.standard_normal(16)
test_query_descrs = rng.standard_normal((1, 16))
test_pert_descrs = rng.standard_normal((32, 16))
test_masks = rng.standard_normal((30, 16, 16)) # Different than above

impl = SimilarityScoring()

Expand All @@ -96,11 +96,11 @@ def test_1_featurevec(self) -> None:
Test basic scoring with a single feature for broadcasting sanity check.
"""
impl = SimilarityScoring()
np.random.seed(2)
ref_feat = np.random.rand(2048)
query_feats = np.random.rand(2, 2048)
pertb_feats = np.random.rand(3, 2048)
pertb_mask = np.random.randint(low=0, high=2, size=(3, 10, 10), dtype='int')
rng = np.random.default_rng(2)
ref_feat = rng.standard_normal(2048)
query_feats = rng.standard_normal((2, 2048))
pertb_feats = rng.standard_normal((3, 2048))
pertb_mask = rng.integers(low=0, high=2, size=(3, 10, 10), dtype='int')
sal = impl.generate(ref_feat, query_feats, pertb_feats, pertb_mask)
assert sal.shape == (2, 10, 10)

Expand All @@ -123,10 +123,10 @@ def test_512_featdim(self) -> None:
Test scoring for features of 512 dims.
"""
impl = SimilarityScoring()
np.random.seed(2)
ref_feat = np.random.rand(512)
query_feats = np.random.rand(1, 512)
pertb_feats = np.random.rand(15, 512)
pertb_mask = np.random.randint(low=0, high=2, size=(15, 10, 10), dtype='int')
rng = np.random.default_rng(2)
ref_feat = rng.standard_normal(512)
query_feats = rng.standard_normal((1, 512))
pertb_feats = rng.standard_normal((15, 512))
pertb_mask = rng.integers(low=0, high=2, size=(15, 10, 10), dtype='int')
sal = impl.generate(ref_feat, query_feats, pertb_feats, pertb_mask)
assert sal.shape == (1, 10, 10)
21 changes: 12 additions & 9 deletions tests/impls/gen_detector_prop_sal/test_drise_scoring.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,10 @@ def test_shape_sanity(self) -> None:
Test basic scoring with a single feature for broadcasting sanity check.
"""
impl = DRISEScoring()
ref_dets = np.random.rand(2, 7)
pert_dets = np.random.rand(10, 3, 7)
pert_mask = np.random.randint(
rng = np.random.default_rng(seed=0)
ref_dets = rng.standard_normal((2, 7))
pert_dets = rng.standard_normal((10, 3, 7))
pert_mask = rng.integers(
low=0, high=2, size=(10, 15, 25), dtype='int')
sal = impl.generate(ref_dets, pert_dets, pert_mask)
assert sal.shape == (2, 15, 25)
Expand All @@ -52,9 +53,10 @@ def test_mask_detections_size_mismatch(self) -> None:
Test size mismatch between perturbed detections and masks.
"""
impl = DRISEScoring()
ref_dets = np.random.rand(2, 7)
pert_dets = np.random.rand(9, 3, 7) # ONE LESS than pert mask mat.
pert_mask = np.random.randint(
rng = np.random.default_rng(seed=0)
ref_dets = rng.standard_normal((2, 7))
pert_dets = rng.standard_normal((9, 3, 7)) # ONE LESS than pert mask mat.
pert_mask = rng.integers(
low=0, high=2, size=(10, 15, 25), dtype='int')
with pytest.raises(
ValueError,
Expand All @@ -68,9 +70,10 @@ def test_detections_classes_mismatch(self) -> None:
Test mismatch in number of classes between perturbed and reference detections.
"""
impl = DRISEScoring()
ref_dets = np.random.rand(2, 8) # ONE MORE than pert dets mat.
pert_dets = np.random.rand(10, 3, 7)
pert_mask = np.random.randint(
rng = np.random.default_rng(seed=0)
ref_dets = rng.standard_normal((2, 8)) # ONE MORE than pert dets mat.
pert_dets = rng.standard_normal((10, 3, 7))
pert_mask = rng.integers(
low=0, high=2, size=(10, 15, 25), dtype='int')
with pytest.raises(
ValueError,
Expand Down
8 changes: 4 additions & 4 deletions tests/impls/gen_image_classifier_blackbox_sal/test_rise.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,10 @@ def test_configuration(self) -> None:
assert isinstance(inst_g, RISEScoring)
assert inst_p.n == 444
assert inst_p.s == 33
assert inst_p.p1 == .22
assert np.allclose(inst_p.p1, .22)
assert inst_p.seed == 42
assert inst_p.threads == 99
assert inst_g.p1 == .22
assert np.allclose(inst_g.p1, .22)
assert inst_i.get_config()['debiased'] is True

def test_configuration_not_debiased(self) -> None:
Expand All @@ -58,8 +58,8 @@ def test_configuration_not_debiased(self) -> None:
inst_g = inst_i._po._generator
assert isinstance(inst_p, RISEGrid)
assert isinstance(inst_g, RISEScoring)
assert inst_p.p1 == .22
assert inst_g.p1 == 0.0
assert np.allclose(inst_p.p1, .22)
assert np.allclose(inst_g.p1, 0.0)
assert inst_i.get_config()['debiased'] is False

def test_generation_rgb(self) -> None:
Expand Down
2 changes: 1 addition & 1 deletion tests/impls/gen_object_detector_blackbox_sal/test_drise.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ def test_configuration(self) -> None:
assert isinstance(inst_g, DRISEScoring)
assert inst_p.n == 123
assert inst_p.s == 8
assert inst_p.p1 == 0.73
assert np.allclose(inst_p.p1, .73)
assert inst_p.seed == 98
assert inst_p.threads == 5
assert inst_g.get_config() == {}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ def test_configuration(self) -> None:
assert isinstance(inst_g, DRISEScoring)
assert inst_p.n == 55
assert inst_p.s == (15, 8)
assert inst_p.p1 == 0.34
assert np.allclose(inst_p.p1, 0.34)
assert inst_p.seed == 7
assert inst_p.threads == 2
assert inst_g.get_config() == {}
Expand Down
32 changes: 17 additions & 15 deletions tests/impls/perturb_image/test_random_grid.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ def test_init_valued(self) -> None:

assert impl.n == test_n
assert impl.s == test_s
assert impl.p1 == test_p1
assert np.allclose(impl.p1, test_p1)
assert impl.seed == test_seed
assert impl.threads == test_threads

Expand All @@ -41,7 +41,7 @@ def test_standard_config(self) -> None:
for inst in configuration_test_helper(impl):
assert inst.n == test_n
assert inst.s == test_s
assert inst.p1 == test_p1
assert np.allclose(impl.p1, test_p1)
assert inst.seed == test_seed
assert inst.threads == test_threads

Expand All @@ -53,7 +53,8 @@ def test_if_random(self) -> None:
impl1 = RandomGrid(n=3, s=(5, 4), p1=0.5)
impl2 = RandomGrid(n=3, s=(5, 4), p1=0.5)

img = np.random.randint(0, 255, size=(20, 20), dtype=np.uint8)
rng = np.random.default_rng(seed=0)
img = rng.integers(0, 255, size=(20, 20), dtype=np.uint8)

masks1 = impl1(img)
masks2 = impl2(img)
Expand All @@ -68,7 +69,8 @@ def test_seed(self) -> None:
impl1 = RandomGrid(n=3, s=(2, 1), p1=0.6, seed=5)
impl2 = RandomGrid(n=3, s=(2, 1), p1=0.6, seed=5)

img = np.random.randint(0, 255, size=(10, 10), dtype=np.uint8)
rng = np.random.default_rng(seed=0)
img = rng.integers(0, 255, size=(10, 10), dtype=np.uint8)

masks1 = impl1(img)
masks2 = impl2(img)
Expand All @@ -80,8 +82,8 @@ def test_call_idempotency(self) -> None:
Test that perturbation generation is idempotent, at least when seeded
and single-threaded.
"""

img = np.random.randint(0, 255, size=(10, 10), dtype=np.uint8)
rng = np.random.default_rng(seed=0)
img = rng.integers(0, 255, size=(10, 10), dtype=np.uint8)

impl = RandomGrid(n=2, s=(1, 2), p1=0.4, seed=1, threads=0)

Expand All @@ -95,8 +97,8 @@ def test_perturb_1_channel(self) -> None:
Test mask generation on a one-channel image of a known size. Number
of channels should not affect output masks.
"""

img = np.random.randint(0, 255, size=(4, 6), dtype=np.uint8)
rng = np.random.default_rng(seed=0)
img = rng.integers(0, 255, size=(4, 6), dtype=np.uint8)

impl = RandomGrid(n=2, s=(2, 2), p1=0.5, seed=123, threads=0)

Expand All @@ -112,8 +114,8 @@ def test_perturb_3_channel(self) -> None:
Test mask generation on a three-channel image of a known size. Number
of channels should not affect output masks.
"""

img = np.random.randint(0, 255, size=(4, 6, 3), dtype=np.uint8)
rng = np.random.default_rng(seed=0)
img = rng.integers(0, 255, size=(4, 6, 3), dtype=np.uint8)

impl = RandomGrid(n=2, s=(2, 2), p1=0.5, seed=123, threads=0)

Expand All @@ -129,11 +131,11 @@ def test_multiple_image_size(self) -> None:
Test that a single implementation can be used for images of varying
sizes.
"""

impl = RandomGrid(n=5, s=(3, 4), p1=0.2, seed=42, threads=0)

img_small = np.random.randint(0, 255, size=(5, 7), dtype=np.uint8)
img_large = np.random.randint(0, 255, size=(55, 77), dtype=np.uint8)
rng = np.random.default_rng(seed=0)
img_small = rng.integers(0, 255, size=(5, 7), dtype=np.uint8)
img_large = rng.integers(0, 255, size=(55, 77), dtype=np.uint8)

masks_small = impl(img_small)
masks_large = impl(img_large)
Expand All @@ -148,8 +150,8 @@ def test_threading(self) -> None:
"""
Test that using threading does not affect results.
"""

img = np.random.randint(0, 255, size=(4, 6), dtype=np.uint8)
rng = np.random.default_rng(seed=0)
img = rng.integers(0, 255, size=(4, 6), dtype=np.uint8)

impl = RandomGrid(n=2, s=(2, 2), p1=0.5, seed=123, threads=1)

Expand Down
Loading
Loading