第1关:生成张量 - Variable 、constant与placeholder方法
任务描述
本关任务:利用TensorFlow中的变量 (Variable类) 编写一个能计算表达式1+…+…+n的值的小程序 (n的值由TensorFlow中的常量constant类给出) 。
相关知识
以下将讲述完成本实训所需要的基础知识。
####张量
张量(tensor)是TensorFlow中的核心数据单位。张量的概念由标量,向量与矩阵扩展而来。张量原本是个数学概念,在编程语言中大家可以将张量理解为任意维的数组。0维张量对应着标量,1维张量对应着向量,2维张量则对应着矩阵。
TensorFlow使用numpy阵列来表示张量的值。
以下是一些例子:
3. # 0维张量,即标量
[1., 2., 3.] # 1维张量,即向量
[[1., 2., 3.], [4., 5., 6.]] # 2维张量,即矩阵
[[[1., 2., 3.]], [[7., 8., 9.]]] # 3维张量
计算图
计算图是TensorFlow中非常重要的概念,计算图由两类对象组成:
操作:操作描述了张量的计算与修改。在图中被表示为节点。
张量:他们代表流经图的值。在图中表示边。
接下来看一个计算图的例子:
import tensorflow as tf
a = tf.constant(3.0)
b = tf.constant(4.0)
total = a + b
这三行语句会被转化为如下的计算图:
可以利用TensorBoard将TensorFlow代码转化为这样的可视图。由于TensorBoard的使用超过了本实训的范围,所以不过多展开。
至此我们也明白了TensorFlow这个名词的来源,Tensor指的是张量,而Flow,指的则是计算图中的数据流。
TensorFlow的程序结构
TensorFlow的程序可以看作独立的两部分:
- 构建计算图
- 运行计算图
TensorFlow程序中可以由不止一张计算图构成,但这超过了本实训的范围。所以不过多展开。
所有Tensor的声明以及操作的使用都会在默认图中构建对应边和节点。
注意在构建计算图时,我们是无法获取任意张量的值的。
计算图模型为TensorFlow提供了如下优势:
- 并行处理
- 分布式处理
- 编译
- 可移植性
运行计算图
当我们需要获取张量的值时,需要先实例化一个tensorflow.Session对象(之后简称Session)。
我们可以调用Session.run(tensor)函数以获取tensor的值,如下:
import tensorflow as tf
a = tf.constant(3.0)
b = tf.constant(4.0)
total = a + b
sess = tf.Session()
print(sess.run(total))
其中最后一行会输出如下的值:
7.0
我们也可以使用字典传入多个参数以获取多个张量的值,如下:
import tensorflow as tf
a = tf.constant(3.0)
b = tf.constant(4.0)
total = a + b
sess = tf.Session()
print(sess.run({'ab':(a, b), 'total':total}))
其中最后一条语句会打印出以下结果:
{'total': 7.0, 'ab': (3.0, 4.0)}
不过在实例化Session之后,我们必须要先初始化需要用到的所有变量。最简单的办法是使用tensorflow.global_variables_initializer()函数,这个函数会返回一个初始化所有变量的操作,使用Session运行此操作可以初始化所有的变量,如:
import tensorflow as tf
省略变量声明
sess = tf.Session()
sess.run(tf.global_variables_initializer())
constant方法
虽然之前说过Tensor是TensorFlow中的基本运算单元,但在TensorFlow中,Tensor对象并没有值。在编程中使用的三种可以表示有值的Tensor的类型是,tf.Varibale,tf.constant以及tf.placeholder。他们可以看作特殊类型的张量。
他们之间的区别是,Variable在一次运行过程中可以改变值,而其他的张量均不能那么做。constant与placeholder的区别是,后者可以在运行时再确定值,而前者必须在构建图时就确定值。
constant方法的原型如下:
tf.constant(
value,
dtype=None,
shape=None,
name='Const',
verify_shape=False
)
除了第一个参数value之外,其余的参数都是可选参数。
如之前所说的一样,张量值由numpy阵列表示,所以参数value的值可以为[1,2,3,4,5],[[22,32],[32,4]]等等。
dtype参数表明了数据类型。不指定这个参数时,会根据value来推断合适的类型。参见的数据类型有tf.float32,tf.int32等等。
其他3个参数暂时还不会用到,这里先跳过。
使用tf.constant声明张量很简单,只需要填入value值就好了,如下:
constant = tf.constant([1, 2, 3])
placeholder
placeholder和constant最大的区别是,placeholder可以等到开始运算时才被赋值,这使得计算多了很多灵活性。
placeholder的原型如下:
tf.placeholder(
dtype,
shape=None,
name=None
)
dtype指明了数据类型,shape指明了之后将要被填入的值的形状,如果不指明这个参数的话,那么placeholder的形状将由之后传入的值决定。name是这个张量的名字。
placeholder在参与运算时必须通过Session.run方法中的feed_dict参数获得初值。
比如说:
import tensorflow as tf
x = tf.placeholder(tf.float32, shape=(1024, 1024))
y = tf.matmul(x, x)
with tf.Session() as sess:
print(sess.run(y)) # 错误,因为x还没有获得初值。
rand_array = np.random.rand(1024, 1024)
print(sess.run(y, feed_dict={x: rand_array})) # 正确的
Variable
变量是具有可变性和持久性的张量,可变性指的是变量的值在Session.run()的过程中可以被改变,持久性指的是变量值的变化在多个Session.run()之间是可见的。
创建变量的方法是像之前一样的,是用tf.Variable()函数,但是因为Varibale在TensorFlow中是个对象,所以这其实是个对象的初始化函数。
Varibale的初始化函数的参数比较多,所以这里直接看例子:
w=tf.Variable([1,2,3],dtype=float32,name=“myVariable”)
这将会创建一个类型为float32,值为[1,2,3],名字为myVariable的变量。
获取张量的值
在Session对象已被实例化,且需要的变量都被初始化的之后。
可以通过Session.run()方法运行操作或变量的值。但如果参数只有一个的话,那么可以使用eval()方法会比较简便:
constant = tf.constant([1, 2, 3])
tensor = constant * constant
print(tensor.eval())
如上,会打印出
[1,2,3]
对应的,可以这样获取placeholder:
p = tf.placeholder(tf.float32)
t = p + 1.0
t.eval() # 错误!p没有初始化
t.eval(feed_dict={p:2.0}) # 正确!因为p被初始化了
值得注意的是,不只是张量的值,操作也可以使用eval()方法,如下:
v=tf.Varibale(1)
sess=tf.Session()
sess.run(tf.global_variables_initializer())
tf.assign_add(v,tf.constant(1)).eval()
print(v.eval())
以上代码会输出:
2
assign_add是TensorFlow中的运算函数,会将第一个参数和第二个参数的值相加后赋值给第一个参数。类似于C语言中的+=。
张量之间的运算
与之前所说的一样,TensorFlow分为两部分,一部分是构建图,另外一部分是计算图,这里所说的运算都是操作。也就是图中的点。
注意要让操作生效必须要使用Session.run()方法或者上一节提到的eval()方法。
张量之间的常见运算如下:
编程要求
根据提示,在右侧编辑器补全sum函数,参数 a 是 Variable,参数 b 是 constant,记 value 为 b 的值。
你需要计算从1+…+value的值,并将其结果存储在a节点中。
提示:
- 获取张量的值可以使用eval()方法。
- 对变量赋值需要使用tf.assign()系列函数,注意TensorFlow的操作都要在使用Session.run()或eval()方法后才会生效。
- 可以先获取参数b的值value,之后使用一个循环计算1+…+value的值,并将其结果使用tf.assign()函数存储在a节点中。
第1关:生成张量 - Variable 、constant与placeholder方法参考代码
# -*- coding: utf-8 -*-
import tensorflow as tf
# 参数 a 是 Variable, 参数 b 是 constant, 记 value 为 b 的值
# 计算从1+..+value的值, 并将其存储在a节点中
def sum(a,b):
# 请在此添加代码 完成本关任务
# ********** Begin *********#
sess = tf.Session()
sess.run(tf.global_variables_initializer())
tf.assign(a, tf.constant(0)).eval()
value = b.eval()
for i in range(value):
tf.assign_add(a,tf.constant(i)).eval()
return a.eval()
# ********** End **********#
第2关:全0张量与全1张量的生成 - zeros方法和ones方法
参考代码:
# -*- coding: utf-8 -*-
import tensorflow as tf
# 输入参数 n 为一正整数 (大于1且小于100)
# 若 n 为偶数, 则返回形状为 [n+1,n-1] 的全0矩阵
# 若 n 为奇数, 则返回形状为 [n-1,n+1] 的全1矩阵
def getMatrix(n):
# 请在此添加代码 完成本关任务
# ********** Begin *********#
if n%2 == 0:
return tf.zeros([n+1, n-1])
else:
return tf.ones([n-1, n+1])
# ********** End **********#
第3关:生成带指定初值的张量 - fill方法
# -*- coding: utf-8 -*-
import tensorflow as tf
# 输入参数x为正整数,y为整数
# 需要生成一个所有元素初值均为y, 形状为x*x的矩阵
# 之后在将矩阵的对角线上的每个元素加1
# 然后若该矩阵有逆矩阵, 则返回该逆矩阵的行列式
# 否则返回0
def getMatrix(x,y):
# 请在此添加代码 完成本关任务
# ********** Begin *********#
A = tf.fill([x, x], y)
V1 = tf.ones([x])
V2 = tf.diag(V1)
#tf.linalg.det只能接受浮点或复数类型的张量为参数
A = tf.cast(A, tf.float32)
V2 = tf.cast(V2, tf.float32)
B = tf.add(A, V2)
if tf.linalg.det(B) != 0:
return tf.linalg.det(tf.linalg.inv(B)).eval()
else:
return 0
# ********** End **********#