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))
#关闭session
sess.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 和不断增加的节点(对当前对话图进行重置,只能看到下面的)
#定义变量a
a = tf.Variable(1, name="a")
#定义操作b为a+1
b = tf.add(a, 1, name="b")
#定义操作c为*4
c = tf.multiply(b, 4, name="c")
#定义d为c-b
d = 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...10
value = 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+。。+10
value=tf.Variable(0,name='value') #动态变量value,设初始值为0
one=tf.constant(1) #常量为1
new_value=tf.add(value,one,name='new_value') #变量+1
update_value=tf.assign(value,new_value) #将变量+1赋值给value
res=tf.Variable(0,name='res') #变量,用作结果和,初始值为0
temp_value=tf.add(res,value) # res+value ,加法操作
update_res_value=tf.assign(res,temp_value) #将 res+value 重新赋值给res
init=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 tf
value = 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
中执行操作