Code for "Diffusion is All You Need for Learning on Surfaces"

Overview

Source code for "Diffusion is All You Need for Learning on Surfaces", by

NOTE: the linked paper is a preprint, and this code should be viewed similarly. A full code release, including experimental details, will be added after publication.

network diagram

Files outline

  • README.md This file.
  • src/utils.py Utilities and helper functions used by the code.
  • src/geometry.py Core geometric routines, mainly to build the Laplacian and gradient matrices, as well as computing the corresponding spectral basis. Includes a caching mechanism.
  • src/layers.py The implemention of the DiffusionNetBlock, including pointwise MLPs, learned diffusion, and learned gradient features.
  • src/human_seg_dataset.py A dataset loader for the human mesh segmentation dataset.
  • src/run_human_seg.py A main script to fit mesh segmentations on the humans dataset.
  • environment.yml A conda environment file which can be used to install packages.

Prerequisites

DiffusionNet depends on pytorch, as well as a handful of other fairly typical numerical packages. These can be installed manually without too much trouble, but alternately a conda environment file is provided with known-working package versions (see conda documentation for additional instructions).

conda env create -f environment.yml

The code assumes a GPU with CUDA support. DiffusionNet has minimal memory requirements; >4GB GPU memory should be sufficient.

Human mesh segmentation example

We include machinery to run one example from the paper, segmenting meshes of humans.

Our dataloader bootstraps off the dataloader graciously provided by the authors of HSN at https://github.com/rubenwiersma/hsn. The corresponding dataset can also be downloaded from the link in that repository: https://surfdrive.surf.nl/files/index.php/s/L68uSYpHtfO6dLa.

  • Install dependencies (see above).
  • Place the dataset in data/seg/raw/, like data/human_seg/raw/ShapeSeg/Adobe/, etc. The dataset can be obtained from the link above; note that the files you need are nested within the downloaded archive.
  • Call python src/run_human_seg.py to train the model. Note that on the first pass through the code will precompute the necessary operators and store them in cache/*.
Comments
  • Problems with robust-laplacian 0.1.0

    Problems with robust-laplacian 0.1.0

    I get compilation errors when installing the dependencies, because robust-laplacian 0.1.0 seems to have problems with the namespace of Vector3. I installed the latest version (0.2.4) and it seems to work.

    So maybe the dependency should just be changed to >=0.2.4 if there is no reason against using a more recent version.

    opened by aschier 2
  • LICENSE?

    LICENSE?

    Hi, when the paper is released or earlier, can you add a license text for the code?

    I'm from Godot Engine so I would prefer that it is MIT-license compatible.

    Amazing work.

    opened by fire 2
  • Classification

    Classification

    Hi,

    as of now, only the segmentation example is online, so I'm wondering how to adapt this for classification.

    In the paper you write: "Various activations can be appended to the end of the network based on the problem at hand, such as a softmax for segmentation, or a global mean followed by a softmax for classification"

    Does that mean I can keep the last_activation as lambda x : torch.nn.functional.log_softmax(x,dim=-1) and I need to add a layer for global mean before? What is exactly meant as global mean? I assume you do not mean average pooling as you write in the paper, no pooling was needed.

    Thanks for your help!

    opened by lucacarotenuto 2
  • Inference

    Inference

    I'm currently looking where I can speed up my whole inference pipeline. Is the computation of the operators at the end of the dataset.py necessary for pure inference or is it just useful for caching during training?

    opened by bensch98 1
  • Is it a typo?

    Is it a typo?

    Hi, @nmwsharp,

    From the experiment in functional correspondences, is there a typo in the last line command in README.md? Should it be : python functional_correspondence.py --test_dataset=faust --input_features=xyz --load_model=pretrained_models/faust_xyz.pth or python functional_correspondence.py --test_dataset=faust --input_features=hks --load_model=pretrained_models/faust_hks.pth

    opened by amiltonwong 1
  • DiffusionNet's diffusion manipulation.

    DiffusionNet's diffusion manipulation.

    It's very lucky to read your great paper. I have a few questions.

    1. Can your method be considered as a kind of mean curvature flow? It is very similar to mean curvature flow.
    2. In fact, diffusion manipulation is a smooth manipulation. We notice the shape information is distorted by the smooth manipulations when features get global support. In this case, the global shape information may be distorted (maybe a sphere), so some researchers viewed HKS as a local metric (not only because of limited diffusion time). Do you think distorted global information is OK for global information?
    opened by lidan233 1
  • Segmentation on the simplified human dataset (face label)

    Segmentation on the simplified human dataset (face label)

    Thank you for your great work! I'm a little confused about the segmentation accuracy of the Human dataset, which is provided by PD-Mesh (Simplified inputs with hard ground truth at faces). I try to use DiffusionNet (xyz) on it, but the accuracy is only 81%. I try to use hks as input, and the accuracy is only 79%.
    image I also try to adjust C_width, but it seems to have no effect. emmmmm..... I want to know what parameters I need to adjust....

    The code for loading data and training: human_seg_dataset.py

    import os
    import sys
    import numpy as np
    import torch
    from torch.utils.data import Dataset
    import potpourri3d as pp3d
    sys.path.append(os.path.join(os.path.dirname(__file__), "../../"))  # add the path to the DiffusionNet src
    import src.diffusion_net as diffusion_net
    
    
    def is_mesh_file(filename):
        return any(filename.endswith(extension) for extension in ['.obj', 'off'])
    
    
    class HumanDataset(Dataset):
        def __init__(self, root_dir, phase, k_eig=128, op_cache_dir=None):
            self.k_eig = k_eig 
            self.root_dir = root_dir
            self.cache_dir = os.path.join(root_dir, "cache")
            self.op_cache_dir = op_cache_dir
            self.dir = os.path.join(self.root_dir, phase)
            self.paths = self.make_dataset(self.dir)
            self.seg_paths = self.get_seg_files(self.paths, os.path.join(self.root_dir, 'seg'))
    
        def __len__(self):
            return len(self.paths)
    
        def __getitem__(self, index):
            path = self.paths[index]
            label = np.loadtxt(open(self.seg_paths[index], 'r'), dtype='float64')
            verts, faces = pp3d.read_mesh(path)
            verts = torch.tensor(verts).float()
    
            faces = torch.tensor(faces)
            label = torch.tensor(label).long()
            frames, mass, L, evals, evecs, gradX, gradY = diffusion_net.geometry.get_operators(verts, faces,
                                                                                               k_eig=self.k_eig,
                                                                                               op_cache_dir=self.op_cache_dir)
            return verts, faces, frames, mass, L, evals, evecs, gradX, gradY, label
    
        @staticmethod
        def get_seg_files(paths, seg_dir, seg_ext='.eseg'):
            segs = []
            for path in paths:
                segfile = os.path.join(seg_dir, os.path.splitext(os.path.basename(path))[0] + seg_ext)
                assert (os.path.isfile(segfile))
                segs.append(segfile)
            return segs
    
        @staticmethod
        def make_dataset(path):
            meshes = []
            assert os.path.isdir(path), '%s is not a valid directory' % path
            for root, _, fnames in sorted(os.walk(path)):
                for fname in fnames:
                    if is_mesh_file(fname):
                        path = os.path.join(root, fname)
                        meshes.append(path)
    
            return meshes
    

    seg_human.py

    import os
    import sys
    import argparse
    import torch
    from torch.utils.data import DataLoader
    from tqdm import tqdm
    
    sys.path.append(os.path.join(os.path.dirname(__file__), "../../"))  # add the path to the DiffusionNet src
    import src.diffusion_net as diffusion_net
    from experiments.human_seg.human_seg_dataset import HumanDataset
    
    # Parse a few args
    parser = argparse.ArgumentParser()
    parser.add_argument("--input_features", type=str, help="('xyz' or 'hks')", default='hks')
    parser.add_argument("--features_width", type=int, choices={32, 64, 128, 256}, default=128)
    parser.add_argument("--data_name", type=str, choices={'human'}, default='human')
    parser.add_argument("--n_class", type=int, choices={8}, default=8)
    args = parser.parse_args()
    
    # system things
    device = torch.device('cuda:0')
    dtype = torch.float32
    input_features = args.input_features  # one of ['xyz', 'hks']
    C_width = args.features_width
    k_eig = 128
    n_epoch = 200
    lr = 1e-3
    decay_every = 50
    decay_rate = 0.5
    augment_random_rotate = (input_features == 'xyz')
    
    # === Load datasets
    data_name = args.data_name  # aliens vases chairs
    base_path = os.path.dirname(__file__)
    op_cache_dir = os.path.join(base_path, "data", "op_cache", data_name)
    dataset_path = os.path.join(base_path, "data", data_name)
    n_class = args.n_class
    # Load the test dataset
    test_dataset = HumanDataset(dataset_path, 'test', k_eig=k_eig, op_cache_dir=op_cache_dir)
    test_loader = DataLoader(test_dataset, batch_size=None)
    # Load the train dataset
    train_dataset = HumanDataset(dataset_path, 'train', k_eig=k_eig, op_cache_dir=op_cache_dir)
    train_loader = DataLoader(train_dataset, batch_size=None, shuffle=True)
    
    
    # === Create the model
    C_in={'xyz': 3, 'hks': 16}[input_features] # dimension of input features
    
    model = diffusion_net.layers.DiffusionNet(C_in=C_in,
                                              C_out=n_class,
                                              C_width=C_width,
                                              N_block=4, 
                                              last_activation=lambda x : torch.nn.functional.log_softmax(x, dim=-1),
                                              outputs_at='faces', 
                                              dropout=True)
    
    
    model = model.to(device)
    
    # === Optimize
    optimizer = torch.optim.Adam(model.parameters(), lr=lr)
    
    def train_epoch(epoch):
    
        # Implement lr decay
        if epoch > 0 and epoch % decay_every == 0:
            global lr 
            lr *= decay_rate
            for param_group in optimizer.param_groups:
                param_group['lr'] = lr 
    
    
        # Set model to 'train' mode
        model.train()
        optimizer.zero_grad()
        
        correct = 0
        total_num = 0
        for data in tqdm(train_loader):
    
            # Get data
            verts, faces, frames, mass, L, evals, evecs, gradX, gradY, labels = data
    
            # Move to device
            verts = verts.to(device)
            faces = faces.to(device)
            frames = frames.to(device)
            mass = mass.to(device)
            L = L.to(device)
            evals = evals.to(device)
            evecs = evecs.to(device)
            gradX = gradX.to(device)
            gradY = gradY.to(device)
            labels = labels.to(device)
            
            # Randomly rotate positions
            if augment_random_rotate:
                verts = diffusion_net.utils.random_rotate_points(verts)
    
            # Construct features
            if input_features == 'xyz':
                features = verts
            elif input_features == 'hks':
                features = diffusion_net.geometry.compute_hks_autoscale(evals, evecs, 16)
    
            # Apply the model
            preds = model(features, mass, L=L, evals=evals, evecs=evecs, gradX=gradX, gradY=gradY, faces=faces)
    
            # Evaluate loss
            loss = torch.nn.functional.nll_loss(preds, labels)
            loss.backward()
            
            # track accuracy
            pred_labels = torch.max(preds, dim=1).indices
            this_correct = pred_labels.eq(labels).sum().item()
            this_num = labels.shape[0]
            correct += this_correct
            total_num += this_num
    
            # Step the optimizer
            optimizer.step()
            optimizer.zero_grad()
    
        train_acc = correct / total_num
        return train_acc
    
    
    # Do an evaluation pass on the test dataset 
    def test():
        
        model.eval()
        
        correct = 0
        total_num = 0
        with torch.no_grad():
        
            for data in tqdm(test_loader):
    
                # Get data
                verts, faces, frames, mass, L, evals, evecs, gradX, gradY, labels = data
    
                # Move to device
                verts = verts.to(device)
                faces = faces.to(device)
                frames = frames.to(device)
                mass = mass.to(device)
                L = L.to(device)
                evals = evals.to(device)
                evecs = evecs.to(device)
                gradX = gradX.to(device)
                gradY = gradY.to(device)
                labels = labels.to(device)
                
                # Construct features
                if input_features == 'xyz':
                    features = verts
                elif input_features == 'hks':
                    features = diffusion_net.geometry.compute_hks_autoscale(evals, evecs, 16)
    
                # Apply the model
                preds = model(features, mass, L=L, evals=evals, evecs=evecs, gradX=gradX, gradY=gradY, faces=faces)
    
                # track accuracy
                pred_labels = torch.max(preds, dim=1).indices
                this_correct = pred_labels.eq(labels).sum().item()
                this_num = labels.shape[0]
                correct += this_correct
                total_num += this_num
    
        test_acc = correct / total_num
        return test_acc 
    
    
    
    print("Training...")
    
    for epoch in range(n_epoch):
        train_acc = train_epoch(epoch)
        test_acc = test()
        print("Epoch {} - Train overall: {:06.3f}%  Test overall: {:06.3f}%".format(epoch, 100*train_acc, 100*test_acc))
    
    
    
    # Test
    test_acc = test()
    print("Overall test accuracy: {:06.3f}%".format(100*test_acc))
    
    

    I'm sorry that this content is too much. Any hint on this problem is appreciated! Thanks! Have a nice day!

    opened by dasbai 0
  • batch size > 1

    batch size > 1

    Hi, thanks for sharing your research.

    I need to stack vertices and faces in a batch, but I note that all your experiments in the repository have batch size=None. Have you tried stacking vertices and faces in a batch, adding padding like pytorch3d to avoid shape differences? Can batch size and padding produce an error or bad behavior in diffusion-net?

    opened by facundolazcano 1
  • Failed to compute eigen-decomposition

    Failed to compute eigen-decomposition

    Hi! Thanks for this awesome work. I wanted to calculate the diffuse operators in a mesh, and it gave error "Failed to compute eigen-decomposition". What can be possible solution for this?

    I have uploaded the particular mesh from Cloth3D here.

    opened by coreqode 0
  • correspondence using non-functional maps methods

    correspondence using non-functional maps methods

    Hi,

    First thanks for sharing your amazing work! I have a shape correspondence model that does not use functional maps but rather a descriptor based created by a graph neural network. I am not sure how to calculate the correspondence on the test set with .vts files that have a different number of vertices. Mine works fine on the test set with the same number of vertices, not variable ones. Any code that you can share with me for this? Thanks!

    opened by mfarazi1991 0
  • Any interest integrating with ludwig?

    Any interest integrating with ludwig?

    Is there any interest in providing diffisuion-net as a module to ludwig?

    I'm new to machine learning but not to software development.

    Will try to think up some use cases, but a use case was given the silhouette of a character (blendshape) create a skeleton for it.

    The part this proposal can do is classify polygon faces as certain parts of the body through diffusion net.

    References

    https://github.com/ludwig-ai/ludwig

    https://github.com/ludwig-ai/ludwig-docs/blob/ludwig05/docs/developer_guide/add_a_feature_type.md

    https://github.com/ludwig-ai/ludwig-docs/blob/ludwig05/docs/developer_guide/add_an_encoder.md

    See also https://github.com/PeizhuoLi/neural-blend-shapes/tree/main/meshcnn.

    opened by fire 0
Owner
Nick Sharp
Nick Sharp
TensorFlow code for the neural network presented in the paper: "Structural Language Models of Code" (ICML'2020)

SLM: Structural Language Models of Code This is an official implementation of the model described in: "Structural Language Models of Code" [PDF] To ap

null 73 Nov 6, 2022
Inference code for "StylePeople: A Generative Model of Fullbody Human Avatars" paper. This code is for the part of the paper describing video-based avatars.

NeuralTextures This is repository with inference code for paper "StylePeople: A Generative Model of Fullbody Human Avatars" (CVPR21). This code is for

Visual Understanding Lab @ Samsung AI Center Moscow 18 Oct 6, 2022
A code generator from ONNX to PyTorch code

onnx-pytorch Generating pytorch code from ONNX. Currently support onnx==1.9.0 and torch==1.8.1. Installation From PyPI pip install onnx-pytorch From

Wenhao Hu 94 Jan 6, 2023
This is the code for our KILT leaderboard submission to the T-REx and zsRE tasks. It includes code for training a DPR model then continuing training with RAG.

KGI (Knowledge Graph Induction) for slot filling This is the code for our KILT leaderboard submission to the T-REx and zsRE tasks. It includes code fo

International Business Machines 72 Jan 6, 2023
Convert Python 3 code to CUDA code.

Py2CUDA Convert python code to CUDA. Usage To convert a python file say named py_file.py to CUDA, run python generate_cuda.py --file py_file.py --arch

Yuval Rosen 3 Jul 14, 2021
Empirical Study of Transformers for Source Code & A Simple Approach for Handling Out-of-Vocabulary Identifiers in Deep Learning for Source Code

Transformers for variable misuse, function naming and code completion tasks The official PyTorch implementation of: Empirical Study of Transformers fo

Bayesian Methods Research Group 56 Nov 15, 2022
Reference implementation of code generation projects from Facebook AI Research. General toolkit to apply machine learning to code, from dataset creation to model training and evaluation. Comes with pretrained models.

This repository is a toolkit to do machine learning for programming languages. It implements tokenization, dataset preprocessing, model training and m

Facebook Research 408 Jan 1, 2023
Code for the prototype tool in our paper "CoProtector: Protect Open-Source Code against Unauthorized Training Usage with Data Poisoning".

CoProtector Code for the prototype tool in our paper "CoProtector: Protect Open-Source Code against Unauthorized Training Usage with Data Poisoning".

Zhensu Sun 1 Oct 26, 2021
Low-code/No-code approach for deep learning inference on devices

EzEdgeAI A concept project that uses a low-code/no-code approach to implement deep learning inference on devices. It provides a componentized framewor

On-Device AI Co., Ltd. 7 Apr 5, 2022
Code for all the Advent of Code'21 challenges mostly written in python

Advent of Code 21 Code for all the Advent of Code'21 challenges mostly written in python. They are not necessarily the best or fastest solutions but j

null 4 May 26, 2022
Code to use Augmented Shapiro Wilks Stopping, as well as code for the paper "Statistically Signifigant Stopping of Neural Network Training"

This codebase is being actively maintained, please create and issue if you have issues using it Basics All data files are included under losses and ea

J K Terry 32 Nov 9, 2021
Opinionated code formatter, just like Python's black code formatter but for Beancount

beancount-black Opinionated code formatter, just like Python's black code formatter but for Beancount Try it out online here Features MIT licensed - b

Launch Platform 16 Oct 11, 2022
a delightful machine learning tool that allows you to train, test and use models without writing code

igel A delightful machine learning tool that allows you to train/fit, test and use models without writing code Note I'm also working on a GUI desktop

Nidhal Baccouri 3k Jan 5, 2023
Pytorch Lightning code guideline for conferences

Deep learning project seed Use this seed to start new deep learning / ML projects. Built in setup.py Built in requirements Examples with MNIST Badges

Pytorch Lightning 1k Jan 2, 2023
Automatically Build Multiple ML Models with a Single Line of Code. Created by Ram Seshadri. Collaborators Welcome. Permission Granted upon Request.

Auto-ViML Automatically Build Variant Interpretable ML models fast! Auto_ViML is pronounced "auto vimal" (autovimal logo created by Sanket Ghanmare) N

AutoViz and Auto_ViML 397 Dec 30, 2022
Code samples for my book "Neural Networks and Deep Learning"

Code samples for "Neural Networks and Deep Learning" This repository contains code samples for my book on "Neural Networks and Deep Learning". The cod

Michael Nielsen 13.9k Dec 26, 2022
Code for: https://berkeleyautomation.github.io/bags/

DeformableRavens Code for the paper Learning to Rearrange Deformable Cables, Fabrics, and Bags with Goal-Conditioned Transporter Networks. Here is the

Daniel Seita 121 Dec 30, 2022
Code for our method RePRI for Few-Shot Segmentation. Paper at http://arxiv.org/abs/2012.06166

Region Proportion Regularized Inference (RePRI) for Few-Shot Segmentation In this repo, we provide the code for our paper : "Few-Shot Segmentation Wit

Malik Boudiaf 138 Dec 12, 2022
Applications using the GTN library and code to reproduce experiments in "Differentiable Weighted Finite-State Transducers"

gtn_applications An applications library using GTN. Current examples include: Offline handwriting recognition Automatic speech recognition Installing

Facebook Research 68 Dec 29, 2022