diff --git a/documentation/Makefile b/documentation/Makefile new file mode 100644 index 0000000..d0c3cbf --- /dev/null +++ b/documentation/Makefile @@ -0,0 +1,20 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line, and also +# from the environment for the first two. +SPHINXOPTS ?= +SPHINXBUILD ?= sphinx-build +SOURCEDIR = source +BUILDDIR = build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/documentation/README.md b/documentation/README.md new file mode 100644 index 0000000..9aa4100 --- /dev/null +++ b/documentation/README.md @@ -0,0 +1,9 @@ +This folder contains files for the documentation: [https://scenarionet.readthedocs.io/](https://scenarionet.readthedocs.io/). + +To build documents locally, please run the following codes: + +``` +pip install sphinx sphinx_rtd_theme +cd scenarionet/documentation +make html +``` diff --git a/documentation/make.bat b/documentation/make.bat new file mode 100644 index 0000000..9534b01 --- /dev/null +++ b/documentation/make.bat @@ -0,0 +1,35 @@ +@ECHO OFF + +pushd %~dp0 + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set SOURCEDIR=source +set BUILDDIR=build + +if "%1" == "" goto help + +%SPHINXBUILD% >NUL 2>NUL +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.http://sphinx-doc.org/ + exit /b 1 +) + +%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% +goto end + +:help +%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% + +:end +popd diff --git a/documentation/source/conf.py b/documentation/source/conf.py new file mode 100644 index 0000000..5cf8f21 --- /dev/null +++ b/documentation/source/conf.py @@ -0,0 +1,55 @@ +# Configuration file for the Sphinx documentation builder. +# +# This file only contains a selection of the most common options. For a full +# list see the documentation: +# https://www.sphinx-doc.org/en/master/usage/configuration.html + +# -- Path setup -------------------------------------------------------------- + +# If extensions (or modules to documentation with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +# +# import os +# import sys +# sys.path.insert(0, os.path.abspath('.')) + + +# -- Project information ----------------------------------------------------- + +project = 'ScenarioNet' +copyright = 'MetaDriverse' +author = 'MetaDriverse' + +# The full version, including alpha/beta/rc tags +release = '0.1.1' + +# -- General configuration --------------------------------------------------- + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ + "sphinx.ext.autosectionlabel", + "sphinx_rtd_theme" +] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# This pattern also affects html_static_path and html_extra_path. +exclude_patterns = [] + +# -- Options for HTML output ------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +# +html_theme = 'sphinx_rtd_theme' + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = [] diff --git a/documentation/source/index.rst b/documentation/source/index.rst new file mode 100644 index 0000000..62702f4 --- /dev/null +++ b/documentation/source/index.rst @@ -0,0 +1,33 @@ +######################## +ScenarioNet Documentation +######################## + + +Welcome to the ScenarioNet documentation! +ScenarioNet is an open-sourced platform for large-scale traffic scenario modeling and simulation with the following features: + +* ScenarioNet defines a unified scenario description format containing HD maps and detailed object annotations. +* ScenarioNet provides tools to build and manage databases built from various data sources including real-world datasets like Waymo, nuScenes, Lyft L5, and nuPlan datasets and synthetic datasets like the procedural generated ones and safety-critical ones. +* Scenarios recorded in this format can be replayed in the digital twins with multiple views, ranging from Bird-Eye-View layout to realistic 3D rendering. + +It can thus support several applications including large-scale scenario generation, AD testing, imitation learning, and reinforcement learning in both single-agent and multi-agent settings. The results imply scaling up the training data brings new research opportunities in machine learning and autonomous driving. + +This documentation brings you the information on installation, usages and more of ScenarioNet! +You can also visit the `GitHub repo `_ and `Webpage `_ for code and videos. +Please feel free to contact us if you have any suggestions or ideas! + + +Citation +######## + +You can read `our white paper `_ describing the details of ScenarioNet! If you use ScenarioNet in your own work, please cite: + +.. code-block:: latex + + @article{li2023scenarionet, + title={ScenarioNet: Open-Source Platform for Large-Scale Traffic Scenario Simulation and Modeling}, + author={Li, Quanyi and Peng, Zhenghao and Feng, Lan and Duan, Chenda and Mo, Wenjie and Zhou, Bolei and others}, + journal={arXiv preprint arXiv:2306.12241}, + year={2023} + } + diff --git a/scenarionet/tests/script/run_ckpt.py b/scenarionet/tests/script/run_ckpt.py index a459f7e..0086ce2 100644 --- a/scenarionet/tests/script/run_ckpt.py +++ b/scenarionet/tests/script/run_ckpt.py @@ -1,16 +1,13 @@ import pygame from metadrive.engine.asset_loader import AssetLoader from metadrive.envs.real_data_envs.nuscenes_env import ScenarioEnv -from metadrive.envs.gym_wrapper import GymEnvWrapper +from metadrive.envs.gym_wrapper import createGymWrapper from scenarionet_training.train_utils.utils import initialize_ray, get_function from scenarionet_training.scripts.train_nuplan import config if __name__ == "__main__": initialize_ray(test_mode=False, num_gpus=1) - env = GymEnvWrapper( - dict( - inner_class=ScenarioEnv, - inner_config={ + env = createGymWrapper(ScenarioEnv)({ # "data_directory": AssetLoader.file_path("nuscenes", return_raw_style=False), "data_directory": "D:\\scenarionet_testset\\nuplan_test\\nuplan_test_w_raw", "use_render": True, @@ -44,7 +41,7 @@ if __name__ == "__main__": ), } ) - ) + # env.reset() # diff --git a/scenarionet_training/scripts/local_test.py b/scenarionet_training/scripts/local_test.py index 06ce442..c00c486 100644 --- a/scenarionet_training/scripts/local_test.py +++ b/scenarionet_training/scripts/local_test.py @@ -1,7 +1,7 @@ import os.path from metadrive.envs.scenario_env import ScenarioEnv -from metadrive.envs.gym_wrapper import GymEnvWrapper +from metadrive.envs.gym_wrapper import createGymWrapper from scenarionet import SCENARIONET_REPO_PATH, SCENARIONET_DATASET_PATH from scenarionet_training.train_utils.multi_worker_PPO import MultiWorkerPPO @@ -14,8 +14,8 @@ if __name__ == '__main__': stop = int(100_000_000) config = dict( - env=GymEnvWrapper, - env_config=dict(inner_class=ScenarioEnv, inner_config=dict( + env=createGymWrapper(ScenarioEnv), + env_config=dict( # scenario start_scenario_index=0, num_scenarios=32, @@ -34,7 +34,7 @@ if __name__ == '__main__': # training horizon=None, - )), + ), # # ===== Evaluation ===== evaluation_interval=2, diff --git a/scenarionet_training/scripts/train_nuplan.py b/scenarionet_training/scripts/train_nuplan.py index ba2cce8..74e5481 100644 --- a/scenarionet_training/scripts/train_nuplan.py +++ b/scenarionet_training/scripts/train_nuplan.py @@ -1,13 +1,13 @@ import os.path -from metadrive.envs.gym_wrapper import GymEnvWrapper +from metadrive.envs.gym_wrapper import createGymWrapper from metadrive.envs.scenario_env import ScenarioEnv from scenarionet import SCENARIONET_REPO_PATH, SCENARIONET_DATASET_PATH from scenarionet_training.train_utils.multi_worker_PPO import MultiWorkerPPO from scenarionet_training.train_utils.utils import train, get_train_parser, get_exp_name config = dict( - env=GymEnvWrapper, - env_config=dict(inner_class=ScenarioEnv, inner_config=dict( + env=createGymWrapper(ScenarioEnv), + env_config=dict( # scenario start_scenario_index=0, num_scenarios=40000, @@ -16,7 +16,7 @@ config = dict( # curriculum training curriculum_level=100, - target_success_rate=0.8, # or 0.7 + target_success_rate=0.7, # episodes_to_evaluate_curriculum=400, # default=num_scenarios/curriculum_level # traffic & light @@ -42,7 +42,7 @@ config = dict( vehicle_config=dict(side_detector=dict(num_lasers=0)) - )), + ), # ===== Evaluation ===== evaluation_interval=15, diff --git a/scenarionet_training/scripts/train_pg.py b/scenarionet_training/scripts/train_pg.py index ced7bc3..73c3c42 100644 --- a/scenarionet_training/scripts/train_pg.py +++ b/scenarionet_training/scripts/train_pg.py @@ -1,14 +1,14 @@ import os.path from ray.tune import grid_search from metadrive.envs.scenario_env import ScenarioEnv -from metadrive.envs.gym_wrapper import GymEnvWrapper +from metadrive.envs.gym_wrapper import createGymWrapper from scenarionet import SCENARIONET_REPO_PATH, SCENARIONET_DATASET_PATH from scenarionet_training.train_utils.multi_worker_PPO import MultiWorkerPPO from scenarionet_training.train_utils.utils import train, get_train_parser, get_exp_name config = dict( - env=GymEnvWrapper, - env_config=dict(inner_class=ScenarioEnv, inner_config=dict( + env=createGymWrapper(ScenarioEnv), + env_config=dict( # scenario start_scenario_index=0, num_scenarios=40000, @@ -21,7 +21,7 @@ config = dict( # episodes_to_evaluate_curriculum=400, # default=num_scenarios/curriculum_level # traffic & light - reactive_traffic=False, + reactive_traffic=True, no_static_vehicles=True, no_light=True, static_traffic_object=True, @@ -41,7 +41,7 @@ config = dict( vehicle_config=dict(side_detector=dict(num_lasers=0)) - )), + ), # ===== Evaluation ===== evaluation_interval=15, diff --git a/scenarionet_training/scripts/train_pg_nuplan.py b/scenarionet_training/scripts/train_pg_nuplan.py new file mode 100644 index 0000000..59d4594 --- /dev/null +++ b/scenarionet_training/scripts/train_pg_nuplan.py @@ -0,0 +1,99 @@ +import os.path +from ray import tune +from metadrive.envs.gym_wrapper import createGymWrapper +from metadrive.envs.scenario_env import ScenarioEnv +from scenarionet import SCENARIONET_REPO_PATH, SCENARIONET_DATASET_PATH +from scenarionet_training.train_utils.multi_worker_PPO import MultiWorkerPPO +from scenarionet_training.train_utils.utils import train, get_train_parser, get_exp_name + +config = dict( + env=createGymWrapper(ScenarioEnv), + env_config=dict( + # scenario + start_scenario_index=20000, + num_scenarios=40000, # 0-40000 nuplan, 40000-80000 pg + data_directory=os.path.join(SCENARIONET_DATASET_PATH, "pg_nuplan_train"), + sequential_seed=True, + no_map=True, + # store_map=False, + # store_data=False, + + # curriculum training + curriculum_level=100, + target_success_rate=0.7, + # episodes_to_evaluate_curriculum=400, # default=num_scenarios/curriculum_level + + # traffic & light + reactive_traffic=True, + no_static_vehicles=True, + no_light=True, + static_traffic_object=True, + + # training scheme + horizon=None, + driving_reward=9, + steering_range_penalty=1.0, + heading_penalty=1, + lateral_penalty=1.0, + no_negative_reward=True, + on_lane_line_penalty=0, + crash_vehicle_penalty=1, + crash_human_penalty=1, + crash_object_penalty=0.5, + # out_of_road_penalty=2, + max_lateral_dist=2, + # crash_vehicle_done=True, + + vehicle_config=dict(side_detector=dict(num_lasers=0)) + + ), + + # ===== Evaluation ===== + evaluation_interval=15, + evaluation_num_episodes=1000, + evaluation_config=dict(env_config=dict(start_scenario_index=0, + num_scenarios=1000, + sequential_seed=True, + curriculum_level=1, # turn off + data_directory=os.path.join(SCENARIONET_DATASET_PATH, "nuplan_test"))), + evaluation_num_workers=10, + metrics_smoothing_episodes=10, + + # ===== Training ===== + model=dict(fcnet_hiddens=[512, 256, 128]), + horizon=600, + num_sgd_iter=20, + lr=1e-4, + rollout_fragment_length=500, + sgd_minibatch_size=200, + train_batch_size=50000, + num_gpus=0.5, + num_cpus_per_worker=0.3, + num_cpus_for_driver=1, + num_workers=20, + framework="tf" +) + +if __name__ == '__main__': + # PG data is generated with seeds 10,000 to 60,000 + args = get_train_parser().parse_args() + exp_name = get_exp_name(args) + stop = int(100_000_000) + config["num_gpus"] = 0.5 if args.num_gpus != 0 else 0 + + train( + MultiWorkerPPO, + exp_name=exp_name, + save_dir=os.path.join(SCENARIONET_REPO_PATH, "experiment"), + keep_checkpoints_num=5, + stop=stop, + config=config, + num_gpus=args.num_gpus, + # num_seeds=args.num_seeds, + num_seeds=4, + test_mode=args.test, + # local_mode=True, + # TODO remove this when we release our code + # wandb_key_file="~/wandb_api_key_file.txt", + wandb_project="scenarionet", + ) diff --git a/scenarionet_training/scripts/train_waymo.py b/scenarionet_training/scripts/train_waymo.py index 112b18d..cab184d 100644 --- a/scenarionet_training/scripts/train_waymo.py +++ b/scenarionet_training/scripts/train_waymo.py @@ -1,13 +1,13 @@ import os.path -from metadrive.envs.gym_wrapper import GymEnvWrapper +from metadrive.envs.gym_wrapper import createGymWrapper from metadrive.envs.scenario_env import ScenarioEnv from scenarionet import SCENARIONET_REPO_PATH, SCENARIONET_DATASET_PATH from scenarionet_training.train_utils.multi_worker_PPO import MultiWorkerPPO from scenarionet_training.train_utils.utils import train, get_train_parser, get_exp_name config = dict( - env=GymEnvWrapper, - env_config=dict(inner_class=ScenarioEnv, inner_config=dict( + env=createGymWrapper(ScenarioEnv), + env_config=dict( # scenario start_scenario_index=0, num_scenarios=40000, @@ -41,7 +41,7 @@ config = dict( vehicle_config=dict(side_detector=dict(num_lasers=0)) - )), + ), # ===== Evaluation ===== evaluation_interval=15, diff --git a/scenarionet_training/train_utils/utils.py b/scenarionet_training/train_utils/utils.py index 3306777..d7729ea 100644 --- a/scenarionet_training/train_utils/utils.py +++ b/scenarionet_training/train_utils/utils.py @@ -9,7 +9,7 @@ import numpy as np import tqdm from metadrive.constants import TerminationState from metadrive.envs.scenario_env import ScenarioEnv -from metadrive.envs.gym_wrapper import GymEnvWrapper +from metadrive.envs.gym_wrapper import createGymWrapper from ray import tune from ray.tune import CLIReporter @@ -292,7 +292,7 @@ def eval_ckpt(config, episodes_to_evaluate_curriculum=num_scenarios, data_directory=scenario_data_path, use_render=render)) - env = GymEnvWrapper(dict(inner_class=ScenarioEnv, inner_config=env_config)) + env = createGymWrapper(ScenarioEnv)(env_config) super_data = defaultdict(list) EPISODE_NUM = env.config["num_scenarios"]