@TOC
pip install networkx
系统会自动调用/project/ev_sdk/model/convert_openvino.sh
内容写为
#!/bin/bash
# Root directory of the script
#!/bin/bash
# Root directory of the script
python /project/LYXXX/export.py --weights '/project/train/models/exp9/weights/best.pt' --img-size 640 --opset-version 10
# .onnx ==> openvino
chmod 777 /project/LYXXX/yolov5_openvino/run_convert.sh
/project/LYXXX/yolov5_openvino/run_convert.sh # need to change path and img_size here!
其中weights为在线训练产生的权重位置
run_convert.sh内容为
python /opt/intel/openvino/deployment_tools/model_optimizer/mo_onnx.py \
--input_model /project/train/models/exp9/best.onnx \
--output_dir /project/train/models/exp9/weights/ \
--input_shape="[1,3,640,640]" \
--log_level DEBUG --data_type FP16
# --mean_values="[128, 128, 128]" \
# --scale_values="[255, 255, 255]" \
# cd /opt/intel/openvino/deployment_tools/model_optimizer/
需要修改
```python
input_h, input_w, input_c, input_n = (640, 640, 3, 1) # TODO: image size
label_id_map = { # TODO: labels
0: "person_no_clothes",
1: "person_clothes",
}
model_xml = "/project/train/models/exp9/weights/best.xml" # TODO: model xml path
data=non_max_suppression(data, 0.5, 0.5) # conf_thres, iou_thres,
image_dir = '/home/data/130'
detect_objs.append(
{
# TODO: need to change
'xmin': int(xmin),
'ymin': int(ymin),
'xmax': int(xmax),
'ymax': int(ymax),
'name': label_id_map[0],
'confidence': float(confidence)
}python /project/LYXXX/train.py --img 800 --batch 36 --epoch 50 --data /project/LYXXX/data/myvoc.yaml --cfg /project/LYXXX/models/yolov5s.yaml --weights /project/LYXXX/weights/yolov5s.pt --workers 1
)
from __future__ import print_function
import logging as log
import os
import pathlib
import json
import cv2
import numpy as np
from openvino.inference_engine import IENetwork, IECore
import torch
import torchvision
import time
def xywh2xyxy(x):
# Convert nx4 boxes from [x, y, w, h] to [x1, y1, x2, y2] where xy1=top-left, xy2=bottom-right
y = torch.zeros_like(x) if isinstance(x, torch.Tensor) else np.zeros_like(x)
y[:, 0] = x[:, 0] - x[:, 2] / 2 # top left x
y[:, 1] = x[:, 1] - x[:, 3] / 2 # top left y
y[:, 2] = x[:, 0] + x[:, 2] / 2 # bottom right x
y[:, 3] = x[:, 1] + x[:, 3] / 2 # bottom right y
return y
def non_max_suppression(prediction, conf_thres=0.1, iou_thres=0.6, merge=False, classes=None, agnostic=False):
"""Performs Non-Maximum Suppression (NMS) on inference results
Returns:
detections with shape: nx6 (x1, y1, x2, y2, conf, cls)
"""
prediction=torch.from_numpy(prediction)
if prediction.dtype is torch.float16:
prediction = prediction.float() # to FP32
nc = prediction[0].shape[1] - 5 # number of classes
xc = prediction[..., 4] > conf_thres # candidates
# Settings
min_wh, max_wh = 2, 4096 # (pixels) minimum and maximum box width and height
max_det = 300 # maximum number of detections per image
time_limit = 10.0 # seconds to quit after
redundant = True # require redundant detections
multi_label = nc > 1 # multiple labels per box (adds 0.5ms/img)
t = time.time()
output = [None] * prediction.shape[0]
for xi, x in enumerate(prediction): # image index, image inference
# Apply constraints
# x[((x[..., 2:4] < min_wh) | (x[..., 2:4] > max_wh)).any(1), 4] = 0 # width-height
x = x[xc[xi]] # confidence
# If none remain process next image
if not x.shape[0]:
continue
# Compute conf
x[:, 5:] *= x[:, 4:5] # conf = obj_conf * cls_conf
# Box (center x, center y, width, height) to (x1, y1, x2, y2)
box = xywh2xyxy(x[:, :4])
# Detections matrix nx6 (xyxy, conf, cls)
if multi_label:
i, j = (x[:, 5:] > conf_thres).nonzero(as_tuple=False).T
x = torch.cat((box[i], x[i, j + 5, None], j[:, None].float()), 1)
else: # best class only
conf, j = x[:, 5:].max(1, keepdim=True)
x = torch.cat((box, conf, j.float()), 1)[conf.view(-1) > conf_thres]
# Filter by class
if classes:
x = x[(x[:, 5:6] == torch.tensor(classes, device=x.device)).any(1)]
# Apply finite constraint
# if not torch.isfinite(x).all():
# x = x[torch.isfinite(x).all(1)]
# If none remain process next image
n = x.shape[0] # number of boxes
if not n:
continue
# Sort by confidence
# x = x[x[:, 4].argsort(descending=True)]
# Batched NMS
c = x[:, 5:6] * (0 if agnostic else max_wh) # classes
boxes, scores = x[:, :4] + c, x[:, 4] # boxes (offset by class), scores
i = torchvision.ops.boxes.nms(boxes, scores, iou_thres)
if i.shape[0] > max_det: # limit detections
i = i[:max_det]
if merge and (1 < n < 3E3): # Merge NMS (boxes merged using weighted mean)
try: # update boxes as boxes(i,4) = weights(i,n) * boxes(n,4)
iou = box_iou(boxes[i], boxes) > iou_thres # iou matrix
weights = iou * scores[None] # box weights
x[i, :4] = torch.mm(weights, x[:, :4]).float() / weights.sum(1, keepdim=True) # merged boxes
if redundant:
i = i[iou.sum(1) > 1] # require redundancy
except: # possible CUDA error https://github.com/ultralytics/yolov3/issues/1139
print(x, i, x.shape, i.shape)
pass
output[xi] = x[i]
if (time.time() - t) > time_limit:
break # time limit exceeded
return output
device = 'CPU'
input_h, input_w, input_c, input_n = (640, 640, 3, 1) # TODO: image size
log.basicConfig(level=log.DEBUG)
# For objection detection task, replace your target labels here.
label_id_map = { # TODO: labels
0: "person_no_clothes",
1: "person_clothes",
}
exec_net = None
def init():
"""Initialize model
Returns: model
"""
model_xml = "/project/train/models/exp2/weights/best.xml" # TODO: model xml path
#model_xml="/project/LYXXXold/__pycache__/exp2/weights/best.xml"
if not os.path.isfile(model_xml):
log.error(f'{model_xml} does not exist')
return None
model_bin = pathlib.Path(model_xml).with_suffix('.bin').as_posix()
log.info("Loading network files:\n\t{}\n\t{}".format(model_xml, model_bin))
net = IENetwork(model=model_xml, weights=model_bin)
# Load Inference Engine
log.info('Loading Inference Engine')
ie = IECore()
global exec_net
exec_net = ie.load_network(network=net, device_name=device)
log.info('Device info:')
versions = ie.get_versions(device)
print("{}".format(device))
print("MKLDNNPlugin version ......... {}.{}".format(versions[device].major, versions[device].minor))
print("Build ........... {}".format(versions[device].build_number))
input_blob = next(iter(net.inputs))
n, c, h, w = net.inputs[input_blob].shape
global input_h, input_w, input_c, input_n
input_h, input_w, input_c, input_n = h, w, c, n
return net
def process_image(net, input_image,args=None, **kwargs):
"""Do inference to analysis input_image and get output
Attributes:
net: model handle
input_image (numpy.ndarray): image to be process, format: (h, w, c), BGR
thresh: thresh value
Returns: process result
"""
if not net or input_image is None:
#log.error('Invalid input args')
return None
#log.info(f'process_image, ({input_image.shape}')
ih, iw, _ = input_image.shape
# --------------------------- Prepare input blobs -----------------------------------------------------
if ih != input_h or iw != input_w:
# input_image = cv2.resize(input_image, (360, 640))
# input_image=input_image.append(np.zeros_like(280,640))
input_image = cv2.resize(input_image, (input_w, input_h))
input_image = cv2.cvtColor(input_image, cv2.COLOR_BGR2RGB)
input_image = input_image/255
input_image = input_image.transpose((2, 0, 1))
images = np.ndarray(shape=(input_n, input_c, input_h, input_w))
images[0] = input_image
input_blob = next(iter(net.inputs))
out_blob = next(iter(net.outputs))
# --------------------------- Performing inference ----------------------------------------------------
#log.info("Creating infer request and starting inference")
res = exec_net.infer(inputs={input_blob: images})
data = res['output'] # 'output'
data=non_max_suppression(data, 0.3, 0.3) # conf_thres, iou_thres,
detect_objs = []
if data[0]==None:
return json.dumps({"objects": detect_objs})
else:
data=data[0].numpy()
for proposal in data:19.5274 0.4469
#print('proposals (hgx):', proposal) # [-0.06005549 -0.18499237 1.6241994 0.14814436 8.453168 1. ]
#print(proposal[5])
if proposal[4] > 0.3 :
confidence = proposal[4]
xmin = np.int(iw * (proposal[0]/640)) # TODO: 640
ymin = np.int(ih * (proposal[1]/640)) # TODO: 640
xmax = np.int(iw * (proposal[2]/640)) # TODO: 640
ymax = np.int(ih * (proposal[3]/640)) # TODO: 640
detect_objs.append(
{
# TODO: need to change
'xmin': int(xmin),
'ymin': int(ymin),
'xmax': int(xmax),
'ymax': int(ymax),
'name': label_id_map[int(proposal[5])],
'confidence': float(confidence)
}
)
return json.dumps({"objects": detect_objs})
if __name__ == '__main__':
# Test API
print("22222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222")
image_dir = '/home/data/130'
image_names = os.listdir(image_dir)
#image_names="/home/data/130/CARTclothes20200821_10.jpg"
predictor = init()
for image_name in image_names:
#print('image_path:', os.path.join(image_dir, image_name))
img = cv2.imread(os.path.join(image_dir, image_name))
result = process_image(predictor, img)
#log.info(result)
数值为20.2503的fps和0.4604的fscore
0.4,0.3时为19.5473和0.4683
0.5,0.3时为19.683和0.4737
0.5,0.2时为19.8365和0.4703
0.55,0.4时为19.5082和0.4764
0.65,0.4时为19.3546 0.4703
0.65,0.4时修改尺寸为384,640 35.3492 0.5395
尺寸设置应为32的倍数
ji.py
input_h, input_w, input_c, input_n = (2*384, 2*640, 3, 1) # TODO: image size
export.py
parser.add_argument('--img-size', nargs='+', type=int, default=[2*384, 2*640], help='image (height, width)')
run_convert.sh
--input_shape="[1,3,2*384,2*640]" \
在/project/LYXXX/models/yolo.py中将augment修改为True即可。
def forward(self, x, augment=True, profile=False, visualize=False):
if augment:
return self.forward_augment(x) # augmented inference, None
return self.forward_once(x, profile, visualize) # single-scale inference, train
def forward_augment(self, x):
img_size = x.shape[-2:] # height, width
s = [1, 0.83, 0.67] # scales
f = [None, 3, None] # flips (2-ud, 3-lr)
y = [] # outputs
for si, fi in zip(s, f):
xi = scale_img(x.flip(fi) if fi else x, si, gs=int(self.stride.max()))
yi = self.forward_once(xi)[0] # forward
# cv2.imwrite(f'img_{si}.jpg', 255 * xi[0].cpu().numpy().transpose((1, 2, 0))[:, :, ::-1]) # save
yi = self._descale_pred(yi, fi, si, img_size)
y.append(yi)
return torch.cat(y, 1), None # augmented inference, train
image_pre=x=np.ones((1,3,384,640))
image_pre=114*image_pre
def process_image(net, input_image,args=None, **kwargs):
"""Do inference to analysis input_image and get output
Attributes:
net: model handle
input_image (numpy.ndarray): image to be process, format: (h, w, c), BGR
thresh: thresh value
Returns: process result
"""
if not net or input_image is None:
#log.error('Invalid input args')
return None
#log.info(f'process_image, ({input_image.shape}')
ih, iw, _ = input_image.shape
# --------------------------- Prepare input blobs -----------------------------------------------------
if ih != input_h or iw != input_w:
# input_image = cv2.resize(input_image, (360, 640))
input_image = cv2.resize(input_image, (input_w, input_h))
input_image = cv2.cvtColor(input_image, cv2.COLOR_BGR2RGB)
#input_image = input_image/255
input_image = input_image.transpose((2, 0, 1))
images = np.ndarray(shape=(input_n, input_c, input_h, input_w))
images[0] = input_image
image_pre[:,:,:input_h,:input_w] = images
input_blob = next(iter(net.inputs))
out_blob = next(iter(net.outputs))
# --------------------------- Performing inference ----------------------------------------------------
#log.info("Creating infer request and starting inference")
res = exec_net.infer(inputs={input_blob: image_pre})
data = res['output'] # 'output'
data=non_max_suppression(data, 0.65, 0.4) # conf_thres, iou_thres,
detect_objs = []
if data[0]==None:
return json.dumps({"objects": detect_objs})
else:
data=data[0].numpy()
for proposal in data:
#print('proposals (hgx):', proposal) # [-0.06005549 -0.18499237 1.6241994 0.14814436 8.453168 1. ]
#print(proposal[5])
if proposal[4] > 0.65 :
confidence = proposal[4]
xmin = np.int(iw * (proposal[0]/640)) # TODO: 640
ymin = np.int(ih * (proposal[1]/384)) # TODO: 640
xmax = np.int(iw * (proposal[2]/640)) # TODO: 640
ymax = np.int(ih * (proposal[3]/384)) # TODO: 640
detect_objs.append(
{
# TODO: need to change
'xmin': int(xmin),
'ymin': int(ymin),
'xmax': int(xmax),
'ymax': int(ymax),
'name': label_id_map[int(proposal[5])],
'confidence': float(confidence)
}
)
return json.dumps({"objects": detect_objs})
python /project/LYXXX/train.py --img 800 --batch 36 --epoch 50 --data /project/LYXXX/data/myvoc.yaml --cfg /project/LYXXX/models/yolov5s.yaml --weights /project/LYXXX/weights/yolov5s.pt --workers 1
/project/LYXXX/data/hyps/hyp.scratch.yaml
# Hyperparameters for COCO training from scratch
# python train.py --batch 40 --cfg yolov5m.yaml --weights '' --data coco.yaml --img 640 --epochs 300
# See tutorials for hyperparameter evolution https://github.com/ultralytics/yolov5#tutorials
lr0: 0.01 # initial learning rate (SGD=1E-2, Adam=1E-3)
lrf: 0.2 # final OneCycleLR learning rate (lr0 * lrf)
momentum: 0.937 # SGD momentum/Adam beta1
weight_decay: 0.0005 # optimizer weight decay 5e-4
warmup_epochs: 3.0 # warmup epochs (fractions ok)
warmup_momentum: 0.8 # warmup initial momentum
warmup_bias_lr: 0.1 # warmup initial bias lr
box: 0.05 # box loss gain
cls: 0.5 # cls loss gain
cls_pw: 1.0 # cls BCELoss positive_weight
obj: 1.0 # obj loss gain (scale with pixels)
obj_pw: 1.0 # obj BCELoss positive_weight
iou_t: 0.20 # IoU training threshold
anchor_t: 4.0 # anchor-multiple threshold
# anchors: 3 # anchors per output layer (0 to ignore)
fl_gamma: 0.0 # focal loss gamma (efficientDet default gamma=1.5)
hsv_h: 0.015 # image HSV-Hue augmentation (fraction)
hsv_s: 0.7 # image HSV-Saturation augmentation (fraction)
hsv_v: 0.4 # image HSV-Value augmentation (fraction)
degrees: 0.0 # image rotation (+/- deg)
translate: 0.1 # image translation (+/- fraction)
scale: 0.5 # image scale (+/- gain)
shear: 0.0 # image shear (+/- deg)
perspective: 0.0 # image perspective (+/- fraction), range 0-0.001
flipud: 0.0 # image flip up-down (probability)
fliplr: 0.5 # image flip left-right (probability)
mosaic: 1.0 # image mosaic (probability)
mixup: 0.0 # image mixup (probability)
copy_paste: 0.0 # segment copy-paste (probability)
训练结果
all 16434 44977 0.959 0.944 0.984 0.828
person_no_clothes 16434 8554 0.959 0.942 0.981 0.838
person_clothes 16434 36423 0.96 0.947 0.988 0.817
测试结果:
800 800 0.3 0.3 6.8955 0.4586
512 800 0.3 0.3 17.2369 0.5318
512 800 0.5 0.3 17.0393 0.5444
多尺度测试 s = [1, 0.83, 0.67] # scales 512 800 0.5 0.3 5.2076 0.5544
512 800 0.7 0.5 11.5858 0.5446
512 800 0.7 0.3 10.4661 0.5423
512 800 0.9 0.3 17.5817 0.3813
512 800 0.6 0.5 19.0995 0 .5548
512 800 0.65 0.5 19.3433 0.5511
512 800 0.6 0.5 尺度为1.5 6.954 0.5631
512 800 0.6 0.5 尺度为0.5 34.5691 0.4943
448 800 0.6 0.5 尺度为1.0 21.2744 0.5498
896 1600 0.6 0.5 尺度为1.0 3.8012 0.5608
544 960 0.6 0.5 尺度为1.0 12.2599 0.5611
544 960 0.55 0.5 尺度为1.25 6.6271 0.5655
544 960 0.55 0.5 尺度为1.5 4.9359 0.57
512 800 0.55 0.5 尺度为1.5 6.9263 0.5639
512 800 0.55 0.5 尺度为1 FLOAT 18.7135 0.5567
512 800 0.55 0.5 尺度为1.5 FLOAT 6.3225 0.5639
训练id 3948
python /project/LYXXX/train.py --img 640 --batch 16 --epoch 50 --data /project/LYXXX/data/myvoc.yaml --cfg /project/LYXXX/models/yolov5s.yaml --weights /project/LYXXX/weights/yolov5s.pt --workers 1
mosaic: 0.0 # image mosaic (probability)
结果
all 16434 44977 0.897 0.822 0.911 0.713
person_no_clothes 16434 8554 0.883 0.771 0.876 0.708
person_clothes 16434 36423 0.911 0.873 0.945 0.719
测试结果:
0.3,0.3 尺寸640640 19.5274 0.4469
0.3,0.3尺寸480480 29.3796 0.4261
0.3, 0.3 384 640 29.2589 0.5225
训练id 4032
python /project/LYXXX/train.py --img 640 --batch 16 --epoch 50 --data /project/LYXXX/data/myvoc.yaml --cfg /project/LYXXX/models/yolov5s.yaml --weights /project/LYXXX/weights/yolov5s.pt --workers 1
mosaic: 1.0 # image mosaic (probability)
mixup: 0.5 # image mixup (probability)
结果
测试结果:
python /project/LYXXX/train.py --img 960 --batch 32 --epoch 45 --data /project/LYXXX/data/myvoc.yaml --cfg /project/LYXXX/models/yolov5s.yaml --weights /project/LYXXX/weights/yolov5s.pt --workers 1
mosaic: 1.0 # image mosaic (probability)
mixup: 0.0 # image mixup (probability)
训练
python /project/LYXXX/train.py --img 240 --batch 128 --epoch 50 --data /project/LYXXX/data/myvoc.yaml --cfg /project/LYXXX/models/yolov5s.yaml --weights /project/LYXXX/weights/yolov5s.pt --workers 1
all 12873 33867 0.963 0.959 0.972 0.821
person 12873 20570 0.973 0.973 0.989 0.823
bicycle 12873 1300 0.935 0.925 0.937 0.777
e_vehicle 12873 11997 0.982 0.978 0.99 0.86
测试
def export_onnx(model, img, file, opset_version, train, dynamic, simplify):
# ONNX model export
prefix = colorstr('ONNX:')
try:
check_requirements(('onnx', 'onnx-simplifier'))
import onnx
print(f'\n{prefix} starting export with onnx {onnx.__version__}...')
f = file.with_suffix('.onnx')
torch.onnx.export(model, img, f, verbose=False, opset_version=opset_version,
training=torch.onnx.TrainingMode.TRAINING if train else torch.onnx.TrainingMode.EVAL,
do_constant_folding=not train,
input_names=['images'],
output_names=['output'],
# dynamic_axes={'images': {0: 'batch', 2: 'height', 3: 'width'}, # shape(1,3,640,640)
# 'output': {0: 'batch', 1: 'anchors'} # shape(1,25200,85)
dynamic_axes={'images': {0: '1', 2: 'height', 3: 'width'}, # shape(1,3,640,640)
'output': {0: 'batch', 1: 'anchors'} # shape(1,25200,85)
} if dynamic else None)
# Checks
model_onnx = onnx.load(f) # load onnx model
onnx.checker.check_model(model_onnx) # check onnx model
# print(onnx.helper.printable_graph(model_onnx.graph)) # print
训了一半测试
16.8405 0.5248 800 512 0.6 0.5
all 16434 44977 0.931 0.911 0.967 0.79
person_no_clothes 16434 8554 0.921 0.899 0.955 0.793
person_clothes 16434 36423 0.941 0.922 0.978 0.787
0.5 0.5 640 352 19.7877 0.8259
0.55 0.5 640 352 21.2569 0.8262
0.6 0.5 640 352 20.8601 0.8229