如何设置tqdm的r_bar部分

9
我使用tqdm来为使用hyperopt进行长时间运行的优化过程打印进度条。该过程调用一个函数大约500次,每次调用需要10到20分钟左右的时间,因此我开始将进度显示细化,并在循环中添加了一些tqdm.update语句,分数式地推进进度条以避免出现两个嵌套的进度条,同时仍能立即看到已执行了多少个函数调用。现在这个丑陋的结果看起来像这样:
 15%|███▌                    | 73.69999999999993/500 [7:40:31<102:54:08, 868.98s/it, evaluating fold 2 of  2 folds...]Iteration 1, loss = 2.50358388

您可以看到,这是函数的第73次调用,而这第73次函数调用已经完成了大约70%。实际上,我只是估计了函数中子步骤m的数量(可能因调用而异),并使用分数1/m来更新进度条。然后,在函数调用结束后,我只需将进度条重新同步为一个完整的整数,以避免添加舍入误差。
当然,准确性在这里不是问题。但我想显示73.70而不是73.69999999999993。 我已经尝试将我的更新值四舍五入到两个小数位,但这没有解决问题,因为浮点数存在精度问题,如果一个数字不能被浮点数精确表示,则变得非常长。 根据 tqdm 的文档,此部分隐藏在整个格式字符串的r_bar部分中,但我找不到设置它的方法。你能帮我吗?
根据文档,r_bar 默认为:
r_bar='| {n_fmt}/{total_fmt} [{elapsed}<{remaining}, '

这是我的代码:
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

在被调用的函数中(它是 kwargs 参数中的一个条目),我会像这样更新进度条:
_progress_bar.update(round(update_value, 2))

好的,我明白了,这不仅建立格式字符串,还建立了一个进度条显示。因此,我必须在使用进度条的任何地方都这样做。 - jottbe
1
我现在正在使用手机,但是我已经简要地阅读了代码,显然你传递的参数将由代码处理。 - Axois
好的,我会检查一下。谢谢。 - jottbe
嗨@Axois,谢谢您的分析。虽然子类化可能是一个选择,但如果可能的话,我想避免它,因为我可能会添加一些依赖于tqm版本的依赖项。与此同时,我发现,如果我提供完全展开的bar格式(我的意思是用r_bar替换它的定义,并将{n_fmt}更改为{n:.2f}n_fmt已经是一个字符串),它会显示我想要的内容。 - jottbe
1
我刚试了一下,它可以工作!好知道。你介意我打出一个答案,这样人们至少可以有一个解决方案供以后参考吗? - Axois
显示剩余6条评论
1个回答

7

对于 tqdm 中的舍入问题,您可以直接在 bar_format 的参数之一中编辑 r_bar 中的格式。例如:

返回结果: 对于`tqdm`中的舍入问题,您可以直接在`bar_format`的参数之一中编辑`r_bar`中的格式。例如:
from tqdm import trange
for i in trange(int(7e7), bar_format = "{desc}: {percentage:.3f}%|{bar}| {n_fmt}/{total_fmt} [{elapsed}<{remaining}"):
    pass

显示:在此输入图片描述 对于保留两位小数,你可以简单地编辑{n_fmt}{n:.2f}。你也可以编辑其他参数,例如{desc}并且添加额外的小数位到percentage
from tqdm import trange
for i in trange(int(7e7), bar_format = "{desc}: {percentage:.10f}%|{bar}| {n:.2f}/{total_fmt} [{elapsed}<{remaining}"):
    pass

展示: enter image description here 在查看“tqdm”的源代码时,发现“n_fmt”实际上指向“str(n)”,因此传入格式化版本的“n”可以绕过其内在格式化。
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

非常感谢您的分析和花费在此上的时间。 - jottbe
@jottbe 很高兴能帮忙 :), 我也从中学到了一些东西! - Axois
2
顺便提一下,因为这个问题我学会了 Decimal 类 :-) 尽管这个知识对解决这个问题没有帮助(这将是一个丑陋的解决方案,而且 tqdm 似乎不喜欢小数),但也许我可以在其他地方使用它。 - jottbe

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接