Пример #1
0
 def gap(self, x: Instance, weight):
     """
     :param x: Instance object
     :param weight: a vector specifying linear weights
     :return: real value of gap(x)
     """
     x_prime = x.get_csr_matrix().toarray().T
     return math.fabs(weight * x_prime - self.threshold)
    def binary_gradient_descent(self, attack_instance: Instance):
        # sparse attack with binary features
        index_lst = []
        iter_time = 0
        attacker_score = self.get_score(
            attack_instance.get_csr_matrix().toarray())
        while iter_time < self.max_iter:
            grad = self.gradient(attack_instance.get_csr_matrix().toarray())
            if index_lst is not []:
                # eliminate the index we have already modified
                for i in index_lst:
                    grad[i] = 0
            change_index = np.argmax(np.absolute(grad))
            new_attack_instance = deepcopy(attack_instance)
            new_attack_instance.get_feature_vector().flip_bit(change_index)
            index_lst.append(change_index)

            new_attacker_score = self.get_score(
                new_attack_instance.get_csr_matrix().toarray())
            if new_attacker_score < attacker_score:
                attack_instance = new_attack_instance
                attacker_score = new_attacker_score
                iter_time += 1
        return attack_instance
Пример #3
0
 def random_start_coordinate_greedy(self, instance: Instance):
     """
     implement the n random start algorithm by performing CG for n times.
     The minimized Q and x is used as new attack instance.
     :param instance:
     :return:
     """
     instance_lst = []
     q_value_lst = []
     old_x = instance.get_csr_matrix().toarray()[0]
     for i in range(self.random_start):
         new_attacked_instance = self.coordinate_greedy(instance)
         x = new_attacked_instance.get_csr_matrix().toarray()[0]
         q = self.transform_cost(x, old_x)
         instance_lst.append(new_attacked_instance)
         q_value_lst.append(q)
     return min(zip(instance_lst, q_value_lst), key=lambda x: x[1])[0]
Пример #4
0
    def coordinate_greedy(self, instance: Instance) -> Instance:
        """
         Greddily update the feature to incrementally improve the attackers
         utility. run CS from L random starting points in the feature space. We
         repeat the alternation until differences of instances are small or
         max_change is reached.

         no_improve_count: number of points
         Q: transofrm cost(we use quodratic distance)
         GreedyImprove: using the coordinate descent algorithm.
        :param instance:
        :return: if the result is still classified as +1, we return origin
                 instance else we return the improved.
        """
        indices = [i for i in range(0, self.num_features)]
        x = xk = instance.get_csr_matrix().toarray()[0]
        no_improve_count = 0
        shuffle(indices)
        count = 0
        for i in indices:

            xkplus1 = self.minimize_transform(xk, x, i)
            oldQ = self.transform_cost(xk, x)
            newQ = self.transform_cost(xkplus1, x)
            # step_change = np.log(newQ) / np.log(oldQ)
            # using difference instead of log ratio for convergence check

            xk = xkplus1
            no_improve_count += 1
            if newQ - oldQ > 0 and oldQ != 0:
                step_change = np.log(newQ - oldQ)
                if step_change <= self.epsilon:
                    break
            if no_improve_count > self.max_change:
                break
            count += 1
        mat_indices = [x for x in range(0, self.num_features) if xk[x] != 0]
        mat_data = [xk[x] for x in range(0, self.num_features) if xk[x] != 0]
        new_instance = Instance(
            -1, RealFeatureVector(self.num_features, mat_indices, mat_data))

        return new_instance
Пример #5
0
    def coordinate_greedy(self, instance: Instance) -> Instance:
        indices = [i for i in range(0, self.num_features)]

        x = xk = instance.get_csr_matrix().toarray()[0]
        # Q = [self.transform_cost(xk,x)]
        # f = [self.learn_model.model.learner.predict(xk.reshape(1,-1))]
        # p = [self.learn_model.model.learner.coef_.dot(xk)+
        #     self.learn_model.model.learner.intercept_]
        # c = [self.quadratic_cost(xk,x)]

        no_improve_count = 0
        shuffle(indices)
        for i in indices:
            xkplus1 = self.minimize_transform(xk, i)
            oldQ = self.transform_cost(xk, x)
            newQ = self.transform_cost(xkplus1, x)
            # step_change = np.log(newQ) / np.log(oldQ)
            # using difference instead of log ratio for convergence check

            step_change = newQ - oldQ
            # print('oldQ= '+str(oldQ) + ' newQ= '+str(newQ)+
            #       ' step_change= '+str(step_change))
            # print('xk[i]= ' + str(xk[i]) + ' xk+1[i]= ' +
            #       str(xkplus1[i]) + ' x[i]= ' + str(x[i]))

            if step_change >= 0:
                no_improve_count += 1
                if no_improve_count >= self.max_change:
                    break
            else:
                xk = xkplus1

                # Q.append(self.transform_cost(xk,x))
                # f.append(
                #     self.learn_model.model.learner.predict(xk.reshape(1, -1)))
                # c.append(self.quadratic_cost(xk,x))
                # p.append(self.learn_model.model.learner.coef_.dot(xk) +
                #          self.learn_model.model.learner.intercept_)

        # print('xk shape: '+str(xk.shape))

        # Q = np.array(Q)
        # f = np.array(f)
        # c = np.array(c)
        # p = np.array(p).reshape((-1,))
        # pnc = p+c
        # print(p.shape)
        # print(c.shape)
        # print(pnc.shape)
        # t = np.array([i for i in range(len(Q))])
        # plt.plot(t,Q,'r', label='Q(x)')
        # plt.plot(t, f, 'b', label='sign(f(x))')
        # plt.plot( t,c ,'g', label='||x-xi||^2')
        # plt.plot(t, p, 'b--',label='w.T*x+b')
        # plt.plot(t, pnc, 'r--',
        #          label='w.T*x+b + ||x-xi||^2')
        # plt.legend()
        # plt.show()

        # ('mod succeeded')

        mat_indices = [x for x in range(0, self.num_features) if xk[x] != 0]
        new_instance = Instance(
            -1, BinaryFeatureVector(self.num_features, mat_indices))

        if self.learn_model.predict(
                new_instance) == self.learn_model.positive_classification:
            return instance
        else:
            return new_instance
Пример #6
0
    def coordinate_greedy(self, instance: Instance):
        """
         Greedily update the feature to incrementally improve the attackers utility.
         run CS from L random starting points in the feature space. We repeat the
         alternation until differences of instances are small or max_change is
         reached.

         no_improve_count: number of points
         Q: transofrm cost(we use quodratic distance)
         GreedyImprove: using the coordinate descent algorithm.
        :param instance:
        :return: if the result is still classified as +1, we return origin instance
                 else we return the improved.
        """
        instance_len = instance.get_feature_count()
        if DEBUG:
            iteration_list = []
            Q_value_list = []

        x = xk = instance.get_csr_matrix().toarray()[0]

        # converge is used for checking convergance conditions
        # if the last convergence_time iterations all satisfy <= eplison condition
        # ,the attack successfully finds a optimum
        converge = 0

        for iteration_time in range(self.max_iteration):
            i = randint(0, instance_len - 1)

            #calcualte cost function and greediy improve from a random feature i
            xkplus1 = self.minimize_transform(xk, x, i)
            old_q = self.transform_cost(xk, x)
            new_q = self.transform_cost(xkplus1, x)

            # check whether Q_value actually descends and converges to a minimum
            # plot the iteration and Q_values using matplotlib
            #if DEBUG:
            #    iteration_list.append(iteration_time)
            #    Q_value_list.append(new_q)

            # if new_q < 0:
            #     print("Attack finishes because Q is less than 0")
            #     break

            if new_q - old_q <= 0:
                xk = xkplus1
                step_change = old_q - new_q
                # the np.log() may not converge in special cases
                # makes sure the cost function actually converges
                # alternative implementation?
                #step_change = np.log(new_q) / np.log(old_q)
                #step_change = np.log(old_q - new_q)

                if step_change <= self.epsilon:
                    converge += 1
                    if converge >= self.convergence_time:
                        #print("Attack finishes because of convergence!")
                        break

        #if DEBUG:
        #    plt.plot(iteration_list,Q_value_list)

        mat_indices = [x for x in range(0, self.num_features) if xk[x] != 0]
        mat_data = [xk[x] for x in range(0, self.num_features) if xk[x] != 0]
        new_instance = Instance(
            -1, RealFeatureVector(self.num_features, mat_indices, mat_data))
        return new_instance
Пример #7
0
    def gradient_descent(self, instance: Instance, neg_instances):
        #store iteration and objective values for plotting....
        #iteration_lst = []
        #objective_lst = []

        # attack_intance-> np array
        attack_instance = instance.get_csr_matrix().toarray()
        root_instance = attack_instance
        obj_function_value_list = []

        # store the modified gradient descent attack instances
        # find a list of potential neg_instances, the closest distance, and updated gradients
        candidate_attack_instances = [attack_instance]
        attacker_score = self.get_score(attack_instance)
        closer_neg_instances, dist, grad_update = self.compute_gradient(
            attack_instance, neg_instances)
        obj_func_value = attacker_score + self.lambda_val * dist
        obj_function_value_list.append(obj_func_value)

        for iter in range(self.max_iter):
            # no d(x,x_prime) is set to limit the boundary of attacks
            # compute the obj_func_value of the last satisfied instance
            # append to the value list
            #iteration_lst.append(iter)
            #objective_lst.append(obj_func_value)

            past_instance = candidate_attack_instances[-1]
            new_instance = self.update_within_boundary(past_instance,
                                                       root_instance,
                                                       grad_update)

            # compute the gradient and objective function value of the new instance
            closer_neg_instances, dist, new_grad_update = \
                self.compute_gradient(new_instance, closer_neg_instances)
            new_attacker_score = self.get_score(new_instance)
            obj_func_value = new_attacker_score + self.lambda_val * dist

            # check convergence information
            # we may reach a local min if the function value does not change
            # if obj_func_value == obj_function_value_list[-1]:
            #    print("Local min is reached. Iteration: %d, Obj value %d" %(iter,obj_func_value))
            #    mat_indices = [x for x in range(0, self.num_features) if new_instance[0][x] != 0]
            #    mat_data = [new_instance[0][x] for x in range(0, self.num_features) if new_instance[0][x] != 0]
            #    return Instance(-1, RealFeatureVector(self.num_features, mat_indices, mat_data))

            # check a small epsilon(difference is a small value after
            # several iterations)
            if self.check_convergence_info(obj_func_value,
                                           obj_function_value_list):
                #print("Goes to Convergence here.... Iteration: %d, Obj value %.4f" % (iter,obj_func_value))
                mat_indices = [
                    x for x in range(0, self.num_features)
                    if new_instance[0][x] != 0
                ]
                mat_data = [
                    new_instance[0][x] for x in range(0, self.num_features)
                    if new_instance[0][x] != 0
                ]

                #plt.plot(iteration_lst,objective_lst)
                return Instance(
                    -1,
                    RealFeatureVector(self.num_features, mat_indices,
                                      mat_data))

            # does not satisfy convergence requirement
            # store onto the list
            elif obj_func_value < obj_function_value_list[-1]:
                obj_function_value_list.append(obj_func_value)

            if not (new_instance == candidate_attack_instances[-1]).all():
                candidate_attack_instances.append(new_instance)

            attacker_score = new_attacker_score
            grad_update = new_grad_update

        #print("Convergence has not been found..")
        #plt.plot(iteration_lst, objective_lst)
        mat_indices = [
            x for x in range(0, self.num_features)
            if candidate_attack_instances[-1][0][x] != 0
        ]
        mat_data = [
            candidate_attack_instances[-1][0][x]
            for x in range(0, self.num_features)
            if candidate_attack_instances[-1][0][x] != 0
        ]

        return Instance(
            -1, RealFeatureVector(self.num_features, mat_indices, mat_data))