读CDO代码

news2025/1/15 13:31:46

前置任务

module 'PIL.Image' has no attribute 'ANTIALIAS'

Image.ANTIALIAS 替换为 Image.LANCZOS,参考https://blog.csdn.net/fovever_/article/details/134690657

OSError: 'science' is not a valid package style, path of style file, URL of

这是对应可视化里面生成期刊风格的图表,但是本地缺少相应的font
参考https://blog.csdn.net/qysh123/article/details/136075472,但是感觉很复杂,而且也不一定能成功,干脆先把plt.style.context([‘science’, ‘ieee’, ‘no-latex’])那一部分注释掉,暂时还是用默认字体在这里插入图片描述

module 'numpy' has no attribute 'bool'

这个报错影响测试环节,参考https://blog.csdn.net/weixin_49779629/article/details/136137827,把bool改成bool_

Argument interpolation should be of type InterpolationMode instead of int. P

这是warning,暂时不影响,可以参考https://blog.csdn.net/weixin_39518984/article/details/119897453,需要调Pillow版本

还有个问题是提供的运行脚本仅针对单一类别(那训练了个啥?),所以我加上个类别列表遍历。但是这样的话,每轮到一个新类别,dataset.py里load_mvtec3d函数中的mvtec3d_classes列表会持续添加’mvtec-'字符,暂时没排查出是哪来的,不过这个只影响assert,所以干脆注释掉

train.py

虽然这个代码是test phase,但不是pure test,还需要训练50epoch(都加上.eval()了结果还是可以算梯度优化,那这个.eval()到底有什么用)
看数据集调用,图像都直接读取存入内存,现在这异常检测空间换时间这么极端吗
输入16,3,256,256的img,16,1,256,256的gt(其实还有类别标签,但训练阶段没有用到,那就是说训练损失是像素级的)

CDOModel(
  (model): ModuleDict(
    (ME): HRNet_(
      调用预训练模型(调用下载)的专家模型不计算梯度
      (model): HighResolutionNet(
        (conv1): Conv2d(3, 64, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)
        16,64,128,128
        (bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
        (relu): ReLU(inplace=True)
        (conv2): Conv2d(64, 64, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)
        16,64,64,64
        (bn2): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
        (relu): ReLU(inplace=True)
        (layer1): Sequential(
          (0): Bottleneck(输入+输出的残差
            (conv1): Conv2d(64, 64, kernel_size=(1, 1), stride=(1, 1), bias=False)
            (bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
            (conv2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
            (bn2): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
            (conv3): Conv2d(64, 256, kernel_size=(1, 1), stride=(1, 1), bias=False)
            (bn3): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
            (relu): ReLU(inplace=True)
            (downsample): Sequential(
              (0): Conv2d(64, 256, kernel_size=(1, 1), stride=(1, 1), bias=False)
              (1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
            )
          )
          (1~3): Bottleneck(
            (conv1): Conv2d(256, 64, kernel_size=(1, 1), stride=(1, 1), bias=False)
            (bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
            (conv2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
            (bn2): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
            (conv3): Conv2d(64, 256, kernel_size=(1, 1), stride=(1, 1), bias=False)
            (bn3): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
            (relu): ReLU(inplace=True)
          )
        )
        16,256,64,64
        (transition1): ModuleList(
          (0): Sequential(
            (0): Conv2d(256, 32, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
            (1): BatchNorm2d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
            (2): ReLU(inplace=True)
          )
          (1): Sequential(
            (0): Sequential(
              (0): Conv2d(256, 64, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)
              (1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
              (2): ReLU(inplace=True)
            )
          )
          分别单独输入给这两层
          然后分别得到16,32,64,6416,64,32,32 x_list
          然后再分别把这俩结果分别输入stage2的两个branch
        )
        (stage2): Sequential(
          (0): HighResolutionModule(
            (branches): ModuleList(
              (0): Sequential(
                (0~3): BasicBlock(
                  (conv1): Conv2d(32, 32, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
                  (bn1): BatchNorm2d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
                  (relu): ReLU(inplace=True)
                  (conv2): Conv2d(32, 32, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
                  (bn2): BatchNorm2d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
                )
                
              )
              (1): Sequential(
                (0~3): BasicBlock(
                  (conv1): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
                  (bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
                  (relu): ReLU(inplace=True)
                  (conv2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
                  (bn2): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
                )
              然后分别得到16,32,64,6416,64,32,32  x
              )
            )
            ~~下面的fuse_layers[i]的层数和前面的x的数量(branch的数量对应)~~ 
            y = x[0] if i == 0 else self.fuse_layers[i][0](x[0])
            (fuse_layers): ModuleList(将不同分支交叉融合
              (0): ModuleList(
                (0): None
                (1): Sequential(
                  (0): Conv2d(64, 32, kernel_size=(1, 1), stride=(1, 1), bias=False)
                  (1): BatchNorm2d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
                )
              )
              也就是说x[0]16,32,64,64直接作为一个y
              计算fuse_layers[0][1](x[1])得到16,32,32,32后对它双线性插值得到16,32,64,64
              再和y相加后relu,存入y_list这个列表
            #(relu): ReLU(inplace=True)              
              (1): ModuleList(
                (0): Sequential(
                  (0): Sequential(
                    (0): Conv2d(32, 64, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)
                    (1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
                  )
                )
                (1): None
              )
              这一层fuse_layers[1][0](x[0])作为y 16,64,32,32
              此时i=j=1相当于相同分支,所以y直接与x[1]求和
            #(relu): ReLU(inplace=True)              
              relu放进y_list
            )

          )
        )
        (transition2): ModuleList(
          (0): None
          (1): None
          (2): Sequential(
            (0): Sequential(
              (0): Conv2d(64, 128, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)
              (1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
              (2): ReLU(inplace=True)
            )
            其实结果来说就是先把y_list放进清空的x_list
            然后再算一下transition2[2](y_list[-1])
            得到16,128,16,16放进x_list
            然后分别通过下面的三个branch
          )
        )
        (stage3): Sequential(
          (0~3): HighResolutionModule(
            (branches): ModuleList(
              (0): Sequential(
                (0~3): BasicBlock(
                  (conv1): Conv2d(32, 32, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
                  (bn1): BatchNorm2d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
                  (relu): ReLU(inplace=True)
                  (conv2): Conv2d(32, 32, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
                  (bn2): BatchNorm2d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
                )                
              )
              (1): Sequential(
                (0~3): BasicBlock(
                  (conv1): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
                  (bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
                  (relu): ReLU(inplace=True)
                  (conv2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
                  (bn2): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
                )                
              )
              (2): Sequential(
                (0~3): BasicBlock(
                  (conv1): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
                  (bn1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
                  (relu): ReLU(inplace=True)
                  (conv2): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
                  (bn2): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
                )                
              )
            )
            此时得到维度不变的x
            (fuse_layers): ModuleList(
              (0): ModuleList(
                (0): None
                (1): Sequential(
                  (0): Conv2d(64, 32, kernel_size=(1, 1), stride=(1, 1), bias=False)
                  (1): BatchNorm2d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
                )
                (2): Sequential(
                  (0): Conv2d(128, 32, kernel_size=(1, 1), stride=(1, 1), bias=False)
                  (1): BatchNorm2d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
                )
              )
              x[0]直接作为y
              随后先后分别像上面一样依次经过fuse_layers[0][1~2](x[1~2])、插值、累加给y,最后relu给清空的y_list
              (1): ModuleList(
                (0): Sequential(
                  (0): Sequential(
                    (0): Conv2d(32, 64, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)
                    (1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
                  )
                )
                (1): None
                (2): Sequential(
                  (0): Conv2d(128, 64, kernel_size=(1, 1), stride=(1, 1), bias=False)
                  (1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
                )
              )
              fuse_layers[1][0](x[0])作为y
              x[1]直接加给y
              fuse_layers[1][2](x[2])插值后再加给y
              relu入组
              (2): ModuleList(
                (0): Sequential(
                  (0): Sequential(
                    (0): Conv2d(32, 32, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)
                    (1): BatchNorm2d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
                    (2): ReLU(inplace=True)
                  )
                  (1): Sequential(
                    (0): Conv2d(32, 128, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)
                    (1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
                  )
                )
                (1): Sequential(
                  (0): Sequential(
                    (0): Conv2d(64, 128, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)
                    (1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
                  )
                )
                (2): None
              )
              fuse_layers[2][0](x[0])作为y
              fuse_layers[2][1](x[1])直接再加给y
              x[2]再加给y
              relu入组              
            )
          注意这里是有三次的高像素模块        
          )

        )
        (transition3): ModuleList(
          (0): None
          (1): None
          (2): None
          (3): Sequential(
            (0): Sequential(
              (0): Conv2d(128, 256, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)
              (1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
              (2): ReLU(inplace=True)
            )
          其实结果来说就是先把y_list放进清空的x_list
          然后再算一下transition3[3](y_list[-1])
          得到16,256,8,8放进x_list
          然后分别通过下面的四个branch
          )
        )
        (stage4): Sequential(
          (0~2): HighResolutionModule(
            (branches): ModuleList(
              (0): Sequential(
                (0~3): BasicBlock(
                  (conv1): Conv2d(32, 32, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
                  (bn1): BatchNorm2d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
                  (relu): ReLU(inplace=True)
                  (conv2): Conv2d(32, 32, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
                  (bn2): BatchNorm2d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
                )                
              )
              (1): Sequential(
                (0~3): BasicBlock(
                  (conv1): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
                  (bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
                  (relu): ReLU(inplace=True)
                  (conv2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
                  (bn2): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
                )                
              )
              (2): Sequential(
                (0~3): BasicBlock(
                  (conv1): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
                  (bn1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
                  (relu): ReLU(inplace=True)
                  (conv2): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
                  (bn2): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
                )                
              )
              (3): Sequential(
                (0~3): BasicBlock(
                  (conv1): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
                  (bn1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
                  (relu): ReLU(inplace=True)
                  (conv2): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
                  (bn2): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
                )
              )
            )
            (fuse_layers): ModuleList(
              (0): ModuleList(
                (0): None
                (1): Sequential(
                  (0): Conv2d(64, 32, kernel_size=(1, 1), stride=(1, 1), bias=False)
                  (1): BatchNorm2d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
                )
                (2): Sequential(
                  (0): Conv2d(128, 32, kernel_size=(1, 1), stride=(1, 1), bias=False)
                  (1): BatchNorm2d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
                )
                (3): Sequential(
                  (0): Conv2d(256, 32, kernel_size=(1, 1), stride=(1, 1), bias=False)
                  (1): BatchNorm2d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
                )
              )
              x[0]作为y
              fuse_layers[0][1](x[1])插值再加给y
              fuse_layers[0][2](x[2])插值再加给y
              fuse_layers[0][3](x[3])插值再加给y
              relu入组       
              (1): ModuleList(
                (0): Sequential(
                  (0): Sequential(
                    (0): Conv2d(32, 64, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)
                    (1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
                  )
                )
                (1): None
                (2): Sequential(
                  (0): Conv2d(128, 64, kernel_size=(1, 1), stride=(1, 1), bias=False)
                  (1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
                )
                (3): Sequential(
                  (0): Conv2d(256, 64, kernel_size=(1, 1), stride=(1, 1), bias=False)
                  (1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
                )
              )
              fuse_layers[1][0](x[0])作为y
              x[1]直接再加给y
              fuse_layers[1][2](x[2])插值再加给y
              fuse_layers[1][3](x[3])插值再加给y
              relu入组       
              (2): ModuleList(
                (0): Sequential(
                  (0): Sequential(
                    (0): Conv2d(32, 32, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)
                    (1): BatchNorm2d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
                    (2): ReLU(inplace=True)
                  )
                  (1): Sequential(
                    (0): Conv2d(32, 128, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)
                    (1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
                  )
                )
                (1): Sequential(
                  (0): Sequential(
                    (0): Conv2d(64, 128, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)
                    (1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
                  )
                )
                (2): None
                (3): Sequential(
                  (0): Conv2d(256, 128, kernel_size=(1, 1), stride=(1, 1), bias=False)
                  (1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
                )
              )
              fuse_layers[2][0](x[0])作为y
              fuse_layers[2][1](x[1])直接再加给y
              x[2]再加给y
              fuse_layers[2][3](x[3])插值再加给y
              relu入组       
              (3): ModuleList(
                (0): Sequential(
                  (0): Sequential(
                    (0): Conv2d(32, 32, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)
                    (1): BatchNorm2d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
                    (2): ReLU(inplace=True)
                  )
                  (1): Sequential(
                    (0): Conv2d(32, 32, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)
                    (1): BatchNorm2d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
                    (2): ReLU(inplace=True)
                  )
                  (2): Sequential(
                    (0): Conv2d(32, 256, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)
                    (1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
                  )
                )
                (1): Sequential(
                  (0): Sequential(
                    (0): Conv2d(64, 64, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)
                    (1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
                    (2): ReLU(inplace=True)
                  )
                  (1): Sequential(
                    (0): Conv2d(64, 256, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)
                    (1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
                  )
                )
                (2): Sequential(
                  (0): Sequential(
                    (0): Conv2d(128, 256, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)
                    (1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
                  )
                )
                (3): None
              )
            )
              fuse_layers[3][0](x[0])作为y
              fuse_layers[3][1](x[1])直接再加给y
              fuse_layers[3][2](x[2])再加给y
              x[3]再加给y
              relu入组

          )
      注意这个高像素模块计算3)
        最后只保留前三个作为x_list

		其实只用到了前面的部分,最后这一部分没有调用
        (last_layer): Sequential(
          (0): Conv2d(480, 480, kernel_size=(1, 1), stride=(1, 1))
          (1): BatchNorm2d(480, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
          (2): ReLU(inplace=True)
          (3): Conv2d(480, 19, kernel_size=(1, 1), stride=(1, 1))
        )
      )
    )
    (MA)	同上
  )
)

从而分别有了专家和学徒的fe_list和fa_list
接下来计算损失

cal_loss

先通过双线性插值把二者中每一个特征图都调整到第一层的特征图长宽(H_0, W_0)即16,32,64,64和16,64,64,64和16,256,64,64
对应遍历每一层的fe和fa,先将mask也最近邻插值到16,1,64,64
fe和fa重塑为65536,32,mask是65532,
根据mask是否为0,分别取出fa和fe的正常区域和异常区域特征。fe_n和fa_n代表正常样本的特征(63576,32),而fe_s和fa_s代表异常(1960,32)

cal_discrepancy

以fe_n和fa_n为例,分别归一化后计算欧氏距离平方d_p,并有其均值 mu_p
自适应计算权重:
对于正常样本,权重计算为((d_p) / mu_p) ** gamma。
对于异常样本,权重计算为((mu_p) / d_p) ** gamma。(等一下,训练的时候为啥会有异常?!)
再聚合,也就是计算加权的特征差异性损失,d_p=torch.sum(d_p*w)
sum_w=torch.sum(w)
从而 对于正常和异常的特征计算得到loss_n、weight_n、loss_s、weight_s
loss += ((loss_n - loss_s) / (weight_n + weight_s) * B)其中B是batchsize

然后测试阶段
取数据有data 16,3,256,256;mask 16,1,256,256;label 16个01标签组成的tensor;name 16个类似bagel_combined_000组成的tuple
先将data逆标准化(乘方差,加均值,乘255,uint8)得到256,256,3组成的列表test_imgs
label转成列表 gt_list
mask转成256,256组成的列表 gt_mask_list

但网络中输入的还是一开始的data
从而有outputs
然后计算评估指标

cal_am

同样先对专家和学徒的fe_list和fa_list通过双线性插值把二者中每一个特征图都调整到第一层的特征图长宽(H_0, W_0)即16,32,64,64和16,64,64,64和16,256,64,64
对应遍历每一层的fe和fa,直接整体视为异常样本计算d_p(视作异常样本其实也就影响OOM自适应计算权重,但是反正这里不自适应计算权重了,所以其实没啥影响)至于这里没有二维化,而是直接输入四维张量,是因为二维化可以方便根据掩码区分正常和异常的像素点,以便分别计算它们的损失,这里不需要区分,所以输入四维张量没有影响

cal_discrepancy

这一次不自适应计算权重
不聚合d_p(这样的话其实权重都根本没有用到)

从而有16,64,64的d_p-》a_map 16,1,64,64,再双线性插值到16,1,256,256
从而遍历每一层的fe和fa的过程中累加这个a_map,再压缩得到16,256,256
请添加图片描述
随后遍历,分别经过高斯滤波后有am_np_list 16个256,256ndarray组成的列表,这也就是score
请添加图片描述

当把所有测试数据遍历完,再把所有的score做成110,256,256的ndarray,和gt_mask_list、gt_list一起送入metric_cal
issue里提到AU-PRO的计算过程确实很耗时,所以不到最后不计算

metric_cal

对于AUC很简单直接调包完事

至于pro

cal_pro_metric

输入:labeled_imgs是110个256,256的ndarray组成的列表,score_imgs是110,256,256的ndarray

  • 二值化标签图:首先,将labeled_imgs(标签图)中的像素值二值化。小于或等于0.45的值被设置为0(非异常),大于0.45的值被设置为1(异常)。然后,将标签图转换为布尔类型,以便后续处理。
  • 初始化变量:定义存储不同阈值下的平均IOU(交并比)、IOU的标准差、平均PRO、PRO的标准差、阈值和假正率(FPR)的列表。
  • 阈值迭代:通过在score_imgs的最大和最小值之间生成一系列阈值,分别根据阈值逐步将score_imgs(分数图)二值化(大于阈值为1,否则为0),创建二进制得分图binary_score_maps。对于每个阈值:
  • a. 计算PRO:对于每个标签图,使用measure.label找到连通区域,并对每个区域计算其与二值化得分图的重叠部分。这是通过计算交集除以实际区域的面积来完成的。
    通过measure.regionprops计算得到的props,它代表了标签图labeled_imgs[i]中的所有连通区域的属性
  • 获取边界框:prop.bbox提供了连通区域的边界框(x_min, y_min, x_max, y_max)。这个边界框定义了包含当前连通区域的最小矩形。(根据真实异常区域裁剪出一个roi框区域)
  • 裁剪预测标签:使用边界框从二进制得分图binary_score_maps[i]中裁剪出对应的预测区域cropped_pred_label。(把预测异常掩码放到roi上)
  • 裁剪实际标签:虽然原始代码中有注释指向masks,但实际使用的是prop.filled_image,它表示的是填充的区域图像,即当前连通区域内部的像素标记为True,外部的像素标记为False。(真实异常掩码在roi上)
  • 计算交集:通过np.logical_and(cropped_pred_label, cropped_mask)计算预测区域和实际区域之间的交集。这里的交集是指两者同时为True的像素点。
  • 计算PRO值:PRO值是交集的像素数除以连通区域的面积(prop.area),这表示预测正确的区域占实际异常区域的比例。
  • b. 计算IOU:对于每幅图像,计算标签图和二值化得分图的交并比(IOU)。这是通过计算交集除以并集来完成的。(可以认为pro更关注于每个独立异常区域的检测效果,而iou是整幅图像级别的平均表现,但是最终这个代码里并没有用到iou,怪不得作者觉得耗时间?)
  • c. 存储结果:将每个步骤计算的IOU和PRO的平均值和标准差存储起来。
  • 计算FPR:对于每个阈值,计算假正率,即错误标记为异常的非异常像素占所有非异常像素的比例。

masks_neg=~labeled_imgs,代表所有非异常(背景)的像素。fpr是在当前阈值下,将背景像素错误分类为异常的比例,即假正率。这是通过计算二值化得分图(binary_score_maps)与masks_neg的逻辑与操作的结果中True值的数量,除以masks_neg中True值的总数量得到的。

  • 计算PRO-AUC:在特定的FPR阈值(如0.3)下,计算PRO曲线下的面积(PRO-AUC)。这是通过插值方法在限定的FPR下对PRO值进行积分得到的(说的是auc函数内部操作)

idx = fprs <= fpr_thresh筛选出所有小于或等于fpr_thresh(0.3)的FPR值的索引
fprs_selected = fprs[idx]选取了低于FPR阈值的FPR值,而pros_mean_selected = pros_mean[idx]选取了对应的PRO平均值。(fprs、pros_mean对应阈值数量)
将fprs_selected的范围从[0, fpr_thresh]归一化到[0, 1],这是因为标准的AUC计算假设FPR的范围是[0, 1]。
使用auc(fprs_selected, pros_mean_selected)计算选定FPR范围内的PRO曲线下的面积(PRO-AUC)。auc函数通常是根据FPR排序的点来计算曲线下面积的,所以输入的FPR和PRO值需要按FPR升序排列。

对比了一下和shape-guided的区别

  • 计算面积:sg显式地使用梯形法则来计算PRO曲线下的面积,而cdo是调用auc函数
  • 阈值的选择:SG方法通过在预测分数的分布中np.linspace均匀选择阈值,而cdo方法在最大和最小预测分数之间均匀取步长来确定阈值。
  • 数据结构:SG方法将预测和真实标签作为二维numpy浮点数组处理,而cdo方法处理的是布尔类型的二维numpy数组。
  • 组件处理:SG方法中一直都是用的整张图的gt掩码来计算重叠,而cdo方法虽然一开始有binary_score_maps,但后面截了roi,是再生成一个cropped_mask得到的区域掩码。
  • 假阳性率(FPR):SG方法计算每个阈值下的假阳性率(FPR),并将其与PRO值一起用于评估,而cdo方法中主要关注于预设特定阈值0.3的FPR。并且sg里是根据像素比例计算fpr,而cdo是逻辑与直接计算

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1513822.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

GraphView实现测量工具

效果演示&#xff1a; 主模块代码&#xff1a; MeasureGraphView::MeasureGraphView(QWidget *parent): QWidget(parent) {ui.setupUi(this);m_measureType NoType;m_bll BllData::getInstance();m_scene new GraphicsScene;connect(m_bll, &BllData::pressMeasurePos…

力扣106 从中序与后续遍历序列构造二叉树

文章目录 题目描述解题思路代码 题目描述 给定两个整数数组 inorder 和 postorder &#xff0c;其中 inorder 是二叉树的中序遍历&#xff0c; postorder 是同一棵树的后序遍历&#xff0c;请你构造并返回这颗 二叉树 。 示例 1: 输入&#xff1a;inorder [9,3,15,20,7], …

【单片机毕业设计7-基于stm32c8t6的智能温室大棚系统】

【单片机毕业设计7-基于stm32c8t6的智能温室大棚系统】 前言一、功能介绍二、硬件部分三、软件部分总结 前言 &#x1f525;这里是小殷学长&#xff0c;单片机毕业设计篇7基于stm32的智能衣柜系统 &#x1f9ff;创作不易&#xff0c;拒绝白嫖可私 一、功能介绍 ---------------…

Sqllab第一关通关笔记

知识点&#xff1a; 明白数值注入和字符注入的区别 数值注入&#xff1a;通过数字运算判断&#xff0c;1/0 1/1 字符注入&#xff1a;通过引号进行判断&#xff0c;奇数个和偶数个单引号进行识别 联合查询&#xff1a;union 或者 union all 需要满足字段数一致&…

基础小白快速入门opencv-------C++ 在opencv的应用以及opencv的下载配置

啥是opencv&#xff1f; OpenCV&#xff08;开源计算机视觉库 Open Source Computer Vision Library&#xff09;是一个跨平台的计算机视觉库&#xff0c;最初由Intel开发&#xff0c;现在由一个跨国团队维护。它免费提供给学术和商业用途&#xff0c;并且是用C语言写成的&…

doit,一个非常实用的 Python 库!

更多Python学习内容&#xff1a;ipengtao.com 大家好&#xff0c;今天为大家分享一个非常实用的 Python 库 - doit。 Github地址&#xff1a;https://github.com/pydoit/doit 在软件开发和数据处理过程中&#xff0c;经常会遇到需要执行一系列任务的情况&#xff0c;这些任务可…

华为数通方向HCIP-DataCom H12-821题库(多选题:161-180)

第161题 以下关于IPv6优势的描述,正确的是哪些项? A、底层自身携带安全特性 B、加入了对自动配置地址的支持,能够无状态自动配置地址 C、路由表相比IPv4会更大,寻址更加精确 D、头部格式灵活,具有多个扩展头 【参考答案】ABD 【答案解析】 第162题 在OSPF视图下使用Filt…

做伦敦银要等怎样的价格与行情?

对于不同的伦敦银投资者来说&#xff0c;合适的入市价格和好的行情机会&#xff0c;标准可能并不一样&#xff0c;因为不同人有不同的交易策略、风险偏好和盈利目标。对于喜欢做趋势跟踪的投资者来说&#xff0c;一波明显而持续的上涨或下跌趋势&#xff0c;可能就是最好的行情…

yolov5-v6.0详细解读

yolov5-v6.0详细解读 一、yolov5版本介绍二、网络结构2.1 Backbone特征提取部分2.1.1 ConvBNSiLU模块2.1.2 C3模块2.1.2.1 BottleNeck模块 2.1.3 SPPF模块 2.2 Neck特征融合部分2.2.1 FPN2.2.2 PANet 2.3Head模块 三、目标框回归3.1 yolo标注格式3.2 yolov4目标回归框3.3 yolov…

数据结构-链表(二)

1.两两交换列表中的节点 给你一个链表&#xff0c;两两交换其中相邻的节点&#xff0c;并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题&#xff08;即&#xff0c;只能进行节点交换&#xff09;。 输入&#xff1a;head [1,2,3,4] 输出&#xff1a;[2…

框架漏洞Shiroweblogicfastjson || 免杀思路

继续来讲一下我们的框架漏洞,先讲一下Shiro 1.Shiro反序列化 1.原理 Shiro的漏洞形成呢&#xff0c;就是因为存在了RememberMe这样的一个字段 Shiro 框架在处理 "rememberMe" 功能时使用了不安全的反序列化方法&#xff0c;攻击者可以构造恶意序列化数据&#xff0…

基于YOLOv8/YOLOv7/YOLOv6/YOLOv5的危险物品检测系统(深度学习模型+PySide6界面+训练数据集+Python代码)

摘要&#xff1a;本文深入介绍了一个采用深度学习技术的危险物品识别系统&#xff0c;该系统融合了最新的YOLOv8算法&#xff0c;并对比了YOLOv7、YOLOv6、YOLOv5等早期版本的性能。该系统在处理图像、视频、实时视频流及批量文件时&#xff0c;能够准确识别和分类各种危险物品…

9、组合模式(结构性模式)

组合模式又叫部分整体模式&#xff0c;它创建了对象组的树形结构&#xff0c;将对象组合成树状结构&#xff0c;以一致的方式处理叶子对象以及组合对象&#xff0c;不以层次高低定义类&#xff0c;都是结点类 一、传统组合模式 举例&#xff0c;大学、学院、系&#xff0c;它们…

勾八头歌之数据科学导论—数据预处理

第1关&#xff1a;引言-根深之树不怯风折&#xff0c;泉深之水不会涸竭 第2关&#xff1a;数据清理-查漏补缺 import numpy as np import pandas as pd import matplotlib.pyplot as pltdef student():# Load the CSV file and replace #NAME? with NaNtrain pd.read_csv(Tas…

人工智能的幽默“失误”

人工智能迷惑行为大赏 随着ChatGPT热度的攀升&#xff0c;越来越多的公司也相继推出了自己的AI大模型&#xff0c;如文心一言、通义千问等。各大应用也开始内置AI玩法&#xff0c;如抖音的AI特效&#xff5e;在使用过程中往往会遇到一些问题&#xff0c;让你不得不怀疑&#x…

反向传播 — 简单解释

一、说明 关于反向传播&#xff0c;我有一个精雕细刻的案例计划&#xff0c;但是实现了一半&#xff0c;目前没有顾得上继续充实&#xff0c;就拿论文的叙述这里先起个头&#xff0c;我后面将修改和促进此文的表述质量。 二、生物神经元 大脑是一个由大约100亿个神经元组成的复…

HD_VG_130M数据集预处理

数据集介绍 HD_VG_130M是文生视频常用数据集&#xff0c;其视频来源于油管&#xff0c;可通过该谷歌云盘链接下载官方文件&#xff0c;如下所示&#xff0c;其中metafiles中包含20个json文件&#xff0c;请先将其全部下载到本地&#xff0c;假设保存地址为"E:/HD_VG_130M…

Android Gradle 开发与应用 (六) : 创建buildSrc插件和使用命令行创建Gradle插件

1. 前言 前文中&#xff0c;我们介绍了在Android中&#xff0c;如何基于Gradle 8.2&#xff0c;创建Gradle插件。这篇文章&#xff0c;我们以buildSrc的方式来创建Gradle插件。此外&#xff0c;还介绍一种用Cmd命令行的方式&#xff0c;来创建独立的Gradle插件的方式。 1.1 本…

开源大数据集群部署(十五)Zookeeper集群部署

作者&#xff1a;櫰木 1、集群规划 主机版本角色系统用户hd1.dtstack.com3.7.1followerzookeeperhd2.dtstack.com3.7.1leaderzookeeperhd3.dtstack.com3.7.1followerzookeeper 2、zookeeper kerberos主体创建 在生产中zk服务端和客户端票据可以设置成不通名称或相同名称&am…

钉钉与实在智能达成战略合作,实在Agent助力钉钉AI助理成为“新质生产力”

3月12日&#xff0c;浙江实在智能科技有限公司&#xff08;简称“实在智能”&#xff09;与钉钉&#xff08;中国&#xff09;信息技术有限公司&#xff08;简称“钉钉”&#xff09;签署战略合作协议&#xff0c;达成战略合作伙伴关系。 未来&#xff0c;基于双方创新领先的技…