callbacks.py 46 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348
  1. # Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved.
  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 numbers
  15. import os
  16. import time
  17. import warnings
  18. import numpy as np
  19. import paddle
  20. from paddle.utils import try_import
  21. from .progressbar import ProgressBar
  22. __all__ = []
  23. def config_callbacks(
  24. callbacks=None,
  25. model=None,
  26. batch_size=None,
  27. epochs=None,
  28. steps=None,
  29. log_freq=2,
  30. verbose=2,
  31. save_freq=1,
  32. save_dir=None,
  33. metrics=None,
  34. mode='train',
  35. ):
  36. cbks = callbacks or []
  37. cbks = cbks if isinstance(cbks, (list, tuple)) else [cbks]
  38. if not any(isinstance(k, ProgBarLogger) for k in cbks) and verbose:
  39. cbks = [ProgBarLogger(log_freq, verbose=verbose)] + cbks
  40. if not any(isinstance(k, ModelCheckpoint) for k in cbks):
  41. cbks = cbks + [ModelCheckpoint(save_freq, save_dir)]
  42. for k in cbks:
  43. if isinstance(k, EarlyStopping):
  44. k.save_dir = save_dir
  45. if not any(isinstance(k, LRScheduler) for k in cbks):
  46. cbks = cbks + [LRScheduler()]
  47. cbk_list = CallbackList(cbks)
  48. cbk_list.set_model(model)
  49. metrics = metrics or [] if mode != 'test' else []
  50. params = {
  51. 'batch_size': batch_size,
  52. 'epochs': epochs,
  53. 'steps': steps,
  54. 'verbose': verbose,
  55. 'metrics': metrics,
  56. }
  57. cbk_list.set_params(params)
  58. return cbk_list
  59. class CallbackList:
  60. def __init__(self, callbacks=None):
  61. # copy
  62. self.callbacks = list(callbacks)
  63. self.params = {}
  64. self.model = None
  65. def append(self, callback):
  66. self.callbacks.append(callback)
  67. def __iter__(self):
  68. return iter(self.callbacks)
  69. def set_params(self, params):
  70. for c in self.callbacks:
  71. c.set_params(params)
  72. def set_model(self, model):
  73. for c in self.callbacks:
  74. c.set_model(model)
  75. def _call(self, name, *args):
  76. for c in self.callbacks:
  77. func = getattr(c, name)
  78. func(*args)
  79. def _check_mode(self, mode):
  80. assert mode in [
  81. 'train',
  82. 'eval',
  83. 'predict',
  84. ], 'mode should be train, eval or predict'
  85. def on_begin(self, mode, logs=None):
  86. self._check_mode(mode)
  87. name = f'on_{mode}_begin'
  88. self._call(name, logs)
  89. def on_end(self, mode, logs=None):
  90. self._check_mode(mode)
  91. name = f'on_{mode}_end'
  92. self._call(name, logs)
  93. def on_epoch_begin(self, epoch=None, logs=None):
  94. self._call('on_epoch_begin', epoch, logs)
  95. def on_epoch_end(self, epoch=None, logs=None):
  96. self._call('on_epoch_end', epoch, logs)
  97. def on_batch_begin(self, mode, step=None, logs=None):
  98. self._check_mode(mode)
  99. name = f'on_{mode}_batch_begin'
  100. self._call(name, step, logs)
  101. def on_batch_end(self, mode, step=None, logs=None):
  102. self._check_mode(mode)
  103. name = f'on_{mode}_batch_end'
  104. self._call(name, step, logs)
  105. class Callback:
  106. """
  107. Base class used to build new callbacks. And new callbacks could also
  108. terminate training by setting `model.stop_training=True`.
  109. Examples:
  110. .. code-block:: python
  111. >>> import paddle
  112. >>> # build a simple model checkpoint callback
  113. >>> class ModelCheckpoint(paddle.callbacks.Callback):
  114. ... def __init__(self, save_freq=1, save_dir=None):
  115. ... self.save_freq = save_freq
  116. ... self.save_dir = save_dir
  117. ...
  118. ... def on_epoch_end(self, epoch, logs=None):
  119. ... if self.model is not None and epoch % self.save_freq == 0:
  120. ... path = '{}/{}'.format(self.save_dir, epoch)
  121. ... print('save checkpoint at {}'.format(path))
  122. ... self.model.save(path)
  123. """
  124. def __init__(self):
  125. self.model = None
  126. self.params = {}
  127. def set_params(self, params):
  128. """
  129. Set parameters, which is dict. The keys contain:
  130. - 'batch_size': an integer. Number of samples per batch.
  131. - 'epochs': an integer. Number of epochs.
  132. - 'steps': an integer. Number of steps of one epoch.
  133. - 'verbose': an integer. Verbose mode is 0, 1 or 2. 0 = silent, 1 = progress bar, 2 = one line per epoch.
  134. - 'metrics': a list of str. Names of metrics, including 'loss' and the names of paddle.metric.Metric.
  135. """
  136. self.params = params
  137. def set_model(self, model):
  138. """model is instance of paddle.Model."""
  139. self.model = model
  140. def on_train_begin(self, logs=None):
  141. """Called at the start of training.
  142. Args:
  143. logs (dict): The logs is a dict or None.
  144. """
  145. def on_train_end(self, logs=None):
  146. """Called at the end of training.
  147. Args:
  148. logs (dict): The logs is a dict or None. The keys of logs
  149. passed by paddle.Model contains 'loss', metric names and
  150. `batch_size`.
  151. """
  152. def on_eval_begin(self, logs=None):
  153. """Called at the start of evaluation.
  154. Args:
  155. logs (dict): The logs is a dict or None. The keys of logs
  156. passed by paddle.Model contains 'steps' and 'metrics',
  157. The `steps` is number of total steps of validation dataset.
  158. The `metrics` is a list of str including 'loss' and the names
  159. of paddle.metric.Metric.
  160. """
  161. def on_eval_end(self, logs=None):
  162. """Called at the end of evaluation.
  163. Args:
  164. logs (dict): The logs is a dict or None. The `logs` passed by
  165. paddle.Model is a dict contains 'loss', metrics and 'batch_size'
  166. of last batch of validation dataset.
  167. """
  168. def on_predict_begin(self, logs=None):
  169. """Called at the beginning of predict.
  170. Args:
  171. logs (dict): The logs is a dict or None.
  172. """
  173. def on_predict_end(self, logs=None):
  174. """Called at the end of predict.
  175. Args:
  176. logs (dict): The logs is a dict or None.
  177. """
  178. def on_epoch_begin(self, epoch, logs=None):
  179. """Called at the beginning of each epoch.
  180. Args:
  181. epoch (int): The index of epoch.
  182. logs (dict): The logs is a dict or None. The `logs` passed by
  183. paddle.Model is None.
  184. """
  185. def on_epoch_end(self, epoch, logs=None):
  186. """Called at the end of each epoch.
  187. Args:
  188. epoch (int): The index of epoch.
  189. logs (dict): The logs is a dict or None. The `logs` passed by
  190. paddle.Model is a dict, contains 'loss', metrics and 'batch_size'
  191. of last batch.
  192. """
  193. def on_train_batch_begin(self, step, logs=None):
  194. """Called at the beginning of each batch in training.
  195. Args:
  196. step (int): The index of step (or iteration).
  197. logs (dict): The logs is a dict or None. The `logs` passed by
  198. paddle.Model is empty.
  199. """
  200. def on_train_batch_end(self, step, logs=None):
  201. """Called at the end of each batch in training.
  202. Args:
  203. step (int): The index of step (or iteration).
  204. logs (dict): The logs is a dict or None. The `logs` passed by
  205. paddle.Model is a dict, contains 'loss', metrics and 'batch_size'
  206. of current batch.
  207. """
  208. def on_eval_batch_begin(self, step, logs=None):
  209. """Called at the beginning of each batch in evaluation.
  210. Args:
  211. step (int): The index of step (or iteration).
  212. logs (dict): The logs is a dict or None. The `logs` passed by
  213. paddle.Model is empty.
  214. """
  215. def on_eval_batch_end(self, step, logs=None):
  216. """Called at the end of each batch in evaluation.
  217. Args:
  218. step (int): The index of step (or iteration).
  219. logs (dict): The logs is a dict or None. The `logs` passed by
  220. paddle.Model is a dict, contains 'loss', metrics and 'batch_size'
  221. of current batch.
  222. """
  223. def on_predict_batch_begin(self, step, logs=None):
  224. """Called at the beginning of each batch in predict.
  225. Args:
  226. step (int): The index of step (or iteration).
  227. logs (dict): The logs is a dict or None.
  228. """
  229. def on_predict_batch_end(self, step, logs=None):
  230. """Called at the end of each batch in predict.
  231. Args:
  232. step (int): The index of step (or iteration).
  233. logs (dict): The logs is a dict or None.
  234. """
  235. class ProgBarLogger(Callback):
  236. """
  237. Logger callback function to print loss and metrics to stdout. It supports
  238. silent mode (not print), progress bar or one line per each printing,
  239. see arguments for more detailed.
  240. Args:
  241. log_freq (int): The frequency, in number of steps,
  242. the logs such as loss, metrics are printed. Default: 1.
  243. verbose (int): The verbosity mode, should be 0, 1, or 2.
  244. 0 = silent, 1 = progress bar, 2 = one line each printing, 3 = 2 +
  245. time counter, such as average reader cost, samples per second.
  246. Default: 2.
  247. Examples:
  248. .. code-block:: python
  249. >>> import paddle
  250. >>> import paddle.vision.transforms as T
  251. >>> from paddle.vision.datasets import MNIST
  252. >>> from paddle.static import InputSpec
  253. >>> inputs = [InputSpec([-1, 1, 28, 28], 'float32', 'image')]
  254. >>> labels = [InputSpec([None, 1], 'int64', 'label')]
  255. >>> transform = T.Compose([
  256. ... T.Transpose(),
  257. ... T.Normalize([127.5], [127.5])
  258. ... ])
  259. >>> train_dataset = MNIST(mode='train', transform=transform)
  260. >>> lenet = paddle.vision.models.LeNet()
  261. >>> model = paddle.Model(lenet,
  262. ... inputs, labels)
  263. >>> optim = paddle.optimizer.Adam(0.001, parameters=lenet.parameters())
  264. >>> model.prepare(optimizer=optim,
  265. ... loss=paddle.nn.CrossEntropyLoss(),
  266. ... metrics=paddle.metric.Accuracy())
  267. >>> callback = paddle.callbacks.ProgBarLogger(log_freq=10)
  268. >>> model.fit(train_dataset, batch_size=64, callbacks=callback)
  269. """
  270. def __init__(self, log_freq=1, verbose=2):
  271. self.epochs = None
  272. self.steps = None
  273. self.progbar = None
  274. self.verbose = verbose
  275. self.log_freq = log_freq
  276. def _is_print(self):
  277. return self.verbose and paddle.distributed.ParallelEnv().local_rank == 0
  278. def on_train_begin(self, logs=None):
  279. self.epochs = self.params['epochs']
  280. assert self.epochs
  281. self.train_metrics = self.params['metrics']
  282. assert self.train_metrics
  283. self._train_timer = {
  284. 'data_time': 0,
  285. 'batch_time': 0,
  286. 'count': 0,
  287. 'samples': 0,
  288. }
  289. if self._is_print():
  290. print(
  291. "The loss value printed in the log is the current step, and the metric is the average value of previous steps."
  292. )
  293. def on_epoch_begin(self, epoch=None, logs=None):
  294. self.steps = self.params['steps']
  295. self.epoch = epoch
  296. self.train_step = 0
  297. if self.epochs and self._is_print():
  298. print('Epoch %d/%d' % (epoch + 1, self.epochs))
  299. self.train_progbar = ProgressBar(num=self.steps, verbose=self.verbose)
  300. self._train_timer['batch_start_time'] = time.time()
  301. def _updates(self, logs, mode):
  302. values = []
  303. metrics = getattr(self, '%s_metrics' % (mode))
  304. progbar = getattr(self, '%s_progbar' % (mode))
  305. steps = getattr(self, '%s_step' % (mode))
  306. for k in metrics:
  307. if k in logs:
  308. values.append((k, logs[k]))
  309. if self.verbose == 3 and hasattr(self, '_%s_timer' % (mode)):
  310. timer = getattr(self, '_%s_timer' % (mode))
  311. cnt = timer['count'] if timer['count'] > 0 else 1.0
  312. samples = timer['samples'] if timer['samples'] > 0 else 1.0
  313. values.append(
  314. ('avg_reader_cost', "%.5f sec" % (timer['data_time'] / cnt))
  315. )
  316. values.append(
  317. ('avg_batch_cost', "%.5f sec" % (timer['batch_time'] / cnt))
  318. )
  319. values.append(
  320. (
  321. 'ips',
  322. "%.5f samples/sec"
  323. % (samples / (timer['data_time'] + timer['batch_time'])),
  324. )
  325. )
  326. timer['count'] = 0
  327. timer['samples'] = 0
  328. timer['data_time'] = 0.0
  329. timer['batch_time'] = 0.0
  330. progbar.update(steps, values)
  331. def on_train_batch_begin(self, step, logs=None):
  332. self._train_timer['batch_data_end_time'] = time.time()
  333. self._train_timer['data_time'] += (
  334. self._train_timer['batch_data_end_time']
  335. - self._train_timer['batch_start_time']
  336. )
  337. def on_train_batch_end(self, step, logs=None):
  338. logs = logs or {}
  339. self.train_step += 1
  340. self._train_timer['batch_time'] += (
  341. time.time() - self._train_timer['batch_data_end_time']
  342. )
  343. self._train_timer['count'] += 1
  344. samples = logs.get('batch_size', 1)
  345. self._train_timer['samples'] += samples
  346. if self._is_print() and self.train_step % self.log_freq == 0:
  347. if self.steps is None or self.train_step < self.steps:
  348. self._updates(logs, 'train')
  349. self._train_timer['batch_start_time'] = time.time()
  350. def on_epoch_end(self, epoch, logs=None):
  351. logs = logs or {}
  352. if self._is_print() and (self.steps is not None):
  353. self._updates(logs, 'train')
  354. def on_eval_begin(self, logs=None):
  355. self.eval_steps = logs.get('steps', None)
  356. self.eval_metrics = logs.get('metrics', [])
  357. self.eval_step = 0
  358. self.evaled_samples = 0
  359. self._eval_timer = {
  360. 'data_time': 0,
  361. 'batch_time': 0,
  362. 'count': 0,
  363. 'samples': 0,
  364. }
  365. self.eval_progbar = ProgressBar(
  366. num=self.eval_steps, verbose=self.verbose
  367. )
  368. if self._is_print():
  369. print('Eval begin...')
  370. self._eval_timer['batch_start_time'] = time.time()
  371. def on_eval_batch_begin(self, step, logs=None):
  372. self._eval_timer['batch_data_end_time'] = time.time()
  373. self._eval_timer['data_time'] += (
  374. self._eval_timer['batch_data_end_time']
  375. - self._eval_timer['batch_start_time']
  376. )
  377. def on_eval_batch_end(self, step, logs=None):
  378. logs = logs or {}
  379. self.eval_step += 1
  380. samples = logs.get('batch_size', 1)
  381. self.evaled_samples += samples
  382. self._eval_timer['batch_time'] += (
  383. time.time() - self._eval_timer['batch_data_end_time']
  384. )
  385. self._eval_timer['count'] += 1
  386. samples = logs.get('batch_size', 1)
  387. self._eval_timer['samples'] += samples
  388. if self._is_print() and self.eval_step % self.log_freq == 0:
  389. if self.eval_steps is None or self.eval_step < self.eval_steps:
  390. self._updates(logs, 'eval')
  391. self._eval_timer['batch_start_time'] = time.time()
  392. def on_predict_begin(self, logs=None):
  393. self.test_steps = logs.get('steps', None)
  394. self.test_metrics = logs.get('metrics', [])
  395. self.test_step = 0
  396. self.tested_samples = 0
  397. self._test_timer = {
  398. 'data_time': 0,
  399. 'batch_time': 0,
  400. 'count': 0,
  401. 'samples': 0,
  402. }
  403. self.test_progbar = ProgressBar(
  404. num=self.test_steps, verbose=self.verbose
  405. )
  406. if self._is_print():
  407. print('Predict begin...')
  408. self._test_timer['batch_start_time'] = time.time()
  409. def on_predict_batch_begin(self, step, logs=None):
  410. self._test_timer['batch_data_end_time'] = time.time()
  411. self._test_timer['data_time'] += (
  412. self._test_timer['batch_data_end_time']
  413. - self._test_timer['batch_start_time']
  414. )
  415. def on_predict_batch_end(self, step, logs=None):
  416. logs = logs or {}
  417. self.test_step += 1
  418. samples = logs.get('batch_size', 1)
  419. self.tested_samples += samples
  420. self._test_timer['batch_time'] += (
  421. time.time() - self._test_timer['batch_data_end_time']
  422. )
  423. self._test_timer['count'] += 1
  424. samples = logs.get('batch_size', 1)
  425. self._test_timer['samples'] += samples
  426. if self.test_step % self.log_freq == 0 and self._is_print():
  427. if self.test_steps is None or self.test_step < self.test_steps:
  428. self._updates(logs, 'test')
  429. self._test_timer['batch_start_time'] = time.time()
  430. def on_eval_end(self, logs=None):
  431. logs = logs or {}
  432. if self._is_print() and (self.eval_steps is not None):
  433. self._updates(logs, 'eval')
  434. print('Eval samples: %d' % (self.evaled_samples))
  435. def on_predict_end(self, logs=None):
  436. logs = logs or {}
  437. if self._is_print():
  438. if self.test_step % self.log_freq != 0 or self.verbose == 1:
  439. self._updates(logs, 'test')
  440. print('Predict samples: %d' % (self.tested_samples))
  441. class ModelCheckpoint(Callback):
  442. """
  443. Model checkpoint callback function to save model weights and optimizer
  444. state during training in conjunction with model.fit(). Currently,
  445. ModelCheckpoint only supports saving after a fixed number of epochs.
  446. Args:
  447. save_freq(int): The frequency, in number of epochs, the model checkpoint
  448. are saved. Default: 1.
  449. save_dir(str|None): The directory to save checkpoint during training.
  450. If None, will not save checkpoint. Default: None.
  451. Examples:
  452. .. code-block:: python
  453. >>> import paddle
  454. >>> import paddle.vision.transforms as T
  455. >>> from paddle.vision.datasets import MNIST
  456. >>> from paddle.static import InputSpec
  457. >>> inputs = [InputSpec([-1, 1, 28, 28], 'float32', 'image')]
  458. >>> labels = [InputSpec([None, 1], 'int64', 'label')]
  459. >>> transform = T.Compose([
  460. ... T.Transpose(),
  461. ... T.Normalize([127.5], [127.5])
  462. ... ])
  463. >>> train_dataset = MNIST(mode='train', transform=transform)
  464. >>> lenet = paddle.vision.models.LeNet()
  465. >>> model = paddle.Model(lenet,
  466. ... inputs, labels)
  467. >>> optim = paddle.optimizer.Adam(0.001, parameters=lenet.parameters())
  468. >>> model.prepare(optimizer=optim,
  469. ... loss=paddle.nn.CrossEntropyLoss(),
  470. ... metrics=paddle.metric.Accuracy())
  471. >>> callback = paddle.callbacks.ModelCheckpoint(save_dir='./temp')
  472. >>> model.fit(train_dataset, batch_size=64, callbacks=callback)
  473. """
  474. def __init__(self, save_freq=1, save_dir=None):
  475. self.save_freq = save_freq
  476. self.save_dir = save_dir
  477. def on_epoch_begin(self, epoch=None, logs=None):
  478. self.epoch = epoch
  479. def _is_save(self):
  480. return (
  481. self.model
  482. and self.save_dir
  483. and paddle.distributed.ParallelEnv().local_rank == 0
  484. )
  485. def on_epoch_end(self, epoch, logs=None):
  486. if self._is_save() and self.epoch % self.save_freq == 0:
  487. path = f'{self.save_dir}/{epoch}'
  488. print(f'save checkpoint at {os.path.abspath(path)}')
  489. self.model.save(path)
  490. def on_train_end(self, logs=None):
  491. if self._is_save():
  492. path = f'{self.save_dir}/final'
  493. print(f'save checkpoint at {os.path.abspath(path)}')
  494. self.model.save(path)
  495. class LRScheduler(Callback):
  496. """Lr scheduler callback function
  497. Args:
  498. by_step(bool, optional): whether to update learning rate scheduler
  499. by step. Default: True.
  500. by_epoch(bool, optional): whether to update learning rate scheduler
  501. by epoch. Default: False.
  502. Examples:
  503. .. code-block:: python
  504. >>> import paddle
  505. >>> import paddle.vision.transforms as T
  506. >>> from paddle.static import InputSpec
  507. >>> inputs = [InputSpec([-1, 1, 28, 28], 'float32', 'image')]
  508. >>> labels = [InputSpec([None, 1], 'int64', 'label')]
  509. >>> transform = T.Compose([
  510. ... T.Transpose(),
  511. ... T.Normalize([127.5], [127.5])
  512. ... ])
  513. >>> train_dataset = paddle.vision.datasets.MNIST(mode='train', transform=transform)
  514. >>> lenet = paddle.vision.models.LeNet()
  515. >>> model = paddle.Model(lenet,
  516. ... inputs, labels)
  517. >>> base_lr = 1e-3
  518. >>> boundaries = [5, 8]
  519. >>> wamup_steps = 4
  520. >>> def make_optimizer(parameters=None):
  521. ... momentum = 0.9
  522. ... weight_decay = 5e-4
  523. ... values = [base_lr * (0.1**i) for i in range(len(boundaries) + 1)]
  524. ... learning_rate = paddle.optimizer.lr.PiecewiseDecay(
  525. ... boundaries=boundaries, values=values)
  526. ... learning_rate = paddle.optimizer.lr.LinearWarmup(
  527. ... learning_rate=learning_rate,
  528. ... warmup_steps=wamup_steps,
  529. ... start_lr=base_lr / 5.,
  530. ... end_lr=base_lr,
  531. ... verbose=True)
  532. ... optimizer = paddle.optimizer.Momentum(
  533. ... learning_rate=learning_rate,
  534. ... weight_decay=weight_decay,
  535. ... momentum=momentum,
  536. ... parameters=parameters)
  537. ... return optimizer
  538. >>> optim = make_optimizer(parameters=lenet.parameters())
  539. >>> model.prepare(optimizer=optim,
  540. ... loss=paddle.nn.CrossEntropyLoss(),
  541. ... metrics=paddle.metric.Accuracy())
  542. >>> # if LRScheduler callback not set, an instance LRScheduler update by step
  543. >>> # will be created auto.
  544. >>> model.fit(train_dataset, batch_size=64)
  545. >>> # create a learning rate scheduler update by epoch
  546. >>> callback = paddle.callbacks.LRScheduler(by_step=False, by_epoch=True)
  547. >>> model.fit(train_dataset, batch_size=64, callbacks=callback)
  548. """
  549. def __init__(self, by_step=True, by_epoch=False):
  550. if by_step and by_epoch:
  551. raise ValueError(
  552. "by_step option is mutually exclusive with by_epoch"
  553. )
  554. self.by_step = by_step
  555. self.by_epoch = by_epoch
  556. def on_epoch_end(self, epoch, logs=None):
  557. if self.by_epoch:
  558. if (
  559. self.model._optimizer
  560. and hasattr(self.model._optimizer, '_learning_rate')
  561. and isinstance(
  562. self.model._optimizer._learning_rate,
  563. paddle.optimizer.lr.LRScheduler,
  564. )
  565. ):
  566. self.model._optimizer._learning_rate.step()
  567. def on_train_batch_end(self, step, logs=None):
  568. if self.by_step:
  569. if (
  570. self.model._optimizer
  571. and hasattr(self.model._optimizer, '_learning_rate')
  572. and isinstance(
  573. self.model._optimizer._learning_rate,
  574. paddle.optimizer.lr.LRScheduler,
  575. )
  576. ):
  577. self.model._optimizer._learning_rate.step()
  578. class EarlyStopping(Callback):
  579. """Stop training when the given monitor stopped improving during evaluation
  580. by setting `model.stop_training=True`.
  581. Args:
  582. monitor(str): Quantity to be monitored. Default: 'loss'.
  583. mode(str|None): Mode should be one of 'auto', 'min' or 'max'. In 'min'
  584. mode, training will stop until monitored quantity stops decreasing.
  585. In 'max' mode, training will stop until monitored quantity stops
  586. increasing. In 'auto' mode, exact mode can be inferred by the name
  587. of monitor. If 'acc' in monitor, the mode will be considered as
  588. 'max', otherwise the mode will be set to 'min'. Default: 'auto'.
  589. patience(int): Number of epochs with no improvement after which
  590. training will be stopped. Default: 0.
  591. verbose(int): The verbosity mode, should be 0 or 1. When verbose=0,
  592. logs will not be printed. When verbose=1, logs will be printed.
  593. Default: 1.
  594. min_delta(int|float): The minimum change of monitored quantity. If
  595. the change is less than min_delta, model could be considered as no
  596. improvement. Default: 0.
  597. baseline(int|float|None): Baseline value for the monitored quantity.
  598. Training will stop if the model doesn't show improvement over the
  599. baseline. Default: None.
  600. save_best_model(bool): Whether to save best model. Default: True.
  601. Examples:
  602. .. code-block:: python
  603. >>> import paddle
  604. >>> from paddle import Model
  605. >>> from paddle.static import InputSpec
  606. >>> from paddle.vision.models import LeNet
  607. >>> from paddle.vision.datasets import MNIST
  608. >>> from paddle.metric import Accuracy
  609. >>> from paddle.nn import CrossEntropyLoss
  610. >>> import paddle.vision.transforms as T
  611. >>> device = paddle.set_device('cpu')
  612. >>> sample_num = 200
  613. >>> save_dir = './best_model_checkpoint'
  614. >>> transform = T.Compose(
  615. ... [T.Transpose(), T.Normalize([127.5], [127.5])])
  616. >>> train_dataset = MNIST(mode='train', transform=transform)
  617. >>> val_dataset = MNIST(mode='test', transform=transform)
  618. >>> net = LeNet()
  619. >>> optim = paddle.optimizer.Adam(
  620. ... learning_rate=0.001, parameters=net.parameters())
  621. >>> inputs = [InputSpec([None, 1, 28, 28], 'float32', 'x')]
  622. >>> labels = [InputSpec([None, 1], 'int64', 'label')]
  623. >>> model = Model(net, inputs=inputs, labels=labels)
  624. >>> model.prepare(
  625. ... optim,
  626. ... loss=CrossEntropyLoss(reduction="sum"),
  627. ... metrics=[Accuracy()])
  628. >>> callbacks = paddle.callbacks.EarlyStopping(
  629. ... 'loss',
  630. ... mode='min',
  631. ... patience=1,
  632. ... verbose=1,
  633. ... min_delta=0,
  634. ... baseline=None,
  635. ... save_best_model=True)
  636. >>> model.fit(train_dataset,
  637. ... val_dataset,
  638. ... batch_size=64,
  639. ... log_freq=200,
  640. ... save_freq=10,
  641. ... save_dir=save_dir,
  642. ... epochs=20,
  643. ... callbacks=[callbacks])
  644. """
  645. def __init__(
  646. self,
  647. monitor='loss',
  648. mode='auto',
  649. patience=0,
  650. verbose=1,
  651. min_delta=0,
  652. baseline=None,
  653. save_best_model=True,
  654. ):
  655. super().__init__()
  656. self.monitor = monitor
  657. self.patience = patience
  658. self.verbose = verbose
  659. self.baseline = baseline
  660. self.min_delta = abs(min_delta)
  661. self.wait_epoch = 0
  662. self.best_weights = None
  663. self.stopped_epoch = 0
  664. self.save_best_model = save_best_model
  665. # The value of `save_dir` is set in function `config_callbacks`
  666. self.save_dir = None
  667. if mode not in ['auto', 'min', 'max']:
  668. warnings.warn(
  669. 'EarlyStopping mode %s is unknown, '
  670. 'fallback to auto mode.' % mode
  671. )
  672. mode = 'auto'
  673. if mode == 'min':
  674. self.monitor_op = np.less
  675. elif mode == 'max':
  676. self.monitor_op = np.greater
  677. # When mode == 'auto', the mode should be inferred by `self.monitor`
  678. else:
  679. if 'acc' in self.monitor:
  680. self.monitor_op = np.greater
  681. else:
  682. self.monitor_op = np.less
  683. if self.monitor_op == np.greater:
  684. self.min_delta *= 1
  685. else:
  686. self.min_delta *= -1
  687. def on_train_begin(self, logs=None):
  688. self.wait_epoch = 0
  689. if self.baseline is not None:
  690. self.best_value = self.baseline
  691. else:
  692. self.best_value = np.inf if self.monitor_op == np.less else -np.inf
  693. self.best_weights = None
  694. def on_eval_end(self, logs=None):
  695. if logs is None or self.monitor not in logs:
  696. warnings.warn(
  697. 'Monitor of EarlyStopping should be loss or metric name.'
  698. )
  699. return
  700. current = logs[self.monitor]
  701. if isinstance(current, (list, tuple)):
  702. current = current[0]
  703. elif isinstance(current, numbers.Number):
  704. current = current
  705. else:
  706. return
  707. if self.monitor_op(current - self.min_delta, self.best_value):
  708. self.best_value = current
  709. self.wait_epoch = 0
  710. if self.save_best_model and self.save_dir is not None:
  711. path = os.path.join(self.save_dir, 'best_model')
  712. self.model.save(path)
  713. else:
  714. self.wait_epoch += 1
  715. if self.wait_epoch >= self.patience:
  716. self.model.stop_training = True
  717. if self.verbose > 0:
  718. print('Epoch %d: Early stopping.' % (self.stopped_epoch + 1))
  719. if self.save_best_model and self.save_dir is not None:
  720. print(
  721. 'Best checkpoint has been saved at %s'
  722. % (
  723. os.path.abspath(
  724. os.path.join(self.save_dir, 'best_model')
  725. )
  726. )
  727. )
  728. self.stopped_epoch += 1
  729. class VisualDL(Callback):
  730. """
  731. VisualDL callback class. After storing the loss values and evaluation metrics in a log file during the training time , the panel is launched to view the visual results.
  732. Args:
  733. log_dir (str): The directory to save visualdl log file.
  734. Examples:
  735. .. code-block:: python
  736. >>> import paddle
  737. >>> import paddle.vision.transforms as T
  738. >>> from paddle.static import InputSpec
  739. >>> inputs = [InputSpec([-1, 1, 28, 28], 'float32', 'image')]
  740. >>> labels = [InputSpec([None, 1], 'int64', 'label')]
  741. >>> transform = T.Compose([
  742. ... T.Transpose(),
  743. ... T.Normalize([127.5], [127.5])
  744. ... ])
  745. >>> train_dataset = paddle.vision.datasets.MNIST(mode='train', transform=transform)
  746. >>> eval_dataset = paddle.vision.datasets.MNIST(mode='test', transform=transform)
  747. >>> net = paddle.vision.models.LeNet()
  748. >>> model = paddle.Model(net, inputs, labels)
  749. >>> optim = paddle.optimizer.Adam(0.001, parameters=net.parameters())
  750. >>> model.prepare(optimizer=optim,
  751. ... loss=paddle.nn.CrossEntropyLoss(),
  752. ... metrics=paddle.metric.Accuracy())
  753. >>> ## uncomment following lines to fit model with visualdl callback function
  754. >>> # callback = paddle.callbacks.VisualDL(log_dir='visualdl_log_dir')
  755. >>> # model.fit(train_dataset, eval_dataset, batch_size=64, callbacks=callback)
  756. """
  757. def __init__(self, log_dir):
  758. self.log_dir = log_dir
  759. self.epochs = None
  760. self.steps = None
  761. self.epoch = 0
  762. def _is_write(self):
  763. return paddle.distributed.ParallelEnv().local_rank == 0
  764. def on_train_begin(self, logs=None):
  765. self.epochs = self.params['epochs']
  766. assert self.epochs
  767. self.train_metrics = self.params['metrics']
  768. assert self.train_metrics
  769. self._is_fit = True
  770. self.train_step = 0
  771. def on_epoch_begin(self, epoch=None, logs=None):
  772. self.steps = self.params['steps']
  773. self.epoch = epoch
  774. def _updates(self, logs, mode):
  775. if not self._is_write():
  776. return
  777. if not hasattr(self, 'writer'):
  778. visualdl = try_import('visualdl')
  779. self.writer = visualdl.LogWriter(self.log_dir)
  780. metrics = getattr(self, '%s_metrics' % (mode))
  781. current_step = getattr(self, '%s_step' % (mode))
  782. if mode == 'train':
  783. total_step = current_step
  784. else:
  785. total_step = self.epoch
  786. for k in metrics:
  787. if k in logs:
  788. temp_tag = mode + '/' + k
  789. if isinstance(logs[k], (list, tuple)):
  790. temp_value = logs[k][0]
  791. elif isinstance(logs[k], numbers.Number):
  792. temp_value = logs[k]
  793. else:
  794. continue
  795. self.writer.add_scalar(
  796. tag=temp_tag, step=total_step, value=temp_value
  797. )
  798. def on_train_batch_end(self, step, logs=None):
  799. logs = logs or {}
  800. self.train_step += 1
  801. if self._is_write():
  802. self._updates(logs, 'train')
  803. def on_eval_begin(self, logs=None):
  804. self.eval_steps = logs.get('steps', None)
  805. self.eval_metrics = logs.get('metrics', [])
  806. self.eval_step = 0
  807. self.evaled_samples = 0
  808. def on_train_end(self, logs=None):
  809. if hasattr(self, 'writer'):
  810. self.writer.close()
  811. delattr(self, 'writer')
  812. def on_eval_end(self, logs=None):
  813. if self._is_write():
  814. self._updates(logs, 'eval')
  815. if (not hasattr(self, '_is_fit')) and hasattr(self, 'writer'):
  816. self.writer.close()
  817. delattr(self, 'writer')
  818. class WandbCallback(Callback):
  819. """Track your training and system metrics using `Weights and Biases <https://docs.wandb.ai>`_.
  820. **Installation and set-up**
  821. Install with pip and log in to your W&B account:
  822. .. code-block:: bash
  823. pip install wandb
  824. wandb login
  825. Args:
  826. project(str, optional): Name of the project. Default: uncategorized
  827. entity(str, optional): Name of the team/user creating the run. Default: Logged in user
  828. name(str, optional): Name of the run. Default: randomly generated by wandb
  829. dir(str, optional): Directory in which all the metadata is stored. Default: `wandb`
  830. mode(str, optional): Can be "online", "offline" or "disabled". Default: "online".
  831. job_type(str, optional): the type of run, for grouping runs together. Default: None
  832. Examples:
  833. .. code-block:: python
  834. >>> import paddle
  835. >>> import paddle.vision.transforms as T
  836. >>> from paddle.static import InputSpec
  837. >>> inputs = [InputSpec([-1, 1, 28, 28], 'float32', 'image')]
  838. >>> labels = [InputSpec([None, 1], 'int64', 'label')]
  839. >>> transform = T.Compose([
  840. ... T.Transpose(),
  841. ... T.Normalize([127.5], [127.5])
  842. ... ])
  843. >>> train_dataset = paddle.vision.datasets.MNIST(mode='train', transform=transform)
  844. >>> eval_dataset = paddle.vision.datasets.MNIST(mode='test', transform=transform)
  845. >>> net = paddle.vision.models.LeNet()
  846. >>> model = paddle.Model(net, inputs, labels)
  847. >>> optim = paddle.optimizer.Adam(0.001, parameters=net.parameters())
  848. >>> model.prepare(optimizer=optim,
  849. ... loss=paddle.nn.CrossEntropyLoss(),
  850. ... metrics=paddle.metric.Accuracy())
  851. >>> ## uncomment following lines to fit model with wandb callback function
  852. >>> # callback = paddle.callbacks.WandbCallback(project='paddle_mnist')
  853. >>> # model.fit(train_dataset, eval_dataset, batch_size=64, callbacks=callback)
  854. """
  855. def __init__(
  856. self,
  857. project=None,
  858. entity=None,
  859. name=None,
  860. dir=None,
  861. mode=None,
  862. job_type=None,
  863. **kwargs,
  864. ):
  865. self.wandb = try_import(
  866. "wandb",
  867. "You want to use `wandb` which is not installed yet install it with `pip install wandb`",
  868. )
  869. self.wandb_args = {
  870. 'project': project,
  871. 'name': name,
  872. 'entity': entity,
  873. 'dir': dir,
  874. 'mode': mode,
  875. 'job_type': job_type,
  876. }
  877. self._run = None
  878. self.wandb_args.update(**kwargs)
  879. _ = self.run
  880. def _is_write(self):
  881. return paddle.distributed.ParallelEnv().local_rank == 0
  882. @property
  883. def run(self):
  884. if self._is_write():
  885. if self._run is None:
  886. if self.wandb.run is not None:
  887. warnings.warn(
  888. "There is a wandb run already in progress and newly created instances"
  889. " of `WandbCallback` will reuse this run. If this is not desired"
  890. " , call `wandb.finish()` before instantiating `WandbCallback`."
  891. )
  892. self._run = self.wandb.run
  893. else:
  894. self._run = self.wandb.init(**self.wandb_args)
  895. return self._run
  896. def on_train_begin(self, logs=None):
  897. self.epochs = self.params['epochs']
  898. assert self.epochs
  899. self.train_metrics = self.params['metrics']
  900. assert self.train_metrics
  901. self._is_fit = True
  902. self.train_step = 0
  903. if self._is_write():
  904. self.run.define_metric("train/step")
  905. self.run.define_metric("train/*", step_metric="train/step")
  906. self.run.define_metric("epoch")
  907. self.run.define_metric("eval/*", step_metric="epoch")
  908. def on_epoch_begin(self, epoch, logs=None):
  909. self.steps = self.params['steps']
  910. self.epoch = epoch
  911. def _updates(self, logs, mode):
  912. if not self._is_write():
  913. return
  914. metrics = getattr(self, '%s_metrics' % (mode))
  915. current_step = getattr(self, '%s_step' % (mode))
  916. _metrics = {}
  917. if mode == 'train':
  918. total_step = current_step
  919. _metrics.update({'train/step': total_step})
  920. else:
  921. total_step = self.epoch
  922. _metrics.update({'epoch': total_step})
  923. for k in metrics:
  924. if k in logs:
  925. temp_tag = mode + '/' + k
  926. if isinstance(logs[k], (list, tuple)):
  927. _metrics.update({temp_tag: logs[k][0]})
  928. elif isinstance(logs[k], numbers.Number):
  929. _metrics.update({temp_tag: logs[k]})
  930. else:
  931. continue
  932. self.run.log(_metrics)
  933. def on_train_batch_end(self, step, logs=None):
  934. logs = logs or {}
  935. self.train_step += 1
  936. if self._is_write():
  937. self._updates(logs, 'train')
  938. def on_eval_begin(self, logs=None):
  939. self.eval_steps = logs.get('steps', None)
  940. self.eval_metrics = logs.get('metrics', [])
  941. self.eval_step = 0
  942. self.evaled_samples = 0
  943. def on_train_end(self, logs=None):
  944. if self._is_write():
  945. self.run.finish()
  946. def on_eval_end(self, logs=None):
  947. if self._is_write():
  948. self._updates(logs, 'eval')
  949. if (not hasattr(self, '_is_fit')) and hasattr(self, 'run'):
  950. self.run.finish()
  951. delattr(self, 'run')
  952. class ReduceLROnPlateau(Callback):
  953. """Reduce learning rate when a metric of evaluation has stopped improving.
  954. Models often benefit from reducing the learning rate by a factor
  955. of 2-10 once learning stagnates. This callback monitors a
  956. quantity and if no improvement is seen for a 'patience' number
  957. of epochs, the learning rate is reduced.
  958. Args:
  959. monitor(str, optional): Quantity to be monitored. Default: 'loss'.
  960. factor(float, optional): factor by which the learning rate will be reduced.
  961. `new_lr = lr * factor`. Default: 0.1.
  962. patience(int, optional): Number of epochs with no improvement after which
  963. learning rate will be reduced. Default: 10.
  964. verbose(int, optional): The verbosity mode. 0: quiet, 1: update messages.
  965. Default: 1.
  966. mode(str, optional): one of `{'auto', 'min', 'max'}`. In `'min'` mode,
  967. the learning rate will be reduced when the quantity monitored has
  968. stopped decreasing. In 'max' mode, learning rate will reduce until
  969. monitored quantity stops increasing. In 'auto' mode, exact mode
  970. can be inferred by the name of monitor. If 'acc' in monitor, the
  971. mode will be considered as 'max', otherwise the mode will be set
  972. to 'min'. Default: 'auto'.
  973. min_delta(int|float, optional): threshold for measuring the new optimum,
  974. to only focus on significant changes. Default: 0.
  975. cooldown(int, optional): number of epochs to wait before resuming normal operation after
  976. lr has been reduced. Default: 0.
  977. min_lr(float, optional): lower bound on the learning rate. Default: 0.
  978. Examples:
  979. .. code-block:: python
  980. >>> import paddle
  981. >>> from paddle import Model
  982. >>> from paddle.static import InputSpec
  983. >>> from paddle.vision.models import LeNet
  984. >>> from paddle.vision.datasets import MNIST
  985. >>> from paddle.metric import Accuracy
  986. >>> from paddle.nn.layer.loss import CrossEntropyLoss
  987. >>> import paddle.vision.transforms as T
  988. >>> sample_num = 200
  989. >>> transform = T.Compose(
  990. ... [T.Transpose(), T.Normalize([127.5], [127.5])])
  991. >>> train_dataset = MNIST(mode='train', transform=transform)
  992. >>> val_dataset = MNIST(mode='test', transform=transform)
  993. >>> net = LeNet()
  994. >>> optim = paddle.optimizer.Adam(
  995. ... learning_rate=0.001, parameters=net.parameters())
  996. >>> inputs = [InputSpec([None, 1, 28, 28], 'float32', 'x')]
  997. >>> labels = [InputSpec([None, 1], 'int64', 'label')]
  998. >>> model = Model(net, inputs=inputs, labels=labels)
  999. >>> model.prepare(
  1000. ... optim,
  1001. ... loss=CrossEntropyLoss(),
  1002. ... metrics=[Accuracy()])
  1003. >>> callbacks = paddle.callbacks.ReduceLROnPlateau(patience=3, verbose=1)
  1004. >>> model.fit(train_dataset,
  1005. ... val_dataset,
  1006. ... batch_size=64,
  1007. ... log_freq=200,
  1008. ... save_freq=10,
  1009. ... epochs=20,
  1010. ... callbacks=[callbacks])
  1011. """
  1012. def __init__(
  1013. self,
  1014. monitor='loss',
  1015. factor=0.1,
  1016. patience=10,
  1017. verbose=1,
  1018. mode='auto',
  1019. min_delta=1e-4,
  1020. cooldown=0,
  1021. min_lr=0,
  1022. ):
  1023. super().__init__()
  1024. self.monitor = monitor
  1025. if factor >= 1.0:
  1026. raise ValueError(
  1027. 'ReduceLROnPlateau ' 'does not support a factor >= 1.0.'
  1028. )
  1029. self.factor = factor
  1030. self.min_lr = min_lr
  1031. self.min_delta = min_delta
  1032. self.patience = patience
  1033. self.verbose = verbose
  1034. self.cooldown = cooldown
  1035. self.cooldown_counter = 0 # Cooldown counter.
  1036. self.wait = 0
  1037. self.best = 0
  1038. self.mode = mode
  1039. self.monitor_op = None
  1040. self.epoch = 0
  1041. self._reset()
  1042. def _reset(self):
  1043. """Resets wait counter and cooldown counter."""
  1044. if self.mode not in ['auto', 'min', 'max']:
  1045. warnings.warn(
  1046. 'Learning rate reduction mode %s is unknown, '
  1047. 'fallback to auto mode.' % self.mode
  1048. )
  1049. self.mode = 'auto'
  1050. if self.mode == 'min' or (
  1051. self.mode == 'auto' and 'acc' not in self.monitor
  1052. ):
  1053. self.monitor_op = lambda a, b: np.less(a, b - self.min_delta)
  1054. self.best = np.inf
  1055. else:
  1056. self.monitor_op = lambda a, b: np.greater(a, b + self.min_delta)
  1057. self.best = -np.inf
  1058. self.cooldown_counter = 0
  1059. self.wait = 0
  1060. def on_train_begin(self, logs=None):
  1061. self._reset()
  1062. def on_eval_end(self, logs=None):
  1063. if logs is None or self.monitor not in logs:
  1064. warnings.warn(
  1065. 'Monitor of ReduceLROnPlateau should be loss or metric name.'
  1066. )
  1067. return
  1068. else:
  1069. try:
  1070. lr = self.model._optimizer._learning_rate
  1071. if not isinstance(lr, float):
  1072. warnings.warn(
  1073. f'Expected learning_rate be float, bug got {type(lr)}.'
  1074. )
  1075. return
  1076. except Exception as e:
  1077. warnings.warn(
  1078. f'There are something wrong when get learning_rate from optimizer: {e}.'
  1079. )
  1080. return
  1081. current = logs[self.monitor]
  1082. if isinstance(current, (list, tuple)):
  1083. current = current[0]
  1084. elif isinstance(current, numbers.Number):
  1085. current = current
  1086. else:
  1087. return
  1088. if self.in_cooldown():
  1089. self.cooldown_counter -= 1
  1090. self.wait = 0
  1091. if self.monitor_op(current, self.best):
  1092. self.best = current
  1093. self.wait = 0
  1094. elif not self.in_cooldown():
  1095. self.wait += 1
  1096. if self.wait >= self.patience:
  1097. old_lr = self.model._optimizer.get_lr()
  1098. if old_lr > np.float32(self.min_lr):
  1099. new_lr = old_lr * self.factor
  1100. new_lr = max(new_lr, self.min_lr)
  1101. self.model._optimizer._learning_rate = new_lr
  1102. if (
  1103. self.verbose > 0
  1104. and paddle.distributed.ParallelEnv().local_rank == 0
  1105. ):
  1106. print(
  1107. '\nEpoch %d: ReduceLROnPlateau reducing learning '
  1108. 'rate to %s.' % (self.epoch + 1, new_lr)
  1109. )
  1110. self.cooldown_counter = self.cooldown
  1111. self.wait = 0
  1112. self.epoch += 1
  1113. def in_cooldown(self):
  1114. return self.cooldown_counter > 0