review all code and dashboard fine tuning
This commit is contained in:
parent
4f08fba81a
commit
07df51cdf4
7
.idea/csv-editor.xml
generated
7
.idea/csv-editor.xml
generated
@ -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>
|
||||
|
||||
121
src/README.md
121
src/README.md
@ -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.
21
src/environment.yml
Normal file
21
src/environment.yml
Normal 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
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"]
|
||||
Binary file not shown.
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 one or more lines are too long
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.
21
src/requirements.txt
Normal file
21
src/requirements.txt
Normal 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
156
src/sagemaker/inference.py
Normal 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}")
|
||||
BIN
src/utils/__pycache__/__init__.cpython-311.pyc
Normal file
BIN
src/utils/__pycache__/__init__.cpython-311.pyc
Normal file
Binary file not shown.
BIN
src/utils/__pycache__/__init__.cpython-312.pyc
Normal file
BIN
src/utils/__pycache__/__init__.cpython-312.pyc
Normal file
Binary file not shown.
BIN
src/utils/__pycache__/helpers.cpython-311.pyc
Normal file
BIN
src/utils/__pycache__/helpers.cpython-311.pyc
Normal file
Binary file not shown.
BIN
src/utils/__pycache__/helpers.cpython-312.pyc
Normal file
BIN
src/utils/__pycache__/helpers.cpython-312.pyc
Normal file
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user