TensorFlow 2
创建和控制张量
矢量加法
可以对张量执行金典的数学运算,试着创建一些矢量。
from __future__ import print_function
import tensorflow as tf
try:
tf.contrib.eager.enable_eager_execution()
print("TF imported with eager execution!")
except ValueError:
print("TF already imported with eager execution!")
# 一个包含质数的‘primes’矢量
primes = tf.constant([2, 3, 5, 7, 11 ,13], dtype=tf.int32)
print("primes:", primes)
# 一个值全为 1 的 ones 矢量
ones = tf.ones([6], dtype=tf.int32)
print(ones)
# 一个通过对前两个矢量执行元素级加法而创建的矢量。
just_beyond_primes = tf.add(primes, ones)
print(just_beyond_primes)
# 把primes中的元素乘二
twos = tf.constant([2, 2, 2, 2, 2, 2], dtype=tf.int32)
primes_doubled = primes * twos
print(primes_doubled)
TF imported with eager execution!
primes: tf.Tensor([ 2 3 5 7 11 13], shape=(6,), dtype=int32)
tf.Tensor([1 1 1 1 1 1], shape=(6,), dtype=int32)
tf.Tensor([ 3 4 6 8 12 14], shape=(6,), dtype=int32)
tf.Tensor([ 4 6 10 14 22 26], shape=(6,), dtype=int32)
输出的张量不仅会返回值,还会返回形状shape,以及储存在张量中的值的类型。调用numpy方法会以NumPy数组的形式返回。
some_matrix = tf.constant([[1, 2, 3], [4, 5, 6]], dtype=tf.int32)
print(some_matrix)
print("\nnumpy matrix:\n", some_matrix.numpy())
tf.Tensor(
[[1 2 3]
[4 5 6]], shape=(2, 3), dtype=int32)
numpy matrix:
[[1 2 3]
[4 5 6]]
张量形状
shape 是用来描述张量维度大小和数量。张量的形状表示为list,其中第 i 个元素表示维度 i 的大小。列表的长度表示张量的阶(即维数)。
如果是二维的则shape=(行数, 列数)
例如shape=(n1, n2, n3, ..., x, y)
则说明 一共有 (n1 x n2 x n3 x ....)个x行y列的数组构成。
例:
# 一个标量
scalar = tf.zeros([])
# 一个有三个元素的向量
vector = tf.zeros([3])
# 一个两行三列的矩阵
matrix = tf.zeros([2, 3])
matrix2 = tf.zeros([2, 3, 4, 5])
print('scalar has shape', scalar.get_shape(), 'and value:\n', scalar.numpy())
print('vector has shape', vector.get_shape(), 'and value:\n', vector.numpy())
print('matrix has shape', matrix.get_shape(), 'and value:\n', matrix.numpy())
print('matrix2 has shape', matrix2.get_shape(), 'and value:\n', matrix2.numpy())
scalar has shape () and value:
0.0
vector has shape (3,) and value:
[0. 0. 0.]
matrix has shape (2, 3) and value:
[[0. 0. 0.]
[0. 0. 0.]]
matrix2 has shape (2, 3, 4, 5) and value:
[[[[0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0.]]
[[0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0.]]
[[0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0.]]]
[[[0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0.]]
[[0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0.]]
[[0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0.]]]]
广播
在数学中,您只能对形状相同的张量执行元素级运算(例如,相加和等于)。不过,在 TensorFlow 中,您可以对张量执行传统意义上不可行的运算。TensorFlow 支持广播(一种借鉴自 NumPy 的概念)。利用广播,元素级运算中的较小数组会增大到与较大数组具有相同的形状。例如,通过广播:
-
如果运算需要大小为
[6]的张量,则大小为[1]或[]的张量可以作为运算数。 -
如果运算需要大小为
[4, 6]的张量,则以下任何大小的张量都可以作为运算数:[1, 6][6][]
-
如果运算需要大小为
[3, 5, 6]的张量,则以下任何大小的张量都可以作为运算数:[1, 5, 6][3, 1, 6][3, 5, 1][1, 1, 1][5, 6][1, 6][6][1][]
注意:当张量被广播时,从概念上来说,系统会复制其条目(出于性能考虑,实际并不复制。广播专为实现性能优化而设计)。
有关完整的广播规则集,请参阅简单易懂的 NumPy 广播文档。
以下代码执行了与之前一样的张量运算,不过使用的是标量值(而不是全包含 1 或全包含 2 的矢量)和广播。
primes = tf.constant([2, 3, 5, 7, 11, 13], dtype=tf.int32)
print("primes:", primes)
one = tf.constant(1, dtype=tf.int32)
print("one:", one)
just_beyond_primes = tf.add(primes, one)
print("just_beyond_primes:", just_beyond_primes)
two = tf.constant(2, dtype=tf.int32)
primes_doubled = primes * two
print(primes_doubled)
primes: tf.Tensor([ 2 3 5 7 11 13], shape=(6,), dtype=int32)
one: tf.Tensor(1, shape=(), dtype=int32)
just_beyond_primes: tf.Tensor([ 3 4 6 8 12 14], shape=(6,), dtype=int32)
tf.Tensor([ 4 6 10 14 22 26], shape=(6,), dtype=int32)
练习 1:矢量运算。
执行矢量运算以创建一个“just_under_primes_squared”矢量,其中第 i 个元素等于 primes 中第 i 个元素的平方减 1。例如,第二个元素为 3 * 3 - 1 = 8。
使用 tf.multiply 或 tf.pow 操作可求得 primes 矢量中每个元素值的平方。
def solution(primes):
primes_squared = tf.pow(primes, 2) # or tf.multiply(primes, primes)
one = tf.constant(1, dtype=tf.int32)
just_under_primes_squared = tf.subtract(primes_squared, one)
return just_under_primes_squared
primes = tf.constant([2, 3, 5, 7, 11, 13], dtype=tf.int32)
just_under_primes_squared = solution(primes)
print(just_under_primes_squared)
tf.Tensor([ 3 8 24 48 120 168], shape=(6,), dtype=int32)
矩阵乘法
在线性代数中,当两个矩阵相乘时,第一个矩阵的列数必须等于第二个矩阵的行数。
3x4矩阵乘以4x2矩阵是 有效 的,可以得出一个3x2矩阵。4x2矩阵乘以3x4矩阵是 无效 的。
# 一个3x4的矩阵
x = tf.constant([[5, 2, 4, 3], [5, 1, 6, -2], [-1, 3, -1, -2]],
dtype=tf.int32)
# 一个4x2的矩阵
y = tf.constant([[2, 2], [3, 5], [4, 5], [1, 6]], dtype=tf.int32)
# 结果是一个3x2的矩阵
matrix_multiply_result = tf.matmul(x, y)
print(matrix_multiply_result)
tf.Tensor(
[[35 58]
[35 33]
[ 1 -4]], shape=(3, 2), dtype=int32)
张量变形
由于张量加法和矩阵乘法均对运算数施加了限制条件,TensorFlow 编程者需要频繁改变张量的形状。
您可以使用 tf.reshape 方法改变张量的形状。
例如,您可以将 8x2 张量变形为 2x8 张量或 4x4 张量(改变形状形成的新矩阵元素数和之前必须一样):
此外,您还可以使用 tf.reshape 更改张量的维数(“阶”)。
例如,您可以将 8x2 张量变形为三维 2x2x4 张量或一维 16 元素张量。
# 创建一个8x2的矩阵
matrix = tf.constant(
[[1, 2], [3, 4], [5, 6], [7, 8], [9, 10], [11, 12], [13, 14], [15, 16]],
dtype=tf.int32)
reshaped_2x8_matrix = tf.reshape(matrix, [2, 8])
reshaped_4x4_matrix = tf.reshape(matrix, [4, 4])
print("Original matrix (8x2):")
print(matrix.numpy())
print("Reshaped matrix (2x8):")
print(reshaped_2x8_matrix.numpy())
print("Reshaped matrix (4x4):")
print(reshaped_4x4_matrix.numpy())
reshaped_2x2x4_tensor = tf.reshape(matrix, [2, 2, 4])
one_dimensional_vector = tf.reshape(matrix, [16])
print("Reshaped 3-D tensor (2x2x4):")
print(reshaped_2x2x4_tensor.numpy())
print("1-D vector:")
print(one_dimensional_vector.numpy())
Original matrix (8x2):
[[ 1 2]
[ 3 4]
[ 5 6]
[ 7 8]
[ 9 10]
[11 12]
[13 14]
[15 16]]
Reshaped matrix (2x8):
[[ 1 2 3 4 5 6 7 8]
[ 9 10 11 12 13 14 15 16]]
Reshaped matrix (4x4):
[[ 1 2 3 4]
[ 5 6 7 8]
[ 9 10 11 12]
[13 14 15 16]]
Reshaped 3-D tensor (2x2x4):
[[[ 1 2 3 4]
[ 5 6 7 8]]
[[ 9 10 11 12]
[13 14 15 16]]]
1-D vector:
[ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16]
练习 2:改变两个张量的形状,使其能够相乘。
下面两个矢量无法进行矩阵乘法运算:
a = tf.constant([5, 3, 2, 7, 1, 4])b = tf.constant([4, 6, 3])
请改变这两个矢量的形状,使其成为可以进行矩阵乘法运算的运算数。
然后,对变形后的张量调用矩阵乘法运算。
a = tf.constant([5, 3, 2, 7, 1, 4])
b = tf.constant([4, 6, 3])
reshaped_a = tf.reshape(a, [2, 3])
reshaped_b = tf.reshape(b, [3, 1])
c = tf.matmul(reshaped_a, reshaped_b)
print("reshaped_a (2x3):")
print(reshaped_a.numpy())
print("reshaped_b (3x1):")
print(reshaped_b.numpy())
print("reshaped_a x reshaped_b (2x1):")
print(c.numpy())
reshaped_a (2x3):
[[5 3 2]
[7 1 4]]
reshaped_b (3x1):
[[4]
[6]
[3]]
reshaped_a x reshaped_b (2x1):
[[44]
[46]]
变量、初始化和赋值
到目前为止,我们执行的所有运算都针对的是静态值 (tf.constant);调用 numpy() 始终返回同一结果。在 TensorFlow 中可以定义 Variable 对象,它的值是可以更改的。
创建变量时,您可以明确设置一个初始值,也可以使用初始化程序(例如分布):
# 创建初始值为3的标量变量
v = tf.contrib.eager.Variable([3])
# 创建一个形状为[1,4]的矢量变量,其初始值为随机的
# 从均值为1,标准差为0.35的正态分布中取样
w = tf.contrib.eager.Variable(tf.random_normal([1, 4], mean=1.0, stddev=0.35))
print("v:", v.numpy())
print("w:", w.numpy())
v: [3]
w: 0.7752843 1.516361 1.1726708 0.9872638
要更改变量的值,请使用 assign 操作,并且向变量赋予新值时,其形状必须和之前的形状一致。
v = tf.contrib.eager.Variable([3])
print(v.numpy())
tf.assign(v, [7])
print(v.numpy())
v.assign([5])
print(v.numpy())
v = tf.contrib.eager.Variable([[1, 2, 3], [4, 5, 6]])
print(v.numpy())
try:
print("Assigning [7, 8, 9] to v")
v.assign([7, 8, 9])
except ValueError as e:
print("Exception:", e)
[3]
[7]
[5]
[[1 2 3]
[4 5 6]]
Assigning [7, 8, 9] to v
Exception: Shapes (2, 3) and (3,) are incompatible
练习 3:模拟投掷两个骰子 10 次。
创建一个骰子模拟,在模拟中生成一个 10x3 二维张量,其中:
- 列
1和2均存储一个六面骰子(值为 1-6)的一次投掷值。 - 列
3存储同一行中列1和2的值的总和。
例如,第一行中可能会包含以下值:
- 列
1存储4 - 列
2存储3 - 列
3存储7
要完成此任务,您需要浏览 TensorFlow 文档。
die1 = tf.contrib.eager.Variable(
tf.random_uniform([10, 1], minval=1, maxval=7, dtype=tf.int32))
die2 = tf.contrib.eager.Variable(
tf.random_uniform([10, 1], minval=1, maxval=7, dtype=tf.int32))
dice_sum = tf.add(die1, die2)
resulting_matrix = tf.concat(values=[die1, die2, dice_sum], axis=1)
print(resulting_matrix)
tf.Tensor(
[[ 2 3 5]
[ 5 6 11]
[ 3 3 6]
[ 5 6 11]
[ 2 1 3]
[ 6 5 11]
[ 1 4 5]
[ 1 1 2]
[ 4 6 10]
[ 5 4 9]], shape=(10, 3), dtype=int32)