点云分割中 offset 与 batch 表示的转换详解
点云分割数据处理中 offset 与 batch 的转换逻辑解析
背景
在点云分割任务中,我们常常需要对点云进行 批处理(batching)。由于每个点云样本中点的数量不固定,因此不能直接用规则的矩阵来表示所有点云。为了解决这个问题,通常会引入 offset、bincount、batch 之间的转换来高效表示点云样本之间的边界和归属关系。
这些函数(offset2bincount
、bincount2offset
、offset2batch
、batch2offset
)就是在点云分割模型的数据处理中,完成点与样本之间映射关系的关键逻辑。
核心概念
在正式看源码前,先明确几个核心概念:
- 点云数量(总点数):所有样本的点合并后得到的点数,等于
offset[-1]
。 - 样本数量(batch size):一批中点云的个数,等于
len(offset)
。 - offset:存储每个点云样本结束位置的索引。
- bincount:存储每个点云样本中点的数量。
- batch:存储每个点属于哪个样本的索引。
三者之间的关系是:
len(offset)
= batch size(样本数)offset[-1]
= 总点数
并且它们之间可以相互转换:
- offset → bincount → batch
- batch → offset
源码解析(逐函数分析)
1. offset2bincount
@torch.no_grad()
def offset2bincount(offset):return torch.diff(offset, prepend=torch.tensor([0], device=offset.device, dtype=torch.long))
-
功能:将 offset 转换为每个样本的点数。
-
逻辑:在 offset 前面加一个
0
,做差分,得到每个样本的点数。 -
示例:
offset = [4, 9, 12]
offset2bincount(offset) = [4, 5, 3]
2. bincount2offset
@torch.no_grad()
def bincount2offset(bincount):return torch.cumsum(bincount, dim=0)
-
功能:将每个样本的点数还原成 offset。
-
逻辑:对点数数组做累加即可。
-
示例:
bincount = [4, 5, 3]
bincount2offset(bincount) = [4, 9, 12]
3. offset2batch
@torch.no_grad()
def offset2batch(offset):bincount = offset2bincount(offset)return torch.arange(len(bincount), device=offset.device, dtype=torch.long).repeat_interleave(bincount)
-
功能:生成每个点对应的样本编号。
-
逻辑:
- 先得到每个样本的点数(bincount)。
- 为每个样本生成索引(0,1,2,…)。
- 每个索引重复对应的点数次。
-
示例:
offset = [4, 9, 12]
bincount = [4, 5, 3]
offset2batch(offset) = [0,0,0,0,1,1,1,1,1,2,2,2]
4. batch2offset
@torch.no_grad()
def batch2offset(batch):return torch.cumsum(batch.bincount(), dim=0).long()
-
功能:根据点所属的样本编号,恢复 offset。
-
逻辑:
- 统计 batch 中每个样本的点数。
- 对点数做累加得到 offset。
-
示例:
batch = [0,0,0,0,1,1,1,1,1,2,2,2]
batch.bincount() = [4, 5, 3]
batch2offset(batch) = [4, 9, 12]
图解说明
假设我们有 3 个点云样本,点数分别为 3、2、4:
样本 0: ● ● ●
样本 1: ● ●
样本 2: ● ● ● ●
对应关系如下:
- bincount = [3, 2, 4] (每个样本的点数)
- offset = [3, 5, 9] (每个样本的结束位置)
- batch = [0,0,0,1,1,2,2,2,2] (每个点的所属样本)
下图直观展示了 offset、bincount、batch 三者之间的关系:
通过上图可以直观理解:
- offset 标记分界线;
- bincount 表示每块区域大小;
- batch 表示点的归属。
示例
import torch# 定义 offset
offset = torch.tensor([3, 5, 9])print("offset2bincount:", offset2bincount(offset))
print("bincount2offset:", bincount2offset(torch.tensor([3,2,4])))
print("offset2batch:", offset2batch(offset))
print("batch2offset:", batch2offset(offset2batch(offset)))
输出结果:
offset2bincount: tensor([3, 2, 4])
bincount2offset: tensor([3, 5, 9])
offset2batch: tensor([0, 0, 0, 1, 1, 2, 2, 2, 2])
batch2offset: tensor([3, 5, 9])
总结
-
offset、bincount、batch 是点云分割任务中常用的三种数据表示方式。
-
三者之间的关系:
len(offset)
= 样本数量offset[-1]
= 总点数
-
各函数逻辑:
offset2bincount
:差分得到点数bincount2offset
:累加得到边界offset2batch
:展开得到点归属batch2offset
:统计恢复边界
-
掌握这些概念和函数,有助于理解深度学习框架在点云任务中的数据流动方式。