config.py 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567
  1. # copyright (c) 2024 PaddlePaddle Authors. All Rights Reserve.
  2. #
  3. # Licensed under the Apache License, Version 2.0 (the "License");
  4. # you may not use this file except in compliance with the License.
  5. # You may obtain a copy of the License at
  6. #
  7. # http://www.apache.org/licenses/LICENSE-2.0
  8. #
  9. # Unless required by applicable law or agreed to in writing, software
  10. # distributed under the License is distributed on an "AS IS" BASIS,
  11. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. # See the License for the specific language governing permissions and
  13. # limitations under the License.
  14. import yaml
  15. from typing import Union
  16. from paddleclas.ppcls.utils.config import get_config, override_config
  17. from ...base import BaseConfig
  18. from ....utils.misc import abspath
  19. class ClsConfig(BaseConfig):
  20. """Image Classification Task Config"""
  21. def update(self, list_like_obj: list):
  22. """update self
  23. Args:
  24. list_like_obj (list): list of pairs(key0.key1.idx.key2=value), such as:
  25. [
  26. 'topk=2',
  27. 'VALID.transforms.1.ResizeImage.resize_short=300'
  28. ]
  29. """
  30. dict_ = override_config(self.dict, list_like_obj)
  31. self.reset_from_dict(dict_)
  32. def load(self, config_file_path: str):
  33. """load config from yaml file
  34. Args:
  35. config_file_path (str): the path of yaml file.
  36. Raises:
  37. TypeError: the content of yaml file `config_file_path` error.
  38. """
  39. dict_ = yaml.load(open(config_file_path, 'rb'), Loader=yaml.Loader)
  40. if not isinstance(dict_, dict):
  41. raise TypeError
  42. self.reset_from_dict(dict_)
  43. def dump(self, config_file_path: str):
  44. """dump self to yaml file
  45. Args:
  46. config_file_path (str): the path to save self as yaml file.
  47. """
  48. with open(config_file_path, 'w', encoding='utf-8') as f:
  49. yaml.dump(self.dict, f, default_flow_style=False, sort_keys=False)
  50. def update_dataset(
  51. self,
  52. dataset_path: str,
  53. dataset_type: str=None,
  54. *,
  55. train_list_path: str=None, ):
  56. """update dataset settings
  57. Args:
  58. dataset_path (str): the root path of dataset.
  59. dataset_type (str, optional): dataset type. Defaults to None.
  60. train_list_path (str, optional): the path of train dataset annotation file . Defaults to None.
  61. Raises:
  62. ValueError: the dataset_type error.
  63. """
  64. dataset_path = abspath(dataset_path)
  65. if dataset_type is None:
  66. dataset_type = 'ClsDataset'
  67. if train_list_path:
  68. train_list_path = f"{train_list_path}"
  69. else:
  70. train_list_path = f"{dataset_path}/train.txt"
  71. if dataset_type in ['ClsDataset']:
  72. ds_cfg = [
  73. f'DataLoader.Train.dataset.name={dataset_type}',
  74. f'DataLoader.Train.dataset.image_root={dataset_path}',
  75. f'DataLoader.Train.dataset.cls_label_path={train_list_path}',
  76. f'DataLoader.Eval.dataset.name={dataset_type}',
  77. f'DataLoader.Eval.dataset.image_root={dataset_path}',
  78. f'DataLoader.Eval.dataset.cls_label_path={dataset_path}/val.txt',
  79. f'Infer.PostProcess.class_id_map_file={dataset_path}/label.txt'
  80. ]
  81. else:
  82. raise ValueError(f"{repr(dataset_type)} is not supported.")
  83. self.update(ds_cfg)
  84. def update_batch_size(self, batch_size: int, mode: str='train'):
  85. """update batch size setting
  86. Args:
  87. batch_size (int): the batch size number to set.
  88. mode (str, optional): the mode that to be set batch size, must be one of 'train', 'eval', 'test'.
  89. Defaults to 'train'.
  90. Raises:
  91. ValueError: `mode` error.
  92. """
  93. if mode == 'train':
  94. if self.DataLoader["Train"]["sampler"].get("batch_size", False):
  95. _cfg = [f'DataLoader.Train.sampler.batch_size={batch_size}']
  96. else:
  97. _cfg = [f'DataLoader.Train.sampler.first_bs={batch_size}']
  98. _cfg = [f'DataLoader.Train.dataset.name=MultiScaleDataset']
  99. elif mode == 'eval':
  100. _cfg = [f'DataLoader.Eval.sampler.batch_size={batch_size}']
  101. elif mode == 'test':
  102. _cfg = [f'DataLoader.Infer.batch_size={batch_size}']
  103. else:
  104. raise ValueError("The input `mode` should be train, eval or test.")
  105. self.update(_cfg)
  106. def update_learning_rate(self, learning_rate: float):
  107. """update learning rate
  108. Args:
  109. learning_rate (float): the learning rate value to set.
  110. """
  111. _cfg = [f'Optimizer.lr.learning_rate={learning_rate}']
  112. self.update(_cfg)
  113. def update_warmup_epochs(self, warmup_epochs: int):
  114. """update warmup epochs
  115. Args:
  116. warmup_epochs (int): the warmup epochs value to set.
  117. """
  118. _cfg = [f'Optimizer.lr.warmup_epoch={warmup_epochs}']
  119. self.update(_cfg)
  120. def update_pretrained_weights(self, pretrained_model: str):
  121. """update pretrained weight path
  122. Args:
  123. pretrained_model (str): the local path or url of pretrained weight file to set.
  124. """
  125. assert isinstance(
  126. pretrained_model, (str, type(None))
  127. ), "The 'pretrained_model' should be a string, indicating the path to the '*.pdparams' file, or 'None', \
  128. indicating that no pretrained model to be used."
  129. if pretrained_model is None:
  130. self.update(['Global.pretrained_model=None'])
  131. self.update(['Arch.pretrained=False'])
  132. else:
  133. if pretrained_model.lower() == "default":
  134. self.update(['Global.pretrained_model=None'])
  135. self.update(['Arch.pretrained=True'])
  136. else:
  137. if not pretrained_model.startswith(('http://', 'https://')):
  138. pretrained_model = abspath(
  139. pretrained_model.replace(".pdparams", ""))
  140. self.update([f'Global.pretrained_model={pretrained_model}'])
  141. def update_num_classes(self, num_classes: int):
  142. """update classes number
  143. Args:
  144. num_classes (int): the classes number value to set.
  145. """
  146. update_str_list = [f'Arch.class_num={num_classes}']
  147. if self._get_arch_name() == "DistillationModel":
  148. update_str_list.append(
  149. f"Arch.models.0.Teacher.class_num={num_classes}")
  150. update_str_list.append(
  151. f"Arch.models.1.Student.class_num={num_classes}")
  152. self.update(update_str_list)
  153. def _update_slim_config(self, slim_config_path: str):
  154. """update slim settings
  155. Args:
  156. slim_config_path (str): the path to slim config yaml file.
  157. """
  158. slim_config = yaml.load(
  159. open(slim_config_path, 'rb'), Loader=yaml.Loader)['Slim']
  160. self.update([f'Slim={slim_config}'])
  161. def _update_amp(self, amp: Union[None, str]):
  162. """update AMP settings
  163. Args:
  164. amp (None | str): the AMP settings.
  165. Raises:
  166. ValueError: AMP setting `amp` error, missing field `AMP`.
  167. """
  168. if amp is None or amp == 'OFF':
  169. if 'AMP' in self.dict:
  170. self._dict.pop('AMP')
  171. else:
  172. if 'AMP' not in self.dict:
  173. raise ValueError("Config must have AMP information.")
  174. _cfg = ['AMP.use_amp=True', f'AMP.level={amp}']
  175. self.update(_cfg)
  176. def update_num_workers(self, num_workers: int):
  177. """update workers number of train and eval dataloader
  178. Args:
  179. num_workers (int): the value of train and eval dataloader workers number to set.
  180. """
  181. _cfg = [
  182. f'DataLoader.Train.loader.num_workers={num_workers}',
  183. f'DataLoader.Eval.loader.num_workers={num_workers}',
  184. ]
  185. self.update(_cfg)
  186. def update_shared_memory(self, shared_memeory: bool):
  187. """update shared memory setting of train and eval dataloader
  188. Args:
  189. shared_memeory (bool): whether or not to use shared memory
  190. """
  191. assert isinstance(shared_memeory,
  192. bool), "shared_memeory should be a bool"
  193. _cfg = [
  194. f'DataLoader.Train.loader.use_shared_memory={shared_memeory}',
  195. f'DataLoader.Eval.loader.use_shared_memory={shared_memeory}',
  196. ]
  197. self.update(_cfg)
  198. def update_shuffle(self, shuffle: bool):
  199. """update shuffle setting of train and eval dataloader
  200. Args:
  201. shuffle (bool): whether or not to shuffle the data
  202. """
  203. assert isinstance(shuffle, bool), "shuffle should be a bool"
  204. _cfg = [
  205. f'DataLoader.Train.loader.shuffle={shuffle}',
  206. f'DataLoader.Eval.loader.shuffle={shuffle}',
  207. ]
  208. self.update(_cfg)
  209. def update_dali(self, dali: bool):
  210. """enable DALI setting of train and eval dataloader
  211. Args:
  212. dali (bool): whether or not to use DALI
  213. """
  214. assert isinstance(dali, bool), "dali should be a bool"
  215. _cfg = [
  216. f'Global.use_dali={dali}',
  217. f'Global.use_dali={dali}',
  218. ]
  219. self.update(_cfg)
  220. def update_seed(self, seed: int):
  221. """update seed
  222. Args:
  223. seed (int): the random seed value to set
  224. """
  225. _cfg = [f'Global.seed={seed}']
  226. self.update(_cfg)
  227. def update_device(self, device: str):
  228. """update device setting
  229. Args:
  230. device (str): the running device to set
  231. """
  232. device = device.split(':')[0]
  233. _cfg = [f'Global.device={device}']
  234. self.update(_cfg)
  235. def update_label_dict_path(self, dict_path: str):
  236. """update label dict file path
  237. Args:
  238. dict_path (str): the path of label dict file to set
  239. """
  240. _cfg = [f'PostProcess.Topk.class_id_map_file={abspath(dict_path)}', ]
  241. self.update(_cfg)
  242. def _update_to_static(self, dy2st: bool):
  243. """update config to set dynamic to static mode
  244. Args:
  245. dy2st (bool): whether or not to use the dynamic to static mode.
  246. """
  247. self.update([f'Global.to_static={dy2st}'])
  248. def _update_use_vdl(self, use_vdl: bool):
  249. """update config to set VisualDL
  250. Args:
  251. use_vdl (bool): whether or not to use VisualDL.
  252. """
  253. self.update([f'Global.use_visualdl={use_vdl}'])
  254. def _update_epochs(self, epochs: int):
  255. """update epochs setting
  256. Args:
  257. epochs (int): the epochs number value to set
  258. """
  259. self.update([f'Global.epochs={epochs}'])
  260. def _update_checkpoints(self, resume_path: Union[None, str]):
  261. """update checkpoint setting
  262. Args:
  263. resume_path (None | str): the resume training setting. if is `None`, train from scratch, otherwise,
  264. train from checkpoint file that path is `.pdparams` file.
  265. """
  266. if resume_path is not None:
  267. resume_path = resume_path.replace(".pdparams", "")
  268. self.update([f'Global.checkpoints={resume_path}'])
  269. def _update_output_dir(self, save_dir: str):
  270. """update output directory
  271. Args:
  272. save_dir (str): the path to save outputs.
  273. """
  274. self.update([f'Global.output_dir={abspath(save_dir)}'])
  275. def update_log_interval(self, log_interval: int):
  276. """update log interval(steps)
  277. Args:
  278. log_interval (int): the log interval value to set.
  279. """
  280. self.update([f'Global.print_batch_step={log_interval}'])
  281. def update_eval_interval(self, eval_interval: int):
  282. """update eval interval(epochs)
  283. Args:
  284. eval_interval (int): the eval interval value to set.
  285. """
  286. self.update([f'Global.eval_interval={eval_interval}'])
  287. def update_save_interval(self, save_interval: int):
  288. """update eval interval(epochs)
  289. Args:
  290. save_interval (int): the save interval value to set.
  291. """
  292. self.update([f'Global.save_interval={save_interval}'])
  293. def update_log_ranks(self, device):
  294. """update log ranks
  295. Args:
  296. device (str): the running device to set
  297. """
  298. log_ranks = device.split(':')[1]
  299. self.update([f'Global.log_ranks="{log_ranks}"'])
  300. def update_print_mem_info(self, print_mem_info: bool):
  301. """setting print memory info"""
  302. assert isinstance(print_mem_info,
  303. bool), "print_mem_info should be a bool"
  304. self.update([f'Global.print_mem_info={print_mem_info}'])
  305. def _update_predict_img(self, infer_img: str, infer_list: str=None):
  306. """update image to be predicted
  307. Args:
  308. infer_img (str): the path to image that to be predicted.
  309. infer_list (str, optional): the path to file that images. Defaults to None.
  310. """
  311. if infer_list:
  312. self.update([f'Infer.infer_list={infer_list}'])
  313. self.update([f'Infer.infer_imgs={infer_img}'])
  314. def _update_save_inference_dir(self, save_inference_dir: str):
  315. """update directory path to save inference model files
  316. Args:
  317. save_inference_dir (str): the directory path to set.
  318. """
  319. self.update(
  320. [f'Global.save_inference_dir={abspath(save_inference_dir)}'])
  321. def _update_inference_model_dir(self, model_dir: str):
  322. """update inference model directory
  323. Args:
  324. model_dir (str): the directory path of inference model fils that used to predict.
  325. """
  326. self.update([f'Global.inference_model_dir={abspath(model_dir)}'])
  327. def _update_infer_img(self, infer_img: str):
  328. """update path of image that would be predict
  329. Args:
  330. infer_img (str): the image path.
  331. """
  332. self.update([f'Global.infer_imgs={infer_img}'])
  333. def _update_infer_device(self, device: str):
  334. """update the device used in predicting
  335. Args:
  336. device (str): the running device setting
  337. """
  338. self.update([f'Global.use_gpu={device.split(":")[0]=="gpu"}'])
  339. def _update_enable_mkldnn(self, enable_mkldnn: bool):
  340. """update whether to enable MKLDNN
  341. Args:
  342. enable_mkldnn (bool): `True` is enable, otherwise is disable.
  343. """
  344. self.update([f'Global.enable_mkldnn={enable_mkldnn}'])
  345. def _update_infer_img_shape(self, img_shape: str):
  346. """update image cropping shape in the preprocessing
  347. Args:
  348. img_shape (str): the shape of cropping in the preprocessing,
  349. i.e. `PreProcess.transform_ops.1.CropImage.size`.
  350. """
  351. self.update([f'PreProcess.transform_ops.1.CropImage.size={img_shape}'])
  352. def _update_save_predict_result(self, save_dir: str):
  353. """update directory that save predicting output
  354. Args:
  355. save_dir (str): the dicrectory path that save predicting output.
  356. """
  357. self.update([f'Infer.save_dir={save_dir}'])
  358. def update_model(self, **kwargs):
  359. """update model settings
  360. """
  361. for k in kwargs:
  362. v = kwargs[k]
  363. self.update([f'Arch.{k}={v}'])
  364. def update_teacher_model(self, **kwargs):
  365. """update teacher model settings
  366. """
  367. for k in kwargs:
  368. v = kwargs[k]
  369. self.update([f'Arch.models.0.Teacher.{k}={v}'])
  370. def update_student_model(self, **kwargs):
  371. """update student model settings
  372. """
  373. for k in kwargs:
  374. v = kwargs[k]
  375. self.update([f'Arch.models.1.Student.{k}={v}'])
  376. def get_epochs_iters(self) -> int:
  377. """get epochs
  378. Returns:
  379. int: the epochs value, i.e., `Global.epochs` in config.
  380. """
  381. return self.dict['Global']['epochs']
  382. def get_log_interval(self) -> int:
  383. """get log interval(steps)
  384. Returns:
  385. int: the log interval value, i.e., `Global.print_batch_step` in config.
  386. """
  387. return self.dict['Global']['print_batch_step']
  388. def get_eval_interval(self) -> int:
  389. """get eval interval(epochs)
  390. Returns:
  391. int: the eval interval value, i.e., `Global.eval_interval` in config.
  392. """
  393. return self.dict['Global']['eval_interval']
  394. def get_save_interval(self) -> int:
  395. """get save interval(epochs)
  396. Returns:
  397. int: the save interval value, i.e., `Global.save_interval` in config.
  398. """
  399. return self.dict['Global']['save_interval']
  400. def get_learning_rate(self) -> float:
  401. """get learning rate
  402. Returns:
  403. float: the learning rate value, i.e., `Optimizer.lr.learning_rate` in config.
  404. """
  405. return self.dict['Optimizer']['lr']['learning_rate']
  406. def get_warmup_epochs(self) -> int:
  407. """get warmup epochs
  408. Returns:
  409. int: the warmup epochs value, i.e., `Optimizer.lr.warmup_epochs` in config.
  410. """
  411. return self.dict['Optimizer']['lr']['warmup_epoch']
  412. def get_label_dict_path(self) -> str:
  413. """get label dict file path
  414. Returns:
  415. str: the label dict file path, i.e., `PostProcess.Topk.class_id_map_file` in config.
  416. """
  417. return self.dict['PostProcess']['Topk']['class_id_map_file']
  418. def get_batch_size(self, mode='train') -> int:
  419. """get batch size
  420. Args:
  421. mode (str, optional): the mode that to be get batch size value, must be one of 'train', 'eval', 'test'.
  422. Defaults to 'train'.
  423. Returns:
  424. int: the batch size value of `mode`, i.e., `DataLoader.{mode}.sampler.batch_size` in config.
  425. """
  426. return self.dict['DataLoader']['Train']['sampler']['batch_size']
  427. def get_qat_epochs_iters(self) -> int:
  428. """get qat epochs
  429. Returns:
  430. int: the epochs value.
  431. """
  432. return self.get_epochs_iters()
  433. def get_qat_learning_rate(self) -> float:
  434. """get qat learning rate
  435. Returns:
  436. float: the learning rate value.
  437. """
  438. return self.get_learning_rate()
  439. def _get_arch_name(self) -> str:
  440. """get architecture name of model
  441. Returns:
  442. str: the model arch name, i.e., `Arch.name` in config.
  443. """
  444. return self.dict["Arch"]["name"]
  445. def _get_dataset_root(self) -> str:
  446. """get root directory of dataset, i.e. `DataLoader.Train.dataset.image_root`
  447. Returns:
  448. str: the root directory of dataset
  449. """
  450. return self.dict["DataLoader"]["Train"]['dataset']['image_root']
  451. def get_train_save_dir(self) -> str:
  452. """get the directory to save output
  453. Returns:
  454. str: the directory to save output
  455. """
  456. return self['Global']['output_dir']