mirror of
https://github.com/facebookresearch/pytorch3d.git
synced 2026-07-28 03:26:09 +08:00
Fix backprop through cot_laplacian
Summary: `_cot_laplacian_python` used in-place tensor operations (`clamp_`, `/=`, `+=`) on intermediates that participate in autograd. Once the resulting sparse Laplacian is used in a backward pass, these in-place mutations raise a runtime error: ``` RuntimeError: one of the variables needed for gradient computation has been modified by an inplace operation: [torch.sparse.FloatTensor [4, 4]], which is output 0 of SparseCooTensorWithDimsAndTensors, is at version 1; expected version 0 instead. Hint: enable anomaly detection to find the operation that failed to compute its gradient, with torch.autograd.set_detect_anomaly(True, check_nan=False). ``` Replace the in-place ops with out-of-place equivalents so gradients can flow back to the input vertices. - `clamp_` → `clamp` - `cot /= 4.0` → `cot = cot / 4.0` - `L += L.t()` → `L = L + L.t()` Reviewed By: bottler Differential Revision: D111896032 fbshipit-source-id: 4c36677487bae5d37a9d81cb791400576f4b2c5f
This commit is contained in:
committed by
meta-codesync[bot]
parent
c8fcd83ff9
commit
3b5ab51de5
@@ -103,8 +103,8 @@ def cot_laplacian(
|
||||
s = 0.5 * (A + B + C)
|
||||
# note that the area can be negative (close to 0) causing nans after sqrt()
|
||||
# we clip it to a small positive value
|
||||
# pyre-fixme[16]: `float` has no attribute `clamp_`.
|
||||
area = (s * (s - A) * (s - B) * (s - C)).clamp_(min=eps).sqrt()
|
||||
# pyre-fixme[16]: `float` has no attribute `clamp`.
|
||||
area = (s * (s - A) * (s - B) * (s - C)).clamp(min=eps).sqrt()
|
||||
|
||||
# Compute cotangents of angles, of shape (sum(F_n), 3)
|
||||
A2, B2, C2 = A * A, B * B, C * C
|
||||
@@ -112,7 +112,7 @@ def cot_laplacian(
|
||||
cotb = (A2 + C2 - B2) / area
|
||||
cotc = (A2 + B2 - C2) / area
|
||||
cot = torch.stack([cota, cotb, cotc], dim=1)
|
||||
cot /= 4.0
|
||||
cot = cot / 4.0
|
||||
|
||||
# Construct a sparse matrix by basically doing:
|
||||
# L[v1, v2] = cota
|
||||
@@ -127,7 +127,7 @@ def cot_laplacian(
|
||||
# L[v2, v1] = cota
|
||||
# L[v0, v2] = cotb
|
||||
# L[v1, v0] = cotc
|
||||
L += L.t()
|
||||
L = L + L.t()
|
||||
|
||||
# For each vertex, compute the sum of areas for triangles containing it.
|
||||
idx = faces.view(-1)
|
||||
|
||||
@@ -118,3 +118,14 @@ class TestLaplacianMatrices(TestCaseMixin, unittest.TestCase):
|
||||
Lnaive[e1, e0] += w01
|
||||
|
||||
self.assertClose(L.to_dense(), Lnaive)
|
||||
|
||||
def test_cot_laplacian_backward(self):
|
||||
"""Regression: in-place ops in _cot_laplacian_python break autograd."""
|
||||
verts = torch.tensor(
|
||||
[[0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [1.0, 1.0, 0.0]],
|
||||
requires_grad=True,
|
||||
)
|
||||
faces = torch.tensor([[0, 1, 2], [1, 3, 2]])
|
||||
L, inv_areas = cot_laplacian(verts, faces)
|
||||
(L.to_dense().sum() + inv_areas.sum()).backward()
|
||||
assert verts.grad is not None
|
||||
|
||||
Reference in New Issue
Block a user