TensorRT 6.xxx - inferência de alto desempenho para modelos de aprendizado profundo (detecção e segmentação de objetos)

imagem
Só dói pela primeira vez!

Olá pessoal! Caros amigos, neste artigo, quero compartilhar minha experiência usando o TensorRT, RetinaNet com base no repositório github.com/aidonchuk/retinanet-examples (este é um garfo da chave na mão oficial da nvidia , que nos permitirá começar a usar modelos otimizados na produção o mais rápido possível). Percorrendo os canais da comunidade ods.ai , me deparo com perguntas sobre o uso do TensorRT, e a maioria das perguntas é repetida, por isso decidi escrever um guia o mais abrangente possível para usar a inferência rápida baseada no TensorRT, RetinaNet, Unet e janela de encaixe.

Descrição da tarefa

Proponho definir a tarefa da seguinte maneira: precisamos marcar o conjunto de dados, treinar a rede RetinaNet / Unet no Pytorch1.3 +, converter os pesos recebidos no ONNX, depois convertê-los no mecanismo TensorRT e executar tudo isso no docker, de preferência no Ubuntu 18 e extremamente de preferência na arquitetura ARM (Jetson) *, minimizando a implantação manual do ambiente. Como resultado, prepararemos um contêiner não apenas para exportação e treinamento do RetinaNet / Unet, mas também para o desenvolvimento e treinamento completos de classificação e segmentação com todas as ligações necessárias.

Etapa 1. Preparação do meio ambiente

É importante notar aqui que recentemente eu abandonei completamente o uso e a implantação de pelo menos algumas bibliotecas na máquina da área de trabalho, bem como no devbox. A única coisa que você precisa criar e instalar é o ambiente virtual python e o cuda 10.2 (você pode restringir-se a um único driver nvidia) do deb.

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

Agora vamos instalar o docker, o guia de instalação do docker pode ser encontrado com facilidade. Aqui está um exemplo www.digitalocean.com/community/tutorials/docker-ubuntu-18-04-1-en , a versão 19+ já está disponível - coloque-o. Bem, não se esqueça de possibilitar o uso do docker sem o sudo, pois será mais conveniente. Depois que tudo acabou, fizemos o seguinte:

distribution=$(. /etc/os-release;echo $ID$VERSION_ID) curl -s -L https://nvidia.imtqy.com/nvidia-docker/gpgkey | sudo apt-key add - curl -s -L https://nvidia.imtqy.com/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 você nem precisa procurar no repositório oficial github.com/NVIDIA/nvidia-docker .

Agora, faça o git clone github.com/aidonchuk/retinanet-examples .

Resta apenas um pouco. Para começar a usar o docker com nvidia-image, precisamos nos registrar no NGC Cloud e fazer login. Vamos aqui para ngc.nvidia.com , registramos e depois de entrar na NGC Cloud, pressione SETUP no canto superior esquerdo da tela ou siga este link ngc.nvidia.com/setup/api-key . Clique em "gerar chave". Eu recomendo salvá-lo, caso contrário, na próxima vez que você o visitar, precisará regenerá-lo e, consequentemente, implantá-lo em um novo carrinho de mão, repita esta operação.

Execute:

 docker login nvcr.io Username: $oauthtoken Password: <Your Key> -   

Nome de usuário apenas copie. Bem, considere, o ambiente está implantado!

Etapa 2. Montagem do contêiner do docker

Na segunda etapa de nosso trabalho, montaremos o docker e nos familiarizaremos com o interior.
Vamos para a pasta raiz relativa ao projeto retina-examples e execute

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

Coletamos o docker jogando o usuário atual nele - isso é muito útil se você escrever algo em um VOLUME montado com os direitos do usuário atual, caso contrário, haverá raiz e problemas.

Enquanto o docker estiver em andamento, vamos explorar o 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@session\s*required\s*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 você pode ver no texto, pegamos todos os nossos favoritos, compilamos a retinanet, distribuímos ferramentas básicas para a conveniência de trabalhar com o Ubuntu e configuramos o servidor openssh. A primeira linha é apenas a herança da imagem nvidia, para a qual fizemos um login no NGC Cloud e que contém Pytorch1.3, TensorRT6.xxx e várias bibliotecas que nos permitem compilar o código-fonte cpp para o nosso detector.

Etapa 3. Iniciando e Depurando o Contêiner do Docker

Vamos para o caso principal de usar o contêiner e o ambiente de desenvolvimento, para iniciar, executar o nvidia docker. Execute:

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

Agora o contêiner está disponível em ssh <curr_user_name> @localhost. Após um lançamento bem-sucedido, abra o projeto no PyCharm. Em seguida, abra

 Settings->Project Interpreter->Add->Ssh Interpreter 

Etapa 1
imagem

Etapa 2
imagem

Etapa 3
imagem

Selecionamos tudo como nas capturas de tela,

 Interpreter -> /opt/conda/bin/python 

- isso será em Python3.6 e

 Sync folder -> /workspace/retinanet 

Pressionamos a linha de chegada, esperamos a indexação, e é isso, o ambiente está pronto para uso!

IMPORTANTE !!! Imediatamente após a indexação, extraia os arquivos compilados do Retinanet da janela de encaixe. No menu de contexto na raiz do projeto, selecione

 Deployment->Download 

Um arquivo e duas pastas de construção, retinanet.egg-info e _so, aparecerão

imagem

Se o seu projeto se parecer com isso, o ambiente verá todos os arquivos necessários e estamos prontos para aprender o RetinaNet.

Etapa 4. Marcando os dados e treinando o detector

Para marcação, eu uso principalmente o supervise.ly - uma ferramenta agradável e conveniente, na última vez em que um monte de batentes foi corrigido e ele se tornou muito melhor.

Suponha que você tenha marcado o conjunto de dados e baixado, mas não funcionará imediatamente para colocá-lo em nosso RetinaNet, pois ele está em seu próprio formato e, para isso, precisamos convertê-lo em COCO. A ferramenta de conversão está em:

 markup_utils/supervisly_to_coco.py 

Observe que a categoria no script é um exemplo e você precisa inserir o seu próprio (não é necessário adicionar a categoria de plano de fundo)

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

Por alguma razão, os autores do repositório original decidiram que você não treinaria nada, exceto COCO / VOC para detecção, então tive que modificar levemente o arquivo de origem

 retinanet/dataset.py 

Adicione suas albumentations.readthedocs.io/en/latest aumentos mais recentes favoritas e recorte as categorias costuradas do COCO. Também é possível espalhar grandes áreas de detecção se você estiver procurando objetos pequenos em imagens grandes, tiver um pequeno conjunto de dados =) e nada funcionar, mas mais sobre isso outra vez.

Em geral, o loop do trem também é fraco, inicialmente não salvou pontos de verificação, usou algum agendador terrível, etc. Mas agora tudo o que você precisa fazer é selecionar o backbone e executar

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

com 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 

No console, você verá:

 Initializing model... model: RetinaNet backbone: ResNet18FPN classes: 2, anchors: 9 Selected optimization level O0: Pure FP32 training. Defaults for this optimization level are: 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 Processing user overrides (additional kwargs that are not None)... After processing overrides, optimization options are: 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 Preparing dataset... loader: pytorch resize: [1024, 1280], max: 1280 device: 4 gpus batch: 4, precision: mixed Training model for 20000 iterations... [ 1/20000] focal loss: 0.95619, box loss: 0.51584, 4.042s/4-batch (fw: 0.698s, bw: 0.459s), 1.0 im/s, lr: 0.0001 [ 12/20000] focal loss: 0.76191, box loss: 0.31794, 0.187s/4-batch (fw: 0.055s, bw: 0.133s), 21.4 im/s, lr: 0.0001 [ 24/20000] focal loss: 0.65036, box loss: 0.30269, 0.173s/4-batch (fw: 0.045s, bw: 0.128s), 23.1 im/s, lr: 0.0001 [ 36/20000] focal loss: 0.46425, box loss: 0.23141, 0.178s/4-batch (fw: 0.047s, bw: 0.131s), 22.4 im/s, lr: 0.0001 [ 48/20000] focal loss: 0.45115, box loss: 0.23505, 0.180s/4-batch (fw: 0.047s, bw: 0.133s), 22.2 im/s, lr: 0.0001 [ 59/20000] focal loss: 0.38958, box loss: 0.25373, 0.184s/4-batch (fw: 0.049s, bw: 0.134s), 21.8 im/s, lr: 0.0001 [ 71/20000] focal loss: 0.37733, box loss: 0.23988, 0.174s/4-batch (fw: 0.049s, bw: 0.125s), 22.9 im/s, lr: 0.0001 [ 83/20000] focal loss: 0.39514, box loss: 0.23878, 0.181s/4-batch (fw: 0.048s, bw: 0.133s), 22.1 im/s, lr: 0.0001 [ 94/20000] focal loss: 0.39947, box loss: 0.23817, 0.185s/4-batch (fw: 0.050s, bw: 0.134s), 21.6 im/s, lr: 0.0001 [ 105/20000] focal loss: 0.37343, box loss: 0.20238, 0.182s/4-batch (fw: 0.048s, bw: 0.134s), 22.0 im/s, lr: 0.0001 [ 116/20000] focal loss: 0.19689, box loss: 0.17371, 0.183s/4-batch (fw: 0.050s, bw: 0.132s), 21.8 im/s, lr: 0.0001 [ 128/20000] focal loss: 0.20368, box loss: 0.16538, 0.178s/4-batch (fw: 0.046s, bw: 0.131s), 22.5 im/s, lr: 0.0001 [ 140/20000] focal loss: 0.22763, box loss: 0.15772, 0.176s/4-batch (fw: 0.050s, bw: 0.126s), 22.7 im/s, lr: 0.0001 [ 148/20000] focal loss: 0.21997, box loss: 0.18400, 0.585s/4-batch (fw: 0.047s, bw: 0.144s), 6.8 im/s, lr: 0.0001 Average Precision (AP) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.52674 Average Precision (AP) @[ IoU=0.50 | area= all | maxDets=100 ] = 0.91450 Average Precision (AP) @[ IoU=0.75 | area= all | maxDets=100 ] = 0.35172 Average Precision (AP) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.61881 Average Precision (AP) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = -1.00000 Average Precision (AP) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = -1.00000 Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets= 1 ] = 0.58824 Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets= 10 ] = 0.61765 Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.61765 Average Recall (AR) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.61765 Average Recall (AR) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = -1.00000 Average Recall (AR) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = -1.00000 Saving model: 148 

Para estudar todo o conjunto de parâmetros, consulte

 retinanet/main.py 

Em geral, eles são padrão para detecção e têm uma descrição. Execute o treinamento e aguarde os resultados. Um exemplo de inferência pode ser encontrado 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 

A perda focal e vários backbones já estão embutidos no repositório e seus

 retinanet/backbones/*.py 

Os autores fornecem algumas características na placa de identificação:

imagem

Há também um backbone ResNeXt50_32x4dFPN e ResNeXt101_32x8dFPN, retirado da visão da tocha.
Espero que tenhamos descoberto um pouco a detecção, mas você definitivamente deve ler a documentação oficial para entender os modos de exportação e registro .

Etapa 5. Exportação e inferência de modelos Unet com codificador Resnet

Como você provavelmente notou, as bibliotecas de segmentação foram instaladas no Dockerfile e, em particular, na maravilhosa biblioteca github.com/qubvel/segmentation_models.pytorch . No pacote Yunet, você pode encontrar exemplos de inferência e exportação de pontos de verificação de pytorch no mecanismo TensorRT.

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

 import torch.onnx.symbolic_opset9 as onnx_symbolic def upsample_nearest2d(g, input, output_size): # Currently, TRT 5.1/6.0 ONNX Parser does not support all ONNX ops # needed to support dynamic upsampling ONNX forumlation # Here we hardcode scale=2 as a temporary workaround 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 

Usando essa conversão, você pode fazer isso automaticamente ao exportar para o ONNX, mas já na versão 7 do TensorRT esse problema foi resolvido e tivemos que esperar muito pouco.

Conclusão

Quando comecei a usar o docker, tive dúvidas sobre o desempenho das minhas tarefas. Em uma das minhas unidades, agora há bastante tráfego de rede criado por várias câmeras.

imagem

Vários testes na Internet revelaram uma sobrecarga relativamente grande para interação e gravação de rede em VOLUME, além de um GIL desconhecido e terrível, e desde que fotografar um quadro, a operação do driver e transmitir um quadro pela rede são operações atômicas no modo difícil em tempo real online são muito críticos para mim.

Mas nada aconteceu =)

PS Resta adicionar seu loop de trem favorito para segmentação e produção!

Obrigado

Graças à comunidade ods.ai , é impossível desenvolver sem ele! Muito obrigado a n01z3 , DL, que desejava que eu assumisse a DL, por seus inestimáveis ​​conselhos e extraordinário profissionalismo!

Use modelos otimizados na produção!

Aurorai, llc

Source: https://habr.com/ru/post/pt483074/


All Articles