当前位置:   article > 正文

Windows系统保姆级复现Pointnet++算法教程笔记(基于Pytorch)_pointnet++复现

pointnet++复现

前言

今天复现了PointNet++网络,中途也遇到过好多报错问题,但都一一解决了,最终实现cls、partseg、semseg训练(train)和测试(test)程序的成功跑通。

首先,我参考的论文和所用的源码参考自这篇文章:

3D点云目标检测算法Pointnet++项目实战 Pytorch实现

附代码:

链接:https://pan.baidu.com/s/10Nk4Zd3S_NklY5PJwzmnWA 
提取码:6688 

论文链接:

https://proceedings.neurips.cc/paper/2017/file/d8bf84be3800d12f74d8b05e9b89836f-Paper.pdf

一、配置环境

按理说复现Pointnet的源码是适用于在Ubuntu下跑,但是我想在Windows实现一下

Windows系统

python 3.8   cuda 11.6 pytorch 1.12.0  torchvision 0.13.0

在这之前要先在anaconda下创建一个pointnet的虚拟环境,python版本选择3.8

  1. # 创建虚拟环境
  2. conda create -n pointnet python=3.8.0
  3. # 激活虚拟环境(切换至这个环境)
  4. conda activate pointnet
  5. # 查看已创建的虚拟环境
  6. conda info -e

然后对应自己CUDA版本下载对应的gpu版的pytorch

  1. # CUDA 11.6
  2. pip install torch==1.13.1+cu116 torchvision==0.14.1+cu116 torchaudio==0.13.1 --extra-index-url https://download.pytorch.org/whl/cu116

这一块虚拟环境的GPU配置就不细说了,如果没有配置过可以参考我这篇文章,基本步骤都差不多:

YOLOv8目标跟踪环境配置笔记(完整记录一次成功)

二、复现步骤

1.先将代码下载下来,目录结构如下:
 

其实这里的东西如果真的想全部能跑是缺了一些东西的,下面具体再说。

2.启动PyCharm打开该项目文件Pointnet2,同时将自己前面创建好的虚拟环境导入进来(具体导入的方法,参考我上面的文章链接,也有步骤)

其中环境Python3.8是自己给虚拟环境起的名称,可以在这里面编辑,因为我前面配置过Python3.7的虚拟环境,而这次采用pythonn3.8版本的,一开始导入进来,前面的环境名称还是默认Python3.7,我以为3.8版本的python编译器没有成功导入进来,担心后面因版本问题引起不必要的报错,后来发现编译器python.exe已经是3.8的了,只是虚拟环境名称需要改一下

如果不确定可以跑下面的程序来确认一下python版本(确认一下导入的虚拟环境是对的)

  1. import sys
  2. print(sys.version)

3.接下来我们就可以依次运行train_cls.py、train_partseg.py、train_semseg.py、test_cls.py、test_partseg.py、test_semseg.py是否可以正常跑通,train代表进行模型训练用的,test代表模型测试用的。

首先我把我自己调通的可以跑的程序先放出来

(1)train_cls.py

  1. from data_utils.ModelNetDataLoader import ModelNetDataLoader
  2. import argparse
  3. import numpy as np
  4. import os
  5. import torch
  6. import datetime
  7. import logging
  8. from pathlib import Path
  9. from tqdm import tqdm
  10. import sys
  11. import provider
  12. import importlib
  13. import shutil
  14. BASE_DIR = os.path.dirname(os.path.abspath(__file__))
  15. ROOT_DIR = BASE_DIR
  16. sys.path.append(os.path.join(ROOT_DIR, 'models'))
  17. """
  18. 需要配置的参数:
  19. --model pointnet2_cls_msg
  20. --normal
  21. --log_dir pointnet2_cls_msg
  22. """
  23. def parse_args():
  24. '''PARAMETERS'''
  25. parser = argparse.ArgumentParser('PointNet')
  26. parser.add_argument('--batch_size', type=int, default=8, help='batch size in training [default: 24]')
  27. parser.add_argument('--model', default='pointnet2_cls_ssg', help='model name [default: pointnet_cls]')
  28. parser.add_argument('--epoch', default=200, type=int, help='number of epoch in training [default: 200]')
  29. parser.add_argument('--learning_rate', default=0.001, type=float, help='learning rate in training [default: 0.001]')
  30. parser.add_argument('--gpu', type=str, default='0', help='specify gpu device [default: 0]')
  31. parser.add_argument('--num_point', type=int, default=1024, help='Point Number [default: 1024]')
  32. parser.add_argument('--optimizer', type=str, default='Adam', help='optimizer for training [default: Adam]')
  33. parser.add_argument('--log_dir', type=str, default=None, help='experiment root')
  34. parser.add_argument('--decay_rate', type=float, default=1e-4, help='decay rate [default: 1e-4]')
  35. parser.add_argument('--normal', action='store_true', default=False, help='Whether to use normal information [default: False]')
  36. return parser.parse_args()
  37. def test(model, loader, num_class=40):
  38. mean_correct = []
  39. class_acc = np.zeros((num_class,3))
  40. for j, data in tqdm(enumerate(loader), total=len(loader)):
  41. points, target = data
  42. target = target[:, 0]
  43. points = points.transpose(2, 1)
  44. points, target = points.cuda(), target.cuda()
  45. classifier = model.eval()
  46. pred, _ = classifier(points)
  47. pred_choice = pred.data.max(1)[1]
  48. for cat in np.unique(target.cpu()):
  49. classacc = pred_choice[target==cat].eq(target[target==cat].long().data).cpu().sum()
  50. class_acc[cat,0]+= classacc.item()/float(points[target==cat].size()[0])
  51. class_acc[cat,1]+=1
  52. correct = pred_choice.eq(target.long().data).cpu().sum()
  53. mean_correct.append(correct.item()/float(points.size()[0]))
  54. class_acc[:,2] = class_acc[:,0]/ class_acc[:,1]
  55. class_acc = np.mean(class_acc[:,2])
  56. instance_acc = np.mean(mean_correct)
  57. return instance_acc, class_acc
  58. def main(args):
  59. def log_string(str):
  60. logger.info(str)
  61. print(str)
  62. '''HYPER PARAMETER'''
  63. os.environ["CUDA_VISIBLE_DEVICES"] = args.gpu
  64. '''CREATE DIR'''
  65. #创建文件夹
  66. timestr = str(datetime.datetime.now().strftime('%Y-%m-%d_%H-%M'))
  67. experiment_dir = Path('./log/')
  68. experiment_dir.mkdir(exist_ok=True)
  69. experiment_dir = experiment_dir.joinpath('classification')
  70. experiment_dir.mkdir(exist_ok=True)
  71. if args.log_dir is None:
  72. experiment_dir = experiment_dir.joinpath(timestr)
  73. else:
  74. experiment_dir = experiment_dir.joinpath(args.log_dir)
  75. experiment_dir.mkdir(exist_ok=True)
  76. checkpoints_dir = experiment_dir.joinpath('checkpoints/')
  77. checkpoints_dir.mkdir(exist_ok=True)
  78. log_dir = experiment_dir.joinpath('logs/')
  79. log_dir.mkdir(exist_ok=True)
  80. '''LOG'''
  81. args = parse_args()
  82. logger = logging.getLogger("Model")
  83. logger.setLevel(logging.INFO)
  84. formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
  85. file_handler = logging.FileHandler('%s/%s.txt' % (log_dir, args.model))
  86. file_handler.setLevel(logging.INFO)
  87. file_handler.setFormatter(formatter)
  88. logger.addHandler(file_handler)
  89. log_string('PARAMETER ...')
  90. log_string(args)
  91. '''DATA LOADING'''
  92. log_string('Load dataset ...')
  93. DATA_PATH = 'data/modelnet40_normal_resampled/'
  94. TRAIN_DATASET = ModelNetDataLoader(root=DATA_PATH, npoint=args.num_point, split='train',
  95. normal_channel=args.normal)
  96. TEST_DATASET = ModelNetDataLoader(root=DATA_PATH, npoint=args.num_point, split='test',
  97. normal_channel=args.normal)
  98. trainDataLoader = torch.utils.data.DataLoader(TRAIN_DATASET, batch_size=args.batch_size, shuffle=True, num_workers=4)
  99. testDataLoader = torch.utils.data.DataLoader(TEST_DATASET, batch_size=args.batch_size, shuffle=False, num_workers=4)
  100. '''MODEL LOADING'''
  101. num_class = 40
  102. MODEL = importlib.import_module(args.model)
  103. shutil.copy('./models/%s.py' % args.model, str(experiment_dir))
  104. shutil.copy('./models/pointnet_util.py', str(experiment_dir))
  105. classifier = MODEL.get_model(num_class,normal_channel=args.normal).cuda()
  106. criterion = MODEL.get_loss().cuda()
  107. try:
  108. checkpoint = torch.load(str(experiment_dir) + '/checkpoints/best_model.pth')
  109. start_epoch = checkpoint['epoch']
  110. classifier.load_state_dict(checkpoint['model_state_dict'])
  111. log_string('Use pretrain model')
  112. except:
  113. log_string('No existing model, starting training from scratch...')
  114. start_epoch = 0
  115. if args.optimizer == 'Adam':
  116. optimizer = torch.optim.Adam(
  117. classifier.parameters(),
  118. lr=args.learning_rate,
  119. betas=(0.9, 0.999),
  120. eps=1e-08,
  121. weight_decay=args.decay_rate
  122. )
  123. else:
  124. optimizer = torch.optim.SGD(classifier.parameters(), lr=0.01, momentum=0.9)
  125. scheduler = torch.optim.lr_scheduler.StepLR(optimizer, step_size=20, gamma=0.7)
  126. global_epoch = 0
  127. global_step = 0
  128. best_instance_acc = 0.0
  129. best_class_acc = 0.0
  130. mean_correct = []
  131. '''TRANING'''
  132. logger.info('Start training...')
  133. for epoch in range(start_epoch,args.epoch):
  134. log_string('Epoch %d (%d/%s):' % (global_epoch + 1, epoch + 1, args.epoch))
  135. # optimizer.step()通常用在每个mini-batch之中,而scheduler.step()通常用在epoch里面,
  136. # 但也不是绝对的,可以根据具体的需求来做。
  137. # 只有用了optimizer.step(),模型才会更新,而scheduler.step()是对lr进行调整。
  138. scheduler.step()
  139. for batch_id, data in tqdm(enumerate(trainDataLoader, 0), total=len(trainDataLoader), smoothing=0.9):
  140. points, target = data
  141. points = points.data.numpy()
  142. points = provider.random_point_dropout(points) #进行数据增强
  143. points[:,:, 0:3] = provider.random_scale_point_cloud(points[:,:, 0:3]) #在数值上调大或调小,设置一个范围
  144. points[:,:, 0:3] = provider.shift_point_cloud(points[:,:, 0:3]) #增加随机抖动,使测试结果更好
  145. points = torch.Tensor(points)
  146. target = target[:, 0]
  147. points = points.transpose(2, 1)
  148. points, target = points.cuda(), target.cuda()
  149. optimizer.zero_grad()
  150. classifier = classifier.train()
  151. pred, trans_feat = classifier(points)
  152. loss = criterion(pred, target.long(), trans_feat) #计算损失
  153. pred_choice = pred.data.max(1)[1]
  154. correct = pred_choice.eq(target.long().data).cpu().sum()
  155. mean_correct.append(correct.item() / float(points.size()[0]))
  156. loss.backward() #反向传播
  157. optimizer.step() #最好的测试结果
  158. global_step += 1
  159. train_instance_acc = np.mean(mean_correct)
  160. log_string('Train Instance Accuracy: %f' % train_instance_acc)
  161. with torch.no_grad():
  162. instance_acc, class_acc = test(classifier.eval(), testDataLoader)
  163. if (instance_acc >= best_instance_acc):
  164. best_instance_acc = instance_acc
  165. best_epoch = epoch + 1
  166. if (class_acc >= best_class_acc):
  167. best_class_acc = class_acc
  168. log_string('Test Instance Accuracy: %f, Class Accuracy: %f'% (instance_acc, class_acc))
  169. log_string('Best Instance Accuracy: %f, Class Accuracy: %f'% (best_instance_acc, best_class_acc))
  170. if (instance_acc >= best_instance_acc):
  171. logger.info('Save model...')
  172. savepath = str(checkpoints_dir) + '/best_model.pth'
  173. log_string('Saving at %s'% savepath)
  174. state = {
  175. 'epoch': best_epoch,
  176. 'instance_acc': instance_acc,
  177. 'class_acc': class_acc,
  178. 'model_state_dict': classifier.state_dict(),
  179. 'optimizer_state_dict': optimizer.state_dict(),
  180. }
  181. torch.save(state, savepath)
  182. global_epoch += 1
  183. logger.info('End of training...')
  184. if __name__ == '__main__':
  185. args = parse_args()
  186. main(args)

(2)train_partseg.py

  1. import argparse
  2. import os
  3. from data_utils.ShapeNetDataLoader import PartNormalDataset
  4. import torch
  5. import datetime
  6. import logging
  7. from pathlib import Path
  8. import sys
  9. import importlib
  10. import shutil
  11. from tqdm import tqdm
  12. import provider
  13. import numpy as np
  14. """
  15. 训练所需设置参数:
  16. --model pointnet2_part_seg_msg
  17. --normal
  18. --log_dir pointnet2_part_seg_msg
  19. """
  20. BASE_DIR = os.path.dirname(os.path.abspath(__file__))
  21. ROOT_DIR = BASE_DIR
  22. sys.path.append(os.path.join(ROOT_DIR, 'models'))
  23. #各个物体部件的编号
  24. seg_classes = {'Earphone': [16, 17, 18], 'Motorbike': [30, 31, 32, 33, 34, 35], 'Rocket': [41, 42, 43], 'Car': [8, 9, 10, 11], 'Laptop': [28, 29], 'Cap': [6, 7], 'Skateboard': [44, 45, 46], 'Mug': [36, 37], 'Guitar': [19, 20, 21], 'Bag': [4, 5], 'Lamp': [24, 25, 26, 27], 'Table': [47, 48, 49], 'Airplane': [0, 1, 2, 3], 'Pistol': [38, 39, 40], 'Chair': [12, 13, 14, 15], 'Knife': [22, 23]}
  25. seg_label_to_cat = {} # {0:Airplane, 1:Airplane, ...49:Table}
  26. for cat in seg_classes.keys():
  27. for label in seg_classes[cat]:
  28. seg_label_to_cat[label] = cat
  29. def to_categorical(y, num_classes):
  30. """ 1-hot encodes a tensor """
  31. new_y = torch.eye(num_classes)[y.cpu().data.numpy(),]
  32. if (y.is_cuda):
  33. return new_y.cuda()
  34. return new_y
  35. def parse_args():
  36. parser = argparse.ArgumentParser('Model')
  37. parser.add_argument('--model', type=str, default='pointnet2_part_seg_msg', help='model name [default: pointnet2_part_seg_msg]')
  38. parser.add_argument('--batch_size', type=int, default=32, help='Batch Size during training [default: 16]')
  39. parser.add_argument('--epoch', default=2, type=int, help='Epoch to run [default: 251]')
  40. parser.add_argument('--learning_rate', default=0.001, type=float, help='Initial learning rate [default: 0.001]')
  41. # parser.add_argument('--gpu', type=str, default='', help='GPU to use [default: GPU 0]')
  42. parser.add_argument('--gpu', default='', help='cuda gpu, i.e. 0 or 0,1,2,3 or cpu')
  43. parser.add_argument('--optimizer', type=str, default='Adam', help='Adam or SGD [default: Adam]')
  44. parser.add_argument('--log_dir', type=str, default=None, help='Log path [default: None]')
  45. parser.add_argument('--decay_rate', type=float, default=1e-4, help='weight decay [default: 1e-4]')
  46. parser.add_argument('--npoint', type=int, default=2048, help='Point Number [default: 2048]')
  47. parser.add_argument('--normal', action='store_true', default=False, help='Whether to use normal information [default: False]')
  48. parser.add_argument('--step_size', type=int, default=20, help='Decay step for lr decay [default: every 20 epochs]')
  49. parser.add_argument('--lr_decay', type=float, default=0.5, help='Decay rate for lr decay [default: 0.5]')
  50. return parser.parse_args()
  51. def main(args):
  52. def log_string(str):
  53. logger.info(str)
  54. print(str)
  55. '''HYPER PARAMETER'''
  56. os.environ["CUDA_VISIBLE_DEVICES"] = args.gpu
  57. '''CREATE DIR'''
  58. timestr = str(datetime.datetime.now().strftime('%Y-%m-%d_%H-%M'))
  59. experiment_dir = Path('./log/')
  60. experiment_dir.mkdir(exist_ok=True)
  61. experiment_dir = experiment_dir.joinpath('part_seg')
  62. experiment_dir.mkdir(exist_ok=True)
  63. if args.log_dir is None:
  64. experiment_dir = experiment_dir.joinpath(timestr)
  65. else:
  66. experiment_dir = experiment_dir.joinpath(args.log_dir)
  67. experiment_dir.mkdir(exist_ok=True)
  68. checkpoints_dir = experiment_dir.joinpath('checkpoints/')
  69. checkpoints_dir.mkdir(exist_ok=True)
  70. log_dir = experiment_dir.joinpath('logs/')
  71. log_dir.mkdir(exist_ok=True)
  72. '''LOG'''
  73. args = parse_args()
  74. logger = logging.getLogger("Model")
  75. logger.setLevel(logging.INFO)
  76. formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
  77. file_handler = logging.FileHandler('%s/%s.txt' % (log_dir, args.model))
  78. file_handler.setLevel(logging.INFO)
  79. file_handler.setFormatter(formatter)
  80. logger.addHandler(file_handler)
  81. log_string('PARAMETER ...')
  82. log_string(args)
  83. root = 'data/shapenetcore_partanno_segmentation_benchmark_v0_normal/'
  84. TRAIN_DATASET = PartNormalDataset(root = root, npoints=args.npoint, split='trainval', normal_channel=args.normal)
  85. trainDataLoader = torch.utils.data.DataLoader(TRAIN_DATASET, batch_size=args.batch_size,shuffle=True, num_workers=4)
  86. TEST_DATASET = PartNormalDataset(root = root, npoints=args.npoint, split='test', normal_channel=args.normal)
  87. testDataLoader = torch.utils.data.DataLoader(TEST_DATASET, batch_size=args.batch_size,shuffle=False, num_workers=4)
  88. log_string("The number of training data is: %d" % len(TRAIN_DATASET))
  89. log_string("The number of test data is: %d" % len(TEST_DATASET))
  90. num_classes = 16
  91. num_part = 50
  92. '''MODEL LOADING'''
  93. MODEL = importlib.import_module(args.model)
  94. shutil.copy('models/%s.py' % args.model, str(experiment_dir))
  95. shutil.copy('models/pointnet_util.py', str(experiment_dir))
  96. classifier = MODEL.get_model(num_part, normal_channel=args.normal).cuda()
  97. criterion = MODEL.get_loss().cuda()
  98. def weights_init(m):
  99. classname = m.__class__.__name__
  100. if classname.find('Conv2d') != -1:
  101. torch.nn.init.xavier_normal_(m.weight.data)
  102. torch.nn.init.constant_(m.bias.data, 0.0)
  103. elif classname.find('Linear') != -1:
  104. torch.nn.init.xavier_normal_(m.weight.data)
  105. torch.nn.init.constant_(m.bias.data, 0.0)
  106. try:
  107. checkpoint = torch.load(str(experiment_dir) + '/checkpoints/best_model.pth')#log/part_seg/pointnet2_part_seg_msg/checkpoints/best_model.pth
  108. start_epoch = checkpoint['epoch']
  109. classifier.load_state_dict(checkpoint['model_state_dict'])
  110. log_string('Use pretrain model')
  111. except:
  112. log_string('No existing model, starting training from scratch...')
  113. start_epoch = 0
  114. classifier = classifier.apply(weights_init)
  115. if args.optimizer == 'Adam':
  116. optimizer = torch.optim.Adam(
  117. classifier.parameters(),
  118. lr=args.learning_rate,
  119. betas=(0.9, 0.999),
  120. eps=1e-08,
  121. weight_decay=args.decay_rate
  122. )
  123. else:
  124. optimizer = torch.optim.SGD(classifier.parameters(), lr=args.learning_rate, momentum=0.9)
  125. def bn_momentum_adjust(m, momentum):
  126. if isinstance(m, torch.nn.BatchNorm2d) or isinstance(m, torch.nn.BatchNorm1d):
  127. m.momentum = momentum
  128. LEARNING_RATE_CLIP = 1e-5
  129. MOMENTUM_ORIGINAL = 0.1
  130. MOMENTUM_DECCAY = 0.5
  131. MOMENTUM_DECCAY_STEP = args.step_size
  132. best_acc = 0
  133. global_epoch = 0
  134. best_class_avg_iou = 0
  135. best_inctance_avg_iou = 0
  136. for epoch in range(start_epoch,args.epoch):
  137. log_string('Epoch %d (%d/%s):' % (global_epoch + 1, epoch + 1, args.epoch))
  138. '''Adjust learning rate and BN momentum'''
  139. lr = max(args.learning_rate * (args.lr_decay ** (epoch // args.step_size)), LEARNING_RATE_CLIP)
  140. log_string('Learning rate:%f' % lr)
  141. for param_group in optimizer.param_groups:
  142. param_group['lr'] = lr
  143. mean_correct = []
  144. momentum = MOMENTUM_ORIGINAL * (MOMENTUM_DECCAY ** (epoch // MOMENTUM_DECCAY_STEP))
  145. if momentum < 0.01:
  146. momentum = 0.01
  147. print('BN momentum updated to: %f' % momentum)
  148. classifier = classifier.apply(lambda x: bn_momentum_adjust(x,momentum))
  149. '''learning one epoch'''
  150. for i, data in tqdm(enumerate(trainDataLoader), total=len(trainDataLoader), smoothing=0.9):
  151. points, label, target = data
  152. points = points.data.numpy()
  153. points[:,:, 0:3] = provider.random_scale_point_cloud(points[:,:, 0:3])
  154. points[:,:, 0:3] = provider.shift_point_cloud(points[:,:, 0:3])
  155. points = torch.Tensor(points)
  156. points, label, target = points.float().cuda(),label.long().cuda(), target.long().cuda()
  157. points = points.transpose(2, 1)
  158. optimizer.zero_grad()
  159. classifier = classifier.train()
  160. seg_pred, trans_feat = classifier(points, to_categorical(label, num_classes))
  161. seg_pred = seg_pred.contiguous().view(-1, num_part)
  162. target = target.view(-1, 1)[:, 0]
  163. pred_choice = seg_pred.data.max(1)[1]
  164. correct = pred_choice.eq(target.data).cpu().sum()
  165. mean_correct.append(correct.item() / (args.batch_size * args.npoint))
  166. loss = criterion(seg_pred, target, trans_feat)
  167. loss.backward()
  168. optimizer.step()
  169. train_instance_acc = np.mean(mean_correct)
  170. log_string('Train accuracy is: %.5f' % train_instance_acc)
  171. with torch.no_grad():
  172. test_metrics = {}
  173. total_correct = 0
  174. total_seen = 0
  175. total_seen_class = [0 for _ in range(num_part)]
  176. total_correct_class = [0 for _ in range(num_part)]
  177. shape_ious = {cat: [] for cat in seg_classes.keys()}
  178. seg_label_to_cat = {} # {0:Airplane, 1:Airplane, ...49:Table}
  179. for cat in seg_classes.keys():
  180. for label in seg_classes[cat]:
  181. seg_label_to_cat[label] = cat
  182. for batch_id, (points, label, target) in tqdm(enumerate(testDataLoader), total=len(testDataLoader), smoothing=0.9):
  183. cur_batch_size, NUM_POINT, _ = points.size()
  184. points, label, target = points.float().cuda(), label.long().cuda(), target.long().cuda()
  185. points = points.transpose(2, 1)
  186. classifier = classifier.eval()
  187. seg_pred, _ = classifier(points, to_categorical(label, num_classes))
  188. cur_pred_val = seg_pred.cpu().data.numpy()
  189. cur_pred_val_logits = cur_pred_val
  190. cur_pred_val = np.zeros((cur_batch_size, NUM_POINT)).astype(np.int32)
  191. target = target.cpu().data.numpy()
  192. for i in range(cur_batch_size):
  193. cat = seg_label_to_cat[target[i, 0]]
  194. logits = cur_pred_val_logits[i, :, :]
  195. cur_pred_val[i, :] = np.argmax(logits[:, seg_classes[cat]], 1) + seg_classes[cat][0]
  196. correct = np.sum(cur_pred_val == target)
  197. total_correct += correct
  198. total_seen += (cur_batch_size * NUM_POINT)
  199. for l in range(num_part):
  200. total_seen_class[l] += np.sum(target == l)
  201. total_correct_class[l] += (np.sum((cur_pred_val == l) & (target == l)))
  202. for i in range(cur_batch_size):
  203. segp = cur_pred_val[i, :]
  204. segl = target[i, :]
  205. cat = seg_label_to_cat[segl[0]]
  206. part_ious = [0.0 for _ in range(len(seg_classes[cat]))]
  207. for l in seg_classes[cat]:
  208. if (np.sum(segl == l) == 0) and (
  209. np.sum(segp == l) == 0): # part is not present, no prediction as well
  210. part_ious[l - seg_classes[cat][0]] = 1.0
  211. else:
  212. part_ious[l - seg_classes[cat][0]] = np.sum((segl == l) & (segp == l)) / float(
  213. np.sum((segl == l) | (segp == l)))
  214. shape_ious[cat].append(np.mean(part_ious))
  215. all_shape_ious = []
  216. for cat in shape_ious.keys():
  217. for iou in shape_ious[cat]:
  218. all_shape_ious.append(iou)
  219. shape_ious[cat] = np.mean(shape_ious[cat])
  220. mean_shape_ious = np.mean(list(shape_ious.values()))
  221. test_metrics['accuracy'] = total_correct / float(total_seen)
  222. test_metrics['class_avg_accuracy'] = np.mean(
  223. np.array(total_correct_class) / np.array(total_seen_class, dtype=np.float))
  224. for cat in sorted(shape_ious.keys()):
  225. log_string('eval mIoU of %s %f' % (cat + ' ' * (14 - len(cat)), shape_ious[cat]))
  226. test_metrics['class_avg_iou'] = mean_shape_ious
  227. test_metrics['inctance_avg_iou'] = np.mean(all_shape_ious)
  228. log_string('Epoch %d test Accuracy: %f Class avg mIOU: %f Inctance avg mIOU: %f' % (
  229. epoch+1, test_metrics['accuracy'],test_metrics['class_avg_iou'],test_metrics['inctance_avg_iou']))
  230. if (test_metrics['inctance_avg_iou'] >= best_inctance_avg_iou):
  231. logger.info('Save model...')
  232. savepath = str(checkpoints_dir) + '/best_model.pth'
  233. log_string('Saving at %s'% savepath)
  234. state = {
  235. 'epoch': epoch,
  236. 'train_acc': train_instance_acc,
  237. 'test_acc': test_metrics['accuracy'],
  238. 'class_avg_iou': test_metrics['class_avg_iou'],
  239. 'inctance_avg_iou': test_metrics['inctance_avg_iou'],
  240. 'model_state_dict': classifier.state_dict(),
  241. 'optimizer_state_dict': optimizer.state_dict(),
  242. }
  243. torch.save(state, savepath)
  244. log_string('Saving model....')
  245. if test_metrics['accuracy'] > best_acc:
  246. best_acc = test_metrics['accuracy']
  247. if test_metrics['class_avg_iou'] > best_class_avg_iou:
  248. best_class_avg_iou = test_metrics['class_avg_iou']
  249. if test_metrics['inctance_avg_iou'] > best_inctance_avg_iou:
  250. best_inctance_avg_iou = test_metrics['inctance_avg_iou']
  251. log_string('Best accuracy is: %.5f'%best_acc)
  252. log_string('Best class avg mIOU is: %.5f'%best_class_avg_iou)
  253. log_string('Best inctance avg mIOU is: %.5f'%best_inctance_avg_iou)
  254. global_epoch+=1
  255. if __name__ == '__main__':
  256. args = parse_args()
  257. main(args)

(3)train_semseg.py

  1. """
  2. Author: Benny
  3. Date: Nov 2019
  4. """
  5. import argparse
  6. import os
  7. from data_utils.S3DISDataLoader import S3DISDataset
  8. import torch
  9. import datetime
  10. import logging
  11. from pathlib import Path
  12. import sys
  13. import importlib
  14. import shutil
  15. from tqdm import tqdm
  16. import provider
  17. import numpy as np
  18. import time
  19. BASE_DIR = os.path.dirname(os.path.abspath(__file__))
  20. ROOT_DIR = BASE_DIR
  21. sys.path.append(os.path.join(ROOT_DIR, 'models'))
  22. classes = ['ceiling','floor','wall','beam','column','window','door','table','chair','sofa','bookcase','board','clutter']
  23. class2label = {cls: i for i,cls in enumerate(classes)}
  24. seg_classes = class2label
  25. seg_label_to_cat = {}
  26. for i,cat in enumerate(seg_classes.keys()):
  27. seg_label_to_cat[i] = cat
  28. def parse_args():
  29. parser = argparse.ArgumentParser('Model')
  30. parser.add_argument('--model', type=str, default='pointnet_sem_seg', help='model name [default: pointnet_sem_seg]')
  31. parser.add_argument('--batch_size', type=int, default=16, help='Batch Size during training [default: 16]')
  32. parser.add_argument('--epoch', default=128, type=int, help='Epoch to run [default: 128]')
  33. parser.add_argument('--learning_rate', default=0.001, type=float, help='Initial learning rate [default: 0.001]')
  34. parser.add_argument('--gpu', type=str, default='0', help='GPU to use [default: GPU 0]')
  35. parser.add_argument('--optimizer', type=str, default='Adam', help='Adam or SGD [default: Adam]')
  36. parser.add_argument('--log_dir', type=str, default=None, help='Log path [default: None]')
  37. parser.add_argument('--decay_rate', type=float, default=1e-4, help='weight decay [default: 1e-4]')
  38. parser.add_argument('--npoint', type=int, default=4096, help='Point Number [default: 4096]')
  39. parser.add_argument('--step_size', type=int, default=10, help='Decay step for lr decay [default: every 10 epochs]')
  40. parser.add_argument('--lr_decay', type=float, default=0.7, help='Decay rate for lr decay [default: 0.7]')
  41. parser.add_argument('--test_area', type=int, default=5, help='Which area to use for test, option: 1-6 [default: 5]')
  42. return parser.parse_args()
  43. def main(args):
  44. def log_string(str):
  45. logger.info(str)
  46. print(str)
  47. '''HYPER PARAMETER'''
  48. os.environ["CUDA_VISIBLE_DEVICES"] = args.gpu
  49. '''CREATE DIR'''
  50. timestr = str(datetime.datetime.now().strftime('%Y-%m-%d_%H-%M'))
  51. experiment_dir = Path('./log/')
  52. experiment_dir.mkdir(exist_ok=True)
  53. experiment_dir = experiment_dir.joinpath('sem_seg')
  54. experiment_dir.mkdir(exist_ok=True)
  55. if args.log_dir is None:
  56. experiment_dir = experiment_dir.joinpath(timestr)
  57. else:
  58. experiment_dir = experiment_dir.joinpath(args.log_dir)
  59. experiment_dir.mkdir(exist_ok=True)
  60. checkpoints_dir = experiment_dir.joinpath('checkpoints/')
  61. checkpoints_dir.mkdir(exist_ok=True)
  62. log_dir = experiment_dir.joinpath('logs/')
  63. log_dir.mkdir(exist_ok=True)
  64. '''LOG'''
  65. args = parse_args()
  66. logger = logging.getLogger("Model")
  67. logger.setLevel(logging.INFO)
  68. formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
  69. file_handler = logging.FileHandler('%s/%s.txt' % (log_dir, args.model))
  70. file_handler.setLevel(logging.INFO)
  71. file_handler.setFormatter(formatter)
  72. logger.addHandler(file_handler)
  73. log_string('PARAMETER ...')
  74. log_string(args)
  75. root = 'data/stanford_indoor3d/'
  76. NUM_CLASSES = 13
  77. NUM_POINT = args.npoint
  78. BATCH_SIZE = args.batch_size
  79. print("start loading training data ...")
  80. TRAIN_DATASET = S3DISDataset(split='train', data_root=root, num_point=NUM_POINT, test_area=args.test_area, block_size=1.0, sample_rate=1.0, transform=None)
  81. print("start loading test data ...")
  82. TEST_DATASET = S3DISDataset(split='test', data_root=root, num_point=NUM_POINT, test_area=args.test_area, block_size=1.0, sample_rate=1.0, transform=None)
  83. trainDataLoader = torch.utils.data.DataLoader(TRAIN_DATASET, batch_size=BATCH_SIZE, shuffle=True, num_workers=0, pin_memory=True, drop_last=True, worker_init_fn = lambda x: np.random.seed(x+int(time.time())))
  84. testDataLoader = torch.utils.data.DataLoader(TEST_DATASET, batch_size=BATCH_SIZE, shuffle=False, num_workers=0, pin_memory=True, drop_last=True)
  85. weights = torch.Tensor(TRAIN_DATASET.labelweights).cuda()
  86. log_string("The number of training data is: %d" % len(TRAIN_DATASET))
  87. log_string("The number of test data is: %d" % len(TEST_DATASET))
  88. '''MODEL LOADING'''
  89. MODEL = importlib.import_module(args.model)
  90. shutil.copy('models/%s.py' % args.model, str(experiment_dir))
  91. shutil.copy('models/pointnet_util.py', str(experiment_dir))
  92. classifier = MODEL.get_model(NUM_CLASSES).cuda()
  93. criterion = MODEL.get_loss().cuda()
  94. def weights_init(m):
  95. classname = m.__class__.__name__
  96. if classname.find('Conv2d') != -1:
  97. torch.nn.init.xavier_normal_(m.weight.data)
  98. torch.nn.init.constant_(m.bias.data, 0.0)
  99. elif classname.find('Linear') != -1:
  100. torch.nn.init.xavier_normal_(m.weight.data)
  101. torch.nn.init.constant_(m.bias.data, 0.0)
  102. try:
  103. checkpoint = torch.load(str(experiment_dir) + '/checkpoints/best_model.pth')
  104. start_epoch = checkpoint['epoch']
  105. classifier.load_state_dict(checkpoint['model_state_dict'])
  106. log_string('Use pretrain model')
  107. except:
  108. log_string('No existing model, starting training from scratch...')
  109. start_epoch = 0
  110. classifier = classifier.apply(weights_init)
  111. if args.optimizer == 'Adam':
  112. optimizer = torch.optim.Adam(
  113. classifier.parameters(),
  114. lr=args.learning_rate,
  115. betas=(0.9, 0.999),
  116. eps=1e-08,
  117. weight_decay=args.decay_rate
  118. )
  119. else:
  120. optimizer = torch.optim.SGD(classifier.parameters(), lr=args.learning_rate, momentum=0.9)
  121. def bn_momentum_adjust(m, momentum):
  122. if isinstance(m, torch.nn.BatchNorm2d) or isinstance(m, torch.nn.BatchNorm1d):
  123. m.momentum = momentum
  124. LEARNING_RATE_CLIP = 1e-5
  125. MOMENTUM_ORIGINAL = 0.1
  126. MOMENTUM_DECCAY = 0.5
  127. MOMENTUM_DECCAY_STEP = args.step_size
  128. global_epoch = 0
  129. best_iou = 0
  130. for epoch in range(start_epoch,args.epoch):
  131. '''Train on chopped scenes'''
  132. log_string('**** Epoch %d (%d/%s) ****' % (global_epoch + 1, epoch + 1, args.epoch))
  133. lr = max(args.learning_rate * (args.lr_decay ** (epoch // args.step_size)), LEARNING_RATE_CLIP)
  134. log_string('Learning rate:%f' % lr)
  135. for param_group in optimizer.param_groups:
  136. param_group['lr'] = lr
  137. momentum = MOMENTUM_ORIGINAL * (MOMENTUM_DECCAY ** (epoch // MOMENTUM_DECCAY_STEP))
  138. if momentum < 0.01:
  139. momentum = 0.01
  140. print('BN momentum updated to: %f' % momentum)
  141. classifier = classifier.apply(lambda x: bn_momentum_adjust(x,momentum))
  142. num_batches = len(trainDataLoader)
  143. total_correct = 0
  144. total_seen = 0
  145. loss_sum = 0
  146. for i, data in tqdm(enumerate(trainDataLoader), total=len(trainDataLoader), smoothing=0.9):
  147. points, target = data
  148. points = points.data.numpy()
  149. points[:,:, :3] = provider.rotate_point_cloud_z(points[:,:, :3])
  150. points = torch.Tensor(points)
  151. points, target = points.float().cuda(),target.long().cuda()
  152. points = points.transpose(2, 1)
  153. optimizer.zero_grad()
  154. classifier = classifier.train()
  155. seg_pred, trans_feat = classifier(points)
  156. seg_pred = seg_pred.contiguous().view(-1, NUM_CLASSES)
  157. batch_label = target.view(-1, 1)[:, 0].cpu().data.numpy()
  158. target = target.view(-1, 1)[:, 0]
  159. loss = criterion(seg_pred, target, trans_feat, weights)
  160. loss.backward()
  161. optimizer.step()
  162. pred_choice = seg_pred.cpu().data.max(1)[1].numpy()
  163. correct = np.sum(pred_choice == batch_label)
  164. total_correct += correct
  165. total_seen += (BATCH_SIZE * NUM_POINT)
  166. loss_sum += loss
  167. log_string('Training mean loss: %f' % (loss_sum / num_batches))
  168. log_string('Training accuracy: %f' % (total_correct / float(total_seen)))
  169. if epoch % 5 == 0:
  170. logger.info('Save model...')
  171. savepath = str(checkpoints_dir) + '/model.pth'
  172. log_string('Saving at %s' % savepath)
  173. state = {
  174. 'epoch': epoch,
  175. 'model_state_dict': classifier.state_dict(),
  176. 'optimizer_state_dict': optimizer.state_dict(),
  177. }
  178. torch.save(state, savepath)
  179. log_string('Saving model....')
  180. '''Evaluate on chopped scenes'''
  181. with torch.no_grad():
  182. num_batches = len(testDataLoader)
  183. total_correct = 0
  184. total_seen = 0
  185. loss_sum = 0
  186. labelweights = np.zeros(NUM_CLASSES)
  187. total_seen_class = [0 for _ in range(NUM_CLASSES)]
  188. total_correct_class = [0 for _ in range(NUM_CLASSES)]
  189. total_iou_deno_class = [0 for _ in range(NUM_CLASSES)]
  190. log_string('---- EPOCH %03d EVALUATION ----' % (global_epoch + 1))
  191. for i, data in tqdm(enumerate(testDataLoader), total=len(testDataLoader), smoothing=0.9):
  192. points, target = data
  193. points = points.data.numpy()
  194. points = torch.Tensor(points)
  195. points, target = points.float().cuda(), target.long().cuda()
  196. # device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
  197. # print("Using device:", device)
  198. # classifier = classifier.to(device)
  199. # points, target = points.float().to(device), target.long().to(device)
  200. points = points.transpose(2, 1)
  201. classifier = classifier.eval()
  202. seg_pred, trans_feat = classifier(points)
  203. pred_val = seg_pred.contiguous().cpu().data.numpy()
  204. seg_pred = seg_pred.contiguous().view(-1, NUM_CLASSES)
  205. batch_label = target.cpu().data.numpy()
  206. target = target.view(-1, 1)[:, 0]
  207. loss = criterion(seg_pred, target, trans_feat, weights)
  208. loss_sum += loss
  209. pred_val = np.argmax(pred_val, 2)
  210. correct = np.sum((pred_val == batch_label))
  211. total_correct += correct
  212. total_seen += (BATCH_SIZE * NUM_POINT)
  213. tmp, _ = np.histogram(batch_label, range(NUM_CLASSES + 1))
  214. labelweights += tmp
  215. for l in range(NUM_CLASSES):
  216. total_seen_class[l] += np.sum((batch_label == l) )
  217. total_correct_class[l] += np.sum((pred_val == l) & (batch_label == l) )
  218. total_iou_deno_class[l] += np.sum(((pred_val == l) | (batch_label == l)) )
  219. labelweights = labelweights.astype(np.float32) / np.sum(labelweights.astype(np.float32))
  220. mIoU = np.mean(np.array(total_correct_class) / (np.array(total_iou_deno_class, dtype=np.float) + 1e-6))
  221. log_string('eval mean loss: %f' % (loss_sum / float(num_batches)))
  222. log_string('eval point avg class IoU: %f' % (mIoU))
  223. log_string('eval point accuracy: %f' % (total_correct / float(total_seen)))
  224. log_string('eval point avg class acc: %f' % (
  225. np.mean(np.array(total_correct_class) / (np.array(total_seen_class, dtype=np.float) + 1e-6))))
  226. iou_per_class_str = '------- IoU --------\n'
  227. for l in range(NUM_CLASSES):
  228. iou_per_class_str += 'class %s weight: %.3f, IoU: %.3f \n' % (
  229. seg_label_to_cat[l] + ' ' * (14 - len(seg_label_to_cat[l])), labelweights[l - 1],
  230. total_correct_class[l] / float(total_iou_deno_class[l]))
  231. log_string(iou_per_class_str)
  232. log_string('Eval mean loss: %f' % (loss_sum / num_batches))
  233. log_string('Eval accuracy: %f' % (total_correct / float(total_seen)))
  234. if mIoU >= best_iou:
  235. best_iou = mIoU
  236. logger.info('Save model...')
  237. savepath = str(checkpoints_dir) + '/best_model.pth'
  238. log_string('Saving at %s' % savepath)
  239. state = {
  240. 'epoch': epoch,
  241. 'class_avg_iou': mIoU,
  242. 'model_state_dict': classifier.state_dict(),
  243. 'optimizer_state_dict': optimizer.state_dict(),
  244. }
  245. torch.save(state, savepath)
  246. log_string('Saving model....')
  247. log_string('Best mIoU: %f' % best_iou)
  248. global_epoch += 1
  249. if __name__ == '__main__':
  250. args = parse_args()
  251. main(args)

(4)test_cls.py

  1. from data_utils.ModelNetDataLoader import ModelNetDataLoader
  2. import argparse
  3. import numpy as np
  4. import os
  5. import torch
  6. import logging
  7. from tqdm import tqdm
  8. import sys
  9. import importlib
  10. BASE_DIR = os.path.dirname(os.path.abspath(__file__))
  11. ROOT_DIR = BASE_DIR
  12. sys.path.append(os.path.join(ROOT_DIR, 'models'))
  13. """
  14. 配置参数:
  15. --normal
  16. --log_dir pointnet2_cls_msg
  17. """
  18. def parse_args():
  19. '''PARAMETERS'''
  20. parser = argparse.ArgumentParser('PointNet')
  21. parser.add_argument('--batch_size', type=int, default=24, help='batch size in training')
  22. parser.add_argument('--gpu', type=str, default='0', help='specify gpu device')
  23. parser.add_argument('--num_point', type=int, default=1024, help='Point Number [default: 1024]')
  24. parser.add_argument('--log_dir', type=str, default='pointnet2_ssg_normal', help='Experiment root')
  25. parser.add_argument('--normal', action='store_true', default=True, help='Whether to use normal information [default: False]')
  26. parser.add_argument('--num_votes', type=int, default=3, help='Aggregate classification scores with voting [default: 3]')
  27. return parser.parse_args()
  28. def test(model, loader, num_class=40, vote_num=1):
  29. mean_correct = []
  30. class_acc = np.zeros((num_class,3))
  31. for j, data in tqdm(enumerate(loader), total=len(loader)):
  32. points, target = data
  33. target = target[:, 0]
  34. points = points.transpose(2, 1)
  35. points, target = points.cuda(), target.cuda()
  36. classifier = model.eval()
  37. vote_pool = torch.zeros(target.size()[0],num_class).cuda()
  38. for _ in range(vote_num):
  39. pred, _ = classifier(points)
  40. vote_pool += pred
  41. pred = vote_pool/vote_num
  42. pred_choice = pred.data.max(1)[1]
  43. for cat in np.unique(target.cpu()):
  44. classacc = pred_choice[target==cat].eq(target[target==cat].long().data).cpu().sum()
  45. class_acc[cat,0]+= classacc.item()/float(points[target==cat].size()[0])
  46. class_acc[cat,1]+=1
  47. correct = pred_choice.eq(target.long().data).cpu().sum()
  48. mean_correct.append(correct.item()/float(points.size()[0]))
  49. class_acc[:,2] = class_acc[:,0]/ class_acc[:,1]
  50. class_acc = np.mean(class_acc[:,2])
  51. instance_acc = np.mean(mean_correct)
  52. return instance_acc, class_acc
  53. def main(args):
  54. def log_string(str):
  55. logger.info(str)
  56. print(str)
  57. '''HYPER PARAMETER'''
  58. os.environ["CUDA_VISIBLE_DEVICES"] = args.gpu
  59. '''CREATE DIR'''
  60. experiment_dir = 'log/classification/' + args.log_dir
  61. '''LOG'''
  62. args = parse_args()
  63. logger = logging.getLogger("Model")
  64. logger.setLevel(logging.INFO)
  65. formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
  66. file_handler = logging.FileHandler('%s/eval.txt' % experiment_dir)
  67. file_handler.setLevel(logging.INFO)
  68. file_handler.setFormatter(formatter)
  69. logger.addHandler(file_handler)
  70. log_string('PARAMETER ...')
  71. log_string(args)
  72. '''DATA LOADING'''
  73. log_string('Load dataset ...')
  74. DATA_PATH = 'data/modelnet40_normal_resampled/'
  75. TEST_DATASET = ModelNetDataLoader(root=DATA_PATH, npoint=args.num_point, split='test', normal_channel=args.normal)
  76. testDataLoader = torch.utils.data.DataLoader(TEST_DATASET, batch_size=args.batch_size, shuffle=False, num_workers=4)
  77. '''MODEL LOADING'''
  78. num_class = 40
  79. model_name = os.listdir(experiment_dir+'/logs')[0].split('.')[0]
  80. MODEL = importlib.import_module(model_name)
  81. classifier = MODEL.get_model(num_class,normal_channel=args.normal).cuda()
  82. checkpoint = torch.load(str(experiment_dir) + '/checkpoints/best_model.pth')
  83. classifier.load_state_dict(checkpoint['model_state_dict'])
  84. with torch.no_grad():
  85. instance_acc, class_acc = test(classifier.eval(), testDataLoader, vote_num=args.num_votes)
  86. log_string('Test Instance Accuracy: %f, Class Accuracy: %f' % (instance_acc, class_acc))
  87. if __name__ == '__main__':
  88. args = parse_args()
  89. main(args)

(5)test_partseg.py

  1. """
  2. Author: Benny
  3. Date: Nov 2019
  4. """
  5. import argparse
  6. import os
  7. from data_utils.ShapeNetDataLoader import PartNormalDataset
  8. import torch
  9. import logging
  10. import sys
  11. import importlib
  12. from tqdm import tqdm
  13. import numpy as np
  14. BASE_DIR = os.path.dirname(os.path.abspath(__file__))
  15. ROOT_DIR = BASE_DIR
  16. sys.path.append(os.path.join(ROOT_DIR, 'models'))
  17. seg_classes = {'Earphone': [16, 17, 18], 'Motorbike': [30, 31, 32, 33, 34, 35], 'Rocket': [41, 42, 43], 'Car': [8, 9, 10, 11], 'Laptop': [28, 29], 'Cap': [6, 7], 'Skateboard': [44, 45, 46], 'Mug': [36, 37], 'Guitar': [19, 20, 21], 'Bag': [4, 5], 'Lamp': [24, 25, 26, 27], 'Table': [47, 48, 49], 'Airplane': [0, 1, 2, 3], 'Pistol': [38, 39, 40], 'Chair': [12, 13, 14, 15], 'Knife': [22, 23]}
  18. seg_label_to_cat = {} # {0:Airplane, 1:Airplane, ...49:Table}
  19. for cat in seg_classes.keys():
  20. for label in seg_classes[cat]:
  21. seg_label_to_cat[label] = cat
  22. def to_categorical(y, num_classes):
  23. """ 1-hot encodes a tensor """
  24. new_y = torch.eye(num_classes)[y.cpu().data.numpy(),]
  25. if (y.is_cuda):
  26. return new_y.cuda()
  27. return new_y
  28. def parse_args():
  29. '''PARAMETERS'''
  30. parser = argparse.ArgumentParser('PointNet')
  31. parser.add_argument('--batch_size', type=int, default=24, help='batch size in testing [default: 24]')
  32. parser.add_argument('--gpu', type=str, default='0', help='specify gpu device [default: 0]')
  33. # parser.add_argument('--device', default='', help='cuda device, i.e. 0 or 0,1,2,3 or cpu')
  34. parser.add_argument('--num_point', type=int, default=2048, help='Point Number [default: 2048]')
  35. parser.add_argument('--log_dir', type=str, default='pointnet2_part_seg_ssg', help='Experiment root')
  36. # parser.add_argument('--log_dir', type=str, default='visual', help='Experiment root')
  37. parser.add_argument('--normal', action='store_true', default=False, help='Whether to use normal information [default: False]')
  38. parser.add_argument('--num_votes', type=int, default=3, help='Aggregate segmentation scores with voting [default: 3]')
  39. return parser.parse_args()
  40. def main(args):
  41. def log_string(str):
  42. logger.info(str)
  43. print(str)
  44. '''HYPER PARAMETER'''
  45. os.environ["CUDA_VISIBLE_DEVICES"] = args.gpu
  46. experiment_dir = 'log/part_seg/' + args.log_dir
  47. '''LOG'''
  48. args = parse_args()
  49. logger = logging.getLogger("Model")
  50. logger.setLevel(logging.INFO)
  51. formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
  52. file_handler = logging.FileHandler('%s/eval.txt' % experiment_dir)
  53. file_handler.setLevel(logging.INFO)
  54. file_handler.setFormatter(formatter)
  55. logger.addHandler(file_handler)
  56. log_string('PARAMETER ...')
  57. log_string(args)
  58. root = 'data/shapenetcore_partanno_segmentation_benchmark_v0_normal/'
  59. TEST_DATASET = PartNormalDataset(root = root, npoints=args.num_point, split='test', normal_channel=args.normal)
  60. testDataLoader = torch.utils.data.DataLoader(TEST_DATASET, batch_size=args.batch_size,shuffle=False, num_workers=4)
  61. log_string("The number of test data is: %d" % len(TEST_DATASET))
  62. num_classes = 16
  63. num_part = 50
  64. '''MODEL LOADING'''
  65. model_name = os.listdir(experiment_dir+'/logs')[0].split('.')[0]
  66. MODEL = importlib.import_module(model_name)
  67. classifier = MODEL.get_model(num_part, normal_channel=args.normal).cuda()
  68. checkpoint = torch.load(str(experiment_dir) + '/checkpoints/best_model.pth')
  69. classifier.load_state_dict(checkpoint['model_state_dict'])
  70. with torch.no_grad():
  71. test_metrics = {}
  72. total_correct = 0
  73. total_seen = 0
  74. total_seen_class = [0 for _ in range(num_part)]
  75. total_correct_class = [0 for _ in range(num_part)]
  76. shape_ious = {cat: [] for cat in seg_classes.keys()}
  77. seg_label_to_cat = {} # {0:Airplane, 1:Airplane, ...49:Table}
  78. for cat in seg_classes.keys():
  79. for label in seg_classes[cat]:
  80. seg_label_to_cat[label] = cat
  81. for batch_id, (points, label, target) in tqdm(enumerate(testDataLoader), total=len(testDataLoader), smoothing=0.9):
  82. batchsize, num_point, _ = points.size()
  83. cur_batch_size, NUM_POINT, _ = points.size()
  84. points, label, target = points.float().cuda(), label.long().cuda(), target.long().cuda()
  85. points = points.transpose(2, 1)
  86. classifier = classifier.eval()
  87. vote_pool = torch.zeros(target.size()[0], target.size()[1], num_part).cuda()
  88. for _ in range(args.num_votes):
  89. seg_pred, _ = classifier(points, to_categorical(label, num_classes))
  90. vote_pool += seg_pred
  91. seg_pred = vote_pool / args.num_votes
  92. cur_pred_val = seg_pred.cpu().data.numpy()
  93. cur_pred_val_logits = cur_pred_val
  94. cur_pred_val = np.zeros((cur_batch_size, NUM_POINT)).astype(np.int32)
  95. target = target.cpu().data.numpy()
  96. for i in range(cur_batch_size):
  97. cat = seg_label_to_cat[target[i, 0]]
  98. logits = cur_pred_val_logits[i, :, :]
  99. cur_pred_val[i, :] = np.argmax(logits[:, seg_classes[cat]], 1) + seg_classes[cat][0]
  100. correct = np.sum(cur_pred_val == target)
  101. total_correct += correct
  102. total_seen += (cur_batch_size * NUM_POINT)
  103. for l in range(num_part):
  104. total_seen_class[l] += np.sum(target == l)
  105. total_correct_class[l] += (np.sum((cur_pred_val == l) & (target == l)))
  106. for i in range(cur_batch_size):
  107. segp = cur_pred_val[i, :]
  108. segl = target[i, :]
  109. cat = seg_label_to_cat[segl[0]]
  110. part_ious = [0.0 for _ in range(len(seg_classes[cat]))]
  111. for l in seg_classes[cat]:
  112. if (np.sum(segl == l) == 0) and (
  113. np.sum(segp == l) == 0): # part is not present, no prediction as well
  114. part_ious[l - seg_classes[cat][0]] = 1.0
  115. else:
  116. part_ious[l - seg_classes[cat][0]] = np.sum((segl == l) & (segp == l)) / float(
  117. np.sum((segl == l) | (segp == l)))
  118. shape_ious[cat].append(np.mean(part_ious))
  119. all_shape_ious = []
  120. for cat in shape_ious.keys():
  121. for iou in shape_ious[cat]:
  122. all_shape_ious.append(iou)
  123. shape_ious[cat] = np.mean(shape_ious[cat])
  124. mean_shape_ious = np.mean(list(shape_ious.values()))
  125. test_metrics['accuracy'] = total_correct / float(total_seen)
  126. test_metrics['class_avg_accuracy'] = np.mean(
  127. np.array(total_correct_class) / np.array(total_seen_class, dtype=np.float))
  128. for cat in sorted(shape_ious.keys()):
  129. log_string('eval mIoU of %s %f' % (cat + ' ' * (14 - len(cat)), shape_ious[cat]))
  130. test_metrics['class_avg_iou'] = mean_shape_ious
  131. test_metrics['inctance_avg_iou'] = np.mean(all_shape_ious)
  132. log_string('Accuracy is: %.5f'%test_metrics['accuracy'])
  133. log_string('Class avg accuracy is: %.5f'%test_metrics['class_avg_accuracy'])
  134. log_string('Class avg mIOU is: %.5f'%test_metrics['class_avg_iou'])
  135. log_string('Inctance avg mIOU is: %.5f'%test_metrics['inctance_avg_iou'])
  136. if __name__ == '__main__':
  137. args = parse_args()
  138. main(args)

(6)test_semseg.py

  1. """
  2. Author: Benny
  3. Date: Nov 2019
  4. """
  5. import argparse
  6. import os
  7. from data_utils.S3DISDataLoader import ScannetDatasetWholeScene
  8. from data_utils.indoor3d_util import g_label2color
  9. import torch
  10. import logging
  11. from pathlib import Path
  12. import sys
  13. import importlib
  14. from tqdm import tqdm
  15. import provider
  16. import numpy as np
  17. BASE_DIR = os.path.dirname(os.path.abspath(__file__))
  18. ROOT_DIR = BASE_DIR
  19. sys.path.append(os.path.join(ROOT_DIR, 'models'))
  20. classes = ['ceiling','floor','wall','beam','column','window','door','table','chair','sofa','bookcase','board','clutter']
  21. class2label = {cls: i for i,cls in enumerate(classes)}
  22. seg_classes = class2label
  23. seg_label_to_cat = {}
  24. for i,cat in enumerate(seg_classes.keys()):
  25. seg_label_to_cat[i] = cat
  26. def parse_args():
  27. '''PARAMETERS'''
  28. parser = argparse.ArgumentParser('Model')
  29. parser.add_argument('--batch_size', type=int, default=32, help='batch size in testing [default: 32]')
  30. parser.add_argument('--gpu', type=str, default='0', help='specify gpu device')
  31. parser.add_argument('--num_point', type=int, default=4096, help='Point Number [default: 4096]')
  32. parser.add_argument('--log_dir', type=str, default='pointnet2_sem_seg', help='Experiment root')
  33. parser.add_argument('--visual', action='store_true', default=True, help='Whether visualize result [default: False]')
  34. parser.add_argument('--test_area', type=int, default=5, help='Which area to use for test, option: 1-6 [default: 5]')
  35. parser.add_argument('--num_votes', type=int, default=5, help='Aggregate segmentation scores with voting [default: 5]')
  36. return parser.parse_args()
  37. def add_vote(vote_label_pool, point_idx, pred_label, weight):
  38. B = pred_label.shape[0]
  39. N = pred_label.shape[1]
  40. for b in range(B):
  41. for n in range(N):
  42. if weight[b,n]:
  43. vote_label_pool[int(point_idx[b, n]), int(pred_label[b, n])] += 1
  44. return vote_label_pool
  45. def main(args):
  46. def log_string(str):
  47. logger.info(str)
  48. print(str)
  49. '''HYPER PARAMETER'''
  50. os.environ["CUDA_VISIBLE_DEVICES"] = args.gpu
  51. experiment_dir = 'log/sem_seg/' + args.log_dir
  52. visual_dir = experiment_dir + '/visual/'
  53. visual_dir = Path(visual_dir)
  54. visual_dir.mkdir(exist_ok=True)
  55. '''LOG'''
  56. args = parse_args()
  57. logger = logging.getLogger("Model")
  58. logger.setLevel(logging.INFO)
  59. formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
  60. file_handler = logging.FileHandler('%s/eval.txt' % experiment_dir)
  61. file_handler.setLevel(logging.INFO)
  62. file_handler.setFormatter(formatter)
  63. logger.addHandler(file_handler)
  64. log_string('PARAMETER ...')
  65. log_string(args)
  66. NUM_CLASSES = 13
  67. BATCH_SIZE = args.batch_size
  68. NUM_POINT = args.num_point
  69. root = 'data/stanford_indoor3d/'
  70. TEST_DATASET_WHOLE_SCENE = ScannetDatasetWholeScene(root, split='test', test_area=args.test_area, block_points=NUM_POINT)
  71. log_string("The number of test data is: %d" % len(TEST_DATASET_WHOLE_SCENE))
  72. '''MODEL LOADING'''
  73. model_name = os.listdir(experiment_dir+'/logs')[0].split('.')[0]
  74. MODEL = importlib.import_module(model_name)
  75. classifier = MODEL.get_model(NUM_CLASSES).cuda()
  76. checkpoint = torch.load(str(experiment_dir) + '/checkpoints/best_model.pth')
  77. classifier.load_state_dict(checkpoint['model_state_dict'])
  78. with torch.no_grad():
  79. scene_id = TEST_DATASET_WHOLE_SCENE.file_list
  80. scene_id = [x[:-4] for x in scene_id]
  81. num_batches = len(TEST_DATASET_WHOLE_SCENE)
  82. total_seen_class = [0 for _ in range(NUM_CLASSES)]
  83. total_correct_class = [0 for _ in range(NUM_CLASSES)]
  84. total_iou_deno_class = [0 for _ in range(NUM_CLASSES)]
  85. log_string('---- EVALUATION WHOLE SCENE----')
  86. for batch_idx in range(num_batches):
  87. print("visualize [%d/%d] %s ..." % (batch_idx+1, num_batches, scene_id[batch_idx]))
  88. total_seen_class_tmp = [0 for _ in range(NUM_CLASSES)]
  89. total_correct_class_tmp = [0 for _ in range(NUM_CLASSES)]
  90. total_iou_deno_class_tmp = [0 for _ in range(NUM_CLASSES)]
  91. if args.visual:
  92. fout = open(os.path.join(visual_dir, scene_id[batch_idx] + '_pred.obj'), 'w')
  93. fout_gt = open(os.path.join(visual_dir, scene_id[batch_idx] + '_gt.obj'), 'w')
  94. whole_scene_data = TEST_DATASET_WHOLE_SCENE.scene_points_list[batch_idx]
  95. whole_scene_label = TEST_DATASET_WHOLE_SCENE.semantic_labels_list[batch_idx]
  96. vote_label_pool = np.zeros((whole_scene_label.shape[0], NUM_CLASSES))
  97. for _ in tqdm(range(args.num_votes), total=args.num_votes):
  98. scene_data, scene_label, scene_smpw, scene_point_index = TEST_DATASET_WHOLE_SCENE[batch_idx]
  99. num_blocks = scene_data.shape[0]
  100. s_batch_num = (num_blocks + BATCH_SIZE - 1) // BATCH_SIZE
  101. batch_data = np.zeros((BATCH_SIZE, NUM_POINT, 9))
  102. batch_label = np.zeros((BATCH_SIZE, NUM_POINT))
  103. batch_point_index = np.zeros((BATCH_SIZE, NUM_POINT))
  104. batch_smpw = np.zeros((BATCH_SIZE, NUM_POINT))
  105. for sbatch in range(s_batch_num):
  106. start_idx = sbatch * BATCH_SIZE
  107. end_idx = min((sbatch + 1) * BATCH_SIZE, num_blocks)
  108. real_batch_size = end_idx - start_idx
  109. batch_data[0:real_batch_size, ...] = scene_data[start_idx:end_idx, ...]
  110. batch_label[0:real_batch_size, ...] = scene_label[start_idx:end_idx, ...]
  111. batch_point_index[0:real_batch_size, ...] = scene_point_index[start_idx:end_idx, ...]
  112. batch_smpw[0:real_batch_size, ...] = scene_smpw[start_idx:end_idx, ...]
  113. batch_data[:, :, 3:6] /= 1.0
  114. torch_data = torch.Tensor(batch_data)
  115. torch_data= torch_data.float().cuda()
  116. torch_data = torch_data.transpose(2, 1)
  117. seg_pred, _ = classifier(torch_data)
  118. batch_pred_label = seg_pred.contiguous().cpu().data.max(2)[1].numpy()
  119. vote_label_pool = add_vote(vote_label_pool, batch_point_index[0:real_batch_size, ...],
  120. batch_pred_label[0:real_batch_size, ...],
  121. batch_smpw[0:real_batch_size, ...])
  122. pred_label = np.argmax(vote_label_pool, 1)
  123. for l in range(NUM_CLASSES):
  124. total_seen_class_tmp[l] += np.sum((whole_scene_label == l))
  125. total_correct_class_tmp[l] += np.sum((pred_label == l) & (whole_scene_label == l))
  126. total_iou_deno_class_tmp[l] += np.sum(((pred_label == l) | (whole_scene_label == l)))
  127. total_seen_class[l] += total_seen_class_tmp[l]
  128. total_correct_class[l] += total_correct_class_tmp[l]
  129. total_iou_deno_class[l] += total_iou_deno_class_tmp[l]
  130. iou_map = np.array(total_correct_class_tmp) / (np.array(total_iou_deno_class_tmp, dtype=np.float64) + 1e-6)
  131. print(iou_map)
  132. arr = np.array(total_seen_class_tmp)
  133. tmp_iou = np.mean(iou_map[arr != 0])
  134. log_string('Mean IoU of %s: %.4f' % (scene_id[batch_idx], tmp_iou))
  135. print('----------------------------')
  136. filename = os.path.join(visual_dir, scene_id[batch_idx] + '.txt')
  137. with open(filename, 'w') as pl_save:
  138. for i in pred_label:
  139. pl_save.write(str(int(i)) + '\n')
  140. pl_save.close()
  141. for i in range(whole_scene_label.shape[0]):
  142. color = g_label2color[pred_label[i]]
  143. color_gt = g_label2color[whole_scene_label[i]]
  144. if args.visual:
  145. fout.write('v %f %f %f %d %d %d\n' % (
  146. whole_scene_data[i, 0], whole_scene_data[i, 1], whole_scene_data[i, 2], color[0], color[1],
  147. color[2]))
  148. fout_gt.write(
  149. 'v %f %f %f %d %d %d\n' % (
  150. whole_scene_data[i, 0], whole_scene_data[i, 1], whole_scene_data[i, 2], color_gt[0],
  151. color_gt[1], color_gt[2]))
  152. if args.visual:
  153. fout.close()
  154. fout_gt.close()
  155. IoU = np.array(total_correct_class) / (np.array(total_iou_deno_class, dtype=np.float) + 1e-6)
  156. iou_per_class_str = '------- IoU --------\n'
  157. for l in range(NUM_CLASSES):
  158. iou_per_class_str += 'class %s, IoU: %.3f \n' % (
  159. seg_label_to_cat[l] + ' ' * (14 - len(seg_label_to_cat[l])),
  160. total_correct_class[l] / float(total_iou_deno_class[l]))
  161. log_string(iou_per_class_str)
  162. log_string('eval point avg class IoU: %f' % np.mean(IoU))
  163. log_string('eval whole scene point avg class acc: %f' % (
  164. np.mean(np.array(total_correct_class) / (np.array(total_seen_class, dtype=np.float) + 1e-6))))
  165. log_string('eval whole scene point accuracy: %f' % (
  166. np.sum(total_correct_class) / float(np.sum(total_seen_class) + 1e-6)))
  167. print("Done!")
  168. if __name__ == '__main__':
  169. args = parse_args()
  170. main(args)

上面这些都是调整好的代码应该是可以直接跑通的,如果哪个程序有问题可以粘贴我的程序过去试一试,注意一些文件路径要修改成自己的

三、复现过程中遇到的问题总结

(1)首先把下面这些文件夹依次打开,你会发现导入的包被标红,因为路径不对

将下面

from pointnet import PointNetEncoder, feature_transform_reguliarzer

修改为

from models.pointnet import PointNetEncoder, feature_transform_reguliarzer

models.是包含pointnet.py的文件夹,也就是说要精确到文件所在文件夹,系统才能正确找到,不报错,其他的脚本遇到这种情况类似处理

(2)报错:AttributeError: module ‘numpy‘ has no attribute ‘float‘

出现这个问题的原因是:从numpy1.24起删除了numpy.bool、numpy.int、numpy.float、numpy.complex、numpy.object、numpy.str、numpy.long、numpy.unicode类型的支持。解决上诉问题主要有两种方法:

方法一:修改numpy版本

安装numpy1.24之前的版本

  1. pip uninstall numpy
  2. pip install numpy==1.23.5

方法二:修改代码

可以用python内置类型或者np.ndarray类型替换:np.float替换为float或者np.float64/np.float32

参考链接:AttributeError: module ‘numpy‘ has no attribute ‘float‘

(3)报错:

choice = np.random.choice(len(point_set.shape[0]), npoints, replace=True) TypeError: object of type 'int' has no len()

 choice = np.random.choice(len(point_set.shape[0]), npoints, replace=True)

替换为

choice = np.random.choice(point_set.shape[0], npoints, replace=True)

(4)报错:

return F.conv1d(input, weight, bias, self.stride, RuntimeError: Given groups=1, weight of size [64, 6, 1], expected input[16, 9, 4096] to have 6 channels, but got 9 channels instead

上面是复现时运行train_semseg.py报错RuntimeError:

  • 该个错误主要是因为S3DIS数据集的数据具有9个通道,涉及xyz、rgb和归一化XYZ。但是代码仅支持 3 或 6 个通道。要解决此问题,应进行一些小的修改。

1 pointnet_sem_seg.py;通过添加 if来考虑通道 =9 的情况。with_normalized_xyz params

  1. class get_model(nn.Module):
  2. def __init__(self, num_class, with_rgb=True, with_normalized_xyz=True):
  3. super(get_model, self).__init__()
  4. if with_rgb:
  5. channel = 6
  6. if with_normalized_xyz:
  7. channel= 9
  8. else:
  9. ...

2 pointnet.py;更改 PointNetEncoder 的前向方法,稍微修改拆分方法

  1. def forward(self, x):
  2. B, D, N = x.size() # batchsize,3(xyz坐标)或6(xyz坐标+法向量),1024(一个物体所取的点的数目)
  3. trans = self.stn(x) # STN3d T-Net
  4. x = x.transpose(2, 1) # 交换一个tensor的两个维度
  5. if D >3 :
  6. # x, feature = x.split(3,dim=2)
  7. x, feature = x.split([3,D-3],dim=2)

3 这样就可以解决S3DIS数据集在pointnet++训练时的场景分割报错了。

参考自:pointnet++复现时运行train_semseg.py报错RuntimeError:

(5)报错

return open(self.baseFilename, self.mode, encoding=self.encoding)

PermissionError: [Errno 13] Permission denied: 'D:\\cs\\Pointnet2\\log\\part_seg\\pointnet2_part_seg_ssg\\eval.txt'

model_name = os.listdir(experiment_dir+'/logs')[0].split('.')[0]

IndexError: list index out of range

这是因为该路径下没有这个名称的文件夹或者文件夹名称不对,我一开始就是文件夹名字写错了,应该是ssg我写成了msg所以一直报错

要有这个文件夹

文件夹里要有这些文件

如果没有的话可以从以往的2024-01-06_22-21记录中复制过来,实在不行建立内容为空的文件,但是一定要让系统在搜索路径的时候能找到

(6)FileNotFoundError: [WinError 3] 系统找不到指定的路径的解决方法

判断文件的父子目录设置是否正确

可参考:FileNotFoundError: [WinError 3] 系统找不到指定的路径。的解决方法

(7)self = reduction.pickle.load(from_parent) EOFError: Ran out of input的解决方法

这是在运行train_semseg.py程序时遇到的错误

将num_workers改为0即可

修改前

修改后

参考:self = reduction.pickle.load(from_parent) EOFError: Ran out of input的解决方法

(8)报错

    rooms = sorted(os.listdir(data_root))
FileNotFoundError: [WinError 3] 系统找不到指定的路径。: 'data/stanford_indoor3d/'

这是因为我们的data文件夹里还没有stanford_indoor3d这个文件夹,这是个数据集,需要我们先运行个脚本生成

下载 3D indoor parsing dataset ( S3DIS ) 数据集 Stanford3dDataset_v1.2_Aligned_Version.zip 并解压 到 data/s3dis/Stanford3dDataset_v1.2_Aligned_Version/ ,首先需要进行的是预处理工作:
 

  1. cd data_utils
  2. python collect_indoor3d_data.py

或者在Pycharm中运行

报错原因是我们没有建立s3dis文件夹,并将Stanford3dDataset_v1.2_Aligned_Version放入其中所以脚本运行时找不到路径,文件夹像下面这样处理

然后再运行collect_indoor3d_data.py就成功了,如下图所示

此时我们在回到 data/s3dis/Stanford3dDataset_v1.2_Aligned_Version/文件夹会发现多了好多npy文件

而我们的stanford_indoor3d文件夹里是空的,但是后续模型数据集的加载又是来自这个文件夹,因此将所有的npy文件复制到stanford_indoor3d文件夹中

现在此时data文件夹里的目录结构是下面这样的

再回来运行train_semseg.py程序就可以了,可能会遇到上面提到的(4)和(7)的报错,对应上面方法就可以解决,成功截图如下:

先训练,训练完才能用test_semseg.py进行测试,测试结果是可以进行可视化的,只需要把test_semseg.py中,visual的default的参数值改为True就可以生成obj文件,然后可以用CloudCompare软件进行可视化

注意,我们网盘下载下来的文件里没有visual,我们要自己建立,否则会因找不到文件路径而报错,目录结构如下,如果缺少eval.txt或其他文件夹,仿着classification建好

运行其他的也是,如果找不到路径就缺啥见啥或检查路径和文件名对不对

参考自:Pointnet++环境配置+复现

(9)visualizer文件中有个show3d_balls.py文件,适用于可视化的,官方链接里的README有提到,但是用到的一些so文件,是ubuntu里的命令文件,如果想在windows下能运行,需要重新改写。

1、win10系统下build.sh文件运行问题

安装git–>安装g++

安装git:https://so.csdn.net/so/search?q=%E5%AE%89%E8%A3%85git&t=&u=

安装g++: MinGW下载和安装教程

可通过linux系统或者已安装的git中bash环境运行build.sh脚本
安装完毕g++之后可通过sh build.sh运行,见上图

2、win10系统下download_data.sh文件运行问题

该文件位于链接https://github.com/KuangenZhang/ldgcnn的part_seg的文件夹下

对于sh download_data运行问题的错误,主要原因为Issued certificate has expired,win10系统下解决方案为:通过记事本打开sh文件,wget指令后添加–no-check-certificate
若显示无–no-check-certificate参数,参考https://blog.csdn.net/topsogn/article/details/121217646?spm=1001.2014.3001.5501

  1. def download():
  2. BASE_DIR = os.path.dirname(os.path.abspath(__file__))
  3. DATA_DIR = os.path.join(BASE_DIR, 'data')
  4. if not os.path.exists(DATA_DIR):
  5. os.mkdir(DATA_DIR)
  6. if not os.path.exists(os.path.join(DATA_DIR, 'modelnet40_ply_hdf5_2048')):
  7. www = 'https://shapenet.cs.stanford.edu/media/modelnet40_ply_hdf5_2048.zip'
  8. zipfile = os.path.basename(www)
  9. os.system('wget --no-check-certificate %s' % (www))
  10. os.system('unzip %s' % (zipfile))
  11. os.system('mv %s %s' % (zipfile[:-4], DATA_DIR))
  12. os.system('rm %s' % (zipfile))

若显示unzip不是内部或外部命令,也不是可运行的程序或批处理文件。则可通过在系统环境变量中添加windows下的zip.exe和unzip.exe的路径

3、 raise OSError(“no file with expected extension”)问题
在运行PointNet的可视化程序时,作者只提供了linux平台下的动态链接库程序源码,自己的windows平台下无法调用。发现是动态链接库的文件格式不对,遂学习如何将.so文件转换成.dll文件
3.1 安装viusal studio

3.2 新建C++动态链接库项目

3.3 修改头文件pch.h
  1. #ifndef PCH_H
  2. #define PCH_H
  3. // 添加要在此处预编译的标头
  4. #include "framework.h"
  5. #endif //PCH_H
  6. //定义宏
  7. #ifdef IMPORT_DLL
  8. #else
  9. #define IMPORT_DLL extern "C" _declspec(dllimport) //指的是允许将其给外部调用
  10. #endif
  11. // 改为你所需要的链接库函数
  12. IMPORT_DLL void render_ball(int h, int w, unsigned char* show, int n, int* xyzs, float* c0, float* c1, float* c2, int r);

3.4 重写dllmain.cpp文件
  1. // dllmain.cpp : 定义 DLL 应用程序的入口点。
  2. #include "pch.h"
  3. #include <cstdio>
  4. #include <vector>
  5. #include <algorithm>
  6. #include <math.h>
  7. using namespace std;
  8. struct PointInfo {
  9. int x, y, z;
  10. float r, g, b;
  11. };
  12. void render_ball(int h, int w, unsigned char* show, int n, int* xyzs, float* c0, float* c1, float* c2, int r) {
  13. r = max(r, 1);
  14. vector<int> depth(h * w, -2100000000);
  15. vector<PointInfo> pattern;
  16. for (int dx = -r; dx <= r; dx++)
  17. for (int dy = -r; dy <= r; dy++)
  18. if (dx * dx + dy * dy < r * r) {
  19. double dz = sqrt(double(r * r - dx * dx - dy * dy));
  20. PointInfo pinfo;
  21. pinfo.x = dx;
  22. pinfo.y = dy;
  23. pinfo.z = dz;
  24. pinfo.r = dz / r;
  25. pinfo.g = dz / r;
  26. pinfo.b = dz / r;
  27. pattern.push_back(pinfo);
  28. }
  29. double zmin = 0, zmax = 0;
  30. for (int i = 0; i < n; i++) {
  31. if (i == 0) {
  32. zmin = xyzs[i * 3 + 2] - r;
  33. zmax = xyzs[i * 3 + 2] + r;
  34. }
  35. else {
  36. zmin = min(zmin, double(xyzs[i * 3 + 2] - r));
  37. zmax = max(zmax, double(xyzs[i * 3 + 2] + r));
  38. }
  39. }
  40. for (int i = 0; i < n; i++) {
  41. int x = xyzs[i * 3 + 0], y = xyzs[i * 3 + 1], z = xyzs[i * 3 + 2];
  42. for (int j = 0; j<int(pattern.size()); j++) {
  43. int x2 = x + pattern[j].x;
  44. int y2 = y + pattern[j].y;
  45. int z2 = z + pattern[j].z;
  46. if (!(x2 < 0 || x2 >= h || y2 < 0 || y2 >= w) && depth[x2 * w + y2] < z2) {
  47. depth[x2 * w + y2] = z2;
  48. double intensity = min(1.0, (z2 - zmin) / (zmax - zmin) * 0.7 + 0.3);
  49. show[(x2 * w + y2) * 3 + 0] = pattern[j].b * c2[i] * intensity;
  50. show[(x2 * w + y2) * 3 + 1] = pattern[j].g * c0[i] * intensity;
  51. show[(x2 * w + y2) * 3 + 2] = pattern[j].r * c1[i] * intensity;
  52. }
  53. }
  54. }
  55. }
  56. // 具体内容改为你的文件内容

转载链接:https://blog.csdn.net/Moringstarluc/article/details/105702543

注: 若pycharm调试时出现OSError: [WinError 193] %1 不是有效的 Win32 应用程序 的问题

原因为visual调试时的 配置: Debug Win32,需修改为Win64,解决方案见下图,修改为x64即可

(10)报错

FileNotFoundError: [Errno 2] No such file or directory: 'E:\\临时

\\Pointnet2\\log\\part_seg\\pointnet2_part_seg_ssg\\eval.txt'

这个就是运行test_partseg.py报的错,原因是原文件家里有一个pointnet2_part_seg_msg的文件夹而我们这里找的是pointnet2_part_seg_ssg文件夹,因此我们要自己建立,结构如下

然后再运行就可以了

(11)报错

FileNotFoundError: [WinError 3] 系统找不到指定的路径。: 'log\\sem_seg\\pointnet2_sem_seg\\visual'

这是运行test_semseg,py找不到文件,做法类似于上面建立文件夹,后续如何用test_semseg,py前面已经介绍

(12)最先开始遇到的错误是,运行train_cls.py遇到的报错

(1)
    return forward_call(*input, **kwargs)
TypeError: forward() missing 1 required positional argument: 'cls_label'
 

一开始查这个问题,一直没有解决掉,后面按照(4)进行修改后,报错变成下面这样了

    print(points.shape) #第三次:[8,128,640],640个特征
AttributeError: 'NoneType' object has no attribute 'shape'

问题在pointnet_util.py这里

  1. if points is not None:
  2. points = points.permute(0, 2, 1)
  3. print(points.shape) #第三次:[8,128,640],640个特征

改为

  1. if points is not None:
  2. points = points.permute(0, 2, 1)
  3. print(points.shape) #第三次:[8,128,640],640个特征

即把print朝里面缩进一下,然后就可以正常跑了

至此,所有程序就都可以正常跑了,复现完成!

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家自动化/article/detail/519244
推荐阅读
相关标签
  

闽ICP备14008679号