回忆一下,我们python语言中,变量的类型有哪些?有多少种数据结构?变量类型有整型,字符串,浮点型,bool等等,数据结构有列表,元组,字典等。
那么
在tensorflow2.0框架当中,有哪些变量类型呢?有哪些数据结构呢?
答案是
在tensorflow2.0中,只存在一种数据结构,这种数据结构英文名叫tensor,中文名叫张量。
有些人就会问了,如果是只存在一种数据结构,那谁来表示字典,元组,列表这些东西呢?
答案是
不需要,tensorflow2.0在进行数据运算的时候,只用到张量这种数据结构就行了。因为张量的数据结构方便计算和使用。如果非要用到字典的操作,完全可以交给python语言来实现。
张量可以存储很多很多信息,得力于它多变的数据结构,因为如何有需要,它的维度可以无限扩张。对于一维张量,数据结构类似于我们的一维列表,对于二维张良,数据结构类似于我们列表里面嵌套着列表,对于三维张量,数据结构类似于我们列表里面嵌套着的列表的元素还是列表。
然后,重点是
这些列表的元素的数据类型可以是python中所有的数据类型,只是为了方便运算,一般元素的数据类型就是整型或者浮点型或者布尔型而已,千万别以为它不可以是别的类型哦。
好的,说了那么多张量,那我们该如何创建张量呢?你明白张量的本质之后,你就会明白,张量的值,当然是可以在创建的时候就初始化了,也可以创建之后不初始化,只指定元素的类型和张量的数据结构,到时候我们想用的时候直接按照指定的元素类型和数据结构shape给它传递值就行。
然后创建的张量初始化之后,这些值能不能被改变,如果能被改变,我们称这种张量为可变张量,简称变量,如果不可以改变,我们称这种张量为不变张量,简称常量。不变张量和可变张量的创建不一样,其实就是两个不同函数而已。
import tensorflow as tf
# 创建不变张量
a = tf.constant(value=2, dtype=tf.float32, shape=(2, 3), name='Const1')
"""
参数解析:
tf.Tensor(
[[2. 2. 2.]
[2. 2. 2.]], shape=(2, 3), dtype=float32)
如果对参数shape进行了指定,那么结果就是元素是value的一个张量
"""
b = tf.constant(value=5)
"""
如果不指定dtype和shape,那么结果tensor就由value值来确定它的dtype和shape
tf.Tensor(5, shape=(), dtype=int32),
shape=(),表示没有维度
shape=(6,),表示维度只有一个维度,在这个维度上面有6个元素,shape的值是一个元组,元组中只包含一个元素时,需要在元素后面添加逗号,否则括号会被当做运算符使用
shape=(28, 28, 3),表示有三个维度,在第一个维度上面有28个元素,在第二个维度上面有28个元素,在第三个维度上面有3个元素,
"""
print(a)
print(b)
# 明白了constant函数的使用,其它创建不变张量的方法我都不想使用,没必要,知道这个方法,我就可以创建出自己想要的一切数据了
另外一个方面也是常用的一个方面,就是创建随机分布数据,见代码分析
import tensorflow as tf
# 均匀分布随机
a = tf.random.uniform(shape=(5, 3), minval=0, maxval=1, dtype=tf.float32, name='a1')
"""
创建均匀分布数据,什么是均匀分布可参见:https://baike.baidu.com/item/%E5%9D%87%E5%8C%80%E5%88%86%E5%B8%83/954451?fr=aladdin
"""
print(a)
b = tf.random.normal(shape=(5, 3), mean=0.0, stddev=1.0, dtype=tf.float32, seed=1.0, name='b')
"""
创建标准正太分布数据, mean=0.0, stddev=1.0,默认就是标准正太分布
https://baike.baidu.com/item/%E6%AD%A3%E6%80%81%E5%88%86%E5%B8%83/829892?fr=aladdin
"""
print(b)
c = tf.random.truncated_normal((5, 5), mean=0.0, stddev=1.0, dtype=tf.float32, name="c")
"""
创建标准正太分布数据, mean=0.0, stddev=1.0,并采取2sigma原则
对于sigma原则可参见:https://zhidao.baidu.com/question/1994458617275793107.html
"""
print(c)
现在开始解释如何创建可变张量,看代码注释,看代码注释,看代码注释,
import tensorflow as tf
a = tf.Variable(initial_value=tf.random.truncated_normal(shape=(2,)))
"""
该函数必须指定初始化值,初始化值就是前面所描述的不变张量,也可以是数值,也可以是数组
<tf.Variable 'Variable:0' shape=(2,) dtype=float32, numpy=array([-0.00675302, -1.3904084 ], dtype=float32)>
"""
print(a)
#############################*我是分割线###########################
接下来介绍张量的切片操作,其实张量最具有艺术感的行为就是切片行为了。你可以把所有完整的数据保存在一个张量里面,然后在使用的时候只是取出一点点所需的东西即可,这种本质赋予了张量强大的功能。
那
如何对张量进行切片操作呢?我们先来看一种极端情形,就是我只需要切一个元素出来,这种我们称之为索引,当我们不只是需要一个元素的时候,我们称之为切片。
索引是怎么一回事呢?看以下代码分析
import tensorflow as tf
a = tf.Variable(initial_value=tf.random.truncated_normal(shape=(3, 3, 3), seed=1.0))
"""
<tf.Variable 'Variable:0' shape=(3, 3, 3) dtype=float32, numpy=
array([[[-0.8113182 , 1.4845988 , 0.06532937],
[ 0.0992484 , 0.6396971 , 1.6108712 ],
[ 0.16353562, -1.5157056 , 1.3587774 ]],
[[ 0.5417414 , -0.86009884, -0.0040246 ],
[ 0.55171245, -0.13107552, -0.04481387],
[ 0.6709832 , -0.20888524, 0.00542188]],
[[ 0.31266254, 0.5998527 , -0.36332107],
[-0.07205155, -0.5527937 , 0.10289733],
[-0.67590594, 0.2866583 , 0.3215887 ]]], dtype=float32)>
"""
# 索引取出一个数据
b = a[0, 0, 0] # tf.Tensor(-0.8113182, shape=(), dtype=float32)取出第一个数据
c = a[0, 0, 1] # tf.Tensor(1.4845988, shape=(), dtype=float32)取出第二个数据
d = a[0, 0, 2] # tf.Tensor(0.06532937, shape=(), dtype=float32)取出第三个数据
# 如果这样子一个一个取数据,太慢了,能不能一次性全部取出来呢?上面一个一个叫索引,我们现在使用切片的方式。索引是用下标并且使用逗号隔开
e = a[0, 0, 0:3] # tf.Tensor([-0.8113182 1.4845988 0.06532937], shape=(3,), dtype=float32)
# 切片操作通过:来实现,表示选择多个索引下标,0:3表示选择0、1、2索引下标,忽略索引# # 下标表示选择该维度下面的全部元素,不建议使用省略号来表示多个冒号,这种表示方法很不明确
print(e)
#############################*我是分割线###########################
接下来分析一些维度变换,看代码注释分析,看代码注释分析,看代码注释分析,
import tensorflow as tf
a = tf.Variable(initial_value=tf.random.truncated_normal(shape=(3, 3, 3), seed=1.0))
b = tf.reshape(tensor=a, shape=(27,))
"""
各种维度变换学习这一钟就够了,可以实现增加一个维度和减少一个维度的工作,也可以改变维度
b = tf.Tensor(
[-0.8113182 1.4845988 0.06532937 0.0992484 0.6396971 1.6108712
0.16353562 -1.5157056 1.3587774 0.5417414 -0.86009884 -0.0040246
0.55171245 -0.13107552 -0.04481387 0.6709832 -0.20888524 0.00542188
0.31266254 0.5998527 -0.36332107 -0.07205155 -0.5527937 0.10289733
-0.67590594 0.2866583 0.3215887 ], shape=(27,), dtype=float32)
"""
# 增加一个维度
c = tf.reshape(b, (27, 1))
"""
c = tf.Tensor(
[[-0.8113182 ]
[ 1.4845988 ]
[ 0.06532937]
[ 0.0992484 ]
[ 0.6396971 ]
[ 1.6108712 ]
[ 0.16353562]
[-1.5157056 ]
[ 1.3587774 ]
[ 0.5417414 ]
[-0.86009884]
[-0.0040246 ]
[ 0.55171245]
[-0.13107552]
[-0.04481387]
[ 0.6709832 ]
[-0.20888524]
[ 0.00542188]
[ 0.31266254]
[ 0.5998527 ]
[-0.36332107]
[-0.07205155]
[-0.5527937 ]
[ 0.10289733]
[-0.67590594]
[ 0.2866583 ]
[ 0.3215887 ]], shape=(27, 1), dtype=float32)
"""
print(c)
另外需要学习的一个函数是tf.transpose,它可以交换张量的维度,看下面代码注释
import tensorflow as tf
a = tf.Variable(initial_value=tf.random.truncated_normal(shape=(32, 28, 28, 3), seed=1.0))
b = tf.transpose(a=a, perm=(1, 2, 3, 0)) # 下标小数字代表移动之后的位置
print(a.shape) # (32, 28, 28, 3)
print(b.shape) # (28, 28, 3, 32)
#############################*我是分割线###########################
我们现在知道切片和维度变换的操作,如果我们有个需求,就是将多个输出变成一个输出,我们就需要把多个输出进行整合,这种整合操作就是将张量进行合并的操作。这种操作主要有两种,一种是concat,它不会增加维度,看下面代码注释分析:
import tensorflow as tf
a = tf.constant([[1.0, 2.0], [3.0, 4.0]]) # (2, 2)
b = tf.constant([[5.0, 6.0], [7.0, 8.0]]) # (2, 2)
c = tf.constant([[9.0, 10.0], [11.0, 12.0]]) # (2, 2)
d = tf.concat(values=[a, b, c], axis=0) # 在第一个维度上进行连接
e = tf.concat(values=[a, b, c], axis=1) # 在第二个维度上进行连接
print(d)
print(e)
"""
tf.Tensor(
[[ 1. 2.]
[ 3. 4.]
[ 5. 6.]
[ 7. 8.]
[ 9. 10.]
[11. 12.]], shape=(6, 2), dtype=float32)
tf.Tensor(
[[ 1. 2. 5. 6. 9. 10.]
[ 3. 4. 7. 8. 11. 12.]], shape=(2, 6), dtype=float32)
"""
另外一种是是堆叠,会增加维度,看下面代码分析
import tensorflow as tf
a = tf.constant([[1.0, 2.0], [3.0, 4.0]]) # (2, 2)
b = tf.constant([[5.0, 6.0], [7.0, 8.0]]) # (2, 2)
c = tf.constant([[9.0, 10.0], [11.0, 12.0]]) # (2, 2)
d = tf.stack(values=[a, b, c], axis=0) # 增加一个第0维度,并在这个维度上面堆叠(常用)
e = tf.stack(values=[a, b, c], axis=1) # 增加一个第1维度,并在这个维度上面堆叠
i = tf.stack(values=[a, b, c], axis=2) # 增加一个第2维度,并在这个维度上面堆叠
print(d)
print(e)
print(i)
到这里所有张量的结构分析和总结就到这里,也许你跟我一样动力,也许你一刷而已,不过咩关系,总有一天你会吃亏然后再来把它们弄懂的,爱你哟么么哒