如何用DL4J对人脸识别模型进行攻击


如何用DL4J对人脸识别模型进行攻击,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。一、前言 下面就来介绍一下如何用DeepLearning4J对人脸识别模型进行FGSM攻击。主要包含两块内容。 1、MLAttack的基本原理。 2、结合天池人脸识别对抗比赛实例讲解攻击过程。二、机器学习模型的攻击 1、对ML攻击的过程对机器学习模型的攻击,一句话描述就是给input特征加入一些微小的噪声让模型识别错误,以图像识别为例。 上图展示的就是原图加上噪声之后,让猫被识别为了狗,这就是攻击的过程。 2、攻击的原理 我们来回想一下,机器学习模型大部分时候是在对Loss Function求极小值,攻击这个Loss函数即可,固定住模型参数,反过来求解一个特征X,让Loss Function值越大越好。 回想一下模型的训练过程,假设有一个图片x,模型的参数p,label为c1(假设c1表示猫的分类),我们定义一个损失函数:L = Loss(x,p,c1),其中x和c1都是固定的,通过调节参数p在训练集上求得L的最小值。 (1)、无目标攻击 无目标攻击就是没有定向目标,让模型分类错误即可,那么用公式描述为:argmax Loss(y,p,c1),在p和c1固定的情况下求得一个y,使得Loss函数最大。 例如,输入一张猫的图片,希望模型预测错误,无论模型预测为什么都可以,只要不是猫就行。 (2)、有目标攻击 有目标攻击是让模型将input识别为我们想要的对象,比方说,我们输入一张猫的图像,希望模型预测为狗的分类。设c2为狗的分类,那么用公式描述有目标攻击如下: argmin (-Loss(y,p,c1)+Loss(y,p,c2)) 在p、c1、c2固定的情况下,求解一个y使得上述函数最小,通俗一点就是说,输入一张猫的图片,希望模型预测为狗 备注:其中y表示原图x加上了噪声,c1表示猫的分类,c2表示狗的分类。 最后还有一个问题,加入噪声如果强度过大,原始图片就失真了,我们希望加入的杂讯很微小,不容易不察觉,我们需要做一个限定,定义函数d(x,y)

我们知道模型的结构,就可以进行攻击了,这个是白盒攻击,但是大部分时候,模型的结构我们无从得知,可以进行黑盒攻击。黑盒攻击就是攻击代理模型,比方说对vggnet的攻击在ResNet上同样管用。下面是一些数据,来证明黑盒攻击有用。(表格里的数字表示正确率)

三、FGSM攻击

论文地址:https://arxiv.org/abs/1412.6572

求解一个y =

四、天池人脸识别对抗

1、比赛地址:https://tianchi.aliyun.com/competition/entrance/231745/information

2、比赛评分规则:

为了保证扰动后人脸的视觉效果,本次比赛限制单个像素的扰动在[-25.5, 25.5]区间内,对于扰动超出该范围的提交结果,我们会在后台强制把图像扰动截断至[-25.5, 25.5]区间(使用numpy.clip函数)。所以请参赛选手控制提交的对抗样本与原图在单像素上的差异。

对每个生成的对抗样本,后台会采用模型对该样本进行预测,并根据识别结果计算相应的扰动量,具体计算公式如下:

其中M表示后台模型预测结果,y表示样本I的真实标签。如果防御算法对样本识别正确,此次攻击不成功,扰动量直接置为上限44.1673。该上限可由约束的最大扰动25.5计算得出。如果攻击成功,计算对抗样本I^a和原始样本I的L2距离,作为得分,得分越小越好。

一句话描述规则就是改动越小,攻击成功率越高,成绩越好。

五、DeepLearning4j进行FGSM攻击

1、解决dl4j对input求梯度问题

我们攻击的代理模型同样是VggFace(为什么一直都是选vggface,确实dl4j只有vggface,哎,也没有其他选择),ComputationGraph中梯度反向传播完成Gradient对象就被回收了 ,这样设计的目的就是为了节省内存。在MultiLayerNetwork中可以通过org.deeplearning4j.nn.multilayer.MultiLayerNetwork#calculateGradients求Loss对input的偏导数,但我们怎么拿的ComputationGraph中Loss对input的偏导数呢?不着急,我们在源码中找答案,我们细看源码org.deeplearning4j.nn.graph.ComputationGraph#calcBackpropGradients中反向传播做了什么?

try(MemoryWorkspacewsWorkingMem=workspaceMgr.notifyScopeEntered(ArrayType.BP_WORKING_MEM)){
pair=current.doBackward(truncatedBPTT,workspaceMgr);
epsilons=pair.getSecond();

//Validateworkspacelocationfortheactivationgradients:
//validateArrayWorkspaces(LayerWorkspaceMgrmgr,INDArrayarray,ArrayTypearrayType,StringvertexName,booleanisInputVertex,Stringop){
for(INDArrayepsilon:epsilons){
if(epsilon!=null){
//MaybenullforEmbeddingLayer,etc
validateArrayWorkspaces(workspaceMgr,epsilon,ArrayType.ACTIVATION_GRAD,vertexName,false,"Backprop");
}
}
}

跟进org.deeplearning4j.nn.graph.vertex.GraphVertex#doBackward方法

publicPairdoBackward(booleantbptt,LayerWorkspaceMgrworkspaceMgr){
if(!canDoBackward()){
if(inputs==null||inputs[0]==null){
thrownewIllegalStateException("Cannotdobackwardpass:inputsnotset.Layer:""+vertexName
+""(idx"+vertexIndex+"),numInputs:"+getNumInputArrays());
}else{
thrownewIllegalStateException("Cannotdobackwardpass:allepsilonsnotset.Layer""+vertexName
+""(idx"+vertexIndex+"),numInputs:"+getNumInputArrays()+";numOutputs:"
+getNumOutputConnections());
}
}

//Edgecase:outputlayer-neverdidforwardpasshencelayer.setInputwasnevercalled...
if(!setLayerInput){
applyPreprocessorAndSetInput(workspaceMgr);
}

Pairpair;
if(tbptt&&layerinstanceofRecurrentLayer){
//TruncatedBPTTforrecurrentlayers
pair=((RecurrentLayer)layer).tbpttBackpropGradient(epsilon,
graph.getConfiguration().getTbpttBackLength(),workspaceMgr);
}else{
//Normalbackprop
pair=layer.backpropGradient(epsilon,workspaceMgr);//epsTotalmaybenullforOutputLayers
}

if(layerPreProcessor!=null){
INDArrayeps=pair.getSecond();
eps=layerPreProcessor.backprop(eps,graph.batchSize(),workspaceMgr);
pair.setSecond(eps);
}

//Layersalwayshavesingleactivationsinput->alwayshavesingleepsilonoutputduringbackprop
returnnewPair(pair.getFirst(),newINDArray[]{pair.getSecond()});
}

里面有个org.deeplearning4j.nn.conf.InputPreProcessor#backprop将梯度回传给InputPreProcessor处理。于是我们就有思路了,我们只需要给第一层卷积层设置一个InputPreProcessor即可获取回传的梯度,注意LayerVertex的InputPreProcessor是final修饰的,那么怎么设置InputPreProcessor呢?这个难不倒Javaer,反射。

publicclassLayerVertexextendsBaseGraphVertex{

privateLayerlayer;
privatefinalInputPreProcessorlayerPreProcessor;
privatebooleansetLayerInput;

接下来先实现一个InputPreProcessor,把回传的梯度放在一个static变量里

publicclassPreprocessorimplementsInputPreProcessor{

	privatestaticfinallongserialVersionUID=1L;
	publicstaticINDArrayepsilon;

	@Override
	publicINDArraypreProcess(INDArrayinput,intminiBatchSize,LayerWorkspaceMgrworkspaceMgr){
		returnworkspaceMgr.dup(ArrayType.ACTIVATIONS,input);
	}

	@Override
	publicInputTypegetOutputType(InputTypeinputType){
		returninputType;
	}

	@Override
	publicPairfeedForwardMaskArray(INDArraymaskArray,MaskStatecurrentMaskState,
			intminibatchSize){
		returnnull;
	}

	@Override
	publicINDArraybackprop(INDArrayoutput,intminiBatchSize,LayerWorkspaceMgrworkspaceMgr){
		epsilon=output.detach();
		returnworkspaceMgr.dup(ArrayType.ACTIVATION_GRAD,output);
	}

	@Override
	publicInputPreProcessorclone(){
		//TODOAuto-gener 香港云主机atedmethodstub
		returnnull;
	}

}

接下来先dl4j transfer learning API加载vggface的模型,去掉全连接层,加上CnnLossLayer作为output,这里Loss函数用的COSINE_PROXIMITY(尝试过多种方法之后,发现cosine距离效果最好),然后反射给第一层卷积层加上InputPreProcessor,反射时调用Field的setAccessible(true)方法,开放private属性的访问权限(当然这是迫不得已的方法),请看下面代码。

ComputationGraphpretrained=(ComputationGraph)VGG16.builder().build().initPretrained(PretrainedType.VGGFACE);
		System.out.println(pretrained.summary());
		FineTuneConfigurationfineTuneConf=newFineTuneConfiguration.Builder().updater(newSgd(0)).seed(123).build();
		ComputationGraphvgg16Transfer=newTransferLearning.GraphBuilder(pretrained)
				.fineTuneConfiguration(fineTuneConf).removeVertexAndConnections("flatten")
				.removeVertexAndConnections("fc6").removeVertexAndConnections("fc7").removeVertexAndConnections("fc8")
				.addLayer("out",newCnnLossLayer.Builder(LossFunctions.LossFunction.COSINE_PROXIMITY)
						.activation(Activation.IDENTITY).build(),"pool5")
				.setOutputs("out").build();
		LayerVertexconv1_1=(LayerVertex)vgg16Transfer.getVertex("conv1_1");

		Class>clz=conv1_1.getClass();
		FieldnameField=clz.getDeclaredField("layerPreProcessor");
		nameField.setAccessible(true);
		nameField.set(conv1_1,newPreprocessor());

		System.out.println(vgg16Transfer.summary());

到此为止,Loss对input的偏导数就可以通过Preprocessor.epsilon获取到了,这个问题解决了,就可以进行攻击了。最终代理模型的结构如下:

================================================================================================
VertexName(VertexType)nIn,nOutTotalParamsParamsShapeVertexInputs
================================================================================================
input_1(InputVertex)-,----
conv1_1(ConvolutionLayer)3,641,792W:{64,3,3,3},b:{1,64}[input_1]
conv1_2(ConvolutionLayer)64,6436,928W:{64,64,3,3},b:{1,64}[conv1_1]
pool1(SubsamplingLayer)-,-0-[conv1_2]
conv2_1(ConvolutionLayer)64,12873,856W:{128,64,3,3},b:{1,128}[pool1]
conv2_2(ConvolutionLayer)128,128147,584W:{128,128,3,3},b:{1,128}[conv2_1]
pool2(SubsamplingLayer)-,-0-[conv2_2]
conv3_1(ConvolutionLayer)128,256295,168W:{256,128,3,3},b:{1,256}[pool2]
conv3_2(ConvolutionLayer)256,256590,080W:{256,256,3,3},b:{1,256}[conv3_1]
conv3_3(ConvolutionLayer)256,256590,080W:{256,256,3,3},b:{1,256}[conv3_2]
pool3(SubsamplingLayer)-,-0-[conv3_3]
conv4_1(ConvolutionLayer)256,5121,180,160W:{512,256,3,3},b:{1,512}[pool3]
conv4_2(ConvolutionLayer)512,5122,359,808W:{512,512,3,3},b:{1,512}[conv4_1]
conv4_3(ConvolutionLayer)512,5122,359,808W:{512,512,3,3},b:{1,512}[conv4_2]
pool4(SubsamplingLayer)-,-0-[conv4_3]
conv5_1(ConvolutionLayer)512,5122,359,808W:{512,512,3,3},b:{1,512}[pool4]
conv5_2(ConvolutionLayer)512,5122,359,808W:{512,512,3,3},b:{1,512}[conv5_1]
conv5_3(ConvolutionLayer)512,5122,359,808W:{512,512,3,3},b:{1,512}[conv5_2]
pool5(SubsamplingLayer)-,-0-[conv5_3]
out(CnnLossLayer)-,-0-[pool5]
------------------------------------------------------------------------------------------------
TotalParameters:14,714,688
TrainableParameters:14,714,688
FrozenParameters:0
================================================================================================

2、生成Label张量

下面把需要攻击的目标图片下载下来,我放在D盘了,目标图片如下。

下面用vggFace读取所有图片,把图片转化为张量,我们只需要获取最后一个池化层的输出就可以了。请看下面代码

NativeImageLoaderloader=newNativeImageLoader(224,224,3,newResizeImageTransform(224,224));
		Filefile=newFile("D:/securityAI_round1_images/images");
		ImageLoaderimageLoader=newImageLoader(112,112,3);
		Listlist=newArrayList();
		for(Filef:file.listFiles()){
			list.add(f);
		}

		MaplabelMap=newHashMap();
		for(inti=0;imap=vgg16Transfer.feedForward(image,false);
			labelMap.put(i,map.get("pool5"));
		}

3、无目标攻击

用第2步获取的张量作为label,用gradient ascent方法找到COSINE_PROXIMITY的极大值,COSINE_PROXIMITY的实现里将consine加了负号,所以是求cosine的最小值。换句话讲就是找到一张改动最小,且最不像自己的图片。代码如下

for(inti=0;i

说明:

(1)、目标图片为112*112的图片,经过尝试,先拓宽为224*224图片后再攻击,效果会提升。(推测dl4j vggface是用224*224的人脸进行训练,所以做了这个尝试)。

(2)、在label中随机加入微小的噪声,可以提升效果,这段代码就是这个原因labelMap.get(i).add(Nd4j.rand(new long[] { 1, 512, 7, 7 }, new NormalDistribution(0, 0.07)))。

(3)、在gradient ascent的过程中,同样加入动量作为更新因素效果会好一点,代码中的NesterovsUpdater就是实现这个功能。

(4)、代码中BooleanIndexing.replaceWhere是为了将图像的改动量限定在一个范围上,实际上是一个clip操作,却写了这么多代码,这一点确实不如Python方便。

(5)、为了进步提升分数,在更新图片时,最对嘴巴、眼睛、鼻子处进行变更,也能提升分数。

(6)、目标Loss Function为COSINE_PROXIMITY,之前也尝试过MSE和MAE效果不佳。

4、最终生成的攻击样本

关于如何用DL4J对人脸识别模型进行攻击问题的解答就分享到这里了,希望以上内容可以对大家有一定的帮助,如果你还有很多疑惑没有解开,可以关注开发云行业资讯频道了解更多相关知识。

我们知道模型的结构,就可以进行攻击了,这个是白盒攻击,但是大部分时候,模型的结构我们无从得知,可以进行黑盒攻击。黑盒攻击就是攻击代理模型,比方说对vggnet的攻击在ResNet上同样管用。下面是一些数据,来证明黑盒攻击有用。(表格里的数字表示正确率)三、FGSM攻击 论文地址:https://arxiv.org/abs/1412.6572 求解一个y =四、天池人脸识别对抗 1、比赛地址:https://tianchi.aliyun.com/competition/entrance/231745/information 2、比赛评分规则:为了保证扰动后人脸的视觉效果,本次比赛限制单个像素的扰动在[-25.5, 25.5]区间内,对于扰动超出该范围的提交结果,我们会在后台强制把图像扰动截断至[-25.5, 25.5]区间(使用numpy.clip函数)。所以请参赛选手控制提交的对抗样本与原图在单像素上的差异。对每个生成的对抗样本,后台会采用模型对该样本进行预测,并根据识别结果计算相应的扰动量,具体计算公式如下: 其中M表示后台模型预测结果,y表示样本I的真实标签。如果防御算法对样本识别正确,此次攻击不成功,扰动量直接置为上限44.1673。该上限可由约束的最大扰动25.5计算得出。如果攻击成功,计算对抗样本I^a和原始样本I的L2距离,作为得分,得分越小越好。 一句话描述规则就是改动越小,攻击成功率越高,成绩越好。五、DeepLearning4j进行FGSM攻击 1、解决dl4j对input求梯度问题 我们攻击的代理模型同样是VggFace(为什么一直都是选vggface,确实dl4j只有vggface,哎,也没有其他选择),ComputationGraph中梯度反向传播完成Gradient对象就被回收了 ,这样设计的目的就是为了节省内存。在MultiLayerNetwork中可以通过org.deeplearning4j.nn.multilayer.MultiLayerNetwork#calculateGradients求Loss对input的偏导数,但我们怎么拿的ComputationGraph中Loss对input的偏导数呢?不着急,我们在源码中找答案,我们细看源码org.deeplearning4j.nn.graph.ComputationGraph#calcBackpropGradients中反向传播做了什么? 跟进org.deeplearning4j.nn.graph.vertex.GraphVertex#doBackward方法 里面有个org.deeplearning4j.nn.conf.InputPreProcessor#backprop将梯度回传给InputPreProcessor处理。于是我们就有思路了,我们只需要给第一层卷积层设置一个InputPreProcessor即可获取回传的梯度,注意LayerVertex的InputPreProcessor是final修饰的,那么怎么设置InputPreProcessor呢?这个难不倒Javaer,反射。 接下来先实现一个InputPreProcessor,把回传的梯度放在一个static变量里 接下来先dl4j transfer learning API加载vggface的模型,去掉全连接层,加上CnnLossLayer作为output,这里Loss函数用的COSINE_PROXIMITY(尝试过多种方法之后,发现cosine距离效果最好),然后反射给第一层卷积层加上InputPreProcessor,反射时调用Field的setAccessible(true)方法,开放private属性的访问权限(当然这是迫不得已的方法),请看下面代码。 到此为止,Loss对input的偏导数就可以通过Preprocessor.epsilon获取到了,这个问题解决了,就可以进行攻击了。最终代理模型的结构如下: 2、生成Label张量 下面把需要攻击的目标图片下载下来,我放在D盘了,目标图片如下。 下面用vggFace读取所有图片,把图片转化为张量,我们只需要获取最后一个池化层的输出就可以了。请看下面代码 3、无目标攻击 用第2步获取的张量作为label,用gradient ascent方法找到COSINE_PROXIMITY的极大值,COSINE_PROXIMITY的实现里将consine加了负号,所以是求cosine的最小值。换句话讲就是找到一张改动最小,且最不像自己的图片。代码如下 说明: (1)、目标图片为112*112的图片,经过尝试,先拓宽为224*224图片后再攻击,效果会提升。(推测dl4j vggface是用224*224的人脸进行训练,所以做了这个尝试)。 (2)、在label中随机加入微小的噪声,可以提升效果,这段代码就是这个原因labelMap.get(i).add(Nd4j.rand(new long[] { 1, 512, 7, 7 }, new NormalDistribution(0, 0.07)))。 (3)、在gradient ascent的过程中,同样加入动量作为更新因素效果会好一点,代码中的NesterovsUpdater就是实现这个功能。 (4)、代码中BooleanIndexing.replaceWhere是为了将图像的改动量限定在一个范围上,实际上是一个clip操作,却写了这么多代码,这一点确实不如Python方便。 (5)、为了进步提升分数,在更新图片时,最对嘴巴、眼睛、鼻子处进行变更,也能提升分数。 (6)、目标Loss Function为COSINE_PROXIMITY,之前也尝试过MSE和MAE效果不佳。 4、最终生成的攻击样本关于如何用DL4J对人脸识别模型进行攻击问题的解答就分享到这里了,希望以上内容可以对大家有一定的帮助,如果你还有很多疑惑没有解开,可以关注开发云行业资讯频道了解更多相关知识。

相关推荐: 如何用nmap对系统版本和服务版本的探测

如何用nmap对系统版本和服务版本的探测,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。接下来是关于nmap渗透测试–版本探测正文: 如果到现在你还认为nmap只是一款端口扫描工具

免责声明:本站发布的图片视频文字,以转载和分享为主,文章观点不代表本站立场,本站不承担相关法律责任;如果涉及侵权请联系邮箱:360163164@qq.com举报,并提供相关证据,经查实将立刻删除涉嫌侵权内容。

Like (0)
Donate 微信扫一扫 微信扫一扫
Previous 10/06 13:40
Next 10/06 13:40

相关推荐