def __init__(self, sess, dual_var, neural_net_param_object, test_input, true_class,
               adv_class, input_minval, input_maxval, epsilon,
               lzs_params=None, project_dual=True):
    """Initializes dual formulation class.

    Args:
      sess: Tensorflow session
      dual_var: dictionary of dual variables containing a) lambda_pos
        b) lambda_neg, c) lambda_quad, d) lambda_lu
      neural_net_param_object: NeuralNetParam object created for the network
        under consideration
      test_input: clean example to certify around
      true_class: the class label of the test input
      adv_class: the label that the adversary tried to perturb input to
      input_minval: minimum value of valid input range
      input_maxval: maximum value of valid input range
      epsilon: Size of the perturbation (scaled for [0, 1] input)
      lzs_params: Parameters for Lanczos algorithm (dictionary) in the form:
        {
          'min_iter': 5
          'max_iter': 50
        }
      project_dual: Whether we should create a projected dual object
    """
    self.sess = sess
    self.nn_params = neural_net_param_object
    self.test_input = tf.convert_to_tensor(test_input, dtype=tf.float32)
    self.true_class = true_class
    self.adv_class = adv_class
    self.input_minval = tf.convert_to_tensor(input_minval, dtype=tf.float32)
    self.input_maxval = tf.convert_to_tensor(input_maxval, dtype=tf.float32)
    self.epsilon = tf.convert_to_tensor(epsilon, dtype=tf.float32)
    self.lzs_params = lzs_params or DEFAULT_LZS_PARAMS.copy()
    self.final_linear = (self.nn_params.final_weights[adv_class, :]
                         - self.nn_params.final_weights[true_class, :])
    self.final_linear = tf.reshape(
        self.final_linear, shape=[tf.size(self.final_linear), 1])
    self.final_constant = (self.nn_params.final_bias[adv_class]
                           - self.nn_params.final_bias[true_class])
    self.lanczos_dtype = tf.float64
    self.nn_dtype = tf.float32

    # Computing lower and upper bounds
    # Note that lower and upper are of size nn_params.num_hidden_layers + 1
    self.lower = []
    self.upper = []

    # Also computing pre activation lower and upper bounds
    # to compute always-off and always-on units
    self.pre_lower = []
    self.pre_upper = []

    # Initializing at the input layer with \ell_\infty constraints
    self.lower.append(
        tf.maximum(self.test_input - self.epsilon, self.input_minval))
    self.upper.append(
        tf.minimum(self.test_input + self.epsilon, self.input_maxval))
    self.pre_lower.append(self.lower[0])
    self.pre_upper.append(self.upper[0])

    for i in range(0, self.nn_params.num_hidden_layers):
      lo_plus_up = self.nn_params.forward_pass(self.lower[i] + self.upper[i], i)
      lo_minus_up = self.nn_params.forward_pass(self.lower[i] - self.upper[i], i, is_abs=True)
      up_minus_lo = self.nn_params.forward_pass(self.upper[i] - self.lower[i], i, is_abs=True)
      current_lower = 0.5 * (lo_plus_up + lo_minus_up) + self.nn_params.biases[i]
      current_upper = 0.5 * (lo_plus_up + up_minus_lo) + self.nn_params.biases[i]
      self.pre_lower.append(current_lower)
      self.pre_upper.append(current_upper)
      self.lower.append(tf.nn.relu(current_lower))
      self.upper.append(tf.nn.relu(current_upper))

    # Run lower and upper because they don't change
    self.pre_lower = self.sess.run(self.pre_lower)
    self.pre_upper = self.sess.run(self.pre_upper)
    self.lower = self.sess.run(self.lower)
    self.upper = self.sess.run(self.upper)

    # Using the preactivation lower and upper bounds
    # to compute the linear regions
    self.positive_indices = []
    self.negative_indices = []
    self.switch_indices = []

    for i in range(0, self.nn_params.num_hidden_layers + 1):
      # Positive index = 1 if the ReLU is always "on"
      self.positive_indices.append(np.asarray(self.pre_lower[i] >= 0, dtype=np.float32))
      # Negative index = 1 if the ReLU is always off
      self.negative_indices.append(np.asarray(self.pre_upper[i] <= 0, dtype=np.float32))
      # Switch index = 1 if the ReLU could be either on or off
      self.switch_indices.append(np.asarray(
          np.multiply(self.pre_lower[i], self.pre_upper[i]) < 0, dtype=np.float32))

    # Computing the optimization terms
    self.lambda_pos = [x for x in dual_var['lambda_pos']]
    self.lambda_neg = [x for x in dual_var['lambda_neg']]
    self.lambda_quad = [x for x in dual_var['lambda_quad']]
    self.lambda_lu = [x for x in dual_var['lambda_lu']]
    self.nu = dual_var['nu']
    self.vector_g = None
    self.scalar_f = None
    self.matrix_h = None
    self.matrix_m = None
    self.matrix_m_dimension = 1 + np.sum(self.nn_params.sizes)

    # The primal vector in the SDP can be thought of as [layer_1, layer_2..]
    # In this concatenated version, dual_index[i] that marks the start
    # of layer_i
    # This is useful while computing implicit products with matrix H
    self.dual_index = [0]
    for i in range(self.nn_params.num_hidden_layers + 1):
      self.dual_index.append(self.dual_index[-1] + self.nn_params.sizes[i])

    # Construct objectives, matrices, and certificate
    self.set_differentiable_objective()
    if not self.nn_params.has_conv:
      self.get_full_psd_matrix()

    # Setup Lanczos functionality for compute certificate
    self.construct_lanczos_params()

    # Create projected dual object
    if project_dual:
      self.projected_dual = self.create_projected_dual()
def __init__ ( self , sess , dual_var , neural_net_param_object , test_input , true_class , adv_class , input_minval , input_maxval , epsilon , lzs_params = None , project_dual = True ) : self . sess = sess self . nn_params = neural_net_param_object self . test_input = tf . convert_to_tensor ( test_input , dtype = tf . float32 ) self . true_class = true_class self . adv_class = adv_class self . input_minval = tf . convert_to_tensor ( input_minval , dtype = tf . float32 ) self . input_maxval = tf . convert_to_tensor ( input_maxval , dtype = tf . float32 ) self . epsilon = tf . convert_to_tensor ( epsilon , dtype = tf . float32 ) self . lzs_params = lzs_params or DEFAULT_LZS_PARAMS . copy ( ) self . final_linear = ( self . nn_params . final_weights [ adv_class , : ] - self . nn_params . final_weights [ true_class , : ] ) self . final_linear = tf . reshape ( self . final_linear , shape = [ tf . size ( self . final_linear ) , 1 ] ) self . final_constant = ( self . nn_params . final_bias [ adv_class ] - self . nn_params . final_bias [ true_class ] ) self . lanczos_dtype = tf . float64 self . nn_dtype = tf . float32 self . lower = [ ] self . upper = [ ] self . pre_lower = [ ] self . pre_upper = [ ] self . lower . append ( tf . maximum ( self . test_input - self . epsilon , self . input_minval ) ) self . upper . append ( tf . minimum ( self . test_input + self . epsilon , self . input_maxval ) ) self . pre_lower . append ( self . lower [ 0 ] ) self . pre_upper . append ( self . upper [ 0 ] ) for i in range ( 0 , self . nn_params . num_hidden_layers ) : lo_plus_up = self . nn_params . forward_pass ( self . lower [ i ] + self . upper [ i ] , i ) lo_minus_up = self . nn_params . forward_pass ( self . lower [ i ] - self . upper [ i ] , i , is_abs = True ) up_minus_lo = self . nn_params . forward_pass ( self . upper [ i ] - self . lower [ i ] , i , is_abs = True ) current_lower = 0.5 * ( lo_plus_up + lo_minus_up ) + self . nn_params . biases [ i ] current_upper = 0.5 * ( lo_plus_up + up_minus_lo ) + self . nn_params . biases [ i ] self . pre_lower . append ( current_lower ) self . pre_upper . append ( current_upper ) self . lower . append ( tf . nn . relu ( current_lower ) ) self . upper . append ( tf . nn . relu ( current_upper ) ) self . pre_lower = self . sess . run ( self . pre_lower ) self . pre_upper = self . sess . run ( self . pre_upper ) self . lower = self . sess . run ( self . lower ) self . upper = self . sess . run ( self . upper ) self . positive_indices = [ ] self . negative_indices = [ ] self . switch_indices = [ ] for i in range ( 0 , self . nn_params . num_hidden_layers + 1 ) : self . positive_indices . append ( np . asarray ( self . pre_lower [ i ] >= 0 , dtype = np . float32 ) ) self . negative_indices . append ( np . asarray ( self . pre_upper [ i ] <= 0 , dtype = np . float32 ) ) self . switch_indices . append ( np . asarray ( np . multiply ( self . pre_lower [ i ] , self . pre_upper [ i ] ) < 0 , dtype = np . float32 ) ) self . lambda_pos = [ x for x in dual_var [ 'lambda_pos' ] ] self . lambda_neg = [ x for x in dual_var [ 'lambda_neg' ] ] self . lambda_quad = [ x for x in dual_var [ 'lambda_quad' ] ] self . lambda_lu = [ x for x in dual_var [ 'lambda_lu' ] ] self . nu = dual_var [ 'nu' ] self . vector_g = None self . scalar_f = None self . matrix_h = None self . matrix_m = None self . matrix_m_dimension = 1 + np . sum ( self . nn_params . sizes ) self . dual_index = [ 0 ] for i in range ( self . nn_params . num_hidden_layers + 1 ) : self . dual_index . append ( self . dual_index [ - 1 ] + self . nn_params . sizes [ i ] ) self . set_differentiable_objective ( ) if not self . nn_params . has_conv : self . get_full_psd_matrix ( ) self . construct_lanczos_params ( ) if project_dual : self . projected_dual = self . create_projected_dual ( )
Initializes dual formulation class.

    Args:
      sess: Tensorflow session
      dual_var: dictionary of dual variables containing a) lambda_pos
        b) lambda_neg, c) lambda_quad, d) lambda_lu
      neural_net_param_object: NeuralNetParam object created for the network
        under consideration
      test_input: clean example to certify around
      true_class: the class label of the test input
      adv_class: the label that the adversary tried to perturb input to
      input_minval: minimum value of valid input range
      input_maxval: maximum value of valid input range
      epsilon: Size of the perturbation (scaled for [0, 1] input)
      lzs_params: Parameters for Lanczos algorithm (dictionary) in the form:
        {
          'min_iter': 5
          'max_iter': 50
        }
      project_dual: Whether we should create a projected dual object