mirror of
https://github.com/facebookresearch/pytorch3d.git
synced 2025-08-02 03:42:50 +08:00
avoid running tests twice
Summary: Avoid test files explicitly importing TestCase objects from each other, because doing so causes the tests to be discovered twice by unittest discover. This means moving a few static functions out of their classes. I noticed this while trying to fix failures from yesterday. Reviewed By: nikhilaravi Differential Revision: D28194679 fbshipit-source-id: ac6e6585603bd4ef9c098cdd56891d94f8923ba6
This commit is contained in:
parent
e3624b4e9d
commit
0ca839cc32
@ -6,7 +6,7 @@ import torch
|
||||
from common_testing import TestCaseMixin
|
||||
from pytorch3d.loss import mesh_edge_loss
|
||||
from pytorch3d.structures import Meshes
|
||||
from test_sample_points_from_meshes import TestSamplePoints
|
||||
from test_sample_points_from_meshes import init_meshes
|
||||
|
||||
|
||||
class TestMeshEdgeLoss(TestCaseMixin, unittest.TestCase):
|
||||
@ -92,7 +92,7 @@ class TestMeshEdgeLoss(TestCaseMixin, unittest.TestCase):
|
||||
|
||||
@staticmethod
|
||||
def mesh_edge_loss(num_meshes: int = 10, max_v: int = 100, max_f: int = 300):
|
||||
meshes = TestSamplePoints.init_meshes(num_meshes, max_v, max_f, device="cuda:0")
|
||||
meshes = init_meshes(num_meshes, max_v, max_f, device="cuda:0")
|
||||
torch.cuda.synchronize()
|
||||
|
||||
def compute_loss():
|
||||
|
@ -10,128 +10,126 @@ from common_testing import TestCaseMixin
|
||||
from pytorch3d.structures.meshes import Meshes
|
||||
|
||||
|
||||
def init_mesh(
|
||||
num_meshes: int = 10,
|
||||
max_v: int = 100,
|
||||
max_f: int = 300,
|
||||
lists_to_tensors: bool = False,
|
||||
device: str = "cpu",
|
||||
requires_grad: bool = False,
|
||||
):
|
||||
"""
|
||||
Function to generate a Meshes object of N meshes with
|
||||
random numbers of vertices and faces.
|
||||
|
||||
Args:
|
||||
num_meshes: Number of meshes to generate.
|
||||
max_v: Max number of vertices per mesh.
|
||||
max_f: Max number of faces per mesh.
|
||||
lists_to_tensors: Determines whether the generated meshes should be
|
||||
constructed from lists (=False) or
|
||||
a tensor (=True) of faces/verts.
|
||||
|
||||
Returns:
|
||||
Meshes object.
|
||||
"""
|
||||
device = torch.device(device)
|
||||
|
||||
verts_list = []
|
||||
faces_list = []
|
||||
|
||||
# Randomly generate numbers of faces and vertices in each mesh.
|
||||
if lists_to_tensors:
|
||||
# If we define faces/verts with tensors, f/v has to be the
|
||||
# same for each mesh in the batch.
|
||||
f = torch.randint(1, max_f, size=(1,), dtype=torch.int32)
|
||||
v = torch.randint(3, high=max_v, size=(1,), dtype=torch.int32)
|
||||
f = f.repeat(num_meshes)
|
||||
v = v.repeat(num_meshes)
|
||||
else:
|
||||
# For lists of faces and vertices, we can sample different v/f
|
||||
# per mesh.
|
||||
f = torch.randint(max_f, size=(num_meshes,), dtype=torch.int32)
|
||||
v = torch.randint(3, high=max_v, size=(num_meshes,), dtype=torch.int32)
|
||||
|
||||
# Generate the actual vertices and faces.
|
||||
for i in range(num_meshes):
|
||||
verts = torch.rand(
|
||||
(v[i], 3),
|
||||
dtype=torch.float32,
|
||||
device=device,
|
||||
requires_grad=requires_grad,
|
||||
)
|
||||
faces = torch.randint(v[i], size=(f[i], 3), dtype=torch.int64, device=device)
|
||||
verts_list.append(verts)
|
||||
faces_list.append(faces)
|
||||
|
||||
if lists_to_tensors:
|
||||
verts_list = torch.stack(verts_list)
|
||||
faces_list = torch.stack(faces_list)
|
||||
|
||||
return Meshes(verts=verts_list, faces=faces_list)
|
||||
|
||||
|
||||
def init_simple_mesh(device: str = "cpu"):
|
||||
"""
|
||||
Returns a Meshes data structure of simple mesh examples.
|
||||
|
||||
Returns:
|
||||
Meshes object.
|
||||
"""
|
||||
device = torch.device(device)
|
||||
|
||||
verts = [
|
||||
torch.tensor(
|
||||
[[0.1, 0.3, 0.5], [0.5, 0.2, 0.1], [0.6, 0.8, 0.7]],
|
||||
dtype=torch.float32,
|
||||
device=device,
|
||||
),
|
||||
torch.tensor(
|
||||
[[0.1, 0.3, 0.3], [0.6, 0.7, 0.8], [0.2, 0.3, 0.4], [0.1, 0.5, 0.3]],
|
||||
dtype=torch.float32,
|
||||
device=device,
|
||||
),
|
||||
torch.tensor(
|
||||
[
|
||||
[0.7, 0.3, 0.6],
|
||||
[0.2, 0.4, 0.8],
|
||||
[0.9, 0.5, 0.2],
|
||||
[0.2, 0.3, 0.4],
|
||||
[0.9, 0.3, 0.8],
|
||||
],
|
||||
dtype=torch.float32,
|
||||
device=device,
|
||||
),
|
||||
]
|
||||
faces = [
|
||||
torch.tensor([[0, 1, 2]], dtype=torch.int64, device=device),
|
||||
torch.tensor([[0, 1, 2], [1, 2, 3]], dtype=torch.int64, device=device),
|
||||
torch.tensor(
|
||||
[
|
||||
[1, 2, 0],
|
||||
[0, 1, 3],
|
||||
[2, 3, 1],
|
||||
[4, 3, 2],
|
||||
[4, 0, 1],
|
||||
[4, 3, 1],
|
||||
[4, 2, 1],
|
||||
],
|
||||
dtype=torch.int64,
|
||||
device=device,
|
||||
),
|
||||
]
|
||||
return Meshes(verts=verts, faces=faces)
|
||||
|
||||
|
||||
class TestMeshes(TestCaseMixin, unittest.TestCase):
|
||||
def setUp(self) -> None:
|
||||
np.random.seed(42)
|
||||
torch.manual_seed(42)
|
||||
|
||||
@staticmethod
|
||||
def init_mesh(
|
||||
num_meshes: int = 10,
|
||||
max_v: int = 100,
|
||||
max_f: int = 300,
|
||||
lists_to_tensors: bool = False,
|
||||
device: str = "cpu",
|
||||
requires_grad: bool = False,
|
||||
):
|
||||
"""
|
||||
Function to generate a Meshes object of N meshes with
|
||||
random numbers of vertices and faces.
|
||||
|
||||
Args:
|
||||
num_meshes: Number of meshes to generate.
|
||||
max_v: Max number of vertices per mesh.
|
||||
max_f: Max number of faces per mesh.
|
||||
lists_to_tensors: Determines whether the generated meshes should be
|
||||
constructed from lists (=False) or
|
||||
a tensor (=True) of faces/verts.
|
||||
|
||||
Returns:
|
||||
Meshes object.
|
||||
"""
|
||||
device = torch.device(device)
|
||||
|
||||
verts_list = []
|
||||
faces_list = []
|
||||
|
||||
# Randomly generate numbers of faces and vertices in each mesh.
|
||||
if lists_to_tensors:
|
||||
# If we define faces/verts with tensors, f/v has to be the
|
||||
# same for each mesh in the batch.
|
||||
f = torch.randint(1, max_f, size=(1,), dtype=torch.int32)
|
||||
v = torch.randint(3, high=max_v, size=(1,), dtype=torch.int32)
|
||||
f = f.repeat(num_meshes)
|
||||
v = v.repeat(num_meshes)
|
||||
else:
|
||||
# For lists of faces and vertices, we can sample different v/f
|
||||
# per mesh.
|
||||
f = torch.randint(max_f, size=(num_meshes,), dtype=torch.int32)
|
||||
v = torch.randint(3, high=max_v, size=(num_meshes,), dtype=torch.int32)
|
||||
|
||||
# Generate the actual vertices and faces.
|
||||
for i in range(num_meshes):
|
||||
verts = torch.rand(
|
||||
(v[i], 3),
|
||||
dtype=torch.float32,
|
||||
device=device,
|
||||
requires_grad=requires_grad,
|
||||
)
|
||||
faces = torch.randint(
|
||||
v[i], size=(f[i], 3), dtype=torch.int64, device=device
|
||||
)
|
||||
verts_list.append(verts)
|
||||
faces_list.append(faces)
|
||||
|
||||
if lists_to_tensors:
|
||||
verts_list = torch.stack(verts_list)
|
||||
faces_list = torch.stack(faces_list)
|
||||
|
||||
return Meshes(verts=verts_list, faces=faces_list)
|
||||
|
||||
@staticmethod
|
||||
def init_simple_mesh(device: str = "cpu"):
|
||||
"""
|
||||
Returns a Meshes data structure of simple mesh examples.
|
||||
|
||||
Returns:
|
||||
Meshes object.
|
||||
"""
|
||||
device = torch.device(device)
|
||||
|
||||
verts = [
|
||||
torch.tensor(
|
||||
[[0.1, 0.3, 0.5], [0.5, 0.2, 0.1], [0.6, 0.8, 0.7]],
|
||||
dtype=torch.float32,
|
||||
device=device,
|
||||
),
|
||||
torch.tensor(
|
||||
[[0.1, 0.3, 0.3], [0.6, 0.7, 0.8], [0.2, 0.3, 0.4], [0.1, 0.5, 0.3]],
|
||||
dtype=torch.float32,
|
||||
device=device,
|
||||
),
|
||||
torch.tensor(
|
||||
[
|
||||
[0.7, 0.3, 0.6],
|
||||
[0.2, 0.4, 0.8],
|
||||
[0.9, 0.5, 0.2],
|
||||
[0.2, 0.3, 0.4],
|
||||
[0.9, 0.3, 0.8],
|
||||
],
|
||||
dtype=torch.float32,
|
||||
device=device,
|
||||
),
|
||||
]
|
||||
faces = [
|
||||
torch.tensor([[0, 1, 2]], dtype=torch.int64, device=device),
|
||||
torch.tensor([[0, 1, 2], [1, 2, 3]], dtype=torch.int64, device=device),
|
||||
torch.tensor(
|
||||
[
|
||||
[1, 2, 0],
|
||||
[0, 1, 3],
|
||||
[2, 3, 1],
|
||||
[4, 3, 2],
|
||||
[4, 0, 1],
|
||||
[4, 3, 1],
|
||||
[4, 2, 1],
|
||||
],
|
||||
dtype=torch.int64,
|
||||
device=device,
|
||||
),
|
||||
]
|
||||
return Meshes(verts=verts, faces=faces)
|
||||
|
||||
def test_simple(self):
|
||||
mesh = TestMeshes.init_simple_mesh("cuda:0")
|
||||
mesh = init_simple_mesh("cuda:0")
|
||||
|
||||
# Check that faces/verts per mesh are set in init:
|
||||
self.assertClose(mesh._num_faces_per_mesh.cpu(), torch.tensor([1, 2, 7]))
|
||||
@ -168,7 +166,7 @@ class TestMeshes(TestCaseMixin, unittest.TestCase):
|
||||
# Check if correct errors are raised when verts/faces are on
|
||||
# different devices
|
||||
|
||||
mesh = TestMeshes.init_mesh(10, 10, 100)
|
||||
mesh = init_mesh(10, 10, 100)
|
||||
verts_list = mesh.verts_list() # all tensors on cpu
|
||||
verts_list = [
|
||||
v.to("cuda:0") if random.uniform(0, 1) > 0.5 else v for v in verts_list
|
||||
@ -192,7 +190,7 @@ class TestMeshes(TestCaseMixin, unittest.TestCase):
|
||||
# Define the test mesh object either as a list or tensor of faces/verts.
|
||||
for lists_to_tensors in (False, True):
|
||||
N = 10
|
||||
mesh = TestMeshes.init_mesh(N, 100, 300, lists_to_tensors=lists_to_tensors)
|
||||
mesh = init_mesh(N, 100, 300, lists_to_tensors=lists_to_tensors)
|
||||
verts_list = mesh.verts_list()
|
||||
faces_list = mesh.faces_list()
|
||||
|
||||
@ -361,7 +359,7 @@ class TestMeshes(TestCaseMixin, unittest.TestCase):
|
||||
|
||||
def test_clone(self):
|
||||
N = 5
|
||||
mesh = TestMeshes.init_mesh(N, 10, 100)
|
||||
mesh = init_mesh(N, 10, 100)
|
||||
for force in [0, 1]:
|
||||
if force:
|
||||
# force mesh to have computed attributes
|
||||
@ -386,7 +384,7 @@ class TestMeshes(TestCaseMixin, unittest.TestCase):
|
||||
|
||||
def test_detach(self):
|
||||
N = 5
|
||||
mesh = TestMeshes.init_mesh(N, 10, 100, requires_grad=True)
|
||||
mesh = init_mesh(N, 10, 100, requires_grad=True)
|
||||
for force in [0, 1]:
|
||||
if force:
|
||||
# force mesh to have computed attributes
|
||||
@ -425,7 +423,7 @@ class TestMeshes(TestCaseMixin, unittest.TestCase):
|
||||
|
||||
# Note that we don't test with random meshes for this case, as the
|
||||
# definition of Laplacian is defined for simple graphs (aka valid meshes)
|
||||
meshes = TestMeshes.init_simple_mesh("cuda:0")
|
||||
meshes = init_simple_mesh("cuda:0")
|
||||
|
||||
lapl_naive = naive_laplacian_packed(meshes)
|
||||
lapl = meshes.laplacian_packed().to_dense()
|
||||
@ -443,7 +441,7 @@ class TestMeshes(TestCaseMixin, unittest.TestCase):
|
||||
return Meshes(verts=new_verts_list, faces=new_faces_list)
|
||||
|
||||
N = 5
|
||||
mesh = TestMeshes.init_mesh(N, 30, 100, lists_to_tensors=True)
|
||||
mesh = init_mesh(N, 30, 100, lists_to_tensors=True)
|
||||
all_v = mesh.verts_packed().size(0)
|
||||
verts_per_mesh = mesh.num_verts_per_mesh()
|
||||
for force, deform_shape in itertools.product([False, True], [(all_v, 3), 3]):
|
||||
@ -577,7 +575,7 @@ class TestMeshes(TestCaseMixin, unittest.TestCase):
|
||||
N = 5
|
||||
for test in ["tensor", "scalar"]:
|
||||
for force in (False, True):
|
||||
mesh = TestMeshes.init_mesh(N, 10, 100, lists_to_tensors=True)
|
||||
mesh = init_mesh(N, 10, 100, lists_to_tensors=True)
|
||||
if force:
|
||||
# force mesh to have computed attributes
|
||||
mesh.verts_packed()
|
||||
@ -686,7 +684,7 @@ class TestMeshes(TestCaseMixin, unittest.TestCase):
|
||||
|
||||
def test_extend_list(self):
|
||||
N = 10
|
||||
mesh = TestMeshes.init_mesh(5, 10, 100)
|
||||
mesh = init_mesh(5, 10, 100)
|
||||
for force in [0, 1]:
|
||||
if force:
|
||||
# force some computes to happen
|
||||
@ -721,7 +719,7 @@ class TestMeshes(TestCaseMixin, unittest.TestCase):
|
||||
mesh.extend(N=-1)
|
||||
|
||||
def test_to(self):
|
||||
mesh = TestMeshes.init_mesh(5, 10, 100, device=torch.device("cuda:0"))
|
||||
mesh = init_mesh(5, 10, 100, device=torch.device("cuda:0"))
|
||||
device = torch.device("cuda:1")
|
||||
|
||||
new_mesh = mesh.to(device)
|
||||
@ -729,7 +727,7 @@ class TestMeshes(TestCaseMixin, unittest.TestCase):
|
||||
self.assertTrue(mesh.device == torch.device("cuda:0"))
|
||||
|
||||
def test_split_mesh(self):
|
||||
mesh = TestMeshes.init_mesh(5, 10, 100)
|
||||
mesh = init_mesh(5, 10, 100)
|
||||
split_sizes = [2, 3]
|
||||
split_meshes = mesh.split(split_sizes)
|
||||
self.assertTrue(len(split_meshes[0]) == 2)
|
||||
@ -756,9 +754,7 @@ class TestMeshes(TestCaseMixin, unittest.TestCase):
|
||||
N = 10
|
||||
for lists_to_tensors in (False, True):
|
||||
for force in (True, False):
|
||||
mesh = TestMeshes.init_mesh(
|
||||
N, 100, 300, lists_to_tensors=lists_to_tensors
|
||||
)
|
||||
mesh = init_mesh(N, 100, 300, lists_to_tensors=lists_to_tensors)
|
||||
num_verts_per_mesh = mesh.num_verts_per_mesh()
|
||||
if force:
|
||||
# force mesh to have computed attributes
|
||||
@ -1166,7 +1162,7 @@ class TestMeshes(TestCaseMixin, unittest.TestCase):
|
||||
num_meshes = 10
|
||||
max_v = 100
|
||||
max_f = 300
|
||||
mesh_cpu = TestMeshes.init_mesh(num_meshes, max_v, max_f, device="cpu")
|
||||
mesh_cpu = init_mesh(num_meshes, max_v, max_f, device="cpu")
|
||||
device = torch.device("cuda:0")
|
||||
mesh_cuda = mesh_cpu.to(device)
|
||||
|
||||
@ -1187,7 +1183,7 @@ class TestMeshes(TestCaseMixin, unittest.TestCase):
|
||||
def compute_packed_with_init(
|
||||
num_meshes: int = 10, max_v: int = 100, max_f: int = 300, device: str = "cpu"
|
||||
):
|
||||
mesh = TestMeshes.init_mesh(num_meshes, max_v, max_f, device=device)
|
||||
mesh = init_mesh(num_meshes, max_v, max_f, device=device)
|
||||
torch.cuda.synchronize()
|
||||
|
||||
def compute_packed():
|
||||
@ -1200,7 +1196,7 @@ class TestMeshes(TestCaseMixin, unittest.TestCase):
|
||||
def compute_padded_with_init(
|
||||
num_meshes: int = 10, max_v: int = 100, max_f: int = 300, device: str = "cpu"
|
||||
):
|
||||
mesh = TestMeshes.init_mesh(num_meshes, max_v, max_f, device=device)
|
||||
mesh = init_mesh(num_meshes, max_v, max_f, device=device)
|
||||
torch.cuda.synchronize()
|
||||
|
||||
def compute_padded():
|
||||
|
@ -33,41 +33,41 @@ DEBUG = False
|
||||
DATA_DIR = get_tests_dir() / "data"
|
||||
|
||||
|
||||
def init_meshes(
|
||||
num_meshes: int = 10,
|
||||
num_verts: int = 1000,
|
||||
num_faces: int = 3000,
|
||||
device: str = "cpu",
|
||||
add_texture: bool = False,
|
||||
):
|
||||
device = torch.device(device)
|
||||
verts_list = []
|
||||
faces_list = []
|
||||
texts_list = []
|
||||
for _ in range(num_meshes):
|
||||
verts = torch.rand((num_verts, 3), dtype=torch.float32, device=device)
|
||||
faces = torch.randint(
|
||||
num_verts, size=(num_faces, 3), dtype=torch.int64, device=device
|
||||
)
|
||||
texts = torch.rand((num_verts, 3), dtype=torch.float32, device=device)
|
||||
verts_list.append(verts)
|
||||
faces_list.append(faces)
|
||||
texts_list.append(texts)
|
||||
|
||||
# create textures
|
||||
textures = None
|
||||
if add_texture:
|
||||
textures = TexturesVertex(texts_list)
|
||||
meshes = Meshes(verts=verts_list, faces=faces_list, textures=textures)
|
||||
|
||||
return meshes
|
||||
|
||||
|
||||
class TestSamplePoints(TestCaseMixin, unittest.TestCase):
|
||||
def setUp(self) -> None:
|
||||
super().setUp()
|
||||
torch.manual_seed(1)
|
||||
|
||||
@staticmethod
|
||||
def init_meshes(
|
||||
num_meshes: int = 10,
|
||||
num_verts: int = 1000,
|
||||
num_faces: int = 3000,
|
||||
device: str = "cpu",
|
||||
add_texture: bool = False,
|
||||
):
|
||||
device = torch.device(device)
|
||||
verts_list = []
|
||||
faces_list = []
|
||||
texts_list = []
|
||||
for _ in range(num_meshes):
|
||||
verts = torch.rand((num_verts, 3), dtype=torch.float32, device=device)
|
||||
faces = torch.randint(
|
||||
num_verts, size=(num_faces, 3), dtype=torch.int64, device=device
|
||||
)
|
||||
texts = torch.rand((num_verts, 3), dtype=torch.float32, device=device)
|
||||
verts_list.append(verts)
|
||||
faces_list.append(faces)
|
||||
texts_list.append(texts)
|
||||
|
||||
# create textures
|
||||
textures = None
|
||||
if add_texture:
|
||||
textures = TexturesVertex(texts_list)
|
||||
meshes = Meshes(verts=verts_list, faces=faces_list, textures=textures)
|
||||
|
||||
return meshes
|
||||
|
||||
def test_all_empty_meshes(self):
|
||||
"""
|
||||
Check sample_points_from_meshes raises an exception if all meshes are
|
||||
@ -298,9 +298,7 @@ class TestSamplePoints(TestCaseMixin, unittest.TestCase):
|
||||
def test_outputs(self):
|
||||
|
||||
for add_texture in (True, False):
|
||||
meshes = TestSamplePoints.init_meshes(
|
||||
device=torch.device("cuda:0"), add_texture=add_texture
|
||||
)
|
||||
meshes = init_meshes(device=torch.device("cuda:0"), add_texture=add_texture)
|
||||
out1 = sample_points_from_meshes(meshes, num_samples=100)
|
||||
self.assertTrue(torch.is_tensor(out1))
|
||||
|
||||
|
@ -15,7 +15,7 @@ from pytorch3d.renderer.mesh.textures import (
|
||||
pack_rectangles,
|
||||
)
|
||||
from pytorch3d.structures import Meshes, list_to_packed, packed_to_list
|
||||
from test_meshes import TestMeshes
|
||||
from test_meshes import init_mesh
|
||||
|
||||
|
||||
def tryindex(self, index, tex, meshes, source):
|
||||
@ -173,7 +173,7 @@ class TestTexturesVertex(TestCaseMixin, unittest.TestCase):
|
||||
|
||||
def test_extend(self):
|
||||
B = 10
|
||||
mesh = TestMeshes.init_mesh(B, 30, 50)
|
||||
mesh = init_mesh(B, 30, 50)
|
||||
V = mesh._V
|
||||
tex_uv = TexturesVertex(verts_features=torch.randn((B, V, 3)))
|
||||
tex_mesh = Meshes(
|
||||
@ -379,7 +379,7 @@ class TestTexturesAtlas(TestCaseMixin, unittest.TestCase):
|
||||
|
||||
def test_extend(self):
|
||||
B = 10
|
||||
mesh = TestMeshes.init_mesh(B, 30, 50)
|
||||
mesh = init_mesh(B, 30, 50)
|
||||
F = mesh._F
|
||||
tex_uv = TexturesAtlas(atlas=torch.randn((B, F, 2, 2, 3)))
|
||||
tex_mesh = Meshes(
|
||||
@ -667,7 +667,7 @@ class TestTexturesUV(TestCaseMixin, unittest.TestCase):
|
||||
|
||||
def test_extend(self):
|
||||
B = 5
|
||||
mesh = TestMeshes.init_mesh(B, 30, 50)
|
||||
mesh = init_mesh(B, 30, 50)
|
||||
V = mesh._V
|
||||
num_faces = mesh.num_faces_per_mesh()
|
||||
num_verts = mesh.num_verts_per_mesh()
|
||||
|
Loading…
x
Reference in New Issue
Block a user