未验证 提交 762753c6 编写于 作者: 片刻小哥哥's avatar 片刻小哥哥 提交者: GitHub

Merge pull request #10 from apachecn/dev

定期合并 - Dev
......@@ -11,7 +11,7 @@ OReilly Hands On Machine Learning with Scikit Learn and TensorFlow (Sklearn与Te
## 目录结构
### 第一部分 机器学习基础
* 1.) [机器学习概览](/docs/1.机器学习愿景.md)
* 1.) [机器学习概览](/docs/1.机器学习概览.md)
* 2.) [端到端的机器学习项目]()
* 3.) [分类]()
* 4.) [训练模型]()
......@@ -22,7 +22,7 @@ OReilly Hands On Machine Learning with Scikit Learn and TensorFlow (Sklearn与Te
### 第二部分 神经网络与深度学习
* 9.) [用TensorFlow启动并运行]()
* 9.) [用TensorFlow启动并运行](/docs/9.用TensorFlow启动并运行.md)
* 10.) [人工神经网络介绍]()
* 11.) [训练深层神经网络]()
* 12.) [在设备和服务器上的分布式TensorFlow]()
......
# 第9章 用TensorFlow启动并运行
**创造第一个图谱,然后运行它**
```python
import tensorflow as tf  
x = tf.Variable(3, name="x")  
y = tf.Variable(4, name="y")  
f = x*x*y + y + 2  
```
这就是它的一切! 最重要的是要知道这个代码实际上并不执行任何计算,即使它看起来像(尤其是最后一行)。 它只是创建一个计算图谱。 事实上,变量都没有初始化.要评估此图,您需要打开一个TensorFlow会话并使用它初始化变量并评估f。 TensorFlow会话负责处理在诸如CPU和GPU之类的设备上的操作并运行它们,并且它保留所有变量值.以下代码创建一个会话,初始化变量,并评估,然后f关闭会话(释放资源):
```python
# way1  
sess = tf.Session()  
sess.run(x.initializer)  
sess.run(y.initializer)  
result = sess.run(f)  
  
print(result)  
sess.close()  
```
不得不每次重复sess.run()有点麻烦,但幸运的是有一个更好的方法:
```python
# way2  
with tf.Session() as sess:  
    x.initializer.run()  
    y.initializer.run()  
    result = f.eval()  
print(result)"font-size:18px;">  
```   
在with块中,会话被设置为默认会话。 调用x.initializer.run()等效于调用tf.get_default_session().run(x.initial), f.eval()等效于调用tf.get_default_session()。运行(F)。 这使得代码更容易阅读。 此外,会话在块的末尾自动关闭。
你可以使用global_variables_initializer()函数,而不是手动初始化每个变量。 请注意,它实际上没有立即执行初始化,而是在图谱中创建一个当程序运行时所有变量都会初始化的节点:
```python
# way3  
# init = tf.global_variables_initializer()  
# with tf.Session() as sess:  
#     init.run()  
#     result = f.eval()  
6. # print(result)  
```
在Jupyter内部或在Python shell中,您可能更喜欢创建一个InteractiveSession。 与常规会话的唯一区别是,当创建InteractiveSession时,它将自动将其自身设置为默认会话,因此您不需要使用模块(但是您需要在完成后手动关闭会话):
```python
# way4  
init = tf.global_variables_initializer()  
sess = tf.InteractiveSession()  
init.run()  
result = f.eval()  
print(result)  
sess.close()  
```
TensorFlow程序通常分为两部分:第一部分构建计算图谱(这称为构造阶段),第二部分运行它(这是执行阶段)。 建设阶段通常构建一个表示ML模型的计算图谱,然后对其进行训练,计算。 执行阶段通常运行循环,重复地评估训练步骤(例如,每个mini-batch),逐渐改进模型参数。 
**管理图谱**
您创建的任何节点都会自动添加到默认图形中:
```python
>>> x1 = tf.Variable(1)  
>>> x1.graph is tf.get_default_graph()  
True  
```
在大多数情况下,这是很好的,但有时您可能需要管理多个独立图形。 您可以通过创建一个新的图形并暂时将其设置为一个块中的默认图形,如下所示:
```python
>>> graph = tf.Graph()  
>>> with graph.as_default():  
... x2 = tf.Variable(2)  
...  
>>> x2.graph is graph  
True  
>>> x2.graph is tf.get_default_graph()  
False  
```
在Jupyter(或Python shell)中,通常在实验时多次运行相同的命令。 因此,您可能会收到包含许多重复节点的默认图形。 一个解决方案是重新启动Jupyter内核(或Python shell),但是一个更方便的解决方案是通过运行tf.reset_default_graph()来重置默认图。
**节点值的生命周期**
评估节点时,TensorFlow会自动确定所依赖的节点集,并首先评估这些节点。 例如,考虑以下代码:
```python
# w = tf.constant(3)  
# x = w + 2  
# y = x + 5  
# z = x * 3  
  
# with tf.Session() as sess:  
#     print(y.eval())  
#     print(z.eval())  
```
首先,这个代码定义了一个非常简单的图。然后,它启动一个会话并运行图来评估y:TensorFlow自动检测到y取决于w,这取决于x,所以它首先评估w,然后x,然后y,并返回y的值。最后,代码运行图来评估z。再次,TensorFlow检测到它必须首先评估w和x。重要的是要注意,它不会重用以前的w和x的评估结果。简而言之,前面的代码评估w和x两次。
所有节点值都在图运行之间删除,除了变量值,由会话跨图形运行维护(队列和读者也保持一些状态)。变量在其初始化程序运行时启动其生命周期,并且在会话关闭时结束。
如果要有效地评估y和z,而不像之前的代码那样评估w和x两次,那么您必须要求TensorFlow在一个图形运行中评估y和z,如下面的代码所示:
```python
# with tf.Session() as sess:  
#     y_val, z_val = sess.run([y, z])  
#     print(y_val) # 10  
#     print(z_val) # 15  
```
在单进程TensorFlow中,多个会话不共享任何状态,即使它们重用同一个图(每个会话都有自己的每个变量的副本)。 在分布式TensorFlow中,变量状态存储在服务器上,而不是在会话中,因此多个会话可以共享相同的变量。
**Linear Regression with TensorFlow**
TensorFlow操作(也称为ops)可以采用任意数量的输入并产生任意数量的输出。 例如,加法运算和乘法运算都需要两个输入并产生一个输出。 常量和变量不输入(它们被称为源操作)。 输入和输出是称为张量的多维数组(因此称为“tensor flow”)。 就像NumPy数组一样,张量具有类型和形状。 实际上,在Python API中,张量简单地由NumPy ndarrays表示。 它们通常包含浮点数,但您也可以使用它们来传送字符串(任意字节数组)。
迄今为止的示例,张量只包含单个标量值,但是当然可以对任何形状的数组执行计算。例如,以下代码操作二维数组来对加利福尼亚房屋数据集进行线性回归(在第2章中介绍)。它从获取数据集开始;那么它会向所有训练实例添加一个额外的偏置输入特征(x0 = 1)(它使用NumPy进行,因此立即运行);那么它创建两个TensorFlow常数节点X和y来保存该数据和目标,并且它使用TensorFlow提供的一些矩阵运算来定义theta。这些矩阵函数transpose(),matmul()和matrix_inverse() 是不言自明的,但是像往常一样,它们不会立即执行任何计算;相反,它们会在图形中创建在运行图形时执行它们的节点。您可以认识到θ的定义对应于方程![](https://img-blog.csdn.net/20171027174355328)
最后,代码创建asession并使用它来评估theta。
```python
import numpy as np  
from sklearn.datasets import fetch_california_housing  
housing = fetch_california_housing()  
m, n = housing.data.shape  
#np.c_按colunm来组合array  
housing_data_plus_bias = np.c_[np.ones((m, 1)), housing.data]  
  
X = tf.constant(housing_data_plus_bias, dtype=tf.float32, name="X")  
y = tf.constant(housing.target.reshape(-1, 1), dtype=tf.float32, name="y")  
= tf.transpose(X)  
theta = tf.matmul(tf.matmul(tf.matrix_inverse(tf.matmul(XT, X)), XT), y)  
with tf.Session() as sess:  
    theta_value = theta.eval()  
print(theta_value)  
```
该代码的主要优点是直接使用NumPy计算正态方程式,如果您有一个(如果您安装了支持GPU的TensorFlow,则TensorFlow将自动运行在GPU卡上),请参阅第12章了解更多详细信息)
其实这里就是用最小二乘法算θ
[http://blog.csdn.net/akon_wang_hkbu/article/details/77503725](http://blog.csdn.net/akon_wang_hkbu/article/details/77503725)
**实现梯度下降**
让我们尝试使用批量梯度下降(在第4章中介绍),而不是普通方程。 首先,我们将通过手动计算梯度来实现,然后我们将使用TensorFlow的自动扩展功能来使TensorFlow自动计算梯度,最后我们将使用几个TensorFlow的优化器。
当使用梯度下降时,请记住,首先要对输入特征向量进行归一化,否则训练可能要慢得多。 您可以使用TensorFlow,NumPy,ScikitLearn的StandardScaler或您喜欢的任何其他解决方案。 以下代码假定此规范化已经完成。
**手动计算渐变**
以下代码应该是相当不言自明的,除了几个新元素:
* random_uniform()函数在图形中创建一个节点,它将生成包含随机值的张量,给定其形状和值范围,就像NumPy的rand()函数一样。
* assign()函数创建一个将为变量分配一个新值的节点。 在这种情况下,它实现了批次梯度下降步骤θ(next step)=θ-η∇θMSE(θ)。
* 主循环一次又一次(n_epochs次)执行训练步骤,每100次迭代都打印出当前均方误差(mse)。 你应该看到MSE在每次迭代中都会下降。
```python
housing = fetch_california_housing()  
m, n = housing.data.shape  
m, n = housing.data.shape  
#np.c_按colunm来组合array  
housing_data_plus_bias = np.c_[np.ones((m, 1)), housing.data]  
scaled_housing_data_plus_bias = scale(housing_data_plus_bias)  
n_epochs = 1000  
learning_rate = 0.01  
X = tf.constant(scaled_housing_data_plus_bias, dtype=tf.float32, name="X")  
y = tf.constant(housing.target.reshape(-1, 1), dtype=tf.float32, name="y")  
theta = tf.Variable(tf.random_uniform([n + 1, 1], -1.0, 1.0), name="theta")  
y_pred = tf.matmul(X, theta, name="predictions")  
error = y_pred - y  
mse = tf.reduce_mean(tf.square(error), name="mse")  
gradients = 2/m * tf.matmul(tf.transpose(X), error)  
training_op = tf.assign(theta, theta - learning_rate * gradients)  
init = tf.global_variables_initializer()  
with tf.Session() as sess:  
    sess.run(init)  
    for epoch in range(n_epochs):  
        if epoch % 100 == 0:  
            print("Epoch", epoch, "MSE =", mse.eval())  
        sess.run(training_op)  
    best_theta = theta.eval()  
```
**Using autodiff**
上述代码运行的不错,但它需要从数学上损失成本函数(MSE)的梯度。 在线性回归的情况下,这是相当容易的,但是如果你必须用深层神经网络来做这个事情,你会感到头痛:这将是乏味和容易出错的。 您可以使用symbolic di‰erentiation来为您自动找到偏导数的方程式,但结果代码不一定非常有效。
为了理解为什么,考虑函数f(x)= exp(exp(exp(x)))。 如果你知道微积分,你可以计算出它的导数f'(x)= exp(x)×exp(exp(x))×exp(exp(exp(x)))。如果您按照普通的计算方式分别去写f(x)和f'(x),您的代码将不会如此有效。 一个更有效的解决方案是写一个首先计算exp(x),然后exp(exp(x)),然后exp(exp(exp(x)))的函数,并返回所有三个。这给你直接(第三项)f(x),如果你需要派生,你可以把这三个子式相乘,你就完成了。 通过传统的方法,您不得不将exp函数调用9次来计算f(x)和f'(x)。 使用这种方法,你只需要调用它三次。
当您的功能由某些任意代码定义时,它会变得更糟。 你可以找到方程(或代码)来计算以下函数的偏导数?
提示:不要尝试。
```python
def my_func(a, b):  
    z = 0  
    for i in range(100):  
    z = a * np.cos(z + i) + z * np.sin(b - i)  
    return z  
```
幸运的是,TensorFlow的自动计算梯度功能可以计算这个公式:它可以自动高效地为您梯度的计算。 只需用以下一行替换上一节中代码的gradients = ... 行,代码将继续工作正常:
```python
gradients = tf.gradients(mse, [theta])[0]  
```
gradients() 函数使用一个op(在这种情况下是mse)和一个变量列表(在这种情况下只是theta),它创建一个ops列表(每个变量一个)来计算op的梯度变量。 因此,梯度节点将计算MSE相对于theta的梯度向量。
自动计算梯度有四种主要方法。 它们总结在表9-2中。 TensorFlow使用反向模式,这是完美的(高效和准确),当有很多输入和少量的输出,如通常在神经网络的情况。 它只是在n(outputs) + 1图遍历中计算所有输出的偏导数。
![](/images/chapter_9/20171030144740842.jpg)
**使用优化器**
所以TensorFlow为您计算梯度。 但它还有更好的方法:它还提供了一些可以直接使用的优化器,包括梯度下降优化器。您可以使用以下代码简单地替换以前的gradients = ...  和training_op = ...行,并且一切都将正常工作:
```python
optimizer = tf.train.GradientDescentOptimizer(learning_rate=learning_rate)  
training_op = optimizer.minimize(mse)  
```
如果要使用其他类型的优化器,则只需要更改一行。 例如,您可以通过定义优化器来使用动量优化器(通常会比渐变渐变收敛得快得多;参见第11章)
```python
optimizer = tf.train.MomentumOptimizer(learning_rate=learning_rate, momentum=0.9)  
```
**将数据提供给训练算法**
我们尝试修改以前的代码来实现小批量梯度(Mini-batch Gradient Descent)下降。 为此,我们需要一种在每次迭代时用下一个小批量替换X和Y的方法。 最简单的方法是使用占位符节点(placeholder)。 这些节点是特别的,因为它们实际上并不执行任何计算,只是输出您在运行时输出的数据。 它们通常用于在培训期间将训练数据传递TensorFlow。 如果在运行时没有为占位符指定值,则会收到异常。
要创建占位符节点,您必须调用placeholder() 函数并指定输出张量的数据类型。 或者,您还可以指定其形状,如果要强制执行。 如果指定维度为“None”,则表示“任何大小”。例如,以下代码创建一个占位符节点A,还有一个节点B = A + 5.当我们评估B时,我们将一个feed_dict传递给eval ()方法指定A的值。注意,A必须具有2级(即它必须是二维的),并且必须有三列(否则引发异常),但它可以有任意数量的行。
```python
>>> A = tf.placeholder(tf.float32, shape=(None, 3))  
>>> B = A + 5  
>>> with tf.Session() as sess:  
... B_val_1 = B.eval(feed_dict={A: [[1, 2, 3]]})  
... B_val_2 = B.eval(feed_dict={A: [[4, 5, 6], [7, 8, 9]]})  
...  
>>> print(B_val_1)  
[[ 6. 7. 8.]]  
>>> print(B_val_2)  
[[ 9. 10. 11.]  
[ 12. 13. 14.]]  
```
您实际上可以提供任何操作的输出,而不仅仅是占位符。 在这种情况下,TensorFlow不会尝试评估这些操作; 它使用您提供的值。
要实现小批量渐变下降,我们只需稍微调整现有的代码。 首先更改X和Y的定义,使其占位符节点:
```python
X = tf.placeholder(tf.float32, shape=(None, n + 1), name="X")  
y = tf.placeholder(tf.float32, shape=(None, 1), name="y")  
```
然后定义批量大小并计算总批次数:
```python
batch_size = 100  
n_batches = int(np.ceil(m / batch_size))  
```
最后,在执行阶段,逐个获取小批量,然后在评估依赖于X和y的值的任何一个节点时,通过feed_dict提供X和y的值。
```python
def fetch_batch(epoch, batch_index, batch_size):
[...] # load the data from disk
return X_batch, y_batch
with tf.Session() as sess:
sess.run(init)
for epoch in range(n_epochs):
for batch_index in range(n_batches):
X_batch, y_batch = fetch_batch(epoch, batch_index, batch_size)
sess.run(training_op, feed_dict={X: X_batch, y: y_batch})
best_theta = theta.eval()
```
在评估theta时,我们不需要传递X和y的值,因为它不依赖于它们。
**MINI-BATCH完整代码**
```python
import numpy as np  
from sklearn.datasets import fetch_california_housing  
import tensorflow as tf  
from sklearn.preprocessing import StandardScaler  
  
housing = fetch_california_housing()  
m, n = housing.data.shape  
print("数据集:{}行,{}列".format(m,n))  
housing_data_plus_bias = np.c_[np.ones((m, 1)), housing.data]  
scaler = StandardScaler()  
scaled_housing_data = scaler.fit_transform(housing.data)  
scaled_housing_data_plus_bias = np.c_[np.ones((m, 1)), scaled_housing_data]  
  
n_epochs = 1000  
learning_rate = 0.01  
  
X = tf.placeholder(tf.float32, shape=(None, n + 1), name="X")  
y = tf.placeholder(tf.float32, shape=(None, 1), name="y")  
theta = tf.Variable(tf.random_uniform([n + 1, 1], -1.0, 1.0, seed=42), name="theta")  
y_pred = tf.matmul(X, theta, name="predictions")  
error = y_pred - y  
mse = tf.reduce_mean(tf.square(error), name="mse")  
optimizer = tf.train.GradientDescentOptimizer(learning_rate=learning_rate)  
training_op = optimizer.minimize(mse)  
  
init = tf.global_variables_initializer()  
  
n_epochs = 10  
batch_size = 100  
n_batches = int(np.ceil(m / batch_size)) #ceil()方法返回x的值上限 - 不小于x的最小整数。  
  
def fetch_batch(epoch, batch_index, batch_size):  
    know = np.random.seed(epoch * n_batches + batch_index)  # not shown in the book  
    print("我是know:",know)  
    indices = np.random.randint(m, size=batch_size)  # not shown  
    X_batch = scaled_housing_data_plus_bias[indices] # not shown  
    y_batch = housing.target.reshape(-1, 1)[indices] # not shown  
    return X_batch, y_batch  
  
with tf.Session() as sess:  
    sess.run(init)  
  
    for epoch in range(n_epochs):  
        for batch_index in range(n_batches):  
            X_batch, y_batch = fetch_batch(epoch, batch_index, batch_size)  
            sess.run(training_op, feed_dict={X: X_batch, y: y_batch})  
  
    best_theta = theta.eval()  
  
print(best_theta)  
```
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册