TensorRT 6.x.x.x — high-performance inference for deep learning models (Object Detection and Segmentation)

TensorRT 6.x.x.x — high-performance inference for deep learning models (Object Detection and Segmentation)
It only hurts the first time!

Hello everyone! Dear friends, in this article I want to share my experience using TensorRT with RetinaNet based on the repository github.com/aidonchuk/retinanet-examples (this is a fork of the official repo from nvidia, which will allow you to start using optimized models in production in the shortest possible time). While scrolling through messages in the community channels ods.ai, I encounter questions regarding the use of TensorRT, and mostly the questions are repetitive, so I decided to write as complete a guide as possible on using fast inference based on TensorRT, RetinaNet, Unet, and docker.

Task Description

Let's set the task this way: we need to annotate the dataset, train the RetinaNet/Unet network on Pytorch1.3+, convert the obtained weights to ONNX, then convert them to a TensorRT engine, and launch all of this in docker, preferably on Ubuntu 18 and highly preferably on ARM(Jetson)* architecture, thus minimizing manual environment setup. As a result, we will get a container ready not only for export and training of RetinaNet/Unet but also for full-fledged development and training of classification and segmentation with all the necessary bindings.

Step 1. Setting up the environment

It's important to note that lately I have completely moved away from using and deploying any libraries on a desktop machine, as well as on a devbox. The only thing I need to create and install is a python virtual environment and cuda 10.2 (it’s enough to have just the NVIDIA driver) from deb.

Suppose you have a freshly installed Ubuntu 18. Let's install cuda 10.2 (deb), I won’t go into detail about the installation process, the official documentation is quite sufficient.

Now let's install docker, you can easily find the installation guide for docker, here’s an example www.digitalocean.com/community/tutorials/docker-ubuntu-18-04-1-ru, the 19+ version is already available — let’s install it. And don’t forget to enable docker usage without sudo, it will be more convenient. After everything is set up, do the following:

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

And you might not even need to check the official repository github.com/NVIDIA/nvidia-docker.

Now do a git clone github.com/aidonchuk/retinanet-examples.

There's just a little more to do before we can start using Docker with the NVIDIA image. We'll need to register in NGC Cloud and log in. Let's go here ngc.nvidia.com, register, and once we get inside NGC Cloud, click SETUP in the upper left corner of the screen or follow this link ngc.nvidia.com/setup/api-key. Click 'generate key.' I recommend saving it; otherwise, you'll have to generate it again the next time you visit, and consequently, repeat this process when setting up on a new machine.

Let's execute:

docker login nvcr.io
Username: $oauthtoken
Password:  - the generated key

Simply copy the username. Well, that's it, the environment is set up!

Step 2. Building the Docker Container

In the second stage of our work, we will build Docker and familiarize ourselves with its internals.
Let's go to the root folder relative to the retina-examples project and execute

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

We are building Docker while passing in the current user — this is very useful if you will be writing something on a mounted VOLUME with the current user's permissions; otherwise, it will default to root, which is inconvenient.

While Docker is being built, let's take a look at the 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"]

As seen from the text, we take all our favorite libs, compile retinanet, add some basic tools for ease of work with Ubuntu, and set up the openssh server. The first line is indeed about inheriting the NVIDIA image, for which we logged into NGC Cloud and which contains Pytorch1.3, TensorRT6.x.x.x, and a bunch of libs that allow us to compile the cpp sources of our detector.

Stage 3. Running and debugging the docker container

Let's move on to the main use case of the container and the development environment; first, we'll run nvidia docker. Execute:

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

Now the container is available via ssh @localhost. After a successful launch, let's open the project in PyCharm. Next, we open

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

Step 1
TensorRT 6.x.x.x — high-performance inference for deep learning models (Object Detection and Segmentation)

Step 2
TensorRT 6.x.x.x — high-performance inference for deep learning models (Object Detection and Segmentation)

Step 3
TensorRT 6.x.x.x — high-performance inference for deep learning models (Object Detection and Segmentation)

We select everything as shown in the screenshots,

Interpreter -> /opt/conda/bin/python

— this will be a link to Python3.6 and

Sync folder -> /workspace/retinanet

Click finish, wait for indexing, and that's it; the environment is ready for use!

IMPORTANT!!! Immediately after indexing, pull the compiled files for Retinanet from docker. In the context menu at the root of the project, we will choose the option

Deployment->Download

One file and two folders will appear: build, retinanet.egg-info, and _С.so

TensorRT 6.x.x.x — high-performance inference for deep learning models (Object Detection and Segmentation)

If your project looks like this, then the environment sees all the necessary files and we are ready to train RetinaNet.

Stage 4. Annotating data and training the detector

For annotation, I mainly use supervise.ly — a nice and convenient tool, recently a bunch of bugs were fixed and it started to behave significantly better.

Let's assume you have annotated the dataset and downloaded it, but you can’t just shove it into our RetinaNet, as it’s in its own format and we need to convert it to COCO. The conversion tool is located at:

markup_utils/supervisly_to_coco.py

Please note that Category in the script is an example, and you need to insert your own (do not add the background category)

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

The authors of the original repository somehow decided that you wouldn’t be training anything other than COCO/VOC for detection, so I had to edit the source file a bit.

retinanet/dataset.py

By adding our favorite augmentations here albumentations.readthedocs.io/en/latest and cut out the hard-coded categories from COCO. There's also an option to crop large detection areas if you're looking for small objects in large images, have a small dataset =), and nothing works, but that's a topic for another time.

Overall, the train loop is also weak; initially, it didn't save checkpoints and used some terrible scheduler, etc. But now you only need to choose a backbone and execute.

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

with parameters:

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

You will see in the console:

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

To review the entire parameter set, look at

retinanet/main.py

Generally, they are standard for detection and have descriptions. Run the training and wait for the results. An example of inference can be viewed at:

retinanet/infer_example.py

or execute the command:

/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

The repository already includes Focal Loss and several backbones, and it also allows for easy integration of your own.

retinanet/backbones/*.py

In the table, the authors provide some characteristics:

TensorRT 6.x.x.x — high-performance inference for deep learning models (Object Detection and Segmentation)

There is also the ResNeXt50_32x4dFPN and ResNeXt101_32x8dFPN backbone taken from torchvision.
I hope you've figured out detection a bit, but it is essential to read the official documentation to understand the export and logging modes..

Stage 5. Export and inference of Unet models with the Resnet encoder.

As you probably noticed, the libraries for segmentation were installed in the Dockerfile, including a wonderful library github.com/qubvel/segmentation_models.pytorch.The Unet package contains examples of inference and exporting PyTorch checkpoints to the TensorRT engine.

The main issue when exporting Unet-like models from ONNX to TensorRT is the necessity to set a fixed size for Upsample or use 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 formulation
            # 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

Using this transformation, this can be done automatically when exporting to ONNX, but this problem has already been solved in TensorRT version 7, and we just have to wait a little longer.

Conclusion

When I started using Docker, I had doubts about its performance for my tasks. One of my setups currently generates a fairly large network traffic from several cameras.

TensorRT 6.x.x.x — high-performance inference for deep learning models (Object Detection and Segmentation)

Various tests on the internet mentioned a relatively high overhead for network interaction and writing to VOLUME, plus the unknown and scary GIL, and since capturing a frame, working with the driver, and transmitting a frame over the network are atomic operations in hard real-time mode, hard real-time, latency in the network is very critical for me.

But everything worked out well =)

P.S. Don't forget to add your favorite train loop for segmentation and go to production!

Acknowledgments

Thank you to the community ods.ai, without which it's impossible to grow! A huge thanks n01z3, for encouraging me to get involved in DL, for his invaluable advice and extraordinary professionalism!

Use optimized models in production!

TensorRT 6.x.x.x — high-performance inference for deep learning models (Object Detection and Segmentation) Aurorai, llc

Source: habr.com

Buy reliable website hosting with DDoS protection, VPS VDS servers 🔥 Buy reliable website hosting with DDoS protection, VPS VDS servers | ProHoster