initial
This commit is contained in:
0
lib/__init__.py
Normal file
0
lib/__init__.py
Normal file
BIN
lib/__pycache__/__init__.cpython-37.pyc
Normal file
BIN
lib/__pycache__/__init__.cpython-37.pyc
Normal file
Binary file not shown.
0
lib/models/__init__.py
Normal file
0
lib/models/__init__.py
Normal file
468
lib/models/blocks.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
0
lib/objects/__init__.py
Normal file
BIN
lib/objects/__pycache__/__init__.cpython-37.pyc
Normal file
BIN
lib/objects/__pycache__/__init__.cpython-37.pyc
Normal file
Binary file not shown.
BIN
lib/objects/__pycache__/map.cpython-37.pyc
Normal file
BIN
lib/objects/__pycache__/map.cpython-37.pyc
Normal file
Binary file not shown.
BIN
lib/objects/__pycache__/trajectory.cpython-37.pyc
Normal file
BIN
lib/objects/__pycache__/trajectory.cpython-37.pyc
Normal file
Binary file not shown.
BIN
lib/objects/__pycache__/variables.cpython-37.pyc
Normal file
BIN
lib/objects/__pycache__/variables.cpython-37.pyc
Normal file
Binary file not shown.
125
lib/objects/map.py
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
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
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
0
lib/utils/__init__.py
Normal file
BIN
lib/utils/__pycache__/__init__.cpython-37.pyc
Normal file
BIN
lib/utils/__pycache__/__init__.cpython-37.pyc
Normal file
Binary file not shown.
BIN
lib/utils/__pycache__/config.cpython-37.pyc
Normal file
BIN
lib/utils/__pycache__/config.cpython-37.pyc
Normal file
Binary file not shown.
BIN
lib/utils/__pycache__/logging.cpython-37.pyc
Normal file
BIN
lib/utils/__pycache__/logging.cpython-37.pyc
Normal file
Binary file not shown.
96
lib/utils/config.py
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
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
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
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
|
||||
Reference in New Issue
Block a user