TensorFlow的运算基本上都是基于张量的。张量是多维array,跟numpy类型,也可以通过方法和tensor进行转换,比如tensor支持.numpy()
方法转换为numpy array,两者在进行运算时,也会自动转换:
import numpy as np
ndarray = np.ones([3, 3])
print("TensorFlow operations convert numpy arrays to Tensors automatically")
tensor = tf.multiply(ndarray, 42)
print(tensor)
print("And NumPy operations convert Tensors to numpy arrays automatically")
print(np.add(tensor, 1))
print("The .numpy() method explicitly converts a Tensor to a numpy array")
print(tensor.numpy())
tensor也有dtype以及shape。最大的区别是tensor是能通过GPU进行加速运算的。
进行张量的点乘运算。
x = tf.matmul([[1]], [[2, 3]])
print(x)
print(x.shape)
print(x.dtype)
将n维的向量拆成n-1维张。返回的值是一个list,里面是拆分好的n-1维张量
:
def unstack(value, num=None, axis=0, name="unstack"):
其反操作为tf.stack
:
def stack(values, axis=0, name="stack")# 这里的values应该是list-like类型
例子:
import tensorflow as tf
import numpy as np
# 将3,4的张量的第一维拆分,
x = tf.reshape(tf.range(12), (3,4))
# 结果为3个shape(4,)的张量
p, q, r = tf.unstack(x)
# 反操作
x=tf.stack([p, q, r])
# 换axis=1维
i, j, k, l = tf.unstack(x, axis=1)
x = tf.stack([i, j, k, l], axis=1)
# 对aixs=2进行拆分
X = np.array([[[0, 1, 2], [9, 8, 7],[3,6,8]],
[[3, 4, 5], [0, 0, 0],[0,0,0]],
[[6, 7, 8], [6, 5, 4],[1,7,4]],
[[9, 0, 1], [3, 7, "A"],[0,0,0]]])# shape=(4,3,3)
# 对axis=2的维度进行拆分,就相当于把这一维分为shape[2](3)个shape(4,3)的tensor。同时每个元素在axis=0,axis=1的索引是不变的
X=tf.unstack(X, axis=2)
print(X)
# axis=1进行维度拆分:相当把这一维分为shape[1](3)个,shape(shape[0],shape[2])个张量,
# 可以看到这里会将原来的元素的axis=2的索引向前提升到axis=1的位置。这样每个元素的关系也就清楚了:
# 如原来是X[3][1][2]=的元素"A",在axis=1拆分后,应该在第二个张量,tensor2[3][2]的位置
tensor1,tensor2,tensor3=tf.unstack(X, axis=1)
总结:
pass
将张量转化为另一种类型。The operation casts x
(in case of Tensor
) or x.values
(in case of SparseTensor
or IndexedSlices
) to dtype
.tf.cast
还有一个别名:tf.dtypes.cast
tf.cast(
x, dtype, name=None
)
Tensor
or SparseTensor
or IndexedSlices
of numeric type. It could be uint8
, uint16
, uint32
, uint64
, int8
, int16
, int32
, int64
, float16
, float32
, float64
, complex64
, complex128
, bfloat16
.x
.通过填充张量来构造一个新的张量。这个操作用过复制input
的multiples
倍来生成新的张量。输出张量的第i维=input.dims(i) * multiples[i]
。第i维的元素将重复multiples[i]
倍,如:tiling [a b c d]
by [2]
produces [a b c d a b c d]
.
tf.tile(
input, multiples, name=None
)
input:A Tensor. 1-D or higher.
multiples:A Tensor. Must be one of the following types: int32
, int64
. 1-D. Length must be the same as the number of dimensions in input。multiples的长度应与input的维度数是一致的。
注意这个tile有填充方向的,可以向inputs的任意维度方向上填充
例如:
a = tf.constant([[1,2,3],[4,5,6]], tf.int32)
b = tf.constant([1,2], tf.int32)
tf.tile(a, b)
#array([[1, 2, 3, 1, 2, 3],
# [4, 5, 6, 4, 5, 6]])>
c = tf.constant([2,1], tf.int32)
tf.tile(a, c)
#array([[1, 2, 3],
# [4, 5, 6],
# [1, 2, 3],
# [4, 5, 6]])>
d = tf.constant([2,2], tf.int32)
tf.tile(a, d)
pass
tf.split(
value, num_or_size_splits, axis=0, num=None, name='split'
)
将tensor切分为一系列的子张量。
如果num_or_size_splits是整数,返回的是一个长度为num_or_size_splits的张量对象的list。如果num_or_size_split是列表或者是张量,返回num_or_size_splits.get_shape[0]个的张量的列表,且每个张量切分的axis轴上的shape,由list指定。
x = tf.Variable(tf.random.uniform([5, 30], -1, 1))
# Split `x` into 3 tensors along dimension 1
s0, s1, s2 = tf.split(x, num_or_size_splits=3, axis=1)
tf.shape(s0).numpy()
# Split `x` into 3 tensors with sizes [4, 15, 11] along dimension 1
split0, split1, split2 = tf.split(x, [4, 15, 11], 1)
tf.shape(split0).numpy()
#array([ 5, 4])
tf.shape(split1).numpy()
#array([ 5, 15])
tf.shape(split2).numpy()
# array([ 5, 11])
注意,这个方法现在是在tf.compat.v1.reduce_mean
里,更多的信息在Migration guide里。还有一个别名就是tf.compat.v1.math.reduce_mean
tf.compat.v1.reduce_mean(
input_tensor,
axis=None,
keepdims=None,
name=None,
reduction_indices=None,
keep_dims=None
)
计算一个张量指定维上的元素平均值。
通过计算跨坐标轴维度的元素的平均值,沿着给定的维度(axis
参数制定的)对input_tensor降维。除非keepdims
为真,张量的秩对于axis
维度上的每一个实体都减少1,这必须是唯一的。如果keepdim
s为true
,则不进行降维,但axis
为1。
参数:
input_tensor
axis:降维时要压缩(or 去掉)的维度。默认为None
,即则所有维度都降维,并且返回一个只有单个元素的张量。注意,这里是沿这轴,最好的理解就是其他的维的索引不变,axis维上的索引遍历一遍,然后提出元素,最后求平均值。
必须是[-rank(input_tensor),rank(input_tensor)]
之间的数,这里的rank,其实就是dims数,而负值相当于列表中的负索引。
keepdims:如果为True
,那么被降得维长度为1,就是说有一个元素了
name:这个操作的名字
reduction_indices:与axis的作用一样,现在已经被废弃,不再使用了
keep_dims:与keepdims一样,现在已经被废弃,不再使用了
例子:
x = tf.constant([[1., 1.], [2., 2.]])
tf.reduce_mean(x)
> <tf.Tensor: shape=(), dtype=float32, numpy=1.5>
tf.reduce_mean(x,0)
> <tf.Tensor: shape=(2,), dtype=float32, numpy=array([1.5, 1.5], dtype=float32)>
tf.reduce_mean(x,1)
> <tf.Tensor: shape=(2,), dtype=float32, numpy=array([1., 2.], dtype=float32)>
tf.reduce_mean(x,-1)
> <tf.Tensor: shape=(2,), dtype=float32, numpy=array([1., 2.], dtype=float32)>
tf.reduce_mean(x,-2)
> <tf.Tensor: shape=(2,), dtype=float32, numpy=array([1.5, 1.5], dtype=float32)>
注意:这个方法其实相当于相当于np.mean
。但是np.mean
有个dtype
属性,默认为float64
,但是tf.reduce_mean
会从输入的input_tensor
猜测dtype
类型,并且覆盖np.mean
默认的float64
属性,导致输出结果有差别,如:
np_x1=np.array([1,0,1,0])
np_x2=np.array([1.,0.,1.,0.])
np.mean(np_x1)
> 0.5
np.mean(np_x2)
> 0.5
x1 = tf.constant([1, 0, 1, 0])
x2 = tf.constant([1., 0., 1., 0.])
tf.reduce_mean(x1)
> <tf.Tensor: shape=(), dtype=int32, numpy=0>
tf.reduce_mean(x2)
> <tf.Tensor: shape=(), dtype=float32, numpy=0.5>
tf.broadcast_to(
input, shape, name=None
)
Broadcasting
的张量Tensor
. Must be one of the following types: int32
, int64
. An 1-D int
Tensor. The shape of the desired output.Broadcasting
是一种可以让数据(array)变成可兼容算术运算的操作。如果两个形状相等或其中一个为一,则两个形状是兼容(compatible)的。
x = tf.constant([[1, 2, 3]]) # Shape (1, 3,)
y = tf.broadcast_to(x, [2, 3])
print(y)
>tf.Tensor(
>[[1 2 3]
> [1 2 3]], shape=(2, 3), dtype=int32)
当Broadcasting
时,如果一个张量的axis少于必要的轴数,它的shape就在左侧填充1。
x = tf.constant([1, 2, 3]) # Shape (3,)
y = tf.broadcast_to(x, [2, 3])
> array([[1, 2, 3],
> [1, 2, 3]])>
要注意的是broadcast_to
一般要求后面的维数与原维数相同,比如:
x = tf.constant([1, 2, 3]) # Shape (3,)
y = tf.broadcast_to(x, [2, 3])#
y = tf.broadcast_to(x, [3,1, 3])#
y = tf.broadcast_to(x, [1,1, 3])# y = tf.broadcast_to(x, [3,1])# 报错
x = tf.constant([[1, 2, 3],[4,5,6]])
y = tf.broadcast_to(x, [2,2, 3])#
y = tf.broadcast_to(x, [1,2, 3])#
y = tf.broadcast_to(x, [2, 3,1])# 报错
y = tf.broadcast_to(x, [2,4,3])#报错
也要注意一个例外,就是上面所举的有一个维度为1,这一维是可以任意扩展的:
x = tf.constant([[1, ],[4,]])# shape(2,1)
y = tf.broadcast_to(x, [2,4])
y = tf.broadcast_to(x, [3,2,4])# 不报错
>>> <tf.Tensor: shape=(3, 2, 4), dtype=int32, numpy=
array([[[1, 1, 1, 1],
[4, 4, 4, 4]],
[[1, 1, 1, 1],
[4, 4, 4, 4]],
[[1, 1, 1, 1],
[4, 4, 4, 4]]])>
当进行广播操作时,例如将一个张量乘以一个标量,广播(通常)提供了一些时间或空间上的好处,因为广播张量从未被现实的创建。然而,broadcast_to
并没有带来任何这样的好处。新创建的张量占用了传播形状的全部内存。(但是,在图上下文中,broadcast_to
可能被融合到后续操作中,然后被优化掉。)