attack复现

attack复现

1.目标检测

重叠度(IOU)

物体检测最终会定位到一个bounding box(边界框),就是最终框到目标的那个框,对于bounding box的定位精度,我们有一个评价指标,就是IOU。

img

就是A交B面积除以A并B,这可以用来评价我们的预测结果与实际结果(人工标注)的误差。

正样本、负样本:

比如我们要检测字母A,那样本里面是A的就是正样本,不是A的就是负样本。我们不光要识别正样本,也要把负样本检测出来。
TP(True Positives):被分为正样本,并且分对了
TN(True Negatives):被分为负样本,并且分对了
FP(False Positives):被分为正样本,但是分错了
FN(False Negatives):被分为负样本,但是分错了
如何判断分的对不对呢?IOU>0.5就是对,反之就是错的

在这里插入图片描述

Precision 和 recall也被叫做查准率和查全率。

PR图绘制

​ 首先我们有很多张图,每张图里面标注了猫,也就是说我们有很多的标注框,也就是GT(ground truth)。

​ 每个标注框我们给他不同的ID。然后经过我们网络识别出来的预测框,有其对应的GT ID(也就是这个框是预测哪个目标的),并且还有置信度,也就是概率Confidence,另外就是如果预测框和对应的GT框IOU>0.5我们记作True。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5mjZz6o9-1686743216844)(

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

FPS

(Frame Per Second)
FPS,即每秒帧率。除了检测准确度,目标检测算法的另一个重要评估指标是速度,只有速度快,才能够实现实时检测。FPS用来评估目标检测的速度。即每秒内可以处理的图片数量。当然要对比FPS,你需要在同一硬件上进行。另外也可以使用处理一张图片所需时间来评估检测速度,时间越短,速度越快。

3.代码复现

在这里插入图片描述

1.安装包

matplotlib==3.5.2
mmcv==2.0.0rc4
mmdet==3.0.0
numpy==1.24.3
opencv_python==4.7.0.72
Pillow==9.2.0
Pillow==9.5.0
scikit_image==0.19.3
scipy==1.6.0
torch==1.12.1
torchvision==0.13.1
tqdm==4.64.1
~pencv_contrib_python==4.7.0.72

2.constan参数定义

device = "cpu"
device1 = "cpu"

3.超参数设置

#
line_interval = 40
#
box_scale = 1.0
# 图片保存路径
save_image_dir = "D:WP\images_p_yolo_momentum_lineinterval_{}".format(line_interval)

4.目标检测模型设置

yolov4_helper = YoLov4Helper()
model_helpers = [yolov4_helper]

5.初始化攻击成功图片个数

success_count = 0
os.system("mkdir -p {}".format(save_image_dir))

6.对训练集image1中图片进行训练

#对所有训练图片
for i, img_path in enumerate(os.listdir("images1")):
    
    #若训练集image1中存在图片在save文件夹中,success率+1
    #否则图片_fail.在save文件夹中,success率不变
    img_path_ps = os.listdir(save_image_dir)
    if img_path in img_path_ps:
        success_count+= 1
        continue
    if img_path.replace(".", "_fail.") in img_path_ps: continue
    print("img_path", img_path)
    
    
    img_path = os.path.join("images1", img_path)
    #mask创建
    #对yolo对象创建mask
    mask = create_yolo_object_mask(yolov4_helper.darknet_model, img_path)
    #mask = create_strip_mask()
    #mask = create_center_mask()
    
    #将加上mask后的图片重新进行目标检测,得到攻击成功率
    success_attack = specific_attack(model_helpers, img_path, mask)
    if success_attack: success_count += 1
    print("success: {}/{}".format(success_count, i))
6.1.mask创建
1.创建yolo对象的mask

(先用darknet2pytorch得到每张图片几个主要检测框区域,使用5*5横线框绘制对抗补丁)

具体效果如图所示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AMsO7LDq-1686743216846)(D:\桌面\csdn\27.png)]

mask = create_yolo_object_mask(yolov4_helper.darknet_model, img_path)
create_yolo_object_mask函数
def create_yolo_object_mask(darknet_model, image_path, shape=(500, 500), size=50):
    
#初始化mask    
    mask = torch.zeros(*shape, 3)
#处理输入图片image
    img = Image.open(image_path).convert('RGB')
    resize_small = transforms.Compose([
            transforms.Resize((608, 608)),
    ])
    img1 = resize_small(img)
    h, w = numpy.array(img).shape[:2]
#生成boxes,do_detect函数    
    boxes = do_detect(darknet_model, img1, 0.5, 0.4, True)
#对boxes处理得到grids
    grids = []
    for i, box in enumerate(boxes):
        x1 = (box[0] - box[2] / 2.0) * w
        y1 = (box[1] - box[3] / 2.0) * h
        x2 = (box[0] + box[2] / 2.0) * w
        y2 = (box[1] + box[3] / 2.0) * h
        print(x1, y1, x2, y2)
        grids += [[int(x1), int(y1), int(x2), int(y2)]]
    for x1, y1, x2, y2 in grids:
        x1 = np.clip(x1, 0, 499)
        x2 = np.clip(x2, 0, 499)

        y1 = np.clip(y1, 0, 499)
        y2 = np.clip(y2, 0, 499)
        print("x1, y1, x2, y2", x1, y1, x2, y2)
#五横线型mask        
        y_interval = max(24, (y2-y1)//5)
        x_interval = max(24, (x2-x1)//5)
        for i in range(1, 5):
            if mask.sum()>4500*3: break
            if y1+i*y_interval>y2: break
            mask[np.clip(y1+i*y_interval, 0, 499), x1:x2, :]=1
        for i in range(1, 5):
            if mask.sum()>4500*3: break
            if x1+i*x_interval>x2: break
            mask[y1:y2, np.clip(x1+i*x_interval, 0, 499), :]=1

    print("mask sum", mask.sum())
    return mask
生成box,do_detect函数
boxes = do_detect(darknet_model, img1, 0.5, 0.4, True)
def do_detect(model, img, conf_thresh, nms_thresh, use_cuda=1):
    model.eval()
#image图像处理   
    if isinstance(img, Image.Image):
        width = img.width
        height = img.height
        img = torch.ByteTensor(torch.ByteStorage.from_buffer(img.tobytes()))
        img = img.view(height, width, 3).transpose(0, 1).transpose(0, 2).contiguous()
        img = img.view(1, 3, height, width)
        img = img.float().div(255.0)
#list_boxes
    list_boxes = model(img)
#定义锚
    anchors = [12, 16, 19, 36, 40, 28, 36, 75, 76, 55, 72, 146, 142, 110, 192, 243, 459, 401]
    num_anchors = 9
    anchor_masks = [[0, 1, 2], [3, 4, 5], [6, 7, 8]]
    strides = [8, 16, 32]
    anchor_step = len(anchors) // num_anchors
#得到boxes    
    boxes = []
    for i in range(3):
#先生成masked_anchors
        masked_anchors = []
        for m in anchor_masks[i]:
            masked_anchors += anchors[m * anchor_step:(m + 1) * anchor_step]
        masked_anchors = [anchor / strides[i] for anchor in masked_anchors]
#用get_region_boxes函数得到boxes
        boxes.append(get_region_boxes1(list_boxes[i].data.cpu().numpy(), conf_thresh, 80, masked_anchors, len(anchor_masks[i])))
       
#num得到boxes
    boxes = boxes[0][0] + boxes[1][0] + boxes[2][0]
    t3 = time.time()
    boxes = nms(boxes, nms_thresh)
return boxes
list_boxes Darknet forward

在这里插入图片描述

class Darknet(nn.Module):
    def __init__(self, cfgfile):
        super(Darknet, self).__init__()
        self.blocks = parse_cfg(cfgfile)
        self.models = self.create_network(self.blocks)  # merge conv, bn,leaky
        self.loss = self.models[len(self.models) - 1]

        self.width = int(self.blocks[0]['width'])
        self.height = int(self.blocks[0]['height'])

        if self.blocks[(len(self.blocks) - 1)]['type'] == 'region':
            self.anchors = self.loss.anchors
            self.num_anchors = self.loss.num_anchors
            self.anchor_step = self.loss.anchor_step
            self.num_classes = self.loss.num_classes

        self.header = torch.IntTensor([0, 0, 0, 0])
        self.seen = 0

    def forward(self, x):
        ind = -2
        self.loss = None
        outputs = dict()
        out_boxes = []
        for block in self.blocks:
            ind = ind + 1
            # if ind > 0:
            #    return x

            if block['type'] == 'net':
                continue
            elif block['type'] in ['convolutional', 'maxpool', 'reorg', 'upsample', 'avgpool', 'softmax', 'connected']:
                x = self.models[ind](x)
                outputs[ind] = x
            elif block['type'] == 'route':
                layers = block['layers'].split(',')
                layers = [int(i) if int(i) > 0 else int(i) + ind for i in layers]
                if len(layers) == 1:
                    x = outputs[layers[0]]
                    outputs[ind] = x
                elif len(layers) == 2:
                    x1 = outputs[layers[0]]
                    x2 = outputs[layers[1]]
                    x = torch.cat((x1, x2), 1)
                    outputs[ind] = x
                elif len(layers) == 4:
                    x1 = outputs[layers[0]]
                    x2 = outputs[layers[1]]
                    x3 = outputs[layers[2]]
                    x4 = outputs[layers[3]]
                    x = torch.cat((x1, x2, x3, x4), 1)
                    outputs[ind] = x
                else:
                    print("rounte number > 2 ,is {}".format(len(layers)))

            elif block['type'] == 'shortcut':
                from_layer = int(block['from'])
                activation = block['activation']
                from_layer = from_layer if from_layer > 0 else from_layer + ind
                x1 = outputs[from_layer]
                x2 = outputs[ind - 1]
                x = x1 + x2
                if activation == 'leaky':
                    x = F.leaky_relu(x, 0.1, inplace=True)
                elif activation == 'relu':
                    x = F.relu(x, inplace=True)
                outputs[ind] = x
            elif block['type'] == 'region':
                continue
                if self.loss:
                    self.loss = self.loss + self.models[ind](x)
                else:
                    self.loss = self.models[ind](x)
                outputs[ind] = None
            elif block['type'] == 'yolo':
                self.features = x
                boxes = self.models[ind](x)
                out_boxes.append(boxes)
                #if self.training:
                #    pass
                #else:
                #    boxes = self.models[ind](x)
                #    out_boxes.append(boxes)
            elif block['type'] == 'cost':
                continue
            else:
                print('unknown type %s' % (block['type']))
        if self.training:
            return out_boxes
            #return loss
        else:
            return out_boxes
get_region_boxes函数
get_region_boxes1(list_boxes[i].data.cpu().numpy(), conf_thresh, 80, masked_anchors, len(anchor_masks[i]))
def get_region_boxes1(output, conf_thresh, num_classes, anchors, num_anchors, only_objectness=1, validation=False):
    anchor_step = len(anchors) // num_anchors
    if len(output.shape) == 3:
        output = np.expand_dims(output, axis=0)
    batch = output.shape[0]
    assert (output.shape[1] == (5 + num_classes) * num_anchors)
    h = output.shape[2]
    w = output.shape[3]

    t0 = time.time()
    all_boxes = []
    output = output.reshape(batch * num_anchors, 5 + num_classes, h * w).transpose((1, 0, 2)).reshape(
        5 + num_classes,
        batch * num_anchors * h * w)

    grid_x = np.expand_dims(np.expand_dims(np.linspace(0, w - 1, w), axis=0).repeat(h, 0), axis=0).repeat(
        batch * num_anchors, axis=0).reshape(
        batch * num_anchors * h * w)
    grid_y = np.expand_dims(np.expand_dims(np.linspace(0, h - 1, h), axis=0).repeat(w, 0).T, axis=0).repeat(batch * num_anchors, axis=0).reshape(batch * num_anchors * h * w)

    xs = sigmoid(output[0]) + grid_x
    ys = sigmoid(output[1]) + grid_y

    anchor_w = np.array(anchors).reshape((num_anchors, anchor_step))[:, 0]
    anchor_h = np.array(anchors).reshape((num_anchors, anchor_step))[:, 1]
    anchor_w = np.expand_dims(np.expand_dims(anchor_w, axis=1).repeat(batch, 1), axis=2) \
        .repeat(h * w, axis=2).transpose(1, 0, 2).reshape(batch * num_anchors * h * w)
    anchor_h = np.expand_dims(np.expand_dims(anchor_h, axis=1).repeat(batch, 1), axis=2) \
        .repeat(h * w, axis=2).transpose(1, 0, 2).reshape(batch * num_anchors * h * w)
    ws = np.exp(output[2]) * anchor_w
    hs = np.exp(output[3]) * anchor_h

    det_confs = sigmoid(output[4])

    cls_confs = softmax(output[5:5 + num_classes].transpose(1, 0))
    cls_max_confs = np.max(cls_confs, 1)
    cls_max_ids = np.argmax(cls_confs, 1)
    t1 = time.time()

    sz_hw = h * w
    sz_hwa = sz_hw * num_anchors
    t2 = time.time()
    for b in range(batch):
        boxes = []
        for cy in range(h):
            for cx in range(w):
                for i in range(num_anchors):
                    ind = b * sz_hwa + i * sz_hw + cy * w + cx
                    det_conf = det_confs[ind]
                    if only_objectness:
                        conf = det_confs[ind]
                    else:
                        conf = det_confs[ind] * cls_max_confs[ind]

                    if conf > conf_thresh:
                        bcx = xs[ind]
                        bcy = ys[ind]
                        bw = ws[ind]
                        bh = hs[ind]
                        cls_max_conf = cls_max_confs[ind]
                        cls_max_id = cls_max_ids[ind]
                        box = [bcx / w, bcy / h, bw / w, bh / h, det_conf, cls_max_conf, cls_max_id]
                        if (not only_objectness) and validation:
                            for c in range(num_classes):
                                tmp_conf = cls_confs[ind][c]
                                if c != cls_max_id and det_confs[ind] * tmp_conf > conf_thresh:
                                    box.append(tmp_conf)
                                    box.append(c)
                        boxes.append(box)
        all_boxes.append(boxes)
    t3 = time.time()
    if False:
        print('---------------------------------')
        print('matrix computation : %f' % (t1 - t0))
        print('        gpu to cpu : %f' % (t2 - t1))
        print('      boxes filter : %f' % (t3 - t2))
        print('---------------------------------')
    return all_boxes
nms
def nms(boxes, nms_thresh):
    if len(boxes) == 0:
        return boxes

    det_confs = torch.zeros(len(boxes))
    for i in range(len(boxes)):
        det_confs[i] = 1 - boxes[i][4]

    _, sortIds = torch.sort(det_confs)
    out_boxes = []
    for i in range(len(boxes)):
        box_i = boxes[sortIds[i]]
        if box_i[4] > 0:
            out_boxes.append(box_i)
            for j in range(i + 1, len(boxes)):
                box_j = boxes[sortIds[j]]
                if bbox_iou(box_i, box_j, x1y1x2y2=False) > nms_thresh:
                    # print(box_i, box_j, bbox_iou(box_i, box_j, x1y1x2y2=False))
                    box_j[4] = 0
    return out_boxes
2.strip_mask

(在图片固定位置处绘制20条横线,2条竖线)

def create_strip_mask(shape=(500,500)):
    mask = torch.zeros(*shape, 3)
    rows = [15*i+125 for i in range(1, 19)]
    for row in rows:
        mask[row, 125:375, :]=1
    mask[125:375, 200, :] = 1
    mask[125:375, 300, :] = 1
    return mask

(yolo_target_mask)

15

(strip_mask)

14
3.watermask
mask = create_watermask_mask(watermask_path='D:\桌面\csdn\watermask.jpg')
def create_watermask_mask(watermask_path, shape=(500, 500)):
    mask = torch.zeros(*shape, 3)
    img = Image.open(watermask_path).convert('RGB')
    resize_small = transforms.Compose([
        transforms.Resize((500, 500)),
    ])
    img = resize_small(img)

    mask = np.array(img).astype(np.float32)
    mask = np.where(mask < 240, 1, 0)
    mask = torch.from_numpy(mask)

    return mask
6
6.2加上mask后在对应的model中得到攻击成功率
success_attack = specific_attack(model_helpers, img_path, mask)
def specific_attack(model_helpers, img_path, mask):
    img = cv2.imread(img_path)
    img = torch.from_numpy(img).float()
#参数设置
	#训练最大次数
    t, max_iterations = 0, 600
	#停止损失    
    stop_loss = 1e-6
	#步长
    eps = 1
    patch_size = 70
    patch_num = 10
#权重初始化
    w = torch.zeros(img.shape).float()+127
    #w = torch.zeros(img.shape).float()
    w.requires_grad = True
#攻击率初始化    
    success_attack = False
#初始化yolo检测到最少object
    min_object_num = 1000
#初始化min-object的图像
    min_img = img
    
    grads = 0
    loop = asyncio.get_event_loop()

#第t次迭代训练  
    while t<max_iterations:
        #optimizer.zero_grad()
        t+=1
#patch_image修改        
        patch_img = img * (1-mask) + get_delta(w)*mask
        patch_img = patch_img.to(device)
#初始化攻击损失
        attack_loss = 0
        object_nums = 0
#得到目标检测损失        
        tasks = [
                get_attack_loss(model_helpers[0], patch_img),
                ]
        res = loop.run_until_complete(asyncio.gather(*tasks))
       # for i, model_helper in enumerate(model_helpers):
       #     al, on = model_helper.attack_loss(patch_img)
#得到损失值al与识别目标个数on
        for al, on in res:
            attack_loss += al
            object_nums += on
#更新min_object个数
        if min_object_num>object_nums:
            min_object_num = object_nums
            min_img = patch_img
#若该轮识别的object个数=0,停止迭代并设攻击成功            
        if object_nums==0:
            success_attack = True
            break
# 输出           
        print("t: {}, attack_loss:{}, object_nums:{}".format(t, attack_loss, object_nums))
    
#反向传播优化w权重    
        attack_loss.backward()
        #positions = get_patch_positions(w.grad, patch_size, patch_num)
        #mask = create_mask_by_positions(positions, patch_size)
        #optimizer.step()
        grads = grads + w.grad / (torch.abs(w.grad)).sum()
        #w = w - eps * w.grad.sign()
        w = w - eps * grads.sign()
        w = w.detach()
        w.requires_grad = True

    min_img = min_img.detach().cpu().numpy()
#    print(img_patch)
    if success_attack:
        sav=save_image_dir+"\\{}".format(img_path.split("\\")[-1])
        cv2.imwrite(sav, min_img)
    else: 
        cv2.imwrite(save_image_dir+"//{}_fail.png".format(img_path.split("\\")[-1].split(".")[0]), min_img)
    return success_attack

ch_size)
#optimizer.step()
grads = grads + w.grad / (torch.abs(w.grad)).sum()
#w = w - eps * w.grad.sign()
w = w - eps * grads.sign()
w = w.detach()
w.requires_grad = True

min_img = min_img.detach().cpu().numpy()

print(img_patch)

if success_attack:
    sav=save_image_dir+"\\{}".format(img_path.split("\\")[-1])
    cv2.imwrite(sav, min_img)
else: 
    cv2.imwrite(save_image_dir+"//{}_fail.png".format(img_path.split("\\")[-1].split(".")[0]), min_img)
return success_attack

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值