提交 e9c1289b 编写于 作者: W wizardforcel

2021-01-19 11:31:09

上级 0bd36462
......@@ -46,7 +46,7 @@ import matplotlib.pyplot as plt
本教程只有三个输入,定义如下:
* `epsilons`-用于运行的`ε`值列表。 在列表中保留 0 很重要,因为它表示原始测试集上的模型性能。 同样,从直觉上讲,我们期望`ε`越大,扰动越明显,但是从降低模型准确率的角度来看,攻击越有效。 由于此处的数据范围为\([0,1] \),因此`ε`值不得超过 1。
* `epsilons`-用于运行的`ε`值列表。 在列表中保留 0 很重要,因为它表示原始测试集上的模型性能。 同样,从直觉上讲,我们期望`ε`越大,扰动越明显,但是从降低模型准确率的角度来看,攻击越有效。 由于此处的数据范围为`[0,1]`,因此`ε`值不得超过 1。
* `pretrained_model`-到使用 [pytorch / examples / mnist](https://github.com/pytorch/examples/tree/master/mnist) 训练的 MNIST 模型的路径。 为简单起见,请在此处下载预训练模型[](https://drive.google.com/drive/folders/1fn83DF14tWmit0RTKWRhPq5uVXt73e0h?usp=sharing)
* `use_cuda`-布尔标志,如果需要和可用,则使用 CUDA。 请注意,具有 CUDA 的 GPU 在本教程中并不重要,因为 CPU 不会花费很多时间。
......@@ -122,7 +122,7 @@ CUDA Available: True
### FGSM 攻击
现在,我们可以通过干扰原始输入来定义创建对抗示例的函数。 `fgsm_attack`函数接受三个输入,`image`是原始的干净图像(`x`),`epsilon`是像素级扰动量\(\ epsilon \)`data_grad`是输入图像损失的梯度(\(\ nabla_ {x} J(\ mathbf {\ theta},\ mathbf {x},y)\))。 该函数然后创建扰动图像为
现在,我们可以通过干扰原始输入来定义创建对抗示例的函数。 `fgsm_attack`函数接受三个输入,`image`是原始的干净图像(`x`),`epsilon`是像素级扰动量`ε``data_grad`是输入图像损失的梯度(\(\ nabla_ {x} J(\ mathbf {\ theta},\ mathbf {x},y)\))。 该函数然后创建扰动图像为
\[perturbed\_image = image + epsilon*sign(data\_grad) = x + \epsilon * sign(\nabla_{x} J(\mathbf{\theta}, \mathbf{x}, y))\]
......@@ -144,7 +144,7 @@ def fgsm_attack(image, epsilon, data_grad):
### 测试功能
最后,本教程的主要结果来自`test`函数。 每次调用此测试功能都会在 MNIST 测试集上执行完整的测试步骤,并报告最终精度。 但是,请注意,此功能还需要`epsilon`输入。 这是因为`test`函数报告实力为`ε`的来自对手的攻击模型的准确率。 更具体地说,对于测试集中的每个样本,函数都会计算输入数据\(data \ _grad \))的损耗梯度,并使用`fgsm_attack`创建一个扰动图像(\(perturbed \ _data \)) ,然后检查受干扰的示例是否具有对抗性。 除了测试模型的准确率外,该功能还保存并返回了一些成功的对抗示例,以供以后可视化。
最后,本教程的主要结果来自`test`函数。 每次调用此测试功能都会在 MNIST 测试集上执行完整的测试步骤,并报告最终精度。 但是,请注意,此功能还需要`epsilon`输入。 这是因为`test`函数报告实力为`ε`的来自对手的攻击模型的准确率。 更具体地说,对于测试集中的每个样本,函数都会计算输入数据`data_grad`的损耗梯度,并使用`fgsm_attack`创建一个扰动图像`perturbed_data`,然后检查受干扰的示例是否具有对抗性。 除了测试模型的准确率外,该功能还保存并返回了一些成功的对抗示例,以供以后可视化。
```py
def test( model, device, test_loader, epsilon ):
......
......@@ -16,13 +16,13 @@ GAN 是用于教授 DL 模型以捕获训练数据分布的框架,因此我们
现在,让我们从鉴别符开始定义一些在整个教程中使用的符号。 令`x`为代表图像的数据。 `D(x)`是判别器网络,其输出`x`来自训练数据而不是生成器的(标量)概率。 在这里,由于我们要处理图像,因此`D(x)`的输入是 CHW 大小为 3x64x64 的图像。 直观地,当`x`来自训练数据时,`D(x)`应该为高,而当`x`来自发生器时,它应该为低。 `D(x)`也可以被认为是传统的二分类器。
对于生成器的表示法,令`z`是从标准正态分布中采样的潜在空间向量。 `G(z)`表示将隐向量`z`映射到数据空间的生成器函数。 `G`的目标是估计训练数据来自\(p_ {data} \)的分布,以便它可以从该估计分布(`p_g`)生成假样本。
对于生成器的表示法,令`z`是从标准正态分布中采样的潜在空间向量。 `G(z)`表示将隐向量`z`映射到数据空间的生成器函数。 `G`的目标是估计训练数据来自`p_data`的分布,以便它可以从该估计分布(`p_g`)生成假样本。
因此,\(D(G(z))\)是发生器`G`的输出是真实图像的概率(标量)。 如 [Goodfellow 的论文](https://papers.nips.cc/paper/5423-generative-adversarial-nets.pdf)中所述,`D``G`玩一个 minimax 游戏,其中`D`试图最大化其正确分类实物和假物(\(logD( x)\)),并且`G`尝试最小化`D`预测其输出为假的概率(\(log(1-D(G(g(x)))\)。 从本文来看,GAN 损失函数为
因此,`D(G(z))`是发生器`G`的输出是真实图像的概率(标量)。 如 [Goodfellow 的论文](https://papers.nips.cc/paper/5423-generative-adversarial-nets.pdf)中所述,`D``G`玩一个 minimax 游戏,其中`D`试图最大化其正确分类实物和假物`log D(x)`,并且`G`尝试最小化`D`预测其输出为假的概率`log(1 - D(G(g(x))))`。 从本文来看,GAN 损失函数为
\[\underset{G}{\text{min}} \underset{D}{\text{max}}V(D,G) = \mathbb{E}_{x\sim p_{data}(x)}\big[logD(x)\big] + \mathbb{E}_{z\sim p_{z}(z)}\big[log(1-D(G(z)))\big]\]
从理论上讲,此极小极大游戏的解决方案是\(p_g = p_ {data} \),判别器会随机猜测输入是真实的还是假的。 但是,GAN 的收敛理论仍在积极研究中,实际上,模型并不总是能达到这一目的。
从理论上讲,此极小极大游戏的解决方案是`p_g = p_data`,判别器会随机猜测输入是真实的还是假的。 但是,GAN 的收敛理论仍在积极研究中,实际上,模型并不总是能达到这一目的。
### 什么是 DCGAN?
......@@ -188,7 +188,7 @@ def weights_init(m):
### 生成器
生成器`G`用于将潜在空间向量(`z`)映射到数据空间。 由于我们的数据是图像,因此将`z`转换为数据空间意味着最终创建与训练图像大小相同的 RGB 图像(即 3x64x64)。 在实践中,这是通过一系列跨步的二维卷积转置层来完成的,每个层都与 2d 批量规范层和 relu 激活配对。 生成器的输出通过 tanh 函数馈送,以使其返回到输入数据范围\([-1,1] \)。 值得注意的是,在卷积转置层之后存在批量规范函数,因为这是 DCGAN 论文的关键贡献。 这些层有助于训练过程中的梯度流动。 DCGAN 纸生成的图像如下所示。
生成器`G`用于将潜在空间向量(`z`)映射到数据空间。 由于我们的数据是图像,因此将`z`转换为数据空间意味着最终创建与训练图像大小相同的 RGB 图像(即 3x64x64)。 在实践中,这是通过一系列跨步的二维卷积转置层来完成的,每个层都与 2d 批量规范层和 relu 激活配对。 生成器的输出通过 tanh 函数馈送,以使其返回到输入数据范围`[-1,1]`。 值得注意的是,在卷积转置层之后存在批量规范函数,因为这是 DCGAN 论文的关键贡献。 这些层有助于训练过程中的梯度流动。 DCGAN 纸生成的图像如下所示。
![dcgan_generator](img/85974d98be6202902f21ce274418953f.png)
......@@ -357,7 +357,7 @@ Discriminator(
\[\ell(x, y) = L = \{l_1,\dots,l_N\}^\top, \quad l_n = - \left[ y_n \cdot \log x_n + (1 - y_n) \cdot \log (1 - x_n) \right]\]
请注意,此函数如何提供目标函数中两个对数分量的计算(即\(log(D(x(x))\)\(log(1-D(G(z)))\))。 我们可以指定`y`输入使用 BCE 方程的哪一部分。 这是在即将到来的训练循环中完成的,但重要的是要了解我们如何仅通过更改`y`(即 GT 标签)即可选择希望计算的分量。
请注意,此函数如何提供目标函数中两个对数分量的计算(即`log D(x)``log(1 - D(G(z)))`)。 我们可以指定`y`输入使用 BCE 方程的哪一部分。 这是在即将到来的训练循环中完成的,但重要的是要了解我们如何仅通过更改`y`(即 GT 标签)即可选择希望计算的分量。
接下来,我们将实际标签定义为 1,将假标签定义为 0。这些标签将在计算`D``G`的损失时使用,这也是 GAN 原始论文中使用的惯例 。 最后,我们设置了两个单独的优化器,一个用于`D`,另一个用于`G`。 如 DCGAN 论文中所指定,这两个都是学习速度为 0.0002 和 Beta1 = 0.5 的 Adam 优化器。 为了跟踪生成器的学习进度,我们将生成一批固定的潜在向量,这些向量是从高斯分布(即 fixed_noise)中提取的。 在训练循环中,我们将定期将此 fixed_noise 输入到`G`中,并且在迭代过程中,我们将看到图像形成于噪声之外。
......@@ -381,20 +381,20 @@ optimizerG = optim.Adam(netG.parameters(), lr=lr, betas=(beta1, 0.999))
### 训练
最后,既然我们已经定义了 GAN 框架的所有部分,我们就可以对其进行训练。 请注意,训练 GAN 某种程度上是一种艺术形式,因为不正确的超参数设置会导致模式崩溃,而对失败的原因几乎没有解释。 在这里,我们将严格遵循 Goodfellow 论文中的算法 1,同时遵守 [ganhacks](https://github.com/soumith/ganhacks) 中显示的一些最佳做法。 即,我们将“为真实和伪造构建不同的小批量”图像,并调整 G 的目标函数以最大化\(logD(G(z))\)。 训练分为两个主要部分。 第 1 部分更新了判别器,第 2 部分更新了生成器。
最后,既然我们已经定义了 GAN 框架的所有部分,我们就可以对其进行训练。 请注意,训练 GAN 某种程度上是一种艺术形式,因为不正确的超参数设置会导致模式崩溃,而对失败的原因几乎没有解释。 在这里,我们将严格遵循 Goodfellow 论文中的算法 1,同时遵守 [ganhacks](https://github.com/soumith/ganhacks) 中显示的一些最佳做法。 即,我们将“为真实和伪造构建不同的小批量”图像,并调整 G 的目标函数以最大化`log D(G(z))`。 训练分为两个主要部分。 第 1 部分更新了判别器,第 2 部分更新了生成器。
**第 1 部分-训练判别器**
回想一下,训练判别器的目的是最大程度地提高将给定输入正确分类为真实或伪造的可能性。 就古德费罗而言,我们希望“通过提高其随机梯度来更新判别器”。 实际上,我们要最大化\(log(D(x))+ log(1-D(G(z)))\)。 由于 ganhacks 提出了单独的小批量建议,因此我们将分两步进行计算。 首先,我们将从训练集中构造一批真实样本,向前通过`D`,计算损失(\(log(D(x(x))\))),然后在向后通过中计算梯度。 其次,我们将使用当前生成器构造一批假样本,将这批伪造通过`D`,计算损失(\(log(1-D(G(z())))\)),然后*反向累积*梯度。 现在,利用全批量和全批量的累积梯度,我们称之为判别器优化程序的一个步骤。
回想一下,训练判别器的目的是最大程度地提高将给定输入正确分类为真实或伪造的可能性。 就古德费罗而言,我们希望“通过提高其随机梯度来更新判别器”。 实际上,我们要最大化`log D(x) + log(1 - D(G(z))`。 由于 ganhacks 提出了单独的小批量建议,因此我们将分两步进行计算。 首先,我们将从训练集中构造一批真实样本,向前通过`D`,计算损失(`log D(x)`),然后在向后通过中计算梯度。 其次,我们将使用当前生成器构造一批假样本,将这批伪造通过`D`,计算损失(`log(1 - D(G(z)))`),然后*反向累积*梯度。 现在,利用全批量和全批量的累积梯度,我们称之为判别器优化程序的一个步骤。
**第 2 部分-训练生成器**
如原始论文所述,我们希望通过最小化\(log(1-D(G(z)))\)来训练 Generator,以产生更好的假货。 如前所述,Goodfellow 证明这不能提供足够的梯度,尤其是在学习过程的早期。 作为解决方法,我们希望最大化\(log(D(G(z())))\)。 在代码中,我们通过以下步骤来实现此目的:将第 1 部分的 Generator 输出与 Discriminator 进行分类,使用实数标签 GT 计算 G 的损失,反向计算 G 的梯度,最后使用优化器更新 G 的参数 步。 将真实标签用作损失函数的 GT 标签似乎是违反直觉的,但这使我们可以使用 BCELoss 的\(log(x)\)部分(而不是\(log(1-x) \)部分),这正是我们想要的。
如原始论文所述,我们希望通过最小化`log(1 - D(G(z)))`来训练 Generator,以产生更好的假货。 如前所述,Goodfellow 证明这不能提供足够的梯度,尤其是在学习过程的早期。 作为解决方法,我们希望最大化`log D(G(z))`。 在代码中,我们通过以下步骤来实现此目的:将第 1 部分的 Generator 输出与 Discriminator 进行分类,使用实数标签 GT 计算 G 的损失,反向计算 G 的梯度,最后使用优化器更新 G 的参数 步。 将真实标签用作损失函数的 GT 标签似乎是违反直觉的,但这使我们可以使用 BCELoss 的`log(x)`部分(而不是`log(1 - x)`部分),这正是我们想要的。
最后,我们将进行一些统计报告,并在每个时期结束时,将我们的 fixed_noise 批量推送到生成器中,以直观地跟踪 G 的训练进度。 报告的训练统计数据是:
* `Loss_D`-判别器损失,计算为所有真实批量和所有假批量的损失总和(\(log(D(x))+ log(D(G(z)))\))。
* `Loss_G`-生成器损耗计算为\(log(D(G(z())))\)
* `Loss_D`-判别器损失,计算为所有真实批量和所有假批量的损失总和(`log D(x) + log D(G(z))`)。
* `Loss_G`-生成器损耗计算为`log D(G(z))`
* `D(x)`-所有真实批量的判别器的平均输出(整个批量)。 这应该从接近 1 开始,然后在 G 变得更好时理论上收敛到 0.5。 想想这是为什么。
* `D(G(z))`-所有假批量的平均判别器输出。 第一个数字在 D 更新之前,第二个数字在 D 更新之后。 这些数字应从 0 开始,并随着 G 的提高收敛到 0.5。 想想这是为什么。
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册