1
+ import time
2
+
3
+ from tensorflow .keras .layers import Input , Dense , Activation , BatchNormalization , Lambda
4
+ from tensorflow .keras .models import Model , load_model
5
+ from tensorflow .keras .optimizers import Adam
6
+ from tensorflow .keras .callbacks import EarlyStopping , ReduceLROnPlateau
7
+ from sklearn .preprocessing import MinMaxScaler
8
+ from tensorflow .keras .initializers import glorot_normal
9
+
10
+ from sklearn .model_selection import train_test_split
11
+ import numpy as np
12
+ import pandas as pd
13
+
14
+
15
+ # This module was developed by Alessandro Erba, the original is found here:
16
+ # https://github.com/scy-phy/ICS-Evasion-Attacks/blob/master/Adversarial_Attacks/Black_Box_Attack/adversarial_AE.py
17
+
18
+ class Adversarial_AE :
19
+
20
+ def __init__ (self , feature_dims , hide_layers ):
21
+ # define parameters
22
+ self .attacker_scaler = MinMaxScaler ()
23
+ self .feature_dims = feature_dims
24
+ self .hide_layers = hide_layers
25
+ self .generator_layers = [self .feature_dims , int (self .hide_layers /
26
+ 2 ), self .hide_layers , int (self .hide_layers / 2 ), self .feature_dims ]
27
+ optimizer = Adam (lr = 0.001 )
28
+
29
+ # Build the generator
30
+ self .generator = self .build_generator ()
31
+ self .generator .compile (optimizer = optimizer , loss = 'mean_squared_error' )
32
+
33
+ def build_generator (self ):
34
+ input = Input (shape = (self .feature_dims ,))
35
+ x = input
36
+ for dim in self .generator_layers [1 :]:
37
+ x = Dense (dim , activation = 'sigmoid' ,
38
+ kernel_initializer = glorot_normal (seed = 12345 ))(x )
39
+ generator = Model (input , x , name = 'generator' )
40
+
41
+ return generator
42
+
43
+ def train_advAE (self , ben_data , xset ):
44
+ ben_data [xset ] = self .attacker_scaler .transform (
45
+ ben_data [xset ])
46
+ x_ben = pd .DataFrame (index = ben_data .index ,
47
+ columns = xset , data = ben_data [xset ])
48
+ x_ben_train , x_ben_test , _ , _ = train_test_split (
49
+ x_ben , x_ben , test_size = 0.33 , random_state = 42 )
50
+ earlyStopping = EarlyStopping (
51
+ monitor = 'val_loss' , patience = 3 , verbose = 0 , min_delta = 1e-4 , mode = 'auto' )
52
+ lr_reduced = ReduceLROnPlateau (
53
+ monitor = 'val_loss' , factor = 0.5 , patience = 1 , verbose = 0 , min_delta = 1e-4 , mode = 'min' )
54
+ print (self .generator .summary ())
55
+ self .generator .fit (x_ben_train , x_ben_train ,
56
+ epochs = 500 ,
57
+ batch_size = 64 ,
58
+ shuffle = False ,
59
+ callbacks = [earlyStopping , lr_reduced ],
60
+ verbose = 2 ,
61
+ validation_data = (x_ben_test , x_ben_test ))
62
+
63
+
64
+ def fix_sample (self , gen_examples , dataset ):
65
+ """
66
+ Adjust discrete actuators values to the nearest allowed value
67
+ Parameters
68
+ ----------
69
+ gen_examples : Pandas Dataframe
70
+ adversarial examples that needs to be adjusted
71
+ dataset : string
72
+ name of the dataset the data come from to select the correct strategy
73
+ Returns
74
+ -------
75
+ pandas DataFrame
76
+ adversarial examples with distrete values adjusted
77
+ """
78
+ if dataset == 'BATADAL' :
79
+ list_pump_status = list (gen_examples .filter (
80
+ regex = 'STATUS_PU[0-9]|STATUS_V[0-9]' ).columns )
81
+
82
+ for j , _ in gen_examples .iterrows ():
83
+ for i in list_pump_status : #list(gen_examples.columns[31:43]):
84
+ if gen_examples .at [j , i ] > 0.5 :
85
+ gen_examples .at [j , i ] = 1
86
+ else :
87
+ gen_examples .at [j , i ] = 0
88
+ gen_examples .at [j , i .replace ('STATUS' , 'FLOW' )] = 0 #gen_examples.columns[(
89
+ # gen_examples.columns.get_loc(i)) - 12]] = 0
90
+
91
+ return gen_examples
92
+
93
+ def decide_concealment (self , n , binary_dataframe , gen_examples , original_examples , xset ):
94
+ """
95
+ Conceal only n variables among the modified ones by the autoencoder
96
+ computes the squared error between original and concealed sample and forward only the first n wrongly reconstructed
97
+ Parameters
98
+ ----------
99
+ n : int
100
+ number of variables to be forwarded concealed
101
+ gen_examples : Pandas Dataframe
102
+ concealed tuples by the autoencoder
103
+ original_examples : Pandas Dataframe
104
+ original tuples
105
+ Returns
106
+ -------
107
+ pandas series
108
+ concealed tuple with exactly n concealed sensor readings
109
+ pandas DataFrame
110
+ one hot encoded table keeping track of which of the n variables have been manipulated
111
+ """
112
+ for j in range (0 , len (gen_examples )):
113
+ distance = (original_examples .iloc [j ] - gen_examples .iloc [j ])
114
+ distance = np .sqrt (distance ** 2 )
115
+ distance = distance .sort_values (ascending = False )
116
+ distance = distance .drop (distance .index [n :])
117
+ binary_row = pd .DataFrame (
118
+ index = [distance .name ], columns = xset , data = 0 )
119
+ for elem in distance .keys ():
120
+ binary_row .loc [distance .name , elem ] = 1
121
+ binary_dataframe = binary_dataframe .append (binary_row )
122
+ for col , _ in distance .iteritems ():
123
+ original_examples .at [j , col ] = gen_examples .at [j , col ]
124
+
125
+ return original_examples .values , binary_dataframe
126
+
127
+ def conceal_fixed (self , constraints , gen_examples , original_examples ):
128
+ """
129
+ Conceal only n variables according to the list of allowed ones.
130
+
131
+ Parameters
132
+ ----------
133
+ constraints : list
134
+ list of sensor values that can be changed
135
+ gen_examples : Pandas Dataframe
136
+ concealed tuples by the autoencoder
137
+ original_examples : Pandas Dataframe
138
+ original tuples
139
+ Returns
140
+ -------
141
+ pandas series
142
+ adversarial examples with the allowed concealed sensor readings
143
+ """
144
+ for j in range (0 , len (gen_examples )):
145
+ #print(constraints)
146
+ #print(original_examples.iloc[j])
147
+ for col in constraints :
148
+ original_examples .at [j , col ] = gen_examples .at [j , col ]
149
+ #print(original_examples.iloc[j])
150
+ return original_examples .values
0 commit comments