diff --git a/src/chapter_3.md b/src/chapter_3.md index c97b3cb..2410316 100644 --- a/src/chapter_3.md +++ b/src/chapter_3.md @@ -1,160 +1,137 @@ -# Analisi +# Metodologia {#sec:methodology} -## RQ1: come il ML e' distribuito sull'architettura dei progetti? {#sec:rq1} +## Research Questions -In questa prima analisi si è andato a verificare l'esistenza di una differenza nei files e nelle directories modificate in base al tipo di cambiamento. -Per poter svolgere questa analisi è stato necessario individuare il numero totale di file modificati per *fix* generici e per i *fix* specifici del \acl{ML}. -A tal fine i commit sono stati raggruppati rispetto al progetto e al tipo di cambiamento (\ac{ML}, no \ac{ML}) e per ogni istanza di questo raggruppamento si è eseguito l'union set dei files modificati. -Come output di questa fase si è generato per ogni progetto: +Questo studio ha l'obiettivo di dare una risposta a queste cinque domande: -- l'insieme dei file modificati per *fix* di \ac{ML} -- l'insieme dei file modificati per fix generici +- **RQ1**: *come il \ac{ML} e' distribuito sull'architettura dei progetti?* -Infine eseguendo l'union set tra questi due insiemi si è ottenere l'insieme totale dei files modificati durante i *fix*. -In questo modo è stato possibile andare a valutare la percentuale di files modificati in relazione al tipo di cambiamento. -Attraverso la funzione di libreria Python `os.path.dirname` sono stati ottenuti i tre insiemi sopra citati anche per quanto riguarda le directories. + In questa *RQ* si vuole investigare l'architettura dei progetti. + In particolare l'attenzione viene concentratala sui files e sulle directories modificate durante interventi di *issues fixing*. + Obbiettivo di questa domanda è anche individuare la percentuale di files che utilizzano import riconducibili a librerie e framework di \acl{ML}. +- **RQ2**: *come sono distribuiti i bug sulle diverse fasi di \ac{ML}?* -Dalla @fig:files-directories si può notare che i cambiamenti generici vanno ad impattare su una superficie maggiore del sistema, sia che l'analisi sia svolta al livello di files che di directories. -Un'ulteriore aspetto interessante riguarda la varianza delle distribuzioni, infatti, indipendentemente dalla granularità dell'analisi, il dato riguardante i cambiamenti di \acl{ML} è caratterizzato da una maggiore varianza. + Il workflow tipico per lo sviluppo di un'applicazione di \acl{ML} si compone di più fasi. + L'obiettivo di questa *RQ* è quello di individuare le fasi più critiche per quanto riguarda l'introduzione di difetti all'interno del prodotto software. +- **RQ3**: *esiste una differenza di entropy tra \ac{ML} bug e altri bug?* -![Percentuale di files e directories modificate in base al tipo di cambiamento](figures/files-and-directories.pdf){#fig:files-directories width=80%} + A partire dai lavori precedenti svolti sull'entropia di un cambiamento, si vuole capire se esiste una differenza in termini di entropia generata tra le correzioni dei difetti ascrivibili al \acl{ML} e gli altri difetti. +- **RQ4**: *come varia il livello di discussione tra \ac{ML} bug e altri bug?* -Un'ulteriore analisi rispetto all'architettura dei progetti è stata svolta mediante gli import. -Attraverso uno script sono stati estratti, per ogni file, gli import utilizzati all'interno del file stesso. -A questo punto sono stati individuati i files di \acl{ML} in base agli import utilizzati. -La classificazione è avvenuta utilizzando due livelli di severità; in un primo (severità *strict*) caso sono stati considerati come import di \acl{ML} solo delle librerie strettamente di \ac{ML} come ad esempio `keras`, `TernsorFlow`, `PyTorch`, ecc. -Mentre in un secondo caso (severità *base*) sono state incluse anche librerie utilizzate spesso in ambito \ac{ML}, ma anche in altri ambiti, come ad esempio `pandas`, `numpy` e `scipy`. + Questa *RQ* riguarda il livello di discussione dei *bug*. + In particolare si vuole capire se, all'interno dei progetti di \acl{ML}, i bug generici sono discussi con lo stesso livello di approfondimento di quelli specifici del \ac{ML}. +- **RQ5**: *come varia il time-to-fix tra \ac{ML} bug e altri bug?* -![Percentuale di file che utilizzano librerie di ML](figures/imports.pdf){#fig:imports width=70%} + Un altro aspetto caratteristico di un *fix* è il tempo necessario per poter essere attuato. + Questa *RQ* ha lo scopo di verificare l'esistenza di differenze tra i *bug* generici e quelli di \acl{ML}. -Dal boxplot riportato in @fig:imports si può notare che, indipendentemente dalla severità dell'analisi, la percentuale di file che utilizzano librerie di \acl{ML} è caratterizzata da una forte varianza. -Ciò indica che i progetti inclusi all'interno dello studio sono di varia natura e che alcuni sono più incentrati sul \ac{ML} rispetto ad altri. -Inoltre, considerando l'analisi *strict*, è possibile osservare come solo un $25\%$ dei progetti abbia una percentuale di files di \ac{ML} superiore al $45\%$. +## Selezione dei progetti -## RQ2: come sono distribuiti i bug sulle diverse fasi di ML? {#sec:rq2} +L'individuazione dei progetti da analizzare è avvenuta mediate l'ausilio dell'\ac{API} messa a disposizione da GitHub. +In particolare è stata eseguita una query per ottenere una lista di repository che fanno uso di librerie e framework di \ac{ML} come `TensorFlow`, `Pytorch` e `scikit-learn`. +In questo modo è stato possibile ottenere una lista di $26758$ repository che è stata successivamente filtrata per individuare solo i progetti d'interesse per il seguente studio. -Come illustrato nella @sec:classificazione-commit per poter determinare la natura di un *issue fix* si è fatto ricorso alla classificazione delle *issues* ad esso associate. -La maggior parte delle *issues* è stata classificata automaticamente, ma è stato comunque necessario classificarne una porzione in modo manuale per poter avere un train/test set. -Come detto precedentemente, nel caso delle *issues* classificate a mano, oltre all'individuazione della tipologia (\ac{ML}, non \ac{ML}) è stata individuata anche la fase in cui il problema si palesava (si veda @sec:classificazione-issues). -Questo dato aggiuntivo presente su alcune issues è stato *proiettato* anche sulla classificazione dei commit di *fix* per andare a valutare come questi sono distribuiti sulle varie fasi. -I risultati di questa analisi sono riportati in @fig:count-fix-phases. +L'operazione di filtraggio è avvenuta attraverso due fasi; una prima automatica e una seconda manuale. +La prima fase ha avuto l'obiettivo di selezionare unicamente i repository *popolari*. +Nella maggior parte dei casi viene utilizzato il numero di stelle come indice della popolarità di un progetto [@borges2016understandingfactorsthat], ma per questo lavoro si è preferito dare maggiore rilevanza ad altri aspetti, come il numero di fork, il numero di *contributors* e il numero di issues chiuse. +Questa scelta è stata dettata dall'esigenza di selezionare non solo repository popolari, ma anche caratterizzati da una forte partecipazione della community. -![Istanze dei fix in base alla fase](figures/count-fix-phases.pdf){#fig:count-fix-phases width=70%} +I progetti che hanno superato questa prima selezione dovevano: -Rispetto alla distribuzione sulle issues (@fig:labeling-phases) è possibile notare la scomparsa della fase *data collection*, inoltre è evidente anche la riduzione delle occorrenze di *model training* e una crescita d'importanza per quanto riguarda le fasi di *model requirements* e *model deployment*. -Sfortunatamente i dati disponibili per questa analisi sono molto limitati (è stato possibile ricavare la fase solo per quaranta *fix*), per cui non è stato possibile effettuare delle analisi più approfondite. +- essere lavori originali, per cui sono stati esclusi tutti i fork. +- avere almeno cento issues chiuse. +- avere almeno dieci contributors. +- avere almeno venticinque fork. -## RQ3: esiste una differenza di entropy tra ML bug e altri bug? {#sec:rq3} +Alla fine di questa prima selezione il numero di repository si è ridotto a sessantasei e sono stati analizzati manualmente per rimuovere listati associati a libri e/o tutorial, progetti non in lingua inglese e librerie. +Alla fine di questa seconda fase il numero di progetti è sceso a trenta. -La successiva analisi avevo lo scopo di verificare l'esistenza di una differenza tra l'entropia del *fix* rispetto alla natura di questi. -L'analisi è stata svolta sia a livello di file, sia a livello di linee, quindi per ogni commit del dataset è stato necessario individuare sia il numero di file che hanno subito delle modifiche, sia il numero di linee alterate, considerando in questo modo sia le aggiunte che le rimozioni. +## Fetch di issues e commit -Inoltre per poter valutare l'entità del cambiamento è stato necessario conoscere anche il numero totale di file e di linee di ogni progetto. -Questi valori sono stati calcolati attraverso la storia `git` del branch `master`[^branch-master]. -Per ogni commit sono stati individuati i file aggiunti ($+1$) e rimossi ($-1$) in modo tale da poter calcolare il delta-cambiamento del commit. -Eseguendo la somma di questo delta su tutti i commit si è ottenuto il numero totale di file del progetto. -In modo analogo si è proceduto anche per quanto riguarda le linee. +Una volta individuati i progetti da analizzare si è reso necessario recuperare l'intera storia dei progetti e le issues ad essi associate. +Per entrambe le operazioni è stato utilizzato il tool *perceval*[@duenas2018percevalsoftwareproject]. +Nel caso delle issues, essendo queste informazioni non direttamente contenute all'interno del repository `git`, è stato necessario utilizzare nuovamente l'\ac{API} di GitHub. +Poiché le chiamate associate ad un singolo *token* sono limitate nel tempo si è scelto di configurare *perseval* in modo tale da introdurre in automatico uno ritardo ogni qualvolta veniva raggiunto il limite. +Inoltre il codice è stato dispiegato su un \ac{VPS} in modo da poter eseguire il fetch senza che fosse necessario mantenere attiva una macchina fisica. -[^branch-master]: Oltre al branch `master` è stato considerato anche il branch `main` diventato molto comune dopo le proteste del movimento Black Lives Matter e il branch `master-V2` unico branch utilizzato da un progetto. +Con il processo precedentemente illustrato è stato possibile recuperare: -Una volta note queste informazioni preliminari è stato possibile calcolare l'entropia dei *fix* che è stata riportata nei boxplot[^boxplot-entropy] in @fig:entropy. -Dal boxplot in @fig:files-entropy è possibile notare una distribuzione equivalente per le due tipologie di fix. -Una situazione analoga si riscontra anche nell'analisi sulle linee (@fig:lines-entropy) anche se in questo caso è possibile notare che i valori di entropia associati ai fix di \ac{ML} sono shiftati leggermente verso l'alto. +- $34180$ commit. +- $15267$ tra issues e pull request. -[^boxplot-entropy]: Per ragioni di visualizzazione è stato scelto il $95$-$esimo$ quantile come limite superiore di entrambi i grafici. +## Classificazione dei dati + +### Classificazione delle issues {#sec:classificazione-issues} + +Al fine di poter eseguire un confronto tra i *fix* di \ac{ML} e quelli *generici* è stato necessario classificare sia le issues che i commit. +Per quanto riguarda i primi si è scelto di attuare una classificazione basata sul testo, in particolare considerando il titolo e il corpo della issue, ma escludendo i commenti di risposta in modo da non rendere i dati troppo rumorosi. +Il numero elevato di elementi non rende praticabile una classificazione manuale per cui si è optato per una classificazione automatica. +A tal fine sono stati implementati ed analizzati due classificatori, uno supervisionato e uno non supervisionato. + +I due modelli considerati sono: + +- un classificatore statico basato su una lista di vocaboli tipici del \ac{ML}. +- un modello *naïve Bayes* [@2021naivebayesclassifier; @harrington2012machinelearningaction]. + +La classificazione mediate il classificatore statico non necessita di un *labeling* manuale dei dati, ma richiede la definizione dei vocaboli tipici del \ac{ML}. +Lista dei termini caratteristici del \acl{ML} non è stata costruita da zero, ma è basata su lavori precedenti[@humbatova-2019-taxonomyrealfaults]. +In questo modo tutte le issues che utilizzavano almeno un vocabolo tipico del \acl{ML} sono state classificate come issues di \ac{ML}. + +Nel caso del modello *naïve Bayes*, essendo questo un algoritmo di apprendimento supervisionato, si è resa necessaria una classificazione manuale delle issues. +A tal scopo è stato eseguito un campionamento stratificato in base al progetto di provenienza di $376$ issues che sono state divise tra due lettori e labellate. +Durante il labeling si scelto di classificare ulteriormente le issue di \ac{ML} al fine di individuare anche la fase in cui il problema si è palesato. +La definizioni delle varie fasi è avvenuta partendo da un lavoro di *Microsoft*[@amershi-2019-softwareengineeringmachine]. + +Le fasi considerate sono: + +- *Model Requirements*: questa fase comprende tutte le discussioni rispetto all'individuazione del modello più adatto, le funzionalità che questo deve esporre e come adattare un modello esistente per eseguire una diversa funzionalità. +- *Data Collection*: comprende le operazioni volte alla definizione di un dataset. + Rientrano in questa fase sia la ricerca di dataset già esistenti che la costruzione di nuovi dataset. +- *Data Labeling*: questa fase si rende necessaria ogni qual volta si opera con modelli basati su apprendimento supervisionato. +- *Data cleaning*: in questa fase non rientrano soltanto le operazioni strettamente di pulizia dei dati come ad esempio rimozione di record rumorosi o incompleti, ma tutte le trasformazioni eseguite sui dati, quindi anche operazioni di standardizzazione, flip di immagini ecc. +- *Feature Engineering*: questa fase serve per identificare le trasformazioni da attuare sui dati e le migliori configurazioni degli *hyperparametri* al fine di migliorare il modello. +- *Model Training*: questa fase racchiude il training vero e proprio del modello. +- *Model Evaluation*: in questa fase vengono valutate le performance del modello utilizzando metriche standard come *precision* e *recall*, ma anche andando a confrontare i risultati ottenuti rispetto a quelli generati da altri modelli o rispetto all'esperienza[^esperienza]. +- *Model Deployment*: questa fase riguarda il dispiegamento del modello sul dispositivo target. +- *Model Monitoring*: una volta dispiegato il modello deve essere continuamente monitora al fini di assicurasi un corretto comportamento anche sui dati reali. + +[^esperienza]: Non sempre è possibile valutare un modello in modo oggettivo, ci sono determinati contesti, come ad esempio la generazione di *deep fakes*, in cui è comunque necessaria una valutazione umana per determinare la qualità del risultato. + +A partire dal dataset *labellato* è stato possibile costruire un training e un test set, mediante i quali è stato possibile allenare e valutare le performance del modello bayesiano. +Mentre le performance del primo modello sono state valutate sull'intero dataset. \begin{figure}[!ht] -\subfloat[Entropia calcolata sui files\label{fig:files-entropy}]{% -\includegraphics[width=0.45\textwidth]{src/figures/files-entropy.pdf} +\subfloat[Numero di issues rispetto al tipo\label{fig:labeling-type}]{% + \includegraphics[width=0.45\textwidth]{src/figures/count-type.pdf} } \hfill -\subfloat[Entropia calcolata sulle linee\label{fig:lines-entropy}]{% - \includegraphics[width=0.45\textwidth]{src/figures/lines-entropy.pdf} +\subfloat[Numero di issues rispetto alla fase\label{fig:labeling-phases}]{% + \includegraphics[width=0.45\textwidth]{src/figures/count-phases.pdf} } -\caption{Entropia in base al tipo di fix} - \label{fig:entropy} + \caption{Risultati della classificazione manuale delle issues} + \label{fig:labeling} \end{figure} -Per verificare la rilevanza statistica di questa diversità sono stati svolti il *ranksum* test e il *Cliff's delta* i cui risultati sono riportati nella @tbl:test-entropy. -Nel caso dell'entropia sui file possiamo dire che la differenza è marginale poiché il *p-value* è prossimo a $0.05$, mentre nel caso dell'entropia calcolato sulle linee la differenza viene confermata dal test. -In entrambi i casi, l'*effect size* è trascurabile. +Al fine di poter confrontare i due modelli sono state utilizzate le metriche di precision e recall. +Com'è possibile notare dai valori riportati in @tbl:confronto-modelli-classificazione-issues, il modello basato sulla lista di vocaboli è leggermente più preciso del modello bayesiano, ma presenta una recall decisamente più bassa. +Dalla @fig:labeling-type si evince la natura minoritaria delle issues di \ac{ML} rispetto alle issues generiche, per questo motivo si è scelto di preferire il modello naïve Bayes in modo da perdere quante meno istanze possibili anche a costo di sacrificare leggermente la precisione. -| | ranksum p-values | Cliff's delta | -|--------------|:----------------:|:-------------:| -| file entropy | 0.059 | 0.044 | -| line entropy | 5.932e-06 | 0.105 | +| | Classificatore statico | naïve Bayes | +|-----------|------------------------|-------------| +| precision | 0.46 | 0.41 | +| recall | 0.74 | 0.94 | -: Risultati dei test statistici per quanto riguarda l'entropia {#tbl:test-entropy} +: Confronto dei due modelli per la classificazione delle issues. {#tbl:confronto-modelli-classificazione-issues} -## RQ4: come varia il livello di discussione tra ML bug e altri bug? {#sec:rq4} +### Classificazione dei commit {#sec:classificazione-commit} -Per rispondere a questa domanda è stato necessario andare a valutare il numero di commenti presenti all'interno di ogni issues. -Poiché un singolo commit può far riferimento a più issues è stato considerato il numero di commenti medi. -I risultati ottenuti sono stati riportati nel boxplot[^boxplot-discussion] in @fig:discussion-comments. +Prima di poter classificare i commit si è reso necessaria un'ulteriore fase di filtraggio in modo da poter separare i commit di *issue fixing* da quelli generici. +Sono stati considerati come commit di *fix* tutti quei commit al cui interno veniva fatto riferimento a delle issues attraverso la notazione *"#"*. +Questa operazione ha ridotto il dataset dei commit a $3321$ unità la cui distribuzione in base al tipo è riportata in @fig:count-commit. -In questo caso si evince una differenza molto più marcata tra le due distribuzioni. -In particolare è possibile notare che le *issue fix* di \ac{ML} presentano una maggiore discussione e anche una maggiore varianza. -Se consideriamo la differenza interquartile, in modo da escludere completamente eventuali outlier, possiamo osservare che nei *fix* generici questa varia tra zero e uno. -Ciò vuol dire che il $50\%$ interno delle issues o non presenta commenti o ne presenta uno solo. -Mentre la differenza interquartile dei *fix* di \acl{ML} è compreso tra uno e cinque quindi nel $50\%$ interno tutte le issues hanno almeno un commento di risposta. +A questo punto è stato possibile separare i *fix* di \acl{ML} da quelli generici. +La classificazione è avvenuta attraverso la lista delle issues citate all'interno del *commit message* e sono stati considerati come commit di \ac{ML} tutti quei commit che facevano riferimento ad almeno una issue di \ac{ML}. -[^boxplot-discussion]: In questo caso il limite superiore è pari al $97$-$esimo$ quantile. +\newpage -\begin{figure}[!ht] -\subfloat[Numero di commenti medi\label{fig:discussion-comments}]{% -\includegraphics[width=0.45\textwidth]{src/figures/comments.pdf} - } - \hfill -\subfloat[Numero di parole medie per commento\label{fig:discussion-words}]{% - \includegraphics[width=0.45\textwidth]{src/figures/words.pdf} - } -\caption{Livello di discussione in base al tipo} - \label{fig:discussion} -\end{figure} - -A questo punto si è cercato di capire se al maggior numero di commenti è associata effettivamente una maggiore quantità di informazioni scambiate. -Per svolgere questa analisi si è partiti dal presupposto che la quantità di informazioni scambiate sia proporzionale al numero di parole utilizzate nel commento. -Quindi per ogni *issue* è stato calcolato il numero medio di parole presenti all'interno di un commento. -I risultati di quest'ulteriore analisi sono riportati in @fig:discussion-words. -Anche in questo caso si può vedere che nel caso di \ac{ML} *fix* la distribuzione presenta valori più elevati e maggiore varianza. -Per cui non solo nei *fix* di \acl{ML} c'è maggiore discussione, ma la discussione è anche più *densa*. - -Anche in questo caso sono stati svolti i test statistici. -In @tbl:test-discussion è possibile vedere come per entrambe le metriche considerate il *p-value* sia abbondantemente inferiore alla soglia di $0.05$ quindi abbiamo una conferma della diversità delle due distribuzioni riscontrata dal boxplot. -Inoltre, per entrambe le metriche, abbiamo un *effect size* medio. - -| | ranksum p-values | Cliff's delta | -|---------------------|:----------------:|:-------------:| -| commenti medi | 9.053e-75 | 0.425 | -| parole per commento | 2.889e-59 | 0.377 | - -: Risultati dei test statistici per quanto riguarda il livello di discussione {#tbl:test-discussion} - -## RQ5: come varia il time-to-fix tra ML bug e altri bug? {#sec:rq5} - -In quest'ultima analisi si vuole andare a valutare se c'è differenza nel tempo necessario per eseguire il *fix*. -Per valutare questo parametro è stato necessario estrarre da ogni *issue* la data di apertura e di chiusura e calcolare i giorni che intercorrono tra queste. -I risultati così ottenuti sono stati riportati in @fig:day-to-fix. - -![Giorni necessari per il fix](figures/day-to-fix.pdf){#fig:day-to-fix width=70%} - -Anche in questo caso è possibile notare una netta differenza tra i *fix* di \ac{ML} e gli altri. -In particolare i bug di \acl{ML} necessitano, mediamente, di maggior tempo per essere risolti e sono caratterizzati da una varianza maggiore. -Inoltre è possibile vedere come la mediana non sia centrata, bensì spostata verso il basso. -Questo vuol dire che il $50\%$ basso dei *bug* di \ac{ML} viene comunque risolto in tempi brevi (due giorni circa), mentre l'altro $50\%$ può richiedere una quantità di tempo decisamente superiore. - -Un'ulteriore testimonianza del maggior tempo necessario per risolvere le problematiche legate al \ac{ML} ci viene data dagli outlier. -Nel caso di un problema generico, questo, viene considerato come *anomalo* se per essere risolto necessita di un tempo superiore ai cinque giorni. -Mentre nel caso dei *fix* di \acl{ML} per essere considerato outlier un *issue*, necessaria di un *time-to-fix* superiore ai trentacinque giorni. - -Il maggior tempo necessario ad attuare la correzione indica che i *bug* di \ac{ML} sono più difficili da individuare e correggere rispetto a quelli generici. -Inoltre questo risultato contribuisce a spiegare il dato emerso dalla sezione precedente, in quanto per individuare la fonte del problema sembrerebbe essere necessaria una discussione più approfondita. - -Anche per quest'ultima *RQ* sono stati svolti i test statistici illustrati precedentemente. -Dai risultati riportati in @tbl:test-time-to-fix è possibile notare un *p-value* inferiore a $0.05$ e un *effect size* medio. - -| | ranksum p-values | Cliff's delta | -|------------|:----------------:|:-------------:| -| day-to-fix | 7.354e-53 | 0.355 | - -: Risultati dei test statistici per quanto riguarda il time-to-fix {#tbl:test-time-to-fix} +![Risultato della classificazione dei commit](figures/count-commit.pdf){#fig:count-commit width=80%}