diff --git a/MARBLE/default_params.yaml b/MARBLE/default_params.yaml index 5110b4d9..9acd8fd7 100644 --- a/MARBLE/default_params.yaml +++ b/MARBLE/default_params.yaml @@ -1,12 +1,12 @@ #training parameters -epochs : 20, # optimisation epochs +epochs : 100 # optimisation epochs batch_size : 64 # batch size lr: 0.01 # learning rate momentum: 0.9 #manifold/signal parameters order: 2 # order to which to compute the directional derivatives -inner_product_features: True +inner_product_features: False diffusion: False frac_sampled_nb: -1 # fraction of neighbours to sample for gradient computation (if -1 then all neighbours) include_positions: False # include positions as features (warning: this is untested!) @@ -18,9 +18,9 @@ hidden_channels: [16] # number of hidden channels out_channels: 3 # number of output channels (if null, then =hidden_channels) bias: True # learn bias parameters in MLP vec_norm: False -batch_norm: False # batch normalisation +batch_norm: True # batch normalisation emb_norm: False # spherical output -skip_connections: True # use skips in MLP +skip_connections: False # use skips in MLP # other params seed: 0 # seed for reproducibility diff --git a/MARBLE/geometry.py b/MARBLE/geometry.py index 06c49342..1a0ea4a8 100644 --- a/MARBLE/geometry.py +++ b/MARBLE/geometry.py @@ -18,7 +18,6 @@ from MARBLE.lib.cknn import cknneighbors_graph # isort:skip from MARBLE import utils # isort:skip - def furthest_point_sampling(x, N=None, stop_crit=0.0, start_idx=0): """A greedy O(N^2) algorithm to do furthest points sampling @@ -457,7 +456,9 @@ def compute_laplacian(data, normalization="rw"): num_nodes=data.num_nodes ) - return PyGu.to_dense_adj(edge_index, edge_attr=edge_attr).squeeze() + # return PyGu.to_dense_adj(edge_index, edge_attr=edge_attr).squeeze() + n = len(data.x) + return sp.coo_array((edge_attr, (edge_index[0], edge_index[1])), shape=(n, n)) def compute_connection_laplacian(data, R, normalization="rw"): @@ -670,11 +671,12 @@ def vector_diffusion(x, t, method="spectral", Lc=None): return out -def compute_eigendecomposition(A, eps=1e-8): +def compute_eigendecomposition(A, k=50, eps=1e-8): """Eigendecomposition of a square matrix A. Args: A: square matrix A + k: number of eigenvectors eps: small error term Returns: @@ -683,15 +685,22 @@ def compute_eigendecomposition(A, eps=1e-8): """ if A is None: return None - - A = A.to_dense() + + if k >= A.shape[0]: + k = None # Compute the eigenbasis failcount = 0 while True: try: - evals, evecs = torch.linalg.eigh(A) + if k is None: + evals, evecs = torch.linalg.eigh(A) + else: + evals, evecs = sp.linalg.eigsh(A, k=k, which="SM") + evals, evecs = torch.tensor(evals), torch.tensor(evecs) + evals = torch.clamp(evals, min=0.0) + evecs *= np.sqrt(len(evecs)) break except Exception as e: # pylint: disable=broad-exception-caught @@ -702,4 +711,4 @@ def compute_eigendecomposition(A, eps=1e-8): print("--- decomp failed; adding eps ===> count: " + str(failcount)) A += torch.eye(A.shape[0]) * (eps * 10 ** (failcount - 1)) - return evals, evecs + return evals, evecs \ No newline at end of file diff --git a/MARBLE/main.py b/MARBLE/main.py index 90903bc4..cf5ee3a9 100644 --- a/MARBLE/main.py +++ b/MARBLE/main.py @@ -18,6 +18,7 @@ from MARBLE import layers from MARBLE import utils +import warnings class net(nn.Module): """MARBLE neural network. @@ -60,16 +61,17 @@ def __init__(self, data, loadpath=None, params=None, verbose=True): """ super().__init__() + device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') + if loadpath is not None: if Path(loadpath).is_dir(): loadpath = max(glob.glob(f"{loadpath}/best_model*")) - self.params = torch.load(loadpath, map_location=torch.device('cuda' if torch.cuda.is_available() else 'cpu'))["params"] + self.params = torch.load(loadpath, map_location=device)["params"] else: if params is not None: - if isinstance(params, str) and Path(params).exists(): - with open(params, "rb") as f: - params = yaml.safe_load(f) self.params = params + else: + self.params = {} self._epoch = 0 # to resume optimisation self.parse_parameters(data) @@ -217,11 +219,7 @@ def setup_layers(self): bias=self.params["bias"], ) - - - - def forward(self, data, n_id, adjs=None): """Forward pass. Messages are passed to a set target nodes (current batch) from source @@ -289,8 +287,12 @@ def forward(self, data, n_id, adjs=None): emb = F.normalize(emb) return emb, mask[: size[1]] + + def evaluate(self, data): + warnings.warn("MARBLE.evaluate() is deprecated. Use MARBLE.transform() instead.") + self.transform(data) - def evaluate(self, data): + def transform(self, data): """Forward pass @ evaluation (no minibatches)""" with torch.no_grad(): size = (data.x.shape[0], data.x.shape[0]) @@ -345,8 +347,13 @@ def batch_loss(self, data, loader, train=False, verbose=False, optimizer=None): self.eval() return cum_loss / len(loader), optimizer - + def run_training(self, data, outdir=None, verbose=False): + warnings.warn("MARBLE.run_training() is deprecated. Use MARBLE.fit() instead.") + + self.fit(data, outdir=outdir, verbose=verbose) + + def fit(self, data, outdir=None, verbose=False): """Network training. Args: diff --git a/MARBLE/plotting.py b/MARBLE/plotting.py index 834337fb..86691ff0 100644 --- a/MARBLE/plotting.py +++ b/MARBLE/plotting.py @@ -131,8 +131,7 @@ def histograms(data, titles=None, col=2, figsize=(10, 10)): """ assert hasattr( data, "clusters" - ), "No clusters found. First, run \ - geometry.cluster(data) or postprocessing(data)!" + ), "No clusters found. First, run postprocessing.cluster(data)!" labels, s = data.clusters["labels"], data.clusters["slices"] n_slices = len(s) - 1 @@ -245,9 +244,9 @@ def embedding( ax.scatter(emb_[t, 0], emb_[t, 1], emb_[t, 2], c=cgrad, alpha=alpha, s=s, label=title) else: if dim == 2: - ax.scatter(emb_[:, 0], emb_[:, 1], c=c_, alpha=alpha, s=s, label=title) + ax.scatter(emb_[:, 0], emb_[:, 1], color=c_, alpha=alpha, s=s, label=title) elif dim == 3: - ax.scatter(emb_[:, 0], emb_[:, 1], emb_[:, 2], c=c, alpha=alpha, s=s, label=title) + ax.scatter(emb_[:, 0], emb_[:, 1], emb_[:, 2], color=c_, alpha=alpha, s=s, label=title) if dim == 2: if hasattr(data, "clusters") and clusters_visible: @@ -296,8 +295,7 @@ def neighbourhoods( assert hasattr( data, "clusters" - ), "No clusters found. First, run \ - geometry.cluster(data) or postprocessing(data)!" + ), "No clusters found. First, run postprocessing.cluster(data)!" vector = data.x.shape[1] > 1 clusters = data.clusters diff --git a/MARBLE/postprocessing.py b/MARBLE/postprocessing.py index 3011ad8b..8084635f 100644 --- a/MARBLE/postprocessing.py +++ b/MARBLE/postprocessing.py @@ -4,6 +4,21 @@ from MARBLE import geometry as g +def cluster(data, cluster_typ="kmeans", n_clusters=15, seed=0): + + clusters = g.cluster(data.emb, cluster_typ, n_clusters, seed) + clusters = g.relabel_by_proximity(clusters) + + clusters["slices"] = data._slice_dict["x"] # pylint: disable=protected-access + + if data.number_of_resamples > 1: + clusters["slices"] = clusters["slices"][:: data.number_of_resamples] + + data.clusters = clusters + + return data + + def distribution_distances(data, cluster_typ="kmeans", n_clusters=None, seed=0): """Return distance between datasets. @@ -18,21 +33,13 @@ def distribution_distances(data, cluster_typ="kmeans", n_clusters=None, seed=0): if n_clusters is not None: # k-means cluster - clusters = g.cluster(emb, cluster_typ, n_clusters, seed) - clusters = g.relabel_by_proximity(clusters) - - clusters["slices"] = data._slice_dict["x"] # pylint: disable=protected-access - - if data.number_of_resamples > 1: - clusters["slices"] = clusters["slices"][:: data.number_of_resamples] + data = cluster(data, cluster_typ, n_clusters, seed) # compute distances between clusters data.dist, data.gamma = g.compute_distribution_distances( - clusters=clusters, slices=clusters["slices"] + clusters=data.clusters, slices=data.clusters["slices"] ) - data.clusters = clusters - else: data.emb = emb data.dist, _ = g.compute_distribution_distances( diff --git a/MARBLE/preprocessing.py b/MARBLE/preprocessing.py index 66deae3e..48c76877 100644 --- a/MARBLE/preprocessing.py +++ b/MARBLE/preprocessing.py @@ -1,5 +1,4 @@ -"""Prepare module.""" -import numpy as np +"""Preprocessing module.""" import torch from torch_geometric.data import Batch from torch_geometric.data import Data @@ -14,16 +13,12 @@ def construct_dataset( labels=None, mask=None, graph_type="cknn", - k=15, - n_geodesic_nb=10, + k=20, + frac_geodesic_nb=1.5, stop_crit=0.0, number_of_resamples=1, - compute_laplacian=False, - compute_connection_laplacian=False, - return_spectrum=True, var_explained=0.9, local_gauges=False, - dim_man=None, delta=1.0, ): """Construct PyG dataset from node positions and features. @@ -34,16 +29,13 @@ def construct_dataset( labels: any additional data labels used for plotting only graph_type: type of nearest-neighbours graph: cknn (default), knn or radius k: number of nearest-neighbours to construct the graph - n_geodesic_nb: number of geodesic neighbours to fit the gauges to - to map to tangent space + frac_geodesic_nb: number of geodesic neighbours to fit the gauges to + to map to tangent space k*frac_geodesic_nb stop_crit: stopping criterion for furthest point sampling number_of_resamples: number of furthest point sampling runs to prevent bias (experimental) - compute_laplacian: set to True to compute laplacian - compute_connection_laplacian: set to True to compute the connection laplacian var_explained: fraction of variance explained by the local gauges local_gauges: is True, it will try to compute local gauges if it can (signal dim is > 2, embedding dimension is > 2 or dim embedding is not dim of manifold) - dim_man: if the manifold dimension is known, it can be set here or it will be estimated delta: argument for cknn graph construction to decide the radius for each points. """ @@ -103,24 +95,15 @@ def construct_dataset( return _compute_geometric_objects( batch, local_gauges=local_gauges, - compute_laplacian=compute_laplacian, - compute_connection_laplacian=compute_connection_laplacian, - n_geodesic_nb=n_geodesic_nb, + frac_geodesic_nb=frac_geodesic_nb, var_explained=var_explained, - dim_man=dim_man, - return_spectrum=return_spectrum ) -def _compute_geometric_objects( - data, - n_geodesic_nb=2.0, +def _compute_geometric_objects(data, + frac_geodesic_nb=2.0, var_explained=0.9, - return_spectrum=True, local_gauges=False, - compute_laplacian=False, - compute_connection_laplacian=False, - dim_man=None, ): """ Compute geometric objects used later: local gauges, Levi-Civita connections @@ -157,7 +140,7 @@ def _compute_geometric_objects( if local_gauges: try: - gauges, Sigma = g.compute_gauges(data, n_geodesic_nb=n_geodesic_nb) + gauges, Sigma = g.compute_gauges(data, n_geodesic_nb=frac_geodesic_nb) except Exception as exc: raise Exception( "\nCould not compute gauges (possibly data is too sparse or the \ @@ -166,44 +149,30 @@ def _compute_geometric_objects( else: gauges = torch.eye(dim_emb).repeat(n, 1, 1) - # Laplacian - if compute_laplacian: - L = g.compute_laplacian(data) - else: - L = None + L = g.compute_laplacian(data) if local_gauges: - if not dim_man: - dim_man = g.manifold_dimension(Sigma, frac_explained=var_explained) - data.dim_man = dim_man - - print(f"\n---- Manifold dimension: {dim_man}") + data.dim_man = g.manifold_dimension(Sigma, frac_explained=var_explained) + print(f"\n---- Manifold dimension: {data.dim_man}") - gauges = gauges[:, :, :dim_man] + gauges = gauges[:, :, :data.dim_man] R = g.compute_connections(data, gauges) print("\n---- Computing kernels ... ", end="") kernels = g.gradient_op(data.pos, data.edge_index, gauges) - kernels = [utils.tile_tensor(K, dim_man) for K in kernels] + kernels = [utils.tile_tensor(K, data.dim_man) for K in kernels] kernels = [K * R for K in kernels] - print("Done ") - if compute_connection_laplacian: - Lc = g.compute_connection_laplacian(data, R) - else: - Lc = None + Lc = g.compute_connection_laplacian(data, R) else: print("\n---- Computing kernels ... ", end="") kernels = g.gradient_op(data.pos, data.edge_index, gauges) - print("Done ") Lc = None - if return_spectrum: - print("---- Computing eigendecomposition ... ", end="") - L = g.compute_eigendecomposition(L) - Lc = g.compute_eigendecomposition(Lc) - print("Done ") + print("---- Computing eigendecomposition ... ", end="") + L = g.compute_eigendecomposition(L) + Lc = g.compute_eigendecomposition(Lc) data.kernels = [ utils.to_SparseTensor(K.coalesce().indices(), value=K.coalesce().values()) for K in kernels diff --git a/examples/rat_task/Demo_consistency.ipynb b/examples/rat_hippocampus/Demo_consistency.ipynb similarity index 100% rename from examples/rat_task/Demo_consistency.ipynb rename to examples/rat_hippocampus/Demo_consistency.ipynb diff --git a/examples/rat_task/Demo_decoding.ipynb b/examples/rat_hippocampus/Demo_decoding.ipynb similarity index 100% rename from examples/rat_task/Demo_decoding.ipynb rename to examples/rat_hippocampus/Demo_decoding.ipynb diff --git a/examples/rat_task/rat_data.pkl b/examples/rat_hippocampus/rat_data.pkl similarity index 100% rename from examples/rat_task/rat_data.pkl rename to examples/rat_hippocampus/rat_data.pkl diff --git a/examples/rat_task/rat_utils.py b/examples/rat_hippocampus/rat_utils.py similarity index 100% rename from examples/rat_task/rat_utils.py rename to examples/rat_hippocampus/rat_utils.py diff --git a/examples/ex_scalar_field_flat_surface.py b/examples/toy_examples/ex_scalar_field_flat_surface.py similarity index 64% rename from examples/ex_scalar_field_flat_surface.py rename to examples/toy_examples/ex_scalar_field_flat_surface.py index adf3ffb4..4cd0e1fe 100644 --- a/examples/ex_scalar_field_flat_surface.py +++ b/examples/toy_examples/ex_scalar_field_flat_surface.py @@ -28,38 +28,35 @@ def main(): x = [dynamics.sample_2d(n, [[-1, -1], [1, 1]], "random") for i in range(4)] y = [f0(x[0]), f1(x[1]), f2(x[2]), f3(x[3])] # evaluated functions - # construct PyG data object - data = preprocessing.construct_dataset(x, y, graph_type="cknn", k=15) + # construct data object + data = preprocessing.construct_dataset(x, y) # train model params = { - "epochs": 50, # optimisation epochs - "order": 2, # order of derivatives - "hidden_channels": 16, # number of internal dimensions in MLP - "out_channels": 5, + "order": 1, # order of derivatives "include_self": False, # remove feature centers, for testing only, to get the figure in the SI - "inner_product_features": False, } model = net(data, params=params) - model.run_training(data) + model.fit(data) # evaluate model on data - data = model.evaluate(data) - n_clusters = 10 # use 15 clusters for simple visualisation - data = postprocessing.distribution_distances(data, n_clusters=n_clusters) + data = model.transform(data) + + # embed into 2D for visualisation + data = postprocessing.cluster(data, n_clusters=10) data = postprocessing.embed_in_2D(data, embed_typ="tsne") # plot titles = ["Constant", "Linear", "Parabola", "Saddle"] plotting.fields(data, titles=titles, node_size=20, col=2) - # plt.savefig('../results/fields.svg') + plt.savefig('fields.png') plotting.embedding(data, data.y.numpy(), titles=titles, clusters_visible=True) - # plt.savefig('../results/embedding.svg') + plt.savefig('embedding.png') plotting.histograms(data, titles=titles) - # plt.savefig('../results/histogram.svg') + plt.savefig('histogram.png') plotting.neighbourhoods(data, hops=1, norm=True, figsize=(10, 20)) - # plt.savefig('../results/neighbourhoods.svg') + plt.savefig('neighbourhoods.png') plt.show() diff --git a/examples/ex_vector_field_curved_surface.py b/examples/toy_examples/ex_vector_field_curved_surface.py similarity index 76% rename from examples/ex_vector_field_curved_surface.py rename to examples/toy_examples/ex_vector_field_curved_surface.py index fad81da2..08d7bfe0 100644 --- a/examples/ex_vector_field_curved_surface.py +++ b/examples/toy_examples/ex_vector_field_curved_surface.py @@ -57,33 +57,29 @@ def main(): # train model params = { - "epochs": 70, # optimisation epochs - "order": 1, # first-order derivatives are enough because the vector field have at most first-order features - "hidden_channels": 32, # 16 is enough in this simple example - "out_channels": 3, # 3 is enough in this simple example + "order": 1, "inner_product_features": True, } model = net(data, params=params) - model.run_training(data) + model.fit(data) # evaluate model on data - data = model.evaluate(data) - n_clusters = 20 # use 15 clusters for simple visualisation - data = postprocessing.distribution_distances(data, n_clusters=n_clusters, cluster_typ="kmeans") + data = model.transform(data) + data = postprocessing.cluster(data) data = postprocessing.embed_in_2D(data) # plot titles = ["Linear left", "Linear right", "Vortex right", "Vortex left"] # plot gauges in black to show that they 'hug' the manifold surface plotting.fields(data, titles=titles, col=2, width=3, scale=10, view=[0, 40], plot_gauges=True) - # plt.savefig('../results/fields.svg') + plt.savefig('fields.png') plotting.embedding(data, data.y.numpy(), titles=titles, clusters_visible=True) - # plt.savefig('../results/embedding.svg') + plt.savefig('embedding.png') plotting.histograms(data, titles=titles) - # plt.savefig('../results/histogram.svg') + plt.savefig('histogram.png') plotting.neighbourhoods(data) - # plt.savefig('../results/neighbourhoods.svg') + plt.savefig('neighbourhoods.png') plt.show() diff --git a/examples/ex_vector_field_flat_surface.py b/examples/toy_examples/ex_vector_field_flat_surface.py similarity index 59% rename from examples/ex_vector_field_flat_surface.py rename to examples/toy_examples/ex_vector_field_flat_surface.py index e785ea63..0095b265 100644 --- a/examples/ex_vector_field_flat_surface.py +++ b/examples/toy_examples/ex_vector_field_flat_surface.py @@ -8,11 +8,9 @@ def f0(x): return x * 0 + np.array([-1, -1]) - def f1(x): return x * 0 + np.array([1, 1]) - def f2(x): eps = 1e-1 norm = np.sqrt((x[:, [0]] + 1) ** 2 + x[:, [1]] ** 2 + eps) @@ -20,7 +18,6 @@ def f2(x): v = -(x[:, [0]] + 1) / norm return np.hstack([u, v]) - def f3(x): eps = 1e-1 norm = np.sqrt((x[:, [0]] - 1) ** 2 + x[:, [1]] ** 2 + eps) @@ -37,36 +34,28 @@ def main(): x = [dynamics.sample_2d(n, [[-1, -1], [1, 1]], "random") for i in range(4)] y = [f0(x[0]), f1(x[1]), f2(x[2]), f3(x[3])] # evaluated functions - # construct PyG data object - data = preprocessing.construct_dataset(x, y, graph_type="cknn", k=20) + # construct data object + data = preprocessing.construct_dataset(x, y) # train model - params = { - "epochs": 100, # optimisation epochs - "order": 1, # first-order derivatives are enough because the vector field have at most first-order features - "hidden_channels": 32, # 16 is enough in this simple example - "out_channels": 3, # 3 is enough in this simple example - "inner_product_features": False, # try changing this to False and see how the embeddings change - } - model = net(data, params=params) - model.run_training(data) + model = net(data) + model.fit(data) # evaluate model on data - data = model.evaluate(data) - n_clusters = 15 # use 15 clusters for simple visualisation - data = postprocessing.distribution_distances(data, n_clusters=n_clusters, cluster_typ="kmeans") + data = model.transform(data) + data = postprocessing.cluster(data) data = postprocessing.embed_in_2D(data) # plot results titles = ["Linear left", "Linear right", "Vortex right", "Vortex left"] plotting.fields(data, titles=titles, col=2) - # plt.savefig('../results/fields.svg') + plt.savefig('fields.png') plotting.embedding(data, data.y.numpy(), titles=titles, clusters_visible=True) - plt.savefig('../results/embedding.svg') + plt.savefig('mbedding.png') plotting.histograms(data, titles=titles) - # plt.savefig('../results/histogram.svg') + plt.savefig('histogram.png') plotting.neighbourhoods(data) - # plt.savefig('../results/neighbourhoods.svg') + plt.savefig('neighbourhoods.png') plt.show() diff --git a/examples/toy_examples/outputs/best_model_20231127-112433.pth b/examples/toy_examples/outputs/best_model_20231127-112433.pth new file mode 100644 index 00000000..b74b6523 Binary files /dev/null and b/examples/toy_examples/outputs/best_model_20231127-112433.pth differ diff --git a/examples/toy_examples/outputs/best_model_20231127-112530.pth b/examples/toy_examples/outputs/best_model_20231127-112530.pth new file mode 100644 index 00000000..762ef0a2 Binary files /dev/null and b/examples/toy_examples/outputs/best_model_20231127-112530.pth differ diff --git a/examples/toy_examples/outputs/best_model_20231127-112638.pth b/examples/toy_examples/outputs/best_model_20231127-112638.pth new file mode 100644 index 00000000..4a5ae00c Binary files /dev/null and b/examples/toy_examples/outputs/best_model_20231127-112638.pth differ diff --git a/examples/toy_examples/outputs/best_model_20231127-112824.pth b/examples/toy_examples/outputs/best_model_20231127-112824.pth new file mode 100644 index 00000000..19f7943c Binary files /dev/null and b/examples/toy_examples/outputs/best_model_20231127-112824.pth differ diff --git a/examples/toy_examples/outputs/best_model_20231127-113924.pth b/examples/toy_examples/outputs/best_model_20231127-113924.pth new file mode 100644 index 00000000..b5d62d9f Binary files /dev/null and b/examples/toy_examples/outputs/best_model_20231127-113924.pth differ diff --git a/examples/toy_examples/outputs/best_model_20231127-114307.pth b/examples/toy_examples/outputs/best_model_20231127-114307.pth new file mode 100644 index 00000000..fae36c19 Binary files /dev/null and b/examples/toy_examples/outputs/best_model_20231127-114307.pth differ diff --git a/examples/toy_examples/outputs/best_model_20231127-120421.pth b/examples/toy_examples/outputs/best_model_20231127-120421.pth new file mode 100644 index 00000000..9c104b25 Binary files /dev/null and b/examples/toy_examples/outputs/best_model_20231127-120421.pth differ diff --git a/examples/toy_examples/outputs/best_model_20231127-121031.pth b/examples/toy_examples/outputs/best_model_20231127-121031.pth new file mode 100644 index 00000000..d4404b9b Binary files /dev/null and b/examples/toy_examples/outputs/best_model_20231127-121031.pth differ diff --git a/examples/toy_examples/outputs/best_model_20231127-121448.pth b/examples/toy_examples/outputs/best_model_20231127-121448.pth new file mode 100644 index 00000000..8a7ee068 Binary files /dev/null and b/examples/toy_examples/outputs/best_model_20231127-121448.pth differ diff --git a/examples/toy_examples/outputs/best_model_20231127-123632.pth b/examples/toy_examples/outputs/best_model_20231127-123632.pth new file mode 100644 index 00000000..9474d0e7 Binary files /dev/null and b/examples/toy_examples/outputs/best_model_20231127-123632.pth differ diff --git a/examples/toy_examples/outputs/best_model_20231127-123834.pth b/examples/toy_examples/outputs/best_model_20231127-123834.pth new file mode 100644 index 00000000..cb95c5c8 Binary files /dev/null and b/examples/toy_examples/outputs/best_model_20231127-123834.pth differ diff --git a/examples/toy_examples/outputs/best_model_20231127-124125.pth b/examples/toy_examples/outputs/best_model_20231127-124125.pth new file mode 100644 index 00000000..f66f2332 Binary files /dev/null and b/examples/toy_examples/outputs/best_model_20231127-124125.pth differ diff --git a/examples/toy_examples/outputs/best_model_20231127-124225.pth b/examples/toy_examples/outputs/best_model_20231127-124225.pth new file mode 100644 index 00000000..e4df20b4 Binary files /dev/null and b/examples/toy_examples/outputs/best_model_20231127-124225.pth differ diff --git a/examples/toy_examples/outputs/last_model_20231127-112433.pth b/examples/toy_examples/outputs/last_model_20231127-112433.pth new file mode 100644 index 00000000..1946a190 Binary files /dev/null and b/examples/toy_examples/outputs/last_model_20231127-112433.pth differ diff --git a/examples/toy_examples/outputs/last_model_20231127-112530.pth b/examples/toy_examples/outputs/last_model_20231127-112530.pth new file mode 100644 index 00000000..a02228d5 Binary files /dev/null and b/examples/toy_examples/outputs/last_model_20231127-112530.pth differ diff --git a/examples/toy_examples/outputs/last_model_20231127-112638.pth b/examples/toy_examples/outputs/last_model_20231127-112638.pth new file mode 100644 index 00000000..e0f140da Binary files /dev/null and b/examples/toy_examples/outputs/last_model_20231127-112638.pth differ diff --git a/examples/toy_examples/outputs/last_model_20231127-112824.pth b/examples/toy_examples/outputs/last_model_20231127-112824.pth new file mode 100644 index 00000000..36fd7040 Binary files /dev/null and b/examples/toy_examples/outputs/last_model_20231127-112824.pth differ diff --git a/examples/toy_examples/outputs/last_model_20231127-113924.pth b/examples/toy_examples/outputs/last_model_20231127-113924.pth new file mode 100644 index 00000000..3cc437df Binary files /dev/null and b/examples/toy_examples/outputs/last_model_20231127-113924.pth differ diff --git a/examples/toy_examples/outputs/last_model_20231127-114307.pth b/examples/toy_examples/outputs/last_model_20231127-114307.pth new file mode 100644 index 00000000..bcfccd43 Binary files /dev/null and b/examples/toy_examples/outputs/last_model_20231127-114307.pth differ diff --git a/examples/toy_examples/outputs/last_model_20231127-120421.pth b/examples/toy_examples/outputs/last_model_20231127-120421.pth new file mode 100644 index 00000000..c7f794f9 Binary files /dev/null and b/examples/toy_examples/outputs/last_model_20231127-120421.pth differ diff --git a/examples/toy_examples/outputs/last_model_20231127-121448.pth b/examples/toy_examples/outputs/last_model_20231127-121448.pth new file mode 100644 index 00000000..3e4f0625 Binary files /dev/null and b/examples/toy_examples/outputs/last_model_20231127-121448.pth differ diff --git a/examples/toy_examples/outputs/last_model_20231127-123632.pth b/examples/toy_examples/outputs/last_model_20231127-123632.pth new file mode 100644 index 00000000..207b83c4 Binary files /dev/null and b/examples/toy_examples/outputs/last_model_20231127-123632.pth differ diff --git a/examples/toy_examples/outputs/last_model_20231127-123834.pth b/examples/toy_examples/outputs/last_model_20231127-123834.pth new file mode 100644 index 00000000..6a5e6769 Binary files /dev/null and b/examples/toy_examples/outputs/last_model_20231127-123834.pth differ diff --git a/examples/toy_examples/outputs/last_model_20231127-124125.pth b/examples/toy_examples/outputs/last_model_20231127-124125.pth new file mode 100644 index 00000000..723d97fb Binary files /dev/null and b/examples/toy_examples/outputs/last_model_20231127-124125.pth differ diff --git a/examples/toy_examples/outputs/last_model_20231127-124225.pth b/examples/toy_examples/outputs/last_model_20231127-124225.pth new file mode 100644 index 00000000..67dc2627 Binary files /dev/null and b/examples/toy_examples/outputs/last_model_20231127-124225.pth differ diff --git a/examples/vanderpol.ipynb b/examples/toy_examples/vanderpol.ipynb similarity index 100% rename from examples/vanderpol.ipynb rename to examples/toy_examples/vanderpol.ipynb