Mindent a YOLOkról - 5. rész - Hogyan kódoljuk?

Ebben a bejegyzésben elmagyarázom, hogy miként lehet felhasználni a YOLOv3 vanília verzióját az objektumok észlelésére a COCO adatállományból, és hogyan állíthat be saját adatállományt saját használatra.

A Yolo-felismerési kód itt Erik Lindernoren Joseph Redmon és Ali Farhadi papírjának megvalósításán alapul.

Itt található a sorozat linkje.

Mindent a YOLOkról - 1. rész - egy kis történelemről

Minden a YOLOkról - 2. rész - Az első YOLO

Mindent a YOLOkról - 3. rész - A jobb, gyorsabb és erősebb YOLOv2

Mindent a YOLOkról - 4. rész - YOLOv3, egy fokozatos fejlesztés

Mindent a YOLOkról - 5. rész - Fel és fut

Kérjük, keresse meg a projekt mappát a gitrepoban.

A projekt mappában található egy config nevű almappák, amelyek tartalmazzák a konfigurációs fájlokat, az osztályneveket és a környezeti változókat, az adatmappát az adatkészletekkel és az utils mappát néhány hasznos python funkcióval.

Először töltse le a YOLOv3 súlyfájlt, és helyezze a projekt konfigurációs mappájába a következő parancs futtatásával. (Hozzáadtam egy .sh fájlt, hogy ezt megtehessem a repóban)

wget https://pjreddie.com/media/files/yolov3.weights

A letöltés után a konfigurációs mappa tartalma a következőképp néz ki.

Hogyan állíthatjuk be a YOLOv3-t a COCO-objektumok detektálására?

Nézzük meg a YOLO vanília megvalósítását a COCO-objektumok bevezetésére.

  • Importálja a szükséges modulokat.
modellekből importálás * az eszközöktől importálás * os, sys, idő, naptári idő, véletlenszerű importálás torch.utils.data importálásból DataLoader a torchvision import adatkészleteiből, átalakítások a torch.autograd importálásból Variableimport matplotlib.pyplot as plt import matplotlib.patches as javítások a PIL import képéből
  • Töltse be az előre képzett konfigurációt és súlyokat, valamint a COCO adatkészlet osztályneveit, amelyeken a Darknet modell képzésre került. Az img_size, conf_thres és num_thresold olyan paraméterek, amelyek a felhasználási eset alapján megcsinálhatók.
Megjegyzés: Állítsa be a modellt eval módba a következtetéshez.
config_path = 'config / yolov3.cfg' weights_path = 'config / yolov3.weights' class_path = 'config / coco.names' img_size = 416 conf_thres = 0,8 nms_thres = 0,4
# Terhelési modell és súlyok = Darknet (config_path, img_size = img_size) model.load_weights (súly_path) model.cuda () model.eval () osztályok = utils.load_classes (class_path) Tensor = torch.cuda.FloatTensor
  • Írjon egy funkciót az alapvető észlelés végrehajtásához egy adott képnél. Kérjük, nézd meg a hozzászólásokat, hogy mit csinál a kód. Leginkább a kép előfeldolgozása.
def detektálás_kép (img): # skála és a pad képaránya = min (img_size / img.size [0], img_size / img.size [1]) imw = round (img.size [0] * arány) imh = round ( img.size [1] * arány) img_transforms = transforms.Compose ([transforms.Resize ((imh, imw)), transforms.Pad ((max (int ((imh-imw) / 2), 0), 0), max ( int ((imw-imh) / 2), 0), max (int ((imh-imw) / 2), 0), max (int ((imw-imh) / 2), 0)), (128,128,128) ), átalakítja.ToTensor (),]) # konvertálja a képet Tensor-ra image_tensor = img_transforms (img) .float () image_tensor = image_tensor.unsqueeze_ (0) input_img = Variable (image_tensor.type (Tensor)) # futtatás következtetés a modellben és detektálást kap a torch.no_grad () segítségével: detections = modell (input_img) detections = utils.non_max_suppression (detections, 80, conf_thres, nms_thres) return detections [0]
  • Most a kód, amellyel ezt a funkciót használhatjuk következtetések levonására. Ez minden objektummal működik, amely a COCO adatkészletben található. A kód nagy része szintén a kép előfeldolgozásával és a keretes mezők ábrázolásával foglalkozik.
# Kép betöltése és az észlelések beolvasása img_path = "images / blueangels.jpg" prev_time = time.time () img = Image.open (img_path) detections = detektálás_kép (img) inference_time = datetime.timedelta (seconds = time.time () - prev_time) print ('Következtetési idő:% s'% (következtetés_idő)) # Határozódoboz-színek beolvasása cmap = plt.get_cmap ('tab20b') színek = [cmap (i) i-re az np.linspace-ben (0, 1, 20)] img = np.array (img) plt.figure () ábra, ax = plt.subplots (1, ábra = (12,9)) ax.imshow (img) pad_x = max (img.shape [0] - img.shape [1], 0) * (img_size / max (img.shape)) pad_y = max (img.shape [1] - img.shape [0], 0) * (img_size / max (img.shape) )) unpad_h = img_size - pad_y unpad_w = img_size - pad_xif detections not Nincs: unique_labels = detections [:, -1] .cpu (). unique () n_cls_preds = len (egyedi_címkék) bbox_colors = random.sample (színek, n_cls_preds) # böngészés az észlelésekben és rajzolhat határoló dobozokat az x1, y1, x2, y2, conf, cls_conf, cls_pred elemzésekhez: box_h = ((y2 - y1) / unpad_h) * img.shape [0] box_w = ((x2 - x1) / unpad_w) * i mg.forma [1] y1 = ((y1 - pad_y // 2) / unpad_h) * img.shape [0] x1 = ((x1 - pad_x // 2) / unpad_w) * img.shape [1] color = bbox_colors [int (np.where (egyedi_címkék == int (cls_pred)) [0])] bbox = patches.Rectangle ((x1, y1), box_w, box_h, linewidth = 2, edgecolor = color, facecolor = 'nincs' ) ax.add_patch (bbox) plt.text (x1, y1, s = osztályok [int (cls_pred)], color = 'white', verticalalignment = 'top', bbox = {'color': color, 'pad': 0}) plt.axis ('ki') # kép mentése plt.savefig (img_path.replace (". Jpg", "-det.jpg"), bbox_inches = 'szoros', pad_inches = 0,0) plt.show ()
  • A fenti szkript kezeli a képek felismerését. Most nézzük meg, hogyan lehet működni a videókhoz.
videopath = 'video / sample_video.mp4'
% pylab inline import cv2 az IPython.display -ból clear_outputcmap = plt.get_cmap ('tab20b') colours = [cmap (i) [: 3] i számára az np.linspace-ben (0, 1, 20)] # inicializálja a vid = cv2-t .VideoCapture (videopath) # időben (True): ii-re a (40) tartományban: ret, frame = vid.read () frame = cv2.cvtColor (frame, cv2.COLOR_BGR2RGB) pilimg = Image.fromarray (frame) detections = detektáló kép (pilimg) img = np.array (pilimg) pad_x = max (img.shape [0] - img.shape [1], 0) * (img_size / max (img.shape)) pad_y = max (img.shape [1] - img.shape [0], 0) * (img_size / max (img.shape)) unpad_h = img_size - pad_y unpad_w = img_size - pad_x, ha a detektálás nem létezik. Nincs egyedi_címke = detektálás [:, -1]. cpu (). egyedi () n_cls_preds = len (egyedi címkék) x1, y1, x2, y2, conf, cls_conf, cls_pred felfedezéseknél: box_h = int ((y2 - y1) / unpad_h) * img.shape [0] ) box_w = int (((x2 - x1) / unpad_w) * img.shape [1]) y1 = int (((y1 - pad_y // 2) / unpad_h) * img.shape [0]) x1 = int ( ((x1 - pad_x // 2) / unpad_w) * img.shape [1]) color = colours [int (cls_conf. tétel ())% len (színek)] szín = [i * 255 az i-nél színes] cls = osztályok [int (cls_pred)] cv2.korrekciós szög (keret, (x1, y1), (x1 + box_w, y1 + box_h ), színes, 4) cv2.szögletes (keret, (x1, y1-35), (x1 + len (cls) * 19 + 60, y1), színes, -1) cv2.putText (keret, cls + "- "+ str (cls_conf.item ()), (x1, y1 - 10), cv2.FONT_HERSHEY_SIMPLEX, 1, (255,255,255), 3) fig = ábra (figsize = (12, 8) cím) (" Video Stream ") imshow (frame) show () clear_output (várakozás = igaz)
Megjegyzés: A fenti kód az élő streaminghez is használható, ha a videó elérési útját IP kamera streamre változtatja.

Hogyan finomíthatjuk a YOLOv3 vanília modelljét az egyedi objektumokhoz való működéshez?

Nézzük meg a YOLOv3 egyedi képzését saját felhasználási esetünkhöz. Ennek többféle módja van. De a következő lépések magyarázzák a legegyszerűbb módszert, amelyet az interneten találtam.

Előfeltételek

Adat

Az első lépés az lenne, ha elkészítené az edzési adatait, azaz címkézi a képeket egy korlátozó mezővel és osztálycímkével, amelyre vonatkozóan a detektálás megtörténik.

Számos eszköz létezik ennek megvalósításához. A legegyszerűbb módszer a LabelImg használata. Ez egy grafikus kép-kommentár eszköz. Telepítheti a pip paranccsal.

pip install labelImg

Kattintson a linkre, és talál egy jó bemutatót annak használatáról.

A kép egyszerű címkézése azt jelenti, hogy megjelölik a határoló doboz koordinátáit és osztályát. Tehát minden képhez a generált címke (.txt fájl) egyetlen sorral rendelkezne. Ezt YOLO formátumnak hívják.

Megjegyzés: Kérjük, feltétlenül válassza a YOLO formátumot, miközben a képeket a LabelImg eszköz segítségével címkézi.
#class xy ​​szélesség magassága 1 0.351466 0.427083 0.367168 0.570486

Miután a képeket megcímkézték és címkéket (.txt fájlok) generáltak, futtass egy szkriptet az adatkészlet szétválasztására a kiképzéshez és az érvényesítéshez. Kérjük, csak egyszer futtassa a következő python kódot. A datasplit.py az ezt a kódot tartalmazó fájl a repóban.

import glob import os import numpy as np import syscurrent_dir = "./data/artifacts/images" split_pct = 10 # 10% érvényesítési készlet file_train = open ("data / artifacts / train.txt", "w") file_val = open ( "data / artifacts / val.txt", "w") counter = 1 index_test = kerek (100 / split_pct) a teljes útvonalhoz a glob.iglob-ban (os.path.join (current_dir, "* .JPG")): cím, ext = os.path.splitext (os.path.basename (fullpath)), ha counter == index_test: counter = 1 file_val.write (current_dir + "/" + title + '.JPG' + "\ n" else: file_train.write (current_dir + "/" + title + '.JPG' + "\ n") counter = counter + 1 file_train.close () file_val.close ()

Ez 2 fájlt hoz létre, a train.txt és a val.txt fájlok teljes útvonalát tartalmazza, 90% -ban vonattal és 10% val.

Ha kész, akkor győződjön meg arról, hogy az adatkészlet a következő mappastruktúrába kerül.

Fő mappa --- adatok --- adatkészlet neve --- képek --- img1.jpg --- img2.jpg .......... --- címkék --- img1.txt --- img2.txt .......... --- train.txt --- val.txt

config

Most a konfigurációs fájlokat a config / mappában. Először is, a coco.data így néz ki:

osztályok = 80 # az osztályok száma itt megy vonat = adatok / alfa / vonat.txt # a vonat.txt útja ide megy érvényes = adatok / alfa / val.txt # a val.txt elérési útja ide megy név = config /coco.names # szerkessze a névfájlt az osztálycímkékkel backup = backup / # Tartsa meg ezt a paramétert, ahogy van

Szerkessze ezeket az értékeket az egyéni adatkészlet szerint. Szerkessze az „osztályokat”, hogy tartalmazza a felhasználási esetben észlelendő osztályok számát. A vonat és az érvényes tartja a vonat.txt és val.txt útvonalat. Szerkessze a „coco.names” fájlt osztálycímkével. állítólag soronként egyet sorol fel az osztályok nevét (a kommentárfájl esetében az első 0-nak felel meg, az 1-es mellett, stb.)

1. osztály 2. osztály ...
Megjegyzés: A biztonsági mentési paramétert nem használja, de úgy tűnik, hogy szükség van rá.

Most a yolov3.cfg fájlhoz. Ez a YOLOv3 algoritmus építészeti részleteit tartalmazza.

Az első [net] részben állítsa be a kötegelt értéket és az alosztásokat, hogy illeszkedjen a GPU memóriájához. Minél nagyobb a tétel, annál jobb és gyorsabb az edzés, de annál több memóriát igényel. Itt is beállíthatja a learning_rate-t.

Egy 11 Gb memóriájú Nvidia GPU-nál a 16 és 1 alosztásos tétel jó.

Két másik alapvető fontosságú dolog van megváltoztatva, amelyek az osztályok és a végső rétegszűrők értékei. És a fájl három különböző helyén kell megtennie.

Ha a fájlban keres, 3 [yolo] szakasz található. Ezen a részen belül állítsa be az osztályokat a modellben szereplő osztályok számához.

A jobb oldali [yolo] fenti [konvolúciós] szakaszban lévő szűrők értékét a következőre kell módosítania.

szűrők = (+ 5 osztály) x 3

a fentiek szerint a készen áll a modell kiképzésére.

Kód

A képzési kör megvalósítása

  • Könyvtárak importálása
a __future__ import részlegről
a modellek importálásából * az utils.utils importból * az utils.datasets importálásból * az utils.parse_config importálásból *
import os import rendszer import idő import naptári idő import argparse
import zseblámpa a torch.utils.data fájlból Import DataLoader a torchvision import adatkészletekből a torchvision importból átalakul a torch.autograd importból A változó import torch.optim az optimális
  • Paraméter beállítása
epochs = 20 image_folder = "data / dataet / images" batch_size = 16 model_config_path = "config / yolov3.cfg" data_config_path = "config / coco.data" weights_path = "config / yolov3.weights" class_path = "config / coco.names "conf_thres = 0,8 nms_thres = 0,4 n_cpu = 0 img_size = 416 checkpoint_interval = 1 checkpoint_dir = 'checkpoint' use_cuda = True
  • Használjon CUDA-t, ha rendelkezésre áll
cuda = torch.cuda.is_avable () and use_cuda
  • Az adatok konfigurálása és a paraméterek beolvasása a memóriába
# Terhelési osztályok os.makedirs ("ellenőrző pontok", létezik_ = = Igaz) osztályok = betöltési osztályok (osztály_út)
# Adatkonfiguráció lekérése data_config = parse_data_config (data_config_path) train_path = data_config ["train"]
# Hiperparaméterek beszerzése hyperparams = parse_model_config (model_config_path) [0] learning_rate = float (hyperparams ["learning_rate"]) lendület = float (hyperparams ["lendület"]) decay = float (hyperparams ["decay"]) burn_in = int ( hyperparams [ "burn_in"])
  • Kezdeményezzék a modellt és állítsák be a vonatot.
# Initiate model model = Darknet (model_config_path) model.load_weights (weights_path)
ha cuda: model = model.cuda () model.train ()
  • Szerezze be az adatbetöltőt, és állítsa be az optimalizálót
# Adatrögzítő adatainak letöltése = torch.utils.data.DataLoader (ListDataset (vonat_út), batch_size = batch_size, shuffle = False, num_workers = n_cpu)
Tensor = fáklya.cuda.FloatTensor, ha cuda más fáklya.FloatTensor
# Optimalizáló optimalizálása = torch.optim.Adam (szűrő (lambda p: p.requires_grad, model.parameters ()))
  • Most a fő képzési körhöz.
a tartományban lévő korszakra (korszakok): batch_i, (_, imgs, célok) felsorolásban (adattároló): imgs = változó (imgs.type (Tensor)) célok = változó (célok.típus (Tensor), igény_grad = hamis)
optimizer.zero_grad ()
veszteség = modell (képek, célok)
loss.backward () optimizer.step ()
nyomtatás ("[% d /% d korszak,% d /% d tétel] [veszteségek: x% f, y% f, w% f, h% f, conf% f, cls% f, total% f, recall :% .5f, pontosság:% .5f] "% (korszak, korszakok, batch_i, len (dataloader), model.losses [" x "], model.losses [" y "], model.losses [" w " ], modell.veszteség ["h"], modell.veszteség ["conf"], modell.vesztés ["cls"], loss.item (), modell.vesztés ["visszahívás]], modell.veszteség" "pontosság "],))
model.seen + = imgs.size (0)
ha epoch% checkpoint_interval == 0: print ("save") model.save_weights ("% s /% d.weights"% (checkpoint_dir, "legújabb"))

A fenti hurok minden korszakra súlyt tartalmazó fájlt tárol és tárol a modell mappájába, epoch számmal. Ezenkívül egy csomó veszteséget nyomtat ki a képzés előrehaladásának nyomon követésére.

A következtetés végrehajtása

  • Könyvtárak importálása
modellekből importálás * az utils importból * import cv2 import os, sys, time, datetime, random import fáklya a torch.utils.data import DataLoader torchvision import adatkészletekből, transzformációk a torch.autograd import változóból
import matplotlib.pyplot as plt import matplotlib.patches as patles from PIL import Image import imutils from imutils.video import WebcamVideoStream
  • Állítsa be a paramétereket. Az új modell felismeréséhez használja a modellek mappájában létrehozott legfrissebb súlyfájlt a konfigurációs mappában található yolov3.weights fájlra. Győződjön meg arról, hogy a következtetési kód súlypályája a legújabb súlypályára mutat.
num_classes = 1 config_path = 'config / yolov3.cfg' weights_path = 'checkpoint_19.weights' class_path = 'config / coco.names' img_size = 416 conf_thres = 0,95 nms_thres = 0,95
  • Töltse be a modellt és állítsa be a következtetések evaljára
# Terhelési modell és súlyok modell = Darknet (config_path, img_size = img_size) model.load_weights (súly_út) # model.cuda () model.eval () osztályok = load_classes (class_path) Tensor = torch.FloatTensor
  • Definiálja az osztályok betöltésének és a kép észlelésének funkcióit.
def load_classes (elérési út): "" "Osztálycímkéket tölt be az" elérési úton "" "fp = open (elérési út," r ") names = fp.read (). split (" \ n ") [:] return names
def detektálás_kép (img): # skála és a pad képaránya = min (img_size / img.size [0], img_size / img.size [1]) imw = round (img.size [0] * arány) imh = round ( img.size [1] * arány) img_transforms = transforms.Compose ([transforms.Resize ((imh, imw)), transforms.Pad ((max (int ((imh-imw) / 2), 0), 0), max ( int ((imw-imh) / 2), 0), max (int ((imh-imw) / 2), 0), max (int ((imw-imh) / 2), 0)), (128,128,128) ), átalakítja.ToTensor (),]) # konvertálja a képet Tensor-ra image_tensor = img_transforms (img) .float () image_tensor = image_tensor.unsqueeze_ (0) input_img = Variable (image_tensor.type (Tensor)) # futtatás következtetés a modellben és detektálást kap a torch.no_grad () segítségével: detections = modell (input_img) detections = utils.non_max_suppression (detections, num_classes, conf_thres, nms_thres) return detections [0]
  • Most a következtetési hurokról.
videopath = 'video / sample_video.mp4'
% pylab inline import cv2 az IPython.display -ból clear_outputcmap = plt.get_cmap ('tab20b') colours = [cmap (i) [: 3] i számára az np.linspace-ben (0, 1, 20)] # inicializálja a vid = cv2-t .VideoCapture (videopath) # időben (True): ii-re a (40) tartományban: ret, frame = vid.read () frame = cv2.cvtColor (frame, cv2.COLOR_BGR2RGB) pilimg = Image.fromarray (frame) detections = detektáló kép (pilimg) img = np.array (pilimg) pad_x = max (img.shape [0] - img.shape [1], 0) * (img_size / max (img.shape)) pad_y = max (img.shape [1] - img.shape [0], 0) * (img_size / max (img.shape)) unpad_h = img_size - pad_y unpad_w = img_size - pad_x, ha a detektálás nem létezik. Nincs egyedi_címke = detektálás [:, -1]. cpu (). egyedi () n_cls_preds = len (egyedi címkék) x1, y1, x2, y2, conf, cls_conf, cls_pred észlelésekben: box_h = int ((y2 - y1) / unpad_h) * img.shape [0] ) box_w = int (((x2 - x1) / unpad_w) * img.shape [1]) y1 = int (((y1 - pad_y // 2) / unpad_h) * img.shape [0]) x1 = int ( ((x1 - pad_x // 2) / unpad_w) * img.shape [1]) color = colours [int (cls_conf. tétel ())% len (színek)] szín = [i * 255 az i-nél színes] cls = osztályok [int (cls_pred)] cv2.korrekciós szög (keret, (x1, y1), (x1 + box_w, y1 + box_h ), színes, 4) cv2.szögletes (keret, (x1, y1-35), (x1 + len (cls) * 19 + 60, y1), színes, -1) cv2.putText (keret, cls + "- "+ str (cls_conf.item ()), (x1, y1 - 10), cv2.FONT_HERSHEY_SIMPLEX, 1, (255,255,255), 3) fig = ábra (figsize = (12, 8) cím) (" Video Stream ") imshow (frame) show () clear_output (várakozás = igaz)

Kérjük, keresse meg a Jupyter notebookokat mind a képzés, mind a következtetés szempontjából a git-repo-ban.

Remélem, hogy ez a sorozat világos képet adott neked arról, hogy mindent meg lehet tudni a YOLO-ról, és megismerheti a saját megvalósításokat.

Ha egy adott témával kapcsolatos blogot szeretne látni, nyugodtan említse meg azt a válaszok szakaszban. Megteszek minden tőlem telhetőt :)

Erőforrások:

YOLO: https://arxiv.org/pdf/1506.02640.pdf

YOLOv2 és YOLO9000: https://arxiv.org/pdf/1612.08242.pdf

YOLOv3: https: //arxiv.org/pdf/1804.02767.pdf

Rólam

A Wavelabs.ai vezető AI szakértője vagyok. Mi, a Wavelabs, segítünk abban, hogy felhasználhassuk a mesterséges intelligenciát (AI) a felhasználói élmény forradalmasításához és a költségek csökkentéséhez. Egyedülállóan fejlesztjük termékeit az AI segítségével, hogy teljes piaci potenciálját elérjék. Igyekszünk élvonalbeli kutatást hozni az Ön alkalmazásaiban.

Nyugodtan fedezhessen fel többet a Wavelabs.ai webhelyen.

Nos, ez mind ebben a bejegyzésben található. Köszönöm, hogy elolvasta :)

Legyen kíváncsi!

A LinkedIn-en felkereshetsz velem.