Inferență GRU pe dispozitivele Apple
Ei bine, puteți spune că, dacă doriți să rulați modelul NN pe un dispozitiv iOS, atunci CoreML este cea mai bună soluție. Da, așa este, când sunteți gata să utilizați .mlmodel. Principalul beneficiu al CoreML este că folosește Neural Engine în unele cazuri. Este extrem de rapid, dar foarte limitat. Neural Engine este utilizat nu pentru multe straturi și nu este foarte util pentru rețelele recurente. În cazul meu, ar putea accelera doar stratul Conv1d care nu ar face prea multe diferențe. De asemenea, CoreML poate utiliza GPU și alternativă la CPU. Dar înainte de a vă putea folosi modelul în CoreML, trebuie să-l exportați din ceva. Și de aici începe durerea.

Am folosit tensorflow 2 pentru antrenamentul modelului meu și m-am gândit că ar fi destul de simplu să export modelul către CoreML, dar nu a făcut-o. În primul rând, am încercat pachetul principal coremltools python de la Apple. Hmm…. Ne pare rău, dar încă nu acceptă tf 2! Am folosit tf2 Keras API și m-am gândit că aș putea folosi Kerasand tf 1 și toate ar trebui să fie bune, deoarece coremltools acceptă Keras. Dar nu a făcut-o. Mi-am exportat cumva modelul; cu toate acestea a fost total inutilizabil.
Apoi am încercat să găsesc ceva pentru a exporta modelul tf2, dar fiecare script găsit nu funcționa normal. Apoi am aflat că TFLite avea delegat CoreML, ceea ce însemna că putea folosi CoreML cumva sub capotă. Apoi am decis să omit CoreML și treceți la TFLite.
Exportul modelului către TFLite este mult mai simplu, dar are și unele probleme.
Permiteți-mi să vă arăt toate capcanele pe care le-am găsit în timpul exportării modelului meu către TFLite și inferență pe un dispozitiv iOS:
- Pentru a exporta un model care va crea un interpret pe dispozitiv fără erori, trebuie să utilizați un nou convertor experimental.
Când am folosit convertorul implicit, a creat încă un subgraf gol, iar Interpretul de pe iOS nu a reușit să creeze.
2. Nu prea știu de ce, dar cu un model pe care l-am avut, nu l-aș putea rula cu ObjC normal pod. Întotdeauna a revenit nul la obținerea tensoarelor de intrare/ieșire. Mi-am rulat rețeaua cu succes numai folosind TensorFlowLiteC API 0.0.1 pe noapte. Nu am testat versiunea Swift de când am folosit ObjC în proiectul curent.
Bine, rețeaua mea a funcționat cu succes, dar a fost lentă pentru procesarea în timp real. După cum am menționat mai devreme, TFLite are delegat CoreML și delegat GPU și am crezut că aș putea face inferențe mai repede. Ei bine, mi-am asamblat rețeaua cu CoreML Delegate care rezervă pe GPU Delegate cu dispozitivul TFLite modelul nu era super cool, am decis să-mi montez rețeaua folosind Metal. Poate că GPU ar trebui să ruleze mai repede.
Pentru asamblarea NN-ului meu cu Metal, Nu am scris toate umbrele de la zero, deoarece Apple a creat o mulțime de straturi NN în cadrul Metal Performance Shaders. Aveam un spectrogram shader, așa că părea un plan bun. Mi-am corectat codul stratului de spectrogramă, așa că a fost aliniat cu MPS și am scris și stratul Conv1d. Am uitat că aș putea simula Conv1d cu Conv2d. Dar chiar și după ce mi-am amintit acest lucru, am decis să îl păstrez. Apropo, iată o repo cu aceste umbrere.
techpro-studio/MetalAudioShaders
Pentru a rula exemplul de proiect, clonați repo-ul și executați mai întâi instalarea podului din directorul Exemplu. MetalAudioShaders este ...
github.com
Toate umbrele rămase au fost implementate de Apple. Am fost foarte fericit când am aflat că stratul GRU a fost dezvoltat de Apple. Am fost dezamăgit mai târziu, dar mai întâi de toate. Ei bine, mi-am asamblat rețeaua strat cu strat, am analizat rezultatele și le-am comparat cu modelul Keras. MPS este foarte enervant, deoarece este axat pe imagini. De exemplu, shader-ul pentru BatchNorm acceptă numai MPSImage, dar umbrele mele (Spectro, Conv1d, matrici folosite) și stratul GRU funcționează mai bine cu matricile (în ceea ce privește documentul Apple), așa că a trebuit să copiez matricea în imagine și invers. Oricum, toate au funcționat bine, până m-am blocat cu stratul GRU.
Nu am înțeles de ce, dar a dat rezultate nevalide de fiecare dată. Pentru a fi sincer, nici măcar nu am înțeles cum să trimit date corect la acest strat, deoarece nu a existat niciun exemplu de utilizare corectă a acestuia. De asemenea, nu este deloc o problemă googlabilă, deoarece chiar și pe site-ul oficial al dezvoltatorului Apple, nu veți găsi documente despre straturile recurente în MPS. Toate documentele sunt doar în cod. Mai târziu am găsit un mic exemplu în sesiunea WWDC când au folosit stratul LSTM și am fixat datele de intrare la GRU, dar totuși a dat rezultate greșite. Am decis să implementez stratul GRU pe CPU pentru o mai bună înțelegere. Ar trebui să mă ajute să găsesc o soluție despre cum să configurez corect stratul GRU în MPS.