
Csak az első alkalommal fáj!
Helló mindenkinek! Kedves barátok, ebben a cikkben szeretném megosztani tapasztalataimat a TensorRT és a RetinaNet használatáról a repozitóriumból (ez a hivatalos repó forkja, , amely lehetővé teszi, hogy a termelésben gyorsan használjunk optimalizált modelleket). A közösségi csatornákbana futása közben rúgok fel a TensorRT használatára vonatkozó kérdésekkel, és főként a kérdések ismétlődnek, ezért úgy döntöttem, hogy a lehető legteljesebb útmutatót írok a TensorRT, RetinaNet, Unet és docker alapú gyors inferálás használatához.
A feladat leírása
Javaslom, hogy a feladatot úgy fogalmazzuk meg: szükségünk van egy adatbázis megjelölésére, a RetinaNet/Unet háló tanítására Pytorch1.3+-on, a nyert súlyok ONNX formátumba való átalakítására, majd az ezekből készült TensorRT engine konvertálására, és mindezt docker alatt, lehetőleg Ubuntu 18-on és lehetőleg ARM (Jetson)* architektúrán futtatni, így minimalizálva a környezet manuális telepítését. Ennek eredményeként egy konténert kapunk, amely nemcsak a RetinaNet/Unet exportálására és tanítására, hanem a klasszifikáció és a szegmentálás teljes körű fejlesztésére és tanítására is alkalmas minden szükséges kötelékével.
1. lépés: A környezet előkészítése
Itt fontos megjegyezni, hogy az utóbbi időben teljes mértékben elhagytam bármilyen könyvtár használatát és telepítését desktop gépen, akárcsak devbox-on. Az egyetlen, amit létre kell hoznunk vagy telepítenünk, az a python virtuális környezet és a cuda 10.2 (elég egy nvidia meghajtó is) deb formátumban.
Tegyük fel, hogy egy frissen telepített Ubuntu 18-as van. Telepítsük a cuda 10.2-t (deb), a telepítési folyamatra részletesen nem fogok kitérni, a hivatalos dokumentáció bőségesen elegendő.
Most telepítsük a dockert, a docker telepítési útmutatója könnyen megtalálható, itt egy példa , már elérhető a 19+ verzió — telepítsük azt. Ne felejtsük el lehetővé tenni a docker használatát sudo nélkül, így kényelmesebb lesz. Miután minden sikerült, ezt csináljuk:
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
És még az official repositoryba sem kell benéznünk. .
Most csináljunk egy git clone-t. .
Már csak egy kicsit van hátra, hogy elkezdhessük használni a dockert az nvidia-image-val, regisztrálnunk kell az NGC Cloud-ba, és be kell jelentkezni. Irány ide: , regisztrálunk, és miután beléptünk az NGC Cloud-ba, kattintsunk a SETUP gombra a bal felső sarokban, vagy kövessük ezt a linket: . Kattints a "kulcs generálására". Javaslom, hogy mentsd el, különben a következő látogatáskor újra generálnod kell, így amikor új gépre telepítesz, ezt a műveletet ismételni kell.
Futtatjuk:
docker login nvcr.io
Felhasználónév: $oauthtoken
Jelszó: - generált kulcs
A felhasználónevet egyszerűen másoljuk. Nos, ez így jól néz ki, a környezet készen áll!
2. lépés. Docker konténer építése
A munka második lépésében össze fogjuk állítani a dockert, és megismerkedünk a belső működésével.
Lépjünk a retina-examples projekthez tartozó gyökérmappa alá, és hajtsuk végre:
docker build --build-arg USER=$USER --build-arg UID=$UID --build-arg GID=$GID --build-arg PW=alex -t retinanet:latest retinanet/
A dockert úgy építjük, hogy átadjuk neki a jelenlegi felhasználót - ez nagyon hasznos, ha valamit írsz egy csatolt VOLUME-ra a jelenlegi felhasználó jogainak megfelelően, különben root lesz, ami problémás.
Amíg épül a docker, nézzük meg a Dockerfile-t:
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"]
Ahogy a szövegből látható, az összes kedvenc könyvtárunkat vesszük, lefordítjuk a retinanet-et, és hozzáadunk alapvető eszközöket az Ubuntu használatához, miközben beállítjuk az openssh szervert. Az első sorban éppen az nvidia kép öröklése történik, amelyhez a NGC Cloud-on bejelentkeztünk, és amely tartalmazza a Pytorch 1.3-at, TensorRT 6.x.x.x-t, és még sok más könyvtárat, amelyek lehetővé teszik a cpp forráskódunk fordítását.
3. lépés. A docker konténer indítása és hibakeresése
Lépjünk a konténer és a fejlesztői környezet fő használati esetére, először indítsuk el a nvidia dockert. Futtassuk:
docker run --gpus all --net=host -v /home/:/workspace/mounted_vol -d -P --rm --ipc=host -it retinanet:latestMost a konténer ssh-n keresztül elérhető @localhost. A sikeres indítás után nyissuk meg a projektet a PyCharm-ban. Ezután nyissuk meg
Beállítások->Projektinterpreter->Hozzáadás->Ssh Interpreter 1. lépés

2. lépés

3. lépés

Válasszunk mindent, mint a képernyőképeken:
Interpreter -> /opt/conda/bin/python— ez lesz a link a Python3.6-ra és
Szinkronizálási mappa -> /workspace/retinanetKattintsunk a befejezésre, várjuk meg az indexelést, és kész, a környezet készen áll a használatra!
FONTOS!!! Az indexelés után azonnal húzzuk ki a dockerből a lefordított fájlokat a Retinanet számára. A projekt gyökérmappájában a kontextuális menüben válasszuk a
Telepítés->LetöltésMegjelenik egy fájl és két mappa: build, retinanet.egg-info és _С.so

Ha a projekted így néz ki, akkor a környezet látja az összes szükséges fájlt, és készen állunk a RetinaNet betanítására.
4. lépés. Az adatok megjelölése és a detektor betanítása
A megjelöléshez főként a következőt használom — egy kellemes és kényelmes eszköz, az utóbbi időben sok hibát javítottak ki, és most sokkal jobban viselkedik.
Tegyük fel, hogy megjelölte az adatbázist és letöltötte, de közvetlenül nem tudja a RetinaNetbe behelyezni, mivel a saját formátumában van, és ahhoz, hogy COCO formátumba konvertálhassa, szükség van a következőre. A konvertáló eszköz a következő helyen található:
markup_utils/supervisly_to_coco.pyKérlek, vedd figyelembe, hogy a Category a szkriptben példa, és neked a saját kategóriádat kell megadnod (a background kategóriát ne add hozzá).
categories = [{'id': 1, 'name': '1'},
{'id': 2, 'name': '2'},
{'id': 3, 'name': '3'},
{'id': 4, 'name': '4'}] Az eredeti tároló szerzői valamiért úgy döntöttek, hogy nem tanítanak mást, csak COCO/VOC-t a detekciós feladathoz, ezért egy kicsit módosítani kellett az alap fájlt.
retinanet/dataset.pyHozzáadva a kedvenc augmentációidat itt, és eltávolítva a COCO-ba keményen beépített kategóriákat. Lehetőség van nagy detekciós területek kivágására is, ha nagy képeken keresel kis objektumokat, és kis adatbázissal rendelkezel =), és semmi nem működik, de erről majd máskor.
Összességében a tanító ciklus is gyenge volt, kezdetben nem mentette a checkpointokat, egy szörnyű scheduler-t használt, stb. De most már csak annyit kell tenned, hogy kiválasztod a backbone-t és végrehajtod
/opt/conda/bin/python retinanet/main.pya következő paraméterekkel:
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
A konzolban ezt fogod látni:
A modell inicializálása...
modell: RetinaNet
háttér: ResNet18FPN
osztályok: 2, horgonyok: 9
Kiválasztott optimalizálási szint O0: Tiszta FP32 képzés.
Az optimalizálási szint alapértelmezett beállításai:
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
Feldolgozás felhasználói felülírások (további kwargs, amelyek nem None)...
A felülírások feldolgozása után az optimalizálási lehetőségek:
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
Adatbázis előkészítése...
loader: pytorch
méretezés: [1024, 1280], max: 1280
eszköz: 4 gpu
batch: 4, precízió: vegyes
A modell tanítása 20000 iteráción keresztül...
[ 1/20000] fókusz veszteség: 0.95619, doboz veszteség: 0.51584, 4-batch idő: 4.042s (fw: 0.698s, bw: 0.459s), 1.0 im/s, lr: 0.0001
[ 12/20000] fókusz veszteség: 0.76191, doboz veszteség: 0.31794, 0.187s/4-batch (fw: 0.055s, bw: 0.133s), 21.4 im/s, lr: 0.0001
[ 24/20000] fókusz veszteség: 0.65036, doboz veszteség: 0.30269, 0.173s/4-batch (fw: 0.045s, bw: 0.128s), 23.1 im/s, lr: 0.0001
[ 36/20000] fókusz veszteség: 0.46425, doboz veszteség: 0.23141, 0.178s/4-batch (fw: 0.047s, bw: 0.131s), 22.4 im/s, lr: 0.0001
[ 48/20000] fókusz veszteség: 0.45115, doboz veszteség: 0.23505, 0.180s/4-batch (fw: 0.047s, bw: 0.133s), 22.2 im/s, lr: 0.0001
[ 59/20000] fókusz veszteség: 0.38958, doboz veszteség: 0.25373, 0.184s/4-batch (fw: 0.049s, bw: 0.134s), 21.8 im/s, lr: 0.0001
[ 71/20000] fókusz veszteség: 0.37733, doboz veszteség: 0.23988, 0.174s/4-batch (fw: 0.049s, bw: 0.125s), 22.9 im/s, lr: 0.0001
[ 83/20000] fókusz veszteség: 0.39514, doboz veszteség: 0.23878, 0.181s/4-batch (fw: 0.048s, bw: 0.133s), 22.1 im/s, lr: 0.0001
[ 94/20000] fókusz veszteség: 0.39947, doboz veszteség: 0.23817, 0.185s/4-batch (fw: 0.050s, bw: 0.134s), 21.6 im/s, lr: 0.0001
[ 105/20000] fókusz veszteség: 0.37343, doboz veszteség: 0.20238, 0.182s/4-batch (fw: 0.048s, bw: 0.134s), 22.0 im/s, lr: 0.0001
[ 116/20000] fókusz veszteség: 0.19689, doboz veszteség: 0.17371, 0.183s/4-batch (fw: 0.050s, bw: 0.132s), 21.8 im/s, lr: 0.0001
[ 128/20000] fókusz veszteség: 0.20368, doboz veszteség: 0.16538, 0.178s/4-batch (fw: 0.046s, bw: 0.131s), 22.5 im/s, lr: 0.0001
[ 140/20000] fókusz veszteség: 0.22763, doboz veszteség: 0.15772, 0.176s/4-batch (fw: 0.050s, bw: 0.126s), 22.7 im/s, lr: 0.0001
[ 148/20000] fókusz veszteség: 0.21997, doboz veszteség: 0.18400, 0.585s/4-batch (fw: 0.047s, bw: 0.144s), 6.8 im/s, lr: 0.0001
A Pontosság Átlag (AP) @[ IoU=0.50:0.95 | terület= mind | maxDets=100 ] = 0.52674
A Pontosság Átlag (AP) @[ IoU=0.50 | terület= mind | maxDets=100 ] = 0.91450
A Pontosság Átlag (AP) @[ IoU=0.75 | terület= mind | maxDets=100 ] = 0.35172
A Pontosság Átlag (AP) @[ IoU=0.50:0.95 | terület= kicsi | maxDets=100 ] = 0.61881
A Pontosság Átlag (AP) @[ IoU=0.50:0.95 | terület=közepes | maxDets=100 ] = -1.00000
A Pontosság Átlag (AP) @[ IoU=0.50:0.95 | terület= nagy | maxDets=100 ] = -1.00000
A Visszahívás Átlag (AR) @[ IoU=0.50:0.95 | terület= mind | maxDets= 1 ] = 0.58824
A Visszahívás Átlag (AR) @[ IoU=0.50:0.95 | terület= mind | maxDets= 10 ] = 0.61765
A Visszahívás Átlag (AR) @[ IoU=0.50:0.95 | terület= mind | maxDets= 100 ] = 0.61765
A Visszahívás Átlag (AR) @[ IoU=0.50:0.95 | terület= kicsi | maxDets=100 ] = 0.61765
A Visszahívás Átlag (AR) @[ IoU=0.50:0.95 | terület=közepes | maxDets=100 ] = -1.00000
A Visszahívás Átlag (AR) @[ IoU=0.50:0.95 | terület= nagy | maxDets=100 ] = -1.00000
A modell mentése: 148A teljes paramétersorozat megtekintéséhez nézze meg
retinanet/main.pyAlapvetően ezek az észleléshez szabványos beállítások, és van leírásuk. Indítsa el a tanítást, és várja meg az eredményeket. Példa az inferálásra megtalálható itt:
retinanet/infer_example.pyvagy futtassa a parancsot:
/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
A Focal Loss és több backbone már be van építve a tárolóba, és könnyedén integrálhatók a saját megoldások.
retinanet/backbones/*.pyA táblázatban a szerzők néhány jellemzőt sorolnak fel:

Van továbbá ResNeXt50_32x4dFPN és ResNeXt101_32x8dFPN backbone is, amelyek a torchvision-ből származnak.
Remélem, hogy a detektálással kicsit tisztábban látunk, de mindenképpen érdemes átnézni a hivatalos dokumentációt, hogy megértsük az exportálási és naplózási módokat..
5. lépés. Unet modellek exportálása és inferálása Resnet enkóderrel.
Ahogy bizonyára észrevették, a Dockerfile-ban telepítve lettek a szegmentációhoz szükséges könyvtárak, és különösen a csodálatos könyvtár . A uNet csomagban található példák a PyTorch checkpointok inferálására és exportálására az engine TensorRT-be.
A fő probléma a Unet-szerű modellek ONNX-ból TensorRT-be való exportálásakor az, hogy rögzített méretű Upsample értéket kell megadni, vagy a ConvTranspose2D-t kell használnunk:
import torch.onnx.symbolic_opset9 as onnx_symbolic
def upsample_nearest2d(g, input, output_size):
# Jelenleg a TRT 5.1/6.0 ONNX Parser nem támogatja az összes ONNX op-t,
# amire szükség van a dinamikus Upsampling ONNX képlet támogatásához.
# Itt a skálát 2-re keménykódoljuk, mint ideiglenes megoldás.
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
Ezzel a transzformációval ezt automatikusan meg tudjuk tenni az ONNX-be való exportáláskor, de a TensorRT 7-es verziójában ezt a problémát megoldották, és már csak egy kicsit kell várnunk.
Zárás
Amikor elkezdtem használni a Dockert, kétségeim voltak a teljesítménye miatt a feladataimhoz. Az egyik aggregátoromban most meglehetősen nagy hálózati forgalom keletkezik több kamerából.

Különböző tesztek az interneten viszonylag nagy overheadről beszéltek a hálózati interakciók és a VOLUME-ra való írás esetén, plusz a rejtélyes és félelmetes GIL miatt, és mivel a keretek rögzítése, a meghajtó működése és a keretek hálózaton való továbbítása atomáris művelet a hard real-time, a hálózati késések számomra nagyon kritikusak.
De végül minden rendben lett =)
P.S. Csak annyit kell még hozzátenni, hogy a kedvenc train loop-ját szegmentáláshoz és irány a termelés!
Hálák
Köszönet a közösségnek , nélküle lehetetlen fejlődni! Hatalmas köszönet , aki arra ösztönzött, hogy a DL-vel foglalkozzam, az értékes tanácsaiért és rendkívüli szakértelméért!
Használjon optimalizált modelleket a termelésben!
Aurorai, llc
Forrás: habr.com
