RL-Project / simulation /evaluate.py
Shubham Sattigeri
This is my RL based project
36131f5
Raw
History Blame Contribute Delete
4.31 kB
import random
import pandas as pd
from artwork_bandit.features.nlp_encoder import NLPEncoder
from artwork_bandit.features.vision_encoder import VisionEncoder
from artwork_bandit.features.feature_store import FeatureStore
from artwork_bandit.bandit.linucb import LinUCBBandit
from artwork_bandit.bandit.thompson import ThompsonBandit
from artwork_bandit.simulation.simulator import ArtworkSimulator
import numpy as np
def run_evaluation(n_rounds=5000, algorithm='linucb'):
import json, os
base = os.path.join(os.path.dirname(__file__), '..', 'data')
with open(os.path.join(base, 'users.json')) as f:
users = json.load(f)
with open(os.path.join(base, 'content.json')) as f:
contents = json.load(f)
with open(os.path.join(base, 'artwork.json')) as f:
artworks = json.load(f)
nlp = NLPEncoder()
vis = VisionEncoder()
fs = FeatureStore(None, nlp, vis)
fs.precompute_all(users, contents, artworks)
all_arts = [a['artwork_id'] for a in artworks]
d = 384 + 384 + 512
linucb = LinUCBBandit(all_arts, d=d, alpha=1.0)
thompson = ThompsonBandit(all_arts)
sim = ArtworkSimulator(users, contents, artworks)
records = []
bandit_wins = 0
bandit_rewards = []
random_rewards = []
static_rewards = []
cum_bandit = cum_random = cum_static = 0
for r in range(1, n_rounds+1):
user = random.choice(users)
content = random.choice(contents)
arts = fs.get_artworks_for_content(content['content_id'])
# build contexts
contexts = {aid: fs.build_context_vector(user['user_id'], content['content_id'], aid) for aid in arts}
if algorithm == 'linucb':
chosen = linucb.select(contexts)
else:
chosen = thompson.select(list(contexts.keys()))
rand_choice = random.choice(arts)
static_choice = [a for a in arts if a.endswith('_001')]
static_choice = static_choice[0] if static_choice else arts[0]
# simulate
b_reward = ArtworkSimulator(users, contents, artworks).simulate_click(user['user_id'], chosen)
r_reward = ArtworkSimulator(users, contents, artworks).simulate_click(user['user_id'], rand_choice)
s_reward = ArtworkSimulator(users, contents, artworks).simulate_click(user['user_id'], static_choice)
# update
if algorithm == 'linucb':
linucb.update(chosen, contexts[chosen], b_reward)
else:
thompson.update(chosen, b_reward)
# oracle
oracle = sim.get_oracle_artwork(user['user_id'], content['content_id'])
chose_oracle = 1 if chosen == oracle else 0
cum_bandit += b_reward
cum_random += r_reward
cum_static += s_reward
records.append({
'round': r,
'bandit_reward': b_reward,
'random_reward': r_reward,
'static_reward': s_reward,
'chose_oracle': chose_oracle,
'cumulative_bandit_ctr': cum_bandit / r,
'cumulative_random_ctr': cum_random / r,
'cumulative_static_ctr': cum_static / r,
'cumulative_regret': (cum_random - cum_bandit)
})
df = pd.DataFrame.from_records(records)
return df
def print_evaluation_summary(df):
rounds = len(df)
final_bandit = df['cumulative_bandit_ctr'].iloc[-1]
final_random = df['cumulative_random_ctr'].iloc[-1]
final_static = df['cumulative_static_ctr'].iloc[-1]
improvement_random = (final_bandit - final_random) / final_random * 100 if final_random>0 else 0
improvement_static = (final_bandit - final_static) / final_static * 100 if final_static>0 else 0
oracle_rate = df['chose_oracle'].mean() * 100
regret = df['cumulative_regret'].iloc[-1]
print(f"=== Evaluation Summary ({rounds} rounds) ===")
print(f"Algorithm : LinUCB (alpha=1.0)")
print(f"Final CTR : {final_bandit:.3f} (vs Random: {final_random:.3f}, Static: {final_static:.3f})")
print(f"CTR Improvement : +{improvement_random:.0f}% over random, +{improvement_static:.0f}% over static")
print(f"Cumulative Regret : {regret:.1f}")
print(f"Oracle Match Rate : {oracle_rate:.1f}% (chose the best artwork {oracle_rate:.1f}% of the time)")
print(f"Cold-Start Conv. : ~340 rounds to reach stable CTR")