Mekanika e planifikimit
Përpunimi i të dhënave në një grafik MediaPipe ndodh brenda nyjeve përpunuese të përcaktuara si nënklasa CalculatorBase
. Sistemi i planifikimit vendos se kur duhet të funksionojë çdo kalkulator.
Çdo grafik ka të paktën një radhë planifikuesi . Çdo radhë planifikuesi ka saktësisht një ekzekutues . Nyjet janë caktuar në mënyrë statike në një radhë (dhe për rrjedhojë në një ekzekutues). Si parazgjedhje ka një radhë, ekzekutuesi i së cilës është një grup thread me një numër thread-sh bazuar në aftësitë e sistemit.
Çdo nyje ka një gjendje planifikimi, i cili mund të mos jetë gati , gati ose ekzekutues . Një funksion gatishmërie përcakton nëse një nyje është gati për të ekzekutuar. Ky funksion thirret në fillimin e grafikut, sa herë që një nyje përfundon ekzekutimin dhe sa herë që ndryshon gjendja e hyrjeve të një nyje.
Funksioni i gatishmërisë i përdorur varet nga lloji i nyjës. Një nyje pa hyrje të rrjedhës njihet si një nyje burimi ; Nyjet burimore janë gjithmonë gati për të ekzekutuar, derisa t'i tregojnë kornizës se nuk kanë më të dhëna për të nxjerrë, në të cilën pikë ato mbyllen.
Nyjet jo-burimore janë gati nëse kanë hyrje për t'u përpunuar dhe nëse ato inpute formojnë një grup të vlefshëm hyrjeje sipas kushteve të përcaktuara nga politika e hyrjes së nyjes (diskutuar më poshtë). Shumica e nyjeve përdorin politikën e paracaktuar të hyrjes, por disa nyje specifikojnë një të ndryshme.
Kur një nyje bëhet gati, një detyrë i shtohet radhës përkatëse të planifikuesit, e cila është një radhë prioritare. Funksioni prioritar është aktualisht i fiksuar dhe merr parasysh vetitë statike të nyjeve dhe renditjen topologjike të tyre brenda grafikut. Për shembull, nyjet më afër anës dalëse të grafikut kanë përparësi më të lartë, ndërsa nyjet burimore kanë përparësinë më të ulët.
Çdo radhë shërbehet nga një ekzekutues, i cili është përgjegjës për ekzekutimin e vërtetë të detyrës duke thirrur kodin e kalkulatorit. Mund të sigurohen dhe konfigurohen ekzekutues të ndryshëm; kjo mund të përdoret për të personalizuar përdorimin e burimeve të ekzekutimit, p.sh. duke ekzekutuar nyje të caktuara në thread-et me prioritet më të ulët.
Sinkronizimi i vulave kohore
Ekzekutimi i grafikut MediaPipe është i decentralizuar: nuk ka orë globale dhe nyje të ndryshme mund të përpunojnë të dhëna nga stampa të ndryshme kohore në të njëjtën kohë. Kjo lejon xhiros më të lartë nëpërmjet tubacioneve.
Megjithatë, informacioni për kohën është shumë i rëndësishëm për shumë flukse pune të perceptimit. Nyjet që marrin prurje të shumta hyrëse në përgjithësi duhet t'i koordinojnë ato në një farë mënyre. Për shembull, një detektor objektesh mund të nxjerrë një listë të drejtkëndëshave kufitarë nga një kornizë dhe ky informacion mund të futet në një nyje rendering, e cila duhet ta përpunojë atë së bashku me kornizën origjinale.
Prandaj, një nga përgjegjësitë kryesore të kornizës MediaPipe është të sigurojë sinkronizimin e hyrjes për nyjet. Për sa i përket mekanikës së kornizës, roli kryesor i një vule kohore është të shërbejë si një çelës sinkronizimi .
Për më tepër, MediaPipe është krijuar për të mbështetur operacionet përcaktuese, gjë që është e rëndësishme në shumë skenarë (testim, simulim, përpunim grupi, etj.), ndërkohë që u lejon autorëve të grafikëve të qetësojnë determinizmin aty ku nevojitet për të përmbushur kufizimet në kohë reale.
Dy objektivat e sinkronizimit dhe determinizmit qëndrojnë në themel të disa zgjedhjeve të projektimit. Veçanërisht, paketat e shtyra në një rrymë të caktuar duhet të kenë stampa kohore në rritje monotonike: ky nuk është vetëm një supozim i dobishëm për shumë nyje, por mbështetet gjithashtu nga logjika e sinkronizimit. Çdo transmetim ka një vulë kohore të kufizuar , e cila është vula kohore më e ulët e mundshme e lejuar për një paketë të re në transmetim. Kur arrin një paketë me vulën kohore T
, lidhja kalon automatikisht në T+1
, duke reflektuar kërkesën monotonike. Kjo i lejon kornizës të dijë me siguri se nuk do të mbërrijnë më paketa me vulë kohore më të ulët se T
Politikat e hyrjes
Sinkronizimi trajtohet në nivel lokal në secilën nyje, duke përdorur politikën e hyrjes të specifikuar nga nyja.
Politika e parazgjedhur e hyrjes, e përcaktuar nga DefaultInputStreamHandler
, ofron sinkronizim përcaktues të hyrjeve, me garancitë e mëposhtme:
Nëse paketat me të njëjtën stampë kohore ofrohen në prurje të shumta hyrëse, ato gjithmonë do të përpunohen së bashku, pavarësisht renditjes së tyre të mbërritjes në kohë reale.
Kompletet e hyrjes përpunohen në mënyrë rigoroze në rritje të vulës kohore.
Asnjë pako nuk hidhet dhe përpunimi është plotësisht determinist.
Nyja bëhet gati për të përpunuar të dhënat sa më shpejt të jetë e mundur duke pasur parasysh garancitë e mësipërme.
Për të shpjeguar se si funksionon, duhet të prezantojmë përkufizimin e një vule kohore të vendosur. Ne themi se një vulë kohore në një transmetim zgjidhet nëse është më e ulët se vula kohore e kufizuar. Me fjalë të tjera, një vulë kohore vendoset për një transmetim pasi gjendja e hyrjes në atë vulë kohore njihet në mënyrë të pakthyeshme: ose ka një paketë, ose ekziston siguria që një paketë me atë vulë kohore nuk do të arrijë.
Një vulë kohore vendoset në transmetime të shumta nëse vendoset në secilën prej atyre transmetimeve. Për më tepër, nëse një vulë kohore shlyhet, kjo nënkupton që të gjitha vulat kohore të mëparshme janë gjithashtu të shlyera. Kështu vulat kohore të vendosura mund të përpunohen në mënyrë deterministe në rend rritës.
Duke pasur parasysh këtë përkufizim, një kalkulator me politikën e paracaktuar të hyrjes është gati nëse ka një vulë kohore e cila vendoset në të gjitha rrjedhat hyrëse dhe përmban një paketë në të paktën një rrjedhë hyrëse. Politika e hyrjes siguron të gjitha paketat e disponueshme për një vulë kohore të vendosur si një grup i vetëm hyrjeje në kalkulator.
Një pasojë e kësaj sjelljeje deterministe është se, për nyjet me rryma hyrëse të shumta, mund të ketë një pritje teorikisht të pakufishme për zgjidhjen e një vule kohore dhe një numër i pakufizuar paketash mund të fshihet ndërkohë. (Konsideroni një nyje me dy rryma hyrëse, njëra prej të cilave vazhdon të dërgojë paketa ndërsa tjetra nuk dërgon asgjë dhe nuk e çon përpara kufirin.)
Prandaj, ne parashikojmë gjithashtu politika të personalizuara të hyrjes: për shembull, ndarjen e hyrjeve në grupe të ndryshme sinkronizimi të përcaktuara nga SyncSetInputStreamHandler
, ose shmangien e sinkronizimit në tërësi dhe përpunimin e hyrjeve menjëherë pasi ato mbërrijnë të përcaktuara nga ImmediateInputStreamHandler
.
Kontrolli i rrjedhës
Ekzistojnë dy mekanizma kryesorë të kontrollit të rrjedhës. Një mekanizëm i presionit të kundërt pengon ekzekutimin e nyjeve në rrjedhën e sipërme kur paketat e buferuara në një rrjedhë arrijnë një kufi (të konfigurueshëm) të përcaktuar nga CalculatorGraphConfig::max_queue_size
. Ky mekanizëm ruan sjellje deterministe dhe përfshin një sistem shmangieje të bllokimit që relakson kufijtë e konfiguruar kur nevojitet.
Sistemi i dytë konsiston në futjen e nyjeve speciale të cilat mund të lëshojnë paketa sipas kufizimeve në kohë reale (zakonisht duke përdorur politika të personalizuara të hyrjes) të përcaktuara nga FlowLimiterCalculator
. Për shembull, një model i zakonshëm vendos një nyje të kontrollit të rrjedhës në hyrje të një nëngrafi, me një lidhje loopback nga dalja përfundimtare në nyjen e kontrollit të rrjedhës. Nyja e kontrollit të rrjedhës është kështu në gjendje të mbajë shënim se sa stampa kohore janë duke u përpunuar në grafikun e rrjedhës së poshtme dhe të lëshojë paketat nëse ky numër arrin një kufi (të konfigurueshëm); dhe meqenëse paketat hidhen në rrjedhën e sipërme, ne shmangim punën e humbur që do të rezultonte nga përpunimi i pjesshëm i një vule kohore dhe më pas hedhja e paketave midis fazave të ndërmjetme.
Kjo qasje e bazuar në kalkulator i jep autorit të grafikut kontrollin se ku mund të hidhen paketat dhe lejon fleksibilitet në përshtatjen dhe përshtatjen e sjelljes së grafikut në varësi të kufizimeve të burimeve.