Learning Memory-guided Normality for Anomaly Detection 代码解析
目录 :
- 整体结构
- 训练(train)部分分析
- 评估(evaluate)部分分析
- 模型(model)部分分析
- 代码环境配置及运行
1.整体结构
1.1 代码文件及作用
根目录下包含 :
- Evaluate.py 评估代码
- Train.py 模型训练代码
- utils.py 负责数值运算:包含均方根差,峰值信噪比,学习率以及评估最后的准确率等.
model文件夹下包含:
- final_future_prediction_with_spatial_sumonly_weight_ranking_top1.py 包含编码器(encoder),译码器(decoder)及卷积自动编码器(convAE)模块.
- memory_final_spatial_sumonly_weight_ranking_top1.py 包含记忆(memory)模块.
- utils.py 数据集(dataset)类模块.
- Memory.py
- Reconstruction.py
上述4,5实现和作用与1,2基本一致,在训练中通过method参数来区别调用:pred对应1,2 , recon对应4,5.(下文省略recon)
1.2 代码结构
1.2.1 训练(Train)部分
Train调用的代码文件:
1.2.2 评估(Evaluate)部分
Evaluate调用的代码文件:
2.训练(train)部分分析
2.1 训练流程
在训练开始之前还存在以下步骤:
- 载入数据集
- 模型设定
- 建立日志文件
训练结束后,会在工程目录下生成exp文件夹,其中包含模型文件及日志文件.
2.2 代码分析
2.2.1 启动参数
- 此处对训练(train)模块代码的启动,参数说明见图中help
2.2.2 数据集载入
- 此处调用的DataLoader为model文件夹下的DataLoader类,该类用于载入数据集,并将数据集分划成mini-batch的形式,每个batch中含5个视频帧.其中ToTensor将(H,W,C)的视频帧转化为(C,H,W)的张量.
2.2.3 模型设定
-
模型选择分为两类:pred与recon;启动时通过输入不同的参数来选择相应的模型.
-
model.encoder.parameters为torch基类torch.nn.Module的函数,其主要作用是作为nn.Module的可训练参数使用.
-
torch.optim.Adam:既Adam优化算法.对梯度的一阶矩估计和二阶矩估计进行综合考虑,计算出更新步长.
-
CosineAnnealingLR:即余弦退火学习率,让学习率随epoch的变化图类似于cos,更新策略:
其中,new表示学习率,initial表示初始学习率,eta表示最小学习率,T表示cos周期的1/2.
2.2.4 训练模块主体部分
- 训练模块的步骤见2.1节的训练流程及图中注释.
3.评估(evaluate)部分分析
3.1 评估流程
3.2 代码分析
与训练部分代码类似,分为以下几部分:
3.2.1 启动参数
3.2.2 载入数据集
3.2.3 载入已训练的模型
3.2.4 初始化
此处对记录数据的数组和变量进行初始化(标签长度,视频编号,峰值信噪比,特征距离).
3.2.5 评估模块主体部分
评估模块的步骤见3.1节的评估流程及图中注释.
4.模型(model)部分分析
该部分由卷积自动编码器(convAE)和记忆模块(Memory)两部分组成,其中卷积自动编码器调用了编码器(encoder),解码器(decoder)及记忆模块(Memory).下面将自上而下分别介绍卷积自动编码器和记忆模块两个部分.
4.1 卷积自动编码器(convAE)部分
4.1.1 编码器(encoder)
编码器的实现为类,继承了神经网络模块基类(torch.nn.Module).其中只定义了初始化函数(init)以及向前传播函数(forward):
其中__init__的实现为:
在__init__中实现了Basic及Basic_函数,二者都对图像进行了卷积,归一化和激活操作,但细节略有不同.在每次调用Basic或Basic_函数之后,再对图像进行最大池化(MaxPool2d)操作.
forward的实现为:
forward仅调用了__init__中的参数,对传入的图像进行了重复的卷积和池化操作,再分别返回.
4.1.2 解码器(decoder)
与编码器类似,解码器同样继承了torch.nn.Module.也定义了初始化函数和前向传播函数:
其中__init__的实现为:
与编码器不同,解码器的初始化函数包含了Basic,Gen及Upsample函数.其中Basic与Gen类似,对图像进行卷积,归一化和激活函数.在每次调用Basic函数后,进行上采样(Upsample)操作.其中上采样(Unsample)函数对图像进行反置卷积操作.
forward的实现为:
forward通过调用__init__函数重复着卷积,上采样,拼接张量的操作.在最后调用Gen操作.
4.1.3 卷积自动编码器(convAE)
同样的,卷积自动编码器(convAE)也继承与torch.nn.Module,定义了__init__和forward函数.
其中__init__与forward的实现为:
可见__init__和forward都调用了编码器和解码器对应的函数,除此之外还对记忆模块(Memory)进行了调用.需要注意的是,在forward中针对训练(train)和评估(evaluate)两个不同状态返回的值也不同.
4.2 记忆模块(Memory)部分
Memory实现如下:
其中,Memory分为read和update两个阶段,下面分别介绍各模块.
4.2.1 read
read实现如下:
该操作主要计算了对于每个查询(query)和记忆项(Memory item)的匹配概率(公式1),以及计算对每个记忆项和匹配概率的特征(公式2)(此时匹配概率作为加权平均值).
其中get_score用于计算匹配概率,后续操作计算基于匹配概率的特征.论文中给出公式如下:
get_score实现如下:
4.2.2 update
update实现如下:
该操作与read同样调用get_score计算了匹配概率,不同的是,read计算的是垂直方向上的概率,而update计算的是水平方向上的概率.接着update在集合U中使用相关概率来计算加权平均值,再与最初的记忆项相加.最后根据集合U来更新记忆项(公式3).论文中给出公式如下:
get_update_query用于获取包含查询的索引的集合(集合U),即公式5:
4.2.3 forward
forward实现如下:
forward为前向传播函数,在训练模式通过下计算了特征分离性损失(Feature separateness loss,公式10)以及特征紧凑性损失(Feature compactness loss,公式12).再通过read和update的调用对记忆模块进行更新(训练和评估时).其中gather_loss的实现如下:
可见在训练时,gather_loss创建了一个三元损失标准,其作用是为了鼓励查询记忆项中最相似的item,从而减小相同正常行为类的差异,增大不同行为的差异.论文中给出公式如下:
其中p:
其中n:
5.代码环境配置及运行
项目地址:https://github.com/cvlab-yonsei/MNAD
其中README介绍了该项目使用的环境版本及使用的训练集(USCD Ped2 , CUHK Avenue , ShanghaiTech).
除了上述的项目文件,我们还需要下载数据集以及预训练模型.
以上文件都准备完毕后,在Pycharm中新建工程,并安装缺失的各种库(numpy,torch等).
需要注意的是,在安装cv2的时候可能会提示失败,此时可以安装opencv-python替代cv2,其使用方法完全一样.
接着我们需要将训练集以及预训练模型放在工程目录下,并在Train.py和Evaluate.py中修改启动参数:
Train.py:
Evaluate.py:
其中dataset_type需要指定数据集的类型(ped2,avenue,shanghai),在dataset_path中给出训练集的路径;model_dir和m_items_dir同样需要给出预训练模型的路径.
下面就可以进行运行测试了.如果想使用cpu进行测试,可以按以下步骤修改代码:
- 在代码的开头加上:
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
- 将所有的.cuda()修改成.to(device);其中torch.load需要在模型路径后再添加一个参数:map_location = torch.device(device).
以上修改将使代码在运行时检测cuda,若不存在则使用cpu运算.
可能出现的问题:
在model/utils.py下的DataLoader类中,定义了__getitem__如下:
其中可能产生路径错误.如报错,可修改为: