initial
2
.idea/.gitignore
generated
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
# Default ignored files
|
||||
/workspace.xml
|
8
.idea/hom_traj_gen.iml
generated
Normal file
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="PYTHON_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$" />
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
6
.idea/inspectionProfiles/profiles_settings.xml
generated
Normal file
@ -0,0 +1,6 @@
|
||||
<component name="InspectionProjectProfileManager">
|
||||
<settings>
|
||||
<option name="USE_PROJECT_PROFILE" value="false" />
|
||||
<version value="1.0" />
|
||||
</settings>
|
||||
</component>
|
7
.idea/misc.xml
generated
Normal file
@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="JavaScriptSettings">
|
||||
<option name="languageLevel" value="ES6" />
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.7" project-jdk-type="Python SDK" />
|
||||
</project>
|
8
.idea/modules.xml
generated
Normal file
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/hom_traj_gen.iml" filepath="$PROJECT_DIR$/.idea/hom_traj_gen.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
6
.idea/vcs.xml
generated
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
11
build_data.py
Normal file
@ -0,0 +1,11 @@
|
||||
from pathlib import Path
|
||||
|
||||
from lib.objects.map import Map
|
||||
from preprocessing.generator import Generator
|
||||
|
||||
if __name__ == '__main__':
|
||||
data_root = Path() / 'data'
|
||||
maps_root = Path() / 'res' / 'maps'
|
||||
map_object = Map('Tate').from_image(maps_root / 'tate_sw.bmp')
|
||||
generator = Generator(data_root, map_object)
|
||||
generator.generate_n_trajectories_m_alternatives(100, 10, 'test')
|
BIN
dataset/__pycache__/dataset.cpython-37.pyc
Normal file
96
dataset/dataset.py
Normal file
@ -0,0 +1,96 @@
|
||||
import shelve
|
||||
from pathlib import Path
|
||||
|
||||
import torch
|
||||
from torch.utils.data import ConcatDataset, Dataset
|
||||
|
||||
from lib.objects.map import Map
|
||||
from preprocessing.generator import Generator
|
||||
|
||||
|
||||
class TrajDataset(Dataset):
|
||||
def __init__(self, data):
|
||||
super(TrajDataset, self).__init__()
|
||||
self.alternatives = data['alternatives']
|
||||
self.trajectory = data['trajectory']
|
||||
self.labels = data['labels']
|
||||
|
||||
def __len__(self):
|
||||
return len(self.alternatives)
|
||||
|
||||
def __getitem__(self, item):
|
||||
return self.trajectory.vertices, self.alternatives[item].vertices, self.labels[item]
|
||||
|
||||
|
||||
class DataSetMapping(Dataset):
|
||||
def __init__(self, dataset, mapping):
|
||||
self._dataset = dataset
|
||||
self._mapping = mapping
|
||||
|
||||
def __len__(self):
|
||||
return self._mapping.shape[0]
|
||||
|
||||
def __getitem__(self, item):
|
||||
return self._dataset[self._mapping[item]]
|
||||
|
||||
|
||||
class TrajData(object):
|
||||
@property
|
||||
def name(self):
|
||||
return self.__class__.__name__
|
||||
|
||||
def __init__(self, data_root, mapname='tate_sw', trajectories=1000, alternatives=10,
|
||||
train_val_test_split=(0.6, 0.2, 0.2), rebuild=False, equal_samples=True, **_):
|
||||
|
||||
self.rebuild = rebuild
|
||||
self.equal_samples = equal_samples
|
||||
self._alternatives = alternatives
|
||||
self._trajectories = trajectories
|
||||
self.mapname = mapname
|
||||
self.train_split, self.val_split, self.test_split = train_val_test_split
|
||||
self.data_root = Path(data_root)
|
||||
self._dataset = None
|
||||
self._dataset, self._train_map, self._val_map, self._test_map = self._load_dataset()
|
||||
|
||||
def _build_data_on_demand(self):
|
||||
maps_root = Path() / 'res' / 'maps'
|
||||
map_object = Map(self.mapname).from_image(maps_root / f'{self.mapname}.bmp')
|
||||
assert maps_root.exists()
|
||||
dataset_file = Path(self.data_root) / f'{self.mapname}.pik'
|
||||
if dataset_file.exists() and self.rebuild:
|
||||
dataset_file.unlink()
|
||||
if not dataset_file.exists():
|
||||
generator = Generator(self.data_root, map_object)
|
||||
generator.generate_n_trajectories_m_alternatives(self._trajectories, self._alternatives,
|
||||
self.mapname, equal_samples=self.equal_samples)
|
||||
return True
|
||||
|
||||
def _load_dataset(self):
|
||||
assert self._build_data_on_demand()
|
||||
with shelve.open(str(self.data_root / f'{self.mapname}.pik')) as d:
|
||||
dataset = ConcatDataset([TrajDataset(d[key]) for key in d.keys() if key != 'map'])
|
||||
indices = torch.randperm(len(dataset))
|
||||
|
||||
train_size = int(len(dataset) * self.train_split)
|
||||
val_size = int(len(dataset) * self.val_split)
|
||||
test_size = int(len(dataset) * self.test_split)
|
||||
|
||||
train_map = indices[:train_size]
|
||||
val_map = indices[train_size:val_size]
|
||||
test_map = indices[test_size:]
|
||||
return dataset, train_map, val_map, test_map
|
||||
|
||||
@property
|
||||
def train_dataset(self):
|
||||
return DataSetMapping(self._dataset, self._train_map)
|
||||
|
||||
@property
|
||||
def val_dataset(self):
|
||||
return DataSetMapping(self._dataset, self._val_map)
|
||||
|
||||
@property
|
||||
def test_dataset(self):
|
||||
return DataSetMapping(self._dataset, self._test_map)
|
||||
|
||||
def get_datasets(self):
|
||||
return self.train_dataset, self.val_dataset, self.test_dataset
|
37
evaluation/classification.py
Normal file
@ -0,0 +1,37 @@
|
||||
import matplotlib.pyplot as plt
|
||||
|
||||
from sklearn.metrics import roc_curve, auc
|
||||
|
||||
|
||||
class ROCEvaluation(object):
|
||||
|
||||
BINARY_PROBLEM = 2
|
||||
linewidth = 2
|
||||
|
||||
def __init__(self, save_fig=True):
|
||||
self.epoch = 0
|
||||
pass
|
||||
|
||||
def __call__(self, prediction, label, prepare_fig=True):
|
||||
|
||||
# Compute ROC curve and ROC area
|
||||
fpr, tpr, _ = roc_curve(prediction, label)
|
||||
roc_auc = auc(fpr, tpr)
|
||||
|
||||
if prepare_fig:
|
||||
fig = self._prepare_fig()
|
||||
fig.plot(fpr, tpr, color='darkorange',
|
||||
lw=2, label=f'ROC curve (area = {roc_auc})')
|
||||
self._prepare_fig()
|
||||
return roc_auc
|
||||
|
||||
def _prepare_fig(self):
|
||||
fig = plt.gcf()
|
||||
fig.plot([0, 1], [0, 1], color='navy', lw=self.linewidth, linestyle='--')
|
||||
fig.xlim([0.0, 1.0])
|
||||
fig.ylim([0.0, 1.05])
|
||||
fig.xlabel('False Positive Rate')
|
||||
fig.ylabel('True Positive Rate')
|
||||
|
||||
fig.legend(loc="lower right")
|
||||
return fig
|
0
lib/__init__.py
Normal file
BIN
lib/__pycache__/__init__.cpython-37.pyc
Normal file
0
lib/models/__init__.py
Normal file
468
lib/models/blocks.py
Normal file
@ -0,0 +1,468 @@
|
||||
from abc import ABC
|
||||
from pathlib import Path
|
||||
from typing import Union
|
||||
|
||||
import torch
|
||||
from torch import nn
|
||||
import torch.nn.functional as F
|
||||
import pytorch_lightning as pl
|
||||
|
||||
|
||||
# Utility - Modules
|
||||
###################
|
||||
from torch.utils.data import DataLoader
|
||||
|
||||
from dataset.dataset import TrajData
|
||||
|
||||
|
||||
class Flatten(nn.Module):
|
||||
def __init__(self, to=(-1, )):
|
||||
super(Flatten, self).__init__()
|
||||
self.to = to
|
||||
|
||||
def forward(self, x):
|
||||
return x.view(x.size(0), *self.to)
|
||||
|
||||
|
||||
class Interpolate(nn.Module):
|
||||
def __init__(self, size=None, scale_factor=None, mode='nearest', align_corners=None):
|
||||
super(Interpolate, self).__init__()
|
||||
self.interp = nn.functional.interpolate
|
||||
self.size = size
|
||||
self.scale_factor = scale_factor
|
||||
self.align_corners = align_corners
|
||||
self.mode = mode
|
||||
|
||||
def forward(self, x):
|
||||
x = self.interp(x, size=self.size, scale_factor=self.scale_factor,
|
||||
mode=self.mode, align_corners=self.align_corners)
|
||||
return x
|
||||
|
||||
|
||||
class AutoPad(nn.Module):
|
||||
|
||||
def __init__(self, interpolations=3, base=2):
|
||||
super(AutoPad, self).__init__()
|
||||
self.fct = base ** interpolations
|
||||
|
||||
def forward(self, x):
|
||||
x = F.pad(x,
|
||||
[0,
|
||||
(x.shape[-1] // self.fct + 1) * self.fct - x.shape[-1] if x.shape[-1] % self.fct != 0 else 0,
|
||||
(x.shape[-2] // self.fct + 1) * self.fct - x.shape[-2] if x.shape[-2] % self.fct != 0 else 0,
|
||||
0])
|
||||
return x
|
||||
|
||||
|
||||
class LightningBaseModule(pl.LightningModule, ABC):
|
||||
|
||||
@classmethod
|
||||
def name(cls):
|
||||
raise NotImplementedError('Give your model a name!')
|
||||
|
||||
@property
|
||||
def shape(self):
|
||||
try:
|
||||
x = torch.randn(self.in_shape).unsqueeze(0)
|
||||
output = self(x)
|
||||
return output.shape[1:]
|
||||
except Exception as e:
|
||||
print(e)
|
||||
return -1
|
||||
|
||||
def __init__(self, params):
|
||||
super(LightningBaseModule, self).__init__()
|
||||
self.hparams = params
|
||||
|
||||
# Data loading
|
||||
# =============================================================================
|
||||
# Dataset
|
||||
self.dataset = TrajData('data')
|
||||
|
||||
def size(self):
|
||||
return self.shape
|
||||
|
||||
def _move_to_model_device(self, x):
|
||||
return x.cuda() if next(self.parameters()).is_cuda else x.cpu()
|
||||
|
||||
def save_to_disk(self, model_path):
|
||||
Path(model_path, exist_ok=True).mkdir(parents=True, exist_ok=True)
|
||||
if not (model_path / 'model_class.obj').exists():
|
||||
with (model_path / 'model_class.obj').open('wb') as f:
|
||||
torch.save(self.__class__, f)
|
||||
return True
|
||||
|
||||
@pl.data_loader
|
||||
def train_dataloader(self):
|
||||
return DataLoader(dataset=self.dataset.train_dataset, shuffle=True,
|
||||
batch_size=self.hparams.data_param.batchsize,
|
||||
num_workers=self.hparams.data_param.worker)
|
||||
|
||||
@pl.data_loader
|
||||
def test_dataloader(self):
|
||||
return DataLoader(dataset=self.dataset.test_dataset, shuffle=True,
|
||||
batch_size=self.hparams.data_param.batchsize,
|
||||
num_workers=self.hparams.data_param.worker)
|
||||
|
||||
@pl.data_loader
|
||||
def val_dataloader(self):
|
||||
return DataLoader(dataset=self.dataset.val_dataset, shuffle=True,
|
||||
batch_size=self.hparams.data_param.batchsize,
|
||||
num_workers=self.hparams.data_param.worker)
|
||||
|
||||
def configure_optimizers(self):
|
||||
raise NotImplementedError
|
||||
|
||||
def forward(self, *args, **kwargs):
|
||||
raise NotImplementedError
|
||||
|
||||
def validation_step(self, *args, **kwargs):
|
||||
raise NotImplementedError
|
||||
|
||||
def validation_end(self, outputs):
|
||||
raise NotImplementedError
|
||||
|
||||
def training_step(self, batch_xy, batch_nb, *args, **kwargs):
|
||||
raise NotImplementedError
|
||||
|
||||
def test_step(self, *args, **kwargs):
|
||||
raise NotImplementedError
|
||||
|
||||
def test_end(self, outputs):
|
||||
from sklearn.metrics import roc_auc_score
|
||||
|
||||
y_scores, y_true = [], []
|
||||
for output in outputs:
|
||||
y_scores.append(output['y_pred'])
|
||||
y_true.append(output['y_true'])
|
||||
|
||||
y_true = torch.cat(y_true, dim=0)
|
||||
# FIXME: What did this do do i need it?
|
||||
# y_true = (y_true != V.HOMOTOPIC).long()
|
||||
y_scores = torch.cat(y_scores, dim=0)
|
||||
|
||||
roc_auc_scores = roc_auc_score(y_true.cpu().numpy(), y_scores.cpu().numpy())
|
||||
print(f'AUC Score: {roc_auc_scores}')
|
||||
return {'roc_auc_scores': roc_auc_scores}
|
||||
|
||||
def init_weights(self):
|
||||
def _weight_init(m):
|
||||
if hasattr(m, 'weight'):
|
||||
if isinstance(m.weight, torch.Tensor):
|
||||
torch.nn.init.xavier_uniform_(m.weight)
|
||||
if hasattr(m, 'bias'):
|
||||
if isinstance(m.bias, torch.Tensor):
|
||||
m.bias.data.fill_(0.01)
|
||||
self.apply(_weight_init)
|
||||
|
||||
|
||||
#
|
||||
# Sub - Modules
|
||||
###################
|
||||
class ConvModule(nn.Module):
|
||||
|
||||
@property
|
||||
def shape(self):
|
||||
x = torch.randn(self.in_shape).unsqueeze(0)
|
||||
output = self(x)
|
||||
return output.shape[1:]
|
||||
|
||||
def __init__(self, in_shape, activation: nn.Module = nn.ELU, pooling_size=None, use_bias=True, use_norm=True,
|
||||
dropout: Union[int, float] = 0,
|
||||
conv_filters=64, conv_kernel=5, conv_stride=1, conv_padding=0):
|
||||
super(ConvModule, self).__init__()
|
||||
|
||||
# Module Paramters
|
||||
self.in_shape = in_shape
|
||||
in_channels, height, width = in_shape[0], in_shape[1], in_shape[2]
|
||||
self.activation = activation()
|
||||
|
||||
# Convolution Paramters
|
||||
self.padding = conv_padding
|
||||
self.stride = conv_stride
|
||||
|
||||
# Modules
|
||||
self.dropout = nn.Dropout2d(dropout) if dropout else False
|
||||
self.pooling = nn.MaxPool2d(pooling_size) if pooling_size else False
|
||||
self.norm = nn.BatchNorm2d(in_channels, eps=1e-04, affine=False) if use_norm else False
|
||||
self.conv = nn.Conv2d(in_channels, conv_filters, conv_kernel, bias=use_bias,
|
||||
padding=self.padding, stride=self.stride
|
||||
)
|
||||
|
||||
def forward(self, x):
|
||||
x = self.norm(x) if self.norm else x
|
||||
|
||||
tensor = self.conv(x)
|
||||
tensor = self.dropout(tensor) if self.dropout else tensor
|
||||
tensor = self.pooling(tensor) if self.pooling else tensor
|
||||
tensor = self.activation(tensor)
|
||||
return tensor
|
||||
|
||||
|
||||
class DeConvModule(nn.Module):
|
||||
|
||||
@property
|
||||
def shape(self):
|
||||
x = torch.randn(self.in_shape).unsqueeze(0)
|
||||
output = self(x)
|
||||
return output.shape[1:]
|
||||
|
||||
def __init__(self, in_shape, conv_filters=3, conv_kernel=5, conv_stride=1, conv_padding=0,
|
||||
dropout: Union[int, float] = 0, autopad=False,
|
||||
activation: Union[None, nn.Module] = nn.ReLU, interpolation_scale=None,
|
||||
use_bias=True, normalize=False):
|
||||
super(DeConvModule, self).__init__()
|
||||
in_channels, height, width = in_shape[0], in_shape[1], in_shape[2]
|
||||
self.padding = conv_padding
|
||||
self.stride = conv_stride
|
||||
self.in_shape = in_shape
|
||||
self.conv_filters = conv_filters
|
||||
|
||||
self.autopad = AutoPad() if autopad else False
|
||||
self.interpolation = Interpolate(scale_factor=interpolation_scale) if interpolation_scale else False
|
||||
self.norm = nn.BatchNorm2d(in_channels, eps=1e-04, affine=False) if normalize else False
|
||||
self.dropout = nn.Dropout2d(dropout) if dropout else False
|
||||
self.de_conv = nn.ConvTranspose2d(in_channels, self.conv_filters, conv_kernel, bias=use_bias,
|
||||
padding=self.padding, stride=self.stride)
|
||||
|
||||
self.activation = activation() if activation else None
|
||||
|
||||
def forward(self, x):
|
||||
x = self.norm(x) if self.norm else x
|
||||
x = self.dropout(x) if self.dropout else x
|
||||
x = self.autopad(x) if self.autopad else x
|
||||
x = self.interpolation(x) if self.interpolation else x
|
||||
|
||||
tensor = self.de_conv(x)
|
||||
tensor = self.activation(tensor) if self.activation else tensor
|
||||
return tensor
|
||||
|
||||
def size(self):
|
||||
return self.shape
|
||||
|
||||
|
||||
#
|
||||
# Full Model Parts
|
||||
###################
|
||||
class Generator(nn.Module):
|
||||
@property
|
||||
def shape(self):
|
||||
x = torch.randn(self.lat_dim).unsqueeze(0)
|
||||
output = self(x)
|
||||
return output.shape[1:]
|
||||
|
||||
# noinspection PyUnresolvedReferences
|
||||
def __init__(self, out_channels, re_shape, lat_dim, use_norm=False, use_bias=True, dropout: Union[int, float] = 0,
|
||||
filters: List[int] = None, activation=nn.ReLU):
|
||||
super(Generator, self).__init__()
|
||||
assert filters, '"Filters" has to be a list of int len 3'
|
||||
self.filters = filters
|
||||
self.activation = activation
|
||||
self.inner_activation = activation()
|
||||
self.out_activation = None
|
||||
self.lat_dim = lat_dim
|
||||
self.dropout = dropout
|
||||
self.l1 = nn.Linear(self.lat_dim, reduce(mul, re_shape), bias=use_bias)
|
||||
# re_shape = (self.lat_dim // reduce(mul, re_shape[1:]), ) + tuple(re_shape[1:])
|
||||
|
||||
self.flat = Flatten(to=re_shape)
|
||||
|
||||
self.deconv1 = DeConvModule(re_shape, conv_filters=self.filters[0],
|
||||
conv_kernel=5,
|
||||
conv_padding=2,
|
||||
conv_stride=1,
|
||||
normalize=use_norm,
|
||||
activation=self.activation,
|
||||
interpolation_scale=2,
|
||||
dropout=self.dropout
|
||||
)
|
||||
|
||||
self.deconv2 = DeConvModule(self.deconv1.shape, conv_filters=self.filters[1],
|
||||
conv_kernel=3,
|
||||
conv_padding=1,
|
||||
conv_stride=1,
|
||||
normalize=use_norm,
|
||||
activation=self.activation,
|
||||
interpolation_scale=2,
|
||||
dropout=self.dropout
|
||||
)
|
||||
|
||||
self.deconv3 = DeConvModule(self.deconv2.shape, conv_filters=self.filters[2],
|
||||
conv_kernel=3,
|
||||
conv_padding=1,
|
||||
conv_stride=1,
|
||||
normalize=use_norm,
|
||||
activation=self.activation,
|
||||
interpolation_scale=2,
|
||||
dropout=self.dropout
|
||||
)
|
||||
|
||||
self.deconv4 = DeConvModule(self.deconv3.shape, conv_filters=out_channels,
|
||||
conv_kernel=3,
|
||||
conv_padding=1,
|
||||
# normalize=use_norm,
|
||||
activation=self.out_activation
|
||||
)
|
||||
|
||||
def forward(self, z):
|
||||
tensor = self.l1(z)
|
||||
tensor = self.inner_activation(tensor)
|
||||
tensor = self.flat(tensor)
|
||||
tensor = self.deconv1(tensor)
|
||||
tensor = self.deconv2(tensor)
|
||||
tensor = self.deconv3(tensor)
|
||||
tensor = self.deconv4(tensor)
|
||||
return tensor
|
||||
|
||||
def size(self):
|
||||
return self.shape
|
||||
|
||||
|
||||
class UnitGenerator(Generator):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
kwargs.update(use_norm=True)
|
||||
super(UnitGenerator, self).__init__(*args, **kwargs)
|
||||
self.norm_f = nn.BatchNorm1d(self.l1.out_features, eps=1e-04, affine=False)
|
||||
self.norm1 = nn.BatchNorm2d(self.deconv1.conv_filters, eps=1e-04, affine=False)
|
||||
self.norm2 = nn.BatchNorm2d(self.deconv2.conv_filters, eps=1e-04, affine=False)
|
||||
self.norm3 = nn.BatchNorm2d(self.deconv3.conv_filters, eps=1e-04, affine=False)
|
||||
|
||||
def forward(self, z_c1_c2_c3):
|
||||
z, c1, c2, c3 = z_c1_c2_c3
|
||||
tensor = self.l1(z)
|
||||
tensor = self.inner_activation(tensor)
|
||||
tensor = self.norm(tensor)
|
||||
tensor = self.flat(tensor)
|
||||
|
||||
tensor = self.deconv1(tensor) + c3
|
||||
tensor = self.inner_activation(tensor)
|
||||
tensor = self.norm1(tensor)
|
||||
|
||||
tensor = self.deconv2(tensor) + c2
|
||||
tensor = self.inner_activation(tensor)
|
||||
tensor = self.norm2(tensor)
|
||||
|
||||
tensor = self.deconv3(tensor) + c1
|
||||
tensor = self.inner_activation(tensor)
|
||||
tensor = self.norm3(tensor)
|
||||
|
||||
tensor = self.deconv4(tensor)
|
||||
return tensor
|
||||
|
||||
|
||||
class BaseEncoder(nn.Module):
|
||||
@property
|
||||
def shape(self):
|
||||
x = torch.randn(self.in_shape).unsqueeze(0)
|
||||
output = self(x)
|
||||
return output.shape[1:]
|
||||
|
||||
# noinspection PyUnresolvedReferences
|
||||
def __init__(self, in_shape, lat_dim=256, use_bias=True, use_norm=False, dropout: Union[int, float] = 0,
|
||||
latent_activation: Union[nn.Module, None] = None, activation: nn.Module = nn.ELU,
|
||||
filters: List[int] = None):
|
||||
super(BaseEncoder, self).__init__()
|
||||
assert filters, '"Filters" has to be a list of int len 3'
|
||||
|
||||
# Optional Padding for odd image-sizes
|
||||
# Obsolet, already Done by autopadding module on incoming tensors
|
||||
# in_shape = [x+1 if x % 2 != 0 and idx else x for idx, x in enumerate(in_shape)]
|
||||
|
||||
# Parameters
|
||||
self.lat_dim = lat_dim
|
||||
self.in_shape = in_shape
|
||||
self.use_bias = use_bias
|
||||
self.latent_activation = latent_activation() if latent_activation else None
|
||||
|
||||
# Modules
|
||||
self.conv1 = ConvModule(self.in_shape, conv_filters=filters[0],
|
||||
conv_kernel=3,
|
||||
conv_padding=1,
|
||||
conv_stride=1,
|
||||
pooling_size=2,
|
||||
use_norm=use_norm,
|
||||
dropout=dropout,
|
||||
activation=activation
|
||||
)
|
||||
|
||||
self.conv2 = ConvModule(self.conv1.shape, conv_filters=filters[1],
|
||||
conv_kernel=3,
|
||||
conv_padding=1,
|
||||
conv_stride=1,
|
||||
pooling_size=2,
|
||||
use_norm=use_norm,
|
||||
dropout=dropout,
|
||||
activation=activation
|
||||
)
|
||||
|
||||
self.conv3 = ConvModule(self.conv2.shape, conv_filters=filters[2],
|
||||
conv_kernel=5,
|
||||
conv_padding=2,
|
||||
conv_stride=1,
|
||||
pooling_size=2,
|
||||
use_norm=use_norm,
|
||||
dropout=dropout,
|
||||
activation=activation
|
||||
)
|
||||
|
||||
self.flat = Flatten()
|
||||
|
||||
def forward(self, x):
|
||||
tensor = self.conv1(x)
|
||||
tensor = self.conv2(tensor)
|
||||
tensor = self.conv3(tensor)
|
||||
tensor = self.flat(tensor)
|
||||
return tensor
|
||||
|
||||
|
||||
class UnitEncoder(BaseEncoder):
|
||||
# noinspection PyUnresolvedReferences
|
||||
def __init__(self, *args, **kwargs):
|
||||
kwargs.update(use_norm=True)
|
||||
super(UnitEncoder, self).__init__(*args, **kwargs)
|
||||
self.l1 = nn.Linear(reduce(mul, self.conv3.shape), self.lat_dim, bias=self.use_bias)
|
||||
|
||||
def forward(self, x):
|
||||
c1 = self.conv1(x)
|
||||
c2 = self.conv2(c1)
|
||||
c3 = self.conv3(c2)
|
||||
tensor = self.flat(c3)
|
||||
l1 = self.l1(tensor)
|
||||
return c1, c2, c3, l1
|
||||
|
||||
|
||||
class VariationalEncoder(BaseEncoder):
|
||||
# noinspection PyUnresolvedReferences
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(VariationalEncoder, self).__init__(*args, **kwargs)
|
||||
|
||||
self.logvar = nn.Linear(reduce(mul, self.conv3.shape), self.lat_dim, bias=self.use_bias)
|
||||
self.mu = nn.Linear(reduce(mul, self.conv3.shape), self.lat_dim, bias=self.use_bias)
|
||||
|
||||
@staticmethod
|
||||
def reparameterize(mu, logvar):
|
||||
std = torch.exp(0.5*logvar)
|
||||
eps = torch.randn_like(std)
|
||||
return mu + eps*std
|
||||
|
||||
def forward(self, x):
|
||||
tensor = super(VariationalEncoder, self).forward(x)
|
||||
mu = self.mu(tensor)
|
||||
logvar = self.logvar(tensor)
|
||||
z = self.reparameterize(mu, logvar)
|
||||
return mu, logvar, z
|
||||
|
||||
|
||||
class Encoder(BaseEncoder):
|
||||
# noinspection PyUnresolvedReferences
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(Encoder, self).__init__(*args, **kwargs)
|
||||
|
||||
self.l1 = nn.Linear(reduce(mul, self.conv3.shape), self.lat_dim, bias=self.use_bias)
|
||||
|
||||
def forward(self, x):
|
||||
tensor = super(Encoder, self).forward(x)
|
||||
tensor = self.l1(tensor)
|
||||
tensor = self.latent_activation(tensor) if self.latent_activation else tensor
|
||||
return tensor
|
0
lib/objects/__init__.py
Normal file
BIN
lib/objects/__pycache__/__init__.cpython-37.pyc
Normal file
BIN
lib/objects/__pycache__/map.cpython-37.pyc
Normal file
BIN
lib/objects/__pycache__/trajectory.cpython-37.pyc
Normal file
BIN
lib/objects/__pycache__/variables.cpython-37.pyc
Normal file
125
lib/objects/map.py
Normal file
@ -0,0 +1,125 @@
|
||||
from pathlib import Path
|
||||
|
||||
import copy
|
||||
from math import sqrt
|
||||
import numpy as np
|
||||
|
||||
from PIL import Image, ImageDraw
|
||||
import networkx as nx
|
||||
from matplotlib import pyplot as plt
|
||||
|
||||
from lib.objects.trajectory import Trajectory
|
||||
|
||||
|
||||
class Map(object):
|
||||
|
||||
white = [1, 255]
|
||||
black = [0]
|
||||
|
||||
def __copy__(self):
|
||||
return copy.deepcopy(self)
|
||||
|
||||
@property
|
||||
def shape(self):
|
||||
return self.map_array.shape
|
||||
|
||||
@property
|
||||
def width(self):
|
||||
return self.shape[0]
|
||||
|
||||
@property
|
||||
def height(self):
|
||||
return self.shape[1]
|
||||
|
||||
@property
|
||||
def as_graph(self):
|
||||
return self._G
|
||||
|
||||
@property
|
||||
def as_array(self):
|
||||
return self.map_array
|
||||
|
||||
def __init__(self, name='', array_like_map_representation=None):
|
||||
self.map_array: np.ndarray = array_like_map_representation
|
||||
self.name = name
|
||||
pass
|
||||
|
||||
def __setattr__(self, key, value):
|
||||
super(Map, self).__setattr__(key, value)
|
||||
if key == 'map_array' and self.map_array is not None:
|
||||
self._G = self._build_graph()
|
||||
|
||||
def _build_graph(self, full_neighbors=True):
|
||||
graph = nx.Graph()
|
||||
# Do checks in order: up - left - upperLeft - lowerLeft
|
||||
neighbors = [(0, -1, 1), (-1, 0, 1), (-1, -1, sqrt(2)), (-1, 1, sqrt(2))]
|
||||
|
||||
# Check pixels for their color (determine if walkable)
|
||||
for idx, value in np.ndenumerate(self.map_array):
|
||||
if value in self.white:
|
||||
y, x = idx
|
||||
# IF walkable, add node
|
||||
graph.add_node((y, x), count=0)
|
||||
# Fully connect to all surrounding neighbors
|
||||
for n, (xdif, ydif, weight) in enumerate(neighbors):
|
||||
# Differentiate between 8 and 4 neighbors
|
||||
if not full_neighbors and n >= 2:
|
||||
break
|
||||
|
||||
query_node = (y + ydif, x + xdif)
|
||||
if graph.has_node(query_node):
|
||||
graph.add_edge(idx, query_node, weight=weight)
|
||||
return graph
|
||||
|
||||
@classmethod
|
||||
def from_image(cls, imagepath: Path):
|
||||
with Image.open(imagepath) as image:
|
||||
return cls(name=imagepath.name, array_like_map_representation=np.array(image))
|
||||
|
||||
def simple_trajectory_between(self, start, dest):
|
||||
vertices = list(nx.shortest_path(self._G, start, dest))
|
||||
trajectory = Trajectory(vertices)
|
||||
return trajectory
|
||||
|
||||
def get_valid_position(self):
|
||||
not_found, valid_position = True, (-9999, -9999)
|
||||
while not_found:
|
||||
valid_position = int(np.random.choice(self.height, 1)), int(np.random.choice(self.width, 1))
|
||||
if self._G.has_node(valid_position):
|
||||
not_found = False
|
||||
pass
|
||||
return valid_position
|
||||
|
||||
def get_trajectory_from_vertices(self, *args):
|
||||
coords = list()
|
||||
for start, dest in zip(args[:-1], args[1:]):
|
||||
coords.extend(nx.shortest_path(self._G, start, dest))
|
||||
return Trajectory(coords)
|
||||
|
||||
def get_random_trajectory(self):
|
||||
start = self.get_valid_position()
|
||||
dest = self.get_valid_position()
|
||||
return self.simple_trajectory_between(start, dest)
|
||||
|
||||
def are_homotopic(self, trajectory, other_trajectory):
|
||||
if not all(isinstance(x, Trajectory) for x in [trajectory, other_trajectory]):
|
||||
raise TypeError
|
||||
polyline = trajectory.vertices.copy()
|
||||
polyline.extend(reversed(other_trajectory.vertices))
|
||||
|
||||
img = Image.new('L', (self.height, self.width), 0)
|
||||
ImageDraw.Draw(img).polygon(polyline, outline=1, fill=1)
|
||||
|
||||
a = (np.array(img) * self.map_array).sum()
|
||||
if a >= 1:
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
def draw(self):
|
||||
fig, ax = plt.gcf(), plt.gca()
|
||||
# The standard colormaps also all have reversed versions.
|
||||
# They have the same names with _r tacked on to the end.
|
||||
# https: // matplotlib.org / api / pyplot_summary.html?highlight = colormaps
|
||||
img = ax.imshow(self.as_array, cmap='Greys_r')
|
||||
return dict(img=img, fig=fig, ax=ax)
|
65
lib/objects/trajectory.py
Normal file
@ -0,0 +1,65 @@
|
||||
from math import atan2
|
||||
from typing import List, Tuple, Union
|
||||
|
||||
from matplotlib import pyplot as plt
|
||||
from lib.objects import variables as V
|
||||
|
||||
|
||||
class Trajectory(object):
|
||||
|
||||
@property
|
||||
def endpoints(self):
|
||||
return self.start, self.dest
|
||||
|
||||
@property
|
||||
def start(self):
|
||||
return self.vertices[0]
|
||||
|
||||
@property
|
||||
def dest(self):
|
||||
return self.vertices[-1]
|
||||
|
||||
@property
|
||||
def xs(self):
|
||||
return [x[1] for x in self.vertices]
|
||||
|
||||
@property
|
||||
def ys(self):
|
||||
return [x[0] for x in self.vertices]
|
||||
|
||||
@property
|
||||
def as_paired_list(self):
|
||||
return list(zip(self.vertices[:-1], self.vertices[1:]))
|
||||
|
||||
def __init__(self, vertices: Union[List[Tuple[int]], None] = None):
|
||||
assert any((isinstance(vertices, list), vertices is None))
|
||||
if vertices is not None:
|
||||
self.vertices = vertices
|
||||
pass
|
||||
|
||||
def is_equal_to(self, other_trajectory):
|
||||
# ToDo: do further equality Checks here
|
||||
return self.vertices == other_trajectory.vertices
|
||||
|
||||
def draw(self, highlights=True, label=None, **kwargs):
|
||||
if label is not None:
|
||||
kwargs.update(color='red' if label == V.HOMOTOPIC else 'green',
|
||||
label='Homotopic' if label == V.HOMOTOPIC else 'Alternative')
|
||||
if highlights:
|
||||
kwargs.update(marker='bo')
|
||||
fig, ax = plt.gcf(), plt.gca()
|
||||
img = plt.plot(self.xs, self.ys, **kwargs)
|
||||
return dict(img=img, fig=fig, ax=ax)
|
||||
|
||||
def min_vertices(self, vertices):
|
||||
vertices, last_angle = [self.start], 0
|
||||
for (x1, y1), (x2, y2) in self.as_paired_list:
|
||||
current_angle = atan2(x1-x2, y1-y2)
|
||||
if current_angle != last_angle:
|
||||
vertices.append((x2, y2))
|
||||
last_angle = current_angle
|
||||
else:
|
||||
continue
|
||||
if vertices[-1] != self.dest:
|
||||
vertices.append(self.dest)
|
||||
return self.__class__(vertices=vertices)
|
9
lib/objects/variables.py
Normal file
@ -0,0 +1,9 @@
|
||||
from pathlib import Path
|
||||
_ROOT = Path('..')
|
||||
|
||||
HOMOTOPIC = 0
|
||||
ALTERNATIVE = 1
|
||||
|
||||
_key_1 = 'eyJhcGlfYWRkcmVzcyI6Imh0dHBzOi8vdWkubmVwdHVuZS5haSIsImFwaV91cmwiOiJodHRwczovL3VpLm'
|
||||
_key_2 = '5lcHR1bmUuYWkiLCJhcGlfa2V5IjoiZmI0OGMzNzUtOTg1NS00Yzg2LThjMzYtMWFiYjUwMDUyMjVlIn0='
|
||||
NEPTUNE_KEY = _key_1 + _key_2
|
0
lib/utils/__init__.py
Normal file
BIN
lib/utils/__pycache__/__init__.cpython-37.pyc
Normal file
BIN
lib/utils/__pycache__/config.cpython-37.pyc
Normal file
BIN
lib/utils/__pycache__/logging.cpython-37.pyc
Normal file
96
lib/utils/config.py
Normal file
@ -0,0 +1,96 @@
|
||||
import ast
|
||||
|
||||
from argparse import Namespace
|
||||
from collections import defaultdict
|
||||
from configparser import ConfigParser
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def is_jsonable(x):
|
||||
import json
|
||||
try:
|
||||
json.dumps(x)
|
||||
return True
|
||||
except TypeError:
|
||||
return False
|
||||
|
||||
|
||||
class Config(ConfigParser):
|
||||
|
||||
# TODO: Do this programmatically; This did not work:
|
||||
# Initialize Default Sections
|
||||
# for section in self.default_sections:
|
||||
# self.__setattr__(section, property(lambda x :x._get_namespace_for_section(section))
|
||||
|
||||
@property
|
||||
def main(self):
|
||||
return self._get_namespace_for_section('main')
|
||||
|
||||
@property
|
||||
def model(self):
|
||||
return self._get_namespace_for_section('model')
|
||||
|
||||
@property
|
||||
def train(self):
|
||||
return self._get_namespace_for_section('train')
|
||||
|
||||
@property
|
||||
def data(self):
|
||||
return self._get_namespace_for_section('data')
|
||||
|
||||
@property
|
||||
def project(self):
|
||||
return self._get_namespace_for_section('project')
|
||||
###################################################
|
||||
|
||||
@property
|
||||
def tags(self, ):
|
||||
return [f'{key}: {val}' for key, val in self.serializable.items()]
|
||||
|
||||
@property
|
||||
def serializable(self):
|
||||
return {f'{section}_{key}': val for section, params in self._sections.items()
|
||||
for key, val in params.items() if is_jsonable(val)}
|
||||
|
||||
@property
|
||||
def as_dict(self):
|
||||
return self._sections
|
||||
|
||||
def _get_namespace_for_section(self, item):
|
||||
return Namespace(**{key: self.get(item, key) for key in self[item]})
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
super(Config, self).__init__(**kwargs)
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def read_namespace(cls, namespace: Namespace):
|
||||
|
||||
space_dict = defaultdict(dict)
|
||||
for key in namespace.__dict__:
|
||||
section, *attr_name = key.split('_')
|
||||
attr_name = '_'.join(attr_name)
|
||||
value = str(namespace.__getattribute__(key))
|
||||
|
||||
space_dict[section][attr_name] = value
|
||||
new_config = cls()
|
||||
new_config.read_dict(space_dict)
|
||||
return new_config
|
||||
|
||||
def get(self, *args, **kwargs):
|
||||
item = super(Config, self).get(*args, **kwargs)
|
||||
try:
|
||||
return ast.literal_eval(item)
|
||||
except SyntaxError:
|
||||
return item
|
||||
except ValueError:
|
||||
return item
|
||||
|
||||
def write(self, filepath, **kwargs):
|
||||
path = Path(filepath, exist_ok=True)
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
with path.open('w') as configfile:
|
||||
super().write(configfile)
|
||||
|
||||
return True
|
69
lib/utils/logging.py
Normal file
@ -0,0 +1,69 @@
|
||||
from pathlib import Path
|
||||
|
||||
from pytorch_lightning.logging.base import LightningLoggerBase
|
||||
from pytorch_lightning.logging.neptune import NeptuneLogger
|
||||
from pytorch_lightning.logging.test_tube import TestTubeLogger
|
||||
|
||||
from lib.utils.config import Config
|
||||
|
||||
|
||||
class Logger(LightningLoggerBase):
|
||||
|
||||
@property
|
||||
def experiment(self):
|
||||
if self.debug:
|
||||
return self.testtubelogger.experiment
|
||||
else:
|
||||
return self.neptunelogger.experiment
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
return self.config.model.type
|
||||
|
||||
@property
|
||||
def project_name(self):
|
||||
return f"{self.config.project.owner}/{self.config.project.name}"
|
||||
|
||||
@property
|
||||
def version(self):
|
||||
return f"version_{self.config.get('main', 'seed')}"
|
||||
|
||||
@property
|
||||
def outpath(self):
|
||||
# ToDo: Add further path modification such as dataset config etc.
|
||||
return Path(self.config.train.outpath)
|
||||
|
||||
def __init__(self, config: Config, debug=False):
|
||||
"""
|
||||
params (dict|None): Optional. Parameters of the experiment. After experiment creation params are read-only.
|
||||
Parameters are displayed in the experiment’s Parameters section and each key-value pair can be
|
||||
viewed in experiments view as a column.
|
||||
properties (dict|None): Optional default is {}. Properties of the experiment.
|
||||
They are editable after experiment is created. Properties are displayed in the experiment’s Details and
|
||||
each key-value pair can be viewed in experiments view as a column.
|
||||
tags (list|None): Optional default []. Must be list of str. Tags of the experiment.
|
||||
They are editable after experiment is created (see: append_tag() and remove_tag()).
|
||||
Tags are displayed in the experiment’s Details and can be viewed in experiments view as a column.
|
||||
"""
|
||||
super(Logger, self).__init__()
|
||||
|
||||
self.debug = debug
|
||||
self.config = config
|
||||
self._testtube_kwargs = dict(save_dir=self.outpath, version=self.version, name=self.name)
|
||||
self._neptune_kwargs = dict(offline_mode=not self.debug,
|
||||
api_key=self.config.project.neptune_key,
|
||||
project_name=self.project_name,
|
||||
name=self.name,
|
||||
upload_source_files=list())
|
||||
self.neptunelogger = NeptuneLogger(**self._neptune_kwargs)
|
||||
self.testtubelogger = TestTubeLogger(**self._testtube_kwargs)
|
||||
|
||||
def log_hyperparams(self, params):
|
||||
self.neptunelogger.log_hyperparams(params)
|
||||
self.testtubelogger.log_hyperparams(params)
|
||||
pass
|
||||
|
||||
def log_metrics(self, metrics, step_num):
|
||||
self.neptunelogger.log_metrics(metrics, step_num)
|
||||
self.testtubelogger.log_metrics(metrics, step_num)
|
||||
pass
|
76
lib/utils/model_io.py
Normal file
@ -0,0 +1,76 @@
|
||||
from argparse import Namespace
|
||||
from pathlib import Path
|
||||
from natsort import natsorted
|
||||
from torch import nn
|
||||
|
||||
|
||||
# Hyperparamter Object
|
||||
class ModelParameters(Namespace):
|
||||
|
||||
_activations = dict(
|
||||
leaky_relu=nn.LeakyReLU,
|
||||
relu=nn.ReLU,
|
||||
sigmoid=nn.Sigmoid,
|
||||
tanh=nn.Tanh
|
||||
)
|
||||
|
||||
@property
|
||||
def model_param(self):
|
||||
return self._model_param
|
||||
|
||||
@property
|
||||
def train_param(self):
|
||||
return self._train_param
|
||||
|
||||
@property
|
||||
def data_param(self):
|
||||
return self._data_param
|
||||
|
||||
def __init__(self, model_param, train_param, data_param):
|
||||
self._model_param = model_param
|
||||
self._train_param = train_param
|
||||
self._data_param = data_param
|
||||
kwargs = vars(model_param)
|
||||
kwargs.update(vars(train_param))
|
||||
kwargs.update(vars(data_param))
|
||||
super(ModelParameters, self).__init__(**kwargs)
|
||||
|
||||
def __getattribute__(self, item):
|
||||
if item == 'activation':
|
||||
try:
|
||||
return self._activations[item]
|
||||
except KeyError:
|
||||
return nn.ReLU
|
||||
return super(ModelParameters, self).__getattribute__(item)
|
||||
|
||||
|
||||
class SavedLightningModels(object):
|
||||
|
||||
@classmethod
|
||||
def load_checkpoint(cls, models_root_path, model, n=-1, tags_file_path=''):
|
||||
assert models_root_path.exists(), f'The path {models_root_path.absolute()} does not exist!'
|
||||
found_checkpoints = list(Path(models_root_path).rglob('*.ckpt'))
|
||||
|
||||
found_checkpoints = natsorted(found_checkpoints, key=lambda y: y.name)
|
||||
|
||||
if not tags_file_path:
|
||||
tag_files = models_root_path.rglob('meta_tags.csv')
|
||||
tags_file_path = list(tag_files)[0]
|
||||
|
||||
return cls(weights=found_checkpoints[n], model=model, tags=tags_file_path)
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
self.weights: str = kwargs.get('weights', '')
|
||||
self.tags: str = kwargs.get('tags', '')
|
||||
|
||||
self.model = kwargs.get('model', None)
|
||||
assert self.model is not None
|
||||
|
||||
def restore(self):
|
||||
pretrained_model = self.model.load_from_metrics(
|
||||
weights_path=self.weights,
|
||||
tags_csv=self.tags
|
||||
)
|
||||
pretrained_model.eval()
|
||||
pretrained_model.freeze()
|
||||
return pretrained_model
|
12
lib/utils/transforms.py
Normal file
@ -0,0 +1,12 @@
|
||||
import numpy as np
|
||||
|
||||
|
||||
class AsArray(object):
|
||||
def __init__(self, width, height):
|
||||
self.width = width
|
||||
self.height = height
|
||||
|
||||
def __call__(self, x):
|
||||
array = np.zeros((self.width, self.height))
|
||||
|
||||
return array
|
71
main.py
Normal file
@ -0,0 +1,71 @@
|
||||
# Imports
|
||||
# =============================================================================
|
||||
import os
|
||||
from distutils.util import strtobool
|
||||
from pathlib import Path
|
||||
from argparse import ArgumentParser
|
||||
|
||||
import warnings
|
||||
|
||||
from pytorch_lightning import Trainer
|
||||
from torch.utils.data import DataLoader
|
||||
|
||||
from dataset.dataset import TrajData
|
||||
from lib.utils.config import Config
|
||||
from lib.utils.logging import Logger
|
||||
|
||||
warnings.filterwarnings('ignore', category=FutureWarning)
|
||||
warnings.filterwarnings('ignore', category=UserWarning)
|
||||
|
||||
_ROOT = Path(__file__).parent
|
||||
|
||||
# Paramter Configuration
|
||||
# =============================================================================
|
||||
# Argument Parser
|
||||
main_arg_parser = ArgumentParser(description="parser for fast-neural-style")
|
||||
|
||||
# Main Parameters
|
||||
main_arg_parser.add_argument("--main_debug", type=strtobool, default=False, help="")
|
||||
main_arg_parser.add_argument("--main_eval", type=strtobool, default=False, help="")
|
||||
main_arg_parser.add_argument("--main_seed", type=int, default=69, help="")
|
||||
|
||||
# Data Parameters
|
||||
main_arg_parser.add_argument("--data_worker", type=int, default=10, help="")
|
||||
main_arg_parser.add_argument("--data_batchsize", type=int, default=100, help="")
|
||||
main_arg_parser.add_argument("--data_root", type=str, default='../data/rpoot', help="")
|
||||
|
||||
# Transformations
|
||||
main_arg_parser.add_argument("--transformations_to_tensor", type=strtobool, default=False, help="")
|
||||
|
||||
# Transformations
|
||||
main_arg_parser.add_argument("--train_outpath", type=str, default="output", help="")
|
||||
main_arg_parser.add_argument("--train_version", type=strtobool, required=False, help="")
|
||||
main_arg_parser.add_argument("--train_epochs", type=int, default=10, help="")
|
||||
main_arg_parser.add_argument("--train_batch_size", type=int, default=512, help="")
|
||||
main_arg_parser.add_argument("--train_lr", type=float, default=0.002, help="")
|
||||
|
||||
# Model
|
||||
main_arg_parser.add_argument("--model_type", type=str, default="LeNetAE", help="")
|
||||
main_arg_parser.add_argument("--model_activation", type=str, default="relu", help="")
|
||||
main_arg_parser.add_argument("--model_filters", type=str, default="[32, 16, 4]", help="")
|
||||
main_arg_parser.add_argument("--model_use_bias", type=strtobool, default=True, help="")
|
||||
main_arg_parser.add_argument("--model_use_norm", type=strtobool, default=True, help="")
|
||||
main_arg_parser.add_argument("--model_dropout", type=float, default=0.00, help="")
|
||||
|
||||
# Project
|
||||
main_arg_parser.add_argument("--project_name", type=str, default='traj-gen', help="")
|
||||
main_arg_parser.add_argument("--project_owner", type=str, default='si11ium', help="")
|
||||
main_arg_parser.add_argument("--project_neptune_key", type=str, default=os.getenv('NEPTUNE_KEY'), help="")
|
||||
|
||||
# Parse it
|
||||
args = main_arg_parser.parse_args()
|
||||
config = Config.read_namespace(args)
|
||||
|
||||
# Trainer loading
|
||||
# =============================================================================
|
||||
trainer = Trainer(logger=Logger(config, debug=True))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
print(next(iter(train_dataloader)))
|
||||
pass
|
BIN
preprocessing/__pycache__/generator.cpython-37.pyc
Normal file
121
preprocessing/generator.py
Normal file
@ -0,0 +1,121 @@
|
||||
import multiprocessing as mp
|
||||
import pickle
|
||||
import shelve
|
||||
from collections import defaultdict
|
||||
|
||||
from pathlib import Path
|
||||
from typing import Union
|
||||
|
||||
from tqdm import trange
|
||||
|
||||
from lib.objects.map import Map
|
||||
|
||||
|
||||
class Generator:
|
||||
|
||||
possible_modes = ['one_patching']
|
||||
|
||||
def __init__(self, data_root, map_obj, binary=True):
|
||||
self.binary: bool = binary
|
||||
self.map: Map = map_obj
|
||||
|
||||
self.data_root = Path(data_root)
|
||||
|
||||
def generate_n_trajectories_m_alternatives(self, n, m, dataset_name='', **kwargs):
|
||||
trajectories_with_alternatives = list()
|
||||
for _ in trange(n, desc='Processing Trajectories'):
|
||||
trajectory = self.map.get_random_trajectory()
|
||||
alternatives, labels = self.generate_n_alternatives(trajectory, m, dataset_name=dataset_name, **kwargs)
|
||||
trajectories_with_alternatives.append(dict(trajectory=trajectory, alternatives=alternatives, labels=labels))
|
||||
return trajectories_with_alternatives
|
||||
|
||||
def generate_alternatives(self, trajectory, output: Union[mp.
|
||||
Queue, None] = None, mode='one_patching'):
|
||||
start, dest = trajectory.endpoints
|
||||
if mode == 'one_patching':
|
||||
patch = self.map.get_valid_position()
|
||||
alternative = self.map.get_trajectory_from_vertices(start, patch, dest)
|
||||
else:
|
||||
raise RuntimeError(f'mode checking went wrong...')
|
||||
|
||||
if output:
|
||||
output.put(alternative)
|
||||
return alternative
|
||||
|
||||
def generate_n_alternatives(self, trajectory, n, dataset_name: Union[str, Path] = '',
|
||||
mode='one_patching', equal_samples=True):
|
||||
assert mode in self.possible_modes, f'Parameter "mode" must be either {self.possible_modes}, but was {mode}.'
|
||||
# Define an output queue
|
||||
output = mp.Queue()
|
||||
# Setup a list of processes that we want to run
|
||||
processes = [mp.Process(target=self.generate_alternatives,
|
||||
kwargs=dict(trajectory=trajectory, output=output, mode=mode))
|
||||
for _ in range(n)]
|
||||
# Run processes
|
||||
for p in processes:
|
||||
p.start()
|
||||
# Exit the completed processes
|
||||
for p in processes:
|
||||
p.join()
|
||||
# Get process results from the output queue
|
||||
results = [output.get() for _ in processes]
|
||||
|
||||
# label per homotopic class
|
||||
homotopy_classes = defaultdict(list)
|
||||
homotopy_classes[0].append(trajectory)
|
||||
for i in range(len(results)):
|
||||
alternative = results[i]
|
||||
class_not_found, label = True, None
|
||||
# check for homotopy class
|
||||
for label in homotopy_classes.keys():
|
||||
if self.map.are_homotopic(homotopy_classes[label][0], alternative):
|
||||
homotopy_classes[label].append(alternative)
|
||||
class_not_found = False
|
||||
break
|
||||
if class_not_found:
|
||||
label = len(homotopy_classes)
|
||||
homotopy_classes[label].append(alternative)
|
||||
|
||||
# There should be as much homotopic samples as non-homotopic samples
|
||||
if equal_samples:
|
||||
homotopy_classes = self._remove_unequal(homotopy_classes)
|
||||
|
||||
# Compose lists of alternatives with labels
|
||||
alternatives, labels = list(), list()
|
||||
for key in homotopy_classes.keys():
|
||||
alternatives.extend([homotopy_classes[key]])
|
||||
labels.extend([key] * len(homotopy_classes[key]))
|
||||
|
||||
# Write to disk
|
||||
if dataset_name:
|
||||
self.write_to_disk(dataset_name, trajectory, alternatives, labels)
|
||||
|
||||
# Return
|
||||
return alternatives, labels
|
||||
|
||||
def write_to_disk(self, filepath, trajectory, alternatives, labels):
|
||||
dataset_name = filepath if filepath.endswith('.pik') else f'{filepath}.pik'
|
||||
self.data_root.mkdir(exist_ok=True, parents=True)
|
||||
with shelve.open(str(self.data_root / dataset_name), protocol=pickle.HIGHEST_PROTOCOL) as f:
|
||||
new_key = len(f)
|
||||
f[f'trajectory_{new_key}'] = dict(alternatives=alternatives,
|
||||
trajectory=trajectory,
|
||||
labels=labels)
|
||||
if 'map' not in f:
|
||||
f['map'] = dict(map=self.map, name=f'map_{self.map.name}')
|
||||
|
||||
@staticmethod
|
||||
def _remove_unequal(hom_dict):
|
||||
hom_dict = hom_dict.copy()
|
||||
|
||||
counter = len(hom_dict)
|
||||
while sum([len(hom_dict[class_id]) for class_id in range(len(hom_dict))]) > len(hom_dict[0]):
|
||||
if counter > len(hom_dict):
|
||||
counter = len(hom_dict)
|
||||
if counter in hom_dict:
|
||||
if len(hom_dict[counter]) == 0:
|
||||
del hom_dict[counter]
|
||||
else:
|
||||
del hom_dict[counter][-1]
|
||||
counter -= 1
|
||||
return hom_dict
|
BIN
res/maps/Map.bmp
Normal file
After Width: | Height: | Size: 21 KiB |
BIN
res/maps/doom.bmp
Normal file
After Width: | Height: | Size: 194 KiB |
BIN
res/maps/home.bmp
Normal file
After Width: | Height: | Size: 35 KiB |
BIN
res/maps/maze.bmp
Normal file
After Width: | Height: | Size: 40 KiB |
BIN
res/maps/oet.bmp
Normal file
After Width: | Height: | Size: 248 KiB |
BIN
res/maps/priz.bmp
Normal file
After Width: | Height: | Size: 198 KiB |
BIN
res/maps/tate.bmp
Normal file
After Width: | Height: | Size: 102 KiB |
BIN
res/maps/tate_sw.bmp
Normal file
After Width: | Height: | Size: 66 KiB |
BIN
res/maps/tum.bmp
Normal file
After Width: | Height: | Size: 129 KiB |
0
visualization/bars.py
Normal file
26
visualization/tools.py
Normal file
@ -0,0 +1,26 @@
|
||||
from pathlib import Path
|
||||
import matplotlib.pyplot as plt
|
||||
|
||||
|
||||
class Plotter(object):
|
||||
def __init__(self, root_path=''):
|
||||
self.root_path = Path(root_path)
|
||||
|
||||
def save_current_figure(self, path, extention='.png'):
|
||||
fig, _ = plt.gcf(), plt.gca()
|
||||
# Prepare save location and check img file extention
|
||||
path = self.root_path / Path(path if str(path).endswith(extention) else f'{str(path)}{extention}')
|
||||
path.parent.mkdir(exist_ok=True, parents=True)
|
||||
fig.savefig(path)
|
||||
fig.clf()
|
||||
|
||||
def show_current_figure(self):
|
||||
fig, _ = plt.gcf(), plt.gca()
|
||||
fig.show()
|
||||
fig.clf()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
output_root = Path('..') / 'output'
|
||||
p = Plotter(output_root)
|
||||
p.save_current_figure('test.png')
|