From 64ec05bb4f213a55ce9f83f6a581624e3a5dcf20 Mon Sep 17 00:00:00 2001 From: "Matthias J. Ehrhardt" Date: Thu, 5 Oct 2017 12:46:56 +0100 Subject: [PATCH 1/6] Improve callbacks by kwargs and add total time --- odl/solvers/util/callback.py | 127 +++++++++++++++++++++++++++++------ 1 file changed, 108 insertions(+), 19 deletions(-) diff --git a/odl/solvers/util/callback.py b/odl/solvers/util/callback.py index 6309f1bcf33..3654335cc9d 100644 --- a/odl/solvers/util/callback.py +++ b/odl/solvers/util/callback.py @@ -20,10 +20,11 @@ from odl.util import signature_string __all__ = ('Callback', 'CallbackStore', 'CallbackApply', - 'CallbackPrintTiming', 'CallbackPrintIteration', - 'CallbackPrint', 'CallbackPrintNorm', 'CallbackShow', - 'CallbackSaveToDisk', 'CallbackSleep', 'CallbackShowConvergence', - 'CallbackPrintHardwareUsage', 'CallbackProgressBar') + 'CallbackPrintTiming', 'CallbackPrintTotalTime', + 'CallbackPrintIteration', 'CallbackPrint', 'CallbackPrintNorm', + 'CallbackShow', 'CallbackSaveToDisk', 'CallbackSleep', + 'CallbackShowConvergence', 'CallbackPrintHardwareUsage', + 'CallbackProgressBar') class Callback(object): @@ -335,7 +336,7 @@ class CallbackPrintIteration(Callback): """Callback for printing the iteration count.""" - def __init__(self, fmt='iter = {}', step=1): + def __init__(self, fmt='iter = {}', step=1, **kwargs): """Initialize a new instance. Parameters @@ -349,6 +350,11 @@ def __init__(self, fmt='iter = {}', step=1): step : positive int, optional Number of iterations between output. + Other Parameters + ---------------- + kwargs : + Key word arguments passed to the print function. + Examples -------- Create simple callback that prints iteration count: @@ -373,11 +379,12 @@ def __init__(self, fmt='iter = {}', step=1): self.fmt = str(fmt) self.step = int(step) self.iter = 0 + self.kwargs = kwargs def __call__(self, _): """Print the current iteration.""" if self.iter % self.step == 0: - print(self.fmt.format(self.iter)) + print(self.fmt.format(self.iter), **self.kwargs) self.iter += 1 @@ -403,7 +410,7 @@ class CallbackPrintTiming(Callback): """Callback for printing the time elapsed since the previous iteration.""" - def __init__(self, fmt='Time elapsed = {:<5.03f} s', step=1): + def __init__(self, fmt='Time elapsed = {:<5.03f} s', step=1, **kwargs): """Initialize a new instance. Parameters @@ -411,23 +418,31 @@ def __init__(self, fmt='Time elapsed = {:<5.03f} s', step=1): fmt : string, optional Formating that should be applied. The time is printed as :: - print(fmt.format(runtime)) + print(fmt.format(runtime, totaltime)) where ``runtime`` is the runtime since the last iterate. step : positive int, optional Number of iterations between prints. + + Other Parameters + ---------------- + kwargs : + Key word arguments passed to the print function. """ self.fmt = str(fmt) self.step = int(step) self.iter = 0 - + self.total_time = 0 self.time = time.time() + self.kwargs = kwargs def __call__(self, _): """Print time elapsed from the previous iteration.""" if self.iter % self.step == 0: t = time.time() - print(self.fmt.format(t - self.time)) + dt = t - self.time + self.total_time += dt + print(self.fmt.format(dt, self.total_time), **self.kwargs) self.time = t self.iter += 1 @@ -436,6 +451,7 @@ def reset(self): """Set `time` to the current time.""" self.time = time.time() self.iter = 0 + self.total_time = 0 def __repr__(self): """Return ``repr(self)``.""" @@ -445,11 +461,64 @@ def __repr__(self): return '{}({})'.format(self.__class__.__name__, inner_str) +class CallbackPrintTotalTime(Callback): + + """Callback for printing the total runtime at each iteration.""" + + def __init__(self, fmt='Total time elapsed = {:<5.03f} s', step=1, + **kwargs): + """Initialize a new instance. + + Parameters + ---------- + fmt : string, optional + Formating that should be applied. The time is printed as :: + + print(fmt.format(totaltime)) + + where ``totaltime`` is the total runtime. + step : positive int, optional + Number of iterations between prints. + + Other Parameters + ---------------- + kwargs : + Key word arguments passed to the print function. + """ + self.fmt = str(fmt) + self.step = int(step) + self.iter = 0 + self.total_time = 0 + self.time = time.time() + self.kwargs = kwargs + + def __call__(self, _): + """Print time elapsed from the previous iteration.""" + if self.iter % self.step == 0: + self.total_time = time.time() - self.time + print(self.fmt.format(self.total_time), **self.kwargs) + + self.iter += 1 + + def reset(self): + """Set `time` to the current time.""" + self.time = time.time() + self.iter = 0 + self.total_time = 0 + + def __repr__(self): + """Return ``repr(self)``.""" + optargs = [('fmt', self.fmt, 'Total time elapsed = {:<5.03f} s'), + ('step', self.step, 1)] + inner_str = signature_string([], optargs) + return '{}({})'.format(self.__class__.__name__, inner_str) + + class CallbackPrint(Callback): """Callback for printing the current value.""" - def __init__(self, func=None, fmt='{!r}', step=1): + def __init__(self, func=None, fmt='{!r}', step=1, **kwargs): """Initialize a new instance. Parameters @@ -467,6 +536,11 @@ def __init__(self, func=None, fmt='{!r}', step=1): step : positive int, optional Number of iterations between prints. + Other Parameters + ---------------- + kwargs : + Key word arguments passed to the print function. + Examples -------- Callback for simply printing the current iterate: @@ -499,6 +573,7 @@ def __init__(self, func=None, fmt='{!r}', step=1): self.fmt = str(fmt) self.step = int(step) self.iter = 0 + self.kwargs = kwargs def __call__(self, result): """Print the current value.""" @@ -506,7 +581,7 @@ def __call__(self, result): if self.func is not None: result = self.func(result) - print(self.fmt.format(result)) + print(self.fmt.format(result), **self.kwargs) self.iter += 1 @@ -796,8 +871,8 @@ class CallbackShowConvergence(Callback): """Displays a convergence plot.""" - def __init__(self, functional, title='convergence', - logx=False, logy=False, **kwargs): + def __init__(self, functional, title='convergence', logx=False, logy=False, + **kwargs): """Initialize a new instance. Parameters @@ -811,6 +886,9 @@ def __init__(self, functional, title='convergence', If true, the x axis is logarithmic. logx : bool, optional If true, the y axis is logarithmic. + + Other Parameters + ---------------- kwargs : Additional parameters passed to the scatter-plotting function. """ @@ -863,7 +941,7 @@ class CallbackPrintHardwareUsage(Callback): """ def __init__(self, step=1, fmt_cpu='CPU usage (% each core): {}', - fmt_mem='RAM usage: {}', fmt_swap='SWAP usage: {}'): + fmt_mem='RAM usage: {}', fmt_swap='SWAP usage: {}', **kwargs): """Initialize a new instance. Parameters @@ -893,6 +971,11 @@ def __init__(self, step=1, fmt_cpu='CPU usage (% each core): {}', where ``swap`` is the current SWAP memory usaged. An empty format string disables printing of SWAP memory usage. + Other Parameters + ---------------- + kwargs : + Key word arguments passed to the print function. + Examples -------- Print memory and CPU usage @@ -914,7 +997,6 @@ def __init__(self, step=1, fmt_cpu='CPU usage (% each core): {}', self.fmt_cpu = str(fmt_cpu) self.fmt_mem = str(fmt_mem) self.fmt_swap = str(fmt_swap) - self.iter = 0 def __call__(self, _): @@ -924,11 +1006,14 @@ def __call__(self, _): if self.iter % self.step == 0: if self.fmt_cpu: - print(self.fmt_cpu.format(psutil.cpu_percent(percpu=True))) + print(self.fmt_cpu.format(psutil.cpu_percent(percpu=True)), + **self.kwargs) if self.fmt_mem: - print(self.fmt_mem.format(psutil.virtual_memory())) + print(self.fmt_mem.format(psutil.virtual_memory()), + **self.kwargs) if self.fmt_swap: - print(self.fmt_swap.format(psutil.swap_memory())) + print(self.fmt_swap.format(psutil.swap_memory()), + **self.kwargs) self.iter += 1 @@ -962,6 +1047,9 @@ def __init__(self, niter, step=1, **kwargs): Total number of iterations. step : positive int, optional Number of iterations between output. + + Other Parameters + ---------------- kwargs : Further parameters passed to ``tqdm.tqdm``. """ @@ -995,6 +1083,7 @@ def __repr__(self): return '{}({})'.format(self.__class__.__name__, inner_str) + if __name__ == '__main__': # pylint: disable=wrong-import-position from odl.util.testutils import run_doctests From 36867621853bb5f68cfd820e5b53d8b59e612630 Mon Sep 17 00:00:00 2001 From: "Matthias J. Ehrhardt" Date: Thu, 5 Oct 2017 12:51:51 +0100 Subject: [PATCH 2/6] revert small change --- odl/solvers/util/callback.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/odl/solvers/util/callback.py b/odl/solvers/util/callback.py index 3654335cc9d..903db76ed4d 100644 --- a/odl/solvers/util/callback.py +++ b/odl/solvers/util/callback.py @@ -418,7 +418,7 @@ def __init__(self, fmt='Time elapsed = {:<5.03f} s', step=1, **kwargs): fmt : string, optional Formating that should be applied. The time is printed as :: - print(fmt.format(runtime, totaltime)) + print(fmt.format(runtime)) where ``runtime`` is the runtime since the last iterate. step : positive int, optional @@ -432,7 +432,6 @@ def __init__(self, fmt='Time elapsed = {:<5.03f} s', step=1, **kwargs): self.fmt = str(fmt) self.step = int(step) self.iter = 0 - self.total_time = 0 self.time = time.time() self.kwargs = kwargs @@ -440,9 +439,7 @@ def __call__(self, _): """Print time elapsed from the previous iteration.""" if self.iter % self.step == 0: t = time.time() - dt = t - self.time - self.total_time += dt - print(self.fmt.format(dt, self.total_time), **self.kwargs) + print(self.fmt.format(t - self.time), **self.kwargs) self.time = t self.iter += 1 @@ -451,7 +448,6 @@ def reset(self): """Set `time` to the current time.""" self.time = time.time() self.iter = 0 - self.total_time = 0 def __repr__(self): """Return ``repr(self)``.""" From 449ddc57e4d243853cfbc6372e319b7b5ecf18d1 Mon Sep 17 00:00:00 2001 From: "Matthias J. Ehrhardt" Date: Thu, 5 Oct 2017 18:01:39 +0100 Subject: [PATCH 3/6] make total time an attribute --- odl/solvers/util/callback.py | 77 +++++++----------------------------- 1 file changed, 15 insertions(+), 62 deletions(-) diff --git a/odl/solvers/util/callback.py b/odl/solvers/util/callback.py index 903db76ed4d..a1c24d4c75e 100644 --- a/odl/solvers/util/callback.py +++ b/odl/solvers/util/callback.py @@ -19,12 +19,10 @@ from odl.util import signature_string -__all__ = ('Callback', 'CallbackStore', 'CallbackApply', - 'CallbackPrintTiming', 'CallbackPrintTotalTime', +__all__ = ('Callback', 'CallbackStore', 'CallbackApply', 'CallbackPrintTiming', 'CallbackPrintIteration', 'CallbackPrint', 'CallbackPrintNorm', - 'CallbackShow', 'CallbackSaveToDisk', 'CallbackSleep', - 'CallbackShowConvergence', 'CallbackPrintHardwareUsage', - 'CallbackProgressBar') + 'CallbackShow', 'CallbackSaveToDisk', 'CallbackShowConvergence', + 'CallbackPrintHardwareUsage', 'CallbackProgressBar') class Callback(object): @@ -410,7 +408,8 @@ class CallbackPrintTiming(Callback): """Callback for printing the time elapsed since the previous iteration.""" - def __init__(self, fmt='Time elapsed = {:<5.03f} s', step=1, **kwargs): + def __init__(self, fmt='Time elapsed = {:<5.03f} s', step=1, + cumulative=False, **kwargs): """Initialize a new instance. Parameters @@ -432,79 +431,33 @@ def __init__(self, fmt='Time elapsed = {:<5.03f} s', step=1, **kwargs): self.fmt = str(fmt) self.step = int(step) self.iter = 0 - self.time = time.time() + self.cumulative = cumulative + self.base_time = time.time() + self.time = 0 self.kwargs = kwargs def __call__(self, _): """Print time elapsed from the previous iteration.""" if self.iter % self.step == 0: t = time.time() - print(self.fmt.format(t - self.time), **self.kwargs) - self.time = t + self.time = t - self.base_time - self.iter += 1 - - def reset(self): - """Set `time` to the current time.""" - self.time = time.time() - self.iter = 0 + if not self.cumulative: + self.base_time = t - def __repr__(self): - """Return ``repr(self)``.""" - optargs = [('fmt', self.fmt, 'Time elapsed = {:<5.03f} s'), - ('step', self.step, 1)] - inner_str = signature_string([], optargs) - return '{}({})'.format(self.__class__.__name__, inner_str) - - -class CallbackPrintTotalTime(Callback): - - """Callback for printing the total runtime at each iteration.""" - - def __init__(self, fmt='Total time elapsed = {:<5.03f} s', step=1, - **kwargs): - """Initialize a new instance. - - Parameters - ---------- - fmt : string, optional - Formating that should be applied. The time is printed as :: - - print(fmt.format(totaltime)) - - where ``totaltime`` is the total runtime. - step : positive int, optional - Number of iterations between prints. - - Other Parameters - ---------------- - kwargs : - Key word arguments passed to the print function. - """ - self.fmt = str(fmt) - self.step = int(step) - self.iter = 0 - self.total_time = 0 - self.time = time.time() - self.kwargs = kwargs - - def __call__(self, _): - """Print time elapsed from the previous iteration.""" - if self.iter % self.step == 0: - self.total_time = time.time() - self.time - print(self.fmt.format(self.total_time), **self.kwargs) + print(self.fmt.format(self.time), **self.kwargs) self.iter += 1 def reset(self): """Set `time` to the current time.""" - self.time = time.time() + self.base_time = time.time() + self.time = 0 self.iter = 0 - self.total_time = 0 def __repr__(self): """Return ``repr(self)``.""" - optargs = [('fmt', self.fmt, 'Total time elapsed = {:<5.03f} s'), + optargs = [('fmt', self.fmt, 'Time elapsed = {:<5.03f} s'), ('step', self.step, 1)] inner_str = signature_string([], optargs) return '{}({})'.format(self.__class__.__name__, inner_str) From 45a80ecb11deef4bfb79a38222f63df53ba7b745 Mon Sep 17 00:00:00 2001 From: "Matthias J. Ehrhardt" Date: Thu, 5 Oct 2017 18:05:32 +0100 Subject: [PATCH 4/6] TYPO: Add function to all --- odl/solvers/util/callback.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/odl/solvers/util/callback.py b/odl/solvers/util/callback.py index a1c24d4c75e..7f2ec06e8a8 100644 --- a/odl/solvers/util/callback.py +++ b/odl/solvers/util/callback.py @@ -21,8 +21,9 @@ __all__ = ('Callback', 'CallbackStore', 'CallbackApply', 'CallbackPrintTiming', 'CallbackPrintIteration', 'CallbackPrint', 'CallbackPrintNorm', - 'CallbackShow', 'CallbackSaveToDisk', 'CallbackShowConvergence', - 'CallbackPrintHardwareUsage', 'CallbackProgressBar') + 'CallbackShow', 'CallbackSaveToDisk', 'CallbackSleep', + 'CallbackShowConvergence', 'CallbackPrintHardwareUsage', + 'CallbackProgressBar') class Callback(object): From bdddf59ee71aaedd20e5f6df38ba4228c4ee7af6 Mon Sep 17 00:00:00 2001 From: "Matthias J. Ehrhardt" Date: Fri, 6 Oct 2017 09:56:19 +0100 Subject: [PATCH 5/6] Improve callback timing and docu --- odl/solvers/util/callback.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/odl/solvers/util/callback.py b/odl/solvers/util/callback.py index 7f2ec06e8a8..358e961fd41 100644 --- a/odl/solvers/util/callback.py +++ b/odl/solvers/util/callback.py @@ -423,6 +423,8 @@ def __init__(self, fmt='Time elapsed = {:<5.03f} s', step=1, where ``runtime`` is the runtime since the last iterate. step : positive int, optional Number of iterations between prints. + cumulative : boolean, optional + Print the time since the initialization instead of the last call. Other Parameters ---------------- @@ -433,27 +435,25 @@ def __init__(self, fmt='Time elapsed = {:<5.03f} s', step=1, self.step = int(step) self.iter = 0 self.cumulative = cumulative - self.base_time = time.time() - self.time = 0 + self.start_time = time.time() self.kwargs = kwargs def __call__(self, _): """Print time elapsed from the previous iteration.""" if self.iter % self.step == 0: - t = time.time() - self.time = t - self.base_time + current_time = time.time() - if not self.cumulative: - self.base_time = t + print(self.fmt.format(current_time - self.start_time), + **self.kwargs) - print(self.fmt.format(self.time), **self.kwargs) + if not self.cumulative: + self.start_time = current_time self.iter += 1 def reset(self): """Set `time` to the current time.""" - self.base_time = time.time() - self.time = 0 + self.start_time = time.time() self.iter = 0 def __repr__(self): From c0c4dbc77fd548802a5de919916536a58789e60b Mon Sep 17 00:00:00 2001 From: "Matthias J. Ehrhardt" Date: Fri, 6 Oct 2017 11:42:12 +0100 Subject: [PATCH 6/6] add cumulative arg to __repr__ --- odl/solvers/util/callback.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/odl/solvers/util/callback.py b/odl/solvers/util/callback.py index 358e961fd41..84a897c917f 100644 --- a/odl/solvers/util/callback.py +++ b/odl/solvers/util/callback.py @@ -459,7 +459,8 @@ def reset(self): def __repr__(self): """Return ``repr(self)``.""" optargs = [('fmt', self.fmt, 'Time elapsed = {:<5.03f} s'), - ('step', self.step, 1)] + ('step', self.step, 1), + ('cumulative', self.cumulative, False)] inner_str = signature_string([], optargs) return '{}({})'.format(self.__class__.__name__, inner_str)