Skip to content

Commit

Permalink
Merge branch 'dev_1.18.0' into dev_1.18.0_scaling
Browse files Browse the repository at this point in the history
  • Loading branch information
beat-buesser authored Apr 3, 2024
2 parents d5a2ffb + 3597228 commit 290519d
Show file tree
Hide file tree
Showing 77 changed files with 2,489 additions and 1,915 deletions.
10 changes: 5 additions & 5 deletions .github/actions/deepspeech-v3/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
pod# Get base from a pytorch image
FROM pytorch/pytorch:2.1.1-cuda12.1-cudnn8-runtime
# Get base from a pytorch image
FROM python:3.10.13-slim-bullseye

# Set to install things in non-interactive mode
ENV DEBIAN_FRONTEND noninteractive
Expand All @@ -26,10 +26,10 @@ RUN apt-get update \
RUN pip install --ignore-installed PyYAML torch==2.1.1 tensorflow==2.14.1 torchaudio==2.1.1 pytorch-lightning==2.1.2 scikit-learn==1.3.2
RUN pip install --no-build-isolation fairscale==0.4.13

RUN git clone https://github.com/SeanNaren/deepspeech.pytorch.git
RUN cd deepspeech.pytorch && sed -i '/^sklearn/d' requirements.txt && pip install -r requirements.txt && pip install -e .
RUN git clone https://github.com/SeanNaren/deepspeech.pytorch.git && cd deepspeech.pytorch && sed -i '/^sklearn/d' requirements.txt && pip install -r requirements.txt && pip install -e .

RUN pip install numba==0.56.4 pytest-cov==4.1.0 pydub==0.25.1
RUN pip list

RUN mkdir -p /root/.art/data && cd /root/.art/data && curl -LJO "https://github.com/SeanNaren/deepspeech.pytorch/releases/download/V3.0/librispeech_pretrained_v3.ckpt"

CMD ["/bin/bash"]
3 changes: 2 additions & 1 deletion .github/workflows/ci-lingvo.yml
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ jobs:
sudo apt-get update
sudo apt-get -y -q install ffmpeg libavcodec-extra
python -m pip install --upgrade pip setuptools wheel
pip install -q -r <(sed '/^scipy/d;/^matplotlib/d;/^pandas/d;/^statsmodels/d;/^numba/d;/^jax/d;/^h5py/d;/^Pillow/d;/^pytest/d;/^pytest-mock/d;/^torch/d;/^torchaudio/d;/^torchvision/d;/^xgboost/d;/^requests/d;/^tensorflow/d;/^keras/d;/^kornia/d;/^librosa/d;/^tqdm/d;/^timm/d;/^catboost/d' requirements_test.txt)
pip install -q -r <(sed '/^scipy/d;/^matplotlib/d;/^pandas/d;/^statsmodels/d;/^numba/d;/^jax/d;/^h5py/d;/^Pillow/d;/^pytest/d;/^pytest-mock/d;/^torch/d;/^torchaudio/d;/^torchvision/d;/^xgboost/d;/^requests/d;/^tensorflow/d;/^keras/d;/^kornia/d;/^librosa/d;/^tqdm/d;/^timm/d;/^catboost/d;/^scikit-learn/d' requirements_test.txt)
pip install scipy==1.5.4
pip install matplotlib==3.3.4
pip install pandas==1.1.5
Expand All @@ -75,6 +75,7 @@ jobs:
pip install librosa==0.9.2
pip install tqdm==4.64.1
pip install catboost==1.1.1
pip install scikit-learn==0.24.2
pip list
- name: Run ${{ matrix.name }} Tests
run: pytest --cov-report=xml --cov=art --cov-append -q -vv tests/estimators/speech_recognition/test_tensorflow_lingvo.py --framework=${{ matrix.framework }} --durations=0
Expand Down
12 changes: 4 additions & 8 deletions .github/workflows/ci-scikit-learn.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,18 +28,14 @@ jobs:
fail-fast: false
matrix:
include:
- name: scikit-learn 1.1.3 (Python 3.9)
framework: scikitlearn
scikit-learn: 1.1.3
python: 3.9
- name: scikit-learn 1.2.2 (Python 3.10)
framework: scikitlearn
scikit-learn: 1.2.2
python: '3.10'
- name: scikit-learn 1.3.2 (Python 3.10)
framework: scikitlearn
scikit-learn: 1.3.2
python: '3.10'
- name: scikit-learn 1.4.0 (Python 3.10)
framework: scikitlearn
scikit-learn: 1.4.0
python: '3.10'

name: ${{ matrix.name }}
steps:
Expand Down
3 changes: 2 additions & 1 deletion .github/workflows/ci-tensorflow-v1.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ jobs:
sudo apt-get update
sudo apt-get -y -q install ffmpeg libavcodec-extra
python -m pip install --upgrade pip setuptools wheel
pip install -q -r <(sed '/^pandas/d;/^scipy/d;/^matplotlib/d;/^xgboost/d;/^tensorflow/d;/^keras/d;/^jax/d;/^torch/d;/^Pillow/d;/^h5py/d' requirements_test.txt)
pip install -q -r <(sed '/^pandas/d;/^scipy/d;/^matplotlib/d;/^xgboost/d;/^tensorflow/d;/^keras/d;/^jax/d;/^torch/d;/^Pillow/d;/^h5py/d;/^scikit-learn/d' requirements_test.txt)
pip install pandas==1.3.5
pip install scipy==1.7.2
pip install matplotlib==3.5.3
Expand All @@ -62,6 +62,7 @@ jobs:
pip install torchvision==0.14.1+cpu
pip install Pillow==9.5.0
pip install h5py==3.8.0
pip install scikit-learn==1.0.2
pip list
- name: Run Tests
run: ./run_tests.sh ${{ matrix.framework }}
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/dockerhub.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,11 @@ jobs:

- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@9dc751fe249ad99385a2583ee0d084c400eee04e
uses: docker/metadata-action@dbef88086f6cef02e264edb7dbf63250c17cef6c
with:
images: adversarialrobustnesstoolbox/releases
tags: |
type=raw,value={{branch}}-1.17.0-{{sha}}
type=raw,value={{branch}}-1.17.1-{{sha}}
type=semver,pattern={{version}}
- name: Build and push Docker image
Expand Down
2 changes: 1 addition & 1 deletion art/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from art import preprocessing

# Semantic Version
__version__ = "1.17.0"
__version__ = "1.17.1"

# pylint: disable=C0103

Expand Down
162 changes: 37 additions & 125 deletions art/estimators/certification/object_seeker/object_seeker.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@
from sklearn.cluster import DBSCAN
from tqdm.auto import tqdm

from art.utils import intersection_over_area, non_maximum_suppression
from art.utils import intersection_over_area

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -94,68 +94,16 @@ def __init__(
self.epsilon = epsilon
self.verbose = verbose

@property
@abc.abstractmethod
def channels_first(self) -> bool:
def _image_dimensions(self) -> Tuple[int, int]:
"""
:return: Boolean to indicate index of the color channels in the sample `x`.
"""
pass

@property
@abc.abstractmethod
def input_shape(self) -> Tuple[int, ...]:
"""
:return: Shape of one input sample.
"""
pass
Get the height and width of a sample input image.
@abc.abstractmethod
def _predict_classifier(self, x: np.ndarray, batch_size: int = 128, **kwargs) -> List[Dict[str, np.ndarray]]:
"""
Perform prediction for a batch of inputs.
:param x: Samples of shape NCHW or NHWC.
:param batch_size: Batch size.
:return: Predictions of format `List[Dict[str, np.ndarray]]`, one for each input image. The fields of the Dict
are as follows:
- boxes [N, 4]: the boxes in [x1, y1, x2, y2] format, with 0 <= x1 < x2 <= W and 0 <= y1 < y2 <= H.
- labels [N]: the labels for each image
- scores [N]: the scores or each prediction.
:return: Tuple containing the height and width of a sample input image.
"""
raise NotImplementedError

def predict(self, x: np.ndarray, batch_size: int = 128, **kwargs) -> List[Dict[str, np.ndarray]]:
"""
Perform prediction for a batch of inputs.
:param x: Samples of shape NCHW or NHWC.
:param batch_size: Batch size.
:return: Predictions of format `List[Dict[str, np.ndarray]]`, one for each input image. The fields of the Dict
are as follows:
- boxes [N, 4]: the boxes in [x1, y1, x2, y2] format, with 0 <= x1 < x2 <= W and 0 <= y1 < y2 <= H.
- labels [N]: the labels for each image
- scores [N]: the scores or each prediction.
"""
predictions = []

for x_i in tqdm(x, desc="ObjectSeeker", disable=not self.verbose):
base_preds, masked_preds = self._masked_predictions(x_i, batch_size=batch_size, **kwargs)
pruned_preds = self._prune_boxes(masked_preds, base_preds)
unionized_preds = self._unionize_clusters(pruned_preds)

preds = {
"boxes": np.concatenate([base_preds["boxes"], unionized_preds["boxes"]]),
"labels": np.concatenate([base_preds["labels"], unionized_preds["labels"]]),
"scores": np.concatenate([base_preds["scores"], unionized_preds["scores"]]),
}

predictions.append(preds)

return predictions

@abc.abstractmethod
def _masked_predictions(
self, x_i: np.ndarray, batch_size: int = 128, **kwargs
) -> Tuple[Dict[str, np.ndarray], Dict[str, np.ndarray]]:
Expand All @@ -167,70 +115,7 @@ def _masked_predictions(
:batch_size: Batch size.
:return: Predictions for the base unmasked image and merged predictions for the masked image.
"""
x_mask = np.repeat(x_i[np.newaxis], self.num_lines * 4 + 1, axis=0)

if self.channels_first:
height = self.input_shape[1]
width = self.input_shape[2]
else:
height = self.input_shape[0]
width = self.input_shape[1]
x_mask = np.transpose(x_mask, (0, 3, 1, 2))

idx = 1

# Left masks
for k in range(1, self.num_lines + 1):
boundary = int(width / (self.num_lines + 1) * k)
x_mask[idx, :, :, :boundary] = 0
idx += 1

# Right masks
for k in range(1, self.num_lines + 1):
boundary = width - int(width / (self.num_lines + 1) * k)
x_mask[idx, :, :, boundary:] = 0
idx += 1

# Top masks
for k in range(1, self.num_lines + 1):
boundary = int(height / (self.num_lines + 1) * k)
x_mask[idx, :, :boundary, :] = 0
idx += 1

# Bottom masks
for k in range(1, self.num_lines + 1):
boundary = height - int(height / (self.num_lines + 1) * k)
x_mask[idx, :, boundary:, :] = 0
idx += 1

if not self.channels_first:
x_mask = np.transpose(x_mask, (0, 2, 3, 1))

predictions = self._predict_classifier(x=x_mask, batch_size=batch_size, **kwargs)
filtered_predictions = [
non_maximum_suppression(
pred, iou_threshold=self.iou_threshold, confidence_threshold=self.confidence_threshold
)
for pred in predictions
]

# Extract base predictions
base_predictions = filtered_predictions[0]

# Extract and merge masked predictions
boxes = np.concatenate([pred["boxes"] for pred in filtered_predictions[1:]])
labels = np.concatenate([pred["labels"] for pred in filtered_predictions[1:]])
scores = np.concatenate([pred["scores"] for pred in filtered_predictions[1:]])
merged_predictions = {
"boxes": boxes,
"labels": labels,
"scores": scores,
}
masked_predictions = non_maximum_suppression(
merged_predictions, iou_threshold=self.iou_threshold, confidence_threshold=self.confidence_threshold
)

return base_predictions, masked_predictions
raise NotImplementedError

def _prune_boxes(
self, masked_preds: Dict[str, np.ndarray], base_preds: Dict[str, np.ndarray]
Expand Down Expand Up @@ -332,6 +217,36 @@ def _unionize_clusters(self, masked_preds: Dict[str, np.ndarray]) -> Dict[str, n
}
return unionized_predictions

def predict(self, x: np.ndarray, batch_size: int = 128, **kwargs) -> List[Dict[str, np.ndarray]]:
"""
Perform prediction for a batch of inputs.
:param x: Samples of shape NCHW or NHWC.
:param batch_size: Batch size.
:return: Predictions of format `List[Dict[str, np.ndarray]]`, one for each input image. The fields of the Dict
are as follows:
- boxes [N, 4]: the boxes in [x1, y1, x2, y2] format, with 0 <= x1 < x2 <= W and 0 <= y1 < y2 <= H.
- labels [N]: the labels for each image
- scores [N]: the scores or each prediction.
"""
predictions = []

for x_i in tqdm(x, desc="ObjectSeeker", disable=not self.verbose):
base_preds, masked_preds = self._masked_predictions(x_i, batch_size=batch_size, **kwargs)
pruned_preds = self._prune_boxes(masked_preds, base_preds)
unionized_preds = self._unionize_clusters(pruned_preds)

preds = {
"boxes": np.concatenate([base_preds["boxes"], unionized_preds["boxes"]]),
"labels": np.concatenate([base_preds["labels"], unionized_preds["labels"]]),
"scores": np.concatenate([base_preds["scores"], unionized_preds["scores"]]),
}

predictions.append(preds)

return predictions

def certify(
self,
x: np.ndarray,
Expand All @@ -348,10 +263,7 @@ def certify(
:return: A list containing an array of bools for each bounding box per image indicating if the bounding
box is certified against the given patch.
"""
if self.channels_first:
_, height, width = self.input_shape
else:
height, width, _ = self.input_shape
height, width = self._image_dimensions()

patch_size = np.sqrt(height * width * patch_size)
height_offset = offset * height
Expand Down
Loading

0 comments on commit 290519d

Please sign in to comment.