TensorfFlow 实战Google深度学习框架读书笔记一:基础模块

1.TensorFlow数据模型-张量

1.1张量的概念

在TensorFlow程 序中,所有的数据都通过张量的形式来表示。
从功能角度上看,张量可以被简单理解为多维数组。

零阶张量 标量(scalar),即一个数
一阶张量 向量(vector),即一维数组
n阶张量 n维数组

但张量在TensorFlow中的实现并不是直接采用数组的形式,它只是对TensorFlow中运算结果的引用。在张量中并没有真正保存数字,它保存的是如何得到这些数字的计算过程。

import tensorflow as tf
a=tf.constant([1.0,2.0],name="a")  #tf.constant是一个计算,计算的结果为一个张量,保存在变量a中
b=tf.constant([2.0,3.0],name="b")
result=tf.add(a,b,name="add")
print(result)

输出

Tensor("add:0", shape=(2,), dtype=float32)

由上可知,运行并不会得到加法的结果,而会得到对结果的一个引用。

一个张量中主要保存了三个属性:名字(name)、维度(shape)和类型(type)。

  1. 张量和计算图上节点代表的结果是对应的。name属性以“node:src_output”的形式表示,node表示节点的名称,src_output表示当前张量来自节点的第几个输出。“add :0”就说明了result 这个张量是计算节点“ add ” 输出的第一个结果(编号从0开始)。
  2. shape属性描述张量的维度。可以通过result.get_shape函数来获取结果张量的维度信息。 shape=(2,)说明张量result是一个一维数组,数组长度为2。
  3. 每一个张量会有一个唯一的类型。TensorFlow 会对参与运算的所有张量进行类型的检查, 当发现类型不匹配时会报错。
import tensorflow as tf
a=tf.constant([1,2],name="a")  #把a的类型由实数变为整数
b=tf.constant([2.0,3.0],name="b")
result=tf.add(a,b,name="add")
print(result)

输出

TypeError: Input 'y' of 'Add' Op has type float32 that does not match type int32 of argument 'x'.

如果不指定类型, TensorFlow 会给出默认的类型。
比如不带小数点的数会被默认为int32 ,带小数点的会默认为float32 。
所以一般建议通过指定dtype 来明确指出变量或者常量的类型。

import tensorflow as tf
a=tf.constant([1,2],dtype=tf.float32,name="a")  #把a的类型指定为float32
b=tf.constant([2.0,3.0],name="b")
result=tf.add(a,b,name="add")
print(result)

输出

Tensor("add:0", shape=(2,), dtype=float32)

TensorFlow支持14种不同的类型,主要包括了实数(tf.float32,tf.float64),整数(tf.int8,tf.int16,tf.int32,tf.int64,tf.uint8),布尔型(tf.bool)和复数(tf.complex64,tf.complex128)

综上,那么constant的用法是什么样的?

tf.constant(value,dtype=None,shape=None,name=’Const’)

1.2张量的使用

1.对中间计算结果的引用

#使用张量记录中间结果
a=tf.constant([1.0,2.0], name='a') # 定义一个常量使用tf.constant方法
b=tf.constant([1.0,2.0], name='b') 
result = a+b 

#直接计算向量的和,可读性比较差
result=tf.constant([1.0,2.0], name='a')+tf.constant([1.0,2.0], name='b') 

2.计算图构造完后,用来获得结果

tf.Session().run(result)

2.TensorFlow计算模型-计算图

2.1计算图的概念

TensorFlow是一个通过计算图的形式来表述计算的编程系统。TensorFlow中的每一个计算都是计算图上的一个节点,而节点之间的边描述了计算之间的依赖关系。
下图展示了通过TensorBoard画出来的两个向量相加的计算图。

在这里插入图片描述
 上图中的每一个节点都是一个运算,而每一条边代表计算之间的依赖关系。如果一个运算的输入依赖于另一个运算的输出,那么这两个运算有依赖关系。
 在上图,a和b这两个常量不依赖任何其他计算,而add计算则依赖读取两个常量的取值,于是可以看到有一条从a到add的边和一条从b到add的边。
 没有任何计算依赖add的结果,于是代表加法的节点add没有任何指向其他节点的边。所有TensorFlow的程序都可以通过上图的计算图的形式表示,这就是TensorFlow的基本计算模型。

2.2计算图的使用

TensorFlow程序一般分为两个阶段:
1、定义计算图中所有的计算
2、在session中执行计算

在TensorFlow程序中,系统会自动维护一个默认的计算图,可以通过tf.get_default_graph()函数获取。以下代码展示了如何获取默认计算图以及如何查看一个运算所属的计算图:

import tensorflow as tf 
a=tf.constant([1.0,2.0], name='a') 
b=tf.constant([1.0,2.0], name='b') 
result = a+b 
# 通过a.graph可以查看张量所属的计算图,如果没有特别指定,则属于当前默认的计算图
print(a.graph is tf.get_default_graph())#查看运算是否属于默认计算图

输出

True

TensorFlow可以通过tf.Graph函数生成新的计算图。不同计算图上的张量和运算都不会共享。

import tensorflow as tf

g1=tf.Graph()
with g1.as_default():
    # 在计算图g1中定义变量'v',并设置初始值为0。
    v=tf.get_variable('v',initializer=tf.zeros_initializer()(shape = [1]))
    
g2=tf.Graph()
with g2.as_default():
    # 在计算图g2中定义变量'v',并设置初始值微1。
    v=tf.get_variable('v',initializer=tf.ones_initializer()(shape = [1]))

# 在计算图g1中读取变量'v'的取值
with tf.Session(graph=g1) as sess:
    tf.global_variables_initializer().run()
    with tf.variable_scope('',reuse=True):
        # 在计算图g1中,变量'v'的取值应该为0,下一行代码会输出[0.]。
        print(sess.run(tf.get_variable('v')))

# 在计算图g2中读取变量'v'的取值
with tf.Session(graph=g2) as sess:
    tf.global_variables_initializer().run()
    with tf.variable_scope('',reuse=True):
        # 在计算图g2中,变量'v'的取值应该为1,下一行代码会输出[1.]。
        print(sess.run(tf.get_variable('v')))

tensorflow中的计算图不仅可以用来隔离张量和计算,它还提供了管理张量和计算的机制。计算图可以通过tf.Graph.device函数来指定运行计算的设备,下面代码指定在GPU上运行加法计算:

g=tf.Graph()
# 指定计算运行的设备。
with g.device('/gpu:0'):
    result=a+b

在一个计算图中,可以通过集合(collection)来管理不同类别的资源。比如通过tf.add_to_collection函数可以将资源加入到一个或多个集合中,然后通过tf.get_collection获取集合里的资源。

tensorflow中自动管理了一些常用的集合,如下表:

集合名称 集合内容 使用场景
tf.GraphKeys.VARIABLES 所有变量 持久化tensorflow模型
tf.GraphKeys.TRAINABLE_VARIABLES 可学习的变量(一般指神经网络中的参数) 模型训练、生成模型可视化内容
tf.GraphKeys.SUMMARIES 日志生成相关的张量 tensorflow计算可视化
tf.GraphKeys.QUEUE_RUNNERS 处理输入的QueueRunner 输入处理
tf.GraphKeys.MOVING_AVERAGE_VARIABLES 所有计算了滑动平均值的变量 计算变量的滑动平均值

3.TensorFlow运行模型-会话

会话( session )来执行定义好的运算。会话拥有并管理TensorFlow 程序运行时的所有资源。所有计算完成之后需要关闭会话来帮助系统回收资源,否则就可能出现资源泄漏的问题。
TensorFlow中使用会话的模式一般有三种。

1.第一种需要明确调用会话生成函数和会话关闭函数。

sess=tf.Session()#创建一个会话
sess.run(...)#运行
sess.close()#关闭会话使得本次运行中是用到的资源可以被释放

例如

import tensorflow as tf
a = tf.constant([1.0,2.0],name="a")
b = tf.constant([2.0,3.0],name="b")
result = a + b
sess = tf.Session()#创建一个会话
print(sess.run(result))#运行
sess.close()#关闭会话使得本次运行中是用到的资源可以被释放

输出

[3. 5.]

使用这种模式时,在完成所有计算之后,需要明确调用Session.close函数来关闭会话并释放资源。然而,当程序因为异常而退出时,关闭会话的函数可能就不会被执行从而导致资源泄露。

2.为了解决异常退出时资源释放的问题,TensorFlow可以通过python的上下文管理器来使用会话。

with tf.Session() as sess:#创建一个会话,并通过python中的上下文管理器来管理这个会话
   sess.run(...)
#不需要调用sess.close()来关闭会话
#当上下文退出时会话关闭和资源释放也自动完成了

例如

import tensorflow as tf
a = tf.constant([1.0,2.0],name="a")
b = tf.constant([2.0,3.0],name="b")
result = a + b
with tf.Session() as sess:#创建一个会话,并通过python中的上下文管理器来管理这个会话
    print(sess.run(result))
#不需要调用sess.close()来关闭会话
#当上下文退出时会话关闭和资源释放也自动完成了

输出同上

3.指定默认会话
TensorFlow会自动生成一个默认的计算图,如果没有特殊指定,运算会自动加入这个计算图中。TensorFlow中会话也有类似的机制,但TensorFlow不会自动生成默认的会话,而是需要手动指定。
当默认的会话被指定之后,可以通过tf.Tensor.eval函数来计算一个张量的取值。

sess = tf.Session()
with sess.as_default():#创建一个会话,并通过python中的上下文管理器来管理这个会话
    print(result.eval())

以下代码也有相同功能

sess = tf.Session()

# 下面的两个命令有相同的功能。

print(sess.run(result))
print(result.eval(session=sess))
sess.close()

也可以通过tf.InteractiveSession函数省去将产生的会话注册为默认会话的过程,它直接构建默认会话。

sess = tf.InteractiveSession()
print(result.eval())
sess.close()

4.其他基础知识

1.矩阵乘法

a = tf.matmul(x,w1)

2.变量
通过tf.Variable声明,需要指定初始值。

TensorFlow中,一个变量的值在被使用之前,需要被显式的初始化。

#声明一个2*3矩阵变量
import tensorflow as tf
weights = tf.Variable(tf.random_normal([2,3],stddev=2,mean=0))#矩阵元素满足正态分布,标准差为2,均值为0
biases = tf.Variable(tf.zeros([1,3]))
print(weights)#<tf.Variable 'Variable:0' shape=(2, 3) dtype=float32_ref>
print(biases)
sess = tf.Session()
sess.run(weights.initializer)#变量使用前,必须显式初始化
sess.run(biases.initializer)
print(sess.run(weights))#变量和张量一样,也要用sess.run()运行
print(sess.run(biases))
sess.close()

tensorflow随机生成函数:

函数名称 随机数分布 主要参数
tf.random_normal 正态分布 平均值、标准差、取值类型
tf.truncated_normal 正态分布,但如果随机出来的值偏离平均值超过2个标准差,那么这个数将会被重新随机 平均值、标准差、取值类型
tf.random_uniform 均匀分布 最小、最大取值,取值类型
tf.random_gamma Gamma分布 形状参数alpha、尺度参数beta、取值类型

tensorflow常数生成函数:

函数名称 功能 样例
tf.zeros 产生全0的数组 tf.zeros([2, 3], int32) >[[0, 0, 0] , [0 , 0, 0]]
tf.ones 产生全1的数组 tf.ones([2, 3], int32) >[[1, 1,1] , [1 , 1, 1]]
tf.fill 产生全为给定数字的数组 tf.fill([2, 3], 9) >[[9, 9,9] , [9 , 9, 9]]
tf.constant G产生一个给定值的常量 tf.constant([1,2,3]) >[1,2,3]

神经网络前向传播算法 神经网络前向传播算法
图中实现程序如下:

#通过常量实现上图前向传播过程
import tensorflow as tf
w1 = tf.constant([[0.2,0.1,0.4],[0.3,-0.5,0.2]])#声明w1,w2变量,通过seed参数设置了随机数种子,保证每次运行得到的结果一样
w2 = tf.constant([[0.6],[0.1],[-0.2]])
x=tf.constant([[0.7,0.9]])#注意这里不是x=tf.constant([0.7,0.9])#这里x是1*2矩阵
a = tf.matmul(x,w1)
y = tf.matmul(a,w2)
sess = tf.Session()
#sess.run(w1.initializer)
#sess.run(w2.initializer)
print(sess.run(y))
sess.close()

输出

[[0.11600002]]

若上述过程用的是变量而不是常量,则需要sess.run(w.initializer)进行初始化。
除了sess.run(w.initializer)以外,还有另一种变量初始化方式:

#通过变量实现前向传播过程
import tensorflow as tf
w1 = tf.Variable(tf.random_normal([2,3],stddev=1,seed=1))#声明w1,w2变量,通过seed参数设置了随机数种子,保证每次运行得到的结果一样
w2 = tf.Variable(tf.random_normal([3,1],stddev=1,seed=1))
x=tf.constant([[0.7,0.9]])#注意这里不是x=tf.constant([0.7,0.9])#这里x是1*2矩阵
a = tf.matmul(x,w1)
y = tf.matmul(a,w2)
sess = tf.Session()
init_op = tf.global_variables_initializer()#初始化所有变量
sess.run(init_op)
print(sess.run(y))
sess.close()

输出

[[3.957578]]

变量是特殊的张量。也有,名字,维度,类型等属性。
变量的类型是不可改变的,一个变量在构建之后,它的类型就不能再改变了。

w1=tf.Variable(tf.random_normal([2,3],stddev=1),name="w1")
w2=tf.Variable(tf.random_normal([2,3],stddev=1,dtype=tf.float64),name="w2")
w1.assign(w2)#tf.assign(state,new_value)#这个操作是:赋值操作。将new_value的值赋值给state变量,update只是一个用于sess的变量

输出

ValueError: Incompatible type conversion requested to type 'float32' for variable of type 'float64_ref'

维度再程序运行中是有可能改变的,但是需要通过设置参数validate_shape=False。
tf.assign(ref, value, validate_shape = None, use_locking = None, name=None)
更改后

w1=tf.Variable(tf.random_normal([2,3],stddev=1),name="w1")
w2=tf.Variable(tf.random_normal([2,3],stddev=1,dtype=tf.float64),name="w2")
tf.assign(w1,w2,validate_shape=False)#validate_shape:一个可选的 bool。默认为 True。如果为 true, 则操作将验证 "value" 的形状是否与分配给的张量的形状相匹配;如果为 false, "ref" 将对 "值" 的形状进行引用。

3.占位符placeholder
TensorFlow提供了placeholder机制用于提供输入数据。placeholder相当于定义了一个位置,这个位置中的数据在程序运行时再指定。这样在程序中就不需要生成大量的常量来提供数据,而值需要将数据通过placeholder传入TensorFlow计算图。

定义placeholder时,这个位置上的数据类型是需要指定的,而且placeholder的类型不可以改变,placeholder中数据的维度信息可以根据提供的数据推导出,所以不一定要给出。

import tensorflow as tf
w1 = tf.Variable(tf.random_normal([2,3],stddev=1,seed=1),name="w1")#标准差为1
w2 = tf.Variable(tf.random_normal([3,1],stddev=1,seed=1),name="w2")
x = tf.placeholder(tf.float32,name="input")#x为张量
a = tf.matmul(x,w1)
y = tf.matmul(a,w2)
sess = tf.Session()
sess.run(tf.global_variables_initializer())
print(sess.run(y,feed_dict={x:[[0.7,0.9]]}))#[[3.957578]]
print(sess.run(y,feed_dict={x:[[0.7,0.9],[0.1,0.4],[0.5,0.8]]}))#[[3.957578 ][1.1537654][3.1674924]]
sess.close()

上述程序替换了原来通过常量定义的输入x。需要提供一个feed_dict来指定x的取值。deed_dict是一个字典,在字典中需要给出每个用到的placeholder的取值。

tip:tf.placeholder 与 tf.Variable区别
https://blog.csdn.net/HHTNAN/article/details/78990618
https://blog.csdn.net/lanchunhui/article/details/61712830

猜你喜欢

转载自blog.csdn.net/qq_38375534/article/details/87459523