标签: 王小草Tensorflow笔记
前期准备:安装好tensorflow1.0
Tensorflow提供了很多API。
最底层的API是Tensorflow core,推荐给机器学习的研究者或者那些想对模型有更好的掌控的大神们用~
较高层的API是在Tensorflow core的基础上封装建立的,肯定比Tensorflow core要更易学,更易使用啦~另外,较高层的API使得一些重复性的任务也更简单,并且在不同使用者中也更稳定。
比如高层API中有tf.contrib.learn, 可以帮助你管理数据集,估计值,训练过程与接口。注意如果较高层API的名称中包含了contrib,表示还在升级开发中,有可能在以后的tensorflow版本中,有些方法会变化或者废弃。
本文先会使用Tensorflow core,然后使用tf.contrib.learn去实现同一个模型。知道Tensorflow core的规则,将对你在使用更高级API时理解模型内部的运行有很大的帮助~
在tensorflow中最核心的数据单元是tensor.一个tensor包含一系列原始值,这些值被放在Array中,可以是任何维度的。
tensor的Rank指的就是维度的数量。举几个例子:
3 # a rank 0 tensor, 这是一个shape[] 的标量
[1., 2., 3.] # a rank 1 tensor,表示有1层维度,是一个shape[3]的向量
[[1., 2., 3.],[1., 2., 3.]] # a rank 2 tensor, 表示2层维度, 是一个shap[2,3]的矩阵
[[[1., 2., 3.]],[[1., 2., 3.]]] # a rank 3 tensor, 表示有3层维度, shape[2,1,3]
首先的首先,肯定要先导入tensorflow包,import tensorflow之后就给了Python 访问所有tensorflow 类,方法,符号的渠道了。
import tensorflow as tf
Tensorflow Core 程序主要包含独立的两个部分:
1. Building the computationnal graph 搭建计算图
2. Running the computationnal graph 运行计算图
computationnal graph 计算图 指的是将一些列tensorflow的操作作为graph的节点node,依照一定的先后步骤会形成一个计算图。
每一个节点将会以tensor作为输入, 然后产生一个新的tensor作为输出(在节点里做了一些运算)。节点的其中一个类型是常数constant,它没有输入,并且输出的就只是它存储的那个常数。
下面,我们来建立两个浮点类型的常数tensor:node1, node2。 在node1中,括号中第一个参数是常数值,第二个参数是常数的类型,如果不设置,默认也是float32(如Node2).
node1 = tf.constant(3.0, tf.float32)
node2 = tf.constant(4.0)
print(node1, node2)
打印结果:
(, )
上面给出了打印的结果,值得注意的是,打印的信息中并没有直接给出tensor中常数的值(3.0,4.0),只有shape, dtype等关于这个tensor的一些信息。因为此时我们只是构建了有两个节点的图,必须要在一个会话session中运行这个图,才会真正打印数值。
所以在运行图之前,需要建立一个Session对象,然后再引用它的.run方法去运行计算图,并且估计node1, node2。如下:
sess = tf.Session()
print(sess.run([node1, node2]))
打印结果:
[3.0, 4.0]
当然啦,我们可以通过组合tensor的操作节点去构建更复杂的计算图。如下,两个常数Node求和然后产生一个新的图:
node3 = tf.add(node1, node2)
print("node3:", node3)
print("sess.run(node3):", sess.run(node3))
打印结果:
('node3:', )
('sess.run(node3):', 7.0)
Tensorflow 还提供了一个功能叫TensorBoard, 可以可视化地展现计算图。
上面这个案例,图的数据输入是内部定义的常数,那么Tensorflow中的图还可以接受外部数据的输入。
如下案例,也就是说,先给要输出的数据占好一个位置,等到真的运行图的时候,再把外部的数据传进这个位置。使用的是.placeholder()函数,括号内传入要站位的数据的类型。
a = tf.placeholder(tf.float32)
b = tf.placeholder(tf.float32)
add_node = a + b # 等同于tf.add(a, b)
//当真正运行的时候才传入指定的数据进行计算
print(sess.run(add_node, {a:3, b:4}))
print(sess.run(add_node, {a:[1,3], b:[2,4]}))
打印结果:
7.0
[ 3. 7.]
可以使上面的计算图更复杂一点,比如:
add_and_triple = add_node * 3
print(sess.run(add_and_triple, {a:3, b:4.5})) # (3+4.5)*3
打印结果:
22.5
上面介绍了常数节点,以及外部变量的占位符,还有一个很重要的概念那就是“变量”Variable。
比如在训练模型的时候,待估计的参数是在每次迭代之后都会改变的,直到获得一个最优的参数。那么这个会变化的参数肯定不能放在常数节点中,也肯定不是外部输入的给定数值,而是应该安放在一个可变的位置上,那就是Variable。
// 创建线性回归的两个权重变量
w = tf.Variable([.3], tf.float32)
b = tf.Variable([-.3], tf.float32)
// 为自变量x创建占位符
x = tf.placeholder(tf.float32)
//建立一元线性模型
linear_model = w * x + b
当使用tf.constant()创建常数节点的时候,这个常数就已经被初始化了,并且再也不会变化了。然而,tf.Variable()并不会去初始化变量,要初始化变量,必须调用特定的操作,如下:
init = tf.global_variables_initializer()
sess.run(init)
因为x是一个Placeholder,在运行linear_model的时候要输入数据:
print(sess.run(linear_model, {x: [1,2,3,4]}))
[ 0. 0.30000001 0.60000002 0.90000004]
上面我们已经常见了一个一元线性模型,并且给定了初始的参数w,b值,然后输出了一组模型的预测值。但是我们怎么知道参数这样设的时候模型的好坏呢?此时,就需要知道一组真实的y值,来和预测的y值作比较从而建立损失函数。这组y值一般都是外部进来的数据,所以也需要placehoder。
损失函数是真实值与预测值之间的差距,这里我们用一个标准的损失函数来评估线性模型:平方差和
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=-1, b=1.
要变换Variable的值,直接调用tf.assign即可
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
上面我们手动调整了参数使得模型的误差降低到了0.在真实的建模中,我们需要让模型不断地去优化寻找最优的参数,从而使得损失最小。具体的过程在接下来的文档中会介绍。
比如Tensorflow中提供了一些优化器,通过损失最小化的目标来改变变量。最简单的优化器是梯度下降法,使用如下:
optimizer = tf.train.GradientDescentOptimizer(0.01) ## 括号内的是学习率
train = optimizer.minimize(loss)
sess.run(init) # 初始化变量
for i in range(1000): # 迭代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)]
以上是在学习率为0.01梯度下降法下训练了1000次的参数,可见几乎等于了我们之前设置的最优的参数了。
所谓更高层的API是说,在底层API的基础上,对一些复杂的运算进行了封装,然后提供一个接口,用户只需要用简单的代码直接调用这个接口,就能实现某种功能,而不再需要自己手动去一行一行写大批代码了。
tf.contrib.learn是一个更高级的Tensorflow库,使得机器学习的机制更简化,具体包括:
1.运行训练
2.运行评估
3.管理数据集
3.管理feeding
接下去的案例,仍然是沿用了上面那个一元线性模型。
import tensorflow as tf
import numpy as np
features = [tf.contrib.layers.real_valued_column("x", dimension=1)]
estimator = tf.contrib.learn.LinearRegressor(feature_columns=features)
WARNING:tensorflow:Using temporary folder as model directory: /tmp/tmpWXFmOU
INFO:tensorflow:Using default config.
INFO:tensorflow:Using config: {'_save_checkpoints_secs': 600, '_num_ps_replicas': 0, '_keep_checkpoint_max': 5, '_tf_random_seed': None, '_task_type': None, '_environment': 'local', '_is_chief': True, '_cluster_spec': , '_tf_config': gpu_options {
per_process_gpu_memory_fraction: 1.0
}
, '_task_id': 0, '_save_summary_steps': 100, '_save_checkpoints_steps': None, '_evaluation_master': '', '_keep_checkpoint_every_n_hours': 10000, '_master': ''}
Tensorflow 提供了很多方法来读取与设置数据集。这里使用numpy_input_fn,括号中必须告诉这个函数,要多少批数据(num_epochs), 以及每批数据的大小(batch_size)
x = np.array([1., 2., 3., 4.])
y = np.array([0.,-1.,-2.,-3.])
input_fn = tf.contrib.learn.io.numpy_input_fn({"x": x}, y, batch_size=4, num_epochs=1000)
对estimator调用fit()方法,然后传入训练的数据集,以及迭代的次数
estimator.fit(input_fn=input_fn, steps=1000)
WARNING:tensorflow:Rank of input Tensor (1) should be the same as output_rank (2) for column. Will attempt to expand dims. It is highly recommended that you resize your input, as this behavior may change.
WARNING:tensorflow:From /home/cc/anaconda2/lib/python2.7/site-packages/tensorflow/contrib/learn/python/learn/estimators/head.py:1362: scalar_summary (from tensorflow.python.ops.logging_ops) is deprecated and will be removed after 2016-11-30.
Instructions for updating:
Please switch to tf.summary.scalar. Note that tf.summary.scalar uses the node name instead of the tag. This means that TensorFlow will automatically de-duplicate summary names based on the scope they are created in. Also, passing a tensor or list of tags to a scalar summary op is no longer supported.
INFO:tensorflow:Create CheckpointSaverHook.
INFO:tensorflow:Saving checkpoints for 1 into /tmp/tmpWXFmOU/model.ckpt.
INFO:tensorflow:loss = 0.25, step = 1
INFO:tensorflow:global_step/sec: 1047.86
INFO:tensorflow:loss = 0.0138355, step = 101
INFO:tensorflow:global_step/sec: 1133.64
INFO:tensorflow:loss = 0.00550354, step = 201
INFO:tensorflow:global_step/sec: 1084.43
INFO:tensorflow:loss = 0.00076083, step = 301
INFO:tensorflow:global_step/sec: 669.811
INFO:tensorflow:loss = 0.00012992, step = 401
INFO:tensorflow:global_step/sec: 701.612
INFO:tensorflow:loss = 8.28051e-06, step = 501
INFO:tensorflow:global_step/sec: 1059.03
INFO:tensorflow:loss = 3.82051e-06, step = 601
INFO:tensorflow:global_step/sec: 1149.84
INFO:tensorflow:loss = 2.79643e-07, step = 701
INFO:tensorflow:global_step/sec: 1306.38
INFO:tensorflow:loss = 6.61448e-08, step = 801
INFO:tensorflow:global_step/sec: 1524
INFO:tensorflow:loss = 9.12863e-10, step = 901
INFO:tensorflow:Saving checkpoints for 1000 into /tmp/tmpWXFmOU/model.ckpt.
INFO:tensorflow:Loss for final step: 1.59366e-09.
LinearRegressor(params={'gradient_clip_norm': None, 'head': , 'joint_weights': False, 'optimizer': None, 'feature_columns': [_RealValuedColumn(column_name='x', dimension=1, default_value=None, dtype=tf.float32, normalizer=None)]})
这里直接使用训练数据来评估。在实际应用中,应使用测试机或验证集来评估模型避免过拟合。
运行以下代码,可以根据输出的损失loss来评估模型的拟合程度。
estimator.evaluate(input_fn=input_fn)
WARNING:tensorflow:Rank of input Tensor (1) should be the same as output_rank (2) for column. Will attempt to expand dims. It is highly recommended that you resize your input, as this behavior may change.
WARNING:tensorflow:From /home/cc/anaconda2/lib/python2.7/site-packages/tensorflow/contrib/learn/python/learn/estimators/head.py:1362: scalar_summary (from tensorflow.python.ops.logging_ops) is deprecated and will be removed after 2016-11-30.
Instructions for updating:
Please switch to tf.summary.scalar. Note that tf.summary.scalar uses the node name instead of the tag. This means that TensorFlow will automatically de-duplicate summary names based on the scope they are created in. Also, passing a tensor or list of tags to a scalar summary op is no longer supported.
INFO:tensorflow:Starting evaluation at 2017-02-21-05:41:13
INFO:tensorflow:Finished evaluation at 2017-02-21-05:41:13
INFO:tensorflow:Saving dict for global step 1000: global_step = 1000, loss = 1.03366e-09
WARNING:tensorflow:Skipping summary for global_step, must be a float or np.float32.
{'global_step': 1000, 'loss': 1.0336563e-09}
tf.contrib.learn不会限制你只使用它预先定义的模型。假设我们想要创建一个用户自定义的模型,这个模型不是在Tensorflow上建立的,我们仍然可以以保持对tf.contrib.learn中的数据集,feeding, training的高层次的抽象。
也是说,上面一节我们直接调用了tf.contrib.learn.LinearRegressor(feature_columns=features),来建立了一个线性回归模型。实际中也许我们并不想完全和它一样,而是想自己自定义一个模型,自定义损失函数与优化器,那么我们可以自己写一个方法,来新建立一个模型。再把这个模型作为参数传入tf.contrib.learn.Estimator()中,从而创建一个基于tensorflow的学习器,故之后的训练和评估都可以按照原来的方式完成。
# 导入需要的包
import tensorflow as tf
import numpy as np
# 1.自定义一个模型
def model(features, labels, mode):
# 设置初始参数
w = tf.get_variable("W", [1], dtype=tf.float64)
b = tf.get_variable("b", [1], dtype=tf.float64)
# 建立线性模型做预测
y = w * features['x'] + b
# 建立损失函数
loss = tf.reduce_sum(tf.square(y-labels))
# 建立优化器
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))
# 返回模型
return tf.contrib.learn.ModelFnOps(mode=mode, predictions=y, loss=loss, train_op=train)
# 2.将自定义模型传入(也就是将子图并入母图中),创建学习器
estimator = tf.contrib.learn.Estimator(model_fn=model)
# 3.设置数据集
x = np.array([1., 2., 3., 4.])
y = np.array([0., -1., -2., -3.])
input_fn = tf.contrib.learn.io.numpy_input_fn({"x": x}, y, 4, num_epochs=1000)
# 4.训练
estimator.fit(input_fn=input_fn, steps=1000)
# 5.评估
print(estimator.evaluate(input_fn=input_fn, steps=10))
WARNING:tensorflow:Using temporary folder as model directory: /tmp/tmpt4EDBt
INFO:tensorflow:Using default config.
INFO:tensorflow:Using config: {'_save_checkpoints_secs': 600, '_num_ps_replicas': 0, '_keep_checkpoint_max': 5, '_tf_random_seed': None, '_task_type': None, '_environment': 'local', '_is_chief': True, '_cluster_spec': , '_tf_config': gpu_options {
per_process_gpu_memory_fraction: 1.0
}
, '_task_id': 0, '_save_summary_steps': 100, '_save_checkpoints_steps': None, '_evaluation_master': '', '_keep_checkpoint_every_n_hours': 10000, '_master': ''}
INFO:tensorflow:Create CheckpointSaverHook.
INFO:tensorflow:Saving checkpoints for 1 into /tmp/tmpt4EDBt/model.ckpt.
INFO:tensorflow:loss = 21.1942814458, step = 1
INFO:tensorflow:global_step/sec: 1082.75
INFO:tensorflow:loss = 0.00423662835422, step = 101
INFO:tensorflow:global_step/sec: 944.412
INFO:tensorflow:loss = 0.00037196827709, step = 201
INFO:tensorflow:global_step/sec: 1102.33
INFO:tensorflow:loss = 3.34862933921e-05, step = 301
INFO:tensorflow:global_step/sec: 1023.64
INFO:tensorflow:loss = 2.09601726413e-06, step = 401
INFO:tensorflow:global_step/sec: 1078.82
INFO:tensorflow:loss = 2.80960418271e-07, step = 501
INFO:tensorflow:global_step/sec: 1149.9
INFO:tensorflow:loss = 1.67142378119e-08, step = 601
INFO:tensorflow:global_step/sec: 752.974
INFO:tensorflow:loss = 2.3071782231e-09, step = 701
INFO:tensorflow:global_step/sec: 924.684
INFO:tensorflow:loss = 2.25977016517e-10, step = 801
INFO:tensorflow:global_step/sec: 1160.17
INFO:tensorflow:loss = 3.5153672322e-11, step = 901
INFO:tensorflow:Saving checkpoints for 1000 into /tmp/tmpt4EDBt/model.ckpt.
INFO:tensorflow:Loss for final step: 1.82005204298e-12.
INFO:tensorflow:Starting evaluation at 2017-02-21-06:05:52
INFO:tensorflow:Evaluation [1/10]
INFO:tensorflow:Evaluation [2/10]
INFO:tensorflow:Evaluation [3/10]
INFO:tensorflow:Evaluation [4/10]
INFO:tensorflow:Evaluation [5/10]
INFO:tensorflow:Evaluation [6/10]
INFO:tensorflow:Evaluation [7/10]
INFO:tensorflow:Evaluation [8/10]
INFO:tensorflow:Evaluation [9/10]
INFO:tensorflow:Evaluation [10/10]
INFO:tensorflow:Finished evaluation at 2017-02-21-06:05:52
INFO:tensorflow:Saving dict for global step 1000: global_step = 1000, loss = 1.58927e-12
WARNING:tensorflow:Skipping summary for global_step, must be a float or np.float32.
{'loss': 1.5892712e-12, 'global_step': 1000}