
Bolí to jen poprvé!
Ahoj všichni! Drazí přátelé, v tomto článku se chci podělit o své zkušenosti s používáním TensorRT, RetinaNet založeného na repozitáři (to je fork oficiální repozitáře od , který vám umožní začít používat optimalizované modely v production co nejrychleji). Při procházení zpráv v komunitních kanálech , narážím na dotazy týkající se používání TensorRT, a většina otázek se opakuje, proto jsem se rozhodl napsat co nejúplnější příručku pro použití rychlého inferenčního systému založeného na TensorRT, RetinaNet, Unet a dockeru.
Popis úkolu
Navrhuji úkol formulovat takto: je třeba anotovat dataset, trénovat síť RetinaNet/Unet na Pytorch1.3+, převedeme získané váhy do ONNX, následně je převedeme do TensorRT engine a celé to spustíme v dockeru, ideálně na Ubuntu 18 a velmi doporučeno na architektuře ARM(Jetson)*, čímž minimalizujeme manuální nasazení prostředí. Nakonec dostaneme kontejner připravený nejen k exportu a trénování RetinaNet/Unet, ale také k plnohodnotnému vývoji a trénování klasifikace a segmentace se všemi potřebnými vazbami.
Krok 1. Příprava prostředí
Je důležité poznamenat, že v poslední době jsem úplně přestal používat a nasazovat jakékoli knihovny na desktopovém počítači, tak jako na devboxu. Jediné, co musím vytvářet a instalovat — je python virtuální prostředí a cuda 10.2 (můžete se omezit na jeden nvidia driver) z deb balíčku.
Předpokládejme, že máte čerstvě nainstalované Ubuntu 18. Nainstalujeme cuda 10.2 (deb), nebudu se podrobně zabývat procesem instalace, oficiální dokumentace je více než dostačující.
Nyní nainstalujeme docker, návod na instalaci dockera můžete snadno najít, zde je příklad , již je k dispozici verze 19+ — instalujeme ji. A nezapomeňte umožnit použití dockera bez sudo, tak bude pohodlnější. Po úspěšném dokončení to uděláme takto:
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
A můžete se ani nepodívat do oficiálního repozitáře .
Nyní uděláme git clone .
Zbývá jen málo, abychom mohli začít používat Docker s nvidia obrazem. Nejprve se musíme registrovat v NGC Cloud a přihlásit se. Jdeme sem , registrujeme se a poté, co se dostaneme do NGC Cloud, klikneme na SETUP v levém horním rohu obrazovky nebo přejdeme na tento odkaz . Klikněte na „vygenerovat klíč“. Doporučuji ho uložit, jinak při příští návštěvě bude třeba ho vygenerovat znovu a při nastavování na novém zařízení tuto operaci zopakovat.
Provedeme:
docker login nvcr.io
Uživatelské jméno: $oauthtoken
Heslo: - vygenerovaný klíč
Uživatelské jméno jednoduše zkopírujte. No a máme to, prostředí je připraveno!
Krok 2. Sestavení docker kontejneru
Ve druhém kroku naší práce poskládáme docker a seznámíme se s jeho vnitřnosti.
Přejdeme do kořenové složky vzhledem k projektu retina-examples a provedeme
docker build --build-arg USER=$USER --build-arg UID=$UID --build-arg GID=$GID --build-arg PW=alex -t retinanet:latest retinanet/
Sestavujeme docker a předáváme mu aktuálního uživatele — to je velmi užitečné, pokud budete něco psát na připojeném VOLUME s právy aktuálního uživatele, jinak to bude pod rootem a obtížné.
Zatímco se docker sestavuje, pojďme si prostudovat 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"]
Jak je vidět z textu, vezmeme všechny naše oblíbené knihovny, zkompilujeme retinanet, přidáme základní nástroje pro pohodlnou práci s Ubuntu a nastavíme server openssh. První řádek se týká dědění obrazu nvidia, pro který jsme se přihlásili do NGC Cloud a který obsahuje Pytorch1.3, TensorRT6.x.x.x a spoustu dalších knihoven, které umožňují zkompilovat cpp zdrojové kódy našeho detektoru.
Krok 3. Spuštění a ladění docker kontejneru
Přejdeme k hlavnímu případu použití kontejneru a vývojového prostředí, nejprve spustíme nvidia docker. Provedeme:
docker run --gpus all --net=host -v /home/:/workspace/mounted_vol -d -P --rm --ipc=host -it retinanet:latestNyní je kontejner dostupný přes ssh @localhost. Po úspěšném spuštění otevřeme projekt v PyCharm. Dále otevřeme
Nastavení->Interpret projektů->Přidat->Ssh interpreter Krok 1

Krok 2

Krok 3

Vybereme všechno jako na screenshotu,
Interpreter -> /opt/conda/bin/python— to bude odkaz na Python3.6 a
Sync folder -> /workspace/retinanetKlikneme na finish, čekáme na indexování a všechno, prostředí je připraveno k použití!
DŮLEŽITÉ!!! Ihned po indexaci stáhneme ze dockeru zkompilované soubory pro Retinanet. V kontextovém menu v kořenovém adresáři projektu vybereme položku
Nasazení->StáhnoutObjeví se jeden soubor a dvě složky build, retinanet.egg-info a _С.so

Pokud váš projekt vypadá takto, pak prostředí vidí všechny potřebné soubory a jsme připraveni na trénink RetinaNet.
Krok 4. Označujeme data a trénujeme detektor
Pro označování většinou používám — příjemný a uživatelsky přívětivý nástroj, v poslední době se opravilo spoustu chyb a začal se chovat mnohem lépe.
Předpokládejme, že jste dataset označili a stáhli jej, ale hned ho do našeho RetinaNet nedáte, protože je ve vlastním formátu a proto je třeba jej převést do COCO. Nástroj pro převod se nachází v:
markup_utils/supervisly_to_coco.pyVšimněte si, že kategorie ve skriptu je příklad a je třeba vložit vaše (kategorii pozadí přidávat nemusíte)
categories = [{'id': 1, 'name': '1'},
{'id': 2, 'name': '2'},
{'id': 3, 'name': '3'},
{'id': 4, 'name': '4'}] Autoři původního repozitáře se z nějakého důvodu domnívali, že nic jiného než COCO/VOC nebudete trénovat pro detekci, a proto bylo nutné mírně upravit původní soubor
retinanet/dataset.pyPřidáním zde oblíbených augmentací a odstranit pevně zabudované kategorie z COCO. Také existuje možnost oříznout velké oblasti detekce, pokud hledáte malé objekty na velkých obrázcích a máte malý dataset =), a nic nefunguje, ale o tom jindy.
Celkově je tréninková smyčka také slabá, původně neukládala kontrolní body, používala nějaký hrozný plánovač atd. Ale teď už stačí jen vybrat backbone a provést to.
/opt/conda/bin/python retinanet/main.pys parametry:
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
V konzole uvidíte:
Inicializace modelu...
model: RetinaNet
backbone: ResNet18FPN
třídy: 2, kotvy: 9
Vybraná úroveň optimalizace O0: Čisté FP32 trénování.
Výchozí hodnoty pro tuto úroveň optimalizace jsou:
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
Zpracování uživatelských přepsání (další parametry, které nejsou None)...
Po zpracování přepsání jsou možnosti optimalizace:
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
Příprava datové sady...
loader: pytorch
resize: [1024, 1280], max: 1280
zařízení: 4 gpus
dávka: 4, preciznost: smíšená
Trénování modelu po dobu 20000 iterací...
[ 1/20000] ztráta ohniskové ztráty: 0.95619, ztráta boxu: 0.51584, 4.042s/4-dávka (vpřed: 0.698s, vzad: 0.459s), 1.0 snímků/s, lr: 0.0001
[ 12/20000] ztráta ohniskové ztráty: 0.76191, ztráta boxu: 0.31794, 0.187s/4-dávka (vpřed: 0.055s, vzad: 0.133s), 21.4 snímků/s, lr: 0.0001
[ 24/20000] ztráta ohniskové ztráty: 0.65036, ztráta boxu: 0.30269, 0.173s/4-dávka (vpřed: 0.045s, vzad: 0.128s), 23.1 snímků/s, lr: 0.0001
[ 36/20000] ztráta ohniskové ztráty: 0.46425, ztráta boxu: 0.23141, 0.178s/4-dávka (vpřed: 0.047s, vzad: 0.131s), 22.4 snímků/s, lr: 0.0001
[ 48/20000] ztráta ohniskové ztráty: 0.45115, ztráta boxu: 0.23505, 0.180s/4-dávka (vpřed: 0.047s, vzad: 0.133s), 22.2 snímků/s, lr: 0.0001
[ 59/20000] ztráta ohniskové ztráty: 0.38958, ztráta boxu: 0.25373, 0.184s/4-dávka (vpřed: 0.049s, vzad: 0.134s), 21.8 snímků/s, lr: 0.0001
[ 71/20000] ztráta ohniskové ztráty: 0.37733, ztráta boxu: 0.23988, 0.174s/4-dávka (vpřed: 0.049s, vzad: 0.125s), 22.9 snímků/s, lr: 0.0001
[ 83/20000] ztráta ohniskové ztráty: 0.39514, ztráta boxu: 0.23878, 0.181s/4-dávka (vpřed: 0.048s, vzad: 0.133s), 22.1 snímků/s, lr: 0.0001
[ 94/20000] ztráta ohniskové ztráty: 0.39947, ztráta boxu: 0.23817, 0.185s/4-dávka (vpřed: 0.050s, vzad: 0.134s), 21.6 snímků/s, lr: 0.0001
[ 105/20000] ztráta ohniskové ztráty: 0.37343, ztráta boxu: 0.20238, 0.182s/4-dávka (vpřed: 0.048s, vzad: 0.134s), 22.0 snímků/s, lr: 0.0001
[ 116/20000] ztráta ohniskové ztráty: 0.19689, ztráta boxu: 0.17371, 0.183s/4-dávka (vpřed: 0.050s, vzad: 0.132s), 21.8 snímků/s, lr: 0.0001
[ 128/20000] ztráta ohniskové ztráty: 0.20368, ztráta boxu: 0.16538, 0.178s/4-dávka (vpřed: 0.046s, vzad: 0.131s), 22.5 snímků/s, lr: 0.0001
[ 140/20000] ztráta ohniskové ztráty: 0.22763, ztráta boxu: 0.15772, 0.176s/4-dávka (vpřed: 0.050s, vzad: 0.126s), 22.7 snímků/s, lr: 0.0001
[ 148/20000] ztráta ohniskové ztráty: 0.21997, ztráta boxu: 0.18400, 0.585s/4-dávka (vpřed: 0.047s, vzad: 0.144s), 6.8 snímků/s, lr: 0.0001
Průměrná přesnost (AP) @[ IoU=0.50:0.95 | oblast= všechny | maxDets=100 ] = 0.52674
Průměrná přesnost (AP) @[ IoU=0.50 | oblast= všechny | maxDets=100 ] = 0.91450
Průměrná přesnost (AP) @[ IoU=0.75 | oblast= všechny | maxDets=100 ] = 0.35172
Průměrná přesnost (AP) @[ IoU=0.50:0.95 | oblast= malá | maxDets=100 ] = 0.61881
Průměrná přesnost (AP) @[ IoU=0.50:0.95 | oblast=střední | maxDets=100 ] = -1.00000
Průměrná přesnost (AP) @[ IoU=0.50:0.95 | oblast= veliká | maxDets=100 ] = -1.00000
Průměrná návratnost (AR) @[ IoU=0.50:0.95 | oblast= všechny | maxDets= 1 ] = 0.58824
Průměrná návratnost (AR) @[ IoU=0.50:0.95 | oblast= všechny | maxDets= 10 ] = 0.61765
Průměrná návratnost (AR) @[ IoU=0.50:0.95 | oblast= všechny | maxDets=100 ] = 0.61765
Průměrná návratnost (AR) @[ IoU=0.50:0.95 | oblast= malá | maxDets=100 ] = 0.61765
Průměrná návratnost (AR) @[ IoU=0.50:0.95 | oblast=střední | maxDets=100 ] = -1.00000
Průměrná návratnost (AR) @[ IoU=0.50:0.95 | oblast= veliká | maxDets=100 ] = -1.00000
Ukládání modelu: 148Pokud chcete prozkoumat všechny parametry, podívejte se na
retinanet/main.pyObecně jsou standardní pro detekci a mají popis. Spusťte školení a vyčkejte na výsledky. Příklad inference naleznete v:
retinanet/infer_example.pynebo zadejte následující příkaz:
/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
V repozitáři je již zabudován Focal Loss a několik backbone, a také se snadno implementují vlastní.
retinanet/backbones/*.pyV tabulce autoři uvádějí některé charakteristiky:

Také existuje backbone ResNeXt50_32x4dFPN a ResNeXt101_32x8dFPN, převzatý z torchvision.
Doufám, že jsme si s detekcí trochu objasnili, ale je nutné přečíst oficiální dokumentaci, aby se pochopily režimy exportu a logování..
Krok 5. Export a inferenční modely Unet s enkodérem Resnet.
Jak jste si pravděpodobně všimli, v Dockerfile byly nainstalovány knihovny pro segmentaci a zejména úžasná knihovna . V balíčku Unet lze najít příklady inferencí a exportu pytorch checkpointů do motoru TensorRT.
Hlavní problém při exportu modelů podobných Unet z ONNX do TensorRT je potřeba stanovit pevnou velikost Upsample nebo použít ConvTranspose2D:
import torch.onnx.symbolic_opset9 as onnx_symbolic
def upsample_nearest2d(g, input, output_size):
# Momentálně TRT 5.1/6.0 ONNX Parser nepodporuje všechny ONNX operace
# potřebné k podpoře dynamického upsampling ONNX formulace
# Zde tvrdě kódujeme scale=2 jako dočasné řešení
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
Pomocí této transformace je možné to udělat automaticky při exportu do ONNX, ale s 7 verzí TensorRT byl tento problém vyřešen, a my musíme čekat už jen chvíli.
Závěr
Když jsem začal používat Docker, měl jsem pochybnosti o jeho výkonu pro mé úkoly. V jednom z mých agregátorů je nyní docela velký síťový provoz generovaný několika kamerami.

Různé testy na internetu mluvily o relativně velkém overheadu na síťovou interakci a zápis na VOLUME, navíc neznámý a děsivý GIL, a protože snímání snímku, práce ovladače a přenos snímku po síti jsou atomární operace v režimu hard real-time, zpoždění v síti je pro mne velmi kritické.
Ale všechno se to zvládlo =)
P.S. Zůstává přidat váš oblíbený tréninkový cyklus pro segmentaci a do produkce!
Poděkování
Děkuji komunitě , bez ní není možné se rozvíjet! Obrovské díky , který mě přiměl zabývat se DL, za jeho cenné rady a mimořádný profesionalismus!
Používejte v produkci optimalizované modely!
Aurorai, llc
Zdroj: habr.com
