可视化#

Tensorboard 可视化#

monai.visualize.img2tensorboard.add_animated_gif(writer, tag, image_tensor, max_out=3, frame_dim=-3, scale_factor=1.0, global_step=None)[source]#

根据‘CHWD’格式的图像张量创建动画 GIF,并使用 SummaryWriter 写入。

参数:
  • writer – 要写入的 Tensorboard SummaryWriter

  • tag – 数据标识符

  • image_tensor – 要添加的图像张量,预期格式为 CHWD

  • max_out – 要制作动画的最大图像通道数

  • frame_dim – 用作 GIF 图像帧的维度,预期输入数据形状为 CHWD,默认为 -3 (第一个空间维度)

  • scale_factor – 用于乘以值的因子。如果图像数据介于 0 和 1 之间,使用 255 将其缩放到可显示范围

  • global_step – 要记录的全局步数值

monai.visualize.img2tensorboard.make_animated_gif_summary(tag, image, writer=None, max_out=3, frame_dim=-3, scale_factor=1.0)[source]#

根据‘CHWD’格式的图像张量创建动画 GIF 并返回 Summary。

参数:
  • tag – 数据标识符

  • image – 图像,预期格式为 CHWD

  • writer – 用于绘制图像的 tensorboard writer

  • max_out – 要制作动画的最大图像通道数

  • frame_dim – 用作 GIF 图像帧的维度,预期输入数据形状为 CHWD,默认为 -3 (第一个空间维度)

  • scale_factor – 用于乘以值的因子。如果图像数据介于 0 和 1 之间,使用 255 将其缩放到可显示范围

monai.visualize.img2tensorboard.plot_2d_or_3d_image(data, step, writer, index=0, max_channels=1, frame_dim=-3, max_frames=24, tag='output')[source]#

在 TensorBoard 上绘制 2D 或 3D 图像,3D 图像将转换为 GIF 图像。

注意

将 3D 或 2D 图像(通道数大于 3)绘制为单独的图像。如果 writer 来自 TensorBoardX,数据有 3 个通道且 max_channels=3,将绘制为 RGB 视频。

参数:
  • data – 要在 TensorBoard 上绘制为图像的目标数据。数据预期具有‘NCHW[D]’维度,或者具有 CHW[D] 维度的数据列表,并且只绘制批处理中的第一个。

  • step – 图表中当前绘制的步数。

  • writer – 指定用于绘制图像的 TensorBoard 或 TensorBoardX SummaryWriter。

  • index – 绘制输入数据批处理中的哪个元素,默认为第一个元素。

  • max_channels – 要绘制的通道数。

  • frame_dim – 如果将 3D 图像绘制为 GIF,指定用作帧的维度,预期输入数据形状为 NCHWD,默认为 -3 (第一个空间维度)

  • max_frames – 如果在 TensorBoardX 中将 3D RGB 图像绘制为视频,将 FPS 设置为 max_frames

  • tag – TensorBoard 上绘制图像的标签。

类激活图#

class monai.visualize.class_activation_maps.CAM(nn_module, target_layers, fc_layers='fc', upsampler=<function default_upsampler>, postprocessing=<function default_normalizer>)[source]#

根据空间池化前的最后一个全连接层计算类激活图。此实现基于

Zhou 等人,Learning Deep Features for Discriminative Localization. CVPR ‘16, https://arxiv.org/abs/1512.04150

示例

import torch

# densenet 2d
from monai.networks.nets import DenseNet121
from monai.visualize import CAM

model_2d = DenseNet121(spatial_dims=2, in_channels=1, out_channels=3)
cam = CAM(nn_module=model_2d, target_layers="class_layers.relu", fc_layers="class_layers.out")
result = cam(x=torch.rand((1, 1, 48, 64)))

# resnet 2d
from monai.networks.nets import seresnet50
from monai.visualize import CAM

model_2d = seresnet50(spatial_dims=2, in_channels=3, num_classes=4)
cam = CAM(nn_module=model_2d, target_layers="layer4", fc_layers="last_linear")
result = cam(x=torch.rand((2, 3, 48, 64)))

注意:为了帮助选择目标层,列出所有层可能会很有用

for name, _ in model.named_modules(): print(name)
__init__(nn_module, target_layers, fc_layers='fc', upsampler=<function default_upsampler>, postprocessing=<function default_normalizer>)[source]#
参数:
  • nn_module – 要可视化的模型

  • target_layers – 用于生成特征图的模型层名称。

  • fc_layers – 用于获取全连接权重以计算来自目标层(不含池化)的激活图的字符串或可调用对象,并在每个空间位置评估它。

  • upsampler – 用于对输出图像进行上采样的上采样方法。默认为 N 维线性插值(双线性、三线性等),取决于输入空间维度的数量。

  • postprocessing – 应用于上采样输出图像的可调用对象。默认为在 min=1 和 max=0 之间进行归一化(即,最大输入将变为 0,最小输入将变为 1)。

compute_map(x, class_idx=None, layer_idx=-1, **kwargs)[source]#

使用输入张量 x 计算实际特征图。

参数:
  • xnn_module 的输入。

  • class_idx – 要可视化的类别索引。默认为 None(从 argmax 计算 class_idx

  • layer_idx – 如果有多个目标层,则为目标层的索引。默认为 -1。

返回:

激活图(未进行上采样/后处理的原始输出。)

class monai.visualize.class_activation_maps.GradCAM(nn_module, target_layers, upsampler=<function default_upsampler>, postprocessing=<function default_normalizer>, register_backward=True)[source]#

计算梯度加权类激活映射 (Grad-CAM)。此实现基于

Selvaraju 等人,Grad-CAM: Visual Explanations from Deep Networks via Gradient-based Localization, https://arxiv.org/abs/1610.02391

示例

import torch

# densenet 2d
from monai.networks.nets import DenseNet121
from monai.visualize import GradCAM

model_2d = DenseNet121(spatial_dims=2, in_channels=1, out_channels=3)
cam = GradCAM(nn_module=model_2d, target_layers="class_layers.relu")
result = cam(x=torch.rand((1, 1, 48, 64)))

# resnet 2d
from monai.networks.nets import seresnet50
from monai.visualize import GradCAM

model_2d = seresnet50(spatial_dims=2, in_channels=3, num_classes=4)
cam = GradCAM(nn_module=model_2d, target_layers="layer4")
result = cam(x=torch.rand((2, 3, 48, 64)))

注意:为了帮助选择目标层,列出所有层可能会很有用

for name, _ in model.named_modules(): print(name)
compute_map(x, class_idx=None, retain_graph=False, layer_idx=-1, **kwargs)[source]#

使用输入张量 x 计算实际特征图。

参数:
  • xnn_module 的输入。

  • class_idx – 要可视化的类别索引。默认为 None(从 argmax 计算 class_idx

  • layer_idx – 如果有多个目标层,则为目标层的索引。默认为 -1。

返回:

激活图(未进行上采样/后处理的原始输出。)

class monai.visualize.class_activation_maps.GradCAMpp(nn_module, target_layers, upsampler=<function default_upsampler>, postprocessing=<function default_normalizer>, register_backward=True)[source]#

计算梯度加权类激活映射 (Grad-CAM++)。此实现基于

Chattopadhyay 等人,Grad-CAM++: Improved Visual Explanations for Deep Convolutional Networks, https://arxiv.org/abs/1710.11063

compute_map(x, class_idx=None, retain_graph=False, layer_idx=-1, **kwargs)[source]#

使用输入张量 x 计算实际特征图。

参数:
  • xnn_module 的输入。

  • class_idx – 要可视化的类别索引。默认为 None(从 argmax 计算 class_idx

  • layer_idx – 如果有多个目标层,则为目标层的索引。默认为 -1。

返回:

激活图(未进行上采样/后处理的原始输出。)

class monai.visualize.class_activation_maps.ModelWithHooks(nn_module, target_layer_names, register_forward=False, register_backward=False)[source]#

一个模型包装器,用于运行模型的前向/后向步骤并存储一些中间特征/梯度信息。

__init__(nn_module, target_layer_names, register_forward=False, register_backward=False)[source]#
参数:
  • nn_module – 要包装的模型。

  • target_layer_names – 要缓存的层名称。

  • register_forward – 是否缓存与 target_layer_names 对应的正向传播输出。

  • register_backward – 是否缓存与 target_layer_names 对应的反向传播输出。

get_layer(layer_id)[source]#
参数:

layer_id – 层名称字符串或可调用对象。如果它是 lambda m: m.fc 这样的可调用对象,此方法将返回模块 self.model.fc

返回:

self.model 的子模块。

monai.visualize.class_activation_maps.default_normalizer(x)[source]#

通过将 (min, max) 映射到 (1, 0) 进行线性强度缩放。如果输入数据是 PyTorch Tensor,输出数据将在同一设备上是 Tensor,否则,输出数据将是 numpy 数组。

注意:这将翻转幅值(即,最小的将变成最大的,反之亦然)。

返回类型:

~NdarrayTensor

遮挡敏感度#

class monai.visualize.occlusion_sensitivity.OcclusionSensitivity(nn_module, mask_size=16, n_batch=16, verbose=True, mode='gaussian', overlap=0.25, activate=True)[source]#

此类计算模型对给定图像预测的遮挡敏感度。遮挡敏感度是指当图像的遮挡部分发生变化时,给定预测的概率如何变化。这有助于理解网络为何做出某些决策。

当图像的重要部分被遮挡时,正确分类图像的概率会降低。因此,更负的值意味着相应的遮挡区域在决策过程中更重要。

__call__ 方法将返回两个 torch.Tensor:一个遮挡图和一个最可能类别的图像。如果使用了边界框,两个图像都将被裁剪,但体素尺寸始终与输入匹配。

遮挡图显示当图像的相应部分被遮挡时的推理概率。因此,更多负值意味着该区域在决策过程中很重要。该图的形状为 BCHW(D)N,其中 N 是网络要推理的类别数。因此,类 i 的遮挡可以通过 map[...,i] 查看。

最可能的类别是当图像的相应部分被遮挡时,该可能类别的图像(等同于 occ_map.argmax(dim=-1))。

参见:R. R. Selvaraju 等人。Grad-CAM: Visual Explanations from Deep Networks via Gradient-based Localization. https://doi.org/10.1109/ICCV.2017.74

示例

# densenet 2d
from monai.networks.nets import DenseNet121
from monai.visualize import OcclusionSensitivity
import torch

model_2d = DenseNet121(spatial_dims=2, in_channels=1, out_channels=3)
occ_sens = OcclusionSensitivity(nn_module=model_2d)
occ_map, most_probable_class = occ_sens(x=torch.rand((1, 1, 48, 64)), b_box=[2, 40, 1, 62])

# densenet 3d
from monai.networks.nets import DenseNet
from monai.visualize import OcclusionSensitivity

model_3d = DenseNet(spatial_dims=3, in_channels=1, out_channels=3, init_features=2, growth_rate=2, block_config=(6,))
occ_sens = OcclusionSensitivity(nn_module=model_3d, n_batch=10)
occ_map, most_probable_class = occ_sens(torch.rand(1, 1, 6, 6, 6), b_box=[1, 3, -1, -1, -1, -1])

另请参阅

  • monai.visualize.occlusion_sensitivity.OcclusionSensitivity.

__init__(nn_module, mask_size=16, n_batch=16, verbose=True, mode='gaussian', overlap=0.25, activate=True)[source]#

遮挡敏感度构造函数。

参数:
  • nn_module – 用于推理的分类模型

  • mask_size – 要遮挡的框的大小,中心位于中心体素。如果给定单个数字,则用于所有维度。如果给定序列,则用于每个维度单独使用。

  • n_batch – 推理时一个批处理中的图像数量。

  • verbose – 使用进度条(如果 tqdm 可用)。

  • mode

    遮挡区域应该替换成什么?如果给定一个浮点数,该值将用于整个遮挡。否则,可以提供 gaussianmean_imgmean_patch

    • gaussian: 遮挡区域乘以 1 - 高斯核。这样,遮挡在中心为 0,在边缘不变,平滑变化。使用高斯时,将使用加权平均值组合重叠区域。这将使用高斯(不是 1-高斯)进行,因为遮挡区域计数更多。

    • mean_patch: 遮挡区域将替换为遮挡区域的均值。

    • mean_img: 遮挡区域将替换为整个图像的均值。

  • overlap – 推理区域之间的重叠。应在 0<=x<1 范围内。

  • activate – 如果为 True,则在通道数 > 1 时进行 softmax 激活,否则进行 sigmoid 激活。如果为 False,则不进行任何激活。如果为 callable,则对推理输出使用可调用对象。

static constant_occlusion(x, val, mask_size)[source]#

使用恒定遮挡进行遮挡。乘法为零,加法为常数值。

返回类型:

tuple[float, Tensor]

static crop_meshgrid(grid, b_box, mask_size)[source]#

裁剪网格,以便我们只对图像的子部分执行遮挡敏感度计算。

返回类型:

tuple[MetaTensor, SpatialCrop, Sequence]

static gaussian_occlusion(x, mask_size, sigma=0.25)[source]#

对于高斯遮挡,乘法为 1-高斯,加法为零。经验表明,默认 sigma 为 0.25 可以获得合理核,参见此处:Project-MONAI/MONAI#5230

返回类型:

tuple[Tensor, float]

static predictor(cropped_grid, nn_module, x, mul, add, mask_size, occ_mode, activate, module_kwargs)[source]#

传递给滑动窗口推理器的预测函数。接受裁剪后的网格,该网格引用输入图像中的坐标。我们使用左上角的索引结合 mask_size 来确定要遮挡的图像区域。遮挡是在原始图像 x 上执行的,使用 cropped_region * mul + add。有时 muladd 是预先计算的(例如,恒定高斯模糊),或者有时是在运行时计算的(例如,遮挡块的均值)。因此提供了 occ_mode。最后,每次调用模型后使用 activate 进行激活。

参数:
  • cropped_grid – 网格的子部分,其中每个体素引用输入图像的坐标。网格由 OcclusionSensitivity 类创建,子集的生成由 sliding_window_inference 确定。

  • nn_module – 对数据调用的模块。

  • x – 最初传递给 OcclusionSensitivity.__call__ 的图像。

  • mul – 遮挡区域将乘以这个值。可以是 torch.Tensorfloat

  • add – 乘法后,将这个值添加到遮挡区域。可以是 torch.Tensorfloat

  • mask_size – 要遮挡的框的大小,中心位于中心体素。应该是一个序列,每个空间维度一个值。

  • occ_mode – 可能用于运行时计算 muladd

  • activate – 如果为 True,则在通道数 > 1 时进行 softmax 激活,否则进行 sigmoid 激活。如果为 False,则不进行任何激活。如果为 callable,则对推理输出使用可调用对象。

  • module_kwargs – 推理时传递给模块的 kwargs

基于梯度的显著性图#

class monai.visualize.gradient_based.GuidedBackpropGrad(model)[source]#

基于 Springenberg 和 Dosovitskiy 等人 https://arxiv.org/abs/1412.6806,通过反向传播正梯度和输入(参见 _AutoGradReLU)计算基于梯度的显著性图。

另请参阅

class monai.visualize.gradient_based.GuidedBackpropSmoothGrad(model, stdev_spread=0.15, n_samples=25, magnitude=True, verbose=True)[source]#

基于 GuidedBackpropGradSmoothGrad 计算基于梯度的显著性图。

class monai.visualize.gradient_based.SmoothGrad(model, stdev_spread=0.15, n_samples=25, magnitude=True, verbose=True)[source]#

基于输入图像 x 的噪声版本的 n_samples(高斯加性)计算平均敏感度图。

另请参阅

class monai.visualize.gradient_based.VanillaGrad(model)[source]#

给定输入图像 x,调用此类将执行前向传播,然后将除一个激活(由 index 定义)之外的所有激活设为零,并反向传播到图像以获得基于梯度的显著性图。

如果 index 为 None,将使用输出 logits 的 argmax。

另请参阅

工具函数#

monai.visualize.utils.blend_images(image, label, alpha=0.5, cmap='hsv', rescale_arrays=True, transparent_background=True)[source]#

融合图像和标签。两者应具有 CHW[D] 形状。图像可以有 C==1 或 3 个通道(灰度或 RGB)。标签预期 C==1。

参数:
  • image – 与标签数据融合的输入图像。

  • label – 与图像数据融合的输入标签。

  • alpha – 指定标签的权重,其中 0 表示完全透明,1 表示完全不透明。可以是一个单一值,也可以是一个与输入图像大小相同的数组/张量。

  • cmap – 指定 matplotlib 中的颜色映射,默认为 hsv,更多详情请参见:https://matplotlib.net.cn/2.0.2/users/colormaps.html

  • rescale_arrays – 是否先将数组重新缩放到 [0, 1],默认为 True

  • transparent_background – 如果为 true,标签字段中的任何零值将不被着色。

_images/blend_images.png
monai.visualize.utils.matshow3d(volume, fig=None, title=None, figsize=(10, 10), frames_per_row=None, frame_dim=-3, channel_dim=None, vmin=None, vmax=None, every_n=1, interpolation='none', show=False, fill_value=nan, margin=1, dtype=<class 'numpy.float32'>, **kwargs)[source]#

创建三维体图像网格。

参数:
  • volume – 要显示的三维体。数据形状可以是 BCHWDCHWDHWD。更高维度的数组将被重塑为 (-1, H, W, [C]),C 取决于 channel_dim 参数。也可以传入通道优先 (C, H[, W, D]) 的数组列表,在这种情况下它们将显示为填充和堆叠的体。

  • fig – 要使用的 matplotlib 图形或 Axes。如果为 None,将创建一个新图形。

  • title – 图形的标题。

  • figsize – 图形的大小。

  • frames_per_row – 每行显示的帧数。如果为 None,将使用 sqrt(firstdim)。

  • frame_dim – 对于更高维度的数组,(-1-2-3) 中的哪个维度移动到 -3 维度。维度并重塑为 (-1, H, W) 形状以构建帧,默认为 -3

  • channel_dim – 如果不是 None,显式指定要转置到最后一个维度的通道维度,形状为 (-1, H, W, C)。这可用于绘制 RGB 彩色图像。如果为 None,通道维度将与 frame_dimbatch_dim 一起展平,形状为 (-1, H, W)。请注意,它只能支持 3D 输入图像。默认为 None。

  • vmin – matplotlib imshowvmin

  • vmax – matplotlib imshowvmax

  • every_n – 帧的下采样因子,以便只显示每 n 帧。

  • interpolation – 用于 matplotlib matshow 的插值方法。

  • show – 如果为 True,显示图形。

  • fill_value – 用于网格空部分的填充值。

  • margin – 用于网格的边距。

  • dtype – 输出堆叠帧的数据类型。

  • kwargs – 传递给 matplotlib matshowimshow 的附加关键字参数。

示例

>>> import numpy as np
>>> import matplotlib.pyplot as plt
>>> from monai.visualize import matshow3d
# create a figure of a 3D volume
>>> volume = np.random.rand(10, 10, 10)
>>> fig = plt.figure()
>>> matshow3d(volume, fig=fig, title="3D Volume")
>>> plt.show()
# create a figure of a list of channel-first 3D volumes
>>> volumes = [np.random.rand(1, 10, 10, 10), np.random.rand(1, 10, 10, 10)]
>>> fig = plt.figure()
>>> matshow3d(volumes, fig=fig, title="List of Volumes")
>>> plt.show()