梯度上升matlab,使用梯度上升欺骗神经网络,让网络进行错误的分类

在本教程中,我将将展示如何使用梯度上升来解决如何对输入进行错误分类。

387fd6cb2ace4ff2c7f7dc49b71bae32.gif

出如何使用梯度上升改变一个输入分类

神经网络是一个黑盒。理解他们的决策需要创造力,但他们并不是那么不透明。

在本教程中,我将向您展示如何使用反向传播来更改输入,使其按照想要的方式进行分类。

人类的黑盒

首先让我们以人类为例。如果我向你展示以下输入:

c913b8251811fb1fcaa04323bb58b5da.png

很有可能你不知道这是5还是6。事实上,我相信我可以让你们相信这也可能是8。

现在,如果你问一个人,他们需要做什么才能把一个东西变成5,你可能会在视觉上做这样的事情:

927b23aa4efb13850245c4b2d108e99b.png

如果我想让你把这个变成8,你可以这样做:

8ae96b65ffb0b497d37a56a8c53cdb5b.png

现在,用几个if语句或查看几个系数不容易解释这个问题的答案。并且对于某些类型的输入(图像,声音,视频等),可解释性无疑会变得更加困难,但并非不可能。

神经网络怎么处理

一个神经网络如何回答我上面提出的同样的问题?要回答这个问题,我们可以用梯度上升来做。

这是神经网络认为我们需要修改输入使其更接近其他分类的方式。

3e98219dcdc31e45a30947425c374820.png

由此产生了两个有趣的结果。首先,黑色区域是我们需要去除像素密度的网络物体。第二,黄色区域是它认为我们需要增加像素密度的地方。

我们可以在这个梯度方向上采取一步,添加梯度到原始图像。当然,我们可以一遍又一遍地重复这个过程,最终将输入变为我们所希望的预测。

363e4d80f2a1c7217b762dd53065d921.png

你可以看到图片左下角的黑斑和人类的想法非常相似。

6f43c760b950a26ea2a6943e56591db4.png

让输入看起来更像8怎么样?这是网络认为你必须改变输入的方式。

6c4e2dc1073cf525e28be456882a8098.png

值得注意的是,在左下角有一团黑色的物质在中间有一团明亮的物质。如果我们把这个和输入相加,我们得到如下结果:

7824dc8abfac4061b45629ddbd7de487.png

在这种情况下,我并不特别相信我们已经将这个5变成了8。但是,我们减少了5的概率,说服你这个是8的论点肯定会更容易使用 右侧的图片,而不是左侧的图片。

梯度

在回归分析中,我们通过系数来了解我们所学到的知识。在随机森林中,我们可以观察决策节点。

在神经网络中,它归结为我们如何创造性地使用梯度。为了对这个数字进行分类,我们根据可能的预测生成了一个分布。

这就是我们说的前向传播

5d640ed0cad35fa55111c9e24abb80f0.gif

在前进过程中,我们计算输出的概率分布

代码类似这样:

e31d4c04450de04c9e69a818a46b1d6d.png

现在假设我们想要欺骗网络,让它预测输入x的值为“5”,实现这一点的方法是给它一个图像(x),计算对图像的预测,然后最大化预测标签“5”的概率。

为此,我们可以使用梯度上升来计算第6个索引处(即label = 5) (p)相对于输入x的预测的梯度。

8bf411391b3a212af6567c0e37b54748.png

为了在代码中做到这一点,我们将输入x作为参数输入到神经网络,选择第6个预测(因为我们有标签:0,1,2,3,4,5,…),第6个索引意味着标签“5”。

视觉上这看起来像:

387fd6cb2ace4ff2c7f7dc49b71bae32.gif

代码如下:

29d982f388e80b3d35c68044c4f1bcd6.png

当我们调用.backward()时,所发生的过程可以通过前面的动画可视化。

现在我们计算了梯度,我们可以可视化并绘制它们:

8c37f67a37268c7d9bd7fa3c92e0fcbe.png

7cbdfe4d0220a750f42cbe3259f36642.png

由于网络还没有经过训练,所以上面的梯度看起来像随机噪声……但是,一旦我们对网络进行训练,梯度的信息会更丰富:

245a421077a9902b9852d690a763d106.png

通过回调实现自动化

这是一个非常有用的工具,帮助阐明在你的网络训练中发生了什么。在这种情况下,我们想要自动化这个过程,这样它就会在训练中自动发生。

为此,我们将使用PyTorch Lightning来实现我们的神经网络:

import torch

import torch.nn.functional as F

import pytorch_lightning as pl

class LitClassifier(pl.LightningModule):

def __init__(self):

super().__init__()

self.l1 = torch.nn.Linear(28 * 28, 10)

def forward(self, x):

return torch.relu(self.l1(x.view(x.size(0), -1)))

def training_step(self, batch, batch_idx):

x, y = batch

y_hat = self(x)

loss = F.cross_entropy(y_hat, y)

result = pl.TrainResult(loss)

# enable the auto confused logit callback

self.last_batch = batch

self.last_logits = y_hat.detach()

result.log('train_loss', loss, on_epoch=True)

return result

def validation_step(self, batch, batch_idx):

x, y = batch

y_hat = self(x)

loss = F.cross_entropy(y_hat, y)

result = pl.EvalResult(checkpoint_on=loss)

result.log('val_loss', loss)

return result

def configure_optimizers(self):

return torch.optim.Adam(self.parameters(), lr=0.005)

可以将自动绘制出此处描述内容的复杂代码,抽象为Lightning中的Callback。Callback回调是一个小程序,您可能会在训练的各个部分调用它。

在本例中,当处理训练批处理时,我们希望生成这些图像,以防某些输入出现混乱。。

import torch

from pytorch_lightning import Callback

from torch import nn

class ConfusedLogitCallback(Callback):

def __init__(

self,

top_k,

projection_factor=3,

min_logit_value=5.0,

logging_batch_interval=20,

max_logit_difference=0.1

):

super().__init__()

self.top_k = top_k

self.projection_factor = projection_factor

self.max_logit_difference = max_logit_difference

self.logging_batch_interval = logging_batch_interval

self.min_logit_value = min_logit_value

def on_train_batch_end(self, trainer, pl_module, batch, batch_idx, dataloader_idx):

# show images only every 20 batches

if (trainer.batch_idx + 1) % self.logging_batch_interval != 0:

return

# pick the last batch and logits

x, y = batch

try:

logits = pl_module.last_logits

except AttributeError as e:

m = """please track the last_logits in the training_step like so:

def training_step(...):

self.last_logits = your_logits

"""

raise AttributeError(m)

# only check when it has opinions (ie: the logit > 5)

if logits.max() > self.min_logit_value:

# pick the top two confused probs

(values, idxs) = torch.topk(logits, k=2, dim=1)

# care about only the ones that are at most eps close to each other

eps = self.max_logit_difference

mask = (values[:, 0] - values[:, 1]).abs() < eps

if mask.sum() > 0:

# pull out the ones we care about

confusing_x = x[mask, ...]

confusing_y = y[mask]

mask_idxs = idxs[mask]

pl_module.eval()

self._plot(confusing_x, confusing_y, trainer, pl_module, mask_idxs)

pl_module.train()

def _plot(self, confusing_x, confusing_y, trainer, model, mask_idxs):

from matplotlib import pyplot as plt

confusing_x = confusing_x[:self.top_k]

confusing_y = confusing_y[:self.top_k]

x_param_a = nn.Parameter(confusing_x)

x_param_b = nn.Parameter(confusing_x)

batch_size, c, w, h = confusing_x.size()

for logit_i, x_param in enumerate((x_param_a, x_param_b)):

x_param = x_param.to(model.device)

logits = model(x_param.view(batch_size, -1))

logits[:, mask_idxs[:, logit_i]].sum().backward()

# reshape grads

grad_a = x_param_a.grad.view(batch_size, w, h)

grad_b = x_param_b.grad.view(batch_size, w, h)

for img_i in range(len(confusing_x)):

x = confusing_x[img_i].squeeze(0).cpu()

y = confusing_y[img_i].cpu()

ga = grad_a[img_i].cpu()

gb = grad_b[img_i].cpu()

mask_idx = mask_idxs[img_i].cpu()

fig, axarr = plt.subplots(nrows=2, ncols=3, figsize=(15, 10))

self.__draw_sample(fig, axarr, 0, 0, x, f'True: {y}')

self.__draw_sample(fig, axarr, 0, 1, ga, f'd{mask_idx[0]}-logit/dx')

self.__draw_sample(fig, axarr, 0, 2, gb, f'd{mask_idx[1]}-logit/dx')

self.__draw_sample(fig, axarr, 1, 1, ga * 2 + x, f'd{mask_idx[0]}-logit/dx')

self.__draw_sample(fig, axarr, 1, 2, gb * 2 + x, f'd{mask_idx[1]}-logit/dx')

trainer.logger.experiment.add_figure('confusing_imgs', fig, global_step=trainer.global_step)

@staticmethod

def __draw_sample(fig, axarr, row_idx, col_idx, img, title):

im = axarr[row_idx, col_idx].imshow(img)

fig.colorbar(im, ax=axarr[row_idx, col_idx])

axarr[row_idx, col_idx].set_title(title, fontsize=20)

但是,通过安装pytorch-lightning-bolts,我们让它变得更容易了

!pip install pytorch-lightning-bolts

from pl_bolts.callbacks.vision import ConfusedLogitCallback

trainer = Trainer(callbacks=[ConfusedLogitCallback(1)])

把它们放在一起

最后,我们可以训练我们的模型,并在判断逻辑产生混乱时自动生成图像。

# data

dataset = MNIST(os.getcwd(), download=True, transform=transforms.ToTensor())

train, val = random_split(dataset, [55000, 5000])

# model

model = LitClassifier()

# attach callback

trainer = Trainer(callbacks=[ConfusedLogitCallback(1)])

# train!

trainer.fit(model, DataLoader(train, batch_size=64), DataLoader(val, batch_size=64))

tensorboard会自动生成如下图片:

0e250d7ba595c0812c9e0c822b02efb4.png

f2fba9fda54bd546d6ed356b7a5cb5f4.png

看看这个是不是变得不一样了

3aeab2389422d34dacfb77a5fbe052da.png

作者:William Falcon

完整代码:https://colab.research.google.com/drive/16HVAJHdCkyj7W43Q3ZChnxZ7DOwx6K5i?usp=sharing

deephub翻译组

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值