• (二十八)mmdetection实用工具: Visualization


    一、基础绘制接口

    可视化器(Visualizer):可视化器负责对模型的特征图、预测结果和训练过程中产生的结构化日志进行可视化,支持 Tensorboard 和 WanDB 等多种可视化后端。

    import torch
    import mmcv
    from mmengine.visualization import Visualizer
    image = mmcv.imread('/home/mby/图片/cat_and_dog.jpg',
                        channel_order='rgb')
     #可视化器初始化
    visualizer = Visualizer(image=image)
    # 绘制单个检测框, xyxy 格式
    visualizer.draw_bboxes(torch.tensor([80, 200, 600, 650]))
    # 绘制多个检测框
    visualizer.draw_bboxes(torch.tensor([[640, 50, 1550, 650], [80, 200, 600, 650]]))
    visualizer.show()
    #为Visualizer设置绘制的图像
    visualizer.set_image(image=image)
    visualizer.draw_texts("cat and dog", torch.tensor([10, 20]))
    visualizer.draw_bboxes(torch.tensor([80, 200, 600, 650]),
                           edge_colors='r',
                           line_widths=3)
    visualizer.draw_bboxes(torch.tensor([[640, 50, 1550, 650]]),line_styles='--')
    visualizer.show()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    draw_bboxes()函数定义:

    def draw_bboxes(
        self,
        bboxes: Union[np.ndarray, torch.Tensor],
        edge_colors: Union[str, tuple, List[str], List[tuple]] = 'g',
        line_styles: Union[str, List[str]] = '-',
        line_widths: Union[Union[int, float], List[Union[int, float]]] = 2,
        face_colors: Union[str, tuple, List[str], List[tuple]] = 'none',
        alpha: Union[int, float] = 0.8,#矩形框的透明度
    ) -> 'Visualizer':
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    import mmcv
    from mmengine.visualization import Visualizer
    import numpy as np
    from torchvision.models import resnet18
    from torchvision.transforms import Compose, Normalize, ToTensor
    #预处理
    def preprocess_image(img, mean, std):
        preprocessing = Compose([
            ToTensor(),
            Normalize(mean=mean, std=std)
        ])
        return preprocessing(img.copy()).unsqueeze(0)
    #模型
    model = resnet18(pretrained=True)
    #前向过程:
    def _forward(x):
        x = model.conv1(x)
        x = model.bn1(x)
        x = model.relu(x)
        x = model.maxpool(x)
    
        x1 = model.layer1(x)
        x2 = model.layer2(x1)
        x3 = model.layer3(x2)
        x4 = model.layer4(x3)
        return x4
    image = mmcv.imread('/home/mby/图片/cat_and_dog0.jpeg',
                        channel_order='rgb')
    model.forward = _forward
    
    image_norm = np.float32(image) / 255
    input_tensor = preprocess_image(image_norm,
                                    mean=[0.485, 0.456, 0.406],
                                    std=[0.229, 0.224, 0.225])
    feat = model(input_tensor)[0]
    
    visualizer = Visualizer()
    drawn_img = visualizer.draw_featmap(feat, channel_reduction='select_max')
    visualizer.show(drawn_img)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    draw_featmap()函数定义

    def draw_featmap(featmap: torch.Tensor,		#特征图(C, H, W).
                     overlaid_image: Optional[np.ndarray] = None,#显示的图像,特征图会叠加到 image 上绘制
                     channel_reduction: Optional[str] = 'squeeze_mean',# 多个通道压缩为单通道的策略
                     topk: int = 20,# 可选择激活度最高的 topk 个特征图显示
                     arrangement: Tuple[int, int] = (4, 5),# 多通道展开为多张图时候布局
                     resize_shape: Optional[tuple] = None, # 可以指定 resize_shape 参数来缩放特征图
                     alpha: float = 0.5					#特征图的透明度
                     ) -> np.ndarray:
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    官方解释:
    输入的 Tensor 一般是包括多个通道的,channel_reduction 参数可以将多个通道压缩为单通道,然后和图片进行叠加显示
    squeeze_mean 将输入的 C 维度采用 mean 函数压缩为一个通道,输出维度变成 (1, H, W)
    select_max 从输入的 C 维度中先在空间维度 sum,维度变成 (C, ),然后选择值最大的通道
    None 表示不需要压缩,此时可以通过 topk 参数可选择激活度最高的 topk 个特征图显示
    在 channel_reduction 参数为 None 的情况下,topk 参数生效,其会按照激活度排序选择 topk 个通道,然后和图片进行叠加显示,并且此时会通过 arrangement 参数指定显示的布局
    如果 topk 不是 -1,则会按照激活度排序选择 topk 个通道显示
    如果 topk = -1,此时通道 C 必须是 1 或者 3 表示输入数据是图片,否则报错提示用户应该设置 channel_reduction来压缩通道。
    考虑到输入的特征图通常非常小,函数支持输入 resize_shape 参数,方便将特征图进行上采样后进行可视化。

    二、基础存储接口

    任何一个可视化器都可以配置任意多个存储后端,可视化器会循环调用配置好的多个存储后端,从而将结果保存到多后端中。
    本地后端存储:

    visualizer = Visualizer(image=image,
                            vis_backends=[dict(type='LocalVisBackend')],
                            save_dir='temp_dir')
    visualizer.draw_bboxes(torch.tensor([[33, 120, 209, 220], [72, 13, 179, 147]]))
    visualizer.draw_texts("cat and dog", torch.tensor([10, 20]))
    visualizer.draw_circles(torch.tensor([40, 50]), torch.tensor([20]))
    
    # 会生成 temp_dir/vis_data/vis_image/demo_0.png
    visualizer.add_image('demo', visualizer.get_image())
    其中生成的后缀 0 是用来区分不同 step 场景
    
    # 会生成 temp_dir/vis_data/vis_image/demo_1.png
    visualizer.add_image('demo', visualizer.get_image(), step=1)
    # 会生成 temp_dir/vis_data/vis_image/demo_3.png
    visualizer.add_image('demo', visualizer.get_image(), step=3)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    其他后端存储:
    这里需要注意,如果没有存储成功,需要安装下面两个库
    文件保存位置:temp_dir/vis_data/events.out.tfevents.xxx

    pip install tensorboard
    pip install wandb
    
    • 1
    • 2

    WandbVisBackend后端可能使用失败,因为需要你在wandb网站创建一个帐户。使用的时候需要指定你的Wandb API密钥

    # TensorboardVisBackend
    visualizer = Visualizer(image=image,
                            vis_backends=[dict(type='TensorboardVisBackend')],
                            save_dir='temp_dir')
    # 或者 WandbVisBackend
    visualizer = Visualizer(image=image,
                            vis_backends=[dict(type='WandbVisBackend')],
                            save_dir='temp_dir')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    保存标量数据:
    会将内容追加到 temp_dir/vis_data/scalars.json

    # 保存 loss
    visualizer.add_scalar('loss', 0.2, step=0)
    visualizer.add_scalar('loss', 0.1, step=1)
    # 保存 acc
    visualizer.add_scalar('acc', 0.7, step=0)
    visualizer.add_scalar('acc', 0.8, step=1)
    #也可以一次性保存多个标量数据
    visualizer.add_scalars({'loss': 0.3, 'acc': 0.8}, step=3)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    保存配置文件:

    from mmengine import Config
    cfg=Config.fromfile('tests/data/config/py_config/config.py')
    # 会生成 temp_dir/vis_data/config.py
    visualizer.add_config(cfg)
    
    • 1
    • 2
    • 3
    • 4

    多后端存储:

    visualizer = Visualizer(image=image,
                            vis_backends=[dict(type='TensorboardVisBackend'),
                                          dict(type='LocalVisBackend')],
                            save_dir='temp_dir')
    # 会生成 temp_dir/vis_data/events.out.tfevents.xxx 文件
    visualizer.draw_bboxes(torch.tensor([[33, 120, 209, 220], [72, 13, 179, 147]]))
    visualizer.draw_texts("cat and dog", torch.tensor([10, 20]))
    visualizer.draw_circles(torch.tensor([40, 50]), torch.tensor([20]))
    
    visualizer.add_image('demo', visualizer.get_image())
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    如果多个存储后端中存在同一个类的多个后端,那么必须指定 name 字段,否则无法区分是哪个存储后端。

    visualizer = Visualizer(
        image=image,
        vis_backends=[
            dict(type='TensorboardVisBackend', name='tb_1', save_dir='temp_dir_1'),
            dict(type='TensorboardVisBackend', name='tb_2', save_dir='temp_dir_2'),
            dict(type='LocalVisBackend', name='local')
        ],
        save_dir='temp_dir')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    三、任意点位进行可视化

    MMEngine 设计的可视化器支持在任意点位获取同一个可视化器然后进行可视化的功能。 用户只需要在初始化时候通过 get_instance 接口实例化可视化对象,此时该可视化对象即为全局可获取唯一对象,后续通过 Visualizer.get_current_instance() 即可在代码任意位置获取

    # 在程序初始化时候调用
    visualizer1 = Visualizer.get_instance(
        name='vis',
        vis_backends=[dict(type='LocalVisBackend')]
    )
    
    # 在任何代码位置都可调用
    visualizer2 = Visualizer.get_current_instance()
    visualizer2.add_scalar('map', 0.7, step=0)
    
    assert id(visualizer1) == id(visualizer2)
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    通过字段配置方式全局初始化

    from mmengine.registry import VISUALIZERS
    
    visualizer_cfg = dict(type='Visualizer',
                          name='vis_new',
                          vis_backends=[dict(type='LocalVisBackend')])
    VISUALIZERS.build(visualizer_cfg)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
  • 相关阅读:
    Java中线程的状态及切换
    Python零基础超详细教程:字典(Dictionary)相关介绍使用
    【Java】工作中常用的一些lambda表达式
    你真的会报bug吗?常见10条错误
    windows下rust调试运行环境部署
    vscode远程连接服务器+Xming:图形化界面
    大学生个人网页模板 简单网页制作作业成品 极简风格个人介绍HTML网页设计(舞蹈培训网页)
    盘点市面上七款好用的代码加密混淆工具,你都用过哪款?
    深度学习入门(十六)实战Kaggle比赛:预测房价
    拆离褶皱(Detachment Fold)
  • 原文地址:https://blog.csdn.net/m0_37737957/article/details/133065539