TensorFlow学习笔记(一)入门

一、 TensorFlow是什么?

是谷歌开源的机器学习实现框架,本文从Python语言来理解学习Tensorflow以及机器学习的知识。

TensorFlow的API主要分两个层次,核心层和基于核心层的高级API。核心层面向机器学习的研究人员,以及对模型控制精细的相关人员。高级API使用和学习相对容易,简化重复性任务,使不同的用户之间保持一致性。

高级API,如tf.contrib.learn可以帮助管理数据集data set,估计量estimators,训练training,推理inference

注意,一些高级API的方法名中包含contrib,意味着这些API依然处于开发过程中,这些方法在后续的TensorFlow版本中可能改变或者不再使用

这篇教程从核心层开始,后边会提到如何使用tf.contrib.learn实现模型。了解核心层,在使用高级API的时候知道程序是如何工作的。

1. 张量Tensors

数据的核心单元,一个tensor是一个包含任意维度的数组,张量的阶Tensor' rank是数组的维度,如下:

3 # 0阶张量,一个标量scalar with shape[]
[1. ,2., 3.] # 1阶张量; 一个向量vector with shape [3]
[[1., 2., 3.], [4., 5., 6.]] # 2阶 张量; 一个矩阵matrix with shape [2, 3]
[[[1., 2., 3.]], [[7., 8., 9.]]] # 3阶 张量tensor with shape [2, 1, 3]
2 是指[[1., 2., 3.]] 和 [[7., 8., 9.]]

1 是指[[1., 2., 3.]] 中有1个 [1., 2., 3.]

3 是指 [1., 2., 3.]中有3个:1., 2., 3.

二、 核心层TensorFlow Core学习

1. 引入TensorFlow

典型的引入语句:import tensorflow as tf

该语句是tensorflow的所有类,方法,符号的入口

2. 计算图Computational Graph

Tensorflow编程包含两个步骤:

1.构造计算图

2.运行计算图

计算图是什么?计算图是一系列的计算操作抽象为图中的节点。

构造一个简单的计算图:每个节点将0或多个tensor作为输入,输出一个tensor。一种类型的节点是常量节点constant,就如同tensorflow中的常数,它有0个输入,输出一个值。

构建两个浮点型tensor:node1和node2

node1 = tf.constant(3.0, 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运行时的状态和控制

接下来创建一个Session会话对象,调用run方法,运行计算图,去评估node1和node2

sess=tf.Session()
print(sess.run([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
Tensorflow提供了一个名为 TensorBoard的部分,可以以图片的方式展示计算图。


这个计算图不是特别有趣,因为它产生的是一个常量结果。

计算图可以使用占位符placeholder参数化的从外部输入数据,placeholder的作用是在稍后提供一个值

# 构造计算图
a=tf.placeholder(tf.float32)
b=tf.placeholder(tf.float32)
adder_node=a+b
#运行计算图
print("adder_node:",adder_node)
print(sess.run(adder_node,{a:3,b:4.5}))
print(sess.run(adder_node,{a:[1,3],b:[2,4]}))

输出结果:

adder_node: Tensor("add:0", dtype=float32)
7.5
[ 3.  7.]
我们可以添加一个操作,使计算图更加复杂:

add_and_triple=adder_node * 3
print("add_and_triple:",add_and_triple)
print("sess run result:",sess.run(add_and_triple,{a:3,b:4.5}))
输出结果:

add_and_triple: Tensor("mul:0", dtype=float32)
sess run result: 22.5

在机器学习中,需要模型可以任意输入,为了模型具有可训练能力,需要修正计算图,使对于同样的输入得到新的输出。变量Variable允许我们为计算图添加训练参数。

构造一个变量,需要提供类型和初始值:

W=tf.Variable([.3],tf.float32)
b=tf.Variable([-.3],tf.float32)
x=tf.placeholder(tf.float32)
linear_model=W*x+b
常量节点在调用tf.constant时就被初始化,而变量在调用tf.Variable时并不初始化,必须显性的执行如下操作:

init = tf.global_variables_initializer()
sess.run(init)
意识到init对象是Tensorflow子图初始化所有全局变量的句柄是重要的,在调用sess.run(init)方法之前,所有变量都是未初始化的。

因为x是一个占位符,我们可以指定几个值来评估linear_model模型(训练)

运行计算图:

print("linear_model:",linear_model)
print(sess.run(linear_model,{x:[1,2,3,4]}))
得到输出:

linear_model: Tensor("add_1:0", dtype=float32)
[ 0.          0.30000001  0.60000002  0.90000004]

我们创建了一个模型,但是不知道这个模型的效果怎么样,基于训练数据来评估模型,还需要一个placeholder y 来提供期望值,我们需要一个损失函数loss function

损失函数测量当前模型与真实数据之间的差距,对于线性模型,我们使用标准损失函数,求模型预测结果与实际数据之间差值的平方和sum the squares of the deltas

linear_model - y 构造了一个向量,对应每个元素的差值,我们调用 tf.square求平方,使用 tf.reduce_sum求和所有的平方差为一个标量scalar

y=tf.placeholder(tf.float32)
squared_deltas=tf.square(linear_model-y)
loss=tf.reduce_sum(squared_deltas)
print("loss:",loss)
print(sess.run(loss,{x:[1,2,3,4],y:[0,-1,-2,-3]}))
输出结果:

loss: Tensor("Sum:0", dtype=float32)
23.66
平方差为23.66

我们可以通过手动的方式将参数W和b置为W=-1,b=1,使模型最优,即损失函数最小。初始化后的变量可以通过tf.assign来更改,tf.assign后需要tf.run生效

fixW=tf.assign(W,[-1.])
fixb=tf.assign(b,[1.])
sess.run([fixW,fixb])
print("fix loss:",sess.run(loss,{x:[1,2,3,4],y:[0,-1,-2,-3]}))
输出结果:

fix loss: 0.0
我们猜想最优的W和b值,但是在机器学习中,就是自动的寻找这些最优的模型参数。下节介绍》》

三、 API  tf. train 

Tensorflow提供了优化器Optimizer慢慢改变每个变量来最小化损失函数。最简单的Optimizer是梯度下降gradient descent,它根据损失函数相对于该变量的导数大小来修改参数值,一般来讲,手动计算导数是乏味且易出错的,Tensorflow可以使用方法tf.gradients自动的为给定模型计算导数。优化器通常做这个工作。

optimizer=tf.train.GradientDescentOptimizer(0.01)
train=optimizer.minimize(loss)
print("train:\n",trian)
sess.run(init)#重置变量到初始化值
for i in range(1000):
    sess.run(train,{x:[1,2,3,4],y:[0,-1,-2,-3]})
print(sess.run([W,b]))
输出结果:

train:
 name: "GradientDescent"
op: "NoOp"
[array([-0.9999969], dtype=float32), array([ 0.99999082], dtype=float32)]
到此,我们实现了一次真实的机器学习,尽管我们只实现的是简单的线下回归,不需要多少Tensorflow core代码,然而复杂的模型和方法输入数据会需要更多的代码量,因此Tensorflow对于一般的模式、结构和功能提供了高级别的抽象。我们在下一章节学习。

完整的代码:

import tensorflow as tf
# NumPy is often used to load, manipulate and preprocess data.
import numpy as np
node1 = tf.constant(3.0,tf.float32)
node2 = tf.constant(4.0)
print(node1,node2)
sess=tf.Session()
print(sess.run([node1,node2]))
node3=tf.add(node1,node2)
print("node3:",node3)
print("sess.run(node3):",sess.run(node3))
# 构造计算图
a=tf.placeholder(tf.float32)
b=tf.placeholder(tf.float32)
adder_node=a+b
#运行计算图
print("adder_node:",adder_node)
print(sess.run(adder_node,{a:3,b:4.5}))
print(sess.run(adder_node,{a:[1,3],b:[2,4]}))
add_and_triple=adder_node * 3
print("add_and_triple:",add_and_triple)
print("sess run result:",sess.run(add_and_triple,{a:3,b:4.5}))

W=tf.Variable([.3],tf.float32)
b=tf.Variable([-.3],tf.float32)
x=tf.placeholder(tf.float32)
linear_model=W*x+b
init = tf.global_variables_initializer()
sess.run(init)
print("linear_model:",linear_model)
print(sess.run(linear_model,{x:[1,2,3,4]}))

y=tf.placeholder(tf.float32)
squared_deltas=tf.square(linear_model-y)
loss=tf.reduce_sum(squared_deltas)
print("loss:",loss)
print(sess.run(loss,{x:[1,2,3,4],y:[0,-1,-2,-3]}))

fixW=tf.assign(W,[-1.])
fixb=tf.assign(b,[1.])
sess.run([fixW,fixb])
print("fix loss:",sess.run(loss,{x:[1,2,3,4],y:[0,-1,-2,-3]}))

optimizer=tf.train.GradientDescentOptimizer(0.01)
train=optimizer.minimize(loss)
print("train:\n",train)
sess.run(init)#重置变量到初始化值
for i in range(1000):
    sess.run(train,{x:[1,2,3,4],y:[0,-1,-2,-3]})

curr_W, curr_b, curr_loss  = sess.run([W, b, loss],{x:[1,2,3,4],y:[0,-1,-2,-3]})
print("W: %s b: %s loss: %s"%(curr_W, curr_b, curr_loss))

四、 API tf. contrib. learn

tf.contrib.learn是Tensorflow高级别的库,简化机器学习:

1.运行训练循环

2.运行评估循环

3.管理数据集

4.管理feeding

tf.contrib.learn定义了许多常见的模型

1.基本使用

使用tf.contrib.learn简化线性回归:

numpy是开源的数值计算扩展,可以用来存储和处理大型矩阵。

声明特征列表list of features:我们在此使用一个real-valued列,另外还有其他复杂有用的列类型

import tensorflow as tf
import numpy as np

features=[tf.contrib.layers.real_valued_column("x",dimension=1)]
print("features:",features)
输出:

features: [_RealValuedColumn(column_name='x', dimension=1, default_value=None, dtype=tf.float32, normalizer=None)]
声明 估计器estimator,estimator负责调用训练和评估。它有很多预先定的类型,如 线性回归linear regression, 逻辑回归logistic regerssion, 线性分类linear classification, 逻辑分类logistic classification, 以及许多神经网络分类器,回归器neural network classifiers and regressors

这里做线性回归,指定特征列表:

estimator=tf.contrib.learn.LinearRegressor(feature_columns=features)
print("estimator:",estimator)
输出结果:

estimator: LinearRegressor(params={'head': <tensorflow.contrib.learn.python.learn.estimators.head._RegressionHead object at 0x7f6c88bcb208>, 'feature_columns': [_RealValuedColumn(column_name='x', dimension=1, default_value=None, dtype=tf.float32, normalizer=None)], 'optimizer': None, 'gradient_clip_norm': None, 'joint_weights': False})
Tensorflow提供了很多方法读取和设置数据集,在这里我们使用 numpy_input_fn,为该方法指定数据的 批次数目num_epochs(how many batches of data ),以及每批次的大小 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)
print("input_fn:",input_fn)
输出结果:

input_fn: <function numpy_input_fn.<locals>.input_fn at 0x7fb572e21e18>
我们可以调用 fit方法进行1000次训练步骤,并且传递训练数据集:

estimator.fit(input_fn=input_fn,steps=1000)
评价模型,在真实例子中,我们会将验证和测试数据分离,以免 过度拟合overftting
print(estimator.evaluate(input_fn=input_fn))
输出结果:

{'loss': 1.8005665e-07, 'global_step': 1000}
完整代码:

import tensorflow as tf
import numpy as np

features=[tf.contrib.layers.real_valued_column("x",dimension=1)]
print("features:",features)
estimator=tf.contrib.learn.LinearRegressor(feature_columns=features)
print("estimator:",estimator)
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)
print("input_fn:",input_fn)
estimator.fit(input_fn=input_fn,steps=1000)
print(">>>>>>>>>>")
res=estimator.evaluate(input_fn=input_fn)
print(res)

2. 定制化模型

tf.contrib.learn不限定用户使用预先定义的模型,假设我们创建一个Tensorflow中不存在的新模型,我们仍然可以保留tf.contrib.learn中的数据集、feeding、训练等

接下来,我们将实现类比于线性回归器LinearRegressor的自定义的线性回归模型。

使用tf.contrib.learn定制化模型,需要使用到类tf.contrib.learn.Estimator, 线性回归器tf.contrib.learn.LinearRegerssor就是tf.contrib.learn.Estimator的子类

通过为Estimator指定model_fn方法,控制模型如何评估,训练,损失等

import tensorflow as tf
import numpy as np
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))
    # ModelFnOps方法将我们构造的子图连接到相应的功能
    return tf.contrib.learn.ModelFnOps(
        mode=mode,predictions=y,loss=loss,train_op=train)

estimator=tf.contrib.learn.Estimator(model_fn=model)
# 构建数据集
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)
# 训练
estimator.fit(input_fn=input_fn,steps=1000)
# 评价模型
print(estimator.evaluate(input_fn=input_fn,steps=10))
说明,model方法中的内容与前边使用底层api的收到模型很相似。














猜你喜欢

转载自blog.csdn.net/WuyZhen_CSDN/article/details/64516733