Example #1
0
 def test_smt_forward(self):
     z3_var = z3.Int('var')
     weights = [np.asarray([[1, 1], [-1, -1]]), np.asarray([[1, 1]])]
     biases = [np.asarray([0, 0]), np.asarray([-1])]
     activations = ['relu', 'linear']
     output, hidden_weighted_sum = utils.smt_forward([z3_var, z3_var],
                                                     weights, biases,
                                                     activations)
     self.assertLen(output, 1)
     self.assertLen(hidden_weighted_sum, 2)
     self._assert_z3_constraint_sat(constraint=output[0] == 1,
                                    z3_var=z3_var)
     self._assert_z3_constraint_sat(
         constraint=hidden_weighted_sum[0][0] == 2, z3_var=z3_var)
     self._assert_z3_constraint_sat(
         constraint=hidden_weighted_sum[0][1] == -2, z3_var=z3_var)
     self._assert_z3_constraint_sat(
         constraint=hidden_weighted_sum[1][0] == 1, z3_var=z3_var)
Example #2
0
 def test_smt_forward_equals_nn_forward(self):
     weights = [
         np.random.random_sample((3, 3)),
         np.random.random_sample((1, 3))
     ]
     biases = [np.random.random_sample(3), np.random.random_sample(1)]
     activations = ['relu', 'linear']
     z3_var = z3.Int('var')
     nn_output, _ = utils.nn_forward(np.ones(3), weights, biases,
                                     activations)
     smt_output, _ = utils.smt_forward(
         [z3.ToReal(z3_var),
          z3.ToReal(z3_var),
          z3.ToReal(z3_var)], weights, biases, activations)
     self._assert_z3_constraint_sat(constraint=z3.And(
         smt_output[0] - nn_output[0] < 1e-4,
         smt_output[0] - nn_output[0] > -1e-4),
                                    z3_var=z3_var)
Example #3
0
def find_mask_full_encoding(image,
                            weights,
                            biases,
                            run_params,
                            window_size,
                            label_index,
                            delta=0,
                            timeout=600,
                            num_unique_solutions=1):
  """Finds a binary mask for a given image and a trained Neural Network.

  Args:
    image: float numpy array with shape (image_edge_length, image_edge_length,
        image_channels), image to be masked. For MNIST, the pixel values are
        between [0, 1] and for Imagenet, the pixel values are between
        [-117, 138].
    weights: list of num_layers float numpy arrays with shape
        (output_dim, input_dim), weights of the neural network.
    biases: list of num_layers float numpy arrays with shape (output_dim,),
        biases of the neural network.
    run_params: RunParams with model_type, model_path, image_placeholder_shape,
        activations, tensor_names.
    window_size: int, side length of the square mask.
    label_index: int, index of the label of the training image.
    delta: float, logit of the correct label is greater than the rest of the
        logit by an amount delta. Its value is always >= 0. It is only used when
        constrain_final_layer is True.
    timeout: int, solver timeout in seconds.
    num_unique_solutions: int, number of unique solutions you want to sample.

  Returns:
    result: dictionary,
      * image: float numpy array with shape
          (image_edge_length * image_edge_length * image_channels,)
      * combined_solver_runtime: float, time taken by the solver to find all
          the solutions.
      * unmasked_logits: float numpy array with shape (num_outputs,)
      * unmasked_first_layer: float numpy array with shape
          (num_hidden_nodes_first_layer,)
      * masked_first_layer: list with length num_sols, contains float numpy
          array with shape (num_hidden_nodes_first_layer,)
      * inv_masked_first_layer: list with length num_sols, contains float numpy
          array with shape (num_hidden_nodes_first_layer,)
      * masks: list with length num_sols, contains float numpy array
          with shape (image_edge_length ** 2,)
      * masked_images: list with length num_sols, contains float numpy array
          with shape (image_edge_length ** 2,)
      * inv_masked_images: list with length num_sols, contains float numpy
          array with shape (image_edge_length ** 2,)
      * masked_logits: list with length num_sols, contains float numpy array
          with shape (num_outputs,)
      * inv_masked_logits: list with length num_sols, contains float numpy
          array with shape (num_outputs,)
      * solver_outputs: list with length num_sols, contains strings
          corresponding to every sampled solution saying 'sat', 'unsat' or
          'unknown'.
  """
  _verify_image_dimensions(image)
  image_placeholder_shape = run_params.image_placeholder_shape
  tensor_names = run_params.tensor_names
  # z3's timeout is in milliseconds
  z3.set_option('timeout', timeout * 1000)
  image_edge_length, _, _ = image.shape
  num_masks_along_row = image_edge_length // window_size
  session = utils.restore_model(run_params.model_path)

  z3_mask = [z3.Int('mask_%d' % i) for i in range(num_masks_along_row ** 2)]

  unmasked_predictions = session.run(
      tensor_names,
      feed_dict={
          tensor_names['input']: image.reshape(image_placeholder_shape)})

  smt_output, _ = utils.smt_forward(
      features=utils.flatten_nested_lists(_encode_input(
          image=image,
          z3_mask=z3_mask,
          window_size=window_size)),
      weights=weights,
      biases=biases,
      activations=run_params.activations)

  z3_optimizer = _formulate_smt_constraints_final_layer(
      z3_optimizer=utils.ImageOptimizer(
          z3_mask=z3_mask,
          window_size=window_size,
          edge_length=image_edge_length),
      smt_output=smt_output,
      delta=delta,
      label_index=label_index)
  solver_start_time = time.time()
  result = collections.defaultdict(list)

  # All the masks found in each call of z3_optimizer.generator() is guarranteed
  # to be unique since duplicated solutions are blocked. For more details
  # refer z3_optimizer.generator().
  for mask, solver_output in z3_optimizer.generator(num_unique_solutions):
    _record_solution(result=result,
                     mask=mask,
                     solver_output=solver_output,
                     image=image,
                     session=session,
                     run_params=run_params)
  result.update({
      'image': image.reshape(-1),
      'combined_solver_runtime': time.time() - solver_start_time,
      'unmasked_logits': np.squeeze(unmasked_predictions['logits']),
      'unmasked_first_layer': np.squeeze(unmasked_predictions['first_layer'])})
  session.close()
  return result
Example #4
0
def find_mask_first_layer(image,
                          label_index,
                          run_params,
                          window_size,
                          score_method,
                          top_k=None,
                          gamma=None,
                          timeout=600,
                          num_unique_solutions=1):
  """Finds a binary mask for a given image and a trained Neural Network.

  Args:
    image:
      * image: float numpy array with shape (image_edge_length,
          image_edge_length, image_channels), image to be masked. For MNIST,
          the pixel values are between [0, 1] and for Imagenet, the pixel
          values are between [-117, 138].
      * text: float numpy array with shape (num_words,), text to be masked.
    label_index: int, index of the label of the training image.
    run_params: RunParams with model_type, model_path, image_placeholder_shape,
        padding, strides, tensor_names.
    window_size: int, side length of the square mask.
    score_method: str, assigns scores to hidden nodes, and nodes with the
        top_k scores are chosen. Takes a value -
        {'activations', 'blurred_gradients', 'gradients',
        'integrated_gradients', 'integrated_gradients_black_white_baselines'}.
    top_k: int, constrain the nodes with top k activations in the first hidden
        layer. It is only used when constrain_final_layer is false.
    gamma: float, masked activation is greater than gamma times the unmasked
        activation. Its value is always between [0,1).
    timeout: int, solver timeout in seconds.
    num_unique_solutions: int, number of unique solutions you want to sample.

  Returns:
    result: dictionary,
      * image: float numpy array with shape
          (image_edge_length * image_edge_length * image_channels,)
      * combined_solver_runtime: float, time taken by the solver to find all
          the solutions.
      * masked_first_layer: list with length num_unique_solutions,
          contains float list with length (num_hidden_nodes_first_layer,)
      * inv_masked_first_layer: list with length num_unique_solutions,
          contains float list with length (num_hidden_nodes_first_layer,)
      * masks: list with length num_unique_solutions, contains float numpy array
          with shape (image_edge_length ** 2,)
      * masked_images: list with length num_unique_solutions, contains float
          numpy array with shape (image_channels * image_edge_length ** 2,)
      * inv_masked_images: list with length num_unique_solutions,
          contains float numpy array with shape (image_edge_length ** 2,)
      * masked_logits: list with length num_unique_solutions,
          contains float list with length (num_outputs,)
      * inv_masked_logits: list with length num_unique_solutions, contains float
          list with length (num_outputs,)
      * solver_outputs: list with length num_unique_solutions, contains strings
          corresponding to every sampled solution saying 'sat', 'unsat' or
          'unknown'.
      * chosen_indices
  """
  # z3's timeout is in milliseconds
  z3.set_option('timeout', timeout * 1000)
  model_type = run_params.model_type
  result = collections.defaultdict(list)

  if model_type == 'text_cnn':
    # For text data, window size is always 1 i.e. 1 masking variable per word.
    masked_input, unmasked_predictions, session, z3_optimizer = _process_text(
        image, run_params)
  else:
    masked_input, unmasked_predictions, session, z3_optimizer = _process_image(
        image, run_params, window_size)

  if model_type == 'fully_connected':
    _, smt_hidden_input = utils.smt_forward(
        features=utils.flatten_nested_lists(masked_input),
        weights=[unmasked_predictions['weights_layer_1']],
        biases=[unmasked_predictions['biases_layer_1']],
        activations=['relu'])
    # assign first layer pre-relu activations to smt_hidden_input
    z3_optimizer = _formulate_smt_constraints_fully_connected_layer(
        z3_optimizer=z3_optimizer,
        nn_first_layer=unmasked_predictions['first_layer'].reshape(-1),
        smt_first_layer=smt_hidden_input[0],
        gamma=gamma,
        top_k=top_k)
  else:
    chosen_indices = _sort_indices(
        unmasked_predictions=unmasked_predictions,
        score_method=score_method,
        session=session,
        image=image,
        run_params=run_params,
        label_index=label_index)
    result.update({'chosen_indices': chosen_indices})
    z3_optimizer = _formulate_smt_constraints_convolution_layer(
        z3_optimizer=z3_optimizer,
        kernels=_reshape_kernels(
            kernels=unmasked_predictions['weights_layer_1'],
            model_type=model_type),
        biases=unmasked_predictions['biases_layer_1'],
        chosen_indices=chosen_indices[-top_k:],  # pylint: disable=invalid-unary-operand-type
        # unmasked_predictions['first_layer'] has the shape
        # (batch_size, output_activation_map_size, output_activation_map_size,
        # output_activation_map_channels). This is reshaped into
        # (output_activation_map_channels, output_activation_map_size,
        # output_activation_map_size) and then flattened.
        conv_activations=_reorder(_remove_batch_axis(
            unmasked_predictions['first_layer'])).reshape(-1),
        input_activation_maps=masked_input,
        output_activation_map_shape=_get_activation_map_shape(
            activation_maps_shape=unmasked_predictions['first_layer'].shape,
            model_type=model_type),
        strides=run_params.strides,
        padding=run_params.padding,
        gamma=gamma)

  solver_start_time = time.time()
  # All the masks found in each call of z3_optimizer.generator() is guaranteed
  # to be unique since duplicated solutions are blocked. For more details
  # refer z3_optimizer.generator().
  for mask, solver_output in z3_optimizer.generator(num_unique_solutions):
    _record_solution(result=result,
                     mask=mask,
                     solver_output=solver_output,
                     image=image,
                     session=session,
                     run_params=run_params)
  result.update({
      'image': image.reshape(-1),
      'combined_solver_runtime': time.time() - solver_start_time,
      'unmasked_logits': unmasked_predictions['logits'].reshape(-1),
      'unmasked_first_layer': unmasked_predictions['first_layer'].reshape(-1)})
  session.close()
  return result