test_rendering.py 7.17 KB
Newer Older
Ruilong Li(李瑞龙)'s avatar
Ruilong Li(李瑞龙) committed
1
import pytest
Ruilong Li(李瑞龙)'s avatar
Ruilong Li(李瑞龙) committed
2
3
import torch

4
5
from nerfacc import (
    accumulate_along_rays,
Ruilong Li(李瑞龙)'s avatar
Ruilong Li(李瑞龙) committed
6
    render_transmittance_from_density,
7
8
9
10
11
    render_visibility,
    render_weight_from_alpha,
    render_weight_from_density,
    rendering,
)
Ruilong Li(李瑞龙)'s avatar
Ruilong Li(李瑞龙) committed
12
13

device = "cuda:0"
14
15
batch_size = 32
eps = 1e-6
Ruilong Li(李瑞龙)'s avatar
Ruilong Li(李瑞龙) committed
16
17


Ruilong Li(李瑞龙)'s avatar
Ruilong Li(李瑞龙) committed
18
@pytest.mark.skipif(not torch.cuda.is_available, reason="No CUDA device")
19
def test_render_visibility():
Ruilong Li(李瑞龙)'s avatar
Ruilong Li(李瑞龙) committed
20
    ray_indices = torch.tensor(
21
        [0, 2, 2, 2, 2], dtype=torch.int64, device=device
Ruilong Li(李瑞龙)'s avatar
Ruilong Li(李瑞龙) committed
22
    )  # (samples,)
23
24
25
26
27
    alphas = torch.tensor(
        [0.4, 0.3, 0.8, 0.8, 0.5], dtype=torch.float32, device=device
    ).unsqueeze(
        -1
    )  # (n_samples, 1)
Ruilong Li(李瑞龙)'s avatar
Ruilong Li(李瑞龙) committed
28

29
    # transmittance: [1.0, 1.0, 0.7, 0.14, 0.028]
Ruilong Li(李瑞龙)'s avatar
Ruilong Li(李瑞龙) committed
30
31
    vis = render_visibility(
        alphas, ray_indices=ray_indices, early_stop_eps=0.03, alpha_thre=0.0
Ruilong Li(李瑞龙)'s avatar
Ruilong Li(李瑞龙) committed
32
    )
33
34
    vis_tgt = torch.tensor(
        [True, True, True, True, False], dtype=torch.bool, device=device
Ruilong Li(李瑞龙)'s avatar
Ruilong Li(李瑞龙) committed
35
    )
36
37
38
    assert torch.allclose(vis, vis_tgt)

    # transmittance: [1.0, 1.0, 1.0, 0.2, 0.04]
Ruilong Li(李瑞龙)'s avatar
Ruilong Li(李瑞龙) committed
39
40
    vis = render_visibility(
        alphas, ray_indices=ray_indices, early_stop_eps=0.05, alpha_thre=0.35
41
42
43
44
45
46
47
48
49
    )
    vis_tgt = torch.tensor(
        [True, False, True, True, False], dtype=torch.bool, device=device
    )
    assert torch.allclose(vis, vis_tgt)


@pytest.mark.skipif(not torch.cuda.is_available, reason="No CUDA device")
def test_render_weight_from_alpha():
Ruilong Li(李瑞龙)'s avatar
Ruilong Li(李瑞龙) committed
50
    ray_indices = torch.tensor(
51
        [0, 2, 2, 2, 2], dtype=torch.int64, device=device
Ruilong Li(李瑞龙)'s avatar
Ruilong Li(李瑞龙) committed
52
    )  # (samples,)
53
54
55
56
57
58
59
60
    alphas = torch.tensor(
        [0.4, 0.3, 0.8, 0.8, 0.5], dtype=torch.float32, device=device
    ).unsqueeze(
        -1
    )  # (n_samples, 1)

    # transmittance: [1.0, 1.0, 0.7, 0.14, 0.028]
    weights = render_weight_from_alpha(
Ruilong Li(李瑞龙)'s avatar
Ruilong Li(李瑞龙) committed
61
        alphas, ray_indices=ray_indices, n_rays=3
62
63
    )
    weights_tgt = torch.tensor(
Ruilong Li(李瑞龙)'s avatar
Ruilong Li(李瑞龙) committed
64
        [1.0 * 0.4, 1.0 * 0.3, 0.7 * 0.8, 0.14 * 0.8, 0.028 * 0.5],
65
66
        dtype=torch.float32,
        device=device,
Ruilong Li(李瑞龙)'s avatar
Ruilong Li(李瑞龙) committed
67
    ).unsqueeze(-1)
68
69
70
    assert torch.allclose(weights, weights_tgt)


Ruilong Li(李瑞龙)'s avatar
Ruilong Li(李瑞龙) committed
71
@pytest.mark.skipif(not torch.cuda.is_available, reason="No CUDA device")
72
def test_render_weight_from_density():
Ruilong Li(李瑞龙)'s avatar
Ruilong Li(李瑞龙) committed
73
    ray_indices = torch.tensor(
74
        [0, 2, 2, 2, 2], dtype=torch.int64, device=device
Ruilong Li(李瑞龙)'s avatar
Ruilong Li(李瑞龙) committed
75
76
77
78
    )  # (samples,)
    sigmas = torch.rand(
        (ray_indices.shape[0], 1), device=device
    )  # (n_samples, 1)
79
80
81
82
    t_starts = torch.rand_like(sigmas)
    t_ends = torch.rand_like(sigmas) + 1.0
    alphas = 1.0 - torch.exp(-sigmas * (t_ends - t_starts))

Ruilong Li(李瑞龙)'s avatar
Ruilong Li(李瑞龙) committed
83
84
85
86
87
88
    weights = render_weight_from_density(
        t_starts, t_ends, sigmas, ray_indices=ray_indices, n_rays=3
    )
    weights_tgt = render_weight_from_alpha(
        alphas, ray_indices=ray_indices, n_rays=3
    )
89
90
91
    assert torch.allclose(weights, weights_tgt)


Ruilong Li(李瑞龙)'s avatar
Ruilong Li(李瑞龙) committed
92
@pytest.mark.skipif(not torch.cuda.is_available, reason="No CUDA device")
93
94
def test_accumulate_along_rays():
    ray_indices = torch.tensor(
95
        [0, 2, 2, 2, 2], dtype=torch.int64, device=device
Ruilong Li(李瑞龙)'s avatar
Ruilong Li(李瑞龙) committed
96
    )  # (n_rays,)
97
98
    weights = torch.tensor(
        [0.4, 0.3, 0.8, 0.8, 0.5], dtype=torch.float32, device=device
Ruilong Li(李瑞龙)'s avatar
Ruilong Li(李瑞龙) committed
99
    ).unsqueeze(-1)
100
101
102
103
104
105
    values = torch.rand((5, 2), device=device)  # (n_samples, 1)

    ray_values = accumulate_along_rays(
        weights, ray_indices, values=values, n_rays=3
    )
    assert ray_values.shape == (3, 2)
Ruilong Li(李瑞龙)'s avatar
Ruilong Li(李瑞龙) committed
106
    assert torch.allclose(ray_values[0, :], weights[0, :] * values[0, :])
107
108
    assert (ray_values[1, :] == 0).all()
    assert torch.allclose(
Ruilong Li(李瑞龙)'s avatar
Ruilong Li(李瑞龙) committed
109
        ray_values[2, :], (weights[1:, :] * values[1:]).sum(dim=0)
110
111
112
    )


Ruilong Li(李瑞龙)'s avatar
Ruilong Li(李瑞龙) committed
113
@pytest.mark.skipif(not torch.cuda.is_available, reason="No CUDA device")
114
115
116
117
def test_rendering():
    def rgb_sigma_fn(t_starts, t_ends, ray_indices):
        return torch.hstack([t_starts] * 3), t_starts

Ruilong Li(李瑞龙)'s avatar
Ruilong Li(李瑞龙) committed
118
    ray_indices = torch.tensor(
119
        [0, 2, 2, 2, 2], dtype=torch.int64, device=device
Ruilong Li(李瑞龙)'s avatar
Ruilong Li(李瑞龙) committed
120
121
122
123
    )  # (samples,)
    sigmas = torch.rand(
        (ray_indices.shape[0], 1), device=device
    )  # (n_samples, 1)
124
125
126
    t_starts = torch.rand_like(sigmas)
    t_ends = torch.rand_like(sigmas) + 1.0

127
    _, _, _ = rendering(
Ruilong Li(李瑞龙)'s avatar
Ruilong Li(李瑞龙) committed
128
129
130
131
132
133
134
135
136
137
138
        t_starts,
        t_ends,
        ray_indices=ray_indices,
        n_rays=3,
        rgb_sigma_fn=rgb_sigma_fn,
    )


@pytest.mark.skipif(not torch.cuda.is_available, reason="No CUDA device")
def test_grads():
    ray_indices = torch.tensor(
139
        [0, 2, 2, 2, 2], dtype=torch.int64, device=device
Ruilong Li(李瑞龙)'s avatar
Ruilong Li(李瑞龙) committed
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
    )  # (samples,)
    packed_info = torch.tensor(
        [[0, 1], [1, 0], [1, 4]], dtype=torch.int32, device=device
    )
    sigmas = torch.tensor([[0.4], [0.8], [0.1], [0.8], [0.1]], device="cuda")
    sigmas.requires_grad = True
    t_starts = torch.rand_like(sigmas)
    t_ends = t_starts + 1.0

    weights_ref = torch.tensor(
        [[0.3297], [0.5507], [0.0428], [0.2239], [0.0174]], device="cuda"
    )
    sigmas_grad_ref = torch.tensor(
        [[0.6703], [0.1653], [0.1653], [0.1653], [0.1653]], device="cuda"
    )

    # naive impl. trans from sigma
    trans = render_transmittance_from_density(
        t_starts, t_ends, sigmas, ray_indices=ray_indices, n_rays=3
    )
    weights = trans * (1.0 - torch.exp(-sigmas * (t_ends - t_starts)))
    weights.sum().backward()
    sigmas_grad = sigmas.grad.clone()
    sigmas.grad.zero_()
    assert torch.allclose(weights_ref, weights, atol=1e-4)
    assert torch.allclose(sigmas_grad_ref, sigmas_grad, atol=1e-4)

    # naive impl. trans from alpha
    trans = render_transmittance_from_density(
        t_starts, t_ends, sigmas, packed_info=packed_info, n_rays=3
    )
    weights = trans * (1.0 - torch.exp(-sigmas * (t_ends - t_starts)))
    weights.sum().backward()
    sigmas_grad = sigmas.grad.clone()
    sigmas.grad.zero_()
    assert torch.allclose(weights_ref, weights, atol=1e-4)
    assert torch.allclose(sigmas_grad_ref, sigmas_grad, atol=1e-4)

    weights = render_weight_from_density(
        t_starts, t_ends, sigmas, ray_indices=ray_indices, n_rays=3
    )
    weights.sum().backward()
    sigmas_grad = sigmas.grad.clone()
    sigmas.grad.zero_()
    assert torch.allclose(weights_ref, weights, atol=1e-4)
    assert torch.allclose(sigmas_grad_ref, sigmas_grad, atol=1e-4)

    weights = render_weight_from_density(
        t_starts, t_ends, sigmas, packed_info=packed_info, n_rays=3
    )
    weights.sum().backward()
    sigmas_grad = sigmas.grad.clone()
    sigmas.grad.zero_()
    assert torch.allclose(weights_ref, weights, atol=1e-4)
    assert torch.allclose(sigmas_grad_ref, sigmas_grad, atol=1e-4)

    alphas = 1.0 - torch.exp(-sigmas * (t_ends - t_starts))
    weights = render_weight_from_alpha(
        alphas, ray_indices=ray_indices, n_rays=3
    )
    weights.sum().backward()
    sigmas_grad = sigmas.grad.clone()
    sigmas.grad.zero_()
    assert torch.allclose(weights_ref, weights, atol=1e-4)
    assert torch.allclose(sigmas_grad_ref, sigmas_grad, atol=1e-4)

    alphas = 1.0 - torch.exp(-sigmas * (t_ends - t_starts))
    weights = render_weight_from_alpha(
        alphas, packed_info=packed_info, n_rays=3
209
    )
Ruilong Li(李瑞龙)'s avatar
Ruilong Li(李瑞龙) committed
210
211
212
213
214
    weights.sum().backward()
    sigmas_grad = sigmas.grad.clone()
    sigmas.grad.zero_()
    assert torch.allclose(weights_ref, weights, atol=1e-4)
    assert torch.allclose(sigmas_grad_ref, sigmas_grad, atol=1e-4)
Ruilong Li(李瑞龙)'s avatar
Ruilong Li(李瑞龙) committed
215
216
217


if __name__ == "__main__":
218
219
220
221
222
    test_render_visibility()
    test_render_weight_from_alpha()
    test_render_weight_from_density()
    test_accumulate_along_rays()
    test_rendering()
Ruilong Li(李瑞龙)'s avatar
Ruilong Li(李瑞龙) committed
223
    test_grads()