unify model names

This commit is contained in:
Dobromir Popov
2025-09-09 01:10:35 +03:00
parent 0e886527c8
commit 317c703ea0
5 changed files with 229 additions and 104 deletions

View File

@@ -6,8 +6,6 @@ Much larger and more sophisticated architecture for better learning
import os import os
import logging import logging
import numpy as np
import matplotlib.pyplot as plt
from datetime import datetime from datetime import datetime
import math import math
@@ -15,10 +13,30 @@ import torch
import torch.nn as nn import torch.nn as nn
import torch.optim as optim import torch.optim as optim
from torch.utils.data import DataLoader, TensorDataset 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 import torch.nn.functional as F
from typing import Dict, Any, Optional, Tuple 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 # Import checkpoint management
from NN.training.model_manager import save_checkpoint, load_best_checkpoint from NN.training.model_manager import save_checkpoint, load_best_checkpoint
from NN.training.model_manager import create_model_manager from NN.training.model_manager import create_model_manager
@@ -423,38 +441,46 @@ class EnhancedCNNModel(nn.Module):
'features': self._memory_barrier(processed_features) '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 Make predictions on feature matrix
Args: Args:
feature_matrix: numpy array of shape [sequence_length, features] feature_matrix: tensor or numpy array of shape [sequence_length, features]
Returns: Returns:
Dictionary with prediction results Dictionary with prediction results
""" """
self.eval() self.eval()
with torch.no_grad(): with torch.no_grad():
# Convert to tensor and add batch dimension # 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 x = torch.FloatTensor(feature_matrix).unsqueeze(0) # Add batch dim
else: elif isinstance(feature_matrix, torch.Tensor):
x = feature_matrix.unsqueeze(0) x = feature_matrix.unsqueeze(0)
else:
x = torch.FloatTensor(feature_matrix).unsqueeze(0)
# Move to device # Move to device
device = next(self.parameters()).device device = next(self.parameters()).device
x = x.to(device) x = x.to(device)
# Forward pass # Forward pass
outputs = self.forward(x) outputs = self.forward(x)
# Extract results with proper shape handling # Extract results with proper shape handling
probs = outputs['probabilities'].cpu().numpy()[0] if HAS_NUMPY:
confidence_tensor = outputs['confidence'].cpu().numpy() probs = outputs['probabilities'].cpu().numpy()[0]
regime = outputs['regime'].cpu().numpy()[0] confidence_tensor = outputs['confidence'].cpu().numpy()
volatility = outputs['volatility'].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 # Handle confidence shape properly
if isinstance(confidence_tensor, np.ndarray): if HAS_NUMPY and isinstance(confidence_tensor, np.ndarray):
if confidence_tensor.ndim == 0: if confidence_tensor.ndim == 0:
confidence = float(confidence_tensor.item()) confidence = float(confidence_tensor.item())
elif confidence_tensor.size == 1: elif confidence_tensor.size == 1:
@@ -465,7 +491,7 @@ class EnhancedCNNModel(nn.Module):
confidence = float(confidence_tensor) confidence = float(confidence_tensor)
# Handle volatility shape properly # Handle volatility shape properly
if isinstance(volatility, np.ndarray): if HAS_NUMPY and isinstance(volatility, np.ndarray):
if volatility.ndim == 0: if volatility.ndim == 0:
volatility = float(volatility.item()) volatility = float(volatility.item())
elif volatility.size == 1: elif volatility.size == 1:
@@ -474,20 +500,29 @@ class EnhancedCNNModel(nn.Module):
volatility = float(volatility[0] if len(volatility) > 0 else 0.0) volatility = float(volatility[0] if len(volatility) > 0 else 0.0)
else: else:
volatility = float(volatility) volatility = float(volatility)
# Determine action (0=BUY, 1=SELL for 2-action system) # 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]) 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 { return {
'action': action, 'action': action,
'action_name': 'BUY' if action == 0 else 'SELL', 'action_name': 'BUY' if action == 0 else 'SELL',
'confidence': float(confidence), 'confidence': float(confidence),
'action_confidence': action_confidence, 'action_confidence': action_confidence,
'probabilities': probs.tolist(), 'probabilities': probs if isinstance(probs, list) else probs.tolist(),
'regime_probabilities': regime.tolist(), 'regime_probabilities': regime if isinstance(regime, list) else regime.tolist(),
'volatility_prediction': float(volatility), 'volatility_prediction': float(volatility),
'raw_logits': outputs['logits'].cpu().numpy()[0].tolist() 'raw_logits': raw_logits
} }
def get_memory_usage(self) -> Dict[str, Any]: def get_memory_usage(self) -> Dict[str, Any]:

View File

@@ -15,11 +15,19 @@ Architecture:
import torch import torch
import torch.nn as nn import torch.nn as nn
import torch.nn.functional as F import torch.nn.functional as F
import numpy as np
import logging import logging
from typing import Dict, List, Optional, Tuple, Any from typing import Dict, List, Optional, Tuple, Any
from abc import ABC, abstractmethod 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 from .model_interfaces import ModelInterface
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@@ -164,45 +172,54 @@ class MassiveRLNetwork(nn.Module):
'features': x # Hidden features for analysis '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 High-level prediction method for COB features
Args: Args:
cob_features: COB features as numpy array [input_size] cob_features: COB features as tensor or numpy array [input_size]
Returns: Returns:
Dict containing prediction results Dict containing prediction results
""" """
self.eval() self.eval()
with torch.no_grad(): with torch.no_grad():
# Convert to tensor and add batch dimension # 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() x = torch.from_numpy(cob_features).float()
else: elif isinstance(cob_features, torch.Tensor):
x = cob_features.float() 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: if x.dim() == 1:
x = x.unsqueeze(0) # Add batch dimension x = x.unsqueeze(0) # Add batch dimension
# Move to device # Move to device
device = next(self.parameters()).device device = next(self.parameters()).device
x = x.to(device) x = x.to(device)
# Forward pass # Forward pass
outputs = self.forward(x) outputs = self.forward(x)
# Process outputs # Process outputs
price_probs = F.softmax(outputs['price_logits'], dim=1) price_probs = F.softmax(outputs['price_logits'], dim=1)
predicted_direction = torch.argmax(price_probs, dim=1).item() predicted_direction = torch.argmax(price_probs, dim=1).item()
confidence = outputs['confidence'].item() confidence = outputs['confidence'].item()
value = outputs['value'].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 { return {
'predicted_direction': predicted_direction, # 0=DOWN, 1=SIDEWAYS, 2=UP 'predicted_direction': predicted_direction, # 0=DOWN, 1=SIDEWAYS, 2=UP
'confidence': confidence, 'confidence': confidence,
'value': value, 'value': value,
'probabilities': price_probs.cpu().numpy()[0], 'probabilities': probabilities,
'direction_text': ['DOWN', 'SIDEWAYS', 'UP'][predicted_direction] '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}") 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""" """Make prediction using the model"""
self.model.eval() self.model.eval()
with torch.no_grad(): with torch.no_grad():
# Convert to tensor and add batch dimension # 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() x = torch.from_numpy(cob_features).float()
else: elif isinstance(cob_features, torch.Tensor):
x = cob_features.float() 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: if x.dim() == 1:
x = x.unsqueeze(0) # Add batch dimension x = x.unsqueeze(0) # Add batch dimension
# Move to device # Move to device
x = x.to(self.device) x = x.to(self.device)
# Forward pass # Forward pass
outputs = self.model(x) outputs = self.model(x)
# Process outputs # Process outputs
price_probs = F.softmax(outputs['price_logits'], dim=1) price_probs = F.softmax(outputs['price_logits'], dim=1)
predicted_direction = torch.argmax(price_probs, dim=1).item() predicted_direction = torch.argmax(price_probs, dim=1).item()
confidence = outputs['confidence'].item() confidence = outputs['confidence'].item()
value = outputs['value'].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 { return {
'predicted_direction': predicted_direction, # 0=DOWN, 1=SIDEWAYS, 2=UP 'predicted_direction': predicted_direction, # 0=DOWN, 1=SIDEWAYS, 2=UP
'confidence': confidence, 'confidence': confidence,
'value': value, 'value': value,
'probabilities': price_probs.cpu().numpy()[0], 'probabilities': probabilities,
'direction_text': ['DOWN', 'SIDEWAYS', 'UP'][predicted_direction] 'direction_text': ['DOWN', 'SIDEWAYS', 'UP'][predicted_direction]
} }

View File

@@ -532,22 +532,18 @@ class ModelManager:
if not self.legacy_checkpoints_dir.exists(): if not self.legacy_checkpoints_dir.exists():
return None return None
# Define search patterns for different model types # Use unified model naming throughout the project
# Handle both orchestrator naming and direct model naming # All model references use consistent short names: dqn, cnn, cob_rl, transformer, decision
model_patterns = { # This eliminates complex mapping and ensures consistency across the entire codebase
'dqn_agent': ['dqn_agent', 'dqn', 'agent'], patterns = [model_name]
'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']
}
# Get patterns for this model name or use generic patterns # Add minimal backward compatibility patterns
patterns = model_patterns.get(model_name, [model_name]) 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 # Search in legacy saved directory first
legacy_saved_dir = self.legacy_checkpoints_dir / "saved" legacy_saved_dir = self.legacy_checkpoints_dir / "saved"
@@ -558,7 +554,7 @@ class ModelManager:
return file_path return file_path
# Search in model-specific directories # 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 model_dir = self.legacy_checkpoints_dir / model_type
if model_dir.exists(): if model_dir.exists():
saved_dir = model_dir / "saved" saved_dir = model_dir / "saved"

View File

@@ -15,19 +15,41 @@ import asyncio
import logging import logging
import time import time
import threading import threading
import numpy as np
import pandas as pd
from datetime import datetime, timedelta from datetime import datetime, timedelta
from typing import Dict, List, Optional, Any, Tuple, Union from typing import Dict, List, Optional, Any, Tuple, Union
from dataclasses import dataclass, field from dataclasses import dataclass, field
from collections import deque from collections import deque
import json 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 os
import shutil import shutil
import torch # Try to import PyTorch
import torch.nn as nn try:
import torch.optim as optim 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 .config import get_config
from .data_provider import DataProvider from .data_provider import DataProvider
@@ -227,7 +249,7 @@ class TradingOrchestrator:
self.rl_agent.load_best_checkpoint() # This loads the state into the model self.rl_agent.load_best_checkpoint() # This loads the state into the model
# Check if we have checkpoints available # Check if we have checkpoints available
from NN.training.model_manager import load_best_checkpoint from NN.training.model_manager import load_best_checkpoint
result = load_best_checkpoint("dqn_agent") result = load_best_checkpoint("dqn")
if result: if result:
file_path, metadata = result file_path, metadata = result
self.model_states['dqn']['initial_loss'] = getattr(metadata, 'initial_loss', None) self.model_states['dqn']['initial_loss'] = getattr(metadata, 'initial_loss', None)
@@ -267,7 +289,7 @@ class TradingOrchestrator:
checkpoint_loaded = False checkpoint_loaded = False
try: try:
from NN.training.model_manager import load_best_checkpoint from NN.training.model_manager import load_best_checkpoint
result = load_best_checkpoint("enhanced_cnn") result = load_best_checkpoint("cnn")
if result: if result:
file_path, metadata = result file_path, metadata = result
self.model_states['cnn']['initial_loss'] = 0.412 self.model_states['cnn']['initial_loss'] = 0.412
@@ -347,57 +369,96 @@ class TradingOrchestrator:
self.extrema_trainer = None self.extrema_trainer = None
# Initialize COB RL Model - UNIFIED with ModelManager # Initialize COB RL Model - UNIFIED with ModelManager
cob_rl_available = False
try: try:
from NN.models.cob_rl_model import COBRLModelInterface 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 if cob_rl_available:
self.cob_rl_agent = COBRLModelInterface( try:
model_checkpoint_dir="@checkpoints/cob_rl", # Initialize COB RL model using unified approach
device='cuda' if torch.cuda.is_available() else 'cpu' 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'] = { self.model_states['cob_rl'] = {
'initial_loss': None, 'initial_loss': None,
'current_loss': None, 'current_loss': None,
'best_loss': None, 'best_loss': None,
'checkpoint_loaded': False 'checkpoint_loaded': False,
'checkpoint_filename': 'dependencies missing'
} }
# Load best checkpoint using unified ModelManager # Try to load checkpoint metadata even without the model
checkpoint_loaded = False
try: try:
from NN.training.model_manager import load_best_checkpoint from NN.training.model_manager import load_best_checkpoint
result = load_best_checkpoint("cob_rl_agent") result = load_best_checkpoint("cob_rl")
if result: if result:
file_path, metadata = 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_loaded'] = True
self.model_states['cob_rl']['checkpoint_filename'] = metadata.checkpoint_id self.model_states['cob_rl']['checkpoint_filename'] = getattr(metadata, 'checkpoint_id', 'found')
checkpoint_loaded = True logger.info(f"COB RL checkpoint metadata loaded (model unavailable): {getattr(metadata, 'checkpoint_id', 'unknown')}")
loss_str = f"{metadata.loss:.4f}" if metadata.loss is not None else "N/A" else:
logger.info(f"COB RL checkpoint loaded: {metadata.checkpoint_id} (loss={loss_str})") logger.info("No COB RL checkpoint found")
except Exception as e: 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 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 # Initialize TRANSFORMER Model
try: try:

View File

@@ -37,16 +37,23 @@ import traceback
import gc import gc
import time import time
import psutil import psutil
import torch
from pathlib import Path from pathlib import Path
# Try to import torch
try:
import torch
HAS_TORCH = True
except ImportError:
torch = None
HAS_TORCH = False
# Setup logging # Setup logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s') logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
def clear_gpu_memory(): def clear_gpu_memory():
"""Clear GPU memory cache""" """Clear GPU memory cache"""
if torch.cuda.is_available(): if HAS_TORCH and torch.cuda.is_available():
torch.cuda.empty_cache() torch.cuda.empty_cache()
torch.cuda.synchronize() torch.cuda.synchronize()