TensorRT 6.x.x.x - inferência de alto desempenho para modelos de aprendizado profundo (Detecção de Objetos e Segmentação).

TensorRT 6.x.x.x - inferência de alto desempenho para modelos de aprendizado profundo (Detecção de Objetos e Segmentação).
Só dói na primeira vez!

Olá a todos! Caros amigos, neste artigo eu quero compartilhar minha experiência com o uso do TensorRT e RetinaNet com base no repositório github.com/aidonchuk/retinanet-examples (este é um fork do repositório oficial de nvidia, que permitirá começar a usar modelos otimizados em produção rapidamente). Ao percorrer as mensagens nos canais da comunidade ods.ai, encontro perguntas sobre o uso do TensorRT, e principalmente as perguntas se repetem, então eu decidi escrever um guia o mais completo possível sobre como realizar inferência rápida usando TensorRT, RetinaNet, Unet e docker.

Descrição da tarefa

Proponho formular a tarefa da seguinte maneira: precisamos anotar o dataset, treinar uma rede RetinaNet/Unet no Pytorch1.3+, converter os pesos obtidos para ONNX, em seguida, convertê-los em engine TensorRT e colocar tudo isso para rodar em um docker, de preferência no Ubuntu 18 e, idealmente, na arquitetura ARM(Jetson)*, minimizando assim a configuração manual do ambiente. No final, teremos um contêiner pronto não apenas para exportar e treinar RetinaNet/Unet, mas também para desenvolver e treinar a classificação e segmentação com toda a infraestrutura necessária.

Etapa 1. Preparação do ambiente

É importante notar que, recentemente, deixei de usar e implantar qualquer biblioteca em uma máquina desktop, assim como em um devbox. A única coisa que preciso criar e instalar é um ambiente virtual python e cuda 10.2 (pode-se limitar a apenas um driver nvidia) a partir de deb.

Suponha que você tenha um Ubuntu 18 recém-instalado. Vamos instalar cuda 10.2(deb), não vou me aprofundar no processo de instalação, a documentação oficial é suficiente.

Agora vamos instalar o docker, um guia para a instalação do docker pode ser facilmente encontrado, aqui está um exemplo www.digitalocean.com/community/tutorials/docker-ubuntu-18-04-1-ru, já está disponível a versão 19+, vamos instalar. E não se esqueça de permitir o uso do docker sem sudo, será mais conveniente. Depois que tudo estiver certo, fazemos assim:

distribution=$(. /etc/os-release; echo $ID$VERSION_ID)
curl -s -L https://nvidia.github.io/nvidia-docker/gpgkey | sudo apt-key add -
curl -s -L https://nvidia.github.io/nvidia-docker/$distribution/nvidia-docker.list | sudo tee /etc/apt/sources.list.d/nvidia-docker.list

sudo apt-get update && sudo apt-get install -y nvidia-container-toolkit
sudo systemctl restart docker

E nem precisamos olhar no repositório oficial github.com/NVIDIA/nvidia-docker.

Agora fazemos git clone github.com/aidonchuk/retinanet-examples.

Está quase na hora de começar a usar o Docker com a imagem da NVIDIA. Precisamos nos registrar no NGC Cloud e fazer login. Vamos para cá ngc.nvidia.com, faça seu registro e, depois de entrar no NGC Cloud, clique em CONFIGURAR no canto superior esquerdo da tela ou acesse este link ngc.nvidia.com/setup/api-key. Clique em "gerar chave". É recomendável salvá-la; do contrário, na próxima vez que visitar, será necessário gerar uma nova e, consequentemente, ao implantar em uma nova máquina, você terá que repetir esta operação.

Vamos executar:

docker login nvcr.io
Username: $oauthtoken
Password:  - chave gerada

Copiamos apenas o nome de usuário. Pronto, a ambiente está configurada!

Etapa 2. Montagem do contêiner Docker

Na segunda etapa do nosso trabalho, iremos montar o Docker e nos familiarizar com seus componentes internos.
Vamos entrar na pasta raiz em relação ao projeto retina-examples e executar

docker build --build-arg USER=$USER --build-arg UID=$UID --build-arg GID=$GID --build-arg PW=alex -t retinanet:latest retinanet/

Estamos montando o Docker passando o usuário atual — é muito útil se você for escrever algo em um VOLUME montado com as permissões do usuário atual; caso contrário, será root e complicado.

Enquanto o Docker está sendo montado, vamos dar uma olhada no Dockerfile:

FROM nvcr.io/nvidia/pytorch:19.10-py3

ARG USER=alex
ARG UID=1000
ARG GID=1000
ARG PW=alex
RUN useradd -m ${USER} --uid=${UID} && echo "${USER}:${PW}" | chpasswd

RUN apt-get -y update && apt-get -y upgrade && apt-get -y install curl && apt-get -y install wget && apt-get -y install git && apt-get -y install automake && apt-get install -y sudo && adduser ${USER} sudo
RUN pip install git+https://github.com/bonlime/pytorch-tools.git@master

COPY . retinanet/
RUN pip install --no-cache-dir -e retinanet/
RUN pip install /workspace/retinanet/extras/tensorrt-6.0.1.5-cp36-none-linux_x86_64.whl
RUN pip install tensorboardx
RUN pip install albumentations
RUN pip install setproctitle
RUN pip install paramiko
RUN pip install flask
RUN pip install mem_top
RUN pip install arrow
RUN pip install pycuda
RUN pip install torchvision
RUN pip install pretrainedmodels
RUN pip install efficientnet-pytorch
RUN pip install git+https://github.com/qubvel/segmentation_models.pytorch
RUN pip install pytorch_toolbelt

RUN chown -R ${USER}:${USER} retinanet/

RUN cd /workspace/retinanet/extras/cppapi && mkdir build && cd build && cmake -DCMAKE_CUDA_FLAGS="--expt-extended-lambda -std=c++14" .. && make && cd /workspace

RUN apt-get install -y openssh-server && apt install -y tmux && apt-get -y install bison flex && apt-cache search pcre && apt-get -y install net-tools && apt-get -y install nmap
RUN apt-get -y install libpcre3 libpcre3-dev && apt-get -y install iputils-ping

RUN mkdir /var/run/sshd
RUN echo 'root:pass' | chpasswd
RUN sed -i 's/PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config
RUN sed 's@sessions*requireds*pam_loginuid.so@session optional pam_loginuid.so@g' -i /etc/pam.d/sshd

ENV NOTVISIBLE "in users profile"
RUN echo "export VISIBLE=now" >> /etc/profile
CMD ["/usr/sbin/sshd", "-D"]

Como pode ser visto no texto, pegamos todas as nossas bibliotecas favoritas, compilamos o retinanet, adicionamos ferramentas básicas para facilitar o trabalho com Ubuntu e configuramos o servidor openssh. A primeira linha é justamente a herança da imagem nvidia, para a qual fizemos login no NGC Cloud e que contém Pytorch1.3, TensorRT6.x.x.x e várias outras bibliotecas que permitem compilar os códigos fonte cpp do nosso detector.

Etapa 3. Execução e depuração do contêiner docker

Vamos ao caso de uso principal do contêiner e do ambiente de desenvolvimento, primeiramente iniciais o nvidia docker. Executamos:

docker run --gpus all --net=host -v /home/:/workspace/mounted_vol -d -P --rm --ipc=host -it retinanet:latest

Agora o contêiner está acessível via ssh @localhost. Após o início bem-sucedido, abra o projeto no PyCharm. Em seguida, abra

Configurações->Intérprete do Projeto->Adicionar->Intérprete Ssh

Passo 1
TensorRT 6.x.x.x - inferência de alto desempenho para modelos de aprendizado profundo (Detecção de Objetos e Segmentação).

Passo 2
TensorRT 6.x.x.x - inferência de alto desempenho para modelos de aprendizado profundo (Detecção de Objetos e Segmentação).

Passo 3
TensorRT 6.x.x.x - inferência de alto desempenho para modelos de aprendizado profundo (Detecção de Objetos e Segmentação).

Escolha tudo como nas capturas de tela,

Intérprete -> /opt/conda/bin/python

--- isso será um link para o Python3.6 e

Pasta de Sincronização -> /workspace/retinanet

Clicamos em concluir, aguardamos a indexação, e pronto, o ambiente está pronto para uso!

IMPORTANTE!!! Imediatamente após a indexação, extrair os arquivos compilados de dentro do docker para o Retinanet. No menu contextual na raiz do projeto, escolheremos a opção

Implantação->Baixar

Um arquivo e duas pastas aparecerão: build, retinanet.egg-info e _С.so

TensorRT 6.x.x.x - inferência de alto desempenho para modelos de aprendizado profundo (Detecção de Objetos e Segmentação).

Se o seu projeto se parecer com isso, então o ambiente vê todos os arquivos necessários e estamos prontos para o treinamento do RetinaNet.

Etapa 4. Rotulando os dados e treinando o detector

Para rotulagem, eu uso principalmente supervise.ly --- uma ferramenta agradável e conveniente, nos últimos tempos corrigiram uma série de bugs e ela começou a se comportar muito melhor.

Suponha que você rotulou o conjunto de dados e o baixou, mas não conseguirá colocar imediatamente no nosso RetinaNet, pois ele está em um formato proprietário e precisamos convertê-lo para COCO. A ferramenta para conversão está em:

markup_utils/supervisly_to_coco.py

Observe que a Categoria no script é um exemplo e você deve inserir suas próprias (não adicione a categoria de fundo)

categories = [{'id': 1, 'name': '1'}, 
                  {'id': 2, 'name': '2'}, 
                  {'id': 3, 'name': '3'},
                  {'id': 4, 'name': '4'}] 

Os autores do repositório original, por algum motivo, decidiram que você não iria treinar nada além de COCO/VOC para detecção, então foi necessário editar um pouco o arquivo original

retinanet/dataset.py

Adicionando aqui as augmentações favoritas albumentations.readthedocs.io/en/latest e remover categorias rigidamente incorporadas do COCO. Também há a possibilidade de recortar grandes áreas de detecção, se você estiver procurando pequenos objetos em imagens grandes, tem um pequeno conjunto de dados =), e nada funciona, mas falaremos mais sobre isso depois.

No geral, o loop de treinamento também é fraco, inicialmente não salvava pontos de verificação, usava algum scheduler horrível, etc. Mas agora você só precisa escolher a backbone e executar.

/opt/conda/bin/python retinanet/main.py

com os parâmetros:

train retinanet_rn34fpn.pth
--backbone ResNet34FPN
--classes 12
--val-iters 10
--images /workspace/mounted_vol/dataset/train/images
--annotations /workspace/mounted_vol/dataset/train_12_class.json
--val-images /workspace/mounted_vol/dataset/test/images_small
--val-annotations /workspace/mounted_vol/dataset/val_10_class_cropped.json
--jitter 256 512
--max-size 512
--batch 32

Você verá no console:

Inicializando modelo...
     modelo: RetinaNet
  backbone: ResNet18FPN
   classes: 2, anchors: 9
Nível de otimização selecionado O0: Treinamento FP32 puro.

Os padrões para este nível de otimização são:
enabled                : True
opt_level              : O0
cast_model_type        : torch.float32
patch_torch_functions  : False
keep_batchnorm_fp32    : None
master_weights         : False
loss_scale             : 1.0
Processando substituições do usuário (kwargs adicionais que não são None)...
Após processar substituições, as opções de otimização são:
enabled                : True
opt_level              : O0
cast_model_type        : torch.float32
patch_torch_functions  : False
keep_batchnorm_fp32    : None
master_weights         : False
loss_scale             : 128.0
Preparando dataset...
    loader: pytorch
    resize: [1024, 1280], max: 1280
    device: 4 gpus
    batch: 4, precision: mixed
Treinando modelo por 20000 iterações...
[    1/20000] perda focal: 0.95619, perda de caixa: 0.51584, 4.042s/4-batch (fw: 0.698s, bw: 0.459s), 1.0 im/s, lr: 0.0001
[   12/20000] perda focal: 0.76191, perda de caixa: 0.31794, 0.187s/4-batch (fw: 0.055s, bw: 0.133s), 21.4 im/s, lr: 0.0001
[   24/20000] perda focal: 0.65036, perda de caixa: 0.30269, 0.173s/4-batch (fw: 0.045s, bw: 0.128s), 23.1 im/s, lr: 0.0001
[   36/20000] perda focal: 0.46425, perda de caixa: 0.23141, 0.178s/4-batch (fw: 0.047s, bw: 0.131s), 22.4 im/s, lr: 0.0001
[   48/20000] perda focal: 0.45115, perda de caixa: 0.23505, 0.180s/4-batch (fw: 0.047s, bw: 0.133s), 22.2 im/s, lr: 0.0001
[   59/20000] perda focal: 0.38958, perda de caixa: 0.25373, 0.184s/4-batch (fw: 0.049s, bw: 0.134s), 21.8 im/s, lr: 0.0001
[   71/20000] perda focal: 0.37733, perda de caixa: 0.23988, 0.174s/4-batch (fw: 0.049s, bw: 0.125s), 22.9 im/s, lr: 0.0001
[   83/20000] perda focal: 0.39514, perda de caixa: 0.23878, 0.181s/4-batch (fw: 0.048s, bw: 0.133s), 22.1 im/s, lr: 0.0001
[   94/20000] perda focal: 0.39947, perda de caixa: 0.23817, 0.185s/4-batch (fw: 0.050s, bw: 0.134s), 21.6 im/s, lr: 0.0001
[  105/20000] perda focal: 0.37343, perda de caixa: 0.20238, 0.182s/4-batch (fw: 0.048s, bw: 0.134s), 22.0 im/s, lr: 0.0001
[  116/20000] perda focal: 0.19689, perda de caixa: 0.17371, 0.183s/4-batch (fw: 0.050s, bw: 0.132s), 21.8 im/s, lr: 0.0001
[  128/20000] perda focal: 0.20368, perda de caixa: 0.16538, 0.178s/4-batch (fw: 0.046s, bw: 0.131s), 22.5 im/s, lr: 0.0001
[  140/20000] perda focal: 0.22763, perda de caixa: 0.15772, 0.176s/4-batch (fw: 0.050s, bw: 0.126s), 22.7 im/s, lr: 0.0001
[  148/20000] perda focal: 0.21997, perda de caixa: 0.18400, 0.585s/4-batch (fw: 0.047s, bw: 0.144s), 6.8 im/s, lr: 0.0001
 Precisão média (AP) @[ IoU=0.50:0.95 | área=   toda | maxDets=100 ] = 0.52674
 Precisão média (AP) @[ IoU=0.50      | área=   toda | maxDets=100 ] = 0.91450
 Precisão média (AP) @[ IoU=0.75      | área=   toda | maxDets=100 ] = 0.35172
 Precisão média (AP) @[ IoU=0.50:0.95 | área= pequena | maxDets=100 ] = 0.61881
 Precisão média (AP) @[ IoU=0.50:0.95 | área=média | maxDets=100 ] = -1.00000
 Precisão média (AP) @[ IoU=0.50:0.95 | área= grande | maxDets=100 ] = -1.00000
 Recall médio (AR) @[ IoU=0.50:0.95 | área=   toda | maxDets=  1 ] = 0.58824
 Recall médio (AR) @[ IoU=0.50:0.95 | área=   toda | maxDets= 10 ] = 0.61765
 Recall médio (AR) @[ IoU=0.50:0.95 | área=   toda | maxDets=100 ] = 0.61765
 Recall médio (AR) @[ IoU=0.50:0.95 | área= pequena | maxDets=100 ] = 0.61765
 Recall médio (AR) @[ IoU=0.50:0.95 | área=média | maxDets=100 ] = -1.00000
 Recall médio (AR) @[ IoU=0.50:0.95 | área= grande | maxDets=100 ] = -1.00000
Salvando modelo: 148

Para estudar todo o conjunto de parâmetros, veja

retinanet/main.py

Em geral, eles são padrões para detecção, e há uma descrição disponível. Execute o treinamento e aguarde os resultados. Um exemplo de inferência pode ser visto em:

retinanet/infer_example.py

ou execute o comando:

/opt/conda/bin/python retinanet/main.py infer retinanet_rn34fpn.pth 
--images /workspace/mounted_vol/dataset/test/images 
--annotations /workspace/mounted_vol/dataset/val.json 
--output result.json 
--resize 256 
--max-size 512 
--batch 32

O repositório já possui Focal Loss e várias backbone integrados, além de permitir a fácil inclusão das suas próprias.

retinanet/backbones/*.py

Na tabela, os autores apresentam algumas características:

TensorRT 6.x.x.x - inferência de alto desempenho para modelos de aprendizado profundo (Detecção de Objetos e Segmentação).

Há também a backbone ResNeXt50_32x4dFPN e ResNeXt101_32x8dFPN, retiradas do torchvision.
Espero que tenhamos conseguido entender a detecção, mas é essencial ler a documentação oficial para compreender os modos de exportação e registro..

Etapa 5. Exportação e Inferência de Modelos Unet com o codificador Resnet.

Como você provavelmente notou, no Dockerfile foram instaladas bibliotecas para segmentação, em particular a biblioteca incrível github.com/qubvel/segmentation_models.pytorch. No pacote Unet, você pode encontrar exemplos de inferência e exportação de checkpoints PyTorch para o engine TensorRT.

O principal problema ao exportar modelos do tipo Unet de ONNX para TensorRT é a necessidade de definir um tamanho fixo para Upsample ou usar ConvTranspose2D:

import torch.onnx.symbolic_opset9 as onnx_symbolic
        def upsample_nearest2d(g, input, output_size):
            # Atualmente, o Parser ONNX do TRT 5.1/6.0 não suporta todas as operações ONNX
            # necessárias para suportar a formulação dinâmica de upsampling
            # Aqui hardcodeamos scale=2 como uma solução temporária
            scales = g.op("Constant", value_t=torch.tensor([1., 1., 2., 2.]))
            return g.op("Upsample", input, scales, mode_s="nearest")

        onnx_symbolic.upsample_nearest2d = upsample_nearest2d

Com essa transformação, é possível fazer isso automaticamente ao exportar para ONNX, mas já na versão 7 do TensorRT esse problema foi resolvido, e nos resta esperar um pouco mais.

Conclusão

Quando comecei a usar Docker, eu tinha dúvidas sobre seu desempenho para minhas tarefas. Em um dos meus agregados, atualmente há um tráfego de rede bastante grande gerado por várias câmeras.

TensorRT 6.x.x.x - inferência de alto desempenho para modelos de aprendizado profundo (Detecção de Objetos e Segmentação).

Vários testes na internet mencionavam um overhead relativamente alto na interação de rede e gravação em VOLUME, e além disso, o misterioso e assustador GIL, já que a captura de quadros, o funcionamento do driver e a transmissão do quadro por rede são operações atômicas em modo de tempo real rígido, os atrasos na rede são muito críticos para mim.

Mas acabou tudo bem =)

P.S. Basta adicionar seu loop de treinamento favorito para segmentação e levar ao produção!

Agradecimentos

Obrigado à comunidade ods.ai, sem a qual é impossível progredir! Um enorme obrigado n01z3, que me inspirou a me dedicar a DL, por seus conselhos inestimáveis e enorme profissionalismo!

Use modelos otimizados em produção!

TensorRT 6.x.x.x - inferência de alto desempenho para modelos de aprendizado profundo (Detecção de Objetos e Segmentação). Aurorai, llc

Fonte: habr.com

Compre hospedagem confiável para sites com proteção contra DDoS, servidores VPS VDS 🔥 Compre hospedagem confiável para sites com proteção contra DDoS, servidores VPS VDS | ProHoster