I use tqdm to print a progress bar for a long running optimization process with hyperopt.
The process calls a function say 500 times and each call will take around 10 to 20 minutes, so I started to make the progress display a bit more fine granular and added some tqdm.update
-statements in the loop, advancing the progress bar fraction-wise to avoid having two nested progress bars while still beeing able to immediately see how many function calls have been performed so far.
Now the ugly result looks like this:
15%|███▌ | 73.69999999999993/500 [7:40:31<102:54:08, 868.98s/it, evaluating fold 2 of 2 folds...]Iteration 1, loss = 2.50358388
You can see above, it is the 73th call of the function and this 73th function call is about 70% finished. In fact I just estimated the number of substeps m
in the function (which might vary from call to call) and used the fraction 1/m
to update the progress bar. Then after the function call I just synchronize the progress bar back to a full integer to avoid adding rounding errors.
Of course accuracy is not an issue at all here. But I would like to display 73.70 rather than 73.69999999999993.
I already tried to round my update value to two decimal places, which doesn't fix the problem, because of precision issues in float, if a number is not exactly representable by a float, then it gets ugly-long again.
According to the documentation of tqdm this part is hidden in the in the part r_bar
of the whole format string, but I couldn't find a way to set it. Can you help me with this?
According to the docs r_bar
defaults to:
r_bar='| {n_fmt}/{total_fmt} [{elapsed}<{remaining}, '
Here is my code:
with tqdm(iterable=None, initial=num_trials, maxinterval=maxinterval, total=max_evals, ascii=False, disable=show_progressbar is False) as progress_bar:
def fn_to_minimize(*args, **kwargs):
return fn(*args, **kwargs, _progress_bar=progress_bar)
for num_trials in range(num_trials, max_evals):
progress_bar.n=float(num_trials)
progress_bar.refresh()
best = fmin(**kwargs, fn=fn_to_minimize, trials=trials, max_evals=num_trials+1)
# do some other stuff here
In the called function (one of the entries in kwargs
btw) I update the progress bar just like this:
_progress_bar.update(round(update_value, 2))
For rounding issues in tqdm
, you can directly edit the formatting in the r_bar
as one of the parameters in the bar_format
. For example:
from tqdm import trange
for i in trange(int(7e7), bar_format = "{desc}: {percentage:.3f}%|{bar}| {n_fmt}/{total_fmt} [{elapsed}<{remaining}"):
pass
For 2 decimal places, you can simply edit the {n_fmt}
to be {n:.2f}
. You can also edit other parameters such as {desc}
or add in additional decimal places to the percentage
.
from tqdm import trange
for i in trange(int(7e7), bar_format = "{desc}: {percentage:.10f}%|{bar}| {n:.2f}/{total_fmt} [{elapsed}<{remaining}"):
pass
Upon looking through the source code of tqdm
, n_fmt
is actually pointing to str(n)
, hence passing in the formatted version of n
can bypass its intrinsic formatting.
if unit_scale:
n_fmt = format_sizeof(n, divisor=unit_divisor)
total_fmt = format_sizeof(total, divisor=unit_divisor) \
if total is not None else '?'
else:
n_fmt = str(n)
total_fmt = str(total) if total is not None else '?'
try:
postfix = ', ' + postfix if postfix else ''
except TypeError:
pass