关于张量的运算操作,从下面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。
# 示例
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模块中。
# 矩阵张量示例。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)
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)