首页 > 编程语言 >异常检测算法-完全卷积数据描述子FCDD

异常检测算法-完全卷积数据描述子FCDD

时间:2023-11-05 20:45:52浏览次数:35  
标签:__ loss FCDD nn 卷积 image 算法 self size

文献来源:
EXPLAINABLE DEEP ONE-CLASS CLASSIFICATION       最近在做一些异物检测之类的算法任务,原本想使用目标识别算法,但是问题是正样本太多,而负样本没几个。所以有必要使用异常检测算法,日后不妨再结合目标识别任务去做。 在正式开始前,需要先简单介绍一个广义损失函数的东西。(https://zhuanlan.zhihu.com/p/494343423)

x损失、alpha变量、C和梯度的关系

 alpha是控制鲁棒性的的变形参数,c则是用来控制二次函数宽度的尺度系数。

当alpha=1时,有huber loss,这个函数的梯度很有意思,当损失很大时,可以反向一个不大于1的梯度。当损失很小时,倾向于反向一个很小的梯度。

当alpha=负无穷时,有Welsch loss。当损失很大时,就直接失效了。

这两个loss和原文提及的损失函数,非常的像,也就是HSC损失函数。

 按原文来说,该函数会使正常数据靠向中心,异常数据远离中心。

 

 网络的主体结构类似于这样,作者简单提了以下感受野这个基础概念,大概就是输出图与原始图之间的映射关系,网络越深,输出的一个像素就能代表更多的原始图像素。

作者仅使用了池化、卷积,只在最后一步:生成高分辨率热图时,使用了类似转置高斯卷积的方法来提高分辨率。其实我觉得没什么用,可能就是找些创新点的。

方法还是相当有效的,我使用了unet也取得了不错的效果,这里贴出代码:

#Unet.py
import torch
import torch.nn as nn
import torchvision

class Decoder(nn.Module):
  def __init__(self, in_channels, middle_channels, out_channels):
    super(Decoder, self).__init__()
    self.up = nn.ConvTranspose2d(in_channels, out_channels, kernel_size=2, stride=2)
    self.conv_relu = nn.Sequential(
        nn.Conv2d(middle_channels, out_channels, kernel_size=3, padding=1),
        nn.ReLU(inplace=True)
        )
  def forward(self, x1, x2):
    x1 = self.up(x1)
    x1 = torch.cat((x1, x2), dim=1)
    x1 = self.conv_relu(x1)
    return x1

class Unet(nn.Module):
    def __init__(self, n_class):
        super().__init__()

        self.base_model = torchvision.models.resnet18(True)
        self.base_layers = list(self.base_model.children())
        self.layer1 = nn.Sequential(
            nn.Conv2d(1, 64, kernel_size=(7, 7), stride=(2, 2), padding=(3, 3), bias=False),
            self.base_layers[1],
            self.base_layers[2])
        self.layer2 = nn.Sequential(*self.base_layers[3:5])
        self.layer3 = self.base_layers[5]
        self.layer4 = self.base_layers[6]
        self.layer5 = self.base_layers[7]
        self.decode4 = Decoder(512, 256+256, 256)
        self.decode3 = Decoder(256, 256+128, 256)
        self.decode2 = Decoder(256, 128+64, 128)
        self.decode1 = Decoder(128, 64+64, 64)
        self.decode0 = nn.Sequential(
            nn.Upsample(scale_factor=2, mode='bilinear', align_corners=True),
            nn.Conv2d(64, 32, kernel_size=3, padding=1, bias=False),
            nn.Conv2d(32, 64, kernel_size=3, padding=1, bias=False)
            )
        self.conv_last = nn.Conv2d(64, n_class, 1)

    def forward(self, input):
        e1 = self.layer1(input) # 64,128,128
        e2 = self.layer2(e1) # 64,64,64
        e3 = self.layer3(e2) # 128,32,32
        e4 = self.layer4(e3) # 256,16,16
        f = self.layer5(e4) # 512,8,8
        d4 = self.decode4(f, e4) # 256,16,16
        d3 = self.decode3(d4, e3) # 256,32,32
        d2 = self.decode2(d3, e2) # 128,64,64
        d1 = self.decode1(d2, e1) # 64,128,128
        d0 = self.decode0(d1) # 64,256,256
        out = self.conv_last(d0) # 1,256,256
        return out
import random

import torchvision.datasets
import torch
import torch.nn as nn
#导入dataloader的包
from torch.utils.data import DataLoader
from torch.utils.data import Dataset
from torch.utils.tensorboard import SummaryWriter
import os
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import cv2
from torchvision import transforms
import Unet
train_path = r"E:\machine_learning\AE\train_pic"
test_path = r"E:\machine_learning\AE\test_pic"
err_path = r"E:\machine_learning\AE\err_pic"
lr=1e-4
epochs=50
batch_size=5
device="cuda"
def load_data(normal_source,anomal_source,image_suffix_name=".jpg"):
    image_file=[]
    label=[]
    for parent_folder, _, file_names in os.walk(normal_source):
        # 遍历当前子文件夹中的所有文件
        for file_name in file_names:
            # 只处理图片文件
            # if file_name.endswith(('jpg', 'jpeg', 'png', 'gif')):#提取jpg、jpeg等格式的文件到指定目录
            if file_name.endswith((image_suffix_name)):  # 提取json格式的文件到指定目录
                # 构造源文件路径和目标文件路径
                image_file.append(normal_source+"\\"+file_name)
                label.append(0)

    for parent_folder, _, file_names in os.walk(anomal_source):
        # 遍历当前子文件夹中的所有文件
        for file_name in file_names:
            # 只处理图片文件
            # if file_name.endswith(('jpg', 'jpeg', 'png', 'gif')):#提取jpg、jpeg等格式的文件到指定目录
            if file_name.endswith((image_suffix_name)):  # 提取json格式的文件到指定目录
                # 构造源文件路径和目标文件路径
                image_file.append(anomal_source+"\\"+file_name)
                label.append(1)
    return image_file,label

def image_rancut(image):
    (MAXheight, MAXwidth) = image.shape
    h=random.randint(64,212)
    w=random.randint(64,212)
    x=random.randint(0,MAXwidth-w)
    y = random.randint(0, MAXheight-h)
    return image[y:y+h,x:x+w,]

def letterbox(im, new_shape=(128, 128), color=114):
    # Resize and pad image while meeting stride-multiple constraints
    shape = im.shape[:2]  # current shape [height, width]

    # Scale ratio (new / old)
    r = min(new_shape[0] / shape[0], new_shape[1] / shape[1])

    # Compute padding
    new_unpad = int(round(shape[1] * r)), int(round(shape[0] * r))
    dw, dh = (new_shape[1] - new_unpad[0]) / 2, (new_shape[0] - new_unpad[1]) / 2  # wh padding
    top, bottom = int(round(dh - 0.1)), int(round(dh + 0.1))
    left, right = int(round(dw - 0.1)), int(round(dw + 0.1))

    if shape[::-1] != new_unpad:  # resize
        im = cv2.resize(im, new_unpad, interpolation=cv2.INTER_LINEAR)
    im = cv2.copyMakeBorder(im, top, bottom, left, right, cv2.BORDER_CONSTANT, value=color)  # add border
    return im


class resizeAndNormalize():
    def __init__(self, size, interpolation=cv2.INTER_LINEAR):
        # 注意对于opencv,size的格式是(w,h)
        self.size = size
        self.interpolation = interpolation
        # ToTensor属于类  """Convert a ``PIL Image`` or ``numpy.ndarray`` to tensor.
        self.toTensor = transforms.ToTensor()

    def __call__(self, image):
        # (x,y) 对于opencv来说,图像宽对应x轴,高对应y轴
        image = letterbox(image, self.size,random.randint(0,255))
        #cv2.imwrite("test.jpg",image)
        # 转为tensor的数据结构
        #cv2.imwrite("test.jpg", image)
        image = self.toTensor(image)
        # 对图像进行归一化操作
        #image = image.sub_(0.5).div_(0.5)
        return image

class FCDD_DataSet(Dataset):
    def __init__(self, normal_source,anomal_source,train=True):
        super(FCDD_DataSet, self).__init__()
        self.image_file,self.label= load_data(normal_source,anomal_source)

    def __len__(self):
        return len(self.image_file)

    def __getitem__(self, index):
        img=cv2.imread(self.image_file[index],cv2.IMREAD_GRAYSCALE)
        #img=image_rancut(img)
        size_width=640
        size_height=640
        transform = resizeAndNormalize((size_width, size_height))
        # 图像预处理
        imageTensor = transform(img)
        labelTensor=torch.tensor(self.label[index])
        #label tensor
        return imageTensor,labelTensor


class FCDDLoss(nn.Module):
    def __int__(self):
        super(FCDDLoss,self).__init__()

    def forward(self,output,labels):
        loss = output ** 2
        loss = (loss + 1).sqrt() - 1
        loss = loss.reshape(labels.size(0), -1).mean(-1)
        norm = loss[labels == 0]
        anom = (-(((1 - (-loss[labels == 1]).exp()) + 1e-31).log()))
        loss[(1 - labels).nonzero().squeeze()] = norm
        loss[labels.nonzero().squeeze()] = anom
        return loss.mean()

class Autoencoder(nn.Module):
    def __init__(self):
        super(Autoencoder, self).__init__()
        # encoder
        self.efc1=nn.Sequential(
            nn.Linear(2048,1024),
            nn.Linear(1024, 512),
            #nn.Linear(256, 128),
        )
        self.dfc1 = nn.Sequential(
            #nn.Linear(128, 256),
            nn.Linear(512, 1024),
            nn.Linear(1024, 2048),
        )
        self.efc = nn.Sequential(
            nn.Conv2d(
                in_channels=1,              # input height
                out_channels=16,            # n_filters
                kernel_size=3,              # filter size
                stride=1,                   # filter movement/step
                padding=1,                  # if want same width and length of this image after Conv2d, padding=(kernel_size-1)/2 if stride=1
            ),                              # output shape (16, 64)                     # activation
            nn.BatchNorm2d(16),
            nn.ReLU(),
            nn.MaxPool2d(kernel_size=2),
            nn.Conv2d(16, 16, 3, 1, 1),  # output shape (16, 32)
            nn.BatchNorm2d(16),
            nn.ReLU(),
            nn.MaxPool2d(2),
            nn.Conv2d(16, 32, 3, 1, 1),  # output shape (32, 16)
            nn.BatchNorm2d(32),
            nn.ReLU(),
            nn.MaxPool2d(2),# output shape (32, 8,8)
        )
        self.dfc = nn.Sequential(
            nn.Linear(32*16*16,2*64*64),
            nn.Dropout(0.3),
            nn.ReLU(),
            nn.Linear(2*64*64,128*128),
        )
    def forward(self, x):
        x = self.efc(x)
        x=x.view(-1,32*16*16)
        y = self.dfc(x)
        y=y.view(-1,1,128,128)
        return y


AE=Unet.Unet(1).to(device)
AE.train()
criterion = FCDDLoss()
optimizer = torch.optim.Adam(AE.parameters(), lr=lr)
train_dataset=FCDD_DataSet(train_path,err_path)
train_dataloder = DataLoader(train_dataset, batch_size=batch_size,
                            num_workers=0, drop_last=True,shuffle=True)

test_dataloder = DataLoader(train_dataset, batch_size=1,
                            num_workers=0, drop_last=True,shuffle=True)
loss_list=[]
for i in range(epochs):
    for data,labels in train_dataloder:
        data=data.to(device)
        labels=labels.to(device)
        output=AE(data)
        loss =criterion(output, labels)  # cross entropy loss
        optimizer.zero_grad()           # clear gradients for this training step
        loss.backward()                 # backpropagation, compute gradients
        optimizer.step()
        loss_list.append(float(loss))
        print(str(i)+"次loss:"+str(float(loss)))
AE.eval()
test_list=[]
for data,labels in test_dataloder:
    data = data.to(device)
    labels = labels.to(device)
    output=AE(data)
    loss =criterion(output,  labels)
    test_list.append(float(loss))

plt.figure(figsize=(10, 10))
plt.subplot(2,1,1)
#plt.ylim(0, 0.5)
plt.plot(loss_list)
plt.title('train')
plt.subplot(2,1,2)
plt.bar(range(len(test_list)),test_list)
plt.title('test_loss')
plt.tight_layout(h_pad=3.0)
plt.savefig("total.jpg")
pp=0
for data,labels in test_dataloder:
    pp+=1
    if(pp==20):
        break
    data = data.to(device)
    output = AE(data)
    output=(output**2 + 1).sqrt() - 1
    data=data.view(1,640,640)
    output =output.view(1, 640, 640)
    test_jpg=data.detach().to("cpu").numpy()*255
    res_jpg=output.detach().to("cpu").numpy()*255
    cv2.imwrite(str(pp)+"etest.jpg",np.transpose(test_jpg, (1, 2, 0)))
    cv2.imwrite(str(pp) +"eres.jpg",np.transpose(res_jpg, (1, 2, 0)))

 

 

标签:__,loss,FCDD,nn,卷积,image,算法,self,size
From: https://www.cnblogs.com/xmds/p/17811099.html

相关文章

  • 分治算法(C语言)
    一、棋盘覆盖问题1、问题2、分析(1)当k>0时,将2k×2k棋盘分割为4个(2k-1)×(2k-1)子棋盘,如图(a)所示。每一次分解,都将原本大小的棋盘,划分为四份,即行号和列号各自缩减一半。(2)特殊方格必位于4个较小子棋盘之一中,其余3个子棋盘中无特殊方格。(3)为将无特殊方格子棋盘转化为特......
  • 【进阶算法】差分
    差分是一种类似于前缀和的编码技巧,可以快速实现对数组某个区间的所有元素增加或减少一个值。一、差分数组示例:数组arr=[8,1,3,-2,5,0,-3,6],输入m个操作,每个操作输入(L,R,val),表示对数组的[L,R]区间中每个元素增加val,要求输出最后的arr数组。比如,第1次操作,输入(0,2......
  • 排序算法
    快速排序......
  • 文心一言 VS 讯飞星火 VS chatgpt (128)-- 算法导论11.1 3题
    三、用go语言,试说明如何实现一个直接寻址表,表中各元素的关键字不必都不相同,且各元素可以有卫星数据。所有三种字典操作(INSERT、DELETE和SEARCH)的运行时间应为O(1)(不要忘记DELETE要处理的是被删除对象的指针变量,而不是关键字。)文心一言,代码正常运行:在Go语言中,我们可以使......
  • ACM竞赛常用算法模板(C++)
    1.快速排序AcWing785.快速排序:https://www.acwing.com/problem/content/787/题目描述给定你一个长度为n的整数数列。请你使用快速排序对这个数列按照从小到大进行排序。并将排好序的数列按顺序输出。输入格式输入共两行,第一行包含整数n。第二行包含n个整数(所有整数均在1∼10......
  • 数据结构与算法—绪论
    前言数据结构与算法是程序员内功体现的重要标准之一,且数据结构也应用在各个方面,业界更有程序=数据结构+算法这个等式存在。各个中间件开发者,架构师他们都在努力的优化中间件、项目结构以及算法提高运行效率和降低内存占用,在这里数据结构起到相当重要的作用。此外数据结构也蕴含一......
  • 算法进阶
    贪心算法定义是指在对问题求解时,总是做出当前看来是最好的选择,着眼于眼前(做出目前对自己好的:贪心),不从整体最优上考虑,做出某种意义上的局部最优解。但有时贪心算法的解就是最优解。要会判断一个问题是否用贪心算法来计算。例题找零问题:假设商店老板需要找零n元钱,钱币的面额有:1......
  • 基于卷积神经网络的美食分类
    使用卷积神经网络解决美食图片的分类问题:::数据集在我这里,私聊给!!!!!!!!!环境:python3.7,飞浆版本2.0,操作平台pycharm步骤1:美食图片数据集介绍与加载:本实践使用的数据集包含5000张格式为jpg的三通道彩色图像,共5种食物类别。对于本实践中的数据包,具体处理与加载的方式与......
  • 排序算法
    一、选择排序12,23,8,15,33,24,77,558,23,12,15,33,24,77,558,12,23,15,33,24,77,558,12,15,23,33,24,77,558,12,15,23,24,33,77,558,12,15,23,24,33,55,77二、冒泡排序12,23,8,15,33,24,77,5512,23,8,15,33,24,55,7712,23,8,15,24,33,55,7712,8,23,15,24,33,55,7712,8,15,23,......
  • 用欧几里得算法求两个数的最大公约数
    一.什么是欧几里得算法1.欧几里得算法就是辗转相除法,用于求两个数的最大公约数。如果用gcd(a,b)表示a和b的最大公约数,gcd(a,b)=gcd(b,a%b),当a%b==0时,b就是最大公约数。2.算法说明:首先按照大小输入两个整数a、b,再用一个中间量用来存放二者的余数。计算后将b的值赋给a,将余数赋给b......