TensorFlow使用数据流图(计算图)来规划计算流程,可以将计算映射到不同的硬件和操作平台。凭借着统一的架构,TensorFlow可以方便的部署到各种平台,大大简化了真实场景中应用机器学习算法的难度。
使用TensorFlow,我们不需要大规模的模型训练和小规模的应用部署开发两套系统,节约时间,TensorFlow给巡逻和预测的共同部分提供一个恰当的抽象。
对于大规模的神经网络训练,TensorFlow可以让用户轻松实现并行计算,同时使用不同的硬件资源进行训练,同步或异步的更新全局共享的模型参数和状态。把一个串行的TensorFlow算法改造成并行的成本也很低。
虽然绝大多数的TensorFlow应用都是机器学习以及深度学校领域,但是TensorFlow抽象出的计算图模型也可以应用在通用数值计算和符号计算上。
tnsorflow分为构建模型和训练两部分,构建模型通常会用到Tensor,variable,placeholder,而训练阶段会用到Session!
Session是一个类,作用是把graph ops部署到Devices(CPUs/GPUs),并提供具体执行这些op的方法。
为什么要这么设计呢?考虑到Python运行性能较低,我们在执行numerical computing的时候,都会尽量使用非python语言编写的代码,比如使用NumPy这种预编译好的C代码来做矩阵运算。在Python内部计算环境和外部计算环境(如NumPy)切换需要花费的时间称为overhead cost。对于一个简单运算,比如矩阵运算,从Python环境切换到Numpy,Numpy运算得到结果,再从Numpy切回Python,这个成本,比纯粹在Python内部做同类运算的成本要低很多。但是,一个复杂数值运算由多个基本运算组合而成,如果每个基本运算来一次这种环境切换,overhead cost就不可忽视了。为了减少来回的环境切换,TensorFlow的做法是,先在Python内定义好整个Graph,然后在Python外运行整个完整的Graph。因此TensorFlow的代码结构也就对应为两个阶段了。
构建模型阶段,构建一个图(graph)来描述我们的模型(数据输入->中间处理->输出),此时不会发生实际运算,而在模型构建完毕之后,会进入训练步骤,此时才会有实际的数据输入以及梯度计算等操作。
下面先一个实例来说明一下
import tesorflow as tf
import numpy as np
# create data
x_data = np.random.rand(100).astype(np.float32) # 随机生成100个数据
y_data = x_data*0.1 + 0.3
# create tensorflow struct start
Weights = tf.Variable(tf.random_uniform([1], -1.0, 1.0)) #生成一维向量
biases = tf.Variable(tf.zeros([1]))
y = Weights*x_data + biases
#计算损失函数
loss = tf.reduce_mean(tf.square(y - y_data))
optimizer = tf.train.GradientDescentOptimizer(0.5)
train = optimizer.minimize(loss)
init = tf.global_variables_initializer()
# create tensorflow struct end
with tf.Session() as sess:
sess.run(init)
for step in range(201):
sess.run(train)
if step % 20 == 0:
print(step, sess.run(Weights), sess.run(biases))
Build Graph
tf.Variable是TensorFlow的一个类,是取值可变的Tensor
,构造函数的第一个参数是初始值initial_value
。
tf.zeros(shape, dtype=tf.float32, name=None)
是一个op,用于生成取值全是0的Constant Value Tensor
。
tf.random_uniform(shape, minval=0, maxval=None, dtype=tf.float32, seed=None, name=None)
是一个op,用于生成服从uniform distribution的Random Tensor
。
y = Weights*x_data + biases
y是线性回归运算产生的Tensor。运算符*
和+
,等价为tf.multiple()
和tf.add()
这两个TensorFlow提供的数学类ops。tf.multiple()
的输入是W和x_data;Weights是Variable,属于Tensor,可以直接作为op的输入;x_data是numpy的多维数组ndarray
,TensorFlow的ops接收到ndarray的输入时,会将其转化为tensor。tf.multiple()
的输出是一个tensor,和biases一起交给optf.add()
,得到输出结果y。
至此,线性回归的模型已经建立好,但这只是Graph的一部分,还需要定义损失。
loss = tf.reduce_mean(tf.square(y - y_data))
loss是最小二乘法需要的目标函数,是一个Tensor,具体的op不再赘述。
optimizer = tf.train.GradientDescentOptimizer(0.5)
train = optimizer.minimize(loss)
这一步指定求解器,并设定求解器的最小化目标为损失。train代表了求解器执行一次的输出Tensor。这里我们使用了梯度下降求解器,每一步会对输入loss求一次梯度,然后将loss里Variable
类型的Tensor按照梯度更新取值。
init = tf.global_variables_initializer()
Build Graph阶段的代码,只是在Python内定义了Graph的结构,并不会真正执行。在Launch Graph阶段,所有的变量要先进行初始化。每个变量可以单独初始化,但这样做有些繁琐,所以TensorFlow提供了一个方便的函数global_variables_initializer()
可以在graph中添加一个初始化所有变量的op。
Launch Graph
sess.run(init)
在进行任何计算以前,先给Variable赋初始值。
for step in range(201):
sess.run(train)
train操作对应梯度下降法的一步迭代。当step为0时,train里的variable取值为初始值,根据初始值可以计算出梯度,然后将初始值根据梯度更新为更好的取值;当step为1时,train里的variable为上一步更新的值,根据这一步的值可以计算出一个新的梯度,然后将variable的取值更新为更好的取值;以此类推,直到达到最大迭代次数。
print(step, sess.run(W), sess.run(b))
如果我们将sess.run()
赋值给Python环境的变量,或者传给Python环境的print
,可以fetch执行op的输出Tensor取值,这些取值会转化为numpy的ndarray结构。因此,这就需要一次环境的切换,会增加overhead cost。所以我们一般会每隔一定步骤才fetch一下计算结果,以减少时间开销。
控件Session:抽象模型的实现者
import tensorflow as tf
matrix1 = tf.constant([3, 3]) # 一行两列的矩阵
matrix2 = tf.constant([[2],
[2]]) # 两行一列的矩阵
# method1
sess = tf.Session()
# 两个矩阵相乘
result1 = tf.matmul(matrix1, matrix2)
print(sess.run(result1))
sess.close()
# method2
with tf.Session() as sess:
result2 = tf.matmul(matrix1, matrix2)
print(sess.run(result2))
session会话,抽象模型的实现者,代码多处会用到它,原因在于,模型是抽象的,只有实现了模型之后,才能够得到具体的值。同样的参数训练、预测,甚至变量的实际查询,都需要用到session。
关于tensor
一些常用的函数。矩阵
tf.zeros tf.ones等等,这里就不一一多讲了,在接下来的代码会不断接触。
Variable变量
import tensorflow as tf
state = tf.Variable(0, name=' counter') # 计算器
one = tf.constant(1) # 常数为1
# 执行new_value = state + one
new_value = tf.add(state, one)
# 将new_value赋值给state
updata = tf.assign(state, new_value)
# 初始化所有变量
init = tf.global_variables_initializer()
with tf.Session() as sess:
sess.run(init)
# 循环3次
for i in range(3):
sess.run(updata)
# sess指针需要在state上run一下才可以得到结果
print(sess.run(state))
只要定义了Variable就一定会要用到tf.global_variables_initializer()来初始化所有的变量,即tf.Variable()与tf.global_varilables_initializer()组合使用的。
Variable需要在session之前初始化才可以在session中被使用。
变量一般是用来计算图中的需要计算的各个参数的,包含矩阵以及向量等。它是可以被读取和修改的,模型参数一般用Variable来表示。
传入值placeholder
import tensorflow as tf
input1 = tf.placeholder(tf.float32)
input2 = tf.placeholder(tf.float32)
# 两个数相乘
output = tf.mul(input1, input2)
with tf.Session() as sess:
print(sess.run(output, feed_dict={input1:[7.], input2:[2.]}))
只要用到tf.placeholder就会用到feed_dict字典,它们是绑定的,组合使用的。
添加层def
import tensoflow as tf
def add_layer(inputs, in_size, out_size, activetion_funtion=None):
Weights = tf.Variable(tf.random_normal([in_size, out_size])) #矩阵一般习惯首字母大写
biases = tf.Variable(tf.zeros([1, out_size]) + 0.1)
Wx_plus_b = tf.matmul(inputs, Weights) + biases
if activetion_funtion is None:
outputs = Wx_plus_b
else:
outputs = activetion_funtion(Wx_plus_b)
return outputs
矩阵首字母大写,并非有这样的规定,只为了便于自己知晓。
推荐biases不为0。初始化值不为0比较好,所以选择随机。
activation_function=None代表线性函数
下面介绍一些常用的函数:
1,tf.random_uniform()函数
格式:tf.random_uniform((4, 4), minval=low,maxval=high,dtype=tf.float32)))
功能:返回4*4的矩阵,产生于low和high之间,产生的值是均匀分布的。
示例:
import tensorflow as tf
import numpy as np
with tf.Session() as sess:
print(sess.run(tf.random_uniform(
(4, 4), minval=-0.5,
maxval=0.5,dtype=tf.float32)))
输出结果:
[[ 0.23706067 0.42579055 0.16444612 0.12134457]
[ 0.14245582 0.32224071 -0.3107301 0.29911542]
[-0.03472292 -0.37411058 -0.22680879 0.21656895]
[-0.37798405 0.31725729 -0.17690742 -0.02995324]]
import tensorflow as tf
import numpy as np
A = [[1,3,4,5,6]]
B = [[1,3,4,3,2]]
with tf.Session() as sess:
print(sess.run(tf.equal(A, B)))
[[ True True True False False]]
import tensorflow as tf
import numpy as np
A = [[1,3,4,5,6]]
B = [[1,3,4], [2,4,1]]
with tf.Session() as sess:
print(sess.run(tf.argmax(A, 1)))
print(sess.run(tf.argmax(B, 1)))
输出:
[4]
[2 1]