机器学习-tensorflow创建和操控张量

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zhangqiluGrubby/article/details/83901664

学习目标:

  • 初始化 TensorFlow Variable 并赋值
  • 创建和操控张量
  • 回忆线性代数中的加法和乘法知识(如果这些内容对您来说很陌生,请参阅矩阵加法乘法简介)
  • 熟悉基本的 TensorFlow 数学和数组运算
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!")

矢量加法

您可以对张量执行很多典型数学运算 (TF API)。以下代码会创建下列矢量(一维张量),所有矢量都正好有六个元素:

  • 一个包含质数的 primes 矢量。
  • 一个值全为 1ones 矢量。
  • 一个通过对前两个矢量执行元素级加法而创建的矢量。
  • 一个通过将 primes 矢量中的元素翻倍而创建的矢量。
primes = tf.constant([2, 3, 5, 7, 11, 13], dtype=tf.int32)
print("primes:", primes)
# 创建 tf.ones 方法创建全部为0
ones = tf.ones([6], dtype=tf.int32)
print("ones:", ones)
#  tf.add 两个矢量执行元素级加法
just_beyond_primes = tf.add(primes, ones)
print("just_beyond_primes:", just_beyond_primes)

twos = tf.constant([2, 2, 2, 2, 2, 2], dtype=tf.int32)
primes_doubled = primes * twos
print("primes_doubled:", primes_doubled)

#输出如下:

primes: tf.Tensor([ 2  3  5  7 11 13], shape=(6,), dtype=int32)
ones: tf.Tensor([1 1 1 1 1 1], shape=(6,), dtype=int32)
just_beyond_primes: tf.Tensor([ 3  4  6  8 12 14], shape=(6,), dtype=int32)
primes_doubled: tf.Tensor([ 4  6 10 14 22 26], shape=(6,), dtype=int32)

输出张量不仅会返回其值,还会返回其形状(将在下一部分中讨论)以及存储在张量中的值的类型。调用张量的 numpy 方法会返回该张量的值(以 NumPy 数组形式):

some_matrix = tf.constant([[1, 2, 3], [4, 5, 6]], dtype=tf.int32)
print(some_matrix)
print("\nvalue of some_matrix is:\n", some_matrix.numpy())

#输出如下:
tf.Tensor(
[[1 2 3]
 [4 5 6]], shape=(2, 3), dtype=int32)

value of some_matrix is:
 [[1 2 3]
 [4 5 6]]

张量形状

形状用于描述张量维度的大小和数量。张量的形状表示为 list,其中第 i 个元素表示维度 i 的大小。列表的长度表示张量的阶(即维数)。

有关详情,请参阅 TensorFlow 文档

以下是一些基本示例:

# A scalar (0-D tensor).
scalar = tf.zeros([])

# A vector with 3 elements.
vector = tf.zeros([3])

# A matrix with 2 rows and 3 columns.
matrix = tf.zeros([2, 3])

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())

#输出:
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.]]

广播

在数学中,您只能对形状相同的张量执行元素级运算(例如,相加等于)。不过,在 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_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)
primes_doubled: 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.multiplytf.pow 操作可求得 primes 矢量中每个元素值的平方。

# 方法一  使用 tf.multiply 和 tf.add 方法
def solution(primes):
  primes_squared = tf.multiply(primes, primes)
  neg_one = tf.constant(-1, dtype=tf.int32)
  just_under_primes_squared = tf.add(primes_squared, neg_one)
  return just_under_primes_squared
  
# 方法二  使用 tf.pow 和 tf.subtract 方法
def alternative_solution(primes):
  primes_squared = tf.pow(primes, 2)
  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:", just_under_primes_squared)

输出:
just_under_primes_squared: tf.Tensor([  3   8  24  48 120 168], shape=(6,), dtype=int32)

矩阵乘法

在线性代数中,当两个矩阵相乘时,第一个矩阵的数必须等于第二个矩阵的数。

  • 3x4 矩阵乘以 4x2 矩阵是**有效**的,可以得出一个 3x2 矩阵。
  • 4x2 矩阵乘以 3x4 矩阵是*无效**的。
# A 3x4 matrix (2-d tensor).
x = tf.constant([[5, 2, 4, 3], [5, 1, 6, -2], [-1, 3, -1, -2]],
                dtype=tf.int32)

# A 4x2 matrix (2-d tensor).
y = tf.constant([[2, 2], [3, 5], [4, 5], [1, 6]], dtype=tf.int32)

# Multiply `x` by `y`; result is 3x2 matrix.
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 张量:

# Create an 8x2 matrix (2-D tensor).
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())

输出:
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]]

此外,您还可以使用 tf.reshape 更改张量的维数(“阶”)。
例如,您可以将 8x2 张量变形为三维 2x2x4 张量或一维 16 元素张量。

# Create an 8x2 matrix (2-D tensor).
matrix = tf.constant(
    [[1, 2], [3, 4], [5, 6], [7, 8], [9, 10], [11, 12], [13, 14], [15, 16]],
    dtype=tf.int32)

reshaped_2x2x4_tensor = tf.reshape(matrix, [2, 2, 4])
one_dimensional_vector = tf.reshape(matrix, [16])

print("Original matrix (8x2):")
print(matrix.numpy())
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 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 变形为 2x3 矩阵,并将 b 变形为 3x1 矩阵,从而在相乘后得到一个 2x1 矩阵:

还有一个解决方案是,将 a 变形为 6x1 矩阵,并将 b 变形为 1x3 矩阵,从而在相乘后得到一个 6x3 矩阵。

# Task: Reshape two tensors in order to multiply them

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 对象,它的值是可以更改的。

创建变量时,您可以明确设置一个初始值,也可以使用初始化程序(例如分布):

# Create a scalar variable with the initial value 3.
v = tf.contrib.eager.Variable([3])

# Create a vector variable of shape [1, 4], with random initial values,
# sampled from a normal distribution with mean 1 and standard deviation 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: [[1.1244123  0.24574566 1.0949733  1.1712703 ]]

要更改变量的值,请使用 assign 操作:

v = tf.contrib.eager.Variable([3])
print(v.numpy())

tf.assign(v, [7])
print(v.numpy())

v.assign([5])
print(v.numpy())

输出:
[3]
[7]
[5]

向变量赋予新值时,其形状必须和之前的形状一致:

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)

输出:
[[1 2 3]
 [4 5 6]]
Assigning [7, 8, 9] to v
Exception: Shapes (2, 3) and (3,) are incompatible

练习 3:模拟投掷两个骰子 10 次。

创建一个骰子模拟,在模拟中生成一个 10x3 二维张量,其中:

  • 12 均存储一个六面骰子(值为 1-6)的一次投掷值。
  • 3 存储同一行中列 12 的值的总和。

例如,第一行中可能会包含以下值:

  • 1 存储 4
  • 2 存储 3
  • 3 存储 7

我们将投掷骰子得到的值分别放入两个 10x1 矩阵中,即 die1die2。两次投掷骰子得到的值的总和将存储在 dice_sum 中,然后,将三个 10x1 矩阵连接成一个矩阵,从而创建一个 10x3 矩阵。

或者,我们可以将投掷骰子得到的值放入一个 10x2 矩阵中,但将同一矩阵的不同列相加会更加复杂。我们还可以将投掷骰子得到的值放入两个一维张量(矢量)中,但这样做需要转置结果。

# Task: Simulate 10 throws of two dice. Store the results in a 10x3 matrix.

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.numpy())

输出:
[[ 2  3  5]
 [ 3  1  4]
 [ 1  6  7]
 [ 4  2  6]
 [ 6  5 11]
 [ 2  6  8]
 [ 4  3  7]
 [ 4  2  6]
 [ 6  4 10]
 [ 6  4 10]]
random_uniform(
    shape,
    minval=0,
    maxval=None,
    dtype=tf.float32,
    seed=None,
    name=None
)

参数:
shape:一维整数张量或 Python 数组。输出张量的形状。
minval:dtype 类型的 0-D 张量或 Python 值;生成的随机值范围的下限;默认为0。
maxval:dtype 类型的 0-D 张量或 Python 值。要生成的随机值范围的上限。如果 dtype 是浮点,则默认为1 。
dtype:输出的类型:float16、float32、float64、int32、orint64。
seed:一个 Python 整数。用于为分布创建一个随机种子。查看 tf.set_random_seed 行为。
name:操作的名称(可选)。
返回:

用于填充随机均匀值的指定形状的张量。

tf.concat

第一个参数values:就是两个或者一组待连接的tensor了
第二个参数axis:必须是一个数,表明在哪一维上连接

如果axis是0,那么在某一个shape的第一个维度上连,对应到实际,就是叠放到列上

t1 = [[1, 2, 3], [4, 5, 6]]
t2 = [[7, 8, 9], [10, 11, 12]]
tf.concat([t1, t2],0) == > [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]]
如果concat_dim是1,那么在某一个shape的第二个维度上连
t1 = [[1, 2, 3], [4, 5, 6]]
t2 = [[7, 8, 9], [10, 11, 12]]
tf.concat([t1, t2],1) ==> [[1, 2, 3, 7, 8, 9], [4, 5, 6, 10, 11, 12

猜你喜欢

转载自blog.csdn.net/zhangqiluGrubby/article/details/83901664