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

device = "cuda:0"


Ruilong Li(李瑞龙)'s avatar
Ruilong Li(李瑞龙) committed
7
@pytest.mark.skipif(not torch.cuda.is_available, reason="No CUDA device")
8
def test_render_visibility():
9
10
    from nerfacc.volrend import render_visibility_from_alpha

Ruilong Li(李瑞龙)'s avatar
Ruilong Li(李瑞龙) committed
11
    ray_indices = torch.tensor(
12
        [0, 2, 2, 2, 2], dtype=torch.int64, device=device
13
    )  # (all_samples,)
14
15
    alphas = torch.tensor(
        [0.4, 0.3, 0.8, 0.8, 0.5], dtype=torch.float32, device=device
16
    )  # (all_samples,)
Ruilong Li(李瑞龙)'s avatar
Ruilong Li(李瑞龙) committed
17

18
    # transmittance: [1.0, 1.0, 0.7, 0.14, 0.028]
19
    vis = render_visibility_from_alpha(
Ruilong Li(李瑞龙)'s avatar
Ruilong Li(李瑞龙) committed
20
        alphas, ray_indices=ray_indices, early_stop_eps=0.03, alpha_thre=0.0
Ruilong Li(李瑞龙)'s avatar
Ruilong Li(李瑞龙) committed
21
    )
22
23
    vis_tgt = torch.tensor(
        [True, True, True, True, False], dtype=torch.bool, device=device
Ruilong Li(李瑞龙)'s avatar
Ruilong Li(李瑞龙) committed
24
    )
25
26
27
    assert torch.allclose(vis, vis_tgt)

    # transmittance: [1.0, 1.0, 1.0, 0.2, 0.04]
28
    vis = render_visibility_from_alpha(
Ruilong Li(李瑞龙)'s avatar
Ruilong Li(李瑞龙) committed
29
        alphas, ray_indices=ray_indices, early_stop_eps=0.05, alpha_thre=0.35
30
31
32
33
34
35
36
37
38
    )
    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():
39
40
    from nerfacc.volrend import render_weight_from_alpha

Ruilong Li(李瑞龙)'s avatar
Ruilong Li(李瑞龙) committed
41
    ray_indices = torch.tensor(
42
        [0, 2, 2, 2, 2], dtype=torch.int64, device=device
43
    )  # (all_samples,)
44
45
    alphas = torch.tensor(
        [0.4, 0.3, 0.8, 0.8, 0.5], dtype=torch.float32, device=device
46
    )  # (all_samples,)
47
48

    # transmittance: [1.0, 1.0, 0.7, 0.14, 0.028]
49
    weights, _ = render_weight_from_alpha(
Ruilong Li(李瑞龙)'s avatar
Ruilong Li(李瑞龙) committed
50
        alphas, ray_indices=ray_indices, n_rays=3
51
52
    )
    weights_tgt = torch.tensor(
Ruilong Li(李瑞龙)'s avatar
Ruilong Li(李瑞龙) committed
53
        [1.0 * 0.4, 1.0 * 0.3, 0.7 * 0.8, 0.14 * 0.8, 0.028 * 0.5],
54
55
        dtype=torch.float32,
        device=device,
56
    )
57
58
59
    assert torch.allclose(weights, weights_tgt)


Ruilong Li(李瑞龙)'s avatar
Ruilong Li(李瑞龙) committed
60
@pytest.mark.skipif(not torch.cuda.is_available, reason="No CUDA device")
61
def test_render_weight_from_density():
62
63
64
65
66
    from nerfacc.volrend import (
        render_weight_from_alpha,
        render_weight_from_density,
    )

Ruilong Li(李瑞龙)'s avatar
Ruilong Li(李瑞龙) committed
67
    ray_indices = torch.tensor(
68
        [0, 2, 2, 2, 2], dtype=torch.int64, device=device
69
    )  # (all_samples,)
Ruilong Li(李瑞龙)'s avatar
Ruilong Li(李瑞龙) committed
70
    sigmas = torch.rand(
71
72
        (ray_indices.shape[0],), device=device
    )  # (all_samples,)
73
74
75
76
    t_starts = torch.rand_like(sigmas)
    t_ends = torch.rand_like(sigmas) + 1.0
    alphas = 1.0 - torch.exp(-sigmas * (t_ends - t_starts))

77
    weights, _, _ = render_weight_from_density(
Ruilong Li(李瑞龙)'s avatar
Ruilong Li(李瑞龙) committed
78
79
        t_starts, t_ends, sigmas, ray_indices=ray_indices, n_rays=3
    )
80
    weights_tgt, _ = render_weight_from_alpha(
Ruilong Li(李瑞龙)'s avatar
Ruilong Li(李瑞龙) committed
81
82
        alphas, ray_indices=ray_indices, n_rays=3
    )
83
84
85
    assert torch.allclose(weights, weights_tgt)


Ruilong Li(李瑞龙)'s avatar
Ruilong Li(李瑞龙) committed
86
@pytest.mark.skipif(not torch.cuda.is_available, reason="No CUDA device")
87
def test_accumulate_along_rays():
88
89
    from nerfacc.volrend import accumulate_along_rays

90
    ray_indices = torch.tensor(
91
        [0, 2, 2, 2, 2], dtype=torch.int64, device=device
92
    )  # (all_samples,)
93
94
    weights = torch.tensor(
        [0.4, 0.3, 0.8, 0.8, 0.5], dtype=torch.float32, device=device
95
96
    )  # (all_samples,)
    values = torch.rand((5, 2), device=device)  # (all_samples, 2)
97
98

    ray_values = accumulate_along_rays(
99
        weights, values=values, ray_indices=ray_indices, n_rays=3
100
101
    )
    assert ray_values.shape == (3, 2)
102
    assert torch.allclose(ray_values[0, :], weights[0, None] * values[0, :])
103
104
    assert (ray_values[1, :] == 0).all()
    assert torch.allclose(
105
        ray_values[2, :], (weights[1:, None] * values[1:]).sum(dim=0)
106
107
108
    )


Ruilong Li(李瑞龙)'s avatar
Ruilong Li(李瑞龙) committed
109
@pytest.mark.skipif(not torch.cuda.is_available, reason="No CUDA device")
110
111
112
113
114
def test_grads():
    from nerfacc.volrend import (
        render_transmittance_from_density,
        render_weight_from_alpha,
        render_weight_from_density,
Ruilong Li(李瑞龙)'s avatar
Ruilong Li(李瑞龙) committed
115
116
117
    )

    ray_indices = torch.tensor(
118
        [0, 2, 2, 2, 2], dtype=torch.int64, device=device
119
    )  # (all_samples,)
Ruilong Li(李瑞龙)'s avatar
Ruilong Li(李瑞龙) committed
120
    packed_info = torch.tensor(
121
        [[0, 1], [1, 0], [1, 4]], dtype=torch.long, device=device
Ruilong Li(李瑞龙)'s avatar
Ruilong Li(李瑞龙) committed
122
    )
123
    sigmas = torch.tensor([0.4, 0.8, 0.1, 0.8, 0.1], device=device)
Ruilong Li(李瑞龙)'s avatar
Ruilong Li(李瑞龙) committed
124
125
126
127
128
    sigmas.requires_grad = True
    t_starts = torch.rand_like(sigmas)
    t_ends = t_starts + 1.0

    weights_ref = torch.tensor(
129
        [0.3297, 0.5507, 0.0428, 0.2239, 0.0174], device=device
Ruilong Li(李瑞龙)'s avatar
Ruilong Li(李瑞龙) committed
130
131
    )
    sigmas_grad_ref = torch.tensor(
132
        [0.6703, 0.1653, 0.1653, 0.1653, 0.1653], device=device
Ruilong Li(李瑞龙)'s avatar
Ruilong Li(李瑞龙) committed
133
134
135
    )

    # naive impl. trans from sigma
136
    trans, _ = render_transmittance_from_density(
Ruilong Li(李瑞龙)'s avatar
Ruilong Li(李瑞龙) committed
137
138
139
140
141
142
143
144
145
146
        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
147
    trans, _ = render_transmittance_from_density(
Ruilong Li(李瑞龙)'s avatar
Ruilong Li(李瑞龙) committed
148
149
150
151
152
153
154
155
156
        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)

157
    weights, _, _ = render_weight_from_density(
Ruilong Li(李瑞龙)'s avatar
Ruilong Li(李瑞龙) committed
158
159
160
161
162
163
164
165
        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)

166
    weights, _, _ = render_weight_from_density(
Ruilong Li(李瑞龙)'s avatar
Ruilong Li(李瑞龙) committed
167
168
169
170
171
172
173
174
175
        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))
176
    weights, _ = render_weight_from_alpha(
Ruilong Li(李瑞龙)'s avatar
Ruilong Li(李瑞龙) committed
177
178
179
180
181
182
183
184
185
        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))
186
    weights, _ = render_weight_from_alpha(
Ruilong Li(李瑞龙)'s avatar
Ruilong Li(李瑞龙) committed
187
        alphas, packed_info=packed_info, n_rays=3
188
    )
Ruilong Li(李瑞龙)'s avatar
Ruilong Li(李瑞龙) committed
189
190
191
192
193
    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
194
195


196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
@pytest.mark.skipif(not torch.cuda.is_available, reason="No CUDA device")
def test_rendering():
    from nerfacc.volrend import rendering

    def rgb_sigma_fn(t_starts, t_ends, ray_indices):
        return torch.stack([t_starts] * 3, dim=-1), t_starts

    ray_indices = torch.tensor(
        [0, 2, 2, 2, 2], dtype=torch.int64, device=device
    )  # (all_samples,)
    sigmas = torch.rand(
        (ray_indices.shape[0],), device=device
    )  # (all_samples,)
    t_starts = torch.rand_like(sigmas)
    t_ends = torch.rand_like(sigmas) + 1.0

    _, _, _, _ = rendering(
        t_starts,
        t_ends,
        ray_indices=ray_indices,
        n_rays=3,
        rgb_sigma_fn=rgb_sigma_fn,
    )


Ruilong Li(李瑞龙)'s avatar
Ruilong Li(李瑞龙) committed
221
if __name__ == "__main__":
222
223
224
225
    test_render_visibility()
    test_render_weight_from_alpha()
    test_render_weight_from_density()
    test_accumulate_along_rays()
Ruilong Li(李瑞龙)'s avatar
Ruilong Li(李瑞龙) committed
226
    test_grads()
227
    test_rendering()