TensorFlow 1.x 深度学习秘籍:1~5(1)

本文涉及的产品
服务治理 MSE Sentinel/OpenSergo,Agent数量 不受限
云原生网关 MSE Higress,422元/月
注册配置 MSE Nacos/ZooKeeper,118元/月
简介: TensorFlow 1.x 深度学习秘籍:1~5

一、TensorFlow 简介

曾经尝试仅使用 NumPy 用 Python 编写用于神经网络的代码的任何人都知道它很繁琐。 为一个简单的单层前馈网络编写代码需要 40 条线,这增加了编写代码和执行时间方面的难度。

TensorFlow 使得一切变得更容易,更快捷,从而减少了实现想法与部署之间的时间。 在这本书中,您将学习如何发挥 TensorFlow 的功能来实现深度神经网络。

在本章中,我们将介绍以下主题:

  • 安装 TensorFlow
  • TensorFlow 中的 HelloWorld
  • 了解 TensorFlow 程序结构
  • 使用常量,变量和占位符
  • 使用 TensorFlow 执行矩阵操作
  • 使用数据流程图
  • 从 0.x 迁移到 1.x
  • 使用 XLA 增强计算性能
  • 调用 CPU/GPU 设备
  • 将 TensorFlow 用于深度学习
  • 基于 DNN 的问题所需的不同 Python 包

介绍

TensorFlow 是 Google Brain 团队针对深层神经网络DNN)开发的功能强大的开源软件库。 它于 2015 年 11 月首次在 Apache 2.x 许可下提供; 截止到今天,其 GitHub 存储库提交了超过 17,000 次提交,在短短两年内大约有 845 个贡献者。 这本身就是 TensorFlow 受欢迎程度和性能的衡量标准。 下图显示了流行的深度学习框架的比较,可以明显看出 TensorFlow 是其中的佼佼者:

该图是基于截至 2017 年 7 月 12 日的每个 Github 存储库中的数据。 每个气泡都有一个图例:(框架,贡献者)。

首先让我们了解 TensorFlow 到底是什么,以及为什么它在 DNN 研究人员和工程师中如此受欢迎。 TensorFlow 是开源深度学习库,它允许使用单个 TensorFlow API 在一个或多个 CPU,服务器,台式机或移动设备上的 GPU 上部署深度神经网络计算。 您可能会问,还有很多其他深度学习库,例如 Torch,Theano,Caffe 和 MxNet。 是什么让 TensorFlow 与众不同? TensorFlow 等大多数其他深度学习库具有自动微分功能,许多都是开源的,大多数都支持 CPU/GPU 选项,具有经过预训练的模型,并支持常用的 NN 架构,例如循环神经网络RNN),卷积神经网络CNN)和深度置信网络DBN)。 那么,TensorFlow 还有什么呢? 让我们为您列出它们:

  • 它适用于所有很酷的语言。 TensorFlow 适用于 Python,C++ ,Java,R 和 Go。
  • TensorFlow 可在多个平台上运行,甚至可以移动和分布式。
  • 所有云提供商(AWS,Google 和 Azure)都支持它。
  • Keras 是高级神经网络 API,已与 TensorFlow 集成。
  • 它具有更好的计算图可视化效果,因为它是本机的,而 Torch/Theano 中的等效视图看上去并不那么酷。
  • TensorFlow 允许模型部署并易于在生产中使用。
  • TensorFlow 具有很好的社区支持。
  • TensorFlow 不仅仅是一个软件库; 它是一套包含 TensorFlow,TensorBoard 和 TensorServing 的软件。

Google 研究博客列出了世界各地使用 TensorFlow 进行的一些引人入胜的项目:

  • Google 翻译正在使用 TensorFlow 和张量处理单元TPU
  • 可以使用基于强化学习的模型生成旋律的 Magenta 项目采用 TensorFlow
  • 澳大利亚海洋生物学家正在使用 TensorFlow 来发现和了解濒临灭绝的海牛
  • 一位日本农民使用 TensorFlow 开发了一个应用,该应用使用大小和形状等物理参数对黄瓜进行分类

列表很长,使用 TensorFlow 的可能性更大。 本书旨在向您提供对应用于深度学习模型的 TensorFlow 的理解,以便您可以轻松地将它们适应于数据集并开发有用的应用。 每章都包含一组秘籍,涉及技术问题,依赖项,实际代码及其理解。 我们已经将这些秘籍彼此构建在一起,以便在每一章的最后,您都拥有一个功能齐全的深度学习模型。

安装 TensorFlow

在本秘籍中,您将学习如何在不同的 OS(Linux,Mac 和 Windows)上全新安装 TensorFlow 1.3。 我们将找到安装 TensorFlow 的必要要求。 TensorFlow 可以在 Ubuntu 和 macOS 上使用本机 PIP,Anaconda,Virtualenv 和 Docker 安装。 对于 Windows 操作系统,可以使用本机 PIP 或 Anaconda。

由于 Anaconda 可以在所有三个 OS 上工作,并且提供了一种简便的方法,不仅可以在同一系统上进行安装,还可以在同一系统上维护不同的项目环境,因此在本书中,我们将集中精力使用 Anaconda 安装 TensorFlow。 可从这里阅读有关 Anaconda 及其管理环境的更多详细信息。

本书中的代码已在以下平台上经过测试:

  • Windows 10,Anaconda 3,Python 3.5,TensorFlow GPU,CUDA 工具包 8.0,cuDNN v5.1,NVDIA®GTX 1070
  • Windows 10 / Ubuntu 14.04 / Ubuntu 16.04 / macOS Sierra,Anaconda3,Python 3.5,TensorFlow(CPU)

准备

TensorFlow 安装的前提条件是系统已安装 Python 2.5 或更高版本。 本书中的秘籍是为 Python 3.5(Anaconda 3 发行版)设计的。 要准备安装 TensorFlow,请首先确保已安装 Anaconda。 您可以从这里下载并安装适用于 Windows/macOS 或 Linux 的 Anaconda。

安装后,您可以在终端窗口中使用以下命令来验证安装:

conda --version

安装 Anaconda 后,我们将继续下一步,确定是安装 TensorFlow CPU 还是 GPU。 尽管几乎所有计算机都支持 TensorFlow CPU,但只有当计算机具有具有 CUDA 计算能力 3.0 或更高版本的 NVDIA®GPU 卡(台式机最低为 NVDIA®GTX 650)时,才能安装 TensorFlow GPU。

CPU versus GPU: Central Processing Unit (CPU) consists of a few cores (4-8) optimized for sequential serial processing. A Graphical Processing Unit (GPU) on the other hand has a massively parallel architecture consisting of thousands of smaller, more efficient cores (roughly in 1,000s) designed to handle multiple tasks simultaneously.

对于 TensorFlow GPU,必须安装 CUDA 工具包 7.0 或更高版本,安装正确的 NVDIA®驱动程序,并安装 cuDNN v3 或更高版本。 在 Windows 上,此外,需要某些 DLL 文件。 您可以下载所需的 DLL 文件,也可以安装 Visual Studio C++ 。 要记住的另一件事是 cuDNN 文件安装在另一个目录中。 需要确保目录位于系统路径中。 也可以选择将相关文件复制到相应文件夹中的 CUDA 库中。

操作步骤

我们按以下步骤进行:

  1. 在命令行中使用以下命令创建 conda 环境(如果使用 Windows,最好在命令行中以管理员身份进行操作):
conda create -n tensorflow python=3.5
  1. 激活 conda 环境:
# Windows    
activate tensorflow
#Mac OS/ Ubuntu:    
source activate tensorflow
  1. 该命令应更改提示符:
# Windows
(tensorflow)C:>
# Mac OS/Ubuntu    
(tensorflow)$
  1. 接下来,根据要在 conda 环境中安装的 TensorFlow 版本,输入以下命令:
## Windows
# CPU Version only(tensorflow)C:>pip install --ignore-installed --upgrade https://storage.googleapis.com/tensorflow/windows/cpu/tensorflow-1.3.0cr2-cp35-cp35m-win_amd64.whl
# GPU Version  
(tensorflow)C:>pip install --ignore-installed --upgrade https://storage.googleapis.com/tensorflow/windows/gpu/tensorflow_gpu-1.3.0cr2-cp35-cp35m-win_amd64.whl
## Mac OS
# CPU only Version
(tensorflow)$ pip install --ignore-installed --upgrade https://storage.googleapis.com/tensorflow/mac/cpu/tensorflow-1.3.0cr2-py3-none-any.whl# GPU version(tensorflow)$ pip install --ignore-installed --upgrade https://storage.googleapis.com/tensorflow/mac/gpu/tensorflow_gpu-1.3.0cr2-py3-none-any.whl
## Ubuntu# CPU only Version(tensorflow)$ pip install --ignore-installed --upgrade https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-1.3.0cr2-cp35-cp35m-linux_x86_64.whl# GPU Version
(tensorflow)$ pip install --ignore-installed --upgrade https://storage.googleapis.com/tensorflow/linux/gpu/tensorflow_gpu-1.3.0cr2-cp35-cp35m-linux_x86_64.whl
  1. 在命令行上,输入python
  2. 编写以下代码:
import tensorflow as tf
message = tf.constant('Welcome to the exciting world of Deep Neural Networks!')
with tf.Session() as sess:
    print(sess.run(message).decode())
  1. 您将收到以下输出:

  1. 在 Windows 上使用命令deactivate在 MAC/Ubuntu 上使用source deactivate在命令行上禁用 conda 环境。

工作原理

Google 使用 Wheels 标准分发 TensorFlow。 它是具有.whl扩展名的 ZIP 格式存档。 Anaconda 3 中的默认 Python 解释器 Python 3.6 没有安装轮子。 在撰写本书时,仅对 Linux/Ubuntu 支持 Python 3.6。 因此,在创建 TensorFlow 环境时,我们指定了 Python 3.5。 这将在名为tensorflow的 conda 环境中安装 PIP,python 和 wheel 以及其他一些包。

创建 conda 环境后,可使用source activate/activate命令激活该环境。 在激活的环境中,将pip install命令与适当的 TensorFlow-API URL 配合使用以安装所需的 TensorFlow。 尽管存在使用 Conda forge 安装 TensorFlow CPU 的 Anaconda 命令,但 TensorFlow 文档建议使用pip install。 在 conda 环境中安装 TensorFlow 之后,我们可以将其停用。 现在您可以执行第一个 TensorFlow 程序了。

程序运行时,您可能会看到一些警告(W)消息,一些信息(I)消息以及最后的代码输出:

Welcome to the exciting world of Deep Neural Networks!

恭喜您成功安装并执行了第一个 TensorFlow 代码! 在下一个秘籍中,我们将更深入地研究代码。

更多

此外,您还可以安装 Jupyter 笔记本:

  1. 如下安装ipython
conda install -c anaconda ipython
  1. 安装nb_conda_kernels
conda install -channel=conda-forge nb_conda_kernels
  1. 启动Jupyter notebook
jupyter notebook

This will result in the opening of a new browser window.

如果您的系统上已经安装了 TensorFlow,则可以使用pip install --upgrade tensorflow对其进行升级。

TensorFlow 中的 HelloWorld

您学习用任何计算机语言编写的第一个程序是 HelloWorld。 我们在本书中保持约定,并从 HelloWorld 程序开始。 我们在上一节中用于验证 TensorFlow 安装的代码如下:

import tensorflow as tf
message = tf.constant('Welcome to the exciting world of Deep Neural Networks!')
 with tf.Session() as sess:
     print(sess.run(message).decode())

让我们深入研究这个简单的代码。

操作步骤

  1. 导入tensorflow会导入 TensorFlow 库,并允许您使用其出色的功能。
import tensorflow as tf
  1. 由于我们要打印的消息是一个常量字符串,因此我们使用tf.constant
message = tf.constant('Welcome to the exciting world of Deep Neural Networks!')
  1. 要执行图元素,我们需要使用with定义Session并使用run运行会话:
with tf.Session() as sess:
     print(sess.run(message).decode())
  1. 根据您的计算机系统和操作系统,输出包含一系列警告消息(W),声称如果针对您的特定计算机进行编译,代码可以更快地运行:
The TensorFlow library wasn't compiled to use SSE instructions, but these are available on your machine and could speed up CPU computations. 
The TensorFlow library wasn't compiled to use SSE2 instructions, but these are available on your machine and could speed up CPU computations. 
The TensorFlow library wasn't compiled to use SSE3 instructions, but these are available on your machine and could speed up CPU computations. 
The TensorFlow library wasn't compiled to use SSE4.1 instructions, but these are available on your machine and could speed up CPU computations. 
The TensorFlow library wasn't compiled to use SSE4.2 instructions, but these are available on your machine and could speed up CPU computations. 
The TensorFlow library wasn't compiled to use AVX instructions, but these are available on your machine and could speed up CPU computations. 
The TensorFlow library wasn't compiled to use AVX2 instructions, but these are available on your machine and could speed up CPU computations. 
The TensorFlow library wasn't compiled to use FMA instructions, but these are available on your machine and could speed up CPU computations.
  1. 如果您正在使用 TensorFlow GPU,则还会获得信息性消息列表(I),其中提供了所用设备的详细信息:
Found device 0 with properties:  
name: GeForce GTX 1070 
major: 6 minor: 1 memoryClockRate (GHz) 1.683 
pciBusID 0000:01:00.0 
Total memory: 8.00GiB 
Free memory: 6.66GiB 
DMA: 0  
0:   Y  
Creating TensorFlow device (/gpu:0) -> (device: 0, name: GeForce GTX 1070, pci bus id: 0000:01:00.0)
  1. 最后是我们要求在会话中打印的消息:
Welcome to the exciting world of Deep Neural Networks

工作原理

前面的代码分为三个主要部分。 导入块包含我们的代码将使用的所有库; 在当前代码中,我们仅使用 TensorFlow。 import tensorflow as tf语句使 Python 可以访问所有 TensorFlow 的类,方法和符号。 第二块包含图定义部分; 在这里,我们建立了所需的计算图。 在当前情况下,我们的图仅由一个节点组成,张量常数消息由字节字符串"Welcome to the exciting world of Deep Neural Networks"组成。 我们代码的第三部分是作为会话运行计算图; 我们使用with关键字创建了一个会话。 最后,在会话中,我们运行上面创建的图。

现在让我们了解输出。 收到的警告消息告诉您,TensorFlow 代码可能会以更高的速度运行,这可以通过从源代码安装 TensorFlow 来实现(我们将在本章稍后的内容中进行此操作)。 收到的信息消息会通知您有关用于计算的设备。 对它们而言,这两种消息都相当无害,但是如果您不希望看到它们,则添加以下两行代码即可解决问题:

import os
os.environ['TF_CPP_MIN_LOG_LEVEL']='2'

该代码将忽略直到级别 2 的所有消息。级别 1 用于提供信息,级别 2 用于警告,级别 3 用于错误消息。

程序将打印运行图的结果,该图是使用sess.run()语句运行的。 运行图的结果将馈送到print函数,可使用decode方法对其进行进一步修改。 sess.run求值消息中定义的张量。 print函数在stdout上打印求值结果:

b'Welcome to the exciting world of Deep Neural Networks'

这表示结果是byte string。 要删除字符串引号和b(用于字节),我们使用方法decode()

了解 TensorFlow 程序结构

TensorFlow 与其他编程语言非常不同。 我们首先需要为要创建的任何神经网络构建一个蓝图。 这是通过将程序分为两个独立的部分来完成的,即计算图的定义及其执行。 首先,这对于常规程序员而言似乎很麻烦,但是执行图与图定义的这种分离赋予了 TensorFlow 强大的力量,即可以在多个平台上工作和并行执行的能力。

计算图:计算图是节点和边的网络。 在本节中,定义了所有要使用的数据,即张量对象(常量,变量和占位符)和所有要执行的计算,即操作对象(简称为ops)。 每个节点可以有零个或多个输入,但只有一个输出。 网络中的节点表示对象(张量和运算),边缘表示在运算之间流动的张量。 计算图定义了神经网络的蓝图,但其中的张量尚无与其关联的值。

为了构建计算图,我们定义了我们需要执行的所有常量,变量和操作。 常量,变量和占位符将在下一个秘籍中处理。 数学运算将在矩阵处理的秘籍中详细介绍。 在这里,我们使用一个简单的示例来描述结构,该示例定义并执行图以添加两个向量。

图的执行:使用会话对象执行图。 会话对象封装了求值张量和操作对象的环境。 这是实际计算和信息从一层传输到另一层的地方。 不同张量对象的值仅初始化,访问并保存在会话对象中。 到目前为止,张量对象仅仅是抽象的定义,在这里它们就变成了现实。

操作步骤

我们按以下步骤进行:

  1. 我们考虑一个简单的例子,将两个向量相加,我们有两个输入向量v_1v_2,它们将被作为Add操作的输入。 我们要构建的图如下:

  1. 定义计算图的相应代码如下:
v_1 = tf.constant([1,2,3,4]) 
v_2 = tf.constant([2,1,5,3]) 
v_add = tf.add(v_1,v_2)  # You can also write v_1 + v_2 instead
  1. 接下来,我们在会话中执行图:
with tf.Session() as sess: 
    prin(sess.run(v_add))

上面的两个命令等效于以下代码。 使用with块的优点是不需要显式关闭会话。

sess = tf.Session() 
print(ses.run(tv_add)) 
sess.close()
  1. 这导致打印两个向量的和:
[3 3 8 7]

请记住,每个会话都需要使用close()方法显式关闭,而with块在结束时会隐式关闭会话。

工作原理

计算图的构建非常简单; 您将继续添加变量和运算,并按照您逐层构建神经网络的顺序将它们传递(使张量流动)。 TensorFlow 还允许您使用with tf.device()将特定设备(CPU/GPU)与计算图的不同对象一起使用。 在我们的示例中,计算图由三个节点组成,v_1v_2代表两个向量,Add是对其执行的操作。

现在,要使该图更生动,我们首先需要使用tf.Session()定义一个会话对象; 我们给会话对象起了名字sess。 接下来,我们使用 Session 类中定义的run方法运行它,如下所示:

run (fetches, feed_dict=None, options=None, run_metadata)

这将求值fetches中的张量; 我们的示例在提取中具有张量v_addrun方法将执行导致v_add的图中的每个张量和每个操作。 如果您在提取中包含v_1而不是v_add,则结果将是向量v_1的值:

[1,2,3,4]

访存可以是单个张量/运算对象,也可以是多个张量/操作对象,例如,如果访存为[v_1, v_2, v_add],则输出将为以下内容:

[array([1, 2, 3, 4]), array([2, 1, 5, 3]), array([3, 3, 8, 7])]

在同一程序代码中,我们可以有许多会话对象。

更多

您一定想知道为什么我们必须编写这么多行代码才能进行简单的向量加法或打印一条小消息。 好吧,您可以很方便地以单线方式完成此工作:

print(tf.Session().run(tf.add(tf.constant([1,2,3,4]),tf.constant([2,1,5,3]))))

编写这种类型的代码不仅会影响计算图,而且在for循环中重复执行相同的操作(OP)时可能会占用大量内存。 养成显式定义所有张量和操作对象的习惯,不仅使代码更具可读性,而且还有助于您以更简洁的方式可视化计算图。

使用 TensorBoard 可视化图形是 TensorFlow 最有用的功能之一,尤其是在构建复杂的神经网络时。 可以在图对象的帮助下查看我们构建的计算图。

如果您正在使用 Jupyter 笔记本或 Python Shell,则使用tf.InteractiveSession代替tf.Session更为方便。 InteractiveSession使其成为默认会话,因此您可以使用eval()直接调用运行张量对象,而无需显式调用该会话,如以下示例代码中所述:

sess = tf.InteractiveSession() 
v_1 = tf.constant([1,2,3,4]) 
v_2 = tf.constant([2,1,5,3]) 
v_add = tf.add(v_1,v_2) 
print(v_add.eval()) 
sess.close()

使用常量,变量和占位符

用最简单的术语讲,TensorFlow 提供了一个库来定义和执行带有张量的不同数学运算。 张量基本上是 n 维矩阵。 所有类型的数据,即标量,向量和矩阵都是张量的特殊类型:

数据类型 张量 形状
标量 0 维张量 []
向量 一维张量 [D0]
矩阵 二维张量 [D0, D1]
张量 ND 张量 [D0, D1, D[n-1]]

TensorFlow 支持三种类型的张量:

  • 常量
  • 变量
  • 占位符

常量:常数是无法更改其值的张量。

变量:当值需要在会话中更新时,我们使用变量张量。 例如,在神经网络的情况下,需要在训练期间更新权重,这是通过将权重声明为变量来实现的。 在使用之前,需要对变量进行显式初始化。 另一个要注意的重要事项是常量存储在计算图定义中。 每次加载图时都会加载它们。 换句话说,它们是昂贵的内存。 另一方面,变量是分开存储的。 它们可以存在于参数服务器上。

占位符:这些占位符用于将值输入 TensorFlow 图。 它们与feed_dict一起用于输入数据。 它们通常用于在训练神经网络时提供新的训练示例。 在会话中运行图时,我们为占位符分配一个值。 它们使我们无需数据即可创建操作并构建计算图。 需要注意的重要一点是,占位符不包含任何数据,因此也无需初始化它们。

操作步骤

让我们从常量开始:

  1. 我们可以声明一个常量标量:
t_1 = tf.constant(4)
  1. 形状为[1,3]的常数向量可以声明如下:
t_2 = tf.constant([4, 3, 2])
  1. 为了创建一个所有元素都为零的张量,我们使用tf.zeros()。 该语句创建一个形状为[M,N]dtype的零矩阵(int32float32等):
tf.zeros([M,N],tf.dtype)

让我们举个例子:

zero_t = tf.zeros([2,3],tf.int32) 
# Results in an 2×3 array of zeros: [[0 0 0], [0 0 0]]
  1. 我们还可以创建与现有 Numpy 数组形状相同的张量常数或张量常数,如下所示:
tf.zeros_like(t_2) 
# Create a zero matrix of same shape as t_2  
tf.ones_like(t_2) 
# Creates a ones matrix of same shape as t_2
  1. 我们可以将所有元素设置为一个来创建张量; 在这里,我们创建一个形状为[M,N]的 1 矩阵:
tf.ones([M,N],tf.dtype)

让我们举个例子:

ones_t = tf.ones([2,3],tf.int32) 
# Results in an 2×3 array of ones:[[1 1 1], [1 1 1]]

让我们继续序列:

  1. 我们可以在总的num值内生成从开始到结束的一系列均匀间隔的向量:
tf.linspace(start, stop, num)
  1. 相应的值相差(stop-start)/(num-1)
  2. 让我们举个例子:
range_t = tf.linspace(2.0,5.0,5) 
# We get: [ 2\.    2.75  3.5   4.25  5\.  ]
  1. 从头开始生成一系列数字(默认值为 0),以增量递增(默认值为 1),直到但不包括限制:
tf.range(start,limit,delta)

这是一个例子:

range_t = tf.range(10) 
# Result: [0 1 2 3 4 5 6 7 8 9]

TensorFlow 允许创建具有不同分布的随机张量

  1. 要根据形状为[M,N]的正态分布创建随机值,其中均值(默认值为 0.0),标准差(默认值为 1.0),种子,我们可以使用以下方法:
t_random = tf.random_normal([2,3], mean=2.0, stddev=4, seed=12) 
# Result: [[ 0.25347459  5.37990952  1.95276058], [-1.53760314  1.2588985   2.84780669]]
  1. 要从形状为[M,N]的截断正态分布(带有平均值(默认值为 0.0)和标准差(默认值为 1.0))创建随机值,我们可以使用以下方法:
t_random = tf.truncated_normal([1,5], stddev=2, seed=12) 
# Result: [[-0.8732627 1.68995488 -0.02361972 -1.76880157 -3.87749004]]
  1. 要根据给定的形状[M,N]的伽玛分布在[minval (default=0), maxval]范围内创建带有种子的随机值,请执行以下操作:
t_random = tf.random_uniform([2,3], maxval=4, seed=12) 
# Result: [[ 2.54461002  3.69636583  2.70510912], [ 2.00850058  3.84459829  3.54268885]]
  1. 要将给定张量随机裁剪为指定大小,请执行以下操作:
tf.random_crop(t_random, [2,5],seed=12)

在这里,t_random是已经定义的张量。 这将导致从张量t_random中随机裁剪出[2,5]张量。

很多时候,我们需要以随机顺序展示训练样本; 我们可以使用tf.random_shuffle()沿其第一维随机调整张量。 如果t_random是我们想要改组的张量,那么我们使用以下代码:

tf.random_shuffle(t_random)
  1. 随机生成的张量受初始种子值的影响。 为了在多个运行或会话中获得相同的随机数,应将种子设置为恒定值。 当使用大量随机张量时,我们可以使用tf.set_random_seed()为所有随机生成的张量设置种子。 以下命令将所有会话的随机张量的种子设置为54
tf.set_random_seed(54)

Seed can have only integer value.

现在转到变量:

  1. 它们是使用变量类创建的。 变量的定义还包括应从中初始化变量的常数/随机值。 在下面的代码中,我们创建两个不同的张量变量t_at_b。 都将初始化为形状为[50, 50]minval=0maxval=10的随机均匀分布:
rand_t = tf.random_uniform([50,50], 0, 10, seed=0) 
t_a = tf.Variable(rand_t) 
t_b = tf.Variable(rand_t)

变量通常用于表示神经网络中的权重和偏置。

  1. 在下面的代码中,我们定义了两个变量权重和偏差。 权重变量使用正态分布随机初始化,均值为零,标准差为 2,权重的大小为100×100。 偏差由 100 个元素组成,每个元素都初始化为零。 在这里,我们还使用了可选的参数名称来为计算图中定义的变量命名。
weights = tf.Variable(tf.random_normal([100,100],stddev=2)) 
bias = tf.Variable(tf.zeros[100], name = 'biases')
  1. 在所有前面的示例中,变量的初始化源都是某个常量。 我们还可以指定一个要从另一个变量初始化的变量。 以下语句将从先前定义的权重中初始化weight2
weight2=tf.Variable(weights.initialized_value(), name='w2')
  1. 变量的定义指定如何初始化变量,但是我们必须显式初始化所有声明的变量。 在计算图的定义中,我们通过声明一个初始化操作对象来实现:
intial_op = tf.global_variables_initializer().
  1. 在运行图中,还可以使用tf.Variable.initializer分别初始化每个变量:
bias = tf.Variable(tf.zeros([100,100]))
 with tf.Session() as sess:
     sess.run(bias.initializer)
  1. 保存变量:我们可以使用Saver类保存变量。 为此,我们定义一个saver操作对象:
saver = tf.train.Saver()
  1. 在常量和变量之后,我们来到最重要的元素占位符,它们用于将数据馈入图。 我们可以使用以下内容定义占位符:
tf.placeholder(dtype, shape=None, name=None)
  1. dtype指定占位符的数据类型,并且在声明占位符时必须指定。 在这里,我们为x定义一个占位符,并使用feed_dict为随机4×5矩阵计算y = 2 * x
x = tf.placeholder("float")
y = 2 * x
data = tf.random_uniform([4,5],10)
with tf.Session() as sess:
     x_data = sess.run(data)
     print(sess.run(y, feed_dict = {x:x_data}))

工作原理

所有常量,变量和占位符都将在代码的计算图部分中定义。 如果在定义部分中使用print语句,我们将仅获得有关张量类型的信息,而不是张量的值。

为了找出该值,我们需要创建会话图,并显式使用run命令,并将所需的张量值设为fetches

print(sess.run(t_1))  
# Will print the value of t_1 defined in step 1

更多

很多时候,我们将需要恒定的大尺寸张量对象。 在这种情况下,为了优化内存,最好将它们声明为具有可训练标志设置为False的变量:

t_large = tf.Variable(large_array, trainable = False)

TensorFlow 的设计可完美地与 Numpy 配合使用,因此所有 TensorFlow 数据类型均基于 Numpy 的数据类型。 使用tf.convert_to_tensor(),我们可以将给定值转换为张量类型,并将其与 TensorFlow 函数和运算符一起使用。 该函数接受 Numpy 数组,Python 列表和 Python 标量,并允许与张量对象互操作。

下表列出了一些常见的 TensorFlow 支持的数据类型(摘自 TensorFlow.org ):

数据类型 TensorFlow 类型
DT_FLOAT tf.float32
DT_DOUBLE tf.float64
DT_INT8 tf.int8
DT_UINT8 tf.uint8
DT_STRING tf.string
DT_BOOL tf.bool
DT_COMPLEX64 tf.complex64
DT_QINT32 tf.qint32

请注意,与 Python/Numpy 序列不同,TensorFlow 序列不可迭代。 尝试以下代码:

for i in tf.range(10)

您会得到一个错误:

#TypeError("'Tensor' object is not iterable.")

使用 TensorFlow 执行矩阵操作

矩阵运算(例如执行乘法,加法和减法)是任何神经网络中信号传播中的重要运算。 通常在计算中,我们需要随机,零,一或恒等矩阵。

本秘籍将向您展示如何获取不同类型的矩阵以及如何对它们执行不同的矩阵操作。

操作步骤

我们按以下步骤进行:

  1. 我们开始一个交互式会话,以便可以轻松求值结果:
import tensorflow as tf
#Start an Interactive Session
sess = tf.InteractiveSession()
#Define a 5x5 Identity matrix
I_matrix = tf.eye(5)
print(I_matrix.eval()) 
# This will print a 5x5 Identity matrix
#Define a Variable initialized to a 10x10 identity matrix
X = tf.Variable(tf.eye(10))
X.initializer.run()  # Initialize the Variable
print(X.eval()) 
# Evaluate the Variable and print the result
#Create a random 5x10 matrix
A = tf.Variable(tf.random_normal([5,10]))
A.initializer.run()
#Multiply two matrices
product = tf.matmul(A, X)
print(product.eval())
#create a random matrix of 1s and 0s, size 5x10
b = tf.Variable(tf.random_uniform([5,10], 0, 2, dtype= tf.int32))
b.initializer.run()
print(b.eval())
b_new = tf.cast(b, dtype=tf.float32)
#Cast to float32 data type
# Add the two matrices
t_sum = tf.add(product, b_new)
t_sub = product - b_new
print("A*X _b\n", t_sum.eval())
print("A*X - b\n", t_sub.eval())
  1. 可以按以下方式执行其他一些有用的矩阵操作,例如按元素进行乘法,与标量相乘,按元素进行除法,按元素进行除法的余数:
import tensorflow as tf
# Create two random matrices
a = tf.Variable(tf.random_normal([4,5], stddev=2))
b = tf.Variable(tf.random_normal([4,5], stddev=2))
#Element Wise Multiplication
A = a * b
#Multiplication with a scalar 2
B = tf.scalar_mul(2, A)
# Elementwise division, its result is
C = tf.div(a,b)
#Element Wise remainder of division
D = tf.mod(a,b)
init_op = tf.global_variables_initializer()
with tf.Session() as sess:
     sess.run(init_op)
     writer = tf.summary.FileWriter('graphs', sess.graph)
     a,b,A_R, B_R, C_R, D_R = sess.run([a , b, A, B, C, D])
     print("a\n",a,"\nb\n",b, "a*b\n", A_R, "\n2*a*b\n", B_R, "\na/b\n", C_R, "\na%b\n", D_R)
writer.close()

tf.div returns a tensor of the same type as the first argument.

工作原理

矩阵的所有算术运算(例如加,乘,除,乘(元素乘),模和叉)都要求两个张量矩阵的数据类型相同。 如果不是这样,它们将产生错误。 我们可以使用tf.cast()将张量从一种数据类型转换为另一种数据类型。

更多

如果我们要在整数张量之间进行除法,最好使用tf.truediv(a,b),因为它首先将整数张量强制转换为浮点,然后执行逐元素除法。

使用数据流程图

TensorFlow 使用 TensorBoard 提供计算图的图形图像。 这使得理解,调试和优化复杂的神经网络程序变得很方便。 TensorBoard 还可以提供有关网络执行情况的定量指标。 它读取 TensorFlow 事件文件,其中包含您在运行 TensorFlow 会话时生成的摘要数据。

操作步骤

  1. 使用 TensorBoard 的第一步是确定您想要的 OP 摘要。 对于 DNN,习惯上要知道损耗项(目标函数)如何随时间变化。 在自适应学习率的情况下,学习率本身随时间变化。 我们可以在tf.summary.scalar OP 的帮助下获得所需项的摘要。 假设变量损失定义了误差项,并且我们想知道它是如何随时间变化的,那么我们可以这样做,如下所示:
loss = tf... 
tf.summary.scalar('loss', loss)
  1. 您还可以使用tf.summary.histogram可视化特定层的梯度,权重甚至输出的分布:
output_tensor  = tf.matmul(input_tensor, weights) + biases 
tf.summary.histogram('output', output_tensor)
  1. 摘要将在会话期间生成。 您可以在计算图中定义tf.merge_all_summaries OP,而不用单独执行每个摘要操作,以便一次运行即可获得所有摘要。
  2. 然后需要使用tf.summary.Filewriter将生成的摘要写入事件文件:
writer = tf.summary.Filewriter('summary_dir', sess.graph)
  1. 这会将所有摘要和图写入'summary_dir'目录。
  2. 现在,要可视化摘要,您需要从命令行调用 TensorBoard:
tensorboard --logdir=summary_dir
  1. 接下来,打开浏览器并输入地址http://localhost:6006/(或运行 TensorBoard 命令后收到的链接)。
  2. 您将看到类似以下的内容,顶部带有许多选项卡。 图表标签会显示图表:

从 0.x 迁移到 1.x

TensorFlow 1.x 不提供向后兼容性。 这意味着适用于 TensorFlow 0.x 的代码可能不适用于 TensorFlow 1.0。 因此,如果您有适用于 TensorFlow 0.x 的代码,则需要对其进行升级(旧的 GitHub 存储库或您自己的代码)。 本秘籍将指出 TensorFlow 0.x 和 TensorFlow 1.0 之间的主要区别,并向您展示如何使用脚本tf_upgrade.py自动升级 TensorFlow 1.0 的代码。

操作步骤

这是我们进行秘籍的方法:

  1. 首先,从这里下载tf_upgrade.py
  2. 如果要将一个文件从 TensorFlow 0.x 转换为 TensorFlow 1.0,请在命令行中使用以下命令:
python tf_upgrade.py --infile old_file.py --outfile upgraded_file.py
  1. 例如,如果您有一个名为test.py的 TensorFlow 程序文件,则将使用以下命令,如下所示:
python tf_upgrade.py --infile test.py --outfile test_1.0.py
  1. 这将导致创建一个名为test_1.0.py的新文件。
  2. 如果要迁移目录的所有文件,请在命令行中使用以下命令:
python tf_upgrade.py --intree InputDIr --outtree OutputDir
 # For example, if you have a directory located at /home/user/my_dir you can migrate all the python files in the directory located at /home/user/my-dir_1p0 using the above command as:
python tf_upgrade.py --intree /home/user/my_dir --outtree /home/user/my_dir_1p0
  1. 在大多数情况下,该目录还包含数据集文件。 您可以使用以下方法确保将非 Python 文件也复制到新目录(上例中为my-dir_1p0):
python tf_upgrade.py --intree /home/user/my_dir --outtree /home/user/my_dir_1p0 -copyotherfiles True
  1. 在所有这些情况下,都会生成一个report.txt文件。 该文件包含转换的详细信息以及过程中的任何错误。
  2. 读取report.txt文件,然后手动升级脚本无法更新的部分代码。

更多

tf_upgrade.py具有某些限制:

  • 它不能更改tf.reverse()的参数:您将必须手动修复它
  • 对于参数列表重新排序的方法,例如tf.split()tf.reverse_split(),它将尝试引入关键字参数,但实际上无法对其重新排序
  • 您将必须手动将tf.get.variable_scope().reuse_variables()之类的结构替换为以下内容:
with tf.variable_scope(tf.get_variable_scope(), resuse=True):

使用 XLA 增强计算性能

加速线性代数XLA)是线性代数的特定领域编译器。 根据这个页面的说法,它仍处于实验阶段,可用于优化 TensorFlow 计算。 它可以提高服务器和移动平台上的执行速度,内存使用率和可移植性。 它提供双向 JIT即时)编译或 AoT预先)编译。 使用 XLA,您可以生成平台相关的二进制文件(适用于 x64,ARM 等大量平台),可以针对内存和速度进行优化。

准备

目前,XLA 不包含在 TensorFlow 的二进制发行版中。 需要从源代码构建它。 要从源代码构建 TensorFlow,需要具备 LLVM 和 Bazel 以及 TensorFlow 的知识。 TensorFlow.org 仅在 MacOS 和 Ubuntu 中支持从源代码构建。 从源代码构建 TensorFlow 所需的步骤如下

  1. 确定要安装的 TensorFlow-仅具有 CPU 支持的 TensorFlow 或具有 GPU 支持的 TensorFlow。
  2. 克隆 TensorFlow 存储库:
git clone https://github.com/tensorflow/tensorflow 
cd tensorflow 
git checkout Branch #where Branch is the desired branch
  1. 安装以下依赖项:
  2. 配置安装。 在此步骤中,您需要选择不同的选项,例如 XLA,Cuda 支持,动词等等:
./configure
  1. 接下来,使用bazel-build
  2. 对于仅 CPU 版本,请使用:
bazel build --config=opt //tensorflow/tools/pip_package:build_pip_package
  1. 如果您有兼容的 GPU 设备,并且需要 GPU 支持,请使用:
bazel build --config=opt --config=cuda //tensorflow/tools/pip_package:build_pip_package
  1. 成功运行后,您将获得一个脚本build_pip_package
  2. 如下运行此脚本以构建whl文件:
bazel-bin/tensorflow/tools/pip_package/build_pip_package /tmp/tensorflow_pkg
  1. 安装pip包:
sudo pip install /tmp/tensorflow_pkg/tensorflow-1.1.0-py2-none-any.whl

现在您可以开始了。

操作步骤

TensorFlow 生成 TensorFlow 图。 借助 XLA,可以在任何新型设备上运行 TensorFlow 图。

  1. JIT 编译:这将在会话级别打开 JIT 编译:
# Config to turn on JIT compilation
 config = tf.ConfigProto()
 config.graph_options.optimizer_options.global_jit_level = tf.OptimizerOptions.ON_1
 sess = tf.Session(config=config)
  1. 这是为了手动打开 JIT 编译:
jit_scope = tf.contrib.compiler.jit.experimental_jit_scope
x = tf.placeholder(np.float32)
with jit_scope():
   y = tf.add(x, x)  # The "add" will be compiled with XLA.
  1. 我们还可以通过将运算符放在特定的 XLA 设备XLA_CPUXLA_GPU上,通过 XLA 运行计算:
with tf.device \ ("/job:localhost/replica:0/task:0/device:XLA_GPU:0"):
   output = tf.add(input1, input2)

AoT 编译:在这里,我们将 tfcompile 作为独立版本将 TensorFlow 图转换为适用于不同设备(移动设备)的可执行代码。

TensorFlow.org 讲述了 tfcompile:

tfcompile 接受一个由 TensorFlow 概念的提要和获取标识的子图,并生成实现该子图的函数。 提要是函数的输入参数,而提取是函数的输出参数。 提要必须完全指定所有输入; 结果修剪后的子图不能包含占位符或变量节点。 通常将所有占位符和变量指定为提要,以确保结果子图不再包含这些节点。 生成的函数打包为 cc_library,带有导出函数签名的头文件和包含实现的目标文件。 用户编写代码以适当地调用生成的函数。

有关执行此操作的高级步骤,可以参考这里

调用 CPU/GPU 设备

TensorFlow 支持 CPU 和 GPU。 它还支持分布式计算。 我们可以在一台或多台计算机系统中的多个设备上使用 TensorFlow。 TensorFlow 将支持的设备命名为 CPU 设备的"/device:CPU:0"(或"/cpu:0"),将第i个 GPU 的设备命名为"/device:GPU:I"(或"/gpu:I")。

如前所述,GPU 比 CPU 快得多,因为它们具有许多小型内核。 但是,就计算速度而言,将 GPU 用于所有类型的计算并不总是一个优势。 与 GPU 相关的开销有时可能比 GPU 提供的并行计算的优势在计算上更为昂贵。 为了解决这个问题,TensorFlow 规定将计算放在特定的设备上。 默认情况下,如果同时存在 CPU 和 GPU,则 TensorFlow 会优先考虑 GPU。

操作步骤

TensorFlow 将设备表示为字符串。 在这里,我们将向您展示如何在 TensorFlow 中手动分配用于矩阵乘法的设备。 为了验证 TensorFlow 确实在使用指定的设备(CPU 或 GPU),我们使用log_device_placement标志设置为True,即config=tf.ConfigProto(log_device_placement=True)创建会话:

  1. 如果您不确定设备并希望 TensorFlow 选择现有和受支持的设备,则可以将allow_soft_placement标志设置为True
config=tf.ConfigProto(allow_soft_placement=True, log_device_placement=True)
  1. 手动选择 CPU 进行操作:
with tf.device('/cpu:0'): 
    rand_t = tf.random_uniform([50,50], 0, 10, dtype=tf.float32, seed=0) 
    a = tf.Variable(rand_t) 
    b = tf.Variable(rand_t) 
    c = tf.matmul(a,b) 
    init = tf.global_variables_initializer() 
sess = tf.Session(config) 
sess.run(init) 
print(sess.run(c))
  1. 我们得到以下输出:

我们可以看到,在这种情况下,所有设备都是'/cpu:0'

  1. 手动选择单个 GPU 进行操作:
with tf.device('/gpu:0'): 
    rand_t = tf.random_uniform([50,50], 0, 10, dtype=tf.float32, seed=0) 
    a = tf.Variable(rand_t) 
    b = tf.Variable(rand_t) 
    c = tf.matmul(a,b) 
    init = tf.global_variables_initializer() 
sess = tf.Session(config=tf.ConfigProto(log_device_placement=True)) 
sess.run(init) 
print(sess.run(c))
  1. 现在,输出更改为以下内容:

  1. 每次操作后的'/cpu:0'现在由'/gpu:0'代替。
  2. 手动选择多个 GPU:
c=[]
for d in ['/gpu:1','/gpu:2']:
     with tf.device(d):
         rand_t = tf.random_uniform([50, 50], 0, 10, dtype=tf.float32, seed=0)
         a = tf.Variable(rand_t)
         b = tf.Variable(rand_t)
         c.append(tf.matmul(a,b))
         init = tf.global_variables_initializer()
sess = tf.Session(config=tf.ConfigProto(allow_soft_placement=True,log_device_placement=True))
sess.run(init)
print(sess.run(c))
sess.close()
  1. 在这种情况下,如果系统具有三个 GPU 设备,则第一组乘法将由'/gpu:1'进行,第二组乘法将由'/gpu:2'进行。

工作原理

tf.device()参数选择设备(CPU 或 GPU)。 with块确保选择设备的操作。 with块中定义的所有变量,常量和操作都将使用tf.device()中选择的设备。 会话配置使用tf.ConfigProto控制。 通过设置allow_soft_placementlog_device_placement标志,我们告诉 TensorFlow 在指定设备不可用的情况下自动选择可用设备,并在执行会话时提供日志消息作为输出,描述设备的分配。

将 TensorFlow 用于深度学习

今天的 DNN 是 AI 社区的流行语。 使用 DNN 的候选人最近赢得了许多数据科学/凝视竞赛。 自 1962 年 Rosenblat 提出感知机以来,就一直使用 DNN 的概念,而 1986 年 Rumelhart,Hinton 和 Williams 发明了梯度下降算法后,DNN 就变得可行了。 直到最近,DNN 才成为 AI/ML 爱好者和全世界工程师的最爱。

造成这种情况的主要原因是现代计算功能的可用性,例如 GPU 和 TensorFlow 之类的工具,这些功能使只需几行代码即可更轻松地访问 GPU 并构建复杂的神经网络。

作为机器学习爱好者,您必须已经熟悉神经网络和深度学习的概念,但是为了完整起见,我们将在此处介绍基础知识并探索 TensorFlow 的哪些功能使其成为深度学习的热门选择。

神经网络是一种受生物学启发的模型,用于计算和学习。 像生物神经元一样,它们从其他单元(神经元或环境)中获取加权输入。 该加权输入经过一个处理元素,并产生可以是二进制(触发或不触发)或连续(概率,预测)的输出。 人工神经网络ANN)是这些神经元的网络,可以随机分布或以分层结构排列。 这些神经元通过一组权重和与之相关的偏置来学习。

下图很好地说明了生物学中的神经网络与人工神经网络的相似性:

由 Hinton 等人定义的深度学习,由包含多个处理层(隐藏层)的计算模型组成。 层数的增加导致学习时间的增加。 由于数据集很大,因此学习时间进一步增加,正如当今的 CNN 或生成对抗网络GAN)的标准一样。 因此,要实际实现 DNN,我们需要很高的计算能力。 NVDIA®的 GPU 的出现使其变得可行,然后 Google 的 TensorFlow 使得无需复杂的数学细节即可实现复杂的 DNN 结构成为可能,并且大型数据集的可用性为 DNN 提供了必要的条件。 TensorFlow 是最受欢迎的深度学习库,其原因如下:

  • TensorFlow 是一个强大的库,用于执行大规模的数值计算,例如矩阵乘法或自动微分。 这两个计算对于实现和训练 DNN 是必需的。
  • TensorFlow 在后端使用 C/C++,这使其计算速度更快。
  • TensorFlow 具有高级的机器学习 API(tf.contrib.learn),使配置,训练和评估大量机器学习模型变得更加容易。
  • 在 TensorFlow 之上,可以使用高级深度学习库 Keras。 Keras 非常易于使用,可以轻松快速地制作原型。 它支持各种 DNN,例如 RNN,CNN,甚至是两者的组合。

操作步骤

任何深度学习网络都包含四个重要组成部分:数据集,定义模型(网络结构),训练/学习和预测/评估。 我们可以在 TensorFlow 中完成所有这些操作; 让我们看看如何:

  • 数据集:DNN 依赖于大量数据。 可以收集或生成数据,或者也可以使用可用的标准数据集。 TensorFlow 支持三种主要方法来读取数据。 有不同的数据集。 我们将用来训练本书中构建的模型的一些数据集如下:
  • MNIST:这是最大的手写数字数据库(0-9)。 它由 60,000 个示例的训练集和 10,000 个示例的测试集组成。 数据集保存在 Yann LeCun 的主页中。 数据集包含在tensorflow.examples.tutorials.mnist中的 TensorFlow 库中。
  • CIFAR10:此数据集包含 10 类 60,000 张32 x 32彩色图像,每类 6,000 张图像。 训练集包含 50,000 张图像和测试数据集 10,000 张图像。 数据集的十类是:飞机,汽车,鸟,猫,鹿,狗,青蛙,马,船和卡车。 数据由多伦多大学计算机科学系维护。
  • WORDNET:这是英语的词汇数据库。 它包含名词,动词,副词和形容词,它们被分组为认知同义词(同义词集),也就是说,代表相同概念的单词(例如,关闭和关闭或汽车和汽车)被分组为无序集合。 它包含 155,287 个单词,按 117,659 个同义词集进行组织,总计 206,941 个单词感对。 数据由普林斯顿大学维护。
  • ImageNET:这是根据 WORDNET 层次结构组织的图像数据集(目前仅名词)。 每个有意义的概念(同义词集)由多个单词或单词短语描述。 每个同义词集平均由 1,000 张图像表示。 目前,它具有 21,841 个同义词集和总共 14,197,122 张图像。 自 2010 年以来,每年组织一次 ImageNet 大规模视觉识别挑战赛ILSVRC),以将图像分类为 1,000 个对象类别之一。 这项工作由普林斯顿大学,斯坦福大学,A9 和 Google 赞助。
  • YouTube-8M:这是一个大规模的标记视频数据集,包含数百万个 YouTube 视频。 它有大约 700 万个 YouTube 视频 URL,分为 4716 个类别,分为 24 个顶级类别。 它还提供了预处理支持和帧级功能。 该数据集由 Google Research维护。

读取数据:在 TensorFlow 中可以通过三种方式读取数据:通过feed_dict馈送,从文件读取以及使用预加载的数据。 我们将在整本书中使用本秘籍中描述的组件来阅读和提供数据。 在接下来的步骤中,您将学习每个步骤。

  1. 馈送:在这种情况下,使用run()eval()函数调用中的feed_dict参数在运行每个步骤时提供数据。 这是在占位符的帮助下完成的,该方法使我们可以传递 Numpy 数据数组。 考虑使用 TensorFlow 的以下代码部分:
... 
y = tf.placeholder(tf.float32) 
x = tf.placeholder(tf.float32). 
... 
with tf.Session as sess: 
   X_Array = some Numpy Array 
   Y_Array = other Numpy Array 
   loss= ... 
sess.run(loss,feed_dict = {x: X_Array, y: Y_Array}). 
...

这里,xy是占位符; 使用它们,我们在feed_dict的帮助下传递包含X值的数组和包含Y值的数组。

  1. 从文件中读取:当数据集非常大时,可以使用此方法来确保并非所有数据都一次占用内存(想象 60 GB YouTube-8m 数据集)。 从文件读取的过程可以按照以下步骤完成:
filename_queue = tf.train.string_input_producer(files) 
# where files is the list of filenames created above

此函数还提供了随机播放和设置最大周期数的选项。 文件名的整个列表将添加到每个周期的队列中。 如果选择了改组选项(shuffle=True),则文件名将在每个周期被改组。

reader = tf.TextLineReader() 
key, value = reader.read(filename_queue)
record_defaults = [[1], [1], [1]]
col1, col2, col3 = tf.decode_csv(value, record_defaults=record_defaults)
  1. 预加载数据:当数据集较小且可以完全加载到内存中时使用。 为此,我们可以将数据存储为常量或变量。 在使用变量时,我们需要将可训练标记设置为False,以便在训练期间数据不会更改。 作为 TensorFlow 常量:
# Preloaded data as constant
training_data = ... 
training_labels = ... 
with tf.Session as sess: 
   x_data = tf.Constant(training_data) 
   y_data = tf.Constant(training_labels) 
...
# Preloaded data as Variables
training_data = ... 
training_labels = ... 
with tf.Session as sess: 
   data_x = tf.placeholder(dtype=training_data.dtype, shape=training_data.shape) 
   data_y = tf.placeholder(dtype=training_label.dtype, shape=training_label.shape) 
   x_data = tf.Variable(data_x, trainable=False, collections[]) 
   y_data = tf.Variable(data_y, trainable=False, collections[]) 
...

按照惯例,数据分为三部分-训练数据,验证数据和测试数据。

  1. 定义模型:建立一个描述网络结构的计算图。 它涉及指定超参数,变量和占位符序列,其中信息从一组神经元流向另一组神经元,并传递损失/误差函数。 您将在本章的后续部分中了解有关计算图的更多信息。
  2. 训练/学习:DNN 中的学习通常基于梯度下降算法,(将在第 2 章,“回归”中详细介绍) 目的是找到训练变量(权重/偏差),以使误差或损失(由用户在步骤 2 中定义)最小。 这是通过初始化变量并使用run()实现的:
with tf.Session as sess: 
   .... 
   sess.run(...) 
   ...
  1. 评估模型:训练完网络后,我们将使用predict()对验证数据和测试数据进行评估。 通过评估,我们可以估计出模型对数据集的拟合程度。 因此,我们可以避免过拟合或拟合不足的常见错误。 对模型满意后,便可以将其部署到生产中。

还有更多

在 TensorFlow 1.3 中,添加了一个称为 TensorFlow 估计器的新功能。 TensorFlow 估计器使创建神经网络模型的任务变得更加容易,它是一个高级 API,封装了训练,评估,预测和服务的过程。 它提供了使用预建估计器的选项,也可以编写自己的自定义估计器。 有了预建的估计器,就不再需要担心构建计算或创建会话,它就可以处理所有这些。

目前,TensorFlow 估计器有六个预建的估计器。 使用 TensorFlow 预建的估计器的另一个优势是,它本身也可以创建可在 TensorBoard 上可视化的摘要。 有关估计器的更多详细信息,请访问这里

基于 DNN 的问题所需的不同 Python 包

TensorFlow 负责大多数神经网络的实现。 但是,这还不够。 对于预处理任务,序列化甚至是绘图,我们需要更多的 Python 包。

操作步骤

以下列出了一些常用的 Python 包:

  1. Numpy:这是使用 Python 进行科学计算的基本包。 它支持 n 维数组和矩阵。 它还具有大量的高级数学函数。 它是 TensorFlow 所需的必需包,因此,如果尚未安装pip install tensorflow,则将其安装。
  2. Matplolib:这是 Python 2D 绘图库。 只需几行代码,您就可以使用它来创建图表,直方图,条形图,误差图,散点图和功率谱。 可以使用pip:安装
pip install matplotlib 
# or using Anaconda    
conda install -c conda-forge matplotlib
  1. OS:这是基本 Python 安装中包含的内容。 它提供了一种使用与操作系统相关的函数(如读取,写入和更改文件和目录)的简便方法。
  2. Pandas:这提供了各种数据结构和数据分析工具。 使用 Pandas,您可以在内存数据结构和不同格式之间读取和写入数据。 我们可以读取.csv和文本文件。 可以使用pip installconda install进行安装。
  3. Seaborn:这是基于 Matplotlib 构建的专门统计数据可视化工具。
  4. H5fs:H5fs是适用于 Linux 的文件系统(也是具有 FUSE 实现的其他操作系统,例如 MacOSX),可以在 HDFS分层数据格式文件系统)上运行 。
  5. PythonMagick:它是ImageMagick库的 Python 绑定。 它是显示,转换和编辑光栅图像和向量图像文件的库。 它支持 200 多种图像文件格式。 可以使用ImageMagick.提供的源代码版本进行安装。某些.whl格式也可用于方便的pip install
  6. TFlearn:TFlearn 是建立在 TensorFlow 之上的模块化透明的深度学习库。 它为 TensorFlow 提供了更高级别的 API,以促进并加速实验。 它目前支持大多数最新的深度学习模型,例如卷积,LSTM,BatchNorm,BiRNN,PReLU,残差网络和生成网络。 它仅适用于 TensorFlow 1.0 或更高版本。 要安装,请使用pip install tflearn
  7. Keras:Keras 也是神经网络的高级 API,它使用 TensorFlow 作为其后端。 它也可以在 Theano 和 CNTK 之上运行。 这是非常用户友好的,添加层只是一项工作。 可以使用pip install keras安装。

另见

您可以在下面找到一些 Web 链接以获取有关 TensorFlow 安装的更多信息

二、回归

本章说明如何使用 TensorFlow 进行回归。 在本章中,我们将介绍以下主题:

  • 选择损失函数
  • TensorFlow 中的优化器
  • 从 CSV 文件读取和预处理数据
  • 房价估计 – 简单线性回归
  • 房价估计 – 多元线性回归
  • MNIST 数据集上的逻辑回归

介绍

回归是用于数学建模,分类和预测的最古老但功能非常强大的工具之一。 回归在工程,物理科学,生物学,金融市场到社会科学等各个领域都有应用。 它是数据科学家手中的基本工具。

回归通常是机器学习中人们使用的第一个算法。 它使我们能够通过学习因变量和自变量之间的关系来根据数据进行预测。 例如,在房价估计的情况下,我们确定房屋面积(自变量)与其价格(因变量)之间的关系; 然后,可以使用这种关系来预测给定房屋面积的任何房屋的价格。 我们可以有多个影响因变量的自变量。 因此,回归有两个重要的组成部分:自变量和因变量之间的关系,以及不同自变量对因变量的影响强度

有多种可用的回归方法:

  • 线性回归:这是最广泛使用的建模技术之一。 它已有 200 多年的历史,几乎从所有可能的角度进行了探索。 线性回归假设输入变量(X)和单个输出变量(Y)之间存在线性关系。 它涉及寻找以下形式的预测值Y的线性方程:

在这里,X = (x[1], x[2], ..., x[n])n个输入变量和W = (w[1], w[2], ... w[n])是线性系数,以b为偏差项。 目标是找到系数W的最佳估计,以使预测Y的误差最小。 线性系数W使用最小二乘法估计,即最小化预测值(Y_hat)和值(Y)之间的平方差之和。因此,我们尝试最小化损失函数:

在这里,总和是所有训练样本的总和。 根据输入变量X的数量和类型,可以使用不同类型的线性回归:简单线性回归(一个输入变量,一个输出变量),多个线性回归(许多独立输入变量,一个输出变量) )或多元线性回归(许多独立的输入变量和多个输出变量)。 有关线性回归的更多信息,请参考这个页面

  • Logistic 回归:用于确定事件的概率。 按照惯例,事件表示为分类因变量。 使用logit函数(sigmoid函数)表示事件的可能性:

现在的目标是估计权重W = (w1, w2, ... wn)和偏差项b。 在逻辑回归中,使用最大似然估计器或随机梯度下降法估计系数。 通常将损耗定义为互熵项,如下所示:

Logistic 回归用于分类问题,例如,给定医学数据,我们可以使用 Logistic 回归对一个人是否患有癌症进行分类。 如果输出分类变量具有两个或多个级别,则可以使用多项逻辑回归。 用于两个或多个输出变量的另一种常用技术是“一对多”。 对于多类逻辑回归,对交叉熵损失函数的修改如下:

在此, K是类别的总数。 有关逻辑回归的更多信息,请参见这个页面

这是两种常用的回归技术。

  • 正则化:当存在大量输入特征时,需要进行正则化以确保预测的模型不复杂。 正则化有助于防止数据过拟合。 它还可以用于获得凸的损失函数。 有两种类型的正则化,L1 和 L2 正则化,在以下几点中进行了描述:

在希腊字母上方,lambda(λ)是正则化参数。

选择损失函数

如前所述,在回归中,我们定义loss函数或目标函数,目的是找到使损失最小的系数。 在本秘籍中,您将学习如何在 TensorFlow 中定义loss函数,并根据眼前的问题选择合适的loss函数。

准备

声明loss函数需要将系数定义为变量,将数据集定义为占位符。 一个人可以具有恒定的学习率或变化的学习率和正则化常数。 在以下代码中,令m为样本数,n为特征数,P为类数。 我们应该在代码之前定义以下全局参数:

m = 1000
n = 15
P = 2

操作步骤

现在让我们看一下如何进行秘籍:

  1. 在标准线性回归的情况下,我们只有一个输入变量和一个输出变量:
# Placeholder for the Training Data
X = tf.placeholder(tf.float32, name='X')
Y = tf.placeholder(tf.float32, name='Y')
# Variables for coefficients initialized to 0
w0 = tf.Variable(0.0)
w1 = tf.Variable(0.0)
# The Linear Regression Model
Y_hat = X*w1 + w0
# Loss function
loss = tf.square(Y - Y_hat, name='loss')
  1. 在多元线性回归的情况下,输入变量大于 1,而输出变量保持为 1。 现在,您可以定义形状为[m, n]X占位符,其中m是样本数,n是特征数,然后代码如下:
# Placeholder for the Training DataX = tf.placeholder(tf.float32, name='X', shape=[m,n])
Y = tf.placeholder(tf.float32, name='Y')
# Variables for coefficients initialized to 0w0 = tf.Variable(0.0)
w1 = tf.Variable(tf.random_normal([n,1]))
# The Linear Regression ModelY_hat = tf.matmul(X, w1) + w0
# Multiple linear regression loss functionloss = tf.reduce_mean(tf.square(Y - Y_hat, name='loss')
  1. 在逻辑回归的情况下,loss函数由交叉熵定义。 现在,输出Y的尺寸将等于训练数据集中的类数。 通过P个类,我们将具有以下内容:
# Placeholder for the Training DataX = tf.placeholder(tf.float32, name='X', shape=[m,n])
Y = tf.placeholder(tf.float32, name='Y', shape=[m,P])
# Variables for coefficients initialized to 0w0 = tf.Variable(tf.zeros([1,P]), name=’bias’)
w1 = tf.Variable(tf.random_normal([n,1]), name=’weights’)
# The Linear Regression ModelY_hat = tf.matmul(X, w1) + w0
# Loss functionentropy = tf.nn.softmax_cross_entropy_with_logits(Y_hat,Y)
loss = tf.reduce_mean(entropy)
  1. 如果我们要对损失添加 L1 正则化,则代码如下:
lamda = tf.constant(0.8)  # regularization parameter
regularization_param = lamda*tf.reduce_sum(tf.abs(W1))
# New loss
loss += regularization_param
  1. 对于 L2 正则化,我们可以使用以下代码:
lamda = tf.constant(0.8)  # regularization parameter
regularization_param = lamda*tf.nn.l2_loss(W1)
# New loss
loss += regularization_param

工作原理

您学习了如何实现不同类型的loss函数。 根据手头的回归任务,您可以选择相应的loss函数或自行设计。 也可以在损耗项中组合 L1 和 L2 正则化。

更多

loss函数应为凸形以确保收敛。 平滑,可微凸的loss函数可提供更好的收敛性。 随着学习的进行,loss函数的值应减小并最终变得稳定。

TensorFlow 中的优化器

从中学数学开始,您必须知道函数的一阶导数的最大值和最小值为零。 梯度下降算法基于相同的原理-调整系数(权重和偏差),以使loss函数的梯度减小。 在回归中,我们使用梯度下降来优化loss函数并获得系数。 在本秘籍中,您将学习如何使用 TensorFlow 的梯度下降优化器及其某些变体。

准备

系数(Wb)的更新与loss函数的梯度的负值成比例地完成。 根据训练样本的大小,梯度下降有三种变化:

  • 普通梯度下降:在普通梯度下降(有时也称为全量梯度下降)中,为每个周期的整个训练集计算loss函数的梯度。 对于非常大的数据集,此过程可能很慢且难以处理。 对于凸loss函数,可以保证收敛到全局最小值,但是对于非凸loss函数,可以收敛到局部最小值。
  • 随机梯度下降:在随机梯度下降中,一次显示一个训练样本,权重和偏差得到更新,以使loss函数的梯度减小,然后我们移至下一个训练样本 。 重复整个过程许多周期。 由于它一次执行一次更新,因此它比普通更新要快,但是同时,由于频繁更新,loss函数可能会有很大差异。
  • 小批量梯度下降:结合了前两种产品的最佳质量; 在这里,为一批训练样本更新了参数。

操作步骤

我们按以下步骤进行:

  1. 我们决定的第一件事是我们想要的优化器。 TensorFlow 为您提供了各种各样的优化器。 我们从最流行,最简单的梯度下降优化器开始:
tf.train.GradientDescentOptimizer(learning_rate)
  1. GradientDescentOptimizerlearning_rate参数可以是常数或张量。 其值可以在 0 到 1 之间。
  2. 必须告知优化器要优化的函数。 这是使用其方法来完成的,最小化。 该方法计算梯度并将梯度应用于学习系数。 TensorFlow 文档中定义的函数如下:
minimize(
     loss,
     global_step=None,
     var_list=None,
     gate_gradients=GATE_OP,
     aggregation_method=None,
     colocate_gradients_with_ops=False,
     name=None,
     grad_loss=None
 )
  1. 结合所有这些,我们定义计算图:
...
optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.01)
train_step = optimizer.minimize(loss)
...
#Execution Graph
with tf.Session() as sess:
    ...
    sess.run(train_step, feed_dict = {X:X_data, Y:Y_data})
    ...
  1. 馈送到feed_dictXY数据可以是单个XY点(随机梯度),整个训练集(普通)或批次。
  2. 梯度下降的另一个变化是增加了动量项(我们将在第 3 章“神经网络感知机”中找到更多相关信息)。 为此,我们使用优化器tf.train.MomentumOptimizer()。 它同时将learning_ratemomentum作为init参数:
optimizer = tf.train.MomentumOtimizer(learning_rate=0.01, momentum=0.5).minimize(loss)
  1. 如果使用tf.train.AdadeltaOptimizer(),则可以自适应地单调降低学习率,它使用两个init自变量learning_rate和衰减因子rho
optimizer = tf.train.AdadeltaOptimizer(learning_rate=0.8, rho=0.95).minimize(loss)
  1. TensorFlow 还支持 Hinton 的 RMSprop,其工作方式类似于 Adadelta – tf.train.RMSpropOptimizer()
optimizer = tf.train.RMSpropOptimizer(learning_rate=0.01, decay=0.8, momentum=0.1).minimize(loss)

Adadelta 和 RMSprop 之间有一些细微的差异。 要了解有关它们的更多信息,可以参考这里这里

  1. TensorFlow 支持的另一种流行的优化器是 Adam 优化器。 该方法使用第一个和第二个梯度矩的估计来计算不同系数的个体自适应学习率:
optimizer = tf.train.AdamOptimizer().minimize(loss)
  1. 除了这些,TensorFlow 还提供以下优化器:
tf.train.AdagradOptimizer  #Adagrad Optimizer
tf.train.AdagradDAOptimizer #Adagrad Dual Averaging optimizer 
tf.train.FtrlOptimizer #Follow the regularized leader optimizer
tf.train.ProximalGradientDescentOptimizer #Proximal GD optimizer
tf.train.ProximalAdagradOptimizer # Proximal Adagrad optimizer

更多

通常建议您从较高的学习率值入手,并随着学习的进行逐渐降低。 这有助于对训练进行微调。 我们可以使用 TensorFlow tf.train.exponential_decay方法来实现。 根据 TensorFlow 文档:

训练模型时,通常建议随着训练的进行降低学习率。 此函数将指数衰减函数应用于提供的初始学习率。 它需要一个global_step值来计算衰减的学习率。 您可以只传递一个 TensorFlow 变量,该变量在每个训练步骤中都会递增。该函数返回递减的学习率。

参数:

  • learning_rate: float32float64标量张量或 Python 数字。 初始学习率。
  • global_step: float32float64标量张量或 Python 数字。 用于衰减计算的全局步长。 不能为负。
  • decay_steps: float32float64标量张量或 Python 数字。 必须是正的。 请参阅前面介绍的衰减计算。
  • decay_rate: float32float64标量张量或 Python 数字。 衰减率。
  • staircase: 布尔值。 如果True,在离散时间间隔衰减学习率。
  • name: 字符串。 操作的可选名称。 默认为'ExponentialDecay'

返回值:

learning_rate类型相同的标量张量。 学习率衰减。

要实现指数衰减的学习率,请考虑以下代码示例:

global_step = tf.Variable(0, trainable = false)
initial_learning_rate = 0.2
learning_rate = tf.train.exponential_decay(initial_learning_rate, global_step, decay_steps=100000, decay_rate=0.95, staircase=True)
# Pass this learning rate to optimizer as before.

另见

以下是一些针对不同优化器的良好链接:

从 CSV 文件读取和预处理数据

你们大多数人已经熟悉 Pandas 及其在处理大型数据集文件中的实用性。 TensorFlow 还提供了读取文件的方法。 在第一章中,我们介绍了从 TensorFlow 中读取文件的方法。 在本秘籍中,我们将重点介绍如何在训练之前从 CSV 文件读取和预处理数据。

准备

我们将考虑 Harrison 和 Rubinfield 在 1978 年收集的波士顿住房价格数据集。该数据集包含 506 个样本案例。 每个房屋都有 14 个属性:

  • CRIM:按城镇划分的人均犯罪率
  • ZN:已划定 25,000 平方英尺以上土地的居住用地比例
  • INDIA:每个城镇的非零售营业面积比例
  • CHAS:查尔斯河虚拟变量(如果束缚河,则为 1;否则为 0)
  • NOX:一氧化氮浓度(百万分之几)
  • RM:每个住宅的平均房间数
  • AGE:1940 年之前建造的自有住房的比例
  • DIS:到五个波士顿就业中心的加权距离
  • RAD:径向公路的可达性指数
  • TAX:每 10,000 美元的全值财产税率
  • PTRATIO:按城镇划分的师生比率
  • B1000(Bk-0.63)^2,其中Bk是按城镇划分的黑人比例
  • LSTAT:人口状况降低的百分比
  • MEDV:自有住房的中位数价值,单位为 1,000 美元

操作步骤

我们按以下步骤进行:

  1. 导入所需的模块并声明全局变量:
import tensorflow as tf
# Global parameters 
DATA_FILE = 'boston_housing.csv' BATCH_SIZE = 10
NUM_FEATURES = 14
  1. 接下来,我们定义一个函数,该函数将文件名作为参数,并以等于BATCH_SIZE的大小批量返回张量:
defdata_generator(filename):
    """
    Generates Tensors in batches of size Batch_SIZE.
    Args: String Tensor
    Filename from which data is to be read
    Returns: Tensors
    feature_batch and label_batch
    """
  1. 定义文件名f_queuereader
f_queue = tf.train.string_input_producer(filename)
reader = tf.TextLineReader(skip_header_lines=1) 
# Skips the first line
_, value = reader.read(f_queue)
  1. 我们指定了数据缺失时要使用的数据。 解码.csv并选择我们需要的特征。 对于示例,我们选择RMPTRATIOLSTAT
record_defaults = [ [0.0] for _ in range(NUM_FEATURES)]
data = tf.decode_csv(value, record_defaults=record_defaults)
features = tf.stack(tf.gather_nd(data,[[5],[10],[12]]))
label = data[-1]
  1. 定义参数以生成批量,并使用tf.train.shuffle_batch()随机调整张量。 函数返回张量-feature_batchlabel_batch
# minimum number elements in the queue after a dequeuemin_after_dequeue = 10 * BATCH_SIZE
# the maximum number of elements in the queue capacity = 20 * BATCH_SIZE
# shuffle the data to generate BATCH_SIZE sample pairs feature_batch, label_batch = tf.train.shuffle_batch([features, label], batch_size=BATCH_SIZE,
                                                 capacity=capacity, min_after_dequeue=min_after_dequeue)
return feature_batch, label_batch
  1. 我们定义了另一个函数来在会话中生成批量:
def generate_data(feature_batch, label_batch):
    with tf.Session() as sess:
        # intialize the queue threads
        coord = tf.train.Coordinator()
        threads = tf.train.start_queue_runners(coord=coord)
        for _ in range(5): 
            # Generate 5 batches
            features, labels = sess.run([feature_batch, label_batch])
            print (features, "HI")
        coord.request_stop()
        coord.join(threads)
  1. 现在,我们可以使用这两个函数来批量获取数据。 在这里,我们只是打印数据。 学习时,我们将在此时执行优化步骤:
if __name__ =='__main__':
    feature_batch, label_batch = data_generator([DATA_FILE])
    generate_data(feature_batch, label_batch)

更多

我们可以使用第一章中介绍的 TensorFlow 控件操作和张量操作来预处理数据。 例如,在波士顿房价的情况下,大约有 16 个数据行,其中MEDV50.0。 这些数据点最有可能包含缺失或审查的值,建议不要在训练中考虑它们。 我们可以使用以下代码将它们从训练数据集中删除:

condition = tf.equal(data[13], tf.constant(50.0))
data = tf.where(condition, tf.zeros(NUM_FEATURES), data[:])

在这里,我们首先定义一个张量布尔条件,如果MEDV等于50.0,则为真。 然后,如果条件为真,则使用 TensorFlow tf.where()操作分配全零。

房价估计 – 简单线性回归

在此秘籍中,我们将基于波士顿房价数据集上的房间数(RM)执行简单的线性回归。

准备

我们的目标是预测最后一栏(MEDV)中给出的房价。 在此秘籍中,我们直接从 TensorFlow Contrib 数据集中加载数据集。 我们使用随机梯度下降优化器优化单个训练样本的系数。

操作步骤

我们按以下步骤进行:

  1. 第一步是导入我们需要的所有包:
import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt
  1. 在神经网络中,所有输入都线性相加以产生活动。 为了进行有效的训练,应该对输入进行标准化,因此我们定义了对输入数据进行标准化的函数:
def normalize(X):
    """ Normalizes the array X"""
    mean = np.mean(X)
    std = np.std(X)
    X = (X - mean)/std
    return X
  1. 现在,我们使用 TensorFlow contrib数据集加载波士顿房价数据集,并将其分为X_trainY_train。 我们可以选择在此处标准化数据:
# Data
boston = tf.contrib.learn.datasets.load_dataset('boston')
X_train, Y_train = boston.data[:,5], boston.target
#X_train = normalize(X_train)  # This step is optional here
n_samples = len(X_train)
  1. 我们为训练数据声明 TensorFlow 占位符:
# Placeholder for the Training Data
X = tf.placeholder(tf.float32, name='X')
Y = tf.placeholder(tf.float32, name='Y')
  1. 我们为权重和偏差创建 TensorFlow 变量,初始值为零:
# Variables for coefficients initialized to 0
b = tf.Variable(0.0)
w = tf.Variable(0.0)
  1. 我们定义了用于预测的线性回归模型:
# The Linear Regression Model
Y_hat = X * w + b
  1. 定义loss函数:
# Loss function
loss = tf.square(Y - Y_hat, name='loss')
  1. 我们选择梯度下降优化器:
# Gradient Descent with learning rate of 0.01 to minimize loss
optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.01).minimize(loss)
  1. 声明初始化操作:
# Initializing Variables
init_op = tf.global_variables_initializer()
total = []
  1. 现在,我们开始计算图。 我们进行了 100 个周期的训练:
# Computation Graph
with tf.Session() as sess:
    # Initialize variables
    sess.run(init_op)
    writer = tf.summary.FileWriter('graphs', sess.graph)
    # train the model for 100 epochs
    for i in range(100):
        total_loss = 0
        for x,y in zip(X_train,Y_train):
            _, l = sess.run ([optimizer, loss],            feed_dict={X:x, Y:y})
            total_loss += l
        total.append(total_loss / n_samples)
        print('Epoch {0}: Loss {1}'.format(i, total_loss/n_samples))
     writer.close()
     b_value, w_value = sess.run([b,w])
  1. 查看结果:
Y_pred = X_train * w_value + b_value
print('Done')
# Plot the result
plt.plot(X_train, Y_train, 'bo', label='Real Data')
plt.plot(X_train,Y_pred,  'r', label='Predicted Data')
plt.legend()
plt.show()
plt.plot(total)
plt.show()

工作原理

从图中可以看出,我们的简单线性回归器试图将线性线拟合到给定的数据集:

在下图中,我们可以看到,随着我们的模型学习到数据,loss函数如预期的那样下降:

以下是我们的简单线性回归器的 TensorBoard 图:

该图具有两个名称作用域节点,即VariableVariable_1,它们是分别表示偏差和权重的高级节点。 名为gradient的节点也是高级节点。 扩展节点,我们可以看到它接受了七个输入并计算了gradient,然后GradientDescentOptimizer使用了这些梯度来计算权重和偏差并应用更新:

更多

好吧,我们执行了简单的线性回归,但是如何找出模型的表现呢? 有多种方法可以做到这一点。 从统计上讲,我们可以计算 R 方或将我们的数据分为训练和交叉验证集,并检查验证集的准确率(损失项)。

房价估计 – 多元线性回归

我们可以通过对权重和占位符的声明进行一些修改来对同一数据进行多元线性回归。 在多元线性回归的情况下,由于每个特征都有不同的值范围,因此规范化必不可少。 这是使用所有 13 种输入特征对波士顿房价数据集进行多元线性回归的代码。

操作步骤

这是我们进行秘籍的方法:

  1. 第一步是导入我们需要的所有包:
import tensorflow as tf
 import numpy as np
 import matplotlib.pyplot as plt
  1. 由于所有特征的数据范围都不同,因此我们需要对特征数据进行规范化。 我们为其定义了归一化函数。 同样,在这里,我们通过添加总是固定为一个值的另一输入来将偏差与权重相结合。 为此,我们定义函数append_bias_reshape()。 有时会使用此技术来简化编程:
def normalize(X)
    """ Normalizes the array X """
    mean = np.mean(X)
    std = np.std(X)
    X = (X - mean)/std
    return X
def append_bias_reshape(features,labels):
    m = features.shape[0]
    n = features.shape[1]
    x = np.reshape(np.c_[np.ones(m),features],[m,n + 1])
    y = np.reshape(labels,[m,1])
    return x, y
  1. 现在,我们使用 TensorFlow contrib 数据集加载波士顿房价数据集,并将其分为X_trainY_train。 观察到这次X_train包含所有特征。 我们可以在此处选择对数据进行规范化,也可以使用附加偏差并为网络重塑数据:
# Data
boston = tf.contrib.learn.datasets.load_dataset('boston')
X_train, Y_train = boston.data, boston.target
X_train = normalize(X_train)
X_train, Y_train = append_bias_reshape(X_train, Y_train)
m = len(X_train)  
#Number of training examples
n = 13 + 1   
# Number of features + bias
  1. 声明 TensorFlow 占位符以获取训练数据。 观察X占位符形状的变化。
# Placeholder for the Training Data
X = tf.placeholder(tf.float32, name='X', shape=[m,n])
Y = tf.placeholder(tf.float32, name='Y')
  1. 我们为权重和偏差创建 TensorFlow 变量。 这次,权重用随机数初始化:
# Variables for coefficients
w = tf.Variable(tf.random_normal([n,1]))
  1. 定义要用于预测的线性回归模型。 现在我们需要矩阵乘法来完成任务:
# The Linear Regression Model
Y_hat = tf.matmul(X, w)
  1. 为了更好的区分,我们定义loss函数:
# Loss function
loss = tf.reduce_mean(tf.square(Y - Y_hat, name='loss'))
  1. 选择合适的优化器:
# Gradient Descent with learning rate of 0.01 to minimize loss
optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.01).minimize(loss)
  1. 定义初始化操作:
# Initializing Variables
init_op = tf.global_variables_initializer()
total = []
  1. 启动计算图:
with tf.Session() as sess:
    # Initialize variables
    sess.run(init_op)
    writer = tf.summary.FileWriter('graphs', sess.graph)
    # train the model for 100 epcohs
    for i in range(100):
       _, l = sess.run([optimizer, loss], feed_dict={X: X_train, Y: Y_train})
       total.append(l)
       print('Epoch {0}: Loss {1}'.format(i, l))
     writer.close()
     w_value, b_value = sess.run([w, b])
  1. 绘制loss函数:
plt.plot(total)
plt.show()

同样在这里,我们发现损失随着训练的进行而减少:

工作原理

在此秘籍中,我们使用了所有 13 个特征来训练模型。 简单线性回归和多元线性回归之间的重要区别在于权重,系数的数量始终等于输入特征的数量。 以下是我们构建的多元线性回归模型的 TensorBoard 图:

更多

我们现在可以使用从模型中学到的系数来预测房价:

N= 500
X_new = X_train [N,:]
Y_pred =  (np.matmul(X_new, w_value) + b_value).round(1)
print('Predicted value: ${0}  Actual value: / ${1}'.format(Y_pred[0]*1000, Y_train[N]*1000) , '\nDone')

MNIST 数据集上的逻辑回归

此秘籍基于这个页面提供的 MNIST 的逻辑回归,但我们将添加一些 TensorBoard 摘要以更好地理解它。 你们大多数人必须已经熟悉 MNIST 数据集-就像机器学习的 ABC 一样。 它包含手写数字的图像和每个图像的标签,说明它是哪个数字。

对于逻辑回归,我们对输出 Y 使用一热编码。因此,我们有 10 位代表输出; 每个位可以具有 0 或 1 的值,并且为 1 热点意味着对于标签 Y 中的每个图像,10 个位中只有 1 个位的值为 1,其余为 0。 在这里,您可以看到手写数字 8 的图像及其热编码值[0 0 0 0 0 0 0 0 0 1 0]

操作步骤

这是我们进行秘籍的方法:

  1. 与往常一样,第一步是导入所需的模块:
import tensorflow as tf
import matplotlib.pyplot as plt,  matplotlib.image as mpimg
  1. 我们从模块input_data中给出的 TensorFlow 示例中获取 MNIST 的输入数据。 one_hot标志设置为True以启用标签的one_hot编码。 这导致生成两个张量,形状为[55000, 784]mnist.train.images和形状为[55000, 10]mnist.train.labelsmnist.train.images的每个条目都是像素强度,其值在 0 到 1 之间:
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)
  1. 为训练数据集输入x创建占位符,并在 TensorFlow 图上标记y
x = tf.placeholder(tf.float32, [None, 784], name='X')
y = tf.placeholder(tf.float32, [None, 10],name='Y')
  1. 创建学习变量,权重和偏置:
W = tf.Variable(tf.zeros([784, 10]), name='W')
b = tf.Variable(tf.zeros([10]), name='b')
  1. 创建逻辑回归模型。 TensorFlow OP 被赋予name_scope("wx_b")
with tf.name_scope("wx_b") as scope:
    y_hat = tf.nn.softmax(tf.matmul(x,W) + b)
  1. 添加摘要 OP,以在训练时收集数据。 我们使用直方图摘要,以便我们可以看到权重和偏差随时间相对于彼此的值如何变化。 我们将可以在 TensorBoard 直方图选项卡中看到以下内容:
w_h = tf.summary.histogram("weights", W)
b_h = tf.summary.histogram("biases", b)
  1. 定义cross-entropyloss函数,并添加名称范围和摘要以更好地可视化。 在这里,我们使用标量汇总来获取loss函数随时间的变化。 标量摘要在“事件”选项卡下可见:
with tf.name_scope('cross-entropy') as scope:
    loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=y, logits=y_hat)
    tf.summary.scalar('cross-entropy', loss)
  1. 使用具有学习率0.01的 TensorFlow GradientDescentOptimizer。 再次,为了更好地可视化,我们定义了name_scope
with tf.name_scope('Train') as scope:
    optimizer = tf.train.GradientDescentOptimizer(0.01).minimize(loss)
  1. 声明变量的初始化操作:
# Initializing the variables
init = tf.global_variables_initializer()
  1. 我们结合了所有汇总操作:
merged_summary_op = tf.summary.merge_all()
  1. 现在,我们定义会话并将摘要存储在定义的文件夹中:
with tf.Session() as sess:
    sess.run(init)  # initialize all variables
    summary_writer = tf.summary.FileWriter('graphs', sess.graph)  # Create an event file
    # Training
    for epoch in range(max_epochs):
        loss_avg = 0
        num_of_batch = int(mnist.train.num_examples/batch_size)
        for i in range(num_of_batch):
            batch_xs, batch_ys = mnist.train.next_batch(100)  # get the next batch of data
            _, l, summary_str = sess.run([optimizer,loss, merged_summary_op], feed_dict={x: batch_xs, y: batch_ys})  # Run the optimizer
           loss_avg += l
           summary_writer.add_summary(summary_str, epoch*num_of_batch + i)  # Add all summaries per batch
        loss_avg = loss_avg/num_of_batch
        print('Epoch {0}: Loss {1}'.format(epoch, loss_avg))
    print('Done')
    print(sess.run(accuracy, feed_dict={x: mnist.test.images,y: mnist.test.labels}))
  1. 在 30 个周期后,我们的准确率为 86.5%,在 50 个周期后为 89.36%,在 100 个周期后,准确率提高到 90.91%。

工作原理

我们使用张量tensorboard --logdir=garphs启动 TensorBoard。 在浏览器中,导航到网址localhost:6006,以查看 TensorBoard。 先前模型的图形如下:

在“直方图”标签下,我们可以看到权重偏置的直方图:

权重偏置的分布如下:

我们可以看到,随着时间的推移,偏差和权重都发生了变化。 从我们的案例来看,偏差更大,从 TensorBoard 中的分布可以看出。

在“事件”选项卡下,我们可以看到标量摘要,在这种情况下为交叉熵。 下图显示交叉熵损失随时间减少:

另见

如果您有兴趣了解更多信息,这些是一些很好的资源:

三、神经网络:感知机

自最近十年以来,神经网络一直处于机器学习研究和应用的最前沿。 深层神经网络DNN),传递学习以及计算效率高的 GPU 的可用性已帮助在图像识别,语音识别甚至文本生成领域取得了重大进展。 在本章中,我们将专注于基本的神经网络感知机,即人工神经元的完全连接的分层架构。 本章将包括以下秘籍:

  • 激活函数
  • 单层感知机
  • 反向传播算法的梯度计算
  • 使用 MLP 的 MNIST 分类器
  • 使用 MLP 进行函数逼近-预测波士顿房价
  • 调整超参数
  • 更高级别的 API – Keras

介绍

神经网络,通常也称为连接器模型,是受人脑启发的。 像人的大脑一样,神经网络是通过称为权重的突触强度相互连接的大量人工神经元的集合。 正如我们通过长辈提供给我们的示例进行学习一样,人工神经网络也可以通过作为训练数据集提供给他们的示例进行学习。 有了足够数量的训练数据集,人工神经网络可以概括信息,然后也可以将其用于看不见的数据。 太棒了,它们听起来像魔术!

神经网络并不是什么新鲜事物。 第一个神经网络模型由 McCulloch Pitts(MCP)最早在 1943 年提出。 建造了第一台计算机!)该模型可以执行 AND/OR/NOT 之类的逻辑运算。 MCP 模型具有固定的权重和偏差; 没有学习的可能。 几年后,Frank Rosenblatt 在 1958 年解决了这个问题。 他提出了第一个学习神经网络,称为感知机

从那时起,众所周知,添加多层神经元并建立一个深而密集的网络将有助于神经网络解决复杂的任务。 正如母亲为孩子的成就感到自豪一样,科学家和工程师对使用神经网络NN。 这些声明不是虚假的,但是由于硬件计算的限制和复杂的网络结构,当时根本不可能实现它们。 这导致了 1970 年代和 1980 年代的 AI 寒冬。 在这些寒战中,由于很少或几乎没有对基于 AI 的项目提供资金,因此该领域的进展放缓了。

随着 DNN 和 GPU 的出现,情况发生了变化。 今天,我们拥有的网络可以在较少的调整参数的情况下实现更好的表现,诸如丢弃和迁移学习之类的技术可以进一步减少训练时间,最后,硬件公司正在提出专门的硬件芯片来执行基于 NN 的快速计算。

人工神经元是所有神经网络的核心。 它由两个主要部分组成-加法器(对加权后的神经元的所有输入求和),以及处理单元,对加权后的总和进行加权,并基于称为激活函数的预定义函数生成输出。 。 每个人工神经元都有其自己的一组权重和阈值(偏差)。 它通过不同的学习算法来学习这些权重和阈值:

来源

当仅存在此类神经元的一层时,它称为感知机。 输入层称为第零层,因为它仅缓冲输入。 存在的唯一神经元层形成输出层。 输出层的每个神经元都有自己的权重和阈值。 当存在许多这样的层时,该网络称为多层感知机MLP)。 一个 MLP 具有一个或多个隐藏层。 这些隐藏层具有不同数量的隐藏神经元。 每个隐藏层的神经元具有相同的激活函数:

上图显示了一个 MLP,它具有四个输入,五个隐藏层,每个隐藏层分别具有 4、5、6、4 和 3 个神经元,而在输出层中具有三个神经元。 在 MLP 中,下层的所有神经元都与其上一层的所有神经元相连。 因此,MLP 也称为全连接层。 MLP 中的信息流始终是从输入到输出。 由于没有反馈或跳跃,因此这些网络也称为前馈网络

使用梯度下降算法训练感知机。 在第 2 章“回归”中,您了解了梯度下降; 在这里,我们对其进行更深入的研究。 感知机通过有监督的学习算法进行学习,也就是说,网络由训练数据集中存在的所有输入的期望输出提供。 在输出中,我们定义一个误差函数或目标函数J(W),这样,当网络完全学习了所有训练数据时,目标函数将最小。

更新输出层和隐藏层的权重,以使目标函数的梯度减小:

为了更好地理解它,请对山丘,高原和坑坑洼洼的景观进行可视化处理。 目的是扎根(目标函数的全局最小值)。 如果您站在山顶上而必须下山,那么很明显的选择是,您将沿着山下坡,即向负坡度(或负坡度)移动。 以相同的方式,感知机中的权重与目标函数的梯度的负值成比例地变化。

梯度值越高,权重值的变化越大,反之亦然。 现在,这一切都很好,但是当梯度达到零,因此权重没有变化时,我们到达高原时就会遇到问题。 当我们进入一个小坑(局部极小值)时,我们也可能遇到问题,因为当我们尝试移动到任一侧时,坡度将增加,从而迫使网络停留在坑中。

如第 2 章,“回归”中所讨论的,梯度下降有多种变体,旨在提高收敛性,避免了陷入局部极小值或高原的问题(增加动量,可变学习率)。

TensorFlow 借助不同的优化器自动计算这些梯度。 但是,需要注意的重要一点是,由于 TensorFlow 将计算梯度,而梯度也将涉及激活函数的导数,因此重要的是,您选择的激活函数是可微的,并且在整个训练场景中最好具有非零梯度 。

感知机梯度下降的主要方法之一不同于第 2 章,“回归”,应用是为输出层定义目标函数,但可用于查找目标层,以及隐藏层的神经元的权重变化。 这是使用反向传播BPN)算法完成的,其中输出端的误差会向后传播到隐藏层,并用于确定权重变化。 您将很快了解更多信息。

激活函数

每个神经元必须具有激活函数。 它们使神经元具有建模复杂非线性数据集所需的非线性特性。 该函数获取所有输入的加权和,并生成一个输出信号。 您可以将其视为输入和输出之间的转换。 使用适当的激活函数,我们可以将输出值限制在定义的范围内。

如果x[j]是第j个输入,则W[j]的第j行输入到我们的神经元,并且b是我们神经元的偏置,即神经元的输出(从生物学的角度来说,是神经元的发射) 通过激活函数,在数学上表示为:

在此, g表示激活函数。 激活函数∑(W[j]x[j]) + b的参数称为神经元的激活

准备

我们对给定输入刺激的反应受神经元激活函数的控制。 有时我们的回答是二进制的是或否。 例如,当开个玩笑时,我们要么笑要么不笑。 在其他时间,响应似乎是线性的,例如由于疼痛而哭泣。 有时,响应似乎在一定范围内。

模仿类似的行为,人工神经元使用了许多不同的激活函数。 在本秘籍中,您将学习如何在 TensorFlow 中定义和使用一些常见的激活函数。

操作步骤

我们继续执行激活函数,如下所示:

  1. 阈值激活函数:这是最简单的激活函数。 在此,如果神经元的活动性大于零,则神经元会触发;否则,神经元会触发。 否则,它不会触发。 这是阈值激活函数随神经元活动变化而变化的图,以及在 TensorFlow 中实现阈值激活函数的代码:
import tensorflow as tf 
import numpy as np 
import matplotlib.pyplot as plt 
# Threshold Activation function 
def threshold (x):  
    cond = tf.less(x, tf.zeros(tf.shape(x), dtype = x.dtype))  
    out = tf.where(cond, tf.zeros(tf.shape(x)), tf.ones(tf.shape(x)))  
    return out 
# Plotting Threshold Activation Function 
h = np.linspace(-1,1,50) 
out = threshold(h) 
init = tf.global_variables_initializer()
with tf.Session() as sess:  
     sess.run(init)  
     y = sess.run(out) 
     plt.xlabel('Activity of Neuron') 
     plt.ylabel('Output of Neuron') 
     plt.title('Threshold Activation Function') 
     plt.plot(h, y)

以下是上述代码的输出:

  1. Sigmoid 激活函数:在这种情况下,神经元的输出由函数g(x) = 1 / (1 + exp(-x))指定。 在 TensorFlow 中,有一种方法tf.sigmoid,它提供了 Sigmoid 激活。 此函数的范围在 0 到 1 之间。形状上看起来像字母 S ,因此名称为 Sigmoid:
# Plotting Sigmoidal Activation function 
h = np.linspace(-10,10,50) 
out = tf.sigmoid(h) 
init = tf.global_variables_initializer()
with tf.Session() as sess:  
    sess.run(init)  
    y = sess.run(out) 
    plt.xlabel('Activity of Neuron') 
    plt.ylabel('Output of Neuron') 
    plt.title('Sigmoidal Activation Function') 
    plt.plot(h, y)

以下是以下代码的输出:

  1. 双曲正切激活函数:在数学上,它是(1 - exp(-2x) / (1 + exp(-2x))。在形状上,它类似于 Sigmoid 函数,但是它以 0 为中心,范围为 -1 至 1。TensorFlow 具有内置函数tf.tanh,用于双曲正切激活函数:
# Plotting Hyperbolic Tangent Activation function 
h = np.linspace(-10,10,50) 
out = tf.tanh(h) 
init = tf.global_variables_initializer()
with tf.Session() as sess:  
    sess.run(init)  
    y = sess.run(out) 
    plt.xlabel('Activity of Neuron') 
    plt.ylabel('Output of Neuron') 
    plt.title('Hyperbolic Tangent Activation Function') 
    plt.plot(h, y)

以下是上述代码的输出:

  1. 线性激活函数:在这种情况下,神经元的输出与神经元的活动相同。 此函数不受任何限制:
# Linear Activation Function
b = tf.Variable(tf.random_normal([1,1], stddev=2))
w = tf.Variable(tf.random_normal([3,1], stddev=2))
linear_out = tf.matmul(X_in, w) + b
init = tf.global_variables_initializer()
with tf.Session() as sess:
    sess.run(init)
    out = sess.run(linear_out)
print(out)
  1. 整流线性单元ReLU)激活函数再次内置在 TensorFlow 库中。 激活函数类似于线性激活函数,但有一个大变化-对于活动的负值,神经元不触发(零输出),对于活动的正值,神经元的输出与给定的活动相同:
# Plotting ReLU Activation function
h = np.linspace(-10,10,50)
out = tf.nn.relu(h)
init = tf.global_variables_initializer()
with tf.Session() as sess:  
    sess.run(init)  
    y = sess.run(out) 
plt.xlabel('Activity of Neuron') 
plt.ylabel('Output of Neuron') 
plt.title('ReLU Activation Function') 
plt.plot(h, y)

以下是 ReLu 激活函数的输出:

  1. Softmax 激活函数是归一化的指数函数。 一个神经元的输出不仅取决于其自身的活动,还取决于该层中存在的所有其他神经元的活动总和。 这样的一个优点是,它使神经元的输出保持较小,因此梯度不会爆炸。 数学上,它是y[i] = exp(x[i]) / ∑j exp(x[j])
# Plotting Softmax Activation function 
h = np.linspace(-5,5,50) 
out = tf.nn.softmax(h) 
init = tf.global_variables_initializer()
with tf.Session() as sess:  
    sess.run(init)  
    y = sess.run(out) 
    plt.xlabel('Activity of Neuron') 
    plt.ylabel('Output of Neuron') 
    plt.title('Softmax Activation Function') 
    plt.plot(h, y)

以下是上述代码的输出:

工作原理

以下是函数的说明:

  • 门控激活函数由 McCulloch Pitts Neuron 和初始感知机使用。 它不可微且在x = 0处不连续。 因此,不可能使用此激活函数来使用梯度下降或其变体进行训练。
  • Sigmoid 激活函数曾经非常流行。 如果看曲线,它看起来像是阈值激活函数的连续版本。 它具有消失的梯度问题,即,函数的梯度在两个边缘附近变为零。 这使得训练和优化变得困难。
  • 双曲正切激活函数再次和 Sigmoid 类似,并具有非线性特性。 该函数以零为中心,并且与 Sigmoid 曲线相比具有更陡峭的导数。 像 Sigmoid 一样,这也遭受消失的梯度问题的困扰。
  • 线性激活函数顾名思义是线性的。 该函数从两侧都是无界的[-inf, inf]。 其线性是其主要问题。 线性函数的总和将是线性函数,线性函数的线性函数也将是线性函数。 因此,使用此函数,无法掌握复杂数据集中存在的非线性。
  • ReLU 激活函数是线性激活函数的整流版本,当在多层中使用时,此整流可以捕获非线性。 使用 ReLU 的主要优点之一是它导致稀疏激活。 在任何时候,所有具有负活动的神经元都不会放电。 这使网络在计算方面更轻便。 ReLU 神经元患有垂死的 ReLU 问题,也就是说,不激发的神经元的梯度将变为零,因此将无法进行任何训练并保持静止(死)。 尽管存在这个问题,如今的 ReLU 还是隐藏层最常用的激活函数之一。
  • Softmax 激活函数通常用作输出层的激活函数。 该函数的范围为[0, 1]。 它用于表示多类分类问题中某类的概率。 所有单元的输出总和将始终为 1。

更多

神经网络已用于各种任务。 这些任务可以大致分为两类:函数逼近(回归)和分类。 根据手头的任务,一个激活函数可能会优于另一个。 通常,最好将 ReLU 神经元用于隐藏层。 对于分类任务,softmax 通常是更好的选择,对于回归问题,最好使用 Sigmoid 或双曲正切。

另见

单层感知机

简单的感知机是单层神经网络。 它使用阈值激活函数,并且正如 Marvin Minsky 论文所证明的那样,只能解决线性可分离的问题。 尽管这将单层感知机的应用限制为仅是线性可分离的问题,但看到它学习仍然总是令人惊奇。

准备

由于感知机使用阈值激活函数,因此我们无法使用 TensorFlow 优化器来更新权重。 我们将不得不使用权重更新规则:

这是学习率。 为了简化编程,可以将偏置作为附加权重添加,输入固定为 +1。 然后,前面的等式可用于同时更新权重和偏差。

操作步骤

这是我们处理单层感知机的方法:

  1. 导入所需的模块:
import tensorflow as tf 
import numpy as np
  1. 定义要使用的超参数:
# Hyper parameters 
eta = 0.4  # learning rate parameter 
epsilon = 1e-03 # minimum accepted error 
max_epochs = 100 # Maximum Epochs
  1. 定义threshold函数:
# Threshold Activation function 
def threshold (x): 
    cond = tf.less(x, tf.zeros(tf.shape(x), dtype = x.dtype)) 
    out = tf.where(cond, tf.zeros(tf.shape(x)), tf.ones(tf.shape(x))) 
    return out
  1. 指定训练数据。 在此示例中,我们采用三个输入神经元(ABC)并对其进行训练以学习逻辑AB + BC
# Training Data  Y = AB + BC, sum of two linear functions. 
T, F = 1., 0\. 
X_in = [ 
    [T, T, T, T], 
    [T, T, F, T], 
    [T, F, T, T], 
    [T, F, F, T], 
    [F, T, T, T], 
    [F, T, F, T], 
    [F, F, T, T], 
    [F, F, F, T], 
    ] 
Y = [ 
    [T], 
    [T], 
    [F], 
    [F], 
    [T], 
    [F], 
    [F], 
    [F] 
]
  1. 定义要使用的变量,计算图以计算更新,最后执行计算图:
W = tf.Variable(tf.random_normal([4,1], stddev=2, seed = 0)) 
h = tf.matmul(X_in, W)  
Y_hat = threshold(h) 
error = Y - Y_hat 
mean_error = tf.reduce_mean(tf.square(error)) 
dW =  eta * tf.matmul(X_in, error, transpose_a=True) 
train = tf.assign(W, W+dW) 
init = tf.global_variables_initializer() 
err = 1 
epoch = 0 
with tf.Session() as sess: 
    sess.run(init) 
    while err > epsilon and epoch < max_epochs: 
        epoch += 1 
        err, _ = sess.run([mean_error, train]) 
        print('epoch: {0}  mean error: {1}'.format(epoch, err)) 
    print('Training complete')

以下是上述代码的输出:

更多

如果我们使用 Sigmoid 激活函数代替阈值激活函数,您会怎么办?

你猜对了; 首先,我们可以使用 TensorFlow 优化器来更新权重。 其次,网络的行为类似于逻辑回归器。

反向传播算法的梯度计算

BPN 算法是神经网络中研究最多的算法之一。 它用于将误差从输出层传播到隐藏层的神经元,然后将其用于更新权重。 整个学习可以分为两阶段-前向阶段和后向阶段。

向前传递:输入被馈送到网络,信号从输入层通过隐藏层传播,最后传播到输出层。 在输出层,计算误差和loss函数。

向后传递:在向后传递中,首先为输出层神经元然后为隐藏层神经元计算loss函数的梯度。 然后使用梯度更新权重。

重复两次遍历,直到达到收敛为止。

准备

首先为网络呈现M个训练对(X, Y),并以X作为输入, Y为所需的输出。 输入通过激活函数g(h)从输入传播到隐藏层,直到输出层。 输出Y_hat是网络的输出,误差为Y - Y_hat

loss函数J(W)如下:

在此, i在输出层(1 到 N)的所有神经元上变化。 W[ij]的权重变化,将输出层第i个神经元连接到隐藏层第j个神经元,然后可以使用J(W)的梯度并使用链规则进行区分来确定隐藏层神经元:

此处, O[j]是隐藏层神经元的输出, jh表示活动。 这很容易,但是现在我们如何找到W[jk],它连接第n个隐藏层的神经元k和第n+1隐藏层的神经元j?流程是相同的,我们将使用loss函数的梯度和链规则进行微分,但是这次我们将针对W[jk]进行计算:

现在方程式就位了,让我们看看如何在 TensorFlow 中做到这一点。 在本秘籍中,我们使用相同的旧 MNIST 数据集

操作步骤

现在让我们开始学习反向传播算法:

  1. 导入模块:
import tensorflow as tf 
from tensorflow.examples.tutorials.mnist import input_data
  1. 加载数据集; 我们通过设置one_hot = True使用一键编码标签:
mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)
  1. 定义超参数和其他常量。 在这里,每个手写数字的大小为28 x 28 = 784像素。 数据集分为 10 类,因为数字可以是 0 到 9 之间的任何数字。这两个是固定的。 学习率,最大周期数,要训练的迷你批次的批次大小以及隐藏层中神经元的数量都是超参数。 可以与他们一起玩耍,看看它们如何影响网络行为:
# Data specific constants
 n_input = 784 # MNIST data input (img shape: 28*28)
 n_classes = 10 # MNIST total classes (0-9 digits)
 # Hyperparameters
 max_epochs = 10000
 learning_rate = 0.5
 batch_size = 10
 seed = 0
 n_hidden = 30  # Number of neurons in the hidden layer
  1. 我们将需要sigmoid函数的导数进行权重更新,因此我们对其进行定义:
def sigmaprime(x):
     return tf.multiply(tf.sigmoid(x), tf.subtract(tf.constant(1.0), tf.sigmoid(x)))
  1. 为训练数据创建占位符:
x_in = tf.placeholder(tf.float32, [None, n_input])
y = tf.placeholder(tf.float32, [None, n_classes])
  1. 创建模型:
def multilayer_perceptron(x, weights, biases):
     # Hidden layer with RELU activation
     h_layer_1 = tf.add(tf.matmul(x, weights['h1']), biases['h1'])
     out_layer_1 = tf.sigmoid(h_layer_1)
     # Output layer with linear activation
     h_out = tf.matmul(out_layer_1, weights['out']) + biases['out']
     return tf.sigmoid(h_out), h_out, out_layer_1, h_layer_1
  1. 定义weightsbiases的变量:
weights = {
     'h1': tf.Variable(tf.random_normal([n_input, n_hidden], seed = seed)),
     'out': tf.Variable(tf.random_normal([n_hidden, n_classes], seed = seed)) }
 biases = {
     'h1': tf.Variable(tf.random_normal([1, n_hidden], seed = seed)),
     'out': tf.Variable(tf.random_normal([1, n_classes], seed = seed))}
  1. 创建用于向前通过,误差,梯度和更新计算的计算图:
# Forward Pass
 y_hat, h_2, o_1, h_1 = multilayer_perceptron(x_in, weights, biases)
 # Error
 err = y_hat - y
 # Backward Pass
 delta_2 = tf.multiply(err, sigmaprime(h_2))
 delta_w_2 = tf.matmul(tf.transpose(o_1), delta_2)
 wtd_error = tf.matmul(delta_2, tf.transpose(weights['out']))
 delta_1 = tf.multiply(wtd_error, sigmaprime(h_1))
 delta_w_1 = tf.matmul(tf.transpose(x_in), delta_1)
 eta = tf.constant(learning_rate)
 # Update weights
 step = [
     tf.assign(weights['h1'],tf.subtract(weights['h1'], tf.multiply(eta, delta_w_1)))
   , tf.assign(biases['h1'],tf.subtract(biases['h1'], tf.multiply(eta, tf.reduce_mean(delta_1, axis=[0]))))
   , tf.assign(weights['out'], tf.subtract(weights['out'], tf.multiply(eta, delta_w_2)))
   , tf.assign(biases['out'], tf.subtract(biases['out'], tf.multiply(eta,tf.reduce_mean(delta_2, axis=[0]))))
 ]
  1. accuracy定义操作:
acct_mat = tf.equal(tf.argmax(y_hat, 1), tf.argmax(y, 1))
accuracy = tf.reduce_sum(tf.cast(acct_mat, tf.float32))
  1. 初始化变量:
init = tf.global_variables_initializer()
  1. 执行图:
with tf.Session() as sess:
     sess.run(init)
     for epoch in range(max_epochs):
         batch_xs, batch_ys = mnist.train.next_batch(batch_size)
         sess.run(step, feed_dict = {x_in: batch_xs, y : batch_ys})
         if epoch % 1000 == 0:
             acc_test = sess.run(accuracy, feed_dict =
                        {x_in: mnist.test.images,
                         y : mnist.test.labels})
             acc_train = sess.run(accuracy, feed_dict=
             {x_in: mnist.train.images,
              y: mnist.train.labels})
             print('Epoch: {0}  Accuracy Train%: {1}  Accuracy Test%: {2}'
                   .format(epoch,acc_train/600,(acc_test/100)))

结果如下:

工作原理

在这里,我们正在以 10 的批量大小训练网络。如果增加它,网络表现就会下降。 同样,在测试数据上检查训练网络的准确率; 对其进行测试的测试数据的大小为 1,000。

更多

我们的一个隐藏层多层感知机在训练数据上的准确率为 84.45,在测试数据上的准确率为 92.1。 很好,但还不够好。 MNIST 数据库用作机器学习中分类问题的基准。 接下来,我们了解使用 TensorFlow 的内置优化器如何影响网络表现。

另见

使用 MLP 的 MNIST 分类器

TensorFlow 支持自动分化; 我们可以使用 TensorFlow 优化器来计算和应用梯度。 它使用梯度自动更新定义为变量的张量。 在此秘籍中,我们将使用 TensorFlow 优化器来训练网络。

准备

在反向传播算法秘籍中,我们定义了层,权重,损耗,梯度,并手动通过梯度进行更新。 为了更好地理解,手动使用方程式进行操作是一个好主意,但是随着网络中层数的增加,这可能会非常麻烦。

在本秘籍中,我们将使用强大的 TensorFlow 功能(例如 Contrib(层))来定义神经网络层,并使用 TensorFlow 自己的优化器来计算和应用梯度。 我们在第 2 章和“回归”中了解了如何使用不同的 TensorFlow 优化器。 contrib 可用于向神经网络模型添加各种层,例如添加构建块。 我们在这里使用的一种方法是tf.contrib.layers.fully_connected,在 TensorFlow 文档中定义如下:

fully_connected(
     inputs,
     num_outputs,
     activation_fn=tf.nn.relu,
     normalizer_fn=None,
     normalizer_params=None,
     weights_initializer=initializers.xavier_initializer(),
     weights_regularizer=None,
     biases_initializer=tf.zeros_initializer(),
     biases_regularizer=None,
     reuse=None,
     variables_collections=None,
     outputs_collections=None,
     trainable=True,
     scope=None
 )

这将添加一个完全连接的层。

fully_connected creates a variable called weights, representing a fully connected weight matrix, which is multiplied by the inputs to produce a tensor of hidden units. If a normalizer_fn is provided (such as batch_norm), it is then applied. Otherwise, if normalizer_fn is None and a biases_initializer is provided then a biases variable would be created and added to the hidden units. Finally, if activation_fn is not None, it is applied to the hidden units as well.

操作步骤

我们按以下步骤进行:

  1. 第一步是更改loss函数; 尽管对于分类,最好使用交叉熵loss函数。 我们目前继续均方误差MSE):
loss = tf.reduce_mean(tf.square(y - y_hat, name='loss'))
  1. 接下来,我们使用GradientDescentOptimizer
optimizer = tf.train.GradientDescentOptimizer(learning_rate= learning_rate)
 train = optimizer.minimize(loss)
  1. 仅通过这两个更改,对于同一组超参数,测试数据集的准确率仅为 61.3%。 增加max_epoch,我们可以提高精度,但这将不是 TensorFlow 功能的有效利用。
  2. 这是一个分类问题,因此最好使用交叉熵损失,用于隐藏层的 ReLU 激活函数以及用于输出层的 softmax。 进行所需的更改,完整代码如下:
import tensorflow as tf
 import tensorflow.contrib.layers as layers
 from tensorflow.python import debug as tf_debug
 # Network Parameters
 n_hidden = 30
 n_classes = 10
 n_input = 784
 # Hyperparameters
 batch_size = 200
 eta = 0.001
 max_epoch = 10
 # MNIST input data
 from tensorflow.examples.tutorials.mnist import input_data
 mnist = input_data.read_data_sets("/tmp/data/", one_hot=True)
 def multilayer_perceptron(x):
     fc1 = layers.fully_connected(x, n_hidden, activation_fn=tf.nn.relu, scope='fc1')
     #fc2 = layers.fully_connected(fc1, 256, activation_fn=tf.nn.relu, scope='fc2')
     out = layers.fully_connected(fc1, n_classes, activation_fn=None, scope='out')
     return out
 # build model, loss, and train op
 x = tf.placeholder(tf.float32, [None, n_input], name='placeholder_x')
 y = tf.placeholder(tf.float32, [None, n_classes], name='placeholder_y')
 y_hat = multilayer_perceptron(x)
 loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=y_hat, labels=y))
 train = tf.train.AdamOptimizer(learning_rate= eta).minimize(loss)
 init = tf.global_variables_initializer()
 with tf.Session() as sess:
     sess.run(init)
     for epoch in range(10):
         epoch_loss = 0.0
         batch_steps = int(mnist.train.num_examples / batch_size)
         for i in range(batch_steps):
             batch_x, batch_y = mnist.train.next_batch(batch_size)
             _, c = sess.run([train, loss],
                                feed_dict={x: batch_x, y: batch_y})
             epoch_loss += c / batch_steps
         print ('Epoch %02d, Loss = %.6f' % (epoch, epoch_loss))
     # Test model
     correct_prediction = tf.equal(tf.argmax(y_hat, 1), tf.argmax(y, 1))
     accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
     print ("Accuracy%:", accuracy.eval({x: mnist.test.images, y: mnist.test.labels}))

工作原理

改进的 MNIST MLP 分类器在测试数据集上的准确率达到了 96%,只有一个隐藏层并且在 10 个周期内。 仅在几行代码中我们就获得了约 96% 的准确率,这就是 TensorFlow 的强大功能:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vIeOBXAk-1681565141622)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/tf-1x-dl-cookbook/img/d915165d-a180-4e7b-9fd9-552b65d2e667.png)]

使用 MLP 预测波士顿房价的函数近似

Hornik 等人的工作证明了以下:

“multilayer feedforward networks with as few as one hidden layer are indeed capable of universal approximation in a very precise and satisfactory sense.”

在本秘籍中,我们将向您展示如何使用 MLP 进行函数逼近; 具体来说,我们将预测波士顿的房价。 我们已经熟悉了数据集; 在第 2 章,“回归”中,我们使用回归技术进行房价预测,现在我们将使用 MLP 进行相同的操作。

准备

对于函数逼近,loss函数应为 MSE。 输入应该标准化,而隐藏层可以是 ReLU,而输出层则最好是 Sigmoid 。

操作步骤

这是我们从使用 MLP 进行函数逼近开始的方法:

  1. 导入所需的模块-sklearn用于数据集,预处理数据,并将其拆分为训练和测试; Pandas 用于了解数据集; matplotlibseaborn用于可视化:
import tensorflow as tf 
import tensorflow.contrib.layers as layers 
from sklearn import datasets 
import matplotlib.pyplot as plt 
from sklearn.model_selection  import train_test_split 
from sklearn.preprocessing import MinMaxScaler 
import pandas as pd 
import seaborn as sns 
%matplotlib inline
  1. 加载数据集并创建一个 Pandas 数据帧以了解数据:
# Data 
boston = datasets.load_boston() 
df = pd.DataFrame(boston.data, columns=boston.feature_names) 
df['target'] = boston.target
  1. 让我们获取有关数据的一些详细信息:
#Understanding Data 
df.describe()

下图很好地说明了这一概念:

  1. 查找不同输入特征和目标之间的关联:
# Plotting correlation 
color map _ , ax = plt.subplots( figsize =( 12 , 10 ) ) 
corr = df.corr(method='pearson') 
cmap = sns.diverging_palette( 220 , 10 , as_cmap = True ) 
_ = sns.heatmap( corr, cmap = cmap, square=True, cbar_kws={ 'shrink' : .9 }, ax=ax, annot = True, annot_kws = { 'fontsize' : 12 })

以下是上述代码的输出:

  1. 从前面的代码中,我们可以看到RMPTRATIOLSTAT这三个参数的相关性在大小上大于 0.5。 我们选择它们进行训练。 将数据集拆分为训练和测试数据集。 我们还使用MinMaxScaler归一化我们的数据集。 需要注意的一个重要变化是,由于我们的神经网络使用了 Sigmoid 激活函数(Sigmoid 的输出只能在 0-1 之间),因此我们也必须将目标值Y标准化:
# Create Test Train Split 
X_train, X_test, y_train, y_test = train_test_split(df [['RM', 'LSTAT', 'PTRATIO']], df[['target']], test_size=0.3, random_state=0) 
# Normalize data 
X_train = MinMaxScaler().fit_transform(X_train) 
y_train = MinMaxScaler().fit_transform(y_train) 
X_test = MinMaxScaler().fit_transform(X_test) 
y_test = MinMaxScaler().fit_transform(y_test)
  1. 定义常量和超参数:
#Network Parameters 
m = len(X_train) 
n = 3 # Number of features 
n_hidden = 20 # Number of hidden neurons 
# Hyperparameters 
batch_size = 200 
eta = 0.01 
max_epoch = 1000
  1. 创建具有一个隐藏层的多层感知机模型:
def multilayer_perceptron(x): 
    fc1 = layers.fully_connected(x, n_hidden, activation_fn=tf.nn.relu, scope='fc1') 
    out = layers.fully_connected(fc1, 1, activation_fn=tf.sigmoid, scope='out') 
    return out
  1. 声明训练数据的占位符,并定义损失和优化器:
# build model, loss, and train op 
x = tf.placeholder(tf.float32, name='X', shape=[m,n]) 
y = tf.placeholder(tf.float32, name='Y') 
y_hat = multilayer_perceptron(x) 
correct_prediction = tf.square(y - y_hat) 
mse = tf.reduce_mean(tf.cast(correct_prediction, "float")) 
train = tf.train.AdamOptimizer(learning_rate= eta).minimize(mse) 
init = tf.global_variables_initializer()
  1. 执行计算图:
# Computation Graph 
with tf.Session() as sess: # Initialize variables
     sess.run(init) writer = tf.summary.FileWriter('graphs', sess.graph) 
# train the model for 100 epcohs 
    for i in range(max_epoch): 
        _, l, p = sess.run([train, loss, y_hat], feed_dict={x: X_train, y: y_train}) 
        if i%100 == 0: 
            print('Epoch {0}: Loss {1}'.format(i, l))
    print("Training Done") 
print("Optimization Finished!") 
# Test model correct_prediction = tf.square(y - y_hat) 
# Calculate accuracy 
accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))
print(" Mean Error:", accuracy.eval({x: X_train, y: y_train})) plt.scatter(y_train, p) 
writer.close()

工作原理

该模型只有一个隐藏层,因此可以预测训练数据集的价格,平均误差为 0.0071。 下图显示了房屋的估计价格与实际价格之间的关系:

更多

在这里,我们使用 TensorFlow ops Layers(Contrib)来构建神经网络层。 由于避免了分别声明每一层的权重和偏差,因此使我们的工作稍微容易一些。 如果我们使用像 Keras 这样的 API,可以进一步简化工作。 这是在 Keras 中使用 TensorFlow 作为后端的相同代码:

#Network Parameters
m = len(X_train)
n = 3 # Number of features
n_hidden = 20 # Number of hidden neurons
# Hyperparameters
batch = 20
eta = 0.01
max_epoch = 100
# Build Model 
model = Sequential() 
model.add(Dense(n_hidden,  
model.add(Dense(1, activation='sigmoid')) 
model.summary() 
# Summarize the model 
#Compile model 
model.compile(loss='mean_squared_error', optimizer='adam') 
#Fit the model 
model.fit(X_train, y_train, validation_data=(X_test, y_test),epochs=max_epoch, batch_size=batch, verbose=1) 
#Predict the values and calculate RMSE and R2 score 
y_test_pred = model.predict(X_test) 
y_train_pred = model.predict(X_train) 
r2 = r2_score( y_test, y_test_pred ) 
rmse = mean_squared_error( y_test, y_test_pred ) 
print( "Performance Metrics R2 : {0:f}, RMSE : {1:f}".format( r2, rmse ) )

前面的代码在预测值和实际值之间给出了以下结果。 我们可以看到,通过消除异常值可以改善结果(某些房屋的最高价格与其他参数无关,位于最右边的点):

调整超参数

正如您现在必须已经观察到的那样,神经网络的表现在很大程度上取决于超参数。 因此,重要的是要了解这些参数如何影响网络。 超参数的常见示例是学习率,正则化器,正则化系数,隐藏层的尺寸,初始权重值,甚至是为优化权重和偏差而选择的优化器。

操作步骤

这是我们进行秘籍的方法:

  1. 调整超参数的第一步是构建模型。 完全按照我们以前的方式在 TensorFlow 中构建模型。
  2. 添加一种将模型保存在model_file中的方法。 在 TensorFlow 中,可以使用Saver对象完成此操作。 然后将其保存在会话中:
... saver = tf.train.Saver() ... with tf.Session() as sess: ... #Do the training steps ... save_path = saver.save(sess, "/tmp/model.ckpt") print("Model saved in file: %s" % save_path)
  1. 接下来,确定要调整的超参数。
  2. 为超参数选择可能的值。 在这里,您可以进行随机选择,等距选择或手动选择。 这三个分别称为随机搜索,网格搜索或用于优化超参数的手动搜索。 例如,这是针对学习率的:
# Random Choice: generate 5 random values of learning rate 
# lying between 0 and 1 
learning_rate =  
#Grid Search: generate 5 values starting from 0, separated by 
# 0.2 
learning_rate = [i for i in np.arange(0,1,0.2)] 
#Manual Search: give any values you seem plausible manually learning_rate = [0.5, 0.6, 0.32, 0.7, 0.01]
  1. 我们选择对我们选择的loss函数具有最佳响应的参数。 因此,我们可以在开始时将loss函数的最大值定义为best_loss(在精度的情况下,您将从模型中选择所需的最小精度):
best_loss = 2 
# It can be any number, but it would be better if you keep it same as the loss you achieved from your base model defined in steps 1 and 2
  1. 将模型包装在for循环中以提高学习率; 然后保存任何可以更好地估计损失的模型:
... # Load and preprocess data 
... # Hyperparameters 
Tuning epochs = [50, 60, 70] 
batches = [5, 10, 20] 
rmse_min = 0.04 
for epoch in epochs: 
    for batch in batches: 
        model = get_model() 
        model.compile(loss='mean_squared_error', optimizer='adam') 
        model.fit(X_train, y_train, validation_data=(X_test, y_test),epochs=epoch, batch_size=batch, verbose=1) 
        y_test_pred = model.predict(X_test) 
        rmse = mean_squared_error( y_test, y_test_pred ) 
        if rmse < rmse_min: 
            rmse_min = rmse 
            # serialize model to JSON 
            model_json = model.to_json() 
            with open("model.json", "w") as json_file: 
                json_file.write(model_json) 
                # serialize weights to HDF5  
                model.save_weights("model.hdf5") 
                print("Saved model to disk")

更多

还有另一种称为贝叶斯优化的方法,该方法也可以用于调整超参数。 在其中,我们定义了一个采集函数以及一个高斯过程。 高斯过程使用一组先前评估的参数以及由此产生的精度来假设大约未观测到的参数。 使用此信息的采集功能建议使用下一组参数。 有一个包装程序甚至可用于基于梯度的超参数优化

另见

更高级别的 API – Keras

Keras 是将 TensorFlow 作为后端使用的高级 API。 向其添加层就像添加一行代码一样容易。 在建立模型架构之后,您可以使用一行代码来编译和拟合模型。 以后,它可以用于预测。 变量,占位符甚至会话的声明均由 API 管理。

操作步骤

我们对 Keras 进行如下操作:

  1. 第一步,我们定义模型的类型。 Keras 提供了两种类型的模型:顺序模型 API 和模型类 API。 Keras 提供了各种类型的神经网络层:
# Import the model and layers needed  
from keras.model import Sequential 
from keras.layers import Dense 
model = Sequential()
  1. 借助model.add()将层添加到模型中。 Keras 为密集连接的神经网络layer Dense(units, activation=None, use_bias=True, kernel_initializer='glorot_uniform', bias_initializer='zeros', kernel_regularizer=None, bias_regularizer=None, activity_regularizer=None, kernel_constraint=None, bias_constraint=None)提供了一个密集层的选项。 根据 Keras 文档:

Dense implements the operation: output = activation(dot(input, kernel) + bias) where activation is the element-wise activation function passed as the activation argument, kernel is a weights matrix created by the layer, and bias is a bias vector created by the layer (only applicable if use_bias is True).

  1. 我们可以使用它来添加任意数量的层,每个隐藏的层都由上一层提供。 我们只需要为第一层指定输入尺寸:
#This will add a fully connected neural network layer with 32 neurons, each taking 13 inputs, and with activation function ReLU 
mode.add(Dense(32, input_dim=13, activation='relu')) )) 
model.add(10, activation='sigmoid')
  1. 定义模型后,我们需要选择loss函数和优化器。 Keras 提供了多种loss_functionsmean_squared_errormean_absolute_errormean_absolute_percentage_errorcategorical_crossentropy; 和优化程序:SGD,RMSprop,Adagrad,Adadelta,Adam 等。 决定了这两个条件后,我们可以使用compile(self, optimizer, loss, metrics=None, sample_weight_mode=None)配置学习过程:
model.compile(optimizer='rmsprop', 
          loss='categorical_crossentropy', 
          metrics=['accuracy'])
  1. 接下来,使用fit方法训练模型:
model.fit(data, labels, epochs=10, batch_size=32)
  1. 最后,可以借助predict方法predict(self, x, batch_size=32, verbose=0)进行预测:
model.predict(test_data, batch_size=10)

更多

Keras 提供了添加卷积层,池化层,循环层甚至本地连接层的选项。 Keras 文档中提供了每种方法的详细说明。

另见

McCulloch, Warren S., and Walter Pitts. A logical calculus of the ideas immanent in nervous activity The bulletin of mathematical biophysics 5.4 (1943): 115-133. http://vordenker.de/ggphilosophy/mcculloch_a-logical-calculus.pdf
Rosenblatt, Frank (1957), The Perceptron--a perceiving and recognizing automaton. Report 85-460-1, Cornell Aeronautical Laboratory. https://blogs.umass.edu/brain-wars/files/2016/03/rosenblatt-1957.pdf
The Thinking Machine, CBS Broadcast https://www.youtube.com/watch?v=jPHUlQiwD9Y

四、卷积神经网络

卷积神经网络CNN 或有时称为 ConvNets)令人着迷。 在短时间内,它们成为一种破坏性技术,打破了从文本,视频到语音的多个领域中的所有最新技术成果,远远超出了最初用于图像处理的范围。 在本章中,我们将介绍一些方法,如下所示:

  • 创建一个卷积网络对手写 MNIST 编号进行分类
  • 创建一个卷积网络对 CIFAR-10 进行分类
  • 使用 VGG19 迁移风格用于图像重绘
  • 使用预训练的 VGG16 网络进行迁移学习
  • 创建 DeepDream 网络

介绍

CNN 由许多神经网络层组成。 卷积和池化两种不同类型的层通常是交替的。 网络中每个过滤器的深度从左到右增加。 最后一级通常由一个或多个完全连接的层组成:

如图所示,卷积神经网络的一个示例

卷积网络背后有三个主要的直觉:局部接受域共享权重池化。 让我们一起回顾一下。

局部接受域

如果我们要保留通常在图像中发现的空间信息,则使用像素矩阵表示每个图像会很方便。 然后,编码局部结构的一种简单方法是将相邻输入神经元的子矩阵连接到属于下一层的单个隐藏神经元中。 单个隐藏的神经元代表一个局部感受野。 请注意,此操作名为卷积,它为这种类型的网络提供了名称。

当然,我们可以通过重叠子矩阵来编码更多信息。 例如,假设每个子矩阵的大小为5 x 5,并且这些子矩阵用于28 x 28像素的 MNIST 图像。 然后,我们将能够在下一个隐藏层中生成23 x 23个局部感受野神经元。 实际上,在触摸图像的边界之前,可以仅将子矩阵滑动 23 个位置。

让我们定义从一层到另一层的特征图。 当然,我们可以有多个可以从每个隐藏层中独立学习的特征图。 例如,我们可以从28 x 28个输入神经元开始处理 MNIST 图像,然后在下一个隐藏的区域中调用k个特征图,每个特征图的大小为23 x 23神经元(步幅为5 x 5)。

权重和偏置

假设我们想通过获得独立于输入图像中放置同一特征的能力来摆脱原始像素表示的困扰。 一个简单的直觉是对隐藏层中的所有神经元使用相同的权重和偏差集。 这样,每一层将学习从图像派生的一组位置无关的潜在特征。

一个数学示例

一种了解卷积的简单方法是考虑应用于矩阵的滑动窗口函数。 在下面的示例中,给定输入矩阵I和内核K,我们得到了卷积输出。 将3 x 3内核K(有时称为过滤器特征检测器)与输入矩阵逐元素相乘,得到输出卷积矩阵中的一个单元格。 通过在I上滑动窗口即可获得所有其他单元格:

卷积运算的一个示例:用粗体显示计算中涉及的单元

在此示例中,我们决定在触摸I的边界后立即停止滑动窗口(因此输出为3 x 3)。 或者,我们可以选择用零填充输入(以便输出为5 x 5)。 该决定与所采用的填充选择有关。

另一个选择是关于步幅,这与我们的滑动窗口采用的移位类型有关。 这可以是一个或多个。 较大的跨度将生成较少的内核应用,并且较小的输出大小,而较小的跨度将生成更多的输出并保留更多信息。

过滤器的大小,步幅和填充类型是超参数,可以在网络训练期间进行微调。

TensorFlow 中的卷积网络

在 TensorFlow 中,如果要添加卷积层,我们将编写以下内容:

tf.nn.conv2d(input, filter, strides, padding, use_cudnn_on_gpu=None, data_format=None, name=None)

以下是参数:

  • input:张量必须为以下类型之一:float32float64
  • filter:张量必须与输入具有相同的类型。
  • strides:整数列表。 长度为 1 的 4D。输入每个维度的滑动窗口的步幅。 必须与格式指定的尺寸顺序相同。
  • padding:来自SAMEVALID的字符串。 要使用的填充算法的类型。
  • use_cudnn_on_gpu:可选的布尔值。 默认为True
  • data_format:来自NHWCNCHW的可选字符串。 默认为NHWC。 指定输入和输出数据的数据格式。 使用默认格式NHWC时,数据按以下顺序存储:[batchin_heightin_widthin_channels]。 或者,格式可以是NCHW,数据存储顺序为:[batchin_channelsin_height, in_width]。
  • name:操作的名称(可选)。

下图提供了卷积的示例:

卷积运算的一个例子

汇聚层

假设我们要总结特征图的输出。 同样,我们可以使用从单个特征图生成的输出的空间连续性,并将子矩阵的值聚合为一个单个输出值,以综合方式描述与该物理区域相关的含义。

最大池

一个简单而常见的选择是所谓的最大池化运算符,它仅输出在该区域中观察到的最大激活。 在 TensorFlow 中,如果要定义大小为2 x 2的最大池化层,我们将编写以下内容:

tf.nn.max_pool(value, ksize, strides, padding, data_format='NHWC', name=None)

这些是参数:

  • value:形状为[batchheightwidthchannels]且类型为tf.float32的 4-D 张量。
  • ksize:长度>= 4的整数的列表。输入张量每个维度的窗口大小。
  • strides:长度>= 4的整数的列表。输入张量每个维度的滑动窗口的步幅。
  • paddingVALIDSAME的字符串。
  • data_format:字符串。 支持NHWCNCHW
  • name:操作的可选名称。

下图给出了最大池化操作的示例:

池化操作示例

平均池化

另一个选择是“平均池化”,它可以将一个区域简单地汇总为在该区域中观察到的激活平均值。

TensorFlow 实现了大量池化层,可在线获取完整列表。简而言之,所有池化操作仅是对给定区域的汇总操作。

卷积网络摘要

CNN 基本上是卷积的几层,具有非线性激活函数,并且池化层应用于结果。 每层应用不同的过滤器(数百或数千)。 要理解的主要观察结果是未预先分配滤波器,而是在训练阶段以最小化合适损失函数的方式来学习滤波器。 已经观察到,较低的层将学会检测基本特征,而较高的层将逐渐检测更复杂的特征,例如形状或面部。 请注意,得益于合并,后一层中的单个神经元可以看到更多的原始图像,因此它们能够组成在前几层中学习的基本特征。

到目前为止,我们已经描述了 ConvNets 的基本概念。 CNN 在沿时间维度的一维中对音频和文本数据应用卷积和池化操作,在沿(高度 x 宽度)维的图像中对二维图像应用卷积和池化操作,对于沿(高度 x 宽度 x 时间)维的视频中的三个维度应用卷积和池化操作。 对于图像,在输入体积上滑动过滤器会生成一个贴图,该贴图为每个空间位置提供过滤器的响应。

换句话说,卷积网络具有堆叠在一起的多个过滤器,这些过滤器学会了独立于图像中的位置来识别特定的视觉特征。 这些视觉特征在网络的初始层很简单,然后在网络的更深层越来越复杂。g操作

TensorFlow 1.x 深度学习秘籍:1~5(2)https://developer.aliyun.com/article/1426763

相关实践学习
部署Stable Diffusion玩转AI绘画(GPU云服务器)
本实验通过在ECS上从零开始部署Stable Diffusion来进行AI绘画创作,开启AIGC盲盒。
相关文章
|
6天前
|
机器学习/深度学习 供应链 TensorFlow
深度学习实战营:TensorFlow+Python,打造你的数据驱动决策引擎
【9月更文挑战第13天】在数据爆炸时代,企业日益依赖精准分析进行决策。深度学习凭借其卓越的特征提取与模式识别能力,成为构建数据驱动决策引擎的关键技术。本项目通过TensorFlow和Python,利用LSTM构建零售业销量预测模型,优化库存管理和营销策略。首先确保安装TensorFlow,然后使用Keras API搭建模型,并通过训练、评估和部署流程,展示深度学习在数据驱动决策中的强大应用潜力,助力企业提升经营效率。
17 3
|
9天前
|
机器学习/深度学习 数据挖掘 TensorFlow
从数据小白到AI专家:Python数据分析与TensorFlow/PyTorch深度学习的蜕变之路
【9月更文挑战第10天】从数据新手成长为AI专家,需先掌握Python基础语法,并学会使用NumPy和Pandas进行数据分析。接着,通过Matplotlib和Seaborn实现数据可视化,最后利用TensorFlow或PyTorch探索深度学习。这一过程涉及从数据清洗、可视化到构建神经网络的多个步骤,每一步都需不断实践与学习。借助Python的强大功能及各类库的支持,你能逐步解锁数据的深层价值。
22 0
|
19天前
|
持续交付 测试技术 jenkins
JSF 邂逅持续集成,紧跟技术热点潮流,开启高效开发之旅,引发开发者强烈情感共鸣
【8月更文挑战第31天】在快速发展的软件开发领域,JavaServer Faces(JSF)这一强大的Java Web应用框架与持续集成(CI)结合,可显著提升开发效率及软件质量。持续集成通过频繁的代码集成及自动化构建测试,实现快速反馈、高质量代码、加强团队协作及简化部署流程。以Jenkins为例,配合Maven或Gradle,可轻松搭建JSF项目的CI环境,通过JUnit和Selenium编写自动化测试,确保每次构建的稳定性和正确性。
42 0
|
19天前
|
测试技术 数据库
探索JSF单元测试秘籍!如何让您的应用更稳固、更高效?揭秘成功背后的测试之道!
【8月更文挑战第31天】在 JavaServer Faces(JSF)应用开发中,确保代码质量和可维护性至关重要。本文详细介绍了如何通过单元测试实现这一目标。首先,阐述了单元测试的重要性及其对应用稳定性的影响;其次,提出了提高 JSF 应用可测试性的设计建议,如避免直接访问外部资源和使用依赖注入;最后,通过一个具体的 `UserBean` 示例,展示了如何利用 JUnit 和 Mockito 框架编写有效的单元测试。通过这些方法,不仅能够确保代码质量,还能提高开发效率和降低维护成本。
33 0
|
19天前
|
UED 开发者
哇塞!Uno Platform 数据绑定超全技巧大揭秘!从基础绑定到高级转换,优化性能让你的开发如虎添翼
【8月更文挑战第31天】在开发过程中,数据绑定是连接数据模型与用户界面的关键环节,可实现数据自动更新。Uno Platform 提供了简洁高效的数据绑定方式,使属性变化时 UI 自动同步更新。通过示例展示了基本绑定方法及使用 `Converter` 转换数据的高级技巧,如将年龄转换为格式化字符串。此外,还可利用 `BindingMode.OneTime` 提升性能。掌握这些技巧能显著提高开发效率并优化用户体验。
38 0
|
19天前
|
Apache 开发者 Java
Apache Wicket揭秘:如何巧妙利用模型与表单机制,实现Web应用高效开发?
【8月更文挑战第31天】本文深入探讨了Apache Wicket的模型与表单处理机制。Wicket作为一个组件化的Java Web框架,提供了多种模型实现,如CompoundPropertyModel等,充当组件与数据间的桥梁。文章通过示例介绍了模型创建及使用方法,并详细讲解了表单组件、提交处理及验证机制,帮助开发者更好地理解如何利用Wicket构建高效、易维护的Web应用程序。
14 0
|
19天前
|
机器学习/深度学习 人工智能 TensorFlow
深度学习入门:使用Python和TensorFlow构建你的第一个神经网络
【8月更文挑战第31天】 本文是一篇面向初学者的深度学习指南,旨在通过简洁明了的语言引导读者了解并实现他们的第一个神经网络。我们将一起探索深度学习的基本概念,并逐步构建一个能够识别手写数字的简单模型。文章将展示如何使用Python语言和TensorFlow框架来训练我们的网络,并通过直观的例子使抽象的概念具体化。无论你是编程新手还是深度学习领域的新兵,这篇文章都将成为你探索这个激动人心领域的垫脚石。
|
19天前
|
机器学习/深度学习 API TensorFlow
深入解析TensorFlow 2.x中的Keras API:快速搭建深度学习模型的实战指南
【8月更文挑战第31天】本文通过搭建手写数字识别模型的实例,详细介绍了如何利用TensorFlow 2.x中的Keras API简化深度学习模型构建流程。从环境搭建到数据准备,再到模型训练与评估,展示了Keras API的强大功能与易用性,适合初学者快速上手。通过简单的代码,即可完成卷积神经网络的构建与训练,显著降低了深度学习的技术门槛。无论是新手还是专业人士,都能从中受益,高效实现模型开发。
11 0
|
19天前
|
机器学习/深度学习 PyTorch TensorFlow
深度学习框架之争:全面解析TensorFlow与PyTorch在功能、易用性和适用场景上的比较,帮助你选择最适合项目的框架
【8月更文挑战第31天】在深度学习领域,选择合适的框架至关重要。本文通过开发图像识别系统的案例,对比了TensorFlow和PyTorch两大主流框架。TensorFlow由Google开发,功能强大,支持多种设备,适合大型项目和工业部署;PyTorch则由Facebook推出,强调灵活性和速度,尤其适用于研究和快速原型开发。通过具体示例代码展示各自特点,并分析其适用场景,帮助读者根据项目需求和个人偏好做出明智选择。
28 0
|
3月前
|
机器学习/深度学习 TensorFlow API
TensorFlow与Keras实战:构建深度学习模型
本文探讨了TensorFlow和其高级API Keras在深度学习中的应用。TensorFlow是Google开发的高性能开源框架,支持分布式计算,而Keras以其用户友好和模块化设计简化了神经网络构建。通过一个手写数字识别的实战案例,展示了如何使用Keras加载MNIST数据集、构建CNN模型、训练及评估模型,并进行预测。案例详述了数据预处理、模型构建、训练过程和预测新图像的步骤,为读者提供TensorFlow和Keras的基础实践指导。
253 59

热门文章

最新文章