【yolov5小技巧(2)】---将yolov5中的特征图以热力图的方式进行可视化

在这里插入图片描述



在这里插入图片描述

👀🎉📜系列文章目录

【yolov5小技巧(1)】—可视化并统计目标检测中的TP、FP、FN

🚀🚀🚀前言

在论文中我们经常可以见到提取的物体特征以热力图的形式展示出来,首先我们要了解为什么要将特征图以热力图的形式进行可视化,将特征图以热力图的方式进行可视化在深度学习中有几个重要的原因:

  • 强调激活区域 :热力图可以帮助我们直观地理解哪些区域对于模型的决策是最重要的。通过热力图,我们可以看到特征图中哪些区域具有较高的激活值,从而了解模型对于不同特征的关注程度。
  • 可视化激活模式 :热力图可以展示模型在特定任务或数据集上学到的激活模式。例如,在图像分类任务中,热力图可以显示模型对于不同物体或区域的激活情况,从而帮助我们理解模型的决策依据。
  • 可视化网络学习的过程 :通过在训练过程中可视化特征图的热力图,我们可以观察模型随着训练的进行而学习到的特征的变化。这有助于我们理解模型是如何逐步改进并适应数据的。
  • 提高解释性和可解释性 :热力图可以帮助解释深度学习模型的决策过程。通过展示模型在输入数据上的激活情况,我们可以更好地理解模型是如何基于输入数据做出预测或分类的。
  • 直观的可视化方式 :热力图是一种直观的可视化方式,易于理解和解释。通过将特征图表示为颜色密度较高的区域,我们可以更直观地理解模型对于不同区域的关注程度

一、1️⃣ 将特征图可视化的文章CFPNet

论文源码:Centralized Feature Pyramid for Object Detection
CFPNet代码链接:https://github.com/QY1994-0919/CFPNet

在特征图可视化方面可以参考CFPNet这篇文章,下图是不同的网络特征进行热力图可视化的一个结果。
在这里插入图片描述
🔥🔥🔥这幅图是视觉识别任务中图像特征演化的可视化。对于(a)中的输入图像,(b)中的CNN模型只定位那些判别性最强的区域;虽然©中的递进模型在注意机制或变压器transformer的帮助下可以看到更宽的范围,但它通常忽略了对密集预测任务很重要的角落线索;(d)中的模型通过将集中约束附加到具有高级远程依赖关系的特征上,不仅可以看到更广泛,而且更全面,更适合于密集预测任务。

二、2️⃣yolov5自带的特征图可视化工具

📌其实在yolov5中的detect.py推理代码中只需要修改一个参数,就可以将输入图片经过每一层网络的特征可视化图保存下来。该参数是visualize,只需要将visualize参数默认为True,修改如下:

parser.add_argument('--visualize', default=True, action='store_true', help='visualize features')

在这里插入图片描述
☀️☀️☀️将该参数设置默认为True之后,再对目标图片进行推理,在runs文件夹下的detect文件夹下除了会生成一个检测的图片,还会再单独生成一个文件夹,该文件保存的是每一层网络对该图片的特征可视化图。
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

三、3️⃣如何将特征图转换成热力图

那么如何将可视化的特征图以热力图的形式进行保存。首先找到utils文件夹下的plots.py文件,在该文件中找到feature_visualization函数,将该函数内容全部注释掉,用下面这段代码代替原代码:

def feature_visualization(x, module_type, stage, n=32, save_dir=Path('runs/detect/exp')):
    """
    x:              Features to be visualized
    module_type:    Module type
    stage:          Module stage within model
    n:              Maximum number of feature maps to plot
    save_dir:       Directory to save results
    """
    if 'Detect' not in module_type:  # 如果不是检测模块
        batch, channels, height, width = x.shape  # 获取特征张量的形状信息(批量大小、通道数、高度、宽度)
        if height > 1 and width > 1:  # 如果特征图的高度和宽度都大于1
            f = save_dir / f"stage{stage}_{module_type.split('.')[-1]}_features.png"  # 生成保存结果的文件名

            blocks = torch.chunk(x[0].cpu(), channels, dim=0)  # 将特征张量按通道数分块,选择批量索引为0的部分
            n = min(n, channels)  # 确定要绘制的特征图数量
            fig, ax = plt.subplots(math.ceil(n / 8), 8, tight_layout=True)  # 创建子图网格,以8列的形式排列绘制的特征图
            ax = ax.ravel()  # 将子图数组展平为一维
            plt.subplots_adjust(wspace=0.05, hspace=0.05)  # 设置子图之间的水平和垂直间距
            for i in range(n):  # 遍历要绘制的特征图数量
                block = blocks[i].squeeze().detach().numpy()  # 提取并转换为NumPy数组
                block = (block - np.min(block)) / (np.max(block) - np.min(block))  # 归一化处理
                temp = np.array(block * 255.0, dtype=np.uint8)  # 将数据缩放到0-255,并转换为8位无符号整数
                temp = cv2.applyColorMap(temp, cv2.COLORMAP_JET)  # 应用热力图颜色映射
                ax[i].imshow(temp, cmap=plt.cm.jet)  # 绘制热力图
                ax[i].axis('off')  # 关闭坐标轴显示

            LOGGER.info(f'Saving {f}... ({n}/{channels})')  # 记录保存结果的信息
            plt.savefig(f, dpi=300, bbox_inches='tight')  # 保存结果图像
            plt.close()  # 关闭图形
            np.save(str(f.with_suffix('.npy')), x[0].cpu().numpy())  # 将结果保存为NumPy数组

这段代码与yolov5原代码的主要区别是在for循环里面,在循环里面添加了热力图颜色映射。

🚀🚀接下来我们重新运行detect.py代码,发现经过卷积神经网络之后的特征图全部都以热力图的形式展示出来。下面第一幅图展示的是经过第一层网络之后的特征热力图;随着网络的加深,特征图所展现出来的特征就越难区分,例如第二幅图是经过最后一层网络之后的特征热力图,已经无法用肉眼去区分疵点的位置和特征。
在这里插入图片描述


在这里插入图片描述


在这里插入图片描述

  • 36
    点赞
  • 48
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

慕溪同学

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值