TensorFlow笔记

来源:互联网 发布:vs打开数据库代码 编辑:程序博客网 时间:2024/05/29 02:37

从今年的年初开始,断断续续的看了TensorFlow一段时间,主要是<TensorFlow实战>和<面向机器智能的TensorFlow实践>,还有<Tensorflow白皮书>,TensorFlow大概还有40W行的源码,但还不是太熟,很多的内容也是没有理解深刻,记下一些笔记,算是以后自己翻阅的参考,给自己一个交代,肯定还有很多不完善的地方,以后在慢慢修改。 


1,何为Tensorflow

官网有一句措辞如下,Tensorflow is an Open Source Software Library for Machine Intelligence

可能上方的还不够具体,在这句话的下方还有一句更具体的解释 Tensorflow is an Open Source Software Library forNumerical Computation usingdata flow graphs

 (1)开源

Tensorflow 最初作为Google内部的机器学习工具创建的,但在2015年11月,它的一个实现被开源,采用的开源协议Apache 2.0,作为开源软件,任何人都可以自由下载,修改和使用。但是,严格的说,我们只能称之为一个实现,而不能说TensorFlow被开源,从技术角度上讲,Tensorflow是<Tensorflow白皮书>描述的一个用于数值计算的内部借口,其内部实现仍然由Google内部维护,然而开源实现和Google内部实现之间的差异主要是由其他内部软件的连接造成的,Google始终源源不断的将内部改进推送到公共代码库,总之,TensorFlow的开源实现包含了Google内部版本完全相同的功能

(2)数值计算库

官网未将Tensorflow定义未一个机器学习库,而是为了使用一个更宽泛的短语‘数值计算’,虽然TensorFlow包含了一个模仿了一个具有单行建模功能的机器学习库Scikit Learn的名为learn的包,TF.learn,在<TensorFlow实战第10章>有专门介绍。但是TensorFlow的主要目的并不是提供机器学习的解决方案,相反,Tensorflow提供了一个可使用户用数学方法从零开始定义模型的函数和类的广泛套件,这使得具有一定技术背景的用户可迅速而直观地创建自定义的,具有高效灵活性的模型

(3)数据流图

TensorFlow的计算模型是有向图,其中每个节点(圆圈或方框)代表函数和计算,而边(通常以箭头或线段表示)代表了数值、矩阵和张量

数据流图极为有用的原因:第一,许多常见的机器学习模型,如神经网络,本身就以有向图表示的,采用数据流图无疑将机器学习的实践者的实现更为自然,第二,通过将计算分解为一些小的,容易微分的环节,TensorFlow能够计算任意节点关于其他对第一个节点输出产生影响的任意节点的导数,第三,通过计算的分解,将计算分布在多个cpu,gpu以及其他计算设备上更加容易,只需要将完整的较大的数据流图分解为一些小的计算图,并让每台设备负责一个独立的计算子图(此外,还需要一定逻辑将不同设备间的共享信息进行调度)


2,Tensorflow的一些特性

(1)分布式功能

刚发布的版本是没有该功能的,但是从0.8.0版本起,分布式运行已经成为TensorFlow内置库的一部分,虽然这部分的API比较臃肿,但是极其强大,大部分的机器学习库不具备该功能,(可以让多台计算机以及单机多CPU、单机多GPU具有良好的伸缩性)

(2)软件套装

虽然TensorFlow主要是用于构建和训练机器学习模型的API,但TensorFlow实际上是一组需要配合使用的软件。第一,TensorFlow使用与定义机器学习模型,用数据训练机器模型,并将模型导出后供后续使用的API.虽然实际的计算是c++编写的,但是主要的API均可以通过Python访问,这使得数据科学家和工程师可利用Python中对用户更友好的环境,而将实际计算交给高效的、经过编译的c++代码。虽然Python也提供了基于c++的API,但是还不是太完善。第二,Tensorboard是一个包含在任意标准TensorFlow安装中的图可视化工具,当用于在TensorFlow中引入某些tensorboard的特定运算时,tensorboard可读取由TensorFlow导出的文件,对分析模型的行为提供有价值的参考,他对概括统计量,分析训练过程,并调试TensorFlow代码都很有帮助,增加趣味性。第三,TensorFlow Serving是一个可为部署预训练的Tensorflow模型带来便利的软件,利用内置的TensorFlow函数,用户可将自己的模型导出到由TensorFlow serving 在本地读取的文件中,之后,他会启动一个简单的高性能服务器,该服务器可接受输入数据,并将之送入预训练的模型,然后将结果返回,此外,TensorFlow serving 还可以在旧模型和新模型之间无缝切换,而不会给用户带来任何停机时间。将serving纳入生产环境中,可避免用户重新实现自己的模型,他们只需要使用TensorFlow导出的文件,(serving完全用c++编写,其中的API也只能通过c++访问)


TensorFlow安装略。。。


3,TensorFlow定义数据流图

TensorFlow的工作流程比较容易记忆

1)定义数据流图

2)执行数据流图(在数据上)



                                                                                                                                        图(1)

用于表示上图(1)数据流图的TensorFlow代码如下

import tensorflow as tf

a =tf.constant(5,name='input_a')

b=tf.constant(3,name='input_b')

c=tf.mul(a,b,name='mul_c')

d=tf.add(a,b,nme='add_d')

e=tf.add(c,d,name='add_e')


#执行数据流图

sess=tf.Session()

output = sess.run(e)


最终得到output输出结果是23,

说明:在数据流图中,每个节点称之为一个Op(全称Operation),各Op可接受0个或多个Tensor输入,并输出0个或多个Tensor对象,在本例中,tf.constant()创建了一个常量op,它接受单个张量值,然后将同样的值输出给与其直接相连接的节点。为方便起见,该函数自动将标量值6和3转换为Tensor对象,此外,我们还为这个构造方法传入了一个可选的字符串参数name,用于对所创建的对象进行标识,c和d是是数据流图定义的另外两个节点,而且他们都使用了之前定义的节点a和b,节点c使用了tf.mul Op,它接受两个输入,然后将他们的乘积输出,对于这些Op,我们均传入了name参数(一般都会标记住名字,便于识别)。我们无需对数据流图的边进行定义,因为TensorFlow中创建节点时已包含了相应的Op完成计算所需的全部输入,TensorFlow会自动绘制必要的连接。。。定义完数据流图后,要想体验下数据流图的运行效果,还需要执行数据流图,Session对象负责对数据流图进行监督,并且是运行数据流图主要接口。将数据流图的结果输出。。


通过以上的定义,我们拥有了一个活动状态的Session对象,且数据流图已定义完毕,下面可以使用TensorBoard进行可视化


writer = tf.summary.FileWriter('./my_graph',sess.graph)


创建了TensorFlow的FileWriter对象,并将它赋给变量writer,所创建的文件放在第一个名为my_graph的文件夹中,该文件夹位于运行Python代码的那个路径下,第二个输入时Session对象的graph属性作为TensorFlow中定义的数据流图管理器,tf.Session拥有一个graph属性,该属性引用了他们所要追踪的数据流图

在终端输入tensorboard --logir="my_grapy"

在控制台能看到一些日志信息打印出来,然后消息‘starting TensorBoard on port 6066’,刚才所做的是启动一个来自‘my_graph’目录下的数据的TensorBoard服务器,默认情况下,TensorBoard服务器启动后会自动监听端口6006,要访问TensorBoard,打开浏览器输入http://localhost:6006,

完成数据流图的构造后,需要将Session对象和FileWriter对象关闭,以释放资源,并做一些清理工作

writer.close()

sess.close()

从技术角度上讲,当程序运行结束后(要使用的是交互式环境,当关闭或重启Python内核时),Session对象会自动关闭,尽管如此,仍建议显式关闭Session对象,以避免任何诡异的边界用例的出现



4,TensorFlow基本概念属性和操作元语

(1)张量

张量是n维数据的抽象,1D张量等于向量,2D张量等于矩阵。。。

当我们需要接受任意长度的输入向量时,

当我们希望输入的长度是2时,如上面的数据流图,实现可以重新定义

import tensorflow as tf

a = tf.constant([5,3],name='input_a')

b=tf.reduce_prod(a,name='prod_b')

c=tf.reduce_sum(a,name='prod_c')

d=tf.add(c,d,name='add_d')


之前接受的标量值得乘法和加法Op,现在用tf.reduce_prod()和tf.reduce_add()函数重新定义,当给定某个输入是,这些函数就接收所有分量,然后分别将他们相乘或相加。

在TensorFlow中,所有节点之间传递的数据都是Tensor对象,TensorFlow可接收标准Python类型,如整型或字符串,并将他们转化为张量。

张量只是矩阵的一个超集


(2)Operation

tensorflow中的Operaton 也成Op,是一些对(或利用)tensor对象执行运算的节点,计算完毕后,返回0个或多个张量,可以在以后为数据流图的其他Op所使用

一些运算,比如tf.add(),tf.abs(),....

有点难度的地方是name参数,为op赋予name,如果希望在一个数据流图为不同的op复用相同的name参数,则无需为每一个name参数加上前缀或后缀,只需要利用name_scope以编程的方式将这些运算组织在一起。。


(3)tesorflow中的Graph对象

学习如何创建更多的数据流图,以及如何让多个数据流图协同工作

创建Graph对象非常简单,它的构造方法不依赖与任何参数

import tensorflow as tf

#创建一个数据流图

g = tf.Graph()

Graph初始化完成后,便可利用Graph.as_default()方法访问其上下文管理器,为其添加op,结合with语句,可利用上下文管理器通知TensorFlow我们将一些Op添加到某个特定Graph对象中

with g.as_default():

      #正常添加Op,他们将被添加到Graph对象g中

      a = tf.mul(2,3)


注意:当TensorFlow库被加载时,它会自动创建一个Graph对象,并将其作为默认的数据流图,因此,在Graph.as_default()上下文管理器之外的任何op,tesnsor对象都会自动放置在默认的数据流图中。

在创建数据流图时,不要将默认的数据流图和用户创建的数据流图混合使用


(4)TensorFlow的Session

Session负责数据流图的执行,tf.Session接受3个参数

a),target指定了所要使用的执行引擎,对于大多数应用,该参数为默认的空字符串,在分布式设置中,使用Session对象时,该参数用于连接不同tf.train.Server实例

b),graph指定将要在session对象中加载Graph对象,其默认值为none,表示使用当前默认数据流图

c),confi参数允许用户指定配置Session对象所需的选项,如限制CPU或GPU的使用数目,为数据流图设置优化参数及日志选项

ses = tf.Session()和tf.Session(graph=tf.get_default_graph())等价


创建session后,需要run来计算所期望tensor对象的输出

sess.run()接收一个参数fetches,以及其他三个可选参数:feed_dict, options和run_metadata

fetches接收任意的数据流图元素(op或tensor对象),后者指定了用户希望执行的对象,如果请求对象为Tensor对象,则run输出为NumPy数组,如果请求为Op,则输出为None 

feed_dict={a:15}由键和值两部分构成,由于张量的值是事先提供的,数据流图不需要对该张量的任何普通依赖节点做计算,这意味着如果有一个规模较大的数据流图,并希望用一些虚构的值对某些部分做测试,TensorFlow将不会再不必要的计算上浪费时间


(5)TensorFlow中的placeholder(占位符)

当需要输入不仅仅是常量,而是从客户那里结束输入值,这样,便可以对数据流图总中所描述的变换以各种不同类型数值进行复用。

eg: tf.placeholder(tf.int32,shape=[2],name='my_input')

dtype参数类型必须指定,shape参数可选,为了给占位符一个实际值,需要使用Session.run()中的feed_dict参数,

import tensorFlow as tf

a = tf.placeholder(tf.int32, shape=[2], name='my_input')

b = tf.reduce_prod(a,name='prod_b')

c = tf.reduct_add(a,name='sum_c')

d = tf.add(b, c, name='add_d')

sess =tf.Session()

input_dict={a:np.array([5,3],dtype=np.int32)}

sess.run(d,feed_dict=input_dict)


注意:必须在feed_dict中为待计算的节点的每个依赖占位符包含一个键值对,上面代码中,需要计算d的输出,而他依赖于a的输出,如果还定义了一些d不依赖的其他占位符,则无需将它们包含在feed_dict中。。


(6)Variable对象

Tensor对象和Op都是不可变的,但机器学习的本质决定了需要一种机制保存随时间变化的值,Variable对象包含了在对Session.run()多次调用中可持久化ee的可变张量值

eg:my_var = tf.Variable(3,name='my_variable')  # 为Variable变量传入一个初始值3

#2*2的零矩阵

zeros = tf.zeros([2,2])

#长度为6的全为1的向量

ones = tf.ones([6])

#3*3*3的张量,元素服从0~10的均匀分布

nuiform = tf.randonm_uniform([3,3,3],mnival=0,maxval=10)


Variable对象初始化

init = tf.global_variables_initializer()

sess=tf.Session()

sess.run(init)


最后,说一下trainable参数,对于自动训练机器学习模型的Optimizer优化类,着意味着这些类将自动修改Variable对象的值,而无需显示做出请求,大多数情况下,这和读者的期望一致,但如果要求Graph中的对象将其Variable只能用于手工修改,而不允许使用Optimizer类时,需要指定Variable对象为False

not_trainable=tf.Variable(0,trainable=False)

对于迭代计数器,或其他不涉及机器学习模型的Variable对象,通常都需要这种设置