数据操作
在深度学习中,通常会频繁地对数据进行操作。而在Tensorflow中,tensor
是一个类,也是存储和变换数据的主要工具。此外tensor
还提供GPU计算和自动求梯度等功能,这使得tensor更加适合深度学习。
1.创建tensor
x = tf.constant(range(12))
print(x.shape)
x
上述代码使用range函数
创建了一个行向量,返回结果为一个tensor
实例,其中包含了从0开始的12个连续整数。输出结果为:
(12,)
<tf.Tensor: id=0, shape=(12,), dtype=int32, numpy=array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])>
提示:range
函数用来创建一个整数数列。
tf.constant(value, dtype=None, shape=None, name='Const', verify_shape=False)
函数用来创建一个常量,其中value
不可少,可以是一个数值,也可以是一个数列。
使用shape
属性获取tensor
实例的形状:
x.shape
输出结果:
TensorShape([12])
使用len
函数得到tensor
实例中元素的总数:
len(x)
输出结果:
12
使用reshape
函数将行向量x
的形状改为(3,4),即一个3行4列的矩阵,并记做X
。除了形状改变意外,X
中的元素保持不变。
X = tf.reshape(x, (3,4))
X
输出结果:
<tf.Tensor: id=2, shape=(3,4), dtype=int32, numpy=array([[0, 1, 2, 3],
[4, 5, 6, 7],
[8, 9, 10, 11]])
可以注意到X
属性中的形状发生了变化。
其中tf.reshape(x, (3,4))
也可以写成tf.reshape(x, (-1, 4))
或tf.reshape(x, (3, -1))
。这里x
的元素个数是已知的,-1是能够通过其它元素个数和其它维度的大小推断出来的。
创建一个各元素为0,形状为(2, 3, 4)的张量。向量与矩阵都是特殊的张量。
tf.zeros((2,3,4))
类似地,我们可以创建各元素为1的张量。
tf.ones((3,4))
也可以使用python的列表(list)指定需要创建的tensor
中每个元素的值。
Y = tf.constant([[2, 1, 4, 3], [1, 2, 3, 4], [4, 3, 2, 1]])
有些情况下,我们需要随机生成tensor
中每个元素的值。下面创建一个形状为(3,4)的tensor
。它的每个元素都随机采样于均值为0,标准差为1的正态分布。
tf.random.normal(shape=[3,4], mean=0, stddev=1)
提示:tf.random.normal(shape, mean=0.0, stddev=1.0, dtype=tf.float32, seed=None, name=None)
,其中shape
为输出张量的形状,必选。
2.运算
tensor
支持大量的运算符。
+
:对应(位置)元素相加
*
:对应(位置)元素相乘
/
:对应(位置)元素相除
指数运算:
Y = tf.cast(Y, tf.float32)
tf.exp(Y)
tf.cast(x, dtype, name = None)
。该函数的作用是执行tensorflow
中张量数据类型转换,比如读入的图片如果是int8类型的,一般要在训练前把图像的数据格式转换为float32.
tf.exp(x, name=None)
。计算e的x次方。
矩阵乘法:
由上面生成的X
和Y
来做矩阵乘法的运算。X
是3(行)*4(列)的矩阵,Y
也是3(行)*4(列)的矩阵,所以X
* Y
的转置。
同时也要保证X
和Y
的数据类型一致。
Y = tf.cast(Y, tf.int32)
tf.matmul(X, tf.transpose(Y))
将多个tensor
连结(concatenate)。
tf.concat([X, Y], axis = 0), tf.concat([X, Y], axis = 1)
输出结果:
(<tf.Tensor: id=28, shape=(6, 4), dtype=int32, numpy=
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11],
[ 2, 1, 4, 3],
[ 1, 2, 3, 4],
[ 4, 3, 2, 1]])>,
<tf.Tensor: id=30, shape=(3, 8), dtype=int32, numpy=
array([[ 0, 1, 2, 3, 2, 1, 4, 3],
[ 4, 5, 6, 7, 1, 2, 3, 4],
[ 8, 9, 10, 11, 4, 3, 2, 1]])>)
分别在行上和列上连结X
和Y
两个矩阵。
可以看到,输出的第一个tensor
在维度0的长度(6)为两个输入矩阵在维度0的长度之和(3+3),而输出的第二个tensor
在维度1的长度(8)为两个输入矩阵在维度1的长度之和(4+4)。
使用条件判断式可以得到元素为0或1的新的tensor
。以X == Y
为例,如果X
和Y
在相同位置的条件判断为真(值相等),那么新的tensor
在相同的位置为1;反之为0。
tf.equal(X, Y)
输出结果:
<tf.Tensor: id=31, shape=(3, 4), dtype=bool, numpy=
array([[False, True, False, True],
[False, False, False, False],
[False, False, False, False]])>
对tensor
中的所有元素求和得到只有一个元素的tensor
。
tf.reduce_sum(X)
输出结果:
<tf.Tensor: id=33, shape=(), dtype=int32, numpy=66>
计算范数。tf.norm(tensor, ord='euclidean', axis=None, keep_dims=False, name=None)
用来计算向量、矩阵和张量的范数。
X = tf.cast(X, tf.float32)
tf.norm(X)
输出结果:
<tf.Tensor: id=39, shape=(), dtype=float32, numpy=22.494444>
3.广播机制
当对两个形状不同的tensor
按元素运算时,可能会出发广播机制(broadcasting)机制;先适当复制元素使这两个tensor
形状相同然后再按元素运算。
定义两个tensor
:
A = tf.reshape(tf.constant(range(3)), (3,1))
B = tf.reshape(tf.constant(range(2)), (1,2))
A, B
输出结果:
(<tf.Tensor: id=42, shape=(3, 1), dtype=int32, numpy=
array([[0],
[1],
[2]])>,
<tf.Tensor: id=45, shape=(1, 2), dtype=int32, numpy=array([[0, 1]])>)
A
和B
分别是3行1列和1行2列的矩阵,如果要计算A + B
,那么A
中第1列的3个元素被广播(复制)到了第2列,而B
中第1行的2个元素被广播(复制)到了第2行和第3行。如此,就可以对2个3行2列的矩阵按元素相加。
A + B
输出结果:
<tf.Tensor: id=46, shape=(3, 2), dtype=int32, numpy=
array([[0, 1],
[1, 2],
[2, 3]])>
4.索引
在tensor
中,索引(index)代表元素的位置。tensor
的索引从0开始逐一递增。例如,一个3行2列的矩阵的行索引分别为0、1和2,列索引分别0和1。
我们可以指定tensor
中需要访问的单个元素的位置,如矩阵中行和列的索引,并为该元素重新赋值。
X = tf.Variable(X)
X[1,2].assign(9)
也可以截取一部分元素,并为它们重新赋值。
X[1:2, :].assign(tf.ones(X[1:2, :].shape, dtype=tf.float32)*12)
5.运算的内存开销
在前面的例子中,我们对每个操作新开内存来存储运算结果。举个例子,即使像Y = X + Y
这样的运算,也会新开内存,然后将Y
指向新内存。
使用Python自带的id
函数:如果两个实例的ID一致,那么它们所对应的内存地址相同;反之不同。
X = tf.Variable(X)
Y = tf.cast(Y, dtype=tf.float32)
before = id(Y)
Y = Y + X
id(Y) == before
输出结果:
False
如果想指定结果到特定内存,我们可以使用前面介绍的索引来进行替换操作。
Z = tf.Variable(tf.zeros_like(Y))
before = id(Z)
Z[:].assign(X + Y)
id(Z) == before
输出结果:
True
这里先通过zeros_like
创建和Y
形状相同且元素为0的tensor
,记为Z
。接下来将X + Y
的结果通过assign函数写进Z
对应的内存中。
6.tensor和Numpy相互变换
将Numpy实例变换成tensor
实例。
import numpy as np
P = np.ones((2,3))
D = tf.constant(P)
D)
输出结果:
<tf.Tensor: id=115, shape=(2, 3), dtype=float64, numpy=
array([[1., 1., 1.],
[1., 1., 1.]])>
将NDArray实例变换成Numpy实例。
np.array(D)
输出结果:
array([[1., 1., 1.],
[1., 1., 1.]])