-
Notifications
You must be signed in to change notification settings - Fork 835
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
Explainer Gateway Fix for Istio, Ambassador and Python Client #1668
Changes from all commits
05ce123
a084dcc
d2123cd
ea77210
c478c83
360cbf9
fcb2115
5517a89
76bf7a3
b907373
e79b940
374e7e9
894b985
4f605ab
6c7fa42
bdb05cf
8d9eed1
b4b0bd5
d66dd08
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change | ||
---|---|---|---|---|
|
@@ -211,10 +211,15 @@ def __init__( | |||
logger.debug("Configuration:" + str(self.config)) | ||||
|
||||
def _gather_args(self, **kwargs): | ||||
|
||||
c2 = {**self.config} | ||||
c2.update({k: v for k, v in kwargs.items() if v is not None}) | ||||
return c2 | ||||
""" | ||||
Performs a left outer join where kwargs is left and self.config is right | ||||
adriangonz marked this conversation as resolved.
Show resolved
Hide resolved
|
||||
which means that the resulting dictionary will only have the variables provided | ||||
by the parameters available in kwargs, but will be overriden by kwargs if a value | ||||
that is not None is present. | ||||
""" | ||||
for k, v in kwargs.items(): | ||||
kwargs[k] = v if kwargs[k] is not None else self.config.get(k, None) | ||||
return kwargs | ||||
|
||||
def _validate_args( | ||||
self, | ||||
|
@@ -512,11 +517,7 @@ def explain( | |||
transport: str = None, | ||||
deployment_name: str = None, | ||||
payload_type: str = None, | ||||
seldon_rest_endpoint: str = None, | ||||
seldon_grpc_endpoint: str = None, | ||||
gateway_endpoint: str = None, | ||||
microservice_endpoint: str = None, | ||||
method: str = None, | ||||
shape: Tuple = (1, 1), | ||||
namespace: str = None, | ||||
data: np.ndarray = None, | ||||
|
@@ -528,6 +529,7 @@ def explain( | |||
headers: Dict = None, | ||||
http_path: str = None, | ||||
client_return_type: str = None, | ||||
predictor: str = None, | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit (feel free to ignore): should we call the arg There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Haha I thought of the same, I think the reason I ended up goign with this is because there were no other params with the format x_name, i.e. method, gateway, namespace, etc There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There is
|
||||
) -> Dict: | ||||
""" | ||||
|
||||
|
@@ -573,6 +575,8 @@ def explain( | |||
Custom http path for predict call to use | ||||
client_return_type | ||||
the return type of all functions can be either dict or proto | ||||
predictor | ||||
The name of the predictor to send the explanations to | ||||
|
||||
Returns | ||||
------- | ||||
|
@@ -583,11 +587,7 @@ def explain( | |||
transport=transport, | ||||
deployment_name=deployment_name, | ||||
payload_type=payload_type, | ||||
seldon_rest_endpoint=seldon_rest_endpoint, | ||||
seldon_grpc_endpoint=seldon_grpc_endpoint, | ||||
gateway_endpoint=gateway_endpoint, | ||||
microservice_endpoint=microservice_endpoint, | ||||
method=method, | ||||
shape=shape, | ||||
namespace=namespace, | ||||
names=names, | ||||
|
@@ -599,6 +599,7 @@ def explain( | |||
headers=headers, | ||||
http_path=http_path, | ||||
client_return_type=client_return_type, | ||||
predictor=predictor, | ||||
) | ||||
self._validate_args(**k) | ||||
if k["gateway"] == "ambassador" or k["gateway"] == "istio": | ||||
|
@@ -1272,7 +1273,7 @@ def get_token( | |||
token = response.json()["access_token"] | ||||
return token | ||||
else: | ||||
print("Failed to get token:" + response.text) | ||||
logger.debug("Failed to get token:" + response.text) | ||||
adriangonz marked this conversation as resolved.
Show resolved
Hide resolved
|
||||
raise SeldonClientException(response.text) | ||||
|
||||
|
||||
|
@@ -1641,6 +1642,8 @@ def explain_predict_gateway( | |||
deployment_name: str, | ||||
namespace: str = None, | ||||
gateway_endpoint: str = "localhost:8003", | ||||
gateway: str = None, | ||||
transport: str = "rest", | ||||
shape: Tuple[int, int] = (1, 1), | ||||
data: np.ndarray = None, | ||||
headers: Dict = None, | ||||
|
@@ -1654,7 +1657,7 @@ def explain_predict_gateway( | |||
channel_credentials: SeldonChannelCredentials = None, | ||||
http_path: str = None, | ||||
client_return_type: str = "dict", | ||||
**kwargs, | ||||
predictor: str = None, | ||||
) -> SeldonClientPrediction: | ||||
""" | ||||
REST explain request to Gateway Ingress | ||||
|
@@ -1667,6 +1670,10 @@ def explain_predict_gateway( | |||
k8s namespace of running deployment | ||||
gateway_endpoint | ||||
The host:port of gateway | ||||
gateway | ||||
The type of gateway which can be seldon or ambassador/istio | ||||
transport | ||||
The type of transport, in this case only rest is supported | ||||
shape | ||||
The shape of the data to send | ||||
data | ||||
|
@@ -1699,6 +1706,9 @@ def explain_predict_gateway( | |||
A JSON Dict | ||||
|
||||
""" | ||||
if transport != "rest": | ||||
raise SeldonClientException("Only supported transport is REST for explanations") | ||||
|
||||
if bin_data is not None: | ||||
request = prediction_pb2.SeldonMessage(binData=bin_data) | ||||
elif str_data is not None: | ||||
|
@@ -1724,17 +1734,27 @@ def explain_predict_gateway( | |||
if not call_credentials.token is None: | ||||
req_headers["X-Auth-Token"] = call_credentials.token | ||||
if http_path is not None: | ||||
url = url = ( | ||||
url = ( | ||||
scheme | ||||
+ "://" | ||||
+ gateway_endpoint | ||||
+ "/seldon/" | ||||
+ namespace | ||||
+ "/" | ||||
+ deployment_name | ||||
+ "-explainer" | ||||
+ "/" | ||||
+ predictor | ||||
+ http_path | ||||
) | ||||
elif gateway == "seldon": | ||||
url = scheme + "://" + gateway_endpoint + "/api/v1.0/explain" | ||||
else: | ||||
if not predictor: | ||||
raise SeldonClientException( | ||||
"Predictor parameter must be provided to talk through explainer via gateway" | ||||
) | ||||
|
||||
if gateway_prefix is None: | ||||
if namespace is None: | ||||
url = ( | ||||
|
@@ -1743,7 +1763,10 @@ def explain_predict_gateway( | |||
+ gateway_endpoint | ||||
+ "/seldon/" | ||||
+ deployment_name | ||||
+ "/explainer/api/v1.0/explain" | ||||
+ "-explainer" | ||||
+ "/" | ||||
+ predictor | ||||
+ "/api/v1.0/explain" | ||||
) | ||||
else: | ||||
url = ( | ||||
|
@@ -1754,15 +1777,14 @@ def explain_predict_gateway( | |||
+ namespace | ||||
+ "/" | ||||
+ deployment_name | ||||
+ "/explainer/api/v1.0/explain" | ||||
+ "-explainer" | ||||
+ "/" | ||||
+ predictor | ||||
+ "/api/v1.0/explain" | ||||
) | ||||
else: | ||||
url = ( | ||||
scheme | ||||
+ "://" | ||||
+ gateway_endpoint | ||||
+ gateway_prefix | ||||
+ +"/api/v1.0/explain" | ||||
scheme + "://" + gateway_endpoint + gateway_prefix + "/api/v1.0/explain" | ||||
) | ||||
verify = True | ||||
cert = None | ||||
|
@@ -1781,7 +1803,6 @@ def explain_predict_gateway( | |||
url, json=payload, headers=req_headers, verify=verify, cert=cert | ||||
) | ||||
if response_raw.status_code == 200: | ||||
print(client_return_type) | ||||
if client_return_type == "dict": | ||||
ret_request = payload | ||||
ret_response = response_raw.json() | ||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
__version__ = "1.0.2" | ||
__version__ = "1.0.3-SNAPSHOT" |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
apiVersion: machinelearning.seldon.io/v1 | ||
kind: SeldonDeployment | ||
metadata: | ||
name: movie | ||
spec: | ||
name: movie | ||
predictors: | ||
- graph: | ||
children: [] | ||
implementation: SKLEARN_SERVER | ||
modelUri: gs://seldon-models/sklearn/moviesentiment | ||
name: classifier | ||
explainer: | ||
type: AnchorText | ||
name: movies-predictor | ||
replicas: 1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Interesting, I didn't know that
ObjectMeta
also had methods defined!There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, those are methods that we added via composition, it's really one that we added to make the name with a hash if too long. Actually, this may have been intended tho - @cliveseldon could you confirm if this was intended?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Which code are you referring to?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh - those are just convenience methods added by k8s.
name
andGetName
are the same.