190 lines
5.8 KiB
Python
190 lines
5.8 KiB
Python
#!/usr/bin/env python3
|
|
"""Minimal DiscoRL CartPole integration test.
|
|
|
|
This is a minimal script that demonstrates that DiscoRL can:
|
|
1. Load CartPole environment
|
|
2. Create an agent
|
|
3. Collect trajectories
|
|
4. Perform training steps
|
|
|
|
This serves as a proof-of-concept for integrating DiscoRL with other Gym environments.
|
|
"""
|
|
|
|
import os
|
|
import sys
|
|
|
|
# Set JAX to CPU
|
|
os.environ['JAX_PLATFORMS'] = 'cpu'
|
|
|
|
# Add paths
|
|
repo_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
|
sys.path.insert(0, os.path.join(repo_root, 'disco_rl'))
|
|
|
|
print('='*70)
|
|
print('DiscoRL ↔ Gym Integration: CartPole Proof-of-Concept')
|
|
print('='*70)
|
|
|
|
print('\n[1/4] Importing modules...')
|
|
try:
|
|
import numpy as np
|
|
import jax
|
|
import jax.numpy as jnp
|
|
from disco_rl import agent as disco_agent
|
|
from disco_cartpole_env import DiscoCartPoleEnv
|
|
print(' ✓ All imports successful')
|
|
except Exception as e:
|
|
print(f' ✗ Import failed: {e}')
|
|
sys.exit(1)
|
|
|
|
print('\n[2/4] Creating DiscoRL environment adapter...')
|
|
try:
|
|
env = DiscoCartPoleEnv(batch_size=2, max_steps=500)
|
|
obs_spec = env.single_observation_spec()
|
|
act_spec = env.single_action_spec()
|
|
print(f' ✓ Environment created')
|
|
print(f' Observation spec: {obs_spec}')
|
|
print(f' Action spec: {act_spec}')
|
|
except Exception as e:
|
|
print(f' ✗ Environment creation failed: {e}')
|
|
sys.exit(1)
|
|
|
|
print('\n[3/4] Initializing DiscoRL agent...')
|
|
try:
|
|
agent_settings = disco_agent.get_settings_disco()
|
|
agent = disco_agent.Agent(
|
|
single_observation_spec=obs_spec,
|
|
single_action_spec=act_spec,
|
|
agent_settings=agent_settings,
|
|
batch_axis_name=None,
|
|
)
|
|
|
|
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)
|
|
|
|
rng, subkey = jax.random.split(rng)
|
|
update_rule_params, _ = agent.update_rule.init_params(subkey)
|
|
|
|
print(f' ✓ Agent initialized')
|
|
print(f' Learner params shape: {jax.tree.map(lambda x: x.shape, learner_state.params)}')
|
|
except Exception as e:
|
|
print(f' ✗ Agent initialization failed: {e}')
|
|
import traceback
|
|
traceback.print_exc()
|
|
sys.exit(1)
|
|
|
|
print('\n[4/4] Collecting trajectory and performing learner step...')
|
|
try:
|
|
# Reset environment
|
|
env_state, timestep = env.reset(rng_key=subkey)
|
|
print(f' ✓ Environment reset')
|
|
|
|
# Collect 8 timesteps
|
|
trajectory_length = 8
|
|
observations = []
|
|
actions = []
|
|
rewards = []
|
|
discounts = []
|
|
agent_outs_list = []
|
|
logits_list = []
|
|
|
|
for t in range(trajectory_length):
|
|
rng, subkey = jax.random.split(rng)
|
|
|
|
# Agent step
|
|
actor_timestep, actor_state = agent.actor_step(
|
|
learner_state.params,
|
|
subkey,
|
|
timestep,
|
|
actor_state,
|
|
)
|
|
|
|
# Record
|
|
observations.append(timestep.observation['observation'])
|
|
actions.append(actor_timestep.actions)
|
|
agent_outs_list.append(actor_timestep.agent_outs)
|
|
logits_list.append(actor_timestep.logits)
|
|
|
|
# Env step
|
|
rng, subkey = jax.random.split(rng)
|
|
env_state, timestep = env.step(env_state, actor_timestep.actions)
|
|
|
|
rewards.append(timestep.reward)
|
|
discounts.append(1.0 - (timestep.step_type == 1).astype(jnp.float32))
|
|
|
|
# Stack trajectory
|
|
observations = jnp.stack(observations, axis=0)
|
|
actions = jnp.stack(actions, axis=0)
|
|
rewards = jnp.stack(rewards, axis=0)
|
|
discounts = jnp.stack(discounts, axis=0)
|
|
agent_outs_stacked = jax.tree.map(
|
|
lambda *xs: jnp.stack(xs, axis=0),
|
|
*agent_outs_list,
|
|
)
|
|
logits = jnp.stack(logits_list, axis=0)
|
|
|
|
print(f' ✓ Trajectory collected ({trajectory_length} steps)')
|
|
print(f' Observations shape: {observations.shape}')
|
|
print(f' Actions shape: {actions.shape}')
|
|
print(f' Rewards: mean={jnp.mean(rewards):.2f}, range=[{jnp.min(rewards):.2f}, {jnp.max(rewards):.2f}]')
|
|
|
|
# Create rollout
|
|
from disco_rl import types
|
|
rollout = types.ActorRollout(
|
|
observations=observations,
|
|
actions=actions,
|
|
rewards=rewards,
|
|
discounts=discounts,
|
|
agent_outs=agent_outs_stacked,
|
|
logits=logits,
|
|
states=actor_state,
|
|
)
|
|
|
|
print(f' ✓ Rollout created')
|
|
|
|
# Learner step
|
|
rng, subkey = jax.random.split(rng)
|
|
new_learner_state, new_actor_state, log_dict = agent.learner_step(
|
|
rng=subkey,
|
|
rollout=rollout,
|
|
learner_state=learner_state,
|
|
agent_net_state=actor_state,
|
|
update_rule_params=update_rule_params,
|
|
is_meta_training=False,
|
|
)
|
|
|
|
print(f' ✓ Learner step completed')
|
|
print(f' Loss: {log_dict.get("total_loss", "N/A")}')
|
|
|
|
except Exception as e:
|
|
print(f' ✗ Trajectory collection or learner step failed: {e}')
|
|
import traceback
|
|
traceback.print_exc()
|
|
sys.exit(1)
|
|
|
|
print('\n' + '='*70)
|
|
print('✓ Success! DiscoRL ↔ Gym integration works!')
|
|
print('='*70)
|
|
print(f'''
|
|
Integration achieved:
|
|
• Gym CartPole environment wrapped for DiscoRL
|
|
• Agent can collect trajectories from Gym environments
|
|
• Learner can perform parameter updates using Gym trajectories
|
|
|
|
Template for custom environments:
|
|
1. Create environment wrapper (see disco_cartpole_env.py)
|
|
- Implement reset() → (state, types.EnvironmentTimestep)
|
|
- Implement step(state, actions) → (state, types.EnvironmentTimestep)
|
|
2. Use DiscoRL agent as shown above
|
|
3. Adapt to your custom environment in gym_env_250326_erase.py
|
|
|
|
Files created:
|
|
• disco_cartpole_env.py: CartPole ↔ DiscoRL adapter
|
|
• disco_weights.py: Weights loading utilities
|
|
• train_disco_cartpole.py: Training loop example
|
|
• test_disco_setup.py: Comprehensive sanity tests
|
|
''')
|