Files
InteractionImitation/src/policies/policy.py
2021-08-04 19:44:55 +02:00

166 lines
5.7 KiB
Python

import torch
from torch import nn
from src.nets.deepsets import DeepSetsModule, Phi
class IntersimStateNet(nn.Module):
def __init__(self, config):
"""
Args:
config (dict): dictionary for configuring the deep sets policy
"""
super(IntersimStateNet, self).__init__()
ego_config = config['ego_encoder']
deepsets_config = config['deepsets']
pathnet_config = config['path_encoder']
self.ego_net = Phi.from_config(ego_config)
self.deepsets_net = DeepSetsModule.from_config(deepsets_config)
self.path_net = Phi.from_config(pathnet_config)
cat_dim = self.ego_net.output_dim + self.deepsets_net.output_dim + self.path_net.output_dim
# head has number of concatenated features as input
head_config = config['head']
head_config["input_dim"] = cat_dim
self.head = Phi.from_config(head_config)
def forward(self, sample):
"""
Args:
sample (dict): sample dictionary with the following entries:
state (torch.tensor): (B, 5) raw state
relative_state (torch.tensor): (B, max_nv, d) relative state (padded with nans)
path (torch.tensor): (B, P, 2) tensor of P future path x and y positions
action (torch.tensor): (B, 1) actions taken from each state
Returns:
x (torch.tensor): (head_output_dim,) output of common head network
"""
ego = self.ego_net(sample["ego_state"])
relative = self.deepsets_net(sample["relative_state"])
path = self.path_net(sample["path"].reshape((sample["path"].shape[0], -1)))
x = torch.cat([ego, relative, path], dim=-1)
x = self.head(x)
return x
class IntersimStateActionNet(nn.Module):
def __init__(self, config):
"""
Args:
config (dict): dictionary for configuring the deep sets policy
"""
super(IntersimStateActionNet, self).__init__()
ego_config = config['ego_encoder']
deepsets_config = config['deepsets']
pathnet_config = config['path_encoder']
self.ego_net = Phi.from_config(ego_config)
self.deepsets_net = DeepSetsModule.from_config(deepsets_config)
self.path_net = Phi.from_config(pathnet_config)
self.action_dim = config["action_dim"]
cat_dim = self.ego_net.output_dim + self.deepsets_net.output_dim + self.path_net.output_dim + self.action_dim
# head has number of concatenated features as input
head_config = config['head']
head_config["input_dim"] = cat_dim
self.head = Phi.from_config(head_config)
def forward(self, sample):
"""
Args:
sample (dict): sample dictionary with the following entries:
state (torch.tensor): (B, 5) raw state
relative_state (torch.tensor): (B, max_nv, d) relative state (padded with nans)
path_x (torch.tensor): (B, P) tensor of P future path x positions
path_y (torch.tensor): (B, P) tensor of P future path y positions
action (torch.tensor): (B, 1) actions taken from each state
Returns:
x (torch.tensor): (head_output_dim,) output of common head network
"""
ego = self.ego_net(sample["ego_state"])
relative = self.deepsets_net(sample["relative_state"])
# cat path_x, path_y to tensor of dim (B, 2*P)
path = torch.cat([sample["path_x"], sample["path_y"]], dim=-1)
path = self.path_net(path)
action = sample["action"]
x = torch.cat([ego, relative, path, action], dim=-1)
x = self.head(x)
return x
class IntersimPolicy():
"""
Base class for intersim policies
"""
def __init__(self, config, transforms):
super(IntersimPolicy, self).__init__()
self._config = config
self._transforms = transforms
@property
def transforms(self):
return self._transforms
@transforms.setter
def transforms(self, transforms):
self._transforms=transforms
@property
def policy(self):
return self._policy
@policy.setter
def policy(self, policy):
self._policy = policy
def transform_observation(self, ob):
# run observation through transforms
transformed_ob = {}
for key in ['ego_state', 'relative_state', 'path', 'action']:
if key in self._transforms.keys():
transformed_ob[key] = self._transforms[key].transform(ob[key])
return transformed_ob
def __call__(self, ob):
if 'ego_state' in ob.keys():
# extract state from dataloader samples
pass
else:
# extract state from observation (using simulator)
ob['ego_state'] = ob['state']
ob['path'] = torch.stack(ob['paths'],dim=-1)
ob = transform_observation(ob)
# run transformed state through model
action = self._policy(ob)
assert action.ndim == 2, 'action has incorrect shape'
# untransform action
if 'action' in self._transforms.keys():
action = self._transforms['action'].inverse_transform(action)
return action
def generate_transforms(dataset):
"""
Generate transform dictionary from dataset
Args:
dataset (Dataset): dataset of demo observations and actions
"""
transforms = {
'action': MinMaxScaler(),
'ego_state': MinMaxScaler(),
'relative_state': MinMaxScaler(reduce_dim=2),
'path': MinMaxScaler(reduce_dim=2),
}
for key in transforms.keys():
if key == 'action':
transforms[key].fit(dataset[:][key])
else:
transforms[key].fit(dataset[:]['state'][key])
return transforms