From: @jxlang910 Reviewed-by: @liu_luobin,@pkuliuliu Signed-off-by: @pkuliuliutags/v1.1.0
@@ -222,21 +222,25 @@ class Attack: | |||||
- numpy.ndarray, the number of objects that are correctly detected. | - numpy.ndarray, the number of objects that are correctly detected. | ||||
""" | """ | ||||
model = check_model('model', model, BlackModel) | model = check_model('model', model, BlackModel) | ||||
box_and_confi, pred_labels = model.predict(*inputs) | |||||
boxes_and_confi, pred_labels = model.predict(*inputs) | |||||
det_scores = [] | det_scores = [] | ||||
correct_labels_num = [] | correct_labels_num = [] | ||||
gt_boxes_num = gt_boxes.shape[0] | |||||
# repeat gt_boxes and gt_labels for all particles cloned from the same sample in PSOAttack/GeneticAttack | |||||
if gt_boxes.shape[0] == 1 and boxes_and_confi.shape[0] > 1: | |||||
gt_boxes = np.repeat(gt_boxes, boxes_and_confi.shape[0], axis=0) | |||||
gt_labels = np.repeat(gt_labels, boxes_and_confi.shape[0], axis=0) | |||||
iou_thres = 0.5 | iou_thres = 0.5 | ||||
for boxes, labels in zip(box_and_confi, pred_labels): | |||||
for boxes, labels, gt_box, gt_label in zip(boxes_and_confi, pred_labels, gt_boxes, gt_labels): | |||||
gt_box_num = gt_box.shape[0] | |||||
score = 0 | score = 0 | ||||
box_num = boxes.shape[0] | box_num = boxes.shape[0] | ||||
correct_label_flag = np.zeros(gt_labels.shape) | |||||
correct_label_flag = np.zeros(gt_label.shape) | |||||
for i in range(box_num): | for i in range(box_num): | ||||
pred_box = boxes[i] | pred_box = boxes[i] | ||||
max_iou_confi = 0 | max_iou_confi = 0 | ||||
for j in range(gt_boxes_num): | |||||
iou = calculate_iou(pred_box[:4], gt_boxes[j][:4]) | |||||
if labels[i] == gt_labels[j] and iou > iou_thres: | |||||
for j in range(gt_box_num): | |||||
iou = calculate_iou(pred_box[:4], gt_box[j][:4]) | |||||
if labels[i] == gt_label[j] and iou > iou_thres: | |||||
max_iou_confi = max(max_iou_confi, pred_box[-1] + iou) | max_iou_confi = max(max_iou_confi, pred_box[-1] + iou) | ||||
correct_label_flag[j] = 1 | correct_label_flag[j] = 1 | ||||
score += max_iou_confi | score += max_iou_confi | ||||
@@ -47,10 +47,11 @@ class GeneticAttack(Attack): | |||||
turns on untargeted attack. It should be noted that only untargeted attack | turns on untargeted attack. It should be noted that only untargeted attack | ||||
is supproted for model_type='detection', Default: False. | is supproted for model_type='detection', Default: False. | ||||
reserve_ratio (Union[int, float]): The percentage of objects that can be detected after attacks, | reserve_ratio (Union[int, float]): The percentage of objects that can be detected after attacks, | ||||
specifically for model_type='detection'. Default: 0.3. | |||||
specifically for model_type='detection'. Reserve_ratio should be in the range of (0, 1). Default: 0.3. | |||||
pop_size (int): The number of particles, which should be greater than | pop_size (int): The number of particles, which should be greater than | ||||
zero. Default: 6. | zero. Default: 6. | ||||
mutation_rate (Union[int, float]): The probability of mutations. Default: 0.005. | |||||
mutation_rate (Union[int, float]): The probability of mutations, which should be in the range of (0, 1). | |||||
Default: 0.005. | |||||
per_bounds (Union[int, float]): Maximum L_inf distance. | per_bounds (Union[int, float]): Maximum L_inf distance. | ||||
max_steps (int): The maximum round of iteration for each adversarial | max_steps (int): The maximum round of iteration for each adversarial | ||||
example. Default: 1000. | example. Default: 1000. | ||||
@@ -83,7 +84,7 @@ class GeneticAttack(Attack): | |||||
self._targeted = check_param_type('targeted', targeted, bool) | self._targeted = check_param_type('targeted', targeted, bool) | ||||
self._reserve_ratio = check_value_non_negative('reserve_ratio', reserve_ratio) | self._reserve_ratio = check_value_non_negative('reserve_ratio', reserve_ratio) | ||||
if self._reserve_ratio > 1: | if self._reserve_ratio > 1: | ||||
msg = "reserve_ratio should be less than 1.0, but got {}.".format(self._reserve_ratio) | |||||
msg = "reserve_ratio should not be greater than 1.0, but got {}.".format(self._reserve_ratio) | |||||
LOGGER.error(TAG, msg) | LOGGER.error(TAG, msg) | ||||
raise ValueError(msg) | raise ValueError(msg) | ||||
self._sparse = check_param_type('sparse', sparse, bool) | self._sparse = check_param_type('sparse', sparse, bool) | ||||
@@ -92,8 +93,11 @@ class GeneticAttack(Attack): | |||||
self._step_size = check_value_positive('step_size', step_size) | self._step_size = check_value_positive('step_size', step_size) | ||||
self._temp = check_value_positive('temp', temp) | self._temp = check_value_positive('temp', temp) | ||||
self._max_steps = check_int_positive('max_steps', max_steps) | self._max_steps = check_int_positive('max_steps', max_steps) | ||||
self._mutation_rate = check_value_positive('mutation_rate', | |||||
mutation_rate) | |||||
self._mutation_rate = check_value_non_negative('mutation_rate', mutation_rate) | |||||
if self._mutation_rate > 1: | |||||
msg = "mutation_rate should not be greater than 1.0, but got {}.".format(self._mutation_rate) | |||||
LOGGER.error(TAG, msg) | |||||
raise ValueError(msg) | |||||
self._adaptive = check_param_type('adaptive', adaptive, bool) | self._adaptive = check_param_type('adaptive', adaptive, bool) | ||||
# initial global optimum fitness value | # initial global optimum fitness value | ||||
self._best_fit = -np.inf | self._best_fit = -np.inf | ||||
@@ -163,7 +167,7 @@ class GeneticAttack(Attack): | |||||
msg = "The parameter 'sparse' of GeneticAttack is True, but the input labels is not sparse style " \ | msg = "The parameter 'sparse' of GeneticAttack is True, but the input labels is not sparse style " \ | ||||
"and got its shape as {}.".format(labels.shape) | "and got its shape as {}.".format(labels.shape) | ||||
LOGGER.error(TAG, msg) | LOGGER.error(TAG, msg) | ||||
raise ValueError | |||||
raise ValueError(msg) | |||||
else: | else: | ||||
labels = np.argmax(labels, axis=1) | labels = np.argmax(labels, axis=1) | ||||
images = inputs | images = inputs | ||||
@@ -186,7 +190,7 @@ class GeneticAttack(Attack): | |||||
auxiliary_input_i = tuple() | auxiliary_input_i = tuple() | ||||
for item in auxiliary_inputs: | for item in auxiliary_inputs: | ||||
auxiliary_input_i += (np.expand_dims(item[i], axis=0),) | auxiliary_input_i += (np.expand_dims(item[i], axis=0),) | ||||
gt_boxes_i, gt_labels_i = gt_boxes[i], gt_labels[i] | |||||
gt_boxes_i, gt_labels_i = np.expand_dims(gt_boxes[i], axis=0), np.expand_dims(gt_labels[i], axis=0) | |||||
inputs_i = (images[i],) + auxiliary_input_i | inputs_i = (images[i],) + auxiliary_input_i | ||||
confi_ori, gt_object_num = self._detection_scores(inputs_i, gt_boxes_i, gt_labels_i, model=self._model) | confi_ori, gt_object_num = self._detection_scores(inputs_i, gt_boxes_i, gt_labels_i, model=self._model) | ||||
LOGGER.info(TAG, 'The number of ground-truth objects is %s', gt_object_num[0]) | LOGGER.info(TAG, 'The number of ground-truth objects is %s', gt_object_num[0]) | ||||
@@ -50,7 +50,7 @@ class PSOAttack(Attack): | |||||
than zero. Default: 6. | than zero. Default: 6. | ||||
t_max (int): The maximum round of iteration for each adversarial example, | t_max (int): The maximum round of iteration for each adversarial example, | ||||
which should be greater than zero. Default: 1000. | which should be greater than zero. Default: 1000. | ||||
pm (Union[int, float]): The probability of mutations. Default: 0.5. | |||||
pm (Union[int, float]): The probability of mutations, which should be in the range of (0, 1). Default: 0.5. | |||||
bounds (Union[list, tuple, None]): Upper and lower bounds of data. In form of (clip_min, | bounds (Union[list, tuple, None]): Upper and lower bounds of data. In form of (clip_min, | ||||
clip_max). Default: None. | clip_max). Default: None. | ||||
targeted (bool): If True, turns on the targeted attack. If False, | targeted (bool): If True, turns on the targeted attack. If False, | ||||
@@ -61,7 +61,7 @@ class PSOAttack(Attack): | |||||
model_type (str): The type of targeted model. 'classification' and 'detection' are supported now. | model_type (str): The type of targeted model. 'classification' and 'detection' are supported now. | ||||
default: 'classification'. | default: 'classification'. | ||||
reserve_ratio (Union[int, float]): The percentage of objects that can be detected after attacks, | reserve_ratio (Union[int, float]): The percentage of objects that can be detected after attacks, | ||||
specifically for model_type='detection'. Default: 0.3. | |||||
specifically for model_type='detection'. Reserve_ratio should be in the range of (0, 1). Default: 0.3. | |||||
Examples: | Examples: | ||||
>>> attack = PSOAttack(model) | >>> attack = PSOAttack(model) | ||||
@@ -77,7 +77,11 @@ class PSOAttack(Attack): | |||||
self._c2 = check_value_positive('c2', c2) | self._c2 = check_value_positive('c2', c2) | ||||
self._c = check_value_positive('c', c) | self._c = check_value_positive('c', c) | ||||
self._pop_size = check_int_positive('pop_size', pop_size) | self._pop_size = check_int_positive('pop_size', pop_size) | ||||
self._pm = check_value_positive('pm', pm) | |||||
self._pm = check_value_non_negative('pm', pm) | |||||
if self._pm > 1: | |||||
msg = "pm should not be greater than 1.0, but got {}.".format(self._pm) | |||||
LOGGER.error(TAG, msg) | |||||
raise ValueError(msg) | |||||
self._bounds = bounds | self._bounds = bounds | ||||
if self._bounds is not None: | if self._bounds is not None: | ||||
self._bounds = check_param_multi_types('bounds', bounds, [list, tuple]) | self._bounds = check_param_multi_types('bounds', bounds, [list, tuple]) | ||||
@@ -93,7 +97,7 @@ class PSOAttack(Attack): | |||||
raise ValueError(msg) | raise ValueError(msg) | ||||
self._reserve_ratio = check_value_non_negative('reserve_ratio', reserve_ratio) | self._reserve_ratio = check_value_non_negative('reserve_ratio', reserve_ratio) | ||||
if self._reserve_ratio > 1: | if self._reserve_ratio > 1: | ||||
msg = "reserve_ratio should be less than 1.0, but got {}.".format(self._reserve_ratio) | |||||
msg = "reserve_ratio should not be greater than 1.0, but got {}.".format(self._reserve_ratio) | |||||
LOGGER.error(TAG, msg) | LOGGER.error(TAG, msg) | ||||
raise ValueError(msg) | raise ValueError(msg) | ||||
@@ -200,7 +204,7 @@ class PSOAttack(Attack): | |||||
msg = "The parameter 'sparse' of PSOAttack is True, but the input labels is not sparse style and " \ | msg = "The parameter 'sparse' of PSOAttack is True, but the input labels is not sparse style and " \ | ||||
"got its shape as {}.".format(labels.shape) | "got its shape as {}.".format(labels.shape) | ||||
LOGGER.error(TAG, msg) | LOGGER.error(TAG, msg) | ||||
raise ValueError | |||||
raise ValueError(msg) | |||||
else: | else: | ||||
labels = np.argmax(labels, axis=1) | labels = np.argmax(labels, axis=1) | ||||
images = inputs | images = inputs | ||||
@@ -227,7 +231,7 @@ class PSOAttack(Attack): | |||||
auxiliary_input_i = tuple() | auxiliary_input_i = tuple() | ||||
for item in auxiliary_inputs: | for item in auxiliary_inputs: | ||||
auxiliary_input_i += (np.expand_dims(item[i], axis=0),) | auxiliary_input_i += (np.expand_dims(item[i], axis=0),) | ||||
gt_boxes_i, gt_labels_i = gt_boxes[i], gt_labels[i] | |||||
gt_boxes_i, gt_labels_i = np.expand_dims(gt_boxes[i], axis=0), np.expand_dims(gt_labels[i], axis=0) | |||||
inputs_i = (images[i],) + auxiliary_input_i | inputs_i = (images[i],) + auxiliary_input_i | ||||
confi_ori, gt_object_num = self._detection_scores(inputs_i, gt_boxes_i, gt_labels_i, self._model) | confi_ori, gt_object_num = self._detection_scores(inputs_i, gt_boxes_i, gt_labels_i, self._model) | ||||
LOGGER.info(TAG, 'The number of ground-truth objects is %s', gt_object_num[0]) | LOGGER.info(TAG, 'The number of ground-truth objects is %s', gt_object_num[0]) | ||||