示例#1
0
def add_backprop_linear_layer(layer_no, squire,
                              input_key, output_key):
    """ Encodes the backprop version of a linear layer """
    network = squire.network
    model = squire.model
    output_vars = []
    output_var_namer = utils.build_var_namer(output_key)
    fc_layer = network.fcs[layer_no]
    fc_weight = utils.as_numpy(fc_layer.weight)

    backprop_bounds = squire.get_ith_backward_box(layer_no)
    input_vars = squire.get_vars(input_key)
    for i in range(fc_layer.in_features):
        output_var = model.addVar(lb=backprop_bounds[i][0],
                                  ub=backprop_bounds[i][1],
                                  name=output_var_namer(i))
        weight_col = fc_weight[:, i]
        model.addConstr(output_var == gb.LinExpr(weight_col, input_vars))
        output_vars.append(output_var)
    model.update()
    squire.set_vars(output_key, output_vars)
示例#2
0
    def __init__(self, dimension, x):
        """ For now just set the dimension of the ambient space
            and the central point (which can be none)"""
        self.dimension = dimension

        if x is None:
            self.x = None
        else:
            self.x = utils.as_numpy(x).reshape(-1)

        # Things we'll set later
        self.box_low = None
        self.box_high = None
        self.l2_radius = None
        self.linf_radius = None

        # Original box constraints to be kept separate from those generated
        # by upper bounds.
        self.original_box_low = None
        self.original_box_high = None
        self.unmodified_bounds_low = None
        self.unmodified_bounds_high = None
示例#3
0
    def _setup_state(self, x, lp_norm, potential):
        """ Sets up the state to be used on a per-run basis
        Shared between min_dist_multiproc and decision_problem_multiproc

        Sets instance variables and does asserts
        """
        assert lp_norm in ['l_2', 'l_inf']
        self.lp_norm = lp_norm
        self.x = x
        self.x_np = utils.as_numpy(x)
        self.true_label = int(self.net(x).max(1)[1].item())
        dist_selector = {
            'l_2': Face.l2_dist_gurobi,
            'l_inf': Face.linf_dist_gurobi
        }
        self.lp_dist = dist_selector[self.lp_norm]
        self.domain = Domain(x.numel(), x)
        if self.hyperbox_bounds is not None:
            self.domain.set_original_hyperbox_bound(*self.hyperbox_bounds)
            self._update_dead_constraints()
        assert potential in ['lp', 'lipschitz']
        if self.net.layer_sizes[-1] > 2 and potential == 'lipschitz':
            raise NotImplementedError(
                "Lipschitz potential buggy w/ >2 classes!")
示例#4
0
 def _backprop_linear_layer(self, fc_layer, input_lows, input_highs):
     """ Subroutine to handle the backprop of a linear layer:
         i.e., given a function defined as y=Wx + b
         and some interval on the value of df/dy, want intervals for df/dx
     ARGS:
         layer_no: nn.Linear object - object we are backpropping through
         input_lows: np.Array - array for the lower bounds of the
                                    input gradient
         input_highs: np.Array - array for the upper bounds of the
                                     input gradient
     RETURNS:
         output_lows : np.Array - array for the lower bounds on
                                  the output gradients
         output_highs : np.Array - tensor for the high bounds on
                                   the output gradients
     """
     weight_t = utils.as_numpy(fc_layer.weight.t())
     midpoint = (input_lows + input_highs) / 2.0
     radius = (input_highs - input_lows) / 2.0
     new_midpoint = weight_t.dot(midpoint)
     new_radius = np.abs(weight_t).dot(radius)
     output_lows = new_midpoint - new_radius
     output_highs = new_midpoint + new_radius
     return output_lows, output_highs
示例#5
0
 def __init__(self, values):
     """ Values gets stored as its numpy array of type np.int8 
         where all values are -1, 0, 1 (0 <=> ? <=> {-1, +1})
     """
     self.values = utils.as_numpy(values).astype(np.int8)
     self.dimension = len(self.values)
示例#6
0
 def contains(self, point):
     """ Returns True if the provided point is in the hyperbox """
     point = utils.as_numpy(point)
     assert len(point) == self.dimension
     return all([lo_i <= point_i <= hi_i for (point_i, (lo_i, hi_i)) in 
                 zip(point, self)])
示例#7
0
 def get_sign_configs(self, x):
     preacts = [
         utils.as_numpy(_.squeeze())
         for _ in self(x.view(-1), return_preacts=True)[:-1]
     ]
     return [_ > 0 for _ in preacts]
def Lin_Lip_verify_modded(network, network_name, images, labels, norm="2", warmup="True", method="ours", targettype="untargeted",
                   lipsbnd='disable', LP=False, LPFULL=False, eps=0.2, lipsteps=30, steps=15):
    """

    :param network: "PLNN network object"
    :param images: "images to verify in format [N, 1, n1, n2] (for MNIST n1=n2=28)"
    :param labels: "labels of images. list of ints"
    :param norm: {"i", "1", "2"}
    :param warmup: {True, False}
           warm up before the first iteration
    :param method: {"ours", "spectral", "naive"}
           "ours": our proposed bound, "spectral": spectral norm bounds, "naive": naive bound'
    :param targettype: {"untargeted", "top2"}
           "tops2: 2nd highest prediction label"
    :param lipsbnd: {"disable", "fast", "naive", "both"}
           compute Lipschitz bound, after using some method to compute neuron lower/upper bounds
    :param LP: {True, False}
           use LP to get bounds for final output
    :param LPFULL: {True, False}
           use FULL LP to get bounds for output
    :param eps: "initial guess for epsilon for verification"
    :param lipsteps: "number of steps to use in lipschitz bound'
    :param steps: "how many steps to binary search"
    :return:
    """

    #TODO: eps?

    tf.reset_default_graph()
    gpu_options = tf.GPUOptions(per_process_gpu_memory_fraction=0.33, allow_growth=True)
    sess = tf.Session(config=tf.ConfigProto(gpu_options=gpu_options))

    with tf.Session() as sess:
        sys.stdout.flush()
        random.seed(1215)
        np.random.seed(1215)
        tf.set_random_seed(1215)


        ##################################################################################
        #                                                                                #
        #                       Network Model + Results Loading                             #
        #                                                                                #
        ##################################################################################

        # =====================
        # Convert Network
        # =====================
        layer_sizes = network.layer_sizes
        num_classes = layer_sizes[-1]
        params = layer_sizes[1:-1]
        restore = [None]
        for fc in network.fcs:
            weight =  as_numpy(fc.weight).T
            bias =  as_numpy(fc.bias)
            restore.append([weight, bias])
            restore.append(None)

        model = NLayerModel_comparison(params, num_classes=num_classes, restore=restore)
        # FL_network = NLayerModel_comparison(params, session=sess)
        numlayer = len(params) + 1
        # restore = 'models/mnist_2layer_relu_20_best'
        # params = [nhidden] * (numlayer - 1)
        # model = NLayerModel(params, restore=modelfile)

        # =======================================
        # Convert Image Shapes + Create targets
        # =======================================
        images_lin_lip =  as_numpy(images.reshape(-1, 28, 28, 1))

        true_labels = []
        top2_targets = []
        preds = []
        for image, label in zip(images, labels):
            label_array = np.zeros([num_classes])
            label_array[label] = 1
            true_labels.append(label_array)
            pred = model.predict(tf.constant( as_numpy(image)))
            array = pred.eval()[0]
            preds.append(array)
            target_index = np.argsort(pred.eval()[0])[-2]
            top2_target = np.zeros([num_classes])
            top2_target[target_index] = 1
            top2_targets.append(top2_target)

        true_labels = np.asarray(true_labels)
        true_ids = [num for num in range(0, np.shape(images)[0] + 1)]
        inputs = images_lin_lip

        if targettype == "untargeted":
            targets = true_labels
            targeted = False
        elif targettype == "top2":
            targets = np.asarray(top2_targets)
            targeted = True
        else:
            raise NotImplementedError

        # =====================================

        sys.stdout.flush()

        random.seed(1215)
        np.random.seed(1215)
        tf.set_random_seed(1215)

        # the weights and bias are saved in lists: weights and bias
        # weights[i-1] gives the ith layer of weight and so on
        weights, biases = get_weights_list(model)
        preds = model.model.predict(inputs)

        Nsamp = 0
        r_sum = 0.0
        r_gx_sum = 0.0

        # warmup
        if warmup:
            print("warming up...")
            sys.stdout.flush()
            if method == "spectral":
                robustness_gx = spectral_bound(weights, biases, 0, 1, inputs[0], preds[0], numlayer, norm, not targeted)
            else:
                compute_worst_bound(weights, biases, 0, 1, inputs[0], preds[0], numlayer, norm, 0.01, method, lipsbnd,
                                    LP, LPFULL, not targeted)
        print("starting robustness verification on {} images!".format(len(inputs)))
        sys.stdout.flush()
        sys.stderr.flush()
        total_time_start = time.time()

        min_dists = []
        times = []

        for i in range(len(inputs)):
            Nsamp += 1
            p = norm  # p = "1", "2", or "i"
            predict_label = np.argmax(true_labels[i])
            target_label = np.argmax(targets[i])
            start = time.time()
            # Spectral bound: no binary search needed
            if method == "spectral":
                robustness_gx = spectral_bound(weights, biases, predict_label, target_label, inputs[i], preds[i],
                                               numlayer, p, not targeted)
            # compute worst case bound
            # no need to pass in sess, model and data
            # just need to pass in the weights, true label, norm, x0, prediction of x0, number of layer and eps
            elif lipsbnd != "disable":
                # You can always use the "multi" version of Lipschitz bound to improve results (about 30%).
                robustness_gx = compute_worst_bound_multi(weights, biases, predict_label, target_label, inputs[i],
                                                          preds[i], numlayer, p, eps, lipsteps, method, lipsbnd,
                                                          not targeted)
                eps = eps
                # if initial eps is too small, then increase it
                if robustness_gx == eps:
                    while robustness_gx == eps:
                        eps = eps * 2
                        print("==============================")
                        print("increase eps to {}".format(eps))
                        print("==============================")
                        robustness_gx = compute_worst_bound_multi(weights, biases, predict_label, target_label,
                                                                  inputs[i], preds[i], numlayer, p, eps, lipsteps,
                                                                  method, lipsbnd, not targeted)
                        # if initial eps is too large, then decrease it
                elif robustness_gx <= eps / 5:
                    while robustness_gx <= eps / 5:
                        eps = eps / 5
                        print("==============================")
                        print("increase eps to {}".format(eps))
                        print("==============================")
                        robustness_gx = compute_worst_bound_multi(weights, biases, predict_label, target_label,
                                                                  inputs[i], preds[i], numlayer, p, eps, lipsteps,
                                                                  method, lipsbnd, not targeted)
            else:
                gap_gx = 100
                eps = eps
                eps_LB = -1
                eps_UB = 1
                counter = 0
                is_pos = True
                is_neg = True

                # perform binary search
                eps_gx_UB = np.inf
                eps_gx_LB = 0.0
                is_pos = True
                is_neg = True
                # eps = eps_gx_LB*2
                eps = eps
                while eps_gx_UB - eps_gx_LB > 0.00001:
                    gap_gx, _, _ = compute_worst_bound(weights, biases, predict_label, target_label, inputs[i],
                                                       preds[i], numlayer, p, eps, method, "disable", LP, LPFULL,
                                                       not targeted)
                    print("[L2][binary search] step = {}, eps = {:.5f}, gap_gx = {:.2f}".format(counter, eps, gap_gx))
                    if gap_gx > 0:
                        if gap_gx < 0.01:
                            eps_gx_LB = eps
                            break
                        if is_pos:  # so far always > 0, haven't found eps_UB
                            eps_gx_LB = eps
                            eps *= 10
                        else:
                            eps_gx_LB = eps
                            eps = (eps_gx_LB + eps_gx_UB) / 2
                        is_neg = False
                    else:
                        if is_neg:  # so far always < 0, haven't found eps_LB
                            eps_gx_UB = eps
                            eps /= 2
                        else:
                            eps_gx_UB = eps
                            eps = (eps_gx_LB + eps_gx_UB) / 2
                        is_pos = False
                    counter += 1
                    if counter >= steps:
                        break

                robustness_gx = eps_gx_LB

            r_gx_sum += robustness_gx
            print(
                "[L1] seq = {}, id = {}, true_class = {}, target_class = {} robustness_gx = {:.5f}, avg_robustness_gx = {:.5f},"
                " time = {:.4f}, total_time = {:.4f}".format(i, true_ids[i], predict_label, target_label,
                                                             robustness_gx, r_gx_sum / Nsamp, time.time() - start,
                                                             time.time() - total_time_start))

            times.append(time.time() - start)
            min_dists.append(robustness_gx)

            sys.stdout.flush()
            sys.stderr.flush()

        # =====================
        # Save Output
        # =====================

        output_dictionary = {'min_dists': min_dists, 'times': times}

        cwd = os.getcwd()
        import os.path as path
        norm_text = get_lp_text(norm)
        filename = cwd + "/Results/Lip_Lin_out_" + str(network_name[0:-4]) + '_' + norm_text + ".pkl"
        f = open(filename, 'wb')
        pickle.dump(output_dictionary, f)
        f.close()
        print('Saved Results @:')
        print(filename)

        print("[L0] avg robustness_gx = {:.5f}, numimage = {}, total_time = {:.4f}".format(r_gx_sum / Nsamp, Nsamp, time.time() - total_time_start))
        sys.stdout.flush()
        sys.stderr.flush()

    sess.close()


    return min_dists, times
示例#9
0
 def l1_norm(cls, w):
     return np.linalg.norm(utils.as_numpy(w), 1)
示例#10
0
 def linf_norm(cls, w):
     # BE CAREFUL HERE -- IS THIS THE BEST WE CAN DO????
     return np.linalg.norm(utils.as_numpy(w), np.inf)  # IS THIS RIGHT???
示例#11
0
 def op_norm(cls, w):
     return np.linalg.norm(utils.as_numpy(w))
示例#12
0
    def display_images(self,
                       include_diffs=True,
                       include_pgd=False,
                       figsize=(12, 12)):
        """ Shorthand method to display images found by GeoCert.
            Useful when doing things with GeoCert in jupyter notebooks
        ARGS:
            include_diffs : boolean - if True, we'll display the differences
                            between the original and GeoCert image
                            (diffs scaled up by 5x!)
            include_pgd : boolean - if True, we'll also display the image
                          found by PGD (useful upper bound)
        RETURNS:
            None, but inline displays the images in the order
            [original | diff | geoCert | PGD]
        """
        if self.best_ex is None:
            # No Geocert image => do nothing
            return

        # Build the display row of numpy elements
        original_np = utils.as_numpy(self.original.reshape(
            self.original_shape))
        best_ex_np = utils.as_numpy(self.best_ex.reshape(self.original_shape))
        display_row = [original_np, best_ex_np]
        label_row = ['original', 'geoCert']
        if include_diffs:
            diff_np = np.clip(0.5 + (best_ex_np - original_np) * 5, 0.0, 1.0)
            display_row.insert(1, diff_np)
            label_row.insert(1, 'difference x5 (+0.5)')

        if include_pgd and self.adv_ex is not None:
            adv_ex_np = utils.as_numpy(self.adv_ex.reshape(
                self.original_shape))
            display_row.append(adv_ex_np)
            label_row.append('PGD')
        # Make sure everything has three dimensions (CxHxW)
        # --- determine if grayscale or not
        grayscale = (original_np.squeeze().ndim == 2)
        if grayscale:
            num_channels = 1
            imshow_kwargs = {'cmap': 'gray'}
        else:
            num_channels = 3
            imshow_kwargs = {}

        # --- determine height/width
        h, w = original_np.squeeze().shape[-2:]

        for i in range(len(display_row)):
            display_row[i] = display_row[i].reshape((num_channels, h, w))

        # Concatenate everything into a single row, and display
        # --- concatenate row together
        cat_row = np.concatenate(display_row, -1)
        if grayscale:
            cat_row = cat_row.squeeze()
        plt.figure(figsize=figsize, dpi=80, facecolor='w', edgecolor='k')
        plt.axis('off')
        plt.imshow(cat_row, **imshow_kwargs)

        # -- add labels underneath the images
        for label_idx, label in enumerate(label_row):
            x_offset = (0.33 + label_idx) * w
            plt.text(x_offset, h + 1, label)
        plt.show()
    def linf_dist(self, x):
        """ Computes the l_infinity distance to point x using LP
            The linear program is as follows

            min_{t, v} t
            such that
            1) A(x + v) <= b        (<==>)  Av <= b - Ax
            2) -t <= v_i <= t       (<==>)  v_i - t <= 0  AND -v_i -t <= 0
            3) (x + v) in Domain
            5) t <= upper_bound
            4) A_eq(x + v) = b_eq   (<==>)


            so if A has shape (m,n) and domain constraints have shape (d, n)
            - (n + 1) variables
            - (m + 2n + d) inequality constraints
            - 1 equality constraint
        """

        ######################################################################
        #       Setup things needed for linprog                              #
        ######################################################################

        m, n = self.ub_A.shape
        zero_m_col = np.zeros((m, 1))
        zero_n_col = np.zeros((n, 1))
        x_row = utils.as_numpy(x).squeeze()
        x_col = x_row.reshape(n, 1)

        ######################################################################
        #       Build constraints row by row                                 #
        ######################################################################

        # VARIABLES ARE (v, t)
        a_constraints = []
        b_constraints = []

        # Constraint 1 has shape (m, n+1)
        constraint_1a = np.hstack((self.ub_A, zero_m_col))
        constraint_1b = (self.ub_b -
                         self.ub_A.dot(x_col).squeeze()).reshape(-1)

        assert constraint_1a.shape == (m, n + 1)
        assert constraint_1b.shape == (m, )

        a_constraints.append(constraint_1a)
        b_constraints.append(constraint_1b)

        # Constraint 2 has shape (2n, n+1)
        constraint_2a_left = np.vstack((np.eye(n), -1 * np.eye(n)))
        constraint_2a = np.hstack((constraint_2a_left, -1 * np.ones(
            (2 * n, 1))))
        constraint_2b = np.zeros(2 * n)

        assert constraint_2a.shape == (2 * n, n + 1)
        assert constraint_2b.shape == (2 * n, )
        a_constraints.append(constraint_2a)
        b_constraints.append(constraint_2b)

        # Constraint 3 is added by the domain
        # If a full box, should have shape (2n, n + 1)
        d_a, d_b = self.domain.original_box_constraints()
        x_dx_low = x_row[self.domain.unmodified_bounds_low]
        x_dx_high = x_row[self.domain.unmodified_bounds_high]
        if d_a is not None:
            d_a_rows = d_a.shape[0]
            constraint_d_a = np.hstack((d_a, np.zeros((d_a_rows, 1))))
            constraint_d_b = d_b + np.hstack((x_dx_low, -x_dx_high))

            assert constraint_d_a.shape == (d_a_rows, n + 1)
            assert constraint_d_b.shape == (d_a_rows, )

            a_constraints.append(constraint_d_a)
            b_constraints.append(constraint_d_b)

        # Constraint 4 is upper bound constraint
        if self.domain.linf_radius is not None:
            constraint_4a = np.zeros((1, n + 1))
            constraint_4a[0][-1] = 1
            constaint_4b = np.array(self.domain.linf_radius)
            a_constraints.append(constraint_4a)
            b_constraints.append(constaint_4b)

        # Constraint 5 is equality constraint, should have (1, n+1)
        a_eq = matrix(np.hstack((self.a_eq, np.zeros((1, 1)))))
        b_eq = matrix((self.b_eq - self.a_eq.dot(x_row)).astype(np.double))

        # Objective should have length (n + 1)
        c = matrix(np.zeros(n + 1))
        c[-1] = 1

        ub_a = matrix(np.vstack(a_constraints))
        ub_b = matrix(np.hstack(b_constraints))

        start = time.time()
        cvxopt_out = solvers.lp(c, ub_a, ub_b, A=a_eq, b=b_eq, solver='mosek')
        end = time.time()
        # print("LP SOLVED IN %.03f" % (end -start))

        if cvxopt_out['status'] == 'optimal':
            return cvxopt_out['primal objective'], \
                   (x_row + np.array(cvxopt_out['x'])[:-1].squeeze())
        elif cvxopt_out['status'] in ['primal infeasible', 'unknown']:
            return None, None
        else:
            print("About to fail...")
            print("CVXOPT status", cvxopt_out['status'])
            raise Exception("LINF DIST FAILED?")
示例#14
0
def build_mip_model(network, x, domain, pre_relu_bounds, true_label,
                    problem_type, radius, lp_norm, timeout=None):
    """
    ARGS:
        network : plnn.PLNN - network we wish to compute bounds on
        x : Tensor or numpy of the point we want to verify
        domain : domain.Domain - domain restricting the input domain
        pre_relu_bounds : list of np arrays of shape [#relu x 2] -
                          holds the upper/lower bounds for each pre_relu
                          (and the logits)
        true_label : int - what the model predicts for x
        problem_type: 'min_dist' or 'decision_problem'
        radius:  float - l_inf ball that we are 'deciding' on for
                 'decision_problem' variant
    """



    ##########################################################################
    #   Step 1: setup things we'll need throughout                           #
    ##########################################################################

    num_pre_relu_layers = len(network.fcs) - 1
    # - build model, add variables and box constraints
    model = gb.Model()
    # model.setParam('OutputFlag', False) # -- uncomment to suppress gurobi logs
    if timeout is not None:
        model.setParam('TimeLimit', timeout)
    model.setParam('Threads', 1) # Fair comparisions -- we only use 1 thread
    x_np = utils.as_numpy(x).reshape(-1)



    assert domain.box_low is not None
    assert domain.box_high is not None

    box_bounds = zip(domain.box_low, domain.box_high)
    x_namer = build_var_namer('x')
    x_vars = [model.addVar(lb=low, ub=high, name= x_namer(i))
                for i, (low, high) in enumerate(box_bounds)]
    for (low, high), xvar in zip(box_bounds, x_vars):
        model.addConstr(xvar >= low)
        model.addConstr(xvar <= high)


    var_dict = {'x': x_vars}


    if lp_norm == 'l_2':
        diff_namer = build_var_namer('diff')
        diff_vars = []
        for i in range(len(x_vars)):
            diff_var = model.addVar(lb=-gb.GRB.INFINITY, ub=gb.GRB.INFINITY,
                                    name=diff_namer(i))
            diff_vars.append(diff_var)
            model.addConstr(diff_var == x_vars[i] - x_np[i])

        l2_norm = gb.quicksum(diff_vars[i] * diff_vars[i]
                              for i in range(len(diff_vars)))
        model.addConstr(l2_norm <= radius ** 2)


    # if l_2, and the radius is not None, add those constraints as well
    model.update()


    ##########################################################################
    #   Step 2: Now add layers iteratively                                   #
    ##########################################################################

    # all layers except the last final layer
    for i, fc_layer in enumerate(network.fcs[:-1]):
        # add linear layer
        if i == 0:
            input_name = 'x'
        else:
            input_name = 'fc_%s_post' % i

        pre_relu_name = 'fc_%s_pre' % (i + 1)
        post_relu_name = 'fc_%s_post' % (i + 1)
        relu_name = 'relu_%s' % (i + 1)
        add_linear_layer_mip(network, i, model, var_dict, input_name,
                             pre_relu_name)
        add_relu_layer_mip(network, i, model, var_dict, pre_relu_name,
                           pre_relu_bounds[i], post_relu_name, relu_name)

    # add the final fully connected layer
    output_var_name = 'logits'

    add_linear_layer_mip(network, len(network.fcs) - 1, model, var_dict,
                         post_relu_name, output_var_name)

    ##########################################################################
    #   Step 3: Add the 'adversarial' constraint and objective               #
    ##########################################################################
    add_adversarial_constraint(model, var_dict[output_var_name], true_label,
                               pre_relu_bounds[-1])


    if lp_norm == 'l_inf':
        add_l_inf_obj(model, x_np, var_dict['x'], problem_type)
    else:
        add_l_2_obj(model, x_np, var_dict['x'], problem_type)

    model.update()
    return model