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