迫于毕业要求,本人转战点云分割。从今天开始更新。
Pointnext文件结构
PointNeXt/
├── cfgs 配置文件
│ ├── default.yaml 所有数据集的公共父类配置文件
│ ├── modelnet40ply2048
│ ├── s3dis
│ ├── s3dis_pix4point
│ ├── scannet
│ ├── scanobjectnn
│ ├── scanobjectnn_pix4point
│ ├── shapenetpart
│ └── shapenetpart_pix4point
├── data 数据集 下载后的数据集放在这里
│ ├── S3DIS
│ └── s3disfull.tar
├── docs 这里存放一些文档
│ ├── changes.md 作者所做的更改和将要做的事情
│ ├── examples 如何下载数据集
│ ├── index.md 这里介绍了openpoints 的基础用法和基本情况介绍
│ ├── misc
│ ├── modelzoo.md
│ └── projects
├── examples 任务
│ ├── classification 分类
│ ├── __init__.py
│ ├── profile.py 修改配置文件
│ ├── segmentation 分割
│ └── shapenetpart 部件分割
├── install.sh
├── LICENSE
├── log 日志文件
│ └── s3dis
├── mkdocs.yml
├── openpoints 开源点云
│ ├── cpp
│ ├── dataset 数据集处理
│ ├── __init__.py
│ ├── loss 自定义损失函数
│ ├── models 自定义模型
│ ├── optim 自定义优化
│ ├── __pycache__
│ ├── README.md
│ ├── scheduler 自定义学习率调度
│ ├── transforms 自定义数据变化
│ └── utils
├── pretrained
│ └── s3dis
├── README.md
├── requirements.txt
├── results
│ └── s3dis
├── script
│ ├── download_s3dis.sh
│ ├── main_classification.sh
│ ├── main_partseg.sh
│ ├── main_segmentation.sh
│ ├── profile_flops.sh
│ └── test_all_in_one.sh
├── slurm_logs
└── update.sh
初步了解了pointnext文件架构
因为主要是完成点云分割的任务,下面阅读一下
segmentation 下的main.py
examples/
├── classification
│ ├── __init__.py
│ ├── main.py
│ ├── pretrain.py
│ └── train.py
├── __init__.py
├── profile.py
├── segmentation
│ ├── __init__.py
│ ├── main_debug.py
│ ├── main.py
│ ├── __pycache__
│ │ ├── __init__.cpython-37.pyc
│ │ └── __init__.cpython-38.pyc
│ ├── test_s3dis_6fold.py
│ └── vis_results.py
└── shapenetpart
├── __init__.py
└── main.py
segmentation.main.py
流程图
主程序流程图
流程比较简单主要 进行config初始化。
代码注释
if __name__ == "__main__":
parser = argparse.ArgumentParser('Scene segmentation training/testing')#创建一个参数解析器
parser.add_argument('--cfg', type=str, required=True, help='config file')#加载命令行--config后面的参数 config 必须要
parser.add_argument('--profile', action='store_true', default=False, help='set to True to profile speed')#启动性能分析,修改yaml配置文件
#默认已知参数
args, opts = parser.parse_known_args()
#args Namespace(cfg='cfgs/s3dis/pointnext-xl.yaml', profile=False) args 是一个命名空间namespace
# print (Namespace(cfg='cfgs/s3dis/pointnet.yaml', profile=False), [])
#opts = []为空
# args.cfg = 'cfgs/s3dis/pointnext-xl.yaml'
# args.profile = False
#opts = ["mode = train"]
cfg = EasyConfig()#创建一个easyconfig 对象
cfg.load(args.cfg, recursive=True) #load cfg from yaml 第一个参数是yanl的地址 第二个参数调用默认的default.yaml
# 加载配置文件
cfg.update(opts) # overwrite the default arguments in yml 重写default.yaml
# 更新配置文件
#当前 cfg 有51个参数 到末尾 我们可以看看cfg有多少个参数
#设置随机种子 pointnext没有设置随机种子 cfg.seed = None
if cfg.seed is None:
cfg.seed = np.random.randint(1, 10000)
# rank 当前好似用的是gpu0 则rank 为0 world_size 为gpu总个数
#用于初始化分布式训练相关参数
# init distributed env first, since logger depends on the dist info.
cfg.rank, cfg.world_size, cfg.distributed, cfg.mp = dist_utils.get_dist_info(cfg)
cfg.sync_bn = cfg.world_size > 1 #不使用同步批量正则化
# init log dir 初始化日志目录
# args.cfg = 'cfgs/s3dis/pointnext-xl.yaml'
# args.cfg.split('.')[-2] = 'cfgs/s3dis/pointnext-xl'
# rgs.cfg.split('.')[-2].split('/')[-2] = "s3dis"
cfg.task_name = args.cfg.split('.')[-2].split('/')[-2] # task/dataset name, \eg s3dis, modelnet40_cls
# task_name 数据集名称
cfg.cfg_basename = args.cfg.split('.')[-2].split('/')[-1] # cfg_basename, \eg pointnext-xl
#backbone名称
tags = [
cfg.task_name, # task name (the folder of name under ./cfgs
cfg.mode, #任务模式 训练还是测试
cfg.cfg_basename, # cfg file name
f'ngpus{cfg.world_size}',#GPU的个数
]
opt_list = [] # for checking experiment configs from logging file
#在这里opts =["mode = train"]
for i, opt in enumerate(opts):
if 'rank' not in opt and 'dir' not in opt and 'root' not in opt and 'pretrain' not in opt and 'path' not in opt and 'wandb' not in opt and '/' not in opt:
opt_list.append(opt)
#
cfg.root_dir = os.path.join(cfg.root_dir, cfg.task_name)
cfg.opts = '-'.join(opt_list)
cfg.is_training = cfg.mode not in ['test', 'testing', 'val', 'eval', 'evaluation']#标记训练模式
# 是其他模式 要提供预训练地址
# 由此可以有四种模式,分别是'resume', 'val', 'test',train
if cfg.mode in ['resume', 'val', 'test']:
# 从文件夹中恢复实验
resume_exp_directory(cfg, pretrained_path=cfg.pretrained_path)
cfg.wandb.tags = [cfg.mode]
else:#train
# 生成实验文件夹
generate_exp_directory(cfg, tags, additional_id=os.environ.get('MASTER_PORT', None))
cfg.wandb.tags = tags
os.environ["JOB_LOG_DIR"] = cfg.log_dir#日志文件地址
cfg_path = os.path.join(cfg.run_dir, "cfg.yaml")
cfg.cfg_path = cfg_path#配置好的配置文件路径
# wandb config wandb配置
cfg.wandb.name = cfg.run_name
# multi processing.
if cfg.mp:
port = find_free_port()
cfg.dist_url = f"tcp://localhost:{port}"
print('using mp spawn for distributed training')
mp.spawn(main, nprocs=cfg.world_size, args=(cfg,))
else:#单一处理器
main(0, cfg)
todo main()
def main(gpu, cfg):
#单gpu 配置日志
# logger
# 初始化 detectron2 记录器并将其详细级别设置为“INFO”
setup_logger_dist(cfg.log_path, cfg.rank, name=cfg.dataset.common.NAME)
writer = SummaryWriter(log_dir=cfg.run_dir) if cfg.is_training else None#创建一个sumary——writer
# 设置随机数种子
set_random_seed(cfg.seed + cfg.rank, deterministic=cfg.deterministic)
torch.backends.cudnn.enabled = True#启动cuda后端
#打印配置文件
logging.info(cfg)
#从配置当中构建模型
if cfg.model.get('in_channels', None) is None:#如果模型没有设置通道数量
cfg.model.in_channels = cfg.model.encoder_args.in_channels#从config.model.encoder_args中初始化输入通道
model = build_model_from_cfg(cfg.model).to(cfg.rank)#从配置文件当中构建模型,并将模型放到gpu_0 上
**model = build_model_from_cfg(cfg.model)**
下面重点讲一下如何从配置文件当中构建模型。 由于最近比较忙,在下一篇文章继续。