Skip to content
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
32 changes: 14 additions & 18 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,21 @@ on:
branches: [develop, release]

jobs:
build:
name: continuous-integration
runs-on: ${{ matrix.os }}
ci:
timeout-minutes: 15
strategy:
matrix:
os: ["ubuntu-latest", "windows-latest"] # Remove MacOS (billing + github.com/ThalesGroup/scio/issues/2)
python-version: ["3.12", "3.13"]
os: ["ubuntu-latest", "windows-latest", "macos-latest"]


runs-on: ${{ matrix.os }}
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Install the latest version of uv and set the python version
- name: Install uv and set python version
uses: astral-sh/setup-uv@v6
with:
version: "0.8.9"
version: "0.8.17"
python-version: ${{ matrix.python-version }}

- name: Run ruff
Expand All @@ -35,8 +33,13 @@ jobs:
run: |
uv -v run mypy

- name: Build & Install
run: |
uv -v build
uv -v pip install dist/scio_pypi-1.0.0rc3-py3-none-any.whl

- name: Build docs (Posix)
if: matrix.os != 'windows-latest' && matrix.os != 'macos-latest' # Temporary (github.com/ThalesGroup/scio/issues/2)
if: matrix.os != 'windows-latest'
env:
SPHINXOPTS: --fail-on-warning
run: |
Expand All @@ -49,13 +52,7 @@ jobs:
run: |
uv -v run cmd /c "docs\\make.bat"

- name: Build & Install
run: |
uv -v build
uv -v pip install dist/scio_pypi-1.0.0rc3-py3-none-any.whl

- name: Run pytest
if: matrix.os != 'macos-latest' # Temporary (github.com/ThalesGroup/scio/issues/2)
id: run-pytest
continue-on-error: true
run: |
Expand All @@ -67,13 +64,13 @@ jobs:
with:
name: pytest-observed-${{ matrix.os }}-py${{ matrix.python-version }}
path: test/expected/*/*.observed.*
retention-days: 7
retention-days: 30

- name: Fail the job if pytest failed
if: ${{ steps.run-pytest.outcome == 'failure' }}
run: exit 1

- name: Upload coverage report to Codecov (Ubuntu, python3.13)
- name: Upload coverage report to Codecov
if: matrix.os == 'ubuntu-latest' && matrix.python-version == '3.13'
uses: codecov/codecov-action@v5
with:
Expand All @@ -82,7 +79,6 @@ jobs:

# TEMPORARILY DISABLED (https://github.com/ThalesGroup/scio/issues/9)
# - name: Run pytest with lowest resolution
# if: matrix.os != 'macos-latest' # Temporary (github.com/ThalesGroup/scio/issues/2)
# id: run-pytest-lowest
# continue-on-error: true
# run: |
Expand Down
4 changes: 2 additions & 2 deletions CONTRIBUTORS.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ Possible contribution values are: `answering questions`, `bug reports`, `code`,
| GitHub username | Contributions | Name (optional) |
|-----------------|---------------|-----------------|
| Sebastienlejeune | infrastructure | Lejeune, Sébastien |
| ego-thales | bug reports, code, documentation, fixes, ideas, maintenance, pr reviews, testing, tutorials | Goudout, Élie |
| eliegoudout | bug reports, documentation, fixes, maintenance | Goudout, Élie |
| ego-thales | bug reports, code, dissemination, documentation, fixes, ideas, maintenance, pr reviews, testing, tutorials | Goudout, Élie |
| eliegoudout | bug reports, dissemination, documentation, fixes, maintenance | Goudout, Élie |
| Lap0u | fixes | Beaurain, Clément |
<!-- TABLE END -->
2 changes: 1 addition & 1 deletion scio/scores/classification/deepmahalanobis.py
Original file line number Diff line number Diff line change
Expand Up @@ -300,7 +300,7 @@ def compute_precision(residues: Tensor) -> Tensor:
if not precision.isfinite().all():
raise torch.linalg.LinAlgError # pragma: no cover # noqa: TRY301
except torch.linalg.LinAlgError:
data_dim = residues.size(1)
data_dim = residues.shape[1]
return torch.full((data_dim, data_dim), torch.nan).to(residues)

return precision
2 changes: 1 addition & 1 deletion scio/scores/classification/dknn.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ def _check_params(self, n_calib: int) -> None:
def calibrate(self, calib_data: Tensor, calib_labels: Tensor) -> None:
"""Calibrate the scoring algorithm with In-Distribution data."""
self.calib_labels = calib_labels
n_samples, n_classes = self.rnet(calib_data).shape # Records activations
n_samples = len(self.rnet(calib_data)) # Records activations
all_activations = self.activations()
self.indexes = make_indexes(all_activations, metric=self.index_metric)

Expand Down
4 changes: 2 additions & 2 deletions scio/scores/classification/gram.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ def calibrate(self, calib_data: Tensor, calib_labels_true: Tensor) -> None:
def get_conformity(self, inputs: Tensor) -> tuple[Tensor, Tensor]:
"""Compute output and associated conformity at inference."""
out = self.rnet(inputs) # Records activations
n_samples, n_classes = out.shape
n_classes = out.shape[1]

total_deviations = torch.zeros_like(out)
for activations, low_high, expected_deviation in zip(
Expand Down Expand Up @@ -184,7 +184,7 @@ def layer_stats(self, activations: Tensor) -> Tensor:
)
raise ValueError(msg)

n_channels = activations.size(1) if ndim == 4 else 1 # noqa: PLR2004 (magic value 4)
n_channels = activations.shape[1] if ndim == 4 else 1 # noqa: PLR2004 (magic value 4)
per_channel = activations.shape[ndim // 2 :].numel()
activations_3d = activations.reshape(len(activations), n_channels, per_channel)

Expand Down
2 changes: 1 addition & 1 deletion scio/scores/classification/isomax.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ def calibrate(self, calib_data: Tensor, calib_labels: Tensor) -> None:
with torch.no_grad():
logits = self.rnet(calib_data, dont_record=True)

n_classes = logits.size(1)
n_classes = logits.shape[1]
# Init at 0 like [IsoMax]
self.prototypes = torch.zeros(
n_classes,
Expand Down
6 changes: 3 additions & 3 deletions scio/scores/classification/jtla.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ def calibrate(self, calib_data: Tensor, calib_labels: Tensor) -> None:
all_activations = self.activations()
self.calib_labels_true = calib_labels
self.calib_labels_pred = out.argmax(1) if self.pred_conditional else None
self.prepare_tests(all_activations, out.size(1))
self.prepare_tests(all_activations, out.shape[1])
# Next are tensors of shape (n_classes, n_calib_samples, n_layers) (or None)
self.calib_tests_true, self.calib_tests_pred = self.run_tests(all_activations)

Expand Down Expand Up @@ -410,7 +410,7 @@ def aggregate_layers(

# Special aK-LPE method
if self.layer_aggregation_method == "lpe":
n_calib = self.lpe_true_calib.size(1)
n_calib = self.lpe_true_calib.shape[1]
similarity_search = self.index_metric == "ip"

normed_true = self.lpe_normalizer(tests_true)
Expand Down Expand Up @@ -510,7 +510,7 @@ def slicer(n: int, mask: Tensor) -> Tensor:
if only_consecutive:
return mask.unfold(1, n, 1)

range_n_layers = torch.arange(mask.size(1)).to(device=device)
range_n_layers = torch.arange(mask.shape[1]).to(device=device)
combs = torch.combinations(range_n_layers, n)
return mask[:, combs]

Expand Down
2 changes: 1 addition & 1 deletion scio/scores/classification/odds.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ def calibrate(self, calib_data: Tensor, calib_labels: Tensor) -> None:
self.rng = torch.Generator(calib_data.device).manual_seed(self.rng_seed)

logits = self.rnet(calib_data, dont_record=True)
n_samples, n_classes = logits.shape
n_classes = logits.shape[1]
self.g_stats_avg = torch.full(
(n_classes,) * 2,
torch.nan,
Expand Down
6 changes: 3 additions & 3 deletions test/scio/eval/classification/roc/test_roc.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,13 @@ def test_roc_trivial():
@parametrize_bool("label")
def test_roc_requires_positive_and_negative(label):
"""Test that both positive and negative samples are required."""
with pytest.raises(AssertionError, match="^$"):
with pytest.raises(AssertionError, match=r"^$"):
ROC([label], [0])


def test_roc_rejects_nan():
"""Test that ``nan`` are forbidden."""
with pytest.raises(AssertionError, match="^$"):
with pytest.raises(AssertionError, match=r"^$"):
ROC([T, F], [0, np.nan])


Expand All @@ -34,7 +34,7 @@ def test_roc_allows_only_posinf(sign):
if sign > 0:
ROC([T, F], [0, I])
else:
with pytest.raises(AssertionError, match="^$"):
with pytest.raises(AssertionError, match=r"^$"):
ROC([T, F], [0, -I])


Expand Down
2 changes: 1 addition & 1 deletion test/scio/scores/classification/base/test_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ def test_raises_on_unexpected_mode(monkeypatch_enum_new_member, score, test_data

def test_accepts_unique_conformity(score, class_aggregation, test_data):
"""Check that the score can output one score only per sample."""
out, conformity = score(test_data)
conformity = score(test_data)[1]
same_conformity_over_classes = (conformity == conformity[:, [0]]).all()

assert conformity.shape == (len(test_data), N_CLASSES)
Expand Down
Loading