calcul model sur bouton
This commit is contained in:
@@ -7,6 +7,11 @@ WORKDIR /src
|
|||||||
# Copier les fichiers nécessaires dans le conteneur
|
# Copier les fichiers nécessaires dans le conteneur
|
||||||
COPY requirements.txt /src/requirements.txt
|
COPY requirements.txt /src/requirements.txt
|
||||||
|
|
||||||
|
# Installer les dépendances système (graphviz)
|
||||||
|
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||||
|
graphviz libgraphviz-dev \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
# Installer les dépendances
|
# Installer les dépendances
|
||||||
RUN pip install --no-cache-dir -r requirements.txt
|
RUN pip install --no-cache-dir -r requirements.txt
|
||||||
|
|
||||||
|
|||||||
40
README.md
40
README.md
@@ -43,3 +43,43 @@ ydata-profiling : https://github.com/ydataai/ydata-profiling
|
|||||||
profile = ProfileReport(dataframe, tsmode=True, sortby="date", title="Time-Series EDA")
|
profile = ProfileReport(dataframe, tsmode=True, sortby="date", title="Time-Series EDA")
|
||||||
|
|
||||||
profile.to_file("report_timeseries.html")
|
profile.to_file("report_timeseries.html")
|
||||||
|
|
||||||
|
|
||||||
|
📉 Erreur moyenne absolue : 308.9832
|
||||||
|
Il s'agit de la MAE (Mean Absolute Error), une métrique d'évaluation de ton modèle.
|
||||||
|
|
||||||
|
MAE = moyenne des distances absolues entre les prédictions et les vraies valeurs.
|
||||||
|
|
||||||
|
Une MAE de 308.98 signifie qu'en moyenne, les prédictions du modèle s'écartent de ~309 unités de la valeur réelle.
|
||||||
|
|
||||||
|
Cela peut être acceptable ou énorme selon l'échelle de ta variable cible. Si tu prédis des prix en crypto à 60 000 USD, c'est relativement faible. Si tu prédis des variations de 0.5, c’est catastrophique.
|
||||||
|
|
||||||
|
🧠 Architecture du modèle
|
||||||
|
C’est un modèle Sequential avec 3 couches Dense (fully connected) :
|
||||||
|
|
||||||
|
Couche Sortie Paramètres
|
||||||
|
dense (None, 64) 320
|
||||||
|
dense_1 (None, 32) 2,080
|
||||||
|
dense_2 (None, 1) 33
|
||||||
|
|
||||||
|
✳️ Détails :
|
||||||
|
(None, 64) signifie : nombre d'exemples non spécifié (None), chaque exemple produit un vecteur de 64.
|
||||||
|
|
||||||
|
Param # = nombre de poids (W) + biais (b) à apprendre.
|
||||||
|
|
||||||
|
Par exemple : dense_1 a 64 entrées et 32 sorties → (64 * 32) + 32 = 2080
|
||||||
|
|
||||||
|
🧮 Total :
|
||||||
|
Paramètres totaux : 7 301 (dont certains sont utilisés pour l’optimiseur)
|
||||||
|
|
||||||
|
Trainables : 2 433 paramètres que le modèle ajuste lors de l’entraînement
|
||||||
|
|
||||||
|
Non-trainables : aucun ici (souvent présents avec des couches gelées ou embeddings fixes)
|
||||||
|
|
||||||
|
|
||||||
|
### Netron
|
||||||
|
|
||||||
|
/home/jerome/.local/bin/netron -p 5000 --host 127.0.0.1 /home/jerome/Perso/freqtradeDocker/user_data/reports/model.h5
|
||||||
|
Serving '/home/jerome/Perso/freqtradeDocker/user_data/reports/model.h5' at http://127.0.0.1:5000
|
||||||
|
|
||||||
|
|
||||||
@@ -15,3 +15,5 @@ keras
|
|||||||
scikit-learn
|
scikit-learn
|
||||||
pydot
|
pydot
|
||||||
graphviz
|
graphviz
|
||||||
|
ann_visualizer
|
||||||
|
netron
|
||||||
95
src/app.py
95
src/app.py
@@ -15,6 +15,10 @@ from tensorflow.keras.models import Sequential
|
|||||||
from tensorflow.keras.layers import Dense
|
from tensorflow.keras.layers import Dense
|
||||||
from tensorflow.keras.utils import plot_model
|
from tensorflow.keras.utils import plot_model
|
||||||
|
|
||||||
|
from keras.models import Sequential
|
||||||
|
from keras.layers import Dense
|
||||||
|
from ann_visualizer.visualize import ann_viz
|
||||||
|
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
FREQTRADE_USERDATA_DIR = '/mnt/external'
|
FREQTRADE_USERDATA_DIR = '/mnt/external'
|
||||||
|
|
||||||
@@ -128,43 +132,6 @@ def read_feather(filename):
|
|||||||
# dataframe['min200'] = talib.MIN(dataframe['close'], timeperiod=200)
|
# dataframe['min200'] = talib.MIN(dataframe['close'], timeperiod=200)
|
||||||
# dataframe['max200'] = talib.MAX(dataframe['close'], timeperiod=200)
|
# dataframe['max200'] = talib.MAX(dataframe['close'], timeperiod=200)
|
||||||
|
|
||||||
# Choisir les colonnes techniques comme variables d'entrée (X)
|
|
||||||
feature_cols = ['rsi', 'sma20', 'sma5_1h', 'volume']
|
|
||||||
df = dataframe
|
|
||||||
# Variable cible
|
|
||||||
df['target'] = df['futur_price_1h']
|
|
||||||
|
|
||||||
# Supprimer les lignes avec des NaN
|
|
||||||
df.dropna(subset=feature_cols + ['target'], inplace=True)
|
|
||||||
|
|
||||||
X = df[feature_cols].values
|
|
||||||
y = df['target'].values
|
|
||||||
|
|
||||||
# Normalisation
|
|
||||||
scaler = StandardScaler()
|
|
||||||
X = scaler.fit_transform(X)
|
|
||||||
|
|
||||||
# Split
|
|
||||||
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)
|
|
||||||
|
|
||||||
# Modèle
|
|
||||||
model = Sequential([
|
|
||||||
Dense(64, input_dim=X.shape[1], activation='relu'),
|
|
||||||
Dense(32, activation='relu'),
|
|
||||||
Dense(1) # Prédiction continue
|
|
||||||
])
|
|
||||||
|
|
||||||
model.compile(optimizer='adam', loss='mse', metrics=['mae'])
|
|
||||||
|
|
||||||
# Entraînement
|
|
||||||
model.fit(X_train, y_train, epochs=50, batch_size=32, validation_data=(X_test, y_test))
|
|
||||||
|
|
||||||
loss, mae = model.evaluate(X_test, y_test)
|
|
||||||
print(f"Erreur moyenne absolue : {mae:.4f}")
|
|
||||||
|
|
||||||
model.summary()
|
|
||||||
|
|
||||||
plot_model(model, show_shapes=True, show_layer_names=True, to_file=FREQTRADE_USERDATA_DIR + "/reports/model.png")
|
|
||||||
return dataframe.to_json(orient="records")
|
return dataframe.to_json(orient="records")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(e)
|
print(e)
|
||||||
@@ -229,8 +196,57 @@ def get_chart_data():
|
|||||||
|
|
||||||
return df.to_json(orient="records") #jsonify(chart_data)
|
return df.to_json(orient="records") #jsonify(chart_data)
|
||||||
|
|
||||||
@app.route('/model')
|
|
||||||
def show_model():
|
@app.route('/generate_model')
|
||||||
|
def generate_model():
|
||||||
|
filename = request.args.get('filename', '')
|
||||||
|
path = os.path.join(FREQTRADE_USERDATA_DIR + "/data/binance/", filename)
|
||||||
|
print(path)
|
||||||
|
# indicators = request.args.get('indicators', '').split(',')
|
||||||
|
df = pd.read_feather(path)
|
||||||
|
|
||||||
|
# Choisir les colonnes techniques comme variables d'entrée (X)
|
||||||
|
feature_cols = ['close', 'rsi', 'sma5', 'sma10', 'sma20', 'sma5_1h', 'volume', 'sma5_1h']
|
||||||
|
|
||||||
|
# Variable cible 2 heures
|
||||||
|
df['target'] = (df['close'].shift(-24) - df['close']) / df['close']
|
||||||
|
|
||||||
|
# Supprimer les lignes avec des NaN
|
||||||
|
df.dropna(subset=feature_cols + ['target'], inplace=True)
|
||||||
|
|
||||||
|
X = df[feature_cols].values
|
||||||
|
y = df['target'].values
|
||||||
|
|
||||||
|
# Normalisation
|
||||||
|
scaler = StandardScaler()
|
||||||
|
X = scaler.fit_transform(X)
|
||||||
|
|
||||||
|
# Split
|
||||||
|
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)
|
||||||
|
|
||||||
|
# Modèle
|
||||||
|
model = Sequential([
|
||||||
|
Dense(64, input_dim=X.shape[1], activation='relu'),
|
||||||
|
Dense(32, activation='relu'),
|
||||||
|
Dense(1) # Prédiction continue
|
||||||
|
])
|
||||||
|
|
||||||
|
model.compile(optimizer='adam', loss='mse', metrics=['mae'])
|
||||||
|
|
||||||
|
# Entraînement
|
||||||
|
model.fit(X_train, y_train, epochs=100, batch_size=64, validation_data=(X_test, y_test))
|
||||||
|
|
||||||
|
loss, mae = model.evaluate(X_test, y_test)
|
||||||
|
print(f"Erreur moyenne absolue : {mae:.4f}")
|
||||||
|
|
||||||
|
model.summary()
|
||||||
|
|
||||||
|
plot_model(model, show_shapes=True, show_layer_names=True, to_file=FREQTRADE_USERDATA_DIR + "/reports/model.png")
|
||||||
|
|
||||||
|
model.save(FREQTRADE_USERDATA_DIR + "/reports/model.h5")
|
||||||
|
|
||||||
|
# ann_viz(model, title="Mon réseau", filename=FREQTRADE_USERDATA_DIR + "/reports/network.gv", view=True)
|
||||||
|
|
||||||
# Créer un exemple de modèle si non encore généré
|
# Créer un exemple de modèle si non encore généré
|
||||||
model_path = FREQTRADE_USERDATA_DIR + "/reports/model.png"
|
model_path = FREQTRADE_USERDATA_DIR + "/reports/model.png"
|
||||||
if not os.path.exists(model_path):
|
if not os.path.exists(model_path):
|
||||||
@@ -242,6 +258,7 @@ def show_model():
|
|||||||
plot_model(model, to_file=model_path, show_shapes=True, show_layer_names=True)
|
plot_model(model, to_file=model_path, show_shapes=True, show_layer_names=True)
|
||||||
return render_template('model.html', model_image=model_path)
|
return render_template('model.html', model_image=model_path)
|
||||||
|
|
||||||
|
|
||||||
# Route pour servir les fichiers statiques (optionnelle si bien configuré)
|
# Route pour servir les fichiers statiques (optionnelle si bien configuré)
|
||||||
@app.route('/static/<path:filename>')
|
@app.route('/static/<path:filename>')
|
||||||
def static_files(filename):
|
def static_files(filename):
|
||||||
|
|||||||
@@ -547,6 +547,16 @@ function initReport(data) {
|
|||||||
indicators.innerHTML = string
|
indicators.innerHTML = string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function generateModel() {
|
||||||
|
|
||||||
|
const element = document.getElementById('current_file_name');
|
||||||
|
let filename = element.value
|
||||||
|
const indicators = Array.from(selectedReportIndicators).join(',');
|
||||||
|
|
||||||
|
fetch(`/generate_model?filename=${filename}`)
|
||||||
|
.then(alert('Generation en cours'));
|
||||||
|
}
|
||||||
|
|
||||||
function generateReport() {
|
function generateReport() {
|
||||||
|
|
||||||
const element = document.getElementById('current_file_name');
|
const element = document.getElementById('current_file_name');
|
||||||
|
|||||||
@@ -52,7 +52,7 @@
|
|||||||
|
|
||||||
</dialog>
|
</dialog>
|
||||||
|
|
||||||
<a href="/model">Voir le modèle</a>
|
<button id="generateModel" style="height: 40px;" onclick="generateModel(this.value)">Modèle</button>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div id='content' class="content">
|
<div id='content' class="content">
|
||||||
|
|||||||
12
src/test/dot.py
Normal file
12
src/test/dot.py
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
from tensorflow.keras.models import Sequential
|
||||||
|
from tensorflow.keras.layers import Dense
|
||||||
|
from tensorflow.keras.utils import plot_model
|
||||||
|
|
||||||
|
# Créer un modèle simple
|
||||||
|
model = Sequential()
|
||||||
|
model.add(Dense(64, input_dim=5, activation='relu'))
|
||||||
|
model.add(Dense(32, activation='relu'))
|
||||||
|
model.add(Dense(1, activation='linear'))
|
||||||
|
|
||||||
|
# Générer l'image du modèle
|
||||||
|
plot_model(model, to_file='/mnt/external/reports/model.png', show_shapes=True, show_layer_names=True)
|
||||||
11
src/test/kera.py
Normal file
11
src/test/kera.py
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import pydot
|
||||||
|
from keras.utils import plot_model
|
||||||
|
from keras.models import Sequential
|
||||||
|
from keras.layers import Dense
|
||||||
|
|
||||||
|
model = Sequential([
|
||||||
|
Dense(4, input_shape=(3,), activation='relu'),
|
||||||
|
Dense(2, activation='softmax')
|
||||||
|
])
|
||||||
|
|
||||||
|
plot_model(model, to_file='model_test.png', show_shapes=True)
|
||||||
Reference in New Issue
Block a user