[Romanian] Microsoft ML.NET 2.0: Cum îmbunătățim un model de machine learning în trei pași simpli

1. ML.NET 2.0

Cea mai scurtă cale între două puncte este cea pe care o cunoști

Ca .NET developer am fost tentat de multe ori spre lumea Python prin ceea ce oferă în domeniul AI.

Îmi amintesc ca pregăteam un material pentru un eveniment, in care făceam o demonstrație pentru .NET pe Raspberry Pi. Fiind pe Raspberry Pi nu se poate sa rezisti prea mult din a folosi datele direct de la senzori. Am citit o mulțime de date de la senzori, în mod natural a venit pasul următor, sa fac ceva cu aceste date. Se cunoaste ca partea nevralgica în AI este lipsa datelor, daca nu ai date, nu ai distractie. 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 sa spun ca în AI datele nu sunt combustibilul ci motorul, spre deosebire de programarea clasică.

Bun, deci am datele și nu știu ce sa fac cu ele. Sa imi extind cunoștințele spre un alt limbaj nu e neapărat o problema, dar sa invat librăriile aferente ar deveni repede o problema de timp și de integrare. Sa ne imaginăm un mediu în care toate procesele sunt pregatite pentru o soluție .NET, sa trebuiasca sa pregatesti mediul pentru Python poate fi o problema serioasa pentru un developer .NET, pentru ca 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 tanar si are mult de recuperat pana sa ajunga la nivelul leaderilor din AI, Însă nu știu dacă ar trebui sa vedem doar dezavantajele. Sa ne uitam putin 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.

Model Builder (AutoML)

ML.NET pune, prin Model Builder, la dispoziția developerilor un tool foarte util pentru antrenarea de modele ML pentru o fereastra de timp predefinita, pornind de la un set de date și terminand cu selecția celui mai bun trainer pentru scenariul selectat. Selecția se face în funcție de calitatea modelelor explorate, modelul ML astfel obtinut putand fi consumat imediat. In plus, Model Builder este capabil sa 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 iti permite preselectarea feature-urilor care doresti sa intre in construirea modelului, însă nu îți oferă nicio sugestie despre care feature-uri sunt mai relevante. Pe de alta parte, un model care conține prea multe features va necesita un timp mai mare de antrenare dar și de predicție și de multe ori unele features mai mult alterează calitatea modelului construit decât ajuta, iar acest lucru inseamna ca prin reducerea atenta a dimensionalitatii modelului ML am putea creste acuratetea si performanta modelului. Sa tinem minte acest lucru, pentru ca ne vom ocupa de el putin mai jos in acest articol. 

Spuneam mai devreme ca Model builder este capabil sa genereze cod boilerplate, însă, din perspectiva unui developer, noi am vrea sa automatizam acest proces de antrenare a modelului ML și nu ne satisface sa avem codul astfel generat.

Dar am vesti bune, în spatele Model builder-ului sta AutoML, care oferă experiența de antrenare a modelului ML și ar fi extraordinar dac-am putea sa preluam controlul asupra acestui cod și să facem cativa pași mai departe analizând calitatea acestui model, pentru a putea face cateva imbunatatirile dorite.

Presupunând că am încărcat unele date în obiectul trainingDataView, acestea cele sunt câteva linii care declanșează experimentarea AutoML pentru clasificarea multi-class (acesta este scenariul pe care l-am ales pentru acest articol) într-un interval de timp dat.

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

2. Analiza modelului

Masoara de doua ori și taie o singura data

As dori sa mergem puțin mai departe și să vedem cum putem îmbunătăți un model de ML. Spun din nou, facem acest lucru fără a avea cunoștințe de Data Science, dar sa nu ma-ntelegi greșit, sa ai noțiuni elementare despre Data Science ar ajuta să înțelegi mai bine ce faci.

Am putea crede ca cel mai dificila parte este construirea modelului de antrenare, pentru ca, in mod evident, acolo pare sa se intample magia lucrurilor, însă pentru acesta parte ne ajuta Model Builder cu al sau AutoML. De fapt, cea mai dificila parte este sa construim un model suficient de bun, iar pentru acest lucru ne vom baza pe analiza din correlation matrix si analiza din PFI, alți doi pași de care ne vom ocupa în continuare, iar dacă am automatiza acești pași, ar fi extraordinar, pentru ca pentru fiecare model obtinut prin AutoML am putea sa mergem mai departe obtinand cu efort minim un model mai bun.

Correlation Matrix

Î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 lucru bun, dar acest lucru crește dimensionalitatea modelului nostru, prin urmare performanța modelului (timpul de antrenament și timpul de predicție, de asemenea), 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 si Temperature au măsurători redundante (pentru că în realitate acești senzori sunt foarte apropiați!) putem alege să eliminăm una din ele.

Permutation Feature Importance

Folosind Permutation Feature Importance (PFI), învățăm cum să interpretăm predicțiile modelului de învățare automată ML.NET, deoarece PFI ne arata contribuția relativă pe care fiecare caracteristică o are in 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 cât de mult scade indicatorul 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 caracteristici 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 caracteristici nu atât de relevante riscăm să introducem bias în modelul nostru.

Putem vedea ocazional valori negative în rezultatele PFI. În acele cazuri, predicțiile privind datele amestecate (“shuffled” sau “noisy”) s-au întâmplat să fie mai precise decât datele reale. Acest lucru se întâmplă atunci când caracteristica nu a contat (ar fi trebuit să aibă o relevanta 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<Microsoft.ML.ITransformer>;
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

3. Concluzie

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).

Poți găsi codul sursă din acest articol aici: https://github.com/dcostea/AutoMLSample și mai multe articole despre ML.NET pe blogul personal: http://apexcode.ro/

Author: Daniel Costea
Trainer. Developer. Speaker. Microsoft MVP.