TensorFlow2.0(一):基本数据结构——张量

 

1引言¶

 

TensorFlow2.0版本已经发布,虽然不是正式版,但预览版都发布了,正式版还会远吗?相比于1.X,2.0版的TensorFlow修改的不是一点半点,这些修改极大的弥补了1.X版本的反人类设计,提升了框架的整体易用性,绝对好评!

赶紧来学习一波吧,做最先吃螃蟹的那一批人!先从TensorFlow的基本数据结构——张量(tensor)开始。

 

2 创建¶

 

2.1 constant()方法¶

In [1]:
import tensorflow as tf
In [2]:
tf.constant(1)  # 创建一个整型张量
Out[2]:
In [3]:
tf.constant(1.)  # 创建一个浮点型张量
Out[3]:
In [4]:
tf.constant(2., dtype=tf.double)  # 创建的同时指定数据类型
Out[4]:
In [5]:
tf.constant([[1.,2.,3.],[4.,5.,6.]])  # 通过传入一个list参数创建
Out[5]:
 

如果输入的数据与指定的数据类型不相符,会产生以下异常:
TypeError: Cannot convert provided value to EagerTensor. Provided value: 2.1 Requested dtype: int32

 

2.2 convert_to_tensor()方法¶

In [9]:
import numpy as np
In [10]:
tf.convert_to_tensor(np.ones([2, 3]))
Out[10]:
In [11]:
tf.convert_to_tensor(np.ones([2, 3]))
Out[11]:
In [12]:
tf.convert_to_tensor([[2.,3.],[3., 4.]])
Out[12]:
 

2.3 创建元素为指定值的tensor¶

 

如果你熟悉numpy创建数组的方法,你一定见过zeros()、ones()等方法,TensorFlow中也有这些方法。

 

(1)zeros()与ones()

In [24]:
a = tf.zeros([2, 3, 3])  # 创建一个元素全为0,形状为[2, 3, 3]的tensor
In [25]:
a
Out[25]:
In [26]:
b = tf.ones([2, 3])  #  创建一个元素全为1,形状为[2, 3]的tensor
In [27]:
b
Out[27]:
 

(2)zeros_like()与ones_like

In [28]:
tf.zeros_like(b)  # 仿照b的shape创建一个全为0的tensor
Out[28]:
In [29]:
tf.ones_like(a)  # 仿照b的shape创建一个全为1的tensor
Out[29]:
 

(3)fill()

In [21]:
tf.fill([2,3],5)  # 创建元素全为5,形状为[2,3]的tensor
Out[21]:
 

2.4 随机初始化¶

 

在实际应用中,经常需要随机初始化元素服从某种分布的tensor,TensorFlow中也提供了这种功能。

(1)从指定正态分布中随机取值:tf.random.normal()。例如,随机初始化一个元素服从均值为1,方差为1的正态分布且形状为[2, 3]的tensor:

In [30]:
tf.random.normal([2, 3], mean=1, stddev=1) 
Out[30]:
 

(2)从指定的截断正态分布中随机取值:truncated_normal()。意思是从指定的正太分布中取值,但是取值范围在两个标准差范围内,也就是:[ mean - 2 stddev, mean + 2 stddev ]

In [31]:
tf.random.truncated_normal([2, 3], mean=1, stddev=1)
Out[31]:
 

(3)从指定均匀分布中随机取值:tf.random.uniform()。

In [32]:
tf.random.uniform([2, 3], minval=1, maxval=2) # 在1~2之间均匀分布
Out[32]:
 

3 索引¶

In [33]:
a = tf.convert_to_tensor(np.arange(80).reshape(2,2,4,5))
In [34]:
a
Out[34]:
 

3.1 基础索引¶

 

TensorFlow支持Python原生的基础索引方式,即多个方括号逐步索引取值:[idx][idx][idx],每个方括号对应一个维度。

In [35]:
a[0]  # 取第一个维度
Out[35]:
In [36]:
a[0][1]  # 同时筛选两个维度
Out[36]:
In [37]:
a[0][1][3][3]  # 同时对4个维度进行筛选
Out[37]:
 

这种索引数据的方法简单,易于理解,但是可读性差,只能按维度依次索引数据,也不能索引列。

 

3.2 numpy索引¶

 

TensorFlow也继承了numpy中的部分索引方式,如果对numpy索引方式不熟悉,可以查看我的前几篇博客。
(1)[idx1, idx2, idx3]
这种索引方式是在一个方括号内写下所有的索引,每个索引序号之间用逗号隔开。

In [38]:
a[1]  # 筛选第一维度,这跟基础索引一样
Out[38]:
In [39]:
a[1,1, 3]  # 同时帅选3个维度
Out[39]:
 

(2)冒号切片与步长:[start:end:step]

 

这种索引方式在Python原生的list类型中也是常见的,而且使用方法也是一样的。

In [40]:
a[1,:,0:2] # 对第1维度选第二块数据,对第二维度选所有数据,对第三维度选前两行
Out[40]:
In [41]:
a[1,:,0:2,0:4] # 继续上面的例子,对第4维度筛选去前4列
Out[41]:
In [42]:
a[1,:,0:2,0:4:2] # 对第4维度加上步长,每隔一个数据取一次
Out[42]:
 

也可以使用负值步长表示逆序索引,但要注意,负数步长时,原本的[start : end : step]也要跟着编程[end : start : step]:

In [43]:
a[1,:,0:2,4:0:-1]
Out[43]:
In [44]:
a[1,:,0:2,4:0:-2]
Out[44]:
 

在numpy和TensorFlow中还有“..."(三个英文句号)的使用,“..."用于表示连续多个维度全选:

In [45]:
a[1,...,0:4] # 等同于a[1, : , : ,0:4]
Out[45]:
In [46]:
a[0,0,...] # 等同于a[0,0,:,:]
Out[46]:
 

3.3 gather与gather_nd¶

 

gather与gather_nd是指TensorFlow通过gather()方法和gather_nd()方法提供的两种索引方式。在numpy中,可以通过嵌套list的方式来指定无规则的索引:

In [47]:
b = np.arange(20).reshape(4,5)
In [48]:
b[1, [0,3,4]] # 选取第2行的第1列、第4列、第5列
Out[48]:
array([5, 8, 9])
 

但是在TensorFlow中,这种索引方式并没有从numpy中继承下来,所以如果在Tensor中使用这种方式,会抛出以下异常:
TypeError: Only integers, slices (:), ellipsis (...), tf.newaxis (None) and scalar tf.int32/tf.int64 tensors are valid indices, got [0, 3, 4]

 

还好的是,在TensorFlow中通过gather()方法和gather_nd()方法提供了这种索引方法。

 

(1)gather()方法

In [54]:
tf.gather(b, axis=0, indices=[0, 2, 3]) # 选取第1行,第3行,第4行
Out[54]:
In [55]:
tf.gather(b, axis=1, indices=[0, 2, 3]) # 选取第1列,第3列,第4列
Out[55]:
 

仔细观察上面gather()方法例子,可以发现,第一个参数时数据源,还有两个参数中,axis指的是将要的维度,indices指的是需要选取的序号。

 

(2)gather_nd()

 

gather()方法一次只能对一个维度进行索引,gather_nd()方法可以同时对多个维度进行索引。

In [56]:
tf.gather_nd(b, [[0, 2],[3, 3]]) # 选取第1行第3列的那个数据,和第4行第4列的数据
Out[56]:
 

4 维度变换¶

 

4.1 reshape()¶

 

numpy中的ndarray数组有个一reshape()方法,用来改变数组的shape,TensorFlow中的reshape()方法,功能也是一样的,不过TensorFlow中的reshape()没有绑定到tensor中:

In [58]:
a = tf.ones([2,3,4])
In [59]:
a.shape
Out[59]:
TensorShape([2, 3, 4])
In [60]:
a
Out[60]:
In [61]:
b = tf.reshape(a, [2, 2, 6])
In [62]:
b.shape
Out[62]:
TensorShape([2, 2, 6])
In [64]:
b
Out[64]:
In [65]:
c = tf.reshape(a, [3, 2, 4])
In [66]:
c
Out[66]:
 

可以看到,在上面的例子中,通过reshape()方法可以很方便的改变tensor的形状,得到一个新的tensor,需要注意的是在进行维度变换时,数据的重量是不变的,上面的例子无论是[2,3,4], [2, 2, 6]还是[3, 2, 4]都对应总量24,如果对应不上,就会产生异常。

 

4.2 转置:transpose()¶

 

transpose()方法提供了一种类似于装置的操作:

In [75]:
a = tf.constant([[1,2,3],[4,5,6]])
In [76]:
a.shape
Out[76]:
TensorShape([2, 3])
In [77]:
b = tf.transpose(a)
In [78]:
b.shape
Out[78]:
TensorShape([3, 2])
In [79]:
b
Out[79]:
 

在默认情况下,transpose()方法会将所有维度按逆序方式完全转置,当然也可以通过perm参数执行需要转置的维度:

In [80]:
a=tf.constant([[[1,2,3],[4,5,6]],[[7,8,9],[10,11,12]]])
In [81]:
a
Out[81]:
In [82]:
b = tf.transpose(a) # 不指定perm参数时,相当于tf.transpose(a, perm=[2, 1, 0])
In [83]:
b
Out[83]:
In [84]:
c = tf.transpose(a, perm=[2, 1, 0])
In [85]:
c
Out[85]:
In [86]:
d = tf.transpose(a, perm=[0, 2, 1]) # 第一个维度不做变换,对第二、第三维度进行转置
In [87]:
d
Out[87]:
 

4.3 添加维度:expand_dims()¶

In [88]:
a=tf.constant([[1,2,3],[4,5,6]])
In [89]:
a
Out[89]:
In [90]:
tf.expand_dims(a, axis=0)
Out[90]:
In [91]:
tf.expand_dims(a, axis=1)
Out[91]:
In [92]:
tf.expand_dims(a, axis=-1)
Out[92]:
In [93]:
tf.expand_dims(a, axis=2)
Out[93]:
 

expand_dims()方法添加维度时,通过axis参数指定添加维度的位置,正数表示从前往后数,负数表示从后往前数。

 

4.4 压缩维度:squeeze()¶

 

squeeze()方法与expand_dims()方法作用刚好相反,其作用是删除张量中dim为1的维度:

In [94]:
a = tf.ones([1,3,1,2])
In [95]:
a
Out[95]:
In [96]:
tf.squeeze(a)
Out[96]:

你可能感兴趣的:(TensorFlow2.0(一):基本数据结构——张量)