review all code and dashboard fine tuning

This commit is contained in:
Giuseppe Nucifora 2024-12-11 04:33:11 +01:00
parent 4f08fba81a
commit 07df51cdf4
27 changed files with 1102 additions and 16808 deletions

7
.idea/csv-editor.xml generated
View File

@ -10,6 +10,13 @@
</Attribute> </Attribute>
</value> </value>
</entry> </entry>
<entry key="$USER_HOME$/Downloads/test.csv">
<value>
<Attribute>
<option name="separator" value="," />
</Attribute>
</value>
</entry>
</map> </map>
</option> </option>
</component> </component>

View File

@ -1,4 +1,121 @@
python -m olive_oil_train_dataset.create_train_dataset --random-seed 42 --num-simulations 100000 --batch-size 10000 --max-workers 7 # Dashboard Produzione Olio d'Oliva
Questa dashboard interattiva permette di simulare e analizzare la produzione di olio d'oliva basandosi su diversi parametri ambientali e varietali.
python -m weather.uv_index.uv_index_model.py ## Requisiti di Sistema
- Python 3.8 o superiore
- Git LFS (per i file di grandi dimensioni)
- Conda (consigliato) o pip
## Configurazione dell'Ambiente
### Utilizzando Conda (Consigliato)
1. Clona il repository:
2. Crea e attiva l'ambiente conda:
```bash
conda env create -f src/environment.yml
conda activate olive-dashboard
```
### Utilizzando pip
1. Clona il repository:
2. Crea e attiva un ambiente virtuale:
```bash
python -m venv venv
source venv/bin/activate # Linux/MacOS
# oppure
.\venv\Scripts\activate # Windows
```
3. Installa le dipendenze:
```bash
pip install -r src/requirements.txt
```
## Configurazione del Progetto
1. Crea un file `.env` nella directory `src` con le seguenti variabili:
```env
DEV_MODE=True # Imposta su False per utilizzare i modelli ML
```
## Esecuzione della Dashboard
1. Assicurati di essere nella directory `src`:
```bash
cd src
```
2. Avvia la dashboard:
```bash
python olive-oil-dashboard.py
```
3. Apri un browser e vai all'indirizzo:
```
http://localhost:8050
```
## Struttura del Progetto
```
src/
├── dashboard/ # Componenti della dashboard
├── sources/ # Dati e modelli
├── utils/ # Utility functions
├── olive-oil-dashboard.py # Main application
├── olive_config.json # Configuration file
└── requirements.txt # Python dependencies
```
## Funzionalità Principali
La dashboard offre diverse funzionalità:
1. **Configurazione Oliveto**
- Gestione delle varietà di olive
- Configurazione delle tecniche di coltivazione
- Impostazione delle percentuali di mix varietale
2. **Simulazione Ambientale**
- Simulazione degli effetti delle condizioni meteorologiche
- Analisi dell'impatto sulla produzione
- Visualizzazione KPI
3. **Analisi Economica**
- Gestione dei costi di produzione
- Analisi dei margini
- Proiezioni finanziarie
4. **Produzione**
- Monitoraggio della produzione
- Analisi del fabbisogno idrico
- Dettagli per varietà
## Risoluzione Problemi Comuni
### ModuleNotFoundError
Se riscontri errori del tipo "ModuleNotFoundError", verifica di:
1. Aver attivato l'ambiente virtuale corretto
2. Aver installato tutte le dipendenze:
```bash
pip install -r requirements.txt # se usi pip
# oppure
conda env update -f environment.yml # se usi conda
```
### Errori di Importazione dei Modelli
Se riscontri errori nell'importazione dei modelli:
1. Verifica che `DEV_MODE=True` nel file `.env`
2. Controlla che tutti i file necessari siano presenti nella directory `sources/`
## Supporto
Per problemi o domande, aprire una issue nel repository del progetto.

21
src/environment.yml Normal file
View File

@ -0,0 +1,21 @@
name: olive-dashboard
channels:
- conda-forge
- defaults
dependencies:
- python>=3.12
- pandas>=1.5.0
- numpy>=1.21.0
- dash>=2.9.0
- dash-bootstrap-components>=1.4.0
- plotly>=5.13.0
- tensorflow>=2.14.0
- keras>=2.14.0
- scikit-learn==1.5.2
- joblib>=1.2.0
- python-dotenv>=0.21.0
- psutil>=5.9.0
- dvc>=2.0.0
- pip
- pip:
- dash-bootstrap-components>=1.4.0

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1 +0,0 @@
["temp", "humidity", "cloudcover", "visibility", "clear_sky_index", "atmospheric_transparency", "hour_sin", "hour_cos", "day_of_year_sin", "day_of_year_cos", "solar_angle", "solar_elevation", "day_length", "solar_noon", "solar_cloud_effect", "cloud_temp_interaction", "visibility_cloud_interaction", "temp_humidity_interaction", "solar_clarity_index", "cloud_rolling_12h", "temp_rolling_mean_6h", "season_Autumn", "season_Spring", "season_Summer", "season_Unknown", "season_Winter", "time_period_Afternoon", "time_period_Evening", "time_period_Morning", "time_period_Night"]

File diff suppressed because it is too large Load Diff

View File

@ -1,27 +0,0 @@
{
"model_params": {
"input_shape": [
24,
30
],
"n_features": 30,
"sequence_length": 24
},
"training_params": {
"batch_size": 128,
"total_epochs": 100,
"best_epoch": 99
},
"performance_metrics": {
"final_loss": 0.6100732088088989,
"final_mae": 0.4086560010910034,
"best_val_loss": 0.5982702970504761,
"out_of_range_predictions": 0
},
"prediction_stats": {
"n_predictions_added": 227879,
"mean_predicted_uv": 1.8527342081069946,
"min_predicted_uv": 0.00121828552801162,
"max_predicted_uv": 9.946621894836426
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1000 KiB

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@ -4,17 +4,17 @@
"varieties": [ "varieties": [
{ {
"variety": "Nocellara dell'Etna", "variety": "Nocellara dell'Etna",
"technique": "Tradizionale", "technique": "intensiva",
"percentage": 30 "percentage": 30
}, },
{ {
"variety": "Frantoio", "variety": "Frantoio",
"technique": "Tradizionale", "technique": "tradizionale",
"percentage": 30 "percentage": 30
}, },
{ {
"variety": "Coratina", "variety": "Coratina",
"technique": "Tradizionale", "technique": "superintensiva",
"percentage": 40 "percentage": 40
} }
] ]

21
src/requirements.txt Normal file
View File

@ -0,0 +1,21 @@
# Data handling and analysis
pandas>=1.5.0
numpy>=1.21.0
scikit-learn==1.5.2
# Dashboard and visualization
dash>=2.9.0
dash-bootstrap-components>=1.4.0
plotly>=5.13.0
# Machine Learning
tensorflow>=2.14.0
keras>=2.14.0
joblib>=1.2.0
# Environment and configuration
python-dotenv>=0.21.0
psutil>=5.9.0
# File handling
dvc>=2.0.0 # Per la gestione dei file sources.dvc

156
src/sagemaker/inference.py Normal file
View File

@ -0,0 +1,156 @@
import os
import json
import tensorflow as tf
import keras
import numpy as np
from tensorflow.keras.models import load_model
@keras.saving.register_keras_serializable()
class DataAugmentation(tf.keras.layers.Layer):
"""Custom layer per l'augmentation dei dati"""
def __init__(self, noise_stddev=0.03, **kwargs):
super().__init__(**kwargs)
self.noise_stddev = noise_stddev
def call(self, inputs, training=None):
if training:
return inputs + tf.random.normal(
shape=tf.shape(inputs),
mean=0.0,
stddev=self.noise_stddev
)
return inputs
def get_config(self):
config = super().get_config()
config.update({"noise_stddev": self.noise_stddev})
return config
@keras.saving.register_keras_serializable()
class PositionalEncoding(tf.keras.layers.Layer):
"""Custom layer per l'encoding posizionale"""
def __init__(self, d_model, **kwargs):
super().__init__(**kwargs)
self.d_model = d_model
def build(self, input_shape):
_, seq_length, _ = input_shape
position = tf.range(seq_length, dtype=tf.float32)[:, tf.newaxis]
div_term = tf.exp(
tf.range(0, self.d_model, 2, dtype=tf.float32) *
(-tf.math.log(10000.0) / self.d_model)
)
pos_encoding = tf.zeros((1, seq_length, self.d_model))
pos_encoding_even = tf.sin(position * div_term)
pos_encoding_odd = tf.cos(position * div_term)
pos_encoding = tf.concat(
[tf.expand_dims(pos_encoding_even, -1),
tf.expand_dims(pos_encoding_odd, -1)],
axis=-1
)
pos_encoding = tf.reshape(pos_encoding, (1, seq_length, -1))
pos_encoding = pos_encoding[:, :, :self.d_model]
self.pos_encoding = self.add_weight(
shape=(1, seq_length, self.d_model),
initializer=tf.keras.initializers.Constant(pos_encoding),
trainable=False,
name='positional_encoding'
)
super().build(input_shape)
def call(self, inputs):
batch_size = tf.shape(inputs)[0]
pos_encoding_tiled = tf.tile(self.pos_encoding, [batch_size, 1, 1])
return inputs + pos_encoding_tiled
def get_config(self):
config = super().get_config()
config.update({"d_model": self.d_model})
return config
@keras.saving.register_keras_serializable()
class WarmUpLearningRateSchedule(tf.keras.optimizers.schedules.LearningRateSchedule):
def __init__(self, initial_learning_rate=1e-3, warmup_steps=500, decay_steps=5000):
super().__init__()
self.initial_learning_rate = initial_learning_rate
self.warmup_steps = warmup_steps
self.decay_steps = decay_steps
def __call__(self, step):
warmup_pct = tf.cast(step, tf.float32) / self.warmup_steps
warmup_lr = self.initial_learning_rate * warmup_pct
decay_factor = tf.pow(0.1, tf.cast(step, tf.float32) / self.decay_steps)
decayed_lr = self.initial_learning_rate * decay_factor
return tf.where(step < self.warmup_steps, warmup_lr, decayed_lr)
def get_config(self):
return {
'initial_learning_rate': self.initial_learning_rate,
'warmup_steps': self.warmup_steps,
'decay_steps': self.decay_steps
}
@keras.saving.register_keras_serializable()
def weighted_huber_loss(y_true, y_pred):
weights = tf.constant([1.0, 0.8, 0.8, 1.0, 0.6], dtype=tf.float32)
huber = tf.keras.losses.Huber(delta=1.0)
loss = huber(y_true, y_pred)
weighted_loss = tf.reduce_mean(loss * weights)
return weighted_loss
def model_fn(model_dir):
"""Carica il modello salvato."""
custom_objects = {
'DataAugmentation': DataAugmentation,
'PositionalEncoding': PositionalEncoding,
'WarmUpLearningRateSchedule': WarmUpLearningRateSchedule,
'weighted_huber_loss': weighted_huber_loss
}
model = load_model(os.path.join(model_dir, 'model.keras'), custom_objects=custom_objects)
return model
def input_fn(request_body, request_content_type):
"""Converte l'input in un formato utilizzabile dal modello."""
if request_content_type == 'application/json':
input_data = json.loads(request_body)
# Estrai i dati temporali e statici
temporal_data = np.array(input_data['temporal']).reshape(1, 1, -1)
static_data = np.array(input_data['static']).reshape(1, -1)
return {
'temporal': temporal_data,
'static': static_data
}
else:
raise ValueError(f"Unsupported content type: {request_content_type}")
def predict_fn(input_data, model):
"""Esegue la predizione usando il modello."""
prediction = model.predict(input_data)
return prediction
def output_fn(prediction, accept):
"""Converte l'output del modello nel formato richiesto."""
if accept == 'application/json':
prediction_list = prediction.tolist()
return json.dumps({
'prediction': prediction_list
})
raise ValueError(f"Unsupported accept type: {accept}")

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.