You need to sign in or sign up before continuing.
Commit 0ca839cc authored by Jeremy Reizenstein's avatar Jeremy Reizenstein Committed by Facebook GitHub Bot
Browse files

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
parent e3624b4e
...@@ -6,7 +6,7 @@ import torch ...@@ -6,7 +6,7 @@ import torch
from common_testing import TestCaseMixin from common_testing import TestCaseMixin
from pytorch3d.loss import mesh_edge_loss from pytorch3d.loss import mesh_edge_loss
from pytorch3d.structures import Meshes 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): class TestMeshEdgeLoss(TestCaseMixin, unittest.TestCase):
...@@ -92,7 +92,7 @@ class TestMeshEdgeLoss(TestCaseMixin, unittest.TestCase): ...@@ -92,7 +92,7 @@ class TestMeshEdgeLoss(TestCaseMixin, unittest.TestCase):
@staticmethod @staticmethod
def mesh_edge_loss(num_meshes: int = 10, max_v: int = 100, max_f: int = 300): 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() torch.cuda.synchronize()
def compute_loss(): def compute_loss():
......
...@@ -10,128 +10,126 @@ from common_testing import TestCaseMixin ...@@ -10,128 +10,126 @@ from common_testing import TestCaseMixin
from pytorch3d.structures.meshes import Meshes from pytorch3d.structures.meshes import Meshes
class TestMeshes(TestCaseMixin, unittest.TestCase): def init_mesh(
def setUp(self) -> None: num_meshes: int = 10,
np.random.seed(42) max_v: int = 100,
torch.manual_seed(42) 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)
@staticmethod if lists_to_tensors:
def init_mesh( verts_list = torch.stack(verts_list)
num_meshes: int = 10, faces_list = torch.stack(faces_list)
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 = [] return Meshes(verts=verts_list, faces=faces_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: def init_simple_mesh(device: str = "cpu"):
verts_list = torch.stack(verts_list) """
faces_list = torch.stack(faces_list) Returns a Meshes data structure of simple mesh examples.
return Meshes(verts=verts_list, faces=faces_list) Returns:
Meshes object.
"""
device = torch.device(device)
@staticmethod verts = [
def init_simple_mesh(device: str = "cpu"): torch.tensor(
""" [[0.1, 0.3, 0.5], [0.5, 0.2, 0.1], [0.6, 0.8, 0.7]],
Returns a Meshes data structure of simple mesh examples. dtype=torch.float32,
device=device,
Returns: ),
Meshes object. 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]],
device = torch.device(device) dtype=torch.float32,
device=device,
verts = [ ),
torch.tensor( torch.tensor(
[[0.1, 0.3, 0.5], [0.5, 0.2, 0.1], [0.6, 0.8, 0.7]], [
dtype=torch.float32, [0.7, 0.3, 0.6],
device=device, [0.2, 0.4, 0.8],
), [0.9, 0.5, 0.2],
torch.tensor( [0.2, 0.3, 0.4],
[[0.1, 0.3, 0.3], [0.6, 0.7, 0.8], [0.2, 0.3, 0.4], [0.1, 0.5, 0.3]], [0.9, 0.3, 0.8],
dtype=torch.float32, ],
device=device, dtype=torch.float32,
), device=device,
torch.tensor( ),
[ ]
[0.7, 0.3, 0.6], faces = [
[0.2, 0.4, 0.8], torch.tensor([[0, 1, 2]], dtype=torch.int64, device=device),
[0.9, 0.5, 0.2], torch.tensor([[0, 1, 2], [1, 2, 3]], dtype=torch.int64, device=device),
[0.2, 0.3, 0.4], torch.tensor(
[0.9, 0.3, 0.8], [
], [1, 2, 0],
dtype=torch.float32, [0, 1, 3],
device=device, [2, 3, 1],
), [4, 3, 2],
] [4, 0, 1],
faces = [ [4, 3, 1],
torch.tensor([[0, 1, 2]], dtype=torch.int64, device=device), [4, 2, 1],
torch.tensor([[0, 1, 2], [1, 2, 3]], dtype=torch.int64, device=device), ],
torch.tensor( dtype=torch.int64,
[ device=device,
[1, 2, 0], ),
[0, 1, 3], ]
[2, 3, 1], return Meshes(verts=verts, faces=faces)
[4, 3, 2],
[4, 0, 1],
[4, 3, 1], class TestMeshes(TestCaseMixin, unittest.TestCase):
[4, 2, 1], def setUp(self) -> None:
], np.random.seed(42)
dtype=torch.int64, torch.manual_seed(42)
device=device,
),
]
return Meshes(verts=verts, faces=faces)
def test_simple(self): 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: # Check that faces/verts per mesh are set in init:
self.assertClose(mesh._num_faces_per_mesh.cpu(), torch.tensor([1, 2, 7])) self.assertClose(mesh._num_faces_per_mesh.cpu(), torch.tensor([1, 2, 7]))
...@@ -168,7 +166,7 @@ class TestMeshes(TestCaseMixin, unittest.TestCase): ...@@ -168,7 +166,7 @@ class TestMeshes(TestCaseMixin, unittest.TestCase):
# Check if correct errors are raised when verts/faces are on # Check if correct errors are raised when verts/faces are on
# different devices # 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 = mesh.verts_list() # all tensors on cpu
verts_list = [ verts_list = [
v.to("cuda:0") if random.uniform(0, 1) > 0.5 else v for v in 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): ...@@ -192,7 +190,7 @@ class TestMeshes(TestCaseMixin, unittest.TestCase):
# Define the test mesh object either as a list or tensor of faces/verts. # Define the test mesh object either as a list or tensor of faces/verts.
for lists_to_tensors in (False, True): for lists_to_tensors in (False, True):
N = 10 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() verts_list = mesh.verts_list()
faces_list = mesh.faces_list() faces_list = mesh.faces_list()
...@@ -361,7 +359,7 @@ class TestMeshes(TestCaseMixin, unittest.TestCase): ...@@ -361,7 +359,7 @@ class TestMeshes(TestCaseMixin, unittest.TestCase):
def test_clone(self): def test_clone(self):
N = 5 N = 5
mesh = TestMeshes.init_mesh(N, 10, 100) mesh = init_mesh(N, 10, 100)
for force in [0, 1]: for force in [0, 1]:
if force: if force:
# force mesh to have computed attributes # force mesh to have computed attributes
...@@ -386,7 +384,7 @@ class TestMeshes(TestCaseMixin, unittest.TestCase): ...@@ -386,7 +384,7 @@ class TestMeshes(TestCaseMixin, unittest.TestCase):
def test_detach(self): def test_detach(self):
N = 5 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]: for force in [0, 1]:
if force: if force:
# force mesh to have computed attributes # force mesh to have computed attributes
...@@ -425,7 +423,7 @@ class TestMeshes(TestCaseMixin, unittest.TestCase): ...@@ -425,7 +423,7 @@ class TestMeshes(TestCaseMixin, unittest.TestCase):
# Note that we don't test with random meshes for this case, as the # 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) # 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_naive = naive_laplacian_packed(meshes)
lapl = meshes.laplacian_packed().to_dense() lapl = meshes.laplacian_packed().to_dense()
...@@ -443,7 +441,7 @@ class TestMeshes(TestCaseMixin, unittest.TestCase): ...@@ -443,7 +441,7 @@ class TestMeshes(TestCaseMixin, unittest.TestCase):
return Meshes(verts=new_verts_list, faces=new_faces_list) return Meshes(verts=new_verts_list, faces=new_faces_list)
N = 5 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) all_v = mesh.verts_packed().size(0)
verts_per_mesh = mesh.num_verts_per_mesh() verts_per_mesh = mesh.num_verts_per_mesh()
for force, deform_shape in itertools.product([False, True], [(all_v, 3), 3]): for force, deform_shape in itertools.product([False, True], [(all_v, 3), 3]):
...@@ -577,7 +575,7 @@ class TestMeshes(TestCaseMixin, unittest.TestCase): ...@@ -577,7 +575,7 @@ class TestMeshes(TestCaseMixin, unittest.TestCase):
N = 5 N = 5
for test in ["tensor", "scalar"]: for test in ["tensor", "scalar"]:
for force in (False, True): 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: if force:
# force mesh to have computed attributes # force mesh to have computed attributes
mesh.verts_packed() mesh.verts_packed()
...@@ -686,7 +684,7 @@ class TestMeshes(TestCaseMixin, unittest.TestCase): ...@@ -686,7 +684,7 @@ class TestMeshes(TestCaseMixin, unittest.TestCase):
def test_extend_list(self): def test_extend_list(self):
N = 10 N = 10
mesh = TestMeshes.init_mesh(5, 10, 100) mesh = init_mesh(5, 10, 100)
for force in [0, 1]: for force in [0, 1]:
if force: if force:
# force some computes to happen # force some computes to happen
...@@ -721,7 +719,7 @@ class TestMeshes(TestCaseMixin, unittest.TestCase): ...@@ -721,7 +719,7 @@ class TestMeshes(TestCaseMixin, unittest.TestCase):
mesh.extend(N=-1) mesh.extend(N=-1)
def test_to(self): 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") device = torch.device("cuda:1")
new_mesh = mesh.to(device) new_mesh = mesh.to(device)
...@@ -729,7 +727,7 @@ class TestMeshes(TestCaseMixin, unittest.TestCase): ...@@ -729,7 +727,7 @@ class TestMeshes(TestCaseMixin, unittest.TestCase):
self.assertTrue(mesh.device == torch.device("cuda:0")) self.assertTrue(mesh.device == torch.device("cuda:0"))
def test_split_mesh(self): def test_split_mesh(self):
mesh = TestMeshes.init_mesh(5, 10, 100) mesh = init_mesh(5, 10, 100)
split_sizes = [2, 3] split_sizes = [2, 3]
split_meshes = mesh.split(split_sizes) split_meshes = mesh.split(split_sizes)
self.assertTrue(len(split_meshes[0]) == 2) self.assertTrue(len(split_meshes[0]) == 2)
...@@ -756,9 +754,7 @@ class TestMeshes(TestCaseMixin, unittest.TestCase): ...@@ -756,9 +754,7 @@ class TestMeshes(TestCaseMixin, unittest.TestCase):
N = 10 N = 10
for lists_to_tensors in (False, True): for lists_to_tensors in (False, True):
for force in (True, False): for force in (True, False):
mesh = TestMeshes.init_mesh( mesh = init_mesh(N, 100, 300, lists_to_tensors=lists_to_tensors)
N, 100, 300, lists_to_tensors=lists_to_tensors
)
num_verts_per_mesh = mesh.num_verts_per_mesh() num_verts_per_mesh = mesh.num_verts_per_mesh()
if force: if force:
# force mesh to have computed attributes # force mesh to have computed attributes
...@@ -1166,7 +1162,7 @@ class TestMeshes(TestCaseMixin, unittest.TestCase): ...@@ -1166,7 +1162,7 @@ class TestMeshes(TestCaseMixin, unittest.TestCase):
num_meshes = 10 num_meshes = 10
max_v = 100 max_v = 100
max_f = 300 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") device = torch.device("cuda:0")
mesh_cuda = mesh_cpu.to(device) mesh_cuda = mesh_cpu.to(device)
...@@ -1187,7 +1183,7 @@ class TestMeshes(TestCaseMixin, unittest.TestCase): ...@@ -1187,7 +1183,7 @@ class TestMeshes(TestCaseMixin, unittest.TestCase):
def compute_packed_with_init( def compute_packed_with_init(
num_meshes: int = 10, max_v: int = 100, max_f: int = 300, device: str = "cpu" 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() torch.cuda.synchronize()
def compute_packed(): def compute_packed():
...@@ -1200,7 +1196,7 @@ class TestMeshes(TestCaseMixin, unittest.TestCase): ...@@ -1200,7 +1196,7 @@ class TestMeshes(TestCaseMixin, unittest.TestCase):
def compute_padded_with_init( def compute_padded_with_init(
num_meshes: int = 10, max_v: int = 100, max_f: int = 300, device: str = "cpu" 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() torch.cuda.synchronize()
def compute_padded(): def compute_padded():
......
...@@ -33,41 +33,41 @@ DEBUG = False ...@@ -33,41 +33,41 @@ DEBUG = False
DATA_DIR = get_tests_dir() / "data" 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): class TestSamplePoints(TestCaseMixin, unittest.TestCase):
def setUp(self) -> None: def setUp(self) -> None:
super().setUp() super().setUp()
torch.manual_seed(1) 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): def test_all_empty_meshes(self):
""" """
Check sample_points_from_meshes raises an exception if all meshes are Check sample_points_from_meshes raises an exception if all meshes are
...@@ -298,9 +298,7 @@ class TestSamplePoints(TestCaseMixin, unittest.TestCase): ...@@ -298,9 +298,7 @@ class TestSamplePoints(TestCaseMixin, unittest.TestCase):
def test_outputs(self): def test_outputs(self):
for add_texture in (True, False): for add_texture in (True, False):
meshes = TestSamplePoints.init_meshes( meshes = init_meshes(device=torch.device("cuda:0"), add_texture=add_texture)
device=torch.device("cuda:0"), add_texture=add_texture
)
out1 = sample_points_from_meshes(meshes, num_samples=100) out1 = sample_points_from_meshes(meshes, num_samples=100)
self.assertTrue(torch.is_tensor(out1)) self.assertTrue(torch.is_tensor(out1))
......
...@@ -15,7 +15,7 @@ from pytorch3d.renderer.mesh.textures import ( ...@@ -15,7 +15,7 @@ from pytorch3d.renderer.mesh.textures import (
pack_rectangles, pack_rectangles,
) )
from pytorch3d.structures import Meshes, list_to_packed, packed_to_list 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): def tryindex(self, index, tex, meshes, source):
...@@ -173,7 +173,7 @@ class TestTexturesVertex(TestCaseMixin, unittest.TestCase): ...@@ -173,7 +173,7 @@ class TestTexturesVertex(TestCaseMixin, unittest.TestCase):
def test_extend(self): def test_extend(self):
B = 10 B = 10
mesh = TestMeshes.init_mesh(B, 30, 50) mesh = init_mesh(B, 30, 50)
V = mesh._V V = mesh._V
tex_uv = TexturesVertex(verts_features=torch.randn((B, V, 3))) tex_uv = TexturesVertex(verts_features=torch.randn((B, V, 3)))
tex_mesh = Meshes( tex_mesh = Meshes(
...@@ -379,7 +379,7 @@ class TestTexturesAtlas(TestCaseMixin, unittest.TestCase): ...@@ -379,7 +379,7 @@ class TestTexturesAtlas(TestCaseMixin, unittest.TestCase):
def test_extend(self): def test_extend(self):
B = 10 B = 10
mesh = TestMeshes.init_mesh(B, 30, 50) mesh = init_mesh(B, 30, 50)
F = mesh._F F = mesh._F
tex_uv = TexturesAtlas(atlas=torch.randn((B, F, 2, 2, 3))) tex_uv = TexturesAtlas(atlas=torch.randn((B, F, 2, 2, 3)))
tex_mesh = Meshes( tex_mesh = Meshes(
...@@ -667,7 +667,7 @@ class TestTexturesUV(TestCaseMixin, unittest.TestCase): ...@@ -667,7 +667,7 @@ class TestTexturesUV(TestCaseMixin, unittest.TestCase):
def test_extend(self): def test_extend(self):
B = 5 B = 5
mesh = TestMeshes.init_mesh(B, 30, 50) mesh = init_mesh(B, 30, 50)
V = mesh._V V = mesh._V
num_faces = mesh.num_faces_per_mesh() num_faces = mesh.num_faces_per_mesh()
num_verts = mesh.num_verts_per_mesh() num_verts = mesh.num_verts_per_mesh()
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment