在你看这篇教程之前,你应该有下列基础:
python基础
了解数组的少许知识
最好有一些机器学习的知识,没有的话就好好看本教程
TensorFlow提供了多种接口,低层接口提供完全的模型编程控制,适合于机器学习的研究者。高层接口适用于应用者,方便大家沟通交流。
这篇教程先介绍了TensorFlow的核心,我们展示了如何使用tf.estimator去实现相同的模型,让你知道TensorFlow内部是如何运行的(当你选择使用高层接口的时候)。
Tensors(张量)
TensorFlow的核心数据单元是tensor(张量)。一个张量是由一些原始值改变成不同形状的数组组成的。一个张量的秩就是它的维度。以下是一些例子:
3 # 一个秩为0的张量; 形状是[]
[1., 2., 3.] # 一个秩为1的张量; 向量的形状是 [3]
[[1., 2., 3.], [4., 5., 6.]] # 一个秩为2的张量; 矩阵的形状是 [2, 3]
[[[1., 2., 3.]], [[7., 8., 9.]]] # 一个秩为3的张量;矩阵的形状是 [2, 1, 3]
TensorFlow Core tutorial(核心教程)
导入TensorFlow
标准的tensorflow导入语句如下:
import tensorflow as tf
这句代码让Python可以进入所有tensorflow的类,方法和符号。大部分的文档已经假设你引入了tensorflow
The Computational Graph(计算图)
计算图由两个部分组成:
1、建立计算图
2、运行计算图
一个计算图是一系列图节点的运算。让我们建立一个简单的计算图。每个节点有0个或者多个张量作为输入,然后产生一个张量作为输出。节点的一种类型可以是常量。我们可以创建两个单精度浮点型的张量node1和node2,如下所示:
node1 = tf.constant(3.0, dtype=tf.float32)
node2 = tf.constant(4.0) # also tf.float32 implicitly
print(node1, node2)
最后一句print产生的结果:
Tensor("Const:0", shape=(), dtype=float32) Tensor("Const_1:0", shape=(), dtype=float32)
注意到输出的节点并没有像你预想的一样是3.0和4.0,而是当需要求值的时候,会产生3.0和4.0。为了去求出节点的值,我们必须用session(会话)去运行计算图。sess = tf.Session()#建立一个session
print(sess.run([node1, node2]))#求解node1和node2的值
得到输出的结果:[3.0, 4.0]
接下去,我们可以结合张量节点以及运算来进行更加复杂的计算。比如我们可以把两个常量张量相加,这样的计算图如下:
node3 = tf.add(node1, node2)
print("node3:", node3)
print("sess.run(node3):", sess.run(node3))
输出的结果为:
node3: Tensor("Add:0", shape=(), dtype=float32)
sess.run(node3): 7.0
更一般地,如果我们要在运算的时候再输入值,而不是直接固定好常量,那么可以使用placeholder(占位符)。一个占位符负责之后提供一个值。
a = tf.placeholder(tf.float32)
b = tf.placeholder(tf.float32)
adder_node = a + b # + provides a shortcut for tf.add(a, b)
然后在运行这个计算图的时候要填入对应占位符的值。
print(sess.run(adder_node, {a: 3, b: 4.5}))
print(sess.run(adder_node, {a: [1, 3], b: [2, 4]}))
结果如下:
7.5
[ 3. 7.]
然后我们可以用其他运算把计算图搞得更加复杂:
add_and_triple = adder_node * 3.
print(sess.run(add_and_triple, {a: 3, b: 4.5}))
结果是:
22.5
在机器学习中,我们一般希望能处理任意的输入,比如上面的例子。Variables(变量)允许我们向计算图加入可训练的参数。由类型和初始值两部分构造而成。
W = tf.Variable([.3], dtype=tf.float32)
b = tf.Variable([-.3], dtype=tf.float32)
x = tf.placeholder(tf.float32)
linear_model = W * x + b
当你调用tf.constant的时候,常量就被初始化了,并且他们的值永远无法改变。相比较而言,调用tf.variable时,变量并没有被初始化。为了在你的tensorflow项目中初始化变量,你需要一个额外的操作:
init = tf.global_variables_initializer()
sess.run(init)
认识到init是tensorflow子图的句柄是非常重要的,它掌管着所有的变量。在我们调用sess.run之前,变量都没有被初始化。
既然x是一个占位符,那么我们用一个线性模型去求解
print(sess.run(linear_model, {x: [1, 2, 3, 4]}))
结果:
[ 0. 0.30000001 0.60000002 0.90000004]
这样我们就建立了一个模型,然而我们并不知道模型的好坏。为了使用训练数据去求得模型,我们需要一个y占位符提供期望值,并且需要写一个损失函数。损失函数度量了当前模型到期望值的远近。我们使用一个标准的线性回归损失函数(模型估计值与期望值的差的平方和)。linear_model - y就是模型估计值与期望值的差。然后我们把它平方。然后使用reduce_sum进行求和(标量)。
y = tf.placeholder(tf.float32)
squared_deltas = tf.square(linear_model - y)
loss = tf.reduce_sum(squared_deltas)
print(sess.run(loss, {x: [1, 2, 3, 4], y: [0, -1, -2, -3]}))
结果是:
23.66
然后我们需要对W,b这样的参数进行赋值来降低损失函数的结果。举例:W=-1,b=1
fixW = tf.assign(W, [-1.])
fixb = tf.assign(b, [1.])
sess.run([fixW, fixb])
print(sess.run(loss, {x: [1, 2, 3, 4], y: [0, -1, -2, -3]}))
结果是:0.0
很幸运,我们直接猜到了最完美的参数设置使得损失函数的值最小,但是在实际情况下,我们需要自动计算出最优的参数,我们将在下面进行讲解
tf.train API
一个机器学习的完整讨论超出了本教程的范围。不过tensorflow提供了最优化器去缓慢地减小损失函数的值。最简单的最优化器是梯度下降。仅仅使用tf.gradients就可以进行自动求导。
optimizer = tf.train.GradientDescentOptimizer(0.01)
train = optimizer.minimize(loss)
sess.run(init) # reset values to incorrect defaults.
for i in range(1000):
sess.run(train, {x: [1, 2, 3, 4], y: [0, -1, -2, -3]})
print(sess.run([W, b]))
结果是:
[array([-0.9999969], dtype=float32), array([ 0.99999082],
dtype=float32)]
现在,我们完成了一个真正的机器学习算法。虽然做这个线性回归的练习并不需要很多的tensorflow的核心代码,但是更复杂的模型和喂数据的方法需要更多的代码。因此tensorflow提供了更高层的接口来完成这些任务,我们将在下节介绍这些知识。
完整的程序
线性回归的完整代码:
import tensorflow as tf
# Model parameters
W = tf.Variable([.3], dtype=tf.float32)
b = tf.Variable([-.3], dtype=tf.float32)
# Model input and output
x = tf.placeholder(tf.float32)
linear_model = W * x + b
y = tf.placeholder(tf.float32)
# loss
loss = tf.reduce_sum(tf.square(linear_model - y)) # sum of the squares
# optimizer
optimizer = tf.train.GradientDescentOptimizer(0.01)
train = optimizer.minimize(loss)
# training data
x_train = [1, 2, 3, 4]
y_train = [0, -1, -2, -3]
# training loop
init = tf.global_variables_initializer()
sess = tf.Session()
sess.run(init) # reset values to wrong
for i in range(1000):
sess.run(train, {x: x_train, y: y_train})
# evaluate training accuracy
curr_W, curr_b, curr_loss = sess.run([W, b, loss], {x: x_train, y: y_train})
print("W: %s b: %s loss: %s"%(curr_W, curr_b, curr_loss))
结果:
W: [-0.9999969] b: [ 0.99999082] loss: 5.69997e-11
tf.estimator
tf.estimator是一个高层的tensorflow接口,可以简化机器学习,包括以下方面:
运行训练循环
运行赋值循环
管理数据集
tf.estimator定义了许多常见模型基本用法:
注意使用tf.estimator后线性回归变得多么简单:
import tensorflow as tf
# NumPy is often used to load, manipulate and preprocess data.
import numpy as np
# Declare list of features. We only have one numeric feature. There are many
# other types of columns that are more complicated and useful.
feature_columns = [tf.feature_column.numeric_column("x", shape=[1])]
# An estimator is the front end to invoke training (fitting) and evaluation
# (inference). There are many predefined types like linear regression,
# linear classification, and many neural network classifiers and regressors.
# The following code provides an estimator that does linear regression.
estimator = tf.estimator.LinearRegressor(feature_columns=feature_columns)
# TensorFlow provides many helper methods to read and set up data sets.
# Here we use two data sets: one for training and one for evaluation
# We have to tell the function how many batches
# of data (num_epochs) we want and how big each batch should be.
x_train = np.array([1., 2., 3., 4.])
y_train = np.array([0., -1., -2., -3.])
x_eval = np.array([2., 5., 8., 1.])
y_eval = np.array([-1.01, -4.1, -7, 0.])
input_fn = tf.estimator.inputs.numpy_input_fn(
{"x": x_train}, y_train, batch_size=4, num_epochs=None, shuffle=True)
train_input_fn = tf.estimator.inputs.numpy_input_fn(
{"x": x_train}, y_train, batch_size=4, num_epochs=1000, shuffle=False)
eval_input_fn = tf.estimator.inputs.numpy_input_fn(
{"x": x_eval}, y_eval, batch_size=4, num_epochs=1000, shuffle=False)
# We can invoke 1000 training steps by invoking the method and passing the
# training data set.
estimator.train(input_fn=input_fn, steps=1000)
# Here we evaluate how well our model did.
train_metrics = estimator.evaluate(input_fn=train_input_fn)
eval_metrics = estimator.evaluate(input_fn=eval_input_fn)
print("train metrics: %r"% train_metrics)
print("eval metrics: %r"% eval_metrics)
运行结果:
train metrics: {'loss': 1.2712867e-09, 'global_step': 1000}
eval metrics: {'loss': 0.0025279333, 'global_step': 1000}