【tensorflow】模块—基础—计算图、张量、session、constant、variable、placeholder、feed
Tensorflow基础
TensorFlowTM是一一个开放源代码软件库,用于进行高性能数值计算借助其灵活的架构,用户可以轻松地将计算工作部署到多种平台(CPU、GPU、TPU) 和设备(桌面设备、服务器集群、移动设备、边缘设备等).
TensorFIlowTM最初是由Google Brain团队(隶属于Google的AI部门)中的研究人员和工程师开发的,可为机器学习和深度学习提供强力支持.
TensorFlow的概念
TensorFlow = Tensor F low
- Tensor张量
- 数据结构:多维数组
- Flow流
- 计算模型:张量之间通过计算而转换的过程
TensorF low是一个通过计算图的形式表述计算的编程系统
- 每一个计算都是计算图上的一个节点
- 节点之间的边描述了计算之间的关系
计算图(数据流图)的概念
计算图是- -个有向图,由以下内容构成:
- 一组节点,每个节点都代表一个操作,是一种运算
- -组有向边,每条边代表节点之间的关系(数据传递和控制依赖)
TensorF low有两种边:
- 常规边(实线) :代表数据依赖关系。-个节点的运算输出成为另-个节点的输入,两个节点之间有tensor流动(值传递)
- 特殊边(虚线) :不携带值,表示两个节点之间的控制相关性。比如,happens-before关系, 源节点必须在目的节点执行前完成执行
#一个简单的计算图node1=tf.constant(3.0,tf.float32,name='node1')node2=tf.constant(4.0,tf.float32,name='node2')node3=tf.add(node1,node2)print(node3) #输出一个张量结构#result:Tensor("Add:0", shape=(), dtype=float32)
#建立对话并显示结果sess=tf.Session()print("运行sess.run(node1)的结果",sess.run(node1))#result:运行sess.run(node1)的结果 3.0#更新变量并返回计算结果print("运行sessrun(node3):",sess.run(node3))#关闭sessionsess.close() #释放内存资源#result:运行sessrun(node3): 7.0
张量的概念
在TensorFlow中, 所有的数据都通过张量的形式来表示
从功能的角度,张量可以简单理解为多维数组
- 零阶张量表示标量(scalar) ,也就是一-个数;
- 一阶张量为向量(vector) ,也就是一维数组;
- n阶张量可以理解为- -个n维数组;
张量并没有真正保存数字,它保存的是计算过程
张量的属性
Tensor("Add:O", shape=(), dtype=float32)
名字(name)
'node:soc_ output”: node
节点名称,src_ _output
来自节点的第几个输出"Add:0"
表示节点的名字交’Add’, 0 0 0来自节点的第 个输出形状(shape):可选的
张量的维度信息,
shape=()
, 表示是标量类型(type):可选的
每一个张量会有一个唯一的类型
TensorF I ow会对参与运算的所有张量进行类型的检查,发现类型不匹配时会报错
张量的形状
三个术语描述张量的维度:阶(rank)、形状(shape)、、 维数(dimens ion number)
阶 | 形状 | 维数 | 例子 |
---|---|---|---|
0 | () | 0-D | 4 |
1 | ( D 0 D0 D0) | 1-D | [ 2 , 3 , 5 ] [2,3,5] [2,3,5] |
2 | ( D 0 , D 1 D0,D1 D0,D1) | 2-D | [ [ 2 , 3 ] , [ 3 , 4 ] ] [[2,3],[3,4]] [[2,3],[3,4]] |
3 | ( D 0 , D 1 , D 2 D0,D1,D2 D0,D1,D2) | 3-D | [ [ [ 7 ] ] , [ [ 3 ] ] , [ [ 2 ] ] , [ [ 4 ] ] ] [[[7]],[[3]],[[2]],[[4]]] [[[7]],[[3]],[[2]],[[4]]] |
N | ( D 0 , D 1 , . . . , D n − 1 D0,D1,...,Dn-1 D0,D1,...,Dn−1) | n-D | 形为 ( D 0 , 1 D 1... , D n − 1 ) (D0,1D1...,Dn-1) (D0,1D1...,Dn−1)的张量 |
tens1=tf.constant([[[1,2,2],[2,2,3]], [[3,5,6],[5,4,3]], [[7,0,1],[9,1,9]], [[11,12,7],[1,3,14]]],name='tens1') #名字在可视化的时候可以显示#语句中包含[]{}()括号中间换行的不需要使用多行链接符print(tens1)#result:Tensor("tens1:0", shape=(4, 2, 3), dtype=int32)print(tens1.get_shape())#result:(4, 2, 3)
获取张量的元素
- 阶为1的张量等价于向量;
- 阶为2的张量等价于矩阵,通过
t[i, j]
获取元素; - 阶为3的张量,通过
t[i, j, k]
获取元素;
tens2 = tf. constant ([[[1, 2], [2, 3]], [[3,4], [5, 6]]])sess = tf. Session()print (sess. run(tens2)[1, 1,0])sess. close()#result:5
张量的类型
TensorF low支持14种不同的类型
- 实数
tf. float32,tf. float64
- 整数
tf. int8, tf. int16, tf. int32,tf. int64,tf. uint8
- 布尔
tf. bool
- 复数
tf. comp I ex64,tf. comp lex128
默认类型:
- 不带小数点的数会被默认为
int32
- 带小数点的会被默认为
f loat32
注意:TensorFlow会对参与运算的所有张量进行类型的检查,发现类型不匹配时会报错。张量对类型的要求很高,栗子
a = tf. constant([1, 2],name="a") #整型b = tf. constant([2.0, 3.0],name="b") #浮点型result=a b
结果报错:
>ValueError: Tensor conversion requested dtype int32 for Tensor with dtype float32: 'Tensor("b:0", shape=(2,), dtype=float32)'
操作
- 计算图中的节点就是操作(Operation)
- -次加法是一个操作
- -次乘法也是一个操作
- 构建一些变量的初始值也是一一个操作
- 每个运算操作都有属性,它在构建图的时候需要确定下来
- 操作可以和计算设备绑定,指定操作在某个设备上执行
- 操作之间存在顺序关系,这些操作之间的依赖就是“边”
- 如果操作A的输入是操作B执行的结果,那么这个操作A就依赖于操作B
#本例用到了TensorBoard,具体使用后面讲解tf.reset_default_graph() #清除default graph 和不断增加的节点(对当前对话图进行重置,只能看到下面的)#定义变量aa = tf.Variable(1, name="a")#定义操作b为a 1b = tf.add(a, 1, name="b")#定义操作c为*4c = tf.multiply(b, 4, name="c")#定义d为c-bd = tf.subtract(c, b, name="d")# # Logdir改为自己机器上的合适路径# logdir='D:/1og' # #生成一个写日志的writer,并将当前的TensorFLow计算图写入日志。# writer = tf. summary. FileWriter(logdir ,tf.get_ default_ _graph())# writer . close()
会话Session
会话拥有并管理TensorF low程序运行时的所有资源
当所有计算完成之后需要关闭会话帮助系统回收资源
#定义计算图tens1 = tf.constant([1,2,3])#创建一个会话sess = tf.Session()#使用这个创建好的会话来得到关心的运算的结果。比如可以调用sess. run(result)print(sess.run(tens1))#关闭会话使得本次运行由使用到的资源可以被释放sess.close()#result:[1 2 3]
需要明确调用Sess ion. close ()函数来关闭会话并释放资源
当程序因为异常退出时,关闭会话函数可能就不会被执行从而导致资源泄漏
所以可以进行如下操作:
会话典型模式1
#定义计算图tens1 = tf.constant([1,2,3])#创建一个会话sess = tf.Session()try: #使用这个创建好的会话来得到关心的运算的结果。比如可以调用sess. run(result) print(sess.run(tens1))except: print("Exception!")#关闭会话使得本次运行由使用到的资源可以被释放finally: sess.close()
会话典型模式2
node1 = tf.constant(3.0,tf.float32 ,name="node1" )node2 = tf.constant(4.0, tf.float32, name="node2" )result = tf.add( node1, node2)#创建一个会话,并通过Python中的上下文管理器来管理这个会话with tf.Session() as sess: #使用这创建好的会话来计算关心的结果 print(sess.run(result)) #不需要再调用Session.cLose()函数来关闭会话#当上下文退出时会话关闭和资源释放也自动完成了
指定默认的会话
TensorFlow不会自动生成默认的会话,需要手动指定
当默认的会话被指定之后可以通过tf.Tensor.eval
函数来计算一个张量的取值
node1=tf.constant(4.0,tf.float32,name='node1')node2 = tf.constant(4.0,tf.float32, name= "node2")result = tf .add(node1, node2)sess = tf .Session()with sess.as_default(): #as_default设置为默认会话 print(result.eval()) #.eval()获取张量结构中的值,是内置函数
下面代码也可以完成相同的功能
sess=tf.Session()#下面两个命令具有相同的功能print(sess.run(result))print(result.eval(session=sess))
交互式环境下设置默认会话
在交互式环境下,Python脚本或者Jupyter编辑器下,通过设置默认会话来获取张量的取值更加方便。
tf. Interact iveSession
使用这个函数会自动将生成的会话注册为默认会话
node1=tf.constant(4.0,tf.float32,name='node1')node2 = tf.constant(4.0,tf.float32, name= "node2")result = tf .add(node1, node2)sess = tf. InteractiveSession() #这也是一个默认会话print(result.eval()) #默认会话,里面不需要加会话参数了sess.close()
常量constant
在运行过程中值不会改变的单元,在TensorF low中无须进行初始化操作
创建语句:constant_ name = tf. constant (value)
a = tf.constant(1.0, name='a')b = tf.constant(2.5, name='b')c = tf.add(a, b, name='c')sess = tf .Session( )c_value = sess.run(c) print(c_value)sess. close( )
变量 variable
变量初始化
在运行过程中值会改变的单元,在TensorF low中须进行初始化操作
创建语句:name_variable = tf. Variable (value,name)
#注意V是大写
个别变量初始化:init_op = name_variable. initializer ()
所有变量初始化:init_op = tf.global_variables_initializer()
#变量node1 =tf.Variable(5.0,tf.float32,name='node1')node2 = tf.Variable(4.0,tf.float32, name= "node2")result = tf.add(node1, node2,name='add')sess = tf .Session( )#变量初始化init=tf.global_variables_initializer() sess.run(init) #将前面所定义的变量初始化 #如果不执行sess.run(init),前面的都是静态图:node1,node2,result,init;系统会报错 print(sess.run(result))
注意:
以上代码在Session对话变量后,增加了一个init初始化变量,并调用会话的run命令对参数进行初始化。
变量的赋值
- 与传统编程语言不同,TensorFlow中的变量定义后,一般无需人工赋值,系统会根据算法模型,训练优化过程中自动调整变量对应的数值
- 后面在将机器学习模型训练时会更能体会,比如权重We i ght变量w,经过多次迭代,会自动调
epoch = tf.Variable(O,name=' epoch' ,trainable=False)
这个变量不参加训练
- 特殊情况需要人工更新的,可用变量赋值语句
update_ op = tf.assign(variable_ _to_ be_ updated, new_ value)
(需要被更新的变量,新值)
栗子:
#通过变量赋值输出1、2、3...10value = tf .Variable(0, name="value")one = tf . constant(1)new_value = tf .add(value, one)update_value = tf.assign(value, new_value)init = tf.global_variables_initializer() #所有变量初始化with tf .Session() as sess: #打开Session会话 sess. run(init) #运行变量初始化 for _ in range(10): sess. run(update_value ) #运行 update_value操作(更新value的值) print(sess . run(value)) #打印运行结果
作业题
如何通过Tensor Flow的变量赋值计算:1 2 3 … 10=?
#如何计算1 2 3 。。 10value=tf.Variable(0,name='value') #动态变量value,设初始值为0one=tf.constant(1) #常量为1new_value=tf.add(value,one,name='new_value') #变量 1update_value=tf.assign(value,new_value) #将变量 1赋值给valueres=tf.Variable(0,name='res') #变量,用作结果和,初始值为0temp_value=tf.add(res,value) # res value ,加法操作update_res_value=tf.assign(res,temp_value) #将 res value 重新赋值给resinit=tf.global_variables_initializer()with tf.Session() as sess: sess.run(init) for _ in range(10): sess.run(update_value) #变量value更新一次 sess.run(update_res_value) #和res更新一次 print(sess.run(res))
1 2 3 4 … n
# 我还看不明白import tensorflow.compat.v1 as tfvalue = tf.Variable(0,name="value")sum = tf.Variable(0,name="sum")one = tf.constant(1)tf.disable_v2_behavior()n = tf.placeholder(tf.int32,name='n') new_value = tf.add(value,one)update_value = tf.assign(value,new_value)new_sum = tf.add(sum,value)update_sum = tf.assign(sum,new_sum) init = tf.global_variables_initializer()with tf.Session() as sess: sess.run(init) number = int(input("请输入数字: ")) for i in range(number): sess.run(update_value) sess.run(update_sum) result = sess.run(sum,feed_dict={n:number}) print(result)
占位符placeholder
TensorF low中的Var iable变量类型,在定义时需要初始化,但有些变量比如训练数据,这时候需要用到占位符
*tf. placeholder
占位符,是TensorF I ow中特有的一种数据结构,类似动态变量,函数的参数、或者C语言或者Python语言中格式化输出时的“%”占位符TensorF low占位符P laceholder,先定义一种数据,其参数为数据的Type和Shape
占位符Placeho lder的函数接口如下:
tf.placeholder(dtype, shape=None, name=None)
x = tf.placeholder(tf.float32, [2,3], name='tx')#此代码生成一个2x3的二维数组,矩阵中每个元素的类型都是tf. float32,内部对应的符号名称是tx
Feed 提交数据
如果构建了-个包含placeholder操作的计算图,当在session中调用run方法时,placeholder占用的变量必须通过feed_dict 参数传递进去,否则报错
placeholder不需要做变量初始化
a=tf.placeholder(tf.float32,name='a')b=tf.placeholder(tf.float32, name='b')c=tf.multiply(a,b,name='c')init = tf.global_variables_initializer()with tf.Session() as sess: sess.run(init) #变量初始化,在这里,没有用到变量,注释掉这行,也不会报错 #通过feed_dict的参数传值,按字典格式 result = sess.run(c,feed_dict={a:8.0, b:3.5}) print(result)
多个操作可以通过一次feed完成执行
a=tf.placeholder(tf.float32,name='a')b=tf.placeholder(tf.float32, name='b')c=tf.multiply(a,b,name='c')d=tf.subtract(a,b,name='d')init = tf.global_variables_initializer()with tf.Session() as sess: #sess.run(init) #通过feed_ dict的参数传值,按字典格式 result = sess.run([c,d], feed_dict={a:[8.0, 2.0, 3.5], b:[1.5, 2.0, 4.0]}) #[c,d]将两个操作放入一个列表 #{a:[8.0, 2.0, 3.5], b:[1.5, 2.0, 4.0]},a & b对应的不再是数值而是向量 print(result) #取结果中的第一个 print(result[0])
>[array([12., 4., 14.], dtype=float32), array([ 6.5, 0. , -0.5], dtype=float32)]>[12. 4. 14.]
一次返回多个值分别赋给多个变量
a=tf.placeholder(tf.float32,name='a')b=tf.placeholder(tf.float32, name='b')c=tf.multiply(a,b,name='c')d=tf.subtract(a,b,name='d')init = tf.global_variables_initializer()with tf.Session() as sess: sess.run(init) #返回的两个值分别赋值给两个变量 rc,rd = sess.run([c,d], feed_dict={a:[8.0, 2.0, 3.5], b:[1.5, 2.0, 4.0]}) print("value of c=",rc,'value of d=',rd)
结果是
>value of c= [12. 4. 14.] value of d= [ 6.5 0. -0.5]
TensorBoard: TensorFlow可视化工具
- TensorBoard是TensorF low的可视化工具
- 通过TensorF low程序运行过程中输出的日志文件可视化TensorFIow程序的运行状态
- TensorBoard和TensorF low程序跑在不同的进程中
案例:在TensorBoard中查看图的结构
#清除default graph和不断增加的节点tf.reset_default_graph()#logdir改为自己机器上的合适路径logdir='D:/1og'#定义一个简单的计算图,实现向量加法的操作input1 = tf .constant([1.0, 2.0,3.0],name="input1")input2 = tf .Variable(tf.random_uniform([3]), name="input2")output = tf .add_n([input1, input2],name="add")#生成一个写日志的writer,并将当前的TensorFlow计算图写入日志。writer = tf.summary.FileWriter(logdir,tf.get_default_graph())#(日志的路径,得到图的信息)writer.close( )
启动TensorBoard
TensorBoard不需要额外安装,在TensorF I ow安装时已自动完成
在Anaconda Prompt中先进入日志存放的目录(非常重要! ! ! )
再运行TensorBoard,并将日志的地址指向程序日志输出的地址
命令: tensorboard --logdir=/path/log
启动服务的端口默认为6006;使用-- port参数可以改编启动服务的端口teng
机器学习相关术语
训练
训练模型表示通过有标签样本来学习(确定) 所有权重和偏差的理想值
在监督式学习中,机器学习算法通过以下方式构建模型:
- 检查多个样本并尝试找出可最大限度地减少损失的模型
- 这-过程称为经验风险最小化
损失
损失是对糟糕预测的惩罚:损失是一个数值,表示对于单个样本而言模型预测的准确程度
如果模型的预测完全准确,则损失为零,否则损失会较大
训练模型的目标是从所有样本中找到一-组平均损失“较小”的权重和偏差
定义损失函数
L 1 L_1 L1损失:基于模型预测的值与标签的实际值之差的绝对值
平方损失:一种常见的损失函数,又称为L2损失
均方误差(MSE)指的是每个样本的平均平方损失
M S E = 1 N ∑ ( x , y ) ∈ D ( y − p r e d i c t i o n ( x ) ) 2 MSE=\frac{1}{N}\sum_{(x,y)\in D}(y-prediction(x))^2 MSE=N1(x,y)∈D∑(y−prediction(x))2
模型训练与降低损失
训练模型的迭代方法
推理:执行预测 特征 模型-预测函数 计算损失 标签 计算参数更新
模型训练要点
- 首先对权重w和偏差b进行初始猜测
- 然后反复调整这些猜测
- 直到获得损失可能最低的权重和偏差为止
收敛(训练停止)
在学习优化过程中,机器学习系统将根据所有标签去重新评估所有特征,为损失函数生成一-个新值,而该值又产生新的参数值。
通常,您可以不断迭代,直到总体损失不再变化或至少变化极其缓慢为止。这时候,我们可以说该模型已收敛
梯度下降法
梯度:一个向量(矢量),表示某一函数在该点处的方向导数沿着该方向取得最大值,即函数在该点处沿着该方向( 此梯度的方向)变化最快,变化率最大。
学习率
沿着负梯度方向进行下一步探索,前进多少合适?
用梯度乘以一个称为学习速率(有时也称为步长)的标量,以确定下一-个点的位置
例如:如果梯度大小为 2.5 2.5 2.5, 学习速率为 0.01 0. 01 0.01,则梯度下降法算法会选择距离前一;个点 0.025 0.025 0.025的位置作为下一个点
超参数
在机器学习中,超参数是在开始学习过程之.前设置值的参数,而不是通过训练得到的参数数据
通常情况下,需要对超参数进行优化,选择- -组好的超参数,可以提高学习的性能和效果
超参数是编程人员在机器学习算法中用于调整的旋钮
典型超参数:学习率、神经网络的隐含层数量…
————————————————————————————————
tensorflow的套路
- 将
变量,常数
修改成tensorflow支持运算的格式—张量 - 变量初始化、常量初始化
- 创建会话
Session
,使常量、变量、运算操作
有执行区域(占据内存) - 在
Session
中执行操作