aidos-lab / pytorch-topological

A topological machine learning framework based on PyTorch
https://pytorch-topological.readthedocs.io/
BSD 3-Clause "New" or "Revised" License
147 stars 21 forks source link

cannot run example scripts #28

Closed beew closed 1 year ago

beew commented 1 year ago

This is the image-smoothing script in the examples folder of the source package.

import numpy as np
import matplotlib.pyplot as plt

from torch_topological.nn import Cubical
from torch_topological.nn import SummaryStatisticLoss

from sklearn.datasets import make_circles

import torch

def _make_data(n_cells, n_samples=1000):
    X = make_circles(n_samples, shuffle=True, noise=0.05)[0]

    heatmap, *_ = np.histogram2d(X[:, 0], X[:, 1], bins=n_cells)
    heatmap -= heatmap.mean()
    heatmap /= heatmap.max()

    return heatmap

class TopologicalSimplification(torch.nn.Module):
    def __init__(self, theta):
        super().__init__()

        self.theta = theta

    def forward(self, x):
        persistence_information = cubical(x)
        persistence_information = [persistence_information[0]]

        gens, pd = persistence_information[0]

        persistence = (pd[:, 1] - pd[:, 0]).abs()
        indices = persistence <= self.theta

        gens = gens[indices]

        indices = torch.vstack((gens[:, 0:2], gens[:, 2:]))

        indices = np.ravel_multi_index(
            (indices[:, 0], indices[:, 1]), x.shape
        )

        x.ravel()[indices] = 0.0

        persistence_information = cubical(x)
        persistence_information = [persistence_information[0]]

        return x, persistence_information

if __name__ == '__main__':

    np.random.seed(23)

    Y = _make_data(50)
    Y = torch.as_tensor(Y, dtype=torch.float)
    X = torch.as_tensor(
        Y + np.random.normal(scale=0.05, size=Y.shape), dtype=torch.float
    )

    theta = torch.nn.Parameter(
        torch.as_tensor(1.0), requires_grad=True,
    )

    topological_simplification = TopologicalSimplification(theta)

    optimizer = torch.optim.Adam(
        [theta], lr=1e-2
    )
    loss_fn = SummaryStatisticLoss('total_persistence', p=1)

    cubical = Cubical()

    persistence_information_target = cubical(Y)
    persistence_information_target = [persistence_information_target[0]]

    for i in range(500):
        X, persistence_information = topological_simplification(X)

        optimizer.zero_grad()

        loss = loss_fn(
            persistence_information,
            persistence_information_target
        )

        print(loss.item(), theta.item())

        theta.backward()
        optimizer.step()

    X = X.detach().numpy()

    plt.imshow(X)
    plt.show()

Trying to run it results in

ImportError: cannot import name 'Cubical' from 'torch_topological.nn' (/home/bernard/opt/python310/lib/python3.10/site-packages/torch_topological/nn/__init__.py)

Changing Cubical to CubicalComplex results in a different error

Traceback (most recent call last):

  File ~/lib/python3.10/site-packages/spyder_kernels/py3compat.py:356 in compat_exec
    exec(code, globals, locals)

  File ~/Examples/torch_topological/examples/image_smoothing.py:82
    X, persistence_information = topological_simplification(X)

  File ~/lib/python3.10/site-packages/torch/nn/modules/module.py:1501 in _call_impl
    return forward_call(*args, **kwargs)

  File ~/Examples/torch_topological/examples/image_smoothing.py:34 in forward
    gens, pd = persistence_information[0]

TypeError: 'PersistenceInformation' object is not iterable
Pseudomanifold commented 1 year ago

Thanks! This is fixed now in the most recent development version. Notice that the image smoothing example is still a work-in-progress, though—I would not use that in production because the simplification process is just too simple.