def transform(self, instance: Instance):
        """
        for the binary case, the f_attack value represents the percentage of
        features we change.
        If f_attack =1, then the result should be exactly the same as innocuous
        target.

        for the real_value case, we generate a value between c_f(x_min - xij)
        and c_f(x_max - xij)
        This value will be added to the xij for the new instance
        :param instance:
        :return: instance
        """

        if self.binary:
            attack_times = int(self.f_attack * self.num_features)
            count = 0
            for i in range(0, self.num_features):
                instance.get_feature_vector().flip_bit(i)
                count += 1
                if count == attack_times:
                    return instance
        else:
            for i in range(0, self.num_features):
                xij = instance.get_feature_vector().get_feature(i)
                if not self.manual:
                    lower_bound = self.f_attack * (self.x_min[i] - xij)
                    upper_bound = self.f_attack * (self.x_max[i] - xij)
                else:
                    lower_bound = self.f_attack * (self.xj_min - xij)
                    upper_bound = self.f_attack * (self.xj_max - xij)
                delta_ij = random.uniform(lower_bound, upper_bound)
                instance.flip(i, xij + delta_ij)
        return instance
Exemple #2
0
 def transform(self, instance: Instance):
     '''
     for the real_value case, we generate a value between 0 and the bound.
     The bound is calculated by 1- c_delta * (abs(xt - x)/abs(x) + abs(xt)) * (xt -x)
     This value will be added to the xij for the new instance
     :param instance:
     :return: instance
     '''
     if self.binary:
         attack_times = int(self.f_attack * self.num_features)
         count = 0
         for i in range(0, self.num_features):
             delta_ij = self.innocuous_target.get_feature_vector().get_feature(i) \
                        - instance.get_feature_vector().get_feature(i)
             if delta_ij != 0:
                 if self.binary:  # when features are binary
                     instance.get_feature_vector().flip_bit(i)
             count += 1
             if count == attack_times:
                 return instance
     else:
         for i in range(0, self.num_features):
             xij = instance.get_feature_vector().get_feature(i)
             target = self.innocuous_target.get_feature_vector(
             ).get_feature(i)
             if abs(xij) + abs(target) == 0:
                 bound = 0
             else:
                 bound = self.discount_factor * (1 - self.f_attack *
                                                 (abs(target - xij) /
                                                  (abs(xij) + abs(target)))) \
                         * abs((target - xij))
             delta_ij = random.uniform(0, bound)
             instance.flip(i, xij + delta_ij)
         return instance
Exemple #3
0
    def optimize(self, instance: Instance):
        """Flip features that lower the prob. of being classified adversarial.
        Args:
            instance: (scipy.sparse.csr_matrix) feature vector

        """
        change = 0
        for i in range(0, self.num_features):
            orig_prob = self.learn_model.predict_proba([instance])[0]
            new_instance = deepcopy(instance)
            new_instance.get_feature_vector().flip_bit(i)
            new_prob = self.learn_model.predict_proba([new_instance])[0]
            if new_prob < (orig_prob - exp(self.lambda_val)):
                instance.get_feature_vector().flip_bit(i)
                change += 1
            if change > self.max_change:
                break
        return instance
Exemple #4
0
    def transform(self, instance: Instance):
        '''
        for the binary case, the f_attack value represents the percentage of
        features we change.
        If f_attack =1, then the result should be exactly the same as innocuous
        target.

        for the real_value case, we generate a value between c_f(x_min - xij)
        and c_f(x_max - xij)
        This value will be added to the xij for the new instance
        :param instance:
        :return: instance
        '''
        if self.binary:
            attack_times = (int)(self.f_attack * self.num_features)
            count = 0
            for i in range(0, self.num_features):
                delta_ij = (self.innocuous_target.get_feature_vector().get_feature(i) -
                            instance.get_feature_vector().get_feature(i))
                if delta_ij != 0:
                    if self.binary:  # when features are binary
                        instance.get_feature_vector().flip_bit(i)
                count += 1
                if count == attack_times:
                    return instance
        else:
            for i in range(0, self.num_features):
                xij = instance.get_feature_vector().get_feature(i)
                if self.xj_min == 0 and self.xj_max == 0:
                    lower_bound = self.f_attack * (
                            self.x_min.get_feature(i) - xij)
                    upper_bound = self.f_attack * (
                            self.x_max.get_feature(i) - xij)
                else:
                    lower_bound = self.f_attack * (self.xj_min - xij)
                    upper_bound = self.f_attack * (self.xj_max - xij)
                # is that ok to just assign a random number between the range???
                delta_ij = random.uniform(lower_bound, upper_bound)
                instance.flip(i, xij + delta_ij)
        return instance
Exemple #5
0
    def get_feature_vector_array(inst: Instance):
        """
        Turns the feature vector into an np.ndarray
        :param inst: the Instance
        :return: the feature vector (np.ndarray)
        """

        fv = inst.get_feature_vector()
        tmp = []
        for j in range(inst.get_feature_count()):
            if fv.get_feature(j) == 1:
                tmp.append(1)
            else:
                tmp.append(0)
        return np.array(tmp)
Exemple #6
0
    def _calc_inst_loss(self, inst: Instance):
        """
        Calculates the logistic loss for one instance
        :param inst: the instance
        :return: the logistic loss
        """

        fv = inst.get_feature_vector().get_csr_matrix()
        fv = np.array(fv.todense().tolist()).flatten()

        # reshape is for the decision function when inputting only one sample
        loss = self.learner.model.learner.decision_function(fv.reshape(1, -1))
        loss *= -1 * inst.get_label()
        loss = math.log(1 + math.exp(loss))

        return loss
Exemple #7
0
    def _calc_inst_loss(self, inst: Instance):
        """
        Calculates the logistic loss for one instance
        :param inst: the instance
        :return: the logistic loss
        """

        fv = []
        for i in range(inst.get_feature_count()):
            if inst.get_feature_vector().get_feature(i) == 1:
                fv.append(1)
            else:
                fv.append(0)
        fv = np.array(fv)

        # reshape is for the decision function when inputting only one sample
        loss = self.learner.model.learner.decision_function(fv.reshape(1, -1))
        loss *= -1 * inst.get_label()
        loss = math.log(1 + math.exp(loss))

        return loss
Exemple #8
0
 def transform(self, instance: Instance):
     '''
     for the real_value case, we generate a value between 0 and the bound.
     The bound is calculated by 1- c_delta * (abs(xt - x)/abs(x) + abs(xt)) * (xt -x)
     This value will be added to the xij for the new instance
     :param instance:
     :return: instance
     '''
     for i in range(0, self.num_features):
         xij = instance.get_feature_vector().get_feature(i)
         target = self.innocuous_target.get_feature_vector().get_feature(i)
         if abs(xij) + abs(target) == 0:
             bound = 0
         else:
             bound = self.discount_factor * (1 - self.f_attack *
                                             (abs(target - xij) /
                                              (abs(xij) + abs(target)))) \
                     * abs((target - xij))
         # is that ok to just assign a random number between the range???
         delta_ij = random.uniform(0, bound)
         instance.flip(i, xij + delta_ij)
     return instance