wikillm

Paper · 2021-04-08 · cs.CV

3D Shape Generation and Completion through Point-Voxel Diffusion

Point-Voxel Diffusion (PVD) applies DDPM-style denoising diffusion to 3D point clouds with a point-voxel CNN. One network does unconditional generation and shape completion, where the partial shape is held fixed and only missing points are denoised. Author-reported 1-NN on ShapeNet: best on all six generation cells (CD and EMD, Airplane, Chair, Car); best EMD but not CD for completion.

Diffusion modelsgenerationdiffusionpoint-cloudshape-completion3d

arXivPDFCodeMarkdown14 min read

AI-compiled by claude-haiku-5-5 on 2026-10-19, not yet reviewed by a human. Every claim cites its source; check it when a detail matters.

In plain words

A 3D shape is stored here as a cloud of points in space. The model learns to make such clouds by starting from random scatter and removing noise in many small steps, the same idea that image diffusion models use to turn static into a picture. During training it sees real shapes with known amounts of noise added, and learns to predict that noise.

The same network can also complete a shape. The points you already have stay fixed, and the model fills in the missing points while the rest of the cloud is denoised around them. Because every run starts from different random noise, you get several plausible completions of the same partial shape rather than one averaged answer.

The model combines points with a coarse voxel grid, so the network can see local structure as well as individual points. Pure voxels and pure point clouds were tried and did worse.

TL;DR

  • Denoising diffusion (DDPM-style) on 3D point clouds, with a point-voxel CNN as the denoiser §3 §1.
  • One trained network does unconditional generation and conditional completion; completion changes only the training objective and the sampling loop §3.2.
  • Trained with a plain L2 loss on the predicted noise eq. 6; sampling runs T = 1000 steps app. H.2.
  • Author-reported: best 1-NN on all six generation cells (ShapeNet Airplane, Chair, Car; CD and EMD) tab. 1. For completion it wins on EMD but not CD tab. 2.
  • Code is public under MIT and matches the paper in most places, but several settings differ (see Paper vs code).

Problem

  • Voxel models are memory-hungry at high resolution, and voxels are binary, which does not suit a Gaussian diffusion process §1.
  • Point-cloud generators usually map a latent vector, produced by a deterministic encoder, to a point set. For completion this gives one output, not a distribution over completions §1.
  • Plain diffusion on pure voxels produced noisy shapes. Plain diffusion on pure points with a PointNet++-style permutation-invariant network produced no visible shapes §4.1.
  • Completion is practically useful when only a single depth view is available §4.2.

Method

The shape is a set of N = 2048 points with xyz coordinates §3. The denoiser is a point-voxel CNN in the style of PVCNN, modified from PointNet++ by replacing the PointNet part with point-voxel convolution §3 app. H.1.

  1. Forward process. Gaussian noise is added over T steps with a schedule β_1..β_T. Each step is q(x_t | x_{t-1}) = N(sqrt(1-β_t) x_{t-1}, β_t I) §3.1 eq. 2. With α_t = 1 - β_t and ᾱ_t = product of α_s, the closed form is x_t = sqrt(ᾱ_t) x_0 + sqrt(1-ᾱ_t) ε app. D.

  2. Training objective. The variational lower bound on the likelihood is maximised §3.1 eq. 3. Because the forward process is fixed, this reduces to maximum likelihood over the reverse transitions §3.1 eq. 4. Each reverse step is matched to the Gaussian posterior q(x_{t-1} | x_t, x_0) §3.1 eq. 5 app. D. Reparameterised to predict the noise, the loss becomes an L2 distance between true and predicted noise §3.1 eq. 6 app. E.

  3. Generation step. Points are sampled by running the reverse chain from t = T down to 1, with mean given by the predicted noise and fresh Gaussian noise added at each step, using σ_t² = β_t §3.1 eq. 7. The paper says this variance choice "works well" empirically §3.1. The derivation is in app. F.

  4. Shape completion. The partial shape z_0 (M points) is fixed for all timesteps. Only the free points x̃_t are diffused §3.2 eq. 8. The reverse transition for the free points is conditioned on z_0 §3.2 eq. 8. The training objective is the same bound, conditioned on z_0 §3.2 eq. 9. The loss is the L2 noise error on the free points only, with the partial points masked out of the error §3.2 eq. 10.

  5. Input at every step. The partial and free points are concatenated and passed through the network. The output is kept only for the free points, and the partial points are reinserted before the next step §3.2 app. H.1.

  6. Time conditioning. A sinusoidal timestep embedding of dimension 64 is passed through a small MLP and concatenated with point features at the start of each set-abstraction and feature-propagation module app. H.1.

  7. Same network for both tasks. Generation and completion use the same architecture. Only the objective (and, for completion, the 200 fixed points) differ §3.2 app. H.1.

Block-level architecture, from app. H.1:

BlockLC_inC_outD (voxel res.)AttentionCentresRadius rNeighbours
SA 1233232no10240.132
SA 23326416yes2560.232
SA 33641288no640.432
SA 40----160.832
FP 131282568no---
FP 232562568yes---
FP 3225612816no---
FP 421286432no---

The output head is an MLP(64, 3) app. H.1. Every PVConv block uses 3x3x3 convolutions, GroupNorm(8), Swish and Dropout(0.1) app. H.1.

Pseudocode for one training step (generation, eq. 6):

Pseudocode
# Training step for shape generation  [§3.1] [eq. 6]
# Input:  points (B, N, 3) with N = 2048; T = 1000
# Output: scalar loss

def training_step(points, alpha_bar):
    # Draw one timestep per shape, uniformly over the schedule
    # [code: train_generation.py#L434]
    steps = uniform_int(0, T, size=B)
    # Sample Gaussian noise with the same shape as the points  [§3.1]
    noise = gaussian(shape=points.shape)
    # Diffuse the points in closed form to timestep steps  [app. D]
    noisy = (
        sqrt(alpha_bar[steps]) * points
        + sqrt(1 - alpha_bar[steps]) * noise
    )
    # Predict the noise with the point-voxel network  [app. H.1]
    predicted = model(noisy, steps)
    # Mean squared error between true and predicted noise  [eq. 6]
    return mean((noise - predicted) ** 2)

Pseudocode for generation (eq. 7, variance as stated in the paper):

Pseudocode
# Sample one shape by ancestral sampling  [§3.1] [eq. 7] [app. F]
# Input:  alpha, beta, alpha_bar of length T; variance[t] (see Pitfalls)
# Output: points (N, 3)

def sample_shape(model):
    # Start from a standard Gaussian over N points  [§3.1]
    points = gaussian(shape=(N, 3))
    # Walk the reverse chain from the last step to the first  [§3.1]
    for step in reversed(range(T)):
        # Predict the noise at this step  [eq. 7]
        predicted = model(points, step)
        # Mean of the reverse transition  [eq. 7]
        mean = (
            points
            - beta[step] / sqrt(1 - alpha_bar[step]) * predicted
        ) / sqrt(alpha[step])
        # Add noise on every step except the last  [eq. 7]
        if step > 0:
            noise = gaussian(shape=(N, 3))
            points = mean + sqrt(variance[step]) * noise
        else:
            points = mean
    return points

Pseudocode for completion (fixed partial shape, eq. 10):

Pseudocode
# One completion training step  [§3.2] [eq. 10]
# Input:  partial (M, 3) with M = 200; free (1848, 3); T = 1000
# Output: scalar loss on the free points

def completion_training_step(partial, free):
    # Draw a timestep for this sample  [code: train_completion.py#L430]
    step = uniform_int(0, T)
    # Sample noise for the free points only  [§3.2]
    noise = gaussian(shape=free.shape)
    # Diffuse the free points; the partial points stay clean  [§3.2]
    noisy_free = (
        sqrt(alpha_bar[step]) * free
        + sqrt(1 - alpha_bar[step]) * noise
    )
    # Predict noise for all points, keep only the free part  [§3.2]
    predicted = model(concat(partial, noisy_free), step)[free_part]
    # L2 loss on the free points  [eq. 10]
    return mean((noise - predicted) ** 2)

Hyperparameters

Values in the paper are cited to the paper. Where the paper says nothing, the code's value is given and labelled.

NameValueWhereNotes
Diffusion steps T1000app. H.2Paper: "lower timesteps (e.g., 100) are not enough" app. H.2
β schedule, Car and Chairlinear, β_1 = 1e-4 to β_T = 0.01app. H.2Code default β_T = 0.02, see Paper vs code
β schedule, Airplaneβ_1 = 1e-5 to β_T = 0.008 over the first 90% of steps, then fixedapp. H.2Code ramps over 10% of steps, see Paper vs code
Variance σ_t²β_t§3.1Code uses the posterior variance, see Paper vs code
OptimiserAdam, learning rate 2e-4app. H.3Code also sets β1 = 0.5, β2 = 0.999 and per-epoch decay 0.998 train_generation.py train_generation.py
Weight decaynot statedapp. H.3Code: 0 train_generation.py
Gradient clippingnot stated-Code: off by default train_generation.py
Batch sizenot stated-Code: 16 for generation train_generation.py; 48 for completion train_completion.py
Training lengthnot stated-Code default 10000 epochs train_generation.py
Random seednot stated-Code default 42 train_generation.py
Points per shape (generation)2048 for training and test§4.1Training draws a random 2048-point subset of 15k points per shape train_generation.py
Partial points (completion)200app. H.1Free points = 2048 - 200 = 1848 app. H.1
Embedding dimension64app. H.1Sinusoidal, then MLP(64, 64), LeakyReLU(0.1), MLP(64, 64) app. H.1
Dropout0.1app. H.1Inside PVConv blocks
AttentionSA 2 and FP 2app. H.1FP attention never activates in code; a global attention layer is added that the table does not list. See Paper vs code
PartNet completion1024 given points, 2048 output points§4.3Paper also says only the 1024 free points are completed for TMD, see Pitfalls
Voxel resolution32, 16, 8 (SA), 8, 8, 16, 32 (FP)app. H.1Per block table above

Results

Author-reported. All results use the authors' own evaluation implementation §4.1. Generation uses ShapeNet Airplane, Chair and Car with 2048 points per shape, compared with r-GAN, l-GAN (CD and EMD), PointFlow, SoftFlow, DPF-Net, Shape-GF and a voxel-diffusion baseline (Vox-Diff) §4.1. Lower is better for 1-NN.

Generation, 1-NN (%), lower is better tab. 1

ModelAirplane CDAirplane EMDChair CDChair EMDCar CDCar EMD
r-GAN98.4096.7983.6999.7094.4699.01
l-GAN (CD)87.3093.9568.5883.8466.4988.78
l-GAN (EMD)89.4976.9171.9064.6571.1666.19
PointFlow75.6870.7462.8460.5758.1056.25
SoftFlow76.0565.8059.2160.0564.7760.09
DPF-Net75.1865.5562.0058.5362.3554.48
Shape-GF80.0076.1768.9665.4863.2056.53
PVD (this paper)73.8264.8156.2653.3254.5553.83

Source: tab. 1.

Voxel baseline, 1-NN (%) app. A

ModelAirplane CDAirplane EMDChair CDChair EMDCar CDCar EMD
Vox-Diff99.7598.1397.1296.7499.5696.83
PVD (this paper)73.8264.8156.2653.3254.5553.83

Full coverage (COV, %, higher is better) and MMD (lower is better) metrics, with CD and EMD distances app. A:

ModelAirplane MMD CDAirplane MMD EMDAirplane COV CDAirplane COV EMDChair MMD CDChair MMD EMDChair COV CDChair COV EMDCar MMD CDCar MMD EMDCar COV CDCar COV EMD
r-GAN0.44712.30930.1214.325.1518.31224.2715.131.4462.13319.036.539
l-GAN (CD)0.33980.583238.5221.232.5892.00741.9929.311.5321.22638.9223.58
l-GAN (EMD)0.39670.416538.2738.522.8111.61938.0744.861.4080.898737.7845.17
PointFlow0.22430.390147.9046.412.4091.59542.9050.000.90100.807146.8850.00
SoftFlow0.23090.374546.9147.902.5281.68241.3947.431.1870.859442.9044.60
DPF-Net0.26420.408646.1748.892.5361.63244.7148.791.1290.852945.7449.43
Shape-GF2.7030.659240.7440.492.8891.70246.6748.039.2320.755849.4350.28
Vox-Diff1.3220.561011.8225.435.8402.93017.5221.755.6461.5516.53022.15
PVD (this paper)0.22430.380348.8852.092.6221.55649.8450.601.0770.793841.1950.56

Bold marks the best value per column in the source app. A. PVD is bold on Airplane COV (CD and EMD), Chair COV (CD and EMD), Chair MMD EMD and Car COV EMD. It ties PointFlow on Airplane MMD CD at 0.2243. Baselines win the other columns: PointFlow on Chair MMD CD and Car MMD CD, SoftFlow on Airplane MMD EMD, Shape-GF on Car MMD EMD and Car COV CD.

Shape completion, from single-view depth on GenRe renderings (CD ×10³, EMD ×10²; lower is better) tab. 2

ModelAirplane CDAirplane EMDChair CDChair EMDCar CDCar EMD
SoftFlow0.40421.1982.7863.2951.8502.789
PointFlow0.40301.1802.7073.6491.8032.851
DPF-Net0.52791.1052.7633.3201.3962.318
PVD (this paper)0.44151.0303.2112.9391.7742.146

Setup: 200 partial points per view, 20 views per shape, all 20 partial shapes evaluated per ground-truth sample §4.2. Shape-GF was left out because its completions were not realistic after Langevin sampling §4.2.

Multi-modal completion on PartNet (TMD ×10², higher is better; MMD ×10³, lower is better; CD distance) tab. 3

ModelTMD ChairTMD TableTMD LampTMD Avg.MMD ChairMMD TableMMD LampMMD Avg.
KNN-latent0.961.371.951.431.421.421.881.57
cGAN1.751.991.941.891.611.562.131.77
PVD (this paper)1.911.705.923.181.271.031.981.43

Setup: 1024 given points, cGAN and KNN-latent protocol §4.3.

Paper vs code

Code: MIT License, Linqi Zhou, 2022 at code_commit 9747265a. The repository is linked from the project page the paper cites. Code paths below are relative to that repository.

  • Generation variance. The paper sets σ_t² = β_t §3.1. The training code's default variance is fixedsmall, the posterior variance β̃_t, and the sampler adds noise with that variance train_generation.py train_generation.py. The test script's sampler has the same switch, use_var test_generation.py.
  • Airplane schedule. The paper interpolates β from 1e-5 to 0.008 over the first 90% of steps, then holds it app. H.2. The code's warm0.1 schedule ramps over the first int(0.1 * T) = 100 steps (10%), then holds train_generation.py train_generation.py. Only the airplane setting is overridden for generation in main.
  • Chair and Car β_T. The paper sets β_T = 0.01 for Car and Chair app. H.2. The default in both scripts is β_T = 0.02, and no category override sets 0.01 train_generation.py train_completion.py. Running the scripts without flags therefore uses 0.02.
  • Completion schedule for Airplane. train_completion.py has no Airplane override, so the completion script uses the linear 0.02 schedule for every category unless flags are passed train_completion.py. The paper reports completion on Airplane, Chair and Car tab. 2.
  • Feature-propagation attention never turns on. The paper's architecture table has attention in FP 2 app. H.1. In both models the FP attention flag requires c < len(fp_blocks) - 1, but fp_blocks holds only the PointNet FP module when the flag is computed (p = 0), so the condition is always false pvcnn_generation.py pvcnn_generation.py. The completion model has the same guard with c % 2 == 0 pvcnn_completion.py. Net effect: no FP block uses attention in the released code, although the paper's table lists one. The paper says the same architecture is used for both tasks §3.2 app. H.1.
  • Global attention. Both models add a global attention layer after SA 4 when attention is enabled pvcnn_generation.py pvcnn_generation.py. The paper's architecture table has no such layer app. H.1.
  • SA 4 widths. The code's SA 4 MLP output is (256, 256, 512) train_generation.py. The paper's SA 4 column lists no output size app. H.1.
  • Time embedding frequencies. The code uses frequencies 10000^(-k/(d/2 - 1)) for k = 0..d/2-1 pvcnn_generation.py. The paper's formula is ω_k = 1/10000^(2k/d) app. H.1. With d = 64 the two exponents differ.
  • Clipping. When clip_denoised is set, the predicted x_0 is clamped to [-0.5, 0.5] train_generation.py. Evaluation and the test script disable clipping train_generation.py test_generation.py. The paper does not mention clipping, and the ±0.5 range is not stated.
  • Optimiser details. The code uses Adam with β1 = 0.5 and an exponential learning-rate decay of 0.998 per epoch train_generation.py train_generation.py train_generation.py train_generation.py. The paper states only the learning rate app. H.3.
  • Test-time de-normalisation. The test script multiplies samples by a per-shape standard deviation and adds a per-shape mean from the dataset before evaluation test_generation.py. The paper does not describe this step.
  • Noise for t = 0. The training loop pre-draws noise for every example and redraws it only for t ≠ 0 train_generation.py train_generation.py. For t = 0 the same fixed noise is reused across epochs. The paper does not describe this.
  • Vox-Diff. The voxel-diffusion baseline is not in the repository. Only PVD is provided.

The following agree between paper and code: the L2 loss on predicted noise eq. 6, T = 1000, the Adam learning rate of 2e-4, the 200 partial points for completion, and the 2048-point shape size.

Pitfalls

  • Variance choice. The paper's σ_t² = β_t and the code's posterior variance β̃_t are both in the repository. The paper does not say which produced the reported numbers. A reimplementation should pick one and state it; the difference is in the sampler's noise scale, and it is not quantified in the paper.
  • Airplane schedule. The paper's 90% ramp and the code's 10% ramp give different noise levels for most of the first 90% of steps. An implementer who follows the paper will not reproduce the released airplane schedule.
  • Chair and Car β_T. Running the public scripts without flags uses β_T = 0.02, not the paper's 0.01.
  • Different metrics per task. Generation is scored with 1-NN §4.1. Completion is scored with CD and EMD distances only §4.2. Numbers from the two tables cannot be compared.
  • CD versus EMD in completion. PVD is worse than the baselines on CD in all three categories tab. 2. The authors argue EMD is the better measure because it enforces matching density, and they note CD is blind to visual inferiority §4.2. A project that optimises CD should expect the baselines to win.
  • Mean-shape failure. When the input view leaves much of the object unseen, baselines output a mean shape, which scores well on CD. PVD outputs a plausible but different shape instead, which scores worse on CD §4.2 fig. 5.
  • PartNet point counts. The text says 1024 points are given and 2048 are generated §4.3. It also says TMD is computed on the 1024 free points only §4.3. The two statements are compatible only if the output is 1024 given plus 1024 new points; the implementation should check this against the released data split.
  • Diversity metric scope. TMD for PVD is computed on free points only, while baselines are scored on a subsampled 1024-point set §4.3. The comparison is not like-for-like.
  • Multi-modal completion data. Real-scan tables come from random views of ShapeNet meshes, not from real scans, because GenRe has no table data §4.3.
  • Sampling cost. Sampling runs T = 1000 network evaluations. The authors say 100 steps is not enough to build shapes app. H.2. No wall-clock time, GPU count or training duration is stated.
  • Naive point or voxel diffusion. The authors report that pure-point diffusion with PointNet++ fails to generate visible shapes and pure-voxel diffusion is noisy §4.1. The repository does not contain these baselines, so the claim cannot be re-run from the code.
  • Controlled completion. Latent interpolation at time T with weight λ, between two partial encodings, is described as a qualitative feature app. G. No numbers are given.
  • Undisclosed training budget. Batch size, epochs, seed and training time are not in the paper. The repository defaults are the only values available train_generation.py.

Lineage

  • Builds on: the DDPM denoising formulation (Ho et al., 2020, as cited in §1 §3.1), and the point-voxel CNN of Liu et al. (2019) §3 §1.
  • Compared against: r-GAN, l-GAN, PointFlow, SoftFlow, DPF-Net and Shape-GF for generation and completion §4.1 §4.2; cGAN and KNN-latent for PartNet multi-modal completion §4.3; a voxel-diffusion baseline (Vox-Diff), which is the authors' own §4.1.
  • Superseded by: not stated in this card's source.

Source and license

Adapted from “3D Shape Generation and Completion through Point-Voxel Diffusion” by Linqi Zhou, Yilun Du, Jiajun Wu (arXiv:2104.03670), used under CC BY 4.0. Changes: condensed and restructured for implementation, with tables, equations and algorithms taken from the paper and its code, each cited to its source. Not affiliated with or endorsed by the authors. Code citations refer to https://github.com/alexzhou907/PVD at commit 9747265a5f14 (MIT). Any quoted code is shown under that license.