Compare commits
31 Commits
idm_upgrad
...
save-video
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3fa370eb8a | ||
|
|
a576f0fb18 | ||
|
|
575e299fc8 | ||
|
|
1e70303c57 | ||
|
|
a9feec4f38 | ||
|
|
3d3b3d510a | ||
|
|
3ac9465997 | ||
|
|
597b9af5d4 | ||
|
|
37f44605d2 | ||
|
|
4076b0361a | ||
|
|
fc04f8e9ee | ||
|
|
f5f1c24f45 | ||
|
|
f93e130498 | ||
|
|
2965dc9982 | ||
|
|
fa0e20998d | ||
|
|
57a42f70ec | ||
|
|
5f6ad37c37 | ||
|
|
e602aa0641 | ||
|
|
5ada1cc543 | ||
|
|
a9314c4657 | ||
|
|
a37995694d | ||
|
|
62c28d0cfa | ||
|
|
e28459a168 | ||
|
|
6f181a7351 | ||
|
|
81e38f55ab | ||
|
|
b94344214b | ||
|
|
6d867466c6 | ||
|
|
8e12996dfe | ||
|
|
a3280893af | ||
|
|
9c3cb4fb55 | ||
|
|
a1db6aa553 |
51
README.md
51
README.md
@@ -19,53 +19,28 @@ The INTERACTION dataset contains a two folders which should be copied into a fol
|
|||||||
- the contents of `recorded_trackfiles` should be copied to `./InteractionSimulator/datasets/trackfiles`
|
- the contents of `recorded_trackfiles` should be copied to `./InteractionSimulator/datasets/trackfiles`
|
||||||
- the contents of `maps` should be copied to `./InteractionSimulator/datasets/maps`
|
- the contents of `maps` should be copied to `./InteractionSimulator/datasets/maps`
|
||||||
|
|
||||||
## Processing, saving, and loading expert demos
|
## Processing and saving expert demos
|
||||||
Once the repository has been set up, you can process and save expert track demonstrations with:
|
Once the repository has been set up, you need to generate two separate sets of expert demos for tracks 0-4. The first command generates true joint and individual states and actions necessary for evaluating, saving them in `expert_data/`. The second command generates trajectory rollouts according to individual agent observations, which is later used as expert data for the learning models.
|
||||||
```
|
```
|
||||||
python src/expert_data.py --loc [LOCNUM] --track [TRACKNUM]
|
python -m src.expert --locs='[DR_USA_Roundabout_FT]' --tracks='[0,1,2,3,4]'
|
||||||
```
|
python -m intersimple-expert-rollout-setobs2 --tracks='[0,1,2,3,4]'
|
||||||
You can (and should) process all tracks at once at location 0 with:
|
|
||||||
```
|
|
||||||
python src/expert_data.py --all-tracks
|
|
||||||
```
|
|
||||||
|
|
||||||
You can then train a default behavior cloning policy with the following. Be sure to check help for main.py for running options.
|
|
||||||
```
|
|
||||||
python src/main.py --train
|
|
||||||
```
|
|
||||||
You can run tensorboard by running the following and opening `localhost:6006` (or alternatively port-forwarding 6006 from the remote server)
|
|
||||||
```
|
|
||||||
tensorboard --logdir output/
|
|
||||||
```
|
|
||||||
You can then test the learned policy with the following, and see the animation file in `output/`:
|
|
||||||
```
|
|
||||||
python src/main.py --test
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
You can load the experts actions manually
|
## Tuning hyperparameters and training finalized models
|
||||||
```
|
To tune models, we use `ray[tune]` grid searches. You can run see the commands we used to train in the top half of `train_models.sh`, as well as the hyperparameters we search over in `bc-experiment.py`, `gail-experiment.py`, and `shail-experiment.py`. After training the models, configurations get saved in `best_configs/` (the best SHAIL confg gets copied to a HAIL config, with the appropriate environment parameters changed for ablation). However, upon manual inspection of the training runs, we note some better performance than the automatically-set configs at earlier epochs, so we adjust the `best_configs` manually.
|
||||||
from src import expert_data
|
|
||||||
observations, actions = expert_data.load_expert_data(loc = [LOCNUM], track = [TRACKNUM])
|
After the `best_configs/` are set, we rerun each configuration with multiple seeds. The commands to do so are in the bottom half of `train_models.sh`. This saves different learned policy files to `test_policies/`.
|
||||||
for (s, a) in zip (observations, actions):
|
|
||||||
# do some imitation learning
|
|
||||||
```
|
## Evaluating models
|
||||||
|
To evaluate the learned policies, we rerun each model in particular setting, evaluate all our metrics, and average over different trained model seeds. The commands to do so are in `evaluate_models.sh`.
|
||||||
|
|
||||||
|
|
||||||
## Package Structure
|
## Package Structure
|
||||||
```
|
```
|
||||||
InteractionImitation
|
InteractionImitation
|
||||||
|- demos
|
|- TODO
|
||||||
|- algorithms
|
|
||||||
|- BC
|
|
||||||
|- AdVIL
|
|
||||||
|- nets
|
|
||||||
|- Encoder
|
|
||||||
|- DeepSet
|
|
||||||
|- Decoder
|
|
||||||
|- policies
|
|
||||||
|- discriminators
|
|
||||||
|- demo_generators
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Type Definitions
|
## Type Definitions
|
||||||
|
|||||||
@@ -142,7 +142,7 @@ if __name__ == '__main__':
|
|||||||
import argparse
|
import argparse
|
||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
parser.add_argument('--train', choices=['A', 'B'])
|
parser.add_argument('--train', choices=['A', 'B'])
|
||||||
parser.add_argument('--epochs', type=int, default=1000)
|
parser.add_argument('--epochs', type=int, default=500)
|
||||||
parser.add_argument('--test', type=str, help='path to config file to run final training on')
|
parser.add_argument('--test', type=str, help='path to config file to run final training on')
|
||||||
parser.add_argument('--test_seeds', type=int, default=5)
|
parser.add_argument('--test_seeds', type=int, default=5)
|
||||||
parser.add_argument('--test_cpus', type=int, help='number of cpus available to split test seed training over')
|
parser.add_argument('--test_cpus', type=int, help='number of cpus available to split test seed training over')
|
||||||
@@ -162,10 +162,10 @@ if __name__ == '__main__':
|
|||||||
},
|
},
|
||||||
'policy': {
|
'policy': {
|
||||||
'learning_rate': 3e-4,
|
'learning_rate': 3e-4,
|
||||||
'learning_rate_decay': 1.0,
|
'learning_rate_decay': tune.grid_search([0.999, 1.0]),
|
||||||
'hidden_layer_size': tune.grid_search([20, 40]),
|
'hidden_layer_size': tune.grid_search([10, 20, 40]),
|
||||||
'n_hidden_layers': tune.grid_search([2, 3]),
|
'n_hidden_layers': tune.grid_search([2, 3]),
|
||||||
'activation':0,
|
'activation':tune.grid_search([0, 1]),
|
||||||
},
|
},
|
||||||
'train_epochs': args.epochs,
|
'train_epochs': args.epochs,
|
||||||
'seed': 0,
|
'seed': 0,
|
||||||
@@ -210,3 +210,5 @@ if __name__ == '__main__':
|
|||||||
check_dir = analysis._checkpoints[i]['logdir']
|
check_dir = analysis._checkpoints[i]['logdir']
|
||||||
shutil.copyfile(os.path.join(check_dir,'policy_final.pt'),
|
shutil.copyfile(os.path.join(check_dir,'policy_final.pt'),
|
||||||
os.path.join(savepath, f'policy_seed{s}.pt'))
|
os.path.join(savepath, f'policy_seed{s}.pt'))
|
||||||
|
shutil.copyfile(os.path.join(check_dir,'params.json'),
|
||||||
|
os.path.join(savepath, 'config.json')) # copy config automatically
|
||||||
|
|||||||
@@ -1,33 +0,0 @@
|
|||||||
{
|
|
||||||
"experiment": "A",
|
|
||||||
"trainenv": {
|
|
||||||
"stop_on_collision": false,
|
|
||||||
"safe_actions_collision_method": null,
|
|
||||||
"abort_unsafe_collision_method": null
|
|
||||||
},
|
|
||||||
"policy": {
|
|
||||||
"learning_rate": 0.0003,
|
|
||||||
"learning_rate_decay": 1.0,
|
|
||||||
"clip_ratio": 0.2,
|
|
||||||
"iterations_per_epoch": 100,
|
|
||||||
"hidden_layer_size": 10,
|
|
||||||
"n_hidden_layers": 3,
|
|
||||||
"activation": 0,
|
|
||||||
"option": 0
|
|
||||||
},
|
|
||||||
"value": {
|
|
||||||
"learning_rate": 0.001,
|
|
||||||
"iterations_per_epoch": 1000
|
|
||||||
},
|
|
||||||
"discriminator": {
|
|
||||||
"learning_rate": 0.001,
|
|
||||||
"weight_decay": 0.0001,
|
|
||||||
"iterations_per_epoch": 100,
|
|
||||||
"n_hidden_layers_element": 3,
|
|
||||||
"n_hidden_layers_global": 2,
|
|
||||||
"hidden_layer_size": 10,
|
|
||||||
"activation": 0
|
|
||||||
},
|
|
||||||
"train_epochs": 100,
|
|
||||||
"seed": 0
|
|
||||||
}
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
{
|
|
||||||
"experiment": "B",
|
|
||||||
"trainenv": {
|
|
||||||
"stop_on_collision": false,
|
|
||||||
"safe_actions_collision_method": null,
|
|
||||||
"abort_unsafe_collision_method": null
|
|
||||||
},
|
|
||||||
"policy": {
|
|
||||||
"learning_rate": 0.0003,
|
|
||||||
"learning_rate_decay": 1.0,
|
|
||||||
"clip_ratio": 0.2,
|
|
||||||
"iterations_per_epoch": 100,
|
|
||||||
"hidden_layer_size": 10,
|
|
||||||
"n_hidden_layers": 3,
|
|
||||||
"activation": 0,
|
|
||||||
"option": 0
|
|
||||||
},
|
|
||||||
"value": {
|
|
||||||
"learning_rate": 0.001,
|
|
||||||
"iterations_per_epoch": 1000
|
|
||||||
},
|
|
||||||
"discriminator": {
|
|
||||||
"learning_rate": 0.001,
|
|
||||||
"weight_decay": 0.0001,
|
|
||||||
"iterations_per_epoch": 100,
|
|
||||||
"n_hidden_layers_element": 3,
|
|
||||||
"n_hidden_layers_global": 2,
|
|
||||||
"hidden_layer_size": 10,
|
|
||||||
"activation": 0
|
|
||||||
},
|
|
||||||
"train_epochs": 100,
|
|
||||||
"seed": 0
|
|
||||||
}
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
{
|
|
||||||
"experiment": "B",
|
|
||||||
"trainenv": {
|
|
||||||
"stop_on_collision": false,
|
|
||||||
"safe_actions_collision_method": null,
|
|
||||||
"abort_unsafe_collision_method": null
|
|
||||||
},
|
|
||||||
"policy": {
|
|
||||||
"learning_rate": 0.0003,
|
|
||||||
"learning_rate_decay": 1.0,
|
|
||||||
"clip_ratio": 0.2,
|
|
||||||
"iterations_per_epoch": 100,
|
|
||||||
"hidden_layer_size": 40,
|
|
||||||
"n_hidden_layers": 3,
|
|
||||||
"activation": 0,
|
|
||||||
"option": 0
|
|
||||||
},
|
|
||||||
"value": {
|
|
||||||
"learning_rate": 0.001,
|
|
||||||
"iterations_per_epoch": 1000
|
|
||||||
},
|
|
||||||
"discriminator": {
|
|
||||||
"learning_rate": 0.001,
|
|
||||||
"weight_decay": 0.0001,
|
|
||||||
"iterations_per_epoch": 100,
|
|
||||||
"n_hidden_layers_element": 3,
|
|
||||||
"n_hidden_layers_global": 2,
|
|
||||||
"hidden_layer_size": 10,
|
|
||||||
"activation": 0
|
|
||||||
},
|
|
||||||
"train_epochs": 100,
|
|
||||||
"seed": 0
|
|
||||||
}
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
{
|
|
||||||
"experiment": "A",
|
|
||||||
"trainenv": {
|
|
||||||
"stop_on_collision": false,
|
|
||||||
"safe_actions_collision_method": null,
|
|
||||||
"abort_unsafe_collision_method": null
|
|
||||||
},
|
|
||||||
"policy": {
|
|
||||||
"learning_rate": 0.0003,
|
|
||||||
"learning_rate_decay": 1.0,
|
|
||||||
"clip_ratio": 0.2,
|
|
||||||
"iterations_per_epoch": 100,
|
|
||||||
"hidden_layer_size": 20,
|
|
||||||
"n_hidden_layers": 4,
|
|
||||||
"activation": 0,
|
|
||||||
"option": 0
|
|
||||||
},
|
|
||||||
"value": {
|
|
||||||
"learning_rate": 0.001,
|
|
||||||
"iterations_per_epoch": 1000
|
|
||||||
},
|
|
||||||
"discriminator": {
|
|
||||||
"learning_rate": 0.001,
|
|
||||||
"weight_decay": 0.0001,
|
|
||||||
"iterations_per_epoch": 100,
|
|
||||||
"n_hidden_layers_element": 3,
|
|
||||||
"n_hidden_layers_global": 2,
|
|
||||||
"hidden_layer_size": 10,
|
|
||||||
"activation": 0
|
|
||||||
},
|
|
||||||
"train_epochs": 100,
|
|
||||||
"seed": 0
|
|
||||||
}
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
{
|
|
||||||
"experiment": "A",
|
|
||||||
"trainenv": {
|
|
||||||
"stop_on_collision": false,
|
|
||||||
"safe_actions_collision_method": "circle",
|
|
||||||
"abort_unsafe_collision_method": "circle"
|
|
||||||
},
|
|
||||||
"policy": {
|
|
||||||
"learning_rate": 0.0003,
|
|
||||||
"learning_rate_decay": 1.0,
|
|
||||||
"clip_ratio": 0.2,
|
|
||||||
"iterations_per_epoch": 100,
|
|
||||||
"hidden_layer_size": 10,
|
|
||||||
"n_hidden_layers": 3,
|
|
||||||
"activation": 0,
|
|
||||||
"option": 0
|
|
||||||
},
|
|
||||||
"value": {
|
|
||||||
"learning_rate": 0.001,
|
|
||||||
"iterations_per_epoch": 1000
|
|
||||||
},
|
|
||||||
"discriminator": {
|
|
||||||
"learning_rate": 0.001,
|
|
||||||
"weight_decay": 0.0001,
|
|
||||||
"iterations_per_epoch": 100,
|
|
||||||
"n_hidden_layers_element": 3,
|
|
||||||
"n_hidden_layers_global": 2,
|
|
||||||
"hidden_layer_size": 10,
|
|
||||||
"activation": 0
|
|
||||||
},
|
|
||||||
"train_epochs": 100,
|
|
||||||
"seed": 0
|
|
||||||
}
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
{
|
|
||||||
"experiment": "B",
|
|
||||||
"trainenv": {
|
|
||||||
"stop_on_collision": false,
|
|
||||||
"safe_actions_collision_method": "circle",
|
|
||||||
"abort_unsafe_collision_method": "circle"
|
|
||||||
},
|
|
||||||
"policy": {
|
|
||||||
"learning_rate": 0.0003,
|
|
||||||
"learning_rate_decay": 1.0,
|
|
||||||
"clip_ratio": 0.2,
|
|
||||||
"iterations_per_epoch": 100,
|
|
||||||
"hidden_layer_size": 10,
|
|
||||||
"n_hidden_layers": 3,
|
|
||||||
"activation": 0,
|
|
||||||
"option": 0
|
|
||||||
},
|
|
||||||
"value": {
|
|
||||||
"learning_rate": 0.001,
|
|
||||||
"iterations_per_epoch": 1000
|
|
||||||
},
|
|
||||||
"discriminator": {
|
|
||||||
"learning_rate": 0.001,
|
|
||||||
"weight_decay": 0.0001,
|
|
||||||
"iterations_per_epoch": 100,
|
|
||||||
"n_hidden_layers_element": 3,
|
|
||||||
"n_hidden_layers_global": 2,
|
|
||||||
"hidden_layer_size": 10,
|
|
||||||
"activation": 0
|
|
||||||
},
|
|
||||||
"train_epochs": 100,
|
|
||||||
"seed": 0
|
|
||||||
}
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
{
|
|
||||||
"experiment": "B",
|
|
||||||
"trainenv": {
|
|
||||||
"stop_on_collision": false,
|
|
||||||
"safe_actions_collision_method": "circle",
|
|
||||||
"abort_unsafe_collision_method": "circle"
|
|
||||||
},
|
|
||||||
"policy": {
|
|
||||||
"learning_rate": 0.0003,
|
|
||||||
"learning_rate_decay": 1.0,
|
|
||||||
"clip_ratio": 0.2,
|
|
||||||
"iterations_per_epoch": 100,
|
|
||||||
"hidden_layer_size": 40,
|
|
||||||
"n_hidden_layers": 3,
|
|
||||||
"activation": 0,
|
|
||||||
"option": 0
|
|
||||||
},
|
|
||||||
"value": {
|
|
||||||
"learning_rate": 0.001,
|
|
||||||
"iterations_per_epoch": 1000
|
|
||||||
},
|
|
||||||
"discriminator": {
|
|
||||||
"learning_rate": 0.001,
|
|
||||||
"weight_decay": 0.0001,
|
|
||||||
"iterations_per_epoch": 100,
|
|
||||||
"n_hidden_layers_element": 3,
|
|
||||||
"n_hidden_layers_global": 2,
|
|
||||||
"hidden_layer_size": 10,
|
|
||||||
"activation": 0
|
|
||||||
},
|
|
||||||
"train_epochs": 100,
|
|
||||||
"seed": 0
|
|
||||||
}
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
{
|
|
||||||
"experiment": "A",
|
|
||||||
"trainenv": {
|
|
||||||
"stop_on_collision": false,
|
|
||||||
"safe_actions_collision_method": "circle",
|
|
||||||
"abort_unsafe_collision_method": "circle"
|
|
||||||
},
|
|
||||||
"policy": {
|
|
||||||
"learning_rate": 0.0003,
|
|
||||||
"learning_rate_decay": 1.0,
|
|
||||||
"clip_ratio": 0.2,
|
|
||||||
"iterations_per_epoch": 100,
|
|
||||||
"hidden_layer_size": 20,
|
|
||||||
"n_hidden_layers": 4,
|
|
||||||
"activation": 0,
|
|
||||||
"option": 0
|
|
||||||
},
|
|
||||||
"value": {
|
|
||||||
"learning_rate": 0.001,
|
|
||||||
"iterations_per_epoch": 1000
|
|
||||||
},
|
|
||||||
"discriminator": {
|
|
||||||
"learning_rate": 0.001,
|
|
||||||
"weight_decay": 0.0001,
|
|
||||||
"iterations_per_epoch": 100,
|
|
||||||
"n_hidden_layers_element": 3,
|
|
||||||
"n_hidden_layers_global": 2,
|
|
||||||
"hidden_layer_size": 10,
|
|
||||||
"activation": 0
|
|
||||||
},
|
|
||||||
"train_epochs": 100,
|
|
||||||
"seed": 0
|
|
||||||
}
|
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,42 +0,0 @@
|
|||||||
{
|
|
||||||
ego_encoder: {
|
|
||||||
input_dim: 5, // number of state vars
|
|
||||||
hidden_n: 0,
|
|
||||||
hidden_dim: 5,
|
|
||||||
output_dim: 5
|
|
||||||
},
|
|
||||||
deepsets: {
|
|
||||||
input_dim: 6, // number of relative state vars for others
|
|
||||||
phi: {
|
|
||||||
hidden_n: 2,
|
|
||||||
hidden_dim: 20,
|
|
||||||
},
|
|
||||||
latent_dim: 20,
|
|
||||||
rho: {
|
|
||||||
hidden_n: 2,
|
|
||||||
hidden_dim: 10,
|
|
||||||
},
|
|
||||||
output_dim: 10
|
|
||||||
},
|
|
||||||
path_encoder: {
|
|
||||||
input_dim: 40, // 2 * path length for (x,y) coordinates
|
|
||||||
hidden_n: 0,
|
|
||||||
hidden_dim: 20,
|
|
||||||
output_dim: 10,
|
|
||||||
},
|
|
||||||
head: {
|
|
||||||
input_dim: 0, // computed in policy constructor
|
|
||||||
hidden_n: 3,
|
|
||||||
hidden_dim: 50,
|
|
||||||
output_dim: 1, // number of outputs e.g. number of actions, or just one
|
|
||||||
final_activation: 'sigmoid',
|
|
||||||
},
|
|
||||||
optim: {
|
|
||||||
optimizer: 'adam',
|
|
||||||
lr: 1e-3,
|
|
||||||
weight_decay: 0.1,
|
|
||||||
},
|
|
||||||
train_epochs: 200,
|
|
||||||
train_batch_size: 32,
|
|
||||||
loss: 'huber',
|
|
||||||
}
|
|
||||||
@@ -1,85 +0,0 @@
|
|||||||
{
|
|
||||||
policy_net: {
|
|
||||||
ego_encoder: {
|
|
||||||
input_dim: 5, // number of state vars
|
|
||||||
hidden_n: 0,
|
|
||||||
hidden_dim: 5,
|
|
||||||
output_dim: 5
|
|
||||||
},
|
|
||||||
deepsets: {
|
|
||||||
input_dim: 6, // number of relative state vars for others
|
|
||||||
phi: {
|
|
||||||
hidden_n: 2,
|
|
||||||
hidden_dim: 20,
|
|
||||||
},
|
|
||||||
latent_dim: 20,
|
|
||||||
rho: {
|
|
||||||
hidden_n: 2,
|
|
||||||
hidden_dim: 10,
|
|
||||||
},
|
|
||||||
output_dim: 10
|
|
||||||
},
|
|
||||||
path_encoder: {
|
|
||||||
input_dim: 40, // 2 * path length for (x,y) coordinates
|
|
||||||
hidden_n: 0,
|
|
||||||
hidden_dim: 20,
|
|
||||||
output_dim: 10,
|
|
||||||
},
|
|
||||||
head: {
|
|
||||||
input_dim: 0, // computed in policy constructor
|
|
||||||
hidden_n: 3,
|
|
||||||
hidden_dim: 50,
|
|
||||||
output_dim: 1, // number of outputs e.g. number of actions, or just one
|
|
||||||
final_activation: 'sigmoid',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
value_net: {
|
|
||||||
ego_encoder: {
|
|
||||||
input_dim: 5, // number of state vars
|
|
||||||
hidden_n: 0,
|
|
||||||
hidden_dim: 5,
|
|
||||||
output_dim: 5
|
|
||||||
},
|
|
||||||
deepsets: {
|
|
||||||
input_dim: 6, // number of relative state vars for others
|
|
||||||
phi: {
|
|
||||||
hidden_n: 2,
|
|
||||||
hidden_dim: 20,
|
|
||||||
},
|
|
||||||
latent_dim: 20,
|
|
||||||
rho: {
|
|
||||||
hidden_n: 2,
|
|
||||||
hidden_dim: 10,
|
|
||||||
},
|
|
||||||
output_dim: 10
|
|
||||||
},
|
|
||||||
path_encoder: {
|
|
||||||
input_dim: 40, // 2 * path length for (x,y) coordinates
|
|
||||||
hidden_n: 0,
|
|
||||||
hidden_dim: 20,
|
|
||||||
output_dim: 10,
|
|
||||||
},
|
|
||||||
action_dim: 1, // number of actions
|
|
||||||
head: {
|
|
||||||
input_dim: 0, // computed in policy constructor
|
|
||||||
hidden_n: 3,
|
|
||||||
hidden_dim: 50,
|
|
||||||
output_dim: 1, // number of outputs e.g. number of actions, or just one
|
|
||||||
final_activation: 'id',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
policy_optim: {
|
|
||||||
optimizer: 'adam',
|
|
||||||
lr: 1e-3,
|
|
||||||
weight_decay: 0.1,
|
|
||||||
},
|
|
||||||
value_optim: {
|
|
||||||
optimizer: 'adam',
|
|
||||||
lr: 1e-3,
|
|
||||||
weight_decay: 0.1,
|
|
||||||
},
|
|
||||||
train_epochs: 200,
|
|
||||||
train_batch_size: 32,
|
|
||||||
discount: 0.95,
|
|
||||||
clip_grad_norm: 1.,
|
|
||||||
}
|
|
||||||
@@ -1,17 +1,23 @@
|
|||||||
import os
|
import os
|
||||||
from src.eval_main import eval_main
|
from src.eval_main import eval_main
|
||||||
from src.evaluation.utils import load_and_average
|
from src.evaluation.utils import load_and_average
|
||||||
|
import torch
|
||||||
|
import json
|
||||||
|
|
||||||
def main(method:str='expert', folder:str=None, locations=[(0,0)], skip_running=False):
|
activations = [torch.nn.Tanh, torch.nn.LeakyReLU]
|
||||||
|
|
||||||
|
def main(method:str='expert', folder:str=None, locations=[(0,0)], skip_running=False, save_videos:bool=False, videos_folder:str='videos', first_seed_only:bool=False):
|
||||||
|
|
||||||
|
exclude_keys_from_policy_kwargs = {'learning_rate', 'learning_rate_decay', 'clip_ratio', 'iterations_per_epoch', 'option'}
|
||||||
policy_kwargs = {}
|
policy_kwargs = {}
|
||||||
if method in ['expert', 'idm']:
|
|
||||||
|
if method in ['expert', 'expert_agent', 'idm']:
|
||||||
env, env_kwargs ='NRasterizedRouteIncrementingAgent', {}
|
env, env_kwargs ='NRasterizedRouteIncrementingAgent', {}
|
||||||
elif method in ['bc','gail']:
|
elif method in ['bc','gail']:
|
||||||
env='NormalizedContinuousEvalEnv'
|
env='NormalizedContinuousEvalEnv'
|
||||||
env_kwargs={'stop_on_collision':True, 'max_episode_steps':1000}
|
env_kwargs={'stop_on_collision':True, 'max_episode_steps':1000}
|
||||||
elif method in ['hail']:
|
elif method in ['hail']:
|
||||||
env = 'NormalizedOptionsEvalEnv'
|
env = 'NormalizedSafeOptionsEvalEnv'
|
||||||
env_kwargs={'stop_on_collision':True, 'max_episode_steps':1000, 'safe_actions_collision_method': None, 'abort_unsafe_collision_method': None}
|
env_kwargs={'stop_on_collision':True, 'max_episode_steps':1000, 'safe_actions_collision_method': None, 'abort_unsafe_collision_method': None}
|
||||||
elif method in ['shail']:
|
elif method in ['shail']:
|
||||||
env = 'NormalizedSafeOptionsEvalEnv'
|
env = 'NormalizedSafeOptionsEvalEnv'
|
||||||
@@ -23,7 +29,23 @@ def main(method:str='expert', folder:str=None, locations=[(0,0)], skip_running=F
|
|||||||
|
|
||||||
if folder is not None:
|
if folder is not None:
|
||||||
files = [os.path.join(folder, f) for f in os.listdir(folder) if os.path.isfile(os.path.join(folder, f))]
|
files = [os.path.join(folder, f) for f in os.listdir(folder) if os.path.isfile(os.path.join(folder, f))]
|
||||||
print('%i folders found in %s folder' %(len(files), folder))
|
files = [f for f in files if f.endswith('.pt')]
|
||||||
|
|
||||||
|
if first_seed_only:
|
||||||
|
files = files[:1]
|
||||||
|
|
||||||
|
with open(os.path.join(folder, 'config.json'), 'rb') as f:
|
||||||
|
config = json.load(f)
|
||||||
|
|
||||||
|
print('%i policy files found in %s folder' %(len(files), folder))
|
||||||
|
print('found policy config', config['policy'])
|
||||||
|
|
||||||
|
policy_config = {k: v for k, v in config['policy'].items() if k not in exclude_keys_from_policy_kwargs}
|
||||||
|
policy_config['activation'] = activations[policy_config['activation']]
|
||||||
|
print('final policy config', policy_config)
|
||||||
|
|
||||||
|
policy_kwargs.update(policy_config)
|
||||||
|
print('final policy kwargs', policy_kwargs)
|
||||||
|
|
||||||
if not skip_running:
|
if not skip_running:
|
||||||
for policy_file in files:
|
for policy_file in files:
|
||||||
@@ -33,7 +55,8 @@ def main(method:str='expert', folder:str=None, locations=[(0,0)], skip_running=F
|
|||||||
policy_file=policy_file,
|
policy_file=policy_file,
|
||||||
policy_kwargs=policy_kwargs,
|
policy_kwargs=policy_kwargs,
|
||||||
env=env,
|
env=env,
|
||||||
env_kwargs=env_kwargs)
|
env_kwargs=env_kwargs,
|
||||||
|
videos_folder=None if not save_videos else videos_folder)
|
||||||
outfolder = os.path.dirname(outbase)
|
outfolder = os.path.dirname(outbase)
|
||||||
else:
|
else:
|
||||||
locstr = 'loc_'+'_'.join([f'r{ro}t{tr}' for (ro,tr) in locations])
|
locstr = 'loc_'+'_'.join([f'r{ro}t{tr}' for (ro,tr) in locations])
|
||||||
@@ -60,7 +83,7 @@ def latex_print(am, light=False):
|
|||||||
print('success rate, distance travelled, RWSE_10, |DeltaV|, AccelJSD')
|
print('success rate, distance travelled, RWSE_10, |DeltaV|, AccelJSD')
|
||||||
if light:
|
if light:
|
||||||
if 'rwse_10s' in am.keys():
|
if 'rwse_10s' in am.keys():
|
||||||
print("%2.1f& %2.1f & %1.2f & %2.1f& "
|
print("%2.1f& %2.1f & %2.1f & %1.2f& "
|
||||||
"%0.3f \\\\" %( 100*am['success rate'][0], am['mean travel distance'][0], am['rwse_10s'][0],
|
"%0.3f \\\\" %( 100*am['success rate'][0], am['mean travel distance'][0], am['rwse_10s'][0],
|
||||||
am['average absolute average velocity'][0],am['acceleration distribution divergence'][0] ))
|
am['average absolute average velocity'][0],am['acceleration distribution divergence'][0] ))
|
||||||
return
|
return
|
||||||
@@ -71,7 +94,7 @@ def latex_print(am, light=False):
|
|||||||
return
|
return
|
||||||
|
|
||||||
print("%2.1f \\scriptstyle\\pm %2.1f & %2.1f \\scriptstyle\\pm %2.1f & "
|
print("%2.1f \\scriptstyle\\pm %2.1f & %2.1f \\scriptstyle\\pm %2.1f & "
|
||||||
"%1.2f \\scriptstyle\\pm %1.2f & %2.1f \\scriptstyle\\pm %1.1f & "
|
"%2.1f \\scriptstyle\\pm %1.1f & %1.2f \\scriptstyle\\pm %1.2f & "
|
||||||
"%0.3f \\scriptstyle\\pm %0.3f \\\\" %( 100*am['success rate'][0], 100*am['success rate'][1],
|
"%0.3f \\scriptstyle\\pm %0.3f \\\\" %( 100*am['success rate'][0], 100*am['success rate'][1],
|
||||||
am['mean travel distance'][0] , am['mean travel distance'][1] ,
|
am['mean travel distance'][0] , am['mean travel distance'][1] ,
|
||||||
am['rwse_10s'][0] , am['rwse_10s'][1] ,
|
am['rwse_10s'][0] , am['rwse_10s'][1] ,
|
||||||
|
|||||||
@@ -1,19 +1,18 @@
|
|||||||
# can add --skip_running if you've run the runs before on the saved policies
|
# can add --skip_running if you've already run the saved policies through the test environments and have appropriate
|
||||||
|
# metrics in the out folder. Doing so will generate average metrics quickly.
|
||||||
|
|
||||||
|
# Experiment A
|
||||||
python -m eval_experiments
|
python -m eval_experiments
|
||||||
python -m eval_experiments --locations='[(0,4)]'
|
|
||||||
python -m eval_experiments --method idm
|
python -m eval_experiments --method idm
|
||||||
python -m eval_experiments --method idm --locations='[(0,4)]'
|
|
||||||
python -m eval_experiments --method bc --folder='test_policies/bc/expA'
|
python -m eval_experiments --method bc --folder='test_policies/bc/expA'
|
||||||
python -m eval_experiments --method bc --folder='test_policies/bc/expB' --locations='[(0,4)]'
|
|
||||||
python -m eval_experiments --method gail --folder='test_policies/gail/expA'
|
python -m eval_experiments --method gail --folder='test_policies/gail/expA'
|
||||||
python -m eval_experiments --method gail --folder='test_policies/gail/expB' --locations='[(0,4)]'
|
|
||||||
python -m eval_experiments --method hail --folder='test_policies/hail/expA'
|
python -m eval_experiments --method hail --folder='test_policies/hail/expA'
|
||||||
python -m eval_experiments --method hail --folder='test_policies/hail/expB' --locations='[(0,4)]'
|
|
||||||
python -m eval_experiments --method shail --folder='test_policies/shail/expA'
|
python -m eval_experiments --method shail --folder='test_policies/shail/expA'
|
||||||
python -m eval_experiments --method shail --folder='test_policies/shail/expB' --locations='[(0,4)]'
|
|
||||||
|
|
||||||
python -m eval_experiments --method hail --folder='test_policies/hail-etienne/expA'
|
# Experiment B
|
||||||
python -m eval_experiments --method hail --folder='test_policies/hail-etienne/expB' --locations='[(0,4)]'
|
python -m eval_experiments --locations='[(0,4)]'
|
||||||
python -m eval_experiments --method shail --folder='test_policies/shail-etienne/expA'
|
python -m eval_experiments --method idm --locations='[(0,4)]' --skip_running
|
||||||
python -m eval_experiments --method shail --folder='test_policies/shail-etienne/expB' --locations='[(0,4)]'
|
python -m eval_experiments --method bc --folder='test_policies/bc/expB' --locations='[(0,4)]' --skip_running
|
||||||
|
python -m eval_experiments --method gail --folder='test_policies/gail/expB' --locations='[(0,4)]' --skip_running
|
||||||
|
python -m eval_experiments --method hail --folder='test_policies/hail/expB' --locations='[(0,4)]' --skip_running
|
||||||
|
python -m eval_experiments --method shail --folder='test_policies/shail/expB' --locations='[(0,4)]' --skip_running
|
||||||
@@ -1,203 +0,0 @@
|
|||||||
import json5
|
|
||||||
from functools import partial
|
|
||||||
import os
|
|
||||||
opj = os.path.join
|
|
||||||
|
|
||||||
# set up ray tune
|
|
||||||
import ray
|
|
||||||
from ray import tune
|
|
||||||
from ray.tune import Analysis, ExperimentAnalysis
|
|
||||||
from ray.tune.schedulers import ASHAScheduler
|
|
||||||
from hyperopt import hp
|
|
||||||
from ray.tune.suggest.hyperopt import HyperOptSearch
|
|
||||||
|
|
||||||
# get graphs
|
|
||||||
import intersim
|
|
||||||
from intersim.graphs import ConeVisibilityGraph
|
|
||||||
|
|
||||||
|
|
||||||
from src.main import basestr, main
|
|
||||||
|
|
||||||
def parse_args():
|
|
||||||
"""
|
|
||||||
Parse arguments to main
|
|
||||||
Returns:
|
|
||||||
kwargs: dictionary of arguments:
|
|
||||||
train (bool): whether to run train loop
|
|
||||||
test (bool): whether to run test loop
|
|
||||||
method (str): the method to try for imitation
|
|
||||||
loc (int): the location index of the roundabout
|
|
||||||
config (str): config path
|
|
||||||
seed (int): RNG seed
|
|
||||||
"""
|
|
||||||
import argparse
|
|
||||||
parser = argparse.ArgumentParser(description='Save Expert Trajectories')
|
|
||||||
parser.add_argument('--loc', default=0, type=int,
|
|
||||||
help='location (default 0)')
|
|
||||||
parser.add_argument("--train", help="train model",
|
|
||||||
action="store_true")
|
|
||||||
parser.add_argument("--ray", help="use ray tune to run multiple experiments",
|
|
||||||
action="store_true")
|
|
||||||
parser.add_argument("--test", help="test model",
|
|
||||||
action="store_true")
|
|
||||||
parser.add_argument("--method", help="modeling method",
|
|
||||||
choices=['bc', 'gail', 'advil', 'vd'], default='bc')
|
|
||||||
parser.add_argument("--config", help="config file path",
|
|
||||||
default=None, type=str)
|
|
||||||
parser.add_argument('--seed', default=0, type=int,
|
|
||||||
help='seed')
|
|
||||||
parser.add_argument('--nframes', default=500, type=int,
|
|
||||||
help='frames for test animation')
|
|
||||||
parser.add_argument('--nsamples', default=200, type=int,
|
|
||||||
help='number of ray samples')
|
|
||||||
parser.add_argument('--graph', action='store_true',
|
|
||||||
help='whether to mask the relative states based on a ConeVisibilityGraph')
|
|
||||||
parser.add_argument('-d', default='./expert_data', type=str,
|
|
||||||
help='data directory')
|
|
||||||
parser.add_argument('-o', default=None, type=str,
|
|
||||||
help='output directory')
|
|
||||||
args = parser.parse_args()
|
|
||||||
kwargs = {
|
|
||||||
'train':args.train,
|
|
||||||
'test':args.test,
|
|
||||||
'method':args.method,
|
|
||||||
'loc':args.loc,
|
|
||||||
'config_path':args.config,
|
|
||||||
'seed':args.seed,
|
|
||||||
'ray':args.ray,
|
|
||||||
'nframes':args.nframes,
|
|
||||||
'nsamples':args.nsamples,
|
|
||||||
'datadir':os.path.abspath(args.d),
|
|
||||||
'graph':None,
|
|
||||||
'outdir': opj('output',args.method,'loc%02i'%(args.loc)),
|
|
||||||
'train_tracks':[0,1,2],
|
|
||||||
'cv_tracks':[3],
|
|
||||||
'test_tracks':[4],
|
|
||||||
}
|
|
||||||
if args.o:
|
|
||||||
kwargs['outdir'] = args.o
|
|
||||||
if args.graph:
|
|
||||||
kwargs['graph'] = ConeVisibilityGraph(r=20, half_angle=120)
|
|
||||||
return kwargs
|
|
||||||
|
|
||||||
def get_full_config(ray_config:dict, method:str)->dict:
|
|
||||||
"""
|
|
||||||
Get full model configuration from ray config and method string
|
|
||||||
Args:
|
|
||||||
ray_config (dict): ray config
|
|
||||||
method (str): method to get full configuration for
|
|
||||||
"""
|
|
||||||
if method == 'bc':
|
|
||||||
from src.bc import bc_config
|
|
||||||
config = bc_config(ray_config)
|
|
||||||
elif method == 'vd':
|
|
||||||
from src.value_dice import vd_config
|
|
||||||
config = vd_config(ray_config)
|
|
||||||
else:
|
|
||||||
raise NotImplementedError
|
|
||||||
return config
|
|
||||||
|
|
||||||
def get_ray_config(method:str)->dict:
|
|
||||||
"""
|
|
||||||
Get configuration for ray based on method.
|
|
||||||
Args:
|
|
||||||
method (str): method to get configuration for
|
|
||||||
Returns:
|
|
||||||
ray_config (dict): configuration for ray
|
|
||||||
"""
|
|
||||||
if method == 'bc':
|
|
||||||
ray_config = {
|
|
||||||
"lr": tune.loguniform(1e-5, 1e-3),
|
|
||||||
"weight_decay": tune.choice([0, 0.1]),
|
|
||||||
"loss": tune.choice(['huber', 'mse']),
|
|
||||||
"train_batch_size": tune.choice([16,32,64]),
|
|
||||||
"deepsets_phi_hidden_n": tune.randint(1,5),
|
|
||||||
"deepsets_phi_hidden_dim": tune.lograndint(8,65),
|
|
||||||
"deepsets_latent_dim": tune.lograndint(8,129),
|
|
||||||
"deepsets_rho_hidden_n": tune.randint(0,3),
|
|
||||||
"deepsets_rho_hidden_dim": tune.lograndint(8,129),
|
|
||||||
"deepsets_output_dim": tune.lograndint(4,129),
|
|
||||||
"head_hidden_n": tune.randint(1,6),
|
|
||||||
"head_hidden_dim": tune.lograndint(16,257),
|
|
||||||
"head_final_activation": tune.choice(['sigmoid', None]),
|
|
||||||
}
|
|
||||||
elif method == 'vd':
|
|
||||||
ray_config = {
|
|
||||||
"policy_lr": tune.loguniform(1e-5, 1e-3),
|
|
||||||
"value_lr": tune.loguniform(1e-5, 1e-3),
|
|
||||||
"policy_weight_decay": tune.choice([0, 0.1]),
|
|
||||||
"value_weight_decay": tune.choice([0, 0.1]),
|
|
||||||
"train_batch_size": tune.choice([16,32,64]),
|
|
||||||
"deepsets_phi_hidden_n": tune.randint(1,5),
|
|
||||||
"deepsets_phi_hidden_dim": tune.lograndint(8,65),
|
|
||||||
"deepsets_latent_dim": tune.lograndint(8,129),
|
|
||||||
"deepsets_rho_hidden_n": tune.randint(0,3),
|
|
||||||
"deepsets_rho_hidden_dim": tune.lograndint(8,129),
|
|
||||||
"deepsets_output_dim": tune.lograndint(4,129),
|
|
||||||
"head_hidden_n": tune.randint(1,6),
|
|
||||||
"head_hidden_dim": tune.lograndint(16,257),
|
|
||||||
"head_final_activation": tune.choice(['sigmoid', None]),
|
|
||||||
"clip_grad_norm": tune.choice([.5, 1., 5., 10.]),
|
|
||||||
"discount": tune.choice([.95, .99])
|
|
||||||
}
|
|
||||||
else:
|
|
||||||
raise NotImplementedError
|
|
||||||
return ray_config
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
kwargs = parse_args()
|
|
||||||
|
|
||||||
# make prefix of output files
|
|
||||||
|
|
||||||
if kwargs['config_path']:
|
|
||||||
# load config
|
|
||||||
with open(kwargs['config_path'], 'r') as cfg:
|
|
||||||
config = json5.load(cfg)
|
|
||||||
if not os.path.isdir(kwargs['outdir']):
|
|
||||||
os.makedirs(kwargs['outdir'])
|
|
||||||
filestr = opj(kwargs['outdir'], basestr(**kwargs))
|
|
||||||
if kwargs['ray']:
|
|
||||||
filestr = kwargs['config_path'].replace('_config.json','')
|
|
||||||
main(config, filestr=filestr, **kwargs)
|
|
||||||
|
|
||||||
elif kwargs['ray'] and kwargs['train']:
|
|
||||||
|
|
||||||
ray.shutdown()
|
|
||||||
ray.init(log_to_driver=False)
|
|
||||||
|
|
||||||
def ray_train(config, datadir=None):
|
|
||||||
full_config = get_full_config(config, kwargs['method'])
|
|
||||||
main(full_config, filestr='exp', **kwargs)
|
|
||||||
|
|
||||||
ray_config = get_ray_config(kwargs['method'])
|
|
||||||
search = HyperOptSearch(ray_config, max_concurrent=8, metric='cv_loss',mode="min",)
|
|
||||||
custom_scheduler = ASHAScheduler(metric='cv_loss', mode="min", grace_period=15)
|
|
||||||
|
|
||||||
analysis = tune.run(
|
|
||||||
ray_train,
|
|
||||||
#config=ray_config,
|
|
||||||
search_alg=search,
|
|
||||||
scheduler=custom_scheduler,
|
|
||||||
local_dir=kwargs['outdir'],
|
|
||||||
#resources_per_trial={"cpu": 2},
|
|
||||||
time_budget_s=120*60,
|
|
||||||
num_samples=kwargs['nsamples'],
|
|
||||||
)
|
|
||||||
elif kwargs['ray'] and kwargs['test']:
|
|
||||||
analysis = Analysis(kwargs['outdir'], default_metric="cv_loss", default_mode="min")
|
|
||||||
config = analysis.get_best_config()
|
|
||||||
filepath = analysis.get_best_logdir()
|
|
||||||
filestr = opj(filepath, 'exp')
|
|
||||||
config_path = filestr+'_config.json'
|
|
||||||
with open(config_path, 'r') as cfg:
|
|
||||||
config = json5.load(cfg)
|
|
||||||
print("Best ray experiment:", filepath)
|
|
||||||
main(config, filestr=filestr, **kwargs)
|
|
||||||
else:
|
|
||||||
raise Exception('No valid config found')
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
|
|
||||||
python experiments/experiment.py --ray --train -d ./expert_data/base
|
|
||||||
python experiments/experiment.py --ray --test -d ./expert_data/base --nframes 1000
|
|
||||||
python experiments/experiment.py --ray --train -d ./expert_data/reg
|
|
||||||
python experiments/experiment.py --ray --test -d ./expert_data/reg --nframes 1000
|
|
||||||
python experiments/experiment.py --ray --train -d ./expert_data/reg_graph --graph
|
|
||||||
python experiments/experiment.py --ray --test -d ./expert_data/reg_graph --graph --nframes 1000
|
|
||||||
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
|
|
||||||
# python experiments/experiment.py --method vd --train --ray -d expert_data/reg -o output/vd/loc00/reg --nsamples 400
|
|
||||||
# python experiments/experiment.py --test --ray --method vd -d expert_data/normal -o output/vd/loc00/normal --nframes 1000
|
|
||||||
python experiments/experiment.py --train --method vd --config config/value_dice.json5
|
|
||||||
@@ -236,3 +236,5 @@ if __name__ == '__main__':
|
|||||||
check_dir = analysis._checkpoints[i]['logdir']
|
check_dir = analysis._checkpoints[i]['logdir']
|
||||||
shutil.copyfile(os.path.join(check_dir,'policy_final.pt'),
|
shutil.copyfile(os.path.join(check_dir,'policy_final.pt'),
|
||||||
os.path.join(savepath, f'policy_seed{s}.pt'))
|
os.path.join(savepath, f'policy_seed{s}.pt'))
|
||||||
|
shutil.copyfile(os.path.join(check_dir,'params.json'),
|
||||||
|
os.path.join(savepath, 'config.json')) # copy config automatically
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
#DEFAULT PARAMETERS:
|
|
||||||
# locs:list=None, (default to all locations)
|
|
||||||
# tracks:list=None, (default to all tracks)
|
|
||||||
# env_class:str='NRasterizedIncrementingAgent',
|
|
||||||
# env_args:dict={width:36,height:36,m_per_px:2},
|
|
||||||
# expert_class:str='NRasterizedRouteIncrementingAgent',
|
|
||||||
# expert_args:dict={mu:0.001}):
|
|
||||||
|
|
||||||
# python -m src.data.expert --locs='[DR_USA_Roundabout_FT]' --tracks='[0]'
|
|
||||||
python -m src.data.expert --locs='[DR_USA_Roundabout_FT]' --tracks='[0]'
|
|
||||||
20
generate_videos.sh
Executable file
20
generate_videos.sh
Executable file
@@ -0,0 +1,20 @@
|
|||||||
|
# can add --skip_running if you've already run the saved policies through the test environments and have appropriate
|
||||||
|
# metrics in the out folder. Doing so will generate average metrics quickly.
|
||||||
|
|
||||||
|
# Experiment A
|
||||||
|
python -m eval_experiments
|
||||||
|
python -m eval_experiments --method expert_agent --save_videos --first_seed_only
|
||||||
|
python -m eval_experiments --method idm --save_videos --first_seed_only
|
||||||
|
python -m eval_experiments --method bc --folder='test_policies/bc/expA' --save_videos --first_seed_only
|
||||||
|
python -m eval_experiments --method gail --folder='test_policies/gail/expA' --save_videos --first_seed_only
|
||||||
|
python -m eval_experiments --method hail --folder='test_policies/hail/expA' --save_videos --first_seed_only
|
||||||
|
python -m eval_experiments --method shail --folder='test_policies/shail/expA' --save_videos --first_seed_only
|
||||||
|
|
||||||
|
# Experiment B
|
||||||
|
python -m eval_experiments --locations='[(0,4)]'
|
||||||
|
python -m eval_experiments --method expert_agent --locations='[(0,4)]' --save_videos --first_seed_only
|
||||||
|
python -m eval_experiments --method idm --locations='[(0,4)]' --save_videos --first_seed_only
|
||||||
|
python -m eval_experiments --method bc --folder='test_policies/bc/expB' --locations='[(0,4)]' --save_videos --first_seed_only
|
||||||
|
python -m eval_experiments --method gail --folder='test_policies/gail/expB' --locations='[(0,4)]' --save_videos --first_seed_only
|
||||||
|
python -m eval_experiments --method hail --folder='test_policies/hail/expB' --locations='[(0,4)]' --save_videos --first_seed_only
|
||||||
|
python -m eval_experiments --method shail --folder='test_policies/shail/expB' --locations='[(0,4)]' --save_videos --first_seed_only
|
||||||
Binary file not shown.
65
intersimple-expert-rollout-setobs2.py
Normal file
65
intersimple-expert-rollout-setobs2.py
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
import torch
|
||||||
|
import functools
|
||||||
|
from src.core.sampling import rollout_sb3
|
||||||
|
from intersim.envs import IntersimpleLidarFlatIncrementingAgent
|
||||||
|
from intersim.envs.intersimple import speed_reward
|
||||||
|
from intersim.expert import NormalizedIntersimpleExpert
|
||||||
|
from src.util.wrappers import CollisionPenaltyWrapper, Setobs
|
||||||
|
import numpy as np
|
||||||
|
from gym.wrappers import TransformObservation
|
||||||
|
|
||||||
|
obs_min = np.array([
|
||||||
|
[-1000, -1000, 0, -np.pi, -1e-1, 0.],
|
||||||
|
[0, -np.pi, -20, -20, -np.pi, -1e-1],
|
||||||
|
[0, -np.pi, -20, -20, -np.pi, -1e-1],
|
||||||
|
[0, -np.pi, -20, -20, -np.pi, -1e-1],
|
||||||
|
[0, -np.pi, -20, -20, -np.pi, -1e-1],
|
||||||
|
[0, -np.pi, -20, -20, -np.pi, -1e-1],
|
||||||
|
]).reshape(-1)
|
||||||
|
|
||||||
|
obs_max = np.array([
|
||||||
|
[1000, 1000, 20, np.pi, 1e-1, 0.],
|
||||||
|
[50, np.pi, 20, 20, np.pi, 1e-1],
|
||||||
|
[50, np.pi, 20, 20, np.pi, 1e-1],
|
||||||
|
[50, np.pi, 20, 20, np.pi, 1e-1],
|
||||||
|
[50, np.pi, 20, 20, np.pi, 1e-1],
|
||||||
|
[50, np.pi, 20, 20, np.pi, 1e-1],
|
||||||
|
]).reshape(-1)
|
||||||
|
|
||||||
|
def main(track:int, loc:int=0):
|
||||||
|
env = IntersimpleLidarFlatIncrementingAgent(
|
||||||
|
loc=loc,
|
||||||
|
track=track,
|
||||||
|
n_rays=5,
|
||||||
|
reward=functools.partial(
|
||||||
|
speed_reward,
|
||||||
|
collision_penalty=0
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
policy = NormalizedIntersimpleExpert(env, mu=0.001)
|
||||||
|
|
||||||
|
env = Setobs(TransformObservation(
|
||||||
|
CollisionPenaltyWrapper(
|
||||||
|
env,
|
||||||
|
collision_distance=6, collision_penalty=100
|
||||||
|
), lambda obs: (obs - obs_min) / (obs_max - obs_min + 1e-10)
|
||||||
|
))
|
||||||
|
print(env.nv, 'vehicles')
|
||||||
|
expert_data = rollout_sb3(env, policy, n_episodes=150, max_steps_per_episode=200)
|
||||||
|
|
||||||
|
states, actions, rewards, dones = expert_data
|
||||||
|
print(f'Expert mean episode length {(~dones).sum() / states.shape[0]}')
|
||||||
|
print(f'Expert mean reward per episode {rewards[~dones].sum() / states.shape[0]}')
|
||||||
|
print(f'Observation mean', states[~dones].mean(0))
|
||||||
|
print(f'Observation std', states[~dones].std(0))
|
||||||
|
|
||||||
|
torch.save(expert_data, f'intersimple-expert-data-setobs2-loc{loc}-track{track}.pt')
|
||||||
|
|
||||||
|
def loop(tracks:list=[0]):
|
||||||
|
for track in tracks:
|
||||||
|
main(track)
|
||||||
|
|
||||||
|
if __name__=='__main__':
|
||||||
|
import fire
|
||||||
|
fire.Fire(loop)
|
||||||
BIN
out/hail/expA/loc_r0t0/policy_seed1_tseed0_comparison.pkl
Normal file
BIN
out/hail/expA/loc_r0t0/policy_seed1_tseed0_comparison.pkl
Normal file
Binary file not shown.
BIN
out/hail/expA/loc_r0t0/policy_seed1_tseed0_summary.pkl
Normal file
BIN
out/hail/expA/loc_r0t0/policy_seed1_tseed0_summary.pkl
Normal file
Binary file not shown.
BIN
out/hail/expA/loc_r0t0/policy_seed2_tseed0_comparison.pkl
Normal file
BIN
out/hail/expA/loc_r0t0/policy_seed2_tseed0_comparison.pkl
Normal file
Binary file not shown.
BIN
out/hail/expA/loc_r0t0/policy_seed2_tseed0_summary.pkl
Normal file
BIN
out/hail/expA/loc_r0t0/policy_seed2_tseed0_summary.pkl
Normal file
Binary file not shown.
BIN
out/hail/expA/loc_r0t0/policy_seed3_tseed0_comparison.pkl
Normal file
BIN
out/hail/expA/loc_r0t0/policy_seed3_tseed0_comparison.pkl
Normal file
Binary file not shown.
BIN
out/hail/expA/loc_r0t0/policy_seed3_tseed0_summary.pkl
Normal file
BIN
out/hail/expA/loc_r0t0/policy_seed3_tseed0_summary.pkl
Normal file
Binary file not shown.
BIN
out/hail/expA/loc_r0t0/policy_seed4_tseed0_comparison.pkl
Normal file
BIN
out/hail/expA/loc_r0t0/policy_seed4_tseed0_comparison.pkl
Normal file
Binary file not shown.
BIN
out/hail/expA/loc_r0t0/policy_seed4_tseed0_summary.pkl
Normal file
BIN
out/hail/expA/loc_r0t0/policy_seed4_tseed0_summary.pkl
Normal file
Binary file not shown.
BIN
out/hail/expA/loc_r0t0/policy_seed5_tseed0_comparison.pkl
Normal file
BIN
out/hail/expA/loc_r0t0/policy_seed5_tseed0_comparison.pkl
Normal file
Binary file not shown.
BIN
out/hail/expA/loc_r0t0/policy_seed5_tseed0_summary.pkl
Normal file
BIN
out/hail/expA/loc_r0t0/policy_seed5_tseed0_summary.pkl
Normal file
Binary file not shown.
BIN
out/hail/expB/loc_r0t4/policy_seed1_tseed0_comparison.pkl
Normal file
BIN
out/hail/expB/loc_r0t4/policy_seed1_tseed0_comparison.pkl
Normal file
Binary file not shown.
BIN
out/hail/expB/loc_r0t4/policy_seed1_tseed0_summary.pkl
Normal file
BIN
out/hail/expB/loc_r0t4/policy_seed1_tseed0_summary.pkl
Normal file
Binary file not shown.
BIN
out/hail/expB/loc_r0t4/policy_seed2_tseed0_comparison.pkl
Normal file
BIN
out/hail/expB/loc_r0t4/policy_seed2_tseed0_comparison.pkl
Normal file
Binary file not shown.
BIN
out/hail/expB/loc_r0t4/policy_seed2_tseed0_summary.pkl
Normal file
BIN
out/hail/expB/loc_r0t4/policy_seed2_tseed0_summary.pkl
Normal file
Binary file not shown.
BIN
out/hail/expB/loc_r0t4/policy_seed3_tseed0_comparison.pkl
Normal file
BIN
out/hail/expB/loc_r0t4/policy_seed3_tseed0_comparison.pkl
Normal file
Binary file not shown.
BIN
out/hail/expB/loc_r0t4/policy_seed3_tseed0_summary.pkl
Normal file
BIN
out/hail/expB/loc_r0t4/policy_seed3_tseed0_summary.pkl
Normal file
Binary file not shown.
BIN
out/hail/expB/loc_r0t4/policy_seed4_tseed0_comparison.pkl
Normal file
BIN
out/hail/expB/loc_r0t4/policy_seed4_tseed0_comparison.pkl
Normal file
Binary file not shown.
BIN
out/hail/expB/loc_r0t4/policy_seed4_tseed0_summary.pkl
Normal file
BIN
out/hail/expB/loc_r0t4/policy_seed4_tseed0_summary.pkl
Normal file
Binary file not shown.
BIN
out/hail/expB/loc_r0t4/policy_seed5_tseed0_comparison.pkl
Normal file
BIN
out/hail/expB/loc_r0t4/policy_seed5_tseed0_comparison.pkl
Normal file
Binary file not shown.
BIN
out/hail/expB/loc_r0t4/policy_seed5_tseed0_summary.pkl
Normal file
BIN
out/hail/expB/loc_r0t4/policy_seed5_tseed0_summary.pkl
Normal file
Binary file not shown.
@@ -1,22 +0,0 @@
|
|||||||
python -m render_options --model_name='gail_options_image_mid_wcollision' --env='NRasterizedRoute' --options=True --width=36 --height=36 --m_per_px=2 --agent=50 --stop_on_collision=False
|
|
||||||
|
|
||||||
import torch, os
|
|
||||||
from src.data import load_experts
|
|
||||||
folder = 'expert_data/DR_USA_Roundabout_FT/track0000'
|
|
||||||
single_agent = os.path.join(folder, 'expert.pkl')
|
|
||||||
multi_agent = os.path.join(folder,'joint_expert_states.pt')
|
|
||||||
multi_agent_actions = os.path.join(folder,'joint_expert_actions.pt')
|
|
||||||
demonstrations = load_experts([single_agent], flatten=False)
|
|
||||||
demonstrations[0].__dict__.keys()
|
|
||||||
len(demonstrations[0].obs)
|
|
||||||
single_agent_lengths = [len(demonstration.obs) for demonstration in demonstrations]
|
|
||||||
states = torch.load(multi_agent)
|
|
||||||
actions = torch.load(multi_agent_actions)
|
|
||||||
multi_agent_lengths = [sum(~torch.isnan(states[:,i,0])).item() for i in range(states.shape[1])]
|
|
||||||
|
|
||||||
single_agent_actions = [demonstration.acts for demonstration in demonstrations]
|
|
||||||
multi_agent_actions = [actions[~torch.isnan(actions[:,i,0])] for i in range(actions.shape[1])]
|
|
||||||
|
|
||||||
import pickle
|
|
||||||
with open(single_agent, "rb") as f:
|
|
||||||
new_trajectories = pickle.load(f)
|
|
||||||
@@ -1,145 +0,0 @@
|
|||||||
from intersim.envs.intersimple import Intersimple
|
|
||||||
from stable_baselines3.common.policies import BasePolicy
|
|
||||||
import gym
|
|
||||||
import intersim.envs.intersimple
|
|
||||||
import imitation.data.rollout as rollout
|
|
||||||
from stable_baselines3.common.vec_env.dummy_vec_env import DummyVecEnv
|
|
||||||
from imitation.data.wrappers import RolloutInfoWrapper
|
|
||||||
|
|
||||||
class IntersimExpert(BasePolicy):
|
|
||||||
|
|
||||||
def __init__(self, intersim_env, mu=0, *args, **kwargs):
|
|
||||||
super().__init__(
|
|
||||||
observation_space=gym.spaces.Space(),
|
|
||||||
action_space=gym.spaces.Space(),
|
|
||||||
*args, **kwargs
|
|
||||||
)
|
|
||||||
self._intersim = intersim_env
|
|
||||||
self._mu = mu
|
|
||||||
|
|
||||||
def forward(self, *args, **kwargs):
|
|
||||||
raise NotImplementedError()
|
|
||||||
|
|
||||||
def _predict(self, *args, **kwargs):
|
|
||||||
raise NotImplementedError()
|
|
||||||
|
|
||||||
def _action(self):
|
|
||||||
target_t = min(self._intersim._ind + 1, len(self._intersim._svt.simstate) - 1)
|
|
||||||
target_state = self._intersim._svt.simstate[target_t]
|
|
||||||
return self._intersim.target_state(target_state, mu=self._mu)
|
|
||||||
|
|
||||||
def predict(self, *args, **kwargs):
|
|
||||||
return self._action(), None
|
|
||||||
|
|
||||||
class IntersimpleExpert(BasePolicy):
|
|
||||||
|
|
||||||
def __init__(self, intersimple_env, mu=0, *args, **kwargs):
|
|
||||||
super().__init__(
|
|
||||||
observation_space=intersimple_env.observation_space,
|
|
||||||
action_space=intersimple_env.action_space,
|
|
||||||
*args, **kwargs
|
|
||||||
)
|
|
||||||
self._intersimple = intersimple_env
|
|
||||||
self._intersim_expert = IntersimExpert(intersimple_env._env, mu=mu)
|
|
||||||
|
|
||||||
def forward(self, *args, **kwargs):
|
|
||||||
raise NotImplementedError()
|
|
||||||
|
|
||||||
def _predict(self, *args, **kwargs):
|
|
||||||
raise NotImplementedError()
|
|
||||||
|
|
||||||
def _action(self):
|
|
||||||
return self._intersim_expert._action()[self._intersimple._agent]
|
|
||||||
|
|
||||||
def predict(self, *args, **kwargs):
|
|
||||||
return self._action(), None
|
|
||||||
|
|
||||||
class NormalizedIntersimpleExpert(IntersimpleExpert):
|
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
super().__init__(*args, **kwargs)
|
|
||||||
|
|
||||||
def predict(self, *args, **kwargs):
|
|
||||||
action, _ = super().predict(*args, **kwargs)
|
|
||||||
return self._intersimple._normalize(action), None
|
|
||||||
|
|
||||||
class DummyVecEnvPolicy(BasePolicy):
|
|
||||||
|
|
||||||
def __init__(self, experts):
|
|
||||||
self._experts = [e() for e in experts]
|
|
||||||
|
|
||||||
def forward(self, *args, **kwargs):
|
|
||||||
raise NotImplementedError()
|
|
||||||
|
|
||||||
def _predict(self, *args, **kwargs):
|
|
||||||
raise NotImplementedError()
|
|
||||||
|
|
||||||
def predict(self, *args, **kwargs):
|
|
||||||
predictions = [e.predict() for e in self._experts]
|
|
||||||
actions = [p[0] for p in predictions]
|
|
||||||
states = [p[1] for p in predictions]
|
|
||||||
return actions, states
|
|
||||||
|
|
||||||
def forward(self, *args, **kwargs):
|
|
||||||
raise NotImplementedError()
|
|
||||||
|
|
||||||
def _predict(self, *args, **kwargs):
|
|
||||||
raise NotImplementedError()
|
|
||||||
|
|
||||||
def save_video(env, expert):
|
|
||||||
env.reset()
|
|
||||||
env.render()
|
|
||||||
done = False
|
|
||||||
while not done:
|
|
||||||
actions, _ = expert.predict()
|
|
||||||
_, _, done, _ = env.step(actions)
|
|
||||||
env.render()
|
|
||||||
env.close()
|
|
||||||
|
|
||||||
def demonstrations(expert='NormalizedIntersimpleExpert', env='NRasterizedIncrementingAgent', path=None, min_timesteps=None, min_episodes=None, video=False, env_args={}, policy_args={}):
|
|
||||||
"""Rollout and save expert demos.
|
|
||||||
|
|
||||||
Usage:
|
|
||||||
python -m intersimple.expert <flags>
|
|
||||||
Args:
|
|
||||||
expert (class): class of expert
|
|
||||||
env (class): class of env intersim.envs.intersimple
|
|
||||||
path (str): path to store output
|
|
||||||
min_timesteps (int): min number of timesteps for call to rollout.rollout_and_save
|
|
||||||
min_episodes (int): min number of episodes for call to rollout.rollout_and_save
|
|
||||||
video (bool): whether to save a video of the expert until a single environment instantiation stops
|
|
||||||
env_args (dict): dictionary of kwargs when instantiating environment class
|
|
||||||
policy_args (dict): dictionary of kwargs when instantiating Expert policy
|
|
||||||
"""
|
|
||||||
|
|
||||||
Env = intersim.envs.intersimple.__dict__[env]
|
|
||||||
Expert = globals()[expert]
|
|
||||||
|
|
||||||
env = Env(**env_args)
|
|
||||||
info_env = RolloutInfoWrapper(env) # getting rollout info (dictionary) from environment
|
|
||||||
venv = DummyVecEnv([lambda: info_env]) # making a DummyVecEnv with a list of a function that when called returns the rollout info
|
|
||||||
|
|
||||||
policy = Expert(env, **policy_args) # instantiate an expert policy from specified class with instantiated environment and policy kwargs
|
|
||||||
venv_policy = DummyVecEnvPolicy([lambda: policy]) # make a DummyVecEnvPolicy with a list of a function that when called returns the Expert policy
|
|
||||||
|
|
||||||
if min_timesteps is None and min_episodes is None:
|
|
||||||
min_episodes = env.nv # one episode per vehicle being controlled in environment (hopefully an incrementing agent environment)
|
|
||||||
|
|
||||||
if video:
|
|
||||||
save_video(env, policy)
|
|
||||||
|
|
||||||
path = path or (policy.__class__.__name__ + '_' + env.__class__.__name__ + '.pkl')
|
|
||||||
suntil = rollout.make_sample_until(
|
|
||||||
min_timesteps=min_timesteps,
|
|
||||||
min_episodes=min_episodes,
|
|
||||||
)
|
|
||||||
rollout.rollout_and_save(
|
|
||||||
path=path,
|
|
||||||
policy=venv_policy,
|
|
||||||
venv=venv,
|
|
||||||
sample_until=suntil
|
|
||||||
)
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
import fire
|
|
||||||
fire.Fire(demonstrations)
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
#python -m expert --env=IntersimpleReward --min_timesteps=200 --env_args='{agent:51}' --path='NormalizedIntersimpleExpert_IntersimpleRewardAgent51.pkl'
|
|
||||||
#python -m expert --env=IntersimpleReward --min_timesteps=200 --env_args='{agent:51}' --policy_args='{mu:0.005}' --path='NormalizedIntersimpleExpert_IntersimpleRewardAgent51Mu.005.pkl'
|
|
||||||
#python -m expert --env=IntersimpleReward --min_timesteps=200 --env_args='{agent:51}' --policy_args='{mu:0.001}' --path='NormalizedIntersimpleExpert_IntersimpleRewardAgent51Mu.001.pkl'
|
|
||||||
#python -m expert --env=NRasterized --min_timesteps=200 --env_args='{agent:51,width:36,height:36,m_per_px:2}' --policy_args='{mu:0.001}' --path='NormalizedIntersimpleExpertMu.001_NRasterizedAgent51w36h36mppx2.pkl'
|
|
||||||
# python -m expert --env=NRasterizedRandomAgent --min_timesteps=10000 --env_args='{width:36,height:36,m_per_px:2}' --policy_args='{mu:0.001}' --path='NormalizedIntersimpleExpertMu.001N10000_NRasterizedRandomAgentw36h36mppx2.pkl'
|
|
||||||
#python -m expert --env=NRasterized --min_timesteps=200 --env_args='{agent:51,width:36,height:36,m_per_px:2}' --policy_args='{mu:0.001}' --path='NormalizedIntersimpleExpertMu.001_NRasterizedAgent51w36h36mppx2.pkl'
|
|
||||||
#python -m expert --env=NRasterized --min_timesteps=3000 --video --env_args='{width:36,height:36,m_per_px:2}' --policy_args='{mu:0.001}' --path='NormalizedIntersimpleExpertMu.001_NRasterizedRandomAgentw36h36mppx2.pkl'
|
|
||||||
#python -m expert --env=NRasterizedIncrementingAgent --env_args='{width:36,height:36,m_per_px:2}' --policy_args='{mu:0.001}' --path='NormalizedIntersimpleExpertMu.001_NRasterizedIncrementingAgentw36h36mppx2.pkl'
|
|
||||||
python -m process_all_experts --env_args='{width:36,height:36,m_per_px:2}' --policy_args='{mu:0.001}'
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
import pickle
|
|
||||||
import imitation.data.rollout as rollout
|
|
||||||
from tqdm import tqdm
|
|
||||||
|
|
||||||
def load_experts(expert_files=[]):
|
|
||||||
"""
|
|
||||||
Load expert trajectories from files and combine their transitions into a single RB
|
|
||||||
|
|
||||||
Args:
|
|
||||||
expert_files (list): list of expert file strings
|
|
||||||
Returns:
|
|
||||||
transitions (list): list of combined expert episode transitions
|
|
||||||
"""
|
|
||||||
transitions = []
|
|
||||||
for file in tqdm(expert_files):
|
|
||||||
with open(file, "rb") as f:
|
|
||||||
trajectories = pickle.load(f)
|
|
||||||
transitions = transitions + rollout.flatten_trajectories(trajectories)
|
|
||||||
return transitions
|
|
||||||
|
|
||||||
if __name__=='__main__':
|
|
||||||
import fire
|
|
||||||
fire.Fire(load_experts)
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
import tqdm
|
|
||||||
import expert
|
|
||||||
import copy
|
|
||||||
import os
|
|
||||||
import intersim
|
|
||||||
from tqdm import tqdm
|
|
||||||
|
|
||||||
def process_all_experts(filename='expert.pkl',env_args={}, policy_args={}):
|
|
||||||
"""
|
|
||||||
Process all experts in the Interaction Dataset
|
|
||||||
For now, using NormalizedIntersimpleExpert with NRasterizedIncrementingAgent environment
|
|
||||||
|
|
||||||
Args:
|
|
||||||
filename (str): name for track file
|
|
||||||
env_args (dict): default environment kwargs
|
|
||||||
policy_args (dict): default policy kwargs
|
|
||||||
"""
|
|
||||||
I, J = len(intersim.LOCATIONS), intersim.MAX_TRACKS
|
|
||||||
pbar = tqdm(total=I*J)
|
|
||||||
for loc in range(I):
|
|
||||||
for track in range(J):
|
|
||||||
|
|
||||||
it_env_args = copy.deepcopy(env_args)
|
|
||||||
it_env_args.update({
|
|
||||||
'loc':loc,
|
|
||||||
'track':track,
|
|
||||||
})
|
|
||||||
out_folder = os.path.join(intersim.LOCATIONS[loc], 'track%04i'%(track))
|
|
||||||
if not os.path.isdir(out_folder):
|
|
||||||
os.makedirs(out_folder)
|
|
||||||
it_path = os.path.join(out_folder,filename)
|
|
||||||
|
|
||||||
expert.demonstrations(
|
|
||||||
expert='NormalizedIntersimpleExpert',
|
|
||||||
env='NRasterizedIncrementingAgent',
|
|
||||||
path=it_path,
|
|
||||||
env_args=it_env_args,
|
|
||||||
policy_args=policy_args,
|
|
||||||
)
|
|
||||||
pbar.update(1)
|
|
||||||
pbar.close()
|
|
||||||
|
|
||||||
|
|
||||||
if __name__=='__main__':
|
|
||||||
import fire
|
|
||||||
fire.Fire(process_all_experts)
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,101 +0,0 @@
|
|||||||
import torch
|
|
||||||
|
|
||||||
# imitation.rewards.discrim_nets.DiscrimNetGAIL is composed of self.discriminator (nn.Module),
|
|
||||||
# which gets called with inputs (state, action) when needed.
|
|
||||||
|
|
||||||
class CnnDiscriminator(torch.nn.Module):
|
|
||||||
"""ConvNet similar to stable_baselines3.common.policies.ActorCriticCnnPolicy."""
|
|
||||||
|
|
||||||
def __init__(self, env):
|
|
||||||
super().__init__()
|
|
||||||
|
|
||||||
obs_channels, _, _ = env.observation_space.shape
|
|
||||||
(action_size,) = env.action_space.shape
|
|
||||||
in_channels = obs_channels + action_size
|
|
||||||
|
|
||||||
self.cnn = torch.nn.Sequential(
|
|
||||||
torch.nn.Conv2d(in_channels, 32, kernel_size=(8, 8), stride=(4, 4)), # 5+1 -> 32
|
|
||||||
torch.nn.ReLU(),
|
|
||||||
torch.nn.Conv2d(32, 64, kernel_size=(4, 4), stride=(2, 2)), # 32 -> 64
|
|
||||||
torch.nn.ReLU(),
|
|
||||||
torch.nn.Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1)), # 64 -> 64
|
|
||||||
torch.nn.ReLU(),
|
|
||||||
torch.nn.Flatten(start_dim=1, end_dim=-1),
|
|
||||||
torch.nn.LazyLinear(512), # 28224 -> 512
|
|
||||||
torch.nn.ReLU(),
|
|
||||||
torch.nn.LazyLinear(1), # 512 -> 1
|
|
||||||
)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _concatenate(state, action):
|
|
||||||
b, _, h, w = state.shape
|
|
||||||
_, a = action.shape
|
|
||||||
act = action.unsqueeze(-1).unsqueeze(-1).expand((b, a, h, w))
|
|
||||||
sa = torch.cat((state, act), -3)
|
|
||||||
return sa
|
|
||||||
|
|
||||||
def forward(self, state, action):
|
|
||||||
sa = self._concatenate(state, action)
|
|
||||||
assert sa.ndim == 4
|
|
||||||
return self.cnn(sa).squeeze(1)
|
|
||||||
|
|
||||||
class CnnDiscriminatorFlatAction(torch.nn.Module):
|
|
||||||
"""ConvNet similar to stable_baselines3.common.policies.ActorCriticCnnPolicy."""
|
|
||||||
|
|
||||||
def __init__(self, env):
|
|
||||||
super().__init__()
|
|
||||||
|
|
||||||
obs_channels, _, _ = env.observation_space.shape
|
|
||||||
(action_size,) = env.action_space.shape
|
|
||||||
in_channels = obs_channels
|
|
||||||
|
|
||||||
self.cnn = torch.nn.Sequential(
|
|
||||||
torch.nn.Conv2d(in_channels, 32, kernel_size=(8, 8), stride=(4, 4)), # in_channels -> 32
|
|
||||||
torch.nn.ReLU(),
|
|
||||||
torch.nn.Conv2d(32, 64, kernel_size=(4, 4), stride=(2, 2)), # 32 -> 64
|
|
||||||
torch.nn.ReLU(),
|
|
||||||
torch.nn.Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1)), # 64 -> 64
|
|
||||||
torch.nn.ReLU(),
|
|
||||||
torch.nn.Flatten(start_dim=1, end_dim=-1),
|
|
||||||
torch.nn.LazyLinear(128), # 28224 -> 128
|
|
||||||
)
|
|
||||||
self.decoder = torch.nn.Sequential(
|
|
||||||
torch.nn.LazyLinear(64), #128 + 2 -> 64
|
|
||||||
torch.nn.ReLU(),
|
|
||||||
torch.nn.LazyLinear(64), #64 -> 64
|
|
||||||
torch.nn.ReLU(),
|
|
||||||
torch.nn.LazyLinear(1) #64 -> 1
|
|
||||||
)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _concatenate(state, action):
|
|
||||||
b, s= state.shape
|
|
||||||
b, a = action.shape
|
|
||||||
sa = torch.cat((state, action), -1)
|
|
||||||
return sa
|
|
||||||
|
|
||||||
def forward(self, state, action):
|
|
||||||
s = self.cnn(state.float())
|
|
||||||
sa = self._concatenate(s, action)
|
|
||||||
assert sa.ndim == 2
|
|
||||||
return self.decoder(sa).squeeze(1)
|
|
||||||
|
|
||||||
class MlpDiscriminator(torch.nn.Module):
|
|
||||||
"""MLP similar to stable_baselines3.common.policies.ActorCriticPolicy."""
|
|
||||||
|
|
||||||
def __init__(self, env=None):
|
|
||||||
super().__init__()
|
|
||||||
self.flatten = torch.nn.Flatten(start_dim=1, end_dim=-1)
|
|
||||||
self.mlp = torch.nn.Sequential(
|
|
||||||
torch.nn.LazyLinear(64), # 42 -> 64
|
|
||||||
torch.nn.Tanh(),
|
|
||||||
torch.nn.LazyLinear(64), # 64 -> 64
|
|
||||||
torch.nn.Tanh(),
|
|
||||||
torch.nn.LazyLinear(1), # 64 -> 1
|
|
||||||
)
|
|
||||||
|
|
||||||
def forward(self, state, action):
|
|
||||||
flat = self.flatten(state)
|
|
||||||
sa = torch.cat((action, flat), -1)
|
|
||||||
assert sa.ndim == 2
|
|
||||||
return self.mlp(sa).squeeze(1)
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
from intersim.envs.intersimple import NRasterized
|
|
||||||
from discriminator import CnnDiscriminator
|
|
||||||
import torch
|
|
||||||
|
|
||||||
def test_image_concatenation():
|
|
||||||
env = NRasterized()
|
|
||||||
disc = CnnDiscriminator(env)
|
|
||||||
s = torch.tensor(env.reset()).unsqueeze(0)
|
|
||||||
a = torch.tensor([[0.5]])
|
|
||||||
sa = disc._concatenate(s, a)
|
|
||||||
|
|
||||||
assert s.shape == (1, 5, 200, 200)
|
|
||||||
assert a.shape == (1, 1)
|
|
||||||
assert sa.shape == (1, 6, 200, 200)
|
|
||||||
assert torch.allclose(sa[:, :5], 1.0 * s)
|
|
||||||
assert (sa[:, 5] == a.unsqueeze(-1)).all()
|
|
||||||
|
|
||||||
def test_image_concatenation3():
|
|
||||||
env = NRasterized()
|
|
||||||
disc = CnnDiscriminator(env)
|
|
||||||
|
|
||||||
s1 = env.reset()
|
|
||||||
a1 = 0.15
|
|
||||||
s2, _, _, _ = env.step(0.9)
|
|
||||||
a2 = 0.25
|
|
||||||
s3, _, _, _ = env.step(-0.9)
|
|
||||||
a3 = 0.35
|
|
||||||
|
|
||||||
s = torch.stack([
|
|
||||||
torch.tensor(s1),
|
|
||||||
torch.tensor(s2),
|
|
||||||
torch.tensor(s3)
|
|
||||||
], axis=0)
|
|
||||||
a = torch.tensor([
|
|
||||||
[a1],
|
|
||||||
[a2],
|
|
||||||
[a3],
|
|
||||||
])
|
|
||||||
sa = disc._concatenate(s, a)
|
|
||||||
|
|
||||||
assert s.shape == (3, 5, 200, 200)
|
|
||||||
assert a.shape == (3, 1)
|
|
||||||
assert sa.shape == (3, 6, 200, 200)
|
|
||||||
assert torch.allclose(sa[:, :5], 1.0 * s)
|
|
||||||
assert (sa[:, 5] == a.unsqueeze(-1)).all()
|
|
||||||
@@ -1,70 +0,0 @@
|
|||||||
# %%
|
|
||||||
import pathlib
|
|
||||||
import pickle
|
|
||||||
import tempfile
|
|
||||||
|
|
||||||
import stable_baselines3 as sb3
|
|
||||||
from stable_baselines3.common.env_util import make_vec_env
|
|
||||||
|
|
||||||
from imitation.algorithms import adversarial, bc
|
|
||||||
from imitation.data import rollout
|
|
||||||
from imitation.util import logger
|
|
||||||
|
|
||||||
from intersim.envs.intersimple import NRasterized
|
|
||||||
|
|
||||||
from gail.discriminator import CnnDiscriminatorFlatAction
|
|
||||||
|
|
||||||
model_name = 'gail_image_multiagent_nocollision'
|
|
||||||
|
|
||||||
# %%
|
|
||||||
# Load pickled test demonstrations.
|
|
||||||
with open("data/NormalizedIntersimpleExpertMu.001_NRasterizedRandomAgentw36h36mppx2.pkl", "rb") as f:
|
|
||||||
# This is a list of `imitation.data.types.Trajectory`, where
|
|
||||||
# every instance contains observations and actions for a single expert
|
|
||||||
# demonstration.
|
|
||||||
trajectories = pickle.load(f)
|
|
||||||
|
|
||||||
# %%
|
|
||||||
# Convert List[types.Trajectory] to an instance of `imitation.data.types.Transitions`.
|
|
||||||
# This is a more general dataclass containing unordered
|
|
||||||
# (observation, actions, next_observation) transitions.
|
|
||||||
transitions = rollout.flatten_trajectories(trajectories)
|
|
||||||
|
|
||||||
venv = make_vec_env(NRasterized, n_envs=2, env_kwargs={'stop_on_collision':False, 'width': 36, 'height': 36, 'm_per_px': 2})
|
|
||||||
|
|
||||||
tempdir = tempfile.TemporaryDirectory(prefix="quickstart")
|
|
||||||
tempdir_path = pathlib.Path(tempdir.name)
|
|
||||||
print(f"All Tensorboards and logging are being written inside {tempdir_path}/.")
|
|
||||||
|
|
||||||
# Train GAIL on expert data.
|
|
||||||
# GAIL, and AIRL also accept as `expert_data` any Pytorch-style DataLoader that
|
|
||||||
# iterates over dictionaries containing observations, actions, and next_observations.
|
|
||||||
logger.configure(tempdir_path / "GAIL/")
|
|
||||||
gail_trainer = adversarial.GAIL(
|
|
||||||
venv,
|
|
||||||
expert_data=transitions,
|
|
||||||
expert_batch_size=32,
|
|
||||||
#n_disc_updates_per_round=2048,
|
|
||||||
discrim_kwargs={'discrim_net': CnnDiscriminatorFlatAction(venv)},
|
|
||||||
gen_algo=sb3.PPO("CnnPolicy", venv, verbose=1, n_steps=1024),
|
|
||||||
allow_variable_horizon=True,
|
|
||||||
)
|
|
||||||
gail_trainer.train(total_timesteps=100000)
|
|
||||||
gail_trainer.gen_algo.save(model_name)
|
|
||||||
|
|
||||||
#del gail_trainer
|
|
||||||
|
|
||||||
# %%
|
|
||||||
model = sb3.PPO.load(model_name)
|
|
||||||
|
|
||||||
env = NRasterized(stop_on_collision=False, width=36, height=36, m_per_px=2)
|
|
||||||
|
|
||||||
obs = env.reset()
|
|
||||||
while True:
|
|
||||||
action, _states = model.predict(obs)
|
|
||||||
obs, rewards, done, info = env.step(action)
|
|
||||||
env.render(mode='post')
|
|
||||||
if done:
|
|
||||||
break
|
|
||||||
|
|
||||||
env.close(filestr='render/'+model_name)
|
|
||||||
@@ -1,70 +0,0 @@
|
|||||||
# %%
|
|
||||||
import pathlib
|
|
||||||
import pickle
|
|
||||||
import tempfile
|
|
||||||
|
|
||||||
import stable_baselines3 as sb3
|
|
||||||
from stable_baselines3.common.env_util import make_vec_env
|
|
||||||
|
|
||||||
from imitation.algorithms import adversarial, bc
|
|
||||||
from imitation.data import rollout
|
|
||||||
from imitation.util import logger
|
|
||||||
|
|
||||||
from intersim.envs.intersimple import NRasterized
|
|
||||||
|
|
||||||
from gail.discriminator import CnnDiscriminator
|
|
||||||
|
|
||||||
model_name = 'gail_image_singleagent_nocollision'
|
|
||||||
|
|
||||||
# %%
|
|
||||||
# Load pickled test demonstrations.
|
|
||||||
with open("data/NormalizedIntersimpleExpertMu.001_NRasterizedAgent51w36h36mppx2.pkl", "rb") as f:
|
|
||||||
# This is a list of `imitation.data.types.Trajectory`, where
|
|
||||||
# every instance contains observations and actions for a single expert
|
|
||||||
# demonstration.
|
|
||||||
trajectories = pickle.load(f)
|
|
||||||
|
|
||||||
# %%
|
|
||||||
# Convert List[types.Trajectory] to an instance of `imitation.data.types.Transitions`.
|
|
||||||
# This is a more general dataclass containing unordered
|
|
||||||
# (observation, actions, next_observation) transitions.
|
|
||||||
transitions = rollout.flatten_trajectories(trajectories)
|
|
||||||
|
|
||||||
venv = make_vec_env(NRasterized, n_envs=2, env_kwargs={'agent':51, 'stop_on_collision':False, 'width': 36, 'height': 36, 'm_per_px': 2})
|
|
||||||
|
|
||||||
tempdir = tempfile.TemporaryDirectory(prefix="quickstart")
|
|
||||||
tempdir_path = pathlib.Path(tempdir.name)
|
|
||||||
print(f"All Tensorboards and logging are being written inside {tempdir_path}/.")
|
|
||||||
|
|
||||||
# Train GAIL on expert data.
|
|
||||||
# GAIL, and AIRL also accept as `expert_data` any Pytorch-style DataLoader that
|
|
||||||
# iterates over dictionaries containing observations, actions, and next_observations.
|
|
||||||
logger.configure(tempdir_path / "GAIL/")
|
|
||||||
gail_trainer = adversarial.GAIL(
|
|
||||||
venv,
|
|
||||||
expert_data=transitions,
|
|
||||||
expert_batch_size=32,
|
|
||||||
#n_disc_updates_per_round=2048,
|
|
||||||
discrim_kwargs={'discrim_net': CnnDiscriminator(venv)},
|
|
||||||
gen_algo=sb3.PPO("CnnPolicy", venv, verbose=1, n_steps=1024),
|
|
||||||
allow_variable_horizon=True,
|
|
||||||
)
|
|
||||||
gail_trainer.train(total_timesteps=100000)
|
|
||||||
gail_trainer.gen_algo.save(model_name)
|
|
||||||
|
|
||||||
#del gail_trainer
|
|
||||||
|
|
||||||
# %%
|
|
||||||
model = sb3.PPO.load(model_name)
|
|
||||||
|
|
||||||
env = NRasterized(agent=51, width=36, height=36, m_per_px=2, stop_on_collision=False)
|
|
||||||
|
|
||||||
obs = env.reset()
|
|
||||||
while True:
|
|
||||||
action, _states = model.predict(obs)
|
|
||||||
obs, rewards, done, info = env.step(action)
|
|
||||||
env.render(mode='post')
|
|
||||||
if done:
|
|
||||||
break
|
|
||||||
|
|
||||||
env.close(filestr='render/'+model_name)
|
|
||||||
@@ -1,172 +0,0 @@
|
|||||||
# %%
|
|
||||||
import sys
|
|
||||||
sys.path.append('../../../')
|
|
||||||
from src.discriminator import CnnDiscriminator, CnnDiscriminatorFlatAction
|
|
||||||
from src.policies import OptionsCnnPolicy
|
|
||||||
from src.util import render_env
|
|
||||||
from src.data import load_experts
|
|
||||||
from src.gail.options import OptionsEnv, LLOptions, HLOptions, RenderOptions
|
|
||||||
from src.gail.train import train_discriminator, train_generator
|
|
||||||
|
|
||||||
from imitation.algorithms import adversarial
|
|
||||||
from imitation.util import logger
|
|
||||||
import imitation.data.rollout as rollout
|
|
||||||
|
|
||||||
import stable_baselines3
|
|
||||||
from stable_baselines3.common.env_util import make_vec_env
|
|
||||||
|
|
||||||
import torch
|
|
||||||
import torch.utils.data
|
|
||||||
import numpy as np
|
|
||||||
import itertools
|
|
||||||
import gym
|
|
||||||
import pickle
|
|
||||||
import tempfile
|
|
||||||
import pathlib
|
|
||||||
from tqdm import tqdm
|
|
||||||
|
|
||||||
from intersim.envs.intersimple import NRasterized, NRasterizedRoute, NRasterizedRandomAgent, NRasterizedIncrementingAgent, NRasterizedRouteRandomAgent
|
|
||||||
|
|
||||||
ALL_OPTIONS = [(v,t) for v in [0,2,4,6,8] for t in [5, 10]] # option 0 is safe fallback
|
|
||||||
|
|
||||||
def flatten_transitions(transitions):
|
|
||||||
return {
|
|
||||||
'obs': np.stack(list(t['obs'] for t in transitions), axis=0),
|
|
||||||
'next_obs': np.stack(list(t['next_obs'] for t in transitions), axis=0),
|
|
||||||
'acts': np.stack(list(t['acts'] for t in transitions), axis=0),
|
|
||||||
'dones': np.stack(list(t['dones'] for t in transitions), axis=0),
|
|
||||||
}
|
|
||||||
|
|
||||||
def train(expert_data, env_class=NRasterizedRouteRandomAgent, env_settings={},
|
|
||||||
epochs=10, discrim_batch_size=32, generator_steps=2048, discount=0.99):
|
|
||||||
"""
|
|
||||||
Args:
|
|
||||||
expert_data: list of transitions
|
|
||||||
env_class: environment class
|
|
||||||
env_settings: environment settings
|
|
||||||
epochs: number of epochs to train for
|
|
||||||
discrim_batch_size: discriminator batch size
|
|
||||||
generator_steps: number of steps taken in generator
|
|
||||||
discount: discount factor
|
|
||||||
Returns:
|
|
||||||
generator (stable_baselines3.PPO): options policy
|
|
||||||
"""
|
|
||||||
env = env_class(**env_settings)
|
|
||||||
env.discount = discount
|
|
||||||
|
|
||||||
tempdir = tempfile.TemporaryDirectory(prefix="quickstart")
|
|
||||||
tempdir_path = pathlib.Path(tempdir.name)
|
|
||||||
logger.configure(tempdir_path / "GAIL/")
|
|
||||||
print(f"All Tensorboards and logging are being written inside {tempdir_path}/.")
|
|
||||||
|
|
||||||
venv = make_vec_env(env_class, n_envs=1, env_kwargs=env_settings)
|
|
||||||
discriminator = adversarial.GAIL(
|
|
||||||
expert_data=expert_data,
|
|
||||||
expert_batch_size=discrim_batch_size,
|
|
||||||
discrim_kwargs={'discrim_net': CnnDiscriminatorFlatAction(venv)},
|
|
||||||
#discrim_kwargs={'discrim_net': CnnDiscriminator(venv)},
|
|
||||||
venv=venv, # unused
|
|
||||||
gen_algo=stable_baselines3.PPO("CnnPolicy", venv), # unused
|
|
||||||
)
|
|
||||||
|
|
||||||
generator = stable_baselines3.PPO(
|
|
||||||
OptionsCnnPolicy,
|
|
||||||
OptionsEnv(env, options=ALL_OPTIONS),
|
|
||||||
verbose=1,
|
|
||||||
n_steps=generator_steps,
|
|
||||||
)
|
|
||||||
|
|
||||||
# PPO.train requires logger as set up in
|
|
||||||
# PPO._setup_learn (called by PPO.learn)
|
|
||||||
generator._logger = stable_baselines3.common.utils.configure_logger(
|
|
||||||
generator.verbose,
|
|
||||||
generator.tensorboard_log,
|
|
||||||
)
|
|
||||||
|
|
||||||
for _ in tqdm(range(epochs)):
|
|
||||||
train_discriminator(LLOptions(env, options=ALL_OPTIONS), generator, discriminator, num_samples=discrim_batch_size)
|
|
||||||
train_generator(HLOptions(env, options=ALL_OPTIONS), generator, discriminator, num_samples=generator_steps)
|
|
||||||
|
|
||||||
return generator
|
|
||||||
|
|
||||||
# %%
|
|
||||||
if __name__ == '__main__':
|
|
||||||
# %%
|
|
||||||
model_name = 'gail_options_image_mid_wcollision'
|
|
||||||
env_class = NRasterizedRouteRandomAgent
|
|
||||||
env_settings = {'width': 36, 'height': 36, 'm_per_px': 2, 'stop_on_collision': False}
|
|
||||||
|
|
||||||
#env_class = NRasterized
|
|
||||||
#env_settings = {'agent': 51, 'width': 36, 'height': 36, 'm_per_px': 2}
|
|
||||||
files = ['../../../expert_data/DR_USA_Roundabout_FT/track%04i/expert.pkl'%(i) for i in range(5)]
|
|
||||||
transitions=load_experts(files)
|
|
||||||
|
|
||||||
generator = train(
|
|
||||||
transitions,
|
|
||||||
env_class=env_class,
|
|
||||||
env_settings=env_settings,
|
|
||||||
epochs=2,
|
|
||||||
discrim_batch_size=256,
|
|
||||||
generator_steps=10,#256,
|
|
||||||
discount=0.99
|
|
||||||
)
|
|
||||||
|
|
||||||
generator.save(model_name)
|
|
||||||
|
|
||||||
# Render
|
|
||||||
render_settings = {'width': 36, 'height': 36, 'm_per_px': 2, 'agent':51, 'stop_on_collision': False}
|
|
||||||
render_env(model_name=model_name, env='NRasterizedRoute', options=True, options_list=ALL_OPTIONS,
|
|
||||||
**render_settings)
|
|
||||||
|
|
||||||
|
|
||||||
# %% Tests
|
|
||||||
|
|
||||||
def test_ll_expert_data():
|
|
||||||
with open("data/NormalizedIntersimpleExpertMu.001_NRasterizedAgent51w36h36mppx2.pkl", "rb") as f:
|
|
||||||
expert_trajectories = pickle.load(f)
|
|
||||||
expert_transitions = rollout.flatten_trajectories(expert_trajectories)
|
|
||||||
|
|
||||||
env = LLOptions(NRasterized(agent=51, width=36, height=36, m_per_px=2))
|
|
||||||
|
|
||||||
gen_transitions = list(itertools.islice(env.sample_ll(
|
|
||||||
policy=stable_baselines3.PPO(
|
|
||||||
OptionsCnnPolicy,
|
|
||||||
OptionsEnv(env),
|
|
||||||
verbose=1,
|
|
||||||
)
|
|
||||||
), 10))
|
|
||||||
gen_transitions = flatten_transitions(gen_transitions)
|
|
||||||
|
|
||||||
assert expert_transitions[:10].obs.shape == gen_transitions['obs'].shape
|
|
||||||
assert expert_transitions[:10].next_obs.shape == gen_transitions['next_obs'].shape
|
|
||||||
assert expert_transitions[:10].acts.shape == gen_transitions['acts'].shape
|
|
||||||
assert expert_transitions[:10].dones.shape == gen_transitions['dones'].shape
|
|
||||||
|
|
||||||
def test_ll_states():
|
|
||||||
env = NRasterized()
|
|
||||||
policy = stable_baselines3.PPO(
|
|
||||||
OptionsCnnPolicy,
|
|
||||||
OptionsEnv(env),
|
|
||||||
verbose=1,
|
|
||||||
)
|
|
||||||
llenv = LLOptions(env)
|
|
||||||
transitions = list(itertools.islice(llenv.sample_ll(policy=policy), 100))
|
|
||||||
|
|
||||||
env2 = NRasterized()
|
|
||||||
s2 = env2.reset()
|
|
||||||
for i, t in enumerate(transitions):
|
|
||||||
assert i == 0 or np.array_equal(t['obs'], transitions[i-1]['next_obs'])
|
|
||||||
assert np.array_equal(t['obs'], s2)
|
|
||||||
assert t['acts'].shape == (1,)
|
|
||||||
|
|
||||||
nexts2, _, done2, _ = env2.step(t['acts'])
|
|
||||||
assert np.array_equal(t['next_obs'], nexts2)
|
|
||||||
assert np.array_equal(t['dones'], done2)
|
|
||||||
|
|
||||||
if done2:
|
|
||||||
break
|
|
||||||
|
|
||||||
s2 = nexts2
|
|
||||||
|
|
||||||
def test_hl_transitions():
|
|
||||||
pass
|
|
||||||
@@ -1,559 +0,0 @@
|
|||||||
# %%
|
|
||||||
from gail.discriminator import CnnDiscriminator, CnnDiscriminatorFlatAction
|
|
||||||
from imitation.algorithms import adversarial
|
|
||||||
import stable_baselines3
|
|
||||||
import torch.utils.data
|
|
||||||
import numpy as np
|
|
||||||
from intersim.envs.intersimple import NRasterized, NRasterizedRandomAgent
|
|
||||||
import itertools
|
|
||||||
from torch.distributions import Categorical
|
|
||||||
import gym
|
|
||||||
import torch
|
|
||||||
import pickle
|
|
||||||
import imitation.data.rollout as rollout
|
|
||||||
import tempfile
|
|
||||||
import pathlib
|
|
||||||
from imitation.util import logger
|
|
||||||
from stable_baselines3.common.env_util import make_vec_env
|
|
||||||
from tqdm import tqdm
|
|
||||||
|
|
||||||
import logging
|
|
||||||
logging.basicConfig(level=logging.DEBUG)
|
|
||||||
|
|
||||||
ALL_OPTIONS = [(v,t) for v in [0,2,4,6,8] for t in [5, 10, 20]] # option 0 is safe fallback
|
|
||||||
|
|
||||||
class OptionsCnnPolicy(stable_baselines3.common.policies.ActorCriticCnnPolicy):
|
|
||||||
"""
|
|
||||||
Class for high-level options policy (generator)
|
|
||||||
"""
|
|
||||||
def __init__(self, observation_space, *args, **kwargs):
|
|
||||||
super().__init__(observation_space['obs'], *args, **kwargs)
|
|
||||||
|
|
||||||
def _prior_distribution(self, s):
|
|
||||||
"""
|
|
||||||
Return prior distribution over high-level options (before masking)
|
|
||||||
Args:
|
|
||||||
s (torch.tensor): observation
|
|
||||||
Returns:
|
|
||||||
values (torch.tensor): values from critic
|
|
||||||
dist (torch.distributions): prior distribution over actions
|
|
||||||
"""
|
|
||||||
latent_pi, latent_vf, latent_sde = self._get_latent(s)
|
|
||||||
distribution = self._get_action_dist_from_latent(latent_pi, latent_sde)
|
|
||||||
values = self.value_net(latent_vf)
|
|
||||||
return values, distribution.distribution
|
|
||||||
|
|
||||||
def predict(self, obs):
|
|
||||||
"""
|
|
||||||
Will mask invalid states before making action selections
|
|
||||||
Args:
|
|
||||||
obs: dict with keys:
|
|
||||||
obs (torch.tensor): (B,o) true observations
|
|
||||||
mask (torch.tensor): (B,m) mask over valid actions
|
|
||||||
Returns:
|
|
||||||
ch (torch.tensor): (B,a) sampled actions
|
|
||||||
values (torch.tensor): (B,) predicted value at observation
|
|
||||||
log_probs (torch.tensor): (B,) log probabilities of selected actions
|
|
||||||
"""
|
|
||||||
s, m = obs['obs'], obs['mask']
|
|
||||||
values, prior = self._prior_distribution(s)
|
|
||||||
posterior = Categorical(prior.probs * m)
|
|
||||||
ch = posterior.sample()
|
|
||||||
return ch, values, posterior.log_prob(ch)
|
|
||||||
|
|
||||||
def evaluate_actions(self, obs, ch):
|
|
||||||
"""
|
|
||||||
Evaluate particular actions
|
|
||||||
Args:
|
|
||||||
obs: dict with keys:
|
|
||||||
obs (torch.tensor): (B,o) true observations
|
|
||||||
mask (torch.tensor): (B,m) masks over valid actions
|
|
||||||
ch (torch.tensor): (B,a) selected actions
|
|
||||||
Returns:
|
|
||||||
values (torch.tensor): (B,) predicted value at observation
|
|
||||||
log_probs (torch.tensor): (B,) log probabilities of selected actions
|
|
||||||
ent (torch.tensor): (B,) entropy of each distribution over actions
|
|
||||||
"""
|
|
||||||
s, m = obs['obs'], obs['mask']
|
|
||||||
values, prior = self._prior_distribution(s)
|
|
||||||
posterior = Categorical(prior.probs * m)
|
|
||||||
return values, posterior.log_prob(ch), posterior.entropy() # additional values used by PPO.train
|
|
||||||
|
|
||||||
class OptionsEnv(gym.Wrapper):
|
|
||||||
"""
|
|
||||||
Wrap an intersimple environment with an options generator
|
|
||||||
"""
|
|
||||||
def __init__(self, env, *args, **kwargs):
|
|
||||||
"""
|
|
||||||
Initialize wrapped environment and set high-level action and observation spaces
|
|
||||||
"""
|
|
||||||
super().__init__(env, *args, **kwargs)
|
|
||||||
num_hl_options = len(ALL_OPTIONS)
|
|
||||||
self.action_space = gym.spaces.Discrete(num_hl_options)
|
|
||||||
self.observation_space = gym.spaces.Dict({
|
|
||||||
'obs': env.observation_space,
|
|
||||||
'mask': gym.spaces.Box(low=0, high=1, shape=(num_hl_options,)),
|
|
||||||
})
|
|
||||||
|
|
||||||
def _after_choice(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def _after_step(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def _transitions(self):
|
|
||||||
raise NotImplementedError('Use `LLOptions` or `HLOptions` for sampling.')
|
|
||||||
|
|
||||||
def sample(self, generator):
|
|
||||||
"""
|
|
||||||
yield transitions using a generator
|
|
||||||
Args:
|
|
||||||
generator (sb3.PPO)
|
|
||||||
Yields:
|
|
||||||
|
|
||||||
"""
|
|
||||||
self.done = True
|
|
||||||
while True:
|
|
||||||
self.episode_start = False
|
|
||||||
|
|
||||||
if self.done:
|
|
||||||
# reset environment
|
|
||||||
self.s = self.env.reset()
|
|
||||||
self.m = available_actions(self.env)
|
|
||||||
self.done = False
|
|
||||||
self.episode_start = True
|
|
||||||
|
|
||||||
# set the action, the value of the start state, and the logprob of the action
|
|
||||||
# according to the current environment state and mask
|
|
||||||
self.ch, self.value, self.log_prob = generator.policy.predict({
|
|
||||||
'obs': torch.tensor(self.s).unsqueeze(0).to(generator.policy.device),
|
|
||||||
'mask': torch.tensor(self.m).unsqueeze(0).to(generator.policy.device),
|
|
||||||
})
|
|
||||||
|
|
||||||
# store a float list of actions to take given the option selected in the environment
|
|
||||||
self.plan = list(map(float, generate_plan(self.env, self.ch)))
|
|
||||||
|
|
||||||
# run whatever _after_choice might dictate in a child class
|
|
||||||
self._after_choice()
|
|
||||||
|
|
||||||
# some checks
|
|
||||||
assert not self.done
|
|
||||||
assert self.plan
|
|
||||||
assert feasible(self.env, self.plan, self.ch)
|
|
||||||
|
|
||||||
# execute the option so long as the episode isn't complete and the plan is still feasible
|
|
||||||
while not self.done and self.plan and feasible(self.env, self.plan, self.ch):
|
|
||||||
|
|
||||||
# pop first action
|
|
||||||
self.a, self.plan = self.plan[0], self.plan[1:]
|
|
||||||
|
|
||||||
# normalize action ??
|
|
||||||
self.a = self.env._normalize(self.a)
|
|
||||||
|
|
||||||
# step through environment
|
|
||||||
self.nexts, _, self.done, _ = self.env.step(self.a)
|
|
||||||
self.nextm = available_actions(self.env)
|
|
||||||
|
|
||||||
# run whatever _after_step might dictate in child class
|
|
||||||
self._after_step()
|
|
||||||
|
|
||||||
# update state and mask to current
|
|
||||||
self.s = self.nexts
|
|
||||||
self.m = self.nextm
|
|
||||||
|
|
||||||
# transitions yielded from self._transitions() functions specied in child classes
|
|
||||||
yield from self._transitions()
|
|
||||||
|
|
||||||
### NOTE: only yields after a full option has been executed / exited
|
|
||||||
|
|
||||||
class LLOptions(OptionsEnv):
|
|
||||||
"""Sample low-level (state, action) tuples for discriminator training."""
|
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
"""
|
|
||||||
LLOption uses the true LL observations
|
|
||||||
"""
|
|
||||||
super().__init__(*args, **kwargs)
|
|
||||||
# overwrite observation space to just output obs directly
|
|
||||||
self.observation_space = self.observation_space['obs']
|
|
||||||
|
|
||||||
def _after_choice(self):
|
|
||||||
"""
|
|
||||||
After each option choice, initialize/reset the transition buffer
|
|
||||||
"""
|
|
||||||
self._transition_buffer = []
|
|
||||||
|
|
||||||
def _after_step(self):
|
|
||||||
"""
|
|
||||||
After each ll action, append s, s', a, done to transition buffer
|
|
||||||
"""
|
|
||||||
self._transition_buffer.append({
|
|
||||||
'obs': self.s,
|
|
||||||
'next_obs': self.nexts,
|
|
||||||
'acts': np.array((self.a,)),
|
|
||||||
'dones': np.array(self.done),
|
|
||||||
})
|
|
||||||
|
|
||||||
def _transitions(self):
|
|
||||||
"""
|
|
||||||
Yield from the transition buffer
|
|
||||||
"""
|
|
||||||
yield from self._transition_buffer
|
|
||||||
|
|
||||||
def sample_ll(self, policy):
|
|
||||||
"""
|
|
||||||
Args:
|
|
||||||
policy
|
|
||||||
Returns:
|
|
||||||
gen: iterable which samples low-level transitions from the environment
|
|
||||||
"""
|
|
||||||
return self.sample(policy)
|
|
||||||
|
|
||||||
class HLOptions(OptionsEnv):
|
|
||||||
"""Sample high-level (state, action, reward) tuples for generator training."""
|
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
super().__init__(*args, **kwargs)
|
|
||||||
|
|
||||||
def _after_choice(self):
|
|
||||||
"""
|
|
||||||
After an option selection, initialize total reward and number of steps
|
|
||||||
"""
|
|
||||||
self.r = 0
|
|
||||||
self.steps = 0
|
|
||||||
|
|
||||||
def _after_step(self):
|
|
||||||
"""
|
|
||||||
After each low-level action, add the discounted discriminated reward score (given a discriminator)
|
|
||||||
"""
|
|
||||||
self.r += self.discount**self.steps * self.discriminator.discrim_net.reward_train(
|
|
||||||
state=torch.tensor(self.s).unsqueeze(0).to(self.discriminator.discrim_net.device()),
|
|
||||||
action=torch.tensor([[self.a]]).to(self.discriminator.discrim_net.device()),
|
|
||||||
next_state=torch.tensor(self.s).unsqueeze(0).to(self.discriminator.discrim_net.device()), # unused
|
|
||||||
done=torch.tensor(self.done).unsqueeze(0).to(self.discriminator.discrim_net.device()), # unused
|
|
||||||
)
|
|
||||||
self.steps += 1
|
|
||||||
|
|
||||||
def _transitions(self):
|
|
||||||
"""
|
|
||||||
Yield a single dictionary per high-level selected action
|
|
||||||
Fields:
|
|
||||||
obs: high-level state and mask at selection
|
|
||||||
action: chosen high-level action
|
|
||||||
reward: accumulated option reward
|
|
||||||
episode_start: whether the action was chosen at the episode start
|
|
||||||
value: the value estimate from the starting state
|
|
||||||
log_prob: the log_prob of the selected action from the starting state
|
|
||||||
done: whether the episode has ended
|
|
||||||
|
|
||||||
"""
|
|
||||||
yield {
|
|
||||||
'obs': {'obs': self.s, 'mask': self.m},
|
|
||||||
'action': self.ch,
|
|
||||||
'reward': self.r.detach(),
|
|
||||||
'episode_start': self.episode_start,
|
|
||||||
'value': self.value.detach(),
|
|
||||||
'log_prob': self.log_prob.detach(),
|
|
||||||
'done': self.done,
|
|
||||||
}
|
|
||||||
|
|
||||||
def sample_hl(self, policy, discriminator):
|
|
||||||
"""
|
|
||||||
Args:
|
|
||||||
policy
|
|
||||||
discriminator: function with which to score rewards
|
|
||||||
Returns:
|
|
||||||
gen: iterable which samples high-level transitions from the environment
|
|
||||||
"""
|
|
||||||
self.discriminator = discriminator
|
|
||||||
return self.sample(policy)
|
|
||||||
|
|
||||||
class RenderOptions(LLOptions):
|
|
||||||
|
|
||||||
def _after_step(self):
|
|
||||||
"""
|
|
||||||
Render the environment after each low-level step
|
|
||||||
"""
|
|
||||||
super()._after_step()
|
|
||||||
self.env.render()
|
|
||||||
|
|
||||||
def close(self, *args, **kwargs):
|
|
||||||
"""
|
|
||||||
On 'close', close the environment
|
|
||||||
"""
|
|
||||||
self.env.close(*args, **kwargs)
|
|
||||||
|
|
||||||
def available_actions(env):
|
|
||||||
"""Return mask of available actions given current `env` state."""
|
|
||||||
valid = np.array([feasible(env, generate_plan(env, i), i) for i in range(len(ALL_OPTIONS))])
|
|
||||||
return valid
|
|
||||||
|
|
||||||
def target_velocity_plan(current_v: float, target_v: float, t: int, dt: float):
|
|
||||||
"""Smoothly target a velocity in a given number of steps"""
|
|
||||||
# for now, constant acceleration
|
|
||||||
a = (target_v - current_v) / (t * dt)
|
|
||||||
return a*np.ones((t,))
|
|
||||||
|
|
||||||
def generate_plan(env, i):
|
|
||||||
"""Generate input profile for high-level action `i`."""
|
|
||||||
assert i < len(ALL_OPTIONS), "Invalid option index {i}"
|
|
||||||
target_v, t = ALL_OPTIONS[i]
|
|
||||||
current_v = env._env.state[env._agent, 1].item() # extract from env
|
|
||||||
plan = target_velocity_plan(current_v, target_v, t, env._env._dt)
|
|
||||||
assert len(plan) == t, "incorrect plan length"
|
|
||||||
return plan
|
|
||||||
|
|
||||||
def check_future_collisions_fast(env, actions):
|
|
||||||
"""Checks whether `env._agent` would collide with other agents assuming `actions` as input.
|
|
||||||
|
|
||||||
Vehicles are (over-)approximated by single circles.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
env (gym.Env): current environment state
|
|
||||||
actions (list of torch.Tensor): list of B (T, nv, adims) T-length action profiles
|
|
||||||
Returns:
|
|
||||||
feasible (torch.Tensor): tensor of shape (B,) indicating whether the respective action profiles are collision-free
|
|
||||||
"""
|
|
||||||
B, (T, nv, _) = len(actions), actions[0].shape
|
|
||||||
|
|
||||||
states = torch.stack(env._env.propagate_action_profile(actions), axis=0)
|
|
||||||
assert states.shape == (B, T, nv, 5)
|
|
||||||
|
|
||||||
distance = ((states[:, :, :, :2] - states[:, :, env._agent:env._agent+1, :2])**2).sum(-1).sqrt()
|
|
||||||
distance = torch.where(distance.isnan(), np.inf*torch.ones_like(distance), distance) # only collide with spawned agents
|
|
||||||
distance[:, :, env._agent] = np.inf # cannot collide with itself
|
|
||||||
assert distance.shape == (B, T, nv)
|
|
||||||
|
|
||||||
radius = (env._env._lengths**2 + env._env._widths**2).sqrt() / 2
|
|
||||||
min_distance = radius[env._agent] + radius
|
|
||||||
min_distance = min_distance.unsqueeze(0).unsqueeze(0)
|
|
||||||
assert min_distance.shape == (1, 1, nv)
|
|
||||||
|
|
||||||
return (distance > min_distance).all(-1).all(-1)
|
|
||||||
|
|
||||||
def check_future_collisions_circles(env, actions, n_circles:int=2):
|
|
||||||
"""Checks whether `env._agent` would collide with other agents assuming `actions` as input.
|
|
||||||
|
|
||||||
Vehicles are (over-)approximated by multiple circles.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
env (gym.Env): current environment state
|
|
||||||
actions (list of torch.Tensor): list of B (T, nv, adims) T-length action profiles
|
|
||||||
Returns:
|
|
||||||
feasible (torch.Tensor): tensor of shape (B,) indicating whether the respective action profiles are collision-free
|
|
||||||
"""
|
|
||||||
assert n_circles >= 2
|
|
||||||
B, (T, nv, _) = len(actions), actions[0].shape
|
|
||||||
|
|
||||||
states = torch.stack(env._env.propagate_action_profile(actions), axis=0)
|
|
||||||
assert states.shape == (B, T, nv, 5)
|
|
||||||
centers = states[:, :, :, :2]
|
|
||||||
psi = states[:, :, :, 3]
|
|
||||||
lon = torch.stack([psi.cos(), psi.sin()],dim=-1) # (B, T, nv, 2)
|
|
||||||
|
|
||||||
# offset between [-env._env.lengths+env._env.widths/2, env._env.lengths/2-env._env.widths/2]
|
|
||||||
back = (-env._env._lengths/2+env._env._widths/2).unsqueeze(-1) # (nv, 1)
|
|
||||||
length = (env._env._lengths-env._env._widths).unsqueeze(-1) # (nv, 1)
|
|
||||||
diff_d = back + length*(torch.arange(n_circles)/(n_circles-1)).unsqueeze(0) # (nv, n_circles)
|
|
||||||
assert diff_d.shape == (nv, n_circles)
|
|
||||||
|
|
||||||
offsets = diff_d[None, None, :, :, None] * lon[:, :, :, None, :]
|
|
||||||
assert offsets.shape == (B, T, nv, n_circles, 2)
|
|
||||||
|
|
||||||
expanded_centers=centers.unsqueeze(-2) + offsets #(B, T, nv, n_circles, 2)
|
|
||||||
assert expanded_centers.shape == (B, T, nv, n_circles, 2)
|
|
||||||
agent_centers = expanded_centers[:,:,env._agent:env._agent+1,:,:] #(B, T, 1, n_circles, 2)
|
|
||||||
ds = expanded_centers.reshape((B, T, nv*n_circles, 1, 2)) - agent_centers #(B, T, nv*nc,1, 2) - (B, T, 1, nc, 2) = (B, T, nv*nc, nc, 2)
|
|
||||||
|
|
||||||
distance = (ds**2).sum(-1).sqrt().reshape((B, T, nv, n_circles, n_circles)) # (B, T, nv, nc, nc)
|
|
||||||
distance = torch.where(distance.isnan(), np.inf*torch.ones_like(distance), distance) # only collide with spawned agents
|
|
||||||
distance[:, :, env._agent] = np.inf # cannot collide with itself
|
|
||||||
assert distance.shape == (B, T, nv, n_circles, n_circles)
|
|
||||||
|
|
||||||
radius = env._env._widths*np.sqrt(2) / 2
|
|
||||||
min_distance = radius[env._agent] + radius
|
|
||||||
min_distance = min_distance[None, None, :, None, None]
|
|
||||||
assert min_distance.shape == (1, 1, nv, 1, 1)
|
|
||||||
|
|
||||||
return (distance > min_distance).all(-1).all(-1).all(-1).all(-1)
|
|
||||||
|
|
||||||
def feasible(env, plan, ch):
|
|
||||||
"""Check if input profile is feasible given current `env` state. Action `ch=0` is safe fallback."""
|
|
||||||
|
|
||||||
# zero pad plan - Take (T,) np plan and convert it to (T, nv, 1) torch.Tensor
|
|
||||||
full_plan = torch.zeros(len(plan), env._env._nv, 1)
|
|
||||||
full_plan[:, env._agent, 0] = torch.tensor(plan)
|
|
||||||
# valid = check_future_collisions_fast(env, [full_plan]) # check_future_collisions_fast takes in B-list and outputs (B,) bool tensor
|
|
||||||
valid = check_future_collisions_circles(env, [full_plan])
|
|
||||||
return ch == 0 or valid.item()
|
|
||||||
|
|
||||||
def flatten_transitions(transitions):
|
|
||||||
return {
|
|
||||||
'obs': np.stack(list(t['obs'] for t in transitions), axis=0),
|
|
||||||
'next_obs': np.stack(list(t['next_obs'] for t in transitions), axis=0),
|
|
||||||
'acts': np.stack(list(t['acts'] for t in transitions), axis=0),
|
|
||||||
'dones': np.stack(list(t['dones'] for t in transitions), axis=0),
|
|
||||||
}
|
|
||||||
|
|
||||||
def train_discriminator(env, generator, discriminator, num_samples):
|
|
||||||
transitions = list(itertools.islice(env.sample_ll(generator), num_samples))
|
|
||||||
generator_samples = flatten_transitions(transitions)
|
|
||||||
discriminator.train_disc(gen_samples=generator_samples)
|
|
||||||
|
|
||||||
def train_generator(env, generator, discriminator, num_samples):
|
|
||||||
generator_samples = list(itertools.islice(env.sample_hl(generator, discriminator), num_samples+1))
|
|
||||||
|
|
||||||
generator.rollout_buffer.reset()
|
|
||||||
for s in generator_samples[:-1]:
|
|
||||||
generator.rollout_buffer.add(
|
|
||||||
obs=s['obs'],
|
|
||||||
action=s['action'].cpu(),
|
|
||||||
reward=s['reward'].cpu(),
|
|
||||||
episode_start=s['episode_start'],
|
|
||||||
value=s['value'],
|
|
||||||
log_prob=s['log_prob'],
|
|
||||||
)
|
|
||||||
|
|
||||||
generator.rollout_buffer.compute_returns_and_advantage(
|
|
||||||
last_values=generator_samples[-1]['value'],
|
|
||||||
dones=generator_samples[-1]['done'],
|
|
||||||
)
|
|
||||||
|
|
||||||
generator.train()
|
|
||||||
|
|
||||||
def train(expert_data, env_class=NRasterizedRandomAgent, env_settings={}, epochs=10, discrim_batch_size=32, generator_steps=2048, discount=0.99):
|
|
||||||
"""
|
|
||||||
Args:
|
|
||||||
expert_data: list of transitions
|
|
||||||
env_class: environment class
|
|
||||||
env_settings: environment settings
|
|
||||||
epochs: number of epochs to train for
|
|
||||||
discrim_batch_size: discriminator batch size
|
|
||||||
generator_steps: number of steps taken in generator
|
|
||||||
discount: discount factor
|
|
||||||
Returns:
|
|
||||||
generator (stable_baselines3.PPO): options policy
|
|
||||||
"""
|
|
||||||
env = env_class(**env_settings)
|
|
||||||
env.discount = discount
|
|
||||||
|
|
||||||
tempdir = tempfile.TemporaryDirectory(prefix="quickstart")
|
|
||||||
tempdir_path = pathlib.Path(tempdir.name)
|
|
||||||
logger.configure(tempdir_path / "GAIL/")
|
|
||||||
print(f"All Tensorboards and logging are being written inside {tempdir_path}/.")
|
|
||||||
|
|
||||||
venv = make_vec_env(env_class, n_envs=1, env_kwargs=env_settings)
|
|
||||||
discriminator = adversarial.GAIL(
|
|
||||||
expert_data=expert_data,
|
|
||||||
expert_batch_size=discrim_batch_size,
|
|
||||||
discrim_kwargs={'discrim_net': CnnDiscriminatorFlatAction(venv)},
|
|
||||||
#discrim_kwargs={'discrim_net': CnnDiscriminator(venv)},
|
|
||||||
venv=venv, # unused
|
|
||||||
gen_algo=stable_baselines3.PPO("CnnPolicy", venv), # unused
|
|
||||||
)
|
|
||||||
|
|
||||||
generator = stable_baselines3.PPO(
|
|
||||||
OptionsCnnPolicy,
|
|
||||||
OptionsEnv(env),
|
|
||||||
verbose=1,
|
|
||||||
n_steps=generator_steps,
|
|
||||||
)
|
|
||||||
|
|
||||||
# PPO.train requires logger as set up in
|
|
||||||
# PPO._setup_learn (called by PPO.learn)
|
|
||||||
generator._logger = stable_baselines3.common.utils.configure_logger(
|
|
||||||
generator.verbose,
|
|
||||||
generator.tensorboard_log,
|
|
||||||
)
|
|
||||||
|
|
||||||
for _ in tqdm(range(epochs)):
|
|
||||||
train_discriminator(LLOptions(env), generator, discriminator, num_samples=discrim_batch_size)
|
|
||||||
train_generator(HLOptions(env), generator, discriminator, num_samples=generator_steps)
|
|
||||||
|
|
||||||
return generator
|
|
||||||
|
|
||||||
# %%
|
|
||||||
if __name__ == '__main__':
|
|
||||||
# %%
|
|
||||||
model_name = 'gail_options_image'
|
|
||||||
env_class = NRasterizedRandomAgent
|
|
||||||
env_settings = {'width': 36, 'height': 36, 'm_per_px': 2}
|
|
||||||
|
|
||||||
with open("data/NormalizedIntersimpleExpertMu.001_NRasterizedIncrementingAgentw36h36mppx2.pkl", "rb") as f:
|
|
||||||
trajectories = pickle.load(f)
|
|
||||||
#import pdb
|
|
||||||
#pdb.set_trace()
|
|
||||||
transitions = rollout.flatten_trajectories(trajectories)
|
|
||||||
generator = train(
|
|
||||||
transitions,
|
|
||||||
env_class=env_class,
|
|
||||||
env_settings=env_settings,
|
|
||||||
epochs=2,
|
|
||||||
discrim_batch_size=32,
|
|
||||||
generator_steps=2048,
|
|
||||||
discount=0.99
|
|
||||||
)
|
|
||||||
|
|
||||||
generator.save(model_name) # save ppo sb3 generator class
|
|
||||||
|
|
||||||
# %%
|
|
||||||
model = stable_baselines3.PPO.load(model_name) # not actually used
|
|
||||||
|
|
||||||
env = RenderOptions(NRasterizedRandomAgent(**env_settings))
|
|
||||||
for s in env.sample_ll(generator):
|
|
||||||
if s['dones']:
|
|
||||||
break
|
|
||||||
|
|
||||||
env.close(filestr='render/'+model_name)
|
|
||||||
|
|
||||||
# %% Tests
|
|
||||||
|
|
||||||
def test_ll_expert_data():
|
|
||||||
with open("data/NormalizedIntersimpleExpertMu.001_NRasterizedAgent51w36h36mppx2.pkl", "rb") as f:
|
|
||||||
expert_trajectories = pickle.load(f)
|
|
||||||
expert_transitions = rollout.flatten_trajectories(expert_trajectories)
|
|
||||||
|
|
||||||
env = LLOptions(NRasterized(agent=51, width=36, height=36, m_per_px=2))
|
|
||||||
|
|
||||||
gen_transitions = list(itertools.islice(env.sample_ll(
|
|
||||||
policy=stable_baselines3.PPO(
|
|
||||||
OptionsCnnPolicy,
|
|
||||||
OptionsEnv(env),
|
|
||||||
verbose=1,
|
|
||||||
)
|
|
||||||
), 10))
|
|
||||||
gen_transitions = flatten_transitions(gen_transitions)
|
|
||||||
|
|
||||||
assert expert_transitions[:10].obs.shape == gen_transitions['obs'].shape
|
|
||||||
assert expert_transitions[:10].next_obs.shape == gen_transitions['next_obs'].shape
|
|
||||||
assert expert_transitions[:10].acts.shape == gen_transitions['acts'].shape
|
|
||||||
assert expert_transitions[:10].dones.shape == gen_transitions['dones'].shape
|
|
||||||
|
|
||||||
def test_ll_states():
|
|
||||||
env = NRasterized()
|
|
||||||
policy = stable_baselines3.PPO(
|
|
||||||
OptionsCnnPolicy,
|
|
||||||
OptionsEnv(env),
|
|
||||||
verbose=1,
|
|
||||||
)
|
|
||||||
llenv = LLOptions(env)
|
|
||||||
transitions = list(itertools.islice(llenv.sample_ll(policy=policy), 100))
|
|
||||||
|
|
||||||
env2 = NRasterized()
|
|
||||||
s2 = env2.reset()
|
|
||||||
for i, t in enumerate(transitions):
|
|
||||||
assert i == 0 or np.array_equal(t['obs'], transitions[i-1]['next_obs'])
|
|
||||||
assert np.array_equal(t['obs'], s2)
|
|
||||||
assert t['acts'].shape == (1,)
|
|
||||||
|
|
||||||
nexts2, _, done2, _ = env2.step(t['acts'])
|
|
||||||
assert np.array_equal(t['next_obs'], nexts2)
|
|
||||||
assert np.array_equal(t['dones'], done2)
|
|
||||||
|
|
||||||
if done2:
|
|
||||||
break
|
|
||||||
|
|
||||||
s2 = nexts2
|
|
||||||
|
|
||||||
def test_hl_transitions():
|
|
||||||
pass
|
|
||||||
@@ -1,510 +0,0 @@
|
|||||||
# %%
|
|
||||||
from gail.discriminator import CnnDiscriminator, CnnDiscriminatorFlatAction
|
|
||||||
from imitation.algorithms import adversarial
|
|
||||||
import stable_baselines3
|
|
||||||
import torch.utils.data
|
|
||||||
import numpy as np
|
|
||||||
from intersim.envs.intersimple import NRasterized, NRasterizedRandomAgent
|
|
||||||
import itertools
|
|
||||||
from torch.distributions import Categorical
|
|
||||||
import gym
|
|
||||||
import torch
|
|
||||||
import pickle
|
|
||||||
import imitation.data.rollout as rollout
|
|
||||||
import tempfile
|
|
||||||
import pathlib
|
|
||||||
from imitation.util import logger
|
|
||||||
from stable_baselines3.common.env_util import make_vec_env
|
|
||||||
from tqdm import tqdm
|
|
||||||
|
|
||||||
import logging
|
|
||||||
logging.basicConfig(level=logging.DEBUG)
|
|
||||||
|
|
||||||
ALL_OPTIONS = [(v,t) for v in [0,2,4,6,8] for t in [5, 10, 20]] # option 0 is safe fallback
|
|
||||||
|
|
||||||
class OptionsCnnPolicy(stable_baselines3.common.policies.ActorCriticCnnPolicy):
|
|
||||||
"""
|
|
||||||
Class for high-level options policy (generator)
|
|
||||||
"""
|
|
||||||
def __init__(self, observation_space, *args, **kwargs):
|
|
||||||
super().__init__(observation_space['obs'], *args, **kwargs)
|
|
||||||
|
|
||||||
def _prior_distribution(self, s):
|
|
||||||
"""
|
|
||||||
Return prior distribution over high-level options (before masking)
|
|
||||||
Args:
|
|
||||||
s (torch.tensor): observation
|
|
||||||
Returns:
|
|
||||||
values (torch.tensor): values from critic
|
|
||||||
dist (torch.distributions): prior distribution over actions
|
|
||||||
"""
|
|
||||||
latent_pi, latent_vf, latent_sde = self._get_latent(s)
|
|
||||||
distribution = self._get_action_dist_from_latent(latent_pi, latent_sde)
|
|
||||||
values = self.value_net(latent_vf)
|
|
||||||
return values, distribution.distribution
|
|
||||||
|
|
||||||
def predict(self, obs):
|
|
||||||
"""
|
|
||||||
Will mask invalid states before making action selections
|
|
||||||
Args:
|
|
||||||
obs: dict with keys:
|
|
||||||
obs (torch.tensor): (B,o) true observations
|
|
||||||
mask (torch.tensor): (B,m) mask over valid actions
|
|
||||||
Returns:
|
|
||||||
ch (torch.tensor): (B,a) sampled actions
|
|
||||||
values (torch.tensor): (B,) predicted value at observation
|
|
||||||
log_probs (torch.tensor): (B,) log probabilities of selected actions
|
|
||||||
"""
|
|
||||||
s, m = obs['obs'], obs['mask']
|
|
||||||
values, prior = self._prior_distribution(s)
|
|
||||||
posterior = Categorical(prior.probs * m)
|
|
||||||
ch = posterior.sample()
|
|
||||||
return ch, values, posterior.log_prob(ch)
|
|
||||||
|
|
||||||
def evaluate_actions(self, obs, ch):
|
|
||||||
"""
|
|
||||||
Evaluate particular actions
|
|
||||||
Args:
|
|
||||||
obs: dict with keys:
|
|
||||||
obs (torch.tensor): (B,o) true observations
|
|
||||||
mask (torch.tensor): (B,m) masks over valid actions
|
|
||||||
ch (torch.tensor): (B,a) selected actions
|
|
||||||
Returns:
|
|
||||||
values (torch.tensor): (B,) predicted value at observation
|
|
||||||
log_probs (torch.tensor): (B,) log probabilities of selected actions
|
|
||||||
ent (torch.tensor): (B,) entropy of each distribution over actions
|
|
||||||
"""
|
|
||||||
s, m = obs['obs'], obs['mask']
|
|
||||||
values, prior = self._prior_distribution(s)
|
|
||||||
posterior = Categorical(prior.probs * m)
|
|
||||||
return values, posterior.log_prob(ch), posterior.entropy() # additional values used by PPO.train
|
|
||||||
|
|
||||||
class OptionsEnv(gym.Wrapper):
|
|
||||||
"""
|
|
||||||
Wrap an intersimple environment with an options generator
|
|
||||||
"""
|
|
||||||
def __init__(self, env, render=False, *args, **kwargs):
|
|
||||||
"""
|
|
||||||
Initialize wrapped environment and set high-level action and observation spaces
|
|
||||||
"""
|
|
||||||
super().__init__(env, *args, **kwargs)
|
|
||||||
num_hl_options = len(ALL_OPTIONS)
|
|
||||||
self.action_space = gym.spaces.Discrete(num_hl_options)
|
|
||||||
self.observation_space = gym.spaces.Dict({
|
|
||||||
'obs': env.observation_space,
|
|
||||||
'mask': gym.spaces.Box(low=0, high=1, shape=(num_hl_options,)),
|
|
||||||
})
|
|
||||||
self._hl_transition_buffer = []
|
|
||||||
self._ll_transition_buffer = []
|
|
||||||
self.render=render
|
|
||||||
|
|
||||||
def _after_option_choice(self):
|
|
||||||
"""
|
|
||||||
After initial option choice,
|
|
||||||
"""
|
|
||||||
self._hl_r = 0
|
|
||||||
self._hl_steps = 0
|
|
||||||
|
|
||||||
def _after_step(self):
|
|
||||||
"""
|
|
||||||
After each step, add the ll transition to the appropriate buffer, add to reward, add to steps, and possibly render
|
|
||||||
"""
|
|
||||||
|
|
||||||
self._ll_transition_buffer.append({
|
|
||||||
'obs': self.s,
|
|
||||||
'next_obs': self.nexts,
|
|
||||||
'acts': np.array((self.a,)),
|
|
||||||
'dones': np.array(self.done),
|
|
||||||
})
|
|
||||||
self.r += self.discount**self.steps * self.discriminator.discrim_net.reward_train(
|
|
||||||
state=torch.tensor(self.s).unsqueeze(0).to(self.discriminator.discrim_net.device()),
|
|
||||||
action=torch.tensor([[self.a]]).to(self.discriminator.discrim_net.device()),
|
|
||||||
next_state=torch.tensor(self.s).unsqueeze(0).to(self.discriminator.discrim_net.device()), # unused
|
|
||||||
done=torch.tensor(self.done).unsqueeze(0).to(self.discriminator.discrim_net.device()), # unused
|
|
||||||
)
|
|
||||||
self.steps += 1
|
|
||||||
if self.render:
|
|
||||||
self.env.render()
|
|
||||||
|
|
||||||
def _after_option(self):
|
|
||||||
"""
|
|
||||||
After each low-level action, add the discounted discriminated reward score (given a discriminator)
|
|
||||||
"""
|
|
||||||
self._hl_transition_buffer.append({
|
|
||||||
'obs': {'obs': self.os, 'mask': self.m},
|
|
||||||
'action': self.ch,
|
|
||||||
'reward': self.r.detach(),
|
|
||||||
'episode_start': self.episode_start,
|
|
||||||
'value': self.value.detach(),
|
|
||||||
'log_prob': self.log_prob.detach(),
|
|
||||||
'done': self.done,
|
|
||||||
})
|
|
||||||
|
|
||||||
def close(self, *args, **kwargs):
|
|
||||||
"""
|
|
||||||
On 'close', close the environment
|
|
||||||
"""
|
|
||||||
self.env.close(*args, **kwargs)
|
|
||||||
|
|
||||||
def sample(self, generator, controller):
|
|
||||||
"""
|
|
||||||
yield transitions using a generator
|
|
||||||
Args:
|
|
||||||
generator (sb3.PPO)
|
|
||||||
controller (str): 'high' or 'low' to yield from proper buffer
|
|
||||||
Yields:
|
|
||||||
|
|
||||||
"""
|
|
||||||
self.done = True
|
|
||||||
# DO I WANT TO EMPTY THE BUFFERS??? Probs naw
|
|
||||||
while True:
|
|
||||||
|
|
||||||
# yield from buffers to empty what was stored previously
|
|
||||||
if controller = 'high':
|
|
||||||
yield from self._hl_transition_buffer
|
|
||||||
elif controller == 'low':
|
|
||||||
yield from self._ll_transition_buffer
|
|
||||||
else:
|
|
||||||
raise('Improper buffer')
|
|
||||||
|
|
||||||
self.episode_start = False
|
|
||||||
if self.done:
|
|
||||||
# reset environment
|
|
||||||
self.s = self.env.reset()
|
|
||||||
self.done = False
|
|
||||||
self.episode_start = True
|
|
||||||
|
|
||||||
self.os = self.s.copy() # option start state
|
|
||||||
self.m = available_actions(self.env)
|
|
||||||
|
|
||||||
# set the action, the value of the start state, and the logprob of the action
|
|
||||||
# according to the current environment state and mask
|
|
||||||
self.ch, self.value, self.log_prob = generator.policy.predict({
|
|
||||||
'obs': torch.tensor(self.os).unsqueeze(0).to(generator.policy.device),
|
|
||||||
'mask': torch.tensor(self.m).unsqueeze(0).to(generator.policy.device),
|
|
||||||
})
|
|
||||||
|
|
||||||
# store a float list of actions to take given the option selected in the environment
|
|
||||||
self.plan = list(map(float, generate_plan(self.env, self.ch)))
|
|
||||||
|
|
||||||
# run whatever _after_choice might dictate in a child class
|
|
||||||
self._after_option_choice()
|
|
||||||
|
|
||||||
# some checks
|
|
||||||
assert not self.done
|
|
||||||
assert self.plan
|
|
||||||
assert feasible(self.env, self.plan, self.ch)
|
|
||||||
|
|
||||||
# execute the option so long as the episode isn't complete and the plan is still feasible
|
|
||||||
while not self.done and self.plan and feasible(self.env, self.plan, self.ch):
|
|
||||||
|
|
||||||
# pop first action
|
|
||||||
self.a, self.plan = self.plan[0], self.plan[1:]
|
|
||||||
|
|
||||||
# normalize action ??
|
|
||||||
self.a = self.env._normalize(self.a)
|
|
||||||
|
|
||||||
# step through environment
|
|
||||||
self.nexts, _, self.done, _ = self.env.step(self.a)
|
|
||||||
|
|
||||||
# run whatever _after_step might dictate in child class
|
|
||||||
self._after_step()
|
|
||||||
|
|
||||||
# update state and mask to current
|
|
||||||
self.s = self.nexts
|
|
||||||
|
|
||||||
# run whatever to do after option
|
|
||||||
self._after_option()
|
|
||||||
|
|
||||||
def sample_ll(self, policy):
|
|
||||||
"""
|
|
||||||
Not quite sure how this works????
|
|
||||||
Why would you do this over LLOptions.sample(policy)
|
|
||||||
"""
|
|
||||||
return self.sample(policy, 'low')
|
|
||||||
|
|
||||||
def sample_hl(self, policy, discriminator):
|
|
||||||
"""
|
|
||||||
Args:
|
|
||||||
policy
|
|
||||||
discriminator: function with which to score rewards
|
|
||||||
Returns:
|
|
||||||
gen: an which samples high-level transitions from the environment
|
|
||||||
"""
|
|
||||||
self.discriminator = discriminator
|
|
||||||
return self.sample(policy)
|
|
||||||
|
|
||||||
def available_actions(env):
|
|
||||||
"""Return mask of available actions given current `env` state."""
|
|
||||||
valid = np.array([feasible(env, generate_plan(env, i), i) for i in range(len(ALL_OPTIONS))])
|
|
||||||
return valid
|
|
||||||
|
|
||||||
def target_velocity_plan(current_v: float, target_v: float, t: int, dt: float):
|
|
||||||
"""Smoothly target a velocity in a given number of steps"""
|
|
||||||
# for now, constant acceleration
|
|
||||||
a = (target_v - current_v) / (t * dt)
|
|
||||||
return a*np.ones((t,))
|
|
||||||
|
|
||||||
def generate_plan(env, i):
|
|
||||||
"""Generate input profile for high-level action `i`."""
|
|
||||||
assert i < len(ALL_OPTIONS), "Invalid option index {i}"
|
|
||||||
target_v, t = ALL_OPTIONS[i]
|
|
||||||
current_v = env._env.state[env._agent, 1].item() # extract from env
|
|
||||||
plan = target_velocity_plan(current_v, target_v, t, env._env._dt)
|
|
||||||
assert len(plan) == t, "incorrect plan length"
|
|
||||||
return plan
|
|
||||||
|
|
||||||
def check_future_collisions_fast(env, actions):
|
|
||||||
"""Checks whether `env._agent` would collide with other agents assuming `actions` as input.
|
|
||||||
|
|
||||||
Vehicles are (over-)approximated by single circles.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
env (gym.Env): current environment state
|
|
||||||
actions (list of torch.Tensor): list of B (T, nv, adims) T-length action profiles
|
|
||||||
Returns:
|
|
||||||
feasible (torch.Tensor): tensor of shape (B,) indicating whether the respective action profiles are collision-free
|
|
||||||
"""
|
|
||||||
B, (T, nv, _) = len(actions), actions[0].shape
|
|
||||||
|
|
||||||
states = torch.stack(env._env.propagate_action_profile(actions), axis=0)
|
|
||||||
assert states.shape == (B, T, nv, 5)
|
|
||||||
|
|
||||||
distance = ((states[:, :, :, :2] - states[:, :, env._agent:env._agent+1, :2])**2).sum(-1).sqrt()
|
|
||||||
distance = torch.where(distance.isnan(), np.inf*torch.ones_like(distance), distance) # only collide with spawned agents
|
|
||||||
distance[:, :, env._agent] = np.inf # cannot collide with itself
|
|
||||||
assert distance.shape == (B, T, nv)
|
|
||||||
|
|
||||||
radius = (env._env._lengths**2 + env._env._widths**2).sqrt() / 2
|
|
||||||
min_distance = radius[env._agent] + radius
|
|
||||||
min_distance = min_distance.unsqueeze(0).unsqueeze(0)
|
|
||||||
assert min_distance.shape == (1, 1, nv)
|
|
||||||
|
|
||||||
return (distance > min_distance).all(-1).all(-1)
|
|
||||||
|
|
||||||
def check_future_collisions_circles(env, actions, n_circles:int=2):
|
|
||||||
"""Checks whether `env._agent` would collide with other agents assuming `actions` as input.
|
|
||||||
|
|
||||||
Vehicles are (over-)approximated by multiple circles.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
env (gym.Env): current environment state
|
|
||||||
actions (list of torch.Tensor): list of B (T, nv, adims) T-length action profiles
|
|
||||||
Returns:
|
|
||||||
feasible (torch.Tensor): tensor of shape (B,) indicating whether the respective action profiles are collision-free
|
|
||||||
"""
|
|
||||||
assert n_circles >= 2
|
|
||||||
B, (T, nv, _) = len(actions), actions[0].shape
|
|
||||||
|
|
||||||
states = torch.stack(env._env.propagate_action_profile(actions), axis=0)
|
|
||||||
assert states.shape == (B, T, nv, 5)
|
|
||||||
centers = states[:, :, :, :2]
|
|
||||||
psi = states[:, :, :, 3]
|
|
||||||
lon = torch.stack([psi.cos(), psi.sin()],dim=-1) # (B, T, nv, 2)
|
|
||||||
|
|
||||||
# offset between [-env._env.lengths+env._env.widths/2, env._env.lengths/2-env._env.widths/2]
|
|
||||||
back = (-env._env._lengths/2+env._env._widths/2).unsqueeze(-1) # (nv, 1)
|
|
||||||
length = (env._env._lengths-env._env._widths).unsqueeze(-1) # (nv, 1)
|
|
||||||
diff_d = back + length*(torch.arange(n_circles)/(n_circles-1)).unsqueeze(0) # (nv, n_circles)
|
|
||||||
assert diff_d.shape == (nv, n_circles)
|
|
||||||
|
|
||||||
offsets = diff_d[None, None, :, :, None] * lon[:, :, :, None, :]
|
|
||||||
assert offsets.shape == (B, T, nv, n_circles, 2)
|
|
||||||
|
|
||||||
expanded_centers=centers.unsqueeze(-2) + offsets #(B, T, nv, n_circles, 2)
|
|
||||||
assert expanded_centers.shape == (B, T, nv, n_circles, 2)
|
|
||||||
agent_centers = expanded_centers[:,:,env._agent:env._agent+1,:,:] #(B, T, 1, n_circles, 2)
|
|
||||||
ds = expanded_centers.reshape((B, T, nv*n_circles, 1, 2)) - agent_centers #(B, T, nv*nc,1, 2) - (B, T, 1, nc, 2) = (B, T, nv*nc, nc, 2)
|
|
||||||
|
|
||||||
distance = (ds**2).sum(-1).sqrt().reshape((B, T, nv, n_circles, n_circles)) # (B, T, nv, nc, nc)
|
|
||||||
distance = torch.where(distance.isnan(), np.inf*torch.ones_like(distance), distance) # only collide with spawned agents
|
|
||||||
distance[:, :, env._agent] = np.inf # cannot collide with itself
|
|
||||||
assert distance.shape == (B, T, nv, n_circles, n_circles)
|
|
||||||
|
|
||||||
radius = env._env._widths*np.sqrt(2) / 2
|
|
||||||
min_distance = radius[env._agent] + radius
|
|
||||||
min_distance = min_distance[None, None, :, None, None]
|
|
||||||
assert min_distance.shape == (1, 1, nv, 1, 1)
|
|
||||||
|
|
||||||
return (distance > min_distance).all(-1).all(-1).all(-1).all(-1)
|
|
||||||
|
|
||||||
def feasible(env, plan, ch):
|
|
||||||
"""Check if input profile is feasible given current `env` state. Action `ch=0` is safe fallback."""
|
|
||||||
|
|
||||||
# zero pad plan - Take (T,) np plan and convert it to (T, nv, 1) torch.Tensor
|
|
||||||
full_plan = torch.zeros(len(plan), env._env._nv, 1)
|
|
||||||
full_plan[:, env._agent, 0] = torch.tensor(plan)
|
|
||||||
# valid = check_future_collisions_fast(env, [full_plan]) # check_future_collisions_fast takes in B-list and outputs (B,) bool tensor
|
|
||||||
valid = check_future_collisions_circles(env, [full_plan])
|
|
||||||
return ch == 0 or valid.item()
|
|
||||||
|
|
||||||
def flatten_transitions(transitions):
|
|
||||||
return {
|
|
||||||
'obs': np.stack(list(t['obs'] for t in transitions), axis=0),
|
|
||||||
'next_obs': np.stack(list(t['next_obs'] for t in transitions), axis=0),
|
|
||||||
'acts': np.stack(list(t['acts'] for t in transitions), axis=0),
|
|
||||||
'dones': np.stack(list(t['dones'] for t in transitions), axis=0),
|
|
||||||
}
|
|
||||||
|
|
||||||
def train_discriminator(env, generator, discriminator, num_samples):
|
|
||||||
transitions = list(itertools.islice(env.sample_ll(generator), num_samples))
|
|
||||||
generator_samples = flatten_transitions(transitions)
|
|
||||||
discriminator.train_disc(gen_samples=generator_samples)
|
|
||||||
|
|
||||||
def train_generator(env, generator, discriminator, num_samples):
|
|
||||||
generator_samples = list(itertools.islice(env.sample_hl(generator, discriminator), num_samples+1))
|
|
||||||
|
|
||||||
generator.rollout_buffer.reset()
|
|
||||||
for s in generator_samples[:-1]:
|
|
||||||
generator.rollout_buffer.add(
|
|
||||||
obs=s['obs'],
|
|
||||||
action=s['action'].cpu(),
|
|
||||||
reward=s['reward'].cpu(),
|
|
||||||
episode_start=s['episode_start'],
|
|
||||||
value=s['value'],
|
|
||||||
log_prob=s['log_prob'],
|
|
||||||
)
|
|
||||||
|
|
||||||
generator.rollout_buffer.compute_returns_and_advantage(
|
|
||||||
last_values=generator_samples[-1]['value'],
|
|
||||||
dones=generator_samples[-1]['done'],
|
|
||||||
)
|
|
||||||
|
|
||||||
generator.train()
|
|
||||||
|
|
||||||
def train(expert_data, env_class=NRasterizedRandomAgent, env_settings={}, epochs=10, discrim_batch_size=32, generator_steps=2048, discount=0.99):
|
|
||||||
"""
|
|
||||||
Args:
|
|
||||||
expert_data: list of transitions
|
|
||||||
env_class: environment class
|
|
||||||
env_settings: environment settings
|
|
||||||
epochs: number of epochs to train for
|
|
||||||
discrim_batch_size: discriminator batch size
|
|
||||||
generator_steps: number of steps taken in generator
|
|
||||||
discount: discount factor
|
|
||||||
Returns:
|
|
||||||
generator (stable_baselines3.PPO): options policy
|
|
||||||
"""
|
|
||||||
env = env_class(**env_settings)
|
|
||||||
env.discount = discount
|
|
||||||
|
|
||||||
tempdir = tempfile.TemporaryDirectory(prefix="quickstart")
|
|
||||||
tempdir_path = pathlib.Path(tempdir.name)
|
|
||||||
logger.configure(tempdir_path / "GAIL/")
|
|
||||||
print(f"All Tensorboards and logging are being written inside {tempdir_path}/.")
|
|
||||||
|
|
||||||
venv = make_vec_env(env_class, n_envs=1, env_kwargs=env_settings)
|
|
||||||
discriminator = adversarial.GAIL(
|
|
||||||
expert_data=expert_data,
|
|
||||||
expert_batch_size=discrim_batch_size,
|
|
||||||
discrim_kwargs={'discrim_net': CnnDiscriminatorFlatAction(venv)},
|
|
||||||
#discrim_kwargs={'discrim_net': CnnDiscriminator(venv)},
|
|
||||||
venv=venv, # unused
|
|
||||||
gen_algo=stable_baselines3.PPO("CnnPolicy", venv), # unused
|
|
||||||
)
|
|
||||||
|
|
||||||
generator = stable_baselines3.PPO(
|
|
||||||
OptionsCnnPolicy,
|
|
||||||
OptionsEnv(env),
|
|
||||||
verbose=1,
|
|
||||||
n_steps=generator_steps,
|
|
||||||
)
|
|
||||||
|
|
||||||
# PPO.train requires logger as set up in
|
|
||||||
# PPO._setup_learn (called by PPO.learn)
|
|
||||||
generator._logger = stable_baselines3.common.utils.configure_logger(
|
|
||||||
generator.verbose,
|
|
||||||
generator.tensorboard_log,
|
|
||||||
)
|
|
||||||
|
|
||||||
for _ in tqdm(range(epochs)):
|
|
||||||
train_discriminator(LLOptions(env), generator, discriminator, num_samples=discrim_batch_size)
|
|
||||||
train_generator(HLOptions(env), generator, discriminator, num_samples=generator_steps)
|
|
||||||
|
|
||||||
return generator
|
|
||||||
|
|
||||||
# %%
|
|
||||||
if __name__ == '__main__':
|
|
||||||
# %%
|
|
||||||
model_name = 'gail_options_image'
|
|
||||||
env_class = NRasterizedRandomAgent
|
|
||||||
env_settings = {'width': 36, 'height': 36, 'm_per_px': 2}
|
|
||||||
|
|
||||||
with open("data/NormalizedIntersimpleExpertMu.001_NRasterizedIncrementingAgentw36h36mppx2.pkl", "rb") as f:
|
|
||||||
trajectories = pickle.load(f)
|
|
||||||
#import pdb
|
|
||||||
#pdb.set_trace()
|
|
||||||
transitions = rollout.flatten_trajectories(trajectories)
|
|
||||||
generator = train(
|
|
||||||
transitions,
|
|
||||||
env_class=env_class,
|
|
||||||
env_settings=env_settings,
|
|
||||||
epochs=2,
|
|
||||||
discrim_batch_size=32,
|
|
||||||
generator_steps=2048,
|
|
||||||
discount=0.99
|
|
||||||
)
|
|
||||||
|
|
||||||
generator.save(model_name) # save ppo sb3 generator class
|
|
||||||
|
|
||||||
# %%
|
|
||||||
model = stable_baselines3.PPO.load(model_name) # not actually used
|
|
||||||
|
|
||||||
env = OptionsGail(NRasterizedRandomAgent(**env_settings), render=True)
|
|
||||||
for s in env.sample_ll(generator):
|
|
||||||
if s['dones']:
|
|
||||||
break
|
|
||||||
|
|
||||||
env.close(filestr='render/'+model_name)
|
|
||||||
|
|
||||||
# %% Tests
|
|
||||||
|
|
||||||
def test_ll_expert_data():
|
|
||||||
with open("data/NormalizedIntersimpleExpertMu.001_NRasterizedAgent51w36h36mppx2.pkl", "rb") as f:
|
|
||||||
expert_trajectories = pickle.load(f)
|
|
||||||
expert_transitions = rollout.flatten_trajectories(expert_trajectories)
|
|
||||||
|
|
||||||
env = LLOptions(NRasterized(agent=51, width=36, height=36, m_per_px=2))
|
|
||||||
|
|
||||||
gen_transitions = list(itertools.islice(env.sample_ll(
|
|
||||||
policy=stable_baselines3.PPO(
|
|
||||||
OptionsCnnPolicy,
|
|
||||||
OptionsEnv(env),
|
|
||||||
verbose=1,
|
|
||||||
)
|
|
||||||
), 10))
|
|
||||||
gen_transitions = flatten_transitions(gen_transitions)
|
|
||||||
|
|
||||||
assert expert_transitions[:10].obs.shape == gen_transitions['obs'].shape
|
|
||||||
assert expert_transitions[:10].next_obs.shape == gen_transitions['next_obs'].shape
|
|
||||||
assert expert_transitions[:10].acts.shape == gen_transitions['acts'].shape
|
|
||||||
assert expert_transitions[:10].dones.shape == gen_transitions['dones'].shape
|
|
||||||
|
|
||||||
def test_ll_states():
|
|
||||||
env = NRasterized()
|
|
||||||
policy = stable_baselines3.PPO(
|
|
||||||
OptionsCnnPolicy,
|
|
||||||
OptionsEnv(env),
|
|
||||||
verbose=1,
|
|
||||||
)
|
|
||||||
llenv = LLOptions(env)
|
|
||||||
transitions = list(itertools.islice(llenv.sample_ll(policy=policy), 100))
|
|
||||||
|
|
||||||
env2 = NRasterized()
|
|
||||||
s2 = env2.reset()
|
|
||||||
for i, t in enumerate(transitions):
|
|
||||||
assert i == 0 or np.array_equal(t['obs'], transitions[i-1]['next_obs'])
|
|
||||||
assert np.array_equal(t['obs'], s2)
|
|
||||||
assert t['acts'].shape == (1,)
|
|
||||||
|
|
||||||
nexts2, _, done2, _ = env2.step(t['acts'])
|
|
||||||
assert np.array_equal(t['next_obs'], nexts2)
|
|
||||||
assert np.array_equal(t['dones'], done2)
|
|
||||||
|
|
||||||
if done2:
|
|
||||||
break
|
|
||||||
|
|
||||||
s2 = nexts2
|
|
||||||
|
|
||||||
def test_hl_transitions():
|
|
||||||
pass
|
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
Environment
|
|
||||||
-- each 'environment' follows a single roundabout and track id (recording of that roundabout)
|
|
||||||
-- on reset, the environment we will use changes the vehicle to control while having the other agents follow their true data (expert controller)
|
|
||||||
---- Note this can be problematic as it can lead to vehicles behind you crashing into you
|
|
||||||
|
|
||||||
TRAINING
|
|
||||||
---------
|
|
||||||
1. Load pre-trained massive set of transitions
|
|
||||||
-- For all roundabouts
|
|
||||||
-- For all tracks
|
|
||||||
-- For all vehicles
|
|
||||||
-- For all valid timesteps
|
|
||||||
-- Rasterized state (incl. path), action
|
|
||||||
|
|
||||||
2. HGAIL
|
|
||||||
-- For each epoch
|
|
||||||
-- INSTANTIATE A NEW ENVIRONMENT (Roundabout + Track) w/ randomized agent, from set of all expert environments
|
|
||||||
-- Train discriminator off training data + yielded low-level transitions in replay buffer
|
|
||||||
-- Train generator off yielded high-level transitions + summed low-level discriminator rewards
|
|
||||||
|
|
||||||
TESTING
|
|
||||||
----------
|
|
||||||
1. Save average vehicle velocities for all expert vehicles (loop roundabout + track + vehicle, average over time)
|
|
||||||
|
|
||||||
2. Run test suite for: expert, BC, GAIL, RAIL, HGAIL, (and hopefully HRAIL)
|
|
||||||
-- For all roundabouts, tracks
|
|
||||||
-- Get expert velocities for track
|
|
||||||
-- Simulate incrementing agent environment (e.g. on reset, agent +=1)
|
|
||||||
-- Store low-level true joint states, actions, and controlled vehicle index
|
|
||||||
-- Per-vehicle statistics (v_all, v_mean, v_shortfall, a_all, jerk_all, n_collisions, T)
|
|
||||||
-- Aggregate statistics + joint
|
|
||||||
|
|
||||||
Problems
|
|
||||||
-----------
|
|
||||||
Should train without stopping for collisions, however when doing so, end up with policy that always takes decelerate option
|
|
||||||
-- It seems safe at the start of each vehicles sim, but actually it isn't since a car will spawn and hit it
|
|
||||||
Solutions:
|
|
||||||
-- Hold cars from spawning if their spawn location is full
|
|
||||||
-- Start simulations a few seconds later (after cars clear their spawn places) <- Preferred
|
|
||||||
|
|
||||||
Test could run indefinitely if stop_on_collision is off
|
|
||||||
Solution:
|
|
||||||
-- Set maximum episode length in intersimple
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Save massive set of transition raw states beforehand (1 from training, but with raw states)
|
|
||||||
# -- For all roundabouts, tracks
|
|
||||||
# -- For all vehicles, steps
|
|
||||||
# -- Raw vehicle state, action
|
|
||||||
@@ -1,58 +0,0 @@
|
|||||||
|
|
||||||
import stable_baselines3 as sb3
|
|
||||||
from intersim.envs.intersimple import NRasterized
|
|
||||||
|
|
||||||
|
|
||||||
def render_env(model_name='gail_image_multiagent_nocollision', agent=51, environment=NRasterized):
|
|
||||||
"""
|
|
||||||
Render a video from an model, agent, and environment
|
|
||||||
Args:
|
|
||||||
model_name (str): name of the model
|
|
||||||
agent (int): agent to start the video from
|
|
||||||
environment (gym.Env): gym environment class to render environment on
|
|
||||||
"""
|
|
||||||
|
|
||||||
model = sb3.PPO.load(model_name)
|
|
||||||
|
|
||||||
env = environment(stop_on_collision=False, width=36, height=36, m_per_px=2, agent=agent)
|
|
||||||
|
|
||||||
obs = env.reset()
|
|
||||||
i=0
|
|
||||||
while True and i < 600:
|
|
||||||
i+=1
|
|
||||||
action, _states = model.predict(obs)
|
|
||||||
obs, rewards, done, info = env.step(action)
|
|
||||||
env.render(mode='post')
|
|
||||||
if done:
|
|
||||||
break
|
|
||||||
|
|
||||||
env.close(filestr='render/'+model_name+'_agent%i'%(agent))
|
|
||||||
|
|
||||||
def render_options_env(model_name='gail_image_multiagent_nocollision', agent=51, environment=NRasterized):
|
|
||||||
"""
|
|
||||||
Render a video from an model, agent, and environment
|
|
||||||
Args:
|
|
||||||
model_name (str): name of the model
|
|
||||||
agent (int): agent to start the video from
|
|
||||||
environment (gym.Env): gym environment class to render environment on
|
|
||||||
"""
|
|
||||||
|
|
||||||
model = sb3.PPO.load(model_name)
|
|
||||||
|
|
||||||
env = environment(stop_on_collision=False, width=36, height=36, m_per_px=2, agent=agent)
|
|
||||||
|
|
||||||
obs = env.reset()
|
|
||||||
i=0
|
|
||||||
while True and i < 600:
|
|
||||||
i+=1
|
|
||||||
action, _states = model.predict(obs)
|
|
||||||
obs, rewards, done, info = env.step(action)
|
|
||||||
env.render(mode='post')
|
|
||||||
if done:
|
|
||||||
break
|
|
||||||
|
|
||||||
env.close(filestr='render/'+model_name+'_agent%i'%(agent))
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
import fire
|
|
||||||
fire.Fire(render_env)
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
import sys
|
|
||||||
sys.path.append('../../../')
|
|
||||||
from src.util import render_env
|
|
||||||
ALL_OPTIONS = [(v,t) for v in [0,2,4,6,8] for t in [5, 10]]
|
|
||||||
|
|
||||||
def render_wrapper(**kwargs):
|
|
||||||
render_env(**kwargs, options_list=ALL_OPTIONS)
|
|
||||||
|
|
||||||
if __name__=='__main__':
|
|
||||||
import fire
|
|
||||||
fire.Fire(render_wrapper)
|
|
||||||
@@ -1,64 +0,0 @@
|
|||||||
# %%
|
|
||||||
import pathlib
|
|
||||||
import pickle
|
|
||||||
import tempfile
|
|
||||||
|
|
||||||
import stable_baselines3 as sb3
|
|
||||||
from stable_baselines3.common.env_util import make_vec_env
|
|
||||||
|
|
||||||
from imitation.algorithms import adversarial, bc
|
|
||||||
from imitation.data import rollout
|
|
||||||
from imitation.util import logger
|
|
||||||
|
|
||||||
from intersim.envs.intersimple import IntersimpleReward
|
|
||||||
|
|
||||||
model_name = 'airl_flat'
|
|
||||||
|
|
||||||
# Load pickled test demonstrations.
|
|
||||||
with open("data/NormalizedIntersimpleExpert_IntersimpleRewardAgent51.pkl", "rb") as f:
|
|
||||||
# This is a list of `imitation.data.types.Trajectory`, where
|
|
||||||
# every instance contains observations and actions for a single expert
|
|
||||||
# demonstration.
|
|
||||||
trajectories = pickle.load(f)
|
|
||||||
|
|
||||||
# %%
|
|
||||||
# Convert List[types.Trajectory] to an instance of `imitation.data.types.Transitions`.
|
|
||||||
# This is a more general dataclass containing unordered
|
|
||||||
# (observation, actions, next_observation) transitions.
|
|
||||||
transitions = rollout.flatten_trajectories(trajectories)
|
|
||||||
|
|
||||||
venv = make_vec_env(IntersimpleReward, n_envs=2, env_kwargs={'agent': 51})
|
|
||||||
|
|
||||||
tempdir = tempfile.TemporaryDirectory(prefix="quickstart")
|
|
||||||
tempdir_path = pathlib.Path(tempdir.name)
|
|
||||||
print(f"All Tensorboards and logging are being written inside {tempdir_path}/.")
|
|
||||||
|
|
||||||
# Train AIRL on expert data.
|
|
||||||
# GAIL, and AIRL also accept as `expert_data` any Pytorch-style DataLoader that
|
|
||||||
# iterates over dictionaries containing observations, actions, and next_observations.
|
|
||||||
logger.configure(tempdir_path / "AIRL/")
|
|
||||||
airl_trainer = adversarial.AIRL(
|
|
||||||
venv,
|
|
||||||
expert_data=transitions,
|
|
||||||
expert_batch_size=64,
|
|
||||||
gen_algo=sb3.PPO("MlpPolicy", venv, verbose=1, n_steps=1024), # n_steps = 2048 ?
|
|
||||||
)
|
|
||||||
airl_trainer.train(total_timesteps=100000)
|
|
||||||
airl_trainer.gen_algo.save(model_name)
|
|
||||||
|
|
||||||
del airl_trainer
|
|
||||||
|
|
||||||
# %%
|
|
||||||
model = sb3.PPO.load(model_name)
|
|
||||||
|
|
||||||
env = IntersimpleReward(agent=51)
|
|
||||||
|
|
||||||
obs = env.reset()
|
|
||||||
while True:
|
|
||||||
action, _states = model.predict(obs)
|
|
||||||
obs, rewards, done, info = env.step(action)
|
|
||||||
env.render(mode='post')
|
|
||||||
if done:
|
|
||||||
break
|
|
||||||
|
|
||||||
env.close(filestr='render/'+model_name)
|
|
||||||
Binary file not shown.
@@ -1,59 +0,0 @@
|
|||||||
# %%
|
|
||||||
import pathlib
|
|
||||||
import pickle
|
|
||||||
import tempfile
|
|
||||||
|
|
||||||
import stable_baselines3 as sb3
|
|
||||||
from stable_baselines3.common.env_util import make_vec_env
|
|
||||||
|
|
||||||
from imitation.algorithms import adversarial, bc
|
|
||||||
from imitation.data import rollout
|
|
||||||
from imitation.util import logger
|
|
||||||
|
|
||||||
from intersim.envs.intersimple import IntersimpleReward
|
|
||||||
|
|
||||||
model_name = 'bc_flat'
|
|
||||||
|
|
||||||
# Load pickled test demonstrations.
|
|
||||||
with open("data/NormalizedIntersimpleExpert_IntersimpleRewardAgent51.pkl", "rb") as f:
|
|
||||||
# This is a list of `imitation.data.types.Trajectory`, where
|
|
||||||
# every instance contains observations and actions for a single expert
|
|
||||||
# demonstration.
|
|
||||||
trajectories = pickle.load(f)
|
|
||||||
|
|
||||||
# %%
|
|
||||||
# Convert List[types.Trajectory] to an instance of `imitation.data.types.Transitions`.
|
|
||||||
# This is a more general dataclass containing unordered
|
|
||||||
# (observation, actions, next_observation) transitions.
|
|
||||||
transitions = rollout.flatten_trajectories(trajectories)
|
|
||||||
|
|
||||||
venv = make_vec_env(IntersimpleReward, n_envs=2, env_kwargs={'agent': 51})
|
|
||||||
|
|
||||||
tempdir = tempfile.TemporaryDirectory(prefix="quickstart")
|
|
||||||
tempdir_path = pathlib.Path(tempdir.name)
|
|
||||||
print(f"All Tensorboards and logging are being written inside {tempdir_path}/.")
|
|
||||||
|
|
||||||
# Train BC on expert data.
|
|
||||||
# BC also accepts as `expert_data` any PyTorch-style DataLoader that iterates over
|
|
||||||
# dictionaries containing observations and actions.
|
|
||||||
logger.configure(tempdir_path / "BC/")
|
|
||||||
bc_trainer = bc.BC(venv.observation_space, venv.action_space, expert_data=transitions)
|
|
||||||
bc_trainer.train(n_epochs=1000)
|
|
||||||
bc_trainer.save_policy(model_name)
|
|
||||||
|
|
||||||
del bc_trainer
|
|
||||||
|
|
||||||
# %%
|
|
||||||
model = bc.reconstruct_policy(model_name)
|
|
||||||
|
|
||||||
env = IntersimpleReward(agent=51)
|
|
||||||
|
|
||||||
obs = env.reset()
|
|
||||||
while True:
|
|
||||||
action, _states = model.predict(obs)
|
|
||||||
obs, rewards, done, info = env.step(action)
|
|
||||||
env.render(mode='post')
|
|
||||||
if done:
|
|
||||||
break
|
|
||||||
|
|
||||||
env.close(filestr='render/'+model_name)
|
|
||||||
Binary file not shown.
Binary file not shown.
@@ -1,138 +0,0 @@
|
|||||||
from intersim.envs.intersimple import Intersimple, InfoFilter
|
|
||||||
from stable_baselines3.common.policies import BasePolicy
|
|
||||||
import gym
|
|
||||||
from intersim.envs.intersimple import *
|
|
||||||
from gail.envs import *
|
|
||||||
import imitation.data.rollout as rollout
|
|
||||||
from stable_baselines3.common.vec_env.dummy_vec_env import DummyVecEnv
|
|
||||||
from imitation.data.wrappers import RolloutInfoWrapper
|
|
||||||
|
|
||||||
class IntersimExpert(BasePolicy):
|
|
||||||
|
|
||||||
def __init__(self, intersim_env, mu=0, *args, **kwargs):
|
|
||||||
super().__init__(
|
|
||||||
observation_space=gym.spaces.Space(),
|
|
||||||
action_space=gym.spaces.Space(),
|
|
||||||
*args, **kwargs
|
|
||||||
)
|
|
||||||
self._intersim = intersim_env
|
|
||||||
self._mu = mu
|
|
||||||
|
|
||||||
def forward(self, *args, **kwargs):
|
|
||||||
raise NotImplementedError()
|
|
||||||
|
|
||||||
def _predict(self, *args, **kwargs):
|
|
||||||
raise NotImplementedError()
|
|
||||||
|
|
||||||
def _action(self):
|
|
||||||
target_t = min(self._intersim._ind + 1, len(self._intersim._svt.simstate) - 1)
|
|
||||||
target_state = self._intersim._svt.simstate[target_t]
|
|
||||||
return self._intersim.target_state(target_state, mu=self._mu)
|
|
||||||
|
|
||||||
def predict(self, *args, **kwargs):
|
|
||||||
return self._action(), None
|
|
||||||
|
|
||||||
class IntersimpleExpert(BasePolicy):
|
|
||||||
|
|
||||||
def __init__(self, intersimple_env, mu=0, *args, **kwargs):
|
|
||||||
super().__init__(
|
|
||||||
observation_space=intersimple_env.observation_space,
|
|
||||||
action_space=intersimple_env.action_space,
|
|
||||||
*args, **kwargs
|
|
||||||
)
|
|
||||||
self._intersimple = intersimple_env
|
|
||||||
self._intersim_expert = IntersimExpert(intersimple_env._env, mu=mu)
|
|
||||||
|
|
||||||
def forward(self, *args, **kwargs):
|
|
||||||
raise NotImplementedError()
|
|
||||||
|
|
||||||
def _predict(self, *args, **kwargs):
|
|
||||||
raise NotImplementedError()
|
|
||||||
|
|
||||||
def _action(self):
|
|
||||||
# RandomLocation mixin re-initializes the intersim sub-env
|
|
||||||
self._intersim_expert._intersim = self._intersimple._env
|
|
||||||
return self._intersim_expert._action()[self._intersimple._agent]
|
|
||||||
|
|
||||||
def predict(self, *args, **kwargs):
|
|
||||||
return self._action(), None
|
|
||||||
|
|
||||||
class NormalizedIntersimpleExpert(IntersimpleExpert):
|
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
super().__init__(*args, **kwargs)
|
|
||||||
|
|
||||||
def predict(self, *args, **kwargs):
|
|
||||||
action, _ = super().predict(*args, **kwargs)
|
|
||||||
return self._intersimple._normalize(action), None
|
|
||||||
|
|
||||||
class DummyVecEnvPolicy(BasePolicy):
|
|
||||||
|
|
||||||
def __init__(self, experts):
|
|
||||||
self._experts = [e() for e in experts]
|
|
||||||
|
|
||||||
def forward(self, *args, **kwargs):
|
|
||||||
raise NotImplementedError()
|
|
||||||
|
|
||||||
def _predict(self, *args, **kwargs):
|
|
||||||
raise NotImplementedError()
|
|
||||||
|
|
||||||
def predict(self, *args, **kwargs):
|
|
||||||
predictions = [e.predict() for e in self._experts]
|
|
||||||
actions = [p[0] for p in predictions]
|
|
||||||
states = [p[1] for p in predictions]
|
|
||||||
return actions, states
|
|
||||||
|
|
||||||
def forward(self, *args, **kwargs):
|
|
||||||
raise NotImplementedError()
|
|
||||||
|
|
||||||
def _predict(self, *args, **kwargs):
|
|
||||||
raise NotImplementedError()
|
|
||||||
|
|
||||||
def save_video(env, expert):
|
|
||||||
env.reset()
|
|
||||||
env.render()
|
|
||||||
done = False
|
|
||||||
while not done:
|
|
||||||
actions, _ = expert.predict()
|
|
||||||
_, _, done, _ = env.step(actions)
|
|
||||||
env.render()
|
|
||||||
env.close()
|
|
||||||
|
|
||||||
def demonstrations(expert='NormalizedIntersimpleExpert', env='NRasterizedRandomAgent', path=None, min_timesteps=25000, min_episodes=None, video=False, env_args={}, policy_args={}):
|
|
||||||
"""Rollout and save expert demos.
|
|
||||||
|
|
||||||
Usage:
|
|
||||||
python -m intersimple.expert <flags>
|
|
||||||
|
|
||||||
"""
|
|
||||||
Env = globals()[env]
|
|
||||||
Expert = globals()[expert]
|
|
||||||
|
|
||||||
env = Env(**env_args)
|
|
||||||
info_env = RolloutInfoWrapper(env)
|
|
||||||
venv = DummyVecEnv([lambda: info_env])
|
|
||||||
|
|
||||||
policy = Expert(env, **policy_args)
|
|
||||||
venv_policy = DummyVecEnvPolicy([lambda: policy])
|
|
||||||
|
|
||||||
if video:
|
|
||||||
save_video(env, policy)
|
|
||||||
|
|
||||||
path = path or (policy.__class__.__name__ + '_' + env.__class__.__name__ + '.pkl')
|
|
||||||
include_infos = isinstance(env, InfoFilter)
|
|
||||||
|
|
||||||
rollout.rollout_and_save(
|
|
||||||
path=path,
|
|
||||||
policy=venv_policy,
|
|
||||||
venv=venv,
|
|
||||||
sample_until=rollout.make_sample_until(
|
|
||||||
min_timesteps=min_timesteps,
|
|
||||||
min_episodes=min_episodes,
|
|
||||||
),
|
|
||||||
exclude_infos=not include_infos,
|
|
||||||
)
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
import fire
|
|
||||||
fire.Fire(demonstrations)
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
#python -m expert --env=IntersimpleReward --min_timesteps=200 --env_args='{agent:51}' --path='NormalizedIntersimpleExpert_IntersimpleRewardAgent51.pkl'
|
|
||||||
#python -m expert --env=IntersimpleReward --min_timesteps=200 --env_args='{agent:51}' --policy_args='{mu:0.005}' --path='NormalizedIntersimpleExpert_IntersimpleRewardAgent51Mu.005.pkl'
|
|
||||||
#python -m expert --env=IntersimpleReward --min_timesteps=200 --env_args='{agent:51}' --policy_args='{mu:0.001}' --path='NormalizedIntersimpleExpert_IntersimpleRewardAgent51Mu.001.pkl'
|
|
||||||
#python -m expert --env=NRasterized --min_timesteps=200 --env_args='{agent:51,width:36,height:36,m_per_px:2}' --policy_args='{mu:0.001}' --path='NormalizedIntersimpleExpertMu.001_NRasterizedAgent51w36h36mppx2.pkl'
|
|
||||||
#python -m expert --env=NRasterized --min_timesteps=200 --env_args='{agent:51,width:36,height:36,m_per_px:2}' --policy_args='{mu:0.001}' --path='NormalizedIntersimpleExpertMu.001_NRasterizedAgent51w36h36mppx2.pkl'
|
|
||||||
#python -m expert --env=NRasterized --min_timesteps=3000 --video --env_args='{width:36,height:36,m_per_px:2}' --policy_args='{mu:0.001}' --path='NormalizedIntersimpleExpertMu.001_NRasterizedRandomAgentw36h36mppx2.pkl'
|
|
||||||
#python -m expert --env=NRasterizedRandomAgent --min_timesteps=200 --env_args='{width:36,height:36,m_per_px:2}' --policy_args='{mu:0.001}' --path='NormalizedIntersimpleExpertMu.001_NRasterizedRandomAgentw36h36mppx2.pkl'
|
|
||||||
#python -m expert --env=NRasterizedRandomAgent --min_timesteps=10000 --env_args='{width:36,height:36,m_per_px:2}' --policy_args='{mu:0.001}' --path='NormalizedIntersimpleExpertMu.001N10000_NRasterizedRandomAgentw36h36mppx2.pkl'
|
|
||||||
#python -m expert --env=NRasterizedRouteRandomAgent --min_timesteps=10000 --env_args='{width:70,height:70,m_per_px:1}' --policy_args='{mu:0.001}' --path='NormalizedIntersimpleExpertMu.001N10000_NRasterizedRouteRandomAgentw70h70mppx1.pkl'
|
|
||||||
#python -m expert --env=NRasterizedRouteRandomAgentLocation --min_timesteps=100000 --env_args='{width:70,height:70,m_per_px:1}' --policy_args='{mu:0.001}' --path='NormalizedIntersimpleExpertMu.001N100000_NRasterizedRouteRandomAgentLocationw70h70mppx1.pkl'
|
|
||||||
#python -m expert --env=NRasterizedRouteRandomAgentLocation --min_timesteps=100000 --env_args='{width:70,height:70,m_per_px:1,map_color:128}' --policy_args='{mu:0.001}' --path='NormalizedIntersimpleExpertMu.001N100000_NRasterizedRouteRandomAgentLocationw70h70mppx1mapc128.pkl'
|
|
||||||
#python -m expert --env=NRasterizedRouteSpeedRandomAgentLocation --min_timesteps=10000 --env_args='{width:70,height:70,m_per_px:1,map_color:128,mu:0.001}' --policy_args='{mu:0.001}' --path='NormalizedIntersimpleExpertMu.001N10000_NRasterizedRouteSpeedRandomAgentLocationw70h70mppx1mapc128mu.001.pkl'
|
|
||||||
#python -m data.expert --env=NRasterizedRouteSpeedRandomAgentLocation --min_timesteps=10000 --env_args='{width:70,height:70,m_per_px:1,map_color:128,mu:0.001,skip_frames:5}' --policy_args='{mu:0.001}' --path='NormalizedIntersimpleExpertMu.001N10000_NRasterizedRouteSpeedRandomAgentLocationw70h70mppx1mapc128mu.001skip5.pkl'
|
|
||||||
#python -m data.expert --env=TLNRasterizedRouteRandomAgentLocation --min_timesteps=100000 --env_args='{width:70,height:70,m_per_px:1,mu:0.001,random_skip:True,max_episode_steps:50}' --policy_args='{mu:0.001}' --path='NormalizedIntersimpleExpertMu.001N100000_TLNRasterizedRouteRandomAgentLocationw70h70mppx1mu.001rskips50.pkl'
|
|
||||||
python -m data.expert --env=TLNRasterizedRouteRandomAgentLocation --min_timesteps=50000 --env_args='{width:70,height:70,m_per_px:1,mu:0.001,random_skip:True,max_episode_steps:50}' --policy_args='{mu:0.001}' --path='NormalizedIntersimpleExpertMu.001N50000_TLNRasterizedRouteRandomAgentLocationw70h70mppx1mu.001rskips50.pkl'
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
import gym
|
|
||||||
from gym.wrappers.time_limit import TimeLimit
|
|
||||||
import numpy as np
|
|
||||||
from intersim.envs.intersimple import NRasterizedRouteRandomAgentLocation, RandomLocation, RandomAgent, RewardVisualization, Reward, \
|
|
||||||
ImageObservationAnimation, RasterizedRoute, NObservations, RasterizedObservation, \
|
|
||||||
NormalizedActionSpace, ActionVisualization, InteractionSimulatorMarkerViz, ImitationCompat, Intersimple
|
|
||||||
|
|
||||||
class RasterizedSpeed:
|
|
||||||
|
|
||||||
def __init__(self, max_speed=12, *args, **kwargs):
|
|
||||||
super().__init__(*args, **kwargs)
|
|
||||||
channels, height, width = self.observation_space.shape
|
|
||||||
self.observation_space = gym.spaces.Box(
|
|
||||||
low=0,
|
|
||||||
high=255,
|
|
||||||
shape=(channels+1, height, width),
|
|
||||||
dtype=np.uint8
|
|
||||||
)
|
|
||||||
self._max_speed = max_speed
|
|
||||||
|
|
||||||
def _simple_obs(self, intersim_obs, intersim_info):
|
|
||||||
img = super()._simple_obs(intersim_obs, intersim_info)
|
|
||||||
|
|
||||||
ego_speed = intersim_obs['state'][self._agent, 2]
|
|
||||||
scaled_speed = (255 * ego_speed) // self._max_speed
|
|
||||||
speed_layer = scaled_speed * np.ones_like(img[:1], dtype=np.uint8)
|
|
||||||
speed_layer = speed_layer.clamp(0, 255)
|
|
||||||
|
|
||||||
obs = np.concatenate((img, speed_layer), axis=0)
|
|
||||||
return obs
|
|
||||||
|
|
||||||
class NRasterizedRouteSpeedRandomAgentLocation(RandomLocation, RandomAgent, RewardVisualization,
|
|
||||||
Reward, ImageObservationAnimation, RasterizedRoute, NObservations, RasterizedSpeed, RasterizedObservation,
|
|
||||||
NormalizedActionSpace, ActionVisualization, InteractionSimulatorMarkerViz, ImitationCompat, Intersimple):
|
|
||||||
pass
|
|
||||||
|
|
||||||
class TransparentTimeLimit(TimeLimit):
|
|
||||||
|
|
||||||
def __getattr__(self, name):
|
|
||||||
return getattr(self.env, name)
|
|
||||||
|
|
||||||
def close(self, *args, **kwargs):
|
|
||||||
return self.env.close(*args, **kwargs)
|
|
||||||
|
|
||||||
def TLNRasterizedRouteRandomAgentLocation(max_episode_steps, *args, **kwargs):
|
|
||||||
return TransparentTimeLimit(NRasterizedRouteRandomAgentLocation(*args, **kwargs), max_episode_steps=max_episode_steps)
|
|
||||||
@@ -1,127 +0,0 @@
|
|||||||
import gym
|
|
||||||
import torch
|
|
||||||
from src.util.collisions import feasible
|
|
||||||
import numpy as np
|
|
||||||
from collections import deque
|
|
||||||
|
|
||||||
def imitation_discriminator(discriminator):
|
|
||||||
return lambda obs, action, next_obs, done: discriminator.discrim_net.predict_reward_train(
|
|
||||||
state=torch.tensor(obs).unsqueeze(0).to(discriminator.discrim_net.device()),
|
|
||||||
action=torch.tensor([[action]]).to(discriminator.discrim_net.device()),
|
|
||||||
next_state=torch.tensor(next_obs).unsqueeze(0).to(discriminator.discrim_net.device()), # unused
|
|
||||||
done=torch.tensor(done).unsqueeze(0).to(discriminator.discrim_net.device()), # unused
|
|
||||||
).item()
|
|
||||||
|
|
||||||
class OptionsEnv(gym.Wrapper):
|
|
||||||
|
|
||||||
def __init__(self, env, options, discriminator, discount, ll_buffer, *args, **kwargs):
|
|
||||||
super().__init__(env, *args, **kwargs)
|
|
||||||
|
|
||||||
self.options = options
|
|
||||||
num_hl_options = len(self.options)
|
|
||||||
self.action_space = gym.spaces.Discrete(num_hl_options)
|
|
||||||
self.observation_space = gym.spaces.Dict({
|
|
||||||
'obs': env.observation_space,
|
|
||||||
'mask': gym.spaces.Box(low=0, high=1, shape=(num_hl_options,)),
|
|
||||||
})
|
|
||||||
|
|
||||||
self.discriminator = discriminator
|
|
||||||
self.discount = discount
|
|
||||||
self.ll_buffer = ll_buffer
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _hl_observation(obs, mask):
|
|
||||||
return {
|
|
||||||
'obs': obs,
|
|
||||||
'mask': mask,
|
|
||||||
}
|
|
||||||
|
|
||||||
def reset(self):
|
|
||||||
self.done = False
|
|
||||||
self.obs = self.env.reset()
|
|
||||||
self.m = available_actions(self.env, self.options)
|
|
||||||
return self._hl_observation(self.obs, self.m)
|
|
||||||
|
|
||||||
def _ll_step(self, action):
|
|
||||||
return self.env.step(action)
|
|
||||||
|
|
||||||
def step(self, action):
|
|
||||||
assert self.m[action]
|
|
||||||
assert not self.done
|
|
||||||
|
|
||||||
plan = list(map(float, generate_plan(self.env, action, self.options)))
|
|
||||||
reward = 0
|
|
||||||
steps = 0
|
|
||||||
|
|
||||||
while not self.done and plan and \
|
|
||||||
(feasible(self.env, safety_plan(self.env, plan)) or self.m.sum() == 1):
|
|
||||||
|
|
||||||
a, plan = plan[0], plan[1:]
|
|
||||||
a = self.env._normalize(a)
|
|
||||||
|
|
||||||
next_obs, _, self.done, info = self._ll_step(a)
|
|
||||||
|
|
||||||
reward += self.discount**steps * self.discriminator(self.obs, a, next_obs, self.done)
|
|
||||||
|
|
||||||
self.ll_buffer.append({
|
|
||||||
'obs': self.obs,
|
|
||||||
'next_obs': next_obs,
|
|
||||||
'acts': np.array((a,)),
|
|
||||||
'dones': np.array(self.done),
|
|
||||||
})
|
|
||||||
|
|
||||||
steps += 1
|
|
||||||
self.obs = next_obs
|
|
||||||
|
|
||||||
self.m = available_actions(self.env, self.options)
|
|
||||||
|
|
||||||
return self._hl_observation(self.obs, self.m), reward, self.done, info
|
|
||||||
|
|
||||||
class RenderOptions(OptionsEnv):
|
|
||||||
|
|
||||||
def __init__(self, env, options, *args, **kwargs):
|
|
||||||
super().__init__(env, options, discriminator=lambda s, a, n, d: 0, discount=1, ll_buffer=deque(maxlen=0), *args, **kwargs)
|
|
||||||
|
|
||||||
def _ll_step(self, action):
|
|
||||||
out = super()._ll_step(action)
|
|
||||||
self.env.render(mode='post')
|
|
||||||
return out
|
|
||||||
|
|
||||||
def close(self, *args, **kwargs):
|
|
||||||
self.env.close(*args, **kwargs)
|
|
||||||
|
|
||||||
def safety_plan(env, plan):
|
|
||||||
return np.concatenate((plan, np.array(5 * [env._env._min_acc])), axis=0)
|
|
||||||
|
|
||||||
def available_actions(env, options):
|
|
||||||
"""Return mask of available actions given current `env` state.
|
|
||||||
Action 0 is considered safe fallback.
|
|
||||||
"""
|
|
||||||
plans = [generate_plan(env, i, options) for i, _ in enumerate(options)]
|
|
||||||
# is emergency braking still possible?
|
|
||||||
plans = list(map(lambda p: safety_plan(env, p), plans))
|
|
||||||
|
|
||||||
T = max(len(p) for p in plans)
|
|
||||||
plans = [np.pad(p, ((0, T-len(p)),), constant_values=np.nan) for p in plans]
|
|
||||||
plans = np.stack(plans, axis=0)
|
|
||||||
|
|
||||||
valid = feasible(env, plans)
|
|
||||||
if not valid.any():
|
|
||||||
valid[0] = True
|
|
||||||
|
|
||||||
return valid
|
|
||||||
|
|
||||||
def target_velocity_plan(current_v: float, target_v: float, t: int, dt: float):
|
|
||||||
"""Smoothly target a velocity in a given number of steps"""
|
|
||||||
# for now, constant acceleration
|
|
||||||
a = (target_v - current_v) / (t * dt)
|
|
||||||
return a*np.ones((t,))
|
|
||||||
|
|
||||||
def generate_plan(env, i, options):
|
|
||||||
"""Generate input profile for high-level action `i`."""
|
|
||||||
assert i < len(options), "Invalid option index {i}"
|
|
||||||
target_v, t = options[i]
|
|
||||||
current_v = env._env.state[env._agent, 1].item() # extract from env
|
|
||||||
plan = target_velocity_plan(current_v, target_v, t, env._env._dt)
|
|
||||||
assert len(plan) == t, "incorrect plan length"
|
|
||||||
return plan
|
|
||||||
@@ -1,70 +0,0 @@
|
|||||||
# %%
|
|
||||||
import pathlib
|
|
||||||
import pickle
|
|
||||||
import tempfile
|
|
||||||
|
|
||||||
import stable_baselines3 as sb3
|
|
||||||
from stable_baselines3.common.env_util import make_vec_env
|
|
||||||
|
|
||||||
from imitation.algorithms import adversarial, bc
|
|
||||||
from imitation.data import rollout
|
|
||||||
from imitation.util import logger
|
|
||||||
|
|
||||||
from intersim.envs.intersimple import IntersimpleReward
|
|
||||||
|
|
||||||
from gail.discriminator import MlpDiscriminator
|
|
||||||
|
|
||||||
model_name = 'gail_flat'
|
|
||||||
|
|
||||||
# %%
|
|
||||||
# Load pickled test demonstrations.
|
|
||||||
with open("data/NormalizedIntersimpleExpert_IntersimpleRewardAgent51.pkl", "rb") as f:
|
|
||||||
# This is a list of `imitation.data.types.Trajectory`, where
|
|
||||||
# every instance contains observations and actions for a single expert
|
|
||||||
# demonstration.
|
|
||||||
trajectories = pickle.load(f)
|
|
||||||
|
|
||||||
# %%
|
|
||||||
# Convert List[types.Trajectory] to an instance of `imitation.data.types.Transitions`.
|
|
||||||
# This is a more general dataclass containing unordered
|
|
||||||
# (observation, actions, next_observation) transitions.
|
|
||||||
transitions = rollout.flatten_trajectories(trajectories)
|
|
||||||
|
|
||||||
venv = make_vec_env(IntersimpleReward, n_envs=2, env_kwargs={'agent': 51})
|
|
||||||
|
|
||||||
tempdir = tempfile.TemporaryDirectory(prefix="quickstart")
|
|
||||||
tempdir_path = pathlib.Path(tempdir.name)
|
|
||||||
print(f"All Tensorboards and logging are being written inside {tempdir_path}/.")
|
|
||||||
|
|
||||||
# Train GAIL on expert data.
|
|
||||||
# GAIL, and AIRL also accept as `expert_data` any Pytorch-style DataLoader that
|
|
||||||
# iterates over dictionaries containing observations, actions, and next_observations.
|
|
||||||
logger.configure(tempdir_path / "GAIL/")
|
|
||||||
gail_trainer = adversarial.GAIL(
|
|
||||||
venv,
|
|
||||||
expert_data=transitions,
|
|
||||||
expert_batch_size=150,
|
|
||||||
n_disc_updates_per_round=32,
|
|
||||||
discrim_kwargs={'discrim_net': MlpDiscriminator()},
|
|
||||||
gen_algo=sb3.PPO("MlpPolicy", venv, verbose=1, n_steps=4530),
|
|
||||||
allow_variable_horizon=True,
|
|
||||||
)
|
|
||||||
gail_trainer.train(total_timesteps=400000)
|
|
||||||
gail_trainer.gen_algo.save(model_name)
|
|
||||||
|
|
||||||
#del gail_trainer
|
|
||||||
|
|
||||||
# %%
|
|
||||||
model = sb3.PPO.load(model_name)
|
|
||||||
|
|
||||||
env = IntersimpleReward(agent=51)
|
|
||||||
|
|
||||||
obs = env.reset()
|
|
||||||
while True:
|
|
||||||
action, _states = model.predict(obs)
|
|
||||||
obs, rewards, done, info = env.step(action)
|
|
||||||
env.render(mode='post')
|
|
||||||
if done:
|
|
||||||
break
|
|
||||||
|
|
||||||
env.close(filestr='render/'+model_name)
|
|
||||||
@@ -1,115 +0,0 @@
|
|||||||
# %%
|
|
||||||
import pathlib
|
|
||||||
import pickle
|
|
||||||
import tempfile
|
|
||||||
|
|
||||||
import stable_baselines3 as sb3
|
|
||||||
from stable_baselines3.common.env_util import make_vec_env
|
|
||||||
|
|
||||||
from imitation.algorithms import adversarial, bc
|
|
||||||
from imitation.data import rollout
|
|
||||||
from imitation.util import logger
|
|
||||||
|
|
||||||
from intersim.envs.intersimple import IntersimpleReward, speed_reward
|
|
||||||
|
|
||||||
from gail.discriminator import MlpDiscriminator
|
|
||||||
import numpy as np
|
|
||||||
import functools
|
|
||||||
from stable_baselines3.common.evaluation import evaluate_policy
|
|
||||||
from ray import tune
|
|
||||||
import os
|
|
||||||
import torch
|
|
||||||
|
|
||||||
model_name = 'gail_flat'
|
|
||||||
|
|
||||||
# %%
|
|
||||||
# Load pickled test demonstrations.
|
|
||||||
#with open("data/NormalizedIntersimpleExpert_IntersimpleRewardAgent51.pkl", "rb") as f:
|
|
||||||
with open("data/NormalizedIntersimpleExpert_IntersimpleRewardAgent51Mu.001.pkl", "rb") as f:
|
|
||||||
# This is a list of `imitation.data.types.Trajectory`, where
|
|
||||||
# every instance contains observations and actions for a single expert
|
|
||||||
# demonstration.
|
|
||||||
trajectories = pickle.load(f)
|
|
||||||
|
|
||||||
# %%
|
|
||||||
# Convert List[types.Trajectory] to an instance of `imitation.data.types.Transitions`.
|
|
||||||
# This is a more general dataclass containing unordered
|
|
||||||
# (observation, actions, next_observation) transitions.
|
|
||||||
transitions = rollout.flatten_trajectories(trajectories)
|
|
||||||
|
|
||||||
venv = make_vec_env(IntersimpleReward, n_envs=2, env_kwargs={'agent': 51})
|
|
||||||
|
|
||||||
tempdir = tempfile.TemporaryDirectory(prefix="quickstart")
|
|
||||||
tempdir_path = pathlib.Path(tempdir.name)
|
|
||||||
print(f"All Tensorboards and logging are being written inside {tempdir_path}/.")
|
|
||||||
|
|
||||||
def training_function(config, checkpoint_dir=None):
|
|
||||||
logger.configure(tempdir_path / "GAIL/")
|
|
||||||
|
|
||||||
discriminator = MlpDiscriminator()
|
|
||||||
if checkpoint_dir:
|
|
||||||
discriminator.load_state_dict(torch.load(os.path.join(checkpoint_dir, 'disc_checkpoint')))
|
|
||||||
generator = sb3.PPO.load(os.path.join(checkpoint_dir, 'gen_checkpoint'))
|
|
||||||
else:
|
|
||||||
generator = sb3.PPO("MlpPolicy", venv, verbose=1, n_steps=config['n_steps'])
|
|
||||||
|
|
||||||
gail_trainer = adversarial.GAIL(
|
|
||||||
venv,
|
|
||||||
expert_data=transitions,
|
|
||||||
expert_batch_size=config['expert_batch_size'],
|
|
||||||
n_disc_updates_per_round=config['n_disc_updates_per_round'],
|
|
||||||
discrim_kwargs={'discrim_net': MlpDiscriminator()},
|
|
||||||
gen_algo=generator,
|
|
||||||
allow_variable_horizon=True,
|
|
||||||
)
|
|
||||||
|
|
||||||
def callback(epoch):
|
|
||||||
print("callback")
|
|
||||||
eval_env = IntersimpleReward(agent=51, reward=functools.partial(speed_reward, collision_penalty=0.))
|
|
||||||
#sync_envs_normalization(self.training_env, self.eval_env)
|
|
||||||
episode_rewards, episode_lengths = evaluate_policy(generator, eval_env, return_episode_rewards=True)
|
|
||||||
tune.report(
|
|
||||||
reward=np.mean(episode_rewards),
|
|
||||||
length=np.mean(episode_lengths),
|
|
||||||
training_iteration=epoch,
|
|
||||||
)
|
|
||||||
|
|
||||||
with tune.checkpoint_dir(step=epoch) as checkpoint_dir:
|
|
||||||
gail_trainer.gen_algo.save(os.path.join(checkpoint_dir, 'gen_checkpoint'))
|
|
||||||
torch.save(discriminator.state_dict(), os.path.join(checkpoint_dir, 'disc_checkpoint'))
|
|
||||||
|
|
||||||
gail_trainer.train(total_timesteps=40000, callback=callback)
|
|
||||||
|
|
||||||
analysis = tune.run(
|
|
||||||
training_function,
|
|
||||||
config = {
|
|
||||||
'expert_batch_size': tune.randint(1, 22), #220,
|
|
||||||
'n_disc_updates_per_round': tune.randint(2, 100), #16,
|
|
||||||
'n_steps': tune.randint(1, 10000), #4096,
|
|
||||||
},
|
|
||||||
resources_per_trial={
|
|
||||||
'cpu': 1,
|
|
||||||
# 'gpu': 1,
|
|
||||||
},
|
|
||||||
local_dir='ray',
|
|
||||||
num_samples=10,
|
|
||||||
)
|
|
||||||
|
|
||||||
print('Best config', analysis.get_best_config(metric='progress', mode='max'))
|
|
||||||
|
|
||||||
#del gail_trainer
|
|
||||||
|
|
||||||
# %%
|
|
||||||
model = sb3.PPO.load(model_name)
|
|
||||||
|
|
||||||
env = IntersimpleReward(agent=51)
|
|
||||||
|
|
||||||
obs = env.reset()
|
|
||||||
while True:
|
|
||||||
action, _states = model.predict(obs)
|
|
||||||
obs, rewards, done, info = env.step(action)
|
|
||||||
env.render(mode='post')
|
|
||||||
if done:
|
|
||||||
break
|
|
||||||
|
|
||||||
env.close(filestr='render/'+model_name)
|
|
||||||
@@ -1,70 +0,0 @@
|
|||||||
# %%
|
|
||||||
import pathlib
|
|
||||||
import pickle
|
|
||||||
import tempfile
|
|
||||||
|
|
||||||
import stable_baselines3 as sb3
|
|
||||||
from stable_baselines3.common.env_util import make_vec_env
|
|
||||||
|
|
||||||
from imitation.algorithms import adversarial, bc
|
|
||||||
from imitation.data import rollout
|
|
||||||
from imitation.util import logger
|
|
||||||
|
|
||||||
from intersim.envs.intersimple import NRasterized
|
|
||||||
|
|
||||||
from gail.discriminator import CnnDiscriminator
|
|
||||||
|
|
||||||
model_name = 'gail_image'
|
|
||||||
|
|
||||||
# %%
|
|
||||||
# Load pickled test demonstrations.
|
|
||||||
with open("data/NormalizedIntersimpleExpertMu.001_NRasterizedAgent51w36h36mppx2.pkl", "rb") as f:
|
|
||||||
# This is a list of `imitation.data.types.Trajectory`, where
|
|
||||||
# every instance contains observations and actions for a single expert
|
|
||||||
# demonstration.
|
|
||||||
trajectories = pickle.load(f)
|
|
||||||
|
|
||||||
# %%
|
|
||||||
# Convert List[types.Trajectory] to an instance of `imitation.data.types.Transitions`.
|
|
||||||
# This is a more general dataclass containing unordered
|
|
||||||
# (observation, actions, next_observation) transitions.
|
|
||||||
transitions = rollout.flatten_trajectories(trajectories)
|
|
||||||
|
|
||||||
venv = make_vec_env(NRasterized, n_envs=2, env_kwargs={'agent': 51, 'width': 36, 'height': 36, 'm_per_px': 2})
|
|
||||||
|
|
||||||
tempdir = tempfile.TemporaryDirectory(prefix="quickstart")
|
|
||||||
tempdir_path = pathlib.Path(tempdir.name)
|
|
||||||
print(f"All Tensorboards and logging are being written inside {tempdir_path}/.")
|
|
||||||
|
|
||||||
# Train GAIL on expert data.
|
|
||||||
# GAIL, and AIRL also accept as `expert_data` any Pytorch-style DataLoader that
|
|
||||||
# iterates over dictionaries containing observations, actions, and next_observations.
|
|
||||||
logger.configure(tempdir_path / "GAIL/")
|
|
||||||
gail_trainer = adversarial.GAIL(
|
|
||||||
venv,
|
|
||||||
expert_data=transitions,
|
|
||||||
expert_batch_size=32,
|
|
||||||
#n_disc_updates_per_round=2048,
|
|
||||||
discrim_kwargs={'discrim_net': CnnDiscriminator(venv)},
|
|
||||||
gen_algo=sb3.PPO("CnnPolicy", venv, verbose=1, n_steps=1024),
|
|
||||||
allow_variable_horizon=True,
|
|
||||||
)
|
|
||||||
gail_trainer.train(total_timesteps=100000)
|
|
||||||
gail_trainer.gen_algo.save(model_name)
|
|
||||||
|
|
||||||
#del gail_trainer
|
|
||||||
|
|
||||||
# %%
|
|
||||||
model = sb3.PPO.load(model_name)
|
|
||||||
|
|
||||||
env = NRasterized(agent=51, width=36, height=36, m_per_px=2)
|
|
||||||
|
|
||||||
obs = env.reset()
|
|
||||||
while True:
|
|
||||||
action, _states = model.predict(obs)
|
|
||||||
obs, rewards, done, info = env.step(action)
|
|
||||||
env.render(mode='post')
|
|
||||||
if done:
|
|
||||||
break
|
|
||||||
|
|
||||||
env.close(filestr='render/'+model_name)
|
|
||||||
@@ -1,70 +0,0 @@
|
|||||||
# %%
|
|
||||||
import pathlib
|
|
||||||
import pickle
|
|
||||||
import tempfile
|
|
||||||
|
|
||||||
import stable_baselines3 as sb3
|
|
||||||
from stable_baselines3.common.env_util import make_vec_env
|
|
||||||
|
|
||||||
from imitation.algorithms import adversarial, bc
|
|
||||||
from imitation.data import rollout
|
|
||||||
from imitation.util import logger
|
|
||||||
|
|
||||||
from intersim.envs.intersimple import NRasterized
|
|
||||||
|
|
||||||
from gail.discriminator import CnnDiscriminatorFlatAction
|
|
||||||
|
|
||||||
model_name = 'gail_image_multiagent_nocollision'
|
|
||||||
|
|
||||||
# %%
|
|
||||||
# Load pickled test demonstrations.
|
|
||||||
with open("data/NormalizedIntersimpleExpertMu.001_NRasterizedRandomAgentw36h36mppx2.pkl", "rb") as f:
|
|
||||||
# This is a list of `imitation.data.types.Trajectory`, where
|
|
||||||
# every instance contains observations and actions for a single expert
|
|
||||||
# demonstration.
|
|
||||||
trajectories = pickle.load(f)
|
|
||||||
|
|
||||||
# %%
|
|
||||||
# Convert List[types.Trajectory] to an instance of `imitation.data.types.Transitions`.
|
|
||||||
# This is a more general dataclass containing unordered
|
|
||||||
# (observation, actions, next_observation) transitions.
|
|
||||||
transitions = rollout.flatten_trajectories(trajectories)
|
|
||||||
|
|
||||||
venv = make_vec_env(NRasterized, n_envs=2, env_kwargs={'stop_on_collision':False, 'width': 36, 'height': 36, 'm_per_px': 2})
|
|
||||||
|
|
||||||
tempdir = tempfile.TemporaryDirectory(prefix="quickstart")
|
|
||||||
tempdir_path = pathlib.Path(tempdir.name)
|
|
||||||
print(f"All Tensorboards and logging are being written inside {tempdir_path}/.")
|
|
||||||
|
|
||||||
# Train GAIL on expert data.
|
|
||||||
# GAIL, and AIRL also accept as `expert_data` any Pytorch-style DataLoader that
|
|
||||||
# iterates over dictionaries containing observations, actions, and next_observations.
|
|
||||||
logger.configure(tempdir_path / "GAIL/")
|
|
||||||
gail_trainer = adversarial.GAIL(
|
|
||||||
venv,
|
|
||||||
expert_data=transitions,
|
|
||||||
expert_batch_size=32,
|
|
||||||
#n_disc_updates_per_round=2048,
|
|
||||||
discrim_kwargs={'discrim_net': CnnDiscriminatorFlatAction(venv)},
|
|
||||||
gen_algo=sb3.PPO("CnnPolicy", venv, verbose=1, n_steps=1024),
|
|
||||||
allow_variable_horizon=True,
|
|
||||||
)
|
|
||||||
gail_trainer.train(total_timesteps=100000)
|
|
||||||
gail_trainer.gen_algo.save(model_name)
|
|
||||||
|
|
||||||
#del gail_trainer
|
|
||||||
|
|
||||||
# %%
|
|
||||||
model = sb3.PPO.load(model_name)
|
|
||||||
|
|
||||||
env = NRasterized(stop_on_collision=False, width=36, height=36, m_per_px=2)
|
|
||||||
|
|
||||||
obs = env.reset()
|
|
||||||
while True:
|
|
||||||
action, _states = model.predict(obs)
|
|
||||||
obs, rewards, done, info = env.step(action)
|
|
||||||
env.render(mode='post')
|
|
||||||
if done:
|
|
||||||
break
|
|
||||||
|
|
||||||
env.close(filestr='render/'+model_name)
|
|
||||||
@@ -1,79 +0,0 @@
|
|||||||
# %%
|
|
||||||
import pathlib
|
|
||||||
import pickle
|
|
||||||
import tempfile
|
|
||||||
|
|
||||||
import stable_baselines3 as sb3
|
|
||||||
from stable_baselines3.common.env_util import make_vec_env
|
|
||||||
|
|
||||||
from imitation.algorithms import adversarial, bc
|
|
||||||
from imitation.data import rollout
|
|
||||||
from imitation.util import logger
|
|
||||||
|
|
||||||
from intersim.envs.intersimple import NRasterizedRandomAgent, IntersimpleReward, speed_reward
|
|
||||||
import functools
|
|
||||||
from stable_baselines3.common.evaluation import evaluate_policy
|
|
||||||
|
|
||||||
from gail.discriminator import CnnDiscriminator
|
|
||||||
|
|
||||||
model_name = 'gail_image_random'
|
|
||||||
|
|
||||||
# %%
|
|
||||||
# Load pickled test demonstrations.
|
|
||||||
with open("data/NormalizedIntersimpleExpertMu.001_NRasterizedRandomAgentw36h36mppx2.pkl", "rb") as f:
|
|
||||||
# This is a list of `imitation.data.types.Trajectory`, where
|
|
||||||
# every instance contains observations and actions for a single expert
|
|
||||||
# demonstration.
|
|
||||||
trajectories = pickle.load(f)
|
|
||||||
|
|
||||||
# %%
|
|
||||||
# Convert List[types.Trajectory] to an instance of `imitation.data.types.Transitions`.
|
|
||||||
# This is a more general dataclass containing unordered
|
|
||||||
# (observation, actions, next_observation) transitions.
|
|
||||||
transitions = rollout.flatten_trajectories(trajectories)
|
|
||||||
|
|
||||||
env_kwargs = {'width': 36, 'height': 36, 'm_per_px': 2}
|
|
||||||
venv = make_vec_env(NRasterizedRandomAgent, n_envs=2, env_kwargs=env_kwargs)
|
|
||||||
|
|
||||||
tempdir = tempfile.TemporaryDirectory(prefix="quickstart")
|
|
||||||
tempdir_path = pathlib.Path(tempdir.name)
|
|
||||||
print(f"All Tensorboards and logging are being written inside {tempdir_path}/.")
|
|
||||||
|
|
||||||
# Train GAIL on expert data.
|
|
||||||
# GAIL, and AIRL also accept as `expert_data` any Pytorch-style DataLoader that
|
|
||||||
# iterates over dictionaries containing observations, actions, and next_observations.
|
|
||||||
logger.configure(tempdir_path / "GAIL/")
|
|
||||||
generator = sb3.PPO("CnnPolicy", venv, verbose=1, n_steps=1024)
|
|
||||||
gail_trainer = adversarial.GAIL(
|
|
||||||
venv,
|
|
||||||
expert_data=transitions,
|
|
||||||
expert_batch_size=32,
|
|
||||||
#n_disc_updates_per_round=2048,
|
|
||||||
discrim_kwargs={'discrim_net': CnnDiscriminator(venv)},
|
|
||||||
gen_algo=generator,
|
|
||||||
allow_variable_horizon=True,
|
|
||||||
)
|
|
||||||
def callback(round):
|
|
||||||
eval_env = NRasterizedRandomAgent(reward=functools.partial(speed_reward, collision_penalty=0.), **env_kwargs)
|
|
||||||
#sync_envs_normalization(self.training_env, self.eval_env)
|
|
||||||
episode_rewards, episode_lengths = evaluate_policy(generator, eval_env, return_episode_rewards=True)
|
|
||||||
|
|
||||||
gail_trainer.train(total_timesteps=100000, callback=callback)
|
|
||||||
gail_trainer.gen_algo.save(model_name)
|
|
||||||
|
|
||||||
#del gail_trainer
|
|
||||||
|
|
||||||
# %%
|
|
||||||
model = sb3.PPO.load(model_name)
|
|
||||||
|
|
||||||
env = NRasterizedRandomAgent(width=36, height=36, m_per_px=2)
|
|
||||||
|
|
||||||
obs = env.reset()
|
|
||||||
while True:
|
|
||||||
action, _states = model.predict(obs)
|
|
||||||
obs, rewards, done, info = env.step(action)
|
|
||||||
env.render(mode='post')
|
|
||||||
if done:
|
|
||||||
break
|
|
||||||
|
|
||||||
env.close(filestr='render/'+model_name)
|
|
||||||
@@ -1,171 +0,0 @@
|
|||||||
# %%
|
|
||||||
import pathlib
|
|
||||||
import pickle
|
|
||||||
import tempfile
|
|
||||||
import os
|
|
||||||
import random
|
|
||||||
import numpy as np
|
|
||||||
import torch
|
|
||||||
|
|
||||||
# set up ray tune
|
|
||||||
import ray
|
|
||||||
from ray import tune
|
|
||||||
from ray.tune import Analysis, ExperimentAnalysis
|
|
||||||
from ray.tune.schedulers import ASHAScheduler
|
|
||||||
from ray.tune.suggest.hyperopt import HyperOptSearch
|
|
||||||
from ray.tune.suggest import ConcurrencyLimiter
|
|
||||||
|
|
||||||
import stable_baselines3 as sb3
|
|
||||||
from stable_baselines3.common.env_util import make_vec_env
|
|
||||||
|
|
||||||
|
|
||||||
from imitation.algorithms import adversarial, bc
|
|
||||||
from imitation.data import rollout
|
|
||||||
from imitation.util import logger
|
|
||||||
|
|
||||||
from intersim.envs.intersimple import NRasterizedRandomAgent, IntersimpleReward, speed_reward, NRasterized, NRasterizedRandomAgentVerbose
|
|
||||||
import functools
|
|
||||||
from stable_baselines3.common.evaluation import evaluate_policy
|
|
||||||
from gym.wrappers import TimeLimit
|
|
||||||
|
|
||||||
from gail.discriminator import CnnDiscriminator
|
|
||||||
|
|
||||||
model_name = 'gail_image_random_ray'
|
|
||||||
env_kwargs={'width': 36, 'height': 36, 'm_per_px': 2}
|
|
||||||
|
|
||||||
# %%
|
|
||||||
|
|
||||||
import argparse
|
|
||||||
parser = argparse.ArgumentParser()
|
|
||||||
parser.add_argument("--outdir", help="result directory", default='ray')
|
|
||||||
parser.add_argument("--test", help="test run", default=False, action="store_true")
|
|
||||||
args = parser.parse_args()
|
|
||||||
outdir = args.outdir
|
|
||||||
|
|
||||||
# %%
|
|
||||||
# Load pickled test demonstrations.
|
|
||||||
with open("data/NormalizedIntersimpleExpertMu.001N10000_NRasterizedRandomAgentw36h36mppx2.pkl", "rb") as f:
|
|
||||||
# This is a list of `imitation.data.types.Trajectory`, where
|
|
||||||
# every instance contains observations and actions for a single expert
|
|
||||||
# demonstration.
|
|
||||||
trajectories = pickle.load(f)
|
|
||||||
|
|
||||||
# Convert List[types.Trajectory] to an instance of `imitation.data.types.Transitions`.
|
|
||||||
# This is a more general dataclass containing unordered
|
|
||||||
# (observation, actions, next_observation) transitions.
|
|
||||||
transitions = rollout.flatten_trajectories(trajectories)
|
|
||||||
# Store transitions in shared ray memory
|
|
||||||
ray_transitions = ray.put(transitions)
|
|
||||||
|
|
||||||
# %%
|
|
||||||
venv = make_vec_env(NRasterizedRandomAgent, n_envs=2, env_kwargs=env_kwargs)
|
|
||||||
|
|
||||||
tempdir = tempfile.TemporaryDirectory(prefix="quickstart")
|
|
||||||
tempdir_path = pathlib.Path(tempdir.name)
|
|
||||||
print(f"All Tensorboards and logging are being written inside {tempdir_path}/.")
|
|
||||||
logger.configure(tempdir_path / "GAIL/")
|
|
||||||
|
|
||||||
def get_ray_config(test=False):
|
|
||||||
if test:
|
|
||||||
return {
|
|
||||||
'expert_batch_size': 2,
|
|
||||||
'ppo_n_steps': 2,
|
|
||||||
'ppo_batch_size': 2,
|
|
||||||
'ppo_n_epochs': 1,
|
|
||||||
'total_timesteps': 10,
|
|
||||||
}
|
|
||||||
else:
|
|
||||||
return {
|
|
||||||
'expert_batch_size': tune.choice([2**x for x in range(6,10)]),
|
|
||||||
'ppo_n_steps': tune.choice([2048, 3072, 4096]),
|
|
||||||
'ppo_batch_size': tune.choice([2**x for x in range(9,13)]),
|
|
||||||
'ppo_n_epochs': tune.choice([6,10]),
|
|
||||||
'total_timesteps': 400_000,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def ray_train(config, checkpoint_dir=None):
|
|
||||||
# Train GAIL on expert data.
|
|
||||||
# GAIL, and AIRL also accept as `expert_data` any Pytorch-style DataLoader that
|
|
||||||
# iterates over dictionaries containing observations, actions, and next_observations.
|
|
||||||
|
|
||||||
discriminator = CnnDiscriminator(venv)
|
|
||||||
if checkpoint_dir:
|
|
||||||
discriminator.load_state_dict(torch.load(os.path.join(checkpoint_dir, 'disc_checkpoint')))
|
|
||||||
generator = sb3.PPO.load(os.path.join(checkpoint_dir, 'gen_checkpoint'))
|
|
||||||
else:
|
|
||||||
generator = sb3.PPO(
|
|
||||||
"CnnPolicy", venv, verbose=0,
|
|
||||||
n_steps=config["ppo_n_steps"],
|
|
||||||
batch_size=config["ppo_batch_size"],
|
|
||||||
n_epochs=config["ppo_n_epochs"]
|
|
||||||
)
|
|
||||||
gail_trainer = adversarial.GAIL(
|
|
||||||
venv,
|
|
||||||
expert_data=ray.get(ray_transitions),
|
|
||||||
expert_batch_size=config["expert_batch_size"],
|
|
||||||
#n_disc_updates_per_round=2048,
|
|
||||||
discrim_kwargs={'discrim_net': discriminator},
|
|
||||||
gen_algo=generator,
|
|
||||||
allow_variable_horizon=True,
|
|
||||||
)
|
|
||||||
def callback(round):
|
|
||||||
# eval_env = NRasterized(agent=51, reward=functools.partial(speed_reward, collision_penalty=0.), **env_kwargs)
|
|
||||||
eval_env = TimeLimit(NRasterizedRandomAgent(reward=functools.partial(speed_reward, collision_penalty=0.), **env_kwargs), max_episode_steps=1000)
|
|
||||||
episode_rewards, episode_lengths = evaluate_policy(generator, eval_env, return_episode_rewards=True)
|
|
||||||
tune.report(
|
|
||||||
reward=np.mean(episode_rewards),
|
|
||||||
length=np.mean(episode_lengths),
|
|
||||||
training_iteration=round,
|
|
||||||
)
|
|
||||||
with tune.checkpoint_dir(step=round) as checkpoint_dir:
|
|
||||||
gail_trainer.gen_algo.save(os.path.join(checkpoint_dir, 'gen_checkpoint'))
|
|
||||||
torch.save(discriminator.state_dict(), os.path.join(checkpoint_dir, 'disc_checkpoint'))
|
|
||||||
|
|
||||||
gail_trainer.train(total_timesteps=config['total_timesteps'], callback=callback)
|
|
||||||
|
|
||||||
|
|
||||||
ray_config = get_ray_config(args.test)
|
|
||||||
search = HyperOptSearch(ray_config, metric='length', mode="max",)
|
|
||||||
search = ConcurrencyLimiter(search, max_concurrent=10)
|
|
||||||
custom_scheduler = ASHAScheduler(time_attr='training_iteration', metric='length', mode="max", grace_period=15)
|
|
||||||
|
|
||||||
analysis = tune.run(
|
|
||||||
ray_train,
|
|
||||||
# config=ray_config,
|
|
||||||
search_alg=search,
|
|
||||||
scheduler=custom_scheduler,
|
|
||||||
local_dir=outdir,
|
|
||||||
resources_per_trial={"cpu":10, "gpu": 0.2},
|
|
||||||
num_samples=1 if args.test else 100,
|
|
||||||
)
|
|
||||||
|
|
||||||
del analysis
|
|
||||||
|
|
||||||
# %%
|
|
||||||
# outdir = "ray/ray_train_2021-09-20_13-33-50/ray_train_f06785b0_33_expert_batch_size=128,ppo_batch_size=1024,ppo_n_epochs=6,ppo_n_steps=2048,total_timesteps=400000_2021-09-20_15-52-05"
|
|
||||||
|
|
||||||
# %%
|
|
||||||
analysis = Analysis(outdir, default_metric="length", default_mode="max")
|
|
||||||
filepath = analysis.get_best_logdir()
|
|
||||||
print("Best ray experiment:", filepath)
|
|
||||||
config = analysis.get_best_config()
|
|
||||||
print("Best config:", config)
|
|
||||||
|
|
||||||
# %%
|
|
||||||
|
|
||||||
model = sb3.PPO.load(os.path.join(analysis.get_last_checkpoint(), 'gen_checkpoint'))
|
|
||||||
|
|
||||||
# env = NRasterized(agent=51, **env_kwargs)
|
|
||||||
env = TimeLimit(NRasterizedRandomAgent(reward=functools.partial(speed_reward, collision_penalty=0.), **env_kwargs), max_episode_steps=1000)
|
|
||||||
obs = env.reset()
|
|
||||||
while True:
|
|
||||||
action, _states = model.predict(obs)
|
|
||||||
obs, rewards, done, info = env.step(action)
|
|
||||||
env.render(mode='post')
|
|
||||||
if done:
|
|
||||||
break
|
|
||||||
|
|
||||||
env.env.close(filestr='render/'+model_name)
|
|
||||||
# %%
|
|
||||||
|
|
||||||
@@ -1,70 +0,0 @@
|
|||||||
# %%
|
|
||||||
import pathlib
|
|
||||||
import pickle
|
|
||||||
import tempfile
|
|
||||||
|
|
||||||
import stable_baselines3 as sb3
|
|
||||||
from stable_baselines3.common.env_util import make_vec_env
|
|
||||||
|
|
||||||
from imitation.algorithms import adversarial, bc
|
|
||||||
from imitation.data import rollout
|
|
||||||
from imitation.util import logger
|
|
||||||
|
|
||||||
from intersim.envs.intersimple import NRasterized
|
|
||||||
|
|
||||||
from gail.discriminator import CnnDiscriminator
|
|
||||||
|
|
||||||
model_name = 'gail_image_singleagent_nocollision'
|
|
||||||
|
|
||||||
# %%
|
|
||||||
# Load pickled test demonstrations.
|
|
||||||
with open("data/NormalizedIntersimpleExpertMu.001_NRasterizedAgent51w36h36mppx2.pkl", "rb") as f:
|
|
||||||
# This is a list of `imitation.data.types.Trajectory`, where
|
|
||||||
# every instance contains observations and actions for a single expert
|
|
||||||
# demonstration.
|
|
||||||
trajectories = pickle.load(f)
|
|
||||||
|
|
||||||
# %%
|
|
||||||
# Convert List[types.Trajectory] to an instance of `imitation.data.types.Transitions`.
|
|
||||||
# This is a more general dataclass containing unordered
|
|
||||||
# (observation, actions, next_observation) transitions.
|
|
||||||
transitions = rollout.flatten_trajectories(trajectories)
|
|
||||||
|
|
||||||
venv = make_vec_env(NRasterized, n_envs=2, env_kwargs={'agent':51, 'stop_on_collision':False, 'width': 36, 'height': 36, 'm_per_px': 2})
|
|
||||||
|
|
||||||
tempdir = tempfile.TemporaryDirectory(prefix="quickstart")
|
|
||||||
tempdir_path = pathlib.Path(tempdir.name)
|
|
||||||
print(f"All Tensorboards and logging are being written inside {tempdir_path}/.")
|
|
||||||
|
|
||||||
# Train GAIL on expert data.
|
|
||||||
# GAIL, and AIRL also accept as `expert_data` any Pytorch-style DataLoader that
|
|
||||||
# iterates over dictionaries containing observations, actions, and next_observations.
|
|
||||||
logger.configure(tempdir_path / "GAIL/")
|
|
||||||
gail_trainer = adversarial.GAIL(
|
|
||||||
venv,
|
|
||||||
expert_data=transitions,
|
|
||||||
expert_batch_size=32,
|
|
||||||
#n_disc_updates_per_round=2048,
|
|
||||||
discrim_kwargs={'discrim_net': CnnDiscriminator(venv)},
|
|
||||||
gen_algo=sb3.PPO("CnnPolicy", venv, verbose=1, n_steps=1024),
|
|
||||||
allow_variable_horizon=True,
|
|
||||||
)
|
|
||||||
gail_trainer.train(total_timesteps=100000)
|
|
||||||
gail_trainer.gen_algo.save(model_name)
|
|
||||||
|
|
||||||
#del gail_trainer
|
|
||||||
|
|
||||||
# %%
|
|
||||||
model = sb3.PPO.load(model_name)
|
|
||||||
|
|
||||||
env = NRasterized(agent=51, width=36, height=36, m_per_px=2, stop_on_collision=False)
|
|
||||||
|
|
||||||
obs = env.reset()
|
|
||||||
while True:
|
|
||||||
action, _states = model.predict(obs)
|
|
||||||
obs, rewards, done, info = env.step(action)
|
|
||||||
env.render(mode='post')
|
|
||||||
if done:
|
|
||||||
break
|
|
||||||
|
|
||||||
env.close(filestr='render/'+model_name)
|
|
||||||
@@ -1,90 +0,0 @@
|
|||||||
# %%
|
|
||||||
import sys
|
|
||||||
sys.path.append('../../../')
|
|
||||||
|
|
||||||
from src.discriminator import CnnDiscriminator, CnnDiscriminatorFlatAction
|
|
||||||
from imitation.algorithms import adversarial
|
|
||||||
import stable_baselines3
|
|
||||||
import torch.utils.data
|
|
||||||
import numpy as np
|
|
||||||
from intersim.envs.intersimple import NRasterized
|
|
||||||
import itertools
|
|
||||||
from torch.distributions import Categorical
|
|
||||||
import gym
|
|
||||||
import torch
|
|
||||||
import pickle
|
|
||||||
import imitation.data.rollout as rollout
|
|
||||||
import tempfile
|
|
||||||
import pathlib
|
|
||||||
from imitation.util import logger
|
|
||||||
from stable_baselines3.common.env_util import make_vec_env
|
|
||||||
from tqdm import tqdm
|
|
||||||
from src.policies.options import OptionsCnnPolicy
|
|
||||||
from src.gail.options import OptionsEnv, LLOptions, HLOptions, RenderOptions
|
|
||||||
from src.gail.train import train_discriminator, train_generator
|
|
||||||
|
|
||||||
model_name = 'gail_options_image'
|
|
||||||
env_settings = {'agent': 51, 'width': 36, 'height': 36, 'm_per_px': 2}
|
|
||||||
|
|
||||||
ALL_OPTIONS = [(v,t) for v in [0,2,4,6,8] for t in [5, 10]] # option 0 is safe fallback
|
|
||||||
|
|
||||||
def train(expert_data, epochs=20, expert_batch_size=32, generator_steps=1024, discount=0.99):
|
|
||||||
env = NRasterized(**env_settings)
|
|
||||||
env.discount = discount
|
|
||||||
|
|
||||||
tempdir = tempfile.TemporaryDirectory(prefix="quickstart")
|
|
||||||
tempdir_path = pathlib.Path(tempdir.name)
|
|
||||||
logger.configure(tempdir_path / "GAIL/")
|
|
||||||
print(f"All Tensorboards and logging are being written inside {tempdir_path}/.")
|
|
||||||
|
|
||||||
venv = make_vec_env(NRasterized, n_envs=1, env_kwargs=env_settings)
|
|
||||||
discriminator = adversarial.GAIL(
|
|
||||||
expert_data=expert_data,
|
|
||||||
expert_batch_size=expert_batch_size,
|
|
||||||
discrim_kwargs={'discrim_net': CnnDiscriminatorFlatAction(venv)},
|
|
||||||
#discrim_kwargs={'discrim_net': CnnDiscriminator(venv)},
|
|
||||||
venv=venv, # unused
|
|
||||||
gen_algo=stable_baselines3.PPO("CnnPolicy", venv), # unused
|
|
||||||
)
|
|
||||||
|
|
||||||
generator = stable_baselines3.PPO(
|
|
||||||
OptionsCnnPolicy,
|
|
||||||
OptionsEnv(env, options=ALL_OPTIONS),
|
|
||||||
verbose=1,
|
|
||||||
n_steps=generator_steps,
|
|
||||||
)
|
|
||||||
|
|
||||||
# PPO.train requires logger as set up in
|
|
||||||
# PPO._setup_learn (called by PPO.learn)
|
|
||||||
generator._logger = stable_baselines3.common.utils.configure_logger(
|
|
||||||
generator.verbose,
|
|
||||||
generator.tensorboard_log,
|
|
||||||
)
|
|
||||||
|
|
||||||
for _ in tqdm(range(epochs)):
|
|
||||||
train_discriminator(LLOptions(env, options=ALL_OPTIONS), generator, discriminator, num_samples=expert_batch_size)
|
|
||||||
train_generator(HLOptions(env, options=ALL_OPTIONS), generator, discriminator, num_samples=generator_steps)
|
|
||||||
|
|
||||||
return generator
|
|
||||||
|
|
||||||
# %%
|
|
||||||
if __name__ == '__main__':
|
|
||||||
# %%
|
|
||||||
|
|
||||||
with open("data/NormalizedIntersimpleExpertMu.001_NRasterizedAgent51w36h36mppx2.pkl", "rb") as f:
|
|
||||||
trajectories = pickle.load(f)
|
|
||||||
transitions = rollout.flatten_trajectories(trajectories)
|
|
||||||
generator = train(transitions)
|
|
||||||
|
|
||||||
generator.save(model_name)
|
|
||||||
|
|
||||||
# %%
|
|
||||||
model = stable_baselines3.PPO.load(model_name)
|
|
||||||
|
|
||||||
env = RenderOptions(NRasterized(**env_settings), options=ALL_OPTIONS)
|
|
||||||
|
|
||||||
for s in env.sample_ll(model):
|
|
||||||
if s['dones']:
|
|
||||||
break
|
|
||||||
|
|
||||||
env.close(filestr='render/'+model_name)
|
|
||||||
@@ -1,410 +0,0 @@
|
|||||||
# %%
|
|
||||||
import sys
|
|
||||||
sys.path.append('../../../')
|
|
||||||
from src.discriminator import CnnDiscriminator, CnnDiscriminatorFlatAction
|
|
||||||
from src.policies import OptionsCnnPolicy
|
|
||||||
from src.util import feasible
|
|
||||||
from src.data import load_experts
|
|
||||||
|
|
||||||
from imitation.algorithms import adversarial
|
|
||||||
from imitation.util import logger
|
|
||||||
import imitation.data.rollout as rollout
|
|
||||||
|
|
||||||
import stable_baselines3
|
|
||||||
from stable_baselines3.common.env_util import make_vec_env
|
|
||||||
|
|
||||||
import torch
|
|
||||||
import torch.utils.data
|
|
||||||
import numpy as np
|
|
||||||
import itertools
|
|
||||||
import gym
|
|
||||||
import pickle
|
|
||||||
import tempfile
|
|
||||||
import pathlib
|
|
||||||
from tqdm import tqdm
|
|
||||||
|
|
||||||
from intersim.envs.intersimple import NRasterized, NRasterizedRandomAgent, NRasterizedIncrementingAgent
|
|
||||||
|
|
||||||
ALL_OPTIONS = [(v,t) for v in [0,2,4,6,8] for t in [5, 10, 20]] # option 0 is safe fallback
|
|
||||||
|
|
||||||
class OptionsEnv(gym.Wrapper):
|
|
||||||
"""
|
|
||||||
Wrap an intersimple environment with an options generator
|
|
||||||
"""
|
|
||||||
def __init__(self, env, *args, **kwargs):
|
|
||||||
"""
|
|
||||||
Initialize wrapped environment and set high-level action and observation spaces
|
|
||||||
"""
|
|
||||||
super().__init__(env, *args, **kwargs)
|
|
||||||
num_hl_options = len(ALL_OPTIONS)
|
|
||||||
self.action_space = gym.spaces.Discrete(num_hl_options)
|
|
||||||
self.observation_space = gym.spaces.Dict({
|
|
||||||
'obs': env.observation_space,
|
|
||||||
'mask': gym.spaces.Box(low=0, high=1, shape=(num_hl_options,)),
|
|
||||||
})
|
|
||||||
|
|
||||||
def _after_choice(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def _after_step(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def _transitions(self):
|
|
||||||
raise NotImplementedError('Use `LLOptions` or `HLOptions` for sampling.')
|
|
||||||
|
|
||||||
def sample(self, generator):
|
|
||||||
"""
|
|
||||||
yield transitions using a generator
|
|
||||||
Args:
|
|
||||||
generator (sb3.PPO)
|
|
||||||
Yields:
|
|
||||||
|
|
||||||
"""
|
|
||||||
self.done = True
|
|
||||||
while True:
|
|
||||||
self.episode_start = False
|
|
||||||
if self.done:
|
|
||||||
self.s = self.env.reset()
|
|
||||||
self.done = False
|
|
||||||
self.episode_start = True
|
|
||||||
|
|
||||||
self.m = available_actions(self.env)
|
|
||||||
self.ch, self.value, self.log_prob = generator.policy.predict({
|
|
||||||
'obs': torch.tensor(self.s).unsqueeze(0).to(generator.policy.device),
|
|
||||||
'mask': torch.tensor(self.m).unsqueeze(0).to(generator.policy.device),
|
|
||||||
})
|
|
||||||
self.plan = list(map(float, generate_plan(self.env, self.ch)))
|
|
||||||
|
|
||||||
self._after_choice()
|
|
||||||
|
|
||||||
assert not self.done
|
|
||||||
assert self.plan
|
|
||||||
#assert feasible(self.env, self.plan, self.ch)
|
|
||||||
|
|
||||||
while not self.done and self.plan and feasible(self.env, self.plan, self.ch):
|
|
||||||
self.a, self.plan = self.plan[0], self.plan[1:]
|
|
||||||
self.a = self.env._normalize(self.a)
|
|
||||||
self.nexts, _, self.done, _ = self.env.step(self.a)
|
|
||||||
|
|
||||||
self._after_step()
|
|
||||||
|
|
||||||
self.s = self.nexts
|
|
||||||
|
|
||||||
yield from self._transitions()
|
|
||||||
|
|
||||||
class LLOptions(OptionsEnv):
|
|
||||||
"""Sample low-level (state, action) tuples for discriminator training."""
|
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
"""
|
|
||||||
LLOption uses the true LL observations
|
|
||||||
"""
|
|
||||||
super().__init__(*args, **kwargs)
|
|
||||||
# overwrite observation space to just output obs directly
|
|
||||||
self.observation_space = self.observation_space['obs']
|
|
||||||
|
|
||||||
def _after_choice(self):
|
|
||||||
"""
|
|
||||||
After each option choice, initialize/reset the transition buffer
|
|
||||||
"""
|
|
||||||
self._transition_buffer = []
|
|
||||||
|
|
||||||
def _after_step(self):
|
|
||||||
"""
|
|
||||||
After each ll action, append s, s', a, done to transition buffer
|
|
||||||
"""
|
|
||||||
self._transition_buffer.append({
|
|
||||||
'obs': self.s,
|
|
||||||
'next_obs': self.nexts,
|
|
||||||
'acts': np.array((self.a,)),
|
|
||||||
'dones': np.array(self.done),
|
|
||||||
})
|
|
||||||
|
|
||||||
def _transitions(self):
|
|
||||||
"""
|
|
||||||
Yield from the transition buffer
|
|
||||||
"""
|
|
||||||
yield from self._transition_buffer
|
|
||||||
|
|
||||||
def sample_ll(self, policy):
|
|
||||||
"""
|
|
||||||
Args:
|
|
||||||
policy
|
|
||||||
Returns:
|
|
||||||
gen: iterable which samples low-level transitions from the environment
|
|
||||||
"""
|
|
||||||
return self.sample(policy)
|
|
||||||
|
|
||||||
class HLOptions(OptionsEnv):
|
|
||||||
"""Sample high-level (state, action, reward) tuples for generator training."""
|
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
super().__init__(*args, **kwargs)
|
|
||||||
|
|
||||||
def _after_choice(self):
|
|
||||||
"""
|
|
||||||
After an option selection, initialize total reward and number of steps
|
|
||||||
"""
|
|
||||||
self.obs = {'obs': np.copy(self.s), 'mask': np.copy(self.m)}
|
|
||||||
self.r = 0
|
|
||||||
self.steps = 0
|
|
||||||
|
|
||||||
def _after_step(self):
|
|
||||||
"""
|
|
||||||
After each low-level action, add the discounted discriminated reward score (given a discriminator)
|
|
||||||
"""
|
|
||||||
self.r += self.discount**self.steps * self.discriminator.discrim_net.reward_train(
|
|
||||||
state=torch.tensor(self.s).unsqueeze(0).to(self.discriminator.discrim_net.device()),
|
|
||||||
action=torch.tensor([[self.a]]).to(self.discriminator.discrim_net.device()),
|
|
||||||
next_state=torch.tensor(self.s).unsqueeze(0).to(self.discriminator.discrim_net.device()), # unused
|
|
||||||
done=torch.tensor(self.done).unsqueeze(0).to(self.discriminator.discrim_net.device()), # unused
|
|
||||||
)
|
|
||||||
self.steps += 1
|
|
||||||
|
|
||||||
def _transitions(self):
|
|
||||||
"""
|
|
||||||
Yield a single dictionary per high-level selected action
|
|
||||||
Fields:
|
|
||||||
obs: high-level state and mask at selection
|
|
||||||
action: chosen high-level action
|
|
||||||
reward: accumulated option reward
|
|
||||||
episode_start: whether the action was chosen at the episode start
|
|
||||||
value: the value estimate from the starting state
|
|
||||||
log_prob: the log_prob of the selected action from the starting state
|
|
||||||
done: whether the episode has ended
|
|
||||||
|
|
||||||
"""
|
|
||||||
yield {
|
|
||||||
'obs': self.obs,
|
|
||||||
'action': self.ch,
|
|
||||||
'reward': self.r.detach(),
|
|
||||||
'episode_start': self.episode_start,
|
|
||||||
'value': self.value.detach(),
|
|
||||||
'log_prob': self.log_prob.detach(),
|
|
||||||
'done': self.done,
|
|
||||||
}
|
|
||||||
|
|
||||||
def sample_hl(self, policy, discriminator):
|
|
||||||
"""
|
|
||||||
Args:
|
|
||||||
policy
|
|
||||||
discriminator: function with which to score rewards
|
|
||||||
Returns:
|
|
||||||
gen: iterable which samples high-level transitions from the environment
|
|
||||||
"""
|
|
||||||
self.discriminator = discriminator
|
|
||||||
return self.sample(policy)
|
|
||||||
|
|
||||||
class RenderOptions(LLOptions):
|
|
||||||
|
|
||||||
def _after_step(self):
|
|
||||||
"""
|
|
||||||
Render the environment after each low-level step
|
|
||||||
"""
|
|
||||||
super()._after_step()
|
|
||||||
self.env.render()
|
|
||||||
|
|
||||||
def close(self, *args, **kwargs):
|
|
||||||
"""
|
|
||||||
On 'close', close the environment
|
|
||||||
"""
|
|
||||||
self.env.close(*args, **kwargs)
|
|
||||||
|
|
||||||
def available_actions(env):
|
|
||||||
"""Return mask of available actions given current `env` state."""
|
|
||||||
valid = np.array([feasible(env, generate_plan(env, i), i) for i in range(len(ALL_OPTIONS))])
|
|
||||||
return valid
|
|
||||||
|
|
||||||
def target_velocity_plan(current_v: float, target_v: float, t: int, dt: float):
|
|
||||||
"""Smoothly target a velocity in a given number of steps"""
|
|
||||||
# for now, constant acceleration
|
|
||||||
a = (target_v - current_v) / (t * dt)
|
|
||||||
return a*np.ones((t,))
|
|
||||||
|
|
||||||
def generate_plan(env, i):
|
|
||||||
"""Generate input profile for high-level action `i`.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
env (gym.Env): current environment state
|
|
||||||
i (int): high-level action `i`
|
|
||||||
Returns:
|
|
||||||
plan (np.array): length T array of acceleration values
|
|
||||||
"""
|
|
||||||
assert i < len(ALL_OPTIONS), "Invalid option index {i}"
|
|
||||||
target_v, t = ALL_OPTIONS[i]
|
|
||||||
current_v = env._env.state[env._agent, 1].item() # extract from env
|
|
||||||
plan = target_velocity_plan(current_v, target_v, t, env._env._dt)
|
|
||||||
assert len(plan) == t, "incorrect plan length"
|
|
||||||
return plan
|
|
||||||
|
|
||||||
def flatten_transitions(transitions):
|
|
||||||
return {
|
|
||||||
'obs': np.stack(list(t['obs'] for t in transitions), axis=0),
|
|
||||||
'next_obs': np.stack(list(t['next_obs'] for t in transitions), axis=0),
|
|
||||||
'acts': np.stack(list(t['acts'] for t in transitions), axis=0),
|
|
||||||
'dones': np.stack(list(t['dones'] for t in transitions), axis=0),
|
|
||||||
}
|
|
||||||
|
|
||||||
def train_discriminator(env, generator, discriminator, num_samples):
|
|
||||||
transitions = list(itertools.islice(env.sample_ll(generator), num_samples))
|
|
||||||
generator_samples = flatten_transitions(transitions)
|
|
||||||
discriminator.train_disc(gen_samples=generator_samples)
|
|
||||||
|
|
||||||
def train_generator(env, generator, discriminator, num_samples):
|
|
||||||
generator_samples = list(itertools.islice(env.sample_hl(generator, discriminator), num_samples+1))
|
|
||||||
|
|
||||||
generator.rollout_buffer.reset()
|
|
||||||
for s in generator_samples[:-1]:
|
|
||||||
generator.rollout_buffer.add(
|
|
||||||
obs=s['obs'],
|
|
||||||
action=s['action'].cpu(),
|
|
||||||
reward=s['reward'].cpu(),
|
|
||||||
episode_start=s['episode_start'],
|
|
||||||
value=s['value'],
|
|
||||||
log_prob=s['log_prob'],
|
|
||||||
)
|
|
||||||
|
|
||||||
generator.rollout_buffer.compute_returns_and_advantage(
|
|
||||||
last_values=generator_samples[-1]['value'],
|
|
||||||
dones=generator_samples[-1]['done'],
|
|
||||||
)
|
|
||||||
|
|
||||||
generator.train()
|
|
||||||
|
|
||||||
def train(expert_data, env_class=NRasterizedRandomAgent, env_settings={}, epochs=10, discrim_batch_size=32, generator_steps=2048, discount=0.99):
|
|
||||||
"""
|
|
||||||
Args:
|
|
||||||
expert_data: list of transitions
|
|
||||||
env_class: environment class
|
|
||||||
env_settings: environment settings
|
|
||||||
epochs: number of epochs to train for
|
|
||||||
discrim_batch_size: discriminator batch size
|
|
||||||
generator_steps: number of steps taken in generator
|
|
||||||
discount: discount factor
|
|
||||||
Returns:
|
|
||||||
generator (stable_baselines3.PPO): options policy
|
|
||||||
"""
|
|
||||||
env = env_class(**env_settings)
|
|
||||||
env.discount = discount
|
|
||||||
|
|
||||||
tempdir = tempfile.TemporaryDirectory(prefix="quickstart")
|
|
||||||
tempdir_path = pathlib.Path(tempdir.name)
|
|
||||||
logger.configure(tempdir_path / "GAIL/")
|
|
||||||
print(f"All Tensorboards and logging are being written inside {tempdir_path}/.")
|
|
||||||
|
|
||||||
venv = make_vec_env(env_class, n_envs=1, env_kwargs=env_settings)
|
|
||||||
discriminator = adversarial.GAIL(
|
|
||||||
expert_data=expert_data,
|
|
||||||
expert_batch_size=discrim_batch_size,
|
|
||||||
discrim_kwargs={'discrim_net': CnnDiscriminatorFlatAction(venv)},
|
|
||||||
#discrim_kwargs={'discrim_net': CnnDiscriminator(venv)},
|
|
||||||
venv=venv, # unused
|
|
||||||
gen_algo=stable_baselines3.PPO("CnnPolicy", venv), # unused
|
|
||||||
)
|
|
||||||
|
|
||||||
generator = stable_baselines3.PPO(
|
|
||||||
OptionsCnnPolicy,
|
|
||||||
OptionsEnv(env),
|
|
||||||
verbose=1,
|
|
||||||
n_steps=generator_steps,
|
|
||||||
)
|
|
||||||
|
|
||||||
# PPO.train requires logger as set up in
|
|
||||||
# PPO._setup_learn (called by PPO.learn)
|
|
||||||
generator._logger = stable_baselines3.common.utils.configure_logger(
|
|
||||||
generator.verbose,
|
|
||||||
generator.tensorboard_log,
|
|
||||||
)
|
|
||||||
|
|
||||||
for _ in tqdm(range(epochs)):
|
|
||||||
train_discriminator(LLOptions(env), generator, discriminator, num_samples=discrim_batch_size)
|
|
||||||
train_generator(HLOptions(env), generator, discriminator, num_samples=generator_steps)
|
|
||||||
|
|
||||||
return generator
|
|
||||||
|
|
||||||
# %%
|
|
||||||
if __name__ == '__main__':
|
|
||||||
# %%
|
|
||||||
model_name = 'gail_options_image'
|
|
||||||
env_class = NRasterizedRandomAgent
|
|
||||||
env_settings = {'width': 36, 'height': 36, 'm_per_px': 2}
|
|
||||||
|
|
||||||
#env_class = NRasterized
|
|
||||||
#env_settings = {'agent': 51, 'width': 36, 'height': 36, 'm_per_px': 2}
|
|
||||||
files = ['../../../expert_data/DR_USA_Roundabout_FT/track%04i/expert.pkl'%(i) for i in range(5)]
|
|
||||||
transitions=load_experts(files)
|
|
||||||
|
|
||||||
generator = train(
|
|
||||||
transitions,
|
|
||||||
env_class=env_class,
|
|
||||||
env_settings=env_settings,
|
|
||||||
epochs=10,
|
|
||||||
discrim_batch_size=32,
|
|
||||||
generator_steps=2048,
|
|
||||||
discount=0.99
|
|
||||||
)
|
|
||||||
|
|
||||||
generator.save(model_name)
|
|
||||||
|
|
||||||
# %%
|
|
||||||
model = stable_baselines3.PPO.load(model_name)
|
|
||||||
|
|
||||||
env = RenderOptions(NRasterizedRandomAgent(**env_args))
|
|
||||||
|
|
||||||
for s in env.sample_ll(model):
|
|
||||||
if s['dones']:
|
|
||||||
break
|
|
||||||
|
|
||||||
env.close(filestr='render/'+model_name)
|
|
||||||
|
|
||||||
# %% Tests
|
|
||||||
|
|
||||||
def test_ll_expert_data():
|
|
||||||
with open("data/NormalizedIntersimpleExpertMu.001_NRasterizedAgent51w36h36mppx2.pkl", "rb") as f:
|
|
||||||
expert_trajectories = pickle.load(f)
|
|
||||||
expert_transitions = rollout.flatten_trajectories(expert_trajectories)
|
|
||||||
|
|
||||||
env = LLOptions(NRasterized(agent=51, width=36, height=36, m_per_px=2))
|
|
||||||
|
|
||||||
gen_transitions = list(itertools.islice(env.sample_ll(
|
|
||||||
policy=stable_baselines3.PPO(
|
|
||||||
OptionsCnnPolicy,
|
|
||||||
OptionsEnv(env),
|
|
||||||
verbose=1,
|
|
||||||
)
|
|
||||||
), 10))
|
|
||||||
gen_transitions = flatten_transitions(gen_transitions)
|
|
||||||
|
|
||||||
assert expert_transitions[:10].obs.shape == gen_transitions['obs'].shape
|
|
||||||
assert expert_transitions[:10].next_obs.shape == gen_transitions['next_obs'].shape
|
|
||||||
assert expert_transitions[:10].acts.shape == gen_transitions['acts'].shape
|
|
||||||
assert expert_transitions[:10].dones.shape == gen_transitions['dones'].shape
|
|
||||||
|
|
||||||
def test_ll_states():
|
|
||||||
env = NRasterized()
|
|
||||||
policy = stable_baselines3.PPO(
|
|
||||||
OptionsCnnPolicy,
|
|
||||||
OptionsEnv(env),
|
|
||||||
verbose=1,
|
|
||||||
)
|
|
||||||
llenv = LLOptions(env)
|
|
||||||
transitions = list(itertools.islice(llenv.sample_ll(policy=policy), 100))
|
|
||||||
|
|
||||||
env2 = NRasterized()
|
|
||||||
s2 = env2.reset()
|
|
||||||
for i, t in enumerate(transitions):
|
|
||||||
assert i == 0 or np.array_equal(t['obs'], transitions[i-1]['next_obs'])
|
|
||||||
assert np.array_equal(t['obs'], s2)
|
|
||||||
assert t['acts'].shape == (1,)
|
|
||||||
|
|
||||||
nexts2, _, done2, _ = env2.step(t['acts'])
|
|
||||||
assert np.array_equal(t['next_obs'], nexts2)
|
|
||||||
assert np.array_equal(t['dones'], done2)
|
|
||||||
|
|
||||||
if done2:
|
|
||||||
break
|
|
||||||
|
|
||||||
s2 = nexts2
|
|
||||||
|
|
||||||
def test_hl_transitions():
|
|
||||||
pass
|
|
||||||
@@ -1,91 +0,0 @@
|
|||||||
# %%
|
|
||||||
import sys
|
|
||||||
sys.path.append('../../../')
|
|
||||||
|
|
||||||
from src.discriminator import CnnDiscriminatorFlatAction
|
|
||||||
from imitation.algorithms import adversarial
|
|
||||||
import stable_baselines3
|
|
||||||
import torch.utils.data
|
|
||||||
import numpy as np
|
|
||||||
from intersim.envs.intersimple import NRasterizedRouteRandomAgent
|
|
||||||
import itertools
|
|
||||||
from torch.distributions import Categorical
|
|
||||||
import gym
|
|
||||||
import torch
|
|
||||||
import pickle
|
|
||||||
import imitation.data.rollout as rollout
|
|
||||||
import tempfile
|
|
||||||
import pathlib
|
|
||||||
from imitation.util import logger
|
|
||||||
from stable_baselines3.common.env_util import make_vec_env
|
|
||||||
from tqdm import tqdm
|
|
||||||
from src.policies.options import OptionsCnnPolicy
|
|
||||||
from src.gail.options import OptionsEnv, LLOptions, HLOptions, RenderOptions
|
|
||||||
from src.gail.train import train_discriminator, train_generator
|
|
||||||
|
|
||||||
model_name = 'gail_options_image_random'
|
|
||||||
env_settings = {'width': 70, 'height': 70, 'm_per_px': 1}
|
|
||||||
|
|
||||||
ALL_OPTIONS = [(v,t) for v in [0,2,4,6,8] for t in [5, 10, 20]] # option 0 is safe fallback
|
|
||||||
|
|
||||||
def train(expert_data, epochs=100, expert_batch_size=64, generator_steps=1024, discount=0.99):
|
|
||||||
env = NRasterizedRouteRandomAgent(**env_settings)
|
|
||||||
env.discount = discount
|
|
||||||
|
|
||||||
tempdir = tempfile.TemporaryDirectory(prefix="quickstart")
|
|
||||||
tempdir_path = pathlib.Path(tempdir.name)
|
|
||||||
logger.configure(tempdir_path / "GAIL/")
|
|
||||||
print(f"All Tensorboards and logging are being written inside {tempdir_path}/.")
|
|
||||||
|
|
||||||
venv = make_vec_env(NRasterizedRouteRandomAgent, n_envs=1, env_kwargs=env_settings)
|
|
||||||
discriminator = adversarial.GAIL(
|
|
||||||
expert_data=expert_data,
|
|
||||||
expert_batch_size=expert_batch_size,
|
|
||||||
discrim_kwargs={'discrim_net': CnnDiscriminatorFlatAction(venv)},
|
|
||||||
#discrim_kwargs={'discrim_net': CnnDiscriminator(venv)},
|
|
||||||
venv=venv, # unused
|
|
||||||
gen_algo=stable_baselines3.PPO("CnnPolicy", venv), # unused
|
|
||||||
)
|
|
||||||
|
|
||||||
generator = stable_baselines3.PPO(
|
|
||||||
OptionsCnnPolicy,
|
|
||||||
OptionsEnv(env, options=ALL_OPTIONS),
|
|
||||||
verbose=1,
|
|
||||||
n_steps=generator_steps,
|
|
||||||
)
|
|
||||||
|
|
||||||
# PPO.train requires logger as set up in
|
|
||||||
# PPO._setup_learn (called by PPO.learn)
|
|
||||||
generator._logger = stable_baselines3.common.utils.configure_logger(
|
|
||||||
generator.verbose,
|
|
||||||
generator.tensorboard_log,
|
|
||||||
)
|
|
||||||
|
|
||||||
for _ in tqdm(range(epochs)):
|
|
||||||
train_discriminator(LLOptions(env, options=ALL_OPTIONS), generator, discriminator, num_samples=expert_batch_size)
|
|
||||||
train_generator(HLOptions(env, options=ALL_OPTIONS), generator, discriminator, num_samples=generator_steps)
|
|
||||||
generator.save(model_name)
|
|
||||||
|
|
||||||
return generator
|
|
||||||
|
|
||||||
def video(model_name, env):
|
|
||||||
model = stable_baselines3.PPO.load(model_name)
|
|
||||||
env = RenderOptions(env, options=ALL_OPTIONS)
|
|
||||||
for s in env.sample_ll(model):
|
|
||||||
if s['dones']:
|
|
||||||
break
|
|
||||||
env.close(filestr='render/'+model_name)
|
|
||||||
|
|
||||||
def evaluate():
|
|
||||||
video(
|
|
||||||
model_name=model_name,
|
|
||||||
env=NRasterizedRouteRandomAgent(**env_settings)
|
|
||||||
)
|
|
||||||
|
|
||||||
# %%
|
|
||||||
if __name__ == '__main__':
|
|
||||||
|
|
||||||
with open("data/NormalizedIntersimpleExpertMu.001N10000_NRasterizedRouteRandomAgentw70h70mppx1.pkl", "rb") as f:
|
|
||||||
trajectories = pickle.load(f)
|
|
||||||
transitions = rollout.flatten_trajectories(trajectories)
|
|
||||||
train(transitions)
|
|
||||||
@@ -1,144 +0,0 @@
|
|||||||
# %%
|
|
||||||
from collections import deque
|
|
||||||
import sys
|
|
||||||
sys.path.append('../../../')
|
|
||||||
|
|
||||||
from src.discriminator import CnnDiscriminator, CnnDiscriminatorFlatAction
|
|
||||||
from imitation.algorithms import adversarial
|
|
||||||
import stable_baselines3
|
|
||||||
import pickle
|
|
||||||
import imitation.data.rollout as rollout
|
|
||||||
import tempfile
|
|
||||||
import pathlib
|
|
||||||
from imitation.util import logger
|
|
||||||
from tqdm import tqdm
|
|
||||||
from src.policies.options import OptionsCnnPolicy
|
|
||||||
from src.gail.train import flatten_transitions
|
|
||||||
from gail.options2 import OptionsEnv, RenderOptions, imitation_discriminator
|
|
||||||
from gail.envs import TLNRasterizedRouteRandomAgentLocation
|
|
||||||
from stable_baselines3.common.vec_env.dummy_vec_env import DummyVecEnv
|
|
||||||
from stable_baselines3.common.env_util import make_vec_env
|
|
||||||
import torch
|
|
||||||
import numpy as np
|
|
||||||
|
|
||||||
model_name = 'gail_options_image_random_location'
|
|
||||||
env_settings = {'width': 70, 'height': 70, 'm_per_px': 1, 'mu': 0.001, 'random_skip': True, 'max_episode_steps': 200}
|
|
||||||
|
|
||||||
ALL_OPTIONS = [(v,t) for v in [0,2,4,8,10] for t in [5, 10, 20]] # option 0 is safe fallback
|
|
||||||
|
|
||||||
class NoisyDiscriminator(CnnDiscriminatorFlatAction):
|
|
||||||
|
|
||||||
def __init__(self, *args, std=0.0, **kwargs):
|
|
||||||
super().__init__(*args, **kwargs)
|
|
||||||
self.std = std
|
|
||||||
|
|
||||||
def forward(self, state, action):
|
|
||||||
noise = self.std * torch.randn(*action.shape, device=action.device)
|
|
||||||
return super().forward(state, action + noise)
|
|
||||||
|
|
||||||
class LLBuffer(deque):
|
|
||||||
|
|
||||||
def sample(self, n):
|
|
||||||
assert n <= self.maxlen, f'Sample size of {n} exceeds buffer capacity of {self.maxlen}'
|
|
||||||
assert n <= len(self), f'Sample size of {n} exceeds buffer size of {len(self)}'
|
|
||||||
ind = np.random.randint(len(self), size=n)
|
|
||||||
return list(self[i] for i in ind)
|
|
||||||
|
|
||||||
def train(
|
|
||||||
expert_data,
|
|
||||||
expert_batch_size=4096,
|
|
||||||
discriminator_updates_per_round=20,
|
|
||||||
generator_steps=1024,
|
|
||||||
generator_batch_size=1024,
|
|
||||||
generator_total_steps=8192,
|
|
||||||
generator_updates_per_round=10,
|
|
||||||
discount=1.0,
|
|
||||||
epochs=200,
|
|
||||||
):
|
|
||||||
env = TLNRasterizedRouteRandomAgentLocation(**env_settings)
|
|
||||||
|
|
||||||
tempdir = tempfile.TemporaryDirectory(prefix="quickstart")
|
|
||||||
tempdir_path = pathlib.Path(tempdir.name)
|
|
||||||
logger.configure(tempdir_path / "GAIL/")
|
|
||||||
print(f"All Tensorboards and logging are being written inside {tempdir_path}/.")
|
|
||||||
|
|
||||||
venv = DummyVecEnv([lambda: env])
|
|
||||||
discriminator = adversarial.GAIL(
|
|
||||||
expert_data=expert_data,
|
|
||||||
expert_batch_size=expert_batch_size,
|
|
||||||
#discrim_kwargs={'discrim_net': NoisyDiscriminator(venv, std=0.25)},
|
|
||||||
disc_opt_cls=torch.optim.RMSprop,
|
|
||||||
disc_opt_kwargs={'lr': 0.0001, 'weight_decay': 0.003},
|
|
||||||
discrim_kwargs={'discrim_net': CnnDiscriminator(venv)},
|
|
||||||
venv=venv, # unused
|
|
||||||
gen_algo=stable_baselines3.PPO("CnnPolicy", venv), # unused
|
|
||||||
)
|
|
||||||
|
|
||||||
ll_buffer = LLBuffer(maxlen=expert_batch_size*10)
|
|
||||||
|
|
||||||
options_env = make_vec_env(
|
|
||||||
OptionsEnv,
|
|
||||||
n_envs=1,
|
|
||||||
#vec_env_cls=SubprocVecEnv,
|
|
||||||
env_kwargs={
|
|
||||||
'env': env,
|
|
||||||
'options': ALL_OPTIONS,
|
|
||||||
'discriminator': imitation_discriminator(discriminator),
|
|
||||||
'discount': discount,
|
|
||||||
'll_buffer': ll_buffer,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
generator = stable_baselines3.PPO(
|
|
||||||
OptionsCnnPolicy,
|
|
||||||
options_env,
|
|
||||||
verbose=1,
|
|
||||||
batch_size=generator_batch_size,
|
|
||||||
n_steps=generator_steps,
|
|
||||||
n_epochs=generator_updates_per_round,
|
|
||||||
gamma=1.0,
|
|
||||||
learning_rate=1e-4,
|
|
||||||
)
|
|
||||||
|
|
||||||
for _ in tqdm(range(epochs)):
|
|
||||||
ll_buffer.clear()
|
|
||||||
|
|
||||||
# train generator
|
|
||||||
generator.learn(total_timesteps=generator_total_steps)
|
|
||||||
|
|
||||||
# train discriminator
|
|
||||||
for _ in range(discriminator_updates_per_round):
|
|
||||||
generator_samples = ll_buffer.sample(expert_batch_size)
|
|
||||||
generator_samples = flatten_transitions(generator_samples)
|
|
||||||
discriminator.train_disc(gen_samples=generator_samples)
|
|
||||||
|
|
||||||
generator.save(model_name)
|
|
||||||
|
|
||||||
return generator
|
|
||||||
|
|
||||||
def video(model_name, env):
|
|
||||||
model = stable_baselines3.PPO.load(model_name)
|
|
||||||
|
|
||||||
done = False
|
|
||||||
obs = env.reset()
|
|
||||||
while not done:
|
|
||||||
action, _ = model.predict(obs)
|
|
||||||
obs, _, done, _ = env.step(action)
|
|
||||||
|
|
||||||
env.close(filestr='render/'+model_name)
|
|
||||||
|
|
||||||
def evaluate():
|
|
||||||
video_settings = { **env_settings, 'random_skip': False, 'max_episode_steps': 200 }
|
|
||||||
env = TLNRasterizedRouteRandomAgentLocation(**video_settings)
|
|
||||||
env = RenderOptions(env, options=ALL_OPTIONS)
|
|
||||||
video(
|
|
||||||
model_name=model_name,
|
|
||||||
env=env
|
|
||||||
)
|
|
||||||
|
|
||||||
# %%
|
|
||||||
if __name__ == '__main__':
|
|
||||||
with open("data/NormalizedIntersimpleExpertMu.001N50000_TLNRasterizedRouteRandomAgentLocationw70h70mppx1mu.001rskips50.pkl", "rb") as f:
|
|
||||||
trajectories = pickle.load(f)
|
|
||||||
transitions = rollout.flatten_trajectories(trajectories)
|
|
||||||
train(transitions)
|
|
||||||
@@ -1,63 +0,0 @@
|
|||||||
# %%
|
|
||||||
import pathlib
|
|
||||||
import pickle
|
|
||||||
import tempfile
|
|
||||||
|
|
||||||
import stable_baselines3 as sb3
|
|
||||||
from stable_baselines3.common.env_util import make_vec_env
|
|
||||||
|
|
||||||
from imitation.algorithms import adversarial, bc
|
|
||||||
from imitation.data import rollout
|
|
||||||
from imitation.util import logger
|
|
||||||
|
|
||||||
from intersim.envs.intersimple import IntersimpleReward
|
|
||||||
|
|
||||||
# Load pickled test demonstrations.
|
|
||||||
with open("data/NormalizedIntersimpleExpert_IntersimpleRewardAgent51.pkl", "rb") as f:
|
|
||||||
# This is a list of `imitation.data.types.Trajectory`, where
|
|
||||||
# every instance contains observations and actions for a single expert
|
|
||||||
# demonstration.
|
|
||||||
trajectories = pickle.load(f)
|
|
||||||
|
|
||||||
# %%
|
|
||||||
# Convert List[types.Trajectory] to an instance of `imitation.data.types.Transitions`.
|
|
||||||
# This is a more general dataclass containing unordered
|
|
||||||
# (observation, actions, next_observation) transitions.
|
|
||||||
transitions = rollout.flatten_trajectories(trajectories)
|
|
||||||
|
|
||||||
venv = make_vec_env(IntersimpleReward, n_envs=2, env_kwargs={'agent': 51})
|
|
||||||
|
|
||||||
tempdir = tempfile.TemporaryDirectory(prefix="quickstart")
|
|
||||||
tempdir_path = pathlib.Path(tempdir.name)
|
|
||||||
print(f"All Tensorboards and logging are being written inside {tempdir_path}/.")
|
|
||||||
|
|
||||||
# Train BC on expert data.
|
|
||||||
# BC also accepts as `expert_data` any PyTorch-style DataLoader that iterates over
|
|
||||||
# dictionaries containing observations and actions.
|
|
||||||
logger.configure(tempdir_path / "BC/")
|
|
||||||
bc_trainer = bc.BC(venv.observation_space, venv.action_space, expert_data=transitions)
|
|
||||||
bc_trainer.train(n_epochs=1)
|
|
||||||
|
|
||||||
# Train GAIL on expert data.
|
|
||||||
# GAIL, and AIRL also accept as `expert_data` any Pytorch-style DataLoader that
|
|
||||||
# iterates over dictionaries containing observations, actions, and next_observations.
|
|
||||||
logger.configure(tempdir_path / "GAIL/")
|
|
||||||
gail_trainer = adversarial.GAIL(
|
|
||||||
venv,
|
|
||||||
expert_data=transitions,
|
|
||||||
expert_batch_size=32,
|
|
||||||
gen_algo=sb3.PPO("MlpPolicy", venv, verbose=1, n_steps=1024),
|
|
||||||
)
|
|
||||||
gail_trainer.train(total_timesteps=2048)
|
|
||||||
|
|
||||||
# Train AIRL on expert data.
|
|
||||||
logger.configure(tempdir_path / "AIRL/")
|
|
||||||
airl_trainer = adversarial.AIRL(
|
|
||||||
venv,
|
|
||||||
expert_data=transitions,
|
|
||||||
expert_batch_size=32,
|
|
||||||
gen_algo=sb3.PPO("MlpPolicy", venv, verbose=1, n_steps=1024),
|
|
||||||
)
|
|
||||||
airl_trainer.train(total_timesteps=2048)
|
|
||||||
|
|
||||||
# %%
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
# %%
|
|
||||||
from stable_baselines3 import PPO
|
|
||||||
from stable_baselines3.common.env_util import make_vec_env
|
|
||||||
from intersim.envs.intersimple import IntersimpleReward, speed_reward
|
|
||||||
|
|
||||||
model_name = "ppo_const"
|
|
||||||
|
|
||||||
env = IntersimpleReward(
|
|
||||||
agent=51,
|
|
||||||
#reward=speed_reward,
|
|
||||||
)
|
|
||||||
|
|
||||||
# %%
|
|
||||||
model = PPO(
|
|
||||||
"MlpPolicy", env,
|
|
||||||
verbose=1,
|
|
||||||
)
|
|
||||||
model.learn(total_timesteps=100000)
|
|
||||||
model.save(model_name)
|
|
||||||
|
|
||||||
print('Done training.')
|
|
||||||
|
|
||||||
del model # remove to demonstrate saving and loading
|
|
||||||
|
|
||||||
# %%
|
|
||||||
model = PPO.load(model_name)
|
|
||||||
|
|
||||||
obs = env.reset()
|
|
||||||
while True:
|
|
||||||
action, _states = model.predict(obs)
|
|
||||||
obs, rewards, done, info = env.step(action)
|
|
||||||
env.render(mode='post')
|
|
||||||
if done:
|
|
||||||
break
|
|
||||||
|
|
||||||
env.close(filestr='render/'+model_name)
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
# %%
|
|
||||||
from stable_baselines3 import PPO
|
|
||||||
from stable_baselines3.common.env_util import make_vec_env
|
|
||||||
from intersim.envs.intersimple import ConstCollisionReward, IntersimpleFlatAgent
|
|
||||||
|
|
||||||
model_name = "ppo_const_collision"
|
|
||||||
|
|
||||||
class IntersimpleConstCollisionAgent(ConstCollisionReward, IntersimpleFlatAgent):
|
|
||||||
pass
|
|
||||||
|
|
||||||
env = IntersimpleConstCollisionAgent(
|
|
||||||
agent=51,
|
|
||||||
speed_reward_weight=0.001,
|
|
||||||
collision_penalty=1000
|
|
||||||
)
|
|
||||||
|
|
||||||
# %%
|
|
||||||
model = PPO(
|
|
||||||
"MlpPolicy", env,
|
|
||||||
learning_rate=3e-6,
|
|
||||||
verbose=1,
|
|
||||||
)
|
|
||||||
model.learn(total_timesteps=2e5)
|
|
||||||
model.save(model_name)
|
|
||||||
|
|
||||||
print('Done training.')
|
|
||||||
|
|
||||||
del model # remove to demonstrate saving and loading
|
|
||||||
|
|
||||||
# %%
|
|
||||||
model = PPO.load(model_name)
|
|
||||||
|
|
||||||
obs = env.reset()
|
|
||||||
while True:
|
|
||||||
action, _states = model.predict(obs)
|
|
||||||
obs, rewards, done, info = env.step(action)
|
|
||||||
env.render(mode='post')
|
|
||||||
if done:
|
|
||||||
break
|
|
||||||
|
|
||||||
env.close(filestr='render/'+model_name)
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
# %%
|
|
||||||
from stable_baselines3 import PPO
|
|
||||||
from stable_baselines3.common.env_util import make_vec_env
|
|
||||||
from intersim.envs.intersimple import NRasterized
|
|
||||||
|
|
||||||
model_name = "ppo_const_image"
|
|
||||||
|
|
||||||
env = NRasterized(
|
|
||||||
agent=51,
|
|
||||||
)
|
|
||||||
|
|
||||||
# %%
|
|
||||||
model = PPO(
|
|
||||||
"CnnPolicy", env,
|
|
||||||
verbose=1,
|
|
||||||
)
|
|
||||||
model.learn(total_timesteps=100000)
|
|
||||||
model.save(model_name)
|
|
||||||
|
|
||||||
print('Done training.')
|
|
||||||
|
|
||||||
del model # remove to demonstrate saving and loading
|
|
||||||
|
|
||||||
# %%
|
|
||||||
model = PPO.load(model_name)
|
|
||||||
|
|
||||||
obs = env.reset()
|
|
||||||
while True:
|
|
||||||
action, _states = model.predict(obs)
|
|
||||||
obs, rewards, done, info = env.step(action)
|
|
||||||
env.render(mode='post')
|
|
||||||
if done:
|
|
||||||
break
|
|
||||||
|
|
||||||
env.close(filestr='render/'+model_name)
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
# %%
|
|
||||||
from stable_baselines3 import PPO
|
|
||||||
from intersim.envs.intersimple import NRasterizedRandomAgent
|
|
||||||
import functools
|
|
||||||
|
|
||||||
model_name = "ppo_const_image_random"
|
|
||||||
|
|
||||||
env = NRasterizedRandomAgent()
|
|
||||||
|
|
||||||
# %%
|
|
||||||
model = PPO(
|
|
||||||
"CnnPolicy", env,
|
|
||||||
verbose=1,
|
|
||||||
)
|
|
||||||
model.learn(total_timesteps=2e5)
|
|
||||||
model.save(model_name)
|
|
||||||
|
|
||||||
print('Done training.')
|
|
||||||
|
|
||||||
del model # remove to demonstrate saving and loading
|
|
||||||
|
|
||||||
# %%
|
|
||||||
model = PPO.load(model_name)
|
|
||||||
|
|
||||||
obs = env.reset()
|
|
||||||
while True:
|
|
||||||
action, _states = model.predict(obs)
|
|
||||||
obs, rewards, done, info = env.step(action)
|
|
||||||
env.render(mode='post')
|
|
||||||
if done:
|
|
||||||
break
|
|
||||||
|
|
||||||
env.close(filestr='render/'+model_name)
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
from stable_baselines3 import PPO
|
|
||||||
from stable_baselines3.common.env_util import make_vec_env
|
|
||||||
from intersim.envs.intersimple import IntersimpleTargetSpeed
|
|
||||||
|
|
||||||
env = IntersimpleTargetSpeed()
|
|
||||||
|
|
||||||
model = PPO("MlpPolicy", env, verbose=1)
|
|
||||||
model.learn(total_timesteps=25000)
|
|
||||||
model.save("ppo_intersimple")
|
|
||||||
|
|
||||||
print('Done training.')
|
|
||||||
|
|
||||||
del model # remove to demonstrate saving and loading
|
|
||||||
|
|
||||||
model = PPO.load("ppo_intersimple")
|
|
||||||
|
|
||||||
obs = env.reset()
|
|
||||||
while True:
|
|
||||||
action, _states = model.predict(obs)
|
|
||||||
obs, rewards, done, info = env.step(action)
|
|
||||||
env.render(mode='post')
|
|
||||||
if done:
|
|
||||||
break
|
|
||||||
|
|
||||||
env.close()
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
# %%
|
|
||||||
from stable_baselines3 import PPO
|
|
||||||
from intersim.envs.intersimple import IntersimpleReward, speed_reward
|
|
||||||
import functools
|
|
||||||
|
|
||||||
model_name = "ppo_speed"
|
|
||||||
|
|
||||||
#def reward(state, action, info):
|
|
||||||
# speed = state[2].item()
|
|
||||||
# r = speed if speed < 10 else (10 - 5 * (speed - 10))
|
|
||||||
# return 0.1 * r
|
|
||||||
|
|
||||||
env = IntersimpleReward(
|
|
||||||
agent=51,
|
|
||||||
reward=functools.partial(
|
|
||||||
speed_reward,
|
|
||||||
collision_penalty=0
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
# %%
|
|
||||||
model = PPO(
|
|
||||||
"MlpPolicy", env,
|
|
||||||
verbose=1,
|
|
||||||
)
|
|
||||||
model.learn(total_timesteps=100000)
|
|
||||||
model.save(model_name)
|
|
||||||
|
|
||||||
print('Done training.')
|
|
||||||
|
|
||||||
del model # remove to demonstrate saving and loading
|
|
||||||
|
|
||||||
# %%
|
|
||||||
model = PPO.load(model_name)
|
|
||||||
|
|
||||||
obs = env.reset()
|
|
||||||
while True:
|
|
||||||
action, _states = model.predict(obs)
|
|
||||||
obs, rewards, done, info = env.step(action)
|
|
||||||
env.render(mode='post')
|
|
||||||
if done:
|
|
||||||
break
|
|
||||||
|
|
||||||
env.close(filestr='render/'+model_name)
|
|
||||||
|
|
||||||
# %%
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
# %%
|
|
||||||
from stable_baselines3 import PPO
|
|
||||||
from intersim.envs.intersimple import NRasterized, speed_reward
|
|
||||||
import functools
|
|
||||||
|
|
||||||
model_name = "ppo_speed_image"
|
|
||||||
|
|
||||||
#def reward(state, action, info):
|
|
||||||
# speed = state[2].item()
|
|
||||||
# r = speed if speed < 10 else (10 - 5 * (speed - 10))
|
|
||||||
# return 0.1 * r
|
|
||||||
|
|
||||||
env = NRasterized(
|
|
||||||
agent=20,
|
|
||||||
reward=functools.partial(
|
|
||||||
speed_reward,
|
|
||||||
collision_penalty=0
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
# %%
|
|
||||||
model = PPO(
|
|
||||||
"CnnPolicy", env,
|
|
||||||
verbose=1,
|
|
||||||
)
|
|
||||||
model.learn(total_timesteps=100000)
|
|
||||||
model.save(model_name)
|
|
||||||
|
|
||||||
print('Done training.')
|
|
||||||
|
|
||||||
del model # remove to demonstrate saving and loading
|
|
||||||
|
|
||||||
# %%
|
|
||||||
model = PPO.load(model_name)
|
|
||||||
|
|
||||||
obs = env.reset()
|
|
||||||
while True:
|
|
||||||
action, _states = model.predict(obs)
|
|
||||||
obs, rewards, done, info = env.step(action)
|
|
||||||
env.render(mode='post')
|
|
||||||
if done:
|
|
||||||
break
|
|
||||||
|
|
||||||
env.close(filestr='render/'+model_name)
|
|
||||||
|
|
||||||
# %%
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
# %%
|
|
||||||
from stable_baselines3 import PPO
|
|
||||||
from intersim.envs.intersimple import NRasterized, speed_reward
|
|
||||||
import functools
|
|
||||||
|
|
||||||
model_name = "ppo_speed_image_lowres"
|
|
||||||
|
|
||||||
#def reward(state, action, info):
|
|
||||||
# speed = state[2].item()
|
|
||||||
# r = speed if speed < 10 else (10 - 5 * (speed - 10))
|
|
||||||
# return 0.1 * r
|
|
||||||
|
|
||||||
env = NRasterized(
|
|
||||||
agent=51,
|
|
||||||
height=36,
|
|
||||||
width=36,
|
|
||||||
m_per_px=2,
|
|
||||||
reward=functools.partial(
|
|
||||||
speed_reward,
|
|
||||||
collision_penalty=0
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
# %%
|
|
||||||
model = PPO(
|
|
||||||
"CnnPolicy", env,
|
|
||||||
verbose=1,
|
|
||||||
)
|
|
||||||
model.learn(total_timesteps=100000)
|
|
||||||
model.save(model_name)
|
|
||||||
|
|
||||||
print('Done training.')
|
|
||||||
|
|
||||||
del model # remove to demonstrate saving and loading
|
|
||||||
|
|
||||||
# %%
|
|
||||||
model = PPO.load(model_name)
|
|
||||||
|
|
||||||
obs = env.reset()
|
|
||||||
while True:
|
|
||||||
action, _states = model.predict(obs)
|
|
||||||
obs, rewards, done, info = env.step(action)
|
|
||||||
env.render(mode='post')
|
|
||||||
if done:
|
|
||||||
break
|
|
||||||
|
|
||||||
env.close(filestr='render/'+model_name)
|
|
||||||
|
|
||||||
# %%
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user