Classificazione delle opinioni con Kili e HuggingFace AutoTrain
'Opinion classification with Kili and HuggingFace AutoTrain'
Introduzione
Capire le esigenze dei tuoi utenti è fondamentale in qualsiasi attività legata agli utenti. Ma richiede anche molto lavoro e analisi, che è piuttosto costoso. Perché non sfruttare l’Apprendimento Automatico allora? Con molto meno codice utilizzando Auto ML.
In questo articolo, sfrutteremo HuggingFace AutoTrain e Kili per costruire un flusso di lavoro di apprendimento attivo per la classificazione del testo. Kili è una piattaforma che favorisce un approccio centrato sui dati per l’Apprendimento Automatico attraverso la creazione di dati di addestramento di qualità. Fornisce strumenti di annotazione collaborativa dei dati e API che consentono iterazioni rapide tra la creazione di dataset affidabili e l’addestramento dei modelli. L’apprendimento attivo è un processo in cui si aggiungono dati etichettati al dataset e quindi si riallena iterativamente un modello. Pertanto, è senza fine e richiede che gli esseri umani etichettino i dati.
Come caso d’uso concreto per questo articolo, costruiremo il nostro flusso di lavoro utilizzando le recensioni degli utenti di VoAGI dal Google Play Store. Dopo di che, classificheremo le recensioni con il flusso di lavoro che abbiamo creato. Infine, applicheremo l’analisi del sentimento alle recensioni classificate. Sarà quindi molto più facile analizzare i risultati e capire le esigenze e la soddisfazione degli utenti.
AutoTrain con HuggingFace
L’Apprendimento Automatico Automatico è un termine che indica l’automazione di un flusso di lavoro di Apprendimento Automatico. Include anche la pulizia dei dati, la selezione del modello e l’ottimizzazione degli iperparametri. Possiamo utilizzare i transformers di 🤗 per la ricerca automatica degli iperparametri. L’ottimizzazione degli iperparametri è un processo difficile e che richiede molto tempo.
- Accelerare l’addestramento di modelli di grandi dimensioni utilizzando PyTorch Fully Sharded Data Parallel
- Generazione di testo più veloce con TensorFlow e XLA
- Proximal Policy Optimization (PPO)
Anche se possiamo costruire il nostro flusso di lavoro utilizzando i transformers e altre potenti API, è anche possibile automatizzare completamente tutto ciò con AutoTrain. AutoTrain si basa su molte potenti API come transformers, datasets e inference-api.
La pulizia dei dati, la selezione del modello e l’ottimizzazione degli iperparametri sono tutte completamente automatizzate in AutoTrain. Si può utilizzare appieno questo framework per costruire modelli trasformatori SOTA pronti per la produzione per un compito specifico. Attualmente, AutoTrain supporta la classificazione binaria e multi-etichetta del testo, la classificazione dei token, la risposta alle domande estrattive, la sommarizzazione del testo e il punteggio del testo. Supporta anche molte lingue come l’inglese, il tedesco, il francese, lo spagnolo, il finlandese, lo svedese, l’hindi, l’olandese e altre ancora. Se la tua lingua non è supportata da AutoTrain, è anche possibile utilizzare modelli personalizzati con tokenizzatori personalizzati.
Kili
Kili è una piattaforma di addestramento AI end-to-end per aziende incentrate sui dati. Kili offre funzionalità di etichettatura ottimizzate e strumenti di gestione della qualità per gestire i tuoi dati. Puoi annotare rapidamente dati di immagini, video, testo, PDF e voce controllando la qualità del dataset. Ha anche potenti API per GraphQL e Python che semplificano molto la gestione dei dati.
È disponibile online o in locale e consente di utilizzare tecniche di Apprendimento Automatico moderne sia per la visione artificiale che per NLP e OCR. Supporta la classificazione del testo, il riconoscimento delle entità denominate (NER), l’estrazione delle relazioni e altre attività di NLP/OCR. Supporta anche attività di visione artificiale come il rilevamento degli oggetti, la trascrizione delle immagini, la classificazione dei video, la segmentazione semantica e molto altro!
Kili è uno strumento commerciale, ma è possibile creare anche un account gratuito per sviluppatori per provare gli strumenti di Kili. Puoi saperne di più dalla pagina dei prezzi.
Progetto
Lavoreremo su un esempio di classificazione delle recensioni, insieme all’analisi del sentimento, per ottenere informazioni su un’applicazione mobile.
Abbiamo estratto circa 40.000 recensioni di VoAGI dal Google Play Store. Annoteremo i testi delle recensioni in questo dataset passo dopo passo. E quindi costruiremo un flusso di lavoro per la classificazione delle recensioni. Nella modellazione, il primo modello sarà preparato con AutoTrain. Quindi costruiremo anche un modello senza utilizzare AutoTrain.
Tutto il codice e il dataset possono essere trovati nel repository GitHub del progetto.
Dataset
Iniziamo dando un’occhiata al dataset grezzo,
In questo dataset ci sono 10 colonne e 40130 campioni. L’unica colonna di cui abbiamo bisogno è content
, che è la recensione dell’utente. Prima di iniziare, dobbiamo definire alcune categorie.
Abbiamo definito 4 categorie:
- Sottoscrizione: dato che VoAGI ha un’opzione di sottoscrizione, tutto ciò che riguarda le opinioni degli utenti sulle funzionalità di sottoscrizione dovrebbe appartenere a questa categoria.
- Contenuto: VoAGI è una piattaforma di condivisione, ci sono molti scritti dalla poesia alla ricerca avanzata sull’intelligenza artificiale. Le opinioni degli utenti su una varietà di argomenti e sulla qualità del contenuto dovrebbero appartenere a questa categoria.
- Interfaccia: Pensieri sull’interfaccia utente, ricerca di articoli, motore di raccomandazione e tutto ciò che riguarda l’interfaccia dovrebbero appartenere a questa categoria. Questo include anche problemi legati al pagamento.
- Esperienza utente: Le opinioni e i pensieri generali dell’utente sull’applicazione. Dovrebbero essere in generale astratti senza indicare un’altra categoria.
Per la parte di etichettatura, dobbiamo prima creare un progetto sulla piattaforma di Kili. Possiamo utilizzare sia l’interfaccia web della piattaforma che le API. Vediamo entrambe le opzioni.
Dall’interfaccia web:
Dalla pagina della lista dei progetti, creiamo un progetto di classificazione testuale multi-classe.
Dopo di che, nella pagina del progetto, è possibile aggiungere i dati cliccando sul pulsante Aggiungi risorse. Attualmente, è possibile aggiungere al massimo 25000 campioni, ma è possibile estendere questo limite contattando il team commerciale di Kili.
Dopo aver creato il nostro progetto, dobbiamo aggiungere dei lavori. Possiamo preparare un’interfaccia di etichettatura dalla pagina delle Impostazioni.
Anche se abbiamo definito 4 categorie, è inevitabile incontrare recensioni che dovrebbero avere più categorie o categorie completamente strane. Aggiungeremo due etichette aggiuntive (che non verranno utilizzate per la modellazione) per rilevare anche questi casi.
Nel nostro esempio, abbiamo aggiunto altre due etichette (Altro, Multi-etichetta). Abbiamo anche aggiunto un lavoro di riconoscimento di entità nominative (NER) solo per specificare come abbiamo deciso un’etichetta durante l’etichettatura. L’interfaccia finale viene mostrata di seguito
Come puoi vedere dal menu a sinistra, è anche possibile inserire un link che descrive le tue etichette nella pagina Istruzioni
. Possiamo anche aggiungere altri membri al nostro progetto da Membri
o aggiungere misure di qualità dalle pagine di Gestione della qualità
. Ulteriori informazioni possono essere trovate nella documentazione.
Ora, creiamo il nostro progetto con le API di Python:
Per prima cosa, dobbiamo importare le librerie necessarie
( notebooks/kili_project_management.ipynb )
import os
# elaboreremo i dati (che è un file csv)
import pandas as pd
# client API
from kili.client import Kili
# Perché non utilizzare delle belle barre di avanzamento?
from tqdm import tqdm
from dotenv import load_dotenv
load_dotenv()
Per accedere alla piattaforma, dobbiamo autenticare il nostro client
API_KEY = os.getenv('KILI_API_KEY')
# inizializza e autentica il client di Kili
kili = Kili(api_key = API_KEY)
Ora possiamo iniziare a preparare la nostra interfaccia, l’interfaccia è solo un dizionario in Python. Definiremo i nostri lavori, quindi riempiremo le etichette. Poiché tutte le etichette potrebbero avere anche etichette figlie, passeremo le etichette anche come dizionari.
labels = ['User experience', 'Subscription', 'Content', 'Other', 'Multi label']
entity_dict = {
'User experience': '#cc4125',
'Subscription': '#4543e6',
'Content': '#3edeb6',
}
project_name = 'User review dataset for topic classification'
project_description = "Recensioni dell'app di VoAGI prese dal Google Play Store per la classificazione dei topic"
interface = {
'jobs': {
'JOB_0': {
'mlTask': 'CLASSIFICATION',
'instruction': 'Etichette',
'required': 1,
'content': {
"categories": {},
"input": "radio",
},
},
'JOB_1': {
'mlTask': "NAMED_ENTITIES_RECOGNITION",
'instruction': 'Entità',
'required': 1,
'content': {
'categories': {},
"input": "radio"
},
},
}
}
# riempi il json dell'interfaccia con i lavori
for label in labels:
# converte le etichette in maiuscolo e sostituisce gli spazi con underscore (_)
# es. User experience -> USER_EXPERIENCE
# questo è il modo preferito per riempire l'interfaccia
label_upper = label.strip().upper().replace(' ', '_')
#
content_dict_0 = interface['jobs']['JOB_0']['content']
categories_0 = content_dict_0['categories']
category = {'name': label, 'children': []}
categories_0[label_upper] = category
for label, color in entity_dict.items():
label_upper = label.strip().upper().replace(' ', '_')
content_dict_1 = interface['jobs']['JOB_1']['content']
categories_1 = content_dict_1['categories']
category = {'name': label, 'children': [], 'color': color}
categories_1[label_upper] = category
# ora possiamo creare il nostro progetto
# questo metodo restituisce l'id del progetto creato
project_id = kili.create_project(json_interface=interface,
input_type='TESTO',
title=project_name,
description=project_description)['id']
Siamo pronti per caricare i nostri dati nel progetto. Il metodo append_many_to_dataset
può essere utilizzato per importare i dati nella piattaforma. Utilizzando l’API di Python, possiamo importare i dati per batch di massimo 100. Ecco una semplice funzione per caricare i dati:
def import_dataframe(project_id:str, dataset:pd.DataFrame, text_data_column:str, external_id_column:str, subset_size:int=100) -> bool:
"""
Argomenti:
Input
- project_id (str): specifica il progetto in cui caricare i dati, viene restituito anche quando creiamo il nostro progetto
- dataset (pandas DataFrame): dataset che ha colonne adeguate per id e input di testo
- text_data_column (str): specifica quale colonna contiene i dati di input di testo
- external_id_column (str): specifica quale colonna contiene gli id
- subset_size (int): specifica il numero di campioni da importare alla volta. Non può essere superiore a 100
Output:
None
Restituisce:
True o False in base al successo del processo
"""
assert subset_size <= 100, "Kili consente di caricare al massimo 100 elementi per volta nell'app"
L = len(dataset)
# imposta 25000 come limite di caricamento, può essere modificato
if L>25000:
print('Kili Projects supporta attualmente al massimo 25000 campioni come predefinito. Importazione dei primi 25000 campioni...')
L=25000
i = 0
while i+subset_size < L:
subset = dataset.iloc[i:i+subset_size]
externalIds = subset[external_id_column].astype(str).to_list()
contents = subset[text_data_column].astype(str).to_list()
kili.append_many_to_dataset(project_id=project_id,
content_array=contents,
external_id_array=externalIds)
i += subset_size
return True
Questo semplicemente importa il DataFrame dataset
fornito in un progetto specificato da project_id.
Possiamo vedere gli argomenti dalla docstring, dobbiamo semplicemente passare il nostro dataset insieme ai nomi delle colonne corrispondenti. Useremo solo gli indici di campione che otteniamo quando carichiamo i dati. E poi voilà, il caricamento dei dati è completo!
dataset_path = '../data/processed/lowercase_cleaned_dataset.csv'
df = pd.read_csv(dataset_path).reset_index() # reimposta l'indice per ottenere gli indici dei campioni
import_dataframe(project_id, df, 'content', 'index')
Non è stato difficile utilizzare l’API di Python, i metodi di supporto che abbiamo utilizzato hanno coperto molte difficoltà. Abbiamo anche utilizzato un altro script per controllare i nuovi campioni quando abbiamo aggiornato il dataset. A volte le prestazioni del modello diminuiscono dopo l’aggiornamento del dataset. Questo è dovuto a errori semplici come l’etichettatura errata e l’introduzione di bias nel dataset. Lo script autentica semplicemente e quindi sposta campioni distinti di due versioni di dataset dati a To Review
. Possiamo cambiare la proprietà di un campione tramite il metodo update_properties_in_assets
:
( scripts/move_diff_to_review.py )
# Configura il client Kili e gli argomenti
from kili.client import Kili
from dotenv import load_dotenv
import os
import argparse
import pandas as pd
load_dotenv()
parser = argparse.ArgumentParser()
parser.add_argument('--first',
required=True,
type=str,
help='Percorso del primo dataframe')
parser.add_argument('--second',
required=True,
type=str,
help='Percorso del secondo dataframe')
args = vars(parser.parse_args())
# Imposta la connessione a Kili
API_KEY = os.getenv('KILI_API_KEY')
kili = Kili(API_KEY)
# Leggi i dataframe
df1 = pd.read_csv(args['first'])
df2 = pd.read_csv(args['second'])
# La concatenazione di entrambi ci permette di avere duplicati di elementi comuni
# quindi possiamo eliminare gli elementi duplicati senza mantenere duplicati per ottenere gli elementi diversi tra i due dataframe
diff_df = pd.concat((df1, df2)).drop_duplicates(keep=False)
diff_ids = diff_df['id'].to_list()
# I cambiamenti devono essere forniti come array che
# contiene la modifica per ogni singolo campione.
# Ecco perché viene passato [‘TO_REVIEW’] * len(diff_df) all'argomento status_array
kili.update_properties_in_assets(diff_ids,
status_array=['TO_REVIEW'] * len(diff_ids))
print('IMPOSTA %d VOCI DA REVISIONARE!' % len(diff_df))
Etichettatura
Ora che abbiamo caricato i dati di origine, la piattaforma ha un’interfaccia di etichettatura integrata che è abbastanza facile da usare. Gli shortcut da tastiera disponibili hanno aiutato durante l’annotazione dei dati. Abbiamo utilizzato l’interfaccia senza sforzo, ci sono shortcut definiti automaticamente e semplificano l’etichettatura. Possiamo vedere gli shortcut cliccando sull’icona della tastiera nella parte superiore destra dell’interfaccia, vengono anche mostrati dai caratteri sottolineati nell’interfaccia di etichettatura a destra.
Alcuni campioni erano molto strani, quindi abbiamo deciso di saltarli durante l’etichettatura. In generale, il processo è stato molto più facile grazie alla piattaforma integrata di Kili.
Esportazione dei dati etichettati
I dati etichettati vengono esportati facilmente utilizzando l’API di Python. Lo script di seguito esporta i campioni etichettati e revisionati in un dataframe, quindi li salva con un nome specificato come file CSV.
( scripts/prepare_dataset.py )
import argparse
import os
import pandas as pd
from dotenv import load_dotenv
from kili.client import Kili
load_dotenv()
parser = argparse.ArgumentParser()
parser.add_argument('--output_name',
required=True,
type=str,
default='dataset.csv')
parser.add_argument('--remove', required=False, type=str)
args = vars(parser.parse_args())
API_KEY = os.getenv('KILI_API_KEY')
dataset_path = '../data/processed/lowercase_cleaned_dataset.csv'
output_path = os.path.join('../data/processed', args['output_name'])
def extract_labels(labels_dict):
response = labels_dict[-1] # seleziona l'ultima versione del campione
label_job_dict = response['jsonResponse']['JOB_0']
categories = label_job_dict['categories']
# tutti i campioni hanno un'etichetta, possiamo prenderla semplicemente dal suo indice
label = categories[0]['name']
return label
kili = Kili(API_KEY)
print('Autenticato!')
# la query restituirà una lista che contiene gli elementi corrispondenti (progetti in questo caso)
# poiché abbiamo solo un progetto con questo nome, possiamo semplicemente prendere il primo indice
project = kili.projects(
search_query='User review dataset for topic classification')[0]
project_id = project['id']
# possiamo personalizzare i campi restituiti
# i campi seguenti sono abbastanza,
# labels.jsonResponse contiene i dati di etichettatura
returned_fields = [
'id', 'externalId', 'labels.jsonResponse', 'skipped', 'status'
]
# leggo anche il dataset grezzo per abbinare i campioni con externalId
dataset = pd.read_csv(dataset_path)
# possiamo recuperare i dati come dataframe
df = kili.assets(project_id=project_id,
status_in=['LABELED', 'REVIEWED'],
fields=returned_fields,
format='pandas')
print('Sono stati ottenuti i campioni!')
# passeremo i campioni saltati
df_ns = df[~df['skipped']].copy()
# estrai i campioni etichettati
df_ns.loc[:, 'label'] = df_ns['labels'].apply(extract_labels)
# La colonna externalId viene restituita come stringa, convertiamola in intero
# per usarla come indici
df_ns.loc[:, 'content'] = dataset.loc[df_ns.externalId.astype(int), 'content']
# possiamo eliminare la colonna `labels` ora
df_ns = df_ns.drop(columns=['labels'])
# rimuoviamo anche i campioni con etichetta specificata nell'argomento remove se viene fornito
if args['remove']:
df_ns = df_ns.drop(index=df_ns[df_ns['label'] == args['remove']].index)
print(‘RECUPERO DATI TERMINATO')
print('IL DATASET HA %d CAMPIONI' % (len(df_ns)))
print('SALVATAGGIO DEL DATASET ELABORATO IN: %s' % os.path.abspath(output_path))
df_ns.to_csv(output_path, index=False)
print('TERMINATO!')
Ottimo! Ora abbiamo i dati etichettati come file csv. Creiamo un repository di dataset in HuggingFace e carichiamo i dati lì!
È davvero semplice, basta fare clic sull’immagine del profilo e selezionare l’opzione Nuovo Dataset
.
Quindi inserisci il nome del repository, scegli una licenza se vuoi e il gioco è fatto!
Ora possiamo caricare il dataset da Aggiungi file
nella scheda File e versioni
.
La visualizzazione del dataset è automaticamente disponibile dopo aver caricato i dati, possiamo controllare facilmente i campioni!
È anche possibile caricare il set di dati nell’hub dei set di dati di Hugging Face utilizzando il pacchetto datasets
.
Modellazione
Utilizziamo l’apprendimento attivo. Etichettiamo e ottimizziamo il modello in modo iterativo. In ogni iterazione, etichettiamo 50 campioni nel set di dati. Il numero di campioni è mostrato di seguito:
Proviamo prima AutoTrain:
Prima, apri AutoTrain
- Crea un progetto
- Possiamo selezionare il repository del set di dati creato in precedenza o caricare nuovamente il set di dati. Quindi dobbiamo scegliere il tipo di divisione, lo lascerò come Auto.
- Allenare i modelli
AutoTrain proverà modelli diversi e selezionerà i migliori modelli. Quindi esegue l’ottimizzazione automatica degli iperparametri. Il set di dati viene anche elaborato automaticamente.
Il prezzo dipende completamente dal tuo caso d’uso. Può essere anche di soli $10 o può essere più costoso del valore attuale.
La formazione è terminata dopo circa 20 minuti, i risultati sono piuttosto buoni!
La precisione del miglior modello è quasi del 89%.
Ora possiamo utilizzare questo modello per eseguire l’analisi, ci sono voluti solo circa 30 minuti per configurare il tutto.
Modellazione senza AutoTrain
Utilizzeremo Ray Tune e l’API Trainer di Hugging Face per cercare iperparametri e ottimizzare un modello di deep learning pre-allenato. Abbiamo selezionato il modello di classificazione di sentimenti base di roBERTa, che è stato allenato su tweet per il fine-tuning. Abbiamo ottimizzato il modello su Google Collaboratory e può essere trovato nella cartella notebooks
nel repository di GitHub.
Ray Tune è una libreria popolare per l’ottimizzazione degli iperparametri che include molti algoritmi SOTA pronti all’uso. È anche possibile utilizzare Optuna e SigOpt. Abbiamo anche utilizzato l’algoritmo di pianificazione [Async Successive Halving Algorithm (ASHA)] come scheduler e HyperOpt come algoritmo di ricerca. Che è più o meno un punto di partenza. Puoi utilizzare diversi scheduler e algoritmi di ricerca.
Cosa faremo?
- Importare le librerie necessarie (una dozzina di esse) e preparare una classe di set di dati
- Definire le funzioni e i metodi necessari per elaborare i dati
- Caricare il modello e il tokenizer pre-allenati
- Eseguire la ricerca degli iperparametri
- Utilizzare i migliori risultati per la valutazione
Iniziamo importando le librerie necessarie! (tutto il codice si trova in notebooks/modeling.ipynb e nel notebook di Google Collaboratory)
# importazioni generali per la scienza dei dati / utilizzo / visualizzazione
import json
import os
import random
# barra di avanzamento
from tqdm import tqdm
# manipolazione / lettura dei dati
import numpy as np
import pandas as pd
# visualizzazione
import plotly.express as px
import matplotlib.pyplot as plt
# metriche di valutazione predefinite
from sklearn.metrics import (accuracy_score, f1_score,
precision_score, recall_score)
from sklearn.model_selection import train_test_split
# importazioni di torch
import torch
import torch.nn as nn
from torch.utils.data import DataLoader, Dataset, random_split
# importazioni di Hugging Face
import transformers
from datasets import load_metric
from transformers import (AutoModelForSequenceClassification, AutoTokenizer,
Trainer, TrainingArguments)
# importazioni di Ray Tune per l'ottimizzazione degli iperparametri
from ray.tune.schedulers import ASHAScheduler, PopulationBasedTraining
from ray.tune.suggest.hyperopt import HyperOptSearch
Imposteremo un seed per le librerie che utilizziamo per la riproducibilità
def seed_all(seed):
torch.manual_seed(seed)
random.seed(seed)
np.random.seed(seed)
SEED=42
seed_all(SEED)
Ora definiamo la nostra classe di set di dati!
class TextClassificationDataset(Dataset):
def __init__(self, dataframe):
self.labels = dataframe.label.to_list()
self.inputs = dataframe.content.to_list()
self.labels_to_idx = {k:v for k,v in labels_dict.items()} # copia il dizionario labels_dict
def __len__(self):
return len(self.inputs)
def __getitem__(self, idx):
if type(idx)==torch.Tensor:
idx = list(idx)
input_data = self.inputs[idx]
target = self.labels[idx]
target = self.labels_to_idx[target]
return {'text': input_data, 'label':target}
Possiamo scaricare facilmente il modello specificando il repository HuggingFace hub. È anche necessario importare il tokenizer per il modello specificato. Dobbiamo fornire una funzione per inizializzare il modello durante l’ottimizzazione degli iperparametri. Il modello verrà definito lì.
La metrica da ottimizzare è l’accuratezza, vogliamo che questo valore sia il più alto possibile. Per questo motivo, dobbiamo caricare la metrica, quindi definire una funzione per ottenere le previsioni e calcolare la metrica preferita.
model_name = 'cardiffnlp/twitter-roberta-base-sentiment'
# eseguiremo la ricerca per ottimizzare l'accuratezza del modello,
# dobbiamo specificare e caricare la metrica di accuratezza come primo passo
metric = load_metric("accuracy")
# poiché abbiamo già inserito un nome di modello, possiamo caricare il tokenizer
# possiamo anche caricare il modello ma lo descriverò nella funzione model_init.
tokenizer = AutoTokenizer.from_pretrained(model_name)
def model_init():
"""
L'ottimizzazione degli iperparametri viene eseguita da modelli appena inizializzati,
quindi dovremo inizializzare il modello nuovamente per ogni singola esecuzione di ricerca.
Questa funzione inizializza e restituisce il modello pre-addestrato selezionato con `model_name`
"""
return AutoModelForSequenceClassification.from_pretrained(model_name, num_labels=4, return_dict=True, ignore_mismatched_sizes=True)
# la funzione per calcolare l'accuratezza
def compute_metrics(eval_pred):
logits, labels = eval_pred
predictions = np.argmax(logits, axis=-1) # scegliamo solo gli indici con i valori massimi
return metric.compute(predictions=predictions, references=labels)
Dopo aver definito il calcolo della metrica e la funzione di inizializzazione del modello, possiamo caricare i dati:
file_name = "dataset-11.csv"
dataset_path = os.path.join('data/processed', file_name)
dataset = pd.read_csv(dataset_path)
Ho anche definito due dizionari per mappare le etichette agli indici e gli indici alle etichette.
idx_to_label = dict(enumerate(dataset.label.unique()))
labels_dict = {v:k for k,v in idx_to_label.items()}
Ora possiamo definire l’algoritmo di ricerca e lo scheduler per la ricerca degli iperparametri.
scheduler = ASHAScheduler(metric='objective', mode='max')
search_algorithm = HyperOptSearch(metric='objective', mode='max', random_state_seed=SEED)
# numero di esecuzioni per la ricerca dei parametri
n_trials = 40
Dobbiamo anche tokenizzare i dati di testo prima di passarli al modello, possiamo farlo facilmente usando il tokenizer caricato. Ray Tune funziona in un ambiente “black-box” quindi ho utilizzato il tokenizer come argomento predefinito per un workaround. Altrimenti, si verificherebbe un errore sulla definizione del tokenizer.
def tokenize(sample, tokenizer=tokenizer):
tokenized_sample = tokenizer(sample['text'], padding=True, truncation=True)
tokenized_sample['label'] = sample['label']
return tokenized_sample
Un’altra funzione di utilità che restituisce suddivisioni di dataset Torch stratificate e tokenizzate:
def prepare_datasets(dataset_df, test_size=.2, val_size=.2):
train_set, test_set = train_test_split(dataset_df, test_size=test_size,
stratify=dataset_df.label, random_state=SEED)
train_set, val_set = train_test_split(train_set, test_size=val_size,
stratify=train_set.label, random_state=SEED)
# mescolare i dataframe in anticipo
train_set = train_set.sample(frac=1, random_state=SEED)
val_set = val_set.sample(frac=1, random_state=SEED)
test_set = test_set.sample(frac=1, random_state=SEED)
# convertire i dataframe in dataset torch
train_dataset = TextClassificationDataset(train_set)
val_dataset = TextClassificationDataset(val_set)
test_dataset = TextClassificationDataset(test_set)
# tokenizzare i dataset
tokenized_train_set = train_dataset.map(tokenize)
tokenized_val_set = val_dataset.map(tokenize)
tokenized_test_set = test_dataset.map(tokenize)
# infine restituire i set elaborati
return tokenized_train_set, tokenized_val_set, tokenized_test_set
Ora possiamo eseguire la ricerca! Iniziamo elaborando i dati:
tokenized_train_set, tokenized_val_set, tokenized_test_set = prepare_datasets(dataset)
training_args = TrainingArguments(
'trial_results',
evaluation_strategy="steps",
disable_tqdm=True,
skip_memory_metrics=True,
)
trainer = Trainer(
args=training_args,
tokenizer=tokenizer,
train_dataset=tokenized_train_set,
eval_dataset=tokenized_val_set,
model_init=model_init,
compute_metrics=compute_metrics
)
best_run = trainer.hyperparameter_search(
direction="maximize",
n_trials=n_trials,
backend="ray",
search_alg=search_algorithm,
scheduler=scheduler
)
Abbiamo effettuato la ricerca con 20 e 40 prove rispettivamente, i risultati sono mostrati di seguito. La media ponderata dei punteggi F1, Recall e Precision per 20 esecuzioni.
La media ponderata dei punteggi F1, Recall e Precision per 40 esecuzioni.
Le prestazioni sono aumentate nella terza versione del dataset. A un certo punto nell’etichettatura dei dati, ho introdotto troppo bias nel dataset per errore. Come possiamo vedere, le prestazioni sono diventate più ragionevoli poiché la varianza del campione è aumentata successivamente. Il modello finale è salvato su Google Drive e può essere scaricato da qui, è anche possibile scaricarlo tramite lo script download_models.py.
Analisi Finale
Ora possiamo utilizzare il modello ottimizzato per condurre l’analisi finale. Tutto ciò che dobbiamo fare è caricare i dati, elaborarli e ottenere i risultati delle previsioni dal modello. Quindi possiamo utilizzare un modello pre-allenato per l’analisi dei sentimenti e sperabilmente ottenere delle intuizioni.
Utilizziamo Google Colab per l’inferenza (qui) e poi esportiamo i risultati in result.csv. Può essere trovato in results
nel repository GitHub. Successivamente, analizziamo i risultati in un altro notebook di Google Colaboratory per un’esperienza interattiva. In questo modo puoi utilizzarlo facilmente e interagire.
Controlliamo ora i risultati!
Possiamo vedere che i punteggi forniti sono molto positivi. In generale, l’applicazione piace agli utenti.
Ciò corrisponde anche all’analisi dei sentimenti, la maggior parte delle recensioni sono positive e la minima quantità di recensioni viene classificata come negativa.
Come possiamo vedere dall’immagine sopra, le prestazioni del modello sono abbastanza comprensibili. I punteggi positivi sono nettamente più alti degli altri, proprio come mostra il grafico dell’analisi dei sentimenti.
Riguardo alle categorie definite in precedenza, sembra che il modello preveda che la maggior parte delle recensioni riguardino le esperienze degli utenti (escludendo esperienze relative ad altre categorie):
Possiamo anche vedere le previsioni dei sentimenti sulle categorie definite di seguito:
Non faremo un’analisi dettagliata delle recensioni, una comprensione di base dei potenziali problemi sarebbe sufficiente. Pertanto, è sufficiente trarre conclusioni semplici dai dati finali:
- È comprensibile che la maggior parte delle recensioni sulla sottoscrizione siano negative. I contenuti a pagamento generalmente non sono ben accolti nelle applicazioni mobile.
- Ci sono molte recensioni negative sull’interfaccia. Questo potrebbe essere un indizio per un’analisi ulteriore. Forse c’è un malinteso riguardo alle funzionalità o una funzione non funziona come gli utenti pensavano.
- Le persone hanno generalmente apprezzato gli articoli e la maggior parte di loro ha avuto buone esperienze.
Nota importante sul grafico: non abbiamo filtrato le recensioni in base alla versione dell’applicazione. Quando guardiamo i risultati dell’ultima versione corrente (4.5), sembra che l’interfaccia dell’applicazione confonda gli utenti o abbia bug fastidiosi.
Conclusioni
Ora possiamo utilizzare il modello pre-allenato per cercare di capire le possibili carenze dell’applicazione mobile. Sarà quindi più facile analizzare una specifica funzionalità.
In questo esempio abbiamo utilizzato le potenti API di HuggingFace e AutoTrain insieme all’interfaccia user-friendly di Kili. La modellazione con AutoTrain ha richiesto solo 30 minuti, ha scelto i modelli e li ha addestrati per il nostro utilizzo. AutoTrain è sicuramente molto più efficiente dato che ho impiegato più tempo quando sviluppavo il modello da solo.
Tutto il codice, i dataset e gli script possono essere trovati su GitHub. Puoi anche provare il modello AutoTrain.
Anche se possiamo considerare questo come un valido punto di partenza, dovremmo raccogliere più dati e cercare di costruire pipeline migliori. Pipeline migliori porterebbero a miglioramenti più efficienti.