在上一篇中,我简单介绍了一下Tensorflow
以及在本机及阿里云的PAI
平台上跑通第一个示例的步骤。在本篇中我将稍微讲解一下几个基本概念以及Tensorflow
的基础语法。node
本文代码都是基于API版本r1.4
。本文中本地开发环境为Pycharm
,在文中再也不赘述。python
和不少开发语言设计同样,Tensorflow
提供了多个级别的客户端API,其中最底层叫Tensorflow Core
,使用这一层API能够彻底控制Tensorflow
,可是使用难度上也相对较大。在Tensorflow Core
之上建立的更高级别的API,对开发者更友好,更易于使用、学习起来也更简单。web
Tensorflow
中该数据的核心单位是张量(Tensor)
,张量
就是将一组基础数值,组织成形态(Shape)
为一个任意维度的数组,张量
的阶(Rank)
就是维度的数量。概念仍是挺拗口的,举个例子就很是明了了:算法
[1., 2., 3.] # Rank=1, Shape=[3] [[1., 2., 3.], [4., 5., 6.]] # Rank=2; Shape=[2, 3]: 表明第一层数组里包含2个子数组,每一个子数组里包含3个值 [[[1., 2., 3.]], [[7., 8., 9.]]] # Rank=3; Shape=[2, 1, 3] : 表明第一层数组里包含2个数组,每一个子数组里又包含1个子数组,子数组里包含3个元素
Tensorflow
其实就是针对张量
的计算图,计算图中的每一个节点(Node)
之间是有向链接的,看起来像张量
的流动图(即从输入开始,流过一系列的节点,最终输出结果),Tensorflow
也由此得名。官方原话是:编程
What is a Data Flow Graph? Data flow graphs describe mathematical computation with a directed graph of nodes & edges. Nodes typically implement mathematical operations, but can also represent endpoints to feed in data, push out results, or read/write persistent variables. Edges describe the input/output relationships between nodes. These data edges carry dynamically-sized multidimensional data arrays, or tensors. The flow of tensors through the graph is where TensorFlow gets its name. Nodes are assigned to computational devices and execute asynchronously and in parallel once all the tensors on their incoming edges becomes available.
Tensorflow Core
编程,有点像画设计稿(构建流图)
->按图施工(执行流图)
这样的过程,执行流图必须使用tf.run()
方法。计算图中的节点
将接受0-N个张量
做为输入值并产生一个输出值。在个人理解中,节点
能够分为数值型
和运算型
两种。api
常量是一种没有输入,只有一个输出值的节点,常量在定义的时候就将其值存储在Tensorflow
内部了,一旦定义则没法修改其值。数组
示例代码:浏览器
# 定义常量c1,并将其数值类型定义为tf.float32,默认值为1.0 c1 = tf.constant(1., dtype=tf.float32) # 定义常量c2,并将其数值类型定义为tf.float32,默认值为2.0 c2 = tf.constant(2., dtype=tf.float32) # 执行流图: c1 + c2 with tf.Session() as sess: print(sess.run(tf.add(c1, c2)))
占位符也是数值型节点的一种定义方式,占位符是一种Promise
,就是承诺在执行tf.run()
的时候必定会在参数feed_dict
中提供其值。相比常量,占位符更像是一种参数,使用起来更灵活。app
用占位符改写上面的示例代码以下:机器学习
# 定义占位值p1,并将其数值类型定义为tf.float32 p1 = tf.placeholder(tf.float32) # 定义占位值p2,并将其数值类型定义为tf.float32 p2 = tf.placeholder(tf.float32) # 执行流图: p1 + p2 with tf.Session() as sess: # 既然承诺过,所以在run的时候必须提供p1,p2的值,不然代码将报错 print(sess.run(tf.add(p1, p2), {p1: 1., p2: 2.}))
比起占位符,变量就更灵活了,能够随时赋值,这样就能够将某些节点的输出值赋值到指定的变量中,以便后续节点使用。这种模式在机器学习中是很是必要的,由于机器学习就是一个调参的过程,在运行的时候就但愿能随时改变某些值以达到预期。
变量在使用的时候须要注意的是,在执行tf.run()
方法以前,必须将变量进行初始化,初始化语句是:
init = tf.global_variables_initializer() sess.run(init)
依旧是上述代码用变量改写:
# 定义变量v1,并将其数值类型定义为tf.float32,默认值为1.0 v1 = tf.Variable(1., tf.float32) # 定义变量v2,并将其数值类型定义为tf.float32,默认值为1.0 v2 = tf.Variable(2., tf.float32) with tf.Session() as sess: init = tf.global_variables_initializer() sess.run(init) print(sess.run(tf.add(v1, v2)))
其实上面的代码中已经用到了加法tf.add()
方法,减法是tf.subtract()
,乘法是tf.multiply()
,除法是tf.divide()
等等。全部的方法能够在官方API文档中找到:https://www.tensorflow.org/api_docs/python/tf,这里就不赘述了。
这里再简单介绍下Tensorflow
自带的很是强大的可视化工具TensorBoard
,TensorBoard
彻底能够单独写一篇博文,本文先抛砖引玉,主要是为了直观的展现上述代码产生的图。
最简单的TensorBoard
的使用方法以下:
# 保存计算图 with tf.summary.FileWriter(logdir='logs', graph=tf.get_default_graph()) as writer: writer.flush()
执行上述代码以后,Tensorflow
会将生成图所需的数据序列化到本地文件中,我指定了生成到当前同级目录logs
中,生成成功以后,能够在PyCharm
的控制台(使用快捷键ALT+F12可调出)中输入:
tensorboard --logdir=logs
等待几秒钟以后,控制台输出相似于以下内容则表示TensorBoard
已经启动成功:
TensorBoard 0.4.0rc3 at http://localhost:6006 (Press CTRL+C to quit)
在本地浏览器(推荐使用Chrome)地址栏中,输入http://localhost:6006
打开TensorBoard
,大体效果以下:
真正的机器学习过程当中,咱们固然是不知道变量的,咱们真正的目的就是去习得
这些变量,以达到模型可以尽量准确预测样本的指望,也就是所谓的损失(loss)
最小化。Tensorflow
提供了优化器(optimizers)
来作这个工做。最简单的优化器
算法叫梯度降低
,这是在线性模型中最经常使用的一种优化算法。优化器
底层会调用Tensorflow Core
中的tf.gradients
方法来实现梯度降低
。
如上图所示,假设如今已知4个蓝色的点(1,0),(2,-1),(3,-2),(4,-3),咱们须要推导出表明红色直线的系数W
和b
(公式为y = Wx + b
),固然这个例子很简单,用肉眼看一下就知道W=-1
,b=1
,用Tensorflow
实现的完整代码以下:
import tensorflow as tf # y = Wx + b, 初始化的时候随便定义一个初始值 W = tf.Variable([.3], dtype=tf.float32) b = tf.Variable([-.3], dtype=tf.float32) # 输入值 x, 定义为占位符, 便于在学习过程当中换成不一样的值 x = tf.placeholder(tf.float32) # 定义线性模型 linear_model = W*x + b # 输出值 y, 定义为占位符, 便于在学习过程当中换成不一样的值 y = tf.placeholder(tf.float32) # 损失loss,线性模型中以欧式距离来衡量损失值 loss = tf.reduce_sum(tf.square(linear_model - y)) # 定义优化器optimizer optimizer = tf.train.GradientDescentOptimizer(0.01) train = optimizer.minimize(loss) # 4个蓝色点的训练数据,分解成x和y的数组为 x_train = [1, 2, 3, 4] y_train = [0, -1, -2, -3] # 初始化Session init = tf.global_variables_initializer() sess = tf.Session() sess.run(init) # 循环1000次,训练模型 for i in range(1000): sess.run(train, {x: x_train, y: y_train}) # 评估准确率 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)) # 保存计算图 with tf.summary.FileWriter(logdir='logs_linear_regression', graph=tf.get_default_graph()) as writer: writer.flush()
我本机的输出结果为:
W: [-0.9999969] b: [ 0.99999082] loss: 5.69997e-11
W
的值无限接近-1,b
的值无限接近1,而loss
无限接近0,这个就是咱们设计的函数y=-x+1
。
在TensorBoard
中查看结果如图所示:
这个图就看起来就比较像这么回事了。
本系列教程我尽可能在阿里云的PAI
平台上也运行一次,虽然目前公测阶段仍是有不少问题,可是也是让不少人对机器学习变得触手可及的一种很是好的方案。
上一篇中,我用web版的OSS管理工具上传了源代码文件,本用例将使用OSS Browser
客户端上传和管理文件,下载地址在阿里云后台以下位置:
下载客户端的同时,能够开通阿里云的Access Key
(用来登陆OSS Browser
),开通位置以下:
开通以后,在管理界面看到以下内容:
打开并解压缩刚才下载的OSS Browser
,双击打开oss-browser.exe
文件,使用刚才开通的Access Key
登陆:
我依旧在上一篇相同的目录oss://danielfu-oss-tf-test/tensorflowtest/
下,建立了一个放summary
文件夹,并上传了代码文件tensorflow-demo2.py
:
在阿里云上使用Tensorflow
须要将上述的demo示例代码进行少许的改造,格式基本也都是固定的,改造完以后的完整代码以下:
# 指定文件的编码格式,这个不加在PAI里运行会报错 #!/usr/bin/python # -*-coding:utf-8 -*- from __future__ import absolute_import from __future__ import division from __future__ import print_function import sys import argparse import tensorflow as tf # 定义FLAGS用来传递全局参数 FLAGS = None def main(_): # y = Wx + b, 初始化的时候随便定义一个初始值 W = tf.Variable([.3], dtype=tf.float32) b = tf.Variable([-.3], dtype=tf.float32) # 输入值 x, 定义为占位符, 便于在学习过程当中换成不一样的值 x = tf.placeholder(tf.float32) # 定义线性模型 linear_model = tf.multiply(W, x) + b # 输出值 y, 定义为占位符, 便于在学习过程当中换成不一样的值 y = tf.placeholder(tf.float32) # 损失loss,线性模型中以欧式距离来衡量损失值 loss = tf.reduce_sum(tf.square(linear_model - y)) # 定义优化器optimizer optimizer = tf.train.GradientDescentOptimizer(0.01) train = optimizer.minimize(loss) # 4个蓝色点的训练数据,分解成x和y的数组为 x_train = [1, 2, 3, 4] y_train = [0, -1, -2, -3] # 初始化Session init = tf.global_variables_initializer() with tf.Session() as sess: sess.run(init) # 循环1000次,训练模型 for i in range(1000): sess.run(train, {x: x_train, y: y_train}) # 评估准确率 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)) # 保存计算图 with tf.summary.FileWriter(FLAGS.summaryDir + 'train', sess.graph) as writer: writer.flush() # 在运行main程序的时候,将参数传入执行代码中 # 本例中就指定了summaryDir参数 if __name__ == '__main__': parser = argparse.ArgumentParser() parser.add_argument('--summaryDir', type=str, default='', help='Summaries log directory') FLAGS, unparsed = parser.parse_known_args() tf.app.run(main=main)
在PAI
中,下图中1
的位置指定为tensorflow-demo2.py
文件,2
的位置指定为summary
目录,而后点击3
处的按钮:
多是PAI的BUG,该示例在执行的时候,输出结果永远是报错,可是在OSS中,summary
文件也已经成功生成,并且若是点击查看Tensorblaord
按钮,实际上是能够启动TensorBoard
的:
如上图所示,能够成功运行PAI
端的TensorBoard
(URL是阿里云的,不是本机localhost的)。并且生成的图和本地运行生成的图也是如出一辙的(废话)。
官方文档:https://www.tensorflow.org/get_started/get_started