文章目录
- 1. 语法
- 1.1 tqdm 参数
- 1.2 bar_format
- 案例
- 2. 基本用法
- 2.1 指定可迭代对象
- 2.2 指定迭代次数
- 2.3 设置显示信息
- 2.3.1 设置进度条前缀(左侧)信息
- 2.3.2 显示进度条后缀(右侧)信息
- 3. 项目案例
- 参考
tqdm 是 Python 进度条库,可以在 Python 长循环中添加一个进度提示信息。用户只需要封装任意的迭代器,是一个快速、扩展性强的进度条工具库。
1. 语法
1.1 tqdm 参数
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]
percentage:百分比 n_fmt:当前数 total_fmt:总数 elapsed:消耗的时间 remaining:剩余时间 rate_fmt:速率 postifx:后缀字典描述 desc: 前缀字符串描述 desc、postfix默认为空;
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格式, 简化了显示内容。
TQDM_BAR_FORMAT = "{l_bar}{bar:10}{r_bar}" if VERBOSE else None
基于新的bar_format格式,重新封装了tqdm,代码如下
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, 使用方法是一样的
pbar = TQDM(enumerate(self.train_loader), total=nb)
2. 基本用法
2.1 指定可迭代对象
传入迭代器对象(iterable), 默认迭代次数为:len(iterable),:
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手动更新进度条
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参数,指定进度条左侧显示的信息
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
等价于:
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, 指定进度条左侧(前缀)显示的信息
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]
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参数,指定进度条右侧(后缀)显示的信息
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, 指定进度条右侧(后缀)显示的信息
# -*- 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中,如下所示
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. 项目案例
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
- (2) 使用set_postfix, 指定进度条右侧(后缀)显示的信息
- (1) 利用postfix参数,指定进度条右侧(后缀)显示的信息
- (2) 使用set_description, 指定进度条左侧(前缀)显示的信息
- (1) 利用desc参数,指定进度条左侧显示的信息