文章目录
tqdm
是 Python 进度条库,可以在 Python 长循环中添加一个进度提示信息
。用户只需要封装任意的迭代器
,是一个快速、扩展性强的进度条工具库。
1. 语法
1.1 tqdm 参数
py
tqdm(iterable=None, desc=None, total=None, leave=True, file=None,
ncols=None, mininterval=0.1, maxinterval=10.0, miniters=None,
ascii=None, disable=False, unit='it', unit_scale=False,
dynamic_ncols=False, smoothing=0.3, bar_format=None, initial=0,
position=None, postfix=None, unit_divisor=1000, write_bytes=None,
lock_args=None, nrows=None, colour=None, delay=0, gui=False,
**kwargs):
iterable
: 接收一个可迭代对象。如果iterable为空
的话,则手动通过update
来更新迭代total
: 总的迭代次数,用于计算进度百分比, 默认等于len(iterable)
desc
: 进度条的显示信息,显示在进度条前面(前缀)postfix
: 字典形式信息,例如:loss=0.56, 显示在进度条的末尾(后缀)mininterval
:设置进度条最小的更新间隔
,单位秒
,默认:0.1s
maxinterval
: 设置进度条最大更新间隔
,单位秒
,默认:10s
bar_format
: 设置进度条显示格式,默认为{desc}: {percentage:3.0f}%|{bar}| {n_fmt}/{total_fmt}
ncols
: 设置进度条的宽度nrows
: 设置进度条的高度unit
: 设置进度条的单位,str类型,默认为it
这些参数为相对比较常用
的参数,并且全部都是可选参数
(optional);在自定义进度条当中比较重要的的一个参数为:bar_format
,用于定义进度条的具体格式,所包含的具体数据信息;
1.2 bar_format
下面主要介绍这个参数的具体用法;
bar_format
默认格式为:{l_bar}{bar}{r_bar}
- 进度条分为三部分: 中间的条形图(bar),条形图左边信息(l_bar)、条形图右边信息(r_bar)
l_bar
:{desc}: {percentage:3.0f}%|
, 即前缀信息(desc)
+当前进度的百分比
bar:
进度条r_bar
:|{n_fmt}/{total_fmt}[{elapsed}<{remaining},{rate_fmt}{postfix}]
100%|█████████████████| 3/3 [00:03<00:00, 1.00s/it]
json
percentage:百分比
n_fmt:当前数
total_fmt:总数
elapsed:消耗的时间
remaining:剩余时间
rate_fmt:速率
postifx:后缀字典描述
desc: 前缀字符串描述
desc、postfix默认为空;
py
for item in tqdm(data, desc="Processing", bar_format="{l_bar}{bar}| {n_fmt}/{total_fmt} [{elapsed}<{remaining}, {rate_fmt}{postfix}]"):
# 在这里添加你的代码
案例
yolov8
代码中将tqdm中的bar_format
进行了设置,没有使用原有的bar_format
格式, 简化了显示内容。
shell
TQDM_BAR_FORMAT = "{l_bar}{bar:10}{r_bar}" if VERBOSE else None
基于新的bar_format格式,重新封装了tqdm
,代码如下
py
from tqdm import tqdm as tqdm_original
class TQDM(tqdm_original):
def __init__(self, *args, **kwargs):
"""Initialize custom Ultralytics tqdm class with different default arguments."""
# Set new default values (these can still be overridden when calling TQDM)
kwargs["disable"] = not VERBOSE or kwargs.get("disable", False) # logical 'and' with default value if passed
kwargs.setdefault("bar_format", TQDM_BAR_FORMAT) # override default value if passed
super().__init__(*args, **kwargs)
- 可以看到,
TQDM
和原来的tqdm
基本是是一样的,只是自定义了bar_format
的形式,使得显示更加简洁。 - 利用
TQDM
代替原有的tqdm
, 使用方法是一样的
py
pbar = TQDM(enumerate(self.train_loader), total=nb)
2. 基本用法
2.1 指定可迭代对象
传入迭代器对象(iterable)
, 默认迭代次数为:len(iterable)
,:
py
import time
from tqdm import *
for i in tqdm(range(1000)):
time.sleep(.01) #进度条每0.01s前进一次,总时间为1000*0.01=10s
# 运行结果如下
100%|██████████| 1000/1000 [00:10<00:00, 93.21it/s]
2.2 指定迭代次数
如果没有传入可迭代对象,可以使用total
指定迭代总数,并配合update
手动更新进度条
py
from tqdm import tqdm
import time
pbar = tqdm(total=200) # 设置总长度
for i in range(100):
time.sleep(0.05)
# 每次更新进度条的长度
pbar.update(1) # 相当于在当前长度的基础上 +1 的操作
pbar.close()
- 由于进度条总长200,现在累加到100就停止,因此最终会停在50%
pbar.update(1)
: update中传入更新的步长
2.3 设置显示信息
2.3.1 设置进度条前缀(左侧)信息
- (1) 利用
desc
参数,指定进度条左侧
显示的信息
py
s = ('%20s' + '%11s' * 6) % ('Class', 'Images', 'Labels', 'P', 'R', 'mAP@.5', 'mAP@.5:.95')
pbar = tqdm(dataloader, desc=s, bar_format='{l_bar}{bar:10}{r_bar}{bar:-10b}')
for batch_i, (im, targets, paths, shapes) in enumerate(pbar):
pass
等价于
:
py
s = ('%20s' + '%11s' * 6) % ('Class', 'Images', 'Labels', 'P', 'R', 'mAP@.5', 'mAP@.5:.95')
pbar = tqdm(dataloader, bar_format='{l_bar}{bar:10}{r_bar}{bar:-10b}')
for batch_i, (im, targets, paths, shapes) in enumerate(pbar):
pbar.desc = s
- (2) 使用
set_description
, 指定进度条左侧
(前缀)显示的信息
py
import time
from tqdm import tqdm
pbar = tqdm(["a","b","c","d"])
for char in pbar:
pbar.set_description("Processing %s" % char) # 设置描述
time.sleep(1) # 每个任务分配1s
# 结果如下
Processing a: 0%| | 0/4 [00:00<?, ?it/s]
Processing b: 25%|██▌ | 1/4 [00:01<00:03, 1.01s/it]
Processing c: 50%|█████ | 2/4 [00:02<00:02, 1.01s/it]
Processing d: 75%|███████▌ | 3/4 [00:03<00:01, 1.01s/it]
py
for epoch in range(self.start_epoch, self.epochs):
pbar = TQDM(enumerate(self.train_loader), total=nb)
for i, batch in pbar:
self.loss, self.loss_items = self.model(batch)
if RANK in (-1, 0):
pbar.set_description(
("%11s" * 2 + "%11.4g" * (2 + loss_len))
% (f"{epoch + 1}/{self.epochs}", mem, *losses, batch["cls"].shape[0], batch["img"].shape[-1])
)
pbar.close()
set_description
以及参数desc
都可以设置进度条左侧
(前缀)信息,- 但
set_description
相比desc
更加灵活,可以在每次迭代
时,传入计算的结果。比如可以显示模型训练的loss
, 图像的shape
大小,以及当前的epoch
等,用起来更加灵活。
2.3.2 显示进度条后缀(右侧)信息
- (1) 利用
postfix
参数,指定进度条右侧
(后缀)显示的信息
py
pbar = tqdm(range(N),total=N, desc="N")
start = time.time()
for i in pbar:
pbar.postfix=f"{i}"
print("w .postfix: {:.2f}".format(time.time() - start))
- (2) 使用
set_postfix
, 指定进度条右侧
(后缀)显示的信息
py
# -*- coding: utf-8 -*-
from tqdm import tqdm
from collections import OrderedDict
total = 10000 #总迭代次数
loss = total
with tqdm(total=total, desc="进度条") as pbar:
for i in range(total):
loss -= 1
# pbar.set_postfix(OrderedDict(loss='{0:1.5f}'.format(loss)))
pbar.set_postfix(val_loss=1.63,fscore=0.88,batch=i) #输入一个字典,显示实验指标
pbar.update(1)
set_postfix
用于设置进度条右侧信息,可以将训练的结果,设置在进度条右侧显示。set_postfix
在指定信息时,需要使用关键字参数
的信息,比如以loss=5, bach=3
的形式,这样也可以容易的参数,某个参数的值
。- 当传入的是
字典dict
时,需要使用**
解包dict对象的每个元素,然后传入到set_postfix
中,如下所示
py
model_train.eval()
for iteration, batch in enumerate(gen_val):
imgs, pngs, labels = batch
outputs = model_train(imgs)
loss = CE_Loss(outputs, pngs, weights, num_classes = num_classes)
f_score = f_score(outputs, labels)
pbar.set_postfix(**{'loss' : loss / (iteration + 1),
'f_score' : f_score / (iteration + 1),
'lr' : get_lr(optimizer)})
pbar.update(1)
可以看到如果传入字典dict
,需要**
将dict解包为关键字参数
,通过字典dict
传参,在实际中应用的更加普遍。
3. 项目案例
py
Init_Epoch =0
Total_Epoch =300
epoch_iters = num_train // batch_size # iters of one epoch for train
epoch_iters_val = num_val // batch_size # # iters of one epoch for val
for epoch in range(Init_Epoch, Total_Epoch):
pbar = tqdm(total=epoch_iters,desc=f'Epoch {epoch + 1}/{Total_Epoch}',postfix=dict,mininterval=0.3)
for iteration, batch in enumerate(train_dataloader):
imgs, pngs, labels = batch
outputs = model_train(imgs)
loss = CE_Loss(outputs, pngs, weights, num_classes = num_classes)
_f_score = f_score(outputs, labels)
pbar.set_postfix(**{'total_loss': total_loss / (iteration + 1),
'f_score' : total_f_score / (iteration + 1),
'lr' : get_lr(optimizer)})
pbar.update(1)
pbar.close()
- 在每个
epoch
中,利用tqdm
定义进度条pbar
- 在
tqdm
中通过total
设置每个epoch的迭代次数 - 在每次迭代中,通过
pbar.set_postfix
设置进度条右侧
显示信息,由于是通过total
设置总迭代数而不是利用一个可迭代对象来控制迭代,因此需要利用update
来更新迭代 - 进度条使用完毕后,记得关闭:
pbar.close()
参考
https://github.com/bubbliiiing/deeplabv3-plus-pytorch
https://www.cnblogs.com/softlin/p/13339766.html
https://github.com/ultralytics/ultralytics