TensorRT 6.x.x.x — inferenza ad alte prestazioni per modelli di deep learning (Rilevamento oggetti e Segmentazione)

TensorRT 6.x.x.x — inferenza ad alte prestazioni per modelli di deep learning (Rilevamento oggetti e Segmentazione)
Fa male solo la prima volta!

Ciao a tutti! Cari amici, in questo articolo voglio condividere la mia esperienza nell'utilizzo di TensorRT, RetinaNet basato sul repository github.com/aidonchuk/retinanet-examples (questo è un fork del repository ufficiale di nvidia, che consentirà di iniziare a utilizzare modelli ottimizzati in produzione in tempi brevi). Scorrendo i messaggi nei canali della comunità ods.ai, mi imbatto in domande sull'uso di TensorRT, e per lo più le domande si ripetono, quindi ho deciso di scrivere una guida il più completa possibile sull'uso di inferenza rapida basata su TensorRT, RetinaNet, Unet e docker.

Descrizione del compito

Propongo di impostare il compito in questo modo: dobbiamo etichettare il dataset, addestrare la rete RetinaNet/Unet su Pytorch1.3+, convertire i pesi ottenuti in ONNX, poi convertirli in engine TensorRT e avviare tutto ciò in docker, preferibilmente su Ubuntu 18 e molto desiderato su architettura ARM(Jetson)*, minimizzando così il deployment manuale dell'ambiente. In conclusione, otterremo un contenitore pronto non solo per l'esportazione e l'addestramento di RetinaNet/Unet, ma anche per uno sviluppo e un addestramento completo di classificazione, segmentazione, con tutta la necessaria interfaccia.

Fase 1. Preparazione dell'ambiente

Qui è importante notare che negli ultimi tempi ho completamente abbandonato l'uso e il deployment di qualsiasi libreria su una macchina desktop, così come su devbox. L'unica cosa che devo creare e installare è un ambiente virtuale python e cuda 10.2 (si può limitare a un solo driver nvidia) da deb.

Supponiamo che tu abbia Ubuntu 18 appena installato. Installeremo cuda 10.2(deb), non approfondirò il processo di installazione, la documentazione ufficiale è più che sufficiente.

Ora installiamo docker, la guida all'installazione di docker si può facilmente trovare, ecco un esempio www.digitalocean.com/community/tutorials/docker-ubuntu-18-04-1-ru, è già disponibile la versione 19+ — la installiamo. E non dimenticate di permettere l'uso di docker senza sudo, sarà più comodo. Dopo che tutto sarà andato a buon fine, facciamo così:

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 si può anche non guardare nel repository ufficiale github.com/NVIDIA/nvidia-docker.

Ora facciamo un git clone github.com/aidonchuk/retinanet-examples.

Manca davvero poco per iniziare a utilizzare Docker con l'immagine NVIDIA, dobbiamo registrarci su NGC Cloud e fare il login. Andiamo qui ngc.nvidia.com, registriamoci e dopo essere entrati in NGC Cloud, clicchiamo su SETUP nell'angolo in alto a sinistra dello schermo o seguiamo questo link ngc.nvidia.com/setup/api-key. Clicchiamo su "genera chiave". Consiglio di salvarla, altrimenti alla prossima visita dovremo generarla di nuovo e, di conseguenza, ripetere questa operazione su una nuova macchina.

Eseguiamo:

docker login nvcr.io
Username: $oauthtoken
Password:  - chiave generata

Copiamo semplicemente l'Username. Bene, consideriamo l'ambiente avviato!

Fase 2. Creazione del contenitore Docker

Nella seconda fase del nostro lavoro creeremo Docker e ci familiarizzeremo con i suoi internals.
Entriamo nella cartella radice rispetto al progetto retina-examples e eseguiamo

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

Stiamo creando Docker passando l'utente corrente — questo è molto utile se intendete scrivere su un VOLUME montato con i diritti dell'utente corrente, altrimenti sarà root e complicato.

Mentre Docker si sta creando, diamo un'occhiata al 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"]

Come risulta dal testo, prendiamo tutte le nostre librerie preferite, compiliamo retinanet, mettiamo a disposizione strumenti di base per un lavoro più facile con Ubuntu e configuriamo il server openssh. La prima riga riguarda proprio l'eredità dell'immagine nvidia, per la quale abbiamo effettuato il login in NGC Cloud e che contiene Pytorch1.3, TensorRT6.x.x.x e molte altre librerie che permettono di compilare i sorgenti cpp del nostro rilevatore.

Fase 3. Avvio e debug del contenitore docker

Passiamo al caso principale di utilizzo del contenitore e dell'ambiente di sviluppo, iniziamo avviando nvidia docker. Eseguiamo:

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

Ora il contenitore è disponibile via ssh @localhost. Dopo un avvio riuscito, apriamo il progetto in PyCharm. Proseguiamo aprendo

Impostazioni->Interprete Progetto->Aggiungi->Interprete Ssh

Passo 1
TensorRT 6.x.x.x — inferenza ad alte prestazioni per modelli di deep learning (Rilevamento oggetti e Segmentazione)

Passo 2
TensorRT 6.x.x.x — inferenza ad alte prestazioni per modelli di deep learning (Rilevamento oggetti e Segmentazione)

Passo 3
TensorRT 6.x.x.x — inferenza ad alte prestazioni per modelli di deep learning (Rilevamento oggetti e Segmentazione)

Selezioniamo tutto come nelle schermate catturate,

Interprete -> /opt/conda/bin/python

— questo sarà un collegamento a Python3.6 e

Cartella di sincronizzazione -> /workspace/retinanet

Facciamo clic su fine, aspettiamo l'indicizzazione, ed ecco, l'ambiente è pronto per l'uso!

IMPORTANTE!!! Subito dopo l'indicizzazione, estrarre dai file compilati in docker per Retinanet. Nel menu contestuale nella radice del progetto selezioniamo l'opzione

Distribuzione->Scarica

Appariranno un file e due cartelle build, retinanet.egg-info e _C.so

TensorRT 6.x.x.x — inferenza ad alte prestazioni per modelli di deep learning (Rilevamento oggetti e Segmentazione)

Se il tuo progetto appare in questo modo, allora l'ambiente vede tutti i file necessari e siamo pronti per addestrare RetinaNet.

Fase 4. Annotiamo i dati e alleniamo il rilevatore

Per l'annotazione, principalmente utilizzo supervise.ly — una ferramenta piacevole e comoda, negli ultimi tempi sono stati risolti molti problemi e ora funziona in modo significativamente migliore.

Supponiamo che tu abbia annotato il dataset e lo abbia scaricato, ma non possiamo semplicemente inserirlo nel nostro RetinaNet, poiché è nel formato proprietario e per questo dobbiamo convertirlo in COCO. Lo strumento per la conversione si trova in:

markup_utils/supervisly_to_coco.py

Nota che Category nello script è un esempio e devi inserire i tuoi (non aggiungere la categoria background)

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

Gli autori del repository originale hanno deciso che non allenerai nulla oltre a COCO/VOC per la rilevazione, quindi è stato necessario modificare un po' il file sorgente

retinanet/dataset.py

Aggiungendo qui le mie augmentazioni preferite albumentations.readthedocs.io/en/latest e rimuovere rigidamente le categorie integrate in COCO. C'è anche la possibilità di ritagliare grandi aree di rilevamento, se stai cercando piccoli oggetti in immagini grandi, hai un piccolo dataset =), e niente funziona, ma di questo parleremo un'altra volta.

In generale, anche il ciclo di addestramento è piuttosto debole, inizialmente non salvava i checkpoint, utilizzava un dispettoso scheduler e così via. Ma ora non ti resta che scegliere il backbone ed eseguire

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

con i seguenti parametri:

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

Vedrai nel terminale:

Inizializzazione del modello...
     modello: RetinaNet
  backbone: ResNet18FPN
   classi: 2, ancore: 9
Livello di ottimizzazione selezionato O0:  Formazione pura FP32.

I valori predefiniti per questo livello di ottimizzazione sono:
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
Elaborazione delle sovrascritture utente (kwargs aggiuntivi che non sono None)...
Dopo l'elaborazione delle sovrascritture, le opzioni di ottimizzazione sono:
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
Preparazione del dataset...
    loader: pytorch
    resize: [1024, 1280], max: 1280
    device: 4 gpu
    batch: 4, precisione: mista
Formazione del modello per 20000 iterazioni...
[    1/20000] perdita focale: 0.95619, perdita della casella: 0.51584, 4.042s/4-batch (fw: 0.698s, bw: 0.459s), 1.0 im/s, lr: 0.0001
[   12/20000] perdita focale: 0.76191, perdita della casella: 0.31794, 0.187s/4-batch (fw: 0.055s, bw: 0.133s), 21.4 im/s, lr: 0.0001
[   24/20000] perdita focale: 0.65036, perdita della casella: 0.30269, 0.173s/4-batch (fw: 0.045s, bw: 0.128s), 23.1 im/s, lr: 0.0001
[   36/20000] perdita focale: 0.46425, perdita della casella: 0.23141, 0.178s/4-batch (fw: 0.047s, bw: 0.131s), 22.4 im/s, lr: 0.0001
[   48/20000] perdita focale: 0.45115, perdita della casella: 0.23505, 0.180s/4-batch (fw: 0.047s, bw: 0.133s), 22.2 im/s, lr: 0.0001
[   59/20000] perdita focale: 0.38958, perdita della casella: 0.25373, 0.184s/4-batch (fw: 0.049s, bw: 0.134s), 21.8 im/s, lr: 0.0001
[   71/20000] perdita focale: 0.37733, perdita della casella: 0.23988, 0.174s/4-batch (fw: 0.049s, bw: 0.125s), 22.9 im/s, lr: 0.0001
[   83/20000] perdita focale: 0.39514, perdita della casella: 0.23878, 0.181s/4-batch (fw: 0.048s, bw: 0.133s), 22.1 im/s, lr: 0.0001
[   94/20000] perdita focale: 0.39947, perdita della casella: 0.23817, 0.185s/4-batch (fw: 0.050s, bw: 0.134s), 21.6 im/s, lr: 0.0001
[  105/20000] perdita focale: 0.37343, perdita della casella: 0.20238, 0.182s/4-batch (fw: 0.048s, bw: 0.134s), 22.0 im/s, lr: 0.0001
[  116/20000] perdita focale: 0.19689, perdita della casella: 0.17371, 0.183s/4-batch (fw: 0.050s, bw: 0.132s), 21.8 im/s, lr: 0.0001
[  128/20000] perdita focale: 0.20368, perdita della casella: 0.16538, 0.178s/4-batch (fw: 0.046s, bw: 0.131s), 22.5 im/s, lr: 0.0001
[  140/20000] perdita focale: 0.22763, perdita della casella: 0.15772, 0.176s/4-batch (fw: 0.050s, bw: 0.126s), 22.7 im/s, lr: 0.0001
[  148/20000] perdita focale: 0.21997, perdita della casella: 0.18400, 0.585s/4-batch (fw: 0.047s, bw: 0.144s), 6.8 im/s, lr: 0.0001
 Precisione Media (AP) @[ IoU=0.50:0.95 | area=   all | maxDets=100 ] = 0.52674
 Precisione Media (AP) @[ IoU=0.50      | area=   all | maxDets=100 ] = 0.91450
 Precisione Media (AP) @[ IoU=0.75      | area=   all | maxDets=100 ] = 0.35172
 Precisione Media (AP) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.61881
 Precisione Media (AP) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = -1.00000
 Precisione Media (AP) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = -1.00000
 Richiamo Medio     (AR) @[ IoU=0.50:0.95 | area=   all | maxDets=  1 ] = 0.58824
 Richiamo Medio     (AR) @[ IoU=0.50:0.95 | area=   all | maxDets= 10 ] = 0.61765
 Richiamo Medio     (AR) @[ IoU=0.50:0.95 | area=   all | maxDets=100 ] = 0.61765
 Richiamo Medio     (AR) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.61765
 Richiamo Medio     (AR) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = -1.00000
 Richiamo Medio     (AR) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = -1.00000
Salvataggio del modello: 148

Per studiare l'intero set di parametri, guarda

retinanet/main.py

In generale, sono standard per la rilevazione e hanno una descrizione. Avvia l'allenamento e attendi i risultati. Un esempio di inferenza può essere visualizzato in:

retinanet/infer_example.py

o eseguire il 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

Nel repository è già integrato Focal Loss e diversi backbone, e si possono facilmente integrare i propri.

retinanet/backbones/*.py

Nella tabella gli autori forniscono alcune caratteristiche:

TensorRT 6.x.x.x — inferenza ad alte prestazioni per modelli di deep learning (Rilevamento oggetti e Segmentazione)

C'è anche il backbone ResNeXt50_32x4dFPN e ResNeXt101_32x8dFPN, preso da torchvision.
Spero che con la detezione siamo riusciti a chiarire, ma è necessario leggere assolutamente la documentazione ufficiale per capire le modalità di esportazione e registrazione..

Fase 5. Esportazione e inferenza dei modelli Unet con l'encoder Resnet.

Come avrete notato, nel Dockerfile sono state installate librerie per la segmentazione, e in particolare la fantastica libreria github.com/qubvel/segmentation_models.pytorch.Nel pacchetto Unet puoi trovare esempi di inferenza e esportazione dei checkpoint pytorch in engine TensorRT.

Il problema principale durante l'esportazione di modelli simili a Unet da ONNX a TensorRT è la necessità di definire una dimensione fissa per l'Upsample o di utilizzare ConvTranspose2D:

import torch.onnx.symbolic_opset9 as onnx_symbolic
        def upsample_nearest2d(g, input, output_size):
            # Attualmente, il parser ONNX di TRT 5.1/6.0 non supporta tutte le operazioni ONNX
            # necessarie per supportare l'upsampling dinamico nella formulazione ONNX
            # Qui hardcodiamo scale=2 come soluzione temporanea
            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

Con questa trasformazione è possibile farlo automaticamente durante l'esportazione in ONNX, ma già nella settima versione di TensorRT questo problema è stato risolto, e non ci resta che aspettare molto poco.

Conclusione

Quando ho iniziato a usare Docker, avevo dei dubbi riguardo alle sue performance per i miei compiti. In uno dei miei aggregati, ora c'è un traffico di rete abbastanza elevato generato da diverse telecamere.

TensorRT 6.x.x.x — inferenza ad alte prestazioni per modelli di deep learning (Rilevamento oggetti e Segmentazione)

Diverse prove su internet parlavano di un overhead relativamente grande sulle interazioni di rete e sulla registrazione su VOLUME, inoltre c'era l'ignoto e spaventoso GIL, e poiché l'acquisizione del frame, il funzionamento del driver e la trasmissione della frame sono operazioni atomiche in modalità hard real-time, le latenze di rete sono per me molto critiche.

Ma è andato tutto bene =)

P.S. Non resta che aggiungere il vostro amato ciclo di addestramento per la segmentazione e mandarlo in produzione!

Ringraziamenti

Grazie alla comunità ods.ai, senza la quale non sarebbe possibile progredire! Un enorme grazie n01z3, che mi ha incoraggiato a intraprendere il DL, per i suoi preziosi consigli e il suo straordinario professionismo!

Utilizzate in produzione modelli ottimizzati!

TensorRT 6.x.x.x — inferenza ad alte prestazioni per modelli di deep learning (Rilevamento oggetti e Segmentazione) Aurorai, llc

Fonte: habr.com

Acquista hosting affidabile per siti web con protezione DDoS, VPS VDS server 🔥 Acquista hosting affidabile per siti web con protezione DDoS, VPS VDS server | ProHoster