
Dhemb vetëm herën e parë!
Përshëndetje të gjithëve! Të dashur miq, në këtë artikull dëshiroj të ndaj përvojën time në përdorimin e TensorRT, RetinaNet të bazuar në depo. (kjo është një fork i depozites zyrtare nga , e cila do të lejojë të filloni të përdorni modele të optimizuara në prodhim në një kohë të shkurtër). Duke shfletuar mesazhet në kanalet e komunitetit , has këto pyetje mbi përdorimin e TensorRT, dhe kryesisht pyetjet përsëriten, prandaj vendosa të shkruaj sa më të plota një udhëzues për përdorimin e inferencës së shpejtë bazuar në TensorRT, RetinaNet, Unet dhe docker.
Përshkrimi i detyrës
Propozoj të formulojmë detyrën kështu: na nevojitet të shënojmë dataset-in, të trajnojmë një rrjet RetinaNet/Unet në Pytorch1.3+, të transformojmë peshat e marra në ONNX, më pas të konvertojmë ato në engine TensorRT dhe gjithë këtë ta nisni në docker, preferohet në Ubuntu 18 dhe është shumë e dëshirueshme në arkitekturën ARM(Jetson)*, duke minimizuar kështu vendosjen manuale të ambientit. Në fund, do të na dalë një kontejner i gatshëm jo vetëm për eksport dhe trajnim të RetinaNet/Unet, por edhe për zhvillim dhe trajnim të klasifikimit, segmentimit me të gjithë mbështetje të nevojshme.
Hapi 1. Përgatitja e mjedisit
ĂshtĂ« e rĂ«ndĂ«sishme tĂ« theksohet se sĂ« fundmi kam kaluar plotĂ«sisht nĂ« shmangien e pĂ«rdorimit dhe ndĂ«rtimeve tĂ« ndonjĂ« biblioteke nĂ« makinĂ«n desktop, ashtu si dhe nĂ« devbox. E vetmja gjĂ« qĂ« duhet tĂ« krijoj dhe instalojĂ« Ă«shtĂ« mjedisi virtual i Python dhe cuda 10.2 (mund tĂ« mjaftohet me njĂ« driver nvidia) nga deb.
Le të supozojmë se keni një Ubuntu 18 të sapoinstaluar. Do të instalojmë cuda 10.2 (deb), nuk do të ndalem në procesin e instalimit, dokumentacioni zyrtar është mjaftueshëm i detajuar.
Tani do tĂ« instalojmĂ« docker, udhĂ«zimet pĂ«r instalimin e docker-it janĂ« lehtĂ«sisht tĂ« gjetshme, ja njĂ« shembull , tashmĂ« Ă«shtĂ« nĂ« dispozicion versioni 19+ â e vendosim atĂ«. Dhe mos harroni tĂ« lejoni pĂ«rdorimin e docker pa sudo, kĂ«shtu do tĂ« jetĂ« mĂ« e lehtĂ«. Pasi tĂ« jetĂ« gjithçka e rregullt, bĂ«ni kĂ«shtu:
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
Dhe madje as nuk keni nevojë të shikoni në depozitat zyrtare .
Tani bëni git clone .
Ka mbetur shumë pak për të filluar përdorimin e docker me imazhin nvidia, na nevojitet të regjistrohemi në NGC Cloud dhe të identifikoheshim. Le të shkojmë këtu , regjistrohemi dhe pasi të hyjmë në NGC Cloud, klikojmë SETUP në cepin e majtë të ekranit ose kalojmë përmes kësaj lidhjeje . Klikoni "gjenë çelësin". E rekomandoj ta ruani, përndryshe gjatë vizitës së ardhshme do të duhet ta gjeneroni përsëri dhe, përkatësisht, gjatë instalimeve në një makinë të re, do të duhet të kryeni përsëri këtë operacion.
Le të ekzekutojmë:
docker login nvcr.io
Username: $oauthtoken
Password: - çelësi i gjeneruar
Username thjesht kopjoni. Ja, konsideroni se mjedisi është instaluar!
Hapi 2. Ndërtimi i kontejnerit docker
Në hapat e dytë të punës sonë, do të ndërtojmë docker dhe do të njihemi me brendësinë e tij.
Do të kalojmë në dosjen rrënjësore në lidhje me projektin retina-examples dhe do të përmbushim
docker build --build-arg USER=$USER --build-arg UID=$UID --build-arg GID=$GID --build-arg PW=alex -t retinanet:latest retinanet/
Ne po ndĂ«rtojmĂ« docker duke kaluar pĂ«rdoruesin aktual â kjo Ă«shtĂ« shumĂ« e dobishme nĂ«se do tĂ« shkruani diçka nĂ« VOLUME tĂ« koduar me tĂ« drejtat e pĂ«rdoruesit aktuell, ndryshe do tĂ« jetĂ« root dhe e dhimbshme.
Derisa docker është duke u ndërtuar, le të studiojmë Dockerfile:
NGA 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"]
Siç shihet nga teksti, ne marrim të gjitha libraritë tona të preferuara, kompilojmë retinanet, vendosim disa mjete bazë për lehtësi punimi me Ubuntu dhe konfigurojmë serverin openssh. Rreshti i parë është pikërisht trashëgimia e imazhit nvidia, për të cilin ne bëmë hyrjen në NGC Cloud dhe që përmban Pytorch1.3, TensorRT6.x.x.x dhe një sërë bibliotekash tjetër që lejojnë kompilimin e burimeve cpp të detektorit tonë.
Hapi 3. Nisja dhe debugging-u i kontejnerit docker
Të kalojmë në rastin kryesor të përdorimit të kontejnerit dhe mjedisit të zhvillimit, fillimisht do të ngremë nvidia docker. Do të ekzekutojmë:
docker run --gpus all --net=host -v /home/:/workspace/mounted_vol -d -P --rm --ipc=host -it retinanet:latestTani kontejneri është i aksesueshëm përmes ssh @localhost. Pas nisjes së suksesshme, hapim projektin në PyCharm. Më pas hapim
Settings->Project Interpreter->Add->Ssh Interpreter Hapi 1

Hapi 2

Hapi 3

Zgjidhim gjithçka siç është në screenshot-et,
Interpreter -> /opt/conda/bin/pythonâ ky do tĂ« jetĂ« ln nĂ« Python3.6 dhe
Sync folder -> /workspace/retinanetKlikojmë përfundimi, presim indeksimin, dhe gjithçka, mjedisi është i gatshëm për përdorim!
E RĂNDĂSISHME!!! MenjĂ«herĂ« pas indeksimit, tĂ« tĂ«rheqim nga docker skedarĂ«t e kompiluar pĂ«r Retinanet. NĂ« menynĂ« kontekstuese nĂ« rrĂ«njĂ«n e projektit, do tĂ« zgjedhim opsionin
Deployment->DownloadDo të shfaqen një skedar dhe dy dosje build, retinanet.egg-info dhe _Х.so

Nëse projekti juaj duket kështu, atëherë mjedisi sheh të gjitha skedarët e nevojshëm dhe jemi të gatshëm për të trajnuar RetinaNet.
Hapi 4. Shënjimi i të dhënave dhe trajnimet e detektorit
PĂ«r shĂ«njimin unĂ«, nĂ« pĂ«rgjithĂ«si, pĂ«rdor â njĂ« mjet i kĂ«ndshĂ«m dhe i rehatshĂ«m, sĂ« fundmi janĂ« riparuar shumĂ« probleme dhe tani po sjell rezultate shumĂ« mĂ« tĂ« mira.
Supozoni se keni shënjuar datasetin dhe e keni shkarkuar, por nuk mund ta futni menjëherë në RetinaNet tonë, sepse ai është në formatin e tij dhe për këtë na nevojitet ta konvertojmë në COCO. Mjeti për konvertim ndodhet në:
markup_utils/supervisly_to_coco.pyKujtoni se Kategoria në skript është një shembull dhe ju duhet të vendosni tuajat (nuk është e nevojshme të shtoni kategorinë background)
categories = [{'id': 1, 'name': '1'},
{'id': 2, 'name': '2'},
{'id': 3, 'name': '3'},
{'id': 4, 'name': '4'}] Autorët e depozitës origjinale për një arsye ose tjetër menduan se nuk do të strehoni asgjë tjetër përveç COCO/VOC për detektimin, prandaj duhej ta redaktojmë pak skedarin fillestar
retinanet/dataset.pyDuke shtuar këtu augmentimet e preferuara dhe hiqni kategoritë e ngurta të integruara nga COCO. Ka gjithashtu mundësinë për të prerë zona të mëdha të detektimit, nëse po kërkoni objekte të vogla në imazhe të mëdha, keni një dataset të vogël =), dhe asgjë nuk funksionon, por për këtë një herë tjetër.
Në përgjithësi, tranimi loop është gjithashtu i dobët, në fillim nuk po ruante piketat, përdorte një scheduler të tmerrshëm etj. Por tani ju mbetet vetëm të zgjidhni backbone dhe të ekzekutoni
/opt/conda/bin/python retinanet/main.pyme parametrat:
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
Do të shihni në konsolë:
Duke modelin...
modeli: RetinaNet
bazamenti: ResNet18FPN
klasat: 2, ankorët: 9
Zgjedhur niveli i optimizimit O0: Trajnim të pastër FP32.
Parazgjedhjet për këtë nivel optimizimi janë:
enabled : E vërtetë
opt_level : O0
cast_model_type : torch.float32
patch_torch_functions : E falsifikuar
keep_batchnorm_fp32 : Asnjë
master_weights : E falsifikuar
loss_scale : 1.0
Po procesojmë mbivendosjet e përdoruesit (kërkesa shtesë që nuk janë asnjë)...
Pas përpunimit të mbivendosjeve, opsionet e optimizimit janë:
enabled : E vërtetë
opt_level : O0
cast_model_type : torch.float32
patch_torch_functions : E falsifikuar
keep_batchnorm_fp32 : Asnjë
master_weights : E falsifikuar
loss_scale : 128.0
Duke përgatitur datasetin...
ngarkuesi: pytorch
rihap: [1024, 1280], maksimumi: 1280
pajisja: 4 gpus
grupi: 4, saktësia: e përzier
Duke trajnuar modelin për 20000 iteracione...
[ 1/20000] humbja fokale: 0.95619, humbja e kutisë: 0.51584, 4.042s/4-grup (fw: 0.698s, bw: 0.459s), 1.0 im/s, lr: 0.0001
[ 12/20000] humbja fokale: 0.76191, humbja e kutisë: 0.31794, 0.187s/4-grup (fw: 0.055s, bw: 0.133s), 21.4 im/s, lr: 0.0001
[ 24/20000] humbja fokale: 0.65036, humbja e kutisë: 0.30269, 0.173s/4-grup (fw: 0.045s, bw: 0.128s), 23.1 im/s, lr: 0.0001
[ 36/20000] humbja fokale: 0.46425, humbja e kutisë: 0.23141, 0.178s/4-grup (fw: 0.047s, bw: 0.131s), 22.4 im/s, lr: 0.0001
[ 48/20000] humbja fokale: 0.45115, humbja e kutisë: 0.23505, 0.180s/4-grup (fw: 0.047s, bw: 0.133s), 22.2 im/s, lr: 0.0001
[ 59/20000] humbja fokale: 0.38958, humbja e kutisë: 0.25373, 0.184s/4-grup (fw: 0.049s, bw: 0.134s), 21.8 im/s, lr: 0.0001
[ 71/20000] humbja fokale: 0.37733, humbja e kutisë: 0.23988, 0.174s/4-grup (fw: 0.049s, bw: 0.125s), 22.9 im/s, lr: 0.0001
[ 83/20000] humbja fokale: 0.39514, humbja e kutisë: 0.23878, 0.181s/4-grup (fw: 0.048s, bw: 0.133s), 22.1 im/s, lr: 0.0001
[ 94/20000] humbja fokale: 0.39947, humbja e kutisë: 0.23817, 0.185s/4-grup (fw: 0.050s, bw: 0.134s), 21.6 im/s, lr: 0.0001
[ 105/20000] humbja fokale: 0.37343, humbja e kutisë: 0.20238, 0.182s/4-grup (fw: 0.048s, bw: 0.134s), 22.0 im/s, lr: 0.0001
[ 116/20000] humbja fokale: 0.19689, humbja e kutisë: 0.17371, 0.183s/4-grup (fw: 0.050s, bw: 0.132s), 21.8 im/s, lr: 0.0001
[ 128/20000] humbja fokale: 0.20368, humbja e kutisë: 0.16538, 0.178s/4-grup (fw: 0.046s, bw: 0.131s), 22.5 im/s, lr: 0.0001
[ 140/20000] humbja fokale: 0.22763, humbja e kutisë: 0.15772, 0.176s/4-grup (fw: 0.050s, bw: 0.126s), 22.7 im/s, lr: 0.0001
[ 148/20000] humbja fokale: 0.21997, humbja e kutisë: 0.18400, 0.585s/4-grup (fw: 0.047s, bw: 0.144s), 6.8 im/s, lr: 0.0001
Saktësia Mesatare (AP) @[ IoU=0.50:0.95 | zona= të gjithë | maxDets=100 ] = 0.52674
Saktësia Mesatare (AP) @[ IoU=0.50 | zona= të gjithë | maxDets=100 ] = 0.91450
Saktësia Mesatare (AP) @[ IoU=0.75 | zona= të gjithë | maxDets=100 ] = 0.35172
Saktësia Mesatare (AP) @[ IoU=0.50:0.95 | zona= e vogël | maxDets=100 ] = 0.61881
Saktësia Mesatare (AP) @[ IoU=0.50:0.95 | zona=mesatare | maxDets=100 ] = -1.00000
Saktësia Mesatare (AP) @[ IoU=0.50:0.95 | zona= e madhe | maxDets=100 ] = -1.00000
Kujtesa Mesatare (AR) @[ IoU=0.50:0.95 | zona= të gjithë | maxDets= 1 ] = 0.58824
Kujtesa Mesatare (AR) @[ IoU=0.50:0.95 | zona= të gjithë | maxDets= 10 ] = 0.61765
Kujtesa Mesatare (AR) @[ IoU=0.50:0.95 | zona= të gjithë | maxDets=100 ] = 0.61765
Kujtesa Mesatare (AR) @[ IoU=0.50:0.95 | zona= e vogël | maxDets=100 ] = 0.61765
Kujtesa Mesatare (AR) @[ IoU=0.50:0.95 | zona=mesatare | maxDets=100 ] = -1.00000
Kujtesa Mesatare (AR) @[ IoU=0.50:0.95 | zona= e madhe | maxDets=100 ] = -1.00000
Duke ruajtur modelin: 148Për të studiuar të gjitha parametrat, shikoni
retinanet/main.pyNë përgjithësi, ato janë standarde për detektimin dhe kanë përshkrim. Nisni trajnimin dhe prisni rezultatet. Shembulli i inferencës mund të shihet në:
retinanet/infer_example.pyose ekzekutoni komandën:
/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
Në repository tashmë është integruar Focal Loss dhe disa backbone, si dhe është e lehtë të integroni të tuajat
retinanet/backbones/*.pyNë tabelë autorët paraqesin disa karakteristika:

Ka gjithashtu backbone ResNeXt50_32x4dFPN dhe ResNeXt101_32x8dFPN, të marra nga torchvision.
Shpresojmë të kemi kuptuar pak me detektimin, por është e domosdoshme të lexoni dokumentacionin zyrtar për të kuptuar modet e eksportit dhe të logimit.
Hapi 5. Eksporti dhe inferenca e modeleve Unet me encoder Resnet
Siç e keni vënë re, në Dockerfile u instaluan bibliotekat për segmentimin dhe në veçanti një bibliotekë e shkëlqyer . Në paketën Unet mund të gjeni shembuj të inferencës dhe eksportit të chekpoint-eve pytorch në motorin TensorRT.
Problemi kryesor gjatë eksportit të modeleve Unet-like nga ONNX në TensoRT është nevoja për të caktuar një madhësi fikse Upsample ose për të përdorur ConvTranspose2D:
import torch.onnx.symbolic_opset9 as onnx_symbolic
def upsample_nearest2d(g, input, output_size):
# Currently, TRT 5.1/6.0 ONNX Parser does not support all ONNX ops
# needed to support dynamic upsampling ONNX forumlation
# Here we hardcode scale=2 as a temporary 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
Me transformimi i kësaj, mund ta bëni këtë automatikisht gjatë eksportimit në ONNX, por që në versionin 7 të TensorRT e kemi zgjidhur këtë problem, dhe na mbetet të presim pak.
Përfundimi
Kur fillova të përdorja docker, kisha dyshime për performancën e tij për detyrat e mia. Në një nga agregatorët e mi tani ka një trafiku të konsiderueshëm rrjetor që krijohet nga disa kamera.

Testet e ndryshme në internet flisnin për një overhead relativisht të madh në ndërveprimin rrjetor dhe regjistrimin në VOLUME, përveç kësaj edhe GIL-i, që është një mister i frikshëm, dhe pasi kapja e një kadri, funksionimi i drejtuesit dhe transferimi i kadrave në rrjet janë operacione atomike në modalitetin hard real-time, vonesat në rrjet për mua janë shumë kritike.
Por gjithçka doli mirë =)
P.S. Duhet vetëm të shtosh ciklin tënd të preferuar për segmentimin dhe në prodhim!
Faleminderit
Faleminderit komunitetit , pa të nuk është e mundur të zhvillohet! Faleminderit shumë , që më këshilloi të angazhohem në DL, për këshillat e tij të çmuara dhe profesionalizmin e jashtëzakonshëm!
Përdorni modele të optimizuara në production!
Aurorai, llc
Burimi: habr.com
