review all code and dashboard fine tuning
This commit is contained in:
1 parent
4f08fba81a
commit
07df51cdf4
27 files changed
+1102
-16808
No files matched your search
Generated
+7
@@ -10,6 +10,13 @@
|
||||
</Attribute>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="$USER_HOME$/Downloads/test.csv">
|
||||
<value>
|
||||
<Attribute>
|
||||
<option name="separator" value="," />
|
||||
</Attribute>
|
||||
</value>
|
||||
</entry>
|
||||
</map>
|
||||
</option>
|
||||
</component>
|
||||
|
||||
+119
-2
@@ -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.
|
||||
Binary file not shown.
@@ -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 it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
Binary file not shown.
@@ -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"]
|
||||
BIN
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large.
Load diff
@@ -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 it is too large.
Load diff
+775
-365
File diff suppressed because it is too large.
Load diff
@@ -4,17 +4,17 @@
|
||||
"varieties": [
|
||||
{
|
||||
"variety": "Nocellara dell'Etna",
|
||||
"technique": "Tradizionale",
|
||||
"technique": "intensiva",
|
||||
"percentage": 30
|
||||
},
|
||||
{
|
||||
"variety": "Frantoio",
|
||||
"technique": "Tradizionale",
|
||||
"technique": "tradizionale",
|
||||
"percentage": 30
|
||||
},
|
||||
{
|
||||
"variety": "Coratina",
|
||||
"technique": "Tradizionale",
|
||||
"technique": "superintensiva",
|
||||
"percentage": 40
|
||||
}
|
||||
]
|
||||
|
||||
Binary file not shown.
@@ -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
|
||||
@@ -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.
Reference in new issue
Block a user