图像分割套件PaddleSeg全面解析(二)Config代码解读

上一篇介绍了图像分割PaddleSeg套件的整体情况,并介绍了训练的入口文件train.py。在train.py文件中会对配置文件进行解析,获得训练参数。这一篇主要介绍,如何通过Config类对配置文件进行解析。

Config类定义在paddleseg/cvlibs/config.py文件中。它保存了数据集配置、模型配置、主干网络的配置、损失函数配置等所有的超参数。

在PaddleSeg中,通过使用YAML文件的方式保存配置。该方法的好处是,只需要对YAML进行修改,或者创建新的YAML文件就可以新建一个训练任务。

YAML的语法比较简单,文件结构也很方便阅读,下面我们从图像分割最基础的FCN网络的配置文件开始了解一下如何从YAML文件生成Config对象。

举个例子,看一下dygraph/configs/fcn/fcn_hrnetw18_cityscapes_1024x512_80k.yml文件内容:

# _base_ 不是必须的,其作用更像基类。
# _base_指定的文件可以保存通用的配置,避免相同配置重复书写。若存在相同配置,会覆盖_base_指定yml文件的配置。
_base_: '../_base_/cityscapes.yml'

#模型信息
model:
  #模型的类型FCN
  type: FCN
  #使用的主干网络为HRNet 
  backbone:
    type: HRNet_W18
    #主干网络的预训练模型的下载地址。
    pretrained: https://bj.bcebos.com/paddleseg/dygraph/hrnet_w18_ssld.tar.gz
  #模型分类数为19,可根据实际情况修改
  num_classes: 19
  #模型的预训练地址,这里为空
  pretrained: Null
  #这个是创建模型时需要传入的参数,该参数可以根据具体模型情况进行自定义设置,这个结合模型在具体讲解。
  backbone_indices: [-1]

#优化器设置,这里只设置了正则化的衰减系数,原因是因为在base里面已经设置了优化器的名称和学习率。
optimizer:
  weight_decay: 0.0005
#总迭代次数为80000次。
iters: 80000

下面在看一下cityscape.yml文件内容:

#如果fcn的配置文件,配置了相同内容会覆盖本配置内容。
batch_size: 4
#迭代次数
iters: 80000
#训练集配置
train_dataset:
  #类型为Cityscapes,这里的type对应的值会在Config类中实例化具体的对象,所以名字要跟类名一致。
  #Citycapes类保存在dygraph/paddleseg/datasets/cityscapes.py文件中
  type: Cityscapes
  #指定数据集的根目录,这里没有指定具体的文件List,是因为list是在Cityscape类中生成的。
  dataset_root: data/cityscapes
  #数据增强操作
  transforms:
  #每一个type 则代表了一个数据增强操作对应的类名。下面的值则为创建对象需要传递的参数。
    - type: ResizeStepScaling
      min_scale_factor: 0.5
      max_scale_factor: 2.0
      scale_step_size: 0.25
    - type: RandomPaddingCrop
      crop_size: [1024, 512]
    - type: RandomHorizontalFlip
    - type: Normalize
  #模式为训练模式
  mode: train
#验证集配置
val_dataset:
  type: Cityscapes
  dataset_root: data/cityscapes
  transforms:
    - type: Normalize
  #模式为验证集模式
  mode: val

#优化器设置。
optimizer:
  #优化器为SGG
  type: sgd
  #动量
  momentum: 0.9
  #正则化
  weight_decay: 4.0e-5

#学习率设置
learning_rate:
  #学习率
  value: 0.01
  #学习率衰减策略
  decay:
    type: poly
    power: 0.9
    end_lr: 0.0
#损失函数设置
loss:
  types:
    #支持多种损失函数
    - type: CrossEntropyLoss
  #损失权重,若包含多个损失函数,可以在此处设置权重,权重数量需要与损失函数数量一致。
  coef: [1]

上面介绍了yml配置文件的内容,下面解读Config类如何将yml文件转换为对象。Config代码比较长,下面截取重要的方法进行解读。

Config类的构造方法:

  def __init__(self,
               path: str,
               learning_rate: float = None,
               batch_size: int = None,
               iters: int = None):
      #path为yml文件的路径,若果没有指定路径则抛出异常。
      if not path:
          raise ValueError('Please specify the configuration file path.')
      #还需要判断路径是否存在,如果不存在则抛出异常。
      if not os.path.exists(path):
          raise FileNotFoundError('File {} does not exist'.format(path))
      #初始化成员变量,模型对象和损失函数对象。
      self._model = None
      self._losses = None
      #判断配置文件类型是否为YAML。
      if path.endswith('yml') or path.endswith('yaml'):
          #如果文件类型正确,则通过_parse_from_yaml方法将文件内容保存到字典中。
          self.dic = self._parse_from_yaml(path)
      else:
          raise RuntimeError('Config file should in yaml format!')
      #更新配置中的learning_rate、batch_size和iters三个参数,这个三个参数是通过命令行传递过来的,
      #优先级高于yaml配置,会覆盖配置文件中的配置。
      self.update(
          learning_rate=learning_rate, batch_size=batch_size, iters=iters)

下面看一下在构造函数中遇到的_parse_from_yaml方法的源代码:

    def _parse_from_yaml(self, path: str):
        '''Parse a yaml file and build config'''
        #首先打开配置文件,通过yaml库中的load方法转换为字典。yaml为第三方库,可以同pip安装。具体使用方法参考yaml相关文档。
        with codecs.open(path, 'r', 'utf-8') as file:
            dic = yaml.load(file, Loader=yaml.FullLoader)
		#判断_base_是否在字典中,本次使用的FCN的配置文件是包含的也就是上面讲解的cityscape.yml文件。
        if '_base_' in dic:
            #同样获取cityscape.yml的路径然后通过本方法获取base配置的字典。
            cfg_dir = os.path.dirname(path)
            base_path = dic.pop('_base_')
            base_path = os.path.join(cfg_dir, base_path)
            #递归调用,因为cityscape.yml中并不包含_base_,所以下面的方法就不会执行到现在这部分代码。
            base_dic = self._parse_from_yaml(base_path)
            #更新dic字典中的内容。
            dic = self._update_dic(dic, base_dic)
        return dic

下面在讲解一下构造函数中的update方法,这个方法比较简单就是更新learning rate、batch size和iters。

    def update(self,
               learning_rate: float = None,
               batch_size: int = None,
               iters: int = None):
        '''Update config'''
        #如果learning_rate存在,更新字典中的值。
        if learning_rate:
            self.dic['learning_rate']['value'] = learning_rate
        #更新batch_size
        if batch_size:
            self.dic['batch_size'] = batch_size
        #更新iters。
        if iters:
            self.dic['iters'] = iters

在_parse_from_yaml中调用_update_dic方法更新字典参数,我们看一下与上面update的区别。

    def _update_dic(self, dic, base_dic):
        """
        Update config from dic based base_dic
        """
        #首先复制一个basc_dic
        base_dic = base_dic.copy()
        #遍历dic中的键值对。
        for key, val in dic.items():
        	#如果dic中的值的类型为字典,同时这个键在base_dic中存在,则需要使用base_dic中值进行更新。
            #递归调用本方法进行更新,直到val类型是基本类型。
            if isinstance(val, dict) and key in base_dic:
                base_dic[key] = self._update_dic(val, base_dic[key])
            #如果是基本类型则直接更新,上面递归到此处会停止,在下面return处直接返回。
            else:
                base_dic[key] = val
        dic = base_dic
        return dic

Config类中还包含了很多以@property为注解的方法,对应了yaml配置文件中的train_dataset、val_dataset、model、loss等配置。前面提到过在这些配置中都会包含一个名字是type的键,它对应的值为类的名字。以property为注解的方法则会通过类的名字创建该对象,并将该对象返回给用户,此处使用的是懒加载的方式,只有当被调用的时候才会去创建。下面我们举例model属性来讲解一下,其他属性工作流程类似。

@property
  def model(self) -> paddle.nn.Layer:
      #从Config的配置字典中获取model的配置内容对应yaml文件中的部分如下:
      #model:
  	  #type: FCN
      #backbone:
      #		type: HRNet_W18
      #		pretrained: https://bj.bcebos.com/paddleseg/dygraph/hrnet_w18_ssld.tar.gz
  	  #num_classes: 19
  	  #pretrained: Null
      #backbone_indices: [-1]
      
      model_cfg = self.dic.get('model').copy()
      #使用train_dataset配置中的类别数量覆盖model中的配置
      model_cfg['num_classes'] = self.train_dataset.num_classes
      #如果model_cfg 不存在则抛出异常
      if not model_cfg:
          raise RuntimeError('No model specified in the configuration file.')
      #在构造函数中_model配置为None,这里只创建一次模型对象。
      if not self._model:
          #创建模型对象。下面会继续解读_load_object方法。
          self._model = self._load_object(model_cfg)
      return self._model

_load_object方法解读:

 def _load_object(self, cfg: dict) -> Any:
 		#拷贝一份配置,因为需要通过type的值创建对象,所以如果cfg中不包含type键则会抛出异常。
        cfg = cfg.copy()
        if 'type' not in cfg:
            raise RuntimeError('No object information in {}.'.format(cfg))
        #通过_load_component方法根据type的值获取类组件,这里的组件都是在定义各个类的时候通过
        #装饰器添加到manager维护的List中的,所以这里可以直接获取。至于如何加入list会在第3节接触到。
        component = self._load_component(cfg.pop('type'))
		#此处获取创建对象需要传递的参数,保存在params中。
        params = {}
        #遍历cfg中的键值对。
        for key, val in cfg.items():
            #这里使用_is_meta_type方法来判断val是字典同时也包含type值,如果包含的的话说明val对应的也是一个对象,
            #需要使用递归的方式获取到,直到参数类型为简单对象。
            if self._is_meta_type(val):
                params[key] = self._load_object(val)
            #如果参数是一个列表,则需要遍历列表中的内容,判断是否需要递归创建对象。
            elif isinstance(val, list):
                params[key] = [
                    self._load_object(item)
                    if self._is_meta_type(item) else item for item in val
                ]
            #遇到基本类型,保存参数。
            else:
                params[key] = val
		#遍历借宿创建对象。
        return component(**params)

至此Config类代码就解读完毕。

PaddleSeg仓库地址:https://github.com/PaddlePaddle/PaddleSeg

  • 16
    点赞
  • 39
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 20
    评论
### 回答1: c解析office文件的开源代码有很多选择,其中比较常见的是libreoffice和Apache POI。libreoffice是一套功能强大的开源办公套件,它支持多种办公文件格式的解析和编辑,包括Microsoft Office的文件格式。libreoffice内部使用的文件格式解析代码是开源的,可以通过查看源码来理解其实现原理。 另一个常用的开源代码是Apache POI。Apache POI是一个用于操作Microsoft Office文件的开源Java库,它能够读取和写入各种Microsoft Office文件格式,如doc、docx、xls、xlsx等。POI提供了丰富的API供开发者使用,通过查看其代码可以了解如何解析和操作这些文件格式。 这些开源代码提供了对office文件格式的详细解析和操作方法,可以帮助开发者更好地理解和处理office文件的内容。通过研究这些代码,我们可以了解文件格式的结构和特性,并能够编写相关代码来实现自己的需求,如读取和修改办公文件的内容、样式、格式等。 总之,通过查看libreoffice和Apache POI等开源项目的代码,可以深入了解office文件的解析和操作原理,为自己开发应用程序提供指导和帮助。 ### 回答2: C 解析 Office 文件开源代码是指通过使用开源代码,对 Microsoft Office 文件进行解析和提取其中的信息。通常情况下,Office 文件包括 Word 文档(.docx)、Excel 表格(.xlsx)和 PowerPoint 演示文稿(.pptx)等格式的文件。 目前,一些优秀的开源项目提供了解析 Office 文件的功能,并提供了相应的代码库供开发者使用。其中,最常用的几个开源项目包括 Apache POI、python-pptx、openpyxl 等。 Apache POI 是一个 Java 库,可用于读取和写入 Microsoft Office 文件。它支持解析 Word、Excel 和 PowerPoint 文件,并提供了一系列的 API 接口,便于开发者操作这些文件。通过 Apache POI,开发者可以读取 Office 文件中的文本、表格、图片及其他对象,并进行相应的操作和处理。 python-pptx 是一个用于处理 PowerPoint 文件的 Python 库。它提供了许多功能,包括读取和写入 PowerPoint 文档、创建和编辑幻灯片、添加文本和图片等。使用 python-pptx,开发者可以轻松地解析 PowerPoint 文件中的内容,并进行一系列的操作。 openpyxl 是一个处理 Excel 文件的 Python 库。使用 openpyxl,开发者可以读取和写入 Excel 表格,包括对表格的编辑、格式化、操作及数据提取等。这个开源项目提供了简单易用的 API 接口,使得通过代码解析和处理 Excel 文件变得更加便捷。 通过使用这些开源库,开发者可以灵活地对 Office 文件进行解析和提取,以满足各种需求,如数据分析、文档处理和自动化操作等。这些开源项目在社区中广泛应用,并得到了不断的更新和改进。 ### 回答3: 解析Office文件是指对Microsoft Office软件中的文件进行分析和提取信息的过程。开源代码是指可以公开查看、使用和修改的软件源代码。 要解析Office文件,可以使用一些开源的代码库和工具,例如Apache POI、LibreOffice、OpenXML SDK等。其中,Apache POI是一个流行的Java库,用于操作Microsoft Office文件。它可以读取、写入和修改Word、Excel和PowerPoint文件的内容和属性。通过POI,我们可以提取文件中的文本、表格、图表、样式等信息,并进行相应的处理和分析。 另外,LibreOffice也是一个强大的开源办公套件,可以处理各种Office文件格式。它提供了Python、Java和C++等不同语言的API,使得解析和操作Office文件变得更加灵活和方便。通过LibreOffice,我们可以提取和转换Office文件的内容,例如将Word文件转换为PDF或HTML格式,或者提取Excel文件中的数据进行统计分析。 OpenXML SDK是微软提供的一个.NET开源库,用于读取和写入Office Open XML(docx、xlsx和pptx)文件。它提供了一组强大的API,可以解析和操作Office文件的内容和结构。我们可以通过OpenXML SDK读取并分析文件的各种属性、段落、样式以及嵌入的对象等信息。 综上所述,解析Office文件的开源代码有很多选择,包括Apache POI、LibreOffice和OpenXML SDK等。使用这些代码库,我们可以方便地读取、分析和处理Office文件中的各种内容和属性。无论是从文本提取数据,还是对表格进行统计分析,都可以借助这些开源代码来实现。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

人工智能研习社

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值