蒋子阳《TensorFlow深度学习算法原理与编程实战》的学习笔记(一)
环境:
Windows
TensorFlow 1.12
GPU:1660ti
TensorFlow 基础知识
tf以计算图为基础,整个计算过程包括 ① 构建图 ②执行图
TensorFlow首先创建一个骨架图,里面包含所有组件,此时没有数据和计算的产生,只有当会话执行时,数据进入图中进行流动,才有实际的结果产生。
计算图 -- 计算模型
图:是相互连接的实体的集合,通常称为节点node,节点通过边edge连接
TensorFlow中的图的每一个节点表示一个操作,并可应用在某个输入或生成传递给其他节点的输出
依赖关系:一个节点的输入取值于另一个节点的输出,那么这两个节点具有依赖关系。存在依赖关系的节点通过边相互连接。
张量(tensor)就是在边中流动(flow)的数据,这也是TensorFlow名称的由来。此外,存在一种不流动数据的边,它们起着依赖控制(control dependencies)作用,让起始节点执行完后才执行下一个目标节点,但中间没有数据传输。
创建图
eg.定义一个简单的graph。 a b相乘得到c, d等于c的正弦,e等于b d的商。(《TensorFlow学习指南》的例题3.1)
import tensorflow as tf
a = tf.constant(5,tf.float32) # 定义常量
b = tf.constant(10,tf.float32)
print(b) # Tensor("Const_1:0", shape=(), dtype=float32) 名称为const_1:0的tensor对象,类型是float32
c = b*a # c = tf.mul(a,b) c定义了这个乘法操作
d = tf.sin(c)
e = b / d
with tf.Session() as sess: # 使用with语句打开会话可以保证计算完成后将会话自动关闭,否则使用sess.close()操作
fetches = [a,b,c,d,e]
out1 = sess.run(fetches) # sess.run可以同时计算多个节点列表 sess.run参数称为fetches(提取),将节点传入参数,用来计算该节点的值
# TensorFlow仅利用依赖关系的集合来计算节点 例如,e依赖 b和d,则通过b d计算e
outs = sess.run(e)
print(out1,type(out1),out1[0])
tf的计算图
导入tf的时候,会自动生成一个空白图,后续的操作都与该默认图关联。
可以通过tf.Graph()创建一个新的空白图,并可以自定义操作与它关联。任何一个节点都可以通过graph属性查看是否属于某个图
import tensorflow as tf
print(tf.get_default_graph()) #默认空白图
g = tf.Graph()
print(g)
a = tf.constant(5)
print(a.graph is tf.get_default_graph()) # 结果是true
print(a.graph is g) #结果是false
多个计算图的管理
with语句可以用于上下文管理,它设置了enter块和exit块,因此可以用它管理某个计算图,使用with语句和as_default()返回上下文管理器,指定某个计算图成为该部分的默认图,同时在该部分定义的计算关联与该图
g1 = tf.get_default_graph()
g2 = tf.Graph()
print(g1 is tf.get_default_graph()) # True
with g2.as_default():
print(g1 is tf.get_default_graph()) # False
print(g1 is tf.get_default_graph()) # true
张量 -- 数据模型
张量tensor类似于数组array,但是张量只保存了运算结果的属性,而没有保存它的具体数值。
import tensorflow as tf
a = tf.constant([1.0, 2.0],name = 'a' , dytpe= tf.float32) # 定义常量
print(a) # Tensor(""Const_1:0", shape=(2,), dtype=float32")
每一个张量都具有操作op、维度shape和数据类型dtype三种属性。
操作op
op是一个张量的名字,也算它的唯一标识符。计算图的每个节点都是一个运算,张量保存的是运算的属性,命名规则是“ node:src_output”。node是节点名称,如const、add、mul等,src_output表示该张量是节点的第几个输出,从0开始编号。
维度shape
类似array的维度,一维标量scalar、二维向量vector.....直至n维数组
数据类型dtype
tf支持十四种类型 int8/16/32/64 、uint8、float32/64、布尔bool、复数complex64/128、字符串string和qint8/32、quint8
会话 -- 运行模型
完成数据和计算图的定义后需要使用会话session执行。
两种开启会话的方式:with语句更方便,自动关闭。
sess = tf.Session() # 开启
sess.run() # 执行
sess.close() # 关闭
with tf.Session() as sess:
sess.run()
placeholder与变量Variable
tf.constant定义的是计算图中的常量,可变数据则是通过placeholder和变量来定义。
palceholder机制
placeholder相当于在计算图中指定了一个位置,数据在程序运行时才给出。placeholder机制用于解决数据量过大的问题,可以将数据分批次传入节点,在编程时只需要传入holder位置即可,这样在有限的节点高效传入大量的数据。
函数原型 placeholder(dtype, shape=None, name=None)
a = tf.placeholder(tf.float32,shape=(None,2),name = "input")
b = tf.placeholder(tf.float32,shape=(None,2),name = "input")
ans =a + b
with tf.Session() as sess:
sess.run(ans, feed_dict={a:[1.0,2.0],
b:[2.0,3.0]})
print(ans)
定义placeholder时,数据类型dtype必须给出且不可改变,shape若是给出时不确定可以用None,不给出的时候程序自动推断。
运行时通过sess.run的feed_dict参数传入holder的取值,它是一个字典数据,传入时的数据类型必须与placeholder定义时的类型一致,否则会报错。
TensorFlow的变量
变量的作用是保存网络中的参数,对参数的更新就是对相应变量值的更新,使用Variable()声明变量,同时需要提供初始值。通常是采用随机分布赋初值。tf提供了正态分布、平均分布、伽马分布等多种类型。
此外变量的初值还可以是常量、其他变量的初值计算而来。z
# 声明一个变量并随机赋值,返回大小3×4 均值0 标准差1 满足正态分布的随机矩阵
weights = tf.Variable(tf.random_normal([3,4], stddev=1))
几种随机分布和常量初始化
函数名 | 功能 | 函数名 | 功能 |
---|---|---|---|
random_normal | 正态分布 | zeros | 全0数组 |
truncate_normal | 正态分布 | ones | 全1数组 |
random_uniform | 平均分布 | fill | 全为给定值的数组 |
random_gamma | 伽马分布 | constant | 给定值的常量 |
获取一个变量的值通过initialized_value()方法
bias = tf.Variable(tf.zeros([3])) #全为1的一维数组,长度3
b1 = tf.Variable(bias.initialized_value()*3) # 使用bias的值乘3初始化bl
批量初始化:
tf.global_variables_initializer() # 初始化全部变量
tf.initialize_all_variables() # 较早版本tf的写法,1.12中仍存在,和上面的方法功能一样
变量和张量
变量在TensorFlow中是一个运算,对应tensorboard里面计算图的一个节点,这个运算的输出结果就是一个具有name、shape和type属性的张量。
变量在构建后数据类型就不能更改,但shape可以发生变化,需要设置validate_shape=False
tf.assign(w1,w2,validate_shape=False) # 将w2赋给w1,若是shape不一致,仍旧可以进行赋值
变量空间
除了Variable()外,可以通过get_variable()创建或者获取变量,该函数的使用类似Variable,但有所不同。name参数此时必须指明,同时通过initializer参数指明初始化方法。
a = tf.get_variable(name= "a", shape=[1],initializer=tf.constant_initializer(1.0))
initializer参数的取值也包括常量和随机分布等初始化方法。
初始化函数 | 初始化为指定常量 |
---|---|
constant_initializer | 正态分布初始化 |
random_normal_initializer | 正态分布初始化 |
truncate_uniform_initializer | 平均分布初始化 |
random_uint_scaling_initialize | 平均分布但不影响输出数量级 |
random_gamma_initialize | 伽马分布 |
zeros_initialize | 全零初始化 |
ones_initialize | 全1初始化 |
variable_scope() 与name_scope(): 在变量空间使用get_variable获取已经创建过的变量
可以通过variable_scope指定一个变量空间,在该空间定义两个name相同的变量会报错。
with tf.variable_scope("one"):
a1 = tf.get_variable("a",[1],initializer=tf.constant_initializer(1.0))
with tf.variable_scope("one"): #报错 因为one空间已经存在一个name=a的变量,错误信息提示是否将reuse设置True
a2 = tf.get_variable("a",[1])
with tf.variable_scope("one",reuse=True):# 不报错,因为reuse=True,可以重复使用,get_variable将获取one空间的name=a的变量赋值给a2
a3 = tf.get_variable("a",[1])
print(a1.name,a3.name) # 输出是 one/a:0 one/a:0 变量空间内的变量name通常会带上空间名字作为前缀
with tf.variable_scope("two",reuse=True): # 报错,尽管reuse=True,但这是在变量空间two,函数只能在该对应空间选择定义过的变量,two空间没有name为a的变量
a4 = tf.get_variable("a",[1])