一、张量
我们知道, 计算图中的一个节点可以表示一个张量或者一个操作符
那么张量是什么?
张量,可理解为一个 n 维数值阵列
每个张量的维度单位用阶来描述,零阶张量是一个标量,一阶张量是一个向量,二阶张量是一个矩阵
所以标量、向量(矢量)和矩阵等都是特殊类型的张量
TensorFlow 支持以下三种类型的张量:
1、常量:常量是其值不能改变的张量。
2、变量:当一个量在会话中的值需要更新时,使用变量来表示。例如,在神经网络中,权重需要在训练期间更新,可以通过将权重声明为变量来实现。变量在使用前需要被显示初始化。
3、占位符:用于将值输入 TensorFlow 图中。它们可以和 feed_dict 一起使用来输入数据。在训练神经网络时,它们通常用于提供新的训练样本。在会话中运行计算图时,可以为占位符赋值。这样在构建一个计算图时不需要真正地输入数据。需要注意的是,占位符不包含任何数据,因此不需要初始化它们。
二、TF常量型张量
import tensorflow as tf
“常规操作”
1、声明一个标量常量:
t_1 = tf.constant(4)
with tf.Session() as sess:
print(sess.run(t_1))
4
2、声明一个向量常量:
t_2 = tf.constant([1,3])
with tf.Session() as sess:
print(sess.run(t_2))
[1 3]
t_2 = tf.constant([4,3,2])
with tf.Session() as sess:
print(sess.run(t_2))
[4 3 2]
3、创建一个所有元素为零的张量,可以使用 tf.zeros() 函数。这个语句可以创建一个形如 [M,N] 的零元素矩阵,数据类型(dtype)可以是 int32、float32 等:
tf.zeros([M,N],tf.dtype)
例如 :
zero_t = tf.zeros([2,3],tf.int32)
with tf.Session() as sess:
print(sess.run(zero_t))
[[0 0 0]
[0 0 0]]
4、创建一个所有元素都设为 1 的张量。下面的语句即创建一个形如 [M,N]、元素均为 1 的矩阵:
tf.ones([M,N],tf,dtype)
ones_t = tf.ones([2,3],tf.int32)
with tf.Session() as sess:
print(sess.run(ones_t))
[[1 1 1]
[1 1 1]]
5、还可以创建与现有 Numpy 数组或张量常量具有相同形状的张量常量,如下所示:
tf.zeros_like(t_2)
<tf.Tensor 'zeros_like:0' shape=(3,) dtype=int32>
tf.ones_like(t_2)
<tf.Tensor 'ones_like:0' shape=(3,) dtype=int32>
6、在一定范围内生成一个从初值到终值等差排布的序列:
tf.linspace(start,stop,num)
相应的值为 (stop-start)/(num-1)。例如:
range_t = tf.linspace(2.0,5.0,5) #从2到5 切成5份
with tf.Session() as sess:
print(sess.run(range_t))
[2. 2.75 3.5 4.25 5. ]
7、从开始(默认值=0)生成一个数字序列,增量为 delta(默认值=1),直到终值(但不包括终值):
tf.range(start,limit,delta)
下面给出实例:
range_t = tf.range(10)
with tf.Session() as sess:
print(sess.run(range_t))
#Result:[0 1 2 3 4 5 6 7 8 9]
[0 1 2 3 4 5 6 7 8 9]
range_t = tf.range(0,10,1)
with tf.Session() as sess:
print(sess.run(range_t))
[0 1 2 3 4 5 6 7 8 9]
“随机操作”
TensorFlow 允许创建具有不同分布的随机张量
1、使用以下语句创建一个具有一定均值(默认值=0.0)和标准差(默认值=1.0)、形状为 [M,N] 的正态分布随机数组:
t_random = tf.random_normal([2,3], mean=2.0, stddev=4,seed=12)
with tf.Session() as sess:
print(sess.run(t_random))
[[ 0.25347447 5.37991 1.9527606 ]
[-1.5376031 1.2588985 2.8478067 ]]
2、创建一个具有一定均值(默认值=0.0)和标准差(默认值=1.0)、形状为 [M,N] 的截尾正态分布随机数组:
t_random = tf.truncated_normal([1,5], stddev=2,seed=12)
with tf.Session() as sess:
print(sess.run(t_random))
[[-0.87326276 1.689955 -0.02361972 -1.7688016 -3.87749 ]]
3、要在种子的 [minval(default=0),maxval] 范围内创建形状为 [M,N] 的给定伽马分布随机数组,请执行如下语句:
t_random = tf.random_uniform([2,3], maxval=4,seed=12)
with tf.Session() as sess:
print(sess.run(t_random))
[[2.54461 3.6963658 2.7051091]
[2.0085006 3.8445983 3.5426888]]
4、(不起作用好像)要将给定的张量随机裁剪为指定的大小,使用以下语句:
图像分类中,在深度学习的训练时将图片的随机剪裁(random crop)已经成为很普遍的数据扩充(data augmentation)方法,随机剪裁(缩写为:IRC)不但提高了模型精度,也增强了模型稳定性
tf.random_crop(t_random,[2,5],seed=12)
<tf.Tensor 'random_crop:0' shape=(2, 5) dtype=float32>
这里,t_random 是一个已经定义好的张量。这将导致随机从张量 t_random 中裁剪出一个大小为 [2,5] 的张量。
5、随机重新排序
很多时候需要以随机的顺序来呈现训练样本,可以使用 tf.random_shuffle() 来沿着它的第一维随机排列张量。如果 t_random 是想要重新排序的张量,使用下面的代码:
with tf.Session() as sess:
print(sess.run(t_random))
print("随机重新排序后")
t = tf.random_shuffle(t_random)
with tf.Session() as sess:
print(sess.run(t))
[[2.54461 3.6963658 2.7051091]
[2.0085006 3.8445983 3.5426888]]
随机重新排序后
[[2.0085006 3.8445983 3.5426888]
[2.54461 3.6963658 2.7051091]]
6、随机生成的张量受初始种子值的影响
要在多次运行或会话中获得相同的随机数,应该将种子设置为一个常数值。当使用大量的随机张量时,可以使用 tf.set_random_seed() 来为所有随机产生的张量设置种子。以下命令将所有会话的随机张量的种子设置为 54:
tf.set_random_seed(54)
种子只能有整数值
三、TF变量型张量
tensorflow中的变量是承载和更新参数的对象
变量通常在神经网络中表示权重和偏置
此外还可以保存或恢复变量
变量是由tf.Variable()语句创建的
它必须初始化, 可以用常量来初始化变量,也可以用一个变量来初始化另一个变量
常量初始化变量
下面的代码中创建了两个不同的张量变量 t_a 和 t_b。两者将被初始化为形状为 [50,50] 的随机均匀分布,最小值=0,最大值=10:
rand_t = tf.random_uniform([50,50],0,10,seed=0)
t_a = tf.Variable(rand_t)
t_b = tf.Variable(rand_t)
注意:变量通常在神经网络中表示权重和偏置。
下面的代码中定义了两个变量,分别是权重和偏置。权重变量使用正态分布随机初始化,均值为 0,标准差为 2,权重大小为 100×100。偏置由 100 个元素组成,每个元素初始化为 0。在这里也使用了可选参数名以给计算图中定义的变量命名:
weights = tf.Variable(tf.random_normal([100,100],stddev=2))
bias = tf.Variable(tf.zeros([100]), name = 'biases')
变量初始化变量
下面的语句将利用前面定义的权重变量来初始化 weight2:
weights2 = tf.Variable(weights.initial_value, name='w2')
赋予变量实际的意义
上面两种方式的初始化, 并不代表计算图中的变量已经被赋值了
我们之前说过, 计算图像是一张蓝图, 在此之前张量只被抽象定义,只有在会话时候, 才将张量赋予实际的意义
在会话时, 赋予常量实际的意义,是自动的; 而赋予变量实际的意义,还需要再加些东西
具体需要通过声明初始化操作对象来实现:
intial_op = tf.global_variables_initializer()
举个栗子, 希望程序实现从1数到10 :
import tensorflow as tf
#创建计算图
value = tf.Variable(0, name="value")#创建一个变量,并将其初始化为标量0:
one = tf.constant(1)
new_value = tf.add(value, one)#add和assign操作符仅仅是计算图中的节点,所以在会话运行前,它们不会执行
update_value = tf.assign(value, new_value)
#运行会话,完成计算图中定义的操作
initialize_var = tf.global_variables_initializer() #声明初始化操作对象, 用于计算图中变量的赋值
with tf.Session() as sess:
sess.run(initialize_var)
print(sess.run(value))
for _ in range(10):
sess.run(update_value)
print(sess.run(value))
0
1
2
3
4
5
6
7
8
9
10
程序解读: 这个栗子的计算图有四个节点,分别是value变量、one常量、add加法操作符以及assign赋值操作符.这个计算图要实现的功能是value和one通过add相加,得到的值流到assign操作符,让它再赋值回value. 运行会话时,由于变量需要显式初始化,所以需要声明初始化操作对象,然后让它run下来完成初始化
此外, 每个变量也可以在运行图中单独使用 tf.Variable.initializer 来初始化
import tensorflow as tf
#创建计算图
value = tf.Variable(0, name="value")#创建一个变量,并将其初始化为标量0:
one = tf.constant(1)
new_value = tf.add(value, one)#add和assign操作符仅仅是计算图中的节点,所以在会话运行前,它们不会执行
update_value = tf.assign(value, new_value)
#运行会话,完成计算图中定义的操作
#initialize_var = tf.global_variables_initializer() #声明初始化操作对象, 用于计算图中变量的赋值
with tf.Session() as sess:
sess.run(value.initializer)#变量在运行图中单独初始化,常量就不用了.
print(sess.run(value))
for _ in range(10):
sess.run(update_value)
print(sess.run(value))
0
1
2
3
4
5
6
7
8
9
10
保存变量
神经网络训练完后, 一般都需要保存训练好的参数,也就是我们所谓的权重和偏置, 其实际上就是变量, 所以我们要使用 Saver 类来保存变量,定义一个 Saver 操作对象:
saver = tf.train.Saver()
四、TF占位符型张量
介绍完常量和变量之后,我们来讲解最重要的张量——占位符
它是不需要初始化的
在会话中运行计算图时,可以为占位符赋值,通过会话对象中run里feed_dict
它用于将值输入计算图中,它和feed_dict一起来输入数据
run(fetches,feed_dict=None,options=None,run_metadata)
所以在训练神经网络时(会话),它们通常用于提供新的训练样本
如何定义一个占位符:
tf.placeholder(dtype,shape=None,name=None)
dtype 是占位符的数据类型,并且必须在声明占位符时指定
下面示例中, 定义一个占位符型张量x, 并计算 y=2*x,会话时使用 feed_dict 输入一个随机的 4×5 矩阵:
import tensorflow as tf
#计算图
x = tf.placeholder("float")#占位符
y = 2*x
data = tf.random_uniform([4,5], 10)#随机常量
#run时才算进入会话
with tf.Session() as sess:
print(data) #未进入会话
x_data = sess.run(data) #会话时才能取出它的值
print(x_data)#提出来了
print("\n\n")
print(sess.run(y, feed_dict = {x:x_data}))
Tensor("random_uniform_2:0", shape=(4, 5), dtype=float32)
[[9.789586 4.122238 2.5008888 2.8134599 2.4266639]
[3.33526 3.5702267 6.666023 1.2452259 3.4237428]
[6.941977 8.032328 2.8022385 8.071983 6.399656 ]
[6.231288 2.589786 1.2040987 8.232471 1.4575834]]
[[19.579172 8.244476 5.0017776 5.6269197 4.8533278]
[ 6.67052 7.1404533 13.332046 2.4904518 6.8474855]
[13.883954 16.064655 5.604477 16.143967 12.799312 ]
[12.462576 5.179572 2.4081974 16.464943 2.9151669]]
代码解释:
计算图一共有4个节点,分别是占位型张量x、常数型张量2、乘法操作符y以及单独的常数型张量data. 会话时取出data的值赋值给x_data,然后放入feed_dict再一次进入会话赋值给占位符x, 提取y的运行结果
run的时候才算进入会话
所以第一次run只是fetch data里的数据, 第二次才开始fetch y进行乘法运算
五、拓展阅读
拓展1
很多时候需要大规模的常量张量对象;在这种情况下,为了优化内存,最好将它们声明为一个可训练标志设置为 False 的变量:
large_array = [1,2,3] #假如时一个很大的数组
t_large = tf.Variable(large_array,trainable=False)
with tf.Session() as sess:
sess.run(t_large.initializer)
print(sess.run(t_large))
[1 2 3]
trainable:如果为True,则会默认将变量添加到图形集合GraphKeys.TRAINABLE_VARIABLES中。此集合用于优化器Optimizer类优化的的默认变量列表【可为optimizer指定其他的变量集合】,也就是要训练的变量列表。
拓展2
TensorFlow 被设计成与 Numpy 配合运行,因此所有的 TensorFlow 数据类型都是基于 Numpy 的。
使用 tf.convert_to_tensor() 可以将给定的值转换为张量类型,并将其与 TensorFlow 函数和运算符一起使用。该函数接受 Numpy 数组、Python 列表和 Python 标量,并允许与张量对象互操作。
拓展3
下表列出了 TensorFlow 支持的常见的数据类型:
拓展4
for i in range(1,10,1):
print(i)
1
2
3
4
5
6
7
8
9
import numpy as np
for i in np.arange(1,10,1):
print(i)
1
2
3
4
5
6
7
8
9
TensorFlow 序列不可迭代。试试下面的代码:
for i in tf.range(10)
File "<ipython-input-30-83ab65fa2626>", line 1
for i in tf.range(10)
^
SyntaxError: invalid syntax