《28天玩转TensorFlow2》第2天:张量运算

关于张量的运算操作,从下面3个级别上的运算说明

  • 一、标量运算
  • 二、向量运算
  • 三、矩阵运算
import tensorflow as tf
print('tensorflow版本', tf.__version__, sep=':')
tensorflow版本:2.1.0

一、标量运算

标量运算就是对张量值中的元素进行运算。运算包括加法(+)、减法(-)、乘法(*)、除(/)、取余(%)、取整(//)等。两个张量的值必须具有相同的类型。

  • 如果进行运算的2个张量的维度数字是完全一致的,进行的运算就是对应元素之间的运算;参见示例1

  • 如果两个张量的维度数并不是完全一致的,就会应用到广播机制进行运算;广播机制的原理,就是将维度数字为1的维度上的数"复制",从而变成和另一个张量该维度的数字一样的,然后在进行对应元素间的计算。 参见示例2.1-2.5

# 示例1:维度数字是完全一致的
a = tf.constant(tf.range(24).numpy().reshape(2, 3, 4), dtype=tf.float32)
b = tf.constant(tf.ones((2, 3, 4))) # 类型默认为tf.float32
print(a, b, sep='\n')
print(a-b) # 减法

输出:

tf.Tensor(
[[[ 0.  1.  2.  3.]
  [ 4.  5.  6.  7.]
  [ 8.  9. 10. 11.]]

 [[12. 13. 14. 15.]
  [16. 17. 18. 19.]
  [20. 21. 22. 23.]]], shape=(2, 3, 4), dtype=float32)
tf.Tensor(
[[[1. 1. 1. 1.]
  [1. 1. 1. 1.]
  [1. 1. 1. 1.]]

 [[1. 1. 1. 1.]
  [1. 1. 1. 1.]
  [1. 1. 1. 1.]]], shape=(2, 3, 4), dtype=float32)
tf.Tensor(
[[[-1.  0.  1.  2.]
  [ 3.  4.  5.  6.]
  [ 7.  8.  9. 10.]]

 [[11. 12. 13. 14.]
  [15. 16. 17. 18.]
  [19. 20. 21. 22.]]], shape=(2, 3, 4), dtype=float32)
# 示例2.1
a = tf.constant(tf.range(24).numpy().reshape(2, 3, 4), dtype=tf.float32)
b = tf.constant(tf.ones((2, 3, 1))) # 类型默认为tf.float32
print(a, b, sep='\n')
print(a+b) # 加法
# 应用到广播机制
# 其实就等于把b在第3个维度上进行扩展,等于"复制”4次,变为tf.ones((2, 3, 4),维度变成(2, 3, 4)

输出:

tf.Tensor(
[[[ 0.  1.  2.  3.]
  [ 4.  5.  6.  7.]
  [ 8.  9. 10. 11.]]

 [[12. 13. 14. 15.]
  [16. 17. 18. 19.]
  [20. 21. 22. 23.]]], shape=(2, 3, 4), dtype=float32)
tf.Tensor(
[[[1.]
  [1.]
  [1.]]

 [[1.]
  [1.]
  [1.]]], shape=(2, 3, 1), dtype=float32)
tf.Tensor(
[[[ 1.  2.  3.  4.]
  [ 5.  6.  7.  8.]
  [ 9. 10. 11. 12.]]

 [[13. 14. 15. 16.]
  [17. 18. 19. 20.]
  [21. 22. 23. 24.]]], shape=(2, 3, 4), dtype=float32)
# 示例2.2
a = tf.constant(tf.range(1, 25).numpy().reshape(2, 3, 4))
b = tf.constant(tf.fill((1, 1, 4), 4)) 
print(a, b, sep='\n')
print(b//a) # 取整
# 应用到广播机制
# 其实就等于把b在第1个维度上"复制”2次,变成tf.fill((2, 1, 4), 4),然后再第2个维度"复制"3次,变成tf.fill((2, 3, 4), 4),维度变为(2, 3, 4)

输出:

tf.Tensor(
[[[ 1  2  3  4]
  [ 5  6  7  8]
  [ 9 10 11 12]]

 [[13 14 15 16]
  [17 18 19 20]
  [21 22 23 24]]], shape=(2, 3, 4), dtype=int32)
tf.Tensor([[[4 4 4 4]]], shape=(1, 1, 4), dtype=int32)
tf.Tensor(
[[[4 2 1 1]
  [0 0 0 0]
  [0 0 0 0]]

 [[0 0 0 0]
  [0 0 0 0]
  [0 0 0 0]]], shape=(2, 3, 4), dtype=int32)
# 示例2.3
a = tf.constant(tf.range(24).numpy().reshape(2, 3, 4))
b = tf.constant(tf.fill((1, 1), 4)) 
print(a, b, sep='\n')
print(a//b) # 取整
# 应用到广播机制
# 其实就等于把b在第1个维度上"复制”2次,变成tf.fill((2, 1), 4)
# 然后在第2个维度"复制"3次,变成tf.fill((2, 3), 4)
# 然后在第3个维度"复制"4次,变成tf.fill((2, 3, 4), 4),维度变为(2, 3, 4)

输出:

tf.Tensor(
[[[ 0  1  2  3]
  [ 4  5  6  7]
  [ 8  9 10 11]]

 [[12 13 14 15]
  [16 17 18 19]
  [20 21 22 23]]], shape=(2, 3, 4), dtype=int32)
tf.Tensor([[4]], shape=(1, 1), dtype=int32)
tf.Tensor(
[[[0 0 0 0]
  [1 1 1 1]
  [2 2 2 2]]

 [[3 3 3 3]
  [4 4 4 4]
  [5 5 5 5]]], shape=(2, 3, 4), dtype=int32)
# 示例2.4
a = tf.constant(tf.range(1, 25).numpy().reshape(2, 3, 4))
b = tf.constant(4) 
print(a, b, sep='\n')
print(b/a) # 除法
# 应用到广播机制
# 其实就等于把b在第1个维度上"复制”2次,然后再第2个维度"复制"3次,然后再第3个维度"复制"4次,维度变为(2, 3, 4)

输出:

tf.Tensor(
[[[ 1  2  3  4]
  [ 5  6  7  8]
  [ 9 10 11 12]]

 [[13 14 15 16]
  [17 18 19 20]
  [21 22 23 24]]], shape=(2, 3, 4), dtype=int32)
tf.Tensor(4, shape=(), dtype=int32)
tf.Tensor(
[[[4.         2.         1.33333333 1.        ]
  [0.8        0.66666667 0.57142857 0.5       ]
  [0.44444444 0.4        0.36363636 0.33333333]]

 [[0.30769231 0.28571429 0.26666667 0.25      ]
  [0.23529412 0.22222222 0.21052632 0.2       ]
  [0.19047619 0.18181818 0.17391304 0.16666667]]], shape=(2, 3, 4), dtype=float64)
# 示例2.5
a = tf.constant(tf.range(1, 9).numpy().reshape(2, 1, 4))
b = tf.constant(tf.range(1, 4).numpy().reshape(1, 3, 1)) 
print(a, b, sep='\n')
print(b*a) # 乘法
# 应用到广播机制
# 其实就等于把a在第2个维度上"复制”3次,维度变为(2, 3, 4)
# 其实就等于把b在第1个维度上"复制”2次,然后在第3个维度"复制"4次,维度变为(2, 3, 4)

输出:

tf.Tensor(
[[[1 2 3 4]]

 [[5 6 7 8]]], shape=(2, 1, 4), dtype=int32)
tf.Tensor(
[[[1]
  [2]
  [3]]], shape=(1, 3, 1), dtype=int32)
tf.Tensor(
[[[ 1  2  3  4]
  [ 2  4  6  8]
  [ 3  6  9 12]]

 [[ 5  6  7  8]
  [10 12 14 16]
  [15 18 21 24]]], shape=(2, 3, 4), dtype=int32)

tensorflow2也提供了一些函数,可在模块tf.math下查找。下面给出机器学习中经常用到的几个函数示例,其他一些机器学习常用的函数也可在tf.nn中找到。

a = tf.constant(tf.linspace(2., 8, 4).numpy().reshape(-1, 1, 4), dtype=tf.float32) / tf.constant(8.)
print(a)

print('神经网络中的激活函数示例')

h = tf.math.sigmoid(a)
print('sigmoid:', h)

h = tf.math.tanh(a)
print('tanh:', h)

h = tf.math.sinh(a)
print('sinh:', h)

h = tf.nn.relu(a)
print('relu:', h)

h = tf.nn.selu(a)
print('selu:', h)

输出:

tf.Tensor([[[0.25 0.5  0.75 1.  ]]], shape=(1, 1, 4), dtype=float32)
神经网络中的激活函数示例
sigmoid: tf.Tensor([[[0.5621765  0.62245935 0.6791787  0.7310586 ]]], shape=(1, 1, 4), dtype=float32)
tanh: tf.Tensor([[[0.24491866 0.46211717 0.635149   0.7615942 ]]], shape=(1, 1, 4), dtype=float32)
sinh: tf.Tensor([[[0.25261232 0.5210953  0.8223167  1.1752012 ]]], shape=(1, 1, 4), dtype=float32)
relu: tf.Tensor([[[0.25 0.5  0.75 1.  ]]], shape=(1, 1, 4), dtype=float32)
selu: tf.Tensor([[[0.26267526 0.5253505  0.78802574 1.050701  ]]], shape=(1, 1, 4), dtype=float32)
print('其他函数示例')
a = tf.constant(tf.linspace(2., 8, 4).numpy().reshape(-1, 4), dtype=tf.float32)
print(a)

h = tf.math.sqrt(a)
print('sqrt:', h)

h = tf.math.pow(a, 2)
print('tan:', h)

h = tf.math.log(a)
print('log:', h)

h = tf.math.exp(a)
print('exp:', h)

输出:

其他函数示例
tf.Tensor([[2. 4. 6. 8.]], shape=(1, 4), dtype=float32)
sqrt: tf.Tensor([[1.4142134 1.9999999 2.4494896 2.8284268]], shape=(1, 4), dtype=float32)
tan: tf.Tensor([[ 4. 16. 36. 64.]], shape=(1, 4), dtype=float32)
log: tf.Tensor([[0.6931472 1.3862944 1.7917595 2.0794415]], shape=(1, 4), dtype=float32)
exp: tf.Tensor([[   7.389056   54.598152  403.4288   2980.958   ]], shape=(1, 4), dtype=float32)

二、向量运算

向量运算是以张量值中的向量为计算对象进行运算。进行向量运算的函数,有一些名称是以reduce开头,也就是降维。在实际的函数中,是否降维是作为函数参数keepdims控制的,设置为True保持原来维度,此时维度保持不变,只是在计算维度上的数字变为1;默认设置为False,不保持原来维度,此时计算的维度消失,也就是降维了。一个参数就是axis,该参数的值表示以哪个维度上的向量为对象,如果不设置该参数的值,则默认该张量中的所有值都参加运算,默认值就是None

  • tf.math.reduce_sum():求和
  • tf.math.reduce_mean():均值
  • tf.math.reduce_max():最大值
  • tf.math.reduce_min():最小值
  • tf.math.reduce_std():标准差
  • tf.math.reduce_prod():乘积
  • tf.math.reduce_reduce_variance():方差
  • tf.math.reduce_euclidean_norm():欧氏距离
  • 张量值为逻辑类型的函数
    • tf.reduce_all()
    • tf.math.reduce_any()
# 示例
a = tf.constant(tf.range(1, 13).numpy().reshape(2, 2, 3))
print('示例数据', a, sep='\n')
print('保持维度:', tf.math.reduce_prod(a, keepdims=True))
print('不保持维度:', tf.math.reduce_prod(a))
for i in [0, 1, 2]:# 张量a有3个维度
    print('==' * 20)
    print('维度%s:' % i, '保持维度:', tf.math.reduce_prod(a, axis=i, keepdims=True),  '不保持维度:', tf.math.reduce_prod(a, axis=i), sep='\n')

print('==' * 20)
x = tf.constant([[True,  True], [False, False]])
print(tf.reduce_all(x))
print(tf.math.reduce_any(x, axis=1, keepdims=True))

输出:

示例数据
tf.Tensor(
[[[ 1  2  3]
  [ 4  5  6]]

 [[ 7  8  9]
  [10 11 12]]], shape=(2, 2, 3), dtype=int32)
保持维度: tf.Tensor([[[479001600]]], shape=(1, 1, 1), dtype=int32)
不保持维度: tf.Tensor(479001600, shape=(), dtype=int32)
========================================
维度0:
保持维度:
tf.Tensor(
[[[ 7 16 27]
  [40 55 72]]], shape=(1, 2, 3), dtype=int32)
不保持维度:
tf.Tensor(
[[ 7 16 27]
 [40 55 72]], shape=(2, 3), dtype=int32)
========================================
维度1:
保持维度:
tf.Tensor(
[[[  4  10  18]]

 [[ 70  88 108]]], shape=(2, 1, 3), dtype=int32)
不保持维度:
tf.Tensor(
[[  4  10  18]
 [ 70  88 108]], shape=(2, 3), dtype=int32)
========================================
维度2:
保持维度:
tf.Tensor(
[[[   6]
  [ 120]]

 [[ 504]
  [1320]]], shape=(2, 2, 1), dtype=int32)
不保持维度:
tf.Tensor(
[[   6  120]
 [ 504 1320]], shape=(2, 2), dtype=int32)
========================================
tf.Tensor(False, shape=(), dtype=bool)
tf.Tensor(
[[ True]
 [False]], shape=(2, 1), dtype=bool)

下面给出几种机器学习模型中会遇到的几个函数示例:

# 最大值索引与最小值索引 
A = tf.constant([2,20,30,3,6])  
print('1,', tf.math.argmax(A, 0)) #  最大值的索引
print('2,', tf.math.argmax(A)) #  最大值的索引

B = tf.constant([[2,20,30,3,6],[3,11,16,1,8],[14,45,23,5,27]])
print('3,', tf.math.argmax(B))
print('4,', tf.math.argmax(B, 0))
print('5,', tf.math.argmax(B,1))

C = tf.constant(tf.range(1, 13).numpy().reshape(2, 2, 3))
print('6,', tf.math.argmin(C)) #  最小值的索引
print('7,', tf.math.argmin(C, 0))
print('8,', tf.math.argmin(C,1))
print('9,', tf.math.argmin(C,2))

输出:

1, tf.Tensor(2, shape=(), dtype=int64)
2, tf.Tensor(2, shape=(), dtype=int64)
3, tf.Tensor([2 2 0 2 2], shape=(5,), dtype=int64)
4, tf.Tensor([2 2 0 2 2], shape=(5,), dtype=int64)
5, tf.Tensor([2 2 1], shape=(3,), dtype=int64)
6, tf.Tensor(
[[0 0 0]
 [0 0 0]], shape=(2, 3), dtype=int64)
7, tf.Tensor(
[[0 0 0]
 [0 0 0]], shape=(2, 3), dtype=int64)
8, tf.Tensor(
[[0 0 0]
 [0 0 0]], shape=(2, 3), dtype=int64)
9, tf.Tensor(
[[0 0]
 [0 0]], shape=(2, 2), dtype=int64)
# 张量值的排序
B = tf.constant([[2,20,30,3,6],[3,11,16,1,8],[14,45,23,5,27]])
print(tf.math.top_k(B)) 
print(tf.math.top_k(B, k=2)) # 默认k=1,选出最大的k个数;默认sorted=True, 返回的值按降序排列;以及返回的值对应的索引

top_k = tf.math.top_k(B, k=2, sorted=False)
print(top_k)

# 获取得到的值和索引
print('值:', top_k.values)
print('索引:', top_k.indices)

输出:

TopKV2(values=, indices=)
TopKV2(values=, indices=)
TopKV2(values=, indices=)
值: tf.Tensor(
[[20 30]
 [11 16]
 [27 45]], shape=(3, 2), dtype=int32)
索引: tf.Tensor(
[[1 2]
 [1 2]
 [4 1]], shape=(3, 2), dtype=int32)

三、矩阵运算

矩阵运算就是以张量值中的矩阵为运算对象,在机器学习中经常用到的包括矩阵乘法,矩阵转置,大部分和矩阵有关的运算都在tf.linalg模块中。

  • tf.linalg.matmul:矩阵乘法,该函数默认的参数下,两个张量的维度必须是一致的,也就是两个要么都是矩阵,要么都是维度相同的n维数据。两个张量的维度数字除最后2个数字以外,前面的必须是相同的,并且该函数中的第一个张量的维度的最后一个数字,必须等于第二个张量的维度的倒数第2个数字。
#  矩阵张量示例。3=3
a = tf.constant(range(12), shape=[4, 3])
print(a) # 矩阵
b = tf.constant([7, 8, 9, 10, 11, 12], shape=[3, 2]) 
print(b) # 矩阵
c = tf.linalg.matmul(a, b) # 矩阵乘法
print(c) 

输出:

tf.Tensor(
[[ 0  1  2]
 [ 3  4  5]
 [ 6  7  8]
 [ 9 10 11]], shape=(4, 3), dtype=int32)
tf.Tensor(
[[ 7  8]
 [ 9 10]
 [11 12]], shape=(3, 2), dtype=int32)
tf.Tensor(
[[ 31  34]
 [112 124]
 [193 214]
 [274 304]], shape=(4, 2), dtype=int32)
# 立方体张量示例,2=2, 5=5
a = tf.constant(tf.range(1, 41, dtype=tf.int32).numpy().reshape(2, 4, 5))
print(a) # 立方体 
b = tf.constant(tf.range(13, 43, dtype=tf.int32).numpy().reshape(2, 5, 3)) 
print(b) # 立方体
c = tf.matmul(a, b) # 矩阵乘法
print(c)  

输出:

tf.Tensor(
[[[ 1  2  3  4  5]
  [ 6  7  8  9 10]
  [11 12 13 14 15]
  [16 17 18 19 20]]

 [[21 22 23 24 25]
  [26 27 28 29 30]
  [31 32 33 34 35]
  [36 37 38 39 40]]], shape=(2, 4, 5), dtype=int32)
tf.Tensor(
[[[13 14 15]
  [16 17 18]
  [19 20 21]
  [22 23 24]
  [25 26 27]]

 [[28 29 30]
  [31 32 33]
  [34 35 36]
  [37 38 39]
  [40 41 42]]], shape=(2, 5, 3), dtype=int32)
tf.Tensor(
[[[ 315  330  345]
  [ 790  830  870]
  [1265 1330 1395]
  [1740 1830 1920]]

 [[3940 4055 4170]
  [4790 4930 5070]
  [5640 5805 5970]
  [6490 6680 6870]]], shape=(2, 4, 3), dtype=int32)
  • tf.transpose:矩阵转置,也就是进行维度的转化,经常用的就是二维矩阵的转置,也就是行列互换。具体的参见第一天张量维度转换中对该函数的解释。
x = tf.constant([[1, 2, 3], [4, 5, 6]])
print(x)
print(tf.transpose(x, perm=[1, 0]))
print(tf.transpose(x))

输出:

tf.Tensor(
[[1 2 3]
 [4 5 6]], shape=(2, 3), dtype=int32)
tf.Tensor(
[[1 4]
 [2 5]
 [3 6]], shape=(3, 2), dtype=int32)
tf.Tensor(
[[1 4]
 [2 5]
 [3 6]], shape=(3, 2), dtype=int32)

点击获得更多项目源码。欢迎Follow,感谢Star!!! 扫描关注微信公众号pythonfan,获取更多。
《28天玩转TensorFlow2》第2天:张量运算_第1张图片
《28天玩转TensorFlow2》第2天:张量运算_第2张图片

你可能感兴趣的:(《28天玩转TensorFlow2》第2天:张量运算)