mirror of
https://github.com/Steffo99/unimore-bda-6.git
synced 2024-11-21 23:44:19 +00:00
more things
This commit is contained in:
parent
7778c648c1
commit
ae2cf563e6
7 changed files with 91 additions and 38 deletions
|
@ -5,14 +5,16 @@
|
|||
<option name="PARENT_ENVS" value="true" />
|
||||
<envs>
|
||||
<env name="CONFIRM_OVERWRITE" value="False" />
|
||||
<env name="EVALUATION_SET_SIZE" value="100" />
|
||||
<env name="NLTK_DATA" value="./data/nltk" />
|
||||
<env name="PYTHONUNBUFFERED" value="1" />
|
||||
<env name="TENSORFLOW_EMBEDDING_SIZE" value="64" />
|
||||
<env name="TENSORFLOW_MAX_FEATURES" value="1000000" />
|
||||
<env name="TF_CPP_MIN_LOG_LEVEL" value="2" />
|
||||
<env name="TRAINING_SET_SIZE" value="2000" />
|
||||
<env name="VALIDATION_SET_SIZE" value="25" />
|
||||
<env name="WORKING_SET_SIZE" value="100000" />
|
||||
<env name="XLA_FLAGS" value="--xla_gpu_cuda_data_dir=/opt/cuda" />
|
||||
<env name="TRAINING_SET_SIZE" value="100" />
|
||||
<env name="VALIDATION_SET_SIZE" value="25" />
|
||||
<env name="EVALUATION_SET_SIZE" value="100" />
|
||||
</envs>
|
||||
<option name="SDK_HOME" value="$PROJECT_DIR$/.venv/bin/python" />
|
||||
<option name="SDK_NAME" value="Poetry (unimore-bda-6)" />
|
||||
|
|
89
README.md
89
README.md
|
@ -26,13 +26,23 @@
|
|||
> (https://jupyter.org/) invece di codice .py e relativi commenti separati su PDF (per comodità di consultazione,
|
||||
> consegnare comunque anche una stampa PDF del notebook oltre al notebook stesso).
|
||||
|
||||
## Sinossi
|
||||
|
||||
In questo progetto si è realizzato una struttura che permettesse di mettere a confronto diversi modi per effettuare sentiment analysis, e poi si sono realizzati su di essa alcuni modelli di sentiment analysis con caratteristiche diverse per confrontarli.
|
||||
|
||||
## Premessa
|
||||
|
||||
### Codice
|
||||
### Packaging
|
||||
|
||||
Il codice dell'attività è incluso come package Python 3.10 compatibile con PEP518.
|
||||
|
||||
Per installare il package, è sufficiente eseguire i seguenti comandi dall'interno della directory del progetto:
|
||||
> **Warning:**
|
||||
>
|
||||
> Il progetto non supporta Python 3.11 per via del mancato supporto di Tensorflow a quest'ultimo.
|
||||
|
||||
#### Installazione del package
|
||||
|
||||
Per installare il package, è necessario eseguire i seguenti comandi dall'interno della directory del progetto:
|
||||
|
||||
```console
|
||||
$ python3.10 -m venv .venv
|
||||
|
@ -40,11 +50,7 @@ $ source venv/bin/activate
|
|||
$ pip install .
|
||||
```
|
||||
|
||||
> **Note:**
|
||||
>
|
||||
> Per via di requisiti particolari di Tensorflow, Python 3.11 non è supportato.
|
||||
|
||||
#### NLTK
|
||||
##### NLTK
|
||||
|
||||
NLTK richiede dipendenze aggiuntive per funzionare, che possono essere scaricate eseguendo il seguente comando su console:
|
||||
|
||||
|
@ -52,11 +58,38 @@ NLTK richiede dipendenze aggiuntive per funzionare, che possono essere scaricate
|
|||
$ ./scripts/download-nltk.sh
|
||||
```
|
||||
|
||||
### Dataset
|
||||
##### Tensorflow
|
||||
|
||||
Il codice dell'attività richiede la connessione a un server MongoDB 6 contenente il dataset di recensioni Amazon fornito a lezione.
|
||||
L'accelerazione hardware di Tensorflow richiede che una scheda grafica NVIDIA con supporto a CUDA sia disponibile sul dispositivo, e che gli strumenti di sviluppo di CUDA siano installati sul sistema operativo.
|
||||
|
||||
Si forniscono alcuni script nella cartella `./data/scripts` per facilitare la configurazione e l'esecuzione di quest'ultimo.
|
||||
Per indicare a Tensorflow il percorso degli strumenti di sviluppo di CUDA, è necessario impostare la seguente variabile d'ambiente, sostituendo a `/opt/cuda` il percorso in cui gli strumenti sono installati sul dispositivo:
|
||||
|
||||
```console
|
||||
$ export XLA_FLAGS=--xla_gpu_cuda_data_dir\=/opt/cuda
|
||||
```
|
||||
|
||||
Per più informazioni, si suggerisce di consultare la pagina [Install Tensorflow 2](https://www.tensorflow.org/install) della documentazione di Tensorflow.
|
||||
|
||||
#### Esecuzione del programma
|
||||
|
||||
Per eseguire il programma principale, è possibile eseguire i seguenti comandi dall'interno della directory del progetto:
|
||||
|
||||
```console
|
||||
$ source venv/bin/activate
|
||||
$ python3.10 -m unimore_bda_6
|
||||
```
|
||||
|
||||
### Dati
|
||||
|
||||
Il codice dell'attività richiede la connessione a un server MongoDB 6 contenente la collezione di recensioni Amazon fornita a lezione.
|
||||
|
||||
> **Warning:**
|
||||
>
|
||||
> La collezione non è inclusa con il repository, in quanto occupa 21 GB!
|
||||
|
||||
Si forniscono alcuni script nella cartella `./data/scripts` per facilitare la configurazione e l'esecuzione di quest'ultima.
|
||||
|
||||
#### Esecuzione del database
|
||||
|
||||
Per eseguire il database MongoDB come processo utente, salvando i dati nella cartella `./data/db`:
|
||||
|
||||
|
@ -64,30 +97,46 @@ Per eseguire il database MongoDB come processo utente, salvando i dati nella car
|
|||
$ ./data/scripts/run-db.sh
|
||||
```
|
||||
|
||||
#### Importazione dei dati da JSON
|
||||
|
||||
Per importare il dataset `./data/raw/reviewsexport.json` fornito a lezione nel database MongoDB:
|
||||
|
||||
```console
|
||||
$ ./data/scripts/import-db.sh
|
||||
```
|
||||
|
||||
Per creare indici MongoDB utili al funzionamento efficiente del codice:
|
||||
#### Creazione indici
|
||||
|
||||
Per creare indici MongoDB potenzialmente utili al funzionamento efficiente del codice:
|
||||
|
||||
```console
|
||||
$ mongosh < ./data/scripts/index-db.js
|
||||
```
|
||||
|
||||
## Introduzione
|
||||
## Struttura per il confronto
|
||||
### Configurazione ambiente e iperparametri - `.config`
|
||||
### Recupero dati dal database - `.database`
|
||||
### Tokenizzatore astratto - `.tokenizer.base`
|
||||
### Analizzatore astratto - `.analysis.base`
|
||||
### Logging - `.log`
|
||||
### Tester - `.__main__`
|
||||
|
||||
<!-- TODO -->
|
||||
## Ri-implementazione dell'esercizio con NLTK - `.analysis.nltk_sentiment`
|
||||
### Wrapping del tokenizzatore di NLTK - `.tokenizer.nltk_word_tokenize`
|
||||
### Ri-creazione del tokenizer di Christopher Potts - `.tokenizer.potts`
|
||||
### Problemi di memoria
|
||||
|
||||
## `.analysis.base`: Costruzione dell'impalcatura necessaria al confronto
|
||||
## Ottimizzazione di memoria
|
||||
### Caching - `.database.cache` e `.gathering`
|
||||
|
||||
<!-- TODO -->
|
||||
## Implementazione di modelli con Tensorflow - `.analysis.tf_text`
|
||||
### Creazione di tokenizzatori compatibili con Tensorflow - `.tokenizer.plain` e `.tokenizer.lower`
|
||||
### Creazione di un modello di regressione - `.analysis.tf_text.TensorflowPolarSentimentAnalyzer`
|
||||
### Creazione di un modello di categorizzazione - `.analysis.tf_text.TensorflowCategorySentimentAnalyzer`
|
||||
#### Esplosione del gradiente
|
||||
|
||||
## `.analysis.nltk_sentiment`: Ricostruzione e ottimizzazione del modello basato su `nltk.sentiment` realizzato a lezione
|
||||
## Implementazione di tokenizzatori di HuggingFace - `.tokenizer.hugging`
|
||||
|
||||
Per avere un modello baseline con cui effettuare un confronto, si è ricostruito un modello basato su `nltk.sentiment` ispirato a quello realizzato a lezione.
|
||||
## Confronto dei modelli
|
||||
|
||||
<!-- TODO -->
|
||||
|
||||
## TODO
|
||||
## Conclusione
|
||||
|
|
|
@ -38,9 +38,9 @@ def main():
|
|||
slog.debug("Selected sample_func: %s", sample_func.__name__)
|
||||
|
||||
for SentimentAnalyzer in [
|
||||
NLTKSentimentAnalyzer,
|
||||
TensorflowPolarSentimentAnalyzer,
|
||||
TensorflowCategorySentimentAnalyzer,
|
||||
# NLTKSentimentAnalyzer,
|
||||
]:
|
||||
|
||||
slog = logging.getLogger(f"{__name__}.{sample_func.__name__}.{SentimentAnalyzer.__name__}")
|
||||
|
|
|
@ -49,9 +49,10 @@ class BaseSentimentAnalyzer(metaclass=abc.ABCMeta):
|
|||
|
||||
for review in evaluation_dataset_func():
|
||||
resulting_category = self.use(review.text)
|
||||
log.debug("Evaluation step: expected %d, received %d, review was %s", review.category, resulting_category, review.text[:80])
|
||||
evaluated += 1
|
||||
try:
|
||||
correct += 1 if round(resulting_category) == round(review.category) else 0
|
||||
correct += 1 if resulting_category == review.category else 0
|
||||
score += 1 - (abs(resulting_category - review.category) / 4)
|
||||
except ValueError:
|
||||
log.warning("Model execution on %s resulted in a NaN value: %s", review, resulting_category)
|
||||
|
|
|
@ -199,7 +199,7 @@ class TensorflowCategorySentimentAnalyzer(TensorflowSentimentAnalyzer):
|
|||
|
||||
log.debug("Compiling model: %s", model)
|
||||
model.compile(
|
||||
optimizer=tensorflow.keras.optimizers.Adam(global_clipnorm=1.0),
|
||||
optimizer=tensorflow.keras.optimizers.Adam(clipnorm=1.0),
|
||||
loss=tensorflow.keras.losses.CategoricalCrossentropy(),
|
||||
metrics=[
|
||||
tensorflow.keras.metrics.CategoricalAccuracy(),
|
||||
|
@ -217,7 +217,7 @@ class TensorflowCategorySentimentAnalyzer(TensorflowSentimentAnalyzer):
|
|||
max_i = i
|
||||
max_p = p
|
||||
result = float(max_i) + 1.0
|
||||
return result
|
||||
return float(round(result))
|
||||
|
||||
|
||||
class TensorflowPolarSentimentAnalyzer(TensorflowSentimentAnalyzer):
|
||||
|
@ -245,25 +245,23 @@ class TensorflowPolarSentimentAnalyzer(TensorflowSentimentAnalyzer):
|
|||
tensorflow.keras.layers.Dropout(0.25),
|
||||
tensorflow.keras.layers.GlobalAveragePooling1D(),
|
||||
tensorflow.keras.layers.Dropout(0.25),
|
||||
tensorflow.keras.layers.Dense(8),
|
||||
tensorflow.keras.layers.Dropout(0.25),
|
||||
tensorflow.keras.layers.Dense(1, activation="relu"),
|
||||
tensorflow.keras.layers.Dense(1, activation="sigmoid"),
|
||||
])
|
||||
|
||||
log.debug("Compiling model: %s", model)
|
||||
model.compile(
|
||||
optimizer=tensorflow.keras.optimizers.Adam(clipnorm=2.0),
|
||||
optimizer=tensorflow.keras.optimizers.Adam(clipnorm=1.0),
|
||||
loss=tensorflow.keras.losses.MeanAbsoluteError(),
|
||||
metrics=[
|
||||
# tensorflow.keras.metrics.MeanAbsoluteError(),
|
||||
]
|
||||
)
|
||||
|
||||
log.debug("Compiled model: %s", model)
|
||||
return model
|
||||
|
||||
def _translate_prediction(self, a: numpy.array) -> Category:
|
||||
return 1 + (a[0, 0] + 0.5) * 4
|
||||
a: float = a[0, 0]
|
||||
a = a * 2 + 1
|
||||
a = float(round(a))
|
||||
return a
|
||||
|
||||
|
||||
__all__ = (
|
||||
|
|
|
@ -124,10 +124,10 @@ def TENSORFLOW_EPOCHS(val: str | None) -> int:
|
|||
"""
|
||||
The number of epochs to train Tensorflow models for.
|
||||
|
||||
Defaults to `5`.
|
||||
Defaults to `3`.
|
||||
"""
|
||||
if val is None:
|
||||
return 5
|
||||
return 3
|
||||
try:
|
||||
return int(val)
|
||||
except ValueError:
|
||||
|
|
|
@ -37,11 +37,14 @@ class Review:
|
|||
else:
|
||||
raise KeyError(item)
|
||||
|
||||
def normvalue(self) -> float:
|
||||
return (self.category - 1) / 2
|
||||
|
||||
def to_tensor_text(self) -> tensorflow.Tensor:
|
||||
return tensorflow.convert_to_tensor(self.text, dtype=tensorflow.string)
|
||||
|
||||
def to_tensor_normvalue(self) -> tensorflow.Tensor:
|
||||
return tensorflow.convert_to_tensor([(self.category - 1) / 4 - 0.5], dtype=tensorflow.float32)
|
||||
return tensorflow.convert_to_tensor([self.normvalue()], dtype=tensorflow.float32)
|
||||
|
||||
def to_tensor_tuple_normvalue(self) -> tuple[tensorflow.Tensor, tensorflow.Tensor]:
|
||||
return (
|
||||
|
|
Loading…
Reference in a new issue