pointcloud saliency map的源代码是使用tensorflow实现的,将其移植到pytorch(0.4.1)版本的RSCNN。
环境:unbuntu16.04+cuda9.0+cudnn7.6+pytorch0.4.1+torchvizion0.2.2
实现代码:
// input :点云 分类模型 标签
//output: 丢弃高分点后的点云
def drop_points(pointclouds_pl, model, target):
pointclouds_pl_adv_list = []
k_list = [5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60] # 分k_list次 丢弃 K_list * 5个点
for k in k_list:
pointclouds_pl_adv = pointclouds_pl.clone()
for i in range(k):
pre = model(pointclouds_pl_adv)
loss = criterion(pre, target)
// 输出(loss)对输入(point cloud)求倒数
grad = torch.autograd.grad(outputs=loss, inputs=pointclouds_pl_adv, only_inputs=True, retain_graph=False)[0] # grad_outputs=None,
grad = grad.cpu()
grad = grad.detach().numpy()
pointclouds_pl_adv = pointclouds_pl_adv.cpu()
pointclouds_pl_adv = pointclouds_pl_adv.detach().numpy()
sphere_core = np.median(pointclouds_pl_adv, axis=1, keepdims=True)
sphere_r = np.sqrt(np.sum(np.square(pointclouds_pl_adv - sphere_core), axis=2)) ## BxN
sphere_axis = pointclouds_pl_adv - sphere_core ## BxNx3
if 0:
sphere_map = np.multiply(np.sum(np.multiply(grad, sphere_axis), axis=2),
np.power(sphere_r, FLAGS.power))
# sphere_map = np.multiply(np.sum(np.multiply(grad, sphere_axis), axis=2), 1/sphere_r)
# sphere_map = np.sum(np.abs(grad), axis=2)
else:
sphere_map = -np.multiply(np.sum(np.multiply(grad, sphere_axis), axis=2), np.power(sphere_r, 1))
# sphere_map = -np.multiply(np.sum(np.multiply(grad, sphere_axis), axis=2), 1/sphere_r)
#sphere_map = np.sum(np.abs(grad), axis=2)
drop_indice = np.argpartition(sphere_map, kth=sphere_map.shape[1] - 5, axis=1)[:, -5:]
tmp = np.zeros((pointclouds_pl_adv.shape[0], pointclouds_pl_adv.shape[1] - 5, 3), dtype=float)
for j in range(pointclouds_pl.shape[0]):
tmp[j] = np.delete(pointclouds_pl_adv[j], drop_indice[j], axis=0) # along N points to delete
pointclouds_pl_adv = tmp.copy()
pointclouds_pl_adv = torch.from_numpy(pointclouds_pl_adv)
pointclouds_pl_adv = pointclouds_pl_adv.type(torch.float32)
pointclouds_pl_adv = pointclouds_pl_adv.cuda()
pointclouds_pl_adv.requires_grad_()
pointclouds_pl_adv_list.append(pointclouds_pl_adv)
return pointclouds_pl_adv_list
在运行grad = torch.autograd.grad(outputs=loss, inputs=pointclouds_pl_adv, only_inputs=True, retain_graph=False)[0] # grad_outputs=None,
时候会报错,错误 大概是 BallQueryBackward 返回了错误数量的gradient (expecte 5, got 4)
这时将文件 pointnet2_utils.py中的
def backward(ctx, a=None):
#print('ball backward')
return None, None, None, None
改为(多加一个None),即可正常运行
def backward(ctx, a=None):
#print('ball backward')
return None, None, None, None, None