Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
安浅Y
apachecn-dl-zh
提交
cd0e53ae
A
apachecn-dl-zh
项目概览
安浅Y
/
apachecn-dl-zh
与 Fork 源项目一致
Fork自
OpenDocCN / apachecn-dl-zh
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
A
apachecn-dl-zh
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
前往新版Gitcode,体验更适合开发者的 AI 搜索 >>
提交
cd0e53ae
编写于
9月 15, 2020
作者:
W
wizardforcel
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
2020-09-15 22:53:24
上级
389d6b1a
变更
9
隐藏空白更改
内联
并排
Showing
9 changed file
with
51 addition
and
51 deletion
+51
-51
docs/handson-cnn-tf/1.md
docs/handson-cnn-tf/1.md
+7
-7
docs/handson-cnn-tf/2.md
docs/handson-cnn-tf/2.md
+9
-9
docs/handson-cnn-tf/3.md
docs/handson-cnn-tf/3.md
+10
-10
docs/handson-cnn-tf/4.md
docs/handson-cnn-tf/4.md
+3
-3
docs/handson-cnn-tf/5.md
docs/handson-cnn-tf/5.md
+2
-2
docs/handson-cnn-tf/6.md
docs/handson-cnn-tf/6.md
+5
-5
docs/handson-cnn-tf/7.md
docs/handson-cnn-tf/7.md
+2
-2
docs/handson-cnn-tf/8.md
docs/handson-cnn-tf/8.md
+12
-12
docs/handson-cnn-tf/9.md
docs/handson-cnn-tf/9.md
+1
-1
未找到文件。
docs/handson-cnn-tf/1.md
浏览文件 @
cd0e53ae
...
...
@@ -133,7 +133,7 @@ def my_conv_2d(input, weight_shape, num_filters, strides):
return
conv_layer_out
```
这个示例比您实际实现的简单得多,但是您已经可以看到开始建立代码的行数,以及必须注意的事情,例如构造权重和添加偏
见
项。 一个模型也将具有许多不同种类的层,而不仅仅是卷积层,所有这些层都必须以与此非常相似的方式来构造。
这个示例比您实际实现的简单得多,但是您已经可以看到开始建立代码的行数,以及必须注意的事情,例如构造权重和添加偏
置
项。 一个模型也将具有许多不同种类的层,而不仅仅是卷积层,所有这些层都必须以与此非常相似的方式来构造。
因此,不仅要为模型中所需的每种新层将这些内容写出来都非常费力,而且还引入了更多的区域,在这些区域中,错误可能会潜入您的代码中,这从来都不是一件好事。
...
...
@@ -195,7 +195,7 @@ test_data = shuffled_data[105:]
test_labels
=
shuffled_labels
[
105
:]
```
让我们再次看一下这段代码,看看到目前为止我们做了什么。 导入 TensorFlow 和 Numpy 之后,我们将整个数据集加载到内存中。 我们的数据由表示为向量的四个数值特征组成。 我们总共有 150 个数据点,因此我们的数据将是形状为
`150 x 4`
的矩阵,其中每一行代表不同的数据点,每一列代表不同的
要素
。 每个数据点还具有与之关联的目标标签,该目标标签存储在单独的标签向量中。
让我们再次看一下这段代码,看看到目前为止我们做了什么。 导入 TensorFlow 和 Numpy 之后,我们将整个数据集加载到内存中。 我们的数据由表示为向量的四个数值特征组成。 我们总共有 150 个数据点,因此我们的数据将是形状为
`150 x 4`
的矩阵,其中每一行代表不同的数据点,每一列代表不同的
特征
。 每个数据点还具有与之关联的目标标签,该目标标签存储在单独的标签向量中。
接下来,我们重新整理数据集; 这一点很重要,因此,当我们将其分为训练集和测试集时,我们在这两个集之间平均分配,并且最终不会在一组集中获得所有一种类型的数据。
...
...
@@ -235,7 +235,7 @@ test_labels = shuffled_labels[105:]
# 变量
我们如何在 TensorFlow 代码中全部写出来? 让我们开始创建权重和偏
见
。 在 TensorFlow 中,如果我们想创建一些可以被我们的代码操纵的张量,那么我们需要使用 TensorFlow 变量。 TensorFlow 变量是
`tf.Variable`
类的实例。
`tf.Variable`
类表示
`tf.Tensor`
对象,可以通过在其上运行 TensorFlow 操作来更改其值。 变量是类似于张量的对象,因此它们可以以与张量相同的方式传递,并且可以与张量一起使用的任何操作都可以与变量一起使用。
我们如何在 TensorFlow 代码中全部写出来? 让我们开始创建权重和偏
置
。 在 TensorFlow 中,如果我们想创建一些可以被我们的代码操纵的张量,那么我们需要使用 TensorFlow 变量。 TensorFlow 变量是
`tf.Variable`
类的实例。
`tf.Variable`
类表示
`tf.Tensor`
对象,可以通过在其上运行 TensorFlow 操作来更改其值。 变量是类似于张量的对象,因此它们可以以与张量相同的方式传递,并且可以与张量一起使用的任何操作都可以与变量一起使用。
要创建变量,我们可以使用
`tf.get_variable()`
。 调用此函数时,必须提供变量的名称。 此函数将首先检查图上是否没有其他具有相同名称的变量,如果没有,则它将创建新变量并将其添加到 TensorFlow 图。
...
...
@@ -328,7 +328,7 @@ initializer = tf.global_variables_initializer()
![](
img/ac5b44f4-5e15-41b7-90d1-139736012555.png
)
这个概念实际上是非常直观的,因为如果我们的权重和偏
见
得到了正确的训练,那么所产生的三个得分中的最高得分就可以自信地表明输入示例所属的正确类别。
这个概念实际上是非常直观的,因为如果我们的权重和偏
置
得到了正确的训练,那么所产生的三个得分中的最高得分就可以自信地表明输入示例所属的正确类别。
由于在训练期间,我们会一次输入许多训练示例,因此,我们将获得多个需要平均的损失。 因此,需要最小化的总损失方程如下:
...
...
@@ -366,7 +366,7 @@ loss = tf.reduce_mean(tf.losses.hinge_loss(logits=model_out, labels=y))
TensorFlow 的好处在于,它使用其内置的优化器(称为
**自动微分**
)为我们计算了所有所需的梯度。 我们要做的就是选择一个梯度下降优化器,并告诉它最小化我们的损失函数。 TensorFlow 将自动计算所有梯度,然后使用这些梯度为我们更新权重。
我们可以在
`tf.train`
模块中找到优化程序类。 现在,我们将使用
`GradientDescentOptimizer`
类,它只是基本的梯度下降优化算法。 创建优化器时,我们必须提供学习率。 学习
速
率的值是
`hyperparameter`
,用户必须通过反复试验和实验来对其进行调整。 0.5 的值应该可以很好地解决此问题。
我们可以在
`tf.train`
模块中找到优化程序类。 现在,我们将使用
`GradientDescentOptimizer`
类,它只是基本的梯度下降优化算法。 创建优化器时,我们必须提供学习率。 学习率的值是
`hyperparameter`
,用户必须通过反复试验和实验来对其进行调整。 0.5 的值应该可以很好地解决此问题。
优化器节点具有一种称为
`minimize`
的方法。 在您提供的损失函数上调用此方法会做两件事。 首先,针对您的整个图计算与该损失有关的梯度。 其次,这些梯度用于更新所有相关变量。
...
...
@@ -382,7 +382,7 @@ optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.5).minimize(loss)
我们汇总了训练模型所需的所有零件。 开始训练之前的最后一件事是,我们想在图中创建一些节点,这些节点将使我们能够在完成训练后测试模型的执行情况。
我们将创建一个节点来计算模型的准确
性
。
我们将创建一个节点来计算模型的准确
率
。
`Tf.equal`
将返回一个布尔列表,指示两个提供的列表在哪里相等。 在找到最大值的索引之后,在这种情况下,我们的两个列表将是模型的标签和输出:
...
...
@@ -432,7 +432,7 @@ with tf.Session() as sess:
print
(
"Test Accuracy:"
,
sess
.
run
(
accuracy
,
feed_dict
=
{
x
:
test_data
,
y
:
test_labels
}))
```
运行 1000 次迭代后,我们使用另一个
`session.run`
调用来获取精度节点的输出。 我们执行两次,一次输入我们的训练数据以获取训练集的准确
性,一次输入我们保留的测试数据以获取测试集的准确性
。 您应该从
`0.977778`
中打印出测试精度,这意味着我们的模型可以正确分类 45 个测试集中的 44 个,一点也不差!
运行 1000 次迭代后,我们使用另一个
`session.run`
调用来获取精度节点的输出。 我们执行两次,一次输入我们的训练数据以获取训练集的准确
率,一次输入我们保留的测试数据以获取测试集的准确率
。 您应该从
`0.977778`
中打印出测试精度,这意味着我们的模型可以正确分类 45 个测试集中的 44 个,一点也不差!
# 总结
...
...
docs/handson-cnn-tf/2.md
浏览文件 @
cd0e53ae
...
...
@@ -40,7 +40,7 @@ ML 使用诸如统计分析,概率模型,决策树和神经网络之类的*
假设对于我们的手部数据,我们有 1000 张不同的图像,现在我们已经对其进行处理以提取每个图像的特征向量。 在机器学习阶段,所有特征向量都将被提供给创建模型的机器学习系统。 我们希望该模型能够推广并能够预测未经过系统训练的任何未来图像的数字。
ML 系统的组成部分是评估。 在评估模型时,我们会看到模型在特定任务中的表现。 在我们的示例中,我们将研究它可以多么准确地从图像中预测数字。 90% 的准确
度
意味着正确预测了 100 张给定图像中的 90 张。 在接下来的章节中,我们将更详细地讨论机器训练和评估过程。
ML 系统的组成部分是评估。 在评估模型时,我们会看到模型在特定任务中的表现。 在我们的示例中,我们将研究它可以多么准确地从图像中预测数字。 90% 的准确
率
意味着正确预测了 100 张给定图像中的 90 张。 在接下来的章节中,我们将更详细地讨论机器训练和评估过程。
# ML 的类型
...
...
@@ -182,7 +182,7 @@ ML 的新型深度学习方法具有的最酷的功能是,它们不需要(
较大的批次大小可以更好地估计真实梯度。 使用较大的批次大小将允许较大的学习率。 权衡是在训练时需要更多的内存来保存此批次。
当模型看到您的整个数据集时,我们说一个
纪元已经完成。 由于训练的随机性,您将需要针对多个时期训练模型,因为您的模型不可能只在一个时
期内收敛。
当模型看到您的整个数据集时,我们说一个
周期已经完成。 由于训练的随机性,您将需要针对多个周期训练模型,因为您的模型不可能只在一个周
期内收敛。
# 损失函数
...
...
@@ -200,7 +200,7 @@ ML 的新型深度学习方法具有的最酷的功能是,它们不需要(
在本书中,我们将看到损失函数的不同示例。
损失函数的另一个重要方面是它们必须是可
区
分的。 否则,我们不能将它们与反向传播一起使用。 这是因为反向传播要求我们能够采用损失函数的导数。
损失函数的另一个重要方面是它们必须是可
微
分的。 否则,我们不能将它们与反向传播一起使用。 这是因为反向传播要求我们能够采用损失函数的导数。
在下图中,您可以看到损失函数连接在神经网络的末端(模型输出),并且基本上取决于模型的输出和数据集所需的目标。
...
...
@@ -236,7 +236,7 @@ TensorFlow 的所有不同优化器都可以在`tf.train`类中找到。 例如
学习率的另一个重要方面是,随着训练的进行和误差的减少,您在训练开始时选择的学习率值可能会变得太大,因此您可能会开始超出最小值。
要解决此问题,您可以安排学习
速率衰减,以免在训练时降低学习速
率。 这个过程称为
**学习率调度**
,我们将在下一章中详细讨论几种流行的方法。
要解决此问题,您可以安排学习
率衰减,以免在训练时降低学习
率。 这个过程称为
**学习率调度**
,我们将在下一章中详细讨论几种流行的方法。
另一种解决方案是使用自适应优化器之一,例如 Adam 或 RMSProp。 这些优化器经过精心设计,可在您训练时自动调整和衰减所有模型参数的学习率。 这意味着从理论上讲,您不必担心安排自己的学习率下降。
...
...
@@ -274,9 +274,9 @@ TensorFlow 的所有不同优化器都可以在`tf.train`类中找到。 例如
如果输入向量的不同维度上的值彼此不成比例,则损失空间将以某种方式扩大。 这将使梯度下降算法难以收敛,或者至少使其收敛较慢。
当数据集的
要素
超出比例时,通常会发生这种情况。 例如,关于房屋的数据集在输入向量中的一个特征可能具有“房间数”,其值可能在 1 到 4 之间,而另一个特征可能是“房屋面积”,并且可能在 1000 到 10000 之间。 ,它们彼此之间严重超出比例,这可能会使学习变得困难。
当数据集的
特征
超出比例时,通常会发生这种情况。 例如,关于房屋的数据集在输入向量中的一个特征可能具有“房间数”,其值可能在 1 到 4 之间,而另一个特征可能是“房屋面积”,并且可能在 1000 到 10000 之间。 ,它们彼此之间严重超出比例,这可能会使学习变得困难。
在下面的图片中,我们看到一个简单的示例,说明如果我们的输入
要素
未全部按比例缩放,则损失函数的外观以及正确缩放比例后的外观。 当数据缩放不正确时,梯度下降很难达到损失函数的最小值。
在下面的图片中,我们看到一个简单的示例,说明如果我们的输入
特征
未全部按比例缩放,则损失函数的外观以及正确缩放比例后的外观。 当数据缩放不正确时,梯度下降很难达到损失函数的最小值。
![](
img/01d83517-803f-4442-b37d-a508371fdd0b.jpg
)
...
...
@@ -304,7 +304,7 @@ reshaped_input_to_dense_layer = tf.reshape(spatial_tensor_in, [-1, 28 * 28 * 3])
# 针对 XOR 问题的 TensorFlow 示例
在这里,我们将到目前为止已经了解的一些知识放在一起,并将使用 TensorFlow 解决布尔 XOR 问题。 在此示例中,我们将创建一个具有 Sigmoid 激活函数的三层神经网络。 我们使用对数
丢
失,因为网络 0 或 1 仅有两种可能的结果:
在这里,我们将到目前为止已经了解的一些知识放在一起,并将使用 TensorFlow 解决布尔 XOR 问题。 在此示例中,我们将创建一个具有 Sigmoid 激活函数的三层神经网络。 我们使用对数
损
失,因为网络 0 或 1 仅有两种可能的结果:
```
py
import
tensorflow
as
tf
...
...
@@ -491,7 +491,7 @@ out_height = ceil(float(in_height) / float(strides[1]))
*
卷积核大小(
`F`
)
*
过滤器数量(
`M`
)
*
输入
要素
图的高度和宽度(
`H`
,
`W`
)
*
输入
特征
图的高度和宽度(
`H`
,
`W`
)
*
输入批量(
`B`
)
*
输入深度大小(通道)(
`C`
)
*
卷积层步幅(
`S`
)
...
...
@@ -702,7 +702,7 @@ print("Test Accuracy:",sess.run(accuracy, feed_dict={x_: mnist.test.images, y_:
# TensorBoard
TensorBoard 是 TensorFlow 随附的基于 Web 的工具,可让您可视化构造的 TensorFlow 图。 最重要的是,它使您能够跟踪大量的统计数据或变量,这些数据或变量可能对训练模型很重要。 您可能希望跟踪的此类变量的示例包括训练损失,测试集准确
性
或学习率。 前面我们看到,我们可以使用张量板可视化损失函数的值。
TensorBoard 是 TensorFlow 随附的基于 Web 的工具,可让您可视化构造的 TensorFlow 图。 最重要的是,它使您能够跟踪大量的统计数据或变量,这些数据或变量可能对训练模型很重要。 您可能希望跟踪的此类变量的示例包括训练损失,测试集准确
率
或学习率。 前面我们看到,我们可以使用张量板可视化损失函数的值。
要运行 TensorBoard,请打开一个新终端并输入以下内容:
...
...
docs/handson-cnn-tf/3.md
浏览文件 @
cd0e53ae
...
...
@@ -51,7 +51,7 @@
# 交叉熵损失(对数损失)
图像分类的最简单形式是二
进制分类。 在这里,我们有一个分类器,该分类器只有一个要分类的对象,例如狗/不是狗。 在这种情况下,我们可能使用的损失函数是二进制
交叉熵损失。
图像分类的最简单形式是二
分类。 在这里,我们有一个分类器,该分类器只有一个要分类的对象,例如狗/不是狗。 在这种情况下,我们可能使用的损失函数是二元
交叉熵损失。
真实标签
`p`
与模型预测
`q`
之间的交叉熵函数定义为:
...
...
@@ -71,7 +71,7 @@
这在直觉上是正确的,因为当
`y=1`
时,我们要最小化
`L(y, y_hat) = - log(y_hat)`
,需要最大化
`y_hat`
;当
`y=0`
时,我们要最小化
`L(y, y_hat) = - log(1 - y_hat)`
,需要最小化
`y_hat`
。
在 TensorFlow 中,可以在
`tf.losses`
模块中找到二
进制
交叉熵损失。 知道我们模型的原始输出
`y_hat`
的名称是
`logits`
很有用。 在将其传递给交叉熵损失之前,我们需要对其应用
**Sigmoid**
函数,以便我们的输出在 0 到 1 之间缩放。TensorFlow 实际上将所有这些步骤组合为一个操作,如下面的代码。 TensorFlow 还将为我们平均分批量损失。
在 TensorFlow 中,可以在
`tf.losses`
模块中找到二
元
交叉熵损失。 知道我们模型的原始输出
`y_hat`
的名称是
`logits`
很有用。 在将其传递给交叉熵损失之前,我们需要对其应用
**Sigmoid**
函数,以便我们的输出在 0 到 1 之间缩放。TensorFlow 实际上将所有这些步骤组合为一个操作,如下面的代码。 TensorFlow 还将为我们平均分批量损失。
```
py
loss
=
tf
.
losses
.
sigmoid_cross_entropy
(
multi_class_labels
=
labels_in
,
logits
=
model_prediction
)
...
...
@@ -349,11 +349,11 @@ decayed_learning_rate = learning_rate * decay_rate ^ (global_step / decay_steps)
通过使用这种方法,学习率会随着训练时间的推移而平稳降低。
最后一种方法是使用我们的验证集,并查看验证集上的当前准确
性。 在验证准确性不断提高的同时,我们对学习率无能为力。 一旦验证准确性
停止增加,我们就将学习率降低某种程度。 重复此过程,直到训练结束。
最后一种方法是使用我们的验证集,并查看验证集上的当前准确
率。 在验证准确率不断提高的同时,我们对学习率无能为力。 一旦验证准确率
停止增加,我们就将学习率降低某种程度。 重复此过程,直到训练结束。
所有方法都可以产生良好的结果,当您进行训练以查看哪种方法更适合您时,可能值得尝试所有这些不同的方法。 对于此特定模型,我们将使用第二种方法,即学习
速
率呈指数衰减。 我们使用 TensorFlow 操作
`tf.train.exponential_decay`
来执行此操作,该操作遵循前面显示的公式。 作为输入,它采用当前的学习率,全局步长,衰减之前的步数和衰减率。
所有方法都可以产生良好的结果,当您进行训练以查看哪种方法更适合您时,可能值得尝试所有这些不同的方法。 对于此特定模型,我们将使用第二种方法,即学习率呈指数衰减。 我们使用 TensorFlow 操作
`tf.train.exponential_decay`
来执行此操作,该操作遵循前面显示的公式。 作为输入,它采用当前的学习率,全局步长,衰减之前的步数和衰减率。
在每次迭代中,当前的学习
速
率都会提供给我们的 Adam 优化器,后者使用
`minimize`
函数,该函数使用梯度下降来使损失最小化并将
`global_step`
变量增加 1。 最后,在训练期间,将
`learning_rate`
和
`global_step`
添加到摘要数据以在 TensorBoard 上显示:
在每次迭代中,当前的学习率都会提供给我们的 Adam 优化器,后者使用
`minimize`
函数,该函数使用梯度下降来使损失最小化并将
`global_step`
变量增加 1。 最后,在训练期间,将
`learning_rate`
和
`global_step`
添加到摘要数据以在 TensorBoard 上显示:
```
py
with
tf
.
name_scope
(
"optimizer"
)
as
scope
:
...
...
@@ -538,7 +538,7 @@ decayed_learning_rate = learning_rate * decay_rate ^ (global_step / decay_steps)
这样做会破坏权重的对称性,因为它们都是随机且唯一的,这是一件好事。 计算向前和向后通过时,我们的模型神经元现在将以不同的方式进行更新。 这将使他们有机会学习许多不同的功能,这些功能将作为大型神经网络的一部分协同工作。
然后唯一需要担心的是我们设定的
体
重值有多小。 如果设置得太小,反向传播更新也将非常小,这可能会在更深层的网络中消失梯度问题。
然后唯一需要担心的是我们设定的
权
重值有多小。 如果设置得太小,反向传播更新也将非常小,这可能会在更深层的网络中消失梯度问题。
下图显示了权重的要求之一(零均值):
...
...
@@ -645,7 +645,7 @@ combined_loss = tf.n_add(train_loss, reg_losses)
# 退出
我们将要讨论的另一种用于正则化的技术是一种称为丢弃的东西。
辍学是由 G.E. Hinton 于 2012 年提出的,它是一种简单的正则化方法,可带来很好的效果。 辍学
背后的想法是,在每次训练迭代中,一层中的所有神经元都可以以随机概率(通常为 50%)打开和关闭。
我们将要讨论的另一种用于正则化的技术是一种称为丢弃的东西。
丢弃法是由 G.E. Hinton 于 2012 年提出的,它是一种简单的正则化方法,可带来很好的效果。 丢弃法
背后的想法是,在每次训练迭代中,一层中的所有神经元都可以以随机概率(通常为 50%)打开和关闭。
这种打开和关闭迫使网络学习与往常相同的概念,但是要通过多个不同的路径。 训练后,所有神经元都保持打开状态,这些路径的行为就像是多个网络的集合,用于平均最终结果,从而提高了泛化能力。 它迫使权重分布在整个网络中,并且像正则化一样将权重保持在较低水平。
...
...
@@ -653,13 +653,13 @@ combined_loss = tf.n_add(train_loss, reg_losses)
![](
img/cce137ca-2838-44ac-b275-7e83d01a5ddb.png
)
在下图中,我们显示了模型测试误差。 显然,通过
辍学,测试集上的误差会减少。 请记住,与所有正则化一样,与不使用正则化相比,使用辍学
会使您的训练损失增加,但是到最后,我们只对模型测试错误率降低(泛化)感兴趣:
在下图中,我们显示了模型测试误差。 显然,通过
丢弃法,测试集上的误差会减少。 请记住,与所有正则化一样,与不使用正则化相比,使用丢弃法
会使您的训练损失增加,但是到最后,我们只对模型测试错误率降低(泛化)感兴趣:
![](
img/eef8f1a2-e6e1-40aa-9c0e-8ef692a60665.png
)
通常,
辍学仅适用于全连接层,但也可以适用于卷积/池化层。 如果这样做,则将使用较低的
`p`
(掉线的可能性),接近 0.2。 同样,您将辍学
层放置在激活层之后。
通常,
丢弃法仅适用于全连接层,但也可以适用于卷积/池化层。 如果这样做,则将使用较低的
`p`
(掉线的可能性),接近 0.2。 同样,您将丢弃
层放置在激活层之后。
要在 TensorFlow 模型中使用丢弃法,我们在希望将丢弃法应用到的输入层上调用
`tf.layers.dropout()`
。 我们还必须指定我们要使用的
辍学率,更重要的是,使用布尔值让 TensorFlow 知道我们的模型是否在训练中。 请记住,当我们在测试时使用模型时,我们会关闭辍学,而这个布尔值将为我们做到这一点。 因此,带有辍学
的代码将如下所示:
要在 TensorFlow 模型中使用丢弃法,我们在希望将丢弃法应用到的输入层上调用
`tf.layers.dropout()`
。 我们还必须指定我们要使用的
丢弃率,更重要的是,使用布尔值让 TensorFlow 知道我们的模型是否在训练中。 请记住,当我们在测试时使用模型时,我们会关闭丢弃,而这个布尔值将为我们做到这一点。 因此,带有丢弃
的代码将如下所示:
```
py
# Fully connected layer (in tf contrib folder for now)
...
...
docs/handson-cnn-tf/4.md
浏览文件 @
cd0e53ae
...
...
@@ -200,7 +200,7 @@ RoI 层的输入将是建议和最后的卷积层激活。 例如,考虑以下
| --- | --- | --- | --- |
| 每个图像的测试时间 | 50 秒 | 2 秒 | 0.2 秒 |
| 加速 | 1 倍 | 25 倍 | 250 倍 |
| 准确
性
| 66% | 66.9% | 66.9% |
| 准确
率
| 66% | 66.9% | 66.9% |
# 将传统的 CNN 转换为全卷积网络
...
...
@@ -234,7 +234,7 @@ YOLO 网络的主要思想是在不使用任何滑动窗口的情况下优化输
请注意,网格的每个单元格都负责预测固定数量的边界框。
下图描述了作为 YOLO 网络输出的单元格条目的样子,它预测了形状的张量
`(N, N, B * 5 + C)`
。 网络的最后一个卷积层将输出与栅格尺寸相同大小的
要素
图。
下图描述了作为 YOLO 网络输出的单元格条目的样子,它预测了形状的张量
`(N, N, B * 5 + C)`
。 网络的最后一个卷积层将输出与栅格尺寸相同大小的
特征
图。
![](
img/c0865621-4388-4c74-80d1-33cfc363f626.png
)
...
...
@@ -448,7 +448,7 @@ Tensorflow 已经具有实现非最大值抑制算法的功能,称为`tf.image
![](
img/a96483b7-4839-448c-b67c-09b8c05d871c.png
)
`C`
是置信度分数(受对象的存在调制的项)。
`C_hat`
是带有真实情况的预测边界框的 IOU。 参数
`λ[noobj] = 0.5`
用于使无对象时的
丢
失关注度降低。
`C`
是置信度分数(受对象的存在调制的项)。
`C_hat`
是带有真实情况的预测边界框的 IOU。 参数
`λ[noobj] = 0.5`
用于使无对象时的
损
失关注度降低。
# 损失第 3 部分
...
...
docs/handson-cnn-tf/5.md
浏览文件 @
cd0e53ae
...
...
@@ -301,7 +301,7 @@ GoogLeNet 的主要优点是,它比 VGG 更为准确,同时使用的参数
# 残差网络
在前面的部分中,已经证明了网络的深度是有助于提高准确
性的关键因素(请参见 VGG)。 TensorFlow 中的第 3 章“图像分类”中也显示,可以通过正确的权重初始化和批量归一化来缓解深度网络中梯度消失或爆炸的问题。 但是,这是否意味着我们添加的层越多,我们得到的系统就越准确? 亚洲研究机构 Microsoft 的《用于图像识别的深度残差学习》的作者发现,只要网络深度达到 30 层,准确性
就会达到饱和。 为了解决此问题,他们引入了一个称为残差块的新层块,该块将上一层的输出添加到下一层的输出中(请参见下图)。 残差网络或 ResNet 在非常深的网络(甚至超过 100 层!)中都显示了出色的结果,例如 152 层的 ResNet 赢得了 2015 LRVC 图像识别挑战,其前 5 个测试误差为 3.57。 事实证明,诸如 ResNets 之类的更深层网络要比包括 Inception 模块(例如 GoogLeNet)在内的更广泛的网络更好地工作。
在前面的部分中,已经证明了网络的深度是有助于提高准确
率的关键因素(请参见 VGG)。 TensorFlow 中的第 3 章“图像分类”中也显示,可以通过正确的权重初始化和批量归一化来缓解深度网络中梯度消失或爆炸的问题。 但是,这是否意味着我们添加的层越多,我们得到的系统就越准确? 亚洲研究机构 Microsoft 的《用于图像识别的深度残差学习》的作者发现,只要网络深度达到 30 层,准确率
就会达到饱和。 为了解决此问题,他们引入了一个称为残差块的新层块,该块将上一层的输出添加到下一层的输出中(请参见下图)。 残差网络或 ResNet 在非常深的网络(甚至超过 100 层!)中都显示了出色的结果,例如 152 层的 ResNet 赢得了 2015 LRVC 图像识别挑战,其前 5 个测试误差为 3.57。 事实证明,诸如 ResNets 之类的更深层网络要比包括 Inception 模块(例如 GoogLeNet)在内的更广泛的网络更好地工作。
![](
img/d8ad63df-15dd-4d20-b918-a3f18767a9c8.png
)
...
...
@@ -380,7 +380,7 @@ for group_i, group in enumerate(groups):
# MobileNet
我们将以一个新的 CNN 系列结束本章,该系列不仅具有较高的准确
性
,而且更轻巧,并且在移动设备上的运行速度更快。
我们将以一个新的 CNN 系列结束本章,该系列不仅具有较高的准确
率
,而且更轻巧,并且在移动设备上的运行速度更快。
由 Google 创建的 MobileNet 的关键功能是它使用了不同的“三明治”形式的卷积块。 它不是通常的(
`CONV`
,
`BATCH_NORM,RELU`
),而是将
`3x3`
卷积拆分为
`3x3`
深度卷积,然后是
`1x1`
点向卷积。他们称此块为深度可分离卷积。
...
...
docs/handson-cnn-tf/6.md
浏览文件 @
cd0e53ae
...
...
@@ -98,7 +98,7 @@ class CAE_CNN(object):
self
.
__y_flat
=
tf
.
reshape
(
self
.
__y
,
[
tf
.
shape
(
self
.
__x
)[
0
],
28
*
28
])
```
与卷积自编码器
丢
失有关的代码段如下:
与卷积自编码器
损
失有关的代码段如下:
```
py
with
tf
.
name_scope
(
"CAE_LOSS"
):
...
...
@@ -172,7 +172,7 @@ KL 散度损失将产生一个数字,该数字指示两个分布彼此之间
0.5
*
tf
.
reduce_sum
(
tf
.
square
(
latent_mean
)
+
tf
.
square
(
latent_stddev
)
-
tf
.
log
(
tf
.
square
(
latent_stddev
))
-
1
,
1
)
```
不幸的是,有一个
**样本**
块,您可以将其视为随机生成器节点,无法
区
分。 这意味着我们不能使用反向传播来训练我们的 VAE。 我们需要一种称为“重新参数化”技巧的东西,该技巧将从反向传播流中取出采样。
不幸的是,有一个
**样本**
块,您可以将其视为随机生成器节点,无法
微
分。 这意味着我们不能使用反向传播来训练我们的 VAE。 我们需要一种称为“重新参数化”技巧的东西,该技巧将从反向传播流中取出采样。
# 重新参数化技巧
...
...
@@ -182,7 +182,7 @@ KL 散度损失将产生一个数字,该数字指示两个分布彼此之间
![](
img/ae58ed7b-25c5-447d-bb71-54d32dc9ed15.jpg
)
产生的潜向量将与以前相同,但是现在进行此更改可以使梯度流回到 VAE 的编码器部分。 下图显示了在进行重新参数化之前的 VAE 模型,在左侧进行了重新参数化之后。 蓝色框是损失函数的两个部分。 查看该图,您可以看到我们的
渐变
现在可以向后流动,因为我们不再具有红色框(示例节点)来挡路了:
产生的潜向量将与以前相同,但是现在进行此更改可以使梯度流回到 VAE 的编码器部分。 下图显示了在进行重新参数化之前的 VAE 模型,在左侧进行了重新参数化之后。 蓝色框是损失函数的两个部分。 查看该图,您可以看到我们的
梯度
现在可以向后流动,因为我们不再具有红色框(示例节点)来挡路了:
![](
img/412bfece-2f71-4956-a5fe-3ae19cce2b6b.png
)
...
...
@@ -349,7 +349,7 @@ GAN 的一些实际用法如下:
# 判别器
我们需要做的第一件事就是创建我们的
区分
网络。 为此,我们将几个全连接层堆叠在一起。 判别器将 784 个长度向量作为输入,这是我们的
`28x28`
MNIST 图像变平。 每个图像的输出将只是一个数字,这是鉴别者对该图像为真实图像的信心程度的分数。 我们使用 Leaky ReLu 作为激活函数,以防止 ReLu 单元死亡。
我们需要做的第一件事就是创建我们的
判别
网络。 为此,我们将几个全连接层堆叠在一起。 判别器将 784 个长度向量作为输入,这是我们的
`28x28`
MNIST 图像变平。 每个图像的输出将只是一个数字,这是鉴别者对该图像为真实图像的信心程度的分数。 我们使用 Leaky ReLu 作为激活函数,以防止 ReLu 单元死亡。
我们返回原始对率,因为损失函数将为我们应用 Sigmoid 激活函数,以确保判别器输出在 0 到 1 之间:
...
...
@@ -486,7 +486,7 @@ generator_sample = generator(z)
```
由于需要分别更新它们,因此我们将
区分符
和生成器的权重分开:
由于需要分别更新它们,因此我们将
判别器
和生成器的权重分开:
```
py
discriminator_vars
=
tf
.
get_collection
(
tf
.
GraphKeys
.
TRAINABLE_VARIABLES
,
'discriminator'
)
...
...
docs/handson-cnn-tf/7.md
浏览文件 @
cd0e53ae
# 七、迁移学习
迁移学习的作用恰如其名。 这个想法是将从一项任务中学到的东西
转
移到另一项任务上。 为什么? 实际上,每次都从头开始训练整个模型的效率很低,其成功取决于许多因素。 另一个重要原因是,对于某些应用,公开可用的数据集不够大,无法训练出像 AlexNet 或 ResNet 这样的深层架构而又不会过拟合,这意味着无法推广。 示例应用可以从用户给出的一些示例中进行在线学习,也可以是细粒度的分类,其中类别之间的差异很小。
迁移学习的作用恰如其名。 这个想法是将从一项任务中学到的东西
迁
移到另一项任务上。 为什么? 实际上,每次都从头开始训练整个模型的效率很低,其成功取决于许多因素。 另一个重要原因是,对于某些应用,公开可用的数据集不够大,无法训练出像 AlexNet 或 ResNet 这样的深层架构而又不会过拟合,这意味着无法推广。 示例应用可以从用户给出的一些示例中进行在线学习,也可以是细粒度的分类,其中类别之间的差异很小。
一个非常有趣的观察结果是,由于您冻结了所有其余部分(无论是检测还是分类),最终的层可以用于完成不同的任务,最终权重看起来非常相似。
...
...
@@ -17,7 +17,7 @@
研究表明,在 ImageNet 上训练的卷积网络权重中的特征提取优于常规特征提取方法,例如 SURF,可变形部分描述符(
**DPD**
),
**直方图定向梯度**
(
**HOG**
)和
**词袋**
(
**BoW**
)。 这意味着无论常规视觉表示如何工作,卷积特征都可以同样好地使用,唯一的缺点是更深的架构可能需要更长的时间来提取特征。
当在 ImageNet 上训练深层卷积神经网络时,第一层中的卷积过滤器的可视化(请参见下图)显示,他们学习了
*低层*
特征,类似于边检测过滤器,而卷积过滤器在最后一层学习
*高级*
功能,这些功能捕获特定于类的信息。 因此,如果我们在第一个池化层之后提取 ImageNet 的特征并将其嵌入 2D 空间(例如,使用 t-SNE),则可视化将显示数据中存在一些无中心状态,而如果在全连接层上执行相同操作,我们将注意到具有相同语义信息的数据被组织成簇。 这意味着网络可以在更高层次上很好地概括,并且有可能将这种知识
转
移到看不见的类别中。
当在 ImageNet 上训练深层卷积神经网络时,第一层中的卷积过滤器的可视化(请参见下图)显示,他们学习了
*低层*
特征,类似于边检测过滤器,而卷积过滤器在最后一层学习
*高级*
功能,这些功能捕获特定于类的信息。 因此,如果我们在第一个池化层之后提取 ImageNet 的特征并将其嵌入 2D 空间(例如,使用 t-SNE),则可视化将显示数据中存在一些无中心状态,而如果在全连接层上执行相同操作,我们将注意到具有相同语义信息的数据被组织成簇。 这意味着网络可以在更高层次上很好地概括,并且有可能将这种知识
迁
移到看不见的类别中。
![](
img/b7b186d6-7803-4517-add9-f559586b2576.png
)
...
...
docs/handson-cnn-tf/8.md
浏览文件 @
cd0e53ae
...
...
@@ -16,7 +16,7 @@
1.
查找与您类似的问题并下载代码(并测试模型以检查结果)
2.
根据需要找到扩展计算的方法(即 AWS/Google Cloud)
3.
从较小的数据集开始,以避免浪费时间等待一个
纪元
3.
从较小的数据集开始,以避免浪费时间等待一个
周期
4.
从简单的架构开始
5.
使用可视化/调试(例如,TensorBoard)
6.
微调模型,微调超参数,深度,架构,层和损失函数
...
...
@@ -40,7 +40,7 @@
为了获得高表现的神经网络,将数据集正确划分为训练集,开发集和测试集非常重要。 它有助于更快地迭代。 另外,它允许更有效地测量算法的偏差和方差,以便我们可以选择有效方式进行改进的方法。
在以前的
时代,我们拥有较小的数据集(例如最多 10,000 个示例)和简单的分类器,我们会将数据集拆分为训练和测试集。 通常将训练集分成较小的集,以使用称为交叉验证的技术来训练分类器。 优良作法是按 60/20/20 的比例拆分数据集(即 60% 的训练数据,20% 的开发数据,20% 的测试数据)。 但是,大数据的现代时代
已经改变了这一经验法则。 如果我们有 1,000,000 个示例,则拆分比例已更改为 98/1/1(即 98% 的训练数据,1% 的开发数据,1% 的测试数据)。
在以前的
周期,我们拥有较小的数据集(例如最多 10,000 个示例)和简单的分类器,我们会将数据集拆分为训练和测试集。 通常将训练集分成较小的集,以使用称为交叉验证的技术来训练分类器。 优良作法是按 60/20/20 的比例拆分数据集(即 60% 的训练数据,20% 的开发数据,20% 的测试数据)。 但是,大数据的现代周期
已经改变了这一经验法则。 如果我们有 1,000,000 个示例,则拆分比例已更改为 98/1/1(即 98% 的训练数据,1% 的开发数据,1% 的测试数据)。
随着我们拥有更多的数据,开发和测试集的比例将变小。
...
...
@@ -66,13 +66,13 @@
最好的方法是根据上图将其拆分。 分布 1 被拆分为训练集,其一部分用作开发集。 在这里,我们称其为“训练开发集”(因为开发集与训练集具有相同的分布)。 分布 1 主要用于训练,因为它是一个大型数据集。 分布 2 分为测试集和开发集,它们与分布 1 中的任一集无关。这里要强调的一点是,测试和开发集应来自同一发行版,并且属于我们实际上关心的应用,即目标应用。 开发集和测试集通常是小的数据集,因为它们的目的是给出模型/算法的无偏表现估计。
模型在不同数据集分区上的误差差异,以及查看人为误差可为我们提供诊断偏
见
和方差问题的见解
模型在不同数据集分区上的误差差异,以及查看人为误差可为我们提供诊断偏
差
和方差问题的见解
下表显示了当左列中的集合之间存在误差时,应如何诊断。 注意,人为水平误差是此分析的基准,它为比较模型提供了基准。
![](
img/43b92390-d3d8-4104-a0e8-0b0e03958557.png
)
下表可以更好地说明这一点。 在这些示例中,我们假设在所有情况下的最佳/人为误差均最小,即 1%。 通常,深度学习模型的准确
性
与人类相似,因此将其作为比较可帮助您找到良好的架构。
下表可以更好地说明这一点。 在这些示例中,我们假设在所有情况下的最佳/人为误差均最小,即 1%。 通常,深度学习模型的准确
率
与人类相似,因此将其作为比较可帮助您找到良好的架构。
*
高偏差/欠拟合
...
...
@@ -81,7 +81,7 @@
| 人为/最佳误差 | 1% |
| 训练误差 | 15% |
与人员水平的表现相比,训练误差较大,这意味着该模型甚至无法拟合数据。 训练有素,因此欠拟合/高偏
见
。 但是,当我们在这种情况下查看开发误差时,它可以很好地概括,因此不会丢失所有内容。
与人员水平的表现相比,训练误差较大,这意味着该模型甚至无法拟合数据。 训练有素,因此欠拟合/高偏
差
。 但是,当我们在这种情况下查看开发误差时,它可以很好地概括,因此不会丢失所有内容。
*
高方差/过拟合
...
...
@@ -127,7 +127,7 @@ ML 基本秘籍
# 数据不平衡
我们已经看到了数据表示和分布在解决偏差和方差问题中的重要性。 我们遇到的另一个相关问题是分类任务中各个类之间的数据分配不均。 这称为数据不平衡。 例如,如果我们有一个二
进制
分类问题,并且其中一个类别有 50000 张图像,而另一个类别只有 1000 张图像,这可能会导致训练算法的表现出现巨大问题。 我们必须通过以下方法解决数据不平衡的问题:
我们已经看到了数据表示和分布在解决偏差和方差问题中的重要性。 我们遇到的另一个相关问题是分类任务中各个类之间的数据分配不均。 这称为数据不平衡。 例如,如果我们有一个二分类问题,并且其中一个类别有 50000 张图像,而另一个类别只有 1000 张图像,这可能会导致训练算法的表现出现巨大问题。 我们必须通过以下方法解决数据不平衡的问题:
# 收集更多数据
...
...
@@ -135,7 +135,7 @@ ML 基本秘籍
# 查看您的效果指标
分类准确
性不是一个很好的衡量标准,尤其是当我们的数据不平衡时。 这种准确性
将更倾向于具有更多数据的类。 有许多良好的表现评估指标可以真实地描述算法的执行方式,例如混淆矩阵,
**受试者工作特性曲线**
(ROC),
**精确召回**
(PR)曲线和 F1 分数。 这些将在本章稍后详细说明。
分类准确
率不是一个很好的衡量标准,尤其是当我们的数据不平衡时。 这种准确率
将更倾向于具有更多数据的类。 有许多良好的表现评估指标可以真实地描述算法的执行方式,例如混淆矩阵,
**受试者工作特性曲线**
(ROC),
**精确召回**
(PR)曲线和 F1 分数。 这些将在本章稍后详细说明。
# 数据综合/增强
...
...
@@ -168,7 +168,7 @@ Tensorflow 已经具有其损失函数,并内置了加权选项:
# 评价指标
在为模型选择评估指标时,我们还需要小心。 假设对于狗/非狗分类问题,我们有两种算法的准确
度分别为 98% 和 96%。 乍一看,这些算法看起来都具有相似的表现。 让我们记住,分类准确度定义为做出的正确预测数除以做出的预测总数。 换句话说,真阳性(TP)和真阴性(TN)预测数除以预测总数。 但是,可能出现的情况是,随着狗图像的出现,我们还会得到大量被错误分类为狗的背景或类似外观的对象,通常称为假阳性(FP)。 另一个不良行为可能是许多狗图像被错误分类为负面或假阴性(FN)。 显然,根据定义,分类准确性
不能捕获误报或误报的概念。 因此,需要更好的评估指标。
在为模型选择评估指标时,我们还需要小心。 假设对于狗/非狗分类问题,我们有两种算法的准确
率分别为 98% 和 96%。 乍一看,这些算法看起来都具有相似的表现。 让我们记住,分类准确率定义为做出的正确预测数除以做出的预测总数。 换句话说,真阳性(TP)和真阴性(TN)预测数除以预测总数。 但是,可能出现的情况是,随着狗图像的出现,我们还会得到大量被错误分类为狗的背景或类似外观的对象,通常称为假阳性(FP)。 另一个不良行为可能是许多狗图像被错误分类为负面或假阴性(FN)。 显然,根据定义,分类准确率
不能捕获误报或误报的概念。 因此,需要更好的评估指标。
第一步,我们将构建一个混淆矩阵,该矩阵总结最后显示的段落:
...
...
@@ -223,9 +223,9 @@ PPV: TP / (TP + FP) = 0/0 = 0
NPV
:
TN
/
(
TN
+
FN
)
=
201
/
286
=
0.70
```
在第一个示例中,我们可以得到 69% 的正确精度,但是在第二个示例中,通过仅对每个示例进行预测,我们实际上将我们的精度提高到 70% ! 显然,仅预测所有事物为负类的模型并不是一个很好的模型,这就是我们所说的准确
性悖论。 简单来说,“准确性悖论”说,即使模型可能具有更高的准确性
,但实际上可能并不是更好的模型。
在第一个示例中,我们可以得到 69% 的正确精度,但是在第二个示例中,通过仅对每个示例进行预测,我们实际上将我们的精度提高到 70% ! 显然,仅预测所有事物为负类的模型并不是一个很好的模型,这就是我们所说的准确
率悖论。 简单来说,“准确率悖论”说,即使模型可能具有更高的准确率
,但实际上可能并不是更好的模型。
如前面的示例中所示,当类别不平衡变大时,更可能发生这种现象。 鼓励读者对包含 85 个正样本和 85 个负样本的平衡数据集重复上述测试。 如果假阳性与假阴性的比例与前面的示例相同,则这将导致第一个示例的分类准确
度为 52%,第二个示例的分类准确度为 50%,这表明准确性
悖论不适用于平衡数据集。
如前面的示例中所示,当类别不平衡变大时,更可能发生这种现象。 鼓励读者对包含 85 个正样本和 85 个负样本的平衡数据集重复上述测试。 如果假阳性与假阴性的比例与前面的示例相同,则这将导致第一个示例的分类准确
率为 52%,第二个示例的分类准确率为 50%,这表明准确率
悖论不适用于平衡数据集。
为了能够正确评估算法,我们需要查看其他评估指标,例如 TPR 和 FPR。 我们可以看到在第二个示例中它们都为零,这表明算法根本无法检测到所需的正向对象。
...
...
@@ -249,9 +249,9 @@ PPV: TP / (TP + FP) = 0.09
NPV
:
TN
/
(
TN
+
FN
)
=
0.99
```
此处的测试似乎表现不错,因为准确
性为 99%。 但是,如果您被诊断出患有癌症,这并不意味着您患该病的可能性为 99%。 应该注意的是,在 1098 个测试阳性的患者中,只有 99 个患有该疾病。 这意味着,如果您获得了阳性测试,那么对于准确度
高达 99% 的测试,您实际患病的可能性仅为 9%。
此处的测试似乎表现不错,因为准确
率为 99%。 但是,如果您被诊断出患有癌症,这并不意味着您患该病的可能性为 99%。 应该注意的是,在 1098 个测试阳性的患者中,只有 99 个患有该疾病。 这意味着,如果您获得了阳性测试,那么对于准确率
高达 99% 的测试,您实际患病的可能性仅为 9%。
这些示例很好地警告了我们的目标是在测试数据中进行均衡分配,尤其是当您使用准确
性
指标比较不同模型的有效性时。
这些示例很好地警告了我们的目标是在测试数据中进行均衡分配,尤其是当您使用准确
率
指标比较不同模型的有效性时。
比较不同算法的其他有用方法是精确调用和接收器操作特性曲线。 如果我们针对不同的阈值计算上述指标,则可以绘制这些图。 如果我们算法的输出不是二进制的(0 表示负数,1 表示正数),但分数在测试为正时接近 1,而在测试为负时接近零,那么 TP,TN,FP,FN 的数量将取决于我们选择的阈值。
...
...
docs/handson-cnn-tf/9.md
浏览文件 @
cd0e53ae
...
...
@@ -80,7 +80,7 @@ for index in range(len(labels)):
尽管我们说最好将所有数据保存在一个文件中,但实际上并非 100% 正确。 由于 TFRecords 是按顺序读取的,因此,如果仅使用一个文件,我们将无法重新整理数据集。 经过一段时间的训练之后,每次到达 TFRecord 的末尾时,您都将返回到数据集的开头,但是不幸的是,每次浏览文件时,数据的顺序都相同。
为了允许我们随机播放数据,我们可以做的一件事是通过创建多个 TFRecord 文件并将数据散布到这些多个文件中来
*分片*
我们的数据。 这样,我们可以在每个
纪元
处重新整理加载 TFRecord 文件的顺序,因此我们在训练时将为我们有效地整理数据。 每 100 万张图像需要 1000 个碎片,这是可以遵循的良好基准。
为了允许我们随机播放数据,我们可以做的一件事是通过创建多个 TFRecord 文件并将数据散布到这些多个文件中来
*分片*
我们的数据。 这样,我们可以在每个
周期
处重新整理加载 TFRecord 文件的顺序,因此我们在训练时将为我们有效地整理数据。 每 100 万张图像需要 1000 个碎片,这是可以遵循的良好基准。
在下一节中,我们将看到如何使用 TFRecords 建立有效的数据馈送流水线。
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录