Skip to content
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

使用客户端调用时的疑问:预处理后处理 #833

Closed
iceriver97 opened this issue Sep 10, 2020 · 13 comments
Closed

使用客户端调用时的疑问:预处理后处理 #833

iceriver97 opened this issue Sep 10, 2020 · 13 comments
Assignees
Labels
question Further information is requested

Comments

@iceriver97
Copy link

我想确认两个事情:

  1. 对模型输入的预处理与模型输出的后处理,需要自己从原来的脚本中抽离吗?
    下面的客户端代码是通用的吗?如果不是我需要修改什么地方?
from paddle_serving_client import Client
from paddle_serving_app.reader import Sequential, File2Image, Resize, Transpose, BGR2RGB, SegPostprocess
import sys
import cv2
import numpy as np

client = Client()
client.load_client_config("seg_client_conf/serving_client_conf.prototxt")
client.connect(["127.0.0.1:9292"])

preprocess = Sequential(
    [File2Image(), Resize(
        (512, 512), interpolation=cv2.INTER_LINEAR)])

postprocess = SegPostprocess(19)

filename = sys.argv[1]
im = preprocess(filename)

fetch_map = client.predict(feed={"image": im}, fetch=["arg_max_0.tmp_0"])
fetch_map["filename"] = filename
postprocess(fetch_map)
  1. inference_model_to_serving 函数返回的值是不是我在使用 client.predict()时的 feed 与 fetch的值?
@TeslaZhao
Copy link
Collaborator

1.对模型输入的预处理与模型输出的后处理,需要自己从原来的脚本中抽离吗?
如果examples中已有相同模型的预处理和后处理,可以直接复用。如果没有example模型时,需要用户参考examples中的示例,结合模型特征,自己来开发前后处理

@TeslaZhao
Copy link
Collaborator

TeslaZhao commented Sep 11, 2020

下面的客户端代码是通用的吗?如果不是我需要修改什么地方?
例子仅供参考,我简单说明一下。

client 配置

client = Client()
client.load_client_config("seg_client_conf/serving_client_conf.prototxt") # 模型配置文件
client.connect(["127.0.0.1:9292"]) #服务端IP/PORT

前后处理,前处理交给预测前的参数拼装,后处理是预测结果到用户结果的转换,都要根据入参来具体编写。

preprocess = Sequential( #简单图像变换
[File2Image(), Resize(
(512, 512), interpolation=cv2.INTER_LINEAR)])

postprocess = SegPostprocess(19) #使用已有Seg后处理

filename = sys.argv[1]
im = preprocess(filename)

请求服务端预测,预测结果转换

fetch_map = client.predict(feed={"image": im}, fetch=["arg_max_0.tmp_0"])
fetch_map["filename"] = filename
postprocess(fetch_map)

@TeslaZhao
Copy link
Collaborator

2.inference_model_to_serving 函数返回的值是不是我在使用 client.predict()时的 feed 与 fetch的值?

inference_model_to_serving函数做模型转换,转为Paddle Serving的可用的模型文件,生成serving_client_conf.prototxt, serving_server_conf.prototxt。这里包括了feed和fetch的参数格式,需要按此格式拼装feed和fetch结构

参考 文档: https://github.com/PaddlePaddle/Serving/blob/develop/doc/SAVE_CN.md

@TeslaZhao TeslaZhao self-assigned this Sep 11, 2020
@TeslaZhao TeslaZhao added the question Further information is requested label Sep 11, 2020
@iceriver97
Copy link
Author

@TeslaZhao 谢谢,因为模型是使用 Seg套件得到的,Serving是不是覆盖到了Seg呢?覆盖到的话,预处理是不是我只需要调用 paddle_serving_app 中的函数即可?其次,SegPostprocess 中出现了将图像resize到(512,512,1)的操作,而我在调用了 fetch_map = client.predict(feed={"image": im}, fetch=["arg_max_0.tmp_0"])之后得到的 shape 为 (1024,1024,2)所以在resize的时候出了问题,是不是这里 predict得到的结果 shape就是错误的?

@iceriver97
Copy link
Author

iceriver97 commented Sep 11, 2020

2.inference_model_to_serving 函数返回的值是不是我在使用 client.predict()时的 feed 与 fetch的值?

inference_model_to_serving函数做模型转换,转为Paddle Serving的可用的模型文件,生成serving_client_conf.prototxt, serving_server_conf.prototxt。这里包括了feed和fetch的参数格式,需要按此格式拼装feed和fetch结构

参考 文档: https://github.com/PaddlePaddle/Serving/blob/develop/doc/SAVE_CN.md

生成的这些 prototxt 文件该如何打开呢? 我在使用 netron 打开时出现了错误;
错误截图:
image

@TeslaZhao
Copy link
Collaborator

生成的这些 prototxt 文件该如何打开呢? 我在使用 netron 打开时出现了错误;

使用文本打开即可

@bjjwwang
Copy link
Collaborator

gPostprocess 中出现了将图像resize到(512,512,1)的操作,而我在调用了 fetch_map = client.predict(feed={"image": im}, fetch=["arg_max_0.tmp_0"])之后得到的 shape 为 (1024,1024,2)所以在resize的时候出了问题,是不是这里 predict得到的结果 shape就是错误的?

resize是preprocess的操作。 想问下是什么样的模型,预期的输入和输出的shape具体的值应该都是多少

@iceriver97
Copy link
Author

iceriver97 commented Sep 11, 2020

@wangjiawei04 是图像分割的模型,使用PaddleSeg套件得到的,没有自己的代码;这是 SegPostprocess 的部分代码:
image
最后一行就是报错的地方,resize的部分;
刚才我查看了 serving_client_conf.prototxt

feed_var {
  name: "image"
  alias_name: "image"
  is_lod_tensor: false
  feed_type: 1
  shape: 3
  shape: 1024
  shape: 1024
}
fetch_var {
  name: "save_infer_model/scale_0"
  alias_name: "save_infer_model/scale_0"
  is_lod_tensor: false
  fetch_type: 1
  shape: 2
  shape: 1024
  shape: 1024
}

应该预期shape与得到的一致;
是不是我需要修改 SegPostprocess?

@iceriver97
Copy link
Author

@TeslaZhao
在 Seg 的套件中 vis.py 中使用模型进行预测时,模型的输入及模型的输出如下面代码所示:

        print(np.shape(imgs)) #(1, 3, 1024, 1024)
        pred_shape = (imgs.shape[2], imgs.shape[3])
        pred, = exe.run(
            program=test_prog,
            feed={'image': imgs},
            fetch_list=fetch_list,
            return_numpy=True)
        print(np.shape(pred)) # (1, 1024, 1024, 1)

这与 serving_client_conf.prototxt 要fetch_var 的 shape不一致啊,是什么原因呢?

@iceriver97
Copy link
Author

gPostprocess 中出现了将图像resize到(512,512,1)的操作,而我在调用了 fetch_map = client.predict(feed={"image": im}, fetch=["arg_max_0.tmp_0"])之后得到的 shape 为 (1024,1024,2)所以在resize的时候出了问题,是不是这里 predict得到的结果 shape就是错误的?

resize是preprocess的操作。 想问下是什么样的模型,预期的输入和输出的shape具体的值应该都是多少

我还是不太理解SegPostprocess 中reshape(512,512,1)的操作,我得到的mask为(1,2,1024,1024)在经过这一步时会出错,我应该改为什么呢?

@iceriver97
Copy link
Author

@TeslaZhao 我的模型是使用 inference_model_to_serving,将推理模型转化为serving模型的,我发现使用这个函数后,serving_client_conf.prototxt中fetch的name总是固定为:"save_infer_model/scale_0";是不是这里有点问题呢?

@iceriver97
Copy link
Author

@TeslaZhao 经我验证,应该是官方代码的BUG,模型catch到的是未经过argmax的变量,但在SegPostprocess中却没有argmax操作;
出现问题的代码在 paddle_serving_app/reader/image_reader.py:

class SegPostprocess(object):
    def __init__(self, class_num):
        self.class_num = class_num

    def __call__(self, image_with_result):
        if "filename" not in image_with_result:
            raise ("filename should be specified in postprocess")
        img_name = image_with_result["filename"]
        ori_img = cv2.imread(img_name, -1)
        ori_shape = ori_img.shape
        mask = None
        for key in image_with_result:
            if ".lod" in key or "filename" in key:
                continue
            mask = image_with_result[key]
        if mask is None:
            raise ("segment mask should be specified in postprocess")
        mask = mask.astype("uint8")
        print(np.shape(mask))
        #mask_png = mask
        mask_png = mask.reshape((512, 512, 1))
        #score_png = mask_png[:, :, np.newaxis]
        score_png = mask_png
        score_png = np.concatenate([score_png] * 3, axis=2)
        color_map = generate_colormap(self.class_num)
        for i in range(score_png.shape[0]):
            for j in range(score_png.shape[1]):
                score_png[i, j] = color_map[score_png[i, j, 0]]
        ext_pos = img_name.rfind(".")
        img_name_fix = img_name[:ext_pos] + "_" + img_name[ext_pos + 1:]
        mask_save_name = img_name_fix + "_mask.png"
        cv2.imwrite(mask_save_name, mask_png, [cv2.CV_8UC1])
        vis_result_name = img_name_fix + "_result.png"
        result_png = score_png

        result_png = cv2.resize(
            result_png, (ori_shape[1], ori_shape[0]),
            fx=0,
            fy=0,
            interpolation=cv2.INTER_CUBIC)
        cv2.imwrite(vis_result_name, result_png, [cv2.CV_8UC1])

应该改为:

class SegPostprocess(object):
    def __init__(self, class_num):
        self.class_num = class_num

    def __call__(self, image_with_result):
        if "filename" not in image_with_result:
            raise ("filename should be specified in postprocess")
        img_name = image_with_result["filename"]
        ori_img = cv2.imread(img_name, -1)
        ori_shape = ori_img.shape
        mask = None
        for key in image_with_result:
            if ".lod" in key or "filename" in key:
                continue
            mask = image_with_result[key]
        if mask is None:
            raise ("segment mask should be specified in postprocess")
        mask = np.argmax(mask[0], axis=0)
        mask = mask.astype("uint8")
        #print(np.shape(mask))
        mask_png = mask
        #mask_png = mask.reshape((512, 512, 1))
        score_png = mask_png[:, :, np.newaxis]
        score_png = mask_png
        score_png = np.concatenate([score_png] * 3, axis=2)
        color_map = generate_colormap(self.class_num)
        for i in range(score_png.shape[0]):
            for j in range(score_png.shape[1]):
                score_png[i, j] = color_map[score_png[i, j, 0]]
        ext_pos = img_name.rfind(".")
        img_name_fix = img_name[:ext_pos] + "_" + img_name[ext_pos + 1:]
        mask_save_name = img_name_fix + "_mask.png"
        cv2.imwrite(mask_save_name, mask_png, [cv2.CV_8UC1])
        vis_result_name = img_name_fix + "_result.png"
        result_png = score_png

        result_png = cv2.resize(
            result_png, (ori_shape[1], ori_shape[0]),
            fx=0,
            fy=0,
            interpolation=cv2.INTER_CUBIC)
        cv2.imwrite(vis_result_name, result_png, [cv2.CV_8UC1])

@TeslaZhao
Copy link
Collaborator

谢谢你的建议,@iceriver97

@paddle-bot paddle-bot bot closed this as completed Mar 5, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

3 participants