diff --git a/paddle/scripts/paddle_build.sh b/paddle/scripts/paddle_build.sh index 69303013d2a41a049276c0d1b03b9d902b555d23..1658f31ddb56c0e98c7d2919832e657c950ed484 100755 --- a/paddle/scripts/paddle_build.sh +++ b/paddle/scripts/paddle_build.sh @@ -1348,7 +1348,7 @@ EOF # run paddle version to install python packages first RUN apt-get update && ${NCCL_DEPS} RUN apt-get install -y wget python3 python3-pip libgtk2.0-dev dmidecode python3-tk && \ - pip3 install opencv-python py-cpuinfo==5.0.0 && wget ${ref_web}/${ref_paddle35} && ${ref_paddle35_mv1} pip3 install ${ref_paddle35_whl} ${ref_paddle35_mv2}; apt-get install -f -y && \ + pip3 install opencv-python visualdl py-cpuinfo==5.0.0 && wget ${ref_web}/${ref_paddle35} && ${ref_paddle35_mv1} pip3 install ${ref_paddle35_whl} ${ref_paddle35_mv2}; apt-get install -f -y && \ apt-get clean -y && \ rm -f ${ref_paddle35} && \ ldconfig @@ -1370,7 +1370,7 @@ EOF CFLAGS="-Wformat" ./configure --prefix=/usr/local/ --enable-shared > /dev/null && \ make -j8 > /dev/null && make altinstall > /dev/null && cd ../ && rm Python-3.6.0.tgz RUN apt-get install -y libgtk2.0-dev dmidecode python3-tk && ldconfig && \ - pip3.6 install opencv-python && wget ${ref_web}/${ref_paddle36} && ${ref_paddle36_mv1} pip3.6 install ${ref_paddle36_whl} ${ref_paddle36_mv2}; apt-get install -f -y && \ + pip3.6 install opencv-python visualdl && wget ${ref_web}/${ref_paddle36} && ${ref_paddle36_mv1} pip3.6 install ${ref_paddle36_whl} ${ref_paddle36_mv2}; apt-get install -f -y && \ apt-get clean -y && \ rm -f ${ref_paddle36} && \ ldconfig @@ -1386,7 +1386,7 @@ EOF CFLAGS="-Wformat" ./configure --prefix=/usr/local/ --enable-shared > /dev/null && \ make -j8 > /dev/null && make altinstall > /dev/null && cd ../ && rm Python-3.7.0.tgz RUN apt-get install -y libgtk2.0-dev dmidecode python3-tk && ldconfig && \ - pip3.7 install opencv-python && wget ${ref_web}/${ref_paddle37} && pip3.7 install ${ref_paddle37_whl}; apt-get install -f -y && \ + pip3.7 install opencv-python visualdl && wget ${ref_web}/${ref_paddle37} && pip3.7 install ${ref_paddle37_whl}; apt-get install -f -y && \ apt-get clean -y && \ rm -f ${ref_paddle37} && \ ldconfig @@ -1402,7 +1402,7 @@ EOF CFLAGS="-Wformat" ./configure --prefix=/usr/local/ --enable-shared > /dev/null && \ make -j8 > /dev/null && make altinstall > /dev/null && cd ../ && rm Python-3.8.0.tgz RUN apt-get install -y libgtk2.0-dev dmidecode python3-tk && ldconfig && \ - pip3.8 install opencv-python && wget ${ref_web}/${ref_paddle38} && pip3.8 install ${ref_paddle38_whl}; apt-get install -f -y && \ + pip3.8 install opencv-python visualdl && wget ${ref_web}/${ref_paddle38} && pip3.8 install ${ref_paddle38_whl}; apt-get install -f -y && \ apt-get clean -y && \ rm -f ${ref_paddle38} && \ ldconfig diff --git a/python/paddle/hapi/callbacks.py b/python/paddle/hapi/callbacks.py index 7ed571fa9c6a4a962b20397c999368dad0734ff0..b72ae389019948663b4c2eb618e7f9a7b20e51fc 100644 --- a/python/paddle/hapi/callbacks.py +++ b/python/paddle/hapi/callbacks.py @@ -15,6 +15,7 @@ import os from paddle.fluid.dygraph.parallel import ParallelEnv +from paddle.utils import try_import from .progressbar import ProgressBar @@ -469,3 +470,111 @@ class ModelCheckpoint(Callback): path = '{}/final'.format(self.save_dir) print('save checkpoint at {}'.format(os.path.abspath(path))) self.model.save(path) + + +class VisualDL(Callback): + """VisualDL callback function + Args: + log_dir (str): The directory to save visualdl log file. + + Examples: + .. code-block:: python + + import paddle + from paddle.static import InputSpec + + inputs = [InputSpec([-1, 1, 28, 28], 'float32', 'image')] + labels = [InputSpec([None, 1], 'int64', 'label')] + + train_dataset = paddle.vision.datasets.MNIST(mode='train') + eval_dataset = paddle.vision.datasets.MNIST(mode='test') + + net = paddle.vision.LeNet() + model = paddle.Model(net, inputs, labels) + + optim = paddle.optimizer.Adam(0.001, parameters=net.parameters()) + model.prepare(optimizer=optim, + loss=paddle.nn.CrossEntropyLoss(), + metrics=paddle.metric.Accuracy()) + + callback = paddle.callbacks.VisualDL(log_dir='visualdl_log_dir') + model.fit(train_dataset, eval_dataset, batch_size=64, callbacks=callback) + + """ + + def __init__(self, log_dir): + self.log_dir = log_dir + self.epochs = None + self.steps = None + + def _is_write(self): + return ParallelEnv().local_rank == 0 + + def on_train_begin(self, logs=None): + self.epochs = self.params['epochs'] + assert self.epochs + self.train_metrics = self.params['metrics'] + assert self.train_metrics + self._is_fit = True + + def on_epoch_begin(self, epoch=None, logs=None): + visualdl = try_import('visualdl') + self.steps = self.params['steps'] + self.epoch = epoch + self.train_step = 0 + self.train_writer = visualdl.LogWriter(self.log_dir) + + def _updates(self, logs, mode): + metrics = getattr(self, '%s_metrics' % (mode)) + writer = getattr(self, '%s_writer' % (mode)) + current_step = getattr(self, '%s_step' % (mode)) + if mode == 'train': + total_step = self.epoch * self.steps + current_step + else: + total_step = self.epoch + + for k in metrics: + if k in logs: + temp_tag = mode + '/' + k + + if isinstance(logs[k], (list, tuple)): + temp_value = logs[k][0] + elif isinstance(logs[k], numbers.Number): + temp_value = logs[k] + else: + continue + writer.add_scalar( + tag=temp_tag, step=total_step, value=temp_value) + + def on_train_batch_end(self, step, logs=None): + logs = logs or {} + self.train_step += 1 + + if self._is_write(): + if self.steps is None or self.train_step < self.steps: + self._updates(logs, 'train') + + def on_epoch_end(self, epoch, logs=None): + logs = logs or {} + if self._is_write() and (self.steps is not None): + self._updates(logs, 'train') + + def on_eval_begin(self, logs=None): + visualdl = try_import('visualdl') + self.eval_steps = logs.get('steps', None) + self.eval_metrics = logs.get('metrics', []) + self.eval_step = 0 + self.evaled_samples = 0 + self.eval_writer = visualdl.LogWriter(self.log_dir) + + def on_train_end(self, logs=None): + if hasattr(self, 'train_writer'): + self.train_writer.close() + if hasattr(self, 'eval_writer'): + self.eval_writer.close() + + def on_eval_end(self, logs=None): + self._updates(logs, 'eval') + + if (not hasattr(self, '_is_fit')) and hasattr(self, 'eval_writer'): + self.eval_writer.close() diff --git a/python/paddle/tests/test_callbacks.py b/python/paddle/tests/test_callbacks.py index f0d9a132b90eb1c7006fd53557a03376394ee2ab..0c8f25af33a82c496e1e7375d93d245175870081 100644 --- a/python/paddle/tests/test_callbacks.py +++ b/python/paddle/tests/test_callbacks.py @@ -17,6 +17,7 @@ import time import random import tempfile import shutil +import paddle from paddle import Model from paddle.static import InputSpec @@ -102,6 +103,33 @@ class TestCallbacks(unittest.TestCase): self.verbose = 2 self.run_callback() + def test_visualdl_callback(self): + try: + import visualdl + except: + return + + inputs = [InputSpec([-1, 1, 28, 28], 'float32', 'image')] + labels = [InputSpec([None, 1], 'int64', 'label')] + + train_dataset = paddle.vision.datasets.MNIST(mode='train') + eval_dataset = paddle.vision.datasets.MNIST(mode='test') + + net = paddle.vision.LeNet() + model = paddle.Model(net, inputs, labels) + + optim = paddle.optimizer.Adam(0.001, parameters=net.parameters()) + model.prepare( + optimizer=optim, + loss=paddle.nn.CrossEntropyLoss(), + metrics=paddle.metric.Accuracy()) + + callback = paddle.callbacks.VisualDL(log_dir='visualdl_log_dir') + model.fit(train_dataset, + eval_dataset, + batch_size=64, + callbacks=callback) + if __name__ == '__main__': unittest.main()