Modèle

Ce document décrit l’architecture et l’implémentation du modèle de prédiction des prix Bitcoin utilisant des réseaux de neurones profonds.

Prérequis et Dépendances

Les bibliothèques Python suivantes sont nécessaires :

# Bibliothèques principales
import numpy as np
import pandas as pd
import tensorflow as tf
import matplotlib.pyplot as plt
import seaborn as sns

# Préprocessing et évaluation
from sklearn.preprocessing import RobustScaler
from sklearn.model_selection import TimeSeriesSplit
from sklearn.metrics import mean_absolute_error, mean_squared_error, r2_score

# Architecture du modèle
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import LSTM, GRU, Dense, Dropout, Conv1D, MaxPooling1D, Bidirectional
from tensorflow.keras.callbacks import EarlyStopping, ReduceLROnPlateau

# Optimisation et pipelines
import optuna
from sklearn.base import BaseEstimator, TransformerMixin
from sklearn.pipeline import Pipeline

Architecture du Pipeline

Transformateur de Séquences Personnalisé

Crée des séquences temporelles pour l’entraînement des modèles RNN :

class SequenceTransformer(BaseEstimator, TransformerMixin):
    def __init__(self, seq_length=60, target_idx=0):
        self.seq_length = seq_length
        self.target_idx = target_idx

    def fit(self, X, y=None):
        return self

    def transform(self, X):
        X_seq, y_seq = [], []
        for i in range(len(X) - self.seq_length):
            X_seq.append(X[i:i+self.seq_length])
            y_seq.append(X[i+self.seq_length, self.target_idx])
        return np.array(X_seq), np.array(y_seq)

Pipeline de Prétraitement

Combine le scaling et la création de séquences :

def create_pipeline(target_idx=0, seq_length=60):
    return Pipeline([
        ('scaler', RobustScaler()),
        ('sequencer', SequenceTransformer(seq_length=seq_length, target_idx=target_idx))
    ])

Architectures du Modèle

Fonction de Construction du Modèle

Implémente trois architectures différentes :

  1. CNN-LSTM : Couches convolutionnelles + LSTM

  2. BiLSTM : LSTM bidirectionnel

  3. LSTM standard

def build_advanced_model(input_shape, model_type='LSTM', units=64, n_layers=2, dropout=0.3):
    model = Sequential()

    # Couche d'entrée spécialisée
    if model_type == 'CNN-LSTM':
        model.add(Conv1D(filters=units, kernel_size=3, activation='relu',
                        padding='causal', input_shape=input_shape))
        model.add(MaxPooling1D(2))
        model.add(LSTM(units//2, return_sequences=(n_layers>1)))
    elif model_type == 'BiLSTM':
        model.add(Bidirectional(LSTM(units, return_sequences=(n_layers>1)),
                              input_shape=input_shape))
    else:
        model.add(LSTM(units, return_sequences=(n_layers>1), input_shape=input_shape))

    # Couches récurrentes intermédiaires
    for _ in range(n_layers - 1):
        model.add(LSTM(units, return_sequences=(_ < n_layers-2)))
        model.add(Dropout(dropout))

    # Couches de sortie
    model.add(Dense(64, activation='relu'))
    model.add(Dense(1))

    return model

Optimisation Hyperparamètres avec Optuna

Fonction Objective pour Optuna

Recherche les meilleurs hyperparamètres via 50 essais :

def objective(trial):
    params = {
        'units': trial.suggest_int('units', 32, 256),
        'n_layers': trial.suggest_int('n_layers', 1, 4),
        'dropout': trial.suggest_float('dropout', 0.1, 0.5),
        'model_type': trial.suggest_categorical('model_type', ['LSTM', 'BiLSTM', 'CNN-LSTM']),
        'lr': trial.suggest_float('lr', 1e-5, 1e-3, log=True)
    }

   lr = params.pop('lr')

   model = build_advanced_model(
       input_shape=(SEQ_LENGTH, X_train.shape[2]),
       **params
 )

   # Compilation du modèle avec l'optimiseur et le taux d'apprentissage
   model.compile(
       optimizer=tf.keras.optimizers.Adam(lr),
       loss=tf.keras.losses.Huber(),
       metrics=['mae']
 )

   # Callbacks adaptatifs
   callbacks = [
       EarlyStopping(patience=15, restore_best_weights=True),
       ReduceLROnPlateau(factor=0.5, patience=5)
 ]

   # Entraînement du modèle
   history = model.fit(
       X_train, y_train,
       validation_data=(X_val, y_val),
       epochs=300,
       batch_size=64,
       verbose=0,
       callbacks=callbacks
   )

   return min(history.history['val_mae'])

Workflow Principal

Étapes Clés du Processus

  1. Chargement des données:

    data = pd.read_csv('/content/drive/MyDrive/timeSerie/Final_Bitcoin_dataset.csv', parse_dates=['Date'])
    data.set_index('Date', inplace=True)
    
  2. Feature Engineering:

    data['Volatility'] = (data['High'] - data['Low']) / data['Low'] * 100
    data['MACD'] = data['Close'].ewm(span=12).mean() - data['Close'].ewm(span=26).mean()
    
  3. Prétraitement:

    pipeline = create_pipeline(target_idx=target_idx, seq_length=SEQ_LENGTH)
    X_seq, y_seq = pipeline.fit_transform(data)
    
  4. Validation Croisée Temporelle:

    tscv = TimeSeriesSplit(n_splits=5)
    train_idx, val_idx = next(tscv.split(X_seq))
    
  5. Optimisation et Entraînement Final:

    study = optuna.create_study(direction='minimize')
    study.optimize(objective, n_trials=50)
    
    # Entraînement avec les meilleurs paramètres
    history = final_model.fit(
        X_seq, y_seq,
        epochs=200,
        batch_size=128,
        validation_split=0.2,
        callbacks=[EarlyStopping(patience=20)]
    )
    
    final_model.save('bitcoin_advanced_model.h5')
    

Diagramme du Workflow

Bonnes Pratiques Implémentées

  • RobustScaler : Préprocessing robuste aux outliers

  • TimeSeriesSplit : Validation croisée temporelle

  • Callbacks adaptatifs : - EarlyStopping pour éviter le surapprentissage - ReduceLROnPlateau pour ajustement dynamique du learning rate

  • Huber Loss : Fonction de perte robuste pour la régression

  • Capitalisation : Sauvegarde du modèle final pour réutilisation