网站建设推广语潮州网站设计
- 作者: 五速梦信息网
- 时间: 2026年03月21日 07:44
当前位置: 首页 > news >正文
网站建设推广语,潮州网站设计,佛山网红打卡地,北关网站制作原文#xff1a;Hands-on Deep Learning with TensorFlow 协议#xff1a;CC BY-NC-SA 4.0 译者#xff1a;飞龙 本文来自【ApacheCN 深度学习 译文集】#xff0c;采用译后编辑#xff08;MTPE#xff09;流程来尽可能提升效率。 不要担心自己的形象#xff0c;只关心如… 原文Hands-on Deep Learning with TensorFlow 协议CC BY-NC-SA 4.0 译者飞龙 本文来自【ApacheCN 深度学习 译文集】采用译后编辑MTPE流程来尽可能提升效率。 不要担心自己的形象只关心如何实现目标。——《原则》生活原则 2.3.c 一、入门 TensorFlow 是 Google 最近发布的新的机器学习和图计算库。 其 Python 接口可确保通用模型的优雅设计而其编译后的后端可确保速度。 让我们看一下应用 TensorFlow 时要学习的技术和要构建的模型。 安装 TensorFlow 在本节中您将学习什么是 TensorFlow如何安装 TensorFlow 以及如何构建简单模型和进行简单计算。 此外您将学习如何建立用于分类的逻辑回归模型并介绍机器学习问题以帮助我们学习 TensorFlow。 我们将学习 TensorFlow 是什么类型的库并将其安装在我们自己的 Linux 机器上如果您无法访问 Linux 机器则将其安装在 CoCalc 的免费实例中。 TensorFlow 主页 首先什么是 TensorFlow TensorFlow 是 Google 推出的新的机器学习库。 它被设计为非常易于使用且非常快。 如果您访问 TensorFlow 网站则可以访问有关 TensorFlow 是什么以及如何使用的大量信息。 我们将经常提到这一点特别是文档。 TensorFlow 安装页面 在我们开始使用 TensorFlow 之前请注意您需要先安装它因为它可能尚未预先安装在您的操作系统上。 因此如果转到 TensorFlow 网页上的“安装”选项卡单击在 Ubuntu 上安装 TensorFlow然后单击“本机 PIP”您将学习如何安装 TensorFlow。 即使对于经验丰富的系统管理员来说安装 TensorFlow 也是非常困难的。 因此我强烈建议您使用类似pip的安装方式。 或者如果您熟悉 Docker请使用 Docker 安装。 您可以从源代码安装 TensorFlow但这可能非常困难。 我们将使用称为 wheel 文件的预编译二进制文件安装 TensorFlow。 您可以使用 Python 的pip模块安装程序来安装此文件。 通过pip安装 对于pip安装您可以选择使用 Python2 或 Python3 版本。 另外您可以在 CPU 和 GPU 版本之间进行选择。 如果您的计算机具有功能强大的显卡则可能适合您使用 GPU 版本。 但是您需要检查显卡是否与 TensorFlow 兼容。 如果不是那很好。 本系列中的所有内容都可以仅使用 CPU 版本来完成。 注意 我们可以使用pip install tensorflow命令基于您的 CPU 或 GPU 支持以及pip版本安装 TensorFlow如前面的屏幕截图所示。 因此如果您为 TensorFlow 复制以下行则也可以安装它
Python 3.4 installation
sudo pip3 install –upgrade
https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-1.2.1-cp34-cp34m-linux_x86_64.whl
如果您没有 Python 3.4请按照 wheel 文件的要求进行操作那就可以了。 您可能仍然可以使用相同的 wheel 文件。 让我们看一下如何在 Python 3.5 上执行此操作。 首先只需将以下 URL 放在浏览器中或使用命令行程序例如wget直接下载 wheel 文件就像我们在这里所做的那样
wget https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-1.2.1-cp34-cp34m-linux_x86_64.whl
如果下载此文件它将很快被您的计算机抓住。
现在您需要做的就是将文件名从cp34代表 Python 3.4更改为您使用的任何版本的 Python3。 在这种情况下我们将其更改为使用 Python 3.5 的版本因此我们将4更改为5
mv tensorflow-1.2.1-cp34-cp34m-linux_x86_64.whl tensorflow-1.2.1-cp35-cp35m-linux_x86_64.whl
现在您可以通过简单地将安装行更改为pip3 install并将新 wheel 文件的名称更改为 3.5 后来为 Python 3.5 安装 TensorFlow
sudo pip3 install ./tensorflow-1.2.1-cp35-cp35m-linux_x86_64.whl
我们可以看到这很好。 现在您已经安装了 TensorFlow。 如果您的安装以后因某种原因损坏了您可以随时跳回到该部分以提醒自己有关安装所涉及的步骤。
通过 CoCalc 安装
如果您没有计算机的管理或安装权限但仍然想尝试 TensorFlow则可以尝试在 CoCalc 实例中通过 Web 运行 TensorFlow。 如果转到 cocalc.com 并创建一个新帐户则可以创建一个新项目。 这将为您提供一种可以玩耍的虚拟机。 方便的是TensorFlow 已经安装在 Anaconda 3 内核中。 让我们创建一个名为TensorFlow的新项目。 单击创建新项目…为您的项目输入标题然后单击创建项目。 现在我们可以通过单击标题进入我们的项目。 加载将需要几秒钟。 单击新建以创建一个新文件。 在这里我们将创建一个 Jupyter 笔记本 Jupyter 是与 IPython 进行交互的便捷方法也是使用 CoCalc 进行这些计算的主要手段。 加载可能需要几秒钟。
进入下面的屏幕快照中所示的界面时您需要做的第一件事是通过转到“内核 | 更改内核… | Python3Anaconda”将内核更改为 Anaconda Python3
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yv3zYsKp-1681566150303)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/hands-on-dl-tf-zh/img/00008.jpg)]
这将为您提供适当的依赖关系以使用 TensorFlow。 更改内核可能需要几秒钟。 连接到新内核后可以在单元格中键入import tensorflow然后转到“单元格 | 运行单元格”以检查其是否有效 如果 Jupyter 笔记本需要很长时间才能加载则可以使用以下屏幕截图中所示的按钮在 CoCalc 中创建终端 到那里后键入anaconda3切换环境然后键入ipython3启动交互式 Python 会话如以下屏幕截图所示 尽管您无法可视化输出但是您可以在这里轻松地工作。 在终端中输入import tensorflow然后离开。
到目前为止您已经了解了 TensorFlow 是什么以及如何在本地或 Web 上的虚拟机上安装 TensorFlow。 现在我们准备在 TensorFlow 中探索简单的计算。
简单的计算
首先我们将看一下张量对象类型。 然后我们将理解定义计算的 TensorFlow 图。 最后我们将使用会话运行图显示如何替换中间值。
定义标量和张量
您需要做的第一件事是下载本书的源代码包并打开simple.py文件。 您可以使用此文件将行复制并粘贴到 TensorFlow 或 CoCalc 中也可以直接键入它们。 首先让我们将tensorflow导入为tf。 这是在 Python 中引用它的便捷方法。 您需要在tf.constant通话中保留常数。 例如做a tf.constant(1)和b tf.constant(2)
import tensorflow as tf
You can create constants in TF to hold specific values
a tf.constant(1) b tf.constant(2)当然您可以将它们相加并相乘以获得其他值即c和d
Of course you can add, multiply, and compute on these as you like
c a b d a * bTensorFlow 数字以张量存储这是多维数组的一个花哨术语。 如果您将 Python 列表传递给 TensorFlow它将做正确的事并将其转换为适当尺寸的张量。 您可以在以下代码中看到这一点
TF numbers are stored in tensors, a fancy term for multidimensional arrays. If you pass TF a Python list, it can convert it
V1 tf.constant([1., 2.]) # Vector, 1-dimensional V2 tf.constant([3., 4.]) # Vector, 1-dimensional M tf.constant([[1., 2.]]) # Matrix, 2d N tf.constant([[1., 2.],[3.,4.]]) # Matrix, 2d K tf.constant([[[1., 2.],[3.,4.]]]) # Tensor, 3dV1向量一维张量作为[1. , 2.]的 Python 列表传递。 这里的点只是强制 Python 将数字存储为十进制值而不是整数。 V2向量是[3. , 4. ]的另一个 Python 列表。 M变量是由 Python 中的列表列表构成的二维矩阵在 TensorFlow 中创建了二维张量。 N变量也是二维矩阵。 请注意这一行实际上有多行。 最后K是一个真实的张量包含三个维度。 请注意最终维度仅包含一个条目即一个2 x 2框。 如果该项有点混乱请不要担心。 每当您看到一个奇怪的新变量时都可以跳回到这一点以了解它可能是什么。 张量计算 您还可以做一些简单的事情例如将张量相加 V3 V1 V2或者您可以将它们逐个元素相乘以便将每个公共位置相乘在一起
Operations are element-wise by default
M2 M * M但是对于真正的矩阵乘法您需要使用tf.matmul传入两个张量作为参数 NN tf.matmul(N,N)执行计算 到目前为止所有内容都已指定 TensorFlow 图 我们还没有计算任何东西。 为此我们需要启动一个进行计算的会话。 以下代码创建一个新的会话 sess tf.Session()打开会话后请执行以下操作sess.run(NN)将计算给定的表达式并返回一个数组。 通过执行以下操作我们可以轻松地将其发送到变量 output sess.run(NN) print(NN is:) print(output)如果现在运行此单元格则应该在屏幕上看到NN输出的正确张量数组 使用完会话后最好将其关闭就像关闭文件句柄一样
Remember to close your session when youre done using it
sess.close()对于交互式工作我们可以像这样使用tf.InteractiveSession() sess tf.InteractiveSession()然后您可以轻松计算任何节点的值。 例如输入以下代码并运行单元格将输出M2的值
Now we can compute any node
print(M2 is:) print(M2.eval())可变张量 当然并非我们所有的数字都是恒定的。 例如要更新神经网络中的权重我们需要使用tf.Variable创建适当的对象 W tf.Variable(0, nameweight)请注意TensorFlow 中的变量不会自动初始化。 为此我们需要使用一个特殊的调用即tf.global_variables_initializer()然后使用sess.run()运行该调用 init_op tf.global_variables_initializer() sess.run(init_op)这是在该变量中放置一个值。 在这种情况下它将把0值填充到W变量中。 让我们验证一下W是否具有该值 print(W is:) print(W.eval())您应该在单元格中看到0的W的输出值 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-evcodNgb-1681566150304)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/hands-on-dl-tf-zh/img/00013.jpg)] 让我们看看向其中添加a会发生什么 W a print(W after adding a:) print(W.eval())回想一下a是1因此您在这里得到1的期望值 让我们再次添加a以确保我们可以递增并且它确实是一个变量 W a print(W after adding a:) print(W.eval())现在您应该看到W持有2因为我们已经使用a对其进行了两次递增 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RIsT1bTs-1681566150305)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/hands-on-dl-tf-zh/img/00015.jpg)] 查看和替换中间值 在执行 TensorFlow 计算时您可以返回或提供任意节点。 让我们定义一个新节点但同时在fetch调用中返回另一个节点。 首先让我们定义新节点E如下所示 E d b # 1*2 2 4让我们看看E的开头是 print(E as defined:) print(E.eval())如您所料您应该看到E等于4。 现在让我们看一下如何传递E和d多个节点以从sess.run调用中返回多个值
Lets see what d was at the same time
print(E and d:) print(sess.run([E,d]))您应该看到输出中返回了多个值即4和2 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pd4MYfVd-1681566150305)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/hands-on-dl-tf-zh/img/00016.jpg)] 现在假设我们要使用其他中间值例如出于调试目的。 返回值时我们可以使用feed_dict将自定义值提供给计算中任何位置的节点。 让我们现在用d等于4而不是2来做
Use a custom d by specifying a dictionary
print(E with custom d4:) print(sess.run(E, feed_dict {d:4.}))请记住E 等于 d bd和b的值都是2。 尽管我们为d插入了4的新值但是您应该看到E的值现在将输出为6 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VSeI9T3C-1681566150306)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/hands-on-dl-tf-zh/img/00017.jpg)] 您现在已经了解了如何使用 TensorFlow 张量进行核心计算。 现在是时候通过建立逻辑回归模型来迈出下一步。 逻辑回归模型构建 好的让我们开始构建一个真正的机器学习模型。 首先我们将看到提出的机器学习问题字体分类。 然后我们将回顾一个简单的分类算法称为逻辑回归。 最后我们将在 TensorFlow 中实现逻辑回归。 字体分类数据集简介 在开始之前让我们加载所有必需的模块 import tensorflow as tf import numpy as np如果要复制并粘贴到 IPython请确保将autoindent属性设置为OFF %autoindenttqdm模块是可选的 它只是显示了不错的进度条 try:from tqdm import tqdm except ImportError:def tqdm(x, *args, **kwargs):return x接下来我们将设置0的种子以使每次运行之间的数据分割保持一致
Set random seed
np.random.seed(0)在本书中我们提供了使用五种字体的字符图像数据集。 为方便起见这些文件存储在压缩的 NumPy 文件data_with_labels.npz中该文件可在本书的下载包中找到。 您可以使用numpy.load轻松将它们加载到 Python 中
Load data
data np.load(data_with_labels.npz) train data[arr_0]/255. labels data[arr_1]这里的train变量保存从 0 到 1 缩放的实际像素值labels保留原来的字体类型。 因此它将是 0、1、2、3 或 4因为总共有五种字体。 您可以打印这些值因此可以使用以下代码查看它们
Look at some data
print(train[0]) print(labels[0])但是这不是很有启发性因为大多数值都是零并且仅屏幕的中央部分包含图像数据 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-o78Voqoa-1681566150306)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/hands-on-dl-tf-zh/img/00018.jpg)] 如果您已安装 Matplotlib则现在是导入它的好地方。 在需要时我们将使用plt.ion()自动调出数字
If you have matplotlib installed
import matplotlib.pyplot as plt plt.ion()这是每种字体的一些字符示例图 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wM6A6vOq-1681566150306)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/hands-on-dl-tf-zh/img/00019.jpg)] 是的他们很浮华。 在数据集中每个图像都表示为像素暗度值的36 x 36二维矩阵。 0 值表示白色像素而 255 表示黑色像素。 两者之间的一切都是灰色阴影。 这是在您自己的计算机上显示这些字体的代码
Lets look at a subplot of one of A in each font
f, plts plt.subplots(5, sharexTrue) c 91 for i in range(5):plts[i].pcolor(train[c i * 558],cmapplt.cm.gray_r)如果您的图看起来确实很宽则可以使用鼠标轻松调整窗口大小。 如果您只是以交互方式进行绘图则在 Python 中提前调整其大小通常需要做很多工作。 鉴于我们还有许多其他标记的字体图像我们的目标是确定图像属于哪种字体。 为了扩展数据集并避免过拟合我们还在36 x 36区域内抖动了每个字符为我们提供了 9 倍的数据点。 在使用较新的模型后重新回到这一点可能会有所帮助。 无论最终模型有多高级记住原始数据都非常重要。 逻辑回归 如果您熟悉线性回归那么您将了解逻辑回归。 基本上我们将为图像中的每个像素分配一个权重然后对这些像素进行加权求和权重为beta像素为X。 这将为我们提供该图像是特定字体的分数。 每种字体都有自己的权重集因为它们对像素的重视程度不同。 要将这些分数转换为适当的概率由Y表示我们将使用softmax函数将其总和强制在 0 到 1 之间如下所示。 对于特定图像而言无论最大概率是多少我们都将其分类为关联的类别。 您可以在大多数统计建模教科书中阅读有关逻辑回归理论的更多信息。 这是它的公式 William H. Greene 的《计量经济学分析》Pearson于 2012 年出版这是一本针对应用的很好的参考。 准备数据 在 TensorFlow 中实现逻辑回归非常容易并将作为更复杂的机器学习算法的基础。 首先我们需要将整数标签转换为单格式。 这意味着不是将字体类标记为 2而是将标签转换为[0, 0, 1, 0, 0]。 也就是说我们将1放在第二个位置注意向上计数在计算机科学中很常见而0则放在其他位置。 这是我们的to_onehot函数的代码 def to_onehot(labels,nclasses 5):Convert labels to one-hot format. a [0,1,2,3] to_onehot(a,5)array([[ 1., 0., 0., 0., 0.],[ 0., 1., 0., 0., 0.],[ 0., 0., 1., 0., 0.],[ 0., 0., 0., 1., 0.]])outlabels np.zeros((len(labels),nclasses))for i,l in enumerate(labels):outlabels[i,l] 1return outlabels完成此操作后我们可以继续调用该函数 onehot to_onehot(labels)对于像素在这种情况下我们实际上并不需要矩阵因此我们将36 x 36的数字展平为长度为 1,296 的一维向量但这会在以后出现。 另外回想一下我们已经重新调整了 0-255 的像素值使其介于 0 和 1 之间。 好的我们的最后准备是将数据集分为训练和验证集。 这将有助于我们稍后解决过拟合问题。 训练集将帮助我们确定逻辑回归模型中的权重而验证集将仅用于确认这些权重在新数据上是否合理
Split data into training and validation
indices np.random.permutation(train.shape[0]) valid_cnt int(train.shape[0] * 0.1) test_idx, training_idx indices[:valid_cnt],\indices[valid_cnt:] test, train train[test_idx,:],\train[training_idx,:] onehot_test, onehot_train onehot[test_idx,:],\onehot[training_idx,:]建立 TensorFlow 模型 好的让我们通过创建一个交互式会话来开始 TensorFlow 代码 sess tf.InteractiveSession()这样我们就在 TensorFlow 中开始了我们的第一个模型。 我们将为x使用占位符变量该变量代表我们的输入图像。 这只是告诉 TensorFlow 我们稍后将通过feed_dict为该节点提供值
These will be inputs
Input pixels, flattened
x tf.placeholder(float, [None, 1296])另外请注意我们可以指定此张量的形状在这里我们将None用作大小之一。 None的大小允许我们立即将任意数量的数据点发送到算法中以进行批量。 同样我们将使用变量y_来保存我们已知的标签以便稍后进行训练
Known labels
y_ tf.placeholder(float, [None,5])要执行逻辑回归我们需要一组权重W。 实际上五个字体类别中的每一个都需要 1,296 的权重这将为我们提供形状。 请注意我们还希望为每个类别添加一个额外的权重作为偏差b。 这与添加始终为1值的额外输入变量相同
Variables
W tf.Variable(tf.zeros([1296,5])) b tf.Variable(tf.zeros([5]))随着所有这些 TensorFlow 变量浮动我们需要确保对其进行初始化。 现在给他们打电话
Just initialize
sess.run(tf.global_variables_initializer())做得好 您已经准备好一切。 现在您可以实现softmax公式来计算概率。 由于我们非常仔细地设置权重和输入因此 TensorFlow 只需调用tf.matmul和tf.nn.softmax就可以轻松完成此任务
Define model
y tf.nn.softmax(tf.matmul(x,W) b)而已 您已经在 TensorFlow 中实现了整个机器学习分类器。辛苦了。但是我们从哪里获得权重的值 让我们看一下使用 TensorFlow 训练模型。 逻辑回归训练 首先您将了解我们的机器学习分类器的损失函数并在 TensorFlow 中实现它。 然后我们将通过求值正确的 TensorFlow 节点来快速训练模型。 最后我们将验证我们的模型是否合理准确权重是否合理。 定义损失函数 优化我们的模型实际上意味着最大程度地减少我们的误差。 使用我们的标签可以很容易地将它们与模型预测的类概率进行比较。 类别cross_entropy函数是测量此函数的正式方法。 尽管确切的统计信息超出了本课程的范围但是您可以将其视为对模型的惩罚以期获得更不准确的预测。 为了进行计算我们将单热的实数标签与预测概率的自然对数相乘然后将这些值相加并取反。 为方便起见TensorFlow 已经包含此函数为tf.nn.softmax_cross_entropy_with_logits()我们可以这样称呼它
Climb on cross-entropy
cross_entropy tf.reduce_mean(tf.nn.softmax_cross_entropy_withlogits(logits y 1e-50, labels y))请注意我们在此处添加了一个较小的1e-50误差值以避免数值不稳定问题。 训练模型 TensorFlow 的便利之处在于它提供了内置的优化器以利用我们刚刚编写的损失函数。 梯度下降是一种常见的选择它将使我们的权重逐渐趋于更好。 这是将更新我们权重的节点
How we train
train_step tf.train.GradientDescentOptimizer(0.02).minimize(cross_entropy)在我们实际开始训练之前我们应该指定一些其他节点来评估模型的表现
Define accuracy
correctprediction tf.equal(tf.argmax(y,1),tf.argmax(y,1)) accuracy tf.reduce_mean(tf.cast(correct_prediction, float))如果我们的模型将最高概率分配给正确的类别则correct_prediction节点为1否则为0。 accuracy变量对可用数据的这些预测取平均值从而使我们对模型的执行情况有一个整体认识。 在进行机器学习训练时我们经常希望多次使用同一数据点以挤出所有信息。 每次遍历整个训练数据都称为一个周期。 在这里我们将每 10 个时间段同时保存训练和验证准确率
Actually train
epochs 1000 train_acc np.zeros(epochs//10) test_acc np.zeros(epochs//10) for i in tqdm(range(epochs)):# Record summary data, and the accuracyif i % 10 0:# Check accuracy on train setA accuracy.eval(feeddict{x: train.reshape([-1,1296]),y: onehot_train})train_acc[i//10] A# And now the validation setA accuracy.eval(feeddict{x: test.reshape([-1,1296]),y: onehot_test})test_acc[i//10] Atrain_step.run(feeddict{x: train.reshape([-1,1296]),y: onehot_train})请注意我们使用feed_dict传递不同类型的数据以获得不同的输出值。 最后train_step.run每次迭代都会更新模型。 在典型的计算机上这只需几分钟如果使用 GPU则要少得多而在功率不足的计算机上则要花更多时间。 您刚刚使用 TensorFlow 训练了模型; 真棒 评估模型准确率 在 1,000 个周期之后让我们看一下模型。 如果您安装了 Matplotlib则可以在绘图中查看精度 如果没有您仍然可以查看电话号码。 对于最终结果请使用以下代码
Notice that accuracy flattens out
print(train_acc[-1]) print(test_acc[-1])如果您确实安装了 Matplotlib则可以使用以下代码显示图
Plot the accuracy curves
plt.figure(figsize(6,6)) plt.plot(train_acc,bo) plt.plot(test_acc,rx)您应该看到类似下面的图请注意我们使用了一些随机初始化因此可能并不完全相同 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1BKlHuBV-1681566150307)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/hands-on-dl-tf-zh/img/00021.jpg)] 验证精度似乎在经过约 400-500 次迭代后趋于平稳 除此之外我们的模型可能过拟合或没有学到更多。 同样即使最终精度大约是 40%看起来也很差但请记住对于五个类别完全随机的猜测将仅具有 20% 的精度。 有了这个有限的数据集简单的模型就可以做到。 查看计算出的权重通常也很有帮助。 这些可以为您提供有关模型认为重要的线索。 让我们按给定类的像素位置绘制它们
Look at a subplot of the weights for each font
f, plts plt.subplots(5, sharexTrue) for i in range(5):plts[i].pcolor(W.eval()[:,i].reshape([36,36]))这应该给您类似于以下的结果同样如果图显示得很宽则可以挤压窗口大小以使其平方 我们可以看到在某些模型中靠近内部的权重很重要而外部的权重基本上为零。 这是有道理的因为没有字体字符到达图像的角落。 同样请注意由于随机初始化的影响最终结果可能看起来有些不同。 随时可以尝试并更改模型的参数 这就是您学习新事物的方式。 总结 在本章中我们在可以使用的机器上安装了 TensorFlow。 经过一些基本计算的小步骤我们跳入了机器学习问题仅通过逻辑回归和几行 TensorFlow 代码就成功构建了一个体面的模型。 在下一章中我们将看到 TensorFlow 在深度神经网络方面的优势。 二、深度神经网络 在上一章中我们研究了简单的 TensorFlow 操作以及如何在字体分类问题上使用逻辑回归。 在本章中我们将深入探讨一种最流行和成功的机器学习方法-神经网络。 使用 TensorFlow我们将构建简单和深度的神经网络以改善字体分类问题的模型。 在这里我们将实践神经网络的基础。 我们还将使用 TensorFlow 构建和训练我们的第一个神经网络。 然后我们将进入具有神经元隐藏层的神经网络并完全理解它。 完成后您将更好地掌握以下主题 基本神经网络单隐藏层模型单隐藏层说明多隐藏层模型多隐藏层的结果 在第一部分中我们将回顾神经网络的基础。 您将学习转换输入数据的常见方法了解神经网络如何将这些转换联系在一起最后如何在 TensorFlow 中实现单个神经元。 基本神经网络 我们的逻辑回归模型运作良好但本质上是线性的。 将像素的强度加倍会使像素对得分的贡献增加一倍但我们可能只真正关心像素是否在某个阈值之上或将较小的权重放在较小的值上。 线性可能无法捕获问题的所有细微差别。 解决此问题的一种方法是使用非线性函数转换输入。 让我们看一下 TensorFlow 中的一个简单示例。 首先请确保加载所需的模块tensorflownumpy和math并启动交互式会话 import tensorflow as tf import numpy as np import mathsess tf.InteractiveSession()在下面的示例中我们创建了三个五长向量的正常随机数这些向量被截断以防止它们过于极端中心不同 x1 tf.Variable(tf.truncated_normal([5],mean3, stddev1./math.sqrt(5))) x2 tf.Variable(tf.truncated_normal([5],mean-1, stddev1./math.sqrt(5))) x3 tf.Variable(tf.truncated_normal([5],mean0, stddev1./math.sqrt(5)))sess.run(tf.global_variables_initializer())注意 请注意由于这是随机的因此您的值可能会有所不同但这很好。 常见的转换是对输入求平方。 这样做会使更大的值变得更加极端当然也使所有事情都变得积极起来 sqx2 x2 * x2 print(x2.eval()) print(sqx2.eval())您可以在以下屏幕截图中看到结果 对数函数 相反如果您需要在较小的值中有更多细微差别则可以尝试采用输入的自然对数或任何基本对数 logx1 tf.log(x1) print(x1.eval()) print(logx1.eval())请参考以下屏幕截图请注意较大的值往往会挤在一起而较小的值则散布得多 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LmQujw6o-1681566150308)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/hands-on-dl-tf-zh/img/00024.jpg)] 但是对数不能处理负输入并且您越接近零小输入就变得越负。 因此请注意对数。 最后是 Sigmoid 变换。 sigmoid 函数 不必担心公式只需知道正负两个极值分别被压缩为加一或零而接近零的输入就接近二分之一 sigx3 tf.sigmoid(x3) print(x3.eval()) print(sigx3.eval())在这里您将看到一个接近一半的示例。 它从四分之一开始到现在将近一半 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KlkXSQCL-1681566150308)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/hands-on-dl-tf-zh/img/00025.jpg)] 在机器学习中我们通常将这些转换称为激活函数。 我们通常将输入的加权总和组合到其中。 当您考虑输入权重和激活函数时就将其称为神经元因为它是受生物神经元启发的。 真正的神经元如何在物理大脑中工作的细节不在本书的讨论范围之内。 如果您对此感兴趣则神经生物学文章可能包含更多内容或者您可以参考 Gordon M. Shepherd 的《神经元学说》作为近期参考。 让我们看一下 TensorFlow 中的一个简单示例 w1 tf.constant(0.1) w2 tf.constant(0.2) sess.run(tf.global_variables_initializer())首先只需创建一些常量w1和w2即可。 我们将x1乘以w1将x2乘以w2然后将这些中间值相加最后将结果通过tf.sigmoid的sigmoid激活函数进行处理。 查看以下屏幕快照中显示的结果 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-C5KApowV-1681566150308)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/hands-on-dl-tf-zh/img/00026.jpg)] 同样现在不必担心确切的公式您可以拥有各种不同的激活函数。 请注意这是您迈向自己的神经网络的第一步。 那么我们如何从单个神经元到整个网络 简单 一个神经元的输入仅成为网络下一层中另一神经元的输入。 在上图中我们有一个简单的网络其中有两个输入X0和X1两个输出Y0和Y1中间有三个神经元。 X0中的值被发送到每个N神经元但是权重不同该权重乘以与每个相关的X0。 X1也发送到每个神经元并具有自己的一组权重。 对于每个神经元我们计算输入的加权总和将其通过激活函数然后产生中间输出。 现在我们做同样的事情但是将神经元的输出视为Y的输入。 注意通过对输入加权和进行非线性激活我们实际上只是为最终模型计算了一组新的特征。 现在您已经了解了 TensorFlow 中非线性转换的基础以及什么是神经网络。 好吧它们可能不会让您读懂思想它们对于深度学习至关重要。 在下一节中我们将使用简单的神经网络来改进分类算法。 单隐藏层模型 在这里我们将实践神经网络的基础知识。 我们将逻辑回归 TenserFlow 代码改编为神经元的单个隐藏层。 然后您将学习反向传播背后的思想以计算权重即训练网络。 最后您将在 TensorFlow 中训练您的第一个真正的神经网络。 本部分的 TensorFlow 代码应该看起来很熟悉。 它只是逻辑回归代码的略微演变版本。 让我们看看如何添加神经元的隐藏层以计算输入像素的非线性组合。 您应该从全新的 Python 会话开始执行代码以读入并按照逻辑模型中的步骤设置数据。 相同的代码只是复制到新文件中 import tensorflow as tf import numpy as np import math from tqdm import tqdm %autoindent try:from tqdm import tqdm except ImportError:def tqdm(x, *args, **kwargs):return x您总是可以回到前面的部分并提醒自己该代码的作用 直到num_hidden变量的所有内容都可以使您快速入门。 探索单隐藏层模型 现在让我们逐步介绍单个隐藏层模型 首先让我们指定num_hidden 128想要多少个神经元 最终这实际上是将多少个非线性组合传递给逻辑对数。 为了适应这一点我们还需要更新W1和b1权重张量的形状。 他们现在正在馈送我们隐藏的神经元因此需要匹配形状 W1 tf.Variable(tf.truncated_normal([1296, num_hidden],stddev1./math.sqrt(1296))) b1 tf.Variable(tf.constant(0.1,shape[num_hidden]))我们计算加权和的激活函数的方法是使用单行h1。 这是将我们的输入像素乘以每个神经元各自的权重 h1 tf.sigmoid(tf.matmul(x,W1) b1)添加神经元偏差项最后通过sigmoid激活函数进行设置 此时我们有 128 个中间值 现在这只是对您友好的逻辑回归 您已经知道该怎么办。 这些新计算的 128 个特征需要它们自己的权重和偏置集来计算输出类的分数分别为W2和b2。 注意形状如何与神经元的形状 128 匹配并且输出类的数量为 5 W2 tf.Variable(tf.truncated_normal([num_hidden, 5],stddev1./math.sqrt(5))) b2 tf.Variable(tf.constant(0.1,shape[5])) sess.run(tf.global_variables_initializer())在所有这些权重中我们使用此奇怪的截断普通调用对其进行初始化。 借助神经网络我们希望获得良好的初始值分布以便我们的权重可以攀升至有意义的值而不是仅仅归零。 截断正态具有给定标准偏差的正态分布中的随机值该研究标准按输入数量进行缩放但抛出的值太极端因此被截断了。 定义好权重和神经元后我们将像以前一样设置最终的softmax模型除了需要注意使用 128 个神经元作为输入h1以及相关的权重和偏差W2和b2 y tf.nn.softmax(tf.matmul(h1,W2) b2)反向传播 训练神经网络和许多其他机器学习模型权重的关键称为反向传播。 完整的推导超出了本书的范围但是让我们直观地进行研究。 当您在空中训练逻辑回归之类的模型并且训练集直接来自选择不当的权重时您可以看到应该调整哪些权重以及应该调整多少权重并相应地更改它们。 从形式上讲TensorFlow 通过计算空气相对于权重的导数并将权重调整为该数值的一小部分来实现此目的。 反向传播实际上是同一过程的扩展。 您从最底层的输出或成本函数层开始计算导数然后使用它们来计算与上一层神经元相关的导数。 通过将从成本到权重的路径上的导数乘积相加我们可以计算相对于要调整的权重的成本的适当偏导数。 上图中显示的公式仅说明了红色箭头显示的内容。 如果这看起来很复杂请不要担心。 TensorFlow 使用优化器在后台为您处理。 由于我们使用 TensorFlow 精心指定了模型来训练模型因此几乎与之前完全相同因此我们将在此处使用相同的代码 epochs 5000 train_acc np.zeros(epochs//10) test_acc np.zeros(epochs//10) for i in tqdm(range(epochs), asciiTrue):if i % 10 0: # Record summary data, and the accuracy# Check accuracy on train setA accuracy.eval(feeddict{x: train.reshape([-1,1296]), y: onehot_train})train_acc[i//10] A# And now the validation setA accuracy.eval(feeddict{x: test.reshape([-1,1296]), y: onehot_test})test_acc[i//10] Atrain_step.run(feeddict{x: train.reshape([-1,1296]), y: onehot_train})需要注意的一件事是因为我们有这些隐藏的神经元所以有更多的权重可以拟合模型。 这意味着我们的模型将需要更长的运行时间并且必须花费更多的迭代时间才能进行训练。 这次我们通过5000历时运行它 该模型可能比以前的模型花费更长的时间可能是前一个模型的四倍。 因此您可能需要几分钟到 10 分钟的时间具体取决于您的计算机。 现在通过模型训练我们将在稍后查看验证准确率。 单隐藏层的说明 在本节中我们将仔细研究构建的模型。 首先我们将验证模型的整体准确率然后查看模型出了哪些问题。 最后我们将可视化与多个神经元相关的权重以查看它们在寻找什么 plt.figure(figsize(6, 6)) plt.plot(train_acc,bo) plt.plot(test_acc,rx)确保您已经按照上一节中的步骤训练了模型如果没有您可能要在这里停下来并首先进行操作。 由于我们每隔 10 个训练周期就评估模型的准确率并保存结果因此现在很容易探索模型的演变方式。 使用 Matplotlib我们可以在同一张图上绘制训练精度蓝色点和测试精度红色点 同样如果您没有 Matplotlib那就没关系。 您可以只查看数组值本身。 请注意训练精度蓝色通常比测试精度红色好一点。 这并不奇怪因为测试图像对于模型来说是全新的并且可能包含以前看不见的特征。 另外观察精度通常会攀升到更多的周期然后逐渐上升然后逐渐上升。 我们的模型在这里达到约 60% 的准确率 并非完美但对简单逻辑回归进行了改进。 要查看我们的模型在哪里混淆创建混淆矩阵会很有帮助。 也就是说我们将寻找一个可以说的实际绘图类别。 该模型将其分类为什么 形式上是5x5矩阵。 对于每个测试图像如果图像实际上是类别i和模型预测类别j则我们增加值和位置i j。 请注意当模型正确时则为i j。 一个好的模型在对角线上将具有很大的值而在其他地方则没有很多。 通过这种类型的分析很容易看出两个类是否经常彼此混淆或者模型很少选择某些类。 在以下示例中我们通过求值y类概率来创建预测类 pred np.argmax(y.eval(feeddict{x: test.reshape([-1,1296]), y: onehot_test}), axis 1) conf np.zeros([5,5]) for p,t in zip(pred,np.argmax(onehot_test,axis1)):conf[t,p] 1plt.matshow(conf) plt.colorbar()np.argmax函数提取概率最大的位置。 同样为了确定实际的类别我们使用np.argmax撤消一次热编码。 创建混乱矩阵始于全零数组然后逐步遍历所有填充的测试数据。Matplotlib 让我们看一下彩色图像但打印与会者的效果几乎相同 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sbLo70Kb-1681566150310)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/hands-on-dl-tf-zh/img/00032.jpg)] 在前面的输出中我们看到模型通常做得不错只是它很少预测类2。 由于初始的随机性您的确切结果可能看起来有些不同。 了解模型的权重 正如我们查看逻辑回归模型的权重一样我们可以监视此模型的权重 plt.figure(figsize(6, 6)) f, plts plt.subplots(4,8, sharexTrue) for i in range(32):plts[i//8, i%8].pcolormesh(W1.eval()[:,i].reshape([36,36]))但是现在我们有 128 个神经元每个神经元的权重都来自输入像素权重为36x36。 让我们看看其中的一些以了解他们的发现。 同样如果您没有 Matplotlib则可以简单地打印出数组以查看相同的行为。 在这里我们将研究 128 个神经元中的 32 个。 因此让我们将子图的格式设置为四行八列。 现在我们逐步求值每个神经元的权重并将其重塑为图像大小。 双斜杠//使用整数除法将图像放入适当的行而百分号%使用余数实际上是模块化算术来选择列。 视觉上在前面的输出中您可以看到一些形状突出。 与它们的权重模式相比某些神经元或多或少具有圆形形状。 其他人看起来很随意但可能会选择我们不容易理解的特征。 我们也可以尝试可视化输出层的权重但是这些不再直观。 我们称其为神经网络。 现在输出逻辑回归是 128 个输入值以及用于计算 5 个分数的权重。 不再有图像结构因为每个像素都进入了隐藏层的每个神经元。 现在您知道了如何评估和解释神经网络结果。 做得好 多隐藏层模型 在本节中我们将向您展示如何使用其他隐藏层构建更复杂的模型。 我们将单层隐藏模型改编为称为深度神经网络的多层模型。 然后我们将讨论选择要使用的神经元和层数。 最后我们将耐心地训练模型本身因为这可能需要一段时间才能计算出来。 还记得我们向逻辑回归模型添加神经元的隐藏层吗 好了我们可以再做一次在我们的单个隐藏层模型中添加另一层。 一旦您拥有一层以上的神经元我们就将其称为深度神经网络。 但是您以前所学的一切都可以立即应用。 与本章前面的部分一样您应该进行一个全新的 Python 会话并执行本部分代码文件中直到num_hidden1的代码。 然后乐趣开始了。 探索多隐藏层模型 首先将旧的num_hidden更改为num_hidden1以指示第一个隐藏层上的神经元数量
Hidden layer 1
num_hidden1 128确保更改变量同时定义权重和偏差变量。 现在我们将插入第二个隐藏层 W1 tf.Variable(tf.truncated_normal([1296,num_hidden1],stddev1./math.sqrt(1296))) b1 tf.Variable(tf.constant(0.1,shape[num_hidden1])) h1 tf.sigmoid(tf.matmul(x,W1) b1)这次使用带有32神经元的神经元。 请注意权重的形状必须如何解释来自上一层的 128 个中间输出中的每一个进入当前层的 32 个输入或神经元但是我们初始化权重和偏差的方式基本上相同
Hidden Layer 2
num_hidden2 32 W2 tf.Variable(tf.truncated_normal([num_hidden1,num_hidden2],stddev2./math.sqrt(num_hidden1))) b2 tf.Variable(tf.constant(0.2,shape[num_hidden2])) h2 tf.sigmoid(tf.matmul(h1,W2) b2)如您在前面的代码中所见我们像以前一样使用sigmoid函数创建h2输出并使用矩阵乘法加法和函数调用。 对于输出逻辑回归层我们只需要更新变量名称
Output Layer
W3 tf.Variable(tf.truncated_normal([num_hidden2, 5],stddev1./math.sqrt(5))) b3 tf.Variable(tf.constant(0.1,shape[5]))现在这是第三组权重当然此形状必须与前面的隐藏层的输出匹配因此32 x 5 不要忘记使用h2W3和b3变量更新y模型函数。 您不想只使用旧模型就更新所有代码。 您可能想知道我们如何决定第一层的 128 个神经元和第二层的 32 个神经元。 事实是为网络确定合适的尺寸和形状可能是一个具有挑战性的问题。 尽管计算可能会很昂贵但是反复试验是开发模型的一种方法。 通常您可能会从旧模型开始并从那里开始工作。 在这里我们从 128 个神经元的单个隐藏层开始然后尝试在其下添加一个新层。 我们要计算一些特征以区分五类因此在选择神经元数量时应牢记这一点。 通常最好从小处着手逐步发展到解释数据的最小模型。 如果在顶层具有 128 个神经元而在下一层具有 8 个神经元的模型的效果较差则可能表明我们需要为最后一层提供更多特征并应添加更多而不是更少的神经元。 尝试将最后一层中的神经元数量加倍当然最好回到较早的层并调整那里的神经元数量。 同样您可以更改优化器的学习率从而改变每一步调整权重的程度甚至更改用于优化的函数。 注意 设置所有这些值称为超参数优化这是机器学习研究中的热门话题。 请注意我们实际上是从最简单的模型逻辑回归开始然后慢慢添加新的功能和结构。 如果一个简单的模型运行良好那么甚至没有必要花时间在更高级的东西上。 现在已经指定了我们的模型让我们实际进行训练
Climb on cross-entropy
cross_entropy tf.reduce_mean(tf.nn.softmax_cross_entropy_withlogits(logits y 1e-50, labels y))# How we train train_step tf.train.GradientDescentOptimizer(0.01).minimize(cross_entropy)# Define accuracy correctprediction tf.equal(tf.argmax(y,1),tf.argmax(y,1)) accuracytf.reduce_mean(tf.cast(correct_prediction, float))同样我们需要在 TensorFlow 图中重新定义我们的训练节点但是这些与以前完全相同。 请注意由于我们的第一个隐藏层现在挂接到神经元的另一层因此我们需要计算更多的权重。 以下是实际的训练代码 epochs 25000 train_acc np.zeros(epochs//10) test_acc np.zeros(epochs//10) for i in tqdm(range(epochs)):# Record summary data, and the accuracyif i % 10 0:# Check accuracy on train setA accuracy.eval(feeddict{x: train.reshape([-1,1296]),y: onehot_train})train_acc[i//10] A# And now the validation setA accuracy.eval(feeddict{x: test.reshape([-1,1296]),y: onehot_test})test_acc[i//10] Atrain_step.run(feeddict{x: train.reshape([-1,1296]),y: onehot_train})以前我们有 128 乘以 5 的权重但是现在我们有 128 乘以 32 的权重-这是该层的六倍这是从像素到神经元第一层的初始权重之上。 深度神经网络的一个缺点是它们可能需要一段时间才能训练。 在这里我们将运行25000个周期以确保权重收敛 这可能需要一个小时或更长时间具体取决于您的计算机和 GPU。 尽管这看起来似乎过多但专业的机器学习研究人员通常会训练模型长达两个星期。 您可能会学得很快但是计算机需要一些时间。 在本节中我们使用 TensorFlow 构建并训练了一个真正的深度神经网络。 许多专业的机器学习模型没有您已经编写的复杂。 多隐藏层的结果 现在我们将研究深度神经网络内部的情况。 首先我们将验证模型的准确率。 然后我们将可视化并研究像素权重。 最后我们还将查看输出权重。 训练完您的深度神经网络后让我们看一下模型的准确率。 我们将以与单隐藏层模型相同的方式进行操作。 这次的唯一区别是从更多的周期开始我们保存了更多的训练和测试准确率样本。 和往常一样如果您没有 Matplotlib请不要担心。 打印数组的一部分很好。 了解多隐藏层的图 执行以下代码以查看结果
Plot the accuracy curves
plt.figure(figsize(6,6)) plt.plot(train_acc,bo) plt.plot(test_acc,rx)从前面的输出图中我们可以达到约 68% 的训练精度也许还有 63% 的验证精度。 这还不错但是确实留出了一些改进的空间。 让我们花点时间看一下准确率在许多周期如何增长。 当然它起步非常糟糕并且存在一些最初的麻烦但是权重是随机的并且在那个时候仍在学习并且在最初的数千个周期中它很快得到了改善。 虽然可能会暂时卡在局部最大值中但通常会爬出并最终减慢其重音。 请注意它仍然可以很好地进入训练阶段。 只是到了尽头模型才可能达到其最大容量。 根据随机初始化您的曲线可能看起来有些不同但这没关系 这是您的模型非常好。 要查看我们的模型在哪里出现问题让我们看一下混淆矩阵 pred np.argmax(y.eval(feeddict{x:test.reshape([-1,1296]), y: onehot_test}), axis 1) conf np.zeros([5,5]) for p,t in zip(pred,np.argmax(onehot_test,axis1)):conf[t,p] 1plt.matshow(conf) plt.colorbar()同样这与我们用于单个隐藏层模型的过程完全相同只是在更高级的方面 对此进行绘图就像在前面的输出中一样我们看到该模型总体上运行良好但是仍然难以识别其中一个类这次是1。 我们正在逐步取得进展。 验证准确率之后让我们检查一下我们的第一层神经元即 128 个人发现了什么样的现象
Lets look at a subplot of some weights
f, plts plt.subplots(4,8, sharexTrue) for i in range(32):plts[i//8, i%8].matshow(W1.eval()[:,i].reshape([36,36]))为了简单起见我们仅查看前 32 个此类神经元。 使用与先前模型相同的代码可以轻松地使用 Matplotlib 进行绘制或打印出来 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-03AQnj8j-1681566150311)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/hands-on-dl-tf-zh/img/00039.jpg)] 毫不奇怪我们看到了许多与先前模型相同的函数。 尽管在这里由于随机初始化即使它们看起来像是同一类型的特征它们也会位于不同的位置。 同样您有一些环形神经元具有非常条纹状特征的神经元以及具有宽条纹状特征的另一个神经元。 就我们的神经网络而言圆形和条纹形状是确定字体类别的良好成分。 尽管我们其他隐藏层中的权重不再具有图像的结构但查看输出的权重可能会很有帮助。 这将告诉我们每个最终神经元对每个类别的贡献。 我们可以将其绘制为热力图或使用W3.eval任意方式打印单个数组
Examine the output weights
plt.matshow(W3.eval()) plt.colorbar()因为我们仔细指定了W3所以每一行将代表一个神经元每一列将代表一个类 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UxmgvdbN-1681566150312)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/hands-on-dl-tf-zh/img/00040.jpg)] 从前面的输出图中我们可以看到不同的神经元对某些类别的贡献要大于其他类别这表明神经元正在计算的某些总体非线性特征与该特定字体类别有关。 也就是说虽然这些神经元产生的值用于计算每种字体的分数但非常重要且权重较大的一种字体的神经元可能与另一种字体几乎无关。 例如对于2类N1神经元的权重非常大而对于所有其他类别N1神经元的权重几乎为零。 该神经元具有什么计算特征对于2类而言非常重要但对于其他类别而言则没有那么重要。 总结 在本章中我们使用 TensorFlow 进行了深度学习。 尽管我们从一个神经元隐藏层的简单模型开始但是并不需要花很长时间就可以开发和训练用于字体分类问题的深度神经网络。 您了解了单层和多层隐藏层模型并对其进行了详细了解。 您还将了解神经网络的不同类型并使用 TensorFlow 构建和训练了我们的第一个神经网络。 在下一章中我们将使用卷积神经网络一种用于图像分类的强大工具来证明我们的模型。 三、卷积神经网络 在上一章中我们探讨了深度神经网络该神经网络需要更多的参数才能拟合。 本章将指导您完成深度学习中最强大的开发之一并让我们使用有关问题空间的一些知识来改进模型。 首先我们将解释一个神经网络中的卷积层然后是一个 TensorFlow 示例。 然后我们将对池化层执行相同的操作。 最后我们将字体分类模型改编为卷积神经网络CNN然后看看它是如何工作的。 在本章中我们将介绍卷积神经网络的背景。 我们还将在 TensorFlow 中实现卷积层。 我们将学习最大池化层并将其付诸实践并以单个池化层为例。 在本章的最后您将对以下概念有很好的控制 卷积层动机卷积层应用池化层动机池化层应用深度 CNN更深的 CNN深层 CNN 总结 现在让我们进入卷积层。 卷积层动机 在本节中我们将逐步使用示例图像上的卷积层。 我们将以图形方式看到卷积只是一个滑动窗口。 此外我们将学习如何从窗口中提取多个特征以及如何接受到窗口的多层输入。 在给定神经元的神经网络的经典密集层中每个输入特征都具有自己的权重。 如果输入特征完全独立并测量不同的事物那么这很好但是如果特征之间存在结构那该怎么办。 想象发生这种情况的最简单示例是如果您的输入特征是图像中的像素。 一些像素彼此相邻而其他像素则相距较远。 对于诸如图像分类尤其是字体分类之类的任务图像中出现小比例尺特征通常并不重要。 我们可以通过在整个图像中滑动较小的窗口来在较大的图像中查找小比例尺特征这对于使用相同的权重矩阵至关重要无论该窗口在图像中的位置如何。 这样我们可以随时随地寻找相同的特征。 假设我们有一个10x10的图像并且想在其中滑动3x3的窗口。 通常机器学习工程师每次只能将此窗口滑动一个像素。 这称为跨步因此从一个窗口到下一个窗口会有一些重叠。 然后逐个元素地将我们小的3x3权重矩阵W1乘到我们的窗口H1[00]中对结果求和并通过称为F的激活函数进行处理。 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SsRFhE9l-1681566150312)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/hands-on-dl-tf-zh/img/00042.jpg)] 第一个窗口W1进入新矩阵的第一个位置如右图H2所示。 窗口以相同的权重滑过一个但结果占据第二个位置。 请注意我们实际上是使用左上像素作为存储结果的参考点。 在整个输入图像上滑动窗口以生成卷积输出。 下图中的点只是提醒您您将在整个空间中滑动此窗口而不仅是图中所示的两个位置 您可能想知道当窗口到达图像边缘时会发生什么。 选择实际上是在忽略超出边缘的窗口和使用占位符值填充窗口之间。 对于卷积层通常的选择是经常用零或平均值填充它们。 由于卷积的输出形状保持不变因此在 Tensorflow 中被称为相同的填充。 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1Fww3Zea-1681566150312)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/hands-on-dl-tf-zh/img/00044.jpg)] 请注意在最后一个窗口中这实际上只是看一个值。 但是该像素还参与了许多其他位置因此不要觉得它被排除在外了。 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9W5QdutC-1681566150313)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/hands-on-dl-tf-zh/img/00045.jpg)] 提取多个特征 上一节介绍了滑动窗口的一组权重。 这实际上使您可以计算滑动特征。 但是您可能想要在同一窗口中查找多个对象例如垂直或水平边缘。 要提取多个特征您只需要将其他权重矩阵初始化为不同的值即可。 这些多组权重类似于其他神经元和紧密连接的层。 中心的每个权重矩阵W1蓝色和W2绿色将为您提供另一个输出矩阵如下图所示它们分别为H2[1]粉红色和H2[0]橙色。 正确的。 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6lknB6Zp-1681566150313)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/hands-on-dl-tf-zh/img/00046.jpg)] 正如您可以从卷积中提取多个特征一样也可以将多个特征放入这样的网络中。 最明显的例子是具有多种颜色的图像。 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WXLjSdNw-1681566150313)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/hands-on-dl-tf-zh/img/00047.jpg)] 现在观察上图中所示的矩阵。 您确实有一个红色值的矩阵一个绿色值的矩阵和一个蓝色值的矩阵。 现在您的权重矩阵实际上是大小为3x3x3的权重张量并且在所有颜色上的窗口大小均相同。 当然您可以组合所有这些方法并且通常在计算完窗口上的 32 个特征后尤其是在第一个卷积层之后进行 现在您有许多用于下一层的输入通道。 卷积层应用 现在让我们在 TensorFlow 中实现一个简单的卷积层。 首先我们将遍历此示例中使用的显式形状因为这通常很棘手。 然后我们将完成实现和卷积的 TensorFlow 调用。 最后我们将通过传递一个简单的示例图像直观地检查卷积的结果。 探索卷积层 让我们通过一个新的 IPython 会话直接进入代码。 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uXnliMUW-1681566150313)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/hands-on-dl-tf-zh/img/00048.jpg)] 这只是一个小例子可以帮助我们熟悉将 TensorFlow 用于卷积层。 导入必要的工具后让我们制作一个假的10x10图像但对角线的值较大
Make some fake data, 1 data points
image np.random.randint(10,size[1,10,10]) np.eye(10)*10请注意前面代码中指定的异常大小。 10, 10只是图像尺寸但是1是指输入通道的数量。 在这种情况下我们使用一个输入通道就像一个灰度图像。 如果您有彩色图像则这可能是代表红色绿色和蓝色的三个通道。 尽管此处的示例和研究问题只有一个通道灰度级但我们将在深度 CNN 部分中看到如何从卷积层产生多个输入从而在下一个卷积层中产生多通道输入。 因此您仍然会感觉如何处理。 向下移动到 TensorFlow 占位符我们还做了一些看似不寻常的事情。 x tf.placeholder(float, [None, 10, 10]) x_im tf.reshape(x, [-1,10,10,1])在用10, 10和None自然地写入了占位符变量以用于可能的许多图像批量之后我们将其称为tf.reshape。 这是为了重新排列图像的尺寸并使它们具有 TensorFlow 期望的形状。 -1只是意味着根据需要填写尺寸以保持整体尺寸。 10,10当然是我们的图像尺寸最后的1现在是通道数。 同样如果您有一个带有三个通道的彩色图像则为三个。 对于我们的卷积层示例我们希望查看图像的三个像素高和三个像素宽的窗口。 因此我们指定了以下代码所示的内容
Window size to use, 3x3 here
winx 3 winy 3另外让我们从每个窗口中提取两个特征这就是我们的过滤器数量
How many features to compute on the window
num_filters 2您可能还会看到称为内核数量的信息。 指定权重是使事情真正有趣的地方但是一旦您知道语法这并不难。 W1 tf.Variable(tf.truncated_normal([winx, winy,1, num_filters],stddev1./math.sqrt(winx*winy)))我们正在像以前一样使用tf.truncated_normal来生成随机权重。 但是大小非常特殊。 属性winx和winy当然是我们窗口的尺寸1这里是输入通道的数量因此只是灰度而最终尺寸num_filters是输出尺寸过滤器的数量。 同样这类似于密集连接层的神经元数量。 对于随机性的标准差我们仍然可以缩放到参数数量但是请注意每个权重都有一个参数因此win x*win y。 当然每个输出神经元的偏差都需要一个变量因此每个滤波器需要一个变量 b1 tf.Variable(tf.constant(0.1,shape[num_filters]))tf.nn.conv2d函数实际上是此处操作的核心。 我们首先传递调整后的输入x_im然后传递应用于每个窗口的权重然后传递strides参数。 注意 strides参数告诉 TensorFlow 每一步移动窗口多少。 卷积层的典型用法是向右移动一个像素完成一行后向下移动一个像素。 因此有很多重叠之处。 如果要向右移动两个像素向下移动两个像素 但是您可以输入strides[1,2,2,1]。 最后一个数字用于在通道上移动第一个数字用于在一批中移动单独的图像。 将这些设置为1是最常见的方法。 xw tf.nn.conv2d(x_im, W1,strides[1, 1, 1, 1],paddingSAME)paddingSAME与上一节完全相同。 这意味着即使部分滑动窗口超出了输入图像的范围滑动窗口也会运行。 结合跨度为 1 的步长这意味着卷积输出尺寸将与输入相同当然不计算通道或滤波器的数量。 最后我们要通过激活函数传递此卷积输出 h1 tf.nn.relu(xw b1)在这里我们使用relu函数它代表整流线性。 基本上这仅意味着将任何负输入设置为零而将正输入保持不变。 您会看到这种激活常与卷积神经网络一起使用。 因此熟悉它是一件好事。 由于我们已经乘以W1权重因此我们只需要在此处添加偏置项即可产生卷积层输出。 在 TensorFlow 中初始化变量
Remember to initialize!
sess.run(tf.global_variables_initializer())现在您有了一个有效的卷积。 太好了 让我们快速看一下我们劳动成果。 首先我们需要求值h1节点并将示例图像作为数据传递
Peek inside
H h1.eval(feed_dict {x: image})因此我们知道从哪里开始让我们使用以下代码查看示例图像
Lets take a look
import matplotlib.pyplot as plt plt.ion()# Original plt.matshow(image[0]) plt.colorbar()前面代码中的0只是因为奇怪的整形实际上并没有多个数据点。 您可以看到对角线上的值大于其他值这与纯随机的区别在于 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gbNkURWw-1681566150314)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/hands-on-dl-tf-zh/img/00049.jpg)] 让我们看一下第一个输出特征回想一下输出H的形状为1,10,10,2因为有1数据点10像素的宽度和高度以及2特征。 因此要抓住第一个我们需要所有像素和零个带过滤器。 好吧那很有趣。
Conv channel 1
plt.matshow(H[0,:,:,0]) plt.colorbar()请注意清零了多少个头寸 这是relu激活的纠正部分。 整齐。 第二个特征应该看起来相似直到随机初始化为止。 这些权重尚未经过任何训练因此我们不应该期望它们产生有意义的输出。 在这里我们看到碰巧有很多零否则有很多小值。 您的图像看起来或多或少会有所不同需要注意的重要一点是我们的输出尺寸相同但是就像我们对同一图像有两个不同的视图一样。 在本部分中我们在 TensorFlow 中创建了我们的第一个卷积层以掌握所需的奇数形状。 池化层动机 现在让我们了解池化层的共同合作伙伴。 在本节中我们将学习与卷积层相似的最大池化层尽管它们在通用用法上有所不同。 最后我们将展示如何组合这些层以获得最大效果。 最大池化层 假设您使用了卷积层从图像中提取特征并假设您有一个小的权重矩阵可以检测图像窗口中的狗形。 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Zu2KbTZf-1681566150314)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/hands-on-dl-tf-zh/img/00052.jpg)] 当您围绕输出进行卷积时可能会报告许多附近呈狗形的区域。 但这实际上只是由于重叠。 尽管可能只有小狗的形象但彼此之间可能并没有多少只狗。 您真的只希望一次看到该特征最好是在特征最强大的位置。 最大池化层尝试执行此操作。 像卷积层一样池化层在图像的小滑动窗口上工作。 通常研究人员在一个或多个卷积层之后添加一个池化层。 您最常看到的窗口大小是2x2。 您要做的只是提取四个相邻的值此处指的是H[00]通常不会对其施加任何权重。 现在我们希望以某种方式组合这四个值以提取此窗口最有趣的特征。 通常我们要提取最引人注目的特征因此我们选择最大值max(H[00])的像素然后丢弃其余像素。 但是您也可以平均结果或做一些更奇特的事情。 同样尽管我们的卷积窗口有很多重叠但对于合并窗口我们通常不希望有任何重叠因此此步长将等于窗口大小 2。 在前面的10x10示例输出中由于步幅的变化我们的池化输出仅为5x5。 与卷积层的另一个主要区别是池化层通常使用不同的填充方案而卷积层乐于使用相同的填充并以零填充我们最常使用具有有效填充的池化层。 这意味着如果窗口超出图像的范围则将其丢弃。 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OTD3L4oL-1681566150315)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/hands-on-dl-tf-zh/img/00055.jpg)] 这确实会丢失一些边缘信息但要确保输出不会因填充值而产生偏差。 注意 请注意此示例对池化层使用9x9输入但由于有效的填充和跨度为 2因此输出仅为4x4。 8x8输入也将具有4x4输出。 当您将卷积层和池化层组合在一起时它们的真正优势就体现出来了。 通常您会在模型的顶部输入端看到一个卷积层也许带有3x3窗口。 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-g5rL1tVe-1681566150315)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/hands-on-dl-tf-zh/img/00056.jpg)] 这会在图像中的任何位置寻找相同的特征集。 然后立即出现一个2x2的最大池化层仅池出最具特征的区域并缩小尺寸。 您也可以重复此过程。 合并后您现在实际上具有较小的图像P1但是具有像素强度而不是像素颜色强度。 因此您可以创建另一个卷积层以读取第一个池的输出即底部出现的P1然后可以对此应用另一个最大池化层。 请注意由于池化图像大小是如何逐渐缩小的。 直观地您可以将其视为建立跨越图像较大区域的较大比例的特征。 早期的卷积权重经常训练以检测简单的边缘而连续的卷积层将这些边缘组合成逐渐更复杂的形状例如人脸汽车甚至狗。 池化层应用 在本节中我们将研究用于最大池化的 TensorFlow 函数然后我们将讨论从池化层过渡到完全连接层的过程。 最后我们将目视观察池输出以验证其减小的大小。 让我们从上一节中停下来的示例开始。 在开始本练习之前请确保您已执行所有操作直到英镑池化层。 回想一下我们通过3x3卷积和校正的线性激活来放置10x10图像。 现在让我们在卷积层之后添加一个最大2x2的池化层。 p1 tf.nn.max_pool(h1, ksize[1, 2, 2, 1],strides[1, 2, 2, 1], paddingVALID)关键是tf.nn.max_pool。 第一个参数只是我们先前的卷积层h1的输出。 接下来我们有一个奇怪的ksize。 这实际上只是定义了池的窗口大小。 在这种情况下为2x2。 第一个1指的是一次或批量多少个数据点。 通常我们将其保留为1。 最后的1指的是一次包含在合并中的通道数。 请注意这里有两个通道因为卷积产生了两个输出滤波器。 但是我们只有1在这个位置 这是一次最多只有一个特征的唯一故障。 步幅的工作方式与卷积层相同。 此处的区别在于我们使用2x2即合并窗口的大小因为我们不希望有任何重叠。 1之前和之后的值与卷积层中的值完全相同。 因此我们的输出将是每个尺寸的一半这里是5x5。 最后我们将padding设置为VALID。 这意味着如果一个窗口超出了图像的边缘实际上是卷积输出我们将把它扔掉而不使用它。 如果我们的池化层进入另一个卷积层则可以在以下代码行中添加它
We automatically determine the size
p1_size np.product([s.value for s in p1.get_shape()[1:]])但是如果您已经完成了卷积层的工作并且想要像上一节中的模型那样馈入经典的完全连接层该怎么办 这很容易做到 我们只需要将具有许多输出通道的 2D 矩阵的输出展平到长的一维向量即可。 该行是自动计算展平池输出长度的一种方法。 它所做的就是乘以所有尺寸的大小。 因此具有两个通道的5x5矩阵将产生5x5x2即50输出。 下一行tf.reshape使用此值实际展平数组 p1f tf.reshape(p1, [-1, p1_size ])前面的代码行中的-1用于一次处理许多输入图像的潜在批量。 它告诉 TensorFlow 选择第一个维度以便参数的总数保持不变。 让我们看一下池化层的输出以便可以看到一个具体示例 P p1.eval(feed_dict {x: image})首先我们必须根据给定输入图像来实际求值池输出。 由于池化层取决于卷积层因此 TensorFlow 会自动将图像首先放置在其中。 我们可以以与卷积输出完全相同的方式查看结果。 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JMlULnBd-1681566150316)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/hands-on-dl-tf-zh/img/00057.jpg)] 仅查看前面的第一个过滤器输出您会注意到它是5x5。 还要注意存在的值全部在卷积输出的某些单元中。 由于我们在池化层上的唯一激活是最大值因此在每个2x2窗口中会丢弃三个值并且一个值会前进到下一层。 深度 CNN 现在在本节中让我们着重考虑。 在本节中我们将向我们的字体分类模型添加卷积和池化层组合。 我们将确保将其填充到一个密集层中然后我们将看到此模型的工作方式。 在进入新的卷积模型之前请确保开始一个新的 IPython 会话。 执行所有操作直到num_filters 4您就可以准备就绪。 添加卷积和池化层组合 对于卷积层我们将使用5x5窗口其中提取了四个特征。 这比示例要大一些。 我们真的希望模型现在学习一些东西。 首先我们应该使用tf.reshape将36x36的图像放入大小为36x36x1的张量中。 x_im tf.reshape(x, [-1,36,36,1])这仅对于保持通道数笔直很重要。 现在我们将如上所述为过滤器和窗口的数量设置常量 num_filters 4 winx 5 winy 5我们可以像示例问题中那样设置权重张量 W1 tf.Variable(tf.truncated_normal([winx, winy, 1 , num_filters],stddev1./math.sqrt(winx*winy)))winx和winy常数只是窗口尺寸。 1值是输入通道数仅是灰色num_filters是我们要提取的特征数。 同样这就像密集层中神经元的数量。 偏差的工作方式相同但只担心过滤器的数量 b1 tf.Variable(tf.constant(0.1,shape[num_filters]))对conv2d本身的调用也与我们的示例相同。 xw tf.nn.conv2d(x_im, W1,strides[1, 1, 1, 1],paddingSAME)好东西我们在那里推广了它现在使生活变得轻松。 以下是上述代码行的描述 x_im是要转换的输入W1属性是我们刚刚指定的权重矩阵strides告诉 TensorFlow 每一步将窗口移动一次paddingSAME表示接受图像边缘上的窗口 现在我们可以通过relu激活函数进行卷积以完成卷积层。 做得好 h1 tf.nn.relu(xw b1)池化层也与上一节完全相同
2x2 Max pooling, no padding on edges
p1 tf.nn.max_pool(h1, ksize[1, 2, 2, 1],strides[1, 2, 2, 1], paddingVALID)只是为了回顾一下我们在每次跨步时将2x2窗口ksize在卷积输出上滑动两个。 当我们超出数据范围时paddingVALID告诉我们停止。 现在我们有了卷积池和池化层的组合让我们附加一个典型的密集连接层 p1_size np.product([s.value for s in p1.get_shape()[1:]]) p1f tf.reshape(p1, [-1, p1_size ])首先我们需要将合并输出调整为一维向量。 这正是我们在上一节中所做的。 我们自动计算池输出的尺寸以获取用于展平的参数数量。 CNN 字体分类 现在让我们创建一个包含 32 个神经元的密集连接层
Dense layer
num_hidden 32 W2 tf.Variable(tf.truncated_normal([p1_size, num_hidden],stddev2./math.sqrt(p1_size))) b2 tf.Variable(tf.constant(0.2,shape[num_hidden])) h2 tf.nn.relu(tf.matmul(p1f,W2) b2)当然我们需要使用p1_size该层的输入数量来初始化权重矩阵。 那只是卷积和池输出中的扁平数组。 我们需要num_hidden 32 个输出。 有偏项对一些小的非零初始值以相同的方式工作。 在这里我们碰巧也在使用relu激活。 最后我们像往常一样定义输出逻辑回归
Output Layer
W3 tf.Variable(tf.truncated_normal([num_hidden, 5],stddev1./math.sqrt(num_hidden))) b3 tf.Variable(tf.constant(0.1,shape[5]))keep_prob tf.placeholder(float) h2_drop tf.nn.dropout(h2, keep_prob)使用旧模型工作只需确保最终权重使用num_hidden, 5作为尺寸即可。 我们在这里有一个名为dropout的新元素。 现在不用担心。 我们将在下一部分中确切描述它的作用。 只知道它有助于过拟合。 现在您可以初始化所有变量并实现对softmax的最终调用
Just initialize
sess.run(tf.global_variables_initializer())# Define model y tf.nn.softmax(tf.matmul(h2_drop,W3) b3)请注意您的变量名正确匹配。 好的现在完成设置让我们对其进行训练
Climb on cross-entropy
cross_entropy tf.reduce_mean(tf.nn.softmax_cross_entropy_withlogits(logits y 1e-50, labels y))# How we train train_step tf.train.GradientDescentOptimizer(0.01).minimize(cross_entropy)# Define accuracy correctprediction tf.equal(tf.argmax(y,1),tf.argmax(y,1)) accuracy tf.reduce_mean(tf.cast(correct_prediction, float))实际上我们训练模型的方式与之前的模型完全相同。 cross_entropy节点测量我们的预测有多少误差GradientDescentOptimizer调整矩阵的权重。 我们还应谨慎定义节点以提高准确率以便以后进行测量。 现在让我们训练模型约 5,000 次
Actually train
epochs 5000 train_acc np.zeros(epochs//10) test_acc np.zeros(epochs//10) for i in tqdm(range(epochs), asciiTrue):# Record summary data, and the accuracyif i % 10 0: # Check accuracy on train setA accuracy.eval(feeddict{x: train,y: onehot_train, keep_prob: 1.0})train_acc[i//10] A# And now the validation setA accuracy.eval(feeddict{x: test,y: onehot_test, keep_prob: 1.0})test_acc[i//10] Atrain_step.run(feeddict{x: train,y: onehot_train, keep_prob: 0.5})这可能需要一个小时或更长时间。 但是试想一下如果您必须为卷积中的每个窗口训练不同的权重。 通过训练模型让我们看一下精度曲线。 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1cAHx0NC-1681566150316)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/hands-on-dl-tf-zh/img/00058.jpg)] 我们可以看到该模型优于旧的紧密连接模型现在达到了 76% 的训练准确率和约 68% 的验证。 这可能是因为字体即使创建许多不同的字母也以相同的方式使用了许多小范围的特征。 让我们也看看混淆矩阵。 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NT8nk9lI-1681566150316)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/hands-on-dl-tf-zh/img/00059.jpg)] 在这里我们看到该模型仍不完美但正在取得进展。 第一类仍然没有得到很好的代表但是它至少在某种程度上是正确的这与某些以前的模型从来都不是正确的不同。 其他类大多都不错。 第三类实际上是完美的。 这不是一个容易的问题因此任何改进都是好的。 我们还设置了一些代码来专门检查权重但是我们将在以后的部分中保存它。 不过请随时与他们一起玩耍。 您可以将模型权重和信息保存在检查点文件中。
Save the weights
saver tf.train.Saver() saver.save(sess, conv1.ckpt)# Restore saver.restore(sess, conv1.ckpt)这很简单。 您只需创建一个saver对象然后将会话保存到文件名即可。 恢复同样容易。 您告诉 TensorFlow 哪个会话将已保存的文件放入和退出。 如果您更喜欢使用 NumPy 手动保存权重则代码文件还提供以下函数
Or use Numpy manually
def save_all(name conv1):np.savez_compressed(name, W1.eval(),b1.eval(), W2.eval(), b2.eval(),W3.eval(), b3.eval())save_all()def load_all(name conv1.npz):data np.load(name)sess.run(W1.assign(data[arr_0]))sess.run(b1.assign(data[arr_1]))sess.run(W2.assign(data[arr_2]))sess.run(b2.assign(data[arr_3]))sess.run(W3.assign(data[arr_4]))sess.run(b3.assign(data[arr_5]))load_all()因为 NumPy 格式非常可移植且相当轻巧所以这会更方便。 如果要将值导出到另一个 Python 脚本中从而不需要 TensorFlow则您可能更喜欢 NumPy。 在本节中我们建立了卷积神经网络对字体进行分类。 一个类似的模型可以解决当前的研究问题。 您处于 TensorFlow 深度学习的最前沿。 更深的 CNN 在本节中我们将向模型添加另一个卷积层。 不用担心我们将逐步遍历参数以使尺寸调整一致并且我们将学习什么是丢弃训练。 将 CNN 的一层添加到另一层 与往常一样在启动新模型时进行一个新的 IPython 会话并执行直到num_filters1的代码。 太好了现在您都可以开始学习了。 让我们跳入卷积模型。 我们为何不抱有雄心将第一个卷积层设置为具有16过滤器远远超过旧模型中的4。 但是这次我们将使用较小的窗口大小。 只有3x3。 另请注意我们将某些变量名称例如num_filters更改为num_filters1。 这是因为我们将在短时间内拥有另一个卷积层并且我们可能希望在每个卷积层上使用不同数量的过滤器。 该层的其余部分与以前完全一样我们可以进行卷积并进行2x2最大池化并使用整流的线性激活单元。 现在我们添加另一个卷积层。 一些模型先进行几次卷积然后再进行池化另一些模型先进行一次卷积再进行一次池化再进行一次卷积依此类推。 我们在这里做后者。 假设您需要四个滤镜和一个3x3的窗口。 这很容易产生权重 与上一层的唯一大不同是我们现在有许多输入通道请参见num_filters1
Conv layer 2
num_filters2 4 winx2 3 winy2 3 W2 tf.Variable(tf.truncated_normal([winx2, winy2, num_filters1, num_filters2],stddev1./math.sqrt(winx2*winy2))) b2 tf.Variable(tf.constant(0.1,shape[num_filters2]))这是因为我们有16输入通道来自上一层。 如果我们使用num_filters1 8则只有8输入通道。 将此视为我们将要建立的低级特征。 请记住通道的数量和输入就像颜色的数量一样因此如果您要这样考虑可能会有所帮助。 当我们进行实际的第二个卷积层时请确保传入第一个池化层p1的输出。 现在这可以进入新的relu激活函数然后是另一个池化层。 像往常一样我们使用有效填充进行最大2x2的池化
3x3 convolution, pad with zeros on edges
p1w2 tf.nn.conv2d(p1, W2,strides[1, 1, 1, 1], paddingSAME) h1 tf.nn.relu(p1w2 b2)
2x2 Max pooling, no padding on edges
p2 tf.nn.max_pool(h1, ksize[1, 2, 2, 1],strides[1, 2, 2, 1], paddingVALID)展平卷积的池化输出也遵循与最后一个模型相同的过程。 但是这次我们当然致力于合并输出 2。 将其所有参数从窗口中的所有特征转换为一个大向量
Need to flatten convolutional output
p2_size np.product([s.value for s in p2.get_shape()[1:]]) p2f tf.reshape(p2, [-1, p2_size ])现在就像在前面的部分中所做的那样将密集连接的层插入到我们的神经网络中。 只要确保更新变量名即可。
Dense layer
num_hidden 32 W3 tf.Variable(tf.truncated_normal([p2_size, num_hidden],stddev2./math.sqrt(p2_size))) b3 tf.Variable(tf.constant(0.2,shape[num_hidden])) h3 tf.nn.relu(tf.matmul(p2f,W3) b3)现在我们看到了与我们使用的相同的tf.nn.dropout但在上一个模型中没有解释
Drop out training
keep_prob tf.placeholder(float) h3_drop tf.nn.dropout(h3, keep_prob)丢弃是一种从模型中暂时切断神经元的方法。 我们在训练过程中这样做是为了避免过拟合。 每批 TensorFlow 将在此连接层选择不同的神经元输出以进行删除。 面对训练期间的细微变化这有助于模型变得健壮。 keep_prob是保持特定神经元输出的概率。 在训练过程中通常将其设置为0.5。 再一次最终的逻辑回归层和训练节点代码与之前的相同
Output Layer
W4 tf.Variable(tf.truncated_normal([num_hidden, 5],stddev1./math.sqrt(num_hidden))) b4 tf.Variable(tf.constant(0.1,shape[5]))# Just initialize sess.run(tf.initialize_all_variables())# Define model y tf.nn.softmax(tf.matmul(h3_drop,W4) b4)### End model specification, begin training code# Climb on cross-entropy cross_entropy tf.reduce_mean(tf.nn.softmax_cross_entropy_withlogits(y 1e-50, y))# How we train train_step tf.train.GradientDescentOptimizer(0.01).minimize(cross_entropy)# Define accuracy correctprediction tf.equal(tf.argmax(y,1),tf.argmax(y,1)) accuracy tf.reduce_mean(tf.cast(correct_prediction, float))您现在可以执行该操作。 现在我们可以训练我们的完整卷积神经网络这是到目前为止建模的顶点
Actually train
epochs 6000 train_acc np.zeros(epochs//10) test_acc np.zeros(epochs//10) for i in tqdm(range(epochs), asciiTrue):# Record summary data, and the accuracyif i % 10 0: # Check accuracy on train setA accuracy.eval(feeddict{x: train,y: onehot_train, keep_prob: 1.0})train_acc[i//10] A# And now the validation setA accuracy.eval(feeddict{x: test,y: onehot_test, keep_prob: 1.0})test_acc[i//10] Atrain_step.run(feeddict{x: train,\y: onehot_train, keep_prob: 0.5})训练该模型可能需要几个小时因此您可能希望在下一节之前立即开始。 深度 CNN 总结 我们将通过评估模型的准确率来总结深层的 CNN。 上一次我们建立了最终的字体识别模型。 现在让我们看看它是如何工作的。 在本节中我们将学习如何在训练期间处理丢弃问题。 然后我们将看到模型达到了什么精度。 最后我们将权重可视化以了解模型学到了什么。 确保在上一个模型中进行训练后在 IPython 会话中接手。 回想一下当我们训练模型时我们使用dropout删除了一些输出。 尽管这有助于过拟合但在测试过程中我们要确保使用每个神经元。 这既提高了准确率又确保我们不会忘记评估模型的一部分。 这就是为什么在以下代码行中keep_prob为1.0以便始终保留所有神经元的原因。
Check accuracy on train setA accuracy.eval(feeddict{x: train,y: onehot_train, keep_prob: 1.0})train_acc[i//10] A# And now the validation setA accuracy.eval(feeddict{x: test,y: onehot_test, keep_prob: 1.0})test_acc[i//10] A让我们看看最终模型是如何做的 像往常一样看一下训练和测试的准确率
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-s6ampip1-1681566150317)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/hands-on-dl-tf-zh/img/00060.jpg)] 这里的训练准确率高达 85%并且测试准确率也相差不远。还不错。模型的效果取决于输入数据的噪声。 如果我们仅包含少量信息无论是示例数量还是参数或像素数量那么我们都无法期望模型表现完美。 在这种情况下您可以应用的一种度量标准是人类将单个字母的图像分类到这些字体中的每种字体的程度。 一些字体非常有特色而另一些则相似尤其是某些字母。 由于这是一个新颖的数据集因此没有直接的基准可以与之进行比较但是您可以挑战自己以击败本课程中介绍的模型。 如果这样做您可能希望减少训练时间。 当然具有较少参数和更简单计算的较小网络将更快。 另外如果您开始使用 GPU 或至少使用多核 CPU则可以显着提高速度。 通常 10 倍更好具体取决于硬件。 其中一部分是并行性一部分是针对神经网络进行了微调的高效低层库。 但是最简单的方法是从简单开始逐步发展到更复杂的模型就像您一直在处理此问题一样。 回到这个模型让我们看一下混淆矩阵
Look at the final testing confusion matrix
pred np.argmax(y.eval(feed_dict{x: test, keepprob: 1.0,y: onehot_test}), axis 1) conf np.zeros([5,5]) for p,t in zip(pred,np.argmax(onehot_test,axis1)):conf[t,p] 1plt.matshow(conf) plt.colorbar()以下是输出 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3fV2tZK4-1681566150317)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/hands-on-dl-tf-zh/img/00061.jpg)] 在这里我们可以看到该模型通常在各个类上都做得很好。 类1仍然不是完美的但是比以前的模型要好得多。 通过将较小比例的特征分解为较大的片段我们终于找到了一些适合这些类的指标。 您的图像可能看起来不完全相同。 根据权重的随机初始化结果可能会有些不幸。 让我们看一下第一卷积层的 16 个特征的权重
Lets look at a subplot of some weights
f, plts plt.subplots(4,4) for i in range(16):plts[i//4,i%4].matshow(W1.eval()[:,:,0,i],cmap plt.cm.gray_r)因为窗口大小是3x3所以每个都是3x3矩阵。 嗯 我们可以看到权重肯定是缩小了小范围的特征。 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-my7CzNBk-1681566150317)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/hands-on-dl-tf-zh/img/00062.jpg)] 您可以看到某些事物例如检测到边缘或圆角诸如此类。 如果我们使用更大的窗口重做模型这可能会更加明显。 但是令人印象深刻的是您可以在这些小补丁中发现多少特征。 我们还要看一下最终的层权重以了解不同的字体类如何解释最终的紧密连接的神经元。 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-V5IN4K4t-1681566150317)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/hands-on-dl-tf-zh/img/00063.jpg)] 每行代表一类每列代表最终的隐藏层神经元之一。 有些类别受到某些神经元的强烈影响而另一些类别的影响则微乎其微。 您会看到对于某些类别给定的神经元在积极或消极方面非常重要而对于其他类别则非常重要。 请注意因为我们已经使卷积变平所以我们不希望在输出中看到明显的结构。 这些列可以按任何顺序排列但仍会产生相同的结果。 在本章的最后部分我们检查了一个真实的实时的坦率的非常好的深度卷积神经网络模型。 我们使用卷积层和池化层的做法来构筑该思想以便提取结构化数据例如图像中的小规模和大规模型征。 对于许多问题这是神经网络最强大的类型之一。 总结 在本章中我们遍历了示例图像上的卷积层。 我们解决了理解卷积的实际问题。 它们可以令人费解但希望不再造成混淆。 我们最终将此概念应用于 TensorFlow 中的一个简单示例。 我们探索了卷积池化层的共同伙伴。 我们解释了常见的卷积伙伴最大池化层的工作原理。 然后随着我们的进步我们通过在示例中添加一个池化层将其付诸实践。 我们还练习了在 TensorFlow 中创建最大池化层。 我们开始将卷积神经网络添加到字体分类问题中。 在下一章中我们将研究具有时间成分的模型即循环神经网络RNN。 四、循环神经网络介绍 在上一章中您了解了卷积网络。 现在该介绍一种新型的模型和问题了-循环神经网络RNN。 在本章中我们将解释 RNN 的工作原理并在 TensorFlow 中实现一个。 我们的示例问题将是具有天气信息的简单季节预报器。 我们还将看一下skflow它是 TensorFlow 的简化接口。 这将使我们能够快速重新实现旧的图像分类模型和新的 RNN。 在本章的最后您将对以下概念有很好的理解 探索 RNNTensorFlow Learn密集神经网络DNN 探索 RNN 在本节中我们将探索 RNN。 一些背景信息将使我们开始工作然后我们将探讨一个激发性的天气建模问题。 我们还将在 TensorFlow 中实现和训练 RNN。 在典型模型中您要预测一些X输入特征和一些Y输出。 我们通常将不同的训练样本视为独立的观察结果。 因此数据点 1 的特征不应影响数据点 2 的预测。 但是如果我们的数据点相互关联怎么办 最常见的示例是每个数据点Xt代表在时间t收集的特征。 自然地假设时间t和时间t1的特征对于时间t1的预测都将很重要。 换句话说历史很重要。 现在在建模时您可以只包含两倍的输入特征将前一个时间步长添加到当前特征中并计算两倍的输入权重。 但是如果您正在努力构建神经网络来计算变换特征那么可以在当前时间步网络中使用上一个时间步的中间特征就很好了。 RNN 正是这样做的。 像往常一样考虑您的输入Xt但在某些状态下添加来自上一个时间步的St-1作为附加特征。 现在您可以像往常一样计算权重以预测Yt并产生一个新的内部状态St以供下一步使用。 对于第一步通常使用默认或零初始状态。 经典的 RNN 实际上就是这么简单但是当今文学中有更高级的结构例如门控循环单元和长短期存储电路。 这些不在本书的讨论范围之内但是它们遵循相同的原理并且通常适用于相同类型的问题。 模型权重 您可能想知道我们如何根据上一个时间步长计算所有这些相关性的权重。 计算梯度确实涉及到时间计算的递归但不要担心TensorFlow 处理乏味的东西让我们进行建模
read in data
filename weather.npz data np.load(filename) daily data[daily] weekly data[weekly]num_weeks len(weekly) dates np.array([datetime.datetime.strptime(str(int(d)),%Y%m%d) for d in weekly[:,0]])要使用 RNN我们需要一个带有时间成分的数据建模问题。 字体分类问题在这里并不是很合适。 因此让我们看一些天气数据。 weather.npz文件是几十年来来自美国一个城市的气象站数据的集合。 daily数组包含一年中每一天的测量值。 数据有六列从日期开始。 接下来是降雨量以英寸为单位测量当日的降雨量。 之后出现两列降雪-第一列是当前地面上的实测雪而第二列是当天的降雪单位是英寸。 最后我们有一些温度信息以华氏度为单位的每日最高和最低每日温度。 我们将使用的weekly数组是每日信息的每周摘要。 我们将使用中间日期来表示一周然后我们将汇总一周中的所有降雨量。 但是对于降雪我们将平均降雪量因为从一个寒冷的天气到第二天坐在地上的积雪都没有意义。 虽然降雪但我们总共要一周就像下雨一样。 最后我们将平均一周的高温和低温。 现在您已经掌握了数据集我们该如何处理 一个有趣的基于时间的建模问题是尝试使用天气信息和前几周的历史来预测特定一周的季节。 在美国的北半球6 月至 8 月的气温较高而 12 月至 2 月的气温较低两者之间有过渡。 春季通常是多雨的冬季通常包括雪。 尽管一周的变化很大但一周的历史应该可以提供一定的预测能力。 了解 RNN 首先让我们从压缩的 NumPy 数组中读取数据。 如果您想探索自己的模型weather.npz文件也包括每日数据。 np.load将两个数组都读入字典并将每周设置为我们感兴趣的数据 num_weeks自然就是我们拥有多少个数据点在这里几十年的信息的值 num_weeks len(weekly)为了格式化星期我们使用 Python datetime.datetime对象以年月日格式读取存储字符串 dates np.array([datetime.datetime.strptime(str(int(d)),%Y%m%d) for d in weekly[:,0]])我们可以使用每周的日期来指定其季节。 对于此模型因为我们正在查看天气数据所以我们使用气象季节而不是普通的天文季节。 幸运的是这很容易通过 Python 函数实现。 从datetime对象中获取月份我们可以直接计算出该季节。 春季零季节是 3 月至 5 月夏季是 6 月至 8 月秋天是 9 月至 11 月最后是冬季 12 月至 2 月。 以下是简单的函数它仅求值月份并实现该月份 def assign_season(date): Assign season based on meteorological season.Spring - from Mar 1 to May 31Summer - from Jun 1 to Aug 31Autumn - from Sep 1 to Nov 30Winter - from Dec 1 to Feb 28 (Feb 29 in a leap year)month date.month# spring 0if 3 month 6:season 0# summer 1elif 6 month 9:season 1# autumn 2elif 9 month 12:season 2# winter 3elif month 12 or month 3:season 3return season让我们注意一下我们有四个季节和五个输入变量例如历史状态中的 11 个值
There are 4 seasons
num_classes 4# and 5 variables num_inputs 5# And a state of 11 numbers state_size 11现在您可以计算标签了 labels np.zeros([num_weeks,num_classes])
read and convert to one-hot
for i,d in enumerate(dates):labels[i,assign_season(d)] 1通过制作全零数组并在分配季节的位置放置一个全零我们直接以一键式格式执行此操作。 凉 您仅用几个命令就总结了几十年的时间。 由于这些输入特征在非常不同的尺度上测量非常不同的事物即降雨降雪和温度因此我们应注意将它们全部置于相同的尺度上。 在下面的代码中我们抓住了输入特征当然跳过了日期列并减去平均值以将所有特征居中为零
extract and scale training data
train weekly[:,1:] train train - np.average(train,axis0) train train / train.std(axis0)然后我们将每个特征除以其标准偏差来缩放。 这说明温度范围大约为 0 到 100而降雨量仅在大约 0 到 10 之间变化。数据准备工作不错 它并不总是很有趣但这是机器学习和 TensorFlow 的关键部分。 现在进入 TensorFlow 模型
These will be inputs
x tf.placeholder(float, [None, num_inputs])
TF likes a funky input to RNN
x_ tf.reshape(x, [1, num_weeks, num_inputs])我们使用占位符变量正常输入数据但是随后您会看到将整个数据集奇怪地重塑为一个大张量。 不用担心这是因为从技术上讲我们有一个漫长而连续的观测序列。 y变量只是我们的输出 y tf.placeholder(float, [None,num_classes])我们将计算每个季节每周的概率。 cell变量是循环神经网络的关键 cell tf.nn.rnn_cell.BasicRNNCell(state_size)这告诉 TensorFlow 当前时间步长如何取决于前一个时间步长。 在这种情况下我们将使用基本的 RNN 单元。 因此我们一次只回首一周。 假设它具有状态大小或 11 个值。 随意尝试使用更多奇异的单元和不同的状态大小。 要使用该单元格我们将使用tf.nn.dynamic_rnn outputs, states tf.nn.dynamicrnn(cell,x,dtypetf.nn.dtypes.float32, initial_stateNone)这可以智能地处理递归而不是简单地将所有时间步长展开成一个巨大的计算图。 因为我们在一个序列中有成千上万的观测值所以这对于获得合理的速度至关重要。 在单元格之后我们指定输入x_然后指定dtype以使用 32 位将十进制数字存储在浮点数中然后指定空的initial_state。 我们使用此输出建立一个简单的模型。 从这一点开始该模型几乎完全符合您对任何神经网络的期望 我们将 RNN 单元的输出一些权重相乘并添加一个偏差以获得该周每个类的分数 W1 tf.Variable(tf.truncated_normal([state_size,num_classes],stddev1./math.sqrt(num_inputs))) b1 tf.Variable(tf.constant(0.1,shape[num_classes]))
reshape the output for traditional usage
h1 tf.reshape(outputs,[-1,state_size])注意 请注意由于我们有一个长序列因此我们确实需要进行此重塑操作以再次获得合适的大小。 您应该非常熟悉我们的分类cross_entropy损失函数和训练优化器
Climb on cross-entropy
cross_entropy tf.reduce_mean(tf.nn.softmax_cross_entropy_withlogits(y 1e-50, y))# How we train train_step tf.train.GradientDescentOptimizer(0.01).minimize(cross_entropy)# Define accuracy correctprediction tf.equal(tf.argmax(y,1),tf.argmax(y,1)) accuracytf.reduce_mean(tf.cast(correct_prediction, float))搭建 TensorFlow 模型的出色工作 为了训练这一点我们将使用一个熟悉的循环
Actually train
epochs 100 train_acc np.zeros(epochs//10) for i in tqdm(range(epochs), asciiTrue):if i % 10 0: # Record summary data, and the accuracy# Check accuracy on train setA accuracy.eval(feeddict{x: train, y: labels})train_acc[i//10] Atrain_step.run(feeddict{x: train, y: labels})由于这是一个虚拟的问题因此我们不必担心模型的实际准确率。 这里的目的只是看 RNN 的工作原理。 您可以看到它像任何 TensorFlow 模型一样运行 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-r1P3J2v3-1681566150318)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/hands-on-dl-tf-zh/img/00065.jpg)] 如果您确实看过准确率您会发现它做得很好。 比 25% 的随机猜测要好得多但仍有很多东西需要学习。 TensorFlowLearn 正如 Scikit-Learn 是传统机器学习算法的便捷接口一样tf.contrib.learn以前称为skflow它是构建和训练 DNN 的简化接口。 现在随 TensorFlow 的每次安装免费提供 即使您不喜欢该语法也值得将 TensorFlow Learn 作为 TensorFlow 的高级 API。 这是因为它是当前唯一受官方支持的版本。 但是您应该知道有许多替代的高级 API 可能具有更直观的接口。 如果有兴趣请参阅 Kerastf.slim包含在 TF 中或 TFLearn。为了了解有关 TensorFlow-Slim 的更多信息请参阅此链接。 起步 要开始使用 TensorFlow Learn您只需导入它即可。 我们还将导入estimators函数这将帮助我们制作常规模型
TF made EZ
import tensorflow.contrib.learn as learn from tensorflow.contrib.learn.python.learn.estimators import estimator我们还希望导入一些用于基本操作的库 – 抓取 NumPymath和 Matplotlib可选。 这里值得注意的是sklearn这是一个通用的机器学习库它试图简化模型的创建训练和使用。 我们主要将其用于方便的指标但是您会发现它具有与 Learn 类似的主接口
Some basics
import numpy as np import math import matplotlib.pyplot as plt plt.ion()# Learn more sklearn
scikit-learn.org
import sklearn from sklearn import metrics接下来我们将读取一些数据进行处理。 由于您熟悉字体分类问题因此让我们继续对其建模。 为了重现性您可以使用自己喜欢的数字为 NumPy 播种
Seed the data
np.random.seed(42)# Load data data np.load(data_with_labels.npz) train data[arr_0]/255. labels data[arr_1]对于本练习将您的数据分为训练和验证集 np.random.permutation对于为您的输入数据生成随机顺序很有用所以让我们像在以前的模块中那样使用它
Split data into training and validation
indices np.random.permutation(train.shape[0]) valid_cnt int(train.shape[0] * 0.1) test_idx, training_idx indices[:valid_cnt],\indices[valid_cnt:] test, train train[test_idx,:],\train[training_idx,:] test_labels, train_labels labels[test_idx],\labels[training_idx]在这里tf.contrib.learn可以对其接收的数据类型有所变幻。 为了发挥出色我们需要重铸数据。 图像输入将是np.float32而不是默认的 64 位。 同样我们的标签将是np.int32而不是np.uint8即使这只会占用更多内存 train np.array(train,dtypenp.float32) test np.array(test,dtypenp.float32) train_labels np.array(train_labels,dtypenp.int32) test_labels np.array(test_labels,dtypenp.int32)逻辑回归 让我们做一个简单的逻辑回归示例。 这将非常迅速并显示learn如何使简单的模型变得异常简单。 首先我们必须创建模型期望输入的变量列表。 您可能希望可以使用一个简单的参数来设置它但实际上是这个不直观的learn.infer_real_valued_columns_from_input函数。 基本上如果将输入数据提供给该函数它将推断出您拥有多少个特征列以及其应处于的形状。在我们的线性模型中我们希望将图像展平为一维因此我们对其执行整形推断函数时
Convert features to learn style
feature_columns learn.infer_real_valued_columns_from_input(train.reshape([-1,36*36]))现在创建一个名为classifier的新变量并为其分配estimator.SKCompat结构。 这是一个 Scikit-Learn 兼容性层允许您在 TensorFlow 模型中使用某些 Scikit-Learn 模块。 无论如何这仅仅是敷料真正创建模型的是learn.LinearClassifier。 这样就建立了模型但是没有训练。 因此它只需要几个参数。 首先是那个时髦的feature_columns对象只是让您的模型知道期望输入什么。 第二个也是最后一个必需的参数是它的反函数模型应具有多少个输出值 我们有五种字体因此设置n_classes 5。 这就是整个模型规格
Logistic Regression
classifier estimator.SKCompat(learn.LinearClassifier(feature_columns feature_columns,n_classes5))要进行训练只需要一行。 调用classifier.fit并输入数据当然是经过调整的形状输出标签请注意这些标签不必是一字不漏的格式以及其他一些参数。 steps参数确定模型将查看多少批次即优化算法要采取的步骤。 batch_size参数通常是优化步骤中要使用的数据点数。 因此您可以将步数乘以批次大小除以训练集中的数据点数来计算周期数。 这似乎有点违反直觉但至少是一个快速的说明您可以轻松编写帮助函数以在步骤和周期之间进行转换
One line training
steps is number of total batches
steps*batch_size/len(train) num_epochs
classifier.fit(train.reshape([-1,36*36]),train_labels,steps1024,batch_size32)为了评估我们的模型我们将照常使用sklearn的metrics。 但是基本学习模型预测的输出现在是字典其中包含预先计算的类标签以及概率和对数。 要提取类标签请使用键classes
sklearn compatible accuracy
test_probs classifier.predict(test.reshape([-1,36*36])) sklearn.metrics.accuracy_score(test_labels,test_probs[classes])DNN 尽管有更好的方法来实现纯线性模型但 TensorFlow 和learn真正的亮点在于简化具有不同层数的 DNN。 我们将使用相同的输入特征但现在我们将构建一个具有两个隐藏层的 DNN首先是10神经元然后是5。 创建此模型仅需一行 Python 代码 这再简单不过了。 规格类似于我们的线性模型。 我们仍然需要SKCompat但现在是learn.DNNClassifier。 对于参数还有一个额外的要求每个隐藏层上的神经元数量以列表的形式传递。 这个简单的参数真正抓住了 DNN 模型的本质使深度学习的力量触手可及。 也有一些可选的参数但是我们只提及optimizer。 这样您就可以在不同的常见优化器例程之间进行选择例如随机梯度下降SGD或 Adam。 很方便
Dense neural net
classifier estimator.SKCompat(learn.DNNClassifier(feature_columns feature_columns,hidden_units[10,5],n_classes5,optimizerAdam))训练和评估与线性模型完全一样。 仅出于演示目的我们还可以查看此模型创建的混淆矩阵。 请注意我们训练不多因此该模型可能无法与使用纯 TensorFlow 的早期作品竞争
Same training call
classifier.fit(train.reshape([-1,36*36]),train_labels,steps1024,batch_size32)# simple accuracy test_probs classifier.predict(test.reshape([-1,36*36])) sklearn.metrics.accuracy_score(test_labels,test_probs[classes])# confusion is easy train_probs classifier.predict(train.reshape([-1,36*36])) conf metrics.confusion_matrix(train_labels,train_probs[classes]) print(conf)TFLearn 中的卷积神经网络CNN CNN 支持一些最成功的机器学习模型因此我们希望learn支持它们。 实际上该库支持使用任意 TensorFlow 代码 您会发现这是一种祝福和诅咒。 拥有任意可用的代码意味着您可以使用learn来执行几乎可以使用纯 TensorFlow 进行的所有操作从而提供最大的灵活性。 但是通用接口往往会使代码更难以读写。 如果您发现自己在learn中使用接口使某些复杂的模型起作用那么可能是时候使用纯 TensorFlow 或切换到另一个 API 了。 为了证明这种通用性我们将构建一个简单的 CNN 来解决字体分类问题。 它将具有一个带有四个过滤器的卷积层然后将其展平为具有五个神经元的隐藏密集层最后以密集连接的输出逻辑回归结束。 首先让我们再进行几个导入。 我们想要访问通用的 TensorFlow但是我们还需要layers模块以learn期望的方式调用 TensorFlow layers
Access general TF functions
import tensorflow as tf import tensorflow.contrib.layers as layers通用接口迫使我们编写为模型创建操作的函数。 您可能会发现这很乏味但这就是灵活性的代价。 用三个参数启动一个名为conv_learn的新函数。 X将作为输入数据y将作为输出标签尚未进行一次热编码mode确定您是训练还是预测。 请注意您永远不会直接与此特征交互 您只需将其传递给需要这些参数的构造器。 因此如果您想改变层的数量或类型则需要编写一个新的模型函数或另一个会生成这种模型函数的函数 def conv_learn(X, y, mode):由于这是卷积模型因此我们需要确保数据格式正确。 特别是这意味着将输入重塑为不仅具有正确的二维形状36x36而且具有 1 个颜色通道最后一个尺寸。 这是 TensorFlow 计算图的一部分因此我们使用tf.reshape而不是np.reshape。 同样由于这是通用图因此我们希望将输出进行一次热编码tf.one_hot提供了该功能。 请注意我们必须描述有多少类5应设置的值1和未设置的值0 # Ensure our images are 2d X tf.reshape(X, [-1, 36, 36, 1])# Well need these in one-hot formaty tf.one_hot(tf.cast(y, tf.int32), 5, 1, 0)现在真正的乐趣开始了。 为了指定卷积层让我们初始化一个新的作用域conv_layer。 这只会确保我们不会破坏任何变量。 layers.convolutional提供了基本的机制。 它接受我们的输入一个 TensorFlow 张量多个输出实际上是内核或过滤器的数量以及内核的大小这里是5x5的窗口。 对于激活函数让我们使用整流线性可以从主 TensorFlow 模块调用它。 这给了我们基本的卷积输出h1。 实际上最大池化的发生与常规 TensorFlow 中的发生完全相同既不容易也不难。 具有通常的内核大小和步幅的tf.nn.max_pool函数可以正常工作。 保存到p1中 # conv layer will compute 4 kernels for each 5x5 patchwith tf.variable_scope(conv_layer):# 5x5 convolution, pad with zeros on edgesh1 layers.convolution2d(X, num_outputs4,kernel_size[5, 5], activation_fntf.nn.relu)# 2x2 Max pooling, no padding on edgesp1 tf.nn.max_pool(h1, ksize[1, 2, 2, 1],strides[1, 2, 2, 1], paddingVALID)现在要在此时展平张量我们需要计算将要成为一维张量的元素数量。 一种方法是将所有尺寸值batch_size除外它占据第一个位置相乘。 此特定操作可以在计算图之外进行因此我们使用np.product。 一旦提供了总大小我们就可以将其传递给tf.reshape以重新划分图中的中间张量 # Need to flatten conv output for use in dense layerp1_size np.product([s.value for s in p1.get_shape()[1:]])p1f tf.reshape(p1, [-1, p1_size ])现在是时候建立紧密连接的层了。 layers模块再次出现这一次具有fully_connected函数致密层的另一个名称。 这需要上一层神经元的数量和激活函数它们又由通用 TensorFlow 提供。 为了演示的目的我们也在此处添加一个dropout对象。 layers.dropout提供了接口。 不出所料它需要上一层以及保持给定节点输出的概率。 但是它也需要我们传递给原始conv_learn函数的mode参数。 所有这些复杂的接口只不过是在训练期间丢弃节点。 如果您能解决这个问题那么我们几乎可以遍历整个模型 # densely connected layer with 32 neurons and dropouth_fc1 layers.fully_connected(p1f,5,activation_fntf.nn.relu)drop layers.dropout(h_fc1, keep_prob0.5,is_trainingmode tf.contrib.learn.ModeKeys.TRAIN)现在有一些坏消息。 我们需要手动写出最终的线性模型损失函数和优化参数。 这可能会因版本而异因为在某些情况下以前对用户来说更容易但对后端的维护则更困难。 但是让我们坚持下去 确实不是很繁琐。 另一个layers.fully_connected层创建最终的逻辑回归。 请注意此处的激活应为None因为它是线性的。 处理方程逻辑方面的是损失函数。 值得庆幸的是TensorFlow 提供了softmax_cross_entropy函数因此我们无需手动将其写出。 给定输入输出和损失函数我们可以应用优化例程。 同样layers.optimize_loss以及相关函数可以最大程度地减少痛苦。 将您的损失节点优化器作为字符串和学习率传递给它。 此外为其提供此get_global_step()参数以确保优化程序正确处理衰减。 最后我们的函数需要返回一些东西。 第一它应该报告预测的类别。 接下来它必须自己提供损失节点输出。 最后训练节点必须可用于外部例程以实际执行所有操作 logits layers.fully_connected(drop, 5, activation_fnNone)loss tf.losses.softmax_cross_entropy(y, logits)# Setup the training function manuallytrain_op layers.optimize_loss(loss,tf.contrib.framework.get_global_step(),optimizerAdam,learning_rate0.01)return tf.argmax(logits, 1), loss, train_op虽然指定模型可能很麻烦但使用它就像以前一样容易。 现在使用最通用的例程learn.Estimator并将模型函数传递给model_fn。 并且不要忘记SKCompat 训练的工作原理与以前完全相同只是请注意我们不需要在此处重塑输入内容因为这是在函数内部处理的。 要使用模型进行预测您可以简单地调用classifier.predict但是请注意您会获得函数返回的第一个参数作为输出。 我们选择返回该类但也可以从softmax函数中返回概率。 这就是tf.contrib.learn模型的基础
Use generic estimator with our function
classifier estimator.SKCompat(learn.Estimator(model_fnconv_learn))classifier.fit(train,train_labels,steps1024,batch_size32)# simple accuracy metrics.accuracy_score(test_labels,classifier.predict(test))提取权重 虽然训练和预测是模型的核心用途但也必须研究模型的内部也很重要。 不幸的是此 API 使得提取参数权重变得困难。 值得庆幸的是本节提供了一些文献记载较弱的功能的简单示例以使权重从tf.contrib.learn模型中消失。 为了拉出模型的权重我们确实需要从基础 TensorFlow 计算图中的某些点获取值。 TensorFlow 提供了许多方法来执行此操作但是第一个问题只是弄清楚您感兴趣的变量被称为什么。 可以使用learn图中的变量名列表但该变量名已隐藏在_estimator隐藏属性下。 调用classifier._estimator.get_variable_names()将返回您各种名称的字符串列表。 其中许多将是无趣的例如OptimizeLoss条目。 在我们的情况下我们正在寻找conv_layer和fully_connected元素
See layer names
print(classifier._estimator.get_variable_names()) [OptimizeLoss/beta1_power,OptimizeLoss/beta2_power,OptimizeLoss/conv_layer/Conv/biases/Adam,OptimizeLoss/conv_layer/Conv/biases/Adam_1,OptimizeLoss/conv_layer/Conv/weights/Adam,OptimizeLoss/conv_layer/Conv/weights/Adam_1,OptimizeLoss/fully_connected/biases/Adam,OptimizeLoss/fully_connected/biases/Adam_1,OptimizeLoss/fully_connected/weights/Adam,OptimizeLoss/fully_connected/weights/Adam_1,OptimizeLoss/fully_connected_1/biases/Adam,OptimizeLoss/fully_connected_1/biases/Adam_1,OptimizeLoss/fully_connected_1/weights/Adam,OptimizeLoss/fully_connected_1/weights/Adam_1,OptimizeLoss/learning_rate,conv_layer/Conv/biases,conv_layer/Conv/weights,fully_connected/biases,fully_connected/weights,fully_connected_1/biases,fully_connected_1/weights,global_step]找出哪个条目是您要查找的层可能是一个挑战。 在这里conv_layer显然来自我们的卷积层。 但是您看到两个fully_connected元素一个是展平时的密集层另一个是输出权重。 事实证明它们是按指定的顺序命名的。 我们首先创建了密集的隐藏层所以它获得了基本的fully_connected名称而输出层位于最后因此在其上面加上了_1。 如果不确定可以随时查看权重数组的形状具体取决于模型的形状。 要真正发挥作用这是另一个不可思议的要求。 这次classifier._estimator.get_variable_value带有变量名字符串提供了具有相关权重的 NumPy 数组。 试用卷积权重和偏差以及密集层
Convolutional Layer Weights
print(classifier._estimator.get_variable_value(conv_layer/Conv/weights)) print(classifier._estimator.get_variable_value(conv_layer/Conv/biases))# Dense Layer print(classifier._estimator.get_variable_value(fully_connected/weights))# Logistic weights print(classifier._estimator.get_variable_value(fully_connected_1/weights))现在掌握了如何在tf.contrib.learn神经网络内部进行交流的深奥知识您将可以使用此高级 API 拥有更多的能力。 尽管在许多情况下很方便但在其他情况下却很麻烦。 永远不要害怕暂停并考虑切换到另一个库 为正确的机器学习工作使用正确的机器学习工具。 总结 从简单理解 RNN 到在新的 TensorFlow 模型中实现它们您在本章中学到了很多东西。 我们还查看了 TensorFlow 的一个简单接口称为 TensorFlow Learn。 我们还遍历了 DNN并了解了 CNN 和详细提取权重。 在下一章中我们将对 TensorFlow 进行总结看看我们已经走了多远以及从这里可以去哪里。 五、总结 在上一章中我们了解了 TensorFlow 和 RNN 模型的另一个接口。 本章将对 TensorFlow 进行总结探讨我们已经走了多远以及从这里可以去哪里。 首先我们将回顾字体分类问题的研究进展然后简要介绍除深度学习之外的 TensorFlow并查看其将来的发展方向。 在本章的最后您将熟悉以下概念 研究回顾快速浏览所有模型TensorFlow 的未来其他一些 TensorFlow 项目 现在让我们开始详细研究和评估模型。 研究回顾 在本节中我们将比较字体分类问题中的模型。 首先我们应该提醒自己数据是什么样的。 然后我们将检查简单的逻辑密集神经网络和卷积神经网络模型。 使用 TensorFlow 建模已经走了很长一段路。 但是在继续进行深度学习之前让我们回头看看模型如何比较字体分类问题。 首先让我们再次查看数据这样我们就不会忽略这个问题。 实际上让我们看一个包含每种字体的所有字母和数字的图像只是看看我们有什么形状
One look at a letter/digit from each font
Best to reshape as one large array, then plot
all_letters np.zeros([5*36,62*36]) for font in range(5):for letter in range(62):all_letters[font*36:(font1)*36,letter*36:(letter1)36] \train[9(font*62 letter)]Matplotlib 需要处理很多子图。 因此我们将创建一个新数组高 5 幅图像5 种字体乘以 36 像素宽 62 幅图像62 个字母或数字乘以 36 像素。 分配零数组后我们可以将训练图像堆叠到其中。 字体和字母充当索引并且我们在大型数组中一次设置36x36的值。 注意这里我们在train数组中有9因为我们每个字母只采取一种抖动类型。 让我们来看一下pcolormesh的快速调用 plt.pcolormesh(all_letters,cmapplt.cm.gray)[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WnKqy2tx-1681566150318)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/hands-on-dl-tf-zh/img/00066.jpg)] 如您所见我们拥有整个字母大写和小写以及数字 0 到 9。某些字体看起来与其他字体相似而无论如何0字体在其自身的世界中无论如何对于人眼都是如此。 每种字体都有有趣的样式属性我们希望我们的模型能够继续使用。 快速浏览所有模型 让我们回顾一下我们构建的每个模型以对这些字体及其优点和缺点进行建模 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-t1TAUczc-1681566150318)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/hands-on-dl-tf-zh/img/00067.jpg)] 乍一看我们缓慢地建立了更复杂的模型并考虑了数据的结构以提高准确率。 逻辑回归模型 首先我们从一个简单的逻辑回归模型开始 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-J5qBGGfL-1681566150319)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/hands-on-dl-tf-zh/img/00068.jpg)] 它具有36x36像素外加 1 倍乘以 5 类总权重即我们需要训练的 6,485 个参数。 经过 1,000 次训练后此模型的验证准确率达到了 40%。 您的结果可能会有所不同。 这相对较差但是该模型具有一些优势。 让我们回头看一下代码
These will be inputs
Input pixels, flattened
x tf.placeholder(float, [None, 1296])
Known labels
y_ tf.placeholder(float, [None,5])# Variables W tf.Variable(tf.zeros([1296,5])) b tf.Variable(tf.zeros([5]))# Just initialize sess.run(tf.initialize_all_variables())# Define model y tf.nn.softmax(tf.matmul(x,W) b)逻辑回归的简单性意味着我们可以直接看到并计算每个像素如何影响类概率。 这种简单性也使模型在训练中相对较快地收敛并且当然也易于编程因为它只需要几行 TensorFlow 代码。 单隐层神经网络模型 我们的下一个模型是具有最终 Softmax 激活层的单个隐藏层密集连接的神经网络等效于逻辑回归 该模型具有36x36像素外加 1 个偏移乘以 128 个节点再加上 128 个隐藏节点加上 1 个偏移乘以 5 个类的总权重即 166,661 个参数。 隐藏层使用sigmoid激活函数来实现非线性。 在经过 5,000 个周期后参数的纠缠达到了约 60% 的验证准确率这是一个很大的改进。 但是此改进的代价是大量增加了计算复杂性中的参数数量您可以从代码中大致了解一下
These will be inputs
Input pixels, flattened
x tf.placeholder(float, [None, 1296])
Known labels
y_ tf.placeholder(float, [None,5])# Hidden layer num_hidden 128 W1 tf.Variable(tf.truncated_normal([1296, num_hidden],stddev1./math.sqrt(1296))) b1 tf.Variable(tf.constant(0.1,shape[num_hidden])) h1 tf.sigmoid(tf.matmul(x,W1) b1)# Output Layer W2 tf.Variable(tf.truncated_normal([num_hidden, 5],stddev1./math.sqrt(5))) b2 tf.Variable(tf.constant(0.1,shape[5]))# Just initialize sess.run(tf.initialize_all_variables())# Define model y tf.nn.softmax(tf.matmul(h1,W2) b2)我们不再具有将单个像素分类到概率的简单函数。 但这仅需要几行编码并且表现会更好。 深度神经网络 深度神经网络更进一步由第一层的 128 个节点组成馈入下一层的 32 个节点然后馈入 Softmax 以获得 170,309 个参数 真的没有那么多 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xkbBscSP-1681566150319)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/hands-on-dl-tf-zh/img/00070.jpg)] 经过 25,000 个周期后我们的验证准确率微幅提高了 63%
These will be inputs
Input pixels, flattened
x tf.placeholder(float, [None, 1296])
Known labels
y_ tf.placeholder(float, [None,5])# Hidden layer 1 num_hidden1 128 W1 tf.Variable(tf.truncated_normal([1296,num_hidden1],stddev1./math.sqrt(1296))) b1 tf.Variable(tf.constant(0.1,shape[num_hidden1])) h1 tf.sigmoid(tf.matmul(x,W1) b1)# Hidden Layer 2 num_hidden2 32 W2 tf.Variable(tf.truncated_normal([num_hidden1,num_hidden2],stddev2./math.sqrt(num_hidden1))) b2 tf.Variable(tf.constant(0.2,shape[num_hidden2])) h2 tf.sigmoid(tf.matmul(h1,W2) b2)# Output Layer W3 tf.Variable(tf.truncated_normal([num_hidden2, 5],stddev1./math.sqrt(5))) b3 tf.Variable(tf.constant(0.1,shape[5]))# Just initialize sess.run(tf.initialize_all_variables())# Define model y tf.nn.softmax(tf.matmul(h2,W3) b3)更深层次的静态模型可能会做得更好但这证明了深度学习的某些优势可以处理相当大的非线性并且这再次花费了一些额外的编程精力。 卷积神经网络 紧密连接的神经网络工作得很好但是字体是由它们的样式而不是特定的像素定义的 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OFG1364K-1681566150319)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/hands-on-dl-tf-zh/img/00071.jpg)] 重复出现的局部特征应该是您模型的重要线索。 我们使用卷积神经网络捕获了其中一些局部特征。 我们从一个卷积层开始一个5x5窗口使用整流线性单元通过四个额外的偏项计算四个特征并提取了有趣的局部参数。 接下来我们将2x2的最大池化层应用于每个特征从而将中间值的数量减少到18x18x4加上 1 个偏差。 将其平整为 1,297 个数字并放入一个密集的神经网络的 32 个节点然后进行 Softmax 激活从而完成了具有 41,773 个参数的模型。 尽管实现和代码比以前要花更多的精力但是这可以很好地缩减模型的整体大小
Conv layer 1
num_filters 4 winx 5 winy 5 W1 tf.Variable(tf.truncated_normal([winx, winy, 1 , num_filters],stddev1./math.sqrt(winx*winy))) b1 tf.Variable(tf.constant(0.1,shape[num_filters]))
5x5 convolution, pad with zeros on edges
xw tf.nn.conv2d(x_im, W1,strides[1, 1, 1, 1],paddingSAME) h1 tf.nn.relu(xw b1)
2x2 Max pooling, no padding on edges
p1 tf.nn.max_pool(h1, ksize[1, 2, 2, 1],strides[1, 2, 2, 1], paddingVALID)# Need to flatten convolutional output for use in dense layer p1_size np.product([s.value for s in p1.get_shape()[1:]]) p1f tf.reshape(p1, [-1, p1_size ])# Dense layer num_hidden 32 W2 tf.Variable(tf.truncated_normal([p1_size, num_hidden],stddev2./math.sqrt(p1_size))) b2 tf.Variable(tf.constant(0.2,shape[num_hidden])) h2 tf.nn.relu(tf.matmul(p1f,W2) b2)# Output Layer W3 tf.Variable(tf.truncated_normal([num_hidden, 5],stddev1./math.sqrt(num_hidden))) b3 tf.Variable(tf.constant(0.1,shape[5]))keep_prob tf.placeholder(float) h2_drop tf.nn.dropout(h2, keep_prob)仅训练了 5000 个周期后我们就清除了 68% 的准确率。 我们确实必须对卷积进行编码但这并不是那么困难。 通过对问题的结构应用一些知识我们同时减小了模型大小但提高了准确率。 干得好 深度卷积神经网络 结合了深度和卷积方法我们最终创建了一个具有几个卷积层的模型 尽管我们使用了较小的3x3窗口但我们在第一个卷积层上计算了 16 个滤镜。 在进行最大2x2的池化之后我们再次使用另一个3x3窗口和 4 个过滤器对池化值进行了处理。 另一个合并层再次馈入 32 个紧密连接的神经元和 Softmax 输出。 因为在馈入密集神经网络之前我们在池中有更多的卷积所以在此模型中实际上我们具有较少的参数准确地说是 10,765 个几乎与逻辑回归模型一样少。 但是该模型以 6,000 个周期的速度达到了 80% 的验证准确率证明了您的新深度学习和 TensorFlow 技能。
Conv layer 1
num_filters1 16 winx1 3 winy1 3 W1 tf.Variable(tf.truncated_normal([winx1, winy1, 1 , num_filters1],stddev1./math.sqrt(winx1*winy1))) b1 tf.Variable(tf.constant(0.1,shape[num_filters1]))
5x5 convolution, pad with zeros on edges
xw tf.nn.conv2d(x_im, W1,strides[1, 1, 1, 1],paddingSAME) h1 tf.nn.relu(xw b1)
2x2 Max pooling, no padding on edges
p1 tf.nn.max_pool(h1, ksize[1, 2, 2, 1],strides[1, 2, 2, 1], paddingVALID)# Conv layer 2 num_filters2 4 winx2 3 winy2 3 W2 tf.Variable(tf.truncated_normal([winx2, winy2, num_filters1, num_filters2],stddev1./math.sqrt(winx2*winy2))) b2 tf.Variable(tf.constant(0.1,shape[num_filters2]))
3x3 convolution, pad with zeros on edges
p1w2 tf.nn.conv2d(p1, W2,strides[1, 1, 1, 1], paddingSAME) h1 tf.nn.relu(p1w2 b2)
2x2 Max pooling, no padding on edges
p2 tf.nn.max_pool(h1, ksize[1, 2, 2, 1],strides[1, 2, 2, 1], paddingVALID)TensorFlow 的未来
在本部分中我们将观察 TensorFlow 的变化方式谁开始使用 TensorFlow 以及如何产生影响。
自 2015 年底发布以来TensorFlow 已经看到更多发布版本
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oaxgLt3O-1681566150320)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/hands-on-dl-tf-zh/img/00073.jpg)]
TensorFlow 不断更新。 尽管它不是 Google 的正式产品但它还是开源的并托管在 GitHub 上。 在撰写本文时TensorFlow 的版本为 1.2。 最新版本增加了分布式计算功能。 这些超出了本书的范围但总的来说它们允许跨多台机器上的多个 GPU 进行计算以实现最大程度的并行化。 在繁重的开发过程中更多功能总是指日可待。 TensorFlow 每天变得越来越流行。
几家软件公司最近发布了机器学习框架但 TensorFlow 在采用方面表现突出。 在内部Google 正在实践他们的讲道。 他们广受赞誉的 DeepMind 团队已改用 TensorFlow。 此外许多拥有机器学习或数据科学程序的大学都将 TensorFlow 用于课程和研究项目。 当然您已经在研究项目中使用过 TensorFlow因此您处于领先地位。
其他一些 TensorFlow 项目
最后无论大小其他公司都在使用 TensorFlow。 现在您是 TensorFlow 的从业人员唯一的限制就是您可能遇到的问题和您的计算资源。 以下是一些有关 TensorFlow 下一步可以解决的问题的想法 图像中的叶子分类 像字体一样植物叶子在一个物种中具有相似的样式。 您是否可以修改在本课程中建立的模型以仅使用图像识别物种 使用行车记录仪视频的路标识别 假设您从长途旅行中获得了许多行车记录仪镜头。 高速公路上的路标可以为您提供许多信息例如您在哪里以及应该走多快。 您可以建立一系列 TensorFlow 模型来查找素材中的速度限制吗 预测出行时间的运输研究 此外无论您的工作距离有多近通勤时间都太长。 在交通和天气等当前条件下您应该能够建立基于回归的模型来预测您的旅行时间。 用于查找兼容日期的匹配算法 最后一家初创公司正在探索使用 TensorFlow 来寻找匹配算法。 如果将来算法会给您带来一个约会请不要感到惊讶。
基于 TensorFlow 的整洁项目太多无法一一列举。 但是有机会您会发现与自己的兴趣有关的东西如果没有那是贡献自己的完美场所。 机器学习库很多但是 TensorFlow 仍然存在。
尽管本书侧重于深度学习但 TensorFlow 是一个通用的图计算库。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LlrwWFy5-1681566150320)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/hands-on-dl-tf-zh/img/00075.jpg)]
深度神经网络确实是 TensorFlow 能够很好处理的一小部分数据建模。 但是正如您在第 1 章入门中的“简单计算”部分所看到的那样在简单计算中可以为图规定的任何操作都可以在 TensorFlow 中进行。 一个实际的例子是在 TensorFlow 中实现 K 均值聚类。
更一般而言可以很好地向量化并且需要某种训练的操作可能会受益于 TensorFlow 的使用。 这一切都说明您是 TensorFlow 的未来
TensorFlow 是开源的并且一直在变化。 因此您可以在 GitHub 上轻松贡献新功能。 这些可能是高度复杂的新模型类型或简单的文档更新。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-peWwYSou-1681566150320)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/hands-on-dl-tf-zh/img/00076.jpg)]
所有更改都可以改善库。 TensorFlow 的日益普及意味着您是最早掌握它的专业人士之一。 您在机器学习事业或研究中拥有优势。 而且由于它不仅仅是深度学习所以无论您处于哪个领域TensorFlow 都可能适用于它的某些方面。
总结
在本章中我们回顾了如何从谦虚的 Logistic 回归模型爬升到使用深度卷积神经网络对字体进行分类的高度。 我们还讨论了 TensorFlow 的未来。 最后我们回顾了用于字体分类的 TensorFlow 模型并回顾了其准确率。 我们还花了一些时间来讨论 TensorFlow 的发展方向。 恭喜 您现在已经精通 TensorFlow。 您已将其应用于本系列中的多个研究问题和模型并了解了其广泛应用。
下一步是在您自己的项目中部署 TensorFlow。 造型愉快
- 上一篇: 网站建设推广有没有建网站怎么选择服务器
- 下一篇: 网站建设推进计划庆阳市建设局海绵城市网站
相关文章
-
网站建设推广有没有建网站怎么选择服务器
网站建设推广有没有建网站怎么选择服务器
- 技术栈
- 2026年03月21日
-
网站建设推广选哪家wordpress 写入权限
网站建设推广选哪家wordpress 写入权限
- 技术栈
- 2026年03月21日
-
网站建设推广平台有哪些方面如何建开发手机网站
网站建设推广平台有哪些方面如何建开发手机网站
- 技术栈
- 2026年03月21日
-
网站建设推进计划庆阳市建设局海绵城市网站
网站建设推进计划庆阳市建设局海绵城市网站
- 技术栈
- 2026年03月21日
-
网站建设托管产品图下载软件的应用app
网站建设托管产品图下载软件的应用app
- 技术栈
- 2026年03月21日
-
网站建设托管模式鲜花商城网站设计
网站建设托管模式鲜花商城网站设计
- 技术栈
- 2026年03月21日

