华为云GPU服务器使用PaddleClas和PaddleServing训练、部署车辆类型分类模型服务

这篇具有很好参考价值的文章主要介绍了华为云GPU服务器使用PaddleClas和PaddleServing训练、部署车辆类型分类模型服务。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

0 前言

以下针对最近使用PaddleClas和PaddleServing在华为云GPU服务器上训练和部署一个车辆类型识别模型过程进行记录,以供日后自己参考和其他有需要的朋友一些帮助,接触这方面东西时间较短,如有问题欢迎批评指正。

如何在华为云服务器上搭建GPU版本的PaddlePaddle环境请参考以下文章: https://blog.csdn.net/loutengyuan/article/details/126527326

1 环境准备

需要准备PaddleClas的运行环境和Paddle Serving的运行环境。

  • 准备PaddleClas的运行环境链接
# 克隆代码
git clone https://github.com/PaddlePaddle/PaddleClas
  • 安装PaddleServing的运行环境,步骤如下
# 安装serving,用于启动服务
wget https://paddle-serving.bj.bcebos.com/test-dev/whl/paddle_serving_server_gpu-0.8.3.post102-py3-none-any.whl
pip3 install paddle_serving_server_gpu-0.8.3.post102-py3-none-any.whl

# 安装client,用于向服务发送请求
wget https://paddle-serving.bj.bcebos.com/test-dev/whl/paddle_serving_client-0.8.3-cp38-none-any.whl
pip3 install paddle_serving_client-0.8.3-cp38-none-any.whl

# 安装serving-app
wget https://paddle-serving.bj.bcebos.com/test-dev/whl/paddle_serving_app-0.8.3-py3-none-any.whl
pip3 install paddle_serving_app-0.8.3-py3-none-any.whl

2 数据集及其处理

将分类整理好的数据按照不同分类分别放在不同文件夹下,然后将数据上传至华为云服务器,目录结构如下:

# tree ./TruckType
.
├── test_01.jpg
├── TruckType
│   ├── 0-qyc
│   │   ├── 10765.jpg
│   │   ├── 19994.jpg
│   │   ├── 1029.jpg
│   │   ├── 106710.jpg
│   │   ├── 9610.jpg
│   │   ├── 98388.jpg
│   │   └── 9938.jpg
│   ├── 1-zhc
│   │   ├── 10154.jpg
│   │   ├── 1055.jpg
│   │   ├── 10801.jpg
│   │   ├── 9969.jpg
│   │   ├── 9970.jpg
│   │   ├── 9513.jpg
│   │   └── 9515.jpg
│   ├── 2-zxc
│   │   ├── 5274.jpg
│   │   ├── 69648.jpg
│   │   ├── 6649.jpg
│   │   ├── 5651.jpg
│   │   ├── 3055.jpg
│   │   ├── 7630.jpg
│   │   ├── 58.jpg
│   │   └── 9082.jpg
│   ├── 3-gc
│   │   ├── 9587.jpg
│   │   ├── 855.jpg
│   │   ├── 663.jpg
│   │   ├── 5611.jpg
│   │   ├── 9085.jpg
│   │   └── 2284.jpg
│   ├── 4-jbc
│   │   ├── 874.jpg
│   │   ├── 56456.jpg
│   │   ├── 36576.jpg
│   │   └── 25244.jpg
│   ├── all_list.txt
│   ├── label_list.txt
│   ├── test_list.txt
│   ├── train_list.txt
│   └── val_list.txt
└── write_label_truck_type.py

test_01.jpg 用于测试训练模型
0-qyc 、1-zhc 、2-zxc 、3-gc 、4-jbc 分别是不同类型的车辆类型图片(注意:图片文件名最好不要有中文、括号或者空格之类的特殊字符,容易训练报错)
all_list.txt、label_list.txt、test_list.txt、train_list.txt、val_list.txt 分别是处理后生成的标签文件
write_label_truck_type.py 是处理数据的脚步文件,用于自动生成以上标签文件

生成标签文件脚步 write_label_truck_type.py 代码如下:

# -*- coding: utf-8 -*-
import os
import sys
from sklearn.utils import shuffle

# 拿到总的训练数据txt
# -*- coding: utf-8 -*-
# 根据官方paddleclas的提示,我们需要把图像变为两个txt文件
# train_list.txt(训练集)
# val_list.txt(验证集)
# 先把路径搞定 比如:foods/beef_carpaccio/855780.jpg ,读取到并写入txt
# 根据左侧生成的文件夹名字来写根目录
# 先得到总的txt后续再进行划分,因为要划分出验证集,所以要先打乱,因为原本是有序的
def get_all_txt(image_root, dir_name):
    all_list = []
    label_list = []
    i = 0 # 标记总文件数量
    # j = -1 # 标记文件类别
    for root, dirs, files in os.walk(image_root+dir_name): # 分别代表根目录、文件夹、文件
        if "ipynb_checkpoints" in root:
            continue
        strs = str(root).replace(image_root+dir_name+"/", "").split('-')
        if len(strs) != 2:
            continue
        label_idx_str = strs[0].replace(" ", "")
        print("root = {}  label_idx_str = {}".format(root, label_idx_str))
        label_list.append("{} {}\n".format(label_idx_str, strs[1]))
        for file in files:
            i = i + 1
            # 文件中每行格式: 图像相对路径      图像的label_id(数字类别)(注意:中间有空格)。
            img_path = os.path.join(root, file).replace(image_root, "")
            all_list.append(img_path+" " + label_idx_str + "\n")
        # j = j + 1
        label_list.sort()
    return all_list, i, label_list


if __name__ == "__main__":
    if len(sys.argv) < 3:
        print("请传入预处理图像根目录和文件夹: 传入参数长度错误!")
    else:
        # for arg in sys.argv:
        #     print(arg)
        image_root = sys.argv[1]
        dir_name = sys.argv[2]
        print("image_root = {}  dir_name = {}".format(image_root, dir_name))
        # 拿到总的训练数据txt
        all_list, all_len, label_list = get_all_txt(image_root, dir_name)
        print(all_len)
        print(label_list)

        # 写入标签文件
        label_str = ''.join(label_list)
        f = open(image_root+dir_name+'/label_list.txt', 'w', encoding='utf-8')
        f.write(label_str)
        print("写入标签文件完成")

        # 把数据打乱
        all_list = shuffle(all_list)
        allstr = ''.join(all_list)
        f = open(image_root+dir_name+'/all_list.txt', 'w', encoding='utf-8')
        f.write(allstr)
        print("打乱成功,并写入文本")

        # 按照比例划分数据集 食品的数据有5000张图片,不算大数据,一般9:1即可
        train_size = int(all_len * 0.8)
        train_list = all_list[:train_size]
        temp_list = all_list[train_size:]
        val_size = int(len(temp_list) * 0.8)
        val_list = temp_list[:val_size]
        test_list = temp_list[val_size:]

        print(len(train_list))
        print(len(val_list))
        print(len(test_list))

        # 生成训练集txt
        train_txt = ''.join(train_list)
        f_train = open(image_root+dir_name+'/train_list.txt', 'w', encoding='utf-8')
        f_train.write(train_txt)
        f_train.close()
        print("train_list.txt 生成成功!")

        # 生成验证集txt
        val_txt = ''.join(val_list)
        f_val = open(image_root+dir_name+'/val_list.txt', 'w', encoding='utf-8')
        f_val.write(val_txt)
        f_val.close()
        print("val_list.txt 生成成功!")

        # 生成测试集txt
        test_txt = ''.join(test_list)
        f_test = open(image_root+dir_name+'/test_list.txt', 'w', encoding='utf-8')
        f_test.write(test_txt)
        f_test.close()
        print("test_list.txt 生成成功!")

执行脚本:

cd 数据目录
python write_label_truck_type.py ./ TruckType

all_list.txt、test_list.txt、train_list.txt、val_list.txt 内容格式类似如下:

TruckType/1-zhc/495218.jp 1
TruckType/3-gc/543432.jpg 3
TruckType/2-zxc/3453.jpg 2
TruckType/2-zxc/343453.jpg 2
TruckType/3-gc/34545.jpg 3
TruckType/1-zhc/637371.jpg 1
TruckType/0-qyc/32354.jpg 0
TruckType/0-qyc/650456.jpg 0

label_list.txt 格式如下:

0 0-qyc
1 1-zhc
2 2-zxc
3 3-gc
4 4-jbc

3 模型训练

进入之前下载的PaddleClas代码目录

# cd PaddleClas
# ll
total 148
drwxr-xr-x  2 root root  4096 Aug 25 14:52 benchmark
drwxr-xr-x  2 root root  4096 Aug 25 14:52 dataset
drwxr-xr-x 22 root root  4096 Sep  2 11:10 deploy
drwxr-xr-x  6 root root  4096 Aug 25 14:52 docs
-rw-r--r--  1 root root 28095 Aug 25 14:52 hubconf.py
drwxr-xr-x  4 root root  4096 Sep  3 09:32 inference
-rw-r--r--  1 root root   705 Aug 25 14:52 __init__.py
-rw-r--r--  1 root root 11357 Aug 25 14:52 LICENSE
-rw-r--r--  1 root root   259 Aug 25 14:52 MANIFEST.in
drwxr-xr-x  6 root root  4096 Sep  3 08:55 output
-rw-r--r--  1 root root 24463 Aug 25 14:52 paddleclas.py
drwxr-xr-x 12 root root  4096 Aug 31 16:34 ppcls
-rw-r--r--  1 root root  9819 Aug 25 14:52 README_ch.md
-rw-r--r--  1 root root  9149 Aug 25 14:52 README_en.md
-rw-r--r--  1 root root    12 Aug 25 14:52 README.md
-rw-r--r--  1 root root   148 Aug 25 14:52 requirements.txt
-rw-r--r--  1 root root  2343 Aug 25 14:52 setup.py
drwxr-xr-x  3 root root  4096 Aug 25 14:52 tests
drwxr-xr-x  5 root root  4096 Aug 25 14:52 test_tipc
drwxr-xr-x  2 root root  4096 Aug 25 14:52 tools

3.1 修改配置文件

主要是以下几点:分类数、训练和验证的路径、图像尺寸、数据预处理、训练和预测的num_workers: 0
(需要将num_workers改为0,因为是单卡的)
下面以新手快速入门的ShuffleNetV2_x0_25为例子演示,实际上PaddleClas/ppcls/configs/ImageNet/下面的文件夹全都是模型文件,可以自行选用。
路径如下:

PaddleClas/ppcls/configs/quick_start/new_user/ShuffleNetV2_x0_25.yaml

将其拷贝一份出来命名为ShuffleNetV2_x0_25_truck_type.yaml 路径如下:

PaddleClas/ppcls/configs/quick_start/new_user/ShuffleNetV2_x0_25_truck_type.yaml

修改配置文件 ShuffleNetV2_x0_25_truck_type.yaml 如下:

# global configs
Global:
  checkpoints: null
  pretrained_model: null
  output_dir: ./output/truck_type/
  # 使用GPU训练
  device: gpu
  # 每几个轮次保存一次
  save_interval: 1 
  eval_during_train: True
  # 每几个轮次验证一次
  eval_interval: 1 
  # 训练轮次
  epochs: 100
  print_batch_step: 1
  use_visualdl: True #开启可视化(目前平台不可用)
  # used for static mode and model export
  # 图像大小
  image_shape: [3, 224, 224] 
  save_inference_dir: ./inference/clas_truck_type_infer
  # training model under @to_static
  to_static: False

# model architecture
Arch:
  # 采用的网络
  name: ShuffleNetV2_x0_25
  class_num: 5
 
# loss function config for traing/eval process
Loss:
  Train:

    - CELoss: 
        weight: 1.0
  Eval:
    - CELoss:
        weight: 1.0


Optimizer:
  name: Momentum
  momentum: 0.9
  lr:
    name: Piecewise
    learning_rate: 0.015
    decay_epochs: [30, 60, 90]
    values: [0.1, 0.01, 0.001, 0.0001]
  regularizer:
    name: 'L2'
    coeff: 0.0005


# data loader for train and eval
DataLoader:
  Train:
    dataset:
      name: ImageNetDataset
      # 根路径
      image_root: /yxdata/truck_type/
      # 前面自己生产得到的训练集文本路径
      cls_label_path: /yxdata/truck_type/TruckType/train_list.txt
      # 数据预处理
      transform_ops:
        - DecodeImage:
            to_rgb: True
            channel_first: False
        - ResizeImage:
            resize_short: 256
        - CropImage:
            size: 224
        - RandFlipImage:
            flip_code: 1
        - NormalizeImage:
            scale: 1.0/255.0
            mean: [0.485, 0.456, 0.406]
            std: [0.229, 0.224, 0.225]
            order: ''

    sampler:
      name: DistributedBatchSampler
      batch_size: 128
      drop_last: False
      shuffle: True
    loader:
      num_workers: 0
      use_shared_memory: True

  Eval:
    dataset: 
      name: ImageNetDataset
      # 根路径
      image_root: /yxdata/truck_type/
      # 前面自己生产得到的验证集文本路径
      cls_label_path: /yxdata/truck_type/TruckType/val_list.txt
      # 数据预处理
      transform_ops:
        - DecodeImage:
            to_rgb: True
            channel_first: False
        - ResizeImage:
            resize_short: 256
        - CropImage:
            size: 224
        - NormalizeImage:
            scale: 1.0/255.0
            mean: [0.485, 0.456, 0.406]
            std: [0.229, 0.224, 0.225]
            order: ''
    sampler:
      name: DistributedBatchSampler
      batch_size: 128
      drop_last: False
      shuffle: True
    loader:
      num_workers: 0
      use_shared_memory: True

Infer:
  infer_imgs: /yxdata/truck_type/test_01.jpg
  batch_size: 10
  transforms:
    - DecodeImage:
        to_rgb: True
        channel_first: False
    - ResizeImage:
        resize_short: 256
    - CropImage:
        size: 224
    - NormalizeImage:
        scale: 1.0/255.0
        mean: [0.485, 0.456, 0.406]
        std: [0.229, 0.224, 0.225]
        order: ''
    - ToCHWImage:
  PostProcess:
    name: Topk
    # 输出的可能性最高的前topk个
    topk: 3
    # 标签文件 需要自己新建文件
    class_id_map_file: /yxdata/truck_type/TruckType/label_list.txt

Metric:
  Train:
    - TopkAcc:
        topk: [1, 3]
  Eval:
    - TopkAcc:
        topk: [1, 3]

3.2 开始训练

python3 tools/train.py \
    -c ./ppcls/configs/quick_start/new_user/ShuffleNetV2_x0_25_truck_type.yaml \
    -o Global.device=gpu

训练后会在 PaddleClas/output/truck_type/ 目录下生成模型文件

# tree ./truck_type/
├── ShuffleNetV2_x0_25
│   ├── best_model.pdopt
│   ├── best_model.pdparams
│   ├── best_model.pdstates
│   ├── epoch_100.pdopt
│   ├── epoch_100.pdparams
│   ├── epoch_100.pdstates
│   ├── epoch_10.pdopt
│   ├── epoch_10.pdparams
│   ├── epoch_10.pdstates
│   ├── epoch_11.pdopt
│   ├── epoch_11.pdparams
│   ├── epoch_11.pdstates
│   ├── epoch_1.pdopt
│   ├── epoch_1.pdparams
│   ├── epoch_1.pdstates
│   ├── export.log
│   ├── infer.log
│   ├── latest.pdopt
│   ├── latest.pdparams
│   ├── latest.pdstates
│   └── train.log
└── vdl
    └── vdlrecords.1662166534.log

3.3 预测一张

python3 tools/infer.py \
    -c ./ppcls/configs/quick_start/new_user/ShuffleNetV2_x0_25_truck_type.yaml \
    -o Infer.infer_imgs=/yxdata/truck_type/test_01.jpg \
    -o Global.pretrained_model=output/truck_type/ShuffleNetV2_x0_25/best_model

预测结果如下:

[{'class_ids': [4, 0, 1], 'scores': [0.9976, 0.00225, 0.0001], 'file_name': '/yxdata/truck_type/test_01.jpg', 'label_names': ['1-zhc', '3-gc', '2-zxc']}]

3.4 批量预测

python3 tools/infer.py \
    -c ./ppcls/configs/quick_start/new_user/ShuffleNetV2_x0_25_truck_type.yaml \
    -o Infer.infer_imgs=/yxdata/truck_type/ \
    -o Global.pretrained_model=output/truck_type/ShuffleNetV2_x0_25/best_model

预测结果如下:

[{'class_ids': [4, 0, 1], 'scores': [0.9976, 0.00225, 0.0001], 'file_name': '/yxdata/truck_type/test_01.jpg', 'label_names': ['1-zhc', '3-gc', '2-zxc']}]

3.5 导出预测模型

python3 tools/export_model.py \
    -c ppcls/configs/quick_start/new_user/ShuffleNetV2_x0_25_truck_type.yaml \
    -o Global.pretrained_model=output/truck_type/ShuffleNetV2_x0_25/best_model

导出成功后将在 PaddleClas/inference/clas_truck_type_infer/ 目录下生成模型文件,结构如下:

# tree ./clas_truck_type_infer/
├── inference.pdiparams
├── inference.pdiparams.info
└── inference.pdmodel

4 模型服务化部署

4.1 模型转换

进入工作目录:

cd PaddleClas/deploy/

创建并进入models文件夹:

# 创建并进入models文件夹
mkdir models
cd models

将上一步模型训练的最后导出的练好的 inference 模型放到该文件夹下,结构如下:

└── clas_truck_type_infer
    ├── inference.pdiparams
    ├── inference.pdiparams.info
    └── inference.pdmodel

转换车辆类型分类 inference 模型为 Serving 模型:

# 转换车辆类型分类模型
python3.8 -m paddle_serving_client.convert \
--dirname ./clas_truck_type_infer/ \
--model_filename inference.pdmodel  \
--params_filename inference.pdiparams \
--serving_server ./clas_truck_type_serving/ \
--serving_client ./clas_truck_type_client/

车辆类型分类 inference 模型转换完成后,会在当前文件夹多出 clas_truck_type_serving/和 clas_truck_type_client/ 的文件夹,具备如下结构:

    ├── clas_truck_type_serving/
    │   ├── inference.pdiparams
    │   ├── inference.pdmodel
    │   ├── serving_server_conf.prototxt
    │   └── serving_server_conf.stream.prototxt
    └── clas_truck_type_client/
          ├── serving_client_conf.prototxt
          └── serving_client_conf.stream.prototxt

模型参数修改
Serving 为了兼容不同模型的部署,提供了输入输出重命名的功能。让不同的模型在推理部署时,只需要修改配置文件的 alias_name 即可,无需修改代码即可完成推理部署。因此在转换完毕后需要分别修改 clas_truck_type_serving下的文件 serving_server_conf.prototxt 和 clas_truck_type_client 下的文件 serving_client_conf.prototxt,将 fetch_var 中 alias_name: 后的字段改为 prediction,修改后的 serving_server_conf.prototxt 和 serving_client_conf.prototxt 如下所示:

feed_var {
  name: "x"
  alias_name: "x"
  is_lod_tensor: false
  feed_type: 1
  shape: 3
  shape: 224
  shape: 224
}
fetch_var {
  name: "softmax_1.tmp_0"
  alias_name: "prediction"
  is_lod_tensor: false
  fetch_type: 1
  shape: 5
}

上述命令中参数具体含义如下表所示:

参数 类型 默认值 描述
dirname str - 需要转换的模型文件存储路径,Program结构文件和参数文件均保存在此目录。
model_filename str None 存储需要转换的模型Inference Program结构的文件名称。如果设置为None,则使用 __model__ 作为默认的文件名
params_filename str None 存储需要转换的模型所有参数的文件名称。当且仅当所有模型参数被保>存在一个单独的二进制文件中,它才需要被指定。如果模型参数是存储在各自分离的文件中,设置它的值为None
serving_server str "serving_server" 转换后的模型文件和配置文件的存储路径。默认值为serving_server
serving_client str "serving_client" 转换后的客户端配置文件存储路径。默认值为serving_client

4.2 服务部署

进入到工作目录

  cd ./deploy/paddleserving/

paddleserving 目录包含启动 Python Pipeline 服务、C++ Serving 服务和发送预测请求的代码,包括:

__init__.py
classification_web_service.py # 启动pipeline服务端的脚本
config.yml                    # 启动pipeline服务的配置文件
pipeline_http_client.py       # http方式发送pipeline预测请求的脚本
pipeline_rpc_client.py        # rpc方式发送pipeline预测请求的脚本
readme.md                     # 分类模型服务化部署文档
run_cpp_serving.sh            # 启动C++ Serving部署的脚本
test_cpp_serving_client.py    # rpc方式发送C++ serving预测请求的脚本

修改config.yml文件如下:

#worker_num, 最大并发数。当build_dag_each_worker=True时, 框架会创建worker_num个进程,每个进程内构建grpcSever和DAG
##当build_dag_each_worker=False时,框架会设置主线程grpc线程池的max_workers=worker_num
worker_num: 1

#http端口, rpc_port和http_port不允许同时为空。当rpc_port可用且http_port为空时,不自动生成http_port
http_port: 8877
#rpc_port: 9993

dag:
    #op资源类型, True, 为线程模型;False,为进程模型
    is_thread_op: False
op:
    clas_truck_type:
        #并发数,is_thread_op=True时,为线程并发;否则为进程并发
        concurrency: 1

        #当op配置没有server_endpoints时,从local_service_conf读取本地服务配置
        local_service_conf:

            #uci模型路径
            model_config: ../models/clas_truck_type_serving
#            model_config: ../models/ResNet50_vd_serving

            #计算硬件类型: 空缺时由devices决定(CPU/GPU),0=cpu, 1=gpu, 2=tensorRT, 3=arm cpu, 4=kunlun xpu
            device_type: 1

            #计算硬件ID,当devices为""或不写时为CPU预测;当devices为"0", "0,1,2"时为GPU预测,表示使用的GPU卡
            devices: "0" # "0,1"

            #client类型,包括brpc, grpc和local_predictor.local_predictor不启动Serving服务,进程内预测
            client_type: local_predictor

            #Fetch结果列表,以client_config中fetch_var的alias_name为准
            fetch_list: ["prediction"]

修改 classification_web_service.py 文件如下:

# Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import datetime
import sys
from paddle_serving_app.reader import Sequential, URL2Image, Resize, CenterCrop, RGB2BGR, Transpose, Div, Normalize, Base64ToImage
try:
    from paddle_serving_server_gpu.web_service import WebService, Op
except ImportError:
    from paddle_serving_server.web_service import WebService, Op
import logging
import numpy as np
import base64, cv2


class TruckTypeClasOp(Op):
    def init_op(self):
        print("------------------------ TruckTypeClasOp init_op ---------------------------")
        self.seq = Sequential([
            Resize(256), CenterCrop(224), RGB2BGR(), Transpose((2, 0, 1)),
            Div(255), Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225],
                                True)
        ])
        self.label_dict = {}
        label_idx = 0
        with open("truck_type_list.label") as fin:
            for line in fin:
                self.label_dict[label_idx] = line.strip()
                label_idx += 1
        print("label_dict --> {}".format(self.label_dict))

    def preprocess(self, input_dicts, data_id, log_id):
        print("{} TruckTypeClasOp preprocess\tbegin\t--> data_id: {}".format(datetime.datetime.now(), data_id))
        (_, input_dict), = input_dicts.items()
        batch_size = len(input_dict.keys())
        imgs = []
        for key in input_dict.keys():
            data = base64.b64decode(input_dict[key].encode('utf8'))
            data = np.fromstring(data, np.uint8)
            im = cv2.imdecode(data, cv2.IMREAD_COLOR)
            img = self.seq(im)
            imgs.append(img[np.newaxis, :].copy())
        input_imgs = np.concatenate(imgs, axis=0)
        print("{} TruckTypeClasOp preprocess\tfinish\t--> data_id: {}".format(datetime.datetime.now(), data_id))
        # return {"inputs": input_imgs}, False, None, ""
        return {"x": input_imgs}, False, None, ""

    def postprocess(self, input_dicts, fetch_dict, data_id, log_id):
        print("{} TruckTypeClasOp postprocess\tbegin\t--> data_id: {}".format(datetime.datetime.now(), data_id))
        score_list = fetch_dict["prediction"]
        print("{} data_id: {}  -->  score_list: {}".format(datetime.datetime.now(), data_id, score_list))
        result = []
        for score in score_list:
            item = {}
            score = score.tolist()
            max_score = max(score)
            idx = score.index(max_score)
            print("{} data_id: {}  -->  max_score = {}  -->  idx = {}".format(datetime.datetime.now(), data_id, max_score, idx))
            if self.label_dict is not None:
                if idx < len(self.label_dict):
                    label = self.label_dict[score.index(max_score)].strip().replace(",", "")
                else:
                    label = 'ErrorType'
            else:
                label = str(idx)
            item["label"] = label
            item["prob"] = max_score
            result.append(item)
        print("{} TruckTypeClasOp postprocess\tfinish\t--> data_id: {} --> result:{}".format(datetime.datetime.now(), data_id, result))
        return {"result": str({"truck_type": result})}, None, ""


class ClassificationService(WebService):
    def get_pipeline_response(self, read_op):
        truck_type_op = TruckTypeClasOp(name="clas_truck_type", input_ops=[read_op])
        return truck_type_op


uci_service = ClassificationService(name="classification")
uci_service.prepare_pipeline_config("config.yml")
uci_service.run_service()

添加文件 truck_type_list.label ,内容如下:

牵引车
载货车
自卸车
挂车
搅拌车

启动服务:

# 启动服务,运行日志保存在 paddleclas_recognition_log.txt
nohup python3.8 -u classification_web_service.py &>./paddleclas_recognition_log.txt &

查看进程

ps -ef|grep python

关闭进程

# 通过上一步查看进程号,杀死指定进程
kill -9 19913
# 或者通过以下命令
python3.8 -m paddle_serving_server.serve stop

查看日志

tail -f 1000 ./paddleclas_recognition_log.txt

如何查看端口占用

$: netstat -anp | grep 8888
tcp        0      0 127.0.0.1:8888          0.0.0.0:*               LISTEN      13404/python3       
tcp        0      1 172.17.0.10:34036       115.42.35.84:8888       SYN_SENT    14586/python3 

强制杀掉进程:通过pid

$: kill -9 13404
$: kill -9 14586
$: netstat -anp | grep 8888
$:

4.3 服务测试

修改pipeline_http_client.py文件如下:

import requests
import json
import base64
import os


def cv2_to_base64(image):
    return base64.b64encode(image).decode('utf8')


if __name__ == "__main__":
    url = "http://127.0.0.1:8877/classification/prediction"
    with open(os.path.join(".", "图片路径.jpg"), 'rb') as file:
        image_data1 = file.read()
    image = cv2_to_base64(image_data1)

    data = {"key": ["image"], "value": [image]}
    for i in range(1):
        r = requests.post(url=url, data=json.dumps(data))
        print(r.json())

发送请求:

python3.8 pipeline_http_client.py

成功运行后,模型预测的结果会打印在客户端中,如下所示:文章来源地址https://www.toymoban.com/news/detail-637453.html

{'err_no': 0, 'err_msg': '', 'key': ['result'], 'value': ["{'truck_type': [{'label': '载货车', 'prob': 0.98669669032096863}]}"], 'tensors': []}

到了这里,关于华为云GPU服务器使用PaddleClas和PaddleServing训练、部署车辆类型分类模型服务的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • (一)ssh远程连接服务器GPU以及其他GPU使用途径——新手指南

    最近在训练语义分割网络时决定使用GPU,本文记录新手在使用GPU时遇到的一些坑。想要在win10系统上配置GPU运行Pytorch代码可以考虑以下几种方式: 安装cuda,以及GPU版本的pytorch和torchvision,使用电脑自带的GPU进行网络训练; 远程连接实验室的服务器,通过IP、账号以及密码进

    2024年02月08日
    浏览(33)
  • 利用Google Colab免费使用GPU服务器详细攻略

    目录 前言 一、Colab限额、提供的GPU类型 二、Colab的使用步骤(如何使用免费GPU资源) 1、添加Colaboratory 2、新建Colab、连接GPU、挂载Google Driver 3、项目上传文件并运行 三、快速下载/上传Google Drive文件的方法(利用MultiCloud) 四、其他相关技巧 Google Colab是一个基于云端的免费

    2024年02月09日
    浏览(38)
  • 配置使用云服务器训练神经网络模型——在阿里GPU服务器训练yolov5模型

    对于没有GPU训练机的人来讲,使用云服务器训练自己的模型应该最最优选择,只是在训练的时候开个按时计费的服务器,训练完成后保存环境镜像之后,可以完全停掉服务器,期间不产生任何费用,下次再训练时,启动环境就可以,很容易保护好自己的训练环境不受污染。

    2024年02月06日
    浏览(50)
  • 华为云云服务器评测|华为云云耀云服务器L实例使用教学

    作者简介: 辭七七,目前大一,正在学习C/C++,Java,Python等 作者主页: 七七的个人主页 文章收录专栏: 七七的闲谈 欢迎大家点赞 👍 收藏 ⭐ 加关注哦!💖💖 随着云计算技术的快速发展,越来越多的企业开始将自己的业务迁移到云端。作为全球领先的云服务提供商之一

    2024年02月09日
    浏览(44)
  • 英伟达H800服务器安装ubuntu2204及使用gpu-burn压测

    安装Ubuntu 22.04 LTS 镜像:ubuntu-22.04.3-live-server-amd64.iso 可以使用两种方式安装: 通过BMC直接挂载ISO,在BIOS里调整顺序 可通过rufus等usb烧录软件,将ISO烧到USB启动盘中,此种方式安装会更快些。 安装系统时选择默认设置,建议选择server安装模式,建议选择安装docker程序。 更新内

    2024年02月20日
    浏览(41)
  • 华为云云耀云服务器L实例评测|服务器实例基础使用实践

    🦖我是Sam9029,一个前端 Sam9029的CSDN博客主页:Sam9029的博客_CSDN博客-JS学习,CSS学习,Vue-2领域博主 **🐱‍🐉🐱‍🐉恭喜你,若此文你认为写的不错,不要吝啬你的赞扬,求收藏,求评论,求一个大大的赞!👍** 华为云云耀云服务器L实例使用教学 【有奖征文】华为云云服务器

    2024年02月09日
    浏览(56)
  • 使用华为云HECS服务器+nodejs开启web服务

    简介: 在华为云HECS服务器上使用nodejs开启一个web服务。 目录 1.开通华为云服务器 2.远程登录 2.1 使用华为官方的网页工具登录        ​编辑 2.2 使用MobaXterm登录 3 安装node 3.1 下载 2. 配置环境变量 4. 安装express模块 5.开启外网访问         这里我已经开通过了。 2.1 使用华为

    2024年04月17日
    浏览(42)
  • 华为云云耀云服务器L实例评测|使用宝塔面板管理服务器教学

    目录 一、概述 1.1 华为云云耀云服务器L实例 1.2 BT(宝塔) 1.3 资源和成本规划 二、购买云耀云服务器L实例并进行相关配置 2.1 购买云耀云服务器L实例 2.2 设置服务器密码 2.3 配置安全组 2.4 设置Nginx安全级别 三、初始化宝塔面板 3.1 获取密码 3.2 登录宝塔Linux面板 3.3 安装基础

    2024年02月09日
    浏览(39)
  • GPU云服务器使用教程、运行YOLOV5项目并连接到本地VSCode(Pycharm)

    编程如画,我是panda! 之前已经教过大家如何在自己的电脑中配置Pytorch深度学习环境,但是有些小伙伴没有英伟达的GPU,所以用CPU的话训练模型会比较慢,所以这次出一期使用GPU云服务器的教程。 码字不易,如果对各位有帮助,希望点赞收藏加关注哦~ 目录 前言 一、服务器

    2024年01月17日
    浏览(48)
  • 华为云云耀云服务器L实例评测 | 实例使用教学之简单使用:通过 Docker 容器化技术在华为云云耀云服务器快速构建网站

    华为云云耀云服务器L实例评测 | 实例使用教学之简单使用:通过 Docker 容器化技术在华为云云耀云服务器快速构建网站 介绍华为云云耀云服务器 华为云云耀云服务器 (目前已经全新升级为 华为云云耀云服务器L实例) 华为云云耀云服务器是什么 华为云云耀云服务器和上一

    2024年02月07日
    浏览(49)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包