“avg在汽车领域有哪些应用?”用户搜索需求了解avg在汽车上的具体使用场景和功能,

生成式对抗网络GAN的高级议题

想把马变成斑马吗?制作DIY动漫人物或名人?生成对抗网络(GAN)就是一个帮你实现的新朋友。

"GAN是过去10年机器学习中最有趣的想法。" - Facebook AI人工智能研究总监Yann LeCun

深层生成模型分类

本文的大部分内容将涉及编码GAN以及对GAN的一些更高级实现的广泛介绍。

GAN的简短回顾

本文将讲述GAN如何使用pandas实例工作。

最近引入了生成对抗网作为训练生成模型的新方法,即创建能够生成数据的模型。它们由两个"对抗"模式:生成模型G获得数据和判别模型D来估计训练数据提供的样本的准确性。G和D可能是一个非线性映射函数,如多层感知。

在生成对抗网络(GAN)中,我们有两个神经网络在零和游戏中相互对抗,其中第一个网络,即生成器,其任务是欺骗第二个网络,即鉴别器。生成器创建"假的"数据,在这种情况下,是大熊猫的图像,试图欺骗鉴别器将图像分类为真正的熊猫。我们可以逐步迭代地改进这两个网络,以便生成逼真的图像以及执行其他应用程序。

最初,图像可能是相当明显的伪造,但随着训练变得更好,区分真实和虚假图像变得更加困难,即使对于人类也是如此!

这两个网络可以被认为是黑盒子,代表一些任意的复杂的特征,应用于噪声或真实数据。生成器的输入是一些随机噪声,产生伪图像,鉴别器的输入既是伪样本,也是来自真实数据集的样本。然后,鉴别器做出关于所提供的图像z是真实图像D(z)= 1还是假图像D(z)= 0的二元判定。

为了训练两个网络,我们必须具有丢失特征,并且每个网络的丢失特征取决于第二网络。为了训练网络,我们进行反向传播,同时冻结其他网络的神经元权重。

重要的是要注意,通常,鉴别器和生成器网络可以是任何形式的映射函数,例如支持向量机。正是GAN的这种概括通常被称为图灵学习。然而,在实践中,神经网络是最常见的,因为它们是任意非线性函数的广义函数逼近器。

本文现在将讨论GAN的一些最酷的应用程序,然后再讨论一些更高级的主题,以及GAN的代码演练,旨在生成名人面孔和动漫角色。

GAN应用程序

在本节中,本文将简要介绍一下在数据科学研究过程中发现的一些最有趣的GAN应用。最常见的主题是:

  • (有条件)合成  - 包括字体生成,Text2Image以及3D对象生成。
  • 数据扩充 - 旨在减少对标记数据的需求(GAN仅用作增强其他模型的训练过程的工具)。
  • 风格迁移和操纵 - 面部老化,绘画,姿势估计和操作,修复和混合。
  • 信号超分辨率 - 人为地提高图像的分辨率。

条件合成

条件合成是相当不可思议的。可以说,条件合成最迷人的应用是Image2Text和Text2Image,它能够将图片翻译成文字,反之亦然。

这种应用影响深远,如果不仅仅是用于分析医学图像来描述图像的特征,从而消除了医生对图像的主观分析。

这也是另一种方式使图像可以纯粹从单词生成。以下是用于执行此文本到图像条件合成的多条件GAN(MC-GAN)的示例:

mc-gan的实现,用于将单词翻译成图像

数据扩充

GAN像在查看VAE时一样学习数据生成分布。因此,我们可以从我们的发生器中采样并生成其他样本,我们可以使用这些样本来增强我们的训练集。因此,GAN提供了另外的方法来执行数据增加(除了旋转和扭曲图像之外)。

风格迁移和操纵

风格迁移涉及将一个图像的"样式"迁移到另一个图像上。这与神经风格迁移非常相似。

使用GAN进行样式传输的示例

这对于背景场景非常有效,并且类似于图像过滤,除了我们可以操纵实际图像的各个方面(比较上面图像中的云以用于输入和输出)。

GAN如何在动物或水果等其他物体上表现?

看起来相当不错!如果我对GAN一无所知,我可能会认为马的形象实际上是风格迁移后的斑马。

我们还可以改变风景来操纵季节,这对于视频游戏和虚拟现实模拟器等事物来说可能是有用的操作。

我们还可以使用GAN更改景深。

我们还可以操纵绘图,将它们变成真实的物体,相对容易。

自动驾驶汽车以与下图相似的视角看世界,这样可以以更加对比的方式观察物体。

我们甚至可以进行风格转换来渲染图像,如侠盗猎车手的环境。

我们也可以以同样的方式将白天迁移到夜晚。

关于风格迁移和图像处理就足够了。这有很多很好的应用,但我们已经看到了该技术的几种恶意使用,人们冒充政治人物并制造虚假的电话交谈,电子邮件等。

这实际上是一个问题,美国军方正在开发一个新的取证领域来研究视频和媒体的类似例子,以确定它们是否是由GAN产生的。

图像超分辨率

图像超分辨率(SR)是指从低分辨率(LR)图像中恢复高分辨率(HR)图像的过程,是计算机视觉和图像处理中一类重要的图像处理技术。

通常,该问题非常具有挑战性并且有固有地不适合的地方,因为总是存在对应于单个LR图像的多个HR图像。

已经应用各种深度学习方法来处理SR任务,范围从早期基于卷积神经网络(CNN)的方法(例如,SRCNN)到最近使用GAN的有希望的SR方法(例如,SRGAN)。通常,使用深度学习技术的SR算法族在以下主要方面彼此不同:不同类型的网络架构,不同类型的损失函数,不同类型的学习原理和策略等。实现这一目的的过程实际上非常复杂,所以本文中不会详细介绍。

GAN问题

以前我们讨论了GAN的一些最基本的问题,主要是需要大量的计算能力,大图像训练的难度,灵敏度以及模态崩溃。本文想重申这些问题,因为训练GAN非常困难且耗时。

振荡

当发生器和鉴别器共同寻找平衡时,可能发生振荡,但模型更新是独立的。没有理论上的收敛性保证,事实上,结果可能会发生变化。

对此的解决方案是广泛的超参数搜索,有时可能需要手动干预。一个广泛的超参数搜索已经需要10个小时才能运行的东西并不是本文推荐的。

消失的梯度

鉴别器可能变得太强而不能为发生器提供信号。这是什么意思?如果生成器太快太好,生成器可以学会一致地欺骗鉴别器,并且不再需要学习任何东西。

GAN表现出消失的梯度问题

解决方案不是预先训练鉴别器,或者与发生器相比降低其学习率。也可以在每次迭代时更改生成器/鉴别器的更新次数。

很容易看出GAN何时融合,因为两个网络的稳定性将发生在中间地带的某个地方。

GAN中Nash均衡的极小极大表达式

模态崩溃

生成器可以折叠,以便始终生成相同的样本。当生成器被约束到小子空间并因此开始生成低分集的样本时,这可能发生。

以上生成的图像中的五个看起来相同,并且其他几个看起来成对出现。

对此的解决方案是通过小批量区分(将整个批次呈现给鉴别器以供审查)或通过特征匹配(即为低多样性添加生成器惩罚)或使用多个GAN来鼓励多样性。

评估指标

GAN仍然在非常定性的基础上进行评估 - 这个图像看起来很好吗?定义有些客观的适当指标令人惊讶地具有挑战性。"好"的生成器看起来如何?

对此没有明确的解决方案,它仍然是一个活跃的研究领域,并且具有特定领域的特定领域。强分类模型通常用于判断生成样本的质量。使用的两个常见分数是初始分数TSTR分数(Train on Synthetic,Test on Real)。

其他类型的GAN

还有许多其他类型的GAN已经出现,用于解决特定于域的问题以及不同类型的数据(例如,时间序列,图像或普通的csv样式数据)。

本文将在本节讨论的GAN类型是:

  • Wasserstein GAN
  • CycleGAN
  • 条件GAN

Wasserstein GAN

在我看来,这是最重要的GAN类型,所以要注意!

使用标准的GAN配方,我们已经观察到训练非常不稳定。鉴别器通常改进太快以至于生成器不能赶上,这就是为什么我们需要调节学习速率或在两个网络之一上执行多个时期。为了获得合适的输出,我们需要仔细平衡,即使这样,模态崩溃也是非常频繁的。

一般而言,生成模型试图最小化实际和学习分布之间的距离。Wasserstein(也称为EM,Earth-Mover)距离,非正式地指的是当分布被解释为在区域D上堆积一定量污垢的两种不同方式.Wasserstein距离是转动一堆的最小成本进入另一个; 假设成本是移动的污垢量乘以它移动的距离。

不幸的是,在这种情况下,精确的计算是难以处理的。但是,我们可以使用CNN来估算Wasserstein距离。在这里,我们重用了鉴别器,其输出现在是无界的。我们定义了与Wasserstein损失相对应的自定义损失函数:

我们可以尽可能地对一种类型进行预测,对尽可能小的其他类型进行预测。

Wasserstein论文的作者声称:

  • 在训练期间更高的稳定性,更少需要仔细平衡生成器和鉴别器。
  • 有意义的损失度量,与样本质量很好地相关。
  • 模态崩溃很少见。

在Keras实施Wasserstein GAN的提示。

  • 使鉴别器输出无限制,即应用线性激活。
  • 使用小权重进行初始化,以便从一开始就不会遇到剪切问题。
  • 请记住运行足够的鉴别器更新。这在WGAN设置中至关重要。
  • 你可以使用Wasserstein代理损失实施。
  • 通过实现你自己的Keras约束来剪辑鉴别器权重。

这是一个复杂的主题,实施Wasserstein GAN并不是一项简单的任务。

CycleGAN

还记得我们看到一匹马与斑马交换的第一张图片吗?这是一个CycleGAN。CycleGAN将样式传输到图像。

举一个例子,想象一下着名的,如金门大桥的照片,然后从另一幅图像中提取风格,这可能是一幅着名的画作,并以所述着名画作的风格重新绘制桥梁的图片。

结合着名的"神奈川大浪"与芝加哥天际线的风格

将GAN应用于这些类型的问题相对简单,它本质上是图像重建。我们使用第一个网络G将图像x转换为y。我们用另一个深度网络F来反转该过程以重建图像。然后,我们使用均方误差MSE来指导GF的训练。

这里的不同之处在于我们实际上并不关心重建图像,我们试图混合两个图像的样式。在GAN实现中,将鉴别器D添加到现有设计中以指导发电机网络更好地执行。D充当训练样本和生成的图像之间的批评者。通过这种批评,我们使用反向传播来修改生成器以产生图像,以解决由鉴别器识别的缺点。在这个问题中,我们引入了一个鉴别器D,以确保Y类似于梵高的绘画。

CycleGAN将图片从一个域传输到另一个域。在真实图像和梵高绘画之间转换图片。我们建立了三个网络。

  • 生成器G将真实图像转换为梵高风格图片。
  • 生成器F将梵高风格的图片转换为真实图像。
  • 鉴别器D用于识别真实或生成的梵高图片。

对于反方向,我们只是反转数据流并构建一个额外的鉴别器来识别真实图像。

创建斑马/马图像的此实现的示例如下所示。

有条件的GAN

与在VAE中一样,GAN可以简单地用于生成特定的数据模式。

如果生成器和鉴别器都以某些额外信息c为条件,我们可以将GAN的生成模型扩展到条件模型。该c可以是任何类型的辅助信息,例如类标签或来自其他模态的数据。我们可以通过将c作为附加输入层馈入鉴别器和发生器来执行调节。

在生成器中,先前输入噪声p(z)和c在联合隐藏表示中组合,并且对抗训练框架允许在如何组成该隐藏表示时具有相当大的灵活性。在鉴别器中,x和c表示为输入和判别函数。

GAN故障排除

简要概述我们到目前为止讨论过的所有故障排除方法。

  1. 模型。确保正确定义模型。你可以通过训练香草图像分类任务来单独调试鉴别器。
  2. 数据。将输入正确归一化为<-1,1>。在这种情况下,确保使用tanh作为生成器的最终激活。
  3. 噪音。尝试从正态分布(不均匀)中采样噪声向量。
  4. 规范化。尽可能应用BatchNorm,并在单独的小批量中发送真实和假冒样本。
  5. 激活。使用LeakyRelu而不是Relu。
  6. 平滑。应用标签平滑以避免在更新鉴别器时过度自信,即将实际图像的目标设置为小于1。
  7. 诊断。不断监测梯度的大小。
  8. 消失的梯度。如果鉴别器变得太强(鉴别器丢失= 0),尝试降低其学习速率或更频繁地更新发生器。

现在让我们进入有趣的部分,实际上构建一个GAN。

构建图像GAN

正如我们已经多次讨论过的那样,训练GAN可能会令人沮丧且耗费时间。在代码示例中,如果不仔细调整参数,则不会超过图像生成的这个级别(见下文):

网络拍摄图像并输出矢量,分类(分类)或单个分数量化照片写实。可以是任何图像分类网络,例如ResNet或DenseNet。我们使用简约的自定义架构。

采用噪声矢量并输出图像。网络必须执行综合。同样,我们使用非常简约的自定义架构。

在Keras中正确定义模型非常重要,这样可以在正确的时间固定各个模型的权重。

  1. 定义鉴别器模型,并进行编译。
  2. 定义生成器模型,无需编译。
  3. 定义由这两者组成的整体模型,在编译之前将鉴别器设置为不可训练:

在最简单的形式中,这就是训练GAN所需要做的一切

训练循环必须手动执行:

  1. 从训练集中选择R实像。
  2. 通过对大小为N的随机向量进行采样,并使用生成器从它们预测图像来生成F伪图像。
  3. 使用train_on_batch训练鉴别器:分别为R真实图像批次和F伪图像调用它,地面实况分别为1和0。
  4. 采样大小为N的新随机向量。
  5. 使用train_on_batch训练新模型的完整模型,目标为1.这将更新生成器。

编码实施

现在,我们将使用着名的CelebA数据集上的Keras以代码格式进行上述简约实现。如果你对代码的结构方式感到困惑,可能需要参考上述过程。

请注意,在这段代码中我没有以任何方式优化它,我忽略了几条经验法则。我将在第3部分中更多地讨论这些内容,这将涉及对GAN代码的更深入的讨论。

输入

首先,我们导入必要的包。

import keras from keras.layers import * from keras.datasets import cifar10 import glob, cv2, os import numpy as np import matplotlib.pyplot as plt %matplotlib inline from IPython.display import clear_output

全局参数

最好在开始时指定这些参数以避免以后混淆,因为这些网络可能会变得相当混乱和参与。

SPATIAL_DIM = 64 # Spatial dimensions of the images. LATENT_DIM = 100 # Dimensionality of the noise vector. BATCH_SIZE = 32 # Batchsize to use for training. DISC_UPDATES = 1 # Number of discriminator updates per training iteration. GEN_UPDATES = 1 # Nmber of generator updates per training iteration.  FILTER_SIZE = 5 # Filter size to be applied throughout all convolutional layers. NUM_LOAD = 10000 # Number of images to load from CelebA. Fit also according to the available memory on your machine. NET_CAPACITY = 16 # General factor to globally change the number of convolutional filters.  PROGRESS_INTERVAL = 80 # Number of iterations after which current samples will be plotted. ROOT_DIR = 'visualization' # Directory where generated samples should be saved to.  if not os.path.isdir(ROOT_DIR): os.mkdir(ROOT_DIR)

准备数据

我们现在进行一些图像预处理以标准化图像,并绘制图像以确保我们的实现正常工作。

def plot_image(x): plt.imshow(x * 0.5 + 0.5)X = <> # Reference to CelebA dataset here. I recommend downloading from the Harvard 2019 ComputeFest GitHub page (there is also some good coding tutorials here)faces = glob.glob('../Harvard/ComputeFest 2019/celeba/img_align_celeba/*.jpg')  for i, f in enumerate(faces): img = cv2.imread(f) img = cv2.resize(img, (SPATIAL_DIM, SPATIAL_DIM)) img = np.flip(img, axis=2) img = img.astype(np.float32) / 127.5 - 1.0 X.append(img) if i >= NUM_LOAD - 1: break X = np.array(X) plot_image(X<4>) X.shape, X.min(), X.max())

定义架构

Keras格式的架构非常简单。最好用块编写代码以保持尽可能简单。

首先,我们添加编码器块部分。请注意,我们使用"相同"填充,以便输入和输出尺寸相同,以及批量标准化和泄漏ReLU。Stride主要是可选的,因为泄漏的ReLU参数的大小也是如此。我放在这里的值没有优化,但确实给了我一个合理的结果。

def add_encoder_block(x, filters, filter_size): x = Conv2D(filters, filter_size, padding='same')(x) x = BatchNormalization()(x) x = Conv2D(filters, filter_size, padding='same', strides=2)(x) x = BatchNormalization()(x) x = LeakyReLU(0.3)(x) return x

接下来是鉴别器本身 - 注意我们如何回收编码器块段并逐渐增加滤波器大小以解决我们之前讨论的用于(大)图像训练的问题(对所有图像执行此操作的最佳实践)。

def build_discriminator(start_filters, spatial_dim, filter_size): inp = Input(shape=(spatial_dim, spatial_dim, 3))  # Encoding blocks downsample the image. x = add_encoder_block(inp, start_filters, filter_size) x = add_encoder_block(x, start_filters * 2, filter_size) x = add_encoder_block(x, start_filters * 4, filter_size) x = add_encoder_block(x, start_filters * 8, filter_size) x = GlobalAveragePooling2D()(x) x = Dense(1, activation='sigmoid')(x) return keras.Model(inputs=inp, outputs=x) 现在为解码器块段。这次我们正在执行卷积层的反面,即反卷积。请注意,为了便于实现,步幅和填充是相同的,我们再次使用批量标准化和泄漏ReLU。def add_decoder_block(x, filters, filter_size): x = Deconvolution2D(filters, filter_size, strides=2, padding='same')(x) x = BatchNormalization()(x) x = LeakyReLU(0.3)(x) return x

现在构建生成器,注意这次我们使用解码器块并逐渐减小过滤器大小。

def build_generator(start_filters, filter_size, latent_dim): inp = Input(shape=(latent_dim,))  # Projection. x = Dense(4 * 4 * (start_filters * 8), input_dim=latent_dim)(inp) x = BatchNormalization()(x) x = Reshape(target_shape=(4, 4, start_filters * 8))(x)  # Decoding blocks upsample the image. x = add_decoder_block(x, start_filters * 4, filter_size) x = add_decoder_block(x, start_filters * 2, filter_size) x = add_decoder_block(x, start_filters, filter_size) x = add_decoder_block(x, start_filters, filter_size)   x = Conv2D(3, kernel_size=5, padding='same', activation='tanh')(x) return keras.Model(inputs=inp, outputs=x)

训练

现在我们已经建立了网络架构,我们可以概述训练过程,这可能是人们容易混淆的地方。我想这可能是因为在更多特征中的函数内部有函数。

def construct_models(verbose=False): # 1. Build discriminator. discriminator = build_discriminator(NET_CAPACITY, SPATIAL_DIM, FILTER_SIZE) discriminator.compile(loss='binary_crossentropy', optimizer=keras.optimizers.Adam(lr=0.0002), metrics=<'mae'>)  # 2. Build generator. generator = build_generator(NET_CAPACITY, FILTER_SIZE, LATENT_DIM)  # 3. Build full GAN setup by stacking generator and discriminator. gan = keras.Sequential() gan.add(generator) gan.add(discriminator) discriminator.trainable = False # Fix the discriminator part in the full setup. gan.compile(loss='binary_crossentropy', optimizer=keras.optimizers.Adam(lr=0.0002), metrics=<'mae'>)  if verbose: # Print model summaries for debugging purposes. generator.summary() discriminator.summary() gan.summary() return generator, discriminator, gan

基本上,我们上面所做的是设计一个基于我们的全局参数创建GAN模型的函数。请注意,我们编译鉴别器,但不编译生成器,但我们最后编译GAN作为一个整体。

另外,请注意我们已经将鉴别器设置为不可训练,这是人们在构建GAN时常常忘记的事情!

这是如此重要的原因是你不能同时训练两个网络,就像试图校正多个变量变化的东西,你会得到零星的结果。在训练任何单个网络时,你需要对模型的其余部分进行固定设置。

现在构建了完整的模型,我们可以继续进行训练。

def run_training(start_it=0, num_epochs=1000):# Save configuration file with global parameters config_name = 'gan_cap' + str(NET_CAPACITY) + '_batch' + str(BATCH_SIZE) + '_filt' + str(FILTER_SIZE) + '_disc' + str(DISC_UPDATES) + '_gen' + str(GEN_UPDATES) folder = os.path.join(ROOT_DIR, config_name)   if not os.path.isdir(folder): os.mkdir(folder)# Initiate loop variables avg_loss_discriminator = <> avg_loss_generator = <> total_it = start_it # Start of training loop for epoch in range(num_epochs): loss_discriminator = <> loss_generator = <> for it in range(200):   # Update discriminator. for i in range(DISC_UPDATES):  # Fetch real examples (you could sample unique entries, too). imgs_real = X, size=BATCH_SIZE)>  # Generate fake examples. noise = np.random.randn(BATCH_SIZE, LATENT_DIM) imgs_fake = generator.predict(noise)  d_loss_real = discriminator.train_on_batch(imgs_real, np.ones())<1> d_loss_fake = discriminator.train_on_batch(imgs_fake, np.zeros())<1>  # Progress visualizations. if total_it % PROGRESS_INTERVAL == 0: plt.figure(figsize=(5,2)) # We sample separate images. num_vis = min(BATCH_SIZE, 8) imgs_real = X, size=num_vis)> noise = np.random.randn(num_vis, LATENT_DIM) imgs_fake = generator.predict(noise) for obj_plot in : plt.figure(figsize=(num_vis * 3, 3)) for b in range(num_vis): disc_score = float(discriminator.predict(np.expand_dims(obj_plot, axis=0))<0>) plt.subplot(1, num_vis, b + 1) plt.title(str(round(disc_score, 3))) plot_image(obj_plot)  if obj_plot is imgs_fake: plt.savefig(os.path.join(folder, str(total_it).zfill(10) + '.jpg'), format='jpg', bbox_inches='tight') plt.show()   # Update generator. loss = 0 y = np.ones()  for j in range(GEN_UPDATES): noise = np.random.randn(BATCH_SIZE, LATENT_DIM) loss += gan.train_on_batch(noise, y)<1>  loss_discriminator.append((d_loss_real + d_loss_fake) / 2.)  loss_generator.append(loss / GEN_UPDATES) total_it += 1  # Progress visualization. clear_output(True) print('Epoch', epoch) avg_loss_discriminator.append(np.mean(loss_discriminator)) avg_loss_generator.append(np.mean(loss_generator)) plt.plot(range(len(avg_loss_discriminator)), avg_loss_discriminator) plt.plot(range(len(avg_loss_generator)), avg_loss_generator) plt.legend(<'discriminator loss', 'generator loss'>) plt.show()

上面的代码可能看起来很混乱。上面的代码中有几个项目只对管理GAN的运行有帮助。例如,第一部分设置配置文件并保存,因此你可以在将来引用它并确切知道网络的体系结构和超参数是什么。

还有进度可视化步骤,可实时打印笔记本的输出,以便你可以访问GAN的当前性能。

如果忽略配置文件和进度可视化,则代码相对简单。首先,我们更新鉴别器,然后更新生成器,然后我们在这两个场景之间进行迭代。

现在,由于我们巧妙地使用了特征,我们可以将模型分为两行。

generator, discriminator, gan = construct_models(verbose=True) run_training()

剩下要做的就是等待,然后测试网络的输出。

来自训练后的GAN的样本

现在,在等待网络完成训练后,我们可以从网络中获取大量样本。

NUM_SAMPLES = 7 plt.figure(figsize=(NUM_SAMPLES * 3, 3))  for i in range(NUM_SAMPLES): noise = np.random.randn(1, LATENT_DIM)  pred_raw = generator.predict(noise)<0> pred = pred_raw * 0.5 + 0.5 plt.subplot(1, NUM_SAMPLES, i + 1) plt.imshow(pred) plt.show()Samples from trained GAN

来自训练有素的GAN的样本

这是我们第一次实现基本的GAN。这可能是构建特征齐全的GAN的最简单方法。

2024-05-13

后面没有了,返回>>电动车百科