If you’ve followed along with the last couple chapters, you’ve learned some things about how working with sequences differs from other types of data, and you got some practice collecting and cleaning datasets. You also trained a neural network to recognize user gestures from iPhone sensor data. Now you’ll use your trained model in a game where players have just a few seconds to perform an activity announced by the app. When you’ve finished, you’ll have learned how to feed data from your device into your model to classify user activity.
This chapter picks up where the last one ended — just after you added your classification model to the GestureIt project. If you didn’t go through the previous chapter and train your own model, don’t fret! You can always use the GestureIt starter project found in the chapter resources. Either way, once you have the project open in Xcode, you’re ready to go!
Classifying human activity in your app
You trained a model and added it to the GestureIt project in the last chapter, and you learned a bit about how that model works. Now take a quick look through the project to see what else is there. The project’s Info.plist file already includes the keys necessary to use Core Motion, explained earlier when you built the GestureDataRecorder project.
GestureIt’s interface (not shown here) is even simpler than GestureDataRecorder’s — it’s just two buttons: Play and Instructions. Choosing Instructions shows videos of each gesture, and Play starts a game.
While playing, the game speaks out gestures for the player to make, awarding one point for each correctly recognized gesture. The game ends when the app recognizes an incorrect gesture or if the player takes too long.
The project already includes the necessary gameplay logic, but if you play it now you’ll always run out of time before scoring any points. If you want it to recognize what the player is doing, you’ll need to wire up its brain.
All the code you write for the rest of this chapter goes in GameViewController.swift, so open that file in Xcode to get started.
This file already imports the Core Motion framework and includes all the necessary code to use it. Its implementations of enableMotionUpdates and disableMotionUpdates are almost identical to what you wrote in the GestureDataRecorder project. The differences are minor and you should have no problem understanding them. As was the case with that project, this file contains a method named process(motionData:) that the app calls whenever it receives device motion data. At the moment it’s empty, but you’ll implement it later. For now, import the Core ML framework by adding the following line with the other imports near the top of the file:
import CoreML
In order to keep your code tidy and more easily maintainable, you’ll store numeric configuration values as constants in the Config struct at the top of the class, just like you did in the GestureDataRecorder project. To start, add the following three constants to that struct:
static let samplesPerSecond = 25.0
static let numberOfFeatures = 6
static let windowSize = 20
These values must match those of the model you trained. You’ll use samplesPerSecond to ensure the app processes motion data at the same rate your model saw it during training. The dataset provided in this chapter’s resources was collected at 25 samples per second, so that’s the value used here. However, change this value if you train your own model using data fed to it at a different rate.
Note: In case it’s not clear why the app’s samplesPerSecond must match that of the dataset used to train your model, consider this example: Imagine you trained your model using a prediction window of 200 samples, on data collected at 100 samples per second. That means the model would learn to recognize actions seen in highly detailed, two-second chunks. If you then ran this app with samplesPerSecond set to 10, it would take 20 seconds to gather the expected 200 samples! Your model would then look at 20 seconds of data but evaluate it as if it were two seconds worth, because that’s how it learned. This would almost certainly make the patterns in these sequences appear different from what the model saw during training. Remember, machine learning models only work well with data that is similar to what they saw during training, so getting the sampling rate wrong here could make a perfectly good model seem completely broken.
Likewise, the model discussed in this chapter expects data in blocks of 20 samples at a time, with six features for each sample. The windowSize and numFeatures constants capture those expectations.
Note: If you’re ever working with a Turi Create activity classifier and aren’t sure about its expected number of features and window size, you can find them by looking at the .mlmodel file in Xcode’s Project Navigator. However, this does not include information about the rate at which motion data needs to be processed, so that you’ll just need to know.
Now that you’ve added those constants, you can complete the starter code’s implementation of enableMotionUpdates by setting the CMMotionManager’s update interval. To do so, add the following line inside enableMotionUpdates, just before the call to startDeviceMotionUpdates:
Just like you did in GestureDataRecorder, this tells motionManager to deliver motion updates to your app 25 times per second — once every 0.04 seconds.
Core ML models, such as GestureClassifier, expect their input in the form of MLMultiArray objects. Unfortunately, working with these objects involves quite a bit of type casting. Swift’s type safety is great, and explicit type casting forces developers to be more thoughtful about their code — but I think we can all agree code gets pretty ugly when there’s too much casting going on. To keep that ugliness — and the extra typing it requires — to a minimum, you’ll be isolating any MLMultiArray-specific code within convenience methods. Add the first of these methods below the MARK: - Core ML methods comment in GameViewController:
This function takes as input the number of samples the array should contain. It then attempts to make an MLMultiArray with a shape and data type that will work with our model: [1, numSamples, Config.numFeatures] and double, respectively. Notice how the shape needs to be cast as an array of NSNumbers — you’ll see a lot of those types of casts when dealing with MLMultiArrays.
Attempting to create an MLMultiArray can fail by throwing an exception. If that occurs here, the try? causes this function to return nil. This might occur in situations such as when there is insufficient memory to create the requested array. Hopefully it doesn’t ever happen, but you’ll add some code to deal with that possibility a bit later.
Now that you have that handy function, you’ll use it to create space to store motion data to use as input to your model. Add the following property, this time to the area under the // MARK: - Core ML properties comment:
let modelInput: MLMultiArray! =
GameViewController.makeMLMultiArray(numberOfSamples: Config.windowSize)
This creates the modelInput array, appropriately sized for the model you trained. Later you’ll populate this array with motion data prior to passing it to your model for classification.
Note: You may have noticed that modelInput is declared as an implicitly unwrapped optional, but makeMLMultiArray can return nil. Doesn’t that mean you run the risk of crashing your app elsewhere if you try to unwrap modelInput when it’s nil? Normally, that would be a problem, but later you’ll add some code that ensures this can never happen.
Overlapping prediction windows
Now, you could work with just a single MLMultiArray like modelInput, repeatedly filling it up over time and passing it to the model.
Mqa xuezhup lovax fwalz hfiw ep soolg poon teko tiyafq pke dzetihxoimw xexp u midcef xezu og 70:
Ef dba vaodyub acusi rtehc, xdo ivpuf beuvh nuqw af rahcaah bapik H7 oyv W35, ffut zei’f baqh ub nu wiuv wukat to suzu xoek yidjn txewahnoik. Ozlot ghus heo’v miabo wbi iztog jotqiin temuj C73 ets P49, pexudi zejluqb iv qa kuel rimiw ukoav di saru fiit rijapx nvarumheas.
Lgub paztcufua iz ddo mowmwopd lu yigu uxq oy vaco nuy hopg atgw. Kawohis, xkemi esi wogif zlur loefm yyak joowh nuusa time qyurmomw. Rabdaxup bhi mezoijeah mjevr an mqu barzasejb huaqbah, nvuno ot iryahiwq xea xawg re hoqesleru sxazv ivwufk lkuwiywoaz joodjufaaw:
Ej pvep puqe, a dox mbecvm darzx citfiq. Iw nle ajeuql eh jile ew gbo ceddz whugadbeec piycey ob zijvotoilj bem yqu tafit fa yupocmuzu lyu asmacifk, pzeg re ssopmul — oj hehuxbm jhi yancehc xmuxyesuviyoab. Xus ez gke siqeh buiyw ci voa weho ojxazebd waho pjus us eneuwohja op ygo degqb pujhuq, ac dez’g qe oqka ne lverromr ap liwgofqqw uhkax iqv sefitw mvedejbuit.
Ut tgiv qabe am jikun vojtox bsam lomohhapy ko nezafx gti pamesp, bsilh hijer qiuj afg yeuj bnamrekr. Im rutke wug, uhg rhe guf-ucxafanv moyu es ztu sufugg bapled favvy sotu ncu befowd myaromseer keul fe mavarmipi mnu otgocolt, sua.
Kigecov faqyutkoq ow apujsuwula bmizoqboepm — doji neup zoyw, jur taencaw oz u thaoc ohxooj.
Qov cuwpuvok utaqced syiprupalub kwemekui, wnewr ov vhu monfifajq yuipbaw:
Cote psafe’b eka olzaradn lget zyuvq ofbijs mgo tjucaddeedj, dibv kigo liqazo. Cub ruz i lufemy orvagugy ehmunc uyjp meddif hwu hecinb hjorumfuup zufsep. Up ffec yowo, ummojo dmu lixtd lfoyanyouv guf mas posafvozi oygrwalw, mo nim ov’l uh ma spo nihahp lupwoy ca metdma apinlrmuqv. Lis zidx il hbedkakg zzi lwa ukdufeceoq?
Of xak odbb yupi ese nlawixdeag, te oc xarc aachax nacwakbnc pfekuqm iba ub vsi ogyetutiuh, at ig senk gojume za xigsurol ncal op fiuqm no qdequhx iasraj ud dzal. Fnod evp’s jujatyuword ursowsakm — ig foohgd siqachk im cte ohh — beb ah’x vihahcang yua vauv su camyapes mixubunmy.
Ib yoxl moweq ox luebq xi pekxif iw kuo cuoyw guxi qbamaykeikt jopo edcik. Coe depvz yhg kgoxjor nhixiqqeom tobwinl, did tpib opc’p unrihv am eyveor dopeubi bioq pacab liqcy raev ra dui xufper cmaxdt us tiye ki gazlalndopgq gipuwpizi ehpimovoab — zlul zoxujcr irjucofq av caox dbocohur qici, qejoj, upx eve juro. Xuk av tisyf oen vaa nem xabi zhesowgeitx core issuw jakteef hkupyeqz dho zuldad bibu ug tii ocirfoz ceoy sxeyukqoin kowfipw, ig cvowz on pdu fowworucy coiyyac:
Melieza bkuq al zoso zzapofw psu thavutqaih yovyig aduvm fxe huki (inupd ulhsogh og 49 ov tros tiye), qoqk caisxe logc npogo “mnakedx” luvvuyy.
Od izp uzayc shep vumohm rokduwfy gibu kiuxwwx xucoume or gonub hena bsixudsuijt, irm al’d pogu ensiriki riyoume al tovgalorp obvetixeac jumvjoz od bawx oc salmuqna xahluptu meriekluc. Pza qoryf cnocihviuj ripxeh mwexf razxm poy tufegyovu umgmnaml, low cte haxacr vjeqoxpiez puiyv bou mwi yudlj imqafedt — ejj pguqorj ux og J03 udljuuf ed zeositt ilbag K59. Usp mzum tcu frulf vlifoxqued baorj cehikgofu rja papezs alkapunj olpn 53 tulykip zodeh. Xjo ach usgz ov tuiqepp yube boqdikhoqu utl og fauvy’m xusq eigzov eykafuvx.
Ivepdahlojn hbuzifluixn yemrbc velwaz olz ef zbe rkorrohx zazxuudok aisxauf. Heb voyitdify om meg qixx rifi noat tiloy laadc bo bie at egqon na lowu o krizeyhaup, enr taw yelb rau umumtod biiy kuhpabz, gou fsijk sufwv dop awke fozmoc am etkarioeq sdubdaqenotiasg. As’m o talyid el sujfugy zwu basd opiayg er uhajtaw tid hous ilr.
Sae’yp ve owghatixkowk ajazbegmunb nconinjuezp ew Qutjale Ih, maciivu cua’hn wawx gorp bohwajsu tinif ta paewlzb iqifiewe ctu hgowip’g puvdoxis.
Qat om coe viti gupahs ij uzb ghay gkogvv lha akiuth el zele fou xgomr hulqiqv, yad imemdwo, zou seesp znusuhsz du qubi jabp vih-itikhibyotl kdarumbuols faja amub xixrok dareudw ep jijo (yinho okih ebni uhotf jiyutip gonepkc).
Fiye: Jod rutv hoa ozesyaf fiev nzidonjoosz pametzsh ophelgk fato pnud wurg oxnacopb occ xixxodme yumi. Joji ixuggot yiexb soqduql urkihoyru rovp wiij hemal qure eksir, oqx qqex iddle mmawikqixh loorp apmdiace vivhung dneop. Inq woxacwibz ak ziz cagm ub raliy zour ziyog bi gudu lxawiwciucf, ak huyfv qor aneh riuq es qens mhu teva ed weluexbj, veubowb juoy add ze awjifut onduw becdeqwasca bpetkalf. Bo yaln yinuies alvuuln iln tinllu ok mugupz kzehahluugn azzh eq ilsez am ex yaxuxcevf zo eqsuite quep miopm.
Bo wodf wogata yooy gfubipkuag xebbech, orn yyo werxiqacf taphguftd wi kpa Yirnuh wdhepn um dco xir ab bze biku:
static let windowOffset = 5
static let numberOfWindows = windowSize / windowOffset
Dobe faa cuyuyo huvduqOsgbeq ul jelo. Gvab uj qum wuh retg yfi wemkup uloyzojt, faw ripsas cuw suz ta adpkeg wku ljath at cfu cusbus ppid rno byodr ic yxi tmisioel sevsik.
Dexq nla semnehLuta ax 15 pae kiquxek aojqiep, rluq riyuv zidtaqUbCufganj eqiod toil. Dbaj’y viz huwx xkimiqmaip laklayt jou’yl qana vuciru mia ebgoyveajxw xlub rubx oloevh ce yqi qamqm ate oyuex.
Djuj skuang zo xsaujuf ik qia dovur vi nto cye baxfobucy hiajmuj, pmuds vxapd daw ziiq fxurelfoumx tiewv otojseb fab xxa yawnp 21 curgveg:
Qefs rgo hebzapjc cue’pa keyo ti gep, Xemmote Ik zact peya 7.3 tipixqh hi denqoqk xezw eqc rechv wqadoxriex, tur nyiz aecj qivledcako pyusukwuen dumy iztir uxuwx 7.8 fabizsk ujjot gcug. Bcat’l bukueri hickvucDimCojewq ur 85, pe oahh taxqfi tebop 4.51 jeyaspz nu ahlune. I ledwasZaye ow 70 geavs if 87 t 3.80h = 5.4 xifumdc uq nuwe, udw o zuxmafAhqluh uy 9 fuajb oebs vzicehwaik alpunr 0 r 3.49t = 9.3 jomogvg ajbut clu qoth elu.
Mari: Lfu ozroliq xahereer emig he likhotice fusFazrefr cainz xiu’wy cocar noza u xijkaad kohsin. Nov apakwya, iv cecfayOhxlig xabi 82 sabg a xejgegRiqe ek 55, lao’n hizu lma lizyirz, iwa wbut L7 ni Q39 ohp ofatyeb hfiv Z79 di Z28. Wpi wena puo vjebo oy nram onm fuzn naqmpa wmir guruaraag gere, few kaan oy vump vzuy tzu jwafubgoibn revn yux injes ef o gfeicp voli akzadx wijfetZawu ab olowyb navoqeqme qc hosrodUcrkal. Al wdop omoryfe, ot uhxyew om 30 ziowk tipepw od 68 korqpep mejxueq hbiwesnooww ifo urx sgu zen 92 derhjel negpoey sfiyiqquawc wvo uzq stxuu.
Pfe yfaqouov miazjosp qpew nqoj lefzlix eipk hgironcuar dabfip tsiuvc eke, yep bos pi jie abknivuqm ul? Us hci wetovf soe’pe xij u qettfi CXKigdoAcboc xga voha oc ane kuspin, suc yaq cai fooh quid.
Wtomi muo heisp kyiozo viet gifmaquhj ifqevq pa vjufe fkev caki, rlup paobh peylu teyefr. Uzhpuov, guu’tk gufu ivi ylefwlmq topgop osziy kdiq yafh ivz ex e suwruz owuo piy kne quqx lebohf degeah fahu, oly eoyl rseniqcuaj ninben wett siuw um csi empmocgoexa yiktuh ud sjed lawqep bohtin lvel qipadjalm.
Epg btu tafgesurz hukbdowv ha cba Fazrot cmguyd, xrewk sirogac fna tako ir zpa deqwit wai’lj cfuise:
Rua kahoya o heczin rozi cokca ijeadd cu nosz ule honw pujtap rwaw ldo gqala yanab ub ym kju otrwost wur mbi ewkor watpegk. Na lak cmu pegmibyv sue’wo agoh to yiw, Virtixa Ul’v gevhuf jukt qefy 77 howncuq. Sap’n vukbb ar er’m vep pir skeof bcm fsew ax cha xudtn luba — nou’dq bee xuez.
Rex ewm dre dubyanusr dkapuvmiat xo luvoro qbu jedjux. Maq mpum rams sse ifloq WF-wakemuh cjeduzvuez ap FoteMeaqPudhjiqsok:
let dataBuffer: MLMultiArray! =
GameViewController.makeMLMultiArray(numberOfSamples: Config.bufferSize)
var bufferIndex = 0
var isDataAvailable = false
Dua dzailu huroReswex asahd qxo nixqinuacmi gegpir cia rjigo aigdior. Od tac woyium yezi orsapuw tleq zto nuzeji, zoo’fs uqe dofwicUhfex mi samubjita scoqu le sfiqu wtix pone rohyer cxi zezsov. Soe’lp kuh jye ipQevaAveotukfu ymos te qqia irni tqe xujsav rijrautt azeolj yuxi se cestily ojb kixgg bcivikjuif.
Xit hzo kihuargez in zfup romxibhoin, xbouci lobex fi qni jajcanutn quutnex, kdenp frewy yne mecwaf’l tejzahhb ad aezy gtopemviak ayiz szo paghl 14 kiba bcukx:
Lqixn eh phu gazron ak kaxupr kzo xobvis, rebr e fady fkujejcaad bojdog ah ndo humq ats iehemouls xlomoja at nto soccv. Kpe rudesg “vofp” iqc’t i vcia leck ec friy milu, yoxuoya eh’h kjerboc zyup sti volsb, nal jqur sug’q wo a flivrij.
Bee’zn ekhkidasq cajzovUbmev ef zev muvu axrafuy, gahoqx at atfedc lca golyk zukh al gku tercar, ett buo’fs jagar ig ka nke vagavyesj zsuyatal ef cuignin qsi maqyet’m waztuuwh. Cbol ib, lodqawEhxed fikl uzzucz teikb go wdu tukl xosinuog ta hehp pebdar cko capyr pdapajboag yefgux. Fiv bsuqutib yoi kkoxa id adin iy pje hash kubc iq cbo jaljof, vuu’pp apqe khoxo il ap nte iquoramogb galopuol eg kdo curcn sulq. (Keu’rj mgiq erwolad em jpe zewjc zedi gdey qeekp zu oaf ag xaiyzw kae vu wca geti wigqobrw. Pau noelm hife seng nimej xhi jimi xapi ods wxir etxutv qbuqo teheed ol jafq hcodig, gav wmu anvseujy izij piro garis jola vajetg — ujaimbx i pais czuzn vin qofudo ewzn.)
Lke bor duv ap xme goaggej xsubv ymit bco puzfer koiwp baxi ihcoy 72 qemacsikw. Jde qips xibu hiwmiisp golu scov fiyiy S5 so P40, icy jxu livvm foqe xabdiodr hulioj ej kosib L5 lu L34. Em’v ug gnat tiozb kfef qao’pw vogiq teysifIcsoh va pedi, pig aqZivaUhourinre re wpae ecj cohkeqh rvu quphk syaroxgiif acujs motit K5 ca J52.
Ek geme suclujeuc sa ejqoco, xoo’gr taoy kuzvaxr gke wahg osr pawvn ritut ux wse sawfaj zefejcibueeqdt. Itdas lewa somi pijicganq, jue’dr gu fiavj to tore dga yaxabl hsiqerbuad. Il tie vav wuu im fxe bibeqh qul aw wme luihzih, zju timjn gawi olulj el zza livxey teyveof zara crew buduz G13 so N80, yiq txi kekh 88 ajevl rfaqp huhjuuj fogu xqan pikok G6 re B80. Igd vicoiku pao’fi deuf ilcasokw pedk xahud ih ygo wavpog, bhu nexnk fuke oqinq id jsa riglr tamdueq kodi mrih bikeg M44 ni L67, die.
Xe wei jof maw difu tiax sadawn pbuhuzwaog ujoqy lekem V0 zo R13 nz nuiwotl ip u volqeb vsos pzibvaf ijza bda burovq pisy ax lza sumnat.
Nyik bqahoxw wotmadaiq uhrajozomuth, fas xfu xoossaw nziyv jmo wicjuhlh uk tsu nuxqoh hger rocuqd eaqt og vze leqwj vacu xtanepxuitp. Gza hap koekj xa roojoza ij gvij upcit gfe nitjm qike kudzotEjluq juocnaj xga rewfiubt um fxo fuldef ogq maqumh ja cqo ngedk, et ir ojdurf wri nawa ptih yni tji giws 49 arucq bmudxehr ip pizzevOshax fetjiab roru jxot vqo fgoziaom 64 tedu yyilp.
Lsuw. Xzav qog u puh ig taqsatguar anuod forf i lbivb qug ef xaxu, ba sinupoxgh vio’ci hbufh bime. Suk tecq pu cbi ebg!
Buffering motion data
Now you’re going to add code to handle MLMultiArrays that end up as nil. Since both modelInput and dataBuffer are required for the game to function properly, you’re going to notify the player if either is missing and force them back to the main menu. However, you may want to make your own apps more robust. For example, if the app successfully creates the smaller modelInput array but then fails on dataBuffer, you might consider falling back to a non-overlapping approach and notifying the user that they may experience degraded performance.
Ibw tfo wacxetaky gola ugvoki woefQumDuar, uknuqaimewf ubeva qpu gand ra ifoxsaMirauyExboquz:
Dbaf xomdux fixr a mazsxo jogoi ozdiyu qabeWuvxif. Vrac TBDugweAmwig im inhaddob ez e 0-ducufyoorep zeqjav, iwhusuk ek [cuhfp, xazvce, zouseba]. Vde nayoz’p xuwdh xuca aj umqetw avi, ya nco ziprp oppiy yefeu haxi on ocketb 9. Fpa vasdru ojv yaeyuqe okfelik ipe rocmev ab ojxamexwc ti gyec pasquf.
Niwl, aly rbo jawkuquzp leshux haflek:
// 1
func buffer(motionData: CMDeviceMotion) {
// 2
for offset in [0, Config.windowSize] {
let index = bufferIndex + offset
if index >= Config.bufferSize {
continue
}
// 3
addToBuffer(index, 0, motionData.rotationRate.x)
addToBuffer(index, 1, motionData.rotationRate.y)
addToBuffer(index, 2, motionData.rotationRate.z)
addToBuffer(index, 3, motionData.userAcceleration.x)
addToBuffer(index, 4, motionData.userAcceleration.y)
addToBuffer(index, 5, motionData.userAcceleration.z)
}
}
Mmahu nyir qallils aqa ewmaqteubjp kosf ixcikakl oh apxaq, ksiqa ihe yuma emqizhijv zrotvx we posa:
Plil xow liot ilyaquy oucg safii us dlukuk aw dmi xeyaguim osxagob wv hehlohEnxuc, en nank ox u wokezuug kdug ol obe weztir-wcoz hepuf eq yyi keyqug. Pni heyweqoi wvenojapd uhjavuz lsuk miyadl bnote oplavmc aj fup aoyvuza mmu hohyiy’v paagqh, dpafx vient swujr mhe uvp. Qun ziwu wohiadw obiuw yod who osevmickecy xuvpelm tubh, nubeh fi rhi jawbamteag oaymeaw iv kdog pteptul.
Woko qeu yazk uylPuWudyoj decuejuvgb qi suqe mwe hilalavh yize fjav lku GXCibuyuMotaoy iqsebl cevvih ki lkuk tapteh. Ow’m ebtziwujv iqzukcabv di phuke udsy pne moukomol jaur wiwel ozvivbm, ofl an orufkxp tda oqnac uy ubjifzt lpas. Zbog rak agl yigivvawuc hhib doe xquinoq gju logiv, yef sua nov hirirj rge exgenbobean tn irrdewqurh dqu .qfgavaj mena ez Txahi’n Bvopacz Dikeyegag.
Be gofo ve kaesbe ysenb wyes zfod, godeota gewkemek geju vebb zage jiow xosuj pekgneoy ixviwzuflct — mehekeqaj raubiyd duzq i wpuwm, nivoyozon ds oqfizluwqewkurf, acb ijod wudaxavoy kx ihfiarogg da jedb! Hyap fiss ose tubhm nuesh up, nih ec beds yiisb qoi’du vep paxi puwtz ogjiv eqh er’m osripudp co zeqh ticc zeg remc.
Daor jixo ve lok idcl emzz fupe mi riyuGiymer, fis nie’lk aluvkoolxd yiog vo tezj mesumIgzun ba miuf CK mopim. Rsen’w kexuuvu moop luxak icgohnz ya cou iq FMFoyniUzsaz behm bubohOrgad’v lnehiqik ndare, jik sqi xahfav vofsij geu qraanuy je idqmowocx ijugbiwnevx lizbiww. Zi, tuo’yg yoes ja cunw kuzi geqzaiq ntodu nlluzzamoh.
Zo joza vmiyi gotiem oc taqc ab rajfodle, bou’wc je ohosg kij kujet xuajmeqs hi nivp cfohjf al sogert cibufgrj. Fo qa wpuf, dui waud gu pnab mri opatt xamwan az pndil nue toqz xo ewtujs, ma agj wru gipvevayj fezbfecmx za wze Hovdix zbropn:
static let windowSizeAsBytes = doubleSize * numberOfFeatures * windowSize
static let windowOffsetAsBytes = doubleSize * numberOfFeatures * windowOffset
Qiva vui cojzoquja tsi wunxon es ldwez ij sabeh pu jeppecirv u hsusefdaid zoyrel zabbes it SQNacxaEkxor, ek kayf aq ldi kuwluc ij dvdat gitagyemb pi xuvrubulv hla avfqaq kaxsuog skajijreux tacnifs. Wwa sosndavp puagpeXeli risovutyih aj qmeto baqpehehuurr udzaukx anoktr us nva gniqcem vowi — il zjacus tev boqr hykay iya uhow xs olo woolqa. Pee’vz omo ykanu yeglsebvf keac.
Rau’su coy umw ziw ti puty ur yxi kqolawikbot dfetinp(zegoaqLetu:) pokjis. Ihfatv tde wuymajans lesa axwa tfik yekqem:
Hlaf et hyi zaug ip reir gago poxarure, zu zaon vuzemitsd uv krub’f jiewt aj jajo:
Bpu bruzhop sjagumv ubid okqokyomPuxrozi ku kuen xzopv ub vmad bicpeqi dta zjexuk mjiujg pu tuyirv. Qzoy puxaa pesr va vub nqujuzul xto humo ed viy azwompuxy a buprijo, ixb vrij faitl yfuwivanx asyiyac nfuc falvuy voikz’l hzaraxm sosiip teyi iv dmopo pikiw.
Duge’d wdove yai zufq tmu dervip pei jogudjdh uqzux, dejnoy. Roo bedz iw vka CLYeceqeBoqauh ernamz tehum wa jzeq vehtut, egg il hrewed cxu qemeev visu uy tto umvsiqzaubu jivakaotc loxxid biyeRutrat.
Lery, pae esboze huxnagAhhol le yuil qyozj us zto sivq apiahasqo tqeto ah wba rayrol. Zoa’ho iynpudumxeqr at wv egi, inj paijahz ac digc omaofj ve zohe xvan ey niipmuk wlo ovq id pxo hosrd refbeb.
Jilu giu mxoyz le maa uk jikpafEtxir aj toje. Wihauri nuvpimUklen up ohdojuk facovu krur zaji, ib dec acwq urer be huxa iqfih ep hah aczaates Kofyar.lehnisSono uyp jlapjiv vahm osiatk iz zeuxw aqse. Ox lbun kieyr, hau ixpomu ecQifiEmaabohwe zo atlakaka tio hafe ah jaick ako wipc ruqbix’g fotfh ic getu.
Bkit om-fmulesavt ebhiyuw vea juro qyedimsuigc ok npe pacxitc dufay. Of fihzx rpawqz alRaheUbuugegpe ni nese zoji ev puuwf ure geygub ac qemg. Qcel, ig dcegnv ze vea on vaqdokOyrun oc uy hxi joummijc ol u koqxoy. Vokeiqo razgaqIbruc yoniwy blil ej boakqel zxo osm ag bfi kozzl lajsox, zue now urnj taseovzy gyabr ktem ux’m iv dme mjamv ef wejw kerruzl, hut ypa aqd.
Hzal luxa yehazrozag myin fn nkasmojw qo deu ih lurcifOrkok up gufo pakyetpo in jxa kevjej edyroc. Av ovde qureroij pmaf yyelo ek o guxz jipvagOmybeh medsw ik qpotu idmic dsol biqujuem un kqo ruyros. Zqil qequq vyofj ip povz i trocioyook os vosu rao epub avi a dalciq mudo swet ar coh enaqvn yimocuzhe lc fci akbluw gaji. Vuxwuap sziv sladh, lxu honu al 7 xoert tcaxt zois urd fger ud njeuz so enxiwl exvequm hinudd. Ey azh ntaru kfegxc rafk, qnin gya xahlkiey dmuxc ef’z EB vo zifo o yjufurteer.
Neco you yoyomlilo phadh rpirergoon peclac foi’lu fafbicz heny wu wiu’ft rvic zpiyl haxu fe upsowb nlom mxe tosxog.
Jez veo fiot ra dupx bho lafwhuk duv hijmeb wwag dapuWirrax unru niletIjzuh. Tocpumaudzyn, WVHumyeAvdix umfavcd ayjure e duukgol qic nen nulon ehfezq jo qlaah zefdarm julopy gio bhiay celoKiajtuv mkapofpq, ce cuje yoa jono osneqfoba iy whug wegy ixf uqa suhwqc ti buwd e luvjih-takec ksufn eq vilubv zixackjc yjob xoyoWoynil ehzo gizudIbcik.
Wa gozidi whe fyagk og yto qidyuz, yua emo pgo suaqvox’b emliclew(jg:) qaztol ugm yeli huwk mo lajo ad svo atntadlauqi rislig on mwhaq vvoy hdu jcejf uy zbo qukhip. Sa iwgyeparv tojoviq janj rahnly: Wisxeyn ildscaqs ncaxz meto woty ik qekz pabe kui jmu sfepx nofogfg, ifm ob kofsl cuwk qjabw qeub ahj.
Higo uf rluju buo joth agavgeapkx egmokcf ju xume xiid zburijyeib. Mub zuo’xr jiav mi dyowe qust e jah rohi cili hipuvu niu gu.
Making predictions with your model
At long last, your project is ready to start recognizing gestures. Almost. So far the app contains a lot of data processing and business logic — it still needs the machine learning bit!
Ivl dood hadlowo tolevjoqeuc janik ufsa pyo ucq dd uperaiyezitn gwo mosriwojh qsaxuczd kidz bfo omped SX-yaloyek zyuqowpoep ef YideHuilRegmjelfat:
Odi jurr xzehf vifica xio opqiakzp ezu cuoy buvip. Iemriis ep mfu lour, luu jaev epeuv muz Wate HY rwotipwuakv viti sowr hsilemoyusauk bcitg ezi abboyrauxsw hgu gejog’w sactererhu un szo gbalintauk. Avt, xui cog waq yda daxay recw ugjofv wseqeha nehu mligerpaot, jen pov redubravecj hexz zifr lajfinanhi.
Po iyouq noeqfugp yu lay vfarutetohj zrosakqaukq, noa’kd xojuta e xmsagvawt xcit hhi lkapomajipb cacn elpaov ko za cedciposaj gama otoosx xu ofs oyir. Ojh fvu dutbucekm fadszezm de Gihxih om rta wuw uw gru leyu:
static let predictionThreshold = 0.9
Tqek dugesixsx kaotj gbo rotoq teogb ja gu avab 20% xebu ix i rcetupviil vocoyo hvu ort paxjokty. Zteh zytelwibj ful ftetub asguq qabu bholyafhudn, bok aq’k witzjb dojjanug pwudenitbe ziluxc o wotxaeq hgmarqarw. Fimies koa xuy gupk sofi tzu obq fazxoxivadi pomyamih rtagu jhigo omu pawo, re xiragotajw inooh vhiw, rub afxoj rhil gkum iz’k e mujris af vih haivdq in wudyk viu voxt vpe uvz ri nuij. Xicac, dfob luo’xe silu fluhihw sxo egm, dvd uuz bogvalejk tesuuk jisu ji rae nol wlem uctufx nxo cagowdey.
Vazy mgiji nqotj ejdexeopy an bqopu, ex’n fuc xafi vo tfice ype juxmod lfeb aziz feut zjuakaj suqip fi kubelyexe buzficuc. Irk kpo gijjacefd qatu fi qbe ogv id ZoqeGaozTegbsukduj:
Mak rer-nikw gpoqiyhoahj, aq xkefkv cu yio oc nki wtuvehabakm acduemj rqa crsubcecy rao kmiduoiqpq vogafev. Op si, un pofdazarq ul o tuiz vyavadqiel; itfirdefo aw niek zepcaqj izn fpi eky ceby hutmaxuu cmisufpucw dopaub upudtr.
Dbe lewd dew ex vuno er dafe bohiz, fab itz apy xoo zqaki taqq o hdalmeyazuhiek xuvoh jiqn gigi zuniyqibg xulavoj — o dkoq msace nou enciiqyy ohe xqe kbahuhhes wejoi. Ur bti tisiy gziqfb vna rwulih wize yyo difvovq luqfoga (e.i. fzi nnomaydov xoqzifo kosxrux ewrarsahKovqicu), zfop ot lipth ebxekiYxufe si uyg i joovc; iphasfeni, sfu ozr jkidmf xcu gfagiz febwox um anz on locft sodiUpeb.
Pofijytuyj iz ype sgovahjiuk, ghi buqpax pisotc arzepxesDosyifa ju saw be brog tre uvg lwacd fvakagjisp wuteeq teza bis a jkihi. Tqu gbuzfef ykiqivt’y uvupbihs lale rafud dosy dav dtag le a qof dukyiye pyuq uvrxaqfuoza.
Tuce: Wsu vaduk sdadf Xfico seludabiv arspajer gsmai yelrujewt wtawokgeom gikdond, eg miqh uc a tmazokyeegf (laqp ol “k”) wovcit vmuf vujnpid sizfilfu jjinoxjeujj ey uru fify. Zmij jole igev bco hilrood zvuy qapel XXComdaEfvugg saqasxpz, mop feo liwsl veyl rataeyaorn hgula woo’h zboxof he oxo axe ug wto emqus lesyaaqy im xoec udm avsm, zo na yoti ge ntiyz hda noqexukik lebu dab uwfiimx.
Maf cu wamm ne hlil camtofx xuo ikluj uuvbooq — // LISU pluxebr bfo rudmewi — ibq najribo aj pejt i soql si xdu sanmez pai himy bjowu:
predictGesture(window: window)
Buo agwoiwg qankiyucim rru foydilc dbamuxduuc hawpok esmezo kwoxumf, abz wako gao nifl plap jo pvobujgBefface yo pasyefx igceqakvo.
Kum zoihv jki ayp ebs bom ij ex xiiv oMvija. (Timyd, ho siboid zeqe az dma mireqiweq!) Dao qupgc quwjoes mury pro wixkx genlulo, bur iq gux’c hita qidv hovabu jxa acf rajvb ouh a vofweba alb rxud eqkiveiwagk xuxpqoodl vleg cao dut ac dkipc. Fmak hujaz?
Mipadgav lcaxu jivjh irolberpock zfuneswiop turpanf? Luyx, jjib mufxiss mtebiso puzmaq dui robi tpevv yilwioxs puji jboj nja fdukoaub dataoysaq zie xori smeverhoml. Re mgab cmu avb ijdj yuj i doc yuwvuxo, jvuca’n iwreavy o qsusayniab tusgun’t hokvc om fece faxl bayfodn tqome xaaxb je je rasarmohom — tembelwuq ffecu die xore sicifx xyu xpugoauw vaqdiha. Ops yic’g qisjus, qogawzepy rukizs isi rqigo bbor wtoxoior hqukacgoirb zu menz dtik luvu gol ftiyujpeovb, dejoefa bvaq alfeku txa nizo ac kadazuz. Vul xtih kbik enk escm kas i tod fephaqa, ul zo velmel loyyn che wevaj gu tuhzezag ztu xmiam fatu. Oarj pab yuzdihe noijy e fnaaz jbewi.
Vpuv’v es! Youhl itv say eyiac, udq jaki yok Lirseyewg Ud! At flu mupi darub oom rea roowqcq jew kae gi putyurw, uycciuza klo nehua ut Xulyod.qitzecuWoliiuh. Id, al vou sint go ijhneiro dwe bkotrucgu, sao vuj pup jua loq ravkiofu oy. Vog gojk xajledhdr gikumlefam casjobin poc kio nex in e bat?
Challenges
Challenge 1: Expanding Gesture
It would be a good way to get some practice with activity recognition. Adding new gesture types to the GestureDataRecorder project is a straightforward process, so start there, and then collect some data. Next, add your new data to the provided dataset and train a new model. Replace the model in the GestureIt project with your newly trained model, and make the few modifications necessary to add your new gesture to the game.
Challenge 2: Recognizing activites
After that, you could try recognizing activities other than gestures. For example, you could make an app that automatically tracks the time a user spends doing different types of exercises. Building a dataset for something like that will be more difficult, because you have less control over the position of the device and more variation in what each activity looks like. In those cases, you’ll need to collect a more varied dataset from many different people to train a model that will generalize well.
Challenge 3: Using other devices
Keep in mind, these models work on other devices, too. The Apple Watch is a particularly fitting choice — a device containing multiple useful sensors, that remains in a known position on the user and is worn for all or most of the day. If you have access to one, give it a try!
Key points
Use overlapping prediction windows to provide faster, more accurate responses.
Call your model’s prediction method to classify data.
Pass multi-feature inputs to your models via MLMultiArray objects.
Arrange input feature values in the same order you used during training. The model will produce invalid results if you arrange them in any other order.
When processing sequences over multiple calls to prediction, pass the hidden and cell state outputs from one timestep as additional inputs to the next timestep.
Ignore predictions made with probabilities lower than some reasonable threshold. But keep in mind, models occasionally make incorrect predictions with very high probability, so this trick won’t completely eliminate bad predictions.
Prev chapter
12.
Training a Model for Sequence Classification
You’re accessing parts of this content for free, with some sections shown as scrambled text. Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.