通常来说,智慧交通行业主要是对交通场景内的行人,机动车,非机动车进行识别分析。
行人识别分析包括对行人的姿态,方向,外观,以及基于行人的交通事件识别分析,(行人闯红灯等)。
机动车识别分析包括对机动车的外型,颜色,车灯,车窗,驾驶员安全事件分析(是否在打电话,是否系安全带等),车牌,车辆方向以及基于机动车的交通事件识别分析(超速检测,违停判定等)。
非机动车识别分析包括对非机动车的细分类别识别,运动状态识别,驾驶员安全事件分析(是否戴头盔等),以及基于非机动车的交通事件识别分析(非机动车闯红灯等)。
在智慧交通场景中,目标检测是AI项目里的前置任务。车辆识别,车辆属性识别,交通事件判定,交通执法判定,行人识别等智慧交通中的复合任务,都需要对感兴趣目标区域进行检测提取后才能接着进行后续的算法流程。然而,就在这些复合任务的流程中,可能会存在AI安全的风险。比如以本次训练营要讲的对抗攻击和对抗防御为例,对抗攻击能够让AI模型产生误判,从而可能引发严重的安全风险。
在对交通指示牌进行对抗攻击,主要有三种类似风格迁移的攻击模式,使得自动驾驶系统对STOP交通指示牌出现了误判,而每一种误判都可能引发严重的交通连锁后果。而智慧交通中的摄像头设备,也会接收此类对抗样本并将其作为后续算法功能的输入,从而导致算法解决方案中的某一环失效。
比如使用对抗贴纸让行人检测模型失效,在人体前放置一个对抗攻击算法特定生成的图画,便能对行人检测模型的性能产生较大的影响,无法对行人做出准确的检测。而当智慧交通中的摄像头设备,接收此类对抗样本并将其作为后续算法功能的输入,可能会导致包含行人检测的算法解决方案出现不确定风险。
车辆检测主要选用了Kaggle开源的车辆数据集,其网址是:https://www.kaggle.com/datasets/sshika
maru/car-object-detection
数据集中总共包含了三个方面的内容:1001张的训练数据集,175张的测试数据集,以及一个标签csv
文件。这个数据集是一个典型的小量级数据,这在实际项目中非常常见。
如果自己的电脑有可以使用的GPU,那么就可以直接使用车辆数据集来训练YOLOv5模型。如果没有GPU,则推荐
对抗攻击(adversarial attack)是AI安全方向的重要分支,其核心逻辑是在数据中增加一些微小扰动,在人类视觉系统无法察觉的情况下,使得算法模型对这些数据产生误判。其中被增加扰动的数据也称为对抗样本。
下面是一些直观的通过增加对抗噪声来让算法模型误判的例子:
在上图的熊猫图片中加入微小的对抗噪声,就能让AI模型将其误判为长臂猿。
我们该怎么去理解对抗样本呢?总的来说,我把它当作生成噪声的艺术,其攻击价值的底层依托是算法模型的过拟合问题。
在智慧交通场景中,由于通常来说场景多样复杂(卡口,出入口,十字路口,停车场等),环境多样复杂(白天,夜晚,雨天,大雾天,反光等),场景目标复杂多样(机动车种类多,非机动车种类多,行人流量大,交通事件种类繁杂等),让对抗攻击有了很广泛的应用价值。
对于攻击者来说,上述场景,环境,场景目标都可能是其攻击对象,这些在前三节课中都已经涉及, 这里就不再展开。
对于防御者来说,对抗攻击作为AI安全方向中的一个分支,其能让算法解决方案提供方对攻击者知己 知彼,促进算法模型去提升其鲁棒性与防御性。
接下来,我们讲讲对于防御者,该如何应用对抗攻击技术。
对抗攻击技术可以作为智慧交通AI业务的鲁棒性与安全性检查工具,用于算法解决方案的测试短,对算法解决方案可能存在的安全风险,早发现,早解决,早完善。
通过研究对抗攻击,来增强对实际场景中受到的攻击种类与情形的判断力,从而能够更好的设计相应 的对抗防御方法。
使用对抗攻击对敏感信息进行隐藏,比如在交通场景的敏感数据进行对抗攻击,防止数据被非法分子 破解和利用。
再比如对抗攻击与验证码相结合,对原始验证码有针对性的加入干扰,使得人眼识别不受影响,但会
显著降低人工智能模型的识别率,从而防范打码平台的破解,同时保持用户体验。 而防御者最直接了当的使用对抗攻击的形式是对抗训练。
使用对抗样本在模型训练过程中进行对抗训练,我们在训练时将对抗样本加入训练集一起训练,即为 对抗训练。
进行对抗训练能扩充训练集的可能性,使得数据集逼近我们想要的数据分布,训练后的模型鲁棒性和 泛化性能也大大增强。
其中,当算法模型参数和训练数据等信息被攻击者所掌握,
并且攻击者在此基础上进行的针对性攻击称为白盒攻击
。白盒攻击主要分为基于梯度的攻击,基于优化的攻击以及基于GAN的攻击。
而在对算法模型的结构和参数一无所知,甚至相关训练数据也一无所知的情况下,进行攻击的过程称为黑盒攻击。
黑盒攻击主要分为基于迁移的攻击和基于查询的攻击两大类。
基于迁移的攻击逻辑由白盒攻击延伸而来,一般会有一个白盒模型作为替身模型(surrogate)进行攻击,而生成的对抗样本一般也会对其他模型有一定的迁移攻击性。
基于查询的攻击其主要是通过查询黑盒模型的输出信息,对黑盒模型进行直接的攻击,但完成整个攻击流程往往需要大量的查询,容易被模型所有者检测到异常。
import torch.nn as nn
from torchvision.models import mobilenet_v2
from advertorch.attacks import LinfPGDAttack
from advertorch_examples.utils import bhwc2bchw
from skimage.io import imread
device = "cuda" if torch.cuda.is_available() else "cpu"
### 常规模型加载
model = mobilenet_v2(pretrained=True)
model.eval()
model = nn.Sequential(normalize, model)
model = model.to(device)
### 数据预处理
np_img = imread(img_path) / 255.
img = torch.tensor(bhwc2bchw(np_img))[None, :, :, :].float().to(device)
imagenet_label2classname = ImageNetClassNameLookup()
### 测试模型输出结果
pred = imagenet_label2classname(predict_from_logits(model(img)))
print("test output:", pred)
### 输出原label
pred_label = predict_from_logits(model(img))
print("===", pred_label)
### 对抗攻击:PGD攻击算法
adversary = LinfPGDAttack(
model, eps=8 / 255, eps_iter=2 / 255, nb_iter=80,
rand_init=True)
### 完成攻击,输出对抗样本
advimg = adversary.perturb(img, pred_label)
在对抗攻击技术出现之后,对抗防御技术也孕育而生。对抗防御一般针对对抗攻击技术而展开,有针对特定攻击的特定防御,也有一般性防御策略,下面我们就一起学习一下。
在智慧交通场景中,常用的对抗防御方法有与对抗攻击结合紧密的AI业务的鲁棒性与安全性检查工具;研究对抗攻击,来增强对实际场景中受到的攻击情形的判断力;使用对抗攻击对敏感信息进行隐藏;使用对抗样本在模型训练过程中进行对抗训练。当然的,除了上面讲到的与对抗攻击结合的形式,还包括在算法解决方案中加入防御预处理,设计鲁棒模型结构,加入对抗攻击检测模型等方法。
由于智慧交通场景的算法解决方案对耗时和内存占用有较高的要求,所以防御预处理与防御后处理作为常规防御的首要选择。同时,针对可能存在的安全风险,在开发阶段,设计鲁棒性的模型结构,提升算法解决方案的整体安全性。或者训练轻量级的对抗攻击检测模型,作为算法解决方案的安全模块,在受到攻击风险时,启动防御算法功能。
具体来说,我们需要生成一些对抗样本,并将其和干净样本一同作为训练集,训练一个能够捕捉对抗扰动的二分类模型,并将其作为实际AI项目中的一个前置防御模块。
其中
对抗训练是指在训练过程中加入对抗样本
,通过不断的学习对抗样本的特征,从而提升模型的鲁棒性。
监测识别对抗样本顾名思义,在项目关键节点处,设置一些能够识别对抗样本的特种模型,从而提前预警对抗攻击风险。
模型鲁棒结构设计
是指在模型中设计特定的滤波结构能够一定程度上增强模型鲁棒性,抵御对抗噪声。
对抗扰动结构破坏
主要在数据流处理的时候使用,通过一些滤波算法,噪声结构破坏算法,噪声覆盖算法等策略,减弱对抗噪声的影响,使其不能对模型造成攻击。
梯度掩膜
则是在白盒对抗防御中非常高效的一种算法,因为其能掩盖真实梯度,从而能够使得白盒攻击算法失效。本次实战中使用到的对抗防御方法主要是基于梯度掩膜的GCM模块。
抗防御方法主要是基于梯度掩膜的GCM模块。分类模型采用Mobilenet_v2(Pytorch已经训练好的预训练模型)
import torch
import torch.nn as nn
from torchvision.models import mobilenet_v2
from robust_layer import GradientConcealment
from advertorch.attacks import LinfPGDAttack
from skimage.io import imread
device = "cuda" if torch.cuda.is_available() else "cpu"
normalize = NormalizeByChannelMeanStd(
mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
### GCM模块
robust_mode = GradientConcealment()
### 常规模型+GCM模块
class Model(nn.Module):
def __init__(self, l=290):
super(Model, self).__init__()
self.l = l
self.gcm = GradientConcealment()
model = mobilenet_v2(pretrained=True)
normalize = NormalizeByChannelMeanStd(
mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
self.model = nn.Sequential(normalize, model)
def load_params(self):
pass
def forward(self, x):
x = self.gcm(x)
# x = ResizedPaddingLayer(self.l)(x)
out = self.model(x)
return out
### 常规模型+GCM模块 加载
model_defense = Model().eval().to(device)
### 数据预处理
np_img = imread(img_path) / 255.
img = torch.tensor(bhwc2bchw(np_img))[None, :, :, :].float().to(device)
imagenet_label2classname = ImageNetClassNameLookup()
### 测试模型输出结果
pred_defense = imagenet_label2classname(predict_from_logits(model_defense(img)))
print("test output:", pred_defense)
pre_label = predict_from_logits(model_defense(img))
### 对抗攻击:PGD攻击算法
adversary = LinfPGDAttack(
model_defense, eps=8 / 255, eps_iter=2 / 255, nb_iter=80,
rand_init=True, targeted=False)
### 完成攻击,输出对抗样本
advimg = adversary.perturb(img, pre_label)
可以看到,模型并未受到对抗攻击的影响,还是输出了正确的结果。
将使用防御模块后生成的对抗扰动与未使用防御模块的对抗扰动进行对比,我们可以发现,防御模块确实起到了应有的防御作用:
一般在实际场景的AI项目中,当对抗攻击监测模型,监测到对抗样本或者对抗攻击后,会出现一个告警弹窗,并且会告知安全人员及时进行安全排查。这里通过微信“喵提醒”的方式模拟现实场景(具体“喵提醒”使用在此不做赘述)。实现代码如下:
import os
import torch
import requests
import time
import torch.nn as nn
from torchvision.models import mobilenet_v2,resnet18
from advertorch.utils import predict_from_logits
from advertorch.utils import NormalizeByChannelMeanStd
from robust_layer import GradientConcealment, ResizedPaddingLayer
from timm.models import create_model
from advertorch.attacks import LinfPGDAttack
from advertorch_examples.utils import ImageNetClassNameLookup
from advertorch_examples.utils import bhwc2bchw
from advertorch_examples.utils import bchw2bhwc
device = "cuda" if torch.cuda.is_available() else "cpu"
### 读取图片
def get_image():
# img_path = os.path.join("/home/Lesson5_code/adv_code/adv_results", "adv_image.png")
img_path = os.path.join("/home/Lesson5_code/adv_code/orig_images", "vid_5_26660.jpg_0.jpg")
img_url = "https://farm1.static.flickr.com/230/524562325_fb0a11d1e1.jpg"
def _load_image():
from skimage.io import imread
return imread(img_path) / 255.
if os.path.exists(img_path):
return _load_image()
else:
import urllib
urllib.request.urlretrieve(img_url, img_path)
return _load_image()
def tensor2npimg(tensor):
return bchw2bhwc(tensor[0].cpu().numpy())
normalize = NormalizeByChannelMeanStd(
mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
np_img = get_image()
img = torch.tensor(bhwc2bchw(np_img))[None, :, :, :].float().to(device)
imagenet_label2classname = ImageNetClassNameLookup()
### 常规模型加载
class Model(nn.Module):
def __init__(self, l=290):
super(Model, self).__init__()
self.l = l
self.gcm = GradientConcealment()
#model = resnet18(pretrained=True)
model = mobilenet_v2(pretrained=True)
# pth_path = "/Users/rocky/Desktop/训练营/model/mobilenet_v2-b0353104.pth"
# print(f'Loading pth from {pth_path}')
# state_dict = torch.load(pth_path, map_location='cpu')
# is_strict = False
# if 'model' in state_dict.keys():
# model.load_state_dict(state_dict['model'], strict=is_strict)
# else:
# model.load_state_dict(state_dict, strict=is_strict)
normalize = NormalizeByChannelMeanStd(
mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
self.model = nn.Sequential(normalize, model)
def load_params(self):
pass
def forward(self, x):
#x = self.gcm(x)
#x = ResizedPaddingLayer(self.l)(x)
out = self.model(x)
return out
### 对抗攻击监测模型
class Detect_Model(nn.Module):
def __init__(self, num_classes=2):
super(Detect_Model, self).__init__()
self.num_classes = num_classes
#model = create_model('mobilenetv3_large_075', pretrained=False, num_classes=num_classes)
model = create_model('resnet50', pretrained=False, num_classes=num_classes)
# self.multi_PreProcess = multi_PreProcess()
pth_path = os.path.join("/home/Lesson5_code/model", 'track2_resnet50_ANT_best_albation1_64_checkpoint.pth')
#pth_path = os.path.join("/Users/rocky/Desktop/训练营/Lesson5_code/model/", "track2_tf_mobilenetv3_large_075_64_checkpoint.pth")
state_dict = torch.load(pth_path, map_location='cpu')
is_strict = False
if 'model' in state_dict.keys():
model.load_state_dict(state_dict['model'], strict=is_strict)
else:
model.load_state_dict(state_dict, strict=is_strict)
normalize = NormalizeByChannelMeanStd(
mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
# self.model = nn.Sequential(normalize, self.multi_PreProcess, model)
self.model = nn.Sequential(normalize, model)
def load_params(self):
pass
def forward(self, x):
# x = x[:,:,32:193,32:193]
# x = F.interpolate(x, size=(224,224), mode="bilinear", align_corners=True)
# x = self.multi_PreProcess.forward(x)
out = self.model(x)
if self.num_classes == 2:
out = out.softmax(1)
print("out的结果",out)
#return out[:,1:]
return out[:,1:]
model = Model().eval().to(device)
detect_model = Detect_Model().eval().to(device)
### 对抗攻击监测
detect_pred = detect_model(img)
print(detect_pred)
if detect_pred > 0.5:
id = 'tTCWvf5'
# 填写喵提醒中,发送的消息,这里放上前面提到的图片外链
text = "出现对抗攻击风险!!"
ts = str(time.time()) # 时间戳
type = 'json' # 返回内容格式
request_url = "http://miaotixing.com/trigger?"
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.67 Safari/537.36 Edg/87.0.664.47'}
result = requests.post(request_url + "id=" + id + "&text=" + text + "&ts=" + ts + "&type=" + type,
headers=headers)
else:
pred = imagenet_label2classname(predict_from_logits(model(img)))
print("预测结果", pred)
将车辆检测+检测框提取+使用对抗样本+AI安全监测与告警功能串联,运行app_main.py ,根据输入判断是否进行攻击,并进行后续操作,当发现对抗样本风险存在时,通过“喵提醒”进行报警。
import cv2
import os
import torch
import requests
import time
import torch.nn as nn
import copy
# aidlux相关的库
from cvs import *
import aidlite_gpu
from detect_adv_code import Model, Detect_Model
from utils1 import detect_postprocess, preprocess_img, draw_detect_res, extract_detect_res
# 对抗攻击相关的库
from torchvision.models import mobilenet_v2,resnet18
from advertorch.utils import predict_from_logits
from advertorch.utils import NormalizeByChannelMeanStd
from robust_layer import GradientConcealment, ResizedPaddingLayer
from timm.models import create_model
from advertorch_examples.utils import ImageNetClassNameLookup
from advertorch_examples.utils import bhwc2bchw
from advertorch_examples.utils import bchw2bhwc
from advertorch.attacks import LinfPGDAttack, LinfPGDAttack
device = "cuda" if torch.cuda.is_available() else "cpu"
normalize = NormalizeByChannelMeanStd(
mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
imagenet_label2classname = ImageNetClassNameLookup()
### 常规模型加载
model = mobilenet_v2(pretrained=True)
model.eval()
model = nn.Sequential(normalize, model)
model = model.to(device)
### 替身模型加载
model_su = resnet18(pretrained=True)
model_su.eval()
model_su = nn.Sequential(normalize, model_su)
model_su = model_su.to(device)
model_detect = Model().eval().to(device)
model_detect_attack = Detect_Model().eval().to(device)
### 对抗攻击
def attackModel(model, model_su, in_img):
### 数据预处理
np_img = in_img[:,:,::-1] / 255.0
img = torch.tensor(bhwc2bchw(np_img))[None, :, :, :].float().to(device)
imagenet_label2classname = ImageNetClassNameLookup()
### 测试模型输出结果
pred = imagenet_label2classname(predict_from_logits(model(img)))
print("test output:", pred)
### 输出原label
pred_label = predict_from_logits(model_su(img))
### 对抗攻击:PGD攻击算法
adversary = LinfPGDAttack(
model_su, eps=8/255, eps_iter=2/255, nb_iter=80,
rand_init=True, targeted=False)
### 完成攻击,输出对抗样本
advimg = adversary.perturb(img, pred_label)
return advimg
###推理截取图片部分
# AidLite初始化:调用AidLite进行AI模型的加载与推理,需导入aidlite
aidlite = aidlite_gpu.aidlite()
# Aidlite模型路径
model_path = '/home/Lesson5_code/yolov5_code/aidlux/yolov5_car_best-fp16.tflite'
# 定义输入输出shape
in_shape = [1 * 640 * 640 * 3 * 4]
out_shape = [1 * 25200 * 6 * 4]
# 加载Aidlite检测模型:支持tflite, tnn, mnn, ms, nb格式的模型加载
aidlite.ANNModel(model_path, in_shape, out_shape, 4, 0)
# 读取图片进行推理
# 设置测试集路径
source = "/home/Lesson5_code/adv_code/test_images"
images_list = os.listdir(source)
# print("images_list:", images_list)
frame_id = 0
Attack_flag = 1 #判断是否进行攻击
# 读取数据集
for image_name in images_list[:1]:
frame_id += 1
print("frame_id:", frame_id)
image_path = os.path.join(source, image_name)
frame = cvs.imread(image_path)
# 预处理
img = preprocess_img(frame, target_shape=(640, 640), div_num=255, means=None, stds=None)
# 数据转换:因为setTensor_Fp32()需要的是float32类型的数据,所以送入的input的数据需为float32,大多数的开发者都会忘记将图像的数据类型转换为float32
aidlite.setInput_Float32(img, 640, 640)
# 模型推理API
aidlite.invoke()
# 读取返回的结果
pred = aidlite.getOutput_Float32(0)
# 数据维度转换
pred = pred.reshape(1, 25200, 6)[0]
# 模型推理后处理
pred = detect_postprocess(pred, frame.shape, [640, 640, 3], conf_thres=0.25, iou_thres=0.45)
# print("pred:", pred)
all_boxes = pred[0]
frame = frame.astype(np.uint8)
if len(all_boxes) > 0:
for box in all_boxes:
x, y, w, h = [int(t) for t in box[:4]]
cut_img = frame[y:(y + h), x:(x + w)]
if Attack_flag == 1:
advimg = attackModel(model, model_su, cut_img)
# print("advimg:", type(advimg), advimg.shape)
else:
cut_img = copy.deepcopy(cut_img[:,:,::-1] / 255)
advimg = torch.tensor(bhwc2bchw(cut_img))[None, :, :, :].float().to(device)
### 无对抗攻击监测模型
# detect_pred = model_detect(advimg)
## 对抗攻击监测
detect_pred = model_detect_attack(advimg)
# print("detcet_pred:", detect_pred)
if detect_pred > 0.5:
id = 'tTCWvf5'
# 填写喵提醒中,发送的消息,这里放上前面提到的图片外链
text = "出现对抗攻击风险!!"
ts = str(time.time()) # 时间戳
type = 'json' # 返回内容格式
request_url = "http://miaotixing.com/trigger?"
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.67 Safari/537.36 Edg/87.0.664.47'}
result = requests.post(request_url + "id=" + id + "&text=" + text + "&ts=" + ts + "&type=" + type,
headers=headers)
print(text)
print("对抗样本:", image_name)
else:
pred = imagenet_label2classname(predict_from_logits(model(advimg)))
# print("pred:", pred)
本次项目实战来源于AidLux智慧交通AI安全实战训练营,通过本次训练营学习对智慧交通中AI算法应用有了一定的了解。此外,初次接触到了AI对抗攻击和AI防御的知识。课程中,通过代码实践和在Aidlux端的部署实践,实现了车辆检测和安全风险防御预警。
采用Aidlux实现对抗检测视频演示