华为云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:continuestrs = str(root).replace(image_root+dir_name+"/", "").split('-')if len(strs) != 2:continuelabel_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 + 1label_list.sort()return all_list, i, label_listif __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))# 拿到总的训练数据txtall_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))# 生成训练集txttrain_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 生成成功!")# 生成验证集txtval_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 生成成功!")# 生成测试集txttest_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: nullpretrained_model: nulloutput_dir: ./output/truck_type/# 使用GPU训练device: gpu# 每几个轮次保存一次save_interval: 1 eval_during_train: True# 每几个轮次验证一次eval_interval: 1 # 训练轮次epochs: 100print_batch_step: 1use_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_staticto_static: False# model architecture
Arch:# 采用的网络name: ShuffleNetV2_x0_25class_num: 5# loss function config for traing/eval process
Loss:Train:- CELoss: weight: 1.0Eval:- CELoss:weight: 1.0Optimizer:name: Momentummomentum: 0.9lr:name: Piecewiselearning_rate: 0.015decay_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: Truechannel_first: False- ResizeImage:resize_short: 256- CropImage:size: 224- RandFlipImage:flip_code: 1- NormalizeImage:scale: 1.0/255.0mean: [0.485, 0.456, 0.406]std: [0.229, 0.224, 0.225]order: ''sampler:name: DistributedBatchSamplerbatch_size: 128drop_last: Falseshuffle: Trueloader:num_workers: 0use_shared_memory: TrueEval:dataset: name: ImageNetDataset# 根路径image_root: /yxdata/truck_type/# 前面自己生产得到的验证集文本路径cls_label_path: /yxdata/truck_type/TruckType/val_list.txt# 数据预处理transform_ops:- DecodeImage:to_rgb: Truechannel_first: False- ResizeImage:resize_short: 256- CropImage:size: 224- NormalizeImage:scale: 1.0/255.0mean: [0.485, 0.456, 0.406]std: [0.229, 0.224, 0.225]order: ''sampler:name: DistributedBatchSamplerbatch_size: 128drop_last: Falseshuffle: Trueloader:num_workers: 0use_shared_memory: TrueInfer:infer_imgs: /yxdata/truck_type/test_01.jpgbatch_size: 10transforms:- DecodeImage:to_rgb: Truechannel_first: False- ResizeImage:resize_short: 256- CropImage:size: 224- NormalizeImage:scale: 1.0/255.0mean: [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.txtMetric: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: falsefeed_type: 1shape: 3shape: 224shape: 224
}
fetch_var {name: "softmax_1.tmp_0"alias_name: "prediction"is_lod_tensor: falsefetch_type: 1shape: 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: 9993dag:#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 xpudevice_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, cv2class 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 = 0with open("truck_type_list.label") as fin:for line in fin:self.label_dict[label_idx] = line.strip()label_idx += 1print("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"] = labelitem["prob"] = max_scoreresult.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_opuci_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 osdef 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
成功运行后,模型预测的结果会打印在客户端中,如下所示:
{'err_no': 0, 'err_msg': '', 'key': ['result'], 'value': ["{'truck_type': [{'label': '载货车', 'prob': 0.98669669032096863}]}"], 'tensors': []}
华为云GPU服务器使用PaddleClas和PaddleServing训练、部署车辆类型分类模型服务相关推荐
- 华为云GPU服务器使用PaddleServing方式部署PaddleClas多个自己训练的识别模型服务
前言 最近公司需要对图片中的不同的货车品牌和车系进行识别,通过PaddleClas进行模型训练后得到一个品牌识别模型和一个车系识别模型,现在对两个模型部署到一台华为云的GPU服务器上,要对多个模型同时 ...
- 华为云GPU服务器部署PaddleOCR中英文识别服务
前言 最近在公司项目中使用到OCR服务,刚开始使用的是百度云上的通用文字识别接口,后来无意中了解到百度开源的飞浆平台的PaddleOCR模块直接有现成的模型可以使用,于是在公司服务器上搭了一个CPU版 ...
- 华为云GPU服务器深度学习环境搭建
Author:ZERO-A-ONE Date:2021-02-26 想了想还是给华为云做一个环境搭建的文档吧,因为某些私人问题 下面是本人购买的服务器的配置,选择的是按需付费: 机型: CPU ...
- 【立即报名】解码AI大杀器:华为云GPU+Tensorflow 容器实战
导语: 人工智能的火热,带来了一波学习TensorFlow深度学习框架的热潮.聊深度学习免不了要用GPU,但目前GPU费用较高,对于个人学习者和创业公司来讲的话,按需配置的云GPU服务器是一个不错的选 ...
- 【深度学习】关于谷歌云GPU服务器创建与使用指南
上一篇介绍了如何使用ssh. [深度学习]谷歌云GPU服务器创建与使用指南(二)_星辰大漠-CSDN博客 本篇主要介绍:在服务器中安装显卡驱动及配置深度学习框架. 服务器与本地主机的区别(待补充) 在 ...
- 创立于使用指南的谷歌云GPU服务器
上一篇介绍了如何使用ssh. [深度学习]谷歌云GPU服务器创建与使用指南(二)_星辰大漠-CSDN博客 本篇主要介绍:在服务器中安装显卡驱动及配置深度学习框架. 服务器与本地主机的区别(待补充) 在 ...
- gpu云服务器运行游戏_在滴滴云 GPU 服务器上使用NVIDIA NGX环境搭建
1.NGX 简介 NVIDIA NGX是一个新的深度学习技术,将基于AI的加速和增强图像.视频处理的功能直接集成到应用程序中.NVIDIA NGX利用Tensor Core最大限度地提高其运行效率,因 ...
- 华为云服务器linux切换账号,华为云Windows服务器如何切换为Linux系统?
目前大多数建站程序都跟 Linux 系统比较契合,效率最高,所以老古一直都建议各位站长想要购买云服务器建站就首选 Linux(CentOS)系统,然后安装一个宝塔 Linux 面板就可以轻松简单管理云 ...
- 台式linux桌面远程链接华为云windows服务器桌面
需求如题: 台式linux桌面远程链接华为云windows服务器桌面 linux(centos)里面安装 remmina软件 sudo yum install remmina 第一步:打开remmin ...
最新文章
- [唐诗]古风(其二十四)-李白
- 使用java.util.LinkedList模拟实现内存页面置换算法--LRU算法
- Mysql (二)Mysql 数据库表增删改查
- docker mysql 防火墙_docker mysql
- 47 -算法 -回文串 -Leetcode 125 - 验证回文串
- 《人月神话》阅读体会(三)
- 9.动态生成实体类,根据XML模板使用Emit生成动态类绑定到DataGrid
- HibernateCRUD基础框架(1)-实体类
- JAVA使用JEP进行动态公式计算
- java聊天室系统用例图_java聊天室的设计与实现.ppt
- 【Opencv卸载与重装】NVIDIA Xavier NX下,卸载opencv3,重装opencv4
- 下载google code中源码的几个工具
- 【esn】 学习回声状态网络
- 恶意软件Emotet卷土重来滥用.LNK文件进行攻击,你只需要一项技术就能有效保护组织
- python抓取豌豆荚app数据信息
- 又猎一“狐”:一名外逃越南嫌疑人落网中
- [转]MATLAB 主要函数指令表(按功能分类)
- Android开发技巧!Android开发大佬的百度,美团,快手等大厂Offer收割之旅,附超全教程文档
- 大兴公寓的那场火,烧毁了我的所有
- 斗地主棋牌类游戏中的洗牌和发牌算法
热门文章
- C#反射:PropertyInfo、FieldInfo和MemberInfo的区别
- 不参加高考去澳洲学计算机,没有参加高考的高三毕业生可以申请澳洲留学吗?...
- 第三周 AVI文件格式解析
- MATLAB | 如何绘制高端大气的分组矩阵图
- 前端cookie设置及有效时间
- Unity 许可证 激活 License Error 无效
- echarts使用之饼图
- 大学计算机成绩统计表怎么做,成绩统计表.ppt
- DMZ-demilitarized zone 隔离区
- zabbix discovery / zabbix 自动发现