
Det gör ont bara första gÄngen!
Hej allihopa! KÀra vÀnner, i denna artikel vill jag dela med mig av min erfarenhet av att anvÀnda TensorRT, RetinaNet baserat pÄ förrÄdet (detta Àr en fork av det officiella förrÄdet frÄn , som gör det möjligt att börja anvÀnda optimerade modeller i produktion pÄ kortast möjliga tid). NÀr jag blÀddrar igenom meddelanden i community-kanalerna , stöter jag pÄ frÄgor om anvÀndningen av TensorRT, och framför allt upprepas frÄgorna, sÄ jag beslutade att skriva en sÄ fullstÀndig som möjligt guide för att anvÀnda snabb inferens baserad pÄ TensorRT, RetinaNet, Unet och docker.
Uppgiftsbeskrivning
Jag föreslÄr att formulera uppgiften pÄ följande sÀtt: vi behöver mÀrka upp en datamÀngd, trÀna ett nÀtverk av RetinaNet/Unet pÄ Pytorch1.3+, konvertera de erhÄllna vikterna till ONNX, sedan konvertera dem till en TensorRT-engine och köra allt detta i docker, helst pÄ Ubuntu 18 och extremt gÀrna pÄ ARM(Jetson)* arkitektur, vilket minimera manuell installation av miljön. Resultatet blir en container som Àr redo för bÄde export och utbildning av RetinaNet/Unet, samt för komplett utveckling och trÀning av klassificering, segmentering med all nödvÀndig infrastruktur.
Steg 1. Förberedelse av miljön
HÀr Àr det viktigt att notera att jag nyligen helt slutat anvÀnda och installera nÄgra bibliotek pÄ skrivbordsmaskinen, liksom pÄ devboxen. Det enda som behöver skapas och installeras Àr en python virtuell miljö och cuda 10.2 (man kan nöja sig med en nvidia-drivrutin) frÄn deb.
LÄt oss anta att du har en nyinstallerad Ubuntu 18. LÄt oss installera cuda 10.2(deb), jag kommer inte att gÄ in pÄ installationsprocessen, officiell dokumentation Àr helt tillrÀcklig.
Nu installerar vi docker, installationsguiden för docker gĂ„r att hitta enkelt, hĂ€r Ă€r ett exempel , version 19+ Ă€r redan tillgĂ€nglig â lĂ„t oss installera den. Och glöm inte att göra det möjligt att anvĂ€nda docker utan sudo, det blir enklare. Efter att allt fungerar, gör vi sĂ„ hĂ€r:
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
Och man kan till och med undvika att kolla i det officiella förrÄdet .
Nu gör vi git clone .
Det Àr bara en liten bit kvar för att börja anvÀnda docker med nvidia-bilden, vi behöver registrera oss i NGC Cloud och logga in. GÄ hit , registrera oss och nÀr vi kommer in i NGC Cloud klickar vi pÄ SETUP i övre vÀnstra hörnet eller gÄr till den hÀr lÀnken . Klicka pÄ "generera nyckel". Jag rekommenderar att spara den, annars mÄste vi generera den igen nÀsta gÄng vi besöker sidan och dÀrmed Äterigen utföra denna operation pÄ en ny maskin.
Utför följande:
docker login nvcr.io
AnvÀndarnamn: $oauthtoken
Lösenord: - den genererade nyckeln
Kopiera anvÀndarnamnet. SÄ, nu Àr miljön igÄng!
Steg 2. Bygga dockercontainrar
I det andra steget av vÄrt arbete kommer vi att bygga docker och lÀra oss om dess inre funktioner.
GÄ till rotmappen i förhÄllande till projektet retina-examples och kör
docker build --build-arg USER=$USER --build-arg UID=$UID --build-arg GID=$GID --build-arg PW=alex -t retinanet:latest retinanet/
Vi bygger docker med nuvarande anvÀndare, vilket Àr mycket anvÀndbart om du planerar att skriva nÄgot pÄ den monterade VOLUMEN med rÀttigheten för den aktuella anvÀndaren, annars blir det root och problematiskt.
Medan docker byggs, lÄt oss ta en titt pÄ 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"]
Som du kan se frÄn texten tar vi alla vÄra favoritbibliotek, kompilera retinanet, lÀgger till grundlÀggande verktyg för att underlÀtta arbetet med Ubuntu och konfigurerar openssh-servern. Den första raden handlar just om arv av nvidia-imagen, för vilken vi loggade in pÄ NGC Cloud och som innehÄller Pytorch1.3, TensorRT6.x.x.x och en mÀngd bibliotek som möjliggör kompilering av cpp-kÀllkoden för vÄr detektor.
Steg 3. Starta och debugga dockercontainern
LÄt oss gÄ vidare till det huvudsakliga anvÀndningsomrÄdet för containern och utvecklingsmiljön, för att börja köra nvidia docker. Utför:
docker run --gpus all --net=host -v /home/:/workspace/mounted_vol -d -P --rm --ipc=host -it retinanet:latestNu Àr containern tillgÀnglig via ssh @localhost. Efter en framgÄngsrik start öppnar vi projektet i PyCharm. DÀrefter öppnar vi
InstÀllningar->Projektinterpretor->LÀgg till->Ssh-Interpreter Steg 1

Steg 2

Steg 3

Vi vÀljer allt som pÄ skÀrmdumparna,
Interpreter -> /opt/conda/bin/pythonâ detta kommer att vara en lĂ€nk till Python3.6 och
Synkroniseringsmapp -> /workspace/retinanetKlicka pÄ fÀrdigt, vÀnta pÄ indexering, och sÄ Àr miljön klar att anvÀnda!
VIKTIGT!!! Direkt efter indexeringen extrahera de kompilera filerna frÄn docker för Retinanet. I snabbmenyn i projektets rot vÀljer vi punkten
Distribution->Ladda nerDet kommer att dyka upp en fil och tvÄ mappar build, retinanet.egg-info och _C.so

Om ditt projekt ser ut sÄ hÀr, dÄ ser miljön alla nödvÀndiga filer och vi Àr redo för trÀning av RetinaNet.
Steg 4. MÀrka data och trÀna detektorn
För mĂ€rkning anvĂ€nder jag för det mesta â ett trevligt och anvĂ€ndarvĂ€nligt verktyg, pĂ„ sistone har mĂ„nga buggar fixats och det har blivit betydligt bĂ€ttre.
Anta att du har mÀrkt datasetet och laddat ner det, men du kan inte bara stoppa in det i vÄr RetinaNet, eftersom det Àr i sitt eget format och vi mÄste konvertera det till COCO. Verktyget för konvertering finns i:
markup_utils/supervisly_to_coco.pyObservera att kategori i skriptet Àr ett exempel och du mÄste sÀtta in dina egna (lÀgg inte till kategorin bakgrund)
categories = [{'id': 1, 'name': '1'},
{'id': 2, 'name': '2'},
{'id': 3, 'name': '3'},
{'id': 4, 'name': '4'}] Författarna till det ursprungliga arkivet tyckte tydligen att du inte skulle trÀna nÄgot annat Àn COCO/VOC för detektion, sÄ jag var tvungen att redigera kÀllfilen lite
retinanet/dataset.pyGenom att hÀr lÀgga till mina favoritförbÀttringar och ta bort hÄrt inbyggda kategorier frÄn COCO. Det finns ocksÄ möjlighet att beskÀra stora detektionsomrÄden om du letar efter smÄ objekt pÄ stora bilder, har en liten dataset =), och ingenting fungerar, men mer om det en annan gÄng.
Generellt sett Àr trÀning loopen ocksÄ svag, frÄn början sparade den inte checkpoints, anvÀnde nÄgon fruktansvÀrd schemalÀggare och sÄ vidare. Men nu behöver du bara vÀlja backbone och köra.
/opt/conda/bin/python retinanet/main.pymed parametrar:
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 konsolen kommer du att se:
Initierar modellen...
modell: RetinaNet
ryggsÀck: ResNet18FPN
klasser: 2, ankar: 9
Vald optimeringsnivÄ O0: Ren FP32-trÀning.
StandardinstÀllningar för denna optimeringsnivÄ Àr:
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
Bearbetar anvÀndaröverskrivningar (ytterligare kwargs som inte Àr None)...
Efter att ha bearbetat överskrivningar Àr optimeringsalternativen:
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
Förbereder dataset...
loader: pytorch
Ă€ndra storlek: [1024, 1280], max: 1280
enhet: 4 gpus
batch: 4, precision: blandad
TrÀnar modellen i 20000 iterationer...
[ 1/20000] fokalförlust: 0.95619, boxförlust: 0.51584, 4-batch (fw: 0.698s, bw: 0.459s), 1.0 im/s, lr: 0.0001
[ 12/20000] fokalförlust: 0.76191, boxförlust: 0.31794, 0.187s/4-batch (fw: 0.055s, bw: 0.133s), 21.4 im/s, lr: 0.0001
[ 24/20000] fokalförlust: 0.65036, boxförlust: 0.30269, 0.173s/4-batch (fw: 0.045s, bw: 0.128s), 23.1 im/s, lr: 0.0001
[ 36/20000] fokalförlust: 0.46425, boxförlust: 0.23141, 0.178s/4-batch (fw: 0.047s, bw: 0.131s), 22.4 im/s, lr: 0.0001
[ 48/20000] fokalförlust: 0.45115, boxförlust: 0.23505, 0.180s/4-batch (fw: 0.047s, bw: 0.133s), 22.2 im/s, lr: 0.0001
[ 59/20000] fokalförlust: 0.38958, boxförlust: 0.25373, 0.184s/4-batch (fw: 0.049s, bw: 0.134s), 21.8 im/s, lr: 0.0001
[ 71/20000] fokalförlust: 0.37733, boxförlust: 0.23988, 0.174s/4-batch (fw: 0.049s, bw: 0.125s), 22.9 im/s, lr: 0.0001
[ 83/20000] fokalförlust: 0.39514, boxförlust: 0.23878, 0.181s/4-batch (fw: 0.048s, bw: 0.133s), 22.1 im/s, lr: 0.0001
[ 94/20000] fokalförlust: 0.39947, boxförlust: 0.23817, 0.185s/4-batch (fw: 0.050s, bw: 0.134s), 21.6 im/s, lr: 0.0001
[ 105/20000] fokalförlust: 0.37343, boxförlust: 0.20238, 0.182s/4-batch (fw: 0.048s, bw: 0.134s), 22.0 im/s, lr: 0.0001
[ 116/20000] fokalförlust: 0.19689, boxförlust: 0.17371, 0.183s/4-batch (fw: 0.050s, bw: 0.132s), 21.8 im/s, lr: 0.0001
[ 128/20000] fokalförlust: 0.20368, boxförlust: 0.16538, 0.178s/4-batch (fw: 0.046s, bw: 0.131s), 22.5 im/s, lr: 0.0001
[ 140/20000] fokalförlust: 0.22763, boxförlust: 0.15772, 0.176s/4-batch (fw: 0.050s, bw: 0.126s), 22.7 im/s, lr: 0.0001
[ 148/20000] fokalförlust: 0.21997, boxförlust: 0.18400, 0.585s/4-batch (fw: 0.047s, bw: 0.144s), 6.8 im/s, lr: 0.0001
Genomsnittlig precision (AP) @[ IoU=0.50:0.95 | omrÄde= alla | maxDets=100 ] = 0.52674
Genomsnittlig precision (AP) @[ IoU=0.50 | omrÄde= alla | maxDets=100 ] = 0.91450
Genomsnittlig precision (AP) @[ IoU=0.75 | omrÄde= alla | maxDets=100 ] = 0.35172
Genomsnittlig precision (AP) @[ IoU=0.50:0.95 | omrÄde= liten | maxDets=100 ] = 0.61881
Genomsnittlig precision (AP) @[ IoU=0.50:0.95 | omrÄde=medel | maxDets=100 ] = -1.00000
Genomsnittlig precision (AP) @[ IoU=0.50:0.95 | omrÄde= stor | maxDets=100 ] = -1.00000
Genomsnittlig Äterkallning (AR) @[ IoU=0.50:0.95 | omrÄde= alla | maxDets= 1 ] = 0.58824
Genomsnittlig Äterkallning (AR) @[ IoU=0.50:0.95 | omrÄde= alla | maxDets= 10 ] = 0.61765
Genomsnittlig Äterkallning (AR) @[ IoU=0.50:0.95 | omrÄde= alla | maxDets= 100 ] = 0.61765
Genomsnittlig Äterkallning (AR) @[ IoU=0.50:0.95 | omrÄde= liten | maxDets=100 ] = 0.61765
Genomsnittlig Äterkallning (AR) @[ IoU=0.50:0.95 | omrÄde=medel | maxDets=100 ] = -1.00000
Genomsnittlig Äterkallning (AR) @[ IoU=0.50:0.95 | omrÄde= stor | maxDets=100 ] = -1.00000
Sparar modell: 148För att se hela parameternaset, titta pÄ
retinanet/main.pyGenerellt sett Àr de standard för detektering, och de har en beskrivning. Kör trÀningen och vÀnta pÄ resultaten. Ett exempel pÄ inferens kan ses i:
retinanet/infer_example.pyeller kör kommandot:
/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 det hÀr arkivet finns redan inbyggd Focal Loss och flera backbone, och det Àr ocksÄ enkelt att integrera egna.
retinanet/backbones/*.pyI tabellen presenterar författarna nÄgra egenskaper:

Det finns ocksÄ backbone ResNeXt50_32x4dFPN och ResNeXt101_32x8dFPN, hÀmtad frÄn torchvision.
Jag hoppas att vi har fÄtt lite klarhet i detekteringen, men det Àr viktigt att lÀsa den officiella dokumentationen för att förstÄ export- och loggningslÀgen..
Steg 5. Export och inferens av Unet-modeller med Resnet-kodare.
Som ni kanske har lagt mÀrke till har bibliotek för segmentering installerats i Dockerfile, sÀrskilt det fantastiska biblioteket . I Unet-paketet kan man hitta exempel pÄ inferens och export av pytorch checkpoints till TensorRT-motorn.
Det största problemet med att exportera Unet-liknande modeller frÄn ONNX till TensorRT Àr behovet av att ange en fast storlek för Upsample eller anvÀnda ConvTranspose2D:
import torch.onnx.symbolic_opset9 as onnx_symbolic
def upsample_nearest2d(g, input, output_size):
# För nÀrvarande stöder TRT 5.1/6.0 ONNX Parser inte alla ONNX-funktioner
# som behövs för att stödja dynamisk uppsampling av ONNX-formatering
# HÀr hÄrdkodar vi scale=2 som en tillfÀllig 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
Genom denna transformation kan det göras automatiskt vid export till ONNX, men i version 7 av TensorRT löstes detta problem, och vi behöver bara vÀnta lite till.
Slutsats
NÀr jag började anvÀnda Docker hade jag tvivel angÄende dess prestanda för mina uppgifter. I en av mina enheter finns det just nu en ganska stor nÀtverkstrafik som skapas av flera kameror.

Olika tester pÄ internet har rapporterat om relativt hög overhead för nÀtverksinteraktion och skrivning till VOLUME, och med det osynliga och skrÀmmande GIL, och eftersom bildtagning, drivrutinsarbete och överföring av ramar över nÀtverk Àr atomÀra operationer i lÀget hÄrd realtid, Àr fördröjningar i nÀtverket mycket kritiska för mig.
Men allt löste sig =)
P.S. Det ÄterstÄr bara att lÀgga till din favorit train loop för segmentering och sÀtta det i produktion!
Tacksamhet
Tack till gemenskapen , utan er Àr det omöjligt att utvecklas! Ett stort tack , som inspirerade mig att ta itu med DL, för sina ovÀrderliga rÄd och extraordinÀra professionalism!
AnvÀnd optimerade modeller i produktion!
Aurorai, llc
KĂ€lla: habr.com
