本文共 4946 字,大约阅读时间需要 16 分钟。
最近学习机器学习相关的东西,理论看了一部分后,想跑几个TensorFlow的小例子,在实践中体会一下,发下总是不能够很好的理解TensorFlow的代码。然后各种查资料,看了下TensorFlow的入门知识,才了解到TensorFlow的编程范式是一种典型的基于符号的编程范式,计算过程是延迟计算,典型的惰性求值。
Tensor是张量,Flow流动。从功能上看,tensor 张量可以简单理解为多维数据。零阶张量表示标量(scalar),即一个数;一阶张量可以理解为向量(vector),也就是一维数组;n阶张量可以理解为多维数组。Tensor 在 TensorFlow 中并不直接计算,保存的计算过程,可以理解为符号编程延迟计算。
Tensor类型的三个重要属性:名字(name)、维度(shape)和类型(dtype):
通过 python 的 list 看 tensor,左边多少中括号,就是几维向量,如:
1 #维度为0, 标量[1,2,3] #维度为1, 一维向量[[1,2],[3,4]] #维度为2, 二维矩阵[[[1,2],[3,4]],[[1,2],[3,4]]] #维度为3, 三维空间矩阵
张量的形状以[D0, D1, … Dn-1]的形式表示,D0 到 Dn 是任意的正整数。如形状[3,4]表示第一维有3个元素,第二维有4个元素。举例:
import tensorflow as tfa = tf.constant([[[1, 2], [3, 4]], [[1, 2], [3, 4]]])print(a.shape) # (2, 2, 2)print(a.name) # Const:0print(a.dtype) #
在TensorFlow程序中,会将定义的计算转化为计算图上的节点。一般系统会自动维护一个默认计算图。计算图是一个有向无环图,可以通过 tf.get_default_graph
函数获取。除了默认的计算图,TensorFlow支持通过 tf.Graph
函数来生成新的计算图。计算图主要作用有:
计算图可通过tf.Graph.device
函数制定运行计算的设备,比如GPU。最后,还可以使用 TensorBoard 读取日志文件,可视化查看计算图。
tf.Variable:主要在于一些可训练变量(trainable variables),比如模型的权重(weights,W)或者偏执值(bias),声明时,必须提供初始值;
tf.placeholder:用于得到传递进来的真实的训练样本,不必指定初始值,可在运行时,通过 Session.run 的函数的 feed_dict 参数指定;
以前看Lisp的时候,接触过惰性求值
这个概念,当时自己还记了篇笔记:。惰性求值(Lazy Evaluation),说白了就是某些中间结果不需要被求出来,求出来反而不利于后面的计算也浪费了时间。惰性求值是一个计算机编程中的一个概念,它的目的是要最小化计算机要做的工作。惰性计算的最重要的好处是它可以构造一个无限的数据类型。使用惰性求值的时候,表达式不在它被绑定到变量之后就立即求值,而是在该值被取用的时候求值。语句如 x:=expression; (把一个表达式的结果赋值给一个变量)明显的调用这个表达式并把计算并把结果放置到 x 中,但是先不管实际在 x 中的是什么,直到通过后面的表达式中到 x 的引用而有了对它的值的需求的时候,而后面表达式自身的求值也可以被延迟,最终为了生成让外界看到的某个符号而计算这个快速增长的依赖树。
Tensorflow两个的重要概念就是 Graph 和 Session,Graph定义计算,Session执行计算。TensorFlow计算的单位是OP(operation),它表示了某种抽象计算。OP的输入/输出以 Tensor 的形式存在,在系统初始化时,系统实现对所有OP进行扫描注册。
比如定义一个运算:f(x)= 3*x^2 + 2*x + 1
, 使用TensorFlow编程,就是先定义出这个计算式子,然后计算,如下:
import tensorflow as tf# 定义计算x = tf.placeholder("float")cal = 3 * x * x + 2 * x + 1 # 重载了运算符print(type(cal)) # cal 是 Tensor 的一个实例# 执行计算init = tf.global_variables_initializer()with tf.Session() as sess: sess.run(init) print(sess.run(cal, {x: 2}))# 写log, 用TensorBoard查看计算图writer = tf.summary.FileWriter("test_log", tf.get_default_graph())writer.close()# 运行TensorBoard,并将日志的地址指向上面程序输出的地址# tensorboard --logdir=./test_log# 然后 localhost 访问即可
为什么定义的计算需要在 session 里 run?这是TensorFlow的体系结构决定的。TensorFlow 的系统结构以 C API 为界,将整个系统分为前端和后端两个子系统。前端系统扮演了 Client 的角色,完成计算图的构造,通过转发 Protobuf 格式的 GraphDef 给后端系统的 Master,并启动计算图的执行过程。Tensorflow 前端支持 C++,Python,Go,Java,后端使用 C++,CUDA。
有了上面的概念,基本就可以看懂这个经典的线性回归的例子了。配合matplot做的图,可以很方便查看最后的结果,代码:
# python 3.6, TensorFlow 1.9.0import tensorflow as tfimport numpyimport matplotlib.pyplot as pltrng = numpy.random# Parameterslearning_rate = 0.01training_epochs = 2000display_step = 50# Training Datatrain_X = numpy.asarray( [3.3, 4.4, 5.5, 6.71, 6.93, 4.168, 9.779, 6.182, 7.59, 2.167, 7.042, 10.791, 5.313, 7.997, 5.654, 9.27, 3.1])train_Y = numpy.asarray( [1.7, 2.76, 2.09, 3.19, 1.694, 1.573, 3.366, 2.596, 2.53, 1.221, 2.827, 3.465, 1.65, 2.904, 2.42, 2.94, 1.3])n_samples = train_X.shape[0]# tf Graph InputX = tf.placeholder("float")Y = tf.placeholder("float")# Create Model# Set model weightsW = tf.Variable(rng.randn(), name="weight")b = tf.Variable(rng.randn(), name="bias")# Construct a linear model,define calculate graphactivation = tf.add(tf.multiply(X, W), b)# Minimize the squared errorscost = tf.reduce_sum(tf.pow(activation - Y, 2)) / (2 * n_samples) # L2 lossoptimizer = tf.train.GradientDescentOptimizer(learning_rate).minimize(cost)# Initializing the variablesinit = tf.global_variables_initializer()# Launch the graphwith tf.Session() as sess: sess.run(init) # Fit all training data for epoch in range(training_epochs): for (x, y) in zip(train_X, train_Y): sess.run(optimizer, feed_dict={X: x, Y: y}) # Display logs per epoch step if epoch % display_step == 0: print("Epoch:", '%04d' % (epoch + 1), "cost=", "{:.9f}".format(sess.run(cost, feed_dict={X: train_X, Y: train_Y})), "W=", sess.run(W), "b=", sess.run(b)) print("Optimization Finished!") print("cost=", sess.run(cost, feed_dict={X: train_X, Y: train_Y}), "W=", sess.run(W), "b=", sess.run(b)) # Graphic display plt.plot(train_X, train_Y, 'ro', label='Original data') plt.plot(train_X, sess.run(W) * train_X + sess.run(b), label='Fitted line') plt.legend() plt.show()
上面例子中,还有一个 epoch 概念:
举个例子,训练集有1000个样本,batchsize=10,那么:训练完整个样本集需要:100次iteration,1次epoch。