#!/usr/bin/env python3 """Demo script: DiscoRL agent evaluation on CartPole. This script loads a trained DiscoRL agent and evaluates it on CartPole. Serves as a template for adapting DiscoRL to custom environments. """ import os import sys import numpy as np import jax import jax.numpy as jnp # Set JAX to CPU-only mode os.environ['JAX_PLATFORMS'] = 'cpu' # Add repo root to path repo_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) sys.path.insert(0, os.path.join(repo_root, 'disco_rl')) from disco_rl import agent as disco_agent from disco_cartpole_env import DiscoCartPoleEnv def evaluate_agent(agent, env, num_episodes: int = 10, max_steps: int = 500): """Evaluate agent on environment. Args: agent: DiscoRL Agent env: DiscoCartPoleEnv num_episodes: number of evaluation episodes max_steps: max steps per episode Returns: (rewards_per_episode, success_rate) """ rewards_per_episode = [] successes = 0 for episode in range(num_episodes): rng = jax.random.PRNGKey(episode) rng, subkey = jax.random.split(rng) # Reset state, timestep = env.reset(rng_key=subkey) actor_state = agent.initial_actor_state(subkey) episode_reward = 0.0 for step in range(max_steps): # Agent step rng, subkey = jax.random.split(rng) actor_output, actor_state = agent.actor_step( timestep.observation, actor_state, is_eval=True, training_state=None, rng=subkey, ) actions = actor_output.actions # Env step state, timestep = env.step(state, actions) # Accumulate reward episode_reward += float(jnp.mean(timestep.reward)) # Check terminal if jnp.any(timestep.step_type == 1): # StepType.LAST break rewards_per_episode.append(episode_reward) if episode_reward > 400: # CartPole "solved" at 400+ steps successes += 1 success_rate = successes / num_episodes return rewards_per_episode, success_rate def main(): print('='*60) print('DiscoRL CartPole Evaluation Demo') print('='*60) # Create environment print('\nCreating environment...') env = DiscoCartPoleEnv(batch_size=1, max_steps=500) single_obs_spec = env.single_observation_spec() single_act_spec = env.single_action_spec() # Create agent print('Creating agent...') agent_settings = disco_agent.get_settings_disco() agent = disco_agent.Agent( single_observation_spec=single_obs_spec, single_action_spec=single_act_spec, agent_settings=agent_settings, batch_axis_name=None, ) # Initialize state print('Initializing agent state...') rng = jax.random.PRNGKey(42) rng, subkey = jax.random.split(rng) learner_state = agent.initial_learner_state(subkey) rng, subkey = jax.random.split(rng) actor_state = agent.initial_actor_state(subkey) # Try to load saved weights saved_path = os.path.join(repo_root, 'models', 'disco_cartpole', 'final_agent.npz') if os.path.exists(saved_path): print(f'\nLoading saved agent from {saved_path}...') try: saved = np.load(saved_path) # Note: You'd need to implement proper deserialization # For now, just note that weights are available print(f' Saved weights available: {list(saved.files)}') except Exception as e: print(f' Warning: Could not load weights: {e}') else: print(f'\nNo saved weights found at {saved_path}') print('Using random initialization for this demo.') # Evaluate print('\n' + '='*60) print('Evaluating Agent') print('='*60) rewards, success_rate = evaluate_agent(agent, env, num_episodes=10) print(f'\nResults (10 episodes):') print(f' Mean reward: {np.mean(rewards):.2f}') print(f' Max reward: {np.max(rewards):.2f}') print(f' Min reward: {np.min(rewards):.2f}') print(f' Success rate: {success_rate:.1%}') print(f'\nRewards by episode:') for i, r in enumerate(rewards): print(f' Episode {i+1:2d}: {r:6.1f}') print('\n' + '='*60) print('Demo Complete') print('='*60) if __name__ == '__main__': main()