Skip to content
Merged
Show file tree
Hide file tree
Changes from 32 commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
4556496
Fix `get_local_repo` to make it work on macOS
tyndria Oct 30, 2025
5915eba
Update python and lock
tyndria Oct 30, 2025
aa27d7e
Update numpy to "1.26.4"
tyndria Oct 30, 2025
1afdd3d
remove `extras=["all"]` from alibi-detect dependency definition and p…
tyndria Oct 30, 2025
47eb56f
Fix build seldonio/conda-ubi9 image
tyndria Oct 30, 2025
284e2ad
Upgrade pip-licenses = "5.5.0"
tyndria Oct 30, 2025
6082bba
Fix building `alibi-detect-server` image
tyndria Oct 30, 2025
49d602b
Fix invoking `make test`
tyndria Oct 30, 2025
135e211
Upgrade tensorflow to fix some tests
tyndria Oct 30, 2025
19ea84e
skip if rclone is unavailable
tyndria Oct 30, 2025
df5d8e3
Updated poetry.lock
tyndria Oct 30, 2025
44e2c60
Update GH action for alibi detect tests
tyndria Oct 30, 2025
3eb84f0
Minor packages upgrades
tyndria Nov 5, 2025
bab6063
Fix minor image warnings
tyndria Nov 5, 2025
7338a90
Remove fix for the solved `pystan` issue
tyndria Nov 6, 2025
29e45c7
Added missing "tensorflow-probability" and "tf-keras" dependencies to…
tyndria Nov 6, 2025
614c5af
Upgrade rclone to v1.71.2 to fix CVEs
tyndria Nov 6, 2025
2cd77bc
Fix poetry installation after conda base image is changed; Introduced…
tyndria Nov 7, 2025
54e7ca6
Fix alibidetect_tests workflow
tyndria Nov 7, 2025
963cd66
Try to run workflow in a fork (expect to be failing)
tyndria Nov 7, 2025
9ed6584
Upgrade `black` to fix lint job
tyndria Nov 7, 2025
3757875
upgrade protobuf, tf, tf-keras, grpcio-tools
tyndria Nov 12, 2025
c5e3d98
Upgrade protobuf patch version to move from yanked version
tyndria Nov 19, 2025
c066833
Use ubi9 base image for the alibi-detect-server image
tyndria Nov 19, 2025
db60069
Return missing option -p for mkdir command in Dockerfile
tyndria Nov 19, 2025
63c6d92
Return type check stage before tests execution and fix one error
tyndria Nov 19, 2025
40f5fb9
Testing with alibi-detect rc
tyndria Nov 27, 2025
f95cd8d
Upgraded mypy to fix type_check action
tyndria Nov 27, 2025
6e16926
Pass TF_USE_LEGACY_KERAS to fix alibi-detect e2e tests on top of the …
tyndria Nov 27, 2025
5e02623
Update readme and mark GPU image as deprecated (only repo
tyndria Dec 1, 2025
1358dff
Fixed helper commands to run quick sanity checks and updated readme
tyndria Dec 1, 2025
01f3fd6
Try to clean up disk space to fix ci for alibi-detect-server
tyndria Dec 1, 2025
20edd64
Clean up
tyndria Dec 1, 2025
e979306
Deprecate components/drift-detection/nvidia-triton-cifar10/cifar10_dr…
tyndria Dec 3, 2025
4886cf9
Added a note about rclone setup to readme
tyndria Dec 3, 2025
0b26e09
Update lint command to use `poetry`; Committing formatted files
tyndria Dec 3, 2025
25c3433
Revert a code to build conda base image on mac
tyndria Dec 3, 2025
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
43 changes: 27 additions & 16 deletions .github/workflows/alibidetect_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,33 @@ name: V1 Alibi Detect Tests

on:
push:
branches: [ master ]
branches: "*" # TODO: return [master]
pull_request:
# TODO revert before merge to master
branches: [ fix/core-1-CVEs ]
branches: "*" # TODO: return [master]

jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up Python 3.8
- name: Free up disk space (android, haskell, dotnet)
run: |
sudo rm -rf /usr/local/lib/android || true
sudo rm -rf /opt/ghc || true
sudo rm -rf /usr/share/dotnet || true
df -h
- uses: actions/checkout@v4
- name: Set up Python 3.12
uses: actions/setup-python@v4
with:
python-version: 3.8
python-version: '3.12'
- name: Install Poetry
uses: snok/install-poetry@v1
with:
version: 1.1.15
version: 2.1.2
virtualenvs-create: false
- name: Install dependencies
run: |
pip install --upgrade pip setuptools
python -m pip install --upgrade pip setuptools
make -C components/alibi-detect-server dev_install
- name: Lint
run: |
Expand All @@ -32,24 +37,30 @@ jobs:
python-tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Free up disk space (android, haskell, dotnet)
run: |
sudo rm -rf /usr/local/lib/android || true
sudo rm -rf /opt/ghc || true
sudo rm -rf /usr/share/dotnet || true
df -h
- uses: actions/checkout@v4
- name: Install Rclone
run: |
wget https://downloads.rclone.org/v1.62.2/rclone-v1.62.2-linux-amd64.zip
unzip rclone-v1.62.2-linux-amd64.zip
mv rclone-v1.62.2-linux-amd64/rclone /usr/local/bin/rclone
- name: Set up Python 3.8
wget https://downloads.rclone.org/v1.71.2/rclone-v1.71.2-linux-amd64.zip
unzip rclone-v1.71.2-linux-amd64.zip
mv rclone-v1.71.2-linux-amd64/rclone /usr/local/bin/rclone
- name: Set up Python 3.12
uses: actions/setup-python@v4
with:
version: 1.1.15
python-version: 3.8
python-version: '3.12'
- name: Install Poetry
uses: snok/install-poetry@v1
with:
version: 2.1.2
virtualenvs-create: false
- name: Install dependencies
run: |
pip install --upgrade pip setuptools
python -m pip install --upgrade pip setuptools
make -C components/alibi-detect-server dev_install
- name: Test
run: |
Expand Down
70 changes: 34 additions & 36 deletions components/alibi-detect-server/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,63 +1,58 @@
ARG VERSION
ARG BASE_IMAGE
FROM ${BASE_IMAGE}:${VERSION} as base
FROM ${BASE_IMAGE}:${VERSION} AS base

ARG VERSION
LABEL name="Seldon Alibi Detect Server" \
vendor="Seldon Technologies" \
version="1.19.0-dev" \
release="1" \
summary="Alibi Detect Server for Seldon Core" \
description="The Alibi Detect Server provides outlier, drift and adversarial detection services for Seldon Core"
vendor="Seldon Technologies" \
version="1.19.0-dev" \
release="1" \
summary="Alibi Detect Server for Seldon Core" \
description="The Alibi Detect Server provides outlier, drift and adversarial detection services for Seldon Core"

FROM base as builder
FROM base AS builder

USER root

RUN microdnf update -y && \
microdnf install -y \
unzip \
make \
automake \
gcc \
gcc-c++
unzip \
make \
automake \
gcc \
gcc-c++

# Install Rclone Binary to be present in the image
RUN wget https://downloads.rclone.org/v1.64.2/rclone-v1.64.2-linux-amd64.zip && \
unzip rclone-v1.64.2-linux-amd64.zip && \
mv rclone-v1.64.2-linux-amd64/rclone /usr/bin/rclone && \
rm -rf rclone-v1.64.2-linux-amd64.zip rclone-v1.64.2-linux-amd64

# Note that we need to force Conda to use the system's std-c++ library, as
# otherwise PyStan won't compile with Conda's older stdc++ library:
# https://github.com/stan-dev/pystan/issues/294#issuecomment-870711100
RUN pip install --upgrade pip setuptools wheel && \
cd /opt/conda/lib && \
rm libstdc++.so libstdc++.so.6 && \
ln -s /usr/lib64/libstdc++.so.6.0.29 libstdc++.so && \
ln -s /usr/lib64/libstdc++.so.6.0.29 libstdc++.so.6
RUN wget https://downloads.rclone.org/v1.71.2/rclone-v1.71.2-linux-amd64.zip && \
unzip rclone-v1.71.2-linux-amd64.zip && \
mv rclone-v1.71.2-linux-amd64/rclone /usr/bin/rclone && \
rm -rf rclone-v1.71.2-linux-amd64.zip rclone-v1.71.2-linux-amd64

# Make home dir
RUN mkdir microservice
WORKDIR /microservice

# Install Poetry
ENV POETRY_HOME /microservice/.poetry
RUN curl -sSL https://install.python-poetry.org | python3 - --version 1.1.15
ENV POETRY_HOME=/microservice/.poetry
RUN /opt/conda/bin/pip install --no-cache-dir "poetry==2.1.2"

ENV PATH "$POETRY_HOME/bin:$PATH"
ENV POETRY_VIRTUALENVS_CREATE false
# Replace vulnerable pip wheel embedded inside virtualenv(CVE-2025-8869)
RUN find /opt/conda/lib/python3.12/site-packages/virtualenv/seed/wheels/embed/ -name "pip-*.whl" -delete && \
/opt/conda/bin/pip wheel pip==25.3.0 --wheel-dir /opt/conda/lib/python3.12/site-packages/virtualenv/seed/wheels/embed/

ENV PATH="$POETRY_HOME/bin:$PATH"
ENV POETRY_VIRTUALENVS_CREATE=false

# Install the server
## NOTE: Removing explicitly requirements.txt file from subdeps test
## dependencies causing false positives in Snyk.
COPY poetry.lock pyproject.toml ./
COPY _seldon_core ./_seldon_core
RUN poetry install --no-dev && \
RUN poetry install --no-root && \
rm ~/.cache/pip -rf && \
rm -f /opt/conda/lib/python3.8/site-packages/gslib/vendored/boto/requirements.txt \
/opt/conda/lib/python3.8/site-packages/gslib/vendored/oauth2client/docs/requirements.txt \
/opt/conda/lib/python3.8/site-packages/tests/conda_env/support/requirements.txt
rm -f /opt/conda/lib/python3.12/site-packages/gslib/vendored/boto/requirements.txt \
/opt/conda/lib/python3.12/site-packages/gslib/vendored/oauth2client/docs/requirements.txt \
/opt/conda/lib/python3.12/site-packages/tests/conda_env/support/requirements.txt

# Add licences
RUN mkdir /licenses
Expand All @@ -70,7 +65,10 @@ COPY adserver adserver
COPY README.md README.md
COPY version.txt version.txt

FROM base as final
# Install the project code
RUN poetry install

FROM base AS final
WORKDIR /microservice

USER root
Expand All @@ -80,7 +78,7 @@ ENV RCLONE_CONFIG_GS_TYPE="google cloud storage" \
DRIFT_ARTIFACTS_DIR="/mnt/artifacts/"

# mesa-libGL: this is to avoid "ImportError: libGL.so.1" from opencv
RUN microdnf clean all && microdnf install -y mesa-libGL
RUN microdnf clean all && microdnf install -y mesa-libGL
RUN microdnf update -y

COPY --from=builder /microservice /microservice
Expand All @@ -89,7 +87,7 @@ COPY --from=builder /usr/bin/rclone /usr/bin/rclone
COPY --from=builder /licenses /licenses

# This is to have writable numba and keops cache directories
ENV NUMBA_CACHE_DIR /tmp/numba-cache
ENV NUMBA_CACHE_DIR=/tmp/numba-cache
RUN mkdir -p /.cache && \
chown -R 8888:0 /.cache && \
chmod -R 776 /.cache
Expand Down
48 changes: 18 additions & 30 deletions components/alibi-detect-server/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ SHELL := /bin/bash
VERSION ?= $(shell cat ../../version.txt)
DOCKER_REGISTRY ?= seldonio

BASE_IMAGE ?= ${DOCKER_REGISTRY}/conda-ubi10
BASE_IMAGE ?= ${DOCKER_REGISTRY}/conda-ubi9
IMAGE ?= ${DOCKER_REGISTRY}/alibi-detect-server
KIND_NAME ?= kind

Expand All @@ -12,7 +12,7 @@ SELDON_CORE_DIR=../..

get_local_repo: clean
cp $(SELDON_CORE_DIR)/version.txt version.txt
cp -rT $(SELDON_CORE_DIR)/python/ _seldon_core/
cp -R "$(SELDON_CORE_DIR)/python/." _seldon_core/

clean:
rm version.txt || true
Expand All @@ -28,7 +28,7 @@ type_check:

.PHONY: test
test: type_check
pytest -W ignore adserver
poetry run pytest -W ignore adserver

.PHONY: lint
lint:
Expand All @@ -39,28 +39,24 @@ lint:
#

run-outlier-detector-tensorflow:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are those make commands running fine after the addition of TF_USE_LEGACY_KERAS=1 🤔

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They are

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

confirmed

python -m adserver --model_name cifar10od --http_port 8080 --protocol tensorflow.http --event_type org.kubeflow.serving.inference.outlier --storage_uri gs://seldon-models/alibi-detect/od/OutlierVAE/cifar10 --event_source http://localhost:8080 OutlierDetector
TF_USE_LEGACY_KERAS=1 python -m adserver --model_name cifar10od --http_port 8080 --protocol tensorflow.http --event_type org.kubeflow.serving.inference.outlier --storage_uri gs://seldon-models/alibi-detect/od/OutlierVAE/cifar10 --event_source http://localhost:8080 OutlierDetector

run-outlier-detector-v2:
python -m adserver --model_name cifar10od --http_port 8080 --protocol kfserving.http --event_type org.kubeflow.serving.inference.outlier --storage_uri gs://seldon-models/alibi-detect/od/OutlierVAE/cifar10 --event_source http://localhost:8080 OutlierDetector
TF_USE_LEGACY_KERAS=1 python -m adserver --model_name cifar10od --http_port 8080 --protocol kfserving.http --event_type org.kubeflow.serving.inference.outlier --storage_uri gs://seldon-models/alibi-detect/od/OutlierVAE/cifar10 --event_source http://localhost:8080 OutlierDetector

run-metrics-server:
SELDON_DEPLOYMENT_ID="sdepname" PREDICTIVE_UNIT_ID="modelname" PREDICTIVE_UNIT_IMAGE="adserver:0.1" PREDICTOR_ID="pred" \
TF_USE_LEGACY_KERAS=1 SELDON_DEPLOYMENT_ID="sdepname" PREDICTIVE_UNIT_ID="modelname" PREDICTIVE_UNIT_IMAGE="adserver:0.1" PREDICTOR_ID="pred" \
python -m adserver --model_name model --http_port 8080 --protocol seldonfeedback.http --event_type io.seldon.serving.feedback --storage_uri "adserver.cm_models.binary_metrics.BinaryMetrics" --event_source http://localhost:8080 MetricsServer

#
# Docker Run
#

docker-run-outlier-detector-tensorflow:
docker run --name cifar10od -it --rm -p 8080:8080 ${IMAGE}:${VERSION} --model_name cifar10od --http_port 8080 --protocol tensorflow.http --event_type org.kubeflow.serving.inference.outlier --storage_uri gs://seldon-models/alibi-detect/od/OutlierVAE/cifar10 --event_source http://localhost:8080 OutlierDetector
docker run --name cifar10od -e TF_USE_LEGACY_KERAS=1 -it --rm -p 8080:8080 ${IMAGE}:${VERSION} --model_name cifar10od --http_port 8080 --protocol tensorflow.http --event_type org.kubeflow.serving.inference.outlier --storage_uri gs://seldon-models/alibi-detect/od/OutlierVAE/cifar10 --event_source http://localhost:8080 OutlierDetector

docker-run-drift-detector-tensorflow:
docker run --name cifar10cd -it --rm -p 8080:8080 ${IMAGE}:${VERSION} --model_name cifar10cd --http_port 8080 --protocol tensorflow.http --event_type org.kubeflow.serving.inference.drift --storage_uri gs://seldon-models/alibi-detect/cd/ks/cifar10-0_4_3 --event_source http://localhost:8080 DriftDetector --drift_batch_size=2

docker-run-drift-detector-torch:
docker run --name cifar10cd -it --rm -p 8080:8080 ${IMAGE}-gpu:${VERSION} --model_name cifar10cd --http_port 8080 --protocol tensorflow.http --event_type org.kubeflow.serving.inference.drift --storage_uri gs://seldon-models/alibi-detect/cd/mmd/cifar10_mmd_torch --event_source http://localhost:8080 DriftDetector --drift_batch_size=2

docker run --name cifar10cd -e TF_USE_LEGACY_KERAS=1 -it --rm -p 8080:8080 ${IMAGE}:${VERSION} --model_name cifar10cd --http_port 8080 --protocol tensorflow.http --event_type org.kubeflow.serving.inference.drift --storage_uri gs://seldon-models/alibi-detect/cd/ks/cifar10-0_6_2 --event_source http://localhost:8080 DriftDetector --drift_batch_size=2

#
# Test curls
Expand All @@ -76,40 +72,32 @@ curl-detector-v2-outlier:
curl -v localhost:8080/ -d @./cifar10-v2-outlier.json -H "ce-namespace: default" -H "ce-modelid: cifar10" -H "ce-type: io.seldon.serving.inference.request" -H "ce-id: 1234" -H "ce-source: localhost" -H "ce-specversion: 1.0"

curl-tensorflow-outlier-detector-scores:
curl -v localhost:8080/ -d @./cifar10.json -H "Alibi-Detect-Return-Feature-Score: true" -H "Alibi-Detect-Return-Instance-Score: true"
curl -v localhost:8080/ -d @./cifar10.json -H "ce-source: localhost" -H "ce-type: io.seldon.serving.inference.request" -H "ce-id: 1234" -H "ce-specversion: 1.0" -H "Alibi-Detect-Return-Feature-Score: true" -H "Alibi-Detect-Return-Instance-Score: true"

curl-metrics-server:
curl -v -X POST -H 'Content-Type: application/json' \
-d '{"truth": {"data": {"ndarray": [0]}}, "response": {"data": {"ndarray": [1]}}}' \
http://localhost:8080/

curl-metrics-server-elasticsearch:
curl-metrics-server-feedback:
curl -v -X POST -H 'Content-Type: application/json' \
-H 'Ce-Requestid: 7983e38c-29dc-45ff-8ffb-77252e7ac86d' \
-H 'Ce-Namespace: seldon' \
-H 'Ce-Inferenceservicename: seldon' \
-d '{"truth": {"data": {"ndarray": [0]}}}' \
-H "ce-source: localhost" \
-H "ce-type: io.seldon.serving.feedback" \
-H "ce-id: 1234" \
-H "ce-specversion: 1.0" \
-d '{"truth": {"data": {"ndarray": [0]}}, "response": {"data": {"ndarray": [1]}}}' \
http://localhost:8080/

curl-metrics-server-metrics:

curl-metrics-server-get:
curl http://localhost:8080/v1/metrics



# image building logic

docker-build: get_local_repo
docker build -f Dockerfile --build-arg BASE_IMAGE=${BASE_IMAGE} --build-arg VERSION=${VERSION} -t ${IMAGE}:${VERSION} .

docker-build-gpu:
docker build -f Dockerfile.gpu -t ${IMAGE}-gpu:${VERSION} .
docker build --platform linux/amd64 -f Dockerfile --build-arg BASE_IMAGE=${BASE_IMAGE} --build-arg VERSION=${VERSION} -t ${IMAGE}:${VERSION} .

docker-push:
docker push ${IMAGE}:${VERSION}

docker-push-gpu:
docker push ${IMAGE}-gpu:${VERSION}

kind_load: docker-build
kind load docker-image ${IMAGE}:${VERSION} --name ${KIND_NAME}

Expand Down
38 changes: 38 additions & 0 deletions components/alibi-detect-server/README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,41 @@
# Alibi-Detect CloudEvents Server

Extends the [Seldon CloudEvents Server](https://github.com/SeldonIO/seldon-models/tree/master/servers/cloudevents) to allow Alibi Detect models to be loaded and events processed.

## Maintanence

In order to build and test integration with the Alibi Detect library, ensure to execute the following commands after pulling changes:

```bash

make dev_install
make test


```

This will install the Alibi Detect library in the development environment and run the tests.

There is also a possibility to quickly run sanity checks in this way:

```bash

make run-outlier-detector-tensorflow # to run the outlier detector server with tensorflow locally
make curl-detector-tensorflow # to send a test request to the server
make curl-tensorflow-outlier-detector-scores # to send a test request to get outlier scores

make run-outlier-detector-v2 # to run the outlier detector server with kfserving protocol locally
make curl-detector-v2 # to send a test request to the server
make curl-detector-v2-outlier # to send a test request to get outlier scores

make run-metrics-server # to run the metrics server locally
make curl-metrics-server-feedback # to submit a test feedback with truth
make curl-metrics-server-get # to get metrics from the server
```

In order to run the integration tests in the Kubernetes cluster, build the Docker image first: `make docker-build`.
Then, as part of the cluster and ecosystem setup in the `testing/scripts` folder, [this test](../../testing/scripts/test_alibi_detect_server.py) can be executed to validate the Alibi Detect server functionality.

## Deprecation Notice for GPU image (starting from Core 1.19.0 release)

GPU image for Alibi Detect server is deprecated and won't be maintained starting from Seldon Core 1.19.0 release.
2 changes: 1 addition & 1 deletion components/alibi-detect-server/adserver/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,7 @@ def create_cloud_event(
event_type: str,
event_source: str,
extensions: dict,
event_id: str = None,
event_id: Optional[str] = None,
) -> v1.Event:
"""
Create a CloudEvent
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ def test_basic(self):
req = [1, 2]
headers = {}
res = ad_model.process_event(req, headers)
self.assert_(res is not None)
self.assertIsNotNone(res)
self.assertEqual(res.data["data"]["is_adversarial"], 1)

def test_no_return_instance_score(self):
Expand All @@ -55,5 +55,5 @@ def test_no_return_instance_score(self):
req = [1, 2]
headers = {HEADER_RETURN_INSTANCE_SCORE: "false"}
res = ad_model.process_event(req, headers)
self.assert_(res is not None)
self.assertIsNotNone(res)
self.assertEqual(res.data["data"]["is_adversarial"], expected_is_adversarial)
Loading