Skip to content

Commit 2b8ec6e

Browse files
committed
[Draft] SHAP test
1 parent 05fe09a commit 2b8ec6e

File tree

16 files changed

+192
-128
lines changed

16 files changed

+192
-128
lines changed

tests/model_explainability/conftest.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,8 @@ def minio_pod(admin_client: DynamicClient, model_namespace: Namespace) -> Genera
8383
"value": "THESECRETKEY",
8484
},
8585
],
86-
"image": "quay.io/rh-ee-mmisiura/modelmesh-minio-examples:latest",
86+
"image": "quay.io/trustyai_testing/modelmesh-minio-examples"
87+
"@sha256:d2ccbe92abf9aa5085b594b2cae6c65de2bf06306c30ff5207956eb949bb49da",
8788
"name": MINIO,
8889
}
8990
],

tests/model_explainability/lm_eval/test_lm_eval.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,10 @@ def test_lmeval_huggingface_model(admin_client, model_namespace, lmevaljob_hf):
2727
[
2828
pytest.param(
2929
{"name": "lmevaljob-local-offline-builtin"},
30-
{"image": "quay.io/trustyai_testing/lmeval-assets-flan-arceasy:latest"},
30+
{
31+
"image": "quay.io/trustyai_testing/lmeval-assets-flan-arceasy"
32+
"@sha256:11cc9c2f38ac9cc26c4fab1a01a8c02db81c8f4801b5d2b2b90f90f91b97ac98"
33+
},
3134
{"task_list": {"taskNames": ["arc_easy"]}},
3235
)
3336
],
@@ -48,7 +51,10 @@ def test_lmeval_local_offline_builtin_tasks_flan_arceasy(
4851
[
4952
pytest.param(
5053
{"name": "lmevaljob-local-offline-unitxt"},
51-
{"image": "quay.io/trustyai_testing/lmeval-assets-flan-20newsgroups:latest"},
54+
{
55+
"image": "quay.io/trustyai_testing/lmeval-assets-flan-20newsgroups"
56+
"@sha256:3778c15079f11ef338a82ee35ae1aa43d6db52bac7bbfdeab343ccabe2608a0c"
57+
},
5258
{
5359
"task_list": {
5460
"taskRecipes": [
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
from typing import Any, Generator
2+
3+
import pytest
4+
from kubernetes.dynamic import DynamicClient
5+
from ocp_resources.inference_service import InferenceService
6+
from ocp_resources.namespace import Namespace
7+
from ocp_resources.secret import Secret
8+
from ocp_resources.serving_runtime import ServingRuntime
9+
from ocp_resources.trustyai_service import TrustyAIService
10+
11+
from tests.model_explainability.trustyai_service.utils import wait_for_isvc_deployment_registered_by_trustyaiservice
12+
from utilities.constants import ModelFormat, KServeDeploymentType, RuntimeTemplates
13+
from utilities.inference_utils import create_isvc
14+
from utilities.serving_runtime import ServingRuntimeFromTemplate
15+
16+
17+
@pytest.fixture(scope="class")
18+
def ovms_runtime(
19+
admin_client: DynamicClient, minio_data_connection: Secret, model_namespace: Namespace
20+
) -> Generator[ServingRuntime, Any, Any]:
21+
with ServingRuntimeFromTemplate(
22+
client=admin_client,
23+
name=f"{ModelFormat.OVMS}-1.x",
24+
namespace=model_namespace.name,
25+
template_name=RuntimeTemplates.OVMS_KSERVE,
26+
multi_model=False,
27+
enable_http=False,
28+
enable_grpc=True,
29+
model_format_name={"name": ModelFormat.ONNX, "version": "1"},
30+
runtime_image="quay.io/opendatahub/openvino_model_server"
31+
"@sha256:564664371d3a21b9e732a5c1b4b40bacad714a5144c0a9aaf675baec4a04b148",
32+
) as sr:
33+
yield sr
34+
35+
36+
@pytest.fixture(scope="class")
37+
def onnx_loan_model(
38+
admin_client: DynamicClient,
39+
model_namespace: Namespace,
40+
minio_data_connection: Secret,
41+
ovms_runtime: ServingRuntime,
42+
trustyai_service_with_pvc_storage: TrustyAIService,
43+
) -> Generator[InferenceService, Any, Any]:
44+
with create_isvc(
45+
client=admin_client,
46+
name="demo-loan-nn-onnx-alpha",
47+
namespace=model_namespace.name,
48+
deployment_mode=KServeDeploymentType.SERVERLESS,
49+
model_format=ModelFormat.ONNX,
50+
runtime=ovms_runtime.name,
51+
storage_key=minio_data_connection.name,
52+
storage_path="ovms/loan_model_alpha",
53+
min_replicas=1,
54+
resources={"limits": {"cpu": "2", "memory": "8Gi"}, "requests": {"cpu": "1", "memory": "4Gi"}},
55+
enable_auth=True,
56+
model_version="1",
57+
wait=True,
58+
wait_for_predictor_pods=False,
59+
) as isvc:
60+
wait_for_isvc_deployment_registered_by_trustyaiservice(
61+
client=admin_client,
62+
isvc=isvc,
63+
trustyai_service=trustyai_service_with_pvc_storage,
64+
runtime_name=ovms_runtime.name,
65+
)
66+
yield isvc
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
MODEL_DATA_PATH: str = "./tests/model_explainability/trustyai_service/model_data"

tests/model_explainability/trustyai_service/drift/conftest.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@ def mlserver_runtime(
3838
containers = [
3939
{
4040
"name": "kserve-container",
41-
"image": "quay.io/rh-ee-mmisiura/mlserver:1.6.1",
41+
"image": "quay.io/trustyai_testing/mlserver"
42+
"@sha256:68a4cd74fff40a3c4f29caddbdbdc9e54888aba54bf3c5f78c8ffd577c3a1c89",
4243
"env": [
4344
{"name": "MLSERVER_MODEL_IMPLEMENTATION", "value": "{{.Labels.modelClass}}"},
4445
{"name": "MLSERVER_HTTP_PORT", "value": "8080"},

tests/model_explainability/trustyai_service/drift/test_drift.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import pytest
22

3+
from tests.model_explainability.trustyai_service.constants import MODEL_DATA_PATH
34
from tests.model_explainability.trustyai_service.utils import (
45
send_inference_requests_and_verify_trustyai_service,
56
verify_upload_data_to_trustyai_service,
@@ -10,7 +11,7 @@
1011
)
1112
from utilities.manifests.openvino import OPENVINO_KSERVE_INFERENCE_CONFIG
1213

13-
BASE_DATA_PATH: str = "./tests/model_explainability/trustyai_service/drift/model_data"
14+
BASE_DATA_PATH: str = f"{MODEL_DATA_PATH}/drift/"
1415

1516

1617
@pytest.mark.parametrize(
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import pytest
2+
3+
from tests.model_explainability.trustyai_service.constants import MODEL_DATA_PATH
4+
from tests.model_explainability.trustyai_service.explainers.utils import verify_shap_explanation
5+
from tests.model_explainability.trustyai_service.utils import send_inference_requests_and_verify_trustyai_service
6+
from utilities.manifests.openvino import OPENVINO_KSERVE_INFERENCE_CONFIG
7+
8+
BASE_DATA_PATH: str = f"{MODEL_DATA_PATH}/fairness/"
9+
10+
11+
@pytest.mark.parametrize(
12+
"model_namespace",
13+
[
14+
pytest.param(
15+
{"name": "test-shap"},
16+
)
17+
],
18+
indirect=True,
19+
)
20+
def test_explainers_shap(
21+
admin_client, current_client_token, model_namespace, trustyai_service_with_pvc_storage, onnx_loan_model
22+
):
23+
send_inference_requests_and_verify_trustyai_service(
24+
client=admin_client,
25+
token=current_client_token,
26+
data_path=f"{BASE_DATA_PATH}",
27+
trustyai_service=trustyai_service_with_pvc_storage,
28+
inference_service=onnx_loan_model,
29+
inference_config=OPENVINO_KSERVE_INFERENCE_CONFIG,
30+
)
31+
32+
verify_shap_explanation(
33+
client=admin_client,
34+
token=current_client_token,
35+
trustyai_service=trustyai_service_with_pvc_storage,
36+
inference_service=onnx_loan_model,
37+
)
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import json
2+
from typing import Any
3+
4+
from kubernetes.dynamic import DynamicClient
5+
from ocp_resources.inference_service import InferenceService
6+
from ocp_resources.trustyai_service import TrustyAIService
7+
from requests import Response
8+
from simple_logger.logger import get_logger
9+
10+
from tests.model_explainability.trustyai_service.utils import TrustyAIServiceClient
11+
12+
LOGGER = get_logger(name=__name__)
13+
14+
15+
def verify_shap_explanation(
16+
client: DynamicClient, token: str, trustyai_service: TrustyAIService, inference_service: InferenceService
17+
) -> None:
18+
tas_client: TrustyAIServiceClient = TrustyAIServiceClient(token=token, service=trustyai_service, client=client)
19+
20+
response: Response = tas_client.get_inference_ids(model_name=inference_service.name)
21+
response_data: Any = json.loads(response.text)
22+
23+
if len(response_data) < 2:
24+
raise ValueError(f"Not enough inferences available. Found only {len(response_data)}")
25+
26+
inference_id: str = response_data[-1]["id"]
27+
28+
response = tas_client.request_shap_explanation(
29+
model_name=inference_service.name,
30+
inference_id=inference_id,
31+
target="knative-local-gateway.istio-system.svc.cluster.local:80",
32+
n_samples=75,
33+
)
34+
LOGGER.error(response.text)

tests/model_explainability/trustyai_service/fairness/conftest.py

Lines changed: 0 additions & 113 deletions
This file was deleted.

tests/model_explainability/trustyai_service/fairness/test_fairness.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import pytest
44
from ocp_resources.inference_service import InferenceService
55

6+
from tests.model_explainability.trustyai_service.constants import MODEL_DATA_PATH
67
from tests.model_explainability.trustyai_service.utils import (
78
send_inference_requests_and_verify_trustyai_service,
89
verify_name_mappings,
@@ -13,7 +14,7 @@
1314
)
1415
from utilities.manifests.openvino import OPENVINO_KSERVE_INFERENCE_CONFIG
1516

16-
BASE_DATA_PATH: str = "./tests/model_explainability/trustyai_service/fairness/model_data"
17+
BASE_DATA_PATH: str = f"{MODEL_DATA_PATH}/fairness/"
1718
IS_MALE_IDENTIFYING: str = "Is Male-Identifying?"
1819
WILL_DEFAULT: str = "Will Default?"
1920

0 commit comments

Comments
 (0)