使用 TensorFlow 构建机器学习项目:1~5

发布时间 2023-04-15 21:41:14作者: ApacheCN

原文:Building Machine Learning Projects with TensorFlow

协议:CC BY-NC-SA 4.0

译者:飞龙

本文来自【ApacheCN 深度学习 译文集】,采用译后编辑(MTPE)流程来尽可能提升效率。

不要担心自己的形象,只关心如何实现目标。——《原则》,生活原则 2.3.c

一、探索和转换数据

TensorFlow 是用于使用数据流图进行数值计算的开源软件库。 图中的节点表示数学运算,而图的边缘表示在它们之间传递的多维数据数组(张量)。

该库包含各种函数,使您能够实现和探索用于图像和文本处理的最先进的卷积神经网络(CNN)和循环神经网络(RNN)架构。 由于复杂的计算以图的形式排列,因此 TensorFlow 可用作框架,使您能够轻松开发自己的模型并将其用于机器学习领域。

它还能够在从 CPU 到移动处理器(包括高度并行的 GPU 计算)的大多数异构环境中运行,并且新的服务架构可以在所有指定选项的非常复杂的混合环境中运行:

Exploring and Transforming Data

TensorFlow 的主要数据结构 -- 张量

TensorFlow 的数据管理基于张量。 张量是来自数学领域的概念,并且是作为向量和矩阵的线性代数项的概括而开发的。

专门讨论 TensorFlow 时,张量只是在张量对象中建模的带类型的多维数组,带有其他操作。

张量属性 -- 阶数,形状和类型

如前所述,TensorFlow 使用张量数据结构表示所有数据。 任何张量都具有静态类型和动态尺寸,因此您可以实时更改张量的内部组织。

张量的另一个特性是,只有张量类型的对象才能在计算图中的节点之间传递。

现在让我们看一下张量的属性是什么(从现在开始,每次使用张量这个词时,我们都将引用 TensorFlow 的张量对象)。

张量阶数

张量阶数表示张量的维度方面,但与矩阵阶数不同。 它表示张量所处的维数,而不是行/列或等效空间中张量扩展的精确度量。

秩为 1 的张量等于向量,秩为 2 的张量是矩阵。 对于二阶张量,您可以使用语法t[i, j]访问任何元素。 对于三阶张量,您将需要使用t[i, j, k]来寻址元素,依此类推。

在下面的示例中,我们将创建一个张量,并访问其分量之一:

>>> import tensorflow as tf 
>>> tens1 = tf.constant([[[1,2],[2,3]],[[3,4],[5,6]]]) 
>>> print sess.run(tens1)[1,1,0] 
5 

这是三阶张量,因为在包含矩阵的每个元素中都有一个向量元素:

数学实体 代码定义示例
0 标量 scalar = 1000
1 向量 vector = [2, 8, 3]
2 矩阵 matrix = [[4, 2, 1], [5, 3, 2], [5, 5, 6]]
3 3 阶张量 tensor = [[[4], [3], [2]], [[6], [100], [4]], [[5], [1], [4]]]
n n 阶张量 ...

张量形状

TensorFlow 文档使用三种符号约定来描述张量维数:阶数,形状和维数。 下表显示了它们之间的相互关系:

形状 维度数量 示例
0 [] 0 4
1 [D0] 1 [2]
2 [D0,D1] 2 [6, 2]
3 [D0,D1,D2] 3 [7, 3, 2]
n [D0,D1,... Dn-1] d 形状为[D0, D1, ..., Dn-1]的张量。

在下面的示例中,我们创建一个样本阶数三张量,并打印其形状:

Tensor shape

张量数据类型

除了维数外,张量还具有固定的数据类型。 您可以将以下任意一种数据类型分配给张量:

数据类型 Python 类型 描述
DT_FLOAT tf.float32 32 位浮点。
DT_DOUBLE tf.float64 64 位浮点。
DT_INT8 tf.int8 8 位有符号整数。
DT_INT16 tf.int16 16 位有符号整数。
DT_INT32 tf.int32 32 位有符号整数。
DT_INT64 tf.int64 64 位有符号整数。
DT_UINT8 tf.uint8 8 位无符号整数。
DT_STRING tf.string 可变长度字节数组。 张量的每个元素都是一个字节数组。
DT_BOOL tf.bool 布尔值。

创建新的张量

我们可以创建自己的张量,也可以从著名的 numpy 库派生它们。 在以下示例中,我们创建一些 numpy 数组,并对其进行一些基本数学运算:

import tensorflow as tf
import numpy as np
x = tf.constant(np.random.rand(32).astype(np.float32))
y=  tf.constant ([1,2,3])

从 numpy 到张量,以及反向

TensorFlow 可与 numpy 互操作,通常eval()函数调用将返回一个 numpy 对象,准备与标准数值工具一起使用。

提示

我们必须注意,张量对象是操作结果的符号句柄,因此它不保存其包含的结构的结果值。 因此,我们必须运行eval()方法来获取实际值,该值等于Session.run(tensor_to_eval)

在此示例中,我们构建了两个 numpy 数组,并将它们转换为张量:

import tensorflow as tf #we import tensorflow 
import numpy as np   #we import numpy 
sess = tf.Session() #start a new Session Object 
x_data = np.array([[1.,2.,3.], 
[3.,2.,6.]]) # 2x3 matrix 
x = tf.convert_to_tensor(x_data, dtype=tf.float32) #Finally, we create the tensor, starting from the fload 3x matrix 

有用的方法

tf.convert_to_tensor:此函数将各种类型的 Python 对象转换为张量对象。 它接受张量对象,numpy 数组,Python 列表和 Python 标量。

完成工作 -- 与 TensorFlow 交互

与大多数 Python 模块一样,TensorFlow 允许使用 Python 的交互式控制台:

Getting things done - interacting with TensorFlow

与 Python 的解释器和 TensorFlow 库轻松交互

在上图中,我们调用 Python 解释器(通过简单地调用 Python)并创建常量类型的张量。 然后我们再次调用它,Python 解释器显示张量的形状和类型。

我们还可以使用 IPython 解释器,该解释器将允许我们采用与笔记本样式工具(例如 Jupyter)更兼容的格式:

Getting things done - interacting with TensorFlow

IPython 提示

在谈论以交互方式运行 TensorFlow 会话时,最好使用InteractiveSession对象。

与普通的tf.Session类不同,tf.InteractiveSession类将自身安装为构造时的默认会话。 因此,当您尝试求值张量或运行操作时,将不需要传递Session对象来指示它所引用的会话。

处理计算工作流程 -- TensorFlow 的数据流程图

TensorFlow 的数据流图是模型计算如何工作的符号表示:

Handling the computing workflow - TensorFlow's data flow graph

在 TensorBoard 上绘制的简单数据流图表示

简而言之,数据流图是一个完整的 TensorFlow 计算,表示为一个图,其中节点是操作,边是操作之间的数据流。

通常,节点执行数学运算,但也表示连接以输入数据或变量,或推出结果。

边缘描述节点之间的输入/输出关系。 这些数据边仅传输张量。 节点被分配给计算设备,并且一旦它们进入边缘上的所有张量都可用,就会异步并行执行。

所有运算都有一个名称,并表示一个抽象计算(例如,矩阵求逆或乘积)。

计算图构建

通常在库用户创建张量和模型将支持的操作时构建计算图,因此无需直接构建Graph()对象。 Python 张量构造器,例如tf.constant(),会将必要的元素添加到默认图。 TensorFlow 操作也会发生同样的情况。

例如,c = tf.matmul(a, b)创建一个MatMul类型的操作,该操作将张量ab作为输入并产生c作为输出。

有用的操作对象方法

  • tf.Operation.type:返回操作的类型(例如MatMul
  • tf.Operation.inputs:返回代表操作输入的张量对象列表
  • tf.Graph.get_operations():返回图中的操作列表
  • tf.Graph.version:返回图的自动数字版本

馈送

TensorFlow 还提供了一种馈送机制,可将张量直接修补到图中的任何操作中。

提要用张量值临时替换操作的输出。 您将提要数据作为run()调用的参数提供。 提要仅用于传递给它的运行调用。 最常见的用例涉及通过使用tf.placeholder()创建特定的操作,使其指定为feed操作。

变量

在大多数计算中,图执行多次。 大多数张量都无法通过图的一次执行而幸存。 但是,变量是一种特殊的操作,它可以将句柄返回到持久可变的张量,该张量在图执行过程中仍然存在。 对于 TensorFlow 的机器学习应用,模型的参数通常存储在变量中保存的张量中,并在运行模型的训练图时进行更新。

变量初始化

要初始化变量,只需使用张量作为参数调用Variable对象构造器。

在此示例中,我们使用1000零数组初始化了一些变量:

b = tf.Variable(tf.zeros([1000])) 

保存数据流程图

数据流图是使用 Google 的协议缓冲区编写的,因此以后可以使用多种语言进行读取。

图序列化语言 -- 协议缓冲区

协议缓冲区是一种不依赖语言,不依赖平台的可扩展机制,用于序列化结构化数据。 首先定义数据结构,然后可以使用专门生成的代码来使用多种语言进行读写。

有用的方法

tf.Graph.as_graph_def(from_version=None, add_shapes=False):返回此图的序列化GraphDef表示形式。

参数:

  • from_version:如果设置了此选项,它将返回带有从该版本添加的节点的GraphDef
  • add_shapes:如果true,则向每个节点添加一个shape属性

建立图的示例

在此示例中,我们将构建一个非常简单的数据流图,并观察生成的 protobuffer 文件的概述:

import tensorflow as tf 
g = tf.Graph() 
with g.as_default(): 
import tensorflow as tf 
sess = tf.Session() 
W_m = tf.Variable(tf.zeros([10, 5])) 
x_v = tf.placeholder(tf.float32, [None, 10]) 
result = tf.matmul(x_v, W_m) 
print g.as_graph_def() 

生成的 protobuffer(摘要)为:

node {
  name: "zeros"
  op: "Const"
  attr {
    key: "dtype"
    value {
      type: DT_FLOAT
    }
  }
  attr {
    key: "value"
    value {
      tensor {
        dtype: DT_FLOAT
        tensor_shape {
          dim {
            size: 10
          }
          dim {
            size: 5
          }
        }
        float_val: 0.0
      }
    }
  }
}
...
node {
  name: "MatMul"
  op: "MatMul"
  input: "Placeholder"
  input: "Variable/read"
  attr {
    key: "T"
    value {
      type: DT_FLOAT
    }
  }
...
}
versions {
  producer: 8
}

运行我们的程序 -- 会话

客户端程序通过创建会话与 TensorFlow 系统交互。 会话对象表示将在其中运行计算的环境。 Session对象开始为空,并且当程序员创建不同的操作和张量时,它们将被自动添加到Session中,在调用Run()方法之前,该对象不会进行任何计算。

Run()方法采用一组需要计算的输出名称,以及一组可选的张量,以代替节点的某些输出输入到图中。

如果调用此方法,并且命名操作依赖于某些操作,则Session对象将执行所有这些操作,然后继续执行命名操作。

这条简单的线是创建会话所需的唯一一行:

s = tf.Session()
Sample command line output:
tensorflow/core/common_runtime/local_session.cc:45]Localsessioninteropparallelism threads:6

基本张量方法

在本节中,我们将探索 TensorFlow 支持的一些基本方法。 它们对于初始数据探索和为更好的并行计算准备数据很有用。

简单矩阵运算

TensorFlow 支持许多更常见的矩阵运算,例如转置,乘法,获取行列式和逆运算。

这是应用于样本数据的那些函数的一个小例子:

In [1]: import tensorflow as tf 
In [2]: sess = tf.InteractiveSession() 
In [3]: x = tf.constant([[2, 5, 3, -5], 
...:                  [0, 3,-2,  5], 
...:                  [4, 3, 5,  3], 
...:                  [6, 1, 4,  0]]) 

In [4]: y = tf.constant([[4, -7, 4, -3, 4], 
...:                  [6, 4,-7,  4, 7], 
...:                  [2, 3, 2,  1, 4], 
...:                  [1, 5, 5,  5, 2]]) 
In [5]: floatx = tf.constant([[2., 5., 3., -5.], 
...:                       [0., 3.,-2.,  5.], 
...:                       [4., 3., 5.,  3.], 
...:                       [6., 1., 4.,  0.]]) 
In [6]: tf.transpose(x).eval() # Transpose matrix 
Out[6]: 
array([[ 2,  0,  4,  6], 
[ 5,  3,  3,  1], 
[ 3, -2,  5,  4], 
[-5,  5,  3,  0]], dtype=int32) 

In [7]: tf.matmul(x, y).eval() # Matrix multiplication 
Out[7]: 
array([[ 39, -10, -46,  -8,  45], 
[ 19,  31,   0,  35,  23], 
[ 47,  14,  20,  20,  63], 
[ 38, -26,  25, -10,  47]], dtype=int32) 

In [8]: tf.matrix_determinant(floatx).eval() # Matrix determinant 
Out[8]: 818.0 

In [9]: tf.matrix_inverse(floatx).eval() # Matrix inverse 
Out[9]: 
array([[-0.00855745,  0.10513446, -0.18948655,  0.29584351], 
[ 0.12958434,  0.12224938,  0.01222495, -0.05134474], 
[-0.01955992, -0.18826403,  0.28117359, -0.18092911], 
[-0.08557458,  0.05134474,  0.10513448, -0.0415648 ]], dtype=float32) 

In [10]: tf.matrix_solve(floatx, [[1],[1],[1],[1]]).eval() # Solve Matrix system 
Out[10]: 
array([[ 0.20293398], 
[ 0.21271393], 
[-0.10757945], 
[ 0.02933985]], dtype=float32) 

归约

归约运算是对张量的一个维度进行运算的操作,而其维数较小。

支持的操作(具有相同参数)包括乘积,最小值,最大值,平均值,所有,任意和accumulate_n)。

In [1]: import tensorflow as tf 

In [2]: sess = tf.InteractiveSession() 
In [3]: x = tf.constant([[1,  2, 3], 
...:                  [3,  2, 1], 
...:                  [-1,-2,-3]]) 
In [4]: 

In [4]: boolean_tensor = tf.constant([[True,  False, True], 
...:                  [False, False, True], 
...:                  [True, False, False]]) 

In [5]: tf.reduce_prod(x, reduction_indices=1).eval() # reduce prod 
Out[5]: array([ 6,  6, -6], dtype=int32) 

In [6]: tf.reduce_min(x, reduction_indices=1).eval() # reduce min 
Out[6]: array([ 1,  1, -3], dtype=int32) 

In [7]: tf.reduce_max(x, reduction_indices=1).eval() # reduce max 
Out[7]: array([ 3,  3, -1], dtype=int32) 

In [8]: tf.reduce_mean(x, reduction_indices=1).eval() # reduce mean 
Out[8]: array([ 2,  2, -2], dtype=int32) 

In [9]: tf.reduce_all(boolean_tensor, reduction_indices=1).eval() # reduce all 
Out[9]: array([False, False, False], dtype=bool) 

In [10]: tf.reduce_any(boolean_tensor, reduction_indices=1).eval() # reduce any 
Out[10]: array([ True,  True,  True], dtype=bool) 

张量分段

张量分段是一个过程,其中某个维度被归约,并且所得元素由索引行确定。 如果该行中的某些元素被重复,则对应的索引将转到其中的值,并且该操作将在具有重复索引的索引之间应用。

索引数组的大小应与索引数组的维度 0 的大小相同,并且必须增加 1。

Tensor segmentation

细分说明(重做)

In [1]: import tensorflow as tf 
In [2]: sess = tf.InteractiveSession() 
In [3]: seg_ids = tf.constant([0,1,1,2,2]); # Group indexes : 0|1,2|3,4 
In [4]: tens1 = tf.constant([[2, 5, 3, -5], 
...:                     [0, 3,-2,  5], 
...:                     [4, 3, 5,  3], 
...:                     [6, 1, 4,  0], 
...:                     [6, 1, 4,  0]])  # A sample constant matrix 

In [5]: tf.segment_sum(tens1, seg_ids).eval()   # Sum segmentation 
Out[5]: 
array([[ 2,  5,  3, -5], 
[ 4,  6,  3,  8], 
[12,  2,  8,  0]], dtype=int32) 

In [6]: tf.segment_prod(tens1, seg_ids).eval() # Product segmentation 
Out[6]: 
array([[  2,   5,   3,  -5], 
[  0,   9, -10,  15], 
[ 36,   1,  16,   0]], dtype=int32) 

In [7]: tf.segment_min(tens1, seg_ids).eval() # minimun value goes to group 
Out[7]: 
array([[ 2,  5,  3, -5], 
[ 0,  3, -2,  3], 
[ 6,  1,  4,  0]], dtype=int32) 

In [8]: tf.segment_max(tens1, seg_ids).eval() # maximum value goes to group 
Out[8]: 
array([[ 2,  5,  3, -5], 
[ 4,  3,  5,  5], 
[ 6,  1,  4,  0]], dtype=int32) 

In [9]: tf.segment_mean(tens1, seg_ids).eval() # mean value goes to group 
Out[9]: 
array([[ 2,  5,  3, -5], 
[ 2,  3,  1,  4], 
[ 6,  1,  4,  0]], dtype=int32) 

序列

序列工具包括诸如argminargmax(显示维度的最小值和最大值),listdiff(显示列表之间交集的补码),where(显示真实值的索引)和unique(在列表上显示唯一值)之类的张量方法。

In [1]: import tensorflow as tf 
In [2]: sess = tf.InteractiveSession() 
In [3]: x = tf.constant([[2, 5, 3, -5], 
...:                  [0, 3,-2,  5], 
...:                  [4, 3, 5,  3], 
...:                  [6, 1, 4,  0]]) 
In [4]: listx = tf.constant([1,2,3,4,5,6,7,8]) 
In [5]: listy = tf.constant([4,5,8,9]) 

In [6]: 

In [6]: boolx = tf.constant([[True,False], [False,True]]) 

In [7]: tf.argmin(x, 1).eval() # Position of the maximum value of columns 
Out[7]: array([3, 2, 1, 3]) 

In [8]: tf.argmax(x, 1).eval() # Position of the minimum value of rows 
Out[8]: array([1, 3, 2, 0]) 

In [9]: tf.listdiff(listx, listy)[0].eval() # List differences 
Out[9]: array([1, 2, 3, 6, 7], dtype=int32) 

In [10]: tf.where(boolx).eval() # Show true values 
Out[10]: 
array([[0, 0], 
[1, 1]]) 

In [11]: tf.unique(listx)[0].eval() # Unique values in list 
Out[11]: array([1, 2, 3, 4, 5, 6, 7, 8], dtype=int32) 

张量形状变换

这些操作与矩阵形状有关,用于调整不匹配的数据结构并检索有关数据量度的快速信息。 这在确定运行时的处理策略时很有用。

在以下示例中,我们将从第二张量张量开始,并将打印有关它的一些信息。

然后,我们将探讨按维度修改矩阵的操作,包括添加或删除维度,例如squeezeexpand_dims

In [1]: import tensorflow as tf 
In [2]: sess = tf.InteractiveSession() 
In [3]: x = tf.constant([[2, 5, 3, -5], 
...:                  [0, 3,-2,  5], 
...:                  [4, 3, 5,  3], 
...:                  [6, 1, 4,  0]]) 

In [4]: tf.shape(x).eval() # Shape of the tensor 
Out[4]: array([4, 4], dtype=int32) 

In [5]: tf.size(x).eval() # size of the tensor 
Out[5]: 16 

In [6]: tf.rank(x).eval() # rank of the tensor 
Out[6]: 2 

In [7]: tf.reshape(x, [8, 2]).eval() # converting to a 10x2 matrix 
Out[7]: 
array([[ 2,  5], 
[ 3, -5], 
[ 0,  3], 
[-2,  5], 
[ 4,  3], 
[ 5,  3], 
[ 6,  1], 
[ 4,  0]], dtype=int32) 

In [8]: tf.squeeze(x).eval() #  squeezing 
Out[8]: 
array([[ 2,  5,  3, -5], 
[ 0,  3, -2,  5], 
[ 4,  3,  5,  3], 
[ 6,  1,  4,  0]], dtype=int32) 

In [9]: tf.expand_dims(x,1).eval() #Expanding dims 
Out[9]: 
array([[[ 2,  5,  3, -5]], 
[[ 0,  3, -2,  5]], 
[[ 4,  3,  5,  3]], 
[[ 6,  1,  4,  0]]], dtype=int32) 

张量切片和合并

为了从大型数据集中提取和合并有用的信息,切片和联接方法使您可以合并所需的列信息,而不必使用非特定信息来占用内存空间。

在以下示例中,我们将提取矩阵切片,对其进行分割,添加填充以及对行进行打包和解包:

In [1]: import tensorflow as tf 
In [2]: sess = tf.InteractiveSession() 
In [3]: t_matrix = tf.constant([[1,2,3], 
...:                         [4,5,6], 
...:                         [7,8,9]]) 
In [4]: t_array = tf.constant([1,2,3,4,9,8,6,5]) 
In [5]: t_array2= tf.constant([2,3,4,5,6,7,8,9]) 

In [6]: tf.slice(t_matrix, [1, 1], [2,2]).eval() # cutting an slice 
Out[6]: 
array([[5, 6], 
[8, 9]], dtype=int32) 

In [7]: tf.split(0, 2, t_array) # splitting the array in two 
Out[7]: 
[<tf.Tensor 'split:0' shape=(4,) dtype=int32>, 
<tf.Tensor 'split:1' shape=(4,) dtype=int32>] 

In [8]: tf.tile([1,2],[3]).eval() # tiling this little tensor 3 times 
Out[8]: array([1, 2, 1, 2, 1, 2], dtype=int32) 

In [9]: tf.pad(t_matrix, [[0,1],[2,1]]).eval() # padding 
Out[9]: 
array([[0, 0, 1, 2, 3, 0], 
[0, 0, 4, 5, 6, 0], 
[0, 0, 7, 8, 9, 0], 
[0, 0, 0, 0, 0, 0]], dtype=int32) 

In [10]: tf.concat(0, [t_array, t_array2]).eval() #concatenating list 
Out[10]: array([1, 2, 3, 4, 9, 8, 6, 5, 2, 3, 4, 5, 6, 7, 8, 9], dtype=int32) 

In [11]: tf.pack([t_array, t_array2]).eval() # packing 
Out[11]: 
array([[1, 2, 3, 4, 9, 8, 6, 5], 
[2, 3, 4, 5, 6, 7, 8, 9]], dtype=int32) 

In [12]: sess.run(tf.unpack(t_matrix)) # Unpacking, we need the run method to view the tensors 
Out[12]: 
[array([1, 2, 3], dtype=int32), 
array([4, 5, 6], dtype=int32), 
array([7, 8, 9], dtype=int32)] 

In [13]: tf.reverse(t_matrix, [False,True]).eval() # Reverse matrix 
Out[13]: 
array([[3, 2, 1], 
[6, 5, 4], 
[9, 8, 7]], dtype=int32) 

数据流结构和结果可视化 -- TensorBoard

可视化摘要信息是任何数据科学家工具箱的重要组成部分。

TensorBoard 是一个软件工具,它允许数据流图的图形表示和用于解释结果的仪表板,通常来自日志记录工具:

Dataflow structure and results visualization - TensorBoard

TensorBoard GUI

可以将图的所有张量和操作设置为将信息写入日志。 TensorBoard 分析在Session运行时正常编写的信息,并向用户显示许多图形项,每个图形项一个。

命令行用法

要调用 TensorBoard,命令行为:

Command line use

TensorBoard 的工作方式

我们构建的每个计算图都有 TensorFlow 的实时日志记录机制,以便保存模型拥有的几乎所有信息。

但是,模型构建者必须考虑应保存的几百个信息维中的哪一个,以后才能用作分析工具。

为了保存所有必需的信息,TensorFlow API 使用了称为摘要的数据输出对象。

这些摘要将结果写入 TensorFlow 事件文件,该文件收集在Session运行期间生成的所有必需数据。

在以下示例中,我们将直接在生成的事件日志目录上运行 TensorBoard:

How TensorBoard works

添加摘要节点

TensorFlow 会话中的所有摘要均由SummaryWriter对象编写。 调用的主要方法是:

tf.train.SummaryWriter.__init__(logdir, graph_def=None) 

该命令将在参数的路径中创建一个SummaryWriter和一个事件文件。

SummaryWriter的构造器将在logdir中创建一个新的事件文件。 当您调用以下函数之一时,此事件文件将包含Event类型的协议缓冲区:add_summary()add_session_log()add_event()add_graph()

如果将graph_def协议缓冲区传递给构造器,则会将其添加到事件文件中。 (这等效于稍后调用add_graph())。

当您运行 TensorBoard 时,它将从文件中读取图定义并以图形方式显示它,以便您可以与其进行交互。

首先,创建您要从中收集摘要数据的 TensorFlow 图,并确定要使用摘要操作标注的节点。

TensorFlow 中的操作在您运行它们或取决于它们的输出的操作之前不会做任何事情。 我们刚刚创建的摘要节点是图的外围:当前运行的所有操作都不依赖于它们。 因此,要生成摘要,我们需要运行所有这些摘要节点。 手动管理它们很繁琐,因此请使用tf.merge_all_summaries将它们组合为一个可生成所有摘要数据的操作。

然后,您可以运行合并的摘要操作,这将在给定步骤中生成一个包含所有摘要数据的序列化摘要protobuf对象。 最后,要将摘要数据写入磁盘,请将摘要protobuf传递给tf.train.SummaryWriter

SummaryWriter在其构造器中带有logdir,此logdir非常重要,它是所有事件将被写出的目录。 同样,SummaryWriter可以选择在其构造器中使用GraphDef。 如果收到一个,TensorBoard 还将可视化您的图。

现在,您已经修改了图并具有SummaryWriter,就可以开始运行网络了! 如果需要,您可以在每个步骤中运行合并的摘要操作,并记录大量的训练数据。 不过,这可能是您需要的更多数据。 相反,请考虑每 n 个步骤运行一次合并的摘要操作。

通用摘要操作

这是不同的摘要类型及其构造所使用的参数的列表:

  • tf.scalar_summary(label, value, collection=None, name=None)
  • tf.image_summary(label, tensor, max_images=3, collection=None, name=None)
  • tf.histogram_summary(label, value, collection=None, name=None)

特殊摘要函数

这些是特殊函数,用于合并不同操作的值,无论是摘要的集合,还是图中的所有摘要:

  • tf.merge_summary(input, collection=None, name=None)
  • tf.merge_all_summaries(key="summary")

最后,作为提高可读性的最后一项帮助,可视化对常数和汇总节点使用特殊的图标。 总而言之,这是节点符号表:

符号 含义
Special Summary functions 代表名称范围的高级节点。 双击以展开一个高级节点。
Special Summary functions 彼此不连接的编号节点序列。
Special Summary functions 彼此连接的编号节点序列。
Special Summary functions 单个操作节点。
Special Summary functions 一个常数。
Special Summary functions 摘要节点。
Special Summary functions 显示操作之间的数据流的边。
Special Summary functions 显示操作之间的控制依赖项的边。
Special Summary functions 显示输出操作节点可以改变输入张量的参考边。

与 TensorBoard 的 GUI 交互

通过平移和缩放来浏览图形。单击并拖动以进行平移,然后使用滚动手势进行缩放。 双击节点,或单击其+按钮,以展开表示操作代码的名称范围。 为了轻松跟踪缩放时的当前视点,右下角有一个小地图:

Interacting with TensorBoard's GUI

具有一个扩展的操作组和图例的 Openflow

要关闭打开的节点,请再次双击它或单击其-按钮。 您也可以单击一次以选择一个节点。 它将变为较暗的颜色,有关该颜色及其连接的节点的详细信息将显示在可视化文件右上角的信息卡中。

选择还有助于理解高级节点。 选择任何高度节点,其他连接的相应节点图标也会被选择。 例如,这可以轻松查看正在保存的节点和未保存的节点。

单击信息卡中的节点名称将其选中。 如有必要,视点将自动平移以使该节点可见。

最后,您可以使用图例上方的颜色菜单为图形选择两种配色方案。 默认的“结构视图”显示结构:当两个高级节点具有相同的结构时,它们以相同的彩虹色显示。 唯一结构化的节点为灰色。 第二个视图显示了不同操作在哪个设备上运行。 名称范围的颜色与设备中用于其内部操作的部分的比例成比例。

从磁盘读取信息

TensorFlow 读取许多最标准的格式,包括众所周知的 CSV,图像文件(JPG 和 PNG 解码器)以及标准 TensorFlow 格式。

列表格式 -- CSV

为了读取众所周知的 CSV 格式,TensorFlow 有自己的方法。 与其他库(例如熊猫)相比,读取简单 CSV 文件的过程稍微复杂一些。

读取 CSV 文件需要完成前面的几个步骤。 首先,我们必须使用要使用的文件列表创建文件名队列对象,然后创建TextLineReader。 使用此行读取器,剩下的操作将是解码 CSV 列,并将其保存在张量上。 如果我们想将同类数据混合在一起,则pack方法将起作用。

鸢尾花数据集

鸢尾花数据集或费舍尔鸢尾花数据集是分类问题的众所周知基准。 这是罗纳德·费舍尔(Ronald Fisher)在 1936 年的论文中引入的多元数据集,该分类法是将生物分类问题中的多次测量用作线性判别分析的示例。

数据集包含来自三种鸢尾花(鸢尾鸢尾,初春鸢尾和杂色鸢尾)中每种的 50 个样本。 在每个样本中测量了四个特征:萼片和花瓣的长度和宽度,以厘米为单位。 基于这四个特征的组合,Fisher 开发了一个线性判别模型以区分物种。 (您可以在书的代码包中获取此数据集的.csv文件。)

为了读取 CSV 文件,您必须下载它并将其放在与 Python 可执行文件运行所在的目录中。

在下面的代码示例中,我们将从知名的鸢尾数据库中读取和打印前五个记录:

import tensorflow as tf 
sess = tf.Session() 
filename_queue = tf.train.string_input_producer( 
tf.train.match_filenames_once("./*.csv"), 
shuffle=True) 
reader = tf.TextLineReader(skip_header_lines=1) 
key, value = reader.read(filename_queue) 
record_defaults = [[0.], [0.], [0.], [0.], [""]] 
col1, col2, col3, col4, col5 = tf.decode_csv(value, record_defaults=record_defaults)  # Convert CSV records to tensors. Each column maps to one tensor. 
features = tf.pack([col1, col2, col3, col4]) 

tf.initialize_all_variables().run(session=sess) 
coord = tf.train.Coordinator() 
threads = tf.train.start_queue_runners(coord=coord, sess=sess) 

for iteration in range(0, 5):
 example = sess.run([features])
 print(example)
 coord.request_stop()
 coord.join(threads)

这就是输出的样子:

The Iris dataset

读取图像数据

TensorFlow 允许从图像格式导入数据,这对于导入面向图像的模型的自定义图像输入将非常有用。可接受的图像格式将为 JPG 和 PNG,内部表示形式为uint8张量,每个张量为图片通道的二阶张量:

Reading image data

要读取的样本图像

加载和处理图像

在此示例中,我们将加载示例图像并对其进行一些其他处理,将生成的图像保存在单独的文件中:

import tensorflow as tf 
sess = tf.Session() 
filename_queue = tf.train.string_input_producer(tf.train.match_filenames_once("./blue_jay.jpg")) 
reader = tf.WholeFileReader() 
key, value = reader.read(filename_queue) 
image=tf.image.decode_jpeg(value) 
flipImageUpDown=tf.image.encode_jpeg(tf.image.flip_up_down(image)) 
flipImageLeftRight=tf.image.encode_jpeg(tf.image.flip_left_right(image)) 
tf.initialize_all_variables().run(session=sess) 
coord = tf.train.Coordinator() 
threads = tf.train.start_queue_runners(coord=coord, sess=sess) 
example = sess.run(flipImageLeftRight) 
print example 
file=open ("flippedUpDown.jpg", "wb+") 
file.write (flipImageUpDown.eval(session=sess)) 
file.close() 
file=open ("flippedLeftRight.jpg", "wb+") 
file.write (flipImageLeftRight.eval(session=sess)) 
file.close() 

print example行将逐行显示图像中 RGB 值的摘要:

Loading and processing the images

最终图像如下所示:

Loading and processing the images

比较原始图像和变更后的图像(上下翻转和左右翻转)

从标准 TensorFlow 格式读取

另一种方法是将您拥有的任意数据转换为正式格式。 这种方法使混合和匹配数据集和网络架构变得更加容易。

您可以编写一个获取数据的小程序,将其填充到示例协议缓冲区中,将协议缓冲区序列化为字符串,然后使用tf.python_io.TFRecordWriter类将字符串写入TFRecords文件。

要读取TFRecords的文件,请将tf.TFRecordReadertf.parse_single_example解码器一起使用。 parse_single_example op将示例协议缓冲区解码为张量。

总结

在本章中,我们学习了可应用于数据的主要数据结构和简单操作,并对计算图的各个部分进行了简要总结。

这些操作将成为即将出现的技术的基础。 通过这些类,数据科学家可以在查看当前数据的总体特征之后,确定类的分离或调整特征是否足够清晰,或者直接使用更复杂的工具,从而决定是否使用更简单的模型。

在下一章中,我们将开始构建和运行图,并使用本章中介绍的某些方法来解决问题。

二、聚类

在本章中,我们将开始应用在上一章中学到的数据转换操作,并开始使用聚类技术在某些给定信息中找到有趣的模式,发现数据组或集群。

在此过程中,我们还将获得两个新工具:能够通过 scikit-learn 库从一组代表性数据结构中生成合成样本集,并且能够通过 matplotlib 库以图形方式绘制我们的数据和模型结果 。

我们将在本章中介绍的主题如下:

  • 了解群集的工作原理,并将其与替代的现有分类技术进行比较
  • 使用 scikit-learn 和 matplotlib 丰富数据集选择的可能性,并获得看起来专业的数据图形表示
  • 实现 K 均值聚类算法
  • 实现最近邻法,并将结果与​​K 均值进行比较

从数据中学习 -- 无监督学习

在本章中,我们将回顾两种无监督学习的情况。

无监督学习基本上包括在先前的数据集中查找模式。 通常,很少或没有信息提供给该技术,并且该过程应该能够自动确定信息的组织方式,并识别数据组织中的不同结构。

聚类

最初可用于未标记数据集的最简单的操作之一是尝试了解数据集成员共同特征的可能组。

为此,可以将数据集划分为任意数量的段,其中每个段都可以表示为中心质量(质心)点,该点代表属于已确定组或聚类的点。

为了定义将同一组分配给不同组成员的标准,我们需要定义一个表示数据元素之间距离的概念,因此我们可以简单地说,所有类成员比任何其他质心更接近自己的质心 。

在下图中,我们可以看到典型聚类算法的结果以及聚类中心的表示形式:

Clustering

样本聚类算法输出

K 均值

K 均值是一种非常流行的聚类算法,可以轻松实现。 这非常简单,将它作为具有良好类分离性的数据集的第一个过程应用,可以对数据有很好的先验理解。

K 均值的原理

K 均值尝试使用成员的平均值作为主要指标,将一组样本分成 k 个不相交的组或簇。 这一点通常称为质心,指代具有相同名称的算术实体,并表示为任意尺寸空间中的向量。

K 均值是一种幼稚的方法,因为它通过查找适当的质心而起作用,但是不知道先验簇的数量是多少。

为了评估多少簇能够很好地表示所提供的数据,Elbow 方法是一种比较流行的方法。

算法迭代准则

此方法的标准和目标是最小化从群集成员到所有包含群集的样本的实际质心的平方距离之和。 这也称为惯性最小化。

Algorithm iteration criterion

K 均值的误差最小化准则

K 均值算法细分

K 均值算法的机制可以通过以下流程图总结:

k-means algorithm breakdown

K 均值过程的简化流程图

该算法可以简化如下:

  1. 我们从未分类的样本开始,以 k 个元素为起始质心。 为了简洁起见,也可以简化此算法,使元素列表中的第一个元素成为第一个元素。
  2. 然后,我们计算样本与首先选择的样本之间的距离,并获得第一个计算出的质心(或其他代表值)。 您可以看到图中的质心向着更常识的质心移动。
  3. 形心更改后,它们的位移将引起各个距离发生更改,因此群集成员身份可能会更改。
  4. 这是我们重新计算质心并在不满足停止条件的情况下重复第一步的时候。

停止条件可以有多种类型:

  • 在 N 次迭代之后,可能是要么我们选择了一个非常大的数,然后我们将进行不必要的计算,否则它可能会收敛得很慢,并且如果质心没有非常稳定的方法,我们将得到非常令人难以置信的结果。 如果我们有一个很长的迭代过程,那么这个停止条件也可以作为最后的手段。
  • 参考先前的平均结果,可能的更好的迭代收敛标准是看重心的变化,无论是在总位移还是总簇元切换中。 最后一个通常被使用,因此一旦没有更多元素从其当前群集更改为另一个群集,我们将停止该过程。

k-means algorithm breakdown

K 均值简化图形

K 均值的优缺点

这种方法的优点是:

  • 它可以很好地扩展(大多数计算可以并行运行)
  • 它已经被用于很多应用中

但是,简单性也要付出代价(没有适用的规则):

  • 它需要先验知识(可能的簇数应事先知道)
  • 离群值可以推入质心的值,因为它们的值与任何其他样本相同
  • 由于我们假设该图是凸且各向同性的,因此对于非圆形定界簇来说效果不佳

K 最近邻

K 最近邻(KNN)是一种简单的经典聚类方法,它将很好地介绍此类技术,着眼于每个样本的附近,并假设每个新样本都应属于的类别。 已经知道的数据点。

k-nearest neighbors

K 最近邻的原理

KNN 可以在我们的多种配置中实现,但是在本章中,我们将使用“半监督”方法。 我们将从一定数量的已分配样本开始,稍后我们将根据训练集的特征猜测集群成员。

Mechanics of k-nearest neighbors

最近邻算法

在上图中,我们可以看到该算法的细分。 可以通过以下步骤进行总结:

  1. 我们将先前已知的样本放在数据结构上。
  2. 然后,我们读取要分类的下一个样本,并计算从新样本到训练集的每个样本的欧几里得距离。
  3. 我们通过根据欧几里得距离选择最近的样本的类别来确定新元素的类别。 KNN 方法需要对 k 个最接近的样本进行投票。
  4. 我们重复该过程,直到没有剩余的样本为止。

KNN 的优缺点

这种方法的优点是:

  • 简单; 无需调整参数
  • 没有正规训练; 我们只需要更多的训练实例来改进模型

缺点:

  • 计算昂贵(必须计算点与每个新样本之间的所有距离)

有用库的实用示例

在以下各节中,我们将讨论一些有用的库。

matplotlib 绘图库

数据绘图是数据科学学科不可或缺的一部分。 因此,我们需要一个非常强大的框架来绘制结果。 对于此任务,我们没有在 TensorFlow 中实现的通用解决方案,我们将使用 matplotlib 库。

在 matplotlib 站点(http://matplotlib.org/)中,定义为:

matplotlib 是一个 Python 2D 绘图库,它以各种硬拷贝格式和跨平台的交互式环境生成出版物质量的图形。

合成样本的数据绘图

在此示例中,我们将生成一个包含 100 个随机数的列表,生成样本图,并将结果保存在图形文件中:

    import tensorflow as tf
    import numpy as np
    import matplotlib.pyplot as plt
    with tf.Session() as sess:
        fig, ax = plt.subplots()
        ax.plot(tf.random_normal([100]).eval(), tf.random_normal([100] ).eval(),'o')
        ax.set_title('Sample random plot for TensorFlow')
        plt.savefig("result.png")

这是结果图像:

Sample synthetic data plotting

使用 TensorFlow 和 matplotlib 生成的示例图

提示

为了查看 scikit 数据集模块的更一般的解释,请参考 matplotlib.org

scikit-learn 数据集模块

TensorFlow 当前未实现用于轻松生成合成数据集的方法。 因此,我们将使用sklearn库作为帮助程序。

关于 scikit-learn 库

从其网站

scikit-learn(以前为scikits.learn)是针对 Python 编程语言的开源机器学习库。它具有各种分类,回归和聚类模型,旨在与 Python 数字和科学库 NumPy 和 SciPy 互操作。

在此示例中,我们将使用数据集模块,该模块处理许多众所周知的合成和现场提取的数据集的生成和加载。

提示

为了查看 scikit 数据集模块的更一般的解释,请参考此链接

合成数据集类型

我们将使用一些生成的数据集类型:

Synthetic dataset types

Blob,圆圈和月亮数据集类型

Blob 数据集

该数据集是测试简单聚类算法的理想选择。 不会出现问题,因为数据是一致地分组的,并且类别的分离很明确。

采用的方法

以下方法用于所采用的方法:

sklearn.datasets.make_blobs(n_samples=100, n_features=2,  centers=3, cluster_std=1.0, center_box=(-10.0, 10.0),  shuffle=True, random_state=None) 

在这里,n_samples是数据总数,n_features是数据的列数或特征数,centers是中心列表或许多随机中心,cluster_std是标准偏差,center_box是随机生成中心时每个聚类中心的边界框,shuffle指示是否必须对样本进行混洗,random_state是随机种子。

圆圈数据集

这是在其他圆圈中具有圆圈的数据集。 这是一个非线性的,可分离的问题,因此需要通过非线性模型来解决。 这排除了诸如 K 均值的简单算法。 在本章中,我们将尝试使用它来阐明观点。

采用的方法

以下方法用于所采用的方法:

sklearn.datasets.make_circles(n_samples=100,shuffle=True,noise=None, random_state=None,factor=0.8) 

在这里,n_samples是数据总数,shuffle表示是否必须对样本进行混洗,noise是要应用于循环数据的随机量的数量,random_state是随机种子,并且factor是圆之间的比例因子。

月亮数据集

这是另一个非线性问题,但是具有另一种类型的类分离,因为没有诸如圆环之类的闭合。

项目 1 -- 合成数据集上的 K 均值聚类

数据集说明和加载

在本章中,我们将使用生成的数据集,这些数据集经过特殊设计以具有特殊的属性。 目标属性中的两个是类别线性分离的可能性以及是否存在明显分离的群集。

生成数据集

通过这些行,我们创建了数据结构,其中将包含用于解决方案的所有元素,即:

centers = [(-2, -2), (-2, 1.5), (1.5, -2), (2, 1.5)] 
data, features = make_blobs (n_samples=200, centers=centers, n_features = 2, cluster_std=0.8, shuffle=False, random_state=42) 

通过 matplotlib 绘制数据集图:

    ax.scatter(np.asarray(centers).transpose()[0], np.asarray(centers).transpose()[1], marker = 'o', s = 250)
    plt.plot()

模型架构

points变量包含数据集点的 2D 坐标,质心变量将包含组中心点的坐标,cluster_assignments变量包含每个数据元素的质心索引。

例如,cluster_assignments[2] = 1表示data[2]数据点属于具有中心重心1的群集。 重心1的位置位于centroids[1]中。

points=tf.Variable(data) 
cluster_assignments = tf.Variable(tf.zeros([N], dtype=tf.int64)) 
centroids = tf.Variable(tf.slice(points.initialized_value(), [0,0], [K,2])) 

然后,我们可以使用 matplotlib 绘制这些质心的位置:

fig, ax = plt.subplots() 
ax.scatter(np.asarray(centers).transpose()[0], np.asarray(centers).transpose()[1], marker = 'o', s = 250) 
plt.show() 

Model architecture

初始中心播种

损失函数描述和优化器循环

然后,我们将对所有质心进行 N 份复制,对每个点进行 K 份复制,对每个点进行N x K份复制,因此我们可以针对每个维度计算出每个点与每个质心之间的距离:

rep_centroids = tf.reshape(tf.tile(centroids, [N, 1]), [N, K, 2]) 
rep_points = tf.reshape(tf.tile(points, [1, K]), [N, K, 2]) 
sum_squares = tf.reduce_sum(tf.square(rep_points - rep_centroids),  
reduction_indices=2) 

然后,我们对所有维度执行总和,并获得最低总和的索引(这将是分配给每个点的质心或聚类的索引):

best_centroids = tf.argmin(sum_squares, 1) 

质心也将使用完整源代码中定义的bucket:mean函数进行更新。

停止条件

这是新质心和分配不变的停止条件:

did_assignments_change = tf.reduce_any(tf.not_equal(best_centroids, cluster_assignments)) 

在这里,我们使用control_dependencies来计算是否需要更新质心:

with tf.control_dependencies([did_assignments_change]): 
    do_updates = tf.group( 
    centroids.assign(means), 
    cluster_assignments.assign(best_centroids)) 

结果描述

程序执行后,我们得到以下输出:

Results description

这是一轮迭代后质心变化的汇总图,其中绘制了从算法生成的原始聚类。

在下图中,我们针对这种明显分离的情况表示了 K 均值算法在应用中的不同阶段:

Results description

每次迭代的质心变化

完整源代码

以下是完整的源代码:

import tensorflow as tf 
import numpy as np 
import time 

import matplotlib 
import matplotlib.pyplot as plt 

from sklearn.datasets.samples_generator import make_blobs 
from sklearn.datasets.samples_generator import make_circles 

DATA_TYPE = 'blobs' 

# Number of clusters, if we choose circles, only 2 will be enough 
if (DATA_TYPE == 'circle'): 
    K=2 
else: 
    K=4 

# Maximum number of iterations, if the conditions are not met 
MAX_ITERS = 1000 

start = time.time() 

centers = [(-2, -2), (-2, 1.5), (1.5, -2), (2, 1.5)] 
if (DATA_TYPE == 'circle'): 
    data, features = make_circles(n_samples=200, shuffle=True, noise= 0.01, factor=0.4) 
else: 
    data, features = make_blobs (n_samples=200, centers=centers, n_features = 2, cluster_std=0.8, shuffle=False, random_state=42) 

fig, ax = plt.subplots() 
ax.scatter(np.asarray(centers).transpose()[0], np.asarray(centers).transpose()[1], marker = 'o', s = 250) 
plt.show() 

fig, ax = plt.subplots() 
if (DATA_TYPE == 'blobs'): 
ax.scatter(np.asarray(centers).transpose()[0], np.asarray(centers).transpose()[1], marker = 'o', s = 250) 
ax.scatter(data.transpose()[0], data.transpose()[1], marker = 'o', s = 100, c = features, cmap=plt.cm.coolwarm ) 
plt.plot() 

points=tf.Variable(data) 
cluster_assignments = tf.Variable(tf.zeros([N], dtype=tf.int64)) 
centroids = tf.Variable(tf.slice(points.initialized_value(), [0,0], [K,2])) 

sess = tf.Session() 
sess.run(tf.initialize_all_variables()) 

rep_centroids = tf.reshape(tf.tile(centroids, [N, 1]), [N, K, 2]) 
rep_points = tf.reshape(tf.tile(points, [1, K]), [N, K, 2]) 
sum_squares = tf.reduce_sum(tf.square(rep_points - rep_centroids),  
reduction_indices=2) 
best_centroids = tf.argmin(sum_squares, 1) 

did_assignments_change = tf.reduce_any(tf.not_equal(best_centroids, cluster_assignments)) 

def bucket_mean(data, bucket_ids, num_buckets): 
total = tf.unsorted_segment_sum(data, bucket_ids, num_buckets) 
count = tf.unsorted_segment_sum(tf.ones_like(data), bucket_ids, num_buckets) 
return total / count 

means = bucket_mean(points, best_centroids, K) 

with tf.control_dependencies([did_assignments_change]): 
do_updates = tf.group( 
centroids.assign(means), 
cluster_assignments.assign(best_centroids)) 

changed = True 
iters = 0 

fig, ax = plt.subplots() 
if (DATA_TYPE == 'blobs'): 
    colourindexes=[2,1,4,3] 
else: 
    colourindexes=[2,1] 
while changed and iters < MAX_ITERS: 
fig, ax = plt.subplots() 
iters += 1 
[changed, _] = sess.run([did_assignments_change, do_updates]) 
[centers, assignments] = sess.run([centroids, cluster_assignments]) 
ax.scatter(sess.run(points).transpose()[0], sess.run(points).transpose()[1], marker = 'o', s = 200, c = assignments, cmap=plt.cm.coolwarm ) 
ax.scatter(centers[:,0],centers[:,1], marker = '^', s = 550, c = colourindexes, cmap=plt.cm.plasma) 
ax.set_title('Iteration ' + str(iters)) 
plt.savefig("kmeans" + str(iters) +".png") 

ax.scatter(sess.run(points).transpose()[0], sess.run(points).transpose()[1], marker = 'o', s = 200, c = assignments, cmap=plt.cm.coolwarm ) 
plt.show() 

end = time.time() 
print ("Found in %.2f seconds" % (end-start)), iters, "iterations" 
print "Centroids:" 
print centers 
print "Cluster assignments:", assignments 

这是观察算法机制的最简单情况。 当数据来自真实世界时,这些类通常没有那么清晰地分开,并且标记数据样本更加困难。

圆圈合成数据上的 K 均值

对于圆图,我们观察到这种数据表征并不容易用一组简单的方法表示。 如图所示,两个圆要么共享一个质心的位置,要么真的很接近,因此我们无法预测明确的结果:

k-means on circle synthetic data

圆型数据集

对于此数据集,我们仅使用两个类来确保了解此算法的主要缺点:

k-means on circle synthetic data

K 均值应用于圆形综合数据集

如我们所见,初始中心向样本数量最集中的区域漂移,因此将数据线性划分。 这是我们现阶段使用的简单模型的局限性之一。 为了处理非线性可分离性样本,我们可以尝试本章范围以外的其他统计方法,例如基于密度的带噪应用空间聚类(DBSCAN)。

项目 2 -- 合成数据集上的最近邻

在这个项目中,我们将加载一个数据集,使用该数据集,以前的算法(K 均值)在分离类时遇到问题。

数据集生成

该数据集是第一个示例中具有两个类的相同循环类数据集,但是这次我们将通过增加一些噪声(从0.010.12)来增加错误概率:

data, features = make_circles(n_samples=N, shuffle=True, noise=0.12,factor=0.4)

这是生成的训练数据图:

Dataset generation

模型架构

将保留数据的变量只是原始数据和测试列表,其中将包含计算出的测试数据类:

data, features = make_circles(n_samples=N, shuffle=True, noise= 0.12, factor=0.4)
tr_data, tr_features= data[:cut], features[:cut]
te_data,te_features=data[cut:], features[cut:]
test=[]

损失函数说明

在聚类中,我们将使用函数来优化为欧式距离,与第 1 章,探索和转换数据相同。 它是在集群分配循环上计算的,获取从新点到现有训练点的距离,要求最小值的索引,然后使用该索引搜索最近的邻居的类:

distances = tf.reduce_sum(tf.square(tf.sub(i , tr_data)),reduction_indices=1)
neighbor = tf.arg_min(distances,0)

停止条件

在这个简单的示例中,一旦访问了测试分区的所有元素,我们将完成操作。

结果描述

这是测试数据类分布的图形,在这里我们可以看到清晰分开的类。 我们可以观察到,至少在此有限的数据集范围内,此方法比非重叠,斑点优化,K 均值方法更好。

Results description

完整源代码

以下是完整的源代码:

import tensorflow as tf 
import numpy as np 
import time 

import matplotlib 
import matplotlib.pyplot as plt 

from sklearn.datasets.samples_generator import make_circles 

N=210 
K=2 
# Maximum number of iterations, if the conditions are not met 
MAX_ITERS = 1000 
cut=int(N*0.7) 

start = time.time() 

data, features = make_circles(n_samples=N, shuffle=True, noise= 0.12, factor=0.4) 
tr_data, tr_features= data[:cut], features[:cut] 
te_data,te_features=data[cut:], features[cut:] 
test=[] 

fig, ax = plt.subplots() 
ax.scatter(tr_data.transpose()[0], tr_data.transpose()[1], marker = 'o', s = 100, c = tr_features, cmap=plt.cm.coolwarm ) 
plt.plot() 

sess = tf.Session() 
sess.run(tf.initialize_all_variables()) 

for i, j in zip(te_data, te_features): 
    distances = tf.reduce_sum(tf.square(tf.sub(i , tr_data)),reduction_indices=1) 
    neighbor = tf.arg_min(distances,0) 

    test.append(tr_features[sess.run(neighbor)]) 
print test 
fig, ax = plt.subplots() 
ax.scatter(te_data.transpose()[0], te_data.transpose()[1], marker = 'o', s = 100, c = test, cmap=plt.cm.coolwarm ) 
plt.plot() 

end = time.time() 
print ("Found in %.2f seconds" % (end-start)) 

print "Cluster assignments:", test 

总结

在本章中,我们简单地概述了一些我们可以实现的最基本的模型,但是尝试在解释中尽可能地详细。

从现在开始,我们将能够生成综合数据集,从而使我们能够快速测试模型对于不同数据配置的适当性,从而评估它们的优缺点,而不必加载具有大量未知特征的模型。

此外,我们已经实现了第一个迭代方法并测试了收敛性,该任务将以类似的方式在后续章节中继续进行,但是将使用更精细,更精确的方法。

在下一章中,我们将使用线性函数解决分类问题,并且首次使用训练集中的先前数据来学习其特征。 这是监督学习技术的目标,通常对于解决许多现实生活中的问题更有用。

三、线性回归

在本章中,我们将开始应用机器学习项目中使用的所有标准步骤,以便使用一条使误差和损失函数最小化的线来拟合先前给定的数据。

在上一章中,我们看到了范围有限和许多可能解决方案的问题。 这些类型的模型还与定性评估类型相关,即基于先前的标签为样本分配标签。 通常在与社会领域有关的问题中发现该结果。

我们还可能对预测(先前建模的)函数的确切数字输出值感兴趣。 这种方法类似于物理领域,可用于在事先了解一系列历史值的情况下预测温度或湿度或某种商品的价值,这称为回归分析。

在线性回归的情况下,我们在输入变量和输出变量之间寻找线性关系表示的确定关系。

单变量线性建模函数

如前所述,在线性回归中,我们尝试找到一个线性方程,以最小化数据点和建模线之间的距离。

此关系可以用以下标准线性函数表示:

Univariate linear modelling function

模型函数采用以下形式:

在这里,ss0bias是截距,x的函数值为零,ss1是建模线的斜率。 变量x通常被称为自变量,y被称为因变量,但它们也可以分别称为回归变量和响应变量。

样本数据生成

在下面的示例中,我们将基于ss0 = 2.0的线,加上最大幅度为0.4的垂直噪声,生成近似样本随机分布。

In[]: 
#Indicate the matplotlib to show the graphics inline 
%matplotlib inline  
import matplotlib.pyplot as plt # import matplotlib 
import numpy as np # import numpy 
trX = np.linspace(-1, 1, 101) # Linear space of 101 and [-1,1] 
#Create The y function based on the x axis 
trY = 2 * trX + np.random.randn(*trX.shape) * 0.4 + 0.2  
plt.figure() # Create a new figure 
plt.scatter(trX,trY) #Plot a scatter draw of the random datapoints 
# Draw one line with the line function 
plt.plot (trX, .2 + 2 * trX)

结果图将如下所示:

Sample data generation

加噪声线性采样和线性函数

成本函数的确定

与所有机器学习技术一样,我们必须确定一个误差函数,我们需要将其最小化,这表明解决问题的适当性。

用于线性回归的最常用的cost函数称为最小二乘。

最小二乘

为了计算函数的最小二乘误差,我们通常会寻找一种测量点与建模线的接近程度的方法。 因此,我们定义了一个函数,用于测量每个元组x[n]y[n]与建模线的对应值之间的距离。

对于 2D 回归,我们有一个数字元组(X[0],Y[0]),(X[1],Y[1])...(X[n],Y[n])的列表,通过最小化以下函数,可以找到β[0]β[1]的值:

Least squares

简单来说,求和代表预测值与实际值之间的欧几里得距离之和。

进行运算的原因是,平方误差的总和为我们提供了一个唯一且简单的全局数,预期数与实数之差为我们提供了适当的距离,平方幂为我们提供了一个正数,这会惩罚一个整数。 多于线性的时尚。

最小化成本函数

下一步是设置最小化cost函数的方法。 在线性演算中,定位极小值任务的基本特征之一被简化为计算函数的导数并寻找其零点。 为此,该函数必须具有导数,最好是凸的。 可以证明最小二乘函数符合这两个条件。 这对于避免已知的局部极小问题非常有用。

Minimizing the cost function

损失函数表示

最小二乘的一般最小值

我们尝试解决的问题(最小二乘)可以用矩阵形式表示:

General minima for least squares

在此,J是成本函数,具有以下解决方案:

General minima for least squares

在本章中,我们将使用迭代方法梯度下降,该方法将在以后的章节中以更通用的方式使用。

迭代方法 -- 梯度下降

梯度下降本身就是一种迭代方法,并且是机器学习领域中最常用的优化算法。 考虑到可以用它优化的参数组合的复杂性,它结合了简单的方法和良好的收敛速度。

2D 线性回归从具有随机定义的权重或线性系数乘数的函数开始。 定义第一个值后,第二步是以以下形式应用迭代函数:

Iterative methods - gradient descent

在该方程式中,我们可以轻松推导该方法的机理。 我们从一组初始系数开始,然后朝函数最大变化的相反方向移动。 α变量被称为步长,将影响我们在梯度搜索方向上移动最小的距离。

最后一步是可选地测试迭代之间的更改,并查看更改是否大于epsilon或检查是否达到了迭代次数。

如果函数不是凸函数,建议使用随机值多次运行梯度下降,然后选择成本值最低的系数。 在非凸函数的情况下,梯度下降最终以最小值出现,这可能是局部的。 因此,对于非凸函数,结果取决于初始值,建议将它们随机设置多次,并在所有解决方案中选择成本最低的解决方案。

示例部分

现在让我们讨论有用的库和模块。

TensorFlow 中的优化器方法 -- train模块

训练或参数优化阶段是机器学习工作流程的重要组成部分。

为此,TensorFlow 具有一个tf.train模块,该模块是一组对象的帮助程序,致力于实现数据科学家所需的各种不同优化策略。 此模块提供的主要对象称为优化器。

tf.train.Optimizer

Optimizer类允许您为loss函数计算梯度并将其应用于模型的不同变量。 在最著名的算法子类中,我们找到了梯度下降,Adam 和 Adagrad。

关于该类的一个主要提示是Optimizer类本身无法实例化。 子类之一。

如前所述,TensorFlow 允许您以符号方式定义函数,因此梯度也将以符号方式应用,从而提高了结果的准确率以及要应用于数据的操作的通用性。

为了使用Optimizer类,我们需要执行以下步骤:

  1. 创建具有所需参数的Optimizer(在这种情况下为梯度下降)。

            opt = GradientDescentOptimizer(learning_rate= [learning rate]) 
    
    
  2. cost函数创建一个调用minimize方法的操作。

            optimization_op = opt.minimize(cost, var_list=[variables list]) 
    
    

minimize方法具有以下形式:

tf.train.Optimizer.minimize(loss, global_step=None, var_list=None, gate_gradients=1, aggregation_method=None, colocate_gradients_with_ops=False, name=None) 

主要参数如下:

  • loss:这是一个张量,其中包含要最小化的值。
  • global_stepOptimizer工作后,此变量将增加 1。
  • var_list:包含要优化的变量。

提示

实际上,optimize方法结合了对compute_gradients()apply_gradients()的调用。 如果要在应用梯度之前对其进行处理,请显式调用compute_gradients()apply_gradients(),而不要使用此函数。 如果我们只想进行一步训练,就必须以opt_op.run().的形式执行run方法

其他优化器实例类型

以下是其他Optimizer实例类型:

  • tf.train.AdagradOptimizer:这是一种基于参数频率的自适应方法,学习率单调下降。
  • tf.train.AdadeltaOptimizer:这是对 Adagrad 的改进,它的学习率没有下降。
  • tf.train.MomentumOptimizer:这是一种适应性方法,可解决尺寸之间的不同变化率。
  • 并且还有其他更具体的参数,例如tf.train.AdamOptimizertf.train.FtrlOptimizertf.train.RMSPropOptimizer

示例 1 -- 单变量线性回归

现在,我们将在一个项目中工作,在该项目中,我们将应用前面几页中简要介绍的所有概念。 在此示例中,我们将创建一个近似线性分布; 之后,我们将创建一个回归模型,该模型试图拟合线性函数以最小化误差函数(由最小二乘法定义)。

给定一个新样本,该模型将使我们能够预测输入值的结果。

数据集说明

对于此示例,我们将生成一个包含线性函数并添加噪声的合成数据集:

import TensorFlow as tf
import numpy as np
trX = np.linspace(-1, 1, 101)
trY = 2 * trX + np.random.randn(*trX.shape) * 0.4 + 0.2 # create a y value which is approximately linear but with some random noise

使用这些线,我们可以将线表示为散点图和理想线函数。

import matplotlib.pyplot as plt 
plt.scatter(trX,trY) 
plt.plot (trX, .2 + 2 * trX)  

Dataset description

生成的样本和原始线性函数无噪声

模型架构

  1. 现在,我们创建一个变量来保存xy轴中的值。 然后,我们将模型定义为X和权重w的乘积。

  2. 然后,我们生成一些变量,并为其分配初始值以启动模型:

            In[]: 
            X = tf.placeholder("float", name="X") # create symbolic variables 
            Y = tf.placeholder("float", name = "Y") 
    
    
  3. 现在,我们通过将name_scope声明为Model来定义模型。 此作用域将其包含的所有变量分组,以形成具有同类实体的唯一实体。 在此范围内,我们首先定义一个函数,该函数接收x轴坐标,权重(斜率)和偏差的变量。 然后,我们创建一个新变量objects,来保存不断变化的参数,并使用y_model变量实例化该模型:

             with tf.name_scope("Model"):
    
               def model(X, w, b):
                 return tf.mul(X, w) + b # just define the line as X*w + b0 
    
               w = tf.Variable(-1.0, name="b0") # create a shared variable
               b = tf.Variable(-2.0, name="b1") # create a shared variable
               y_model = model(X, w, b)
    
    

在仪表板上,您可以看到我们一直在收集的损失函数的图像。 在图部分中,放大模型时,您可以看到求和与乘法运算,参数变量b0b1以及应用于模型的梯度运算,如下所示:

Model architecture

成本函数描述和优化器循环

  1. Cost Function中,我们创建了一个新的范围以包括该组的所有操作,并使用先前创建的y_model来说明用于计算损失的计算出的y轴值。

            with tf.name_scope("CostFunction"): 
            cost = (tf.pow(Y-y_model, 2)) # use sqr error for cost  
    
    
  2. 为了定义选择的optimizer,,我们初始化一个GradientDescentOptimizer,步骤将是0.01,这似乎是收敛的合理起点。

             train_op = tf.train.GradientDescentOptimizer(0.05).minimize(cost) 
    
    
  3. 现在是时候创建会话并初始化要保存在 TensorBoard 中进行查看的变量了。 在此示例中,我们将为每个迭代保存一个标量变量以及最后一个样本的误差结果。 我们还将图结构保存在文件中以供查看。

            sess = tf.Session() 
            init = tf.initialize_all_variables()
            tf.train.write_graph(sess.graph,
              '/home/ubuntu/linear','graph.pbtxt')
            cost_op = tf.scalar_summary("loss", cost) 
            merged = tf.merge_all_summaries() 
            sess.run(init) 
            writer = tf.train.SummaryWriter('/home/ubuntu/linear',
              sess.graph) 
    
    
  4. 对于模型训练,我们将目标设置为 100 次迭代,然后将每个样本发送到梯度下降的train操作。 每次迭代后,我们绘制建模线并将最后一个误差的值添加到summary中。

            In[]:
            for i in range(100):
             for (x, y) in zip(trX, trY): 
               sess.run(train_op, feed_dict={X: x, Y: y}) 
               summary_str = sess.run(cost_op, feed_dict={X: x, Y: y})
               writer.add_summary(summary_str, i) 
             b0temp=b.eval(session=sess)
             b1temp=w.eval(session=sess)
             plt.plot (trX, b0temp + b1temp * trX )
    

结果图如下: 我们可以看到初始行如何迅速收敛为更合理的结果:

Cost function description and Optimizer loop

放大损失函数范围后,我们可以看到幂和减法运算以及书面摘要,如下图所示:

Cost function description and Optimizer loop

停止条件

结果描述

现在让我们检查参数结果,打印wb变量的run输出:

printsess.run(w) # Should be around 2  
printsess.run(b) #Should be around 0.2 
2.09422 
0.256044 

现在是时候再次以图形方式查看数据和建议的最后一行。

plt.scatter(trX,trY) 
plt.plot (trX, testb + trX * testw) 

Results description

使用 TensorBoard 查看结果

现在,让我们回顾一下保存在 TensorBoard 中的数据。

为了启动 TensorBoard,您可以转到logs目录并执行以下行:

$ tensorboard --logdir=. 

TensorBoard 将加载事件和图形文件,并且将在6006端口上监听。 然后,您可以从浏览器转到localhost:6000,然后查看 TensorBoard 仪表板,如下图所示:

Reviewing results with TensorBoard

完整源代码

以下是完整的源代码:

import matplotlib.pyplot as plt # import matplotlib 
import numpy as np # import numpy 
import tensorflow as tf 
import numpy as np 

trX = np.linspace(-1, 1, 101) #Create a linear space of 101 points between 1 and 1 
trY = 2 * trX + np.random.randn(*trX.shape) * 0.4 + 0.2 #Create The y function based on the x axis 
plt.figure() # Create a new figure 
plt.scatter(trX,trY) #Plot a scatter draw of the random datapoints 
plt.plot (trX, .2 + 2 * trX) # Draw one line with the line function 

get_ipython().magic(u'matplotlib inline') 

import matplotlib.pyplot as plt 
import tensorflow as tf 
import numpy as np 

trX = np.linspace(-1, 1, 101) 
trY = 2 * trX + np.random.randn(*trX.shape) * 0.4 + 0.2 # create a y value which is approximately linear but with some random noise 

plt.scatter(trX,trY) 
plt.plot (trX, .2 + 2 * trX) 

X = tf.placeholder("float", name="X") # create symbolic variables 
Y = tf.placeholder("float", name = "Y") 

withtf.name_scope("Model"): 

    def model(X, w, b): 
        returntf.mul(X, w) + b # We just define the line as X*w + b0   

    w = tf.Variable(-1.0, name="b0") # create a shared variable 
    b = tf.Variable(-2.0, name="b1") # create a shared variable 
    y_model = model(X, w, b) 

withtf.name_scope("CostFunction"): 
    cost = (tf.pow(Y-y_model, 2)) # use sqr error for cost function 

train_op = tf.train.GradientDescentOptimizer(0.05).minimize(cost) 

sess = tf.Session() 
init = tf.initialize_all_variables() 
tf.train.write_graph(sess.graph, '/home/ubuntu/linear','graph.pbtxt') 
cost_op = tf.scalar_summary("loss", cost) 
merged = tf.merge_all_summaries() 
sess.run(init) 
writer = tf.train.SummaryWriter('/home/ubuntu/linear', sess.graph) 

fori in range(100): 
for (x, y) in zip(trX, trY): 
sess.run(train_op, feed_dict={X: x, Y: y})     
summary_str = sess.run(cost_op, feed_dict={X: x, Y: y}) 
writer.add_summary(summary_str, i)        
    b0temp=b.eval(session=sess) 
    b1temp=w.eval(session=sess) 
plt.plot (trX, b0temp + b1temp * trX ) 

printsess.run(w) # Should be around 2  
printsess.run(b) #Should be around 0.2 

plt.scatter(trX,trY) 
plt.plot (trX, sess.run(b) + trX * sess.run(w)) 

Full source code

Full source code

示例 2 -- 多元线性回归

在此示例中,我们将处理涉及多个变量的回归问题。

这将基于 1993 年波士顿某些郊区不同价格的研究数据集。 它最初包含 13 个变量以及该处房产的平均价格。

与原始文件相比,文件中唯一的变化是删除了一个变量(b),该变量在种族上对不同的郊区进行了概述。

除此之外,我们将选择一些我们认为具有线性条件可以建模的良好条件的变量。

有用的库和方法

本部分包含一个有用的库列表,我们将在此示例中以及本书其余部分中 TensorFlow 之外的部分中使用这些库,以帮助解决我们将要解决的各种问题。

Pandas 库

当我们想快速读取并获得有关正常大小的数据文件的提示时,创建读取缓冲区和其他附加机制可能会减少开销。 这是熊猫当前的现实生活用例之一。

这是 Pandas 网站的摘录:

Pandas 是 BSD 许可的开放源代码库,为 Python 提供了高表现,易于使用的数据结构和数据分析工具。

熊猫的主要特征如下:

  • 它具有 CSV 和文本文件,MS Excel,SQL 数据库甚至面向科学的 HDF5 格式的读写文件功能。
  • CSV 文件加载例程自动识别列标题并支持更直接的列寻址
  • 数据结构自动转换为 NumPy 多维数组

数据集说明

数据集以 CSV 文件表示,我们将使用 Pandas 库打开它。

数据集包含以下变量:

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

在这里,我们有一个简单的程序,它将读取数据集并创建数据的详细说明:

import tensorflow.contrib.learn as skflow 
fromsklearn import datasets, metrics, preprocessing 
import numpy as np 
import pandas as pd 

df = pd.read_csv("data/boston.csv", header=0) 
printdf.describe() 

这将输出数据集变量的统计摘要。 前六个结果如下:


CRIM         ZN       INDUS         CHAS         NOX          RM  \ 
count  506.000000  506.000000  506.000000  506.000000  506.000000  506.000000    
mean     3.613524   11.363636   11.136779    0.069170    0.554695    6.284634    
std      8.601545   23.322453    6.860353    0.253994    0.115878    0.702617    
min      0.006320    0.000000    0.460000    0.000000    0.385000    3.561000    
25%      0.082045    0.000000    5.190000    0.000000    0.449000    5.885500   
50%      0.256510    0.000000    9.690000    0.000000    0.538000    6.208500    
75%      3.677082   12.500000   18.100000    0.000000    0.624000    6.623500    
max     88.976200  100.000000   27.740000    1.000000    0.871000    8.780000    

Dataset description

模型架构

在此示例中,我们将使用的模型很简单,但是几乎包含了处理更复杂模型所需的所有元素。

在下图中,我们看到了整个设置的不同参与者:模型,损失函数和梯度。 TensorFlow 真正有用的功能是能够自动微分模型和函数。

Model architecture

在这里,我们可以找到上一节中表示的变量的定义:wb和模型线性方程。

X = tf.placeholder("float", name="X") # create symbolic variables 
Y = tf.placeholder("float", name = "Y") 

withtf.name_scope("Model"): 
    w = tf.Variable(tf.random_normal([2], stddev=0.01), name="b0") # create a shared variable 
    b = tf.Variable(tf.random_normal([2], stddev=0.01), name="b1") # create a shared variable 
def model(X, w, b): 
returntf.mul(X, w) + b # We just define the line as X*w + b0   
y_model = model(X, w, b)

Model architecture

损失函数说明和优化器循环

在此示例中,我们将使用常用的均方误差,但是这次使用了多变量; 因此我们应用reduce_mean来收集不同维度上的误差值:

withtf.name_scope("CostFunction"): 
    cost = tf.reduce_mean(tf.pow(Y-y_model, 2)) # use sqr error for cost function 
train_op = tf.train.AdamOptimizer(0.1).minimize(cost)

Loss function description and Optimizer loop

 for a in range (1,10): 
    cost1=0.0 
fori, j in zip(xvalues, yvalues):    
sess.run(train_op, feed_dict={X: i, Y: j})  
        cost1+=sess.run(cost, feed_dict={X: i, Y: i})/506.00 
        #writer.add_summary(summary_str, i)  
xvalues, yvalues = shuffle (xvalues, yvalues) 

停止条件

停止条件将仅由针对所有数据样本训练参数来确定外循环中确定的周期数。

结果描述

结果如下:

1580.53295174 
[ 2.25225258  1.30112672] 
[ 0.80297691  0.22137061] 
1512.3965525 
[ 4.62365675  2.90244412] 
[ 1.16225874  0.28009811] 
1495.47174799 
[ 6.52791834  4.29297304] 
[ 0.824792270.17988272] 
... 
1684.6247849 
[ 29.71323776  29.96078873] 
[-0.68271929 -0.13493828] 
1688.25864746 
[ 29.78564262  30.09841156] 
[-0.58272243 -0.08323665] 
1684.27538102 
[ 29.75390816  30.13044167] 
[-0.59861398 -0.11895057] 

从结果中我们可以看到,在训练的最后阶段,建模线同时基于以下系数:

price = 0.6 x Industry + 29.75

price = 0.1 x Age + 30.13

完整源代码

以下是完整的源代码:

import matplotlib.pyplot as plt 
import tensorflow as tf 
import tensorflow.contrib.learn as skflow 
from sklearn.utils import shuffle 
import numpy as np 
import pandas as pd 

df = pd.read_csv("data/boston.csv", header=0) 
printdf.describe() 

f, ax1 = plt.subplots() 
plt.figure() # Create a new figure 

y = df['MEDV'] 

for i in range (1,8): 
    number = 420 + i 
    ax1.locator_params(nbins=3) 
    ax1 = plt.subplot(number) 
    plt.title(list(df)[i]) 
    ax1.scatter(df[df.columns[i]],y) #Plot a scatter draw of the datapoints 
plt.tight_layout(pad=0.4, w_pad=0.5, h_pad=1.0) 

X = tf.placeholder("float", name="X") # create symbolic variables 
Y = tf.placeholder("float", name = "Y") 

with tf.name_scope("Model"): 

    w = tf.Variable(tf.random_normal([2], stddev=0.01), name="b0") # create a shared variable 
    b = tf.Variable(tf.random_normal([2], stddev=0.01), name="b1") # create a shared variable 

    def model(X, w, b): 
        return tf.mul(X, w) + b # We just define the line as X*w + b0   

    y_model = model(X, w, b) 

with tf.name_scope("CostFunction"): 
    cost = tf.reduce_mean(tf.pow(Y-y_model, 2)) # use sqr error for cost function 

train_op = tf.train.AdamOptimizer(0.001).minimize(cost) 

sess = tf.Session() 
init = tf.initialize_all_variables() 
tf.train.write_graph(sess.graph, '/home/bonnin/linear2','graph.pbtxt') 
cost_op = tf.scalar_summary("loss", cost) 
merged = tf.merge_all_summaries() 
sess.run(init) 
writer = tf.train.SummaryWriter('/home/bonnin/linear2', sess.graph) 

xvalues = df[[df.columns[2], df.columns[4]]].values.astype(float) 
yvalues = df[df.columns[12]].values.astype(float) 
b0temp=b.eval(session=sess) 
b1temp=w.eval(session=sess) 

for a in range (1,10): 
    cost1=0.0 
for i, j in zip(xvalues, yvalues):    
sess.run(train_op, feed_dict={X: i, Y: j})  
        cost1+=sess.run(cost, feed_dict={X: i, Y: i})/506.00 
        #writer.add_summary(summary_str, i)  
xvalues, yvalues = shuffle (xvalues, yvalues) 
print (cost1) 
b0temp=b.eval(session=sess) 
b1temp=w.eval(session=sess) 
print (b0temp) 
print (b1temp) 
#plt.plot (trX, b0temp + b1temp * trX ) 

总结

在本章中,我们使用 TensorFlow 的训练工具构建了第一个具有标准损失函数的完整模型。 我们还建立了一个多元模型来说明多个维度来计算回归。 除此之外,我们使用 TensorBoard 在训练阶段观察变量的行为。

在下一章中,我们将开始使用非线性模型,通过它我们将更接近神经网络领域,这是 TensorFlow 的主要支持领域,其效用提供了巨大价值。

四、逻辑回归

在上一章中,我们已经看到了一种将现实的一部分建模为线性函数的方法,该函数具有独立变量,并且偏差最小化了误差函数。

除了某些非常明确定义的问题(预期结果是连续的变量和函数)之外,这种特殊的分析还不够。

但是,如果我们面对具有定性因变量的数据,将会发生什么? 例如,是否存在确定的特征; 受试者有金色的头发吗? 病人以前有病吗?

这些是我们将在本章中处理的问题。

问题描述

线性回归旨在解决的问题不是基于连续函数的值预测,这一次,我们想知道样本属于确定类别的可能性。

在本章中,我们将依靠线性模型的一般化来解决回归问题,但最终目标是解决分类问题,我们必须应用标签或将观察集中的所有元素分配给预定义的组。

Problem description

在上图中,我们可以看到如何对旧问题和新问题进行分类。 第一个(线性回归)可以想象为值不断增长的连续体。

另一个是基于x值的输出只能具有两个不同值的域。 在第二张图的特定情况下,我们可以看到对其中一个选项的特定偏向极端:在左侧,y值偏向 0,在右侧偏向 1。

鉴于即使在进行回归从而寻找连续值的情况下,这种项也可能有些棘手,实际上,最终目标是为具有离散变量的分类问题建立预测。

此处的关键是要了解我们将获得与类有关的项目的概率,而不是完全离散的值。

sigmoid 函数的前身 -- 对率(Logit)函数

在研究逻辑函数之前,我们将回顾该函数所基于的原始函数,并为其提供一些更一般的属性。

本质上,当我们谈论logit函数时,我们正在使用随机变量p的函数,更具体地说,是与伯努利分布相对应的函数。

伯努利分布

在解释理论细节之前,值得注意的是伯努利分布是一个随机变量,它具有:

  • 取值为 0 且失败概率为q = 1 - p

  • 取值为 1,成功概率为p

可以表示如下(对于具有伯努利分布的随机变量X):

Bernoulli distribution

这是一种概率分布,它将以二元选项的形式表示事件的发生概率,就像我们要表示自己的变量(特征的存在,事件的发生,现象的因果关系等)一样。

链接函数

在尝试建立广义线性模型时,我们要从线性函数开始,并从因变量开始,获取到概率分布的映射。

由于选项具有二元性质,因此通常选择的分布是最近提到的伯努利分布,而倾向于 logistic 函数的链接函数是logit函数。

Logit 函数

我们可以利用的可能变量之一是p等于 1 的几率的自然对数。 此函数称为logit函数:

Logit function

我们也可以将logit函数称为对数奇数函数,因为对于给定的概率p,我们正在计算赔率的对数(p/1-p)

Logit function

因此,正如我们可以直观地推断出的那样,用自变量的组合替换X,无论它们的值是什么,用从负无穷大到无穷大的任何出现替换X,我们将响应缩放到01

Logit 反函数的重要性

假设我们计算logit函数的逆。 这将使我们编写以下函数:

The importance of the logit inverse

此函数是sigmoid函数。

sigmoid 函数

逻辑函数将帮助我们在新的回归任务中表示二元类别。

在下图中,您将找到sigmoid函数的图形表示:

The logistic function

逻辑函数或 Sigmoid 的图形表示

Logistic 函数作为线性建模的泛化

逻辑函数δ(t)定义如下:

Logistic function as a linear modeling generalization

该方程式的正常解释是t代表一个简单的自变量。 但是,我们将改进此模型,并假定t是单个解释变量x的线性函数(对t是多个解释变量的线性组合的情况进行类似处理)。

然后,我们将t表示为:

Logistic function as a linear modeling generalization

最终估计的回归方程

因此,我们从以下等式开始:

Final estimated regression equation

使用所有这些元素,我们可以计算回归方程,这将为我们提供回归概率:

Final estimated regression equation

下图将显示如何将从任意范围的映射最终转换为范围[0, 1],该范围可以解释为表示事件发生的概率p

Final estimated regression equation

什么影响会改变线性函数的参数? 它们是将更改sigmoid函数的中心斜率和从零开始的位移的值,从而使其可以更精确地减小回归值与实际数据点之间的误差。

Logistic 函数的属性

函数空间中的每条曲线都可以通过可能适用的目标来描述。 对于 logistic 函数,它们是:

  • 根据一个或多个独立变量对事件的概率p进行建模。 例如,鉴于先前的资格,被授予奖品的可能性。
  • 对确定的观测值进行估计(这是回归部分)p,与事件未发生的可能性有关。
  • 预测自变量变化对二元响应的影响。
  • 通过计算某项属于确定类别的概率对观察进行分类。

损失函数

在上一节中,我们看到了近似的p^函数,该函数将对样本属于特定类别的概率进行建模。 为了衡量我们对解的近似程度,我们将寻找精心选择的损失函数。

该损失函数表示为:

Loss function

该损失函数的主要特性是它不会以类似的方式惩罚误差,当误差增加到远远超过 0.5 时,误差惩罚因子会渐近增长。

多类应用 -- softmax 回归

到目前为止,我们仅针对两个类的情况进行分类,或者以概率语言对事件发生概率p进行分类。

在要决定两个以上类别的情况下,有两种主要方法: 一对一,一对剩余。

  • 第一种技术包括计算许多模型,这些模型代表每个类别相对于所有其他类别的概率。
  • 第二个由一组概率组成,其中我们代表一个类别相对于所有其他类别的概率。
  • 第二种方法是softmax回归的输出格式,它是 n 个类的逻辑回归的概括。

因此,为了训练样本,我们将使用句柄y(i)ε{1,...,K},将二元标签( y(i)ε{0,1})更改为向量标签,其中K是类别数,标签Y可以采用K不同的值, 而不是只有两个。

因此,对于这种特定技术,给定测试输入X,我们想要针对k=1,...,K的每个值估计Py=k|x)的概率。 softmax回归将输出K维向量(其元素总和为 1),从而为我们提供了K估计的概率。

在下图中,我们表示在单类和多类逻辑回归的概率映射上发生的映射:

Multiclass application - softmax regression

成本函数

softmax函数的成本函数是自适应的交叉熵函数,该函数不是线性的,因此对大阶函数差异的惩罚要比对小阶函数的惩罚更大。

Cost function

在这里,c是类别编号,I是各个训练样本索引,yc对于期望的类别为 1,对于其余类别为 0。

扩展这个方程,我们得到以下结果:

Cost function

迭代方法的数据标准化

正如我们将在以下各节中看到的那样,对于逻辑回归,我们将使用gradient descent方法来最小化成本函数。

Data normalization for iterative methods

此方法对特征数据的形式和分布非常敏感。

因此,我们将进行一些预处理,以便获得更好,更快的收敛结果。

我们将把这种方法的理论原因留给其他书籍,但我们将总结其原因,即通过归一化可以平滑误差表面,使迭代gradient descent更快地达到最小误差。

输出的单热表示

为了将softmax函数用作回归函数,我们必须使用一种称为单热编码的编码。 这种编码形式只是将变量的数字整数值转换为数组,其中将值列表转换为数组列表,每个数组的长度与该列表的最大值相同,并且每个数组的表示方式是在值的索引上添加 1,其余元素保持为 0。

例如,这将是单热编码形式的列表[1, 3, 2, 4]的表示形式:

[[0 1 0 0 0] 
[0 0 0 1 0] 
[0 0 1 0 0]
[0 0 0 0 1]]

示例 1 -- 单变量 logistic 回归

在第一个示例中,我们将使用单变量 logistic 回归(患者年龄)来估计心脏病的概率。

有用的库和方法

从 0.8 版开始,TensorFlow 提供了一种生成热点的方法。 用于此生成的函数是tf.one_hot,其形式如下:

tf.one_hot(indices, depth, on_value=1, off_value=0, axis=None, dtype=tf.float32, name=None)

此函数生成通用的单热编码数据结构,该结构可以指定值,生成轴,数据类型等。

在生成的张量中,索引的指示值将采用on_value(默认值为1),其他值将具有off_value(默认0)。

Dtype是生成的张量的数据类型; 默认值为float32

depth变量定义每个元素将具有多少列。 我们假设它在逻辑上应该为max(indices) + 1,但也可以将其切掉。

TensorFlow 的 softmax 实现

在 TensorFlow 中应用softmax回归的方法包括tf.nn.log_softmax, with the following form:

tf.nn.log_softmax(logits, name=None)

在这里,参数为:

  • logits:张量必须为以下类型之一:float32float64 形状为[batch_size, num_classes]的 2D
  • name:操作的名称(可选)

此函数返回具有与logits相同类型和形状的张量。

数据集说明和加载

我们将讨论的第一种情况是我们要拟合逻辑回归的方法,仅测量一个变量,并且只有两个可能的结果。

CHDAGE 数据集

对于第一个简单的示例,我们将使用一个非常简单且经过研究的数据集,该数据集以在书中出版而闻名。 应用逻辑回归第三版,David W. Hosmer Jr.,Stanley Lemeshow,Rodney X. Sturdivant,作者:Wiley。

列出age的年限(AGE),以及对心脏病风险因素进行假设性研究的 100 名受试者是否患有严重冠心病(CHD)的证据。 该表还包含一个标识符变量(ID)和一个年龄组变量(AGEGRP)。 结果变量是 CHD,它用0值编码以表示不存在 CHD,或用1编码以指示其存在于个体中。 通常,可以使用任何两个值,但是我们发现使用零和一最为方便。 我们将此数据集称为 CHDAGE 数据。

CHDAGE 数据集格式

CHDAGE 数据集是一个两列的 CSV 文件,我们将从外部仓库下载该文件。

在第 1 章(探索和转换数据)中,我们使用了本机 TensorFlow 方法来读取数据集。 在本章中,我们将使用一个互补且流行的库来获取数据。

进行此新添加的原因是,鉴于数据集只有 100 个元组,实际上只需要一行读取即可,而且pandas库提供了免费但简单但强大的分析方法 。

因此,在该项目的第一阶段,我们将开始加载 CHDAGE 数据集的实例,然后将打印有关数据的重要统计信息,然后进行预处理。

在对数据进行一些绘制之后,我们将构建一个由激活函数组成的模型,该激活函数将在特殊情况下成为softmax函数,在特殊情况下它将变为标准逻辑回归。 那就是只有两个类别(疾病的存在与否)。

数据集加载和预处理实现

首先,我们导入所需的库,并指示所有matplotlib程序都将内联(如果我们使用 Jupyter):

>>> import pandas as pd 
>>> import numpy as np 
>>> %matplotlib inline 
>>> import matplotlib.pyplot as plt 

然后,我们读取数据并要求pandas检查有关数据集的重要统计信息:

>>> df = pd.read_csv("data/CHD.csv", header=0) 
>>> print df.describe() 

    age        chd
    count  100.000000  100.00000
    mean    44.380000    0.43000
    std     11.721327    0.49757
    min     20.000000    0.00000
    25%     34.750000    0.00000
    50%     44.000000    0.00000
    75%     55.000000    1.00000
    max     69.000000    1.000000

然后,我们继续绘制数据以了解数据:

plt.figure() # Create a new figure 
plt.scatter(df['age'],df['chd']) #Plot a scatter draw of the random datapoints 

Dataset loading and preprocessing implementation

模型架构

在这里,我们从以下变量开始,描述将在其中构建模型元素的代码部分:

learning_rate = 0.8 #Learning speed 
batch_size = 100 #number of samples for the batch 
display_step = 2 #number of steps before showing progress

在这里,我们为图创建初始变量和占位符,即单变量xy浮点值:

x = tf.placeholder("float", [None, 1]) # Placeholder for the 1D data 
y = tf.placeholder("float", [None, 2]) # Placeholder for the classes (2)

现在,我们将创建线性模型变量,随着模型拟合的进行,将对其进行修改和更新:

W = tf.Variable(tf.zeros([1, 2])) 
b = tf.Variable(tf.zeros([2]))

最后,我们将对线性函数应用softmax操作来构建激活函数:

activation = tf.nn.softmax(tf.matmul(x, W) + b) 

损失函数描述和优化器循环

在这里,我们仅将互相关函数定义为loss函数,并定义optimizer操作,即gradient descent。 以下各章将对此进行解释; 现在,您可以看到它是一个黑框,它将改变变量,直到损失最小:

cost = tf.reduce_mean(-tf.reduce_sum(y*tf.log(activation), reduction_indices=1)) 
optimizer = tf.train.GradientDescentOptimizer(learning_rate).minimize(cost) 
#Iterate through all the epochs 
for epoch in range(training_epochs): 
        avg_cost = 0\. 
        total_batch = 400/batch_size 
# Loop over all batches 
        for i in range(total_batch): 
            # Transform the array into a one hot format 

        temp=tf.one_hot(indices = df['chd'].values, depth=2, on_value = 1, off_value = 0, axis = -1 , name = "a")       
        batch_xs, batch_ys =(np.transpose([df['age']])-44.38)/11.721327, temp 

        # Fit training using batch data 
        sess.run(optimizer, feed_dict={x: batch_xs.astype(float), y: batch_ys.eval()}) 

        # Compute average loss, suming the corrent cost divided by the batch total number 
        avg_cost += sess.run(cost, feed_dict={x: batch_xs.astype(float), y: batch_ys.eval()})/total_batch 

停止条件

一旦根据训练周期对数据进行了训练,该过程将简单地停止。

结果描述

这将是程序的输出:

Epoch: 0001 cost= 0.638730764
[ 0.04824295 -0.04824295]
[[-0.17459483  0.17459483]]
Epoch: 0002 cost= 0.589489654
[ 0.08091066 -0.08091066]
[[-0.29231569  0.29231566]]
Epoch: 0003 cost= 0.565953553
[ 0.10427245 -0.10427245]
[[-0.37499282  0.37499279]]
Epoch: 0004 cost= 0.553756475
[ 0.12176144 -0.12176143]
[[-0.43521613  0.4352161 ]]
Epoch: 0005 cost= 0.547019333
[ 0.13527818 -0.13527818]
[[-0.48031801  0.48031798]]

拟合函数的跨周期表示

在下图中,我们表示了拟合函数在不同周期之间的进展:

Fitting function representations across epochs

完整源代码

这是完整的源代码:

import pandas as pd 
import numpy as np 
get_ipython().magic(u'matplotlib inline') 
import matplotlib.pyplot as plt 
import tensorflow as tf 

df = pd.read_csv("data/CHD.csv", header=0) 
# Parameters 

learning_rate = 0.2 
training_epochs = 5 
batch_size = 100 
display_step = 1 
sess = tf.Session() 
b=np.zeros((100,2)) 

# tf Graph Input 

x = tf.placeholder("float", [None, 1]) 
y = tf.placeholder("float", [None, 2]) 

# Create model 
# Set model weights 
W = tf.Variable(tf.zeros([1, 2])) 
b = tf.Variable(tf.zeros([2])) 

# Construct model 
activation = tf.nn.softmax(tf.matmul(x, W) + b) 
# Minimize error using cross entropy 
cost = tf.reduce_mean(-tf.reduce_sum(y*tf.log(activation), reduction_indices=1)) # Cross entropy 
optimizer = tf.train.GradientDescentOptimizer(learning_rate).minimize(cost) # Gradient Descent 

# Initializing the variables 
init = tf.initialize_all_variables() 

# Launch the graph 

with tf.Session() as sess: 
    tf.train.write_graph(sess.graph, './graphs','graph.pbtxt') 
    sess.run(init) 
    writer = tf.train.SummaryWriter('./graphs', sess.graph) 
    #Initialize the graph structure 

    graphnumber=321 

    #Generate a new graph 
    plt.figure(1) 

    #Iterate through all the epochs 
    for epoch in range(training_epochs): 
        avg_cost = 0\. 
        total_batch = 400/batch_size 
        # Loop over all batches 

        for i in range(total_batch): 
            # Transform the array into a one hot format 

            temp=tf.one_hot(indices = df['chd'].values, depth=2, on_value = 1, off_value = 0, axis = -1 , name = "a")       
            batch_xs, batch_ys = (np.transpose([df['age']])-44.38)/11.721327, temp 

            # Fit training using batch data 
            sess.run(optimizer, feed_dict={x: batch_xs.astype(float), y: batch_ys.eval()}) 

            # Compute average loss, suming the corrent cost divided by the batch total number 
            avg_cost += sess.run(cost, feed_dict={x: batch_xs.astype(float), y: batch_ys.eval()})/total_batch 
        # Display logs per epoch step 

        if epoch % display_step == 0: 
            print "Epoch:", '%05d' % (epoch+1), "cost=", "{:.8f}".format(avg_cost) 

            #Generate a new graph, and add it to the complete graph 

            trX = np.linspace(-30, 30, 100) 
            print (b.eval()) 
            print (W.eval()) 
            Wdos=2*W.eval()[0][0]/11.721327 
            bdos=2*b.eval()[0] 

            # Generate the probabiliy function 
            trY = np.exp(-(Wdos*trX)+bdos)/(1+np.exp(-(Wdos*trX)+bdos) ) 

            # Draw the samples and the probability function, whithout the normalization 
            plt.subplot(graphnumber) 
            graphnumber=graphnumber+1 

            #Plot a scatter draw of the random datapoints 
            plt.scatter((df['age']),df['chd']) 
            plt.plot(trX+44.38,trY) #Plot a scatter draw of the random datapoints 
            plt.grid(True) 

        #Plot the final graph 
        plt.savefig("test.svg")  

图形表示

使用 TensorBoard 工具,我们将看到操作链。 请注意,在一半的操作图中,我们定义了主要的全局操作(“小数点”)以及应用于其余项的梯度操作,这是进行loss函数最小化所必需的。 这是接下来几章要讨论的主题。

Graphical representation

示例 2 -- skflow 中的单变量 logistic 回归

在此示例中,我们将探索单变量示例域,但是这次我们将使用来自新库的帮助,该库为我们简化了模型构建,称为skflow

有用的库和方法

在机器学习库领域中,有很多选择。 最知名的之一是sklearn,我们在第 2 章聚类中讨论过。

在 TensorFlow 发布之后的很早,一个新的贡献库就出现了,叫做skflow,其主要目的是模拟sklearn的接口和工作流程,在这个 TensorFlow 会话环境中工作更简洁。

在下面的示例中,我们将使用skflow接口重复先前回归的分析。

在示例中,我们还将看到 skflow 如何为回归模型自动生成详细且组织良好的图,只需将日志目录设置为参数即可。

数据集说明

使用pandas库,数据集加载阶段与前面的示例相同:

import pandas as pd 

df = pd.read_csv("data/CHD.csv", header=0) 
print df.describe() 

模型架构

这是my_model的代码段:

 def my_model(X, y): 
    return skflow.models.logistic_regression(X, y) 

X1 =a.fit_transform(df['age'].astype(float)) 
y1 = df['chd'].values 
classifier = skflow.TensorFlowEstimator(model_fn=my_model, n_classes=2) 

在这里,我们可以使用softmax分类器查看逻辑回归阶段的详细视图:

Model architecture

Model architecture

结果描述

score = metrics.accuracy_score(df['chd'].astype(float), classifier.predict(X)) 
print("Accuracy: %f" % score) 

输出结果可观(为了简化模型)74% 的准确率:

Accuracy: 0.740000

完整源代码

这是完整的源代码:

import tensorflow.contrib.learn as skflow 
from sklearn import datasets, metrics, preprocessing 
import numpy as np 
import pandas as pd 

df = pd.read_csv("data/CHD.csv", header=0) 
print df.describe() 

def my_model(X, y): 
    return skflow.models.logistic_regression(X, y) 

a = preprocessing.StandardScaler() 

X1 =a.fit_transform(df['age'].astype(float)) 

y1 = df['chd'].values 

classifier = skflow.TensorFlowEstimator(model_fn=my_model, n_classes=2) 
classifier.fit(X1,y1 , logdir='/tmp/logistic') 

score = metrics.accuracy_score(df['chd'].astype(float), classifier.predict(X)) 
print("Accuracy: %f" % score) 

总结

在本章中,我们学习了一种新的建模技术,即逻辑函数,并从一种简单的分类任务入手。

我们还学习了一种通过pandas库读取基于文本的数据的新方法。

此外,我们还看到了与skflow库一起使用的经典工作流的一种补充方法。

在下一章中,我们将开始处理更复杂的架构,并进入 TensorFlow 库擅长的领域:训练,测试和最终实现神经网络以解决实际问题。

五、简单的前馈神经网络

神经网络确实是 Tensorflow 擅长的机器学习领域。 可以用它实现多种类型的架构和算法,以及结合了符号引擎的其他优点,这实际上将有助于训练更复杂的设置。

在本章中,我们开始利用高表现原语的功能来解决大量支持输入变量的日益复杂的问题。

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

  • 神经网络的初步概念
  • 非线性一般函数回归的神经网络项目
  • 利用非线性回归预测汽车燃油效率的项目
  • 学习葡萄酒的分类和多分类

初步概念

为了将简单的框架构建到神经网络的组件和架构中,我们将对原始概念进行简单明了的构建,这些原始概念为当前,复杂而多样的神经网络格局铺平了道路。

人工神经元

人工神经元是一种数学函数,被视为真实生物神经元的模型。

它的主要特征是它接收一个或多个输入(训练数据),并对它们求和以产生输出。 此外,通常对总和进行加权(权重和偏差),然后将总和传递给非线性函数(激活函数或传递函数)。

原始示例 -- 感知器

感知器是实现人工神经元的最简单方法之一,并且它的算法可以追溯到 1950 年代,最早是在 1960 年代实现的。

从本质上讲,它是一种学习二分类函数的算法,该算法将一个实数映射为两个数:

Original example - the Perceptron

下图显示了单层感知器

感知机算法

感知器的简化算法为:

  1. 用随机分布初始化权重(通常为低值)

  2. 选择一个输入向量并将其呈现给网络,

  3. 为指定的输入向量和权重值计算网络的输出y'

  4. 用于感知机的函数是:

    Perceptron algorithm

  5. 如果y' ≠ y,则通过添加更改Δw = yx[i]修改所有连接w[i]

  6. 返回步骤 2。

神经网络层

单层感知器可以推广到彼此连接的多个层,但是仍然存在问题;表示函数是输入的线性组合,并且感知器只是一种线性分类器,不可能正确拟合非线性函数。

Neural network layers

神经网络激活函数

仅靠单变量线性分类器,神经网络的学习表现就不会那么好。 甚至机器学习中的一些轻微复杂的问题都涉及多个非线性变量,因此开发了许多变体来替代感知器的传递函数。

为了表示非线性模型,可以在激活函数中使用许多不同的非线性函数。 这意味着神经元将对输入变量的变化做出反应的方式发生变化。 实际上,最常用的激活函数是:

  • Sigmoid: 规范的激活函数,对于计算分类属性的概率具有很好的属性。

    Neural Network activation functions

  • Tanh: 与 Sigmoid 非常相似,但其值范围是[-1,1]而不是[0,1]

    Neural Network activation functions

  • Relu: 这称为整流线性单元,其主要优点之一是它不受“梯度消失”问题的影响,该问题通常存在于网络的第一层,趋向于 0 或很小的epsilon值:

    Neural Network activation functions

梯度和反向传播算法

当我们描述感知器的学习阶段时,我们描述了根据权重对最终误差的“责任”来按比例调整权重的阶段。

在这个复杂的神经元网络中,误差的责任将分布在整个架构中应用于数据的所有函数之间。

因此,一旦我们计算了总误差,并且将整个函数应用于原始数据,我们现在就必须尝试调整方程式中的所有变量以将其最小化。

正如最优化领域所研究的那样,我们需要知道的是能够使该误差最小化的是损失函数的梯度。

鉴于数据要经过许多权重和传递函数,因此必须通过链式法则来解决合成函数的梯度。

最小化损失函数:梯度下降

让我们看下图以了解损失函数:

Minimizing loss function: Gradient descent

神经网络问题的选择 -- 分类与回归

神经网络可用于回归问题和分类问题。 架构上的共同差异在于输出层:为了能够带来实数为基础的结果,不应应用诸如 Sigmoid 之类的标准化函数,这样我们就不会将变量的结果更改为许多可能的类别值之一,获得了可能的连续结果。

有用的库和方法

在本章中,我们将使用 TensorFlow 和工具库中的一些新工具,这些是最重要的工具:

TensorFlow 激活函数

TensorFlow 导航中最常用的函数:

  • tf.sigmoid(x):标准 Sigmoid 函数
  • tf.tanh(x):双曲正切
  • tf.nn.relu(features):Relu 传递函数

TensorFlow 导航的其他函数:

  • tf.nn.elu(features):计算指数线性:如果< 0则为exp(features) - 1,否则为features
  • tf.nn.softsign(features):计算 softsign:features / (abs(features) + 1)
  • tf.nn.bias_add(value, bias):为值增加偏差

TensorFlow 损失优化方法

TensorFlow 损失优化方法如下所述:

  • tf.train.GradientDescentOptimizer(learning_rate, use_locking, name):这是原始的梯度下降方法,仅具有学习率参数
  • tf.train.AdagradOptimizer(learning_rate, initial_accumulator_value, use_locking, name):此方法使学习率适应参数的频率,从而提高了最小搜索稀疏参数的效率
  • tf.train.AdadeltaOptimizer(learning_rate, rho, epsilon, use_locking, name):这是改良的 AdaGrad,它将限制频繁参数的累积到最大窗口,因此它考虑了一定数量的步骤,而不是整个参数历史记录。
  • tf.train.AdamOptimizer tf.train.AdamOptimizer.__init__(learning_rate, beta1, beta2, epsilon, use_locking, name):此方法在计算梯度时会添加一个因子,该因子对应于过去梯度的平均值,等同于动量因子。 因此,来自自适应矩估计的亚当这个名字。

Sklearn 预处理工具

让我们看一下以下 Sklearn 预处理工具:

  • preprocessing.StandardScaler():数据集的正则化是许多机器学习估计器的普遍要求,因此,为了使收敛更加直接,数据集将必须更像是标准正态分布,即具有零均值和单位方差的高斯曲线。 在实践中,我们通常会忽略分布的形状,而只是通过删除每个特征的平均值来变换数据以使其居中,然后通过将非恒定特征除以它们的标准偏差来缩放它。 对于此任务,我们使用StandardScaler,它实现了前面提到的任务。 它还存储转换,以便能够将其重新应用于测试集。
  • StandardScalerfit_transform():简单地将数据调整为所需格式。 StandardScaler对象将保存转换变量,因此您将能够取回非规格化数据。
  • cross_validation.train_test_split:此方法将数据集分为训练和测试段,我们只需要提供分配给每个阶段的数据集的百分比即可。

第一个项目 -- 非线性一般函数回归

人工神经网络示例通常包含绝大多数分类问题,但实际上有大量应用可以表示为回归。

用于回归的网络架构与用于分类问题的网络架构没有很大不同:它们可以采用多变量输入,也可以使用线性和非线性激活函数。

在某些情况下,唯一必要的情况是仅在层的末尾删除类似于 Sigmoid 的函数,以允许出现所有选项。

在第一个示例中,我们将对一个简单的,有噪声的二次函数进行建模,并将尝试通过单个隐藏层网络对其进行回归,并查看我们可以多么接近地预测从测试总体中得出的值。

数据集说明和加载

在这种情况下,我们将使用生成的数据集,该数据集与第 3 章的线性回归中的数据集非常相似。

我们将使用常见的 Numpy 方法生成二次函数,然后添加随机噪声,这将有助于我们了解线性回归如何推广。

核心样本创建例程如下:

import numpy as np 
trainsamples = 200 
testsamples = 60 
dsX = np.linspace(-1, 1, trainsamples + testsamples).transpose() 
dsY = 0.4* pow(dsX,2) +2 * dsX + np.random.randn(*dsX.shape) * 0.22 + 0.8  

数据集预处理

该数据集在生成时不需要进行预处理,并且具有良好的属性,例如居中并具有-1, 1的样本分布。

模型架构 -- 损失函数描述

此设置的损耗将简单地用均方根误差表示,如下所示:

cost = tf.pow(py_x-Y, 2)/(2)  

损失函数优化器

在这种情况下,我们将使用梯度下降成本优化器,可以通过以下代码调用该优化器:

train_op = tf.train.AdamOptimizer(0.5).minimize(cost)  

准确率和收敛性测试

predict_op = tf.argmax(py_x, 1)

cost1 += sess.run(cost, feed_dict={X: [[x1]], Y: y1}) / testsamples 

示例代码

让我们看一下下面显示的示例代码:

import tensorflow as tf
import numpy as np
from sklearn.utils import shuffle
%matplotlib inline
import matplotlib.pyplot as plt
trainsamples = 200
testsamples = 60
#Here we will represent the model, a simple imput, a hidden layer of sigmoid activation
def model(X, hidden_weights1, hidden_bias1, ow):
    hidden_layer =  tf.nn.sigmoid(tf.matmul(X, hidden_weights1)+ b)
    return tf.matmul(hidden_layer, ow)  
dsX = np.linspace(-1, 1, trainsamples + testsamples).transpose()
dsY = 0.4* pow(dsX,2) +2 * dsX + np.random.randn(*dsX.shape) * 0.22 + 0.8
plt.figure() # Create a new figure
plt.title('Original data')
plt.scatter(dsX,dsY) #Plot a scatter draw of the datapoints

Example code

X = tf.placeholder("float")
Y = tf.placeholder("float")
# Create first hidden layer
hw1 = tf.Variable(tf.random_normal([1, 10], stddev=0.1))
# Create output connection
ow = tf.Variable(tf.random_normal([10, 1], stddev=0.0))
# Create bias
b = tf.Variable(tf.random_normal([10], stddev=0.1))
model_y = model(X, hw1, b, ow)
# Cost function
cost = tf.pow(model_y-Y, 2)/(2)
# construct an optimizer
train_op = tf.train.GradientDescentOptimizer(0.05).minimize(cost)
# Launch the graph in a session
with tf.Session() as sess:
    tf.initialize_all_variables().run() #Initialize all variables
    for i in range(1,100):
        dsX, dsY = shuffle (dsX.transpose(), dsY) #We randomize the samples to mplement a better training
        trainX, trainY =dsX[0:trainsamples], dsY[0:trainsamples]
        for x1,y1 in zip (trainX, trainY):
            sess.run(train_op, feed_dict={X: [[x1]], Y: y1})
        testX, testY = dsX[trainsamples:trainsamples + testsamples], dsY[0:trainsamples:trainsamples+testsamples]
        cost1=0.
        for x1,y1 in zip (testX, testY):
            cost1 += sess.run(cost, feed_dict={X: [[x1]], Y: y1}) / testsamples      
        if (i%10 == 0):
            print "Average cost for epoch " + str (i) + ":" + str(cost1)

结果描述

这是不同周期的结果的副本。请注意,由于这是一个非常简单的函数,因此即使第一次迭代也具有非常好的结果:

Average cost for epoch 1:[[ 0.00753353]]
Average cost for epoch 2:[[ 0.00381996]]
Average cost for epoch 3:[[ 0.00134867]]
Average cost for epoch 4:[[ 0.01020064]]
Average cost for epoch 5:[[ 0.00240157]]
Average cost for epoch 6:[[ 0.01248318]]
Average cost for epoch 7:[[ 0.05143405]]
Average cost for epoch 8:[[ 0.00621457]]
Average cost for epoch 9:[[ 0.0007379]]

第二个项目 -- 非线性回归和汽车的燃油效率建模

在此示例中,我们将进入一个区域,其中神经网络可提供大部分附加价值; 解决非线性问题。 为了开始这一旅程,我们将基于几个变量对几种汽车模型的燃油效率建模一个回归模型,该变量可以更好地用非线性函数表示。

数据集说明和加载

对于这个问题,我们将分析一个非常著名的,标准的,格式正确的数据集,该数据集将使我们能够分析一个多变量问题:根据离散和连续的一些相关变量来猜测汽车的 MPG。

这可以被认为是一个玩具,并且有些过时了,但是它将为更复杂的问题铺平道路,并且具有已经被众多书目分析的优势。

属性信息

该数据集具有以下数据列:

  • mpg:连续
  • cylinders:多值离散
  • displacement:连续
  • horsepower:连续
  • weight:连续
  • acceleration:连续
  • model year:多值离散
  • origin:多值离散
  • car name:字符串(将不使用)

我们将不对数据进行详细的分析,但是我们可以非正式地推断出所有连续变量都与增加或减少目标变量相关:

Dataset description and loading

数据集预处理

对于此任务,我们将使用来自 sklearn 的上述缩放器对象:

  • scaler = preprocessing.StandardScaler()
  • X_train = scaler.fit_transform(X_train)

模型架构

我们将要构建的是一个前馈神经网络,具有多变量输入和简单输出:

Modeling architecture

收敛性测试

score = metrics.mean_squared_error(regressor.predict(scaler.transform(X_test)), y_test)
print('MSE: {0:f}'.format(score))

结果描述

Step #99, avg. train loss: 182.33624
Step #199, avg. train loss: 25.09151
Step #300, epoch #1, avg. train loss: 11.92343
Step #400, epoch #1, avg. train loss: 11.20414
Step #500, epoch #1, avg. train loss: 5.14056
Total Mean Squared Error: 15.0792258911
%matplotlib inline  
import matplotlib.pyplot as plt 
import pandas as pd 

from sklearn import datasets, cross_validation, metrics 
from sklearn import preprocessing 
from tensorflow.contrib import skflow 

# Read the original dataset 
df = pd.read_csv("data/mpg.csv", header=0) 
# Convert the displacement column as float 
df['displacement']=df['displacement'].astype(float) 
# We get data columns from the dataset 
# First and last (mpg and car names) are ignored for X 
X = df[df.columns[1:8]] 
y = df['mpg'] 

plt.figure() # Create a new figure 

for i in range (1,8): 
    number = 420 + i 
    ax1.locator_params(nbins=3) 
    ax1 = plt.subplot(number) 
    plt.title(list(df)[i]) 
    ax1.scatter(df[df.columns[i]],y) #Plot a scatter draw of the  datapoints 
plt.tight_layout(pad=0.4, w_pad=0.5, h_pad=1.0) 
# Split the datasets 

X_train, X_test, y_train, y_test = cross_validation.train_test_split(X, y, 
test_size=0.25) 

# Scale the data for convergency optimization 
scaler = preprocessing.StandardScaler() 

# Set the transform parameters 
X_train = scaler.fit_transform(X_train) 

# Build a 2 layer fully connected DNN with 10 and 5 units respectively 
regressor = skflow.TensorFlowDNNRegressor(hidden_units=[10, 5], 
steps=500, learning_rate=0.051, batch_size=1) 

# Fit the regressor 
regressor.fit(X_train, y_train) 

# Get some metrics based on the X and Y test data 
score = metrics.mean_squared_error(regressor.predict(scaler.transform(X_test)), y_test) 

print(" Total Mean Squared Error: " + str(score)) 

第三个项目 -- 葡萄酒分类:多类分类的学习

在本节中,我们将使用更复杂的数据集,尝试根据产地对葡萄酒进行分类。

数据集说明和加载

该数据包含对来自意大利同一地区但来自三个不同品种的葡萄酒进行化学分析的结果。 分析确定了三种葡萄酒中每种所含 13 种成分的数量。

数据变量:

  • 苹果酸
  • 灰的碱度
  • 总酚
  • 黄酮
  • 非类黄酮酚
  • 花青素
  • 色彩强度
  • 色调
  • 稀释酒的 OD280/OD315
  • 脯氨酸

要读取数据集,我们将仅使用提供的 CSV 文件和熊猫:

df = pd.read_csv("./wine.csv", header=0)

Dataset description and loading

数据集预处理

随着 csv 上的值从 1 开始,我们将归一化带有偏差的值:

y = df['Wine'].values-1 

对于结果,我们将这些选项表示为一个数组的热门列表:

Y = tf.one_hot(indices = y, depth=3, on_value = 1., off_value = 0., axis = 1 , name = "a").eval() 

我们还将预先洗净值:

X, Y = shuffle (X, Y) 
scaler = preprocessing.StandardScaler() 
X = scaler.fit_transform(X) 

模型架构

这个特定的模型将由一个单层,全连接的神经网络组成:

  • x = tf.placeholder(tf.float32, [None, 12])
  • W = tf.Variable(tf.zeros([12, 3]))
  • b = tf.Variable(tf.zeros([3]))
  • y = tf.nn.softmax(tf.matmul(x, W) + b)

损失函数说明

我们将使用交叉熵函数来衡量损失:

y_ = tf.placeholder(tf.float32, [None, 3]) 
cross_entropy = tf.reduce_mean(-tf.reduce_sum(y_ * tf.log(y), reduction_indices=[1])) 

损失函数优化器

同样,将使用“梯度下降”方法来减少损失函数:

train_step = tf.train.GradientDescentOptimizer(0.1).minimize(cross_entropy) 

收敛测试

在收敛性测试中,我们将每个良好的回归均转换为 1,将每个错误的回归均转换为 0,然后获取值的平均值来衡量模型的准确率:

correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(y_, 1)) 
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32)) 
print(accuracy.eval({x: Xt, y_: Yt})) 

结果描述

如我们所见,随着历时的发展,我们具有可变精度,但是它总是优于 90% 的精度,具有 30% 的随机基数(如果我们生成 0 到 3 之间的随机数来猜测结果)。

0.973684
0.921053
0.921053
0.947368
0.921053

完整源代码

让我们看一下完整的源代码:

sess = tf.InteractiveSession() 
import pandas as pd 
# Import data 
from tensorflow.examples.tlutorials.mnist import input_data 
from sklearn.utils import shuffle 
import tensorflow as tf 

from sklearn import preprocessing 

flags = tf.app.flags 
FLAGS = flags.FLAGS 

df = pd.read_csv("./wine.csv", header=0) 
print (df.describe()) 
#df['displacement']=df['displacement'].astype(float) 
X = df[df.columns[1:13]].values 
y = df['Wine'].values-1 
Y = tf.one_hot(indices = y, depth=3, on_value = 1., off_value = 0., axis = 1 , name = "a").eval() 
X, Y = shuffle (X, Y) 

scaler = preprocessing.StandardScaler() 
X = scaler.fit_transform(X) 

# Create the model 
x = tf.placeholder(tf.float32, [None, 12]) 
W = tf.Variable(tf.zeros([12, 3])) 
b = tf.Variable(tf.zeros([3])) 
y = tf.nn.softmax(tf.matmul(x, W) + b) 

# Define loss and optimizer 
y_ = tf.placeholder(tf.float32, [None, 3]) 
cross_entropy = tf.reduce_mean(-tf.reduce_sum(y_ * tf.log(y), reduction_indices=[1])) 
train_step = tf.train.GradientDescentOptimizer(0.1).minimize(cross_entropy) 
# Train 
tf.initialize_all_variables().run() 
for i in range(100): 
X,Y =shuffle (X, Y, random_state=1) 

Xtr=X[0:140,:] 
Ytr=Y[0:140,:] 

Xt=X[140:178,:] 
Yt=Y[140:178,:] 
Xtr, Ytr = shuffle (Xtr, Ytr, random_state=0) 
#batch_xs, batch_ys = mnist.train.next_batch(100) 
batch_xs, batch_ys = Xtr , Ytr 
train_step.run({x: batch_xs, y_: batch_ys}) 
cost = sess.run (cross_entropy, feed_dict={x: batch_xs, y_: batch_ys}) 
# Test trained model 
correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(y_, 1)) 
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32)) 
print(accuracy.eval({x: Xt, y_: Yt})) 

总结

在本章中,我们已经开始着手实现 TensorFlow 能力的真正替代物:神经网络模型。

我们还看到了在回归和分类任务中使用简单神经网络,简单生成模型和实验模型的情况。

在下一章中,我们将以卷积神经网络的形式提高新架构的知识以及将神经网络范式应用于其他知识领域(例如计算机视觉)的方式。