Modifique la capa de detección de yolov5 para mejorar el rendimiento del servicio de inferencia Triton

En el modo Inferir, la salida de datos de la capa de detección predeterminada de yolov5 es un [batches, 25200, 85]tensor con forma. Si se implementa en Nvidia Triton, el tamaño del tensor de la capa de salida es demasiado grande y el tiempo para procesar la salida será más largo, lo que provocará una acumulación de colas. Especialmente cuando no está en Triton Serverla Clientmisma máquina y no se puede utilizar shared memory, el tiempo para transmitir datos al cliente a través de la red será más largo, lo que afectará el rendimiento del servicio de inferencia. Enlaces de código relacionados


1. Método de prueba

Convierta el modelo al motor tensorrt e impleméntelo en Triton Inference Server. El número de grupo de instancias es 1 y el tipo es GPU. Realice pruebas de rendimiento en otras máquinas a través de la herramienta perf_analyzer proporcionada por Triton.

  • Convertir yolov5s.pt al formato onnx
  • Convertir onnx a motor tensorrt

    /usr/src/tensorrt/bin/trtexec  \
    --onnx=yolov5s.onnx \
    --minShapes=images:1x3x640x640 \
    --optShapes=images:8x3x640x640 \
    --maxShapes=images:32x3x640x640 \
    --workspace=4096 \
    --saveEngine=yolov5s.engine \
    --shapes=images:1x3x640x640 \
    --verbose \
    --fp16 \
    > result-FP16.txt
    
  • Implementado en el servidor de inferencia Triton

    Cargue el modelo en la ruta del repositorio de modelos establecida por el servidor Triton y escriba la configuración del servicio del modelo.

  • Generar datos reales

    python generate_input.py --input_images <image_path> ----output_file <real_data>.json
    
  • Pruebas de rendimiento utilizando datos reales

    perf_analyzer  -m <triton_model_name>  -b 1  --input-data <real_data>.json  --concurrency-range 1:10  --measurement-interval 10000  -u <triton server endpoint> -i gRPC  -f <triton_model_name>.csv
    

2. Indicadores de desempeño antes de la modificación.

El siguiente es el resultado de la prueba de rendimiento del motor yolov5 trt usando la capa de detección predeterminada, implementada en triton. Se puede ver que al usar la capa de detección predeterminada, se consume mucho tiempo en la acumulación de cola () y el procesamiento de datos de salida ( Server Queue) Server Compute Output, y el rendimiento ni siquiera llega a llegar1 infer/sec

Excepto por el rendimiento, las unidades de otros indicadores somos nosotros, donde Client Send y Client Recv son el tiempo para la serialización y deserialización de datos de gRPC, respectivamente.

concurrencia Inferencias/Segundo Envío de cliente Red+Servidor Envío/Recepción Cola del servidor Entrada de cálculo del servidor Inferir cálculo del servidor Salida de cálculo del servidor latencia p90
1 0,7 1683 1517232 466 8003 4412 9311 1592936
2 0,8 1464 1514475 393 10659 4616 956736 2583025
3 0,7 2613 1485868 1013992 7370 4396 1268070 3879331
4 0,7 2268 1463386 2230040 9933 5734 1250245 4983687
5 0,6 2064 1540583 3512025 11057 4843 1226058 6512305
6 0,6 2819 1573869 4802885 10134 4320 1234644 7888080
7 0,5 1664 1507386 6007235 11197 4899 1244482 8854777

Por lo tanto, una solución para la transformación es simplificar la capa de datos, filtrar aproximadamente el bbox según conf antes de enviarlo a nms y, finalmente, hacer referencia al procesamiento de la capa de detección en tensorrtx para transformar la salida en un vector de forma, [batches, num_bboxes, 6]dondenum_bboxes=1000

6 = [cx,cy,w,h,conf,cls_id], enconf = obj_conf * cls_prob


3. Pasos específicos

3.1 repositorio clon ultralítico yolov5

git clone -b v6.1 https://github.com/ultralytics/yolov5.git

3.2 Transformar la capa de detección

Modifique la función directa de detección para

def forward(self, x):
    z = []  # inference output
    for i in range(self.nl):
        x[i] = self.m[i](x[i])  # conv
        bs, _, ny, nx = x[i].shape  # x(bs,255,20,20) to x(bs,3,20,20,85)
        x[i] = x[i].view(bs, self.na, self.no, ny, nx).permute(0, 1, 3, 4, 2).contiguous()

        if not self.training:  # inference
            if self.onnx_dynamic or self.grid[i].shape[2:4] != x[i].shape[2:4]:
                self.grid[i], self.anchor_grid[i] = self._make_grid(nx, ny, i)

            y = x[i].sigmoid()
            if self.inplace:
                y[..., 0:2] = (y[..., 0:2] * 2 - 0.5 + self.grid[i]) * self.stride[i]  # xy
                y[..., 2:4] = (y[..., 2:4] * 2) ** 2 * self.anchor_grid[i]  # wh
            else:  # for YOLOv5 on AWS Inferentia https://github.com/ultralytics/yolov5/pull/2953
                xy = (y[..., 0:2] * 2 - 0.5 + self.grid[i]) * self.stride[i]  # xy
                wh = (y[..., 2:4] * 2) ** 2 * self.anchor_grid[i]  # wh
                y = torch.cat((xy, wh, y[..., 4:]), -1)
            z.append(y.view(bs, -1, self.no))

    # custom output >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    # [bs, 25200, 85]
    origin_output = torch.cat(z, 1)
    output_bboxes_nums = 1000
    # operator argsort to ONNX opset version 12 is not supported.
    # top_conf_index = origin_output[..., 4].argsort(descending=True)[:,:output_bboxes_nums]

    # [bs, 1000]
    top_conf_index =origin_output[..., 4].topk(k=output_bboxes_nums)[1]

    # torch.Size([bs, 1000, 85])
    filter_output = origin_output.gather(1, top_conf_index.unsqueeze(-1).expand(-1, -1, 85))

    filter_output[...,5:] *= filter_output[..., 4].unsqueeze(-1)  # conf = obj_conf * cls_conf
    bboxes =  filter_output[..., :4]
    conf, cls_id = filter_output[..., 5:].max(2, keepdim=True)
    # [bs, 1000, 6]
    filter_output = torch.cat((bboxes, conf, cls_id.float()), 2)

    return x if self.training else filter_output
    # custom output >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    
    # return x if self.training else (torch.cat(z, 1), x)

3.3 Exportar onnx

onnx simplifyCuando, debe comentar el siguiente código ; de lo contrario, el modelo onnx exportado seguirá siendostatic shape

model_onnx, check = onnxsim.simplify(
    model_onnx,
    dynamic_input_shape=dynamic
    # 必须注释
    #input_shapes={'images': list(im.shape)} if dynamic else None
    )

Ejecute python export.py --weight yolov5s.pt --dynamic --simplify --include onnxel modelo export onnx. La estructura onnx exportada es la siguiente:

Insertar descripción de la imagen aquí

3.4 Exportar motor tensorrt

Véase más arriba


4. Rendimiento modificado

  • tamaño del lote = 1

    El rendimiento se ha incrementado más de 25 veces Server Queuey Server Compute Outputel tiempo de suma también se ha reducido significativamente.

    concurrencia Inferencias/Segundo Envío de cliente Red+Servidor Envío/Recepción Cola del servidor Entrada de cálculo del servidor Inferir cálculo del servidor Salida de cálculo del servidor Recepción de cliente latencia p90
    1 11.9 1245 69472 286 7359 5022 340 3 93457
    2 19.2 1376 89804 341 7538 4997 161 3 118114
    3 20.2 1406 131265 1500 8240 4881 500 3 171370
    4 20 1382 180621 2769 9051 5184 496 3 235043
    5 20,5 1362 226046 2404 8112 5068 622 3 286810
    6 20.8 1487 271714 2034 8331 5076 506 3 406248
    7 20.1 1535 328144 2626 8444 5122 405 3 430850
    8 19.9 1512 384690 3511 8168 5018 581 5 465658
    9 20.2 1433 420893 3499 9034 5180 389 3 522285
    10 20,5 1476 469029 3369 8280 5165 442 3 622745
  • tamaño del lote = 8

    En relación con el tamaño del lote = 1, Server Compute Input、Server Compute Infer, Server Compute Outputla velocidad aumenta aproximadamente 1,4 veces, 2 veces y 4 veces respectivamente. El precio es que a medida que aumenta el tamaño del lote, aumenta el tiempo de transmisión de datos.

    concurrencia Inferencias/Segundo Envío de cliente Red+Servidor Envío/Recepción Cola del servidor Entrada de cálculo del servidor Inferir cálculo del servidor Salida de cálculo del servidor Recepción de cliente latencia p90
    1 15.2 11202 527075 360 5386 2488 43 5 570189
    2 18.4 10424 829927 124 5780 2491 33 4 901743
    3 20 10203 1178111 2290 5640 2570 20 4 1267145
    4 20 10097 1595614 4843 5998 2454 104 5 1716309
    5 19.2 9117 1971608 2397 5376 2480 203 4 2518530
    6 20 8728 2338066 2914 6304 2496 96 4 2706257
    7 20 14785 2708292 6581 5556 2489 160 5 3170047
    8 20 13035 3052707 5067 6353 2492 62 4 3235293
    9 17.6 10870 3535601 7037 6307 2480 136 5 3856391
    10 18.4 9357 3953830 8044 5629 2520 64 3 4531638

REFERENCIAS

Supongo que te gusta

Origin blog.csdn.net/weixin_41817841/article/details/127590963
Recomendado
Clasificación