
Der erste Schmerz ist der schlimmste!
Hallo zusammen! Liebe Freunde, in diesem Artikel möchte ich meine Erfahrungen mit TensorRT und RetinaNet auf Grundlage des Repositories teilen. (das ist ein Fork des offiziellen Repositories von , das es ermöglicht, optimierte Modelle in kürzester Zeit für die Produktion zu verwenden). Während ich durch die Nachrichten in den Community-Kanälen blättere, , stoße ich auf Fragen zur Verwendung von TensorRT, und die Fragen wiederholen sich hauptsächlich, deshalb habe ich mich entschieden, ein möglichst umfassendes Handbuch zur Nutzung des schnellen Inferencing mit TensorRT, RetinaNet, Unet und Docker zu schreiben.
Aufgabenbeschreibung
Ich schlage vor, die Aufgabe wie folgt zu formulieren: Wir müssen einen Datensatz kennzeichnen, das RetinaNet/Unet-Netzwerk mit Pytorch 1.3+ trainieren, die erhaltenen Gewichte in ONNX umwandeln, dann in ein TensorRT-Engine konvertieren und all das in Docker betreiben, idealerweise auf Ubuntu 18 und äußerst wünschenswert auf ARM(Jetson)* Architektur, um die manuelle Einrichtung der Umgebung zu minimieren. Am Ende erhalten wir einen Container, der bereit ist, nicht nur für den Export und das Training von RetinaNet/Unet, sondern auch für die vollständige Entwicklung und das Training von Klassifizierung und Segmentierung mit allen notwendigen Tools.
Schritt 1. Umgebung vorbereiten
Hier ist wichtig zu beachten, dass ich in letzter Zeit vollständig von der Nutzung und dem Einsatz jeglicher Bibliotheken auf Desktop-Maschinen, sowie auf dem Devbox, abgesehen habe. Das Einzige, was ich erstellen und installieren muss, ist ein Python-virtuelles Environment 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 im Detail auf den Installationsprozess eingehen, die offizielle Dokumentation ist dafür völlig ausreichend.
Jetzt installieren wir Docker. Eine Installationsanleitung für Docker ist leicht zu finden, hier ein Beispiel: , die Version 19+ ist bereits verfügbar – also installieren wir sie. Vergessen Sie nicht, Docker ohne sudo zu nutzen, das macht es bequemer. Nachdem alles gelungen ist, machen wir Folgendes:
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 nicht einmal im offiziellen Repository nachsehen. .
Jetzt machen wir ein git clone. .
Es ist nicht mehr weit, um Docker mit dem Nvidia-Image zu nutzen. Dafür müssen wir uns im NGC Cloud registrieren und einloggen. Gehen Sie hierhin , registrieren uns und nachdem wir im NGC Cloud sind, klicken wir auf SETUP in der oberen linken Ecke des Bildschirms oder folgen diesem Link . Klicken Sie auf „Schlüssel generieren“. Ich empfehle, ihn zu speichern, da er bei einem späteren Besuch neu generiert werden muss und somit bei der Bereitstellung auf einem neuen Gerät diese Operation erneut durchgeführt werden muss.
Lass uns das ausführen:
docker login nvcr.io
Benutzername: $oauthtoken
Passwort: - generierter Schlüssel
Den Benutzernamen kopieren wir einfach. So, die Umgebung ist praktisch bereit!
Schritt 2. Container-Bau mit Docker
Im zweiten Schritt unserer Arbeit werden wir Docker bauen und uns mit seinen Inneren vertrautmachen.
Gehen wir in das Wurzelverzeichnis 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, indem wir den aktuellen Benutzer hineinführen – das ist sehr nützlich, wenn Sie etwas in ein montiertes VOLUME mit den Rechten des aktuellen Benutzers schreiben. Andernfalls wird es root sein und das ist schmerzhaft.
Während Docker gebaut wird, lassen Sie uns den Dockerfile ansehen:
VON 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 im Text zu sehen ist, nehmen wir all unsere bevorzugten Bibliotheken, kompilieren Retinanet, fügen grundlegende Werkzeuge für die Arbeit mit Ubuntu hinzu und konfigurieren den OpenSSH-Server. In der ersten Zeile steht genau das Erben des NVIDIA-Images, für das wir uns in der NGC Cloud angemeldet haben und das Pytorch 1.3, TensorRT 6.x.x.x und eine Menge Bibliotheken enthält, die es ermöglichen, die C++-Quellen unseres Detektors zu kompilieren.
Schritt 3: Starten und Debuggen 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:latestJetzt ist der Container über ssh @localhost erreichbar. Nach dem erfolgreichen Start öffnen wir das Projekt in PyCharm. Weiter geht's mit
Einstellungen -> Projekt-Interpreter -> Hinzufügen -> Ssh-Interpreter Schritt 1

Schritt 2

Schritt 3

Wählen Sie alles wie auf den Screenshots,
Interpreter -> /opt/conda/bin/python— das wird ein Link zu Python 3.6 sein und
Sync-Ordner -> /workspace/retinanetKlicken Sie auf Fertig, warten Sie auf die Indizierung, und fertig, die Umgebung ist bereit zur Verwendung!
WICHTIG!!! Ziehen Sie sofort nach der Indizierung die kompilierten Dateien für Retinanet aus Docker. Im Kontextmenü im Stammverzeichnis des Projekts wählen Sie den Punkt
Bereitstellung -> HerunterladenEs werden eine Datei und zwei Verzeichnisse erstellt: build, retinanet.egg-info und _C.so

Wenn Ihr Projekt so aussieht, erkennt die Umgebung alle erforderlichen Dateien und wir sind bereit, RetinaNet zu trainieren.
Schritt 4. Daten annotieren und den Detektor trainieren
Für die Annotation verwende ich meist — ein benutzerfreundliches Tool, das in letzter Zeit viele Probleme behoben hat und sich deutlich besser verhält.
Angenommen, Sie haben das Dataset annotiert und heruntergeladen, aber Sie können es nicht direkt in unser RetinaNet einfügen, da es in einem eigenen Format vorliegt und wir es in COCO konvertieren müssen. Das Konvertierungstool befindet sich unter:
markup_utils/supervisly_to_coco.pyBitte beachten Sie, dass 'Category' im Skript ein Beispiel ist und Sie Ihre eigenen einfügen müssen (die Kategorie 'background' sollte nicht hinzugefügt werden).
categories = [{'id': 1, 'name': '1'},
{'id': 2, 'name': '2'},
{'id': 3, 'name': '3'},
{'id': 4, 'name': '4'}] Die Autoren des Originalrepositories haben offenbar beschlossen, dass Sie nichts außer COCO/VOC für die Detektion trainieren werden, weshalb ich die Quelldatei etwas anpassen musste.
retinanet/dataset.pyHier habe ich meine bevorzugten Augmentierungen hinzugefügt. und die starr eingebetteten Kategorien aus COCO entfernen. Es gibt auch die Möglichkeit, große Erkennungsbereiche zuzuschneiden, wenn Sie auf großen Bildern nach kleinen Objekten suchen, Ihr Datensatz klein ist =), und nichts funktioniert, aber das ist ein anderes Thema.
Im Allgemeinen ist die Trainingsschleife ebenfalls schwach, ursprünglich wurden keine Checkpoints gespeichert, ein schrecklicher Scheduler verwendet usw. Aber jetzt müssen Sie nur noch das Backbone auswählen und ausführen.
/opt/conda/bin/python retinanet/main.pymit 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 sehen Sie:
Modell wird initialisiert...
Modell: RetinaNet
Backbone: ResNet18FPN
Klassen: 2, Anker: 9
Ausgewähltes Optimierungslevel O0: Reines FP32-Training.
Standardeinstellungen für dieses Optimierungslevel sind:
aktiviert : Wahr
opt_level : O0
cast_model_type : torch.float32
patch_torch_functions : Falsch
keep_batchnorm_fp32 : Keine
master_weights : Falsch
loss_scale : 1.0
Verarbeite Benutzerüberschreibungen (zusätzliche kwargs, die nicht None sind)...
Nach Verarbeitung der Überschreibungen sind die Optimierungsoptionen:
aktiviert : Wahr
opt_level : O0
cast_model_type : torch.float32
patch_torch_functions : Falsch
keep_batchnorm_fp32 : Keine
master_weights : Falsch
loss_scale : 128.0
Bereite Datensatz vor...
Loader: pytorch
Resize: [1024, 1280], max: 1280
Gerät: 4 GPUs
Batch: 4, Präzision: gemischt
Trainiere Modell für 20.000 Iterationen...
[ 1/20000] Fokussierte Verlust: 0.95619, Boxverlust: 0.51584, 4-Batch in 4.042s (fw: 0.698s, bw: 0.459s), 1.0 Bilder/s, lr: 0.0001
[ 12/20000] Fokussierte Verlust: 0.76191, Boxverlust: 0.31794, 0.187s/4-Batch (fw: 0.055s, bw: 0.133s), 21.4 Bilder/s, lr: 0.0001
[ 24/20000] Fokussierte Verlust: 0.65036, Boxverlust: 0.30269, 0.173s/4-Batch (fw: 0.045s, bw: 0.128s), 23.1 Bilder/s, lr: 0.0001
[ 36/20000] Fokussierte Verlust: 0.46425, Boxverlust: 0.23141, 0.178s/4-Batch (fw: 0.047s, bw: 0.131s), 22.4 Bilder/s, lr: 0.0001
[ 48/20000] Fokussierte Verlust: 0.45115, Boxverlust: 0.23505, 0.180s/4-Batch (fw: 0.047s, bw: 0.133s), 22.2 Bilder/s, lr: 0.0001
[ 59/20000] Fokussierte Verlust: 0.38958, Boxverlust: 0.25373, 0.184s/4-Batch (fw: 0.049s, bw: 0.134s), 21.8 Bilder/s, lr: 0.0001
[ 71/20000] Fokussierte Verlust: 0.37733, Boxverlust: 0.23988, 0.174s/4-Batch (fw: 0.049s, bw: 0.125s), 22.9 Bilder/s, lr: 0.0001
[ 83/20000] Fokussierte Verlust: 0.39514, Boxverlust: 0.23878, 0.181s/4-Batch (fw: 0.048s, bw: 0.133s), 22.1 Bilder/s, lr: 0.0001
[ 94/20000] Fokussierte Verlust: 0.39947, Boxverlust: 0.23817, 0.185s/4-Batch (fw: 0.050s, bw: 0.134s), 21.6 Bilder/s, lr: 0.0001
[ 105/20000] Fokussierte Verlust: 0.37343, Boxverlust: 0.20238, 0.182s/4-Batch (fw: 0.048s, bw: 0.134s), 22.0 Bilder/s, lr: 0.0001
[ 116/20000] Fokussierte Verlust: 0.19689, Boxverlust: 0.17371, 0.183s/4-Batch (fw: 0.050s, bw: 0.132s), 21.8 Bilder/s, lr: 0.0001
[ 128/20000] Fokussierte Verlust: 0.20368, Boxverlust: 0.16538, 0.178s/4-Batch (fw: 0.046s, bw: 0.131s), 22.5 Bilder/s, lr: 0.0001
[ 140/20000] Fokussierte Verlust: 0.22763, Boxverlust: 0.15772, 0.176s/4-Batch (fw: 0.050s, bw: 0.126s), 22.7 Bilder/s, lr: 0.0001
[ 148/20000] Fokussierte Verlust: 0.21997, Boxverlust: 0.18400, 0.585s/4-Batch (fw: 0.047s, bw: 0.144s), 6.8 Bilder/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
Durchschnittliche Rückrufrate (AR) @[ IoU=0.50:0.95 | Bereich= alle | maxDets= 1 ] = 0.58824
Durchschnittliche Rückrufrate (AR) @[ IoU=0.50:0.95 | Bereich= alle | maxDets= 10 ] = 0.61765
Durchschnittliche Rückrufrate (AR) @[ IoU=0.50:0.95 | Bereich= alle | maxDets=100 ] = 0.61765
Durchschnittliche Rückrufrate (AR) @[ IoU=0.50:0.95 | Bereich= klein | maxDets=100 ] = 0.61765
Durchschnittliche Rückrufrate (AR) @[ IoU=0.50:0.95 | Bereich=mittel | maxDets=100 ] = -1.00000
Durchschnittliche Rückrufrate (AR) @[ IoU=0.50:0.95 | Bereich= groß | maxDets=100 ] = -1.00000
Modell wird gespeichert: 148Um den gesamten Parameterkatalog zu entdecken, schauen Sie sich bitte an
retinanet/main.pyIm Allgemeinen sind sie standardmäßig für die Detektion und sind dokumentiert. Starten Sie das Training und warten Sie auf die Ergebnisse. Ein Beispiel für die Inferenz finden Sie unter:
retinanet/infer_example.pyoder 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 eigene können ebenfalls problemlos hinzugefügt werden.
retinanet/backbones/*.pyIn der Tabelle führen die Autoren einige Eigenschaften auf:

Es gibt auch den Backbone ResNeXt50_32x4dFPN und ResNeXt101_32x8dFPN, die aus torchvision stammen.
Ich hoffe, Sie haben das Thema Detektion ein bisschen geklärt, aber es ist unbedingt notwendig, die offizielle Dokumentation zu 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 hervorragende Bibliothek . Im Unet-Paket finden Sie Inferenz- und Exportbeispiele für Pytorch-Checkpoints in die Engine TensorRT.
Das Hauptproblem beim Exportieren von Unet-ähnlichen Modellen von ONNX nach TensorRT ist die Notwendigkeit, eine feste Größe für Upsample festzulegen oder ConvTranspose2D zu verwenden.
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 für die Unterstützung der dynamischen Upsampling-ONNX-Formulierung erforderlich sind.
# Hier kodieren wir scale=2 vorübergehend als 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
Mit dieser Umwandlung kann dies automatisch beim Export nach ONNX erfolgen, aber in der Version 7 von TensorRT wurde dieses Problem bereits behoben, und wir müssen nur noch kurz warten.
Fazit
Als ich mit Docker anfing, hatte ich Bedenken hinsichtlich der Leistung für meine Aufgaben. In einem meiner Aggregate gibt es jetzt einen ziemlich hohen Netzwerkverkehr, verursacht durch mehrere Kameras.

Verschiedene Tests im Internet berichteten von einem relativ hohen Overhead bei der Netzwerkinteraktion und dem Schreiben auf VOLUME. Hinzu kommt das unbekannte und gefürchtete GIL, und da die Bildaufnahme, die Arbeit des Treibers und die Übertragung des Bildes über das Netzwerk atomare Operationen im harten Echtzeitmodus, sind Netzwerkverzögerungen für mich sehr kritisch.
Aber alles hat gut geklappt =)
P.S. Fügen Sie Ihren Lieblings-Train Loop für die Segmentierung hinzu und ab ins Prod!
Dankbarkeit
Danke an die Community , ohne ihn ist Wachstum unmöglich! Vielen Dank , der mich dazu 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!
Aurorai, llc
Quelle: habr.com
