【三维重建】【3DGS系列】【深度学习】3DGS的代码讲解之arguments配置管理模块解析
【三维重建】【3DGS系列】【深度学习】3DGS的代码讲解之arguments配置管理模块解析
文章目录
前言
在详细解析3DGS代码之前,首要任务是成功运行3DGS代码【理论基础及代码运行(win11下)解析参考教程】,后续学习才有意义。本博文对arguments配置管理模块块代码进行解析,arguments通过面向对象的方式实现了参数的结构化管理、命令行接口自动生成、参数提取与合并等功能,统一管理项目中的所有命令行参数配置。其他模块代码后续的博文将会陆续讲解。这里只做arguments相关模块的代码解析。

class GroupParams
主要用途是作为一个 动态属性容器(Dynamic Attribute Container)或者说是一个轻量级自定义命名空间(Custom Namespace),创建实例可以运行时动态添加属性,适合用于组织和封装一组相关参数。
class GroupParams:
# 空类定义作为一个动态属性容器,相当于自定义的“命名空间”类:用于封装存储从命令行参数中提取出的一组相关参数,作为其变成成员变量.
pass
class ParamGroup
将类的成员变量封装配置为命令行参数,并支持从命令行提取属于类的参数封装成参数对象返回。
用于将类成员变量映射为命令行参数组并支持从完整的命令行参数对象中反向提取的通用参数管理类,使得命令行参数的管理和使用更加模块化、自动化和结构清晰。
__init__成员函数
用于将该类的属性自动转换为命令行参数,并将这些参数添加到一个参数组中。
将一个类的属性(self.lr = 0.01)自动注册为命令行参数(如 --lr 0.01),并将其归类在一个参数组中,便于管理和展示,减少手动编写 add_argument() 的重复工作,提升代码可读性和可维护性。
def __init__(self, parser: ArgumentParser, name: str, fill_none=False):
"""
构造函数:将一个类的属性自动转换为命令行参数,并作为参数组添加到参数解析器中.
@param parser:ArgumentParser实例,用于添加命令行参数
@param name:当前参数组的名字,会显示在帮助信息中,作为参数组标题
@param fill_none:布尔值,是否将默认值设置为None
"""
group = parser.add_argument_group(name) # 在命令行解析器中创建参数组,用于组织相关的参数
# vars(self)返回当前对象的所有成员变量和值组成的字典
for key, value in vars(self).items(): # 遍历字典
shorthand = False # 简写(shorthand)标识符
if key.startswith("_"): # 支持简写参数:当前属性名以 _ 开头则表示可以简写参数
shorthand = True
key = key[1:] # 去掉下划线后的实际参数名
t = type(value) # 获取当前属性的类型
value = value if not fill_none else None # 设置默认值:fill_none决定默认值设为None还是保留原始值
if shorthand: # 判断是否为简写参数
# 简写参数两种形式:,长格式 --key 全名称;短格式 -k 首字母
if t == bool: # 判断是否为布尔型参数
# 尔类型使用action="store_true"创建不带值的开关型参数
group.add_argument("--" + key, ("-" + key[0:1]), default=value, action="store_true") # 添加参数到组中
else:
# 从属性值中提取指定类型
group.add_argument("--" + key, ("-" + key[0:1]), default=value, type=t)
else: # 非简写参数只有长格式参数--key
if t == bool:
group.add_argument("--" + key, default=value, action="store_true")
else:
group.add_argument("--" + key, default=value, type=t)
extract成员函数
从传入的完整命令行参数中筛选出当前类中已经定义的成员变量(对应的命令行参数,并将这些参数封装到一个新对象中返回。
多个模块共享一个命令行解析器,但每个模块只关心自己的参数,提取特定模块或组件所需的参数。
def extract(self, args):
"""
从完整的命令行参数序列提取出属于当前类的对应成员变量的参数,并将这些参数封装成一个新对象返回.
@param args:完整的命令行参数对象
@return:封装的当前参数组新对象
"""
group = GroupParams() # 用于动态地添加提取出的参数的GroupParams自定义对象
for arg in vars(args).items(): # 遍历传入的命令行参数对象
if arg[0] in vars(self) or ("_" + arg[0]) in vars(self): # 判断参数是否属于当前类
# setattr(对象,属性名,属性值)
setattr(group, arg[0], arg[1]) # 将匹配的参数作为成员变量动态地添加到对象中
return group
class ModelParams
继承自ParamGroup的命令行参数配置类,用于封装数据加载相关参数的高度模块化的参数管理类。
__init__成员函数
通过继承ParamGroup实现了对数据加载相关参数的集中管理和命令行接口自动生成,使得配置更加清晰、灵活、可扩展。
def __init__(self, parser, sentinel=False):
"""
构造函数:继承ParamGroup,将类成员变量自动映射为命令行参数.
@param parser:argparse.ArgumentParser实例,用于添加命令行参数
@param sentinel:控制映射的参数默认值保留原始成员变量的值还是设置为None
"""
self.sh_degree = 3 # 球谐函数的最大阶数,默认为3(不大于3)
self._source_path = "" # COLMAP或NeRF数据集源路径,默认为空字符串
self._model_path = "" # 训练阶段的输出文件夹,默认为空
self._images = "images" # 图像所在目录名称,默认images
self._resolution = -1 # 图像分辨率缩放比例,默认为-1(强制限制),提供1、2、4或8选项分别对应原始、1/2、1/4或1/8分辨率
self._white_background = False # 是否使用白色背景代替黑色背景,默认为False
self.data_device = "cuda" # 数数据加载所使用的设备,默认是"cuda"
self.eval = False # 是否启用“评估模式”,默认为False
# 参数归类为名为"Loading Parameters";
super().__init__(parser, "Loading Parameters", sentinel) # 调用父类ParamGroup.__init__()将上述所有属性自动注册为命令行参数
extract成员函数
用于从完整的命令行参数中提取当前参数组相关的参数,并在父类方法的基础上增加了路径的标准化处理的,使得从命令行提取出的参数更加规范、可靠。
def extract(self, args):
"""
从完整的命令行参数中提取当前参数组相关的参数,完成路径转换并返回一个封装好的参数对象.
@param args:整的命令行参数
@return:封装当前参数组的参数对象
"""
g = super().extract(args) # 调用父类extract()方法筛选出属于当前类的参数
g.source_path = os.path.abspath(g.source_path) # 将用户传入的相对路径或空路径转换为绝对路径
return g
class PipelineParams
继承自ParamGroup的命令行参数配置类,用于封装渲染和训练流程中相关参数的高度模块化的参数管理类。
__init__成员函数
通过继承ParamGroup实现了对渲染和训练流程相关参数的集中管理和命令行接口自动生成。
def __init__(self, parser):
"""
构造函数:继承ParamGroup,将类成员变量自动映射为命令行参数.
@param parser:argparse.ArgumentParser实例,用于添加命令行参数
"""
# 是否替换作者自定义的方法
self.convert_SHs_python = False # 使用PyTorch的前向/后向传播方式来处理球谐函数,默认为False关闭
self.compute_cov3D_python = False # 使用PyTorch的前向/后向传播方式来处理3D协方差,默认为False关闭
# 开启后可能输出更多日志或进行额外检查
self.debug = False # 否启用调试模式,默认为False关闭
# 参数归类为名为"Pipeline Parameters"
super().__init__(parser, "Pipeline Parameters") # 调用父类ParamGroup.__init__()将上述所有属性自动注册为命令行参数
class OptimizationParams
继承自ParamGroup的命令行参数配置类,用于封装训练过程中所需优化的3d高斯模型参数的高度模块化的参数管理类。
__init__成员函数
通过继承ParamGroup实现了对所需优化的3d高斯模型参数的集中管理和命令行接口自动生成。
def __init__(self, parser):
"""
构造函数:继承ParamGroup,将类成员变量自动映射为命令行参数.
@param parser:parser:argparse.ArgumentParser实例,用于添加命令行参数
"""
self.iterations = 30_000 # 总训练轮数
self.position_lr_init = 0.00016 # 3D高斯核位置初始学习率
self.position_lr_final = 0.0000016 # 3D高斯核位置最终学习率
self.position_lr_delay_mult = 0.01 # 控制位置学习率衰减的因子
self.position_lr_max_steps = 30_000 # 学习率从初始值下降到最终值所需的总轮数
self.feature_lr = 0.0025 # 球谐函数特征的学习率
self.opacity_lr = 0.05 # 不透明度的学习率
self.scaling_lr = 0.005 # 高斯球尺度的学习率
self.rotation_lr = 0.001 # 高斯球旋转的学习率
self.percent_dense = 0.01 # 高斯核是否需要被强制稠密化的阈值(占场景范围的百分比0~1)
self.lambda_dssim = 0.2 # SSIM损失在总损失中的权重(0~1)
self.densification_interval = 100 # 稠密化的频率,以迭代轮数为单位
self.opacity_reset_interval = 3000 # 重置透明度的频率,以迭代轮数为单位
self.densify_from_iter = 500 # 第几次迭代轮数开始执行稠密化
self.densify_until_iter = 15_000 # 第几次迭代轮数停止执行稠密化
self.densify_grad_threshold = 0.0002 # 根据梯度判断是否对高斯核进行加密的阈值
self.random_background = False # 是否使用随机背景进行训练
super().__init__(parser, "Optimization Parameters") # 调用父类ParamGroup.__init__()方法将上述所有属性自动注册为命令行参数
get_combined_args
从命令行参数和配置文件中读取参数,并将二者合并,优先使用命令行参数值。如果配置文件存在,则加载其中的默认值;如果命令行中有指定参数,则覆盖配置文件中的值。在3D Splatting中,训练模型时需要保存一组完整的超参数(如学习率、路径、迭代次数等)。训练完成后会将这些参数保存到一个文件(如 cfg_args)中,下次推理或恢复训练时,可以通过这个文件恢复原始参数设置,并允许通过命令行覆盖部分参数。
def get_combined_args(parser : ArgumentParser):
"""
从命令行参数和配置文件中读取参数,并将二者合并,优先使用命令行参数值.
@param parser: 命令行参数实例,
@return:参数的对象
"""
cmdlne_string = sys.argv[1:] # 除脚本名外的所以命令行参数
cfgfile_string = "Namespace()" # 默认用空命名空间,用于防止找不到配置文件时报错
args_cmdline = parser.parse_args(cmdlne_string) # 解析命令行参数
# 从model_path路径下读取名为cfg_args的配置文件
try:
cfgfilepath = os.path.join(args_cmdline.model_path, "cfg_args")
print("Looking for config file in", cfgfilepath)
with open(cfgfilepath) as cfg_file:
print("Config file found: {}".format(cfgfilepath))
cfgfile_string = cfg_file.read() # 获取文件内容
except TypeError:
# 没有配置文件可用
print("Config file not found at")
pass
args_cfgfile = eval(cfgfile_string) # 将配置文件字符串转换为实际的Namespace对象
##eg:Namespace(sh_degree=3, source_path='data/lego', model_path='output', ...)
merged_dict = vars(args_cfgfile).copy() # 复制配置文件中的参数
for k,v in vars(args_cmdline).items(): # 遍历命令行参数字典
if v != None: # 命令行参数优先级高于配置文件:用命令行参数中非None的参数的值更新到merged_dict中对应参数的值
merged_dict[k] = v
return Namespace(**merged_dict)
Namespace 是Python的argparse模块中用于存储参数的一个简单对象,它使得解析后的命令行参数可以通过属性访问的方式进行引用:
ns_with_values = Namespace(sh_degree=3, source_path=‘data/lego’, model_path=‘output’)
==>
print(ns_with_values.sh_degree) # 输出: 3
总结
尽可能简单、详细的介绍了arguments配置管理模块的功能和作用。
更多推荐
所有评论(0)