一、TensorFlow 101
TensorFlow 是解决机器学习和深度学习问题的流行库之一。在开发供 Google 内部使用后,它作为开源发布供公众使用和开发。让我们理解 TensorFlow 的三个模型:数据模型,编程模型和执行模型。
TensorFlow 数据模型由张量组成,编程模型由数据流图或计算图组成。 TensorFlow 执行模型包括基于依赖条件从序列中触发节点,从依赖于输入的初始节点开始。
在本章中,我们将回顾构成这三个模型的 TensorFlow 元素,也称为核心 TensorFlow。
我们将在本章中介绍以下主题:
本书的编写注重实际,因此您可以从本书的 GitHub 仓库中克隆代码或从 Packt Publishing 下载它。 您可以使用代码包中包含的 Jupyter 笔记本ch-01_TensorFlow_101
来遵循本章中的代码示例。
根据 TensorFlow 网站:
TensorFlow 是一个使用数据流图进行数值计算的开源库。
最初由谷歌开发用于其内部消费,它于 2015 年 11 月 9 日开源发布。从那时起,TensorFlow 已被广泛用于开发各种领域的机器学习和深度神经网络模型,并继续在谷歌内部用于研究和产品开发。 TensorFlow 1.0 于 2017 年 2 月 15 日发布。让人怀疑这是否是 Google 向机器学习工程师赠送的情人节礼物!
TensorFlow 可以用数据模型,编程模型和执行模型来描述:
要在项目中使用 TensorFlow,您需要学习如何使用 TensorFlow API 进行编程。 TensorFlow 有多个 API,可用于与库交互。 TF API 或库分为两个级别:
TensorFlow 核心是较低级别的库,其上构建了更高级别的 TensorFlow 模块。在深入学习高级 TensorFlow 之前,学习低级库的概念非常重要。在本节中,我们将快速回顾所有这些核心概念。
作为学习任何新编程语言,库或平台的习惯传统,让我们在深入探讨之前,编写简单的 Hello TensorFlow 代码作为热身练习。
我们假设您已经安装了 TensorFlow。 如果还没有,请参阅 TensorFlow 安装指南,了解安装 TensorFlow 的详细说明。
打开 Jupyter 笔记本中的文件ch-01_TensorFlow_101.ipynb
,在学习文本时关注并运行代码。
import tensorflow as tf
Session()
和InteractiveSession()
。我们将使用以下代码创建交互式会话:tfs = tf.InteractiveSession()
Session()
和InteractiveSession()
之间的唯一区别是用InteractiveSession()
创建的会话成为默认会话。因此,我们不需要指定会话上下文以便稍后执行与会话相关的命令。例如,假设我们有一个会话对象tfs
和一个常量对象hello
。如果tfs
是一个InteractiveSession()
对象,那么我们可以使用代码hello.eval()
来求值hello
。如果tfs
是Session()
对象,那么我们必须使用tfs.hello.eval()
或with
块。最常见的做法是使用with
块,这将在本章后面介绍。
hello
:hello = tf.constant("Hello TensorFlow !!")
print(tfs.run(hello))
'Hello TensorFlow !!'
现在您已经使用 TensorFlow 编写并执行了前两行代码,让我们来看看 TensorFlow 的基本组成部分。
张量是 TensorFlow 中计算的基本元素和基本数据结构。可能是您需要学习使用 TensorFlow 的唯一数据结构。张量是由维度,形状和类型标识的 n 维数据集合。
阶数是张量的维数,形状是表示每个维度的大小的列表。张量可以具有任意数量的尺寸。您可能已经熟悉零维集合(标量),一维集合(向量),二维集合(矩阵)的数量,以及多维集合。
标量值是等级 0 的张量,因此具有[1]的形状。向量或一维数组是秩 1 的张量,并且具有列或行的形状。矩阵或二维数组是秩 2 的张量,并且具有行和列的形状。三维数组将是秩 3 的张量,并且以相同的方式,n 维数组将是秩n
的张量。
请参阅以下资源以了解有关张量及其数学基础的更多信息:
张量可以在其所有维度中存储一种类型的数据,并且其元素的数据类型被称为张量的数据类型。
您还可以在这里查看最新版本的 TensorFlow 库中定义的数据类型。
在编写本书时,TensorFlow 定义了以下数据类型:
TensorFlow Python API 数据类型 | 描述 |
---|---|
tf.float16 | 16 位半精度浮点 |
tf.float32 | 32 位单精度浮点 |
tf.float64 | 64 位双精度浮点 |
tf.bfloat16 | 16 位截断浮点 |
tf.complex64 | 64 位单精度复数 |
tf.complex128 | 128 位双精度复数 |
tf.int8 | 8 位有符号整数 |
tf.uint8 | 8 位无符号整数 |
tf.uint16 | 16 位无符号整数 |
tf.int16 | 16 位有符号整数 |
tf.int32 | 32 位有符号整数 |
tf.int64 | 64 位有符号整数 |
tf.bool | 布尔 |
tf.string | 字符串 |
tf.qint8 | 量化的 8 位有符号整数 |
tf.quint8 | 量化的 8 位无符号整数 |
tf.qint16 | 量化的 16 位有符号整数 |
tf.quint16 | 量化的 16 位无符号整数 |
tf.qint32 | 量化的 32 位有符号整数 |
tf.resource | 可变资源 |
我们建议您避免使用 Python 本地数据类型。 使用 TensorFlow 数据类型来定义张量,而不是 Python 本地数据类型。
可以通过以下方式创建张量:
session.run()
。tf.convert_to_tensor()
函数转换 Python 对象,如标量值,列表和 NumPy 数组。让我们来看看创建张量的不同方法。
使用具有以下签名的tf.constant()
函数创建常量值张量:
tf.constant(
value,
dtype=None,
shape=None,
name='Const',
verify_shape=False
)
让我们看看本书中 Jupyter 笔记本中提供的示例代码:
c1=tf.constant(5,name='x')
c2=tf.constant(6.0,name='y')
c3=tf.constant(7.0,tf.float32,name='z')
让我们详细研究一下代码:
c1
,给它值 5,并将其命名为x
。c2
,存储值为 6.0,并将其命名为y
。c1
和c2
的数据类型由 TensorFlow 自动推导出来。dtype
参数或将数据类型作为第二个参数。在前面的代码示例中,我们将tf.float32
的数据类型定义为tf.float32
。让我们打印常量c1
,c2
和c3
:
print('c1 (x): ',c1)
print('c2 (y): ',c2)
print('c3 (z): ',c3)
当我们打印这些常量时,我们得到以下输出:
c1 (x): Tensor("x:0", shape=(), dtype=int32)
c2 (y): Tensor("y:0", shape=(), dtype=float32)
c3 (z): Tensor("z:0", shape=(), dtype=float32)
为了打印这些常量的值,我们必须使用tfs.run()
命令在 TensorFlow 会话中执行它们:
print('run([c1,c2,c3]) : ',tfs.run([c1,c2,c3]))
我们看到以下输出:
run([c1,c2,c3]) : [5, 6.0, 7.0]
TensorFlow 为我们提供了许多可以应用于张量的操作。通过传递值并将输出分配给另一个张量来定义操作。例如,在提供的 Jupyter 笔记本文件中,我们定义了两个操作,op1
和op2
:
op1 = tf.add(c2,c3)
op2 = tf.multiply(c2,c3)
当我们打印op1
和op2
时,我们发现它们被定义为张量:
print('op1 : ', op1)
print('op2 : ', op2)
输出如下:
op1 : Tensor("Add:0", shape=(), dtype=float32)
op2 : Tensor("Mul:0", shape=(), dtype=float32)
要打印这些操作的值,我们必须在 TensorFlow 会话中运行它们:
print('run(op1) : ', tfs.run(op1))
print('run(op2) : ', tfs.run(op2))
输出如下:
run(op1) : 13.0
run(op2) : 42.0
下表列出了一些内置操作:
操作类型 | 操作 |
---|---|
算术运算 | tf.add,tf.subtract,tf.multiply,tf.scalar_mul,tf.div,tf.divide,tf.truediv,tf.floordiv,tf.realdiv,tf.truncatediv,tf.floor_div,tf.truncatemod,tf.floormod,tf.mod,tf.cross |
基本的数学运算 | tf.add_n,tf.abs,tf.negative,tf.sign,tf.reciprocal,tf.square,tf.round,tf.sqrt,tf.rsqrt,tf.pow,tf.exp,tf.expm1,tf.log,tf.log1p,tf.ceil,tf.floor,tf.maximum,tf.minimum,tf.cos,tf.sin,tf.lbeta,tf.tan,tf.acos,tf.asin,tf.atan,tf.lgamma,tf.digamma,tf.erf,tf.erfc,tf.igamma,tf.squared_difference,tf.igammac,tf.zeta,tf.polygamma,tf.betainc,tf.rint |
矩阵数学运算 | tf.diag,tf.diag_part,tf.trace,tf.transpose,tf.eye,tf.matrix_diag,tf.matrix_diag_part,tf.matrix_band_part,tf.matrix_set_diag,tf.matrix_transpose,tf.matmul,tf.norm,tf.matrix_determinant ],tf.matrix_inverse,tf.cholesky,tf.cholesky_solve,tf.matrix_solve,tf.matrix_triangular_solve,tf.matrix_solve_ls,tf.qr, tf.self_adjoint_eig,tf.self_adjoint_eigvals,tf.svd |
张量数学运算 | tf.tensordot |
复数运算 | tf.complex,tf.conj,tf.imag,tf.real |
字符串操作 | tf.string_to_hash_bucket_fast,tf.string_to_hash_bucket_strong,tf.as_string,tf.encode_base64,tf.decode_base64,tf.reduce_join,tf.string_join,tf.string_split,tf.substr,tf.string_to_hash_bucket |
虽然常量允许我们在定义张量时提供值,但占位符允许我们创建可在运行时提供其值的张量。 TensorFlow 为tf.placeholder()
函数提供以下签名以创建占位符:
tf.placeholder(
dtype,
shape=None,
name=None
)
例如,让我们创建两个占位符并打印它们:
p1 = tf.placeholder(tf.float32)
p2 = tf.placeholder(tf.float32)
print('p1 : ', p1)
print('p2 : ', p2)
我们看到以下输出:
p1 : Tensor("Placeholder:0", dtype=float32)
p2 : Tensor("Placeholder_1:0", dtype=float32)
现在让我们使用这些占位符定义一个操作:
op4 = p1 * p2
TensorFlow 允许使用速记符号进行各种操作。在前面的例子中,p1 * p2
是tf.multiply(p1,p2)
的简写:
print('run(op4,{p1:2.0, p2:3.0}) : ',tfs.run(op4,{p1:2.0, p2:3.0}))
上面的命令在 TensorFlow 会话中运行op4
,为p1
和p2
的值提供 Python 字典(run()
操作的第二个参数)。
输出如下:
run(op4,{p1:2.0, p2:3.0}) : 6.0
我们还可以使用run()
操作中的feed_dict
参数指定字典:
print('run(op4,feed_dict = {p1:3.0, p2:4.0}) : ',
tfs.run(op4, feed_dict={p1: 3.0, p2: 4.0}))
输出如下:
run(op4,feed_dict = {p1:3.0, p2:4.0}) : 12.0
让我们看一下最后一个例子,向量被送到同一个操作:
print('run(op4,feed_dict = {p1:[2.0,3.0,4.0], p2:[3.0,4.0,5.0]}) : ',
tfs.run(op4,feed_dict = {p1:[2.0,3.0,4.0], p2:[3.0,4.0,5.0]}))
输出如下:
run(op4,feed_dict={p1:[2.0,3.0,4.0],p2:[3.0,4.0,5.0]}):[ 6\. 12\. 20.]
两个输入向量的元素以元素方式相乘。
我们可以使用带有以下签名的tf.convert_to_tensor()
操作从 Python 对象(如列表和 NumPy 数组)创建张量:
tf.convert_to_tensor(
value,
dtype=None,
name=None,
preferred_dtype=None
)
让我们创建一些张量并打印出来进行练习:
tf_t=tf.convert_to_tensor(5.0,dtype=tf.float64)
print('tf_t : ',tf_t)
print('run(tf_t) : ',tfs.run(tf_t))
输出如下:
tf_t : Tensor("Const_1:0", shape=(), dtype=float64)
run(tf_t) : 5.0
a1dim = np.array([1,2,3,4,5.99])
print("a1dim Shape : ",a1dim.shape)
tf_t=tf.convert_to_tensor(a1dim,dtype=tf.float64)
print('tf_t : ',tf_t)
print('tf_t[0] : ',tf_t[0])
print('tf_t[0] : ',tf_t[2])
print('run(tf_t) : \n',tfs.run(tf_t))
输出如下:
a1dim Shape : (5,)
tf_t : Tensor("Const_2:0", shape=(5,), dtype=float64)
tf_t[0] : Tensor("strided_slice:0", shape=(), dtype=float64)
tf_t[0] : Tensor("strided_slice_1:0", shape=(), dtype=float64)
run(tf_t) :
[ 1\. 2\. 3\. 4\. 5.99]
a2dim = np.array([(1,2,3,4,5.99),
(2,3,4,5,6.99),
(3,4,5,6,7.99)
])
print("a2dim Shape : ",a2dim.shape)
tf_t=tf.convert_to_tensor(a2dim,dtype=tf.float64)
print('tf_t : ',tf_t)
print('tf_t[0][0] : ',tf_t[0][0])
print('tf_t[1][2] : ',tf_t[1][2])
print('run(tf_t) : \n',tfs.run(tf_t))
输出如下:
a2dim Shape : (3, 5)
tf_t : Tensor("Const_3:0", shape=(3, 5), dtype=float64)
tf_t[0][0] : Tensor("strided_slice_3:0", shape=(), dtype=float64)
tf_t[1][2] : Tensor("strided_slice_5:0", shape=(), dtype=float64)
run(tf_t) :
[[ 1\. 2\. 3\. 4\. 5.99]
[ 2\. 3\. 4\. 5\. 6.99]
[ 3\. 4\. 5\. 6\. 7.99]]
a3dim = np.array([[[1,2],[3,4]],
[[5,6],[7,8]]
])
print("a3dim Shape : ",a3dim.shape)
tf_t=tf.convert_to_tensor(a3dim,dtype=tf.float64)
print('tf_t : ',tf_t)
print('tf_t[0][0][0] : ',tf_t[0][0][0])
print('tf_t[1][1][1] : ',tf_t[1][1][1])
print('run(tf_t) : \n',tfs.run(tf_t))
输出如下:
a3dim Shape : (2, 2, 2)
tf_t : Tensor("Const_4:0", shape=(2, 2, 2), dtype=float64)
tf_t[0][0][0] : Tensor("strided_slice_8:0", shape=(), dtype=float64)
tf_t[1][1][1] : Tensor("strided_slice_11:0", shape=(), dtype=float64)
run(tf_t) :
[[[ 1\. 2.][ 3\. 4.]]
[[ 5\. 6.][ 7\. 8.]]]
TensorFlow 可以将 NumPy ndarray
无缝转换为 TensorFlow 张量,反之亦然。
到目前为止,我们已经看到了如何创建各种张量对象:常量,操作和占位符。在使用 TensorFlow 构建和训练模型时,通常需要将参数值保存在可在运行时更新的内存位置。该内存位置由 TensorFlow 中的变量标识。
在 TensorFlow 中,变量是张量对象,它们包含可在程序执行期间修改的值。
虽然tf.Variable
看起来与tf.placeholder
类似,但两者之间存在细微差别:
tf.placeholder | tf.Variable |
---|---|
tf.placeholder定义了不随时间变化的输入数据 | tf.Variable定义随时间修改的变量值 |
tf.placeholder在定义时不需要初始值 | tf.Variable在定义时需要初始值 |
在 TensorFlow 中,可以使用tf.Variable()
创建变量。让我们看一个带有线性模型的占位符和变量的示例:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vIVy2mAR-1681566326302)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/mastering-tf-1x-zh/img/e7e3cb1f-7f3a-4ff6-9902-2295abdd0822.png)]
w
和b
分别定义为具有[.3]
和[-0.3]
初始值的变量:w = tf.Variable([.3], tf.float32)
b = tf.Variable([-.3], tf.float32)
x
定义为占位符,输出y
定义为操作:x = tf.placeholder(tf.float32)
y = w * x + b
w
,v
,x
和y
,看看我们得到了什么:print("w:",w)
print("x:",x)
print("b:",b)
print("y:",y)
我们得到以下输出:
w: <tf.Variable 'Variable:0' shape=(1,) dtype=float32_ref>
x: Tensor("Placeholder_2:0", dtype=float32)
b: <tf.Variable 'Variable_1:0' shape=(1,) dtype=float32_ref>
y: Tensor("add:0", dtype=float32)
输出显示x
是占位符张量,y
是操作张量,而w
和b
是形状(1,)
和数据类型float32
的变量。
在 TensorFlow 会话中使用变量之前,必须先初始化它们。您可以通过运行其初始化程序操作来初始化单个变量。
例如,让我们初始化变量w
:
tfs.run(w.initializer)
但是,在实践中,我们使用 TensorFlow 提供的便利函数来初始化所有变量:
tfs.run(tf.global_variables_initializer())
您还可以使用tf.variables_initializer()
函数来初始化一组变量。
也可以通过以下方式调用全局初始化程序便利函数,而不是在会话对象的run()
函数内调用:
tf.global_variables_initializer().run()
在初始化变量之后,让我们运行我们的模型来给出x = [1,2,3,4]
的值的输出:
print('run(y,{x:[1,2,3,4]}) : ',tfs.run(y,{x:[1,2,3,4]}))
我们得到以下输出:
run(y,{x:[1,2,3,4]}) : [ 0\. 0.30000001 0.60000002 0.90000004]
张量也可以从各种 TensorFlow 函数生成。这些生成的张量可以分配给常量或变量,也可以在初始化时提供给它们的构造器。
例如,以下代码生成 100 个零的向量并将其打印出来:
a=tf.zeros((100,))
print(tfs.run(a))
TensorFlow 提供了不同类型的函数来在定义时填充张量:
下表列出了一些张量生成库函数,用于使用相同的值填充张量的所有元素:
zeros(
shape,
dtype=tf.float32,
name=None
)
创建所提供形状的张量,所有元素都设置为零
zeros_like(
tensor,
dtype=None,
name=None,
optimize=True
)
创建与参数形状相同的张量,所有元素都设置为零
ones(
shape,
dtype=tf.float32,
name=None
)
创建所提供形状的张量,所有元素都设置为 1
ones_like(
tensor,
dtype=None,
name=None,
optimize=True
)
创建与参数形状相同的张量,所有元素都设置为 1
fill(
dims,
value,
name=None
)
创建一个形状的张量作为dims
参数,,所有元素都设置为value
;例如,a = tf.fill([100],0)
下表列出了一些张量生成函数,用于使用序列填充张量元素:
lin_space(
start,
stop,
num,
name=None
)
从[start, stop]
范围内的num
序列生成 1D 张量。张量与start
参数具有相同的数据类型。例如,a = tf.lin_space(1,100,10)
生成值为[1,12,23,34,45,56,67,78,89,100]
的张量。
range(
limit,
delta=1,
dtype=None,
name='range'
)
range(
start,
limit,
delta=1,
dtype=None,
name='range'
)
从[start, limit]
范围内的数字序列生成 1D 张量,增量为delta
。如果未指定dtype
参数,则张量具有与start
参数相同的数据类型。 此函数有两个版本。在第二个版本中,如果省略start
参数,则start
变为数字 0。例如,a = tf.range(1,91,10)
生成具有值[1,11,21,31,41,51,61,71,81]
的张量。请注意,limit
参数的值(即 91)不包含在最终生成的序列中。
TensorFlow 为我们提供了生成填充随机值分布的张量的函数。
生成的分布受图级别或操作级别种子的影响。使用tf.set_random_seed
设置图级种子,而在所有随机分布函数中给出操作级种子作为参数seed
。如果未指定种子,则使用随机种子。
有关 TensorFlow 中随机种子的更多详细信息,请访问此链接。
下表列出了一些张量生成函数,用于使用随机值分布填充张量元素:
random_normal(
shape,
mean=0.0,
stddev=1.0,
dtype=tf.float32,
seed=None,
name=None
)
生成指定形状的张量,填充正态分布的值:normal(mean, stddev)
。
truncated_normal(
shape,
mean=0.0,
stddev=1.0,
dtype=tf.float32,
seed=None,
name=None
)
生成指定形状的张量,填充来自截断的正态分布的值:normal(mean, stddev)
。截断意味着返回的值始终与平均值的距离小于两个标准偏差。
random_uniform(
shape,
minval=0,
maxval=None,
dtype=tf.float32,
seed=None,
name=None
)
生成指定形状的张量,填充均匀分布的值:uniform([minval, maxval))
。
random_gamma(
shape,
alpha,
beta=None,
dtype=tf.float32,
seed=None,
name=None
)
生成指定形状的张量,填充来自伽马分布的值:gamma(alpha,beta)
。有关random_gamma
函数的更多详细信息,请访问此链接。
tf.get_variable()
获取变量如果使用之前定义的名称定义变量,则 TensorFlow 会抛出异常。因此,使用tf.get_variable()
函数代替tf.Variable()
很方便。函数tf.get_variable()
返回具有相同名称的现有变量(如果存在),并创建具有指定形状的变量和初始化器(如果它不存在)。例如:
w = tf.get_variable(name='w',shape=[1],dtype=tf.float32,initializer=[.3])
b = tf.get_variable(name='b',shape=[1],dtype=tf.float32,initializer=[-.3])
初始化程序可以是上面示例中显示的张量或值列表,也可以是内置初始化程序之一:
tf.constant_initializer
tf.random_normal_initializer
tf.truncated_normal_initializer
tf.random_uniform_initializer
tf.uniform_unit_scaling_initializer
tf.zeros_initializer
tf.ones_initializer
tf.orthogonal_initializer
在分布式 TensorFlow 中,我们可以跨机器运行代码,tf.get_variable()
为我们提供了全局变量。要获取局部变量,TensorFlow 具有类似签名的函数:tf.get_local_variable()
。
共享或重用变量:获取已定义的变量可促进重用。但是,如果未使用tf.variable_scope.reuse_variable()
或tf.variable.scope(reuse=True)
设置重用标志,则会抛出异常。
现在您已经学会了如何定义张量,常量,运算,占位符和变量,让我们了解 TensorFlow 中的下一级抽象,它将这些基本元素组合在一起形成一个基本的计算单元,即数据流图或计算图。
数据流图或计算图是 TensorFlow 中的基本计算单元。从现在开始,我们将它们称为计算图。计算图由节点和边组成。每个节点代表一个操作(tf.Operation
),每个边代表一个在节点之间传递的张量(tf.Tensor
)。
TensorFlow 中的程序基本上是计算图。您可以使用表示变量,常量,占位符和操作的节点创建图,并将其提供给 TensorFlow。 TensorFlow 找到它可以触发或执行的第一个节点。触发这些节点会导致其他节点触发,依此类推。
因此,TensorFlow 程序由计算图上的两种操作组成:
TensorFlow 附带一个默认图。除非明确指定了另一个图,否则会将新节点隐式添加到默认图中。我们可以使用以下命令显式访问默认图:
graph = tf.get_default_graph()
例如,如果我们想要定义三个输入并添加它们以产生输出y = x1 + x2 + x3
,我们可以使用以下计算图来表示它:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pPtSdvP4-1681566326303)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/mastering-tf-1x-zh/img/09c14036-55e8-48e6-b22b-f126211aae0c.png)]
在 TensorFlow 中,前一图像中的添加操作将对应于代码y = tf.add( x1 + x2 + x3 )
。
在我们创建变量,常量和占位符时,它们会添加到图中。然后我们创建一个会话对象,以执行操作对象,求值张量对象。
让我们构建并执行一个计算图来计算y = w × x + b
,正如我们在前面的例子中已经看到的那样:
# Assume Linear Model y = w * x + b
# Define model parameters
w = tf.Variable([.3], tf.float32)
b = tf.Variable([-.3], tf.float32)
# Define model input and output
x = tf.placeholder(tf.float32)
y = w * x + b
output = 0
with tf.Session() as tfs:
# initialize and print the variable y
tf.global_variables_initializer().run()
output = tfs.run(y,{x:[1,2,3,4]})
print('output : ',output)
在with
块中创建和使用会话可确保在块完成时会话自动关闭。否则,必须使用tfs.close()
命令显式关闭会话,其中tfs
是会话名称。
节点按依赖顺序执行。如果节点a
依赖于节点b
,则a
将在执行b
之前执行请求b
。除非未请求执行节点本身或取决于它的其他节点,否则不执行节点。这也称为延迟加载;即,在需要之前不创建和初始化节点对象。
有时,您可能希望控制在图中执行节点的顺序。这可以通过tf.Graph.control_dependencies()
函数实现。 例如,如果图具有节点a, b, c
和d
并且您想在a
和b
之前执行c
和d
,请使用以下语句:
with graph_variable.control_dependencies([c,d]):
# other statements here
这确保了在执行了节点c
和d
之后,才执行前面with
块中的任何节点。
图可以分为多个部分,每个部分可以放置在不同的设备上执行,例如 CPU 或 GPU。您可以使用以下命令列出可用于执行图的所有设备:
from tensorflow.python.client import device_lib
print(device_lib.list_local_devices())
我们得到以下输出(您的输出会有所不同,具体取决于系统中的计算设备):
[name: "/device:CPU:0"
device_type: "CPU"
memory_limit: 268435456
locality {
}
incarnation: 12900903776306102093
, name: "/device:GPU:0"
device_type: "GPU"
memory_limit: 611319808
locality {
bus_id: 1
}
incarnation: 2202031001192109390
physical_device_desc: "device: 0, name: Quadro P5000, pci bus id: 0000:01:00.0, compute capability: 6.1"
]
TensorFlow 中的设备用字符串/device:<device_type>:<device_idx>
标识。在上述输出中,CPU
和GPU
表示器件类型,0
表示器件索引。
关于上述输出需要注意的一点是它只显示一个 CPU,而我们的计算机有 8 个 CPU。原因是 TensorFlow 隐式地在 CPU 单元中分配代码,因此默认情况下CPU:0
表示 TensorFlow 可用的所有 CPU。当 TensorFlow 开始执行图时,它在一个单独的线程中运行每个图中的独立路径,每个线程在一个单独的 CPU 上运行。我们可以通过改变inter_op_parallelism_threads
的数量来限制用于此目的的线程数。类似地,如果在独立路径中,操作能够在多个线程上运行,TensorFlow 将在多个线程上启动该特定操作。可以通过设置intra_op_parallelism_threads
的数量来更改此池中的线程数。
让我们通过定义配置对象来启用变量放置的记录,将log_device_placement
属性设置为true
,然后将此config
对象传递给会话,如下所示:
tf.reset_default_graph()
# Define model parameters
w = tf.Variable([.3], tf.float32)
b = tf.Variable([-.3], tf.float32)
# Define model input and output
x = tf.placeholder(tf.float32)
y = w * x + b
config = tf.ConfigProto()
config.log_device_placement=True
with tf.Session(config=config) as tfs:
# initialize and print the variable y
tfs.run(global_variables_initializer())
print('output',tfs.run(y,{x:[1,2,3,4]}))
我们在 Jupyter 笔记本控制台中获得以下输出:
b: (VariableV2): /job:localhost/replica:0/task:0/device:GPU:0
b/read: (Identity): /job:localhost/replica:0/task:0/device:GPU:0
b/Assign: (Assign): /job:localhost/replica:0/task:0/device:GPU:0
w: (VariableV2): /job:localhost/replica:0/task:0/device:GPU:0
w/read: (Identity): /job:localhost/replica:0/task:0/device:GPU:0
mul: (Mul): /job:localhost/replica:0/task:0/device:GPU:0
add: (Add): /job:localhost/replica:0/task:0/device:GPU:0
w/Assign: (Assign): /job:localhost/replica:0/task:0/device:GPU:0
init: (NoOp): /job:localhost/replica:0/task:0/device:GPU:0
x: (Placeholder): /job:localhost/replica:0/task:0/device:GPU:0
b/initial_value: (Const): /job:localhost/replica:0/task:0/device:GPU:0
Const_1: (Const): /job:localhost/replica:0/task:0/device:GPU:0
w/initial_value: (Const): /job:localhost/replica:0/task:0/device:GPU:0
Const: (Const): /job:localhost/replica:0/task:0/device:GPU:0
因此,默认情况下,TensorFlow 会在设备上创建变量和操作节点,从而获得最高表现。 可以使用tf.device()
函数将变量和操作放在特定设备上。让我们把图放在 CPU 上:
tf.reset_default_graph()
with tf.device('/device:CPU:0'):
# Define model parameters
w = tf.get_variable(name='w',initializer=[.3], dtype=tf.float32)
b = tf.get_variable(name='b',initializer=[-.3], dtype=tf.float32)
# Define model input and output
x = tf.placeholder(name='x',dtype=tf.float32)
y = w * x + b
config = tf.ConfigProto()
config.log_device_placement=True
with tf.Session(config=config) as tfs:
# initialize and print the variable y
tfs.run(tf.global_variables_initializer())
print('output',tfs.run(y,{x:[1,2,3,4]}))
在 Jupyter 控制台中,我们看到现在变量已经放在 CPU 上,并且执行也发生在 CPU 上:
b: (VariableV2): /job:localhost/replica:0/task:0/device:CPU:0
b/read: (Identity): /job:localhost/replica:0/task:0/device:CPU:0
b/Assign: (Assign): /job:localhost/replica:0/task:0/device:CPU:0
w: (VariableV2): /job:localhost/replica:0/task:0/device:CPU:0
w/read: (Identity): /job:localhost/replica:0/task:0/device:CPU:0
mul: (Mul): /job:localhost/replica:0/task:0/device:CPU:0
add: (Add): /job:localhost/replica:0/task:0/device:CPU:0
w/Assign: (Assign): /job:localhost/replica:0/task:0/device:CPU:0
init: (NoOp): /job:localhost/replica:0/task:0/device:CPU:0
x: (Placeholder): /job:localhost/replica:0/task:0/device:CPU:0
b/initial_value: (Const): /job:localhost/replica:0/task:0/device:CPU:0
Const_1: (Const): /job:localhost/replica:0/task:0/device:CPU:0
w/initial_value: (Const): /job:localhost/replica:0/task:0/device:CPU:0
Const: (Const): /job:localhost/replica:0/task:0/device:CPU:0
TensorFlow 遵循这些简单的规则,也称为简单放置,用于将变量放在设备上:
If the graph was previously run,
then the node is left on the device where it was placed earlier
Else If the tf.device() block is used,
then the node is placed on the specified device
Else If the GPU is present
then the node is placed on the first available GPU
Else If the GPU is not present
then the node is placed on the CPU
tf.device()
也可以传递函数名而不是设备字符串。在这种情况下,该函数必须返回设备字符串。此函数允许使用复杂的算法将变量放在不同的设备上。例如,TensorFlow 在tf.train.replica_device_setter()
中提供循环设备设置器,我们将在下一节中讨论。
当您在 GPU 上放置 TensorFlow 操作时,TF 必须具有该操作的 GPU 实现,称为内核。如果内核不存在,则放置会导致运行时错误。此外,如果您请求的 GPU 设备不存在,您将收到运行时错误。处理此类错误的最佳方法是,如果请求 GPU 设备导致错误,则允许将操作置于 CPU 上。这可以通过设置以下config
值来实现:
config.allow_soft_placement = True
当您开始运行 TensorFlow 会话时,默认情况下它会抓取所有 GPU 内存,即使您将操作和变量仅放置在多 GPU 系统中的一个 GPU 上也是如此。如果您尝试同时运行另一个会话,则会出现内存不足错误。这可以通过多种方式解决:
CUDA_VISIBLE_DEVICES=<list of device idx>
os.environ['CUDA_VISIBLE_DEVICES']='0'
在此设置之后执行的代码将能够获取仅可见 GPU 的所有内存。
per_process_gpu_memory_fraction
来分配一定百分比的内存:config.gpu_options.per_process_gpu_memory_fraction = 0.5
这将分配所有 GPU 设备的 50% 的内存。
config.gpu_options.allow_growth = True
此选项仅允许分配的内存增长,但内存永远不会释放。
您将学习在后面的章节中跨多个计算设备和多个节点分配计算的技术。
您可以创建与默认图分开的图,并在会话中执行它们。但是,不建议创建和执行多个图,因为它具有以下缺点:
因此,推荐的方法是在单个图中包含多个子图。如果您希望使用自己的图而不是默认图,可以使用tf.graph()
命令执行此操作。下面是我们创建自己的图g
并将其作为默认图执行的示例:
g = tf.Graph()
output = 0
# Assume Linear Model y = w * x + b
with g.as_default():
# Define model parameters
w = tf.Variable([.3], tf.float32)
b = tf.Variable([-.3], tf.float32)
# Define model input and output
x = tf.placeholder(tf.float32)
y = w * x + b
with tf.Session(graph=g) as tfs:
# initialize and print the variable y
tf.global_variables_initializer().run()
output = tfs.run(y,{x:[1,2,3,4]})
print('output : ',output)
即使对于中等大小的问题,计算图的复杂性也很高。代表复杂机器学习模型的大型计算图可能变得非常混乱且难以理解。可视化有助于轻松理解和解释计算图,从而加速 TensorFlow 程序的调试和优化。 TensorFlow 附带了一个内置工具,可以让我们可视化计算图,即 TensorBoard。
TensorBoard 可视化计算图结构,提供统计分析并绘制在计算图执行期间作为摘要捕获的值。让我们看看它在实践中是如何运作的。
# Assume Linear Model y = w * x + b
# Define model parameters
w = tf.Variable([.3], name='w',dtype=tf.float32)
b = tf.Variable([-.3], name='b', dtype=tf.float32)
# Define model input and output
x = tf.placeholder(name='x',dtype=tf.float32)
y = w * x + b
tf.summary.FileWriter
将使用默认图中的事件在tflogs
文件夹中创建输出y
的值,有效地执行我们的线性模型with tf.Session() as tfs:
tfs.run(tf.global_variables_initializer())
writer=tf.summary.FileWriter('tflogs',tfs.graph)
print('run(y,{x:3}) : ', tfs.run(y,feed_dict={x:3}))
run(y,{x:3}) : [ 0.60000002]
当程序执行时,日志将收集在tflogs
文件夹中,TensorBoard 将使用该文件夹进行可视化。打开命令行界面,导航到运行ch-01_TensorFlow_101
笔记本的文件夹,然后执行以下命令:
tensorboard --logdir='tflogs'
您会看到类似于此的输出:
Starting TensorBoard b'47' at http://0.0.0.0:6006
打开浏览器并导航到http://0.0.0.0:6006
。看到 TensorBoard 仪表板后,不要担心显示任何错误或警告,只需单击顶部的 GRAPHS 选项卡即可。您将看到以下屏幕:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jjkEvBCb-1681566326304)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/mastering-tf-1x-zh/img/0651fc7c-9a4d-42c3-98e0-efc991572877.png)]TensorBoard console
您可以看到 TensorBoard 将我们的第一个简单模型可视化为计算图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VG0Ejbi3-1681566326304)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/mastering-tf-1x-zh/img/02f0f1ee-75f1-4da4-bd65-9fd36e21f3b7.png)]Computation graph in TensorBoard
现在让我们试着了解 TensorBoard 的详细工作原理。
TensorBoard 通过读取 TensorFlow 生成的日志文件来工作。因此,我们需要修改此处定义的编程模型,以包含其他操作节点,这些操作节点将在我们想要使用 TensorBoard 可视化的日志中生成信息。编程模型或使用 TensorBoard 的程序流程通常可以说如下:
tf.summary
包中的摘要操作附加到输出您要收集和分析的值的节点。
tf.summary.merge_all()
将所有汇总节点合并到一个汇总节点中。然后执行此合并节点将基本上执行所有摘要节点。合并的摘要节点生成包含所有摘要的并集的序列化Summary
ProtocolBuffers 对象。
Summary
ProtocolBuffers 对象传递给tf.summary.FileWriter
对象将事件日志写入磁盘。
在本节中,我们没有创建汇总节点,而是以非常简单的方式使用 TensorBoard。我们将在本书后面介绍 TensorBoard 的高级用法。
在本章中,我们快速回顾了 TensorFlow 库。我们了解了可用于构建 TensorFlow 计算图的 TensorFlow 数据模型元素,例如常量,变量和占位符。我们学习了如何从 Python 对象创建 Tensors。张量对象也可以作为特定值,序列或来自 TensorFlow 中可用的各种库函数的随机值分布生成。
TensorFlow 编程模型包括构建和执行计算图。计算图具有节点和边。节点表示操作,边表示将数据从一个节点传输到另一个节点的张量。我们介绍了如何创建和执行图,执行顺序以及如何在不同的计算设备(如 GPU 和 CPU)上执行图。我们还学习了可视化 TensorFlow 计算图 TensorBoard 的工具。
在下一章中,我们将探索构建在 TensorFlow 之上的一些高级库,并允许我们快速构建模型。
TensorFlow 有几个高级库和接口(API),允许我们使用 TFLearn,TFSlim,Sonnet,PrettyTensor,Keras 和最近发布的 TensorFlow Estimators 轻松构建和训练模型。
我们将在本章中介绍以下高级库,同时将下一章专门用于 Keras:
我们将提供使用所有五个库构建 MNIST 数据集模型的示例。当我们从第 4 章开始介绍模型的细节时,不要担心理解模型的细节。
您可以使用代码包中包含的 Jupyter 笔记本ch-02_TF_High_Level_Libraries
来遵循本章中的代码示例。 尝试修改笔记本中的示例以进行实验和游戏。
TFEstimator 是一个高级 API,通过封装训练,评估,预测和导出函数,可以轻松创建和训练模型。 TensorFlow 最近重新命名并在 TensorFlow 中以新名称 TFEstimator 发布了 TFLearn 包,可能是为了避免与 tflearn.org 的 TFLearn 包混淆。 TFEstimator API 对原始 TF 学习包进行了重大改进,这些包在 KDD 17 会议上提供的研究论文中有所描述,可以在此链接中找到。
TFEstimator 接口设计灵感来自流行的机器学习库 SciKit Learn,允许从不同类型的可用模型创建估计器对象,然后在任何类型的估计器上提供四个主要函数:
estimator.fit()
estimator.evaluate()
estimator.predict()
estimator.export()
函数的名称是不言自明的。估计器对象表示模型,但模型本身是从提供给估计器的模型定义函数创建的。
我们可以在下图中描述估计器对象及其接口:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bokRyUJ9-1681566326305)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/mastering-tf-1x-zh/img/f96f0dc6-5093-419b-8c1c-1b0eb1cf388a.png)]
使用 Estimator API 而不是在核心 TensorFlow 中构建所有内容,可以不用担心图,会话,初始化变量或其他低级细节。在撰写本书时,TensorFlow 提供了以下预构建的估计器:
tf.contrib.learn.KMeansClustering
tf.contrib.learn.DNNClassifier
tf.contrib.learn.DNNRegressor
tf.contrib.learn.DNNLinearCombinedRegressor
tf.contrib.learn.DNNLinearCombinedClassifier
tf.contrib.learn.LinearClassifier
tf.contrib.learn.LinearRegressor
tf.contrib.learn.LogisticRegressor
TFEstimator API 中的简单工作流程如下:
下一章讨论的 Keras 库提供了将 Keras 模型转换为 Estimators 的便捷函数:keras.estimator.model_to_estimator()
。
笔记本ch-02_TF_High_Level_Libraries
中提供了 MNIST 分类示例的完整代码。 TFEstimator MNIST 示例的输出如下:
INFO:tensorflow:Using default config.
WARNING:tensorflow:Using temporary folder as model directory: /tmp/tmprvcqgu07
INFO:tensorflow:Using config: {'_save_checkpoints_steps': None, '_task_type': 'worker', '_save_checkpoints_secs': 600, '_service': None, '_task_id': 0, '_master': '', '_session_config': None, '_num_worker_replicas': 1, '_keep_checkpoint_max': 5, '_cluster_spec': <tensorflow.python.training.server_lib.ClusterSpec object at 0x7ff9d15f5fd0>, '_keep_checkpoint_every_n_hours': 10000, '_log_step_count_steps': 100, '_is_chief': True, '_save_summary_steps': 100, '_model_dir': '/tmp/tmprvcqgu07', '_num_ps_replicas': 0, '_tf_random_seed': None}
INFO:tensorflow:Create CheckpointSaverHook.
INFO:tensorflow:Saving checkpoints for 1 into /tmp/tmprvcqgu07/model.ckpt.
INFO:tensorflow:loss = 2.4365, step = 1
INFO:tensorflow:global_step/sec: 597.996
INFO:tensorflow:loss = 1.47152, step = 101 (0.168 sec)
INFO:tensorflow:global_step/sec: 553.29
INFO:tensorflow:loss = 0.728581, step = 201 (0.182 sec)
INFO:tensorflow:global_step/sec: 519.498
INFO:tensorflow:loss = 0.89795, step = 301 (0.193 sec)
INFO:tensorflow:global_step/sec: 503.414
INFO:tensorflow:loss = 0.743328, step = 401 (0.202 sec)
INFO:tensorflow:global_step/sec: 539.251
INFO:tensorflow:loss = 0.413222, step = 501 (0.181 sec)
INFO:tensorflow:global_step/sec: 572.327
INFO:tensorflow:loss = 0.416304, step = 601 (0.174 sec)
INFO:tensorflow:global_step/sec: 543.99
INFO:tensorflow:loss = 0.459793, step = 701 (0.184 sec)
INFO:tensorflow:global_step/sec: 687.748
INFO:tensorflow:loss = 0.501756, step = 801 (0.146 sec)
INFO:tensorflow:global_step/sec: 654.217
INFO:tensorflow:loss = 0.666772, step = 901 (0.153 sec)
INFO:tensorflow:Saving checkpoints for 1000 into /tmp/tmprvcqgu07/model.ckpt.
INFO:tensorflow:Loss for final step: 0.426257.
INFO:tensorflow:Starting evaluation at 2017-12-15-02:27:45
INFO:tensorflow:Restoring parameters from /tmp/tmprvcqgu07/model.ckpt-1000
INFO:tensorflow:Finished evaluation at 2017-12-15-02:27:45
INFO:tensorflow:Saving dict for global step 1000: accuracy = 0.8856, global_step = 1000, loss = 0.40996
{'accuracy': 0.88559997, 'global_step': 1000, 'loss': 0.40995964}
您将在第 5 章中看到如何使用核心 TensorFlow 创建此类模型。
TFSlim 是一个基于 TensorFlow 核心构建的轻量级库,用于定义和训练模型。 TFSlim 可与其他 TensorFlow 低级和高级库(如 TFLearn)结合使用。 TFSlim 是包装中 TensorFlow 安装的一部分:tf.contrib.slim
。运行以下命令以检查 TFSlim 安装是否正常工作:
python3 -c 'import tensorflow.contrib.slim as slim; eval = slim.evaluation.evaluate_once'
TFSlim 提供了几个模块,可以独立挑选和应用,并与其他 TensorFlow 包混合使用。例如,在撰写本书时,TFSlim 有以下主要模块:
TFSlim 模块 | 模块说明 |
---|---|
arg_scope | 提供将元素应用于作用域下定义的所有图节点的机制。 |
layer | 提供几种不同的层,如fully_connected,conv2d等等。 |
loss | 提供用于训练优化器的损失函数 |
learn | 提供训练模型的函数 |
evaluate | 提供评估函数 |
metics | 提供用于评估模型的度量函数 |
regularizers | 提供用于创建正则化方法的函数 |
variable | 提供变量创建的函数 |
net | 提供各种预制和预训练模型,如 VGG16,InceptionV3,ResNet |
TFSlim 的简单工作流程如下:
get_total_loss()
获得全部损失。slim.learning.create_train_op()
,total_loss
和optimizer
创建训练函数。slim.learning.train()
和训练函数运行训练。笔记本ch-02_TF_High_Level_Libraries
中提供了 MNIST 分类示例的完整代码。 TFSlim MNIST 示例的输出如下:
INFO:tensorflow:Starting Session.
INFO:tensorflow:Saving checkpoint to path ./slim_logs/model.ckpt
INFO:tensorflow:global_step/sec: 0
INFO:tensorflow:Starting Queues.
INFO:tensorflow:global step 100: loss = 2.2669 (0.010 sec/step)
INFO:tensorflow:global step 200: loss = 2.2025 (0.010 sec/step)
INFO:tensorflow:global step 300: loss = 2.1257 (0.010 sec/step)
INFO:tensorflow:global step 400: loss = 2.0419 (0.009 sec/step)
INFO:tensorflow:global step 500: loss = 1.9532 (0.009 sec/step)
INFO:tensorflow:global step 600: loss = 1.8733 (0.010 sec/step)
INFO:tensorflow:global step 700: loss = 1.8002 (0.010 sec/step)
INFO:tensorflow:global step 800: loss = 1.7273 (0.010 sec/step)
INFO:tensorflow:global step 900: loss = 1.6688 (0.010 sec/step)
INFO:tensorflow:global step 1000: loss = 1.6132 (0.010 sec/step)
INFO:tensorflow:Stopping Training.
INFO:tensorflow:Finished training! Saving model to disk.
final loss=1.6131552457809448
从输出中可以看出,便捷函数slim.learning.train()
将训练输出保存在指定日志目录中的检查点文件中。如果重新开始训练,它将首先检查检查点是否存在,并且默认情况下将从检查点恢复训练。
在撰写本文时,TFSlim 的文档页面在此链接中被发现为空。 但是,可以在此链接的源代码中找到一些文档。
我们将使用 TFSlim 来学习如何在后面的章节中使用预训练的模型,如 VGG16 和 InceptionV3。
TFLearn 是 Python 中的模块化库,它构建在核心 TensorFlow 之上。
TFLearn 与 TensorFlow Learn 包不同,后者也称为 TFLearn(TF 和 Learn 之间有一个空格)。TFLearn 可从此链接获得,源代码可在 GitHub 上的此链接获得。
可以使用以下命令在 Python 3 中安装 TFLearn:
pip3 install tflearn
要在其他环境或源中安装 TFLearn,请参阅此链接。
TFLearn 中的简单工作流程如下:
regression
)创建网络。model.fit()
方法训练模型。让我们学习如何在 TFLearn 中创建神经网络模型的层:
input_layer = tflearn.input_data(shape=[None,num_inputs]
layer1 = tflearn.fully_connected(input_layer,10,
activation='relu')
layer2 = tflearn.fully_connected(layer1,10,
activation='relu')
output = tflearn.fully_connected(layer2,n_classes,
activation='softmax')
regression
:net = tflearn.regression(output,
optimizer='adam',
metric=tflearn.metrics.Accuracy(),
loss='categorical_crossentropy'
)
TFLearn 为以下子部分中描述的层提供了几个类。
TFLearn 在tflearn.layers.core
模块中提供以下层:
层类 | 描述 |
---|---|
input_data | 该层用于指定神经网络的输入层。 |
fully_connected | 该层用于指定一个层,其中所有神经元都连接到前一层中的所有神经元。 |
dropout | 该层用于指定丢弃正则化。输入元素由1/keep_prob缩放,同时保持预期的总和不变。 |
custom_layer | 此层用于指定要应用于输入的自定义函数。此类包装我们的自定义函数并将该函数显示为层。 |
reshape | 此层将输入重新整形为指定形状的输出。 |
flatten | 该层将输入张量转换为 2D 张量。 |
activation | 该层将指定的激活函数应用于输入张量。 |
single_unit | 该层将线性函数应用于输入。 |
highway | 该层实现了完全连接的公路函数。 |
one_hot_encoding | 此层将数字标签转换为二元向量单热编码表示。 |
time_distributed | 该层将指定的函数应用于输入张量的每个时间步长。 |
multi_target_data | 此层创建并连接多个占位符,特别是在层使用来自多个源的目标时使用。 |
TFLearn 在tflearn.layers.conv
模块中提供以下层:
层类 | 描述 |
---|---|
conv_1d | 该层将 1D 卷积应用于输入数据 |
conv_2d | 该层将 2D 卷积应用于输入数据 |
conv_3d | 该层将 3D 卷积应用于输入数据 |
conv_2d_transpose | 该层将conv2_d的转置应用于输入数据 |
conv_3d_transpose | 该层将conv3_d的转置应用于输入数据 |
atrous_conv_2d | 该层计算二维动态卷积 |
grouped_conv_2d | 该层计算深度 2D 卷积 |
max_pool_1d | 该层计算 1D 最大池化 |
max_pool_2d | 该层计算 2D 最大池化 |
avg_pool_1d | 该层计算 1D 平均池化 |
avg_pool_2d | 该层计算 2D 平均池化 |
upsample_2d | 该层应用行和列 2D 重复操作 |
upscore_layer | 该层实现了这个页面中规定的最高分。 |
global_max_pool | 该层实现全局最大池化操作 |
global_avg_pool | 该层实现全局平均池化操作 |
residual_block | 该层实现残差块以创建深度残差网络 |
residual_bottleneck | 该层实现深度残差网络的残差瓶颈块 |
resnext_block | 该层实现 ResNext 块 |
TFLearn 在tflearn.layers.recurrent
模块中提供以下层:
层类 | 描述 |
---|---|
simple_rnn | 该层实现了简单的循环神经网络模型 |
bidirectional_rnn | 该层实现双向 RNN 模型 |
lstm | 该层实现了 LSTM 模型 |
gru | 该层实现 GRU 模型 |
TFLearn 在tflearn.layers.normalization
模块中提供以下层:
层类 | 描述 |
---|---|
batch_normalization | 该层正则化每个批次的先前层激活的输出 |
local_response_normalization | 该层实现 LR 正则化 |
l2_normalization | 该层将 L2 归一化应用于输入张量 |
TFLearn 在tflearn.layers.embedding_ops
模块中只提供一层:
层类 | 描述 |
---|---|
embedding | 该层实现整数 ID 或浮点序列的嵌入函数 |
TFLearn 在tflearn.layers.merge_ops
模块中提供以下层:
层类 | 描述 |
---|---|
merge_outputs | 该层将张量列表合并为单个张量,通常用于合并相同形状的输出张量 |
merge | 该层将张量列表合并为单个张量;您可以指定需要进行合并的轴 |
TFLearn 在tflearn.layers.estimator
模块中只提供一层:
层类 | 描述 |
---|---|
regression | 该层实现线性或逻辑回归 |
在创建回归层时,您可以指定优化器以及损失和度量函数。
TFLearn 在tflearn.optimizers
模块中提供以下优化器函数作为类:
SGD
RMSprop
Adam
Momentum
AdaGrad
Ftrl
AdaDelta
ProximalAdaGrad
Nesterov
您可以通过扩展tflearn.optimizers.Optimizer
基类来创建自定义优化器。
TFLearn 在tflearn.metrics
模块中提供以下度量函数作为类或操作:
Accuracy
或accuracy_op
Top_k
或top_k_op
R2
或r2_op
WeightedR2
或weighted_r2_op
binary_accuracy_op
您可以通过扩展tflearn.metrics.Metric
基类来创建自定义指标。
TFLearn 在tflearn.objectives
模块中提供以下损失函数,称为目标:
softymax_categorical_crossentropy
categorical_crossentropy
binary_crossentropy
weighted_crossentropy
mean_square
hinge_loss
roc_auc_score
weak_cross_entropy_2d
在指定输入,隐藏和输出层时,您可以指定要应用于输出的激活函数。 TFLearn 在tflearn.activations
模块中提供以下激活函数:
linear
tanh
sigmoid
softmax
softplus
softsign
relu
relu6
leaky_relu
prelu
elu
crelu
selu
从上一步创建的网络创建模型(创建 TFLearn 层部分的步骤 4):
model = tflearn.DNN(net)
TFLearn 提供两种不同的模型:
DNN
(深度神经网络)模型:此类允许您从通过层创建的网络创建多层感知机SequenceGenerator
模型:该类允许您创建可以生成序列的深度神经网络创建后,使用model.fit()
方法训练模型:
model.fit(X_train,
Y_train,
n_epoch=n_epochs,
batch_size=batch_size,
show_metric=True,
run_id='dense_model')
使用训练的模型预测或评估:
score = model.evaluate(X_test, Y_test)
print('Test accuracy:', score[0])
笔记本ch-02_TF_High_Level_Libraries
中提供了 TFLearn MNIST 分类示例的完整代码。 TFLearn MNIST 示例的输出如下:
Training Step: 5499 | total loss: 0.42119 | time: 1.817s
| Adam | epoch: 010 | loss: 0.42119 - acc: 0.8860 -- iter: 54900/55000
Training Step: 5500 | total loss: 0.40881 | time: 1.820s
| Adam | epoch: 010 | loss: 0.40881 - acc: 0.8854 -- iter: 55000/55000
--
Test accuracy: 0.9029
PrettyTensor 在 TensorFlow 上提供了一个薄包装器。 PrettyTensor 提供的对象支持可链接的语法来定义神经网络。例如,可以通过链接层来创建模型,如以下代码所示:
model = (X.
flatten().
fully_connected(10).
softmax_classifier(n_classes, labels=Y))
可以使用以下命令在 Python 3 中安装 PrettyTensor:
pip3 install prettytensor
PrettyTensor 以名为apply()
的方法提供了一个非常轻量级和可扩展的接口。可以使用.apply(function, arguments)
方法将任何附加函数链接到 PrettyTensor 对象。 PrettyTensor 将调用function
并提供当前张量作为function
的第一个参数。
用户创建的函数可以使用@prettytensor.register
装饰器来装饰。详细信息在这里。
在 PrettyTensor 中定义和训练模型的工作流程如下:
runner.train_model()
方法训练模型。runner.evaluate_model()
方法评估模型。笔记本ch-02_TF_High_Level_Libraries
中提供了 PrettyTensor MNIST 分类示例的完整代码。 PrettyTensor MNIST 示例的输出如下:
[1] [2.5561881]
[600] [0.3553167]
Accuracy after 1 epochs 0.8799999952316284
[601] [0.47775066]
[1200] [0.34739292]
Accuracy after 2 epochs 0.8999999761581421
[1201] [0.19110668]
[1800] [0.17418651]
Accuracy after 3 epochs 0.8999999761581421
[1801] [0.27229539]
[2400] [0.34908807]
Accuracy after 4 epochs 0.8700000047683716
[2401] [0.40000191]
[3000] [0.30816519]
Accuracy after 5 epochs 0.8999999761581421
[3001] [0.29905257]
[3600] [0.41590339]
Accuracy after 6 epochs 0.8899999856948853
[3601] [0.32594997]
[4200] [0.36930788]
Accuracy after 7 epochs 0.8899999856948853
[4201] [0.26780865]
[4800] [0.2911002]
Accuracy after 8 epochs 0.8899999856948853
[4801] [0.36304188]
[5400] [0.39880857]
Accuracy after 9 epochs 0.8999999761581421
[5401] [0.1339224]
[6000] [0.14993289]
Accuracy after 10 epochs 0.8899999856948853
Sonnet 是一个用 Python 编写的面向对象的库。它是由 DeepMind 在 2017 年发布的。Sonnet 打算从对象中清晰地分离构建计算图的以下两个方面:
可以使用以下命令在 Python3 中安装 Sonnet:
pip3 install dm-sonnet
模块被定义为抽象类sonnet.AbstractModule
的子类。在编写本书时,Sonnet 中提供了以下模块:
基本模块 | AddBias,BatchApply,BatchFlatten,BatchReshape,FlattenTrailingDimensions,Linear,MergeDims,SelectInput,SliceByDim,TileByDim和TrainableVariable |
---|---|
循环模块 | DeepRNN,ModelRNN,VanillaRNN,BatchNormLSTM,GRU和LSTM |
Recurrent + ConvNet 模块 | Conv1DLSTM和Conv2DLSTM |
ConvNet 模块 | Conv1D,Conv2D,Conv3D,Conv1DTranspose,Conv2DTranspose,Conv3DTranspose,DepthWiseConv2D,InPlaneConv2D和SeparableConv2D |
ResidualNets | Residual,ResidualCore和SkipConnectionCore |
其他 | BatchNorm,LayerNorm,clip_gradient和scale_gradient |
我们可以通过创建sonnet.AbstractModule
的子类来定义我们自己的新模块。从函数创建模块的另一种非推荐方法是通过传递要包装为模块的函数来创建sonnet.Module
类的对象。
在 Sonnet 库中构建模型的工作流程如下:
sonnet.AbstractModule
继承的数据集和网络架构创建类。在我们的示例中,我们创建了一个 MNIST 类和一个 MLP 类。
model = MLP([20, n_classes])
创建了一个 MLP 网络,其中包含两层 20 和每个神经元n_classes
的数量。
y_hat
占位符。
笔记本电脑ch-02_TF_High_Level_Libraries
中提供了 Sonnet MNIST 分类示例的完整代码。 每个类中的__init__
方法初始化类和相关的超类。_build
方法在调用类时创建并返回数据集或模型对象。 Sonnet MNIST 示例的输出如下:
Epoch : 0 Training Loss : 236.79913330078125
Epoch : 1 Training Loss : 227.3693084716797
Epoch : 2 Training Loss : 221.96337890625
Epoch : 3 Training Loss : 220.99142456054688
Epoch : 4 Training Loss : 215.5921173095703
Epoch : 5 Training Loss : 213.88958740234375
Epoch : 6 Training Loss : 203.7091064453125
Epoch : 7 Training Loss : 204.57427978515625
Epoch : 8 Training Loss : 196.17218017578125
Epoch : 9 Training Loss : 192.3954315185547
Test loss : 192.8847198486328
由于神经网络中计算的随机性,您的输出可能会有所不同。这包括我们对 Sonnet 模块的概述。
在本章中,我们浏览了一些构建在 TensorFlow 之上的高级库。我们了解了 TFEstimator,TFSlim,TFLearn,PrettyTensor 和 Sonnet。我们为所有五个实现了 MNIST 分类示例。如果您无法理解模型的细节,请不要担心,因为为 MNIST 示例构建的模型将在以下章节中再次介绍。
我们总结了下表中提供的库和框架,如下表所示:
高级库 | 文档链接 | 源代码链接 | PIP3 安装包 |
---|---|---|---|
TFEstimator | https://www.tensorflow.org/get_started/estimator | https://github.com/tensorflow/tensorflow/tree/master/tensorflow/python/estimator | TensorFlow 预置 |
TFSlim | https://github.com/tensorflow/tensorflow/tree/r1.4/tensorflow/contrib/slim | https://github.com/tensorflow/tensorflow/tree/r1.4/tensorflow/contrib/slim/python/slim | TensorFlow 预置 |
TFLearn | http://tflearn.org/ | https://github.com/tflearn/tflearn | tflearn |
PrettyTensor | https://github.com/google/prettytensor/tree/master/docs | https://github.com/google/prettytensor | prettytensor |
Sonnet | https://deepmind.github.io/sonnet/ | https://github.com/deepmind/sonnet | dm-sonnet |
在下一章中,我们将了解 Keras,这是用于创建和训练 TensorFlow 模型的最流行的高级库。
Keras 是一个高级库,允许使用 TensorFlow 作为后端深度学习库。 TensorFlow 团队将 TrasorFlow Core 中的 Keras 作为模块tf.keras
。除了 TensorFlow 之外,Keras 在撰写本书时还支持 Theano 和 CNTK。
以下 Keras 的指导原则使其在深度学习社区中非常受欢迎:
在本书的其余部分中,我们将学习如何使用低级 TensorFlow API 和高级 Keras API 构建不同类型的深度学习和机器学习模型。
我们将在本章中介绍以下主题:
使用以下命令可以在 Python 3 中安装 Keras:
pip3 install keras
Keras 中的神经网络模型将定义为层图。 Keras 中的模型可以使用顺序或函数式 API 创建。函数式和顺序 API 都可用于构建任何类型的模型。函数式 API 可以更轻松地构建具有多个输入,多个输出和共享层的复杂模型。
因此,根据经验,我们已经看到工程师将顺序 API 用于从简单层构建的简单模型,以及用于涉及分支和共享层的复杂模型的函数式 API。我们还观察到,使用函数式 API 构建简单模型可以更轻松地将模型扩展为具有分支和共享的复杂模型。因此,对于我们的工作,我们总是使用函数式 API。
Keras 的简单工作流程如下:
我们来看看每个步骤。
您可以使用代码包中包含的 Jupyter 笔记本ch-03_Keras_101
来遵循本章中的代码示例。 尝试修改笔记本中的代码以探索各种选项。
可以使用顺序 API 或函数式 API 创建 Keras 模型。以下两小节给出了以两种方式创建模型的示例 。
在顺序 API 中,使用以下代码创建空模型:
model = Sequential()
您现在可以将层添加到此模型中,我们将在下一节中看到。
或者,您也可以将所有层作为列表传递给构造器。例如,我们通过使用以下代码将它们传递给构造器来添加四个层:
model = Sequential([ Dense(10, input_shape=(256,)),
Activation('tanh'),
Dense(10),
Activation('softmax')
])
在函数式 API 中,模型创建为Model
类的一个实例,它接受输入和输出参数。输入和输出参数分别代表一个或多个输入和输出张量。
例如,使用以下代码从函数式 API 实例化模型:
model = Model(inputs=tensor1, outputs=tensor2)
在上面的代码中,tensor1
和tensor2
是张量或对象,可以像张量一样对待,例如,Keras layer
对象。
如果有多个输入和输出张量,则可以将它们作为列表传递,如以下示例所示:
model = Model(inputs=[i1,i2,i3], outputs=[o1,o2,o3])
Keras 为网络架构的简单构建提供了几个内置层类。以下部分概述和描述了 Keras2 在撰写本书时提供的各种类型的层。
Keras 核心层实现基本操作,几乎用于各种网络架构。下表给出了 Keras2 提供的层的摘要和说明:
层名称 | 描述 |
---|---|
Dense | 这是一个简单的完全连接的神经网络层。该层生成以下函数的输出:激活(输入 x 权重 + 偏差),其中激活是指传递给层的激活函数,默认为None。 |
Activation | 该层将指定的激活函数应用于输出。该层生成以下函数的输出:激活(输入),其中激活是指传递给该层的激活函数。以下激活函数可用于实例化层:softmax,elu,selu,softplus,softsign,relu,tanh,sigmoid,hard_sigmoid和linear |
Dropout | 该层以指定的丢弃率将丢弃正则化应用于输入。 |
Flatten | 该层使输入变平,即对于三维输入,它变平并产生一维输出。 |
Reshape | 此层将输入转换为指定的形状。 |
Permute | 此层按照指定的模式重新排序输入尺寸。 |
RepeatVector | 该层以给定次数重复输入。因此,如果输入是 2D 张量的形状(#samples, #feature)并且该层被赋予n次重复,那么输出将是 3D 张量的形状(#samples, n, #feature)。 |
Lambda | 该层将提供的函数包装为层。因此,输入通过提供的自定义函数传递以产生输出。该层为 Keras 用户提供了最终的可扩展性,可以将自己的自定义函数添加为层。 |
ActivityRegularization | 该层将 L1 或 L2 或两种正则化的组合应用于其输入。该层应用于激活层的输出或具有激活函数的层的输出。 |
Masking | 此层在输入张量中屏蔽或跳过这些时间步长,其中输入张量中的所有值都等于作为层参数提供的屏蔽值。 |
这些层为卷积神经网络实现了不同类型的卷积,采样和裁剪操作:
层名称 | 描述 |
---|---|
Conv1D | 该层将单个空间或时间维度上的卷积应用于输入。 |
Conv2D | 该层将二维卷积应用于输入。 |
SeparableConv2D | 该层在每个输入通道上应用深度方式空间卷积,然后是逐点卷积,将所得到的输出通道混合在一起。 |
Conv2DTranspose | 该层将卷积的形状恢复为产生这些卷积的输入的形状。 |
Conv3D | 该层将三维卷积应用于输入。 |
Cropping1D | 该层沿时间维度裁剪输入数据。 |
Cropping2D | 此层沿空间维度裁剪输入数据,例如图像的宽度和高度。 |
Cropping3D | 该层沿着时空裁剪输入数据,即所有三维。 |
UpSampling1D | 该层按时间轴指定的时间重复输入数据。 |
UpSampling2D | 此层沿两个维度按指定时间重复输入数据的行和列维度。 |
UpSampling3D | 该层按三个维度的指定时间重复输入数据的三个维度。 |
ZeroPadding1D | 该层将零添加到时间维度的开头和结尾。 |
ZeroPadding2D | 此层将行和列的零添加到 2D 张量的顶部,底部,左侧或右侧。 |
ZeroPadding3D | 该层将零添加到 3D 张量的三个维度。 |
这些层为卷积神经网络实现不同的池化操作:
层名称 | 描述 |
---|---|
MaxPooling1D | 该层实现一维输入数据的最大池化操作。 |
MaxPooling2D | 该层实现二维输入数据的最大池化操作。 |
MaxPooling3D | 该层实现三维输入数据的最大池化操作。 |
AveragePooling1D | 该层实现一维输入数据的平均池化操作。 |
AveragePooling2D | 该层实现二维输入数据的平均池化操作。 |
AveragePooling3D | 该层实现三维输入数据的平均吃阿虎操作。 |
GlobalMaxPooling1D | 该层实现一维输入数据的全局最大池化操作。 |
GlobalAveragePooling1D | 该层实现一维输入数据的全局平均池化操作。 |
GlobalMaxPooling2D | 该层实现二维输入数据的全局最大池化操作。 |
GlobalAveragePooling2D | 该层实现二维输入数据的全局平均池化操作。 |
这些层在卷积神经网络中很有用:
层名称 | 描述 |
---|---|
LocallyConnected1D | 该层通过在输入的每个不同补丁上应用不同的滤波器组,将单个空间或时间维度上的卷积应用于输入,从而不共享权重。 |
LocallyConnected2D | 该层通过在输入的每个不同补丁上应用不同的滤波器组,将两个维上的卷积应用于输入,从而不共享权重。 |
这些层实现循环神经网络的不同变体:
层名称 | 描述 |
---|---|
SimpleRNN | 该层实现了完全连接的循环神经网络。 |
GRU | 该层实现了门控循环单元网络。 |
LSTM | 该层实现了长期短期记忆网络。 |
目前,只有一个嵌入层选项可用:
层名称 | 描述 |
---|---|
Embedding | 该层采用由下标组成的 2D 张量,形状为(batch_size, sequence_length),并产生由形状(batch_size, sequence_length, output_dim)的密集向量组成的张量。 |
这些层合并两个或多个输入张量,并通过应用每个层表示的特定操作产生单个输出张量:
层名称 | 描述 |
---|---|
Add | 该层计算输入张量的逐元素加法。 |
Multiply | 该层计算输入张量的逐元素乘法 |
Average | 该层计算输入张量的逐元素平均值。 |
Maximum | 该层计算输入张量的逐元素最大值。 |
Concatenate | 此层沿指定轴连接输入张量。 |
Dot | 该层计算两个输入张量中样本之间的点积。 |
add,multiply,average,maximum,concatenate和dot | 这些函数表示此表中描述的各个合并层的函数接口。 |
这些层实现了高级激活函数,这些函数无法作为简单的底层后端函数实现。它们的操作类似于我们在核心层部分中介绍的Activation()
层:
层名称 | 描述 |
---|---|
LeakyReLU | 该层计算ReLU激活函数的泄漏版本。 |
PReLU | 该层计算参数化ReLU激活函数。 |
ELU | 该层计算指数线性单元激活函数。 |
ThresholdedReLU | 该层计算阈值版本的ReLU激活函数。 |
目前,只有一个标准化层可用:
层名称 | 描述 |
---|---|
BatchNormalization | 该层标准化前一层的每个批量的输出,使得该层的输出近似为具有接近零的平均值和接近 1 的标准偏差。 |
这些层可以添加到模型中,以防止过拟合添加噪音;它们也被称为正则化层。这些层的操作方式与核心层部分中的Dropout()
和ActivityRegularizer()
层相同。
层名称 | 描述 |
---|---|
GaussianNoise | 该层将附加的零中心高斯噪声应用于输入。 |
GaussianDropout | 该层将乘法的单中心高斯噪声应用于输入。 |
AlphaDropout | 该层丢弃一定百分比的输入,使得丢弃后输出的均值和方差与输入的均值和方差紧密匹配。 |
上一节中提到的所有层都需要添加到我们之前创建的模型中。在以下部分中,我们将介绍如何使用函数式 API 和顺序 API 添加层。
在顺序 API 中,可以通过实例化前面部分中给出的某个层类型的对象来创建层。然后使用model.add()
函数将创建的层添加到模型中。作为示例,我们将创建一个模型,然后为其添加两个层:
model = Sequential()
model.add(Dense(10, input_shape=(256,))
model.add(Activation('tanh'))
model.add(Dense(10))
model.add(Activation('softmax'))
在函数式 API 中,首先以函数方式创建层,然后在创建模型时,输入和输出层作为张量参数提供,如我们在上一节。
这是一个例子:
input = Input(shape=(64,))
hidden = Dense(10)(inputs)
hidden = Activation('tanh')(hidden)
hidden = Dense(10)(hidden)
output = Activation('tanh')(hidden)
model = Model(inputs=input, outputs=output)
有关创建顺序和函数式 Keras 模型的更深入细节,您可以阅读由 Antonio Gulli 和 Sujit Pal,Packt Publishing,2017 年出版的题为 Deep Learning with Keras 的书。
前面部分中构建的模型需要使用model.compile()
方法进行编译,然后才能用于训练和预测。compile()
方法的完整签名如下:
compile(self, optimizer, loss, metrics=None, sample_weight_mode=None)
compile
方法有三个参数:
optimizer
:您可以指定自己的函数或 Keras 提供的函数之一。此函数用于更新优化迭代中的参数。 Keras 提供以下内置优化器函数:
SGD
RMSprop
Adagrad
Adadelta
Adam
Adamax
Nadam
loss
:您可以指定自己的损失函数或使用提供的损失函数之一。优化器函数优化参数,以便最小化此损失函数的输出。 Keras 提供以下损失函数:
mean_squared_error
mean_absolute_error
mean_absolute_pecentage_error
mean_squared_logarithmic_error
squared_hinge
hinge
categorical_hinge
sparse_categorical_crossentropy
binary_crossentropy
poisson
cosine proximity
binary_accuracy
categorical_accuracy
sparse_categorical_accuracy
top_k_categorical_accuracy
sparse_top_k_categorical_accuracy
metrics
:第三个参数是训练模型时需要收集的指标列表。如果启用了详细输出,则会为每次迭代打印度量标准。指标就像损失函数;一些由 Keras 提供,能够编写您自己的度量函数。所有损失函数也可用作度量函数。
训练 Keras 模型就像调用model.fit()
方法一样简单。该方法的完整签名如下:
fit(self, x, y, batch_size=32, epochs=10, verbose=1, callbacks=None,
validation_split=0.0, validation_data=None, shuffle=True,
class_weight=None, sample_weight=None, initial_epoch=0)
我们不会详细介绍这种方法的参数; 您可以在 Keras 网站上阅读详细信息。
对于我们之前创建的示例模型,使用以下代码训练模型:
model.fit(x_data, y_labels)
经过训练的模型可用于使用model.predict()
方法来预测值,或用model.evaluate()
方法评估模型。
这两种方法的签名如下:
predict(self, x, batch_size=32, verbose=0)
evaluate(self, x, y, batch_size=32, verbose=1, sample_weight=None)
Keras 提供了几个补充基本工作流程的附加模块(附加函数在本章开头描述)。部分模块如下:
preprocessing
模块提供了几种预处理序列,图像和文本数据的函数。datasets
模块提供了多种函数,可以快速访问几个流行的数据集,如 CIFAR10 图像,CIFAR100 图像,IMDB 电影评论,路透社新闻专线主题,MNIST 手写数字和波士顿房价。initializers
模块提供了几种设置层初始随机权重参数的函数,如Zeros
,Ones
,Constant
,RandomNormal
,RandomUniform
,TruncatedNormal
,VarianceScaling
,Orthogonal
,Identity
,lecun_normal
,lecun_uniform
,glorot_normal
,glorot_uniform
,he_normal
和he_uniform
。models
模块提供了几种恢复模型架构和权重的函数,如model_from_json
,model_from_yaml
,和load_model
。可以使用model.to_yaml()
和model.to_json()
方法保存模型架构。通过调用model.save()
方法可以保存模型权重。权重保存在 HDF5 文件中。applications
模块提供了几种预先构建和预训练的模型,例如 Xception,VGG16,VGG19,ResNet50,InceptionV3,InceptionResNetV2 和 MobileNet。我们将学习如何使用预建模型来预测我们的数据集。我们还将学习,如何使用来自略有不同的域的数据集,再训练applications
模块中的预训练模型。这就结束了我们对 Keras 的简要介绍,这是 TensorFlow 的高级框架。我们将在本书中提供使用 Keras 构建模型的示例。
以下是构建简单多层感知机(在第 5 章中详细介绍)的一个小例子,用于对 MNIST 集中的手写数字进行分类:
import keras
from keras.datasets import mnist
from keras.models import Sequential
from keras.layers import Dense, Dropout
from keras.optimizers import SGD
from keras import utils
import numpy as np
# define some hyper parameters
batch_size = 100
n_inputs = 784
n_classes = 10
n_epochs = 10
# get the data
(x_train, y_train), (x_test, y_test) = mnist.load_data()
# reshape the two dimensional 28 x 28 pixels
# sized images into a single vector of 784 pixels
x_train = x_train.reshape(60000, n_inputs)
x_test = x_test.reshape(10000, n_inputs)
# convert the input values to float32
x_train = x_train.astype(np.float32)
x_test = x_test.astype(np.float32)
# normalize the values of image vectors to fit under 1
x_train /= 255
x_test /= 255
# convert output data into one hot encoded format
y_train = utils.to_categorical(y_train, n_classes)
y_test = utils.to_categorical(y_test, n_classes)
# build a sequential model
model = Sequential()
# the first layer has to specify the dimensions of the input vector
model.add(Dense(units=128, activation='sigmoid', input_shape=(n_inputs,)))
# add dropout layer for preventing overfitting
model.add(Dropout(0.1))
model.add(Dense(units=128, activation='sigmoid'))
model.add(Dropout(0.1))
# output layer can only have the neurons equal to the number of outputs
model.add(Dense(units=n_classes, activation='softmax'))
# print the summary of our model
model.summary()
# compile the model
model.compile(loss='categorical_crossentropy',
optimizer=SGD(),
metrics=['accuracy'])
# train the model
model.fit(x_train, y_train,
batch_size=batch_size,
epochs=n_epochs)
# evaluate the model and print the accuracy score
scores = model.evaluate(x_test, y_test)
print('\n loss:', scores[0])
print('\n accuracy:', scores[1])
我们从描述和训练 Keras 模型得到以下输出:
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
dense_7 (Dense) (None, 128) 100480
_________________________________________________________________
dropout_5 (Dropout) (None, 128) 0
_________________________________________________________________
dense_8 (Dense) (None, 128) 16512
_________________________________________________________________
dropout_6 (Dropout) (None, 128) 0
_________________________________________________________________
dense_9 (Dense) (None, 10) 1290
=================================================================
Total params: 118,282
Trainable params: 118,282
Non-trainable params: 0
_________________________________________________________________
Epoch 1/10
60000/60000 [========================] - 3s - loss: 2.3018 - acc: 0.1312
Epoch 2/10
60000/60000 [========================] - 2s - loss: 2.2395 - acc: 0.1920
Epoch 3/10
60000/60000 [========================] - 2s - loss: 2.1539 - acc: 0.2843
Epoch 4/10
60000/60000 [========================] - 2s - loss: 2.0214 - acc: 0.3856
Epoch 5/10
60000/60000 [========================] - 3s - loss: 1.8269 - acc: 0.4739
Epoch 6/10
60000/60000 [========================] - 2s - loss: 1.5973 - acc: 0.5426
Epoch 7/10
60000/60000 [========================] - 2s - loss: 1.3846 - acc: 0.6028
Epoch 8/10
60000/60000 [========================] - 3s - loss: 1.2133 - acc: 0.6502
Epoch 9/10
60000/60000 [========================] - 3s - loss: 1.0821 - acc: 0.6842
Epoch 10/10
60000/60000 [========================] - 3s - loss: 0.9799 - acc: 0.7157
loss: 0.859834249687
accuracy: 0.788
您可以看到,在 Keras 中构建和训练模型是多么容易。
您可以从他们记录完备的网站获取有关 Keras 的更多信息。
在本章中,我们了解了 Keras。 Keras 是 TensorFlow 最受欢迎的高级库。我个人更喜欢将 Keras 用于我为商业制作和学术研究开发的所有模型。我们学习了使用函数式和顺序 API 在 Keras 中创建和训练模型所遵循的工作流程。我们了解了各种 Keras 层以及如何将层添加到顺序和函数式模型中。我们还学习了如何编译,训练和评估 Keras 模型。我们还看到了 Keras 提供的一些附加模块。
在本书的其余章节中,我们将介绍核心 TensorFlow 和 Keras 中的大多数示例。 在下一章中,我们将学习如何使用 TensorFlow 构建传统的机器学习模型进行分类和回归。
机器学习是计算机科学领域,涉及算法的研究,开发和应用,以使计算机器从数据中学习。计算机学习的模型用于进行预测和预测。机器学习研究人员和工程师通过构建模型然后使用这些模型进行预测来实现这一目标。现在众所周知,机器学习已成功地应用于各种领域,如自然语言理解,视频处理,图像识别,语音和视觉。
我们来谈谈模型。所有机器学习问题都以一种或另一种形式抽象为以下等式:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wyTw8KUu-1681566326305)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/mastering-tf-1x-zh/img/3d553b03-80b7-4120-9df0-a607ad64af36.png)]
这里,y
是输出或目标,x
是输入或特征。如果x
是一组特征,我们也将其称为特征向量,并用X
表示。当我们说模型时,我们的意思是找到将特征映射到目标的函数f
。因此,一旦我们找到f
,我们就可以使用x
的新值来预测y
的值。
机器学习的核心是找到可用于从x
的值预测y
的函数f
。正如您可能从高中数学周期回忆的那样,该线的等式如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-a6E2bnuo-1681566326306)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/mastering-tf-1x-zh/img/ba408e0e-2d86-4499-bc6d-a8fbeaf344d7.png)]
我们可以重写前面的简单等式如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LQ2bS5Xm-1681566326306)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/mastering-tf-1x-zh/img/fc46f48c-ee0d-43bd-b8bf-998f54b785c6.png)]
这里,W
称为权重,b
称为偏差。不要担心现在的权重和偏置,我们稍后会介绍它们。现在,您可以将W
视为等效于m
和b
等效于c
。因此,现在机器学习问题可以说是从X
的当前值找到W
和b
的问题,这样该方程可用于预测y
的值。
回归分析或回归建模是指用于估计变量之间关系的方法和技术。输入到回归模型的变量称为独立变量或预测变量或特征,而回归模型的输出变量称为因变量或目标。回归模型定义如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-W5h3zBa3-1681566326306)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/mastering-tf-1x-zh/img/5fc17d1b-7188-4209-bce2-77f97aa72877.png)]
其中Y
是目标变量,X
是特征向量,β
是参数向量
通常,我们使用一种非常简单的回归形式,称为简单线性回归来估计参数 β。
在机器学习问题中,我们必须从给定数据中学习模型参数β0
和β1
,以便我们有一个估计模型,从X
的未来值预测Y
的值。我们对偏置使用β1
,对权重项使用β0
,分别用w
和b
代表它们。
因此模型如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qsQe0BCO-1681566326306)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/mastering-tf-1x-zh/img/ff368a23-744e-4bc3-9c9a-82686936c8a1.png)]
分类是机器学习中的经典问题之一。正在考虑的数据可以属于一个或其他类别,例如,如果提供的图像是数据,则它们可以是猫或狗的图片。因此,在这种情况下,类别是猫和狗。分类是指识别或识别所考虑的数据或对象的标签或类别。分类属于监督机器学习的范畴。在分类问题中,提供具有特征或输入及其相应输出或标签的训练数据集。使用该训练数据集,训练模型;换句话说,计算模型的参数。然后将训练的模型用于新数据以找到其正确的标签。
分类问题可以有两种类型:两类或多类。两类意味着数据被分类为两个不同且不连续的标签,例如,患者患有癌症或患者没有癌症,图像是猫或狗。多类意味着数据将被分类到多个类别中,例如,电子邮件分类问题会将电子邮件分成社交媒体电子邮件,与工作相关的电子邮件,个人电子邮件,与家人相关的电子邮件,垃圾邮件,购物优惠电子邮件等等。 。另一个例子是数字图片的例子;每张图片可以标记在 0 到 9 之间,具体取决于图片所代表的数字。在本章中,我们将看到两种分类的示例。
在本章中,我们将进一步扩展以下主题:
您可能使用过其他机器学习库;现在让我们练习使用 TensorFlow 学习简单的线性回归模型。在继续讨论特定于域的示例之前,我们将首先使用生成的数据集解释这些概念。
我们将使用生成的数据集,以便来自所有不同域的读者可以学习而不会被示例的特定域的细节所淹没。
您可以按照 Jupyter 笔记本中的代码ch-04a_Regression
。
要生成数据集,我们使用sklearn
库的datasets
模块中的make_regression
函数:
from sklearn import datasets as skds
X, y = skds.make_regression(n_samples=200,
n_features=1,
n_informative=1,
n_targets=1,
noise = 20.0)
这将生成一个回归数据集,其中包含一个特征的 200 个样本值和每个特征的一个目标,并添加了一些噪声。因为我们只生成一个目标,所以该函数使用一维 NumPy 数组生成y
;因此,我们重塑y
有两个维度:
if (y.ndim == 1):
y = y.reshape(len(y),1)
我们使用以下代码绘制生成的数据集以查看数据:
import matplotlib.pyplot as plt
plt.figure(figsize=(14,8))
plt.plot(X,y,'b.')
plt.title('Original Dataset')
plt.show()
我们得到以下绘图。由于生成的数据是随机的,您可能会得到不同的绘图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vcgMegEv-1681566326307)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/mastering-tf-1x-zh/img/9dd24ca6-c0a6-427a-bc83-e12c3480d5fa.png)]
现在让我们将数据分为训练集和测试集:
X_train, X_test, y_train, y_test = skms.train_test_split(X, y,
test_size=.4,
random_state=123)
要在 TensorFlow 中构建和训练回归模型,通常采取以下步骤:
在我们使用 TensorFlow 构建和训练回归模型之前,让我们定义一些重要的变量和操作。我们从X_train
和y_train
中找出输出和输入变量的数量,然后使用这些数字来定义x
(x_tensor
),y
(y_tensor
),权重(w
)和偏置(b
):
num_outputs = y_train.shape[1]
num_inputs = X_train.shape[1]
x_tensor = tf.placeholder(dtype=tf.float32,
shape=[None, num_inputs],
name="x")
y_tensor = tf.placeholder(dtype=tf.float32,
shape=[None, num_outputs],
name="y")
w = tf.Variable(tf.zeros([num_inputs,num_outputs]),
dtype=tf.float32,
name="w")
b = tf.Variable(tf.zeros([num_outputs]),
dtype=tf.float32,
name="b")
x_tensor
被定义为具有可变行和num_inputs
列的形状,并且在我们的示例中列数仅为 1y_tensor
定义为具有可变行和num_outputs
列的形状,列数在我们的示例中只有一个w
被定义为维度num_inputs
x num_outputs
的变量,在我们的例子中是1 x 1
b
被定义为维度num_outputs
的变量,在我们的例子中是一个接下来,我们将模型定义为x_tensor × w + b
:
model = tf.matmul(x_tensor, w) + b
接下来,我们使用均方误差(MSE)定义损失函数。 MSE 定义如下:
有关 MSE 的更多详细信息,请访问此链接
y
的实际值和估计值的差异称为残差。损失函数计算残差平方的平均值。我们通过以下方式在 TensorFlow 中定义它:
loss = tf.reduce_mean(tf.square(model - y_tensor))
model - y_tensor
计算残差tf.square(model - y_tensor)
计算每个残差的平方tf.reduce_mean( ... )
最终计算在前一步骤中计算的平方均值我们还定义均方误差(MSE)和 R 平方(RS)函数来评估训练模型。我们使用单独的mse
函数,因为在接下来的章节中,损失函数将改变但mse
函数将保持不变。
# mse and R2 functions
mse = tf.reduce_mean(tf.square(model - y_tensor))
y_mean = tf.reduce_mean(y_tensor)
total_error = tf.reduce_sum(tf.square(y_tensor - y_mean))
unexplained_error = tf.reduce_sum(tf.square(y_tensor - model))
rs = 1 - tf.div(unexplained_error, total_error)
接下来,我们实例化学习率为 0.001 的theGradientDescentOptimizer
函数并将其设置为最小化损失函数:
learning_rate = 0.001
optimizer = tf.train.GradientDescentOptimizer(learning_rate).minimize(loss)
有关梯度下降的更多详细信息,请访问此链接:
https://en.wikipedia.org/wiki/Gradient_descent
TensorFlow 提供了许多其他优化器函数,如 Adadelta,Adagrad 和 Adam。我们将在以下章节中介绍其中一些内容。
现在我们已经定义了模型,损失函数和优化函数,训练模型来学习参数w
和b
。要训练模型,请定义以下全局变量:
num_epochs
:运行训练的迭代次数。每次迭代,模型都会学习更好的参数,我们将在后面的图中看到。w_hat
和b_hat
:收集估计的w
和b
参数。loss_epochs
,mse_epochs
,rs_epochs
:收集训练数据集中的总误差值,以及每次迭代中测试数据集上模型的 mse 和 R 平方值。mse_score
和rs_score
:收集最终训练模型的 mse 和 R 平方值。num_epochs = 1500
w_hat = 0
b_hat = 0
loss_epochs = np.empty(shape=[num_epochs],dtype=float)
mse_epochs = np.empty(shape=[num_epochs],dtype=float)
rs_epochs = np.empty(shape=[num_epochs],dtype=float)
mse_score = 0
rs_score = 0
初始化会话和全局变量后,运行num_epoch
次的训练循环:
with tf.Session() as tfs:
tf.global_variables_initializer().run()
for epoch in range(num_epochs):
在循环的每次迭代中,在训练数据上运行优化器:
tfs.run(optimizer, feed_dict={x_tensor: X_train, y_tensor: y_train})
使用学习的w
和b
值,计算误差并将其保存在loss_val
中以便稍后绘制:
loss_val = tfs.run(loss,feed_dict={x_tensor: X_train, y_tensor: y_train})
loss_epochs[epoch] = loss_val
计算测试数据预测值的均方误差和 R 平方值:
mse_score = tfs.run(mse,feed_dict={x_tensor: X_test, y_tensor: y_test})
mse_epochs[epoch] = mse_score
rs_score = tfs.run(rs,feed_dict={x_tensor: X_test, y_tensor: y_test})
rs_epochs[epoch] = rs_score
最后,一旦完成循环,保存w
和b
的值以便稍后绘制它们:
w_hat,b_hat = tfs.run([w,b])
w_hat = w_hat.reshape(1)
让我们在 2,000 次迭代后打印模型和测试数据的最终均方误差:
print('model : Y = {0:.8f} X + {1:.8f}'.format(w_hat[0],b_hat[0]))
print('For test data : MSE = {0:.8f}, R2 = {1:.8f} '.format(
mse_score,rs_score))
This gives us the following output:
model : Y = 20.37448120 X + -2.75295663
For test data : MSE = 297.57995605, R2 = 0.66098368
因此,我们训练的模型不是一个非常好的模型,但我们将在后面的章节中看到如何使用神经网络来改进它。
本章的目标是介绍如何使用 TensorFlow 构建和训练回归模型,而无需使用神经网络。
让我们绘制估计模型和原始数据:
plt.figure(figsize=(14,8))
plt.title('Original Data and Trained Model')
x_plot = [np.min(X)-1,np.max(X)+1]
y_plot = w_hat*x_plot+b_hat
plt.axis([x_plot[0],x_plot[1],y_plot[0],y_plot[1]])
plt.plot(X,y,'b.',label='Original Data')
plt.plot(x_plot,y_plot,'r-',label='Trained Model')
plt.legend()
plt.show()
我们得到以下原始数据与受训模型数据的关系图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HL0lY202-1681566326307)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/mastering-tf-1x-zh/img/987b1418-d3bc-40d6-9412-0826b81fded5.png)]
让我们绘制每次迭代中训练和测试数据的均方误差:
plt.figure(figsize=(14,8))
plt.axis([0,num_epochs,0,np.max(loss_epochs)])
plt.plot(loss_epochs, label='Loss on X_train')
plt.title('Loss in Iterations')
plt.xlabel('# Epoch')
plt.ylabel('MSE')
plt.axis([0,num_epochs,0,np.max(mse_epochs)])
plt.plot(mse_epochs, label='MSE on X_test')
plt.xlabel('# Epoch')
plt.ylabel('MSE')
plt.legend()
plt.show()
我们得到以下图,显示每次迭代时,均方误差减小,然后保持在 500 附近的相同水平:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hwTFmUAz-1681566326307)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/mastering-tf-1x-zh/img/02e135a4-4a8a-47ad-a85e-48bec81ce693.png)]
让我们绘制 R 平方的值:
plt.figure(figsize=(14,8))
plt.axis([0,num_epochs,0,np.max(rs_epochs)])
plt.plot(rs_epochs, label='R2 on X_test')
plt.xlabel('# Epoch')
plt.ylabel('R2')
plt.legend()
plt.show()
当我们绘制 R 平方超过周期的值时,我们得到以下图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VJWxV3C3-1681566326307)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/mastering-tf-1x-zh/img/b8c11857-8723-4d5c-9e56-a064607aabe8.png)]
这基本上表明该模型以 R 的平均值开始,但随着模型的训练并减少误差,R 平方的值开始变高,最终在某一点变得稳定略高于 0.6。
绘制 MSE 和 R 平方可以让我们看到我们的模型得到多快的训练以及它开始变得稳定的地方,以便进一步的训练在减少误差方面产生微不足道的好处或几乎没有好处。
现在您已经拥有训练有素的模型,它可用于预测新数据。线性模型的预测是通过理解我们在前一个图中看到的一些最小均方误差得出的,因为直线可能不完全适合数据。
为了获得更好的拟合模型,我们必须使用不同的方法扩展我们的模型,例如添加变量的线性组合。
现在您已经学习了如何使用 TensorFlow 创建基本回归模型,让我们尝试在不同域的示例数据集上运行它。我们作为示例数据集生成的数据集是单变量的,即目标仅依赖于一个特征。
实际上,大多数数据集都是多变量的。为了强调一点,目标取决于多个变量或特征,因此回归模型称为多元回归或多维回归。
我们首先从最受欢迎的波士顿数据集开始。该数据集包含波士顿 506 所房屋的 13 个属性,例如每个住所的平均房间数,一氧化氮浓度,到波士顿五个就业中心的加权距离等等。目标是自住房屋的中位数值。让我们深入探索这个数据集的回归模型。
从sklearn
库加载数据集并查看其描述:
boston=skds.load_boston()
print(boston.DESCR)
X=boston.data.astype(np.float32)
y=boston.target.astype(np.float32)
if (y.ndim == 1):
y = y.reshape(len(y),1)
X = skpp.StandardScaler().fit_transform(X)
我们还提取X
,一个特征矩阵,和y
,一个前面代码中的目标向量。我们重塑y
使其成为二维的,并将x
中的特征缩放为平均值为零,标准差为 1。现在让我们使用这个X
和y
来训练回归模型,就像我们在前面的例子中所做的那样:
您可能会发现该示例的代码与上一部分有关简单回归的代码相似; 但是,我们正在使用多种特征来训练模型,因此将其称为多元回归。
X_train, X_test, y_train, y_test = skms.train_test_split(X, y,
test_size=.4, random_state=123)
num_outputs = y_train.shape[1]
num_inputs = X_train.shape[1]
x_tensor = tf.placeholder(dtype=tf.float32,
shape=[None, num_inputs], name="x")
y_tensor = tf.placeholder(dtype=tf.float32,
shape=[None, num_outputs], name="y")
w = tf.Variable(tf.zeros([num_inputs,num_outputs]),
dtype=tf.float32, name="w")
b = tf.Variable(tf.zeros([num_outputs]),
dtype=tf.float32, name="b")
model = tf.matmul(x_tensor, w) + b
loss = tf.reduce_mean(tf.square(model - y_tensor))
# mse and R2 functions
mse = tf.reduce_mean(tf.square(model - y_tensor))
y_mean = tf.reduce_mean(y_tensor)
total_error = tf.reduce_sum(tf.square(y_tensor - y_mean))
unexplained_error = tf.reduce_sum(tf.square(y_tensor - model))
rs = 1 - tf.div(unexplained_error, total_error)
learning_rate = 0.001
optimizer = tf.train.GradientDescentOptimizer(learning_rate).minimize(loss)
num_epochs = 1500
loss_epochs = np.empty(shape=[num_epochs],dtype=np.float32)
mse_epochs = np.empty(shape=[num_epochs],dtype=np.float32)
rs_epochs = np.empty(shape=[num_epochs],dtype=np.float32)
mse_score = 0
rs_score = 0
with tf.Session() as tfs:
tfs.run(tf.global_variables_initializer())
for epoch in range(num_epochs):
feed_dict = {x_tensor: X_train, y_tensor: y_train}
loss_val, _ = tfs.run([loss, optimizer], feed_dict)
loss_epochs[epoch] = loss_val
feed_dict = {x_tensor: X_test, y_tensor: y_test}
mse_score, rs_score = tfs.run([mse, rs], feed_dict)
mse_epochs[epoch] = mse_score
rs_epochs[epoch] = rs_score
print('For test data : MSE = {0:.8f}, R2 = {1:.8f} '.format(
mse_score, rs_score))
我们从模型中获得以下输出:
For test data : MSE = 30.48501778, R2 = 0.64172244
让我们绘制 MSE 和 R 平方值。
下图显示了 MSE 的绘图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KScRpOxr-1681566326308)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/mastering-tf-1x-zh/img/b90f3cfb-8b86-47d7-9d0d-64d94acd59f2.png)]
下图显示了 R 平方值的绘图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AfNyl46Z-1681566326308)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/mastering-tf-1x-zh/img/60be36ac-1116-4f4e-a5dc-15fffcea81f1.png)]
正如我们在单变量数据集中看到的那样,我们看到了 MSE 和 R 平方的类似模式。
在线性回归中,我们训练的模型返回训练数据的最佳拟合参数。但是,在训练数据上找到最合适的参数可能会导致过拟合。
过拟合意味着模型最适合训练数据,但会给测试数据带来更大的误差。因此,我们通常在模型中添加惩罚项以获得更简单的模型。
该惩罚项称为正则化项,由此获得的回归模型称为正则化回归模型。正则化模型有三种主要类型:
α
乘以权重w
绝对值之和。因此,损失函数如下:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wLOkeZVN-1681566326308)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/mastering-tf-1x-zh/img/662a9855-a00c-41ad-8b0e-2b65dbfbdd69.png)]
α
乘以i-th
权重w
的平方和。因此,损失函数如下:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CWgQA3Lf-1681566326309)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/mastering-tf-1x-zh/img/b6aba15b-577d-4a22-a559-bd6f1f2e0d1b.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pSaFpuE0-1681566326309)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/mastering-tf-1x-zh/img/f6144fe6-9175-4d26-9e6b-f07fb0cd3212.png)]
有关正则化的更多详细信息,请参阅互联网上的这些资源。
一个简单的经验法则是当我们想要删除某些特征时使用 L1 或 LASSO,从而减少计算时间,但代价是降低了准确率。
现在让我们看看在 TensorFlow 中实现的这些正则化损失函数。我们将继续使用前面示例中使用的波士顿数据集。
我们将 lasso 参数定义为值 0.8:
lasso_param = tf.Variable(0.8, dtype=tf.float32)
lasso_loss = tf.reduce_mean(tf.abs(w)) * lasso_param
将 LASSO 参数设置为零意味着没有正则化,因为该项变为零。正则化项的值越高,惩罚越高。以下是 LASSO 正则化回归的完整代码,用于训练模型以预测波士顿房屋定价:
下面的代码假定训练和测试数据集已按照前面的示例进行拆分。
num_outputs = y_train.shape[1]
num_inputs = X_train.shape[1]
x_tensor = tf.placeholder(dtype=tf.float32,
shape=[None, num_inputs], name='x')
y_tensor = tf.placeholder(dtype=tf.float32,
shape=[None, num_outputs], name='y')
w = tf.Variable(tf.zeros([num_inputs, num_outputs]),
dtype=tf.float32, name='w')
b = tf.Variable(tf.zeros([num_outputs]),
dtype=tf.float32, name='b')
model = tf.matmul(x_tensor, w) + b
lasso_param = tf.Variable(0.8, dtype=tf.float32)
lasso_loss = tf.reduce_mean(tf.abs(w)) * lasso_param
loss = tf.reduce_mean(tf.square(model - y_tensor)) + lasso_loss
learning_rate = 0.001
optimizer = tf.train.GradientDescentOptimizer(learning_rate).minimize(loss)
mse = tf.reduce_mean(tf.square(model - y_tensor))
y_mean = tf.reduce_mean(y_tensor)
total_error = tf.reduce_sum(tf.square(y_tensor - y_mean))
unexplained_error = tf.reduce_sum(tf.square(y_tensor - model))
rs = 1 - tf.div(unexplained_error, total_error)
num_epochs = 1500
loss_epochs = np.empty(shape=[num_epochs],dtype=np.float32)
mse_epochs = np.empty(shape=[num_epochs],dtype=np.float32)
rs_epochs = np.empty(shape=[num_epochs],dtype=np.float32)
mse_score = 0.0
rs_score = 0.0
num_epochs = 1500
loss_epochs = np.empty(shape=[num_epochs], dtype=np.float32)
mse_epochs = np.empty(shape=[num_epochs], dtype=np.float32)
rs_epochs = np.empty(shape=[num_epochs], dtype=np.float32)
mse_score = 0.0
rs_score = 0.0
with tf.Session() as tfs:
tfs.run(tf.global_variables_initializer())
for epoch in range(num_epochs):
feed_dict = {x_tensor: X_train, y_tensor: y_train}
loss_val,_ = tfs.run([loss,optimizer], feed_dict)
loss_epochs[epoch] = loss_val
feed_dict = {x_tensor: X_test, y_tensor: y_test}
mse_score,rs_score = tfs.run([mse,rs], feed_dict)
mse_epochs[epoch] = mse_score
rs_epochs[epoch] = rs_score
print('For test data : MSE = {0:.8f}, R2 = {1:.8f} '.format(
mse_score, rs_score))
我们得到以下输出:
For test data : MSE = 30.48978233, R2 = 0.64166653
让我们使用以下代码绘制 MSE 和 R 平方的值:
plt.figure(figsize=(14,8))
plt.axis([0,num_epochs,0,np.max([loss_epochs,mse_epochs])])
plt.plot(loss_epochs, label='Loss on X_train')
plt.plot(mse_epochs, label='MSE on X_test')
plt.title('Loss in Iterations')
plt.xlabel('# Epoch')
plt.ylabel('Loss or MSE')
plt.legend()
plt.show()
plt.figure(figsize=(14,8))
plt.axis([0,num_epochs,np.min(rs_epochs),np.max(rs_epochs)])
plt.title('R-squared in Iterations')
plt.plot(rs_epochs, label='R2 on X_test')
plt.xlabel('# Epoch')
plt.ylabel('R2')
plt.legend()
plt.show()
我们得到以下损失绘图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dWpZpUa2-1681566326309)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/mastering-tf-1x-zh/img/e0e1db8b-6a49-4e35-89a8-0acde4ad83cc.png)]
迭代中 R 平方的图如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DEVcakta-1681566326310)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/mastering-tf-1x-zh/img/f75f8e2b-1395-4a1c-b50e-1f44ba2dd7da.png)]
让我们用岭回归重复相同的例子。
以下是岭正则化回归的完整代码,用于训练模型以预测波士顿房屋定价:
num_outputs = y_train.shape[1]
num_inputs = X_train.shape[1]
x_tensor = tf.placeholder(dtype=tf.float32,
shape=[None, num_inputs], name='x')
y_tensor = tf.placeholder(dtype=tf.float32,
shape=[None, num_outputs], name='y')
w = tf.Variable(tf.zeros([num_inputs, num_outputs]),
dtype=tf.float32, name='w')
b = tf.Variable(tf.zeros([num_outputs]),
dtype=tf.float32, name='b')
model = tf.matmul(x_tensor, w) + b
ridge_param = tf.Variable(0.8, dtype=tf.float32)
ridge_loss = tf.reduce_mean(tf.square(w)) * ridge_param
loss = tf.reduce_mean(tf.square(model - y_tensor)) + ridge_loss
learning_rate = 0.001
optimizer = tf.train.GradientDescentOptimizer(learning_rate).minimize(loss)
mse = tf.reduce_mean(tf.square(model - y_tensor))
y_mean = tf.reduce_mean(y_tensor)
total_error = tf.reduce_sum(tf.square(y_tensor - y_mean))
unexplained_error = tf.reduce_sum(tf.square(y_tensor - model))
rs = 1 - tf.div(unexplained_error, total_error)
num_epochs = 1500
loss_epochs = np.empty(shape=[num_epochs],dtype=np.float32)
mse_epochs = np.empty(shape=[num_epochs],dtype=np.float32)
rs_epochs = np.empty(shape=[num_epochs],dtype=np.float32)
mse_score = 0.0
rs_score = 0.0
with tf.Session() as tfs:
tfs.run(tf.global_variables_initializer())
for epoch in range(num_epochs):
feed_dict = {x_tensor: X_train, y_tensor: y_train}
loss_val, _ = tfs.run([loss, optimizer], feed_dict=feed_dict)
loss_epochs[epoch] = loss_val
feed_dict = {x_tensor: X_test, y_tensor: y_test}
mse_score, rs_score = tfs.run([mse, rs], feed_dict=feed_dict)
mse_epochs[epoch] = mse_score
rs_epochs[epoch] = rs_score
print('For test data : MSE = {0:.8f}, R2 = {1:.8f} '.format(
mse_score, rs_score))
我们得到以下结果:
For test data : MSE = 30.64177132, R2 = 0.63988018
绘制损失和 MSE 的值,我们得到以下损失图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qnX5QdGI-1681566326310)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/mastering-tf-1x-zh/img/0f74f654-50a2-4203-b9e8-0a2f29d7cd38.png)]
我们得到以下 R 平方图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UXnOv1Vu-1681566326310)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/mastering-tf-1x-zh/img/56fd975b-a22b-44b4-83aa-dc0d38ad77ce.png)]
让我们来看看 LASSO 和岭正则化方法的组合。
笔记本ch-04a_Regression
提供了 ElasticNet 正规回归的完整代码,用于训练模型以预测波士顿房屋定价。在运行模型时,我们得到以下结果:
For test data : MSE = 30.64861488, R2 = 0.63979971
绘制损失和 MSE 的值,我们得到以下图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0sZ64J2O-1681566326311)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/mastering-tf-1x-zh/img/71369789-39e3-4c2c-affb-d46290e841ab.png)]
我们得到以下 R 平方图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4Ekt5Ih3-1681566326311)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/mastering-tf-1x-zh/img/c8314797-8170-4325-b9ac-d563348c0609.png)]
最常用的分类方法是使用逻辑回归。逻辑回归是概率和线性分类器。输入是特征向量,特定类的成员的概率可以正式写成如下等式:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZGPZvRTo-1681566326311)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/mastering-tf-1x-zh/img/b54ac424-2f70-4aee-afca-253935b4a455.png)]In the above equation:
y
代表输出,i
代表其中一个类x
代表输入w
代表权重b
代表偏置z
代表回归方程z = w × x + b
φ
代表我们案例中的平滑函数或模型前面的等式表示当w
和b
被给出时x
属于i
类的概率由函数表示φ((z)
。因此,必须训练模型以最大化概率值。
对于二分类,我们将模型函数φ(z)
定义为 sigmoid 函数,如下所示:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Wc9HKyGp-1681566326312)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/mastering-tf-1x-zh/img/62e26ec4-6cff-4601-b544-cb79aa11a704.png)]
sigmoid 函数在范围[0, 1]
之间产生 y 的值。因此,我们可以使用y = φ(z)
的值来预测类:如果y > 0.5
则类别等于 1,否则类别等于 0。
正如我们在本章的前几节中所见,对于线性回归,可以通过查找最小化损失函数的参数来训练模型,并且损失函数可以是平方误差或均方误差的总和。对于逻辑回归,我们希望最大化可能性:L(w) = P(y|x, w, b)
。
但是,由于更容易使对数似然最大化,因此我们使用对数似然l(w)
作为成本函数。因此,损失函数(J(w)
)被写为-1(w)
,其可以使用诸如梯度下降的优化算法来最小化。
二元逻辑回归的损失函数在数学上写成如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dfObkdLX-1681566326312)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/mastering-tf-1x-zh/img/43249834-ffa5-490f-842b-3be538ea34e8.png)]
其中φ(z)
是 Sigmoid 函数。
我们将在下一节中实现这个损失函数。
当涉及两个以上的类时,逻辑回归是已知的多项逻辑回归。在多项逻辑回归中,我们使用 softmax 函数代替 sigmoid,它是最受欢迎的函数之一。 Softmax 可以用数学表示如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zBfU7tLh-1681566326312)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/mastering-tf-1x-zh/img/31227522-ba57-4b0d-a624-566ce56452aa.png)]
Softmax 函数产生每个类的概率,概率向量和为 1。在预测时,具有最高 softmax 值的类成为输出或预测类。正如我们前面讨论的那样,损失函数是负对数似然函数-l(w)
,它可以被优化器最小化,例如梯度下降。
多项逻辑回归的损失函数正式写成如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QWvFTLE3-1681566326313)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/mastering-tf-1x-zh/img/8a2c95b7-307d-4e20-8374-6db23980125e.png)]
其中φ(z)
是 softmax 函数。
我们将在本章后面实现这种损失函数。
让我们在下一节中深入研究一些例子。
您可以按照 Jupyter 笔记本中的代码ch-04b_Classification
。
二分类是指仅有两个不同类的问题。正如我们在上一章中所做的那样,我们将使用 SciKit Learn 库中的便捷函数make_classification()
生成数据集:
X, y = skds.make_classification(n_samples=200,
n_features=2,
n_informative=2,
n_redundant=0,
n_repeated=0,
n_classes=2,
n_clusters_per_class=1)
if (y.ndim == 1):
y = y.reshape(-1,1)
make_classification()
的论据是不言自明的;n_samples
是要生成的数据点数,n_features
是要生成的特征数,n_classes
是类的数量,即 2:
n_samples
是要生成的数据点数。我们将其保持在 200 以保持数据集较小。n_features
是要生成的特征数量;我们只使用两个特征,因此我们可以将它作为一个简单的问题来理解 TensorFlow 命令。n_classes
是类的数量,它是 2,因为它是二分类问题。让我们使用以下代码绘制数据:
plt.scatter(X[:,0],X[:,1],marker='o',c=y)
plt.show()
我们得到以下绘图;您可能会得到一个不同的图,因为每次运行数据生成函数时都会随机生成数据:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1EjcDt2E-1681566326313)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/mastering-tf-1x-zh/img/707586af-1084-493a-86a8-f827a115cfa5.png)]
然后我们使用 NumPy eye
函数将y
转换为单热编码目标:
print(y[0:5])
y=np.eye(num_outputs)[y]
print(y[0:5])
单热编码目标如下所示:
[1 0 0 1 0]
[[ 0\. 1.]
[ 1\. 0.]
[ 1\. 0.]
[ 0\. 1.]
[ 1\. 0.]]
将数据划分为训练和测试类别:
X_train, X_test, y_train, y_test = skms.train_test_split(
X, y, test_size=.4, random_state=42)
在分类中,我们使用 sigmoid 函数来量化模型的值,使得输出值位于范围[0,1]之间。以下等式表示由φ(z)
表示的 Sigmoid 函数,其中z
是等式w × x + b
。损失函数现在变为由J(θ)
表示的值,其中θ
表示参数。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9z9iVA6M-1681566326313)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/mastering-tf-1x-zh/img/af47d49d-2bb6-4e48-b6d3-4d7cd65ff6d5.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nBDfxRbg-1681566326314)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/mastering-tf-1x-zh/img/e5b82a11-b867-4a43-9f3d-09d6cb44099b.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GKrvVhY8-1681566326315)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/mastering-tf-1x-zh/img/717945b1-b35a-43d9-a469-44f33de91e8a.png)]
我们使用以下代码实现新模型和损失函数:
num_outputs = y_train.shape[1]
num_inputs = X_train.shape[1]
learning_rate = 0.001
# input images
x = tf.placeholder(dtype=tf.float32, shape=[None, num_inputs], name="x")
# output labels
y = tf.placeholder(dtype=tf.float32, shape=[None, num_outputs], name="y")
# model paramteres
w = tf.Variable(tf.zeros([num_inputs,num_outputs]), name="w")
b = tf.Variable(tf.zeros([num_outputs]), name="b")
model = tf.nn.sigmoid(tf.matmul(x, w) + b)
loss = tf.reduce_mean(-tf.reduce_sum(
(y * tf.log(model)) + ((1 - y) * tf.log(1 - model)), axis=1))
optimizer = tf.train.GradientDescentOptimizer(
learning_rate=learning_rate).minimize(loss)
最后,我们运行我们的分类模型:
num_epochs = 1
with tf.Session() as tfs:
tf.global_variables_initializer().run()
for epoch in range(num_epochs):
tfs.run(optimizer, feed_dict={x: X_train, y: y_train})
y_pred = tfs.run(tf.argmax(model, 1), feed_dict={x: X_test})
y_orig = tfs.run(tf.argmax(y, 1), feed_dict={y: y_test})
preds_check = tf.equal(y_pred, y_orig)
accuracy_op = tf.reduce_mean(tf.cast(preds_check, tf.float32))
accuracy_score = tfs.run(accuracy_op)
print("epoch {0:04d} accuracy={1:.8f}".format(
epoch, accuracy_score))
plt.figure(figsize=(14, 4))
plt.subplot(1, 2, 1)
plt.scatter(X_test[:, 0], X_test[:, 1], marker='o', c=y_orig)
plt.title('Original')
plt.subplot(1, 2, 2)
plt.scatter(X_test[:, 0], X_test[:, 1], marker='o', c=y_pred)
plt.title('Predicted')
plt.show()
我们获得了大约 96% 的相当好的准确率,原始和预测的数据图如下所示:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SG9WJoX7-1681566326315)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/mastering-tf-1x-zh/img/abc7eea6-1cdf-486e-9f34-0b571ef90b67.png)]
很简约!!现在让我们让我们的问题变得复杂,并尝试预测两个以上的类。
多类分类的一个流行示例是标记手写数字的图像。此示例中的类或标签为{0,1,2,3,4,5,6,7,8,9}。在以下示例中,我们将使用 MNIST。让我们像前面章节中所做的那样加载 MNIST 图像,代码如下:
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets(os.path.join(
datasetslib.datasets_root, 'mnist'), one_hot=True)
如果已按照前一章的说明下载了 MNIST 数据集,那么我们将获得以下输出:
Extracting /Users/armando/datasets/mnist/train-images-idx3-ubyte.gz
Extracting /Users/armando/datasets/mnist/train-labels-idx1-ubyte.gz
Extracting /Users/armando/datasets/mnist/t10k-images-idx3-ubyte.gz
Extracting /Users/armando/datasets/mnist/t10k-labels-idx1-ubyte.gz
现在让我们设置一些参数,如下面的代码所示:
num_outputs = 10 # 0-9 digits
num_inputs = 784 # total pixels
learning_rate = 0.001
num_epochs = 1
batch_size = 100
num_batches = int(mnist.train.num_examples/batch_size)
上面代码中的参数如下:
num_outputs
:由于我们必须预测图像代表十位数中的哪一位,因此我们将输出数设置为 10.数字由打开或设置为 1 的输出表示。num_inputs
:我们知道我们的输入数字是28 x 28
像素,因此每个像素都是模型的输入。因此,我们总共有 784 个输入。learning_rate
:此参数表示梯度下降优化器算法的学习率。我们将学习率任意设定为 0.001。num_epochs
:我们将仅针对一次迭代运行我们的第一个示例,因此我们将周期数设置为 1。batch_size
:在现实世界中,我们可能拥有庞大的数据集并加载整个数据集以便训练模型可能是不可能的。因此,我们将输入数据分成随机选择的批次。我们将batch_size
设置为 100 个图像,可以使用 TensorFlow 的内置算法一次选择。num_batches
:此参数设置应从总数据集中选择批次的次数;我们将其设置为等于数据集中的项目数除以批量中的项目数。我们鼓励您尝试使用这些参数的不同值。
现在让我们使用以下代码定义输入,输出,参数,模型和损失函数:
# input images
x = tf.placeholder(dtype=tf.float32, shape=[None, num_inputs], name="x")
# output labels
y = tf.placeholder(dtype=tf.float32, shape=[None, num_outputs], name="y")
# model paramteres
w = tf.Variable(tf.zeros([784, 10]), name="w")
b = tf.Variable(tf.zeros([10]), name="b")
model = tf.nn.softmax(tf.matmul(x, w) + b)
loss = tf.reduce_mean(-tf.reduce_sum(y * tf.log(model), axis=1))
optimizer = tf.train.GradientDescentOptimizer(
learning_rate=learning_rate).minimize(loss)
代码类似于二分类示例,但有一个显着差异:我们使用softmax
而不是sigmoid
函数。 Softmax 用于多类分类,而 sigmoid 用于二元类分类。 Softmax 函数是 sigmoid 函数的推广,它将任意实数值的 n 维向量 z 转换为实数值的 n 维向量σ(z)
,范围(0, 1]
和为 1。
现在让我们运行模型并打印精度:
with tf.Session() as tfs:
tf.global_variables_initializer().run()
for epoch in range(num_epochs):
for batch in range(num_batches):
batch_x, batch_y = mnist.train.next_batch(batch_size)
tfs.run(optimizer, feed_dict={x: batch_x, y: batch_y})
predictions_check = tf.equal(tf.argmax(model, 1), tf.argmax(y, 1))
accuracy_function = tf.reduce_mean(
tf.cast(predictions_check, tf.float32))
feed_dict = {x: mnist.test.images, y: mnist.test.labels}
accuracy_score = tfs.run(accuracy_function, feed_dict)
print("epoch {0:04d} accuracy={1:.8f}".format(
epoch, accuracy_score))
我们得到以下准确率:
epoch 0000 accuracy=0.76109999
让我们尝试在多次迭代中训练我们的模型,以便在每次迭代中学习不同的批次。我们建立了两个支持函数来帮助我们:
def mnist_batch_func(batch_size=100):
batch_x, batch_y = mnist.train.next_batch(batch_size)
return [batch_x, batch_y]
上述函数将批量中的示例数作为输入,并使用mnist.train.next_batch()
函数返回一批特征(batch_x
)和目标(batch_y
):
def tensorflow_classification(num_epochs, num_batches, batch_size,
batch_func, optimizer, test_x, test_y):
accuracy_epochs = np.empty(shape=[num_epochs], dtype=np.float32)
with tf.Session() as tfs:
tf.global_variables_initializer().run()
for epoch in range(num_epochs):
for batch in range(num_batches):
batch_x, batch_y = batch_func(batch_size)
feed_dict = {x: batch_x, y: batch_y}
tfs.run(optimizer, feed_dict)
predictions_check = tf.equal(
tf.argmax(model, 1), tf.argmax(y, 1))
accuracy_function = tf.reduce_mean(
tf.cast(predictions_check, tf.float32))
feed_dict = {x: test_x, y: test_y}
accuracy_score = tfs.run(accuracy_function, feed_dict)
accuracy_epochs[epoch] = accuracy_score
print("epoch {0:04d} accuracy={1:.8f}".format(
epoch, accuracy_score))
plt.figure(figsize=(14, 8))
plt.axis([0, num_epochs, np.min(
accuracy_epochs), np.max(accuracy_epochs)])
plt.plot(accuracy_epochs, label='Accuracy Score')
plt.title('Accuracy over Iterations')
plt.xlabel('# Epoch')
plt.ylabel('Accuracy Score')
plt.legend()
plt.show()
上述函数获取参数并执行训练迭代,打印每次迭代的准确率分数并打印准确率分数。它还可以保存accuracy_epochs
数组中每个周期的准确率分数。之后,它绘制了每个周期的准确率。让我们使用我们之前设置的参数运行此函数 30 个周期,使用以下代码:
num_epochs=30
tensorflow_classification(num_epochs=num_epochs,
num_batches=num_batches,
batch_size=batch_size,
batch_func=mnist_batch_func,
optimizer=optimizer,
test_x=mnist.test.images,test_y=mnist.test.labels)
我们得到以下准确率和图表:
epoch 0000 accuracy=0.76020002
epoch 0001 accuracy=0.79420000
epoch 0002 accuracy=0.81230003
epoch 0003 accuracy=0.82309997
epoch 0004 accuracy=0.83230001
epoch 0005 accuracy=0.83770001
--- epoch 6 to 24 removed for brevity ---
epoch 0025 accuracy=0.87930000
epoch 0026 accuracy=0.87970001
epoch 0027 accuracy=0.88059998
epoch 0028 accuracy=0.88120002
epoch 0029 accuracy=0.88180000
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Cxu4vASV-1681566326315)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/mastering-tf-1x-zh/img/19db0579-c2c6-4d7a-a4ef-a2417fc5fd2f.png)]
从图中我们可以看出,初始迭代中的准确率会急剧提高,然后准确率的提高速度会降低。稍后,我们将看到如何在 TensorFlow 中使用神经网络的全部功能,并将此分类精度提高到更大的值。
在本章中,我们学习了如何在 TensorFlow 中应用经典机器学习算法,而不使用神经网络。在本章的第一部分,我们了解了回归模型。我们解释了如何训练具有一个或多个特征的线性回归模型。我们使用 TensorFlow 编写线性回归代码。我们还讨论了正则化基本上是增加一个惩罚项,以便模型在训练阶段学习参数时不会过拟合训练数据。我们使用 TensorFlow 实现了 Lasso,Ridge 和 ElasticNet 正则化。 TensorFlow 有一些内置的正则化方法,我们将在下一章中学习。
在本章的后续章节中,我们了解了有监督机器学习中的分类问题。我们讨论了两类和多类分类的模型函数,平滑函数和损失函数。我们在本章中使用了逻辑回归,因为这是实现分类的最简单方法。对于二分类,我们使用 sigmoid 函数,对于多类分类,我们使用 softmax 函数来平滑线性模型的值,以产生输出在特定类中的概率。
我们在 TensorFlow 中实现了模型和损失函数的逻辑,并训练模型进行二分类和多类分类。虽然我们在本章中使用了经典的机器学习方法,并使用 TensorFlow 实现了它们,但是当我们实现神经网络和深度神经网络来解决机器学习问题时,TensorFlow 的全部功能得以释放。我们将在本书的神经网络相关章节中研究这些高级方法。
建议您阅读以下书籍以了解有关回归和分类的更多详细信息:
Sebastian Raschka,Python 机器学习,第 2 版,Packt Publishing,2017
Trevor Hastie,Robert Tibshirani,Jerome Friedman,统计学习的要素,第二版,施普林格,2013
神经网络是一种受大脑结构和功能启发的建模技术。正如大脑包含数百万个被称为神经元的微小互连单元一样,今天的神经网络由数百万个分层排列的微小互连计算单元组成。由于神经网络的计算单元仅存在于数字世界中,与大脑的物理神经元相反,它们也被称为人工神经元。类似地,神经网络(NN)也称为人工神经网络(ANN)。
在本章中,我们将进一步扩展以下主题:
让我们了解神经网络的最基本构建块,感知机,也称为人工神经元。感知机的概念起源于 Frank Rosenblatt 于 1962 年的作品。
您可能希望阅读以下工作来探索神经网络的起源:
Frank Rosenblatt,神经动力学原理:感知器和脑机制理论,斯巴达书籍,1962 年
在最简化的视图中,感知机被建模在生物神经元之后,使得它接收一个或多个输入并将它们组合以产生输出。
如下图所示,感知机采用三个输入并将它们相加以生成输出y
:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xefYKr7w-1681566326315)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/mastering-tf-1x-zh/img/a19eccda-749c-4dab-9020-41120070fd53.png)]
这种感知机太简单了,不具备任何实际用途。因此,通过添加权重,偏差和激活函数的概念来增强它。将权重添加到每个输入以获得加权和。如果加权和Σw[i]x[i]
小于阈值,则输出为 0,否则输出为 1:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tDa46bxZ-1681566326316)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/mastering-tf-1x-zh/img/ad008099-c40e-4e5f-bc65-721e82255fa8.png)]
阈值称为偏差。让我们将偏差移到等式的左边,用b
表示它,Σw·x
代表w
和x
的向量点积。感知机的等式现在变为如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NEzmPXAJ-1681566326316)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/mastering-tf-1x-zh/img/144a0cb4-f3e8-440c-9778-28e0f4c8b603.png)]
感知机现在看起来像下图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YvbzKvAB-1681566326316)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/mastering-tf-1x-zh/img/6c2085db-a65d-495c-96b9-4524ba54eacf.png)] Simple perceptron with weights and bias
到目前为止,神经元是一个线性函数。为了使这个神经元产生非线性决策边界,通过称为激活或传递函数的非线性函数运行求和输出。有许多流行的激活函数可用:
ReLU
:整流线性单元,将值平滑到范围(0, x)
,
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ICvcbHeW-1681566326316)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/mastering-tf-1x-zh/img/7538f31f-444e-4922-9d11-7ae37e375e4f.png)]
sigmoid
:Sigmoid 将值平滑到(0, 1)
,
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IOdw2Kfj-1681566326316)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/mastering-tf-1x-zh/img/5433180b-4099-4c59-ad7d-9ca67d6deff1.png)]
tanh
:双曲正切将值平滑到(-1, 1)
,
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NEXNPiPG-1681566326317)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/mastering-tf-1x-zh/img/bf847fab-b08c-41e5-af41-19d2bb877240.png)]
使用激活函数,感知机的等式变为:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HNDvguh4-1681566326317)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/mastering-tf-1x-zh/img/d16676a1-31ee-43ba-9f94-25cc90573568.png)]
其中φ(·)
是激活函数。
神经元看起来像下图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IoPijA2s-1681566326317)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/mastering-tf-1x-zh/img/4ec4a553-192d-42a2-bf66-e6790103a7c6.png)]
当我们将人工神经元连接在一起时,基于明确定义的结构,我们将其称为神经网络。这是一个神经元最简单的神经网络:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DoeDU9ZZ-1681566326317)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/mastering-tf-1x-zh/img/ba2849d1-c6bf-42c2-a9d3-d50f9d49de08.png)]Neural network with one neuron
我们连接神经元,使得一层的输出成为下一层的输入,直到最后一层的输出成为最终输出。这种神经网络被称为前馈神经网络(FFNN)。由于这些 FFNN 由连接在一起的神经元层组成,因此它们被称为多层感知机(MLP)或深度神经网络(DNN)。
作为示例,下图中描绘的 MLP 具有三个特征作为输入:两个隐藏层,每个神经元包含五个神经元,一个输出 y。神经元完全连接到下一层的神经元。这些层也称为致密层或仿射层,并且这种模型也称为顺序模型。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GGzRhi1L-1681566326318)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/mastering-tf-1x-zh/img/2f715ec1-4960-4c19-b0c0-150dadcdadd0.png)]
让我们重温一下我们之前探索过的一些示例数据集,并在 TensorFlow 中构建简单的神经网络(MLP 或 DNN)。
您可以按照 Jupyter 笔记本ch-05_MLP
中的代码进行操作。
让我们使用不同的库(例如 TensorFlow,Keras 和 TFLearn)构建用于图像分类的 MLP 网络。 我们将在本节中使用示例的 MNIST 数据集。
MNIST 数据集包含从 0 到 9 的手写数字的28x28
像素图像,以及它们的标签,训练集为 60K,测试集为 10K。 MNIST 数据集是使用最广泛的数据集,包括 TensorFlow 示例和教程。
让我们从纯 TensorFlow 方法开始。
首先,加载 MNIST 数据集,并使用以下代码定义训练和测试特征以及目标:
from tensorflow.examples.tutorials.mnist import input_data
mnist_home = os.path.join(datasetslib.datasets_root, 'mnist')
mnist = input_data.read_data_sets(mnist_home, one_hot=True)
X_train = mnist.train.images
X_test = mnist.test.images
Y_train = mnist.train.labels
Y_test = mnist.test.labels
num_outputs = 10 # 0-9 digits
num_inputs = 784 # total pixels
我们创建了三个辅助函数,它们将帮助我们创建一个只有一个隐藏层的简单 MLP,然后是一个更大的 MLP,每层有多个层和多个神经元。
mlp()
函数使用以下逻辑构建网络层:
mlp()
函数需要五个输入: x
是输入特征张量num_inputs
是输入特征的数量num_outputs
是输出目标的数量num_layers
是所需隐藏层数num_neurons
是包含每层神经元数量的列表 w=[]
b=[]
w_<layer_num>
和b_<layer_num>
。命名张量有助于调试和查找代码问题。tf.random_normal()
以正态分布初始化张量。num_inputs
。权重张量的第二维是当前层中的神经元的数量。 for i in range(num_layers):
# weights
w.append(tf.Variable(tf.random_normal(
[num_inputs if i == 0 else num_neurons[i - 1],
num_neurons[i]]),
name="w_{0:04d}".format(i)
))
# biases
b.append(tf.Variable(tf.random_normal(
[num_neurons[i]]),
name="b_{0:04d}".format(i)
))
w.append(tf.Variable(tf.random_normal(
[num_neurons[num_layers - 1] if num_layers > 0 else num_inputs,
num_outputs]), name="w_out"))
b.append(tf.Variable(tf.random_normal([num_outputs]),
name="b_out"))
x
视为第一个最明显的输入层:# x is input layer
layer = x
tf.nn.relu()
使线性函数tf.matmul(layer, w[i]) + b[i]
非线性化:# add hidden layers
for i in range(num_layers):
layer = tf.nn.relu(tf.matmul(layer, w[i]) + b[i])
layer = tf.matmul(layer, w[num_layers]) + b[num_layers]
layer
对象:return layer
整个 MLP 函数的完整代码如下:
def mlp(x, num_inputs, num_outputs, num_layers, num_neurons):
w = []
b = []
for i in range(num_layers):
# weights
w.append(tf.Variable(tf.random_normal(
[num_inputs if i == 0 else num_neurons[i - 1],
num_neurons[i]]),
name="w_{0:04d}".format(i)
))
# biases
b.append(tf.Variable(tf.random_normal(
[num_neurons[i]]),
name="b_{0:04d}".format(i)
))
w.append(tf.Variable(tf.random_normal(
[num_neurons[num_layers - 1] if num_layers > 0 else num_inputs,
num_outputs]), name="w_out"))
b.append(tf.Variable(tf.random_normal([num_outputs]), name="b_out"))
# x is input layer
layer = x
# add hidden layers
for i in range(num_layers):
layer = tf.nn.relu(tf.matmul(layer, w[i]) + b[i])
# add output layer
layer = tf.matmul(layer, w[num_layers]) + b[num_layers]
return layer
辅助函数mnist_batch_func()
为 MNIST 数据集包装 TensorFlow 的批量函数,以提供下一批图像:
def mnist_batch_func(batch_size=100):
X_batch, Y_batch = mnist.train.next_batch(batch_size)
return [X_batch, Y_batch]
此函数不言自明。 TensorFlow 为 MNIST 数据集提供此函数;但是,对于其他数据集,我们可能必须编写自己的批量函数。
辅助函数tensorflow_classification()
训练并评估模型。
tensorflow_classification()
函数有几个输入:n_epochs
是要运行的训练循环的数量n_batches
是应该运行每个循环中的训练的随机抽样批次的数量batch_size
是每批中的样本数batch_func
是batch_size
并返回X
和Y
样本批次的函数model
是具有神经元的实际神经网络或层optimizer
是使用 TensorFlow 定义的优化函数loss
是优化器优化参数的成本函数损失accuracy_function
是计算准确率分数的函数X_test
和Y_test
是测试的数据集with tf.Session() as tfs:
tf.global_variables_initializer().run()
n_epoch
循环来训练:for epoch in range(n_epochs):
n_batches
数量并训练模型,计算每批的损失,计算每个周期的平均损失:epoch_loss = 0.0
for batch in range(n_batches):
X_batch, Y_batch = batch_func(batch_size)
feed_dict = {x: X_batch, y: Y_batch}
_, batch_loss = tfs.run([optimizer, loss], feed_dict)
epoch_loss += batch_loss
average_loss = epoch_loss / n_batches
print("epoch: {0:04d} loss = {1:0.6f}".format(
epoch, average_loss))
accuracy_function
计算的精度分数: feed_dict = {x: X_test, y: Y_test}
accuracy_score = tfs.run(accuracy_function,
feed_dict=feed_dict)
print("accuracy={0:.8f}".format(accuracy_score))
tensorflow_classification()
函数的完整代码如下:
def tensorflow_classification(n_epochs, n_batches,
batch_size, batch_func,
model, optimizer, loss, accuracy_function,
X_test, Y_test):
with tf.Session() as tfs:
tfs.run(tf.global_variables_initializer())
for epoch in range(n_epochs):
epoch_loss = 0.0
for batch in range(n_batches):
X_batch, Y_batch = batch_func(batch_size)
feed_dict = {x: X_batch, y: Y_batch}
_, batch_loss = tfs.run([optimizer, loss], feed_dict)
epoch_loss += batch_loss
average_loss = epoch_loss / n_batches
print("epoch: {0:04d} loss = {1:0.6f}".format(
epoch, average_loss))
feed_dict = {x: X_test, y: Y_test}
accuracy_score = tfs.run(accuracy_function, feed_dict=feed_dict)
print("accuracy={0:.8f}".format(accuracy_score))
现在让我们定义输入和输出占位符,x
和y
以及其他超参数:
# input images
x = tf.placeholder(dtype=tf.float32, name="x",
shape=[None, num_inputs])
# target output
y = tf.placeholder(dtype=tf.float32, name="y",
shape=[None, num_outputs])
num_layers = 0
num_neurons = []
learning_rate = 0.01
n_epochs = 50
batch_size = 100
n_batches = int(mnist.train.num_examples/batch_size)
参数如下所述:
num_layers
是隐藏层数。我们首先练习没有隐藏层,只有输入和输出层。num_neurons
是空列表,因为没有隐藏层。learning_rate
是 0.01,随机选择的小数。num_epochs
代表 50 次迭代,以学习将输入连接到输出的唯一神经元的参数。batch_size
保持在 100,这也是一个选择问题。较大的批量大小不一定提供更高的好处。您可能需要探索不同的批量大小,以找到神经网络的最佳批量大小。n_batches
:批次数大致计算为示例数除以批次中的样本数。现在让我们将所有内容放在一起,使用到目前为止定义的变量定义网络,loss
函数,optimizer
函数和accuracy
函数。
model = mlp(x=x,
num_inputs=num_inputs,
num_outputs=num_outputs,
num_layers=num_layers,
num_neurons=num_neurons)
loss = tf.reduce_mean(
tf.nn.softmax_cross_entropy_with_logits(logits=model, labels=y))
optimizer = tf.train.GradientDescentOptimizer(
learning_rate=learning_rate).minimize(loss)
predictions_check = tf.equal(tf.argmax(model, 1), tf.argmax(y, 1))
accuracy_function = tf.reduce_mean(tf.cast(predictions_check, tf.float32))
在这段代码中,我们使用一个新的 tensorflow 函数来定义损失函数:
tf.nn.softmax_cross_entropy_with_logits(logits=model, labels=y)
当使用softmax_cross_entropy_with_logits()
函数时,请确保输出未缩放且尚未通过softmax
激活函数。 此函数在内部使用softmax
来缩放输出。
该函数计算模型之间的 softmax 熵(估计值y
)和y
的实际值。当输出属于一个类而不是一个类时,使用熵函数。在我们的示例中,图像只能属于其中一个数字。
有关此熵函数的更多信息,请参阅此链接。
一旦定义了所有内容,运行tensorflow_classification
函数来训练和评估模型:
tensorflow_classification(n_epochs=n_epochs,
n_batches=n_batches,
batch_size=batch_size,
batch_func=mnist_batch_func,
model = model,
optimizer = optimizer,
loss = loss,
accuracy_function = accuracy_function,
X_test = mnist.test.images,
Y_test = mnist.test.labels
)
我们从运行分类得到以下输出:
epoch: 0000 loss = 8.364567
epoch: 0001 loss = 4.347608
epoch: 0002 loss = 3.085622
epoch: 0003 loss = 2.468341
epoch: 0004 loss = 2.099220
epoch: 0005 loss = 1.853206
--- Epoch 06 to 45 output removed for brevity ---
epoch: 0046 loss = 0.684285
epoch: 0047 loss = 0.678972
epoch: 0048 loss = 0.673685
epoch: 0049 loss = 0.668717
accuracy=0.85720009
我们看到单个神经元网络在 50 次迭代中缓慢地将损失从 8.3 降低到 0.66,最终得到几乎 85% 的准确率。对于这个具体的例子,这是非常糟糕的准确率,因为这只是使用 TensorFlow 进行分类使用 MLP 的演示。
我们使用更多层和神经元运行相同的代码,并获得以下准确率:
层数 | 每个隐藏层中的神经元数量 | 准确率 |
---|---|---|
0 | 0 | 0.857 |
1 | 8 | 0.616 |
2 | 256 | 0.936 |
因此,通过在每层添加两行和 256 个神经元,我们将精度提高到 0.936。我们鼓励您尝试使用不同变量值的代码来观察它如何影响损失和准确率。
现在让我们与 Keras 建立相同的 MLP 网络,Keras 是 TensorFlow 的高级库。我们保留所有参数与本章中用于 TensorFlow 示例的参数相同,例如,隐藏层的激活函数保留为 ReLU 函数。
import keras
from keras.models import Sequential
from keras.layers import Dense
from keras.optimizers import SGD
X_train
,Y_train
,X_test
和Y_test
变量):num_layers = 2
num_neurons = []
for i in range(num_layers):
num_neurons.append(256)
learning_rate = 0.01
n_epochs = 50
batch_size = 100
model = Sequential()
model.add(Dense(units=num_neurons[0], activation='relu',
input_shape=(num_inputs,)))
model.add(Dense(units=num_neurons[1], activation='relu'))
model.add(Dense(units=num_outputs, activation='softmax'))
model.summary()
我们得到以下输出:
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
dense_1 (Dense) (None, 256) 200960
_________________________________________________________________
dense_2 (Dense) (None, 256) 65792
_________________________________________________________________
dense_3 (Dense) (None, 10) 2570
=================================================================
Total params: 269,322
Trainable params: 269,322
Non-trainable params: 0
_________________________________________________________________
model.compile(loss='categorical_crossentropy',
optimizer=SGD(lr=learning_rate),
metrics=['accuracy'])
model.fit(X_train, Y_train,
batch_size=batch_size,
epochs=n_epochs)
在训练模型时,我们可以观察每次训练迭代的损失和准确率:
Epoch 1/50
55000/55000 [========================] - 4s - loss: 1.1055 - acc: 0.7413
Epoch 2/50
55000/55000 [========================] - 3s - loss: 0.4396 - acc: 0.8833
Epoch 3/50
55000/55000 [========================] - 3s - loss: 0.3523 - acc: 0.9010
Epoch 4/50
55000/55000 [========================] - 3s - loss: 0.3129 - acc: 0.9112
Epoch 5/50
55000/55000 [========================] - 3s - loss: 0.2871 - acc: 0.9181
--- Epoch 6 to 45 output removed for brevity ---
Epoch 46/50
55000/55000 [========================] - 4s - loss: 0.0689 - acc: 0.9814
Epoch 47/50
55000/55000 [========================] - 4s - loss: 0.0672 - acc: 0.9819
Epoch 48/50
55000/55000 [========================] - 4s - loss: 0.0658 - acc: 0.9822
Epoch 49/50
55000/55000 [========================] - 4s - loss: 0.0643 - acc: 0.9829
Epoch 50/50
55000/55000 [========================] - 4s - loss: 0.0627 - acc: 0.9829
score = model.evaluate(X_test, Y_test)
print('\n Test loss:', score[0])
print('Test accuracy:', score[1])
我们得到以下输出:
Test loss: 0.089410082236
Test accuracy: 0.9727
笔记本ch-05_MLP
中提供了使用 Keras 进行 MNIST 分类的 MLP 的完整代码。
现在让我们看看如何使用 TFLearn 实现相同的 MLP,TFLearn 是 TensorFlow 的另一个高级库:
import tflearn
X_train
,Y_train
,X_test
和Y_test
变量):num_layers = 2
num_neurons = []
for i in range(num_layers):
num_neurons.append(256)
learning_rate = 0.01
n_epochs = 50
batch_size = 100
# Build deep neural network
input_layer = tflearn.input_data(shape=[None, num_inputs])
dense1 = tflearn.fully_connected(input_layer, num_neurons[0],
activation='relu')
dense2 = tflearn.fully_connected(dense1, num_neurons[1],
activation='relu')
softmax = tflearn.fully_connected(dense2, num_outputs,
activation='softmax')
softmax
中)定义优化器函数,神经网络和 MLP 模型(在 TFLearn 中称为 DNN):optimizer = tflearn.SGD(learning_rate=learning_rate)
net = tflearn.regression(softmax, optimizer=optimizer,
metric=tflearn.metrics.Accuracy(),
loss='categorical_crossentropy')
model = tflearn.DNN(net)
model.fit(X_train, Y_train, n_epoch=n_epochs,
batch_size=batch_size,
show_metric=True, run_id="dense_model")
训练结束后,我们得到以下输出:
Training Step: 27499 | total loss: 0.11236 | time: 5.853s
| SGD | epoch: 050 | loss: 0.11236 - acc: 0.9687 -- iter: 54900/55000
Training Step: 27500 | total loss: 0.11836 | time: 5.863s
| SGD | epoch: 050 | loss: 0.11836 - acc: 0.9658 -- iter: 55000/55000
--
score = model.evaluate(X_test, Y_test)
print('Test accuracy:', score[0])
我们得到以下输出:
Test accuracy: 0.9637
与使用 TFLearn 相比,我们获得了相当的精确度。
在笔记本ch-05_MLP
中提供了使用 TFLearn 进行 MNIST 分类的 MLP 的完整代码。
在前面的部分中,我们学习了如何使用 TensorFLow 及其高级库构建简单的 MLP 架构。纯 TensorFlow 的准确率约为 0.93-0.94,Keras 的准确率为 0.96-0.98,TFLearn 的准确率为 0.96-0.97。尽管我们的代码的所有示例都使用下面的 TensorFlow,但相同架构和参数的准确率差异可归因于这样的事实:尽管我们初始化了一些重要的超参数,但高级库和 TensorFlow 却抽象了许多其他超级 - 我们没有从默认值修改的参数。
我们观察到,与 Keras 和 TFLearn 相比,TensorFlow 中的代码非常详细和冗长。高级库使我们更容易构建和训练神经网络模型。
我们已经看到了图像数据分类的例子;现在让我们看一下时间序列数据的回归。我们将建立并使用 MLP 作为一个较小的单变量时间序列数据集,称为国际航空公司乘客数据集。该数据集包含多年来的乘客总数。该数据集可从此链接获得:
让我们从准备数据集开始。
filename = os.path.join(datasetslib.datasets_root,
'ts-data',
'international-airline-passengers-cleaned.csv')
dataframe = pd.read_csv(filename,usecols=[1],header=0)
dataset = dataframe.values
dataset = dataset.astype('float32')
datasetslib
的效用函数,我们将数据集分成测试和训练集。对于时间序列数据集,我们有一个单独的函数,不会改变观察结果,因为对于时间序列回归,我们需要维持观察的顺序。我们使用 67% 的数据进行训练,33% 的数据用于测试。您可能希望尝试使用不同比例的示例。train,test=dsu.train_test_split(dataset,train_size=0.67)
n_x
设置为 2,mvts_to_xy()
函数返回输入和输出(X
和Y
)训练和测试集,使得X
是两列具有时间{t-1, t}
的值,Y
是一列中具有时间{t + 1}
的值。我们的学习算法假设通过找到时间{t-1, t, t + 1}
的值之间的关系,可以学习时间t + 1
的值。# reshape into X=t-1,t and Y=t+1
n_x=2
n_y=1
X_train, Y_train, X_test, Y_test = tsd.mvts_to_xy(train,
test,n_x=n_x,n_y=n_y)
有关将时间序列数据集转换为监督学习问题的更多信息,请访问此链接。
现在我们在我们的训练数据集上构建和训练模型:
from keras.models import Sequential
from keras.layers import Dense
from keras.optimizers import SGD
num_layers = 2
num_neurons = [8,8]
n_epochs = 50
batch_size = 2
请注意,我们使用批量大小为 2,因为数据集非常小。我们使用两层 MLP,每层只有八个神经元,因为我们的示例问题的规模很小。
model = Sequential()
model.add(Dense(num_neurons[0], activation='relu',
input_shape=(n_x,)))
model.add(Dense(num_neurons[1], activation='relu'))
model.add(Dense(units=1))
model.summary()
model.compile(loss='mse', optimizer='adam')
model.fit(X_train, Y_train,
batch_size=batch_size,
epochs=n_epochs)
请注意,我们使用 Adam 优化器而不是 SGD。 您可能想要尝试 TensorFlow 和 Keras 中可用的不同优化器。
score = model.evaluate(X_test, Y_test)
print('\nTest mse:', score)
print('Test rmse:', math.sqrt(score))
我们得到以下输出:
Test mse: 5619.24934188
Test rmse: 74.96165247566114
# make predictions
Y_train_pred = model.predict(X_train)
Y_test_pred = model.predict(X_test)
# shift train predictions for plotting
Y_train_pred_plot = np.empty_like(dataset)
Y_train_pred_plot[:, :] = np.nan
Y_train_pred_plot[n_x-1:len(Y_train_pred)+n_x-1, :] = Y_train_pred
# shift test predictions for plotting
Y_test_pred_plot = np.empty_like(dataset)
Y_test_pred_plot[:, :] = np.nan
Y_test_pred_plot[len(Y_train_pred)+(n_x*2)-1:len(dataset)-1, :] = \
Y_test_pred
# plot baseline and predictions
plt.plot(dataset,label='Original Data')
plt.plot(Y_train_pred_plot,label='Y_train_pred')
plt.plot(Y_test_pred_plot,label='Y_test_pred')
plt.legend()
plt.show()
我们得到以下关于原始和预测时间序列值的图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-O16oIKvo-1681566326318)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/mastering-tf-1x-zh/img/3d26fd19-43da-4196-8f1f-4c19ed3040fe.png)]
如你所见,这是一个非常好的估计。然而,在现实生活中,数据本质上是多变量和复杂的。因此,我们将在后面的章节中看到时间序列数据的循环神经网络架构。
在本章中,我们了解了多层感知机。我们解释了如何为分类和回归问题构建和训练 MLP 模型。我们使用纯 TensorFlow,Keras 和 TFLearn 构建了 MLP 模型。对于分类,我们使用图像数据,对于回归,我们使用时间序列数据。
构建和训练 MLP 网络模型的技术对于任何其他类型的数据(例如数字或文本)是相同的。然而,对于图像数据集,CNN 架构已被证明是最佳架构,对于序列数据集,例如时间序列和文本,RNN 模型已被证明是最佳架构。
虽然我们在本章中仅使用简单的数据集示例来演示 MLP 架构,但在后面的章节中,我们将介绍具有一些大型和高级数据集的 CNN 和 RNN 架构。