본문 바로가기
Engineering/토치서브(Torchserve)

[Torchserve] torchserve explanations API 사용하기

by Hyen4110 2022. 9. 1.
반응형

[torchserve에서 기본으로 제공하는 API]

torchserve는 기본적으로 아래 3가지 Service API를 제공하고 있습니다.

- Inference API

- Management API

- Metrics API 

 

그리고 각각의 API는 다른 포트와 path 로 구분을 하여 request 합니다.

각 API 별 curl 예시는 아래와 같습니다.

 

<curl example>

API  curl example PORT path
inference http://127.0.0.1:8080/predictions/resnet-18/2.0 -T kitten_small.jpg 8080 predictions
management http://127.0.0.1:8081/models/noop 8181 models
metrics http://127.0.0.1:8082/metrics 8082 metrics

 

여기서 8080 PORT 는 기본적으로 inference로 쓰지만,

디폴트로 설정되어있는 API가 하나 더 있는데, 

explanation API입니다. 

(https://pytorch.org/serve/inference_api.html#explanations-api)

 

 

[torchserve의 explanations API]

explanation API는 아래처럼 입력한 데이터에 대해

정의한 설명을 response로 받을 수 있습니다.

아래는 공식 documnet에 있는 예시입니다.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

API  curl example PORT path
inference http://127.0.0.1:8080/predictions/resnet-18/2.0 -T kitten_small.jpg 8080 predictions
explanation http://127.0.0.1:8080/explanations/mnist -T test_data/0.png 8080 explanations

 

이 때 inference와 explanation 모두

request시 handler파일의 'handle' 함수를 실행하기 때문에

어떤 경우에 inference를 실행하고, 

어떤 경우에 explanation을 실행할지를 지정해야합니다. 

다행히 이는 BaseHandler에 구현이 되어있어서 해당 코드를 참고해서 구현할 수있습니다. 

https://github.com/pytorch/serve/blob/master/ts/torch_handler/base_handler.py

 

이때 inference를 할 것이냐 explanation을 할 것이냐는

self._is_explain() return 값을 받아서 판단합니다. 

_is_explain() 함수를 실행했을때

어떻게 True, False를 return하는지 좀더 보겠습니다.

 def handle(self, data, context):

    self.context = context
    metrics = self.context.metrics
    
    if self._is_describe():
        output = [self.describe_handle()]
    else:
        data_preprocess = self.preprocess(data)

        if not self._is_explain():
            output = self.inference(data_preprocess)
            output = self.postprocess(output)
        else:
            output = self.explain_handle(data_preprocess, data)

    return output

 

BaseHandler의 메소드인 _is_explain() 을 보면,

BaseHandler가 갖는 self.context의 값에서 "explain" 여부를 판단하는것을 볼 수있습니다.

 

기본적으로 BaseHandler는 초기화 당시

self.explain = False

를 기본값으로 갖고있지만

explanation API를 request를 한 경우에 

이 self.explain 값을 True로 바꾸게 되고

이것을 기준으로 삼아서, 위의 handle 함수에서 

inference 와 explanation을 실행하는것을 알 수있습니다.

def _is_explain(self):
    if self.context and self.context.get_request_header(0, "explain"):
        if self.context.get_request_header(0, "explain") == "True":
            self.explain = True
            return True
    return False

 

[explanation API를 request해도 is_explain() = False인 경우]

하지만, explanation API 를 reqeust 했음에도

_is_explain()의 결과가 False로 나오는 오류가 발생해서

해결방법을 찾던 중

 

CustomHandler에 handle함수를 구현하지 않고

해당 클래스를 import한 다른 handler 파일을 만든후 handle 함수를 구현해서

self.explain값이 바뀌지 않는다는 것을 확인했습니다. 

그리고 굳이 그렇게 handle 함수만 뽑아서 구현할 필요가 없음을 확인하고

기존에 CustomHandler 클래스의 메소드로 추가하여 만들었습니다. 

이후 is_explain()값이 True로 잘 바뀐것을 확인하였습니다.

 

<오류가 났던 handler 파일 예시>

from CustomHandler import *

_service = ImageCLFHandler()

def handle(data, context):
    if not _service._is_explain():
        if data is None:
            return None
        else:
            data = _service.preprocess(data)
            data = _service.inference(data)
            data = _service.postprocess(data)
            return data

    else:
        _service.explain_handle()
        return 202
반응형

댓글