Ca .NET developer am fost tentat de multe ori spre lumea Python datorită a ceea ce oferă în domeniul AI. Îmi amintesc că pregăteam un material pentru un eveniment, în care făceam o demonstrație pentru .NET pe Raspberry Pi. Fiind pe Raspberry Pi nu se poate să reziști prea mult din a folosi datele direct de la senzori. Cum am citit o mulțime de date de la senzori, în mod natural a venit pasul următor, acela de a face ceva cu aceste date. Se cunoaște că partea nevralgica în AI este lipsa datelor. Dacă nu ai date, nu ai distracție. Eu aveam acele date însă nu știam ce să fac cu ele, chiar dacă în ele stătea un potențial uriaș. Acum îmi place să spun că în AI datele nu sunt combustibilul, ci motorul, spre deosebire de programarea clasică.
Prin urmare, am datele, dar nu știu ce să fac cu ele. Să îmi extind cunoștințele spre un alt limbaj nu e neapărat o problemă, dar să învăț librăriile aferente ar deveni repede o problemă de timp și de integrare. Să ne imaginăm un mediu în care toate procesele sunt pregătite pentru o soluție .NET. Să trebuiască să pregătești mediul pentru Python poate fi o problemă serioasă pentru un developer .NET, pentru că este un alt ecosistem.
Momentul în care ML.NET a fost lansat a fost perfect pentru mine pentru că am simțit că am primit o pereche de aripi. ML.NET este simplu de folosit pentru crearea unui model de ML, chiar și de către cei care nu au cunoștințe de Data Science și, poate cel mai important lucru, este un framework .NET în care scrii exclusiv cod C#.
ML.NET este un framework tânăr și are mult de recuperat până să ajungă la nivelul liderilor din AI. Însă nu știu dacă ar trebui să vedem doar dezavantajele. Să ne uitam puțin peste acest whitepaper https://arxiv.org/pdf/1905.05715.pdf:
Using a 9GB Amazon review data set ML.NET trained a sentiment-analysis model with 95% accuracy. Other popular machine learning frameworks failed to process the dataset due to memory errors. Training on 10% of the data set, to let all the frameworks complete training, ML.NET demonstrated the highest speed and accuracy.
The performance evaluation found similar results in other machine learning scenarios, including click-through rate prediction and flight delay prediction.
ML.NET pune, prin Model Builder, la dispoziția developerilor un tool foarte util pentru antrenarea de modele ML pentru o fereastră de timp predefinită, pornind de la un set de date și terminând cu selecția celui mai bun trainer pentru scenariul selectat. Selecția se face în funcție de calitatea modelelor explorate, modelul ML astfel obținut putând fi consumat imediat. În plus, Model Builder este capabil să genereze cod boilerplate cu toți pașii făcuți în mod interactiv oferind un bun punct de pornire în lumea AI.
Model Builder este un tool extraordinar care îți permite preselectarea feature-urilor pe care le dorești intrate în construirea modelului, dar nu îți oferă nicio sugestie despre care feature-uri sunt mai relevante. Pe de altă parte, un model care conține prea multe feature-uri va necesita un timp mai mare de antrenare dar și de predicție. De asemenea, de multe ori, unele feature-uri mai mult alterează calitatea modelului construit decât ajută, demonstrând că prin reducerea atentă a dimensionalității modelului ML am putea crește acuratețea și performanța modelului.
Menționam anterior că Model builder este capabil să genereze cod boilerplate. Dar ca developeri am vrea să automatizam acest proces de antrenare a modelului ML și nu ne satisface să avem codul astfel generat.
În același timp sunt și avantaje: în spatele Model builderului stă AutoML, care oferă experiența de antrenare a modelului ML. Ar fi extraordinar dacă am putea să preluam controlul asupra acestui cod și să facem câțiva pași mai departe analizând calitatea acestui model, pentru a putea face câteva dintre îmbunătățirile dorite.
Presupunând că am încărcat unele date în obiectul training DataView, acestea cele sunt câteva linii care declanșează experimentarea AutoML pentru clasificarea multi-class într-un interval de timp dat. Acesta este scenariul pe care l-am ales pentru acest articol.
Context = new MLContext(seed: 1);
SweepablePipeline preprocessingPipeline =
Context.Transforms.Conversion
.MapValueToKey(columnInference.ColumnInformation
.LabelColumnName, columnInference
.ColumnInformation.LabelColumnName)
.Append(Context.Auto().Featurizer(data,
columnInformation: columnInference
.ColumnInformation));
var pipeline = preprocessingPipeline
.Append(Context.Auto().MultiClassification(
labelColumnName: columnInference
.ColumnInformation.LabelColumnName));
AutoMLExperiment experiment = Context.Auto()
.CreateExperiment()
.SetPipeline(pipeline)
.SetMulticlassClassificationMetric(
MulticlassClassificationMetric.MicroAccuracy,
labelColumn: columnInference.ColumnInformation
.LabelColumnName)
.SetTrainingTimeInSeconds(time)
.SetDataset(data);
var experimentResult = await experiment.RunAsync();
AutoML Output:
Best trainer: FastTreeOva Accuracy: 0.926 Training time: 338
------------------------------------------------------------
MicroAccuracy MacroAccuracy LogLoss LogLossReduction
0.926 0.929 0.235 0.826
"Măsoară de două ori și taie o singură dată."
Aș dori să mergem puțin mai departe și să vedem cum putem îmbunătăți un model de ML. Subliniez, facem acest lucru fără a avea cunoștințe de Data Science, dar deținerea de noțiuni elementare despre Data Science ar ajuta să înțelegi mai bine ce faci.
Am putea crede că cea mai dificilă este construirea modelului de antrenare, pentru că, în mod evident, acolo pare să se întâmple magia lucrurilor. Dar pentru această parte ne ajută Model Builder cu AI sau AutoML. De fapt, cel mai complicat este să construim un model suficient de bun. Pentru a realiza acest lucru, ne vom baza pe analiza din correlation matrix și analiza din PFI, doi pași, pe care dacă i-am automatiza, ar fi extraordinar. Deoarece pentru fiecare model realizat prin AutoML, am putea să avansăm obținând cu efort minim un model mai bun.
În Machine Learning, o matrice de corelație (cunoscută și ca "heatmap") este un tabel care afișează coeficienții de corelație dintre toate perechile posibile de caracteristici existente (cum ar fi produsul cartezian).
În general, a avea mai multe caracteristici este un avantaj, care crește însă dimensionalitatea modelului nostru. Dar chiar avem nevoie de toate aceste caracteristici? Unele caracteristici ar putea fi destul de redundante.
O valoare mai apropiată de 0 înseamnă caracteristici corelate scăzute (sau nu), o valoare mai apropiată de 1 înseamnă caracteristici corelate ridicate, iar o valoare mai apropiată de -1 înseamnă caracteristici inversate înalt corelate.
var matrix = Correlation.PearsonMatrix(dataArray);
Rezultatele din Correlation Matrix (folosind un prag predefinit de 0,9):
Correlation Matrix, threshold: 0.9
-------------------------------------------------------------
TemperatuTemperatuLuminosit Infrared Distance PIR Humidity
Temperature 1.0000 0.9998 0.4831 0.5865 -0.2873 -0.0020 0.0607
Temperature2 0.9998 1.0000 0.4822 0.5855 -0.2859 -0.0018 0.0621
Luminosity 0.4831 0.4822 1.0000 0.4388 -0.5428 0.1175 0.0457
Infrared 0.5865 0.5855 0.4388 1.0000 -0.3765 0.0359 0.0051
Distance -0.2873 -0.2859 -0.5428 -0.3765 1.0000 -0.1412 -0.0824
PIR -0.0020 -0.0018 0.1175 0.0359 -0.1412 1.0000 0.0809
Humidity 0.0607 0.0621 0.0457 0.0051 -0.0824 0.0809 1.0000
-------------------------------------------------------------
---------------------
No Feature vs. Feature Rate
1. Temperature vs. Temperature2 0.9998
Pentru că Temperature2 și Temperature au măsurători redundante- în realitate, acești senzori sunt foarte apropiați!- putem alege să eliminăm una din ele.
Folosind Permutation Feature Importance (PFI), învățăm cum să interpretăm predicțiile modelului de învățare automată ML.NET, deoarece PFI ne arată contribuția relativă pe care fiecare caracteristică o are în predicție. Modul în care funcționează PFI este prin amestecarea aleatorie a datelor, câte o caracteristică la un moment dat, pentru întregul set de date și calcularea scăderii indicatorului de performanță de interes. Cu cât schimbarea este mai mare, cu atât această caracteristică este mai importantă. În plus, evidențiind cele mai relevante caracteristici, ne putem concentra pe utilizarea unui subset de trăsături mai semnificative care pot reduce potențial zgomotul și timpul de antrenament. Trebuie să decidem cu atenție de ce caracteristici nu avem nevoie, deoarece eliminând unele dintre ele mai puțin relevante, riscăm să introducem bias în modelul nostru.
Putem observa ocazional valori negative în rezultatele PFI. În acele cazuri, predicțiile privind datele amestecate ("shuffled" sau "noisy") au fost mai precise decât datele reale. Acest lucru se întâmplă atunci când caracteristica nu a contat (ar fi trebuit să aibă o relevanță apropiată de 0), dar șansa aleatorie a făcut ca predicțiile privind datele amestecate să fie mai precise. Acest lucru este mai frecvent cu seturile de date mici, precum cel din acest exemplu, deoarece există mai mult spațiu pentru noroc sau șansă.
Codul poate părea puțin mai complicat, deoarece trebuie să replicăm pipeline-ul folosit pentru AutoML.
var model = experimentResult.Model as Microsoft.ML.Data.TransformerChain;
var transformedTrainingData = experimentResult.Model
.Transform(trainingData);
var pfi = Context.MulticlassClassification
.PermutationFeatureImportance(
model.LastTransformer, transformedTrainingData,
permutationCount: 3);
var metrics = pfi.Select(p => (p.Key,
p.Value.MicroAccuracy))
.OrderBy(m => m.MicroAccuracy.Mean);
Rezultatele PFI (folosind un prag predefinit de 0.02):
PFI (by MicroAccuracy), threshold: 0.02
----------------------------------------------------------------------
No Feature MicroAccuracy 95% Mean
1. Infrared -0.2467 0.0274
2. Luminosity -0.2181 0.0121
3. Temperature -0.1224 0.0019
4. Distance -0.0795 0.0025
5. Temperature2 -0.0257 0.0043
6. CreatedAt -0.0186 0.0074
(candidate for deletion!)
7. PIR -0.0076 0.0033
(candidate for deletion!)
8. Humidity 0.0000 0.0000
(candidate for deletion!)
Extragem trainerul cel mai bun obținut cu AutoML și facem evaluarea sa.
var predictions = experimentResult.BestRun.Model
.Transform(testingData);
var metrics = Context.MulticlassClassification
.Evaluate(predictions);
Rezultatele evaluării folosind dataset-ul original:
Best trainer: FastTreeOva Accuracy: 0.926 Training time: 338
----------------------------------------------------------------------
MicroAccuracy MacroAccuracy LogLoss LogLossReduction
0.926 0.929 0.235 0.826
Acum putem să scăpăm de caracteristicile redundante (indicate de matricea de corelație) și de caracteristicile irelevante (indicate de PFI) din setul de date și să trecem la o altă experimentare cu setul de date diminuat și să verificăm din nou setările de evaluare.
Lista de caracteristici arată așa acum:
var features = { "Temperature", "Luminosity",
"Infrared", "Distance" };
Rezultatele evaluării cu lista redusă de caracteristici (fără caracteristicile redundante sau irelevante).
Best trainer: FastTreeOva Accuracy: 0.943 Training time: 342
---------------------------------------------------------------------- MicroAccuracy MacroAccuracy LogLoss LogLossReduction
0.943 0.942 0.207 0.847
"Mai puțin înseamnă mai mult."
Dacă avem un set de date cu multe caracteristici neprocesate, PFI va marca caracteristicile candidate pentru ștergere. Înlăturând una sau mai multe dintre aceste caracteristici și reantrenând modelul, putem obține un model mai bun. (AutoML se va ocupa de găsirea celui mai bun antrenor pentru un anumit set de caracteristici.)
Dacă Corelation Matrix identifică caracteristici foarte corelate, din nou, este posibil să ștergem astfel de caracteristici una câte una, să facem reantrenarea și să verificăm dacă modelul se îmbunătățește cu noul set de caracteristici.
O îmbunătățire plăcută a codului sursă asociat acestui articol ar fi automatizarea ștergerii celor mai irelevante caracteristici (folosind PFI) sau a celor mai corelate (redundante) caracteristici (folosind Corelation Matrix).
Puteți găsi codul sursă din acest articol aici și mai multe articole despre ML.NET pe blogul personal.