PyTorch中含argsort与gather的点云处理流程能否反向传播?
问题解答
原流程能否实现梯度非零的反向传播?
不能。原因是torch.argsort返回的是整数类型的索引张量,这类离散选择操作在PyTorch中是不可导的——梯度无法穿过索引传递到之前的神经网络输出张量B。后续的torch.gather虽然本身支持梯度回传,但如果输入的索引是不可导的(来自argsort),最终只会导致B的梯度全部为0,无法完成有效的反向传播训练。
解决方法
针对这个问题,核心是用可微分的连续操作替代离散的硬排序/硬选择,以下是几种可行方案:
1. 软选择(Soft Selection,推荐)
通过温度化的Softmax将离散的“选前10个点”转化为连续的权重分布,让整个过程可导:
import torch # 假设A是(N,3)的原始点云张量,B是(N,1)的神经网络输出分数 tau = 0.1 # 温度参数,值越小越接近硬选择,值越大越平滑 # 将分数转化为权重分布 weights = torch.softmax(B / tau, dim=0) # 取权重最高的前10个点的加权组合(近似硬选择的效果) top_weights, _ = torch.topk(weights, k=10, dim=0) # 用权重加权点云,得到可导的选中点表示 selected_points = (A * top_weights).sum(dim=0, keepdim=True) # 基于selected_points计算损失(示例) loss = torch.mean(selected_points ** 2) loss.backward()
这种方法既保留了“关注高分点”的逻辑,又能让梯度顺利传递到B。
2. 重参数化采样
如果必须使用硬选择逻辑,可以用重参数化技巧将离散采样转化为可导操作(适合对精度要求不高或能接受梯度噪声的场景):
# 基于B构建带噪声的分数,实现可导的近似排序 gumbel_noise = -torch.log(-torch.log(torch.rand_like(B))) noisy_scores = B + gumbel_noise top_indices = torch.argsort(noisy_scores, dim=0, descending=True)[:10] # 用重参数化后的索引取点,梯度可通过噪声传递到B selected_points = torch.gather(A, 0, top_indices.repeat(1,3)) loss = torch.mean(selected_points) loss.backward()
注意:这种方法的梯度带有噪声,通常需要多次采样取平均来稳定训练。
3. 修改损失函数,规避硬选择
如果业务逻辑允许,直接基于所有点的分数加权计算损失,无需显式排序:
# 用分数作为权重,让高分点对损失的贡献更大 weights = torch.sigmoid(B) # 或者用softmax,根据需求选择 loss_per_point = torch.norm(A - target_points, dim=1, keepdim=True) # 示例损失项 total_loss = torch.mean(weights * loss_per_point) total_loss.backward()
这种方法完全避免了离散操作,梯度传递最顺畅,适合不需要严格取前10个点,只需要关注高分点的场景。
内容的提问来源于stack exchange,提问作者Hai W.X.
相关产品推荐
相关产品推荐

