赞
踩
下面介绍论文的核心–Anomaly Attention
对于先验关联,作者采用可学习的高斯核来计算相对时间距离的先验。利用高斯核的特性,对每个时间点可以在更多地关注相邻时间点。对于高斯核还用了一个可学习的尺度参数
σ
\sigma
σ,使先验关联适应不同的时间序列模式,主要用于匹配不同长度的异常时间段。
序列关联从原始序列中学习,能够自适应地找到最有效的associations(关联)。这两种关联有种局部信息与全局信息的味道。
作者采用对称KL散度形式化先验关联和序列关联之间的关联差异,表示这两个分布之间的信息增益。对所有的
L
L
L层的关联差异进行平均,将多层特征的关联组合成一个更有信息量的度量:
A
s
s
D
i
s
(
P
,
S
,
X
)
=
[
1
L
∑
l
=
1
L
(
K
L
(
P
i
,
:
l
∣
∣
S
i
,
:
l
)
+
K
L
(
S
i
,
:
l
∣
∣
P
i
,
:
l
)
]
i
=
1
,
.
.
.
,
N
=
[
1
L
∑
l
=
1
L
(
K
L
(
P
1
,
:
l
∣
∣
S
1
,
:
l
)
+
K
L
(
S
1
,
:
l
∣
∣
P
1
,
:
l
)
1
L
∑
l
=
1
L
(
K
L
(
P
2
,
:
l
∣
∣
S
2
,
:
l
)
+
K
L
(
S
2
,
:
l
∣
∣
P
2
,
:
l
)
⋮
1
L
∑
l
=
1
L
(
K
L
(
P
N
,
:
l
∣
∣
S
N
,
:
l
)
+
K
L
(
S
N
,
:
l
∣
∣
P
N
,
:
l
)
]
∈
R
N
×
1
AssDis(\mathcal{P}, \mathcal{S}, \mathcal{X})=[\frac{1}{L}\sum_{l=1}^L(KL(\mathcal{P}_{i, :}^l||\mathcal{S}_{i, :}^l) + KL(\mathcal{S}_{i, :}^l||\mathcal{P}_{i, :}^l)]_{i=1,...,N}=\\
作为一个无监督任务,作者使用重构损失优化模型。重构损失将引导序列关联找到最具信息量的关联。为了进一步放大正常和异常点的差异,还使用额外的损失来放大关联差异。由于先验关联的单峰性,差异损失会引导序列关联更多地关注非相邻区域(解释:对于异常点,Gauss距离会关注附近的点,注意力也会如此,导致AssDis很小, 如果放大AssDis,则会使其关注较远的点),这使得异常重建更加困难(解释:无法重构所以就很容易的判断为异常),异常的可识别性更强。损失函数为:
L
(
X
^
,
P
,
S
,
λ
;
X
)
=
∣
∣
X
−
X
^
∣
∣
F
2
−
λ
×
∣
∣
AssDis
(
P
,
S
;
X
)
∣
∣
1
\mathcal{L}(\hat{\mathcal{X}}, \mathcal{P}, \mathcal{S}, \lambda; \mathcal{X}) = ||\mathcal{X}-\hat{\mathcal{X}}||^2_F - \lambda \times ||\text{AssDis}(\mathcal{P}, \mathcal{S}; \mathcal{X})||_1
L(X^,P,S,λ;X)=∣∣X−X^∣∣F2−λ×∣∣AssDis(P,S;X)∣∣1
注意,直接最大化关联差异将极大地降低高斯核的尺度参数,使先验关联变得毫无意义。
为了更好地控制关联学习,作者提出了一个极大极小策略:具体来说,对于最小化阶段,用先验关联
P
l
\mathcal{P}^l
Pl近似从原始序列中学习到的序列关联
S
l
\mathcal{S}^l
Sl,使
P
\mathcal{P}
P适应不同的时间模式。在最大化阶段,我们对序列关联进行优化,扩大关联差异。这个过程迫使序列关联更多地关注非相邻的区域。即存在两个阶段的损失函数:
Minimize Phase:
L
T
o
t
a
l
(
X
^
,
P
,
S
d
e
t
a
c
h
,
−
λ
;
X
)
Maxmize Phase:
L
T
o
t
a
l
(
X
^
,
P
d
e
t
a
c
h
,
S
,
λ
;
X
)
\text{Minimize Phase:} \mathcal{L}_{Total}(\hat{\mathcal{X}}, \mathcal{P}, \mathcal{S}_{detach}, -\lambda; \mathcal{X})\\ \text{Maxmize Phase:} \mathcal{L}_{Total}(\hat{\mathcal{X}}, \mathcal{P_{detach}}, \mathcal{S}, \lambda; \mathcal{X})
Minimize Phase:LTotal(X^,P,Sdetach,−λ;X)Maxmize Phase:LTotal(X^,Pdetach,S,λ;X)
由于
P
\mathcal{P}
P在最小阶段近似于
S
d
e
t
a
c
h
\mathcal{S}_{detach}
Sdetach,因此最大阶段将对序列关联进行更强的约束,迫使时间点更加关注非相邻区域。在重构损失下,异常比正常时间点更难达到这一点,从而放大了关联差异的正常-异常可分辨性。
以上有很多个人理解,如有错误请指出,感激不尽。
若要加载个人数据集训练与预测,可根据以下步骤
if __name__ == '__main__': parser = argparse.ArgumentParser() parser.add_argument('--lr', type=float, default=1e-4) parser.add_argument('--num_epochs', type=int, default=10) parser.add_argument('--k', type=int, default=3) parser.add_argument('--win_size', type=int, default=100) parser.add_argument('--input_c', type=int, default=34) parser.add_argument('--output_c', type=int, default=34) parser.add_argument('--batch_size', type=int, default=32) parser.add_argument('--pretrained_model', type=str, default=None) parser.add_argument('--dataset', type=str, default='MY_TEST') parser.add_argument('--mode', type=str, default='test', choices=['train', 'test']) parser.add_argument('--data_path', type=str, default=r'个人存放test.csv/train.csv的路径') parser.add_argument('--model_save_path', type=str, default='checkpoints') parser.add_argument('--anormly_ratio', type=float, default=4.00) config = parser.parse_args() args = vars(config) print('------------ Options -------------') for k, v in sorted(args.items()): print('%s: %s' % (str(k), str(v))) print('-------------- End ----------------') main(config)
class MY_TESTSegLoader(object): def __init__(self, data_path, win_size, step, mode="train"): self.mode = mode self.step = step self.win_size = win_size self.scaler = StandardScaler() data = pd.read_csv(data_path + '/train.csv') data = data.values[:, 1:] data = np.nan_to_num(data) self.scaler.fit(data) data = self.scaler.transform(data) test_data = pd.read_csv(data_path + '/test.csv') test_data = test_data.values[:, 1:] test_data = np.nan_to_num(test_data) self.test = self.scaler.transform(test_data) self.train = data self.val = self.test self.test_labels = pd.read_csv(data_path + '/test_label.csv').values[:, 1:] print("test:", self.test.shape) print("train:", self.train.shape) def __len__(self): """ Number of images in the object dataset. """ if self.mode == "train": return (self.train.shape[0] - self.win_size) // self.step + 1 elif (self.mode == 'val'): return (self.val.shape[0] - self.win_size) // self.step + 1 elif (self.mode == 'test'): return (self.test.shape[0] - self.win_size) // self.step + 1 else: return (self.test.shape[0] - self.win_size) // self.win_size + 1 def __getitem__(self, index): index = index * self.step if self.mode == "train": return np.float32(self.train[index:index + self.win_size]), np.float32(self.test_labels[0:self.win_size]) elif (self.mode == 'val'): return np.float32(self.val[index:index + self.win_size]), np.float32(self.test_labels[0:self.win_size]) elif (self.mode == 'test'): return np.float32(self.test[index:index + self.win_size]), np.float32( self.test_labels[index:index + self.win_size]) else: return np.float32(self.test[ index // self.step * self.win_size:index // self.step * self.win_size + self.win_size]), np.float32( self.test_labels[index // self.step * self.win_size:index // self.step * self.win_size + self.win_size]) def get_loader_segment(data_path, batch_size, win_size=100, step=100, mode='train', dataset='KDD'): if (dataset == 'SMD'): dataset = SMDSegLoader(data_path, win_size, step, mode) elif (dataset == 'MSL'): dataset = MSLSegLoader(data_path, win_size, 1, mode) elif (dataset == 'SMAP'): dataset = SMAPSegLoader(data_path, win_size, 1, mode) elif (dataset == 'PSM'): dataset = PSMSegLoader(data_path, win_size, 1, mode) elif dataset == 'MY_TEST': dataset = MY_TESTSegLoader(data_path, win_size, 1, mode) shuffle = False if mode == 'train': shuffle = True data_loader = DataLoader(dataset=dataset, batch_size=batch_size, shuffle=shuffle, num_workers=0) return data_loader
def main(config):
cudnn.benchmark = True
if (not os.path.exists(config.model_save_path)):
mkdir(config.model_save_path)
solver = Solver(vars(config))
if config.mode == 'train':
solver.train()
elif config.mode == 'test':
_, _, _, _, pred_1, pred = solver.test()
pd.DataFrame(np.concatenate([pred, pred_1]), columns=['pred_after', 'pred']).to_csv(r'pred_res.csv')
return solver
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。