def detect_om(model, img, cfg):
pred_results = []
height,width,_ = img.shape
img, ratio, _ = letterbox(img, new_shape=(640, 640),auto = False)
img = img[:, :, ::-1].transpose(2, 0, 1) # BGR to RGB, to 3x416x416
img = np.ascontiguousarray(img)
#如果是torch张量
img = torch.from_numpy(img)
img = img.half()
#如果是numpy数组
#img = img.astype(np.float16)
img /= 255.0 # 0 - 255 to 0.0 - 1.0
# 确保 img 是四维的
if len(img.shape) == 3:
# 如果是 NumPy 数组
#img = np.expand_dims(img, axis=0)
# 或者如果是 PyTorch 张量,加一维张量,试batch_size为1
img = img.unsqueeze(0)
nb, _, _, _ = img.shape # batch size, channels, height, width
# 注意这里的nb指的是batchsize,以上代码将nb写死默认为1,如果转模型更改了batchsize,要在这里对应更改nb
padding = False
# batch_size = model.get_inputs()[0].shape[0]
# if nb != batch_size:
# img = np.pad(img, ((0, batch_size - nb), (0,0), (0,0),(0,0)), 'constant', constant_values=0)
# padding = True
# else:
img = img.numpy()
# om infer
old_time = time.time()
result = model.infer([img])
#new_time = time.time()
#print("model.infer时间为%.2f" % (new_time - old_time))
if len(result) == 3: # number of output nodes is 3, each shape is (bs, na, no, ny, nx)
out = []
for i in range(len(result)):
anchors = torch.tensor(cfg['anchors'])
stride = torch.tensor(cfg['stride'])
cls_num = cfg['class_num']
if padding == True:
result[i] = result[i][:nb]
correct_bbox(result[i], anchors[i], stride[i], cls_num, out)
box_out = torch.cat(out, 1)
else: # only use the first output node, which shape is (bs, -1, no)
if padding == True:
result[0] = result[0][:nb]
box_out = torch.tensor(result[0])
# non_max_suppression
boxout = nms(box_out, conf_thres=cfg["conf_thres"], iou_thres=cfg["iou_thres"])
for idx, pred in enumerate(boxout):
try:
#scale_coords(img[idx].shape[1:], pred[:, :4], (height, width), (ratio,x)) # native-space pred
scale_coords(img[idx].shape[1:], pred[:, :4], (height, width))
#det[:, :4] = scale_coords(img.shape[2:], det[:, :4], im0.shape).round()
except:
pred = torch.tensor([[0.0, 0.0, 0.0, 0.0, 0.0, 0.0]])
# append to COCO-JSON dictionary
#path = Path(paths[idx])
#image_id = int(path.stem) if path.stem.isnumeric() else path.stem
save_coco_json(pred, pred_results, "111" , coco80_to_coco91_class())
del (img)
torch_npu.npu.empty_cache()
return pred_results
推理函数
def detect_om(model, img, cfg): pred_results = [] height,width,_ = img.shape img, ratio, _ = letterbox(img, new_shape=(640, 640),auto = False) img = img[:, :, ::-1].transpose(2, 0, 1) # BGR to RGB, to 3x416x416 img = np.ascontiguousarray(img) #如果是torch张量 img = torch.from_numpy(img) img = img.half() #如果是numpy数组 #img = img.astype(np.float16) img /= 255.0 # 0 - 255 to 0.0 - 1.0 # 确保 img 是四维的 if len(img.shape) == 3: # 如果是 NumPy 数组 #img = np.expand_dims(img, axis=0) # 或者如果是 PyTorch 张量,加一维张量,试batch_size为1 img = img.unsqueeze(0) nb, _, _, _ = img.shape # batch size, channels, height, width # 注意这里的nb指的是batchsize,以上代码将nb写死默认为1,如果转模型更改了batchsize,要在这里对应更改nb padding = False # batch_size = model.get_inputs()[0].shape[0] # if nb != batch_size: # img = np.pad(img, ((0, batch_size - nb), (0,0), (0,0),(0,0)), 'constant', constant_values=0) # padding = True # else: img = img.numpy() # om infer old_time = time.time() result = model.infer([img]) #new_time = time.time() #print("model.infer时间为%.2f" % (new_time - old_time)) if len(result) == 3: # number of output nodes is 3, each shape is (bs, na, no, ny, nx) out = [] for i in range(len(result)): anchors = torch.tensor(cfg['anchors']) stride = torch.tensor(cfg['stride']) cls_num = cfg['class_num'] if padding == True: result[i] = result[i][:nb] correct_bbox(result[i], anchors[i], stride[i], cls_num, out) box_out = torch.cat(out, 1) else: # only use the first output node, which shape is (bs, -1, no) if padding == True: result[0] = result[0][:nb] box_out = torch.tensor(result[0]) # non_max_suppression boxout = nms(box_out, conf_thres=cfg["conf_thres"], iou_thres=cfg["iou_thres"]) for idx, pred in enumerate(boxout): try: #scale_coords(img[idx].shape[1:], pred[:, :4], (height, width), (ratio,x)) # native-space pred scale_coords(img[idx].shape[1:], pred[:, :4], (height, width)) #det[:, :4] = scale_coords(img.shape[2:], det[:, :4], im0.shape).round() except: pred = torch.tensor([[0.0, 0.0, 0.0, 0.0, 0.0, 0.0]]) # append to COCO-JSON dictionary #path = Path(paths[idx]) #image_id = int(path.stem) if path.stem.isnumeric() else path.stem save_coco_json(pred, pred_results, "111" , coco80_to_coco91_class()) del (img) torch_npu.npu.empty_cache() return pred_resultsdef fireandsmokeDetection_Result_om(image, models,cfg,conf_thres,labelnameDict): result_dict = {} result_dict["data"] = [] #old_time = time.time() pred_results = detect_om(models, image, cfg) #new_time = time.time() #print("detect_om时间为%.2f" % (new_time - old_time)) for i,x in enumerate(pred_results): if x["score"] > conf_thres: result_dict["data"].append({}) bbox = list(map(int, x['bbox'])) # 将左上角点的横坐标和纵坐标改为中间点 #bbox[0] = int(bbox[0] + bbox[2] / 2) #bbox[1] = int(bbox[1] + bbox[3] / 2) result_dict["data"][i]["bbox"] = bbox #print(x["category_id"]) #print(labelnameDict[x["category_id"]]) if x["category_id"] in list(labelnameDict.keys()): result_dict["data"][i]["type"] = str(labelnameDict[x["category_id"]]) result_dict["data"][i]["score"] = float(x["score"]) result_dict["data"][i]["is_alarm"] = 1 result_dict["data"][i]["area_id"] = "" del(pred_results) #torch_npu.npu.empty_cache() return result_dictfastapi接口
if h_model == None: # load custom plugins print("加载烟火om版模型") h_model = InferSession(0, "/home/css/project/runServer/yolov5/weights/fireandsmoke_bs1_cann6.3.RC2.om") #h_model = InferSession(0, "/root/zsh_code/fireandsmoke_om_docker_stream/project/runServer/yolov5/weights/fireandsmoke_bs1_cann6.3.RC2.om")with open("/home/css/project/API/model.yaml") as f: cfg = yaml.load(f, Loader=yaml.FullLoader) #设置标签映射 labelnameDict = {1:"fire", 2: "smoke"} #设置阈值 conf_thres = 0.65class AreaMonitor(BaseModel): area_id: Any = None area: List[List[Any]] =None class Req(BaseModel): timestamp: Any = None seqid: Any = None image: Any = None area_monitor: List[AreaMonitor] = None image_url: Any = Noneapp.add_middleware( CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["POST"], allow_headers=["*"], ) @app.post("/APIService/fireandsmokedetectionService") async def fireandsmokedetectionService(req:Req): #oldold_time = time.time() dic_xml = {} dic_xml['data'] = [] dic_xml["seqid"] = "" statusCode_str, imgdata,inp_dict,statusMessage_str = getAndCheckInputImageData(req) if "seqid" in inp_dict.keys() and inp_dict["seqid"] is not None: dic_xml["seqid"] = inp_dict["seqid"] #logger.info("获取请求时间:" +str(time.time()-t1)) if (statusCode_str != '10000'): dic_xml['code'] = statusCode_str dic_xml['message'] = statusMessage_str json_str = json.dumps(dic_xml, ensure_ascii=False) del(dic_xml) return Response(content=json_str, media_type="application/json;charset=utf-8") try: #start = time.time() #t1 = time.time() try: showimage = jpeg.decode(imgdata) except: img_array = np.fromstring(imgdata, np.uint8) # 转换np序列 showimage = cv2.imdecode(img_array, cv2.COLOR_BGR2RGB) # 转换Opencv格式 dic_xml.update(fireandsmokeDetection_Result_om(showimage, h_model,cfg,conf_thres,labelnameDict)) dic_xml['code'] = statusCode_str #dic_xml['log_id'] = log_id dic_xml['message'] = statusMessage_str imgH, imgW = showimage.shape[0], showimage.shape[1] del showimage # 判断是否在监控区域内 if "area_monitor" in inp_dict.keys() and inp_dict["area_monitor"] is not None: #print("在监控区域内") monitorResult = [] for result in dic_xml["data"]: part_list = [] flag = 0 #print(inp_dict["area_monitor"]) for monitorArea in inp_dict["area_monitor"]: # ROI区域 ROI = np.zeros((imgH, imgW)) monitorPoint = monitorArea["area"] #### ROI = point2area_beta(monitorPoint, ROI) obj = [int(result['bbox'][0]), int(result['bbox'][1]), int(result['bbox'][0] + result['bbox'][2]), int(result['bbox'][1] + result['bbox'][3])] #print(obj) if check_objs_roi(obj, ROI): if 'area_id' in monitorArea.keys(): monitorID = monitorArea['area_id'] #part_list.append(monitorID) result['area_id'] = monitorID if flag == 0: monitorResult.append(result) flag = 1 # break dic_xml["data"] = monitorResult return_str = json.dumps(dic_xml, ensure_ascii=False) del(dic_xml) except Exception: traceback.print_exc() dic_xml['code'] = '10903' dic_xml['message'] = '服务执行失败' #dic_xml['log_id'] = log_id json_str = json.dumps(dic_xml,ensure_ascii=False) del (dic_xml) return Response(content=json_str, media_type="application/json;charset=utf-8") newnew_time = time.time() return Response(content=return_str, media_type="application/json;charset=utf-8")运行脚本
#!/bin/bash source /usr/local/Ascend/ascend-toolkit/set_env.sh export PYTHONPATH="/home/css/project:$PYTHONPATH" export rootSaveFile=/data if [ $max_task_num ]; then max_task_num=$max_task_num else max_task_num=14 fi cd /home/css/project #### nginx #### for i in `seq $max_task_num`; do port=$((6000+i)) sed -i "/upstream detection{/a server localhost:$echo$port;" /home/css/nginx/conf/nginx_home.conf nohup uvicorn API.imageAPIServerForExample:app --host 0.0.0.0 --port $port &>/dev/null & done mkdir -p /usr/share/nginx/logs && mkdir -p /var/log/nginx && mkdir -p /var/lib/nginx/body chown root:root /usr/sbin/nginx && chmod 777 /usr/sbin/nginx /usr/sbin/nginx -c /home/css/nginx/conf/nginx_home.conf netstat -ntulp | grep 5123 cd /home/css/project python deleteImages.py /bin/bash 脚本中挂了nginx代理并开了多进程,nginx日志和python日志全关了使用模型:yolov5-3.1的yolov5m模型结构训练的模型,以batch_size为1转换成了om模型,放入镜像推理
基础镜像使用的是
打包镜像后的容器启动命令为
docker run -d -e max_task_num=15 \
--device=/dev/davinci0 \
--device=/dev/davinci_manager \
--device=/dev/devmm_svm \
--device=/dev/hisi_hdc \
--user root -p 8001:5002 \
hx_fireandsmoke_om_bs1:v1.0
容器启动后用docker stats观测容器内存,并且jmeter长时间压测,发现内存缓慢上涨

测试团队测试的结果是
使用的晟腾推理接口是:
自己写的推理函数是上文的def detect_om(model, img, cfg):
我们的图片流代码在原先的英伟达的A10上也有测试,这次除了推理代码、加载模型的代码、基础镜像进行了改动,其余几乎没有变化,原来的镜像测试内存一直都很稳定,希望华为的老师能协助排查一下,在将推理代码注释掉之后发现内存没有了上涨现象