This commit is contained in:
Executable
+109
@@ -0,0 +1,109 @@
|
||||
|
||||
import os
|
||||
import sys
|
||||
import torch
|
||||
import torch.nn.functional as F
|
||||
import pandas as pd
|
||||
import numpy as np
|
||||
|
||||
# Path alignment
|
||||
sys.path.append(os.getcwd())
|
||||
sys.path.append(os.path.join(os.getcwd(), 'ai-engine'))
|
||||
|
||||
from pipeline.tiered_loader import TieredDataLoader
|
||||
from pipeline.sequence_builder import SequenceBuilder
|
||||
from models.hybrid_v11 import HybridDeepModel
|
||||
from features.odds_history import OddsHistoryEngine
|
||||
from features.synthetic_xg import SyntheticXGModel
|
||||
|
||||
DEVICE = 'cpu'
|
||||
MODEL_PATH = 'ai-engine/models/v11_hybrid_model.pth'
|
||||
TARGET_ID = 'en78ih6ec7exnpxcku3xc3das'
|
||||
|
||||
def audit():
|
||||
print(f"🕵️ Auditing Match: {TARGET_ID}")
|
||||
|
||||
# 1. Pipeline Data
|
||||
builder = SequenceBuilder()
|
||||
X, y, meta = builder.build_sequences()
|
||||
|
||||
# Check if target is in dataset
|
||||
idx_list = meta.index[meta['match_id'] == TARGET_ID].tolist()
|
||||
if not idx_list:
|
||||
print("❌ Match not found in generated sequences. Is it too old or too new?")
|
||||
return
|
||||
|
||||
idx = idx_list[0]
|
||||
row_meta = meta.iloc[idx]
|
||||
|
||||
# 2. Features
|
||||
loader = TieredDataLoader()
|
||||
odds_df = loader.load_gold_data([TARGET_ID])
|
||||
eng = OddsHistoryEngine()
|
||||
xg_model = SyntheticXGModel()
|
||||
|
||||
# Team Mapping
|
||||
unique_teams = meta['team_id'].unique()
|
||||
team_map = {tid: i for i, tid in enumerate(unique_teams)}
|
||||
|
||||
# 3. Predict exactly like Backtest
|
||||
state = torch.load(MODEL_PATH, map_location=DEVICE)
|
||||
emb_key = 'entity_emb.weight' if 'entity_emb.weight' in state else 'team_embedding.weight'
|
||||
saved_vocab_size = state[emb_key].shape[0]
|
||||
|
||||
model = HybridDeepModel(num_teams=saved_vocab_size)
|
||||
new_state = {k.replace('team_embedding', 'entity_emb'): v for k, v in state.items()}
|
||||
model.load_state_dict(new_state, strict=False)
|
||||
model.eval()
|
||||
|
||||
# Data components
|
||||
team_idx = team_map.get(row_meta['team_id'], 0)
|
||||
entities = torch.LongTensor([team_idx, 0]).unsqueeze(0)
|
||||
seq = torch.FloatTensor(X[idx]).unsqueeze(0)
|
||||
|
||||
# Context (Odds + xG)
|
||||
odds_lookup = {}
|
||||
for _, r in odds_df.iterrows():
|
||||
mid = r['match_id']
|
||||
if mid not in odds_lookup: odds_lookup[mid] = {}
|
||||
if r['category'] == 'Maç Sonucu': odds_lookup[mid][r['selection']] = r['odd_value']
|
||||
elif r['category'] == '2,5 Alt/Üst':
|
||||
if 'Üst' in r['selection']: odds_lookup[mid]['Over'] = r['odd_value']
|
||||
else: odds_lookup[mid]['Under'] = r['odd_value']
|
||||
|
||||
odds = odds_lookup.get(TARGET_ID, {'1': 1.0, 'X': 1.0, '2': 1.0, 'Over': 1.0, 'Under': 1.0})
|
||||
syn_xg = 1.35 # Placeholder in trainer for xG component if used
|
||||
hist_win_rate = eng.get_feature(row_meta['team_id'], float(odds.get('1', 1.0)))
|
||||
|
||||
ctx = torch.FloatTensor([
|
||||
float(odds.get('1', 1.0)), float(odds.get('X', 1.0)), float(odds.get('2', 1.0)),
|
||||
float(odds.get('Over', 1.0)), float(odds.get('Under', 1.0)),
|
||||
syn_xg, syn_xg,
|
||||
hist_win_rate
|
||||
]).unsqueeze(0)
|
||||
|
||||
with torch.no_grad():
|
||||
logits_res, pred_goals, logits_btts, logits_ht_ft = model(entities, seq, ctx)
|
||||
probs = F.softmax(logits_res, dim=1).numpy()[0]
|
||||
prob_btts = torch.sigmoid(logits_btts).item()
|
||||
probs_ht = F.softmax(logits_ht_ft, dim=1).numpy()[0]
|
||||
|
||||
print("\n📊 INTERNAL PIPELINE PREDICTION:")
|
||||
print(f"Target Team: {row_meta['team_id']}")
|
||||
print(f"1X2 Probs: Home:{probs[0]:.4f} Draw:{probs[1]:.4f} Away:{probs[2]:.4f}")
|
||||
print(f"BTTS Prob: {prob_btts:.4f}")
|
||||
|
||||
ht_map = ["1/1", "1/X", "1/2", "X/1", "X/X", "X/2", "2/1", "2/X", "2/2"]
|
||||
top3_ht = np.argsort(probs_ht)[-3:][::-1]
|
||||
print("Top 3 HT/FT:")
|
||||
for idx_ht in top3_ht:
|
||||
print(f" {ht_map[idx_ht]}: {probs_ht[idx_ht]:.4f}")
|
||||
|
||||
actual_res = y[idx][0]
|
||||
actual_ht_idx = int(y[idx][3])
|
||||
print(f"\n✅ ACTUAL REALITY:")
|
||||
print(f"Result (Y): {actual_res} (0.0=Away)")
|
||||
print(f"HT/FT Class: {actual_ht_idx} ({ht_map[actual_ht_idx]})")
|
||||
|
||||
if __name__ == "__main__":
|
||||
audit()
|
||||
Reference in New Issue
Block a user