TensorRT 6.x.x.x — Hochleistungsinferenz fĂŒr Deep-Learning-Modelle (Objekterkennung und Segmentierung)

TensorRT 6.x.x.x — Hochleistungsinferenz fĂŒr Deep-Learning-Modelle (Objekterkennung und Segmentierung)
Es tut nur beim ersten Mal weh!

Hallo zusammen! Liebe Freunde, in diesem Artikel möchte ich meine Erfahrungen mit TensorRT und RetinaNet auf Basis des Repositories github.com/aidonchuk/retinanet-examples (das ist ein Fork des offiziellen Repos von nvidia, das es ermöglicht, optimierte Modelle in kĂŒrzester Zeit in der Produktion zu nutzen). WĂ€hrend ich die Nachrichten in den KanĂ€len der Community ods.aidurchblĂ€ttere, stoße ich auf Fragen zur Verwendung von TensorRT, und die Fragen wiederholen sich hauptsĂ€chlich, daher habe ich beschlossen, zu schreiben so vollstĂ€ndig wie möglich eine Anleitung zur Verwendung von schnellem Infereing unter Verwendung von TensorRT, RetinaNet, Unet und Docker.

Aufgabenbeschreibung

Ich schlage vor, die Aufgabe wie folgt zu formulieren: Wir mĂŒssen einen Datensatz annotieren, das Netzwerk RetinaNet/Unet auf Pytorch1.3+ darauf trainieren, die erhaltenen Gewichte in ONNX umzuwandeln, dann in an einen TensorRT-Engine zu konvertieren und all dies in Docker auszufĂŒhren, vorzugsweise auf Ubuntu 18 und Ă€ußerst wĂŒnschenswert auf ARM(Jetson)* Architektur, wobei wir die manuelle Bereitstellung der Umgebung minimieren. Am Ende erhalten wir einen Container, der nicht nur fĂŒr den Export und das Training von RetinaNet/Unet bereit ist, sondern auch fĂŒr die vollstĂ€ndige Entwicklung und das Training von Klassifikation, Segmentierung mit der gesamten notwendigen Anbindung.

Schritt 1. Vorbereitung der Umgebung

Es ist wichtig zu beachten, dass ich in letzter Zeit vollstĂ€ndig von der Verwendung und Bereitstellung irgendwelcher Bibliotheken auf Desktopmaschinen abgerĂŒckt bin, ebenso wenig wie auf devboxen. Das Einzige, was ich erstellen und installieren muss, ist eine python-virtuelle Umgebung und cuda 10.2 (man kann sich auf einen nvidia-Treiber beschrĂ€nken) aus deb.

Angenommen, Sie haben ein frisch installiertes Ubuntu 18. Lassen Sie uns cuda 10.2 (deb) installieren, ich werde nicht auf den Installationsprozess eingehen, die offizielle Dokumentation ist ausreichend.

Jetzt installieren wir Docker, die Installationsanleitung fĂŒr Docker ist leicht zu finden, hier ein Beispiel www.digitalocean.com/community/tutorials/docker-ubuntu-18-04-1-de, die 19+ Version ist bereits verfĂŒgbar – wir installieren sie. Und vergessen Sie nicht, die Verwendung von Docker ohne sudo zu ermöglichen, das ist praktischer. Nachdem alles geklappt hat, machen wir es so:

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

Und man muss sich nicht einmal im offiziellen Repository umschauen github.com/NVIDIA/nvidia-docker.

Jetzt machen wir git clone github.com/aidonchuk/retinanet-examples.

Es ist nur noch ein kleiner Schritt nötig, um Docker mit dem NVIDIA-Image zu verwenden. Wir mĂŒssen uns bei NGC Cloud registrieren und anmelden. Gehen wir hierhin ngc.nvidia.com, registrieren wir uns und nachdem wir im NGC Cloud angekommen sind, klicken wir auf SETUP in der oberen linken Ecke des Bildschirms oder folgen wir diesem Link ngc.nvidia.com/setup/api-key. Klicken Sie auf „SchlĂŒssel generieren“. Ich empfehle, ihn zu speichern, da wir ihn sonst beim nĂ€chsten Besuch erneut generieren mĂŒssen und wir diese Operation erneut durchfĂŒhren mĂŒssen, wenn wir auf einem neuen GerĂ€t arbeiten.

FĂŒhren wir aus:

docker login nvcr.io
Username: $oauthtoken
Password:  - der generierte SchlĂŒssel

Den Benutzernamen kopieren wir einfach. Nun, so betrachtet, ist die Umgebung bereit!

Schritt 2. Erstellen des Docker-Containers

Im zweiten Schritt unserer Arbeit werden wir Docker erstellen und uns mit seinen Innereien vertrautmachen.
Wechseln wir in das Hauptverzeichnis des Projekts retina-examples und fĂŒhren wir aus

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

Wir bauen Docker und ĂŒbergeben den aktuellen Benutzer — das ist sehr nĂŒtzlich, wenn Sie etwas auf einem gemounteten VOLUME mit den Rechten des aktuellen Benutzers schreiben möchten, ansonsten wird es root und schmerzhaft.

WĂ€hrend Docker gebaut wird, lassen Sie uns die Dockerfile untersuchen:

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"]

Wie aus dem Text hervorgeht, verwenden wir alle unsere Lieblingsbibliotheken, kompilieren retinanet, fĂŒgen grundlegende Tools fĂŒr den Umgang mit Ubuntu hinzu und konfigurieren den openssh-Server. In der ersten Zeile geht es um das Erben des nvidia-Images, fĂŒr das wir uns im NGC Cloud angemeldet haben und das Pytorch1.3, TensorRT6.x.x.x und viele weitere Bibliotheken enthĂ€lt, die es ermöglichen, die cpp-Quellcodes unseres Detektors zu kompilieren.

Schritt 3. Start und Debugging des Docker-Containers

Kommen wir zum Hauptanwendungsfall des Containers und der Entwicklungsumgebung; zuerst starten wir nvidia docker. FĂŒhren Sie aus:

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

Jetzt ist der Container ĂŒber ssh @localhost verfĂŒgbar. Nach einem erfolgreichen Start öffnen wir das Projekt in PyCharm. Dann öffnen wir

Einstellungen->Projekt-Interpreter->HinzufĂŒgen->Ssh-Interpreter

Schritt 1
TensorRT 6.x.x.x — Hochleistungsinferenz fĂŒr Deep-Learning-Modelle (Objekterkennung und Segmentierung)

Schritt 2
TensorRT 6.x.x.x — Hochleistungsinferenz fĂŒr Deep-Learning-Modelle (Objekterkennung und Segmentierung)

Schritt 3
TensorRT 6.x.x.x — Hochleistungsinferenz fĂŒr Deep-Learning-Modelle (Objekterkennung und Segmentierung)

WĂ€hlen Sie alles aus wie auf den Screenshots,

Interpreter -> /opt/conda/bin/python

— das wird ein ln auf Python3.6 sein und

Sync-Ordner -> /workspace/retinanet

Klicken Sie auf Fertigstellen, warten Sie auf die Indizierung, und das war's, die Umgebung ist bereit zur Nutzung!

WICHTIG!!! Ziehen Sie sofort nach der Indizierung die kompilierten Dateien fĂŒr Retinanet aus Docker. WĂ€hlen Sie im KontextmenĂŒ im Stammverzeichnis des Projekts den Punkt

Bereitstellung->Herunterladen

Es erscheinen eine Datei und zwei Ordner build, retinanet.egg-info und _ĐĄ.so

TensorRT 6.x.x.x — Hochleistungsinferenz fĂŒr Deep-Learning-Modelle (Objekterkennung und Segmentierung)

Wenn Ihr Projekt so aussieht, sieht die Umgebung alle erforderlichen Dateien und wir sind bereit, RetinaNet zu trainieren.

Schritt 4. Daten beschriften und den Detektor trainieren

FĂŒr die Beschriftung nutze ich hauptsĂ€chlich supervise.ly — ein nettes und praktisches Tool, das in letzter Zeit viele Fehler behoben hat und sich wesentlich besser verhĂ€lt.

Nehmen wir an, Sie haben das Dataset beschriftet und heruntergeladen, aber Sie können es nicht sofort in unser RetinaNet einfĂŒgen, da es in einem eigenen Format vorliegt und wir es dafĂŒr in COCO konvertieren mĂŒssen. Das Konvertierungstool befindet sich unter:

markup_utils/supervisly_to_coco.py

Bitte beachten Sie, dass Category im Skript ein Beispiel ist und Sie Ihre eigenen einfĂŒgen mĂŒssen (die Kategorie Hintergrund muss nicht hinzugefĂŒgt werden)

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

Die Autoren des ursprĂŒnglichen Repositories dachten anscheinend, dass Sie nichts außer COCO/VOC zum Trainieren fĂŒr die Detektion verwenden wĂŒrden, daher musste die Quelldatei etwas bearbeitet werden.

retinanet/dataset.py

Indem ich hier meine Lieblingsaugmentierungen hinzufĂŒgte, albumentations.readthedocs.io/en/latest und die fest eingebetteten Kategorien aus COCO entfernen. Es besteht auch die Möglichkeit, große Erkennungsbereiche zuzuschneiden, wenn Sie auf großen Bildern nach kleinen Objekten suchen, Sie ein kleines Dataset haben =), und nichts funktioniert, aber dazu spĂ€ter mehr.

Insgesamt ist die Trainingsschleife ebenfalls schwach, ursprĂŒnglich hat sie keine Checkpoints gespeichert, hat einen furchtbaren Scheduler verwendet usw. Aber jetzt bleibt Ihnen nur noch, das Backbone auszuwĂ€hlen und auszufĂŒhren

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

mit den Parametern:

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

In der Konsole werden Sie sehen:

Modell wird initialisiert...
     Modell: RetinaNet
  Backbone: ResNet18FPN
   Klassen: 2, Anker: 9
AusgewÀhlte Optimierungsstufe O0: Reines FP32-Training.

Standardeinstellungen fĂŒr diese Optimierungsstufe sind:
eingeschaltet            : True
opt_stufe                : O0
modell_typ_gießen       : torch.float32
patch_torch_funktionen  : False
batchnorm_fp32_behalten : None
master_weights           : False
verlust_skala           : 1.0
Verarbeite BenutzerĂŒberschreibungen (zusĂ€tzliche kwargs, die nicht None sind)...
Nach der Verarbeitung der Überschreibungen sind die Optimierungsoptionen:
eingeschaltet            : True
opt_stufe                : O0
modell_typ_gießen       : torch.float32
patch_torch_funktionen  : False
batchnorm_fp32_behalten : None
master_weights           : False
verlust_skala           : 128.0
Vorbereiten des Datensatzes...
    lader: pytorch
    skalierung: [1024, 1280], max: 1280
    gerÀt: 4 gpus
    stapel: 4, prÀzision: gemischt
Modell fĂŒr 20000 Iterationen trainieren...
[    1/20000] fokale verlust: 0.95619, box verlust: 0.51584, 4.042s/4-stapel (fw: 0.698s, bw: 0.459s), 1.0 im/s, lr: 0.0001
[   12/20000] fokale verlust: 0.76191, box verlust: 0.31794, 0.187s/4-stapel (fw: 0.055s, bw: 0.133s), 21.4 im/s, lr: 0.0001
[   24/20000] fokale verlust: 0.65036, box verlust: 0.30269, 0.173s/4-stapel (fw: 0.045s, bw: 0.128s), 23.1 im/s, lr: 0.0001
[   36/20000] fokale verlust: 0.46425, box verlust: 0.23141, 0.178s/4-stapel (fw: 0.047s, bw: 0.131s), 22.4 im/s, lr: 0.0001
[   48/20000] fokale verlust: 0.45115, box verlust: 0.23505, 0.180s/4-stapel (fw: 0.047s, bw: 0.133s), 22.2 im/s, lr: 0.0001
[   59/20000] fokale verlust: 0.38958, box verlust: 0.25373, 0.184s/4-stapel (fw: 0.049s, bw: 0.134s), 21.8 im/s, lr: 0.0001
[   71/20000] fokale verlust: 0.37733, box verlust: 0.23988, 0.174s/4-stapel (fw: 0.049s, bw: 0.125s), 22.9 im/s, lr: 0.0001
[   83/20000] fokale verlust: 0.39514, box verlust: 0.23878, 0.181s/4-stapel (fw: 0.048s, bw: 0.133s), 22.1 im/s, lr: 0.0001
[   94/20000] fokale verlust: 0.39947, box verlust: 0.23817, 0.185s/4-stapel (fw: 0.050s, bw: 0.134s), 21.6 im/s, lr: 0.0001
[  105/20000] fokale verlust: 0.37343, box verlust: 0.20238, 0.182s/4-stapel (fw: 0.048s, bw: 0.134s), 22.0 im/s, lr: 0.0001
[  116/20000] fokale verlust: 0.19689, box verlust: 0.17371, 0.183s/4-stapel (fw: 0.050s, bw: 0.132s), 21.8 im/s, lr: 0.0001
[  128/20000] fokale verlust: 0.20368, box verlust: 0.16538, 0.178s/4-stapel (fw: 0.046s, bw: 0.131s), 22.5 im/s, lr: 0.0001
[  140/20000] fokale verlust: 0.22763, box verlust: 0.15772, 0.176s/4-stapel (fw: 0.050s, bw: 0.126s), 22.7 im/s, lr: 0.0001
[  148/20000] fokale verlust: 0.21997, box verlust: 0.18400, 0.585s/4-stapel (fw: 0.047s, bw: 0.144s), 6.8 im/s, lr: 0.0001
 Durchschnittliche PrÀzision (AP) @[ IoU=0.50:0.95 | Bereich=   alle | maxDets=100 ] = 0.52674
 Durchschnittliche PrÀzision (AP) @[ IoU=0.50      | Bereich=   alle | maxDets=100 ] = 0.91450
 Durchschnittliche PrÀzision (AP) @[ IoU=0.75      | Bereich=   alle | maxDets=100 ] = 0.35172
 Durchschnittliche PrÀzision (AP) @[ IoU=0.50:0.95 | Bereich= klein | maxDets=100 ] = 0.61881
 Durchschnittliche PrÀzision (AP) @[ IoU=0.50:0.95 | Bereich=mittel | maxDets=100 ] = -1.00000
 Durchschnittliche PrĂ€zision (AP) @[ IoU=0.50:0.95 | Bereich= groß | maxDets=100 ] = -1.00000
 Durchschnittlicher RĂŒckruf (AR) @[ IoU=0.50:0.95 | Bereich=   alle | maxDets=  1 ] = 0.58824
 Durchschnittlicher RĂŒckruf (AR) @[ IoU=0.50:0.95 | Bereich=   alle | maxDets= 10 ] = 0.61765
 Durchschnittlicher RĂŒckruf (AR) @[ IoU=0.50:0.95 | Bereich=   alle | maxDets=100 ] = 0.61765
 Durchschnittlicher RĂŒckruf (AR) @[ IoU=0.50:0.95 | Bereich= klein | maxDets=100 ] = 0.61765
 Durchschnittlicher RĂŒckruf (AR) @[ IoU=0.50:0.95 | Bereich=mittel | maxDets=100 ] = -1.00000
 Durchschnittlicher RĂŒckruf (AR) @[ IoU=0.50:0.95 | Bereich= groß | maxDets=100 ] = -1.00000
Modell wird gespeichert: 148

Um das gesamte Parameter-Set zu analysieren, schauen Sie bitte

retinanet/main.py

Insgesamt sind sie standardmĂ€ĂŸig fĂŒr die Detektion und haben eine Beschreibung. FĂŒhren Sie das Training aus und warten Sie auf die Ergebnisse. Ein Beispiel fĂŒr die Inferenz finden Sie unter:

retinanet/infer_example.py

oder fĂŒhren Sie den Befehl aus:

/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

Im Repository sind bereits Focal Loss und mehrere Backbones integriert, und man kann auch eigene leicht hinzufĂŒgen.

retinanet/backbones/*.py

In der Tabelle geben die Autoren einige Eigenschaften an:

TensorRT 6.x.x.x — Hochleistungsinferenz fĂŒr Deep-Learning-Modelle (Objekterkennung und Segmentierung)

Es gibt auch den Backbone ResNeXt50_32x4dFPN und ResNeXt101_32x8dFPN, die aus torchvision entnommen wurden.
Ich hoffe, das Thema Detektion ist jetzt etwas klarer geworden, aber man sollte unbedingt die offizielle Dokumentation lesen, um die Export- und Logging-Modi zu verstehen..

Schritt 5. Export und Inferenz von Unet-Modellen mit dem Resnet-Encoder.

Wie Sie wahrscheinlich bemerkt haben, wurden im Dockerfile Bibliotheken fĂŒr die Segmentierung installiert, insbesondere die großartige Bibliothek github.com/qubvel/segmentation_models.pytorch.Im Unet-Paket finden Sie Beispiele fĂŒr die Inferenz und den Export von Pytorch-Checkpoints in den TensorRT-Engine.

Das Hauptproblem beim Export von Unet-Ă€hnlichen Modellen von ONNX nach TensorRT besteht darin, dass die GrĂ¶ĂŸe des Upsample festgelegt oder ConvTranspose2D verwendet werden muss:

import torch.onnx.symbolic_opset9 as onnx_symbolic
        def upsample_nearest2d(g, input, output_size):
            # Derzeit unterstĂŒtzt der TRT 5.1/6.0 ONNX Parser nicht alle ONNX-Operationen,
            # die zur UnterstĂŒtzung der dynamischen Upsampling ONNX-Formulierung erforderlich sind.
            # Hier kodieren wir scale=2 als vorĂŒbergehenden Workaround fest.
            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

Mit dieser Umwandlung kann dies automatisch beim Exportieren nach ONNX durchgefĂŒhrt werden, doch in der Version 7 von TensorRT wurde dieses Problem gelöst, und wir mĂŒssen nur noch sehr wenig warten.

Fazit

Als ich anfing, Docker zu verwenden, hatte ich Bedenken hinsichtlich seiner Leistung fĂŒr meine Aufgaben. In einem meiner Systeme gibt es derzeit ein recht hohes Netzwerkaufkommen, das von mehreren Kameras erzeugt wird.

TensorRT 6.x.x.x — Hochleistungsinferenz fĂŒr Deep-Learning-Modelle (Objekterkennung und Segmentierung)

Verschiedene Tests im Internet berichteten von relativ hohen Overheads beim Netzwerkzugriff und der Aufzeichnung auf VOLUME, dazu kam das unbekannte und furchterregende GIL. Da das Erfassen eines Frames, das Arbeiten des Treibers und die Übertragung eines Frames ĂŒber das Netzwerk atomare VorgĂ€nge im Modus sind hard real-time, sind Netzwerkverzögerungen fĂŒr mich sehr kritisch.

Aber alles hat gut geklappt =)

P.S. Vergessen Sie nicht, Ihre bevorzugte Trainingsschleife fĂŒr die Segmentierung hinzuzufĂŒgen und in die Produktion zu bringen!

Dankbarkeit

Danke an die Community ods.ai, ohne die es nicht möglich wĂ€re, sich weiterzuentwickeln! Ein großes Dankeschön n01z3, der mich angeregt hat, mich mit DL zu beschĂ€ftigen, fĂŒr seine unschĂ€tzbaren RatschlĂ€ge und außergewöhnlichen Professionalismus!

Verwenden Sie in der Produktion optimierte Modelle!

TensorRT 6.x.x.x — Hochleistungsinferenz fĂŒr Deep-Learning-Modelle (Objekterkennung und Segmentierung) Aurorai, llc

Quelle: habr.com

60GB SSD 8Gb DDR4