Pointnet++代码详解(五):sample_and_group函数和samle_and_group_all函数

Sampling + Grouping主要用于将整个点云分散成局部的group,对每一个group都可以用PointNet单独的提取局部的全局特征。Sampling + Grouping需要用到前面分析定义的那些函数,分成了sample_and_group和sample_and_group_all两个函数,其区别在于sample_and_group_all直接将所有点作为一个group
sample_and_group的实现步骤入下:

  • 先用farthest_point_sample函数实现最远点采样FPS得到采样点的索引,再通过index_points将这些点的从原始点中挑出来,作为new_xyz
  • 利用query_ball_point和index_points将原始点云通过new_xyz 作为中心分为npoint个球形区域其中每个区域有nsample个采样点
  • 每个区域的点减去区域的中心值
  • 如果每个点上面有新的特征的维度,则用新的特征与旧的特征拼接,否则直接返回旧的特征

sample_and_group_all直接将所有点作为一个group,即增加一个长度为1的维度而已,当然也存在拼接新的特征的过程。

def sample_and_group(npoint, radius, nsample, xyz, points, returnfps=False):
    """
    Input:
        npoint: number of samples,FPS采样点的数量
        radius: local region radius,球形区域所定义的半径
        nsample: max sample number in local region,球形区域所能包围的最大的点数量
        xyz: input points position data, [B, N, 3]
        points: input points data, [B, N, D],D不包含坐标数据x,y,z
    Return:
        new_xyz: sampled points position data, [B, npoint, 3]
        new_points: sampled points data, [B, npoint, nsample, 3+D]
    """
    B, N, C = xyz.shape
    S = npoint
    # 从原点云中挑出最远点采样的采样点为new_xyz
    fps_idx = farthest_point_sample(xyz, npoint) # [B, npoint]
    torch.cuda.empty_cache()
    #通过index_points将FPS采样点从原始点中挑出来
    #new_xyz代表中心点,此时维度为[B, S, 3]
    new_xyz = index_points(xyz, fps_idx)
    torch.cuda.empty_cache()
    # idx:[B, npoint, nsample] 代表npoint个球形区域中每个区域的nsample个采样点的索引
    idx = query_ball_point(radius, nsample, xyz, new_xyz)
    torch.cuda.empty_cache()
    # grouped_xyz:[B, npoint, nsample, C],
    #通过index_points将所有group内的nsample个采样点从原始点中挑出来
    grouped_xyz = index_points(xyz, idx)
    torch.cuda.empty_cache()
    # grouped_xyz减去中心点:每个区域的点减去区域的中心值
    grouped_xyz_norm = grouped_xyz - new_xyz.view(B, S, 1, C)
    torch.cuda.empty_cache()
    # 如果每个点上面有新的特征的维度,则用新的特征与旧的特征拼接,否则直接返回旧的特征
    if points is not None:
        #通过index_points将所有group内的nsample个采样点从原始点中挑出来,得到group内点的除坐标维度外的其他维度的数据
        grouped_points = index_points(points, idx)
        #dim=-1代表按照最后的维度进行拼接,即相当于dim=3
        new_points = torch.cat([grouped_xyz_norm, grouped_points], dim=-1) # [B, npoint, nsample, C+D]
    else:
        new_points = grouped_xyz_norm
    if returnfps:
        return new_xyz, new_points, grouped_xyz, fps_idx
    else:
        return new_xyz, new_points


def samle_and_group_all(xyz, points):
    '''
       Input:
           xyz: input points position data, [B, N, 3]
           points: input points data, [B, N, D]
       Return:
           new_xyz: sampled points position data, [B, 1, 3]
           new_points: sampled points data, [B, 1, N, 3+D]
        直接将所有点作为一个group,即增加一个长度为1的维度而已
    '''
    device = xyz.device
    B, N, C =xyz.shape
    #new_xyz代表中心点,用原点表示
    new_xyz = torch.zeros(B, 1, C).to(device)
    # grouped_xyz减去中心点:每个区域的点减去区域的中心值,由于中心点为原点,所以结果仍然是grouped_xyz
    grouped_xyz = xyz.view(B, 1, N, C)
    # 如果每个点上面有新的特征的维度,则用新的特征与旧的特征拼接,否则直接返回旧的特征
    if points is not None:
        #view(B, 1, N, -1),-1代表自动计算,即结果等于view(B, 1, N, D)
        new_points = torch.cat([grouped_xyz, points.view(B, 1, N, -1)], dim=-1)
    else:
        new_points = grouped_xyz
    return new_xyz, new_points

torch.cuda.empty_cache():

Pytorch已经可以自动回收我们不用的显存,类似于python的引用机制,当某一内存内的数据不再有任何变量引用时,这部分的内存便会被释放。但有一点需要注意,当我们有一部分显存不再使用的时候,这部分释放的显存通过Nvidia-smi命令是看不到的,举个例子:

device = torch.device('cuda:0')
# 定义两个tensor
dummy_tensor_4 = torch.randn(120, 3, 512, 512).float().to(device)  # 120*3*512*512*4/1000/1000 = 377.48M
dummy_tensor_5 = torch.randn(80, 3, 512, 512).float().to(device)  # 80*3*512*512*4/1000/1000 = 251.64M

# 然后释放
dummy_tensor_4 = dummy_tensor_4.cpu()
dummy_tensor_2 = dummy_tensor_2.cpu()
# 这里虽然将上面的显存释放了,但是我们通过Nvidia-smi命令看到显存依然在占用
torch.cuda.empty_cache()
# 只有执行完上面这句,显存才会在Nvidia-smi中释放

Pytorch的开发者也对此进行说明了,这部分释放后的显存可以用,只不过不在Nvidia-smi中显示罢了。


 

  • 7
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值