def test_graceful_interrupt(monkeypatch): """SMARTS should only throw a KeyboardInterript exception.""" agent_spec = AgentSpec( interface=AgentInterface.from_type(AgentType.Laner), agent_builder=lambda: Agent.from_function(lambda _: "keep_lane"), ) agent = agent_spec.build_agent() env = build_env(agent_spec) with pytest.raises(KeyboardInterrupt): obs = env.reset() # To simulate a user interrupting the sim (e.g. ctrl-c). We just need to # hook in to some function that SMARTS calls internally (like this one). with mock.patch( "smarts.core.sensors.Sensors.observe", side_effect=KeyboardInterrupt ): for episode in range(10): obs, _, _, _ = env.step({AGENT_ID: agent.act(obs)}) assert episode == 0, "SMARTS should have been interrupted, ending early" with pytest.raises(SMARTSNotSetupError): env.step({AGENT_ID: agent.act(obs)})
def main(scenarios, sim_name, headless, num_episodes, seed): agent_spec = AgentSpec( interface=AgentInterface.from_type(AgentType.Tracker, max_episode_steps=None), agent_builder=TrackingAgent, ) env = gym.make( "smarts.env:hiway-v0", scenarios=scenarios, agent_specs={AGENT_ID: agent_spec}, sim_name=sim_name, headless=headless, visdom=False, fixed_timestep_sec=0.1, sumo_headless=True, seed=seed, # envision_record_data_replay_path="./data_replay", ) for episode in episodes(n=num_episodes): agent = agent_spec.build_agent() observations = env.reset() episode.record_scenario(env.scenario_log) dones = {"__all__": False} while not dones["__all__"]: agent_obs = observations[AGENT_ID] agent_action = agent.act(agent_obs) observations, rewards, dones, infos = env.step({AGENT_ID: agent_action}) episode.record_step(observations, rewards, dones, infos) env.close()
def main(scenarios, headless, num_episodes, max_episode_steps=None): agent_spec = AgentSpec( interface=AgentInterface.from_type( AgentType.LanerWithSpeed, max_episode_steps=max_episode_steps ), agent_builder=ChaseViaPointsAgent, ) env = gym.make( "smarts.env:hiway-v0", scenarios=scenarios, agent_specs={"SingleAgent": agent_spec}, headless=headless, sumo_headless=True, ) # Convert `env.step()` and `env.reset()` from multi-agent interface to # single-agent interface. env = SingleAgent(env=env) for episode in episodes(n=num_episodes): agent = agent_spec.build_agent() observation = env.reset() episode.record_scenario(env.scenario_log) done = False while not done: agent_action = agent.act(observation) observation, reward, done, info = env.step(agent_action) episode.record_step(observation, reward, done, info) env.close()
def test_building_agent_with_tuple_params(): agent_spec = AgentSpec( agent_params=(32, 41), agent_builder=lambda x, y: Agent.from_function(lambda _: (x, y)), ) agent = agent_spec.build_agent() assert agent.act("dummy observation") == (32, 41)
def train(training_scenarios, evaluation_scenarios, sim_name, headless, num_episodes, seed): agent_params = {"input_dims": 4, "hidden_dims": 7, "output_dims": 3} agent_spec = AgentSpec( interface=AgentInterface.from_type(AgentType.Standard, max_episode_steps=5000), agent_params=agent_params, agent_builder=PyTorchAgent, observation_adapter=observation_adapter, ) env = gym.make( "smarts.env:hiway-v0", scenarios=training_scenarios, agent_specs={AGENT_ID: agent_spec}, sim_name=sim_name, headless=headless, fixed_timestep_sec=0.1, seed=seed, ) steps = 0 for episode in episodes(n=num_episodes): agent = agent_spec.build_agent() observations = env.reset() episode.record_scenario(env.scenario_log) dones = {"__all__": False} while not dones["__all__"]: agent_obs = observations[AGENT_ID] agent_action = agent.act(agent_obs) observations, rewards, dones, infos = env.step( {AGENT_ID: agent_action}) episode.record_step(observations, rewards, dones, infos) steps += 1 if steps % 500 == 0: print("Evaluating agent") # We construct an evaluation agent based on the saved # state of the agent in training. model_path = tempfile.mktemp() agent.save(model_path) eval_agent_spec = agent_spec.replace( agent_params=dict(agent_params, model_path=model_path)) # Remove the call to ray.wait if you want evaluation to run # in parallel with training ray.wait([ evaluate.remote(eval_agent_spec, evaluation_scenarios, headless, seed) ]) env.close()
def test_building_agent_with_dict_params(): agent_spec = AgentSpec( agent_params={ "y": 2, "x": 1 }, agent_builder=lambda x, y: Agent.from_function(lambda _: x / y), ) agent = agent_spec.build_agent() assert agent.act("dummy observation") == 1 / 2
def test_graceful_shutdown(): """SMARTS should not throw any exceptions when shutdown.""" agent_spec = AgentSpec( interface=AgentInterface.from_type(AgentType.Laner), agent_builder=lambda: Agent.from_function(lambda _: "keep_lane"), ) env = build_env(agent_spec) agent = agent_spec.build_agent() obs = env.reset() for _ in range(10): obs = env.step({AGENT_ID: agent.act(obs)}) env.close()
def on_trigger(ctx: Dict[str, Any]): # Define agent specs to be assigned agent_spec = AgentSpec( interface=AgentInterface(waypoints=True, action=ActionSpaceType.Lane), agent_builder=BasicAgent, ) # Select a random sample from candidates k = ctx.get("vehicles_to_replace_randomly", 0) if k <= 0: logger.warning( "default (0) or negative value specified for replacement. Replacing all valid vehicle candidates." ) sample = ctx["vehicle_candidates"] else: logger.info( f"Choosing {k} vehicles randomly from {len(ctx['vehicle_candidates'])} valid vehicle candidates." ) sample = random.sample(ctx["vehicle_candidates"], k) assert len(sample) != 0 for veh_id in sample: # Map selected vehicles to agent ids & specs agent_id = f"agent-{veh_id}" ctx["agents"][agent_id] = agent_spec.build_agent() # Create missions based on current state and traffic history positional, traverse = scenario.create_dynamic_traffic_history_mission( veh_id, ctx["elapsed_sim_time"], ctx["positional_radius"] ) # Take control of vehicles immediately try: # Try to assign a PositionalGoal at the last recorded timestep smarts.add_agent_and_switch_control( veh_id, agent_id, agent_spec.interface, positional ) except PlanningError: logger.warning( f"Unable to create PositionalGoal for vehicle {veh_id}, falling back to TraverseGoal" ) smarts.add_agent_and_switch_control( veh_id, agent_id, agent_spec.interface, traverse )
def prepare_test_agent_and_environment( required_interface: Dict[str, Any], action_adapter: Callable = lambda action: action, info_adapter: Callable = lambda observation, reward, info: info, observation_adapter: Callable = lambda observation: observation, reward_adapter: Callable = lambda _, reward: reward, headless: bool = True, ) -> Tuple[Agent, UltraEnv]: if "waypoints" not in required_interface: required_interface["waypoints"] = Waypoints(lookahead=20) if "neighborhood_vehicles" not in required_interface: required_interface["neighborhood_vehicles"] = NeighborhoodVehicles( radius=200) if "action" not in required_interface: required_interface["action"] = ActionSpaceType.Lane agent_spec = AgentSpec( interface=AgentInterface(**required_interface), agent_builder=RandomAgent, agent_params={"action_type": required_interface["action"]}, action_adapter=action_adapter, info_adapter=info_adapter, observation_adapter=observation_adapter, reward_adapter=reward_adapter, ) agent = agent_spec.build_agent() environment = gym.make( "ultra.env:ultra-v0", agent_specs={AGENT_ID: agent_spec}, scenario_info=("00", "easy"), headless=headless, timestep_sec=TIMESTEP_SEC, seed=SEED, ) return agent, environment
def main( script: str, scenarios: Sequence[str], headless: bool, seed: int, vehicles_to_replace: int, episodes: int, ): assert vehicles_to_replace > 0 assert episodes > 0 logger = logging.getLogger(script) logger.setLevel(logging.INFO) logger.debug("initializing SMARTS") smarts = SMARTS( agent_interfaces={}, traffic_sim=None, envision=None if headless else Envision(), ) random_seed(seed) traffic_history_provider = smarts.get_provider_by_type( TrafficHistoryProvider) assert traffic_history_provider scenario_list = Scenario.get_scenario_list(scenarios) scenarios_iterator = Scenario.variations_for_all_scenario_roots( scenario_list, []) for scenario in scenarios_iterator: logger.debug("working on scenario {}".format(scenario.name)) veh_missions = scenario.discover_missions_of_traffic_histories() if not veh_missions: logger.warning("no vehicle missions found for scenario {}.".format( scenario.name)) continue veh_start_times = { v_id: mission.start_time for v_id, mission in veh_missions.items() } k = vehicles_to_replace if k > len(veh_missions): logger.warning( "vehicles_to_replace={} is greater than the number of vehicle missions ({})." .format(vehicles_to_replace, len(veh_missions))) k = len(veh_missions) # XXX replace with AgentSpec appropriate for IL model agent_spec = AgentSpec( interface=AgentInterface.from_type(AgentType.Imitation), agent_builder=ReplayCheckerAgent, agent_params=smarts.fixed_timestep_sec, ) for episode in range(episodes): logger.info(f"starting episode {episode}...") agentid_to_vehid = {} agent_interfaces = {} # Build the Agents for the to-be-hijacked vehicles # and gather their missions agents = {} dones = {} ego_missions = {} sample = {} if scenario.traffic_history.dataset_source == "Waymo": # For Waymo, we only hijack the vehicle that was autonomous in the dataset waymo_ego_id = scenario.traffic_history.ego_vehicle_id if waymo_ego_id is not None: assert ( k == 1 ), f"do not specify -k > 1 when just hijacking Waymo ego vehicle (it was {k})" veh_id = str(waymo_ego_id) sample = {veh_id} else: logger.warning( f"Waymo ego vehicle id not mentioned in the dataset. Hijacking a random vehicle." ) if not sample: # For other datasets, hijack a sample of the recorded vehicles # Pick k vehicle missions to hijack with agent # and figure out which one starts the earliest sample = scenario.traffic_history.random_overlapping_sample( veh_start_times, k) if len(sample) < k: logger.warning( f"Unable to choose {k} overlapping missions. allowing non-overlapping." ) leftover = set(veh_start_times.keys()) - sample sample.update(set(random.sample(leftover, k - len(sample)))) agent_spec.interface.max_episode_steps = max([ scenario.traffic_history.vehicle_final_exit_time(veh_id) / 0.1 for veh_id in sample ]) history_start_time = None logger.info(f"chose vehicles: {sample}") for veh_id in sample: agent_id = f"ego-agent-IL-{veh_id}" agentid_to_vehid[agent_id] = veh_id agent_interfaces[agent_id] = agent_spec.interface if (not history_start_time or veh_start_times[veh_id] < history_start_time): history_start_time = veh_start_times[veh_id] for agent_id in agent_interfaces.keys(): agent = agent_spec.build_agent() veh_id = agentid_to_vehid[agent_id] agent.load_data_for_vehicle(veh_id, scenario, history_start_time) agents[agent_id] = agent dones[agent_id] = False mission = veh_missions[veh_id] ego_missions[agent_id] = replace( mission, start_time=mission.start_time - history_start_time) # Tell the traffic history provider to start traffic # at the point when the earliest agent enters... traffic_history_provider.start_time = history_start_time # and all the other agents to offset their missions by this much too scenario.set_ego_missions(ego_missions) logger.info(f"offsetting sim_time by: {history_start_time}") # Take control of vehicles with corresponding agent_ids smarts.switch_ego_agents(agent_interfaces) # Finally start the simulation loop... logger.info(f"starting simulation loop...") observations = smarts.reset(scenario) while not all(done for done in dones.values()): actions = { agent_id: agents[agent_id].act(agent_obs) for agent_id, agent_obs in observations.items() } logger.debug("stepping @ sim_time={} for agents={}...".format( smarts.elapsed_sim_time, list(observations.keys()))) observations, rewards, dones, infos = smarts.step(actions) for agent_id in agents.keys(): if dones.get(agent_id, False): if not observations[agent_id].events.reached_goal: logger.warning( "agent_id={} exited @ sim_time={}".format( agent_id, smarts.elapsed_sim_time)) logger.warning(" ... with {}".format( observations[agent_id].events)) else: logger.info( "agent_id={} reached goal @ sim_time={}". format(agent_id, smarts.elapsed_sim_time)) logger.debug(" ... with {}".format( observations[agent_id].events)) del observations[agent_id] smarts.destroy()
import gym from smarts.core.agent import Agent from smarts.core.agent_interface import AgentInterface, AgentType from smarts.zoo.agent_spec import AgentSpec agent_id = "Agent-007" agent_spec = AgentSpec( interface=AgentInterface.from_type(AgentType.Laner), agent_params={"agent_function": lambda _: "keep_lane"}, agent_builder=Agent.from_function, ) env = gym.make( "smarts.env:hiway-v0", scenarios=["scenarios/loop"], agent_specs={agent_id: agent_spec}, ) agent = agent_spec.build_agent() observations = env.reset() dones = {"__all__": False} while not dones["__all__"]: action = agent.act(observations[agent_id]) observations, _, dones, _ = env.step({agent_id: action}) env.close()
def test_observations_stacking(self): EPISODES = 3 WIDTH = 64 HEIGHT = WIDTH RESOLUTION = 50 / WIDTH ENVIRONMENT_STACK_SIZE = 4 agent_spec = AgentSpec( interface=AgentInterface( waypoints=Waypoints(lookahead=1), neighborhood_vehicles=NeighborhoodVehicles(radius=10.0), rgb=RGB(width=WIDTH, height=HEIGHT, resolution=RESOLUTION), action=ActionSpaceType.Lane, ), agent_builder=TestLaneAgent, ) agent = agent_spec.build_agent() environment = gym.make( "ultra.env:ultra-v0", agent_specs={AGENT_ID: agent_spec}, scenario_info=("00", "easy"), headless=True, timestep_sec=0.1, seed=2, ) def check_environment_observations_stack(environment): self.assertIsInstance(environment.smarts_observations_stack, deque) self.assertEqual(len(environment.smarts_observations_stack), ENVIRONMENT_STACK_SIZE) self.assertIsInstance(environment.smarts_observations_stack[0], dict) self.assertTrue( all( str(environment.smarts_observations_stack[0]) == str( observations) for observations in environment.smarts_observations_stack)) def check_stacked_observations(environment, observations): self.assertIn(AGENT_ID, observations) self.assertTrue(AGENT_ID, observations[AGENT_ID].top_down_rgb) self.assertIsInstance(observations[AGENT_ID].top_down_rgb, TopDownRGB) self.assertEqual( observations[AGENT_ID].top_down_rgb.metadata, environment.smarts_observations_stack[-1] [AGENT_ID].top_down_rgb.metadata, ) self.assertEqual( observations[AGENT_ID].top_down_rgb.data.shape, (ENVIRONMENT_STACK_SIZE, HEIGHT, WIDTH, 3), ) # Ensure the stacked observation's TopDownRGB data is in the same order, and # and contains the same NumPy arrays as the environment's observation stack. self.assertTrue( all( np.array_equal( observations_from_stack[AGENT_ID].top_down_rgb.data, observations[AGENT_ID].top_down_rgb.data[i], ) for i, observations_from_stack in enumerate( environment.smarts_observations_stack))) for _ in range(EPISODES): dones = {"__all__": False} observations = environment.reset() check_environment_observations_stack(environment) check_stacked_observations(environment, observations) while not dones["__all__"]: action = agent.act(observations[AGENT_ID]) observations, _, dones, _ = environment.step( {AGENT_ID: action}) check_stacked_observations(environment, observations) environment.close()