# 使用 TorchServe 部署 Model

**系統架構** TorchServe 主要提供兩個 API：**Management API 是用來設定 TorchServe 服務**，如註冊新的 Model 服務、卸載 Model 服務，監看 TorchServe 的狀態；**Inference API 用來取得辨識結果**。

![系統架構](https://cdn-images-1.medium.com/max/800/1*w2xTsxjj1aimOsVIVZPw0w.png)

* Frontend：指的是 request batching + **Inference API Handler。**&#x72;equest batching 是由 **Management API** 設定；**Inference API Handler** 則是由開發者自行撰寫
* Worker Process：指的是一組辨識程式的運行(trained model + model handler)，概念像是 Thread，可由 **Management API 進行設定運行的數量**。
* Model Store：透過 TorchServe 工具壓縮後的 model package。
* Backend：指的是管理 Worker Process 的程式，由 **Management API** 讓使用者管理。

**使用指南** 使用 TorchServe 需要準備三個檔案：Trained Model、Inference handler 、model Handler，將這三個東西使用 TorchServe Archiver 將其壓縮成 .mar 檔案。最後將 .mar 檔放入 TorchServe 裡，註冊後就佈署！

TorchServe 預設 8080 port 用於 inference ; 8081 port 用於管理 TorchServe 如下圖：

![TorchServe](https://cdn-images-1.medium.com/max/800/1*HyvdEPTr16G-FCxPOlP7qQ.png)

[**舉例：以官方 densenet161 Example 為例**](https://github.com/pytorch/serve)

1. 開始之前必須先安裝 **TorchServe**、**torch-model-archiver，**&#x4E00;個是用來跑 TorchServe 服務的，另一個是用來壓縮 Trained Model、Inference handler 、model Handler 的套件。
2. 使用 **torch-model-archiver** 進行壓縮，會得到[densenet161](http://127.0.0.1:8080/predictions/densenet161).mar檔案，
3. 最後將該檔案註冊進去 TorchServe 就可以使用了。

指令如下：

```bash
pip install torchserve torch-model-archiver       # 安裝必要套件
git clone https://github.com/pytorch/serve.git    # clone example
cd serve/examples/image_classifier/               # 進入image_classifier example
cp index_to_name.json densenet_161/               # 
cd densenet_161/
 # 若無預設輸出資料夾，則創建一個
if [ ! -d "model-store" ]; then                   
    echo "creates new folder: " $export_path
    mkdir $export_path
fi
#下載trained model
wget https://download.pytorch.org/models/densenet161-8d451a50.pth
#壓縮densenet161範例 -> densenet161.mar
torch-model-archiver --model-name densenet161 --version 1.0 --model-file model.py \
                    --serialized-file densenet161-8d451a50.pth --handler image_classifier \
                    --extra-files index_to_name.json --export-path="model-store" 
torchserve --start --model-store model-store/ --models densenet161.mar  # 註冊densenet1611並啟動torchserve
```

可以使用 curl 進行驗證是否抓到 [densenet161](http://127.0.0.1:8080/predictions/densenet161) model，並試著傳一張圖看看是否有成功運行。

```
curl 127.0.0.1:8081/models
curl http://127.0.0.1:8080/predictions/densenet161 -T kitten.jpg
```

![img](https://cdn-images-1.medium.com/max/800/1*eRXtMN-zFSLrcUew9JZe_g.png)

#### **Debug 經驗談**

TorchServe 是一個非常新的部署工具，debug 不知道如何 debug，用起來真的很崩潰。其實一開始壓縮的 .mar 檔，TorchServe 抓到之後會將其解壓縮至 /tmp 中。

![img](https://cdn-images-1.medium.com/max/800/1*uubZ3uHv4SRGqEXQ7WtFKw.png)

![img](https://cdn-images-1.medium.com/max/800/1*9Qy_s7HLw91_yo0SsE2A0Q.png)

因此當想要進行 debug 的時候，**要切到 /tmp 資料夾中使用 python3 指令執行**，如果沒問題，理論上 TorchServe 就能夠成功運作。

**常用Management API 介紹** 在這邊分享一些過去部署TorchServe常用用的一些API，首先在註冊的時候會不知道目前到底有沒有抓到Trained model?這時候可以使用**List models API**

```
curl "http://localhost:8081/models"
```

![](https://cdn-images-1.medium.com/max/800/1*i-I6Fn25WH80ae5exdK5mg.png)

此外就是考慮到效能面的話，或許有需要修改某一個model的Worker Process數量這種需求，也可利用PUT對某一個model修改Worker Process的數量。

```
curl -v -X PUT "http://localhost:8081/models/<modelname>?min_worker=3"
```

就已feature\_extractor這個model為例：首先先看一下model的資訊

![](https://cdn-images-1.medium.com/max/800/1*SaA7LEMJ-guXfwoADZwedg.png)

```
# 進行修改之後
curl -v -X PUT “http://localhost:8081/models/feature_extractor?min_worker=3"
```

![](https://cdn-images-1.medium.com/max/800/1*VFxqC8ig2eHIMqA_M6VyYA.png)

**Inference handler撰寫經驗談**： inference handler文件相當的簡潔，在撰寫handler的時候可參考下面程式碼，**大致上每個區塊的function要杜撰什麼都記載註解上**。此外撰寫完，註冊進去TorchServe後**要能夠在/tmp中找到，同時是可直接執行的狀態**，若不是則需要繼續debug。

**Debug有雷請小心**： 1. 輸出只吃JSON格式 2. batch size 大小(如果batch size 為1，JSON List數量只能是1)

```python
class ModelHandler(BaseHandler):

    def __init__(self):
        self._context = None
        self.initialized = False

    # 用於load trained model 的地方，以及其他設定檔
    def initialize(self, context):
        self._context = context
        self.initialized = True
        #  load the model, refer 'custom handler class' above for details

    # 用於predictions的時候，接收http post request的function: 預設接收key為data的資料
    def preprocess(self, data):
        # Take the input data and make it inference ready
        preprocessed_data = data[0].get("data")
        if preprocessed_data is None:
            preprocessed_data = data[0].get("body")

        return preprocessed_data

    # 用來進行運算的function，最後的結果會交由postprocess()後處理
    def inference(self, model_input):

        # Do some inference call to engine here and return output
        model_output = self.model.forward(model_input)
        return model_output

    # 指的是發送post：inference()之後的結果
    def postprocess(self, inference_output):
        postprocess_output = inference_output
        return postprocess_output

    def handle(self, data, context):

        model_input = self.preprocess(data)
        model_output = self.inference(model_input)
        return self.postprocess(model_output)
```

> 1. 雖然預設輸出是JSON，打request進去的資料格式沒有規定喔，可利用像是protocol buffers這種技術進行傳遞是沒有問題的！
> 2. batchsize 修改方法:
>
>    *curl -v -X PUT "*<http://localhost:8081/models/>*?batch\_size="*


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://xiang753017.gitbook.io/zixiang-blog/shi-yong-torchserve-bu-shu-model.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
