
Det gør kun ondt første gang!
Hej alle! Kære venner, i denne artikel vil jeg dele min erfaring med at bruge TensorRT, RetinaNet baseret på repository (dette er en fork af det officielle repo fra , som vil gøre det muligt at begynde at bruge optimerede modeller i produktionen på kort tid). Når jeg ruller gennem beskeder i fællesskabets kanaler , støder jeg på spørgsmål om brugen af TensorRT, og størstedelen af spørgsmålene går igen, så jeg besluttede at skrive en så fuldstændig som muligt vejledning til brug af hurtig inferens baseret på TensorRT, RetinaNet, Unet og docker.
Beskrivelse af opgaven
Jeg foreslår at formulere opgaven således: vi skal annotere et datasæt, træne en RetinaNet/Unet model på Pytorch1.3+, konvertere de opnåede vægte til ONNX, derefter konvertere dem til TensorRT engine og køre hele dette setup i docker, helst på Ubuntu 18 og meget gerne på ARM(Jetson)* arkitektur, dermed minimere manuel opsætning af miljøet. I sidste ende vil vi få en container klar til ikke kun eksport og træning af RetinaNet/Unet, men også til den fulde udvikling og træning af klassifikation, segmentering med alt nødvendigt tilbehør.
Trin 1. Klargøring af miljøet
Det er vigtigt at bemærke, at jeg for nylig helt er gået væk fra at bruge og opsætte nogen biblioteker på desktop maskinen, ligesom på devbox. Det eneste, jeg skal oprette og installere – er python virtuel miljø og cuda 10.2 (man kan klart nøjes med en nvidia driver) fra deb.
Lad os antage, at du har en nyinstalleret Ubuntu 18. Lad os installere cuda 10.2(deb), jeg vil ikke gå i detaljer med installationsprocessen, den officielle dokumentation er helt tilstrækkelig.
Lad os nu installere docker, en vejledning til installation af docker kan nemt findes, her er et eksempel , version 19+ er allerede tilgængelig — lad os installere den. Og glem ikke at gøre det muligt at bruge docker uden sudo, så er det nemmere. Når det hele er klaret, gør vi således:
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
Og man kunne endda undgå at kigge i det officielle repository .
Nu laver vi git clone .
Der er kun lidt tilbage, før du kan begynde at bruge Docker med Nvidia-billedet, vi skal registrere os i NGC Cloud og logge ind. Gå hertil , registrer dig, og efter vi kommer ind i NGC Cloud, klikker vi på SETUP i øverste venstre hjørne af skærmen eller går til dette link . Klik på 'generere nøgle'. Jeg anbefaler at gemme den, ellers skal den genereres igen ved næste besøg, og dermed skal denne proces gentages, når du opretter på en ny maskine.
Lad os udføre:
docker login nvcr.io
Brugernavn: $oauthtoken
Adgangskode: - den genererede nøgle
Vi kopierer blot brugernavnet. Nå, nu er miljøet næsten oprettet!
Trin 2. Bygning af Docker-container
I det andet trin af vores arbejde vil vi opbygge Docker og lære om dets indre funktioner.
Lad os navigere til rodmappen i forhold til projektet retina-examples og udføre
docker build --build-arg USER=$USER --build-arg UID=$UID --build-arg GID=$GID --build-arg PW=alex -t retinanet:latest retinanet/
Vi opbygger Docker ved at passere den aktuelle bruger gennem, hvilket er meget nyttigt, hvis du skal skrive noget på det monterede VOLUME med den aktuelle brugers rettigheder, ellers vil det være root, og det er besværligt.
Mens Docker bygges, lad os tage et kig på Dockerfilen:
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"]
Som det fremgår af teksten, tager vi alle vores yndlingsbiblioteker, kompilerer retinanet, tilføjer grundlæggende værktøjer til arbejde med Ubuntu, og konfigurerer serveren openssh. Den første linje handler om arven fra nvidia-billedet, som vi loggede ind på i NGC Cloud, og som indeholder Pytorch1.3, TensorRT6.x.x.x og en masse biblioteker, der gør det muligt at kompilere cpp-kildekoden til vores detektor.
Trin 3. Start og fejlfinding af docker-containeren
Lad os gå videre til det primære anvendelsessag for containeren og udviklingsmiljøet, først skal vi starte nvidia docker. Udfør:
docker run --gpus all --net=host -v /home/:/workspace/mounted_vol -d -P --rm --ipc=host -it retinanet:latestNu er containeren tilgængelig via ssh @localhost. Efter en vellykket opstart åbner vi projektet i PyCharm. Dernæst åbner vi
Indstillinger-> Projektfortolker-> Tilføj-> Ssh-fortolker Trin 1

Trin 2

Trin 3

Vi vælger alt som på skærmbillederne,
Fortolker -> /opt/conda/bin/python— det vil være ln til Python3.6 og
Synkroniseringsmappe -> /workspace/retinanetVi klikker på afslut, venter på indeksering, og så er miljøet klar til brug!
VIGTIGT!!! Straks efter indeksering trækker vi de kompilerede filer til Retinanet fra docker. I kontekstmenuen i rodmappen af projektet vælger vi punktet
Deployment-> DownloadDer vil dukke en fil og to mapper op: build, retinanet.egg-info og _C.so

Hvis dit projekt ser sådan ud, så ser miljøet alle de nødvendige filer, og vi er klar til træning af RetinaNet.
Trin 4. Vi mærker data og træner detektoren
For annotering bruger jeg primært — et behageligt og brugervenligt værktøj, som i den seneste tid har rettet mange fejl og er blevet betydeligt bedre.
Antag, at du har annoteret datasættet og downloadet det, men du kan ikke straks bruge det i vores RetinaNet, da det er i et eget format, og vi derfor skal konvertere det til COCO. Værktøjet til konvertering findes i:
markup_utils/supervisly_to_coco.pyBemærk, at Category i scriptet er et eksempel, og du skal indsætte dine egne (kategorien baggrund skal ikke tilføjes)
categories = [{'id': 1, 'name': '1'},
{'id': 2, 'name': '2'},
{'id': 3, 'name': '3'},
{'id': 4, 'name': '4'}] Forfatterne af det originale repositorium mente åbenbart, at du ikke ville træne noget andet end COCO/VOC til detektion, så jeg måtte redigere kildefilen lidt
retinanet/dataset.pyVed at tilføje her de yndlingsaugmentationer og og fjerne hårdt indlejrede kategorier fra COCO. Der er også mulighed for at beskære store detektionsområder, hvis du leder efter små objekter på store billeder, har et lille datasæt =), og intet fungerer, men det er et emne for en anden gang.
Generelt er træningssløjfen også svag, den gemte oprindeligt ikke checkpoints, brugte en forfærdelig scheduler osv. Men nu er det kun tilbage at vælge backbone og udføre.
/opt/conda/bin/python retinanet/main.pymed parametre:
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
I konsollen vil du se:
Initialisering af model...
model: RetinaNet
backbone: ResNet18FPN
klasser: 2, ankre: 9
Valgt optimeringsniveau O0: Ren FP32 træning.
Standarder for dette optimeringsniveau er:
tændt : Sand
opt_niveau : O0
cast_model_type : torch.float32
patch_torch_functions : Falsk
keep_batchnorm_fp32 : Ingen
master_weights : Falsk
loss_scale : 1.0
Behandler brugeroverskridelser (yderligere kwargs, der ikke er None)...
Efter behandling af overskridelser er optimeringsmulighederne:
tændt : Sand
opt_niveau : O0
cast_model_type : torch.float32
patch_torch_functions : Falsk
keep_batchnorm_fp32 : Ingen
master_weights : Falsk
loss_scale : 128.0
Forbereder datasæt...
loader: pytorch
størrelse: [1024, 1280], maks: 1280
enhed: 4 gpu'er
batch: 4, præcision: blandet
Træner model i 20000 iterationer...
[ 1/20000] fokus tab: 0.95619, boks tab: 0.51584, 4-batch 4.042s (fw: 0.698s, bw: 0.459s), 1.0 im/s, lr: 0.0001
[ 12/20000] fokus tab: 0.76191, boks tab: 0.31794, 0.187s/4-batch (fw: 0.055s, bw: 0.133s), 21.4 im/s, lr: 0.0001
[ 24/20000] fokus tab: 0.65036, boks tab: 0.30269, 0.173s/4-batch (fw: 0.045s, bw: 0.128s), 23.1 im/s, lr: 0.0001
[ 36/20000] fokus tab: 0.46425, boks tab: 0.23141, 0.178s/4-batch (fw: 0.047s, bw: 0.131s), 22.4 im/s, lr: 0.0001
[ 48/20000] fokus tab: 0.45115, boks tab: 0.23505, 0.180s/4-batch (fw: 0.047s, bw: 0.133s), 22.2 im/s, lr: 0.0001
[ 59/20000] fokus tab: 0.38958, boks tab: 0.25373, 0.184s/4-batch (fw: 0.049s, bw: 0.134s), 21.8 im/s, lr: 0.0001
[ 71/20000] fokus tab: 0.37733, boks tab: 0.23988, 0.174s/4-batch (fw: 0.049s, bw: 0.125s), 22.9 im/s, lr: 0.0001
[ 83/20000] fokus tab: 0.39514, boks tab: 0.23878, 0.181s/4-batch (fw: 0.048s, bw: 0.133s), 22.1 im/s, lr: 0.0001
[ 94/20000] fokus tab: 0.39947, boks tab: 0.23817, 0.185s/4-batch (fw: 0.050s, bw: 0.134s), 21.6 im/s, lr: 0.0001
[ 105/20000] fokus tab: 0.37343, boks tab: 0.20238, 0.182s/4-batch (fw: 0.048s, bw: 0.134s), 22.0 im/s, lr: 0.0001
[ 116/20000] fokus tab: 0.19689, boks tab: 0.17371, 0.183s/4-batch (fw: 0.050s, bw: 0.132s), 21.8 im/s, lr: 0.0001
[ 128/20000] fokus tab: 0.20368, boks tab: 0.16538, 0.178s/4-batch (fw: 0.046s, bw: 0.131s), 22.5 im/s, lr: 0.0001
[ 140/20000] fokus tab: 0.22763, boks tab: 0.15772, 0.176s/4-batch (fw: 0.050s, bw: 0.126s), 22.7 im/s, lr: 0.0001
[ 148/20000] fokus tab: 0.21997, boks tab: 0.18400, 0.585s/4-batch (fw: 0.047s, bw: 0.144s), 6.8 im/s, lr: 0.0001
Gennemsnitlig præcision (AP) @[ IoU=0.50:0.95 | område= alt | maxDets=100 ] = 0.52674
Gennemsnitlig præcision (AP) @[ IoU=0.50 | område= alt | maxDets=100 ] = 0.91450
Gennemsnitlig præcision (AP) @[ IoU=0.75 | område= alt | maxDets=100 ] = 0.35172
Gennemsnitlig præcision (AP) @[ IoU=0.50:0.95 | område= lille | maxDets=100 ] = 0.61881
Gennemsnitlig præcision (AP) @[ IoU=0.50:0.95 | område=middel | maxDets=100 ] = -1.00000
Gennemsnitlig præcision (AP) @[ IoU=0.50:0.95 | område= stor | maxDets=100 ] = -1.00000
Gennemsnitlig tilbagekaldelse (AR) @[ IoU=0.50:0.95 | område= alt | maxDets= 1 ] = 0.58824
Gennemsnitlig tilbagekaldelse (AR) @[ IoU=0.50:0.95 | område= alt | maxDets= 10 ] = 0.61765
Gennemsnitlig tilbagekaldelse (AR) @[ IoU=0.50:0.95 | område= alt | maxDets=100 ] = 0.61765
Gennemsnitlig tilbagekaldelse (AR) @[ IoU=0.50:0.95 | område= lille | maxDets=100 ] = 0.61765
Gennemsnitlig tilbagekaldelse (AR) @[ IoU=0.50:0.95 | område=middel | maxDets=100 ] = -1.00000
Gennemsnitlig tilbagekaldelse (AR) @[ IoU=0.50:0.95 | område= stor | maxDets=100 ] = -1.00000
Gemmer model: 148For at lære alle parametrene, se venligst
retinanet/main.pyGenerelt er de standard for detektion, og de har en beskrivelse. Start træningen og vent på resultaterne. Et eksempel på inferens kan findes i:
retinanet/infer_example.pyeller udfør kommandoen:
/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
I repositoriet er der allerede indbygget Focal Loss og flere backbone, og man kan nemt integrere sine egne.
retinanet/backbones/*.pyI tabellen giver forfatterne nogle specifikationer:

Der er også backbone ResNeXt50_32x4dFPN og ResNeXt101_32x8dFPN, taget fra torchvision.
Jeg håber, at vi har fået styr på detektion, men det er vigtigt at læse den officielle dokumentation for at forstå eksport- og loggingsindstillingerne..
Trin 5. Eksport og inferens af Unet-modeller med Resnet-encoder.
Som du nok har bemærket, er der blevet installeret biblioteker til segmentering i Dockerfile, især det fremragende bibliotek I Unet-pakken kan du finde eksempler på inferens og eksport af pytorch checkpoints til TensorRT-motoren.
Det primære problem ved eksport af Unet-lignende modeller fra ONNX til TensorRT er behovet for at angive en fast størrelse for Upsample eller bruge ConvTranspose2D:
import torch.onnx.symbolic_opset9 as onnx_symbolic
def upsample_nearest2d(g, input, output_size):
# I øjeblikket understøtter TRT 5.1/6.0 ONNX Parser ikke alle ONNX-funktioner
# nødvendige for at understøtte dynamisk opskalerings ONNX-formulering.
# Her hardcoder vi scale=2 som en midlertidig løsning.
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
Med denne transformation kan dette gøres automatisk ved eksport til ONNX, men i den 7. version af TensorRT er dette problem blevet løst, og vi skal blot vente lidt.
Konklusion
Da jeg begyndte at bruge Docker, havde jeg mine tvivl om dets ydeevne til mine opgaver. I en af mine aggregationer genereres der nu en ret stor netværkstrafik af flere kameraer.

Forskellige tests på internettet talte om en relativt stor overhead ved netværksinteraktion og skrivning til VOLUME, plus den ukendte og skræmmende GIL, og da optagelse af et billede, arbejde med driveren og overførsel af et billede over nettet er atomare operationer i tilstand hard real-time, er netværksforsinkelse meget kritisk for mig.
Men alt gik godt =)
P.S. Husk at tilføje din yndlings træningsløkke for segmentering og i produktion!
Taknemmelighed
Tak til fællesskabet , uden det er det umuligt at udvikle sig! Mange tak , som fik mig til at tage fat på DL, for hans uvurderlige råd og ekstreme professionalisme!
Brug optimerede modeller i produktionen!
Aurorai, llc
Kilde: habr.com
