TensorFlow实战-started
Tensors,长量,数据在TensorFlow里面的基础但是就是tensor。长量的秩就是他的维数。这是一些tonsors的例子:
3 # a rank 0 tensor; a scalar with shape []
[1., 2., 3.] # a rank 1 tensor; a vector with shape [3]
[[1., 2., 3.], [4., 5., 6.]] # a rank 2 tensor; a matrix with shape [2, 3]
[[[1., 2., 3.]], [[7., 8., 9.]]] # a rank 3 tensor with shape [2, 1, 3]
computational graph是一系列由节点图组成的TensorFlow操作。节点的一种类型是常量。下面我们建立两个浮点型的长量:
In [3]: node1 = tf.constant(3.0, dtype=tf.float32)
...: node2 = tf.constant(4.0) # also tf.float32 implicitly
...: print(node1, node2)
...:
Tensor("Const:0", shape=(), dtype=float32) Tensor("Const_1:0", shape=(), dtype=float32)
但是输出的值并不是3.0和4.0。其实,他在计算的时候会产生对应的值。session封装了TensorFlow runtime的控制和状态:
In [8]: sess = tf.Session()
...: print(sess.run([node1, node2]))
...:
[3.0, 4.0]
placeholder可以参数化的接受一个外部的输入值:
a = tf.placeholder(tf.float32)
b = tf.placeholder(tf.float32)
adder_node = a + b # + provides a shortcut for tf.add(a, b)
In [10]: 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.]
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
初始化变量前必须明确进行如下操作:
init = tf.global_variables_initializer()
sess.run(init)
下面测试一下结果:
In [13]: print(sess.run(linear_model, {x: [1, 2, 3, 4]}))
[ 0. 0.30000001 0.60000002 0.90000004]
我们使用placeholder来提供一个期望值,下面写一个损失函数。损失值度量了当前值和所提供值的差距。linear_model - y衡量了误差面积。
In [14]: 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
变量的值可以通过tf.Variable方法:
In [15]: 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提供了优化器来缓慢的改变变量来最小化损失函数。最简单的例子就是梯度下降。他根据损失倒数的大小修改每一个变量。
In [16]: optimizer = tf.train.GradientDescentOptimizer(0.01)
...: train = optimizer.minimize(loss)
...:
In [17]: 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)]
一个完整的可训练线性回归模型如下:
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))
结果可能不尽相同,因为初始化是用的伪随机数。这个稍加复杂的程序可以被TensorBoard以图的形式展现出来:
tf.estimator
这是一个高级别的TensorFlow库,用来简化如下的机器学习技术:
-运行训练循环
-运行评估循环
-管理数据集
注意tf.estimator是回归程序变得如何简单:
# NumPy is often used to load, manipulate and preprocess data.
import numpy as np
import tensorflow as tf
# 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': 7.2587181e-10, 'average_loss': 1.8146795e-10, 'global_step': 1000}
eval metrics: {'loss': 0.010104778, 'average_loss': 0.0025261946, 'global_step': 1000}
评估数据集损失更高,但是仍然接近于0。
A custom model
假设我们要创建一个TensorFlow里没有的自定义模型。我们将演示如何使用底层API创建一个和LR等效的模型。
import numpy as np
import tensorflow as tf
# Declare list of features, we only have one real-valued feature
def model_fn(features, labels, mode):
# Build a linear model and predict values
W = tf.get_variable("W", [1], dtype=tf.float64)
b = tf.get_variable("b", [1], dtype=tf.float64)
y = W*features['x'] + b
# Loss sub-graph
loss = tf.reduce_sum(tf.square(y - labels))
# Training sub-graph
global_step = tf.train.get_global_step()
optimizer = tf.train.GradientDescentOptimizer(0.01)
train = tf.group(optimizer.minimize(loss),
tf.assign_add(global_step, 1))
# EstimatorSpec connects subgraphs we built to the
# appropriate functionality.
return tf.estimator.EstimatorSpec(
mode=mode,
predictions=y,
loss=loss,
train_op=train)
estimator = tf.estimator.Estimator(model_fn=model_fn)
# define our data sets
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)
# train
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.7678869e-11, 'global_step': 1000}
eval metrics: {'loss': 0.010100719, 'global_step': 1000}
MNIST(Mixed National Institute of Standard and Technology database)是一个非常简单的机器视觉数据集。
直接使用在线下载的命令失败:
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)
在http://yann.lecun.com/exdb/mnist/自行下载数据集后放在py文件的同一个目录以后成功:
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)
print(mnist.train.images.shape, mnist.train.labels.shape)
print(mnist.test.images.shape, mnist.test.labels.shape)
print(mnist.validation.images.shape, mnist.validation.labels.shape)
In [3]: runfile('D:/test/1/1.py', wdir='D:/test/1')
Extracting MNIST_data/train-images-idx3-ubyte.gz
Extracting MNIST_data/train-labels-idx1-ubyte.gz
Extracting MNIST_data/t10k-images-idx3-ubyte.gz
Extracting MNIST_data/t10k-labels-idx1-ubyte.gz
(55000, 784) (55000, 10)
(10000, 784) (10000, 10)
(5000, 784) (5000, 10)
可以看出训练集测试机和验证机分别有55000,10000,5000个样本。同时每一个样本都有对应的标签信息
10个种类是one-hot编码,Label是一个10维的向量,只有一个值维1,其余为0
这里使用一个叫做Softmax Regression的算法训练手写数字识别的分类模型。原理很简答,将可以判定为某类的特征加权相加。我们可以将这些特征写成如下公式:i代表第i类,j代表一张图片第j个像素。bi就是bias,顾名思义就是数据本身的倾向,比如大部分数字都是0,则0
的bias就会很大:
接下来计算softmax,简单说就是计算exp函数,然后标准化(让所有类别输出的概率值和为1):
其中判定为第i类的概率就可以:
如果将整个计算过程可视化:
接着,变成公式,最后将元素相乘变成矩阵乘法,结果如图所示:
接下来使用TensorFlow实现一个Soft Regression。首先载入TensorFlow库,并创建一个新的InteractiveSession,之后的运算默认跑在整个session里,不同的session之间的数据和运算都是相互独立的。None代表不限制条数的输入:
import tensorflow as tf
sess = tf.InteractiveSession()
x = tf.placeholder(tf.float32, [None, 784])
下面将weights和biases全部初始化为0:
W = tf.Variable(tf.zeros([784, 10]))
b = tf.Variable(tf.zeros([10]))
然后构建SR算法(y=softmax(Wx+b)):
y = tf.nn.softmax(tf.matmul(x, W) + b)
Softmax是tf.nn下面的一个函数,而tf.nn则包含了大量神经网络组件。tf.matmul是TensorFlow中的矩阵乘法函数。
这里使用cross-entropy作为loss function,定义如下:y是预测的概率分布,y'是真实的概率分布(label的one-shot编码),他通常可以用来判断模型对真实概率分布估计的准确程度:
在TensorFlow中定义如下:
y_ = tf.placeholder(tf.float32, [None, 10])
cross_entropy = tf.reduce_mean(-tf.reduce_sum(y_ * tf.log(y), reduction_indices=[1]))
tf.reduce_sum是求和,tf.reduce_mean则是用来每个batch数据结果求平均值
我们采用常见的随机梯度下降(SGD)。定义好算好以后,TensorFlow就可以根据我们定义的整个计算图自动求导,并根据反向传播算法进行训练,在每一轮迭代时更新参数来减小loss。我们直接调用tf.train.GradientDesentOptimizer,并设置学习速率为0.5,优化目标设定为cross-entropy,得到进行训练的操作train_step:
train_step = tf.train.GradientDescentOptimizer(0.5).minimize(cross_entropy)
下一步就是使用TensorFlow的全局参数初始化器并直接执行它的run方法:
tf.global_variables_initializer().run()
这里每一次都随机从训练集中抽取100条样本构成一个mini-batch,并feed给placeholder,然后调用train_step对这些样本进行训练:
for _ in range(1000):
batch_xs, batch_ys = mnist.train.next_batch(100)
sess.run(train_step, feed_dict={x: batch_xs, y_: batch_ys})
下面进行验证。tf.argmax是从tensor中寻找最大值的序号:
correct_prediction = tf.equal(tf.argmax(y,1), tf.argmax(y_,1))
然后用tf.cast将bool值全部换成float32,再求平均值:
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
打印准确率:
print(accuracy.eval({x: mnist.test.images, y_: mnist.test.labels}))
In [6]: runfile('D:/test/1/1.py', wdir='D:/test/1')
Extracting MNIST_data/train-images-idx3-ubyte.gz
Extracting MNIST_data/train-labels-idx1-ubyte.gz
Extracting MNIST_data/t10k-images-idx3-ubyte.gz
Extracting MNIST_data/t10k-labels-idx1-ubyte.gz
0.9174
通过上面简单的例子,我们使用TensorFlow实现了一个简单的机器学习算法Softmax Regression,这可以算做一个没有隐含层的最浅的神经网络,分为4个部分:
(1)定义算法公式,也就是神经网络forward时的计算;
(2)定义loss,选定优化器,并指定优化器优化loss;
(3)迭代地对数据进行训练;
(4)在测试集或者验证集对准确率进行评测