From 01d7172ba86aad83ca5f9574c9f769b260f0111d Mon Sep 17 00:00:00 2001 From: wizardforcel <562826179@qq.com> Date: Tue, 15 Sep 2020 14:06:33 +0800 Subject: [PATCH] 2020-09-15 14:06:33 --- docs/handson-cnn-tf/1.md | 4 +- docs/handson-cnn-tf/2.md | 6 +-- docs/handson-cnn-tf/3.md | 16 +++--- docs/handson-cnn-tf/4.md | 4 +- docs/handson-cnn-tf/5.md | 16 +++--- docs/handson-cnn-tf/6.md | 110 +++++++++++++++++++-------------------- docs/handson-cnn-tf/7.md | 14 ++--- docs/handson-cnn-tf/8.md | 14 ++--- docs/handson-cnn-tf/9.md | 32 ++++++------ 9 files changed, 108 insertions(+), 108 deletions(-) diff --git a/docs/handson-cnn-tf/1.md b/docs/handson-cnn-tf/1.md index b6a31b2f..0846a0b7 100644 --- a/docs/handson-cnn-tf/1.md +++ b/docs/handson-cnn-tf/1.md @@ -137,7 +137,7 @@ def my_conv_2d(input, weight_shape, num_filters, strides): 因此,不仅要为模型中所需的每种新层将这些内容写出来都非常费力,而且还引入了更多的区域,在这些区域中,错误可能会潜入您的代码中,这从来都不是一件好事。 -对我们来说幸运的是,TensorFlow 具有第二层抽象,可以帮助您简化构建 TensorFlow 图时的工作。 这种抽象级别的一个示例是层 API。 图层 API 使您可以轻松处理许多机器学习任务中常见的许多构建基块。 +对我们来说幸运的是,TensorFlow 具有第二层抽象,可以帮助您简化构建 TensorFlow 图时的工作。 这种抽象级别的一个示例是层 API。 层 API 使您可以轻松处理许多机器学习任务中常见的许多构建基块。 层 API 的工作方式是包装我们在上一个示例中编写的所有内容并将其抽象出来,因此我们不必再为它担心。 例如,我们可以压缩前面的代码以将卷积层构造为一个函数调用。 与以前建立相同的卷积层现在看起来像这样: @@ -153,7 +153,7 @@ API 堆栈的最后一层是 TensorFlow 提供的最高抽象层,这称为估 本书不会介绍估计器 API 的用法,但是如果读者希望了解有关估计器的更多信息,可以在 TensorFlow 网站上找到一些有用的教程。 -本书将重点介绍如何使用低级 API 以及图层,数据集和指标 API 来构建,训练和评估自己的 ML 模型。 我们相信,通过使用这些较低级别的 API,读者将对 TensorFlow 的幕后工作方式有更深入的了解,并有能力更好地应对可能需要使用这些较低级别 API 的各种未来问题。 +本书将重点介绍如何使用低级 API 以及层,数据集和指标 API 来构建,训练和评估自己的 ML 模型。 我们相信,通过使用这些较低级别的 API,读者将对 TensorFlow 的幕后工作方式有更深入的了解,并有能力更好地应对可能需要使用这些较低级别 API 的各种未来问题。 # 急切执行 diff --git a/docs/handson-cnn-tf/2.md b/docs/handson-cnn-tf/2.md index 1c2922b4..9ef1645a 100644 --- a/docs/handson-cnn-tf/2.md +++ b/docs/handson-cnn-tf/2.md @@ -66,7 +66,7 @@ ML 系统的组成部分是评估。 在评估模型时,我们会看到模型 ML 工程师可能会遵循的典型流程来开发预测模型,如下所示: -1. 收集资料 +1. 收集数据 2. 从数据中提取相关特征 3. 选择 ML 体系结构(CNN,ANN,SVM,决策树等) 4. 训练模型 @@ -436,7 +436,7 @@ TensorFlow 卷积操作为您提供了两种用于填充需求的选项:相同 * 有效-TensorFlow 不填充图像。 卷积内核将仅进入输入中的“有效”位置。 * 相同-如果我们假设步幅为 1,则在这种情况下,TensorFlow 将足够填充输入,以便输出空间大小与输入空间大小相同。 -如果您确实希望对填充有更多控制,则可以在图层的输入上使用`tf.pad()`,以用所需的零个位数来填充输入。 +如果您确实希望对填充有更多控制,则可以在层的输入上使用`tf.pad()`,以用所需的零个位数来填充输入。 通常,我们可以使用以下公式计算卷积运算的输出大小: @@ -589,7 +589,7 @@ tf.layers.max_pooling2d(inputs=some_input_layer, pool_size=[2, 2], strides=2) 这些计算与是否使用卷积或池化层无关,例如,步幅为 2 的卷积层将与步幅为 2 的池化层具有相同的感受域。 -例如,给定以下图层之后的`14x14x3`图像,这将适用: +例如,给定以下层之后的`14x14x3`图像,这将适用: * 卷积:S:1,P:0,K:3 * 卷积:S:1,P:0,K:3 diff --git a/docs/handson-cnn-tf/3.md b/docs/handson-cnn-tf/3.md index 63ce7dd6..600f78c8 100644 --- a/docs/handson-cnn-tf/3.md +++ b/docs/handson-cnn-tf/3.md @@ -41,7 +41,7 @@ # CNN 模型架构 -图像分类模型的关键部分是其 CNN 层。 这些层将负责从图像数据中提取特征。 这些 CNN 图层的输出将是一个特征向量,就像以前一样,我们可以将其用作所选分类器的输入。 对于许多 CNN 模型,分类器将只是连接到我们 CNN 输出的完全连接层。 如第 1 章,“TensorFlow 简介和设置”中所示,我们的线性分类器只是一个全连接层; 除了层的大小和输入会有所不同之外,这里就是这种情况。 +图像分类模型的关键部分是其 CNN 层。 这些层将负责从图像数据中提取特征。 这些 CNN 层的输出将是一个特征向量,就像以前一样,我们可以将其用作所选分类器的输入。 对于许多 CNN 模型,分类器将只是连接到我们 CNN 输出的完全连接层。 如第 1 章,“TensorFlow 简介和设置”中所示,我们的线性分类器只是一个全连接层; 除了层的大小和输入会有所不同之外,这里就是这种情况。 重要的是要注意,分类或回归问题(例如定位)(或其他使用图像的其他问题)所使用的 CNN 架构在本质上是相同的。 唯一真正的不同是,在 CNN 层完成特征提取之后会发生什么。 例如,一个差异可能是用于不同任务的损失函数,如下图所示: @@ -407,13 +407,13 @@ decayed_learning_rate = learning_rate * decay_rate ^ (global_step / decay_steps) # `tf.data` API 简介 -在继续之前,我们将看一下 TensorFlow 处理数据输入到我们可能训练的任何模型的方式。 TensorFlow `tf.data` API 为我们提供了轻松构建复杂的输入管道可能需要的所有工具。 您可能通常会构建的一个管道将涉及加载原始训练数据,对其进行一些预处理,改组,然后将其分批准备进行训练。 `tf.data` API 使我们能够使用简单且可重复使用的代码段轻松地完成所有这些步骤。 +在继续之前,我们将看一下 TensorFlow 处理数据输入到我们可能训练的任何模型的方式。 TensorFlow `tf.data` API 为我们提供了轻松构建复杂的输入流水线可能需要的所有工具。 您可能通常会构建的一个流水线将涉及加载原始训练数据,对其进行一些预处理,改组,然后将其分批准备进行训练。 `tf.data` API 使我们能够使用简单且可重复使用的代码段轻松地完成所有这些步骤。 您需要了解`tf.data` API 的两个主要组件。 首先是`tf.data.Dataset`; 这就是您的原始数据。 更具体地说,它包含一系列元素,其中每个元素包含一个或多个张量对象。 对于图像分类任务,一个元素将是一个训练示例,并且它将由两个张量组成-一个张量用于图像,一个张量用于其相应的标签。 第二个成分是`tf.data.Iterator`。 这些允许您从数据集中提取元素,并充当数据集和模型代码之间的连接。 TensorFlow 中有几种不同类型的迭代器,它们都有不同的用途,涉及不同的使用难度。 -创建数据集可以通过两种方式完成。 第一种方法是通过创建数据源。 一个简单的例子是使用`tf.data.Dataset.from_tensor_slices()`,它将根据一个或多个张量对象的切片创建一个数据集。 产生数据集的另一种方法是在现有数据集上使用数据集转换。 这样做将返回合并了所应用转换的新数据集。 重要的是要了解所有输入管道必须以数据源开头。 一旦有了`Dataset`对象,通常对它应用所有链接在一起的多个转换。 +创建数据集可以通过两种方式完成。 第一种方法是通过创建数据源。 一个简单的例子是使用`tf.data.Dataset.from_tensor_slices()`,它将根据一个或多个张量对象的切片创建一个数据集。 产生数据集的另一种方法是在现有数据集上使用数据集转换。 这样做将返回合并了所应用转换的新数据集。 重要的是要了解所有输入流水线必须以数据源开头。 一旦有了`Dataset`对象,通常对它应用所有链接在一起的多个转换。 目前,一些简单的转换示例包括`Dataset.batch()`和`Dataset.repeat()`,它们从`Dataset`对象返回一批具有指定大小的批次,当`Dataset`内容到达末尾时,它将继续重复该内容。 一种可以多次遍历数据集的简单方法(`count`参数)。 @@ -522,7 +522,7 @@ decayed_learning_rate = learning_rate * decay_rate ^ (global_step / decay_steps) # 模型初始化 -随着我们向模型中添加越来越多的图层,使用反向传播训练它们的难度越来越大。 通过模型传递回去以更新权重的误差值随着我们的深入而变得越来越小。 这被称为消失梯度问题。 +随着我们向模型中添加越来越多的层,使用反向传播训练它们的难度越来越大。 通过模型传递回去以更新权重的误差值随着我们的深入而变得越来越小。 这被称为消失梯度问题。 因此,在开始训练模型之前,需要注意的重要一件事是将权重初始化为什么值。 错误的初始化会使模型收敛非常慢,或者甚至根本不会收敛。 @@ -546,7 +546,7 @@ decayed_learning_rate = learning_rate * decay_rate ^ (global_step / decay_steps) # Xavier-Bengio 和初始化器 -在了解*训练深度前馈神经网络*的难度时,Xavier Glorot 和 Yoshua Bengio 表明,如果从均匀分布`U ~ [-1/√n, 1/√n]`初始化每一层的权重,其中`n`是上一层中的大小,对于乙状结肠激活函数,顶层(更靠近输出)的神经元迅速饱和为 0。我们知道,由于乙状结肠函数的形式,激活值 0 表示权重非常大,并且反向传播的梯度接近零。 较小的梯度值会减慢学习过程,因为早期图层中的权重停止更新或停止学习。 +在了解*训练深度前馈神经网络*的难度时,Xavier Glorot 和 Yoshua Bengio 表明,如果从均匀分布`U ~ [-1/√n, 1/√n]`初始化每一层的权重,其中`n`是上一层中的大小,对于乙状结肠激活函数,顶层(更靠近输出)的神经元迅速饱和为 0。我们知道,由于乙状结肠函数的形式,激活值 0 表示权重非常大,并且反向传播的梯度接近零。 较小的梯度值会减慢学习过程,因为早期层中的权重停止更新或停止学习。 因此,我们想要的是使权重在最初确定的时间间隔内均匀分布,也就是说,权重的方差应该在我们从底层移动到顶层时保持不变。 这将使错误平稳地流到顶层,从而使网络在训练期间收敛更快。 @@ -580,7 +580,7 @@ bias_initializer=tf.zeros_initializer()) 到目前为止,在本章中,我们已经看到了如何使用 TensorFlow 训练卷积神经网络来完成图像分类任务。 训练完模型后,我们将其遍历测试集,并从一开始就将其存储起来,以查看其在从未见过的数据上的性能如何。 在测试集上评估模型的过程向我们表明了在部署模型时模型将泛化的程度。 能够很好地泛化的模型显然是理想的属性,因为它可以在许多情况下使用。 -我们使用的 CNN 架构是可以提高模型泛化能力的方法之一。 要记住的一种简单技术是从设计模型开始就尽可能简单地使用很少的图层或滤镜。 由于非常小的模型很可能无法适应您的数据,因此您可以慢慢增加复杂性,直到不再发生适应不足的情况为止。 如果您以这种方式设计模型,则将限制过拟合的可能性,因为您不允许自己拥有的模型对于数据集而言过大。 +我们使用的 CNN 架构是可以提高模型泛化能力的方法之一。 要记住的一种简单技术是从设计模型开始就尽可能简单地使用很少的层或滤镜。 由于非常小的模型很可能无法适应您的数据,因此您可以慢慢增加复杂性,直到不再发生适应不足的情况为止。 如果您以这种方式设计模型,则将限制过拟合的可能性,因为您不允许自己拥有的模型对于数据集而言过大。 但是,在本节中,我们将探索我们可以做的其他一些事情,以建立更好的机器学习模型,以及如何将它们纳入我们的训练过程中。 以下方法旨在防止过拟合,并通过这样做,有助于创建更强大的模型,并能更好地进行泛化。 防止模型过拟合的过程称为**正则化**。 @@ -618,7 +618,7 @@ bias_initializer=tf.zeros_initializer()) l2_reg = tf.contrib.layers.l2_regularizer(scale=0.001) ``` -`scale`参数是我们通常需要通过交叉验证找到并设置自己的`λ`。 如果将其设置为 0,则不会进行任何正则化。 现在,当我们创建任何图层时,我们会将正则化函数作为参数传递。 TensorFlow 将进行计算以获取我们需要添加到损失函数中的所有正则化项: +`scale`参数是我们通常需要通过交叉验证找到并设置自己的`λ`。 如果将其设置为 0,则不会进行任何正则化。 现在,当我们创建任何层时,我们会将正则化函数作为参数传递。 TensorFlow 将进行计算以获取我们需要添加到损失函数中的所有正则化项: ```py # Example of adding passing regularizer to a conv layer. @@ -675,7 +675,7 @@ fc1 = tf.layers.dropout(fc1, rate=dropout, training=is_training) 之前,我们已经完成了权重的初始化工作,以使梯度下降优化器的工作更加轻松。 但是,好处仅在训练的早期阶段才能看到,并不能保证在后期阶段有所改善。 那就是我们转向另一个称为批量规范层的伟大发明的地方。 在 CNN 模型中使用批量规范层产生的效果与第 2 章,“深度学习和卷积神经网络”中看到的输入标准化大致相同。 现在唯一的区别是,这将在模型中所有卷积层和完全连接层的输出处发生。 -批量规范层通常将附加到每个完全连接或卷积层的末端,但是在激活函数之前,它将对层输出进行规范化,如下图所示。 它通过获取图层输出(一批激活)并减去批次平均值并除以批次标准差来执行此操作,因此图层输出具有零均值和单位标准差。 请注意,在激活函数之前或之后放置批量规范化是一个引起激烈争论的话题,但是两者都应该起作用。 +批量规范层通常将附加到每个完全连接或卷积层的末端,但是在激活函数之前,它将对层输出进行规范化,如下图所示。 它通过获取层输出(一批激活)并减去批次平均值并除以批次标准差来执行此操作,因此层输出具有零均值和单位标准差。 请注意,在激活函数之前或之后放置批量规范化是一个引起激烈争论的话题,但是两者都应该起作用。 ![](img/3e1365ac-328e-48f0-8077-920bb837324e.png) diff --git a/docs/handson-cnn-tf/4.md b/docs/handson-cnn-tf/4.md index 84ff304b..59cb35b9 100644 --- a/docs/handson-cnn-tf/4.md +++ b/docs/handson-cnn-tf/4.md @@ -160,7 +160,7 @@ R-CNN 在计算上仍然很昂贵,因为您必须对大约 2,000 个单独的 # Fast R-CNN -2015 年,提出了快速 R-CNN 来解决 R-CNN 的速度问题。 在此方法中,主要的变化是我们在管道中获取投标区域的位置。 首先,我们通过 CNN 运行整个输入图像,而不是从输入图像中直接获取它们,并提取靠近网络末端的生成的特征图。 接下来,再次使用区域提议方法,以与 R-CNN 类似的方式从该特征图中提取候选区域。 +2015 年,提出了快速 R-CNN 来解决 R-CNN 的速度问题。 在此方法中,主要的变化是我们在流水线中获取投标区域的位置。 首先,我们通过 CNN 运行整个输入图像,而不是从输入图像中直接获取它们,并提取靠近网络末端的生成的特征图。 接下来,再次使用区域提议方法,以与 R-CNN 类似的方式从该特征图中提取候选区域。 以这种方式获取建议有助于重用和共享昂贵的卷积计算。 网络中位于网络下方的全连接层将分类并另外定位,仅接受固定大小的输入。 因此,使用称为 **RoI 池**的新层将特征图中建议的区域扭曲为固定大小(在下一节中进一步讨论)。 RoI 池会将区域大小调整为最后一个 FC 层所需的大小。 下图显示了整个过程: @@ -566,7 +566,7 @@ def loss_layer(self, predicts, labels, scope='loss_layer'): 这个运算相当不好地称为反卷积,这意味着它是卷积的逆运算,但实际上并非如此。 更恰当的名称是转置卷积或分数步卷积。 -此图层类型为您提供了一种对输入体积进行升采样的学习方法,并且可以在每次需要将输入要素地图智能地投影到更高的空间时使用。 一些用例包括以下内容: +此层类型为您提供了一种对输入体积进行升采样的学习方法,并且可以在每次需要将输入要素地图智能地投影到更高的空间时使用。 一些用例包括以下内容: * 上采样(条纹转置卷积)== UNPOOL + CONV * 可视化显着图 diff --git a/docs/handson-cnn-tf/5.md b/docs/handson-cnn-tf/5.md index 37e0cb4e..5cced1db 100644 --- a/docs/handson-cnn-tf/5.md +++ b/docs/handson-cnn-tf/5.md @@ -70,7 +70,7 @@ 一些网络体系结构,例如残差网络(我们将在后面看到),使用瓶颈技术再次减少了参数数量并增加了非线性。 -# 虚拟网 +# VGGNet VGGNet 由牛津大学的**视觉几何组**(**VGG**)创建,是真正引入堆叠更多层的想法的首批架构之一。 虽然 AlexNet 最初以其七层出现时被认为很深,但与 VGG 和其他现代体系结构相比,这现在已经很小了。 @@ -80,7 +80,7 @@ VGGNet 由牛津大学的**视觉几何组**(**VGG**)创建,是真正引 堆叠过滤器的这种洞察力带来了能够拥有更深的结构(我们通常会看到更好的结构)的优点,该结构保留了相同的感受域大小,同时还减少了参数数量。 本章后面将进一步探讨这个想法。 -# 建筑 +# 架构 接下来,我们将看到 VGGNet 的体系结构,特别是包含 16 层的 VGG-16 风格。 所有卷积层都有空间大小为`3x3`的滤镜,并且随着我们深入网络,卷积层中滤镜的数量从 64 个增加到 512 个。 @@ -110,7 +110,7 @@ VGG 最酷的功能之一是,由于其在 conv 层中的内核较小,因此 如前所述,您需要在训练数据集中使用大量样本来消耗模型参数,因此最好避免过度使用全连接层来避免参数爆炸。 幸运的是,人们发现,如果最后只有一层而不是三层,那么 VGGNet 的工作原理几乎相同。 因此,删除这些全连接层会从模型中删除大量参数,而不会大大降低性能。 因此,如果您决定实现 VGGNet,我们建议您也这样做。 -# 码 +# 代码 接下来,我们介绍负责在 Tensorflow 中构建 VGG-16 模型图的函数。 像本章中的所有模型一样,VGGNet 旨在对 Imagenet 挑战的 1,000 个类别进行分类,这就是为什么该模型输出大小为 1000 的向量的原因。 显然,可以为您自己的数据集轻松更改此设置,如下所示: @@ -200,7 +200,7 @@ VGG 最酷的功能之一是,由于其在 conv 层中的内核较小,因此 self.predictions = tf.nn.softmax(self.fc8, name='predictions') ``` -# 关于 VGG 的更多信息 +# VGG 的更多信息 2014 年,VGG 在 Imagenet 分类挑战中获得第二名,在 Imagenet 定位挑战中获得第一名。 正如我们所看到的,VGGNet 的设计选择是堆叠许多小的卷积层,从而可以实现更深的结构,同时具有更少的参数(如果我们删除了不必要的全连接层),则性能更好。 这种设计选择在创建强大而高效的网络方面非常有效,以至于几乎所有现代体系结构都复制了这种想法,并且很少(如果有的话)使用大型过滤器。 @@ -219,7 +219,7 @@ GoogLeNet 具有 22 层,参数几乎比 AlexNet 少 12 倍。 因此,除了 ![](img/a792bf21-afb7-4617-90ee-9eaf988cddd9.png) -# 起始模块 +# Inception 模块 起始模块(或层的块)旨在覆盖较大的区域,但也保持较高的分辨率,以便也可以在图像中查看重要的本地信息。 除了创建更深的网络外,起始块还引入了并行卷积的思想。 我们的意思是在前一层的输出上执行不同大小的并行卷积。 @@ -295,7 +295,7 @@ def inception_block_a(x, name='inception_a'): return concat ``` -# 有关 GoogLeNet 的更多信息 +# GoogLeNet 的更多信息 GoogLeNet 的主要优点是,它比 VGG 更为准确,同时使用的参数更少,计算能力也更低。 主要的缺点仍然是,如果我们开始堆叠很多初始层,梯度将消失,而且整个网络具有多个分支和多个损失的设计相当复杂。 @@ -378,7 +378,7 @@ for group_i, group in enumerate(groups): net = conv + net ``` -# 移动网 +# MobileNet 我们将以一个新的 CNN 系列结束本章,该系列不仅具有较高的准确性,而且更轻巧,并且在移动设备上的运行速度更快。 @@ -406,7 +406,7 @@ MobileNets 使用两个超参数来帮助控制精度和速度之间的折衷, * **宽度倍增器**:通过统一减少整个网络中使用的滤波器数量,控制深度卷积精度 * **分辨率倍增器**:只需将输入图像缩小到不同大小 -# 有关 MobileNets 的更多信息 +# MobileNets 的更多信息 对于任何神经网络设计,MobileNets 都具有一些最佳的精度,速度和参数比率。 diff --git a/docs/handson-cnn-tf/6.md b/docs/handson-cnn-tf/6.md index fe6f8a09..8fb660a7 100644 --- a/docs/handson-cnn-tf/6.md +++ b/docs/handson-cnn-tf/6.md @@ -8,12 +8,12 @@ 本章列出了一些我们将要学习的关键主题: -* 汽车编码器 +* 自编码器 * 变分自编码器 * 生成对抗网络 * 实现各种生成模型以生成手写数字 -# 为什么要生成模型 +# 为什么是生成模型 在下图中,我们可以看到生成模型和判别模型之间的主要区别。 使用判别模型,我们通常尝试找到在数据中不同类别之间进行区分或“区分”的方法。 但是,使用生成模型,我们尝试找出数据的概率分布。 在图示中,分布由包含较小圆圈的蓝色和黄色大斑点表示。 如果我们从数据中学到这种分布,我们将能够采样或“生成”应该属于它的新数据点,例如红色三角形。 @@ -30,7 +30,7 @@ 训练了生成神经网络模型,以产生类似于训练集的数据样本。 由于模型参数的数量小于训练数据的维数,因此迫使模型发现有效的数据表示形式。 -# 汽车编码器 +# 自编码器 我们将要看到的第一个生成模型是自编码器模型。 自编码器是一个简单的神经网络,由两部分组成:**编码器**和**解码器**。 这个想法是编码器部分会将您的输入压缩到较小的尺寸。 然后,从这个较小的维度尝试使用模型的解码器部分重建输入。 通常用许多名称来称呼这种较小的尺寸,例如潜在空间,隐藏空间,嵌入或编码。 @@ -323,15 +323,15 @@ class VAE_CNN_GEN(object): # 生成对抗网络 -**生成对抗网络**(**GAN**)是另一种非常新的生成模型,由于其令人印象深刻的结果而受到关注。 GAN 由两个网络组成:生成器网络和鉴别器网络。 在训练过程中,他们俩都玩零和游戏,其中鉴别器网络试图发现输入到其中的图像是真实的还是伪造的。 同时,生成器网络尝试创建足以欺骗鉴别器的伪造图像。 +**生成对抗网络**(**GAN**)是另一种非常新的生成模型,由于其令人印象深刻的结果而受到关注。 GAN 由两个网络组成:生成器网络和判别器网络。 在训练过程中,他们俩都玩零和游戏,其中判别器网络试图发现输入到其中的图像是真实的还是伪造的。 同时,生成器网络尝试创建足以欺骗判别器的伪造图像。 -想法是经过一段时间的训练,鉴别器和生成器都非常擅长于他们的任务。 结果,生成器被迫尝试创建看起来越来越接近原始数据集的图像。 为此,它必须捕获数据集的概率分布。 +想法是经过一段时间的训练,判别器和生成器都非常擅长于他们的任务。 结果,生成器被迫尝试创建看起来越来越接近原始数据集的图像。 为此,它必须捕获数据集的概率分布。 下图概述了此 GAN 模型的外观: ![](img/98fcbf21-46e3-45f0-8a2d-a7004af773c3.png) -鉴别器和发生器都将具有自己的损失函数,但是它们的损失都相互依赖。 +判别器和发生器都将具有自己的损失函数,但是它们的损失都相互依赖。 让我们总结一下 GAN 模型的两个主要模块或网络: @@ -340,18 +340,18 @@ class VAE_CNN_GEN(object): GAN 的一些实际用法如下: -* 使用鉴别器网络权重作为不同任务的初始化,类似于我们对自编码器可以执行的操作 +* 使用判别器网络权重作为不同任务的初始化,类似于我们对自编码器可以执行的操作 * 使用生成器网络创建新图像,可能会扩大您的数据集,就像我们可以使用经过训练的 VAE 解码器一样 -* 将鉴别器用作损失函数(对于图像,可能优于 L1/L2),并且也可以在 VAE 中使用 +* 将判别器用作损失函数(对于图像,可能优于 L1/L2),并且也可以在 VAE 中使用 * 通过将生成的数据与标记的数据混合来进行半监督学习 现在我们将向您展示如何在 TensorFlow 中实现非常简单的 GAN。 一旦经过训练,我们的 GAN 的生成器部分就可以用于根据 100 个长随机噪声矢量创建 MNIST 手写数字。 让我们开始吧! -# 鉴别器 +# 判别器 -我们需要做的第一件事就是创建我们的区分网络。 为此,我们将几个全连接层堆叠在一起。 鉴别器将 784 个长度向量作为输入,这是我们的`28x28` MNIST 图像变平。 每个图像的输出将只是一个数字,这是鉴别者对该图像为真实图像的信心程度的分数。 我们使用 Leaky ReLu 作为激活函数,以防止 ReLu 单元死亡。 +我们需要做的第一件事就是创建我们的区分网络。 为此,我们将几个全连接层堆叠在一起。 判别器将 784 个长度向量作为输入,这是我们的`28x28` MNIST 图像变平。 每个图像的输出将只是一个数字,这是鉴别者对该图像为真实图像的信心程度的分数。 我们使用 Leaky ReLu 作为激活函数,以防止 ReLu 单元死亡。 -我们返回原始对率,因为损失函数将为我们应用 Sigmoid 激活函数,以确保鉴别器输出在 0 到 1 之间: +我们返回原始对率,因为损失函数将为我们应用 Sigmoid 激活函数,以确保判别器输出在 0 到 1 之间: ```py def discriminator(x): @@ -362,9 +362,9 @@ def discriminator(x): return logits ``` -# 发电机 +# 生成器 -现在我们创建发电机网络。 生成器的工作是将随机噪声的矢量作为输入,并从中生成输出图像。 在此示例中,我们再次使用全连接层,这些层最后将产生 784 个长向量的输出,我们可以对其进行整形以获得`28x28`的图像: +现在我们创建生成器网络。 生成器的工作是将随机噪声的矢量作为输入,并从中生成输出图像。 在此示例中,我们再次使用全连接层,这些层最后将产生 784 个长向量的输出,我们可以对其进行整形以获得`28x28`的图像: ```py def generator(z): @@ -381,15 +381,15 @@ def generator(z): # GAN 损失函数 -如前所述,鉴别器和生成器都有自己的损失函数,这些函数取决于彼此网络的输出。 我们可以将 GAN 视为在鉴别器和生成器之间玩 minimax 游戏,如下所示: +如前所述,判别器和生成器都有自己的损失函数,这些函数取决于彼此网络的输出。 我们可以将 GAN 视为在判别器和生成器之间玩 minimax 游戏,如下所示: ![](img/1d24b043-c4b8-42f0-8f9c-8f2c7db22ec3.png) 在这里,`D`是我们的判别器,`G`是我们的生成器,`z`是输入到生成器的随机矢量,`x`是真实图像。 尽管我们在此处给出了 GAN 损失的总和,但实际上更容易分别考虑这两种优化。 -为了训练 GAN,我们将在鉴别器和生成器之间交替进行梯度步骤更新。 在更新判别器时,我们要尝试使**最大化**判别器做出**正确选择**的概率。 在更新生成器时,我们想尝试使**最小化**鉴别器做出**正确选择**的可能性。 +为了训练 GAN,我们将在判别器和生成器之间交替进行梯度步骤更新。 在更新判别器时,我们要尝试使**最大化**判别器做出**正确选择**的概率。 在更新生成器时,我们想尝试使**最小化**判别器做出**正确选择**的可能性。 -但是,为了实际实现,我们将与之前给出的内容相比,稍微改变 GAN 损失函数; 这样做是为了帮助训练收敛。 变化是,当更新生成器时,而不是**最小化**鉴别器做出**正确选择**的可能性; 我们改为**最大化**判别器做出**错误选择**的概率: +但是,为了实际实现,我们将与之前给出的内容相比,稍微改变 GAN 损失函数; 这样做是为了帮助训练收敛。 变化是,当更新生成器时,而不是**最小化**判别器做出**正确选择**的可能性; 我们改为**最大化**判别器做出**错误选择**的概率: ![](img/5222b764-d50d-4fbc-9747-47a475579e50.png) @@ -397,37 +397,37 @@ def generator(z): ![](img/82987b0d-594f-4f08-9c76-436c0ec89fbc.png) -# 发电机损失 +# 生成器损失 -生成器想要欺骗鉴别器,换句话说,使鉴别器输出`q`用于生成的图像`G(z)`。 发生器损失只是施加到发生器结果的鉴别器输出的二项式交叉熵损失的负值。 请注意,由于生成器始终尝试生成“真实”图像,因此交叉熵损失可简化为: +生成器想要欺骗判别器,换句话说,使判别器输出`q`用于生成的图像`G(z)`。 发生器损失只是施加到发生器结果的判别器输出的二项式交叉熵损失的负值。 请注意,由于生成器始终尝试生成“真实”图像,因此交叉熵损失可简化为: ![](img/1761cebc-4eca-4a0f-81cf-9a128632ee81.png) 在这里,每个术语的含义如下: * `m`:批量 -* `D`:鉴别器 +* `D`:判别器 * `G`:生成器 * `z`:随机噪声向量 -我们想在训练 GAN 时最大化损失函数。 当损失最大化时,这意味着生成器能够生成可能使鉴别器蒙蔽的图像,并且鉴别器针对生成的图像输出 1。 +我们想在训练 GAN 时最大化损失函数。 当损失最大化时,这意味着生成器能够生成可能使判别器蒙蔽的图像,并且判别器针对生成的图像输出 1。 -# 鉴别器损失 +# 判别器损失 -鉴别者希望能够区分真实图像和生成图像。 它想为真实图像输出 1,为生成图像输出 0。 鉴别器损失函数具有以下公式,由于 GAN 训练和标记的工作方式而再次简化: +鉴别者希望能够区分真实图像和生成图像。 它想为真实图像输出 1,为生成图像输出 0。 判别器损失函数具有以下公式,由于 GAN 训练和标记的工作方式而再次简化: ![](img/6afbb7c8-d706-49dc-b74b-f8d9f894e8d3.png) 此损失函数有两个术语: -* 应用于鉴别器模型的二项式交叉熵产生了一些真实数据`x` -* 将二项式交叉熵应用于所生成数据`G(z)`的鉴别器模型结果 +* 应用于判别器模型的二项式交叉熵产生了一些真实数据`x` +* 将二项式交叉熵应用于所生成数据`G(z)`的判别器模型结果 -如前所述,我们采取这些不利条件,并希望在训练 GAN 时最大化此损失函数。 当这种损失最大化时,这意味着鉴别器能够区分实际输出和生成的输出。 注意,当鉴别器对于真实图像输出 1 而对于所生成图像输出 0 时,该损失最大。 +如前所述,我们采取这些不利条件,并希望在训练 GAN 时最大化此损失函数。 当这种损失最大化时,这意味着判别器能够区分实际输出和生成的输出。 注意,当判别器对于真实图像输出 1 而对于所生成图像输出 0 时,该损失最大。 # 综合损失 -在 TensorFlow 中,我们可以实现整个 GAN 损失,如以下代码所示。 作为输入,我们从鉴别器的输出中获取来自生成器的一批伪图像和来自我们的数据集的一批真实图像: +在 TensorFlow 中,我们可以实现整个 GAN 损失,如以下代码所示。 作为输入,我们从判别器的输出中获取来自生成器的一批伪图像和来自我们的数据集的一批真实图像: ```py def gan_loss(logits_real, logits_fake): @@ -452,15 +452,15 @@ def gan_loss(logits_real, logits_fake): return discriminator_loss , generator_loss ``` -您可能已经注意到,不可能同时最大化鉴别器损失和发生器损失。 这就是 GAN 的优点,因为在训练时,该模型有望达到某种平衡,在这种情况下,生成器必须生成真正高质量的图像,以欺骗鉴别器。 +您可能已经注意到,不可能同时最大化判别器损失和发生器损失。 这就是 GAN 的优点,因为在训练时,该模型有望达到某种平衡,在这种情况下,生成器必须生成真正高质量的图像,以欺骗判别器。 TensorFlow 仅允许其优化器最小化而不是最大化。 结果,我们实际上采用了前面所述的损失函数的负值,这意味着我们从最大化损失变为最小化损失。 不过,我们无需执行任何其他操作,因为`tf.nn.sigmoid_cross_entropy_with_logits()`会为我们解决此问题。 # 训练 GAN -因此,现在有了生成器,鉴别器和损失函数,剩下的就是训练! 我们将在 TensorFlow 中给出如何执行此操作的草图,因为这部分没有花哨的内容。 就像我们之前所做的那样,它只是将上一节中的内容以及加载和馈送 MNIST 图像拼凑在一起。 +因此,现在有了生成器,判别器和损失函数,剩下的就是训练! 我们将在 TensorFlow 中给出如何执行此操作的草图,因为这部分没有花哨的内容。 就像我们之前所做的那样,它只是将上一节中的内容以及加载和馈送 MNIST 图像拼凑在一起。 -首先,设置两个求解器:一个用于鉴别器,一个用于生成器。 已显示`AdamOptimizer`的较小值`beta1`,因为它已显示出可帮助 GAN 训练收敛: +首先,设置两个求解器:一个用于判别器,一个用于生成器。 已显示`AdamOptimizer`的较小值`beta1`,因为它已显示出可帮助 GAN 训练收敛: ```py discriminator_solver = tf.train.AdamOptimizer(learning_rate=0.001, beta1=0.5) @@ -475,7 +475,7 @@ generator_sample = generator(z) ``` -然后,我们将一批真实图像和一批生成的样本提供给鉴别器。 我们在这里使用变量范围来重用我们的模型变量,并确保不创建第二个图: +然后,我们将一批真实图像和一批生成的样本提供给判别器。 我们在这里使用变量范围来重用我们的模型变量,并确保不创建第二个图: ```py with tf.variable_scope("") as scope: @@ -509,13 +509,13 @@ generator_vars = tf.get_collection(tf.GraphKeys.TRAINABLE_VARIABLES, 'generator' ![](img/b6e289a6-0c13-4ee0-bb09-78bd4387231b.png) -# Deep convolutional GAN +# 深度卷积 GAN **深度卷积 GAN**(**DCGAN**)是我们之前看到的普通 GAN 的扩展。 我们不是使用全连接层,而是使用卷积层。 想法是使用卷积层可以帮助生成器形成更好的图像。 以下是这种模型的示例: ![](img/b9cf2f8e-db74-44ab-8090-d032d5a82d24.jpg) -DCGAN 的示例实现与之前训练普通 GAN 相同,只是简单地将鉴别器和生成器网络换成一些卷积架构,如以下代码所示。 请注意,生成器将使用转置卷积来上采样: +DCGAN 的示例实现与之前训练普通 GAN 相同,只是简单地将判别器和生成器网络换成一些卷积架构,如以下代码所示。 请注意,生成器将使用转置卷积来上采样: ```py def discriminator(x): @@ -549,7 +549,7 @@ def generator(z): return img ``` -只需换出生成器和鉴别器网络以使用卷积运算,我们就能生成如下图像: +只需换出生成器和判别器网络以使用卷积运算,我们就能生成如下图像: ![](img/ada0a5b7-1268-4f61-820a-3aca71dba80f.png) @@ -557,10 +557,10 @@ def generator(z): 需要注意的几点是: -* 对于鉴别器:再次使用泄漏的 relu,不要使用最大池。 仅使用跨步卷积或平均池。 +* 对于判别器:再次使用泄漏的 relu,不要使用最大池。 仅使用跨步卷积或平均池。 * 对于生成器:在最后一层使用 relu 和 tanh。 -* 通常,最佳实践是在生成器和鉴别器上都使用批量规范化层。 它们将始终设置为训练模式。 -* 有时,人们运行生成器优化器的次数是运行鉴别器优化器的两倍。 +* 通常,最佳实践是在生成器和判别器上都使用批量规范化层。 它们将始终设置为训练模式。 +* 有时,人们运行生成器优化器的次数是运行判别器优化器的两倍。 这是一个简单的 DCGAN 在生成人脸图像时可以达到的质量的示例: @@ -570,12 +570,12 @@ def generator(z): Wasserstein GAN 是 GAN 的另一种变体,它解决了训练 GAN 时可能发生的问题,即模式崩溃。 此外,其目的在于给出一种度量,该度量指示 GAN 何时收敛,换句话说,损失函数具有该值的含义。 -重要的更改是从损失中删除对数并修剪鉴别器权重。 +重要的更改是从损失中删除对数并修剪判别器权重。 此外,请按照下列步骤操作: -* 火车鉴别器比发电机更多 -* 减少鉴别器的重量 +* 火车判别器比生成器更多 +* 减少判别器的重量 * 使用 RMSProp 代替 Adam * 使用低学习率(0.0005) @@ -589,9 +589,9 @@ WGAN 的缺点是训练起来较慢: WGAN 产生的图像结果仍然不是很好,但是该模型确实有助于解决模式崩溃问题。 -# 开始 +# BEGAN -BEGAN 的主要思想是在鉴别器上使用自编码器,这将有其自身的损失,该损失会衡量自编码器对某些图像(生成器或真实数据)的重构程度: +BEGAN 的主要思想是在判别器上使用自编码器,这将有其自身的损失,该损失会衡量自编码器对某些图像(生成器或真实数据)的重构程度: ![](img/1a6f3311-6e16-492c-860d-45414eedbc67.jpg) @@ -607,9 +607,9 @@ BEGAN 的一些优点如下: ![](img/bf3a0b45-8535-40ec-93ed-fb4ca994202c.jpg) -# 有条件的 GAN +# 条件 GAN -条件 GAN 是普通 GAN 的扩展,其中鉴别器和生成器都被设置为某些特定类别`y`。这具有有趣的应用程序,因为您可以将生成器固定到特定的类,然后使其生成我们选择的特定同一类的多个不同版本。 例如,如果将`y`设置为与 MNIST 中的数字 7 对应的标签,则生成器将仅生成 7 的图像。 +条件 GAN 是普通 GAN 的扩展,其中判别器和生成器都被设置为某些特定类别`y`。这具有有趣的应用程序,因为您可以将生成器固定到特定的类,然后使其生成我们选择的特定同一类的多个不同版本。 例如,如果将`y`设置为与 MNIST 中的数字 7 对应的标签,则生成器将仅生成 7 的图像。 使用条件 GAN,minimax 游戏变为: @@ -629,7 +629,7 @@ GAN 当前最大的问题是,它们很难训练。 幸运的是,有一些技 # 损失可解释性 -训练 GAN 时的问题之一是,生成器损失和鉴别器损失的值都没有明显的影响。 这不像训练分类器,只是等待损失下降以查看模型是否在训练。 +训练 GAN 时的问题之一是,生成器损失和判别器损失的值都没有明显的影响。 这不像训练分类器,只是等待损失下降以查看模型是否在训练。 对于 GAN,损失值的下降并不一定意味着该模型正在训练中: @@ -637,14 +637,14 @@ GAN 当前最大的问题是,它们很难训练。 幸运的是,有一些技 通过许多人的实验和研究,以下是有关如何使用 GAN 损失值的一些提示: -* 您不希望鉴别器的损失下降得很快,因为它将无法向生成器提供反馈以改善它。 -* 如果发电机损失迅速下降,则意味着它发现了一个鉴别器弱点,并一次又一次地利用了这一弱点。 如果发生这种情况,则称为**模式折叠**。 +* 您不希望判别器的损失下降得很快,因为它将无法向生成器提供反馈以改善它。 +* 如果生成器损失迅速下降,则意味着它发现了一个判别器弱点,并一次又一次地利用了这一弱点。 如果发生这种情况,则称为**模式折叠**。 -损失实际上仅对查看训练中是否出现问题有好处。 因此,没有很好的方法知道训练已经收敛。 通常,最好的办法是继续查看发电机的输出。 确保输出看起来与您的期望接近,并且输出种类丰富。 +损失实际上仅对查看训练中是否出现问题有好处。 因此,没有很好的方法知道训练已经收敛。 通常,最好的办法是继续查看生成器的输出。 确保输出看起来与您的期望接近,并且输出种类丰富。 # 模式崩溃 -这可能是您在训练 GAN 时遇到的第一个问题。 当生成器找到一组特定的输入来欺骗鉴别器时,就会发生模式崩溃,并且它会继续利用这种故障情况并将潜伏`Z`空间中的许多值折叠为相同的值。 +这可能是您在训练 GAN 时遇到的第一个问题。 当生成器找到一组特定的输入来欺骗判别器时,就会发生模式崩溃,并且它会继续利用这种故障情况并将潜伏`Z`空间中的许多值折叠为相同的值。 解决此问题的一种方法是使用“小批量功能”或“展开 GANs”,或者完全停止训练,然后在生成器开始创建非常狭窄的输出分布时重新开始: @@ -659,21 +659,21 @@ GAN 当前最大的问题是,它们很难训练。 幸运的是,有一些技 * 归一化输入到 -1/1 之间 * 使用 BatchNorm * 使用 Leaky Relu(判别器) -* 在发电机输出上使用 Relu(发电机),tanh +* 在生成器输出上使用 Relu(生成器),tanh * 对于下采样,请使用平均池化或跨步卷积 * 使用 Adam 优化器 -* 如果鉴别器损失迅速下降,则说明存在问题 -* 在发电机上使用压降(在训练阶段和测试阶段) +* 如果判别器损失迅速下降,则说明存在问题 +* 在生成器上使用压降(在训练阶段和测试阶段) -# 小批量鉴别器 +# 小批量判别器 用于改善模式崩溃的一些技术如下: -* 取得鉴别器某层的输出 -* 将鉴别器的输入重塑为矩阵 +* 取得判别器某层的输出 +* 将判别器的输入重塑为矩阵 * 计算 L1 距离 * 计算 L1 距离的指数和 -* 将结果连接到输入(鉴别器的某些层) +* 将结果连接到输入(判别器的某些层) ![](img/9f716a8f-5a7f-40fc-94fc-ae5f004e4724.jpg) diff --git a/docs/handson-cnn-tf/7.md b/docs/handson-cnn-tf/7.md index 592bd424..8c63d300 100644 --- a/docs/handson-cnn-tf/7.md +++ b/docs/handson-cnn-tf/7.md @@ -11,7 +11,7 @@ 本章涵盖的主要主题如下: * 使用来自另一个训练过的模型的权重预先初始化一个模型 -* 在需要时使用 TensorFlow 加载模型并冻结/解冻图层 +* 在需要时使用 TensorFlow 加载模型并冻结/解冻层 # 什么时候? @@ -108,9 +108,9 @@ class CAE_CNN_Encoder(object): return self.__x_image ``` -# 选择图层 +# 选择层 -一旦定义了模型`model = CAE_CNN_Encoder` `()`,选择将要使用预训练权重初始化的图层就很重要。 请注意,两个网络的结构(要初始化的网络和提供训练后的权重的网络)必须相同。 因此,例如,以下代码片段将选择名称为`convs`为`fc`的所有层: +一旦定义了模型`model = CAE_CNN_Encoder` `()`,选择将要使用预训练权重初始化的层就很重要。 请注意,两个网络的结构(要初始化的网络和提供训练后的权重的网络)必须相同。 因此,例如,以下代码片段将选择名称为`convs`为`fc`的所有层: ```py from models import CAE_CNN_Encoder @@ -133,7 +133,7 @@ list_fc_linear = [v for v in tf.global_variables() if "fc" in v.name or "output" ] ``` -将定义图的图层分为卷积和完全连接两个列表后,您将使用`tf.Train.Saver`加载所需的权重。 首先,我们需要创建一个保存器对象,将要从检查点加载的变量列表作为输入,如下所示: +将定义图的层分为卷积和完全连接两个列表后,您将使用`tf.Train.Saver`加载所需的权重。 首先,我们需要创建一个保存器对象,将要从检查点加载的变量列表作为输入,如下所示: ```py # Define the saver object to load only the conv variables @@ -157,15 +157,15 @@ saver = tf.train.Saver() 请注意,调用`restore`会覆盖`global_variables_initializer`,所有选定的权重都将替换为检查点的权重。 -# 仅训练一些层次 +# 仅训练一些层 -迁移学习的另一个重要部分是冻结不需要训练的图层的权重,同时允许对某些图层(通常是最后一层)进行训练。 在 TensorFlow 中,我们可以仅将要优化的层传递给求解器(在此示例中,仅将 FC 层传递给): +迁移学习的另一个重要部分是冻结不需要训练的层的权重,同时允许对某些层(通常是最后一层)进行训练。 在 TensorFlow 中,我们可以仅将要优化的层传递给求解器(在此示例中,仅将 FC 层传递给): ```py train_step = tf.train.AdamOptimizer(learning_rate).minimize(loss, var_list=list_fc_linear) ``` -# 完整资料 +# 完整代码 在此示例中,我们将从 MNIST 卷积自编码器示例中加载权重。 我们将仅恢复编码器部分的权重,冻结卷积层,并训练 FC 层以执行数字分类: diff --git a/docs/handson-cnn-tf/8.md b/docs/handson-cnn-tf/8.md index 3a18289e..bec2e03b 100644 --- a/docs/handson-cnn-tf/8.md +++ b/docs/handson-cnn-tf/8.md @@ -24,7 +24,7 @@ 8. 将您的数据集分为训练,开发和测试集 9. 评估模型 -# 资料准备 +# 数据准备 所有机器学习算法的骨干都是数据。 机器学习算法学习的一切都来自数据。 因此,至关重要的是向算法提供代表问题陈述的正确数据。 就像已经看到的那样,深度学习特别需要大量数据用于训练模型。 有时我们可以说一定数量的数据足以解决问题,但是却永远不够! 多多益善。 能够正确训练的模型的复杂度与训练模型上的数据量成正比。 有限的数据将为该问题的模型体系结构选择设定上限。 在考虑可用数据量时,还值得注意的是,其中一部分也需要用于验证和测试目的。 @@ -125,7 +125,7 @@ ML 基本配方 ![](img/3b7eb077-6c15-4a77-989a-40b12e4b70db.png) -# 资料不平衡 +# 数据不平衡 我们已经看到了数据表示和分布在解决偏差和方差问题中的重要性。 我们遇到的另一个相关问题是分类任务中各个类之间的数据分配不均。 这称为数据不平衡。 例如,如果我们有一个二进制分类问题,并且其中一个类别有 50000 张图像,而另一个类别只有 1000 张图像,这可能会导致训练算法的性能出现巨大问题。 我们必须通过以下方法解决数据不平衡的问题: @@ -135,13 +135,13 @@ ML 基本配方 # 查看您的效果指标 -分类准确性不是一个很好的衡量标准,尤其是当我们的数据不平衡时。 这种准确性将更倾向于具有更多数据的类。 有许多良好的性能评估指标可以真实地描述算法的执行方式,例如混淆矩阵,**受试者工作特性曲线**(ROC),**精确找回**(PR)曲线和 F1 分数。 这些将在本章稍后详细说明。 +分类准确性不是一个很好的衡量标准,尤其是当我们的数据不平衡时。 这种准确性将更倾向于具有更多数据的类。 有许多良好的性能评估指标可以真实地描述算法的执行方式,例如混淆矩阵,**受试者工作特性曲线**(ROC),**精确召回**(PR)曲线和 F1 分数。 这些将在本章稍后详细说明。 -# 数据综合/扩充 +# 数据综合/增强 在无法从其他资源收集数据,数据集太小或收集的数据不能很好地表示的情况下,我们需要以某种方式自行生成数据。 这称为数据增强。 智能生成的数据可以解决许多问题,包括数据集不平衡,训练数据不足和过拟合。 -数据扩充通常是作为输入数据管道的一部分来完成的,该管道在训练时为模型提供数据。 随机地,而不是提供原始训练图像,您将应用一些增强来更改它。 有很多方法可以进行数据扩充,但是一些示例是: +数据扩充通常是作为输入数据流水线的一部分来完成的,该流水线在训练时为模型提供数据。 随机地,而不是提供原始训练图像,您将应用一些增强来更改它。 有很多方法可以进行数据扩充,但是一些示例是: * 增加噪音 * 应用几何变换 @@ -166,7 +166,7 @@ Tensorflow 已经具有其损失函数,并内置了加权选项: 例如,如果您尝试对 A,B,C 三个类别进行分类,其中 A 为 10%,B 为 45%,C 为 45%,则可以将`tf.losses.sparse_softmax_cross_entropy`用于以下权重:`[1.0, 0.3, 0.3]`。 -# 评估指标 +# 评价指标 在为模型选择评估指标时,我们还需要小心。 假设对于狗/非狗分类问题,我们有两种算法的准确度分别为 98% 和 96%。 乍一看,这些算法看起来都具有相似的性能。 让我们记住,分类准确度定义为做出的正确预测数除以做出的预测总数。 换句话说,真阳性(TP)和真阴性(TN)预测数除以预测总数。 但是,可能出现的情况是,随着狗图像的出现,我们还会得到大量被错误分类为狗的背景或类似外观的物体,通常称为假阳性(FP)。 另一个不良行为可能是许多狗图像被错误分类为负面或假阴性(FN)。 显然,根据定义,分类准确性不能捕获误报或误报的概念。 因此,需要更好的评估指标。 @@ -341,7 +341,7 @@ class CAE_CNN_Encoder(object): return self.__x_image ``` -# CNN 创建食谱 +# CNN 创建秘籍 以下几点基于我们在训练神经网络方面的经验以及该领域研究人员认为的当前最佳实践。 希望如果您需要从头开始设计自己的 CNN 架构,他们将为您提供帮助。 但是,在尝试设计自己的 CNN 之前,您应该查看其他现成的体系结构以从中学习,并检查它们是否已经为您完成了工作。 diff --git a/docs/handson-cnn-tf/9.md b/docs/handson-cnn-tf/9.md index 1490141a..d79b917a 100644 --- a/docs/handson-cnn-tf/9.md +++ b/docs/handson-cnn-tf/9.md @@ -34,7 +34,7 @@ 我们可以根据需要使用几种不同的格式来存储数据,例如 HDF5 或 LMDB。 但是,当我们使用 TensorFlow 时,我们将继续使用其自己的内置格式 TFRecords。 TFRecords 是 TensorFlow 自己的标准文件格式,用于存储数据。 它是一种二进制文件格式,提供对其内容的顺序访问。 它足够灵活,可以存储复杂的数据集和标签以及我们可能想要的任何元数据。 -# 制作 TFRecord +# 创建 TFRecord 在开始之前,让我们分解一下 TFRecord 的工作方式。 打开 TFRecord 文件进行写入后,创建一个称为`Example`的内容。 这只是一个协议缓冲区,我们将使用它填充要保存在其中的所有数据。 在示例中,我们将数据存储在`Feature`中。 功能是描述示例中数据的一种方式。 功能可以是以下三种类型之一:字节列表,浮点列表或`int64`列表。 将所有数据放入功能部件并将它们写入示例缓冲区后,我们会将整个协议缓冲区序列化为字符串,然后将其写入 TFRecord 文件。 @@ -82,13 +82,13 @@ for index in range(len(labels)): 为了允许我们随机播放数据,我们可以做的一件事是通过创建多个 TFRecord 文件并将数据散布到这些多个文件中来*分片*我们的数据。 这样,我们可以在每个纪元处重新整理加载 TFRecord 文件的顺序,因此我们在训练时将为我们有效地整理数据。 每 100 万张图像需要 1000 个碎片,这是可以遵循的良好基准。 -在下一节中,我们将看到如何使用 TFRecords 建立有效的数据馈送管道。 +在下一节中,我们将看到如何使用 TFRecords 建立有效的数据馈送流水线。 -# 建立高效的管道 +# 建立高效的流水线 当我们处理较小的数据集时,仅将整个数据集加载到计算机内存中就足够了。 如果您的数据集足够小,这很简单并且可以正常工作; 但是,在很多时候,情况并非如此。 现在我们将研究如何克服这个问题。 -为了避免一次加载所有数据,我们将需要创建一个数据管道以将我们的训练数据馈入模型。 除其他事项外,该管道将负责从存储中加载一批元素,对数据进行预处理,最后将数据提供给我们的模型。 幸运的是,这一切都可以使用 TensorFlow 数据 API 轻松完成。 +为了避免一次加载所有数据,我们将需要创建一个数据流水线以将我们的训练数据馈入模型。 除其他事项外,该流水线将负责从存储中加载一批元素,对数据进行预处理,最后将数据提供给我们的模型。 幸运的是,这一切都可以使用 TensorFlow 数据 API 轻松完成。 对于这些示例,我们将假定已将数据保存到多个(在本例中为两个)TFRecord 文件中,如先前所述。 如果您有两个以上,则没有区别; 您只需在设置内容时包括所有名称即可。 @@ -126,7 +126,7 @@ return image, label train_dataset = train_dataset.map(decode_tfrec, num_parallel_calls=4) ``` -# 并行调用地图转换 +# 映射转换的并行调用 默认情况下,您在数据集上调用的任何地图转换都仅作用于数据集的单个元素,并且将按顺序处理元素。 要加快速度并使用所有 CPU 功能,最简单的方法是将`num_parallel_calls`参数设置为可用的 CPU 内核数。 这样,我们就不会浪费任何可用的 CPU 能力。 但是,警告您不要将其设置为高于可用内核的数量,因为由于调度效率低下,这实际上可能会降低性能。 @@ -140,17 +140,17 @@ train_dataset = train_dataset.map(decode_tfrec, num_parallel_calls=4) # Decode # 批量 -您希望在管道末尾做的最后一件事是生成一批准备发送到 GPU 进行训练的数据。 这可以通过批量方法简单地完成,并传入所需的批量大小: +您希望在流水线末尾做的最后一件事是生成一批准备发送到 GPU 进行训练的数据。 这可以通过批量方法简单地完成,并传入所需的批量大小: ```py train_dataset = train_dataset.batch(128) # Take a batch of 128 from the dataset. ``` -当试图使我们的管道尽可能高效时,批次的大小是一个重要的参数。 尽可能大可能并不总是最好的。 例如,如果您的图像上有很多预处理步骤,那么当 CPU 对大量图像进行预处理时,GPU 可能会处于空闲状态。 +当试图使我们的流水线尽可能高效时,批次的大小是一个重要的参数。 尽可能大可能并不总是最好的。 例如,如果您的图像上有很多预处理步骤,那么当 CPU 对大量图像进行预处理时,GPU 可能会处于空闲状态。 # 预取 -我们能够建立有效数据管道的另一种方法是始终准备好一批数据准备发送到 GPU。 理想情况下,在训练模型时,我们希望 GPU 的使用率始终保持在 100%。 这样,我们可以最大程度地利用昂贵的硬件,该硬件可以在训练时有效地计算前进和后退的传球次数。 +我们能够建立有效数据流水线的另一种方法是始终准备好一批数据准备发送到 GPU。 理想情况下,在训练模型时,我们希望 GPU 的使用率始终保持在 100%。 这样,我们可以最大程度地利用昂贵的硬件,该硬件可以在训练时有效地计算前进和后退的传球次数。 为此,我们需要 CPU 加载并准备一批图像,以准备在向前和向后传递模型的过程中传递给 GPU。 幸运的是,在收集批量之后,我们可以使用简单的预取转换轻松完成此操作,如下所示: @@ -158,13 +158,13 @@ train_dataset = train_dataset.batch(128) # Take a batch of 128 from the dataset train_dataset= train_dataset.batch(128).prefetch(1) ``` -使用预取将确保我们的数据管道在进行训练时为我们准备一整批数据,准备将其加载到 GPU 中以进行下一次迭代。 这样做可以确保我们的管道在等待一批批次收集之前不会减慢速度,并且如果获取批次所需的时间少于模型的前后传递时间,那么我们的管道将尽可能高效。 +使用预取将确保我们的数据流水线在进行训练时为我们准备一整批数据,准备将其加载到 GPU 中以进行下一次迭代。 这样做可以确保我们的流水线在等待一批批次收集之前不会减慢速度,并且如果获取批次所需的时间少于模型的前后传递时间,那么我们的流水线将尽可能高效。 要清楚的是,此处使用`prefetch(1)`表示我们`prefetch`整批数据。 这就是为什么我们将批量作为流水线的最后一步,并在此处使用预取功能,因为这样做最有效。 -# 追踪图形 +# 追踪图 -TensorFlow 提供了一种很好的方式来分析并查看整个图形通过其时间轴跟踪工具执行所需的时间。 这是查看图表的哪些部分正在减慢训练速度并发现数据管道中任何低效率的好工具。 +TensorFlow 提供了一种很好的方式来分析并查看整个图形通过其时间轴跟踪工具执行所需的时间。 这是查看图表的哪些部分正在减慢训练速度并发现数据流水线中任何低效率的好工具。 我们将从为您提供如何跟踪图形的示例开始。 这非常简单:您只需在常规代码中添加几行,就会生成一个 JSON 文件,我们可以将该文件加载到 Google Chrome 浏览器中,以查看图形执行的所有时间: @@ -192,7 +192,7 @@ with tf.Session() as sess: 现在将显示跟踪图形的结果。 查看此内容将告诉您图形的每个部分执行所需的时间。 您应该特别注意存在大块空白的地方。 这些空白表示设备(例如您的 GPU)正坐在那里等待数据,以便它们可以执行计算。 您应该尝试通过优化数据馈送方式来消除这些问题。 -但是请注意,您的管道可能已完全优化,但是您没有 CPU 周期来足够快地处理管道。 检查您的 CPU 使用情况,看看是否是这种情况。 +但是请注意,您的流水线可能已完全优化,但是您没有 CPU 周期来足够快地处理流水线。 检查您的 CPU 使用情况,看看是否是这种情况。 # TensorFlow 中的分布式计算 @@ -305,7 +305,7 @@ CREATE INDEX idxAngle ON tb_drive (wheel_angle);​ CREATE INDEX idxAcc ON tb_drive (acc);​ ``` -# 用 Python 进行查询 +# 将 Python 用于查询 首先,在开始玩之前,我们需要安装 Python 驱动程序`pip install cassandra-driver​`; 以下代码片段仅列出了 Cassandra 集群中表的内容: @@ -372,7 +372,7 @@ nodetool -h localhost snapshot mydb​ * **弹性计算云**(**EC2**) * S3 -* 贤者 +* SageMaker # EC2 @@ -394,7 +394,7 @@ nodetool -h localhost snapshot mydb​ 可用端口 -# 哪一个 +# AMI 这是 AWS 中最酷的功能之一,它使您可以从所有数据和已安装的工具(从一个服务器实例到另一个服务器实例)创建映像。 因此,您可以仅使用所有工具,驱动程序等配置一台服务器,以后再使用具有相同映像的另一台服务器: @@ -412,7 +412,7 @@ Amazon S3 是存储系统,您可以在其中从常规 HTTP 请求上传/下载 S3 系统可以进行公共配置,因此人们可以从任何地方下载/上传内容。 -# 贤者 +# SageMaker SageMaker 提供了一种在云中训练/部署机器学习模型的简便方法。 SageMaker 将提供 Jupyter 笔记本,您可以在其中可视化/训练模型并直接连接到 S3 中的数据(提供了访问 S3 的 API): -- GitLab