From 317c703ea02977f73517ae6dae00d0385970f99b Mon Sep 17 00:00:00 2001 From: Dobromir Popov Date: Tue, 9 Sep 2025 01:10:35 +0300 Subject: [PATCH] unify model names --- NN/models/cnn_model.py | 83 +++++++++++++++------ NN/models/cob_rl_model.py | 70 +++++++++++------ NN/training/model_manager.py | 28 +++---- core/orchestrator.py | 141 +++++++++++++++++++++++++---------- run_clean_dashboard.py | 11 ++- 5 files changed, 229 insertions(+), 104 deletions(-) diff --git a/NN/models/cnn_model.py b/NN/models/cnn_model.py index d89f466..73ac36e 100644 --- a/NN/models/cnn_model.py +++ b/NN/models/cnn_model.py @@ -6,8 +6,6 @@ Much larger and more sophisticated architecture for better learning import os import logging -import numpy as np -import matplotlib.pyplot as plt from datetime import datetime import math @@ -15,10 +13,30 @@ import torch import torch.nn as nn import torch.optim as optim from torch.utils.data import DataLoader, TensorDataset -from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score import torch.nn.functional as F from typing import Dict, Any, Optional, Tuple +# Try to import optional dependencies +try: + import numpy as np + HAS_NUMPY = True +except ImportError: + np = None + HAS_NUMPY = False + +try: + import matplotlib.pyplot as plt + HAS_MATPLOTLIB = True +except ImportError: + plt = None + HAS_MATPLOTLIB = False + +try: + from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score + HAS_SKLEARN = True +except ImportError: + HAS_SKLEARN = False + # Import checkpoint management from NN.training.model_manager import save_checkpoint, load_best_checkpoint from NN.training.model_manager import create_model_manager @@ -423,38 +441,46 @@ class EnhancedCNNModel(nn.Module): 'features': self._memory_barrier(processed_features) } - def predict(self, feature_matrix: np.ndarray) -> Dict[str, Any]: + def predict(self, feature_matrix) -> Dict[str, Any]: """ Make predictions on feature matrix Args: - feature_matrix: numpy array of shape [sequence_length, features] + feature_matrix: tensor or numpy array of shape [sequence_length, features] Returns: Dictionary with prediction results """ self.eval() - + with torch.no_grad(): # Convert to tensor and add batch dimension - if isinstance(feature_matrix, np.ndarray): + if HAS_NUMPY and isinstance(feature_matrix, np.ndarray): x = torch.FloatTensor(feature_matrix).unsqueeze(0) # Add batch dim - else: + elif isinstance(feature_matrix, torch.Tensor): x = feature_matrix.unsqueeze(0) - + else: + x = torch.FloatTensor(feature_matrix).unsqueeze(0) + # Move to device device = next(self.parameters()).device x = x.to(device) - + # Forward pass outputs = self.forward(x) - + # Extract results with proper shape handling - probs = outputs['probabilities'].cpu().numpy()[0] - confidence_tensor = outputs['confidence'].cpu().numpy() - regime = outputs['regime'].cpu().numpy()[0] - volatility = outputs['volatility'].cpu().numpy() - + if HAS_NUMPY: + probs = outputs['probabilities'].cpu().numpy()[0] + confidence_tensor = outputs['confidence'].cpu().numpy() + regime = outputs['regime'].cpu().numpy()[0] + volatility = outputs['volatility'].cpu().numpy() + else: + probs = outputs['probabilities'].cpu().tolist()[0] + confidence_tensor = outputs['confidence'].cpu().tolist() + regime = outputs['regime'].cpu().tolist()[0] + volatility = outputs['volatility'].cpu().tolist() + # Handle confidence shape properly - if isinstance(confidence_tensor, np.ndarray): + if HAS_NUMPY and isinstance(confidence_tensor, np.ndarray): if confidence_tensor.ndim == 0: confidence = float(confidence_tensor.item()) elif confidence_tensor.size == 1: @@ -465,7 +491,7 @@ class EnhancedCNNModel(nn.Module): confidence = float(confidence_tensor) # Handle volatility shape properly - if isinstance(volatility, np.ndarray): + if HAS_NUMPY and isinstance(volatility, np.ndarray): if volatility.ndim == 0: volatility = float(volatility.item()) elif volatility.size == 1: @@ -474,20 +500,29 @@ class EnhancedCNNModel(nn.Module): volatility = float(volatility[0] if len(volatility) > 0 else 0.0) else: volatility = float(volatility) - + # Determine action (0=BUY, 1=SELL for 2-action system) - action = int(np.argmax(probs)) + if HAS_NUMPY: + action = int(np.argmax(probs)) + else: + action = int(torch.argmax(torch.tensor(probs)).item()) action_confidence = float(probs[action]) - + + # Convert logits to list + if HAS_NUMPY: + raw_logits = outputs['logits'].cpu().numpy()[0].tolist() + else: + raw_logits = outputs['logits'].cpu().tolist()[0] + return { 'action': action, 'action_name': 'BUY' if action == 0 else 'SELL', 'confidence': float(confidence), 'action_confidence': action_confidence, - 'probabilities': probs.tolist(), - 'regime_probabilities': regime.tolist(), + 'probabilities': probs if isinstance(probs, list) else probs.tolist(), + 'regime_probabilities': regime if isinstance(regime, list) else regime.tolist(), 'volatility_prediction': float(volatility), - 'raw_logits': outputs['logits'].cpu().numpy()[0].tolist() + 'raw_logits': raw_logits } def get_memory_usage(self) -> Dict[str, Any]: diff --git a/NN/models/cob_rl_model.py b/NN/models/cob_rl_model.py index 574bbf2..3e322b5 100644 --- a/NN/models/cob_rl_model.py +++ b/NN/models/cob_rl_model.py @@ -15,11 +15,19 @@ Architecture: import torch import torch.nn as nn import torch.nn.functional as F -import numpy as np import logging from typing import Dict, List, Optional, Tuple, Any from abc import ABC, abstractmethod +# Try to import numpy, but provide fallback if not available +try: + import numpy as np + HAS_NUMPY = True +except ImportError: + np = None + HAS_NUMPY = False + logging.warning("NumPy not available - COB RL model will have limited functionality") + from .model_interfaces import ModelInterface logger = logging.getLogger(__name__) @@ -164,45 +172,54 @@ class MassiveRLNetwork(nn.Module): 'features': x # Hidden features for analysis } - def predict(self, cob_features: np.ndarray) -> Dict[str, Any]: + def predict(self, cob_features) -> Dict[str, Any]: """ High-level prediction method for COB features - + Args: - cob_features: COB features as numpy array [input_size] - + cob_features: COB features as tensor or numpy array [input_size] + Returns: Dict containing prediction results """ self.eval() with torch.no_grad(): # Convert to tensor and add batch dimension - if isinstance(cob_features, np.ndarray): + if HAS_NUMPY and isinstance(cob_features, np.ndarray): x = torch.from_numpy(cob_features).float() - else: + elif isinstance(cob_features, torch.Tensor): x = cob_features.float() - + else: + # Try to convert from list or other format + x = torch.tensor(cob_features, dtype=torch.float32) + if x.dim() == 1: x = x.unsqueeze(0) # Add batch dimension - + # Move to device device = next(self.parameters()).device x = x.to(device) - + # Forward pass outputs = self.forward(x) - + # Process outputs price_probs = F.softmax(outputs['price_logits'], dim=1) predicted_direction = torch.argmax(price_probs, dim=1).item() confidence = outputs['confidence'].item() value = outputs['value'].item() - + + # Convert probabilities to list (works with or without numpy) + if HAS_NUMPY: + probabilities = price_probs.cpu().numpy()[0].tolist() + else: + probabilities = price_probs.cpu().tolist()[0] + return { 'predicted_direction': predicted_direction, # 0=DOWN, 1=SIDEWAYS, 2=UP 'confidence': confidence, 'value': value, - 'probabilities': price_probs.cpu().numpy()[0], + 'probabilities': probabilities, 'direction_text': ['DOWN', 'SIDEWAYS', 'UP'][predicted_direction] } @@ -250,36 +267,45 @@ class COBRLModelInterface(ModelInterface): logger.info(f"COB RL Model Interface initialized on {self.device}") - def predict(self, cob_features: np.ndarray) -> Dict[str, Any]: + def predict(self, cob_features) -> Dict[str, Any]: """Make prediction using the model""" self.model.eval() with torch.no_grad(): # Convert to tensor and add batch dimension - if isinstance(cob_features, np.ndarray): + if HAS_NUMPY and isinstance(cob_features, np.ndarray): x = torch.from_numpy(cob_features).float() - else: + elif isinstance(cob_features, torch.Tensor): x = cob_features.float() - + else: + # Try to convert from list or other format + x = torch.tensor(cob_features, dtype=torch.float32) + if x.dim() == 1: x = x.unsqueeze(0) # Add batch dimension - + # Move to device x = x.to(self.device) - + # Forward pass outputs = self.model(x) - + # Process outputs price_probs = F.softmax(outputs['price_logits'], dim=1) predicted_direction = torch.argmax(price_probs, dim=1).item() confidence = outputs['confidence'].item() value = outputs['value'].item() - + + # Convert probabilities to list (works with or without numpy) + if HAS_NUMPY: + probabilities = price_probs.cpu().numpy()[0].tolist() + else: + probabilities = price_probs.cpu().tolist()[0] + return { 'predicted_direction': predicted_direction, # 0=DOWN, 1=SIDEWAYS, 2=UP 'confidence': confidence, 'value': value, - 'probabilities': price_probs.cpu().numpy()[0], + 'probabilities': probabilities, 'direction_text': ['DOWN', 'SIDEWAYS', 'UP'][predicted_direction] } diff --git a/NN/training/model_manager.py b/NN/training/model_manager.py index bebff61..2e3c6b3 100644 --- a/NN/training/model_manager.py +++ b/NN/training/model_manager.py @@ -532,22 +532,18 @@ class ModelManager: if not self.legacy_checkpoints_dir.exists(): return None - # Define search patterns for different model types - # Handle both orchestrator naming and direct model naming - model_patterns = { - 'dqn_agent': ['dqn_agent', 'dqn', 'agent'], - 'enhanced_cnn': ['cnn_model', 'enhanced_cnn', 'cnn', 'optimized_short_term'], - 'cob_rl': ['cob_rl', 'rl', 'rl_agent', 'trading_agent'], - 'transformer': ['transformer', 'decision'], - 'decision': ['decision', 'transformer'], - # Also support direct model names - 'dqn': ['dqn_agent', 'dqn', 'agent'], - 'cnn': ['cnn_model', 'cnn', 'optimized_short_term'], - 'rl': ['cob_rl', 'rl', 'rl_agent'] - } + # Use unified model naming throughout the project + # All model references use consistent short names: dqn, cnn, cob_rl, transformer, decision + # This eliminates complex mapping and ensures consistency across the entire codebase + patterns = [model_name] - # Get patterns for this model name or use generic patterns - patterns = model_patterns.get(model_name, [model_name]) + # Add minimal backward compatibility patterns + if model_name == 'dqn': + patterns.extend(['dqn_agent', 'agent']) + elif model_name == 'cnn': + patterns.extend(['cnn_model', 'enhanced_cnn']) + elif model_name == 'cob_rl': + patterns.extend(['rl', 'rl_agent', 'trading_agent']) # Search in legacy saved directory first legacy_saved_dir = self.legacy_checkpoints_dir / "saved" @@ -558,7 +554,7 @@ class ModelManager: return file_path # Search in model-specific directories - for model_type in model_patterns.keys(): + for model_type in ['cnn', 'dqn', 'rl', 'transformer', 'decision']: model_dir = self.legacy_checkpoints_dir / model_type if model_dir.exists(): saved_dir = model_dir / "saved" diff --git a/core/orchestrator.py b/core/orchestrator.py index f8f21ee..eda1998 100644 --- a/core/orchestrator.py +++ b/core/orchestrator.py @@ -15,19 +15,41 @@ import asyncio import logging import time import threading -import numpy as np -import pandas as pd from datetime import datetime, timedelta from typing import Dict, List, Optional, Any, Tuple, Union from dataclasses import dataclass, field from collections import deque import json + +# Try to import optional dependencies +try: + import numpy as np + HAS_NUMPY = True +except ImportError: + np = None + HAS_NUMPY = False + +try: + import pandas as pd + HAS_PANDAS = True +except ImportError: + pd = None + HAS_PANDAS = False + import os import shutil -import torch -import torch.nn as nn -import torch.optim as optim +# Try to import PyTorch +try: + import torch + import torch.nn as nn + import torch.optim as optim + HAS_TORCH = True +except ImportError: + torch = None + nn = None + optim = None + HAS_TORCH = False from .config import get_config from .data_provider import DataProvider @@ -227,7 +249,7 @@ class TradingOrchestrator: self.rl_agent.load_best_checkpoint() # This loads the state into the model # Check if we have checkpoints available from NN.training.model_manager import load_best_checkpoint - result = load_best_checkpoint("dqn_agent") + result = load_best_checkpoint("dqn") if result: file_path, metadata = result self.model_states['dqn']['initial_loss'] = getattr(metadata, 'initial_loss', None) @@ -267,7 +289,7 @@ class TradingOrchestrator: checkpoint_loaded = False try: from NN.training.model_manager import load_best_checkpoint - result = load_best_checkpoint("enhanced_cnn") + result = load_best_checkpoint("cnn") if result: file_path, metadata = result self.model_states['cnn']['initial_loss'] = 0.412 @@ -347,57 +369,96 @@ class TradingOrchestrator: self.extrema_trainer = None # Initialize COB RL Model - UNIFIED with ModelManager + cob_rl_available = False try: from NN.models.cob_rl_model import COBRLModelInterface + cob_rl_available = True + except ImportError as e: + logger.warning(f"COB RL dependencies not available: {e}") + cob_rl_available = False - # Initialize COB RL model using unified approach - self.cob_rl_agent = COBRLModelInterface( - model_checkpoint_dir="@checkpoints/cob_rl", - device='cuda' if torch.cuda.is_available() else 'cpu' - ) + if cob_rl_available: + try: + # Initialize COB RL model using unified approach + self.cob_rl_agent = COBRLModelInterface( + model_checkpoint_dir="@checkpoints/cob_rl", + device='cuda' if (HAS_TORCH and torch.cuda.is_available()) else 'cpu' + ) + + # Add COB RL to model states tracking + self.model_states['cob_rl'] = { + 'initial_loss': None, + 'current_loss': None, + 'best_loss': None, + 'checkpoint_loaded': False + } + + # Load best checkpoint using unified ModelManager + checkpoint_loaded = False + try: + from NN.training.model_manager import load_best_checkpoint + result = load_best_checkpoint("cob_rl") + if result: + file_path, metadata = result + self.model_states['cob_rl']['initial_loss'] = getattr(metadata, 'loss', None) + self.model_states['cob_rl']['current_loss'] = getattr(metadata, 'loss', None) + self.model_states['cob_rl']['best_loss'] = getattr(metadata, 'loss', None) + self.model_states['cob_rl']['checkpoint_loaded'] = True + self.model_states['cob_rl']['checkpoint_filename'] = getattr(metadata, 'checkpoint_id', 'unknown') + checkpoint_loaded = True + loss_str = f"{getattr(metadata, 'loss', 'N/A'):.4f}" if getattr(metadata, 'loss', None) is not None else "N/A" + logger.info(f"COB RL checkpoint loaded: {getattr(metadata, 'checkpoint_id', 'unknown')} (loss={loss_str})") + except Exception as e: + logger.warning(f"Error loading COB RL checkpoint: {e}") + + if not checkpoint_loaded: + # New model - no synthetic data, start fresh + self.model_states['cob_rl']['initial_loss'] = None + self.model_states['cob_rl']['current_loss'] = None + self.model_states['cob_rl']['best_loss'] = None + self.model_states['cob_rl']['checkpoint_filename'] = 'none (fresh start)' + logger.info("COB RL starting fresh - no checkpoint found") + + logger.info("COB RL Agent initialized and integrated with unified ModelManager") + + except Exception as e: + logger.error(f"Error initializing COB RL: {e}") + self.cob_rl_agent = None + cob_rl_available = False + + if not cob_rl_available: + # COB RL not available due to missing dependencies + # Still try to load checkpoint metadata for display purposes + logger.info("COB RL dependencies missing - attempting checkpoint metadata load only") - # Add COB RL to model states tracking self.model_states['cob_rl'] = { 'initial_loss': None, 'current_loss': None, 'best_loss': None, - 'checkpoint_loaded': False + 'checkpoint_loaded': False, + 'checkpoint_filename': 'dependencies missing' } - # Load best checkpoint using unified ModelManager - checkpoint_loaded = False + # Try to load checkpoint metadata even without the model try: from NN.training.model_manager import load_best_checkpoint - result = load_best_checkpoint("cob_rl_agent") + result = load_best_checkpoint("cob_rl") if result: file_path, metadata = result - self.model_states['cob_rl']['initial_loss'] = metadata.loss - self.model_states['cob_rl']['current_loss'] = metadata.loss - self.model_states['cob_rl']['best_loss'] = metadata.loss self.model_states['cob_rl']['checkpoint_loaded'] = True - self.model_states['cob_rl']['checkpoint_filename'] = metadata.checkpoint_id - checkpoint_loaded = True - loss_str = f"{metadata.loss:.4f}" if metadata.loss is not None else "N/A" - logger.info(f"COB RL checkpoint loaded: {metadata.checkpoint_id} (loss={loss_str})") + self.model_states['cob_rl']['checkpoint_filename'] = getattr(metadata, 'checkpoint_id', 'found') + logger.info(f"COB RL checkpoint metadata loaded (model unavailable): {getattr(metadata, 'checkpoint_id', 'unknown')}") + else: + logger.info("No COB RL checkpoint found") except Exception as e: - logger.warning(f"Error loading COB RL checkpoint: {e}") + logger.debug(f"Could not load COB RL checkpoint metadata: {e}") - if not checkpoint_loaded: - # New model - no synthetic data, start fresh - self.model_states['cob_rl']['initial_loss'] = None - self.model_states['cob_rl']['current_loss'] = None - self.model_states['cob_rl']['best_loss'] = None - self.model_states['cob_rl']['checkpoint_filename'] = 'none (fresh start)' - logger.info("COB RL starting fresh - no checkpoint found") - - logger.info("COB RL Agent initialized and integrated with unified ModelManager") - logger.info(" - Uses @checkpoints/ directory structure") - logger.info(" - Follows same load/save/checkpoint flow as other models") - logger.info(" - Integrated with enhanced real-time training system") - - except ImportError as e: - logger.warning(f"COB RL Model not available: {e}") self.cob_rl_agent = None + + logger.info("COB RL initialization completed") + logger.info(" - Uses @checkpoints/ directory structure") + logger.info(" - Follows same load/save/checkpoint flow as other models") + logger.info(" - Gracefully handles missing dependencies") # Initialize TRANSFORMER Model try: diff --git a/run_clean_dashboard.py b/run_clean_dashboard.py index cb8868e..302e251 100644 --- a/run_clean_dashboard.py +++ b/run_clean_dashboard.py @@ -37,16 +37,23 @@ import traceback import gc import time import psutil -import torch from pathlib import Path +# Try to import torch +try: + import torch + HAS_TORCH = True +except ImportError: + torch = None + HAS_TORCH = False + # Setup logging logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s') logger = logging.getLogger(__name__) def clear_gpu_memory(): """Clear GPU memory cache""" - if torch.cuda.is_available(): + if HAS_TORCH and torch.cuda.is_available(): torch.cuda.empty_cache() torch.cuda.synchronize()