美文网首页程序员
TF2 基础 (2) : Tensor 介绍

TF2 基础 (2) : Tensor 介绍

作者: 数科每日 | 来源:发表于2021-01-16 09:33 被阅读0次

    本文是对官方文档 的学习笔记。


    介绍

    Tensor 的特点:

    • 多维
    • 一个Tensor 内部数据结构一致, 数据格式见 tf.dtypes.DType
    • 不可变(immutable), 就像 Python string, 所有 Tensor 都是常量

    基础

    这是一个 0 阶 Tensor, 没有“轴”

    # This will be an int32 tensor by default; see "dtypes" below.
    rank_0_tensor = tf.constant(4)
    print(rank_0_tensor)
    
    tf.Tensor(4, shape=(), dtype=int32)
    

    一阶 Tensor 类似一个 List, 有一个“轴”

    # Let's make this a float tensor.
    rank_1_tensor = tf.constant([2.0, 3.0, 4.0])
    print(rank_1_tensor)
    
    tf.Tensor([2. 3. 4.], shape=(3,), dtype=float32)
    

    二阶 Tensor 类似一个 Matrix , 有两个“轴”

    # If you want to be specific, you can set the dtype (see below) at creation time
    rank_2_tensor = tf.constant([[1, 2],
                                 [3, 4],
                                 [5, 6]], dtype=tf.float16)
    print(rank_2_tensor)
    
    tf.Tensor([2. 3. 4.], shape=(3,), dtype=float32)
    

    高阶 Tensor, 这是个 3阶 Tensor , shape 是 [3, 2, 5]

    # There can be an arbitrary number of
    # axes (sometimes called "dimensions")
    rank_3_tensor = tf.constant([
      [[0, 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]],])
    
    print(rank_3_tensor)
    

    注意:shape 的规则,最内部的数据个数, 在最后边。 比如上例, 它的shape 是 [3, 2, 5], 意思是最内部的数组(不再包含其他数组)所包含的元素是 5个, 次内部的数组,每个包含2个元素, 以此类推。

    A 3-axis tensor, shape: [3, 2, 5]
    
    image.png

    Tensor 转化到 numpy

    np.array(rank_2_tensor)
    
    rank_2_tensor.numpy()
    

    常见 Tensor 包含的数据格式

    • int
    • float
    • complex (复数)
    • string

    Tensor 的形状

    对于一般的 Tensor 来说 tf.Tensor (之前我们讨论的) 要求内部数据形状必须是矩形 (所有轴上的数据长度相等), 但也有比较特殊的Tensor , 支持不规则数据形状。

    数学运算

    Tensor 支持常见的数学运算

    a = tf.constant([[1, 2],
                     [3, 4]])
    b = tf.constant([[1, 1],
                     [1, 1]]) # Could have also said `tf.ones([2,2])`
    
    print(tf.add(a, b), "\n")
    print(tf.multiply(a, b), "\n")
    print(tf.matmul(a, b), "\n")
    
    tf.Tensor(
    [[2 3]
     [4 5]], shape=(2, 2), dtype=int32) 
    
    tf.Tensor(
    [[1 2]
     [3 4]], shape=(2, 2), dtype=int32) 
    
    tf.Tensor(
    [[3 3]
     [7 7]], shape=(2, 2), dtype=int32) 
    
    print(a + b, "\n") # element-wise addition
    print(a * b, "\n") # element-wise multiplication
    print(a @ b, "\n") # matrix multiplication
    

    Shape

    关于 Tensor 的词汇

    • Shape: 各个坐标的长度
    • Rank: 坐标的个数, 标量的 Rank 为0
    • Axis or Dimension: A particular dimension of a tensor.
    • Size: The total number of items in the tensor, the product shape vector.
    image.png

    关于这一段, 原文里面大部分说的很抽象, 没啥指导意义。 倒是这张图, 还有其中的一句话比较有意义。 右边的数值,更加local ,而且在内存上距离更近。 比如上面图所示, 右边的feature 就表示一个sample 的中的feature ,他们之间距离更近。

    索引

    TensorFlow index 规则:

    • indexes 索引从0开始
    • 负数代表从后向前
    • :用于索引, 格式为: 开始:结束:步长

    多数轴索引

    print(rank_2_tensor.numpy())
    --------------------------------------------
    [[1. 2.]
     [3. 4.]
     [5. 6.]]
    
    =================================
    # Pull out a single value from a 2-rank tensor
    print(rank_2_tensor[1, 1].numpy())
    --------------------------------------------
    4.0
    =================================
    # You can index using any combination of integers and slices:
    # Get row and column tensors
    print("Second row:", rank_2_tensor[1, :].numpy())
    print("Second column:", rank_2_tensor[:, 1].numpy())
    print("Last row:", rank_2_tensor[-1, :].numpy())
    print("First item in last column:", rank_2_tensor[0, -1].numpy())
    print("Skip the first row:")
    print(rank_2_tensor[1:, :].numpy(), "\n")
    --------------------------------------------
    Second row: [3. 4.]
    Second column: [2. 4. 6.]
    Last row: [5. 6.]
    First item in last column: 2.0
    Skip the first row:
    [[3. 4.]
     [5. 6.]] 
    =================================
    print(rank_3_tensor[:, :, 4])
    --------------------------------------------
    # Here is an example with a 3-axis tensor:
    
    

    Shape 操作

    转换成 Python list

    把 [3,1] shape 转换成 Python list : as_list

    x = tf.constant([[1], [2], [3]])
    print(x.shape)
    
    # You can convert this object into a Python list, too
    print(x.shape.as_list())
    

    Reshape

    reshape 是转换Tensor shape 的最简单的方式

    # You can reshape a tensor to a new shape.
    # Note that you're passing in a list
    reshaped = tf.reshape(x, [1, 3])
    

    reshape 以后, Tensor 对象会更新, 新的Tensor 还指向相同的数据(The data maintains its layout in memory and a new tensor is created, with the requested shape, pointing to the same data. )

    拍平一个Tensor

    用: tf.reshape(some_tensor, [-1])

    print(rank_3_tensor)
    ----------------------------------------------------------------------------------------
    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 24]
      [25 26 27 28 29]]], shape=(3, 2, 5), dtype=int32)
    ===================================================
    
    # A `-1` passed in the `shape` argument says "Whatever fits".
    print(tf.reshape(rank_3_tensor, [-1]))
    ----------------------------------------------------------------------------------------
    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
     24 25 26 27 28 29], shape=(30,), dtype=int32)
    

    reshape 正确打开方式

    reshape 一般用于增加、减少一个维度。对于上面 3* 2 * 3 Tensor 的例子,减少维度的例子:

    print(tf.reshape(rank_3_tensor, [3*2, 5]), "\n")
    print(tf.reshape(rank_3_tensor, [3, -1])) 
    # 上面第二行等于 : print(tf.reshape(rank_3_tensor, [3,2 * 5]))
    

    使用 Shape 的误区

    1. 用reshape 来改变轴的顺序

    如下, 改变轴的顺序应该用 tf.transpose

    # Bad examples: don't do this
    
    # You can't reorder axes with reshape.
    print(tf.reshape(rank_3_tensor, [2, 3, 5]), "\n") 
    
    # This is a mess
    print(tf.reshape(rank_3_tensor, [5, 6]), "\n")
    
    2. 新旧Shape 包含元素总数对不上
    # This doesn't work at all
    try:
      tf.reshape(rank_3_tensor, [7, -1])
    except Exception as e:
      print(f"{type(e).__name__}: {e}")
    

    位置shape Tensor

    有人称为是动态形状 Tensor

    改变 Tensor Dtype

    the_f64_tensor = tf.constant([2.2, 3.3, 4.4], dtype=tf.float64)
    the_f16_tensor = tf.cast(the_f64_tensor, dtype=tf.float16)
    # Now, cast to an uint8 and lose the decimal precision
    the_u8_tensor = tf.cast(the_f16_tensor, dtype=tf.uint8)
    print(the_u8_tensor)
    ------------------------------------------------------------------------------------------------------
    tf.Tensor([2 3 4], shape=(3,), dtype=uint8)
    

    广播

    广播是从NumPy中的等效功能中借用的概念。简而言之,在某些情况下,在对它们进行组合操作时,较小的张量会自动“拉伸”以适合较大的张量。

    最简单和最常见的情况是尝试将张量乘或加到标量时。在这种情况下,标量被广播为与其他自变量相同的形状。

    x = tf.constant([1, 2, 3])
    
    y = tf.constant(2)
    z = tf.constant([2, 2, 2])
    # All of these are the same computation
    print(tf.multiply(x, 2))
    print(x * y)
    print(x * z)
    ------------------------------------------------------------------------------------------------------
    tf.Tensor([2 4 6], shape=(3,), dtype=int32)
    tf.Tensor([2 4 6], shape=(3,), dtype=int32)
    tf.Tensor([2 4 6], shape=(3,), dtype=int32)
    

    在大多数情况下,广播既节省时间又节省空间,因为广播操作永远不会实现内存中扩展的张量。

    利用 broadcast_to 在Tensor 内部复制数据
    print(tf.broadcast_to(tf.constant([1, 2, 3]), [3, 3]))
    ------------------------------------------------------------------------------------------------------
    tf.Tensor(
    [[1 2 3]
     [1 2 3]
     [1 2 3]], shape=(3, 3), dtype=int32)
    

    注意, 这不和上面广播不一样, broadcast_to 产生的新 Tensor 并不会节约内存。

    tf.convert_to_tensor

    TF2 中很多函数都会要求参数是 Tensor ,如果参数不是 Tensor 则会调用 convert_to_tensor 来做转换。 有些类型, 比如 ndarray, TensorShape,Python list, tf.Variable 已经“注册”了, 他们可以自动转换成 Tensor。 对于自定义类型, 可以tf.register_tensor_conversion_function 来注册转换函数。

    Ragged Tensors

    沿某个轴具有可变数量元素的张量称为“Ragged Tensors”。使用 tf.ragged.RaggedTensor处理不整齐的数据。
    例如

    | A [`tf.RaggedTensor`](https://www.tensorflow.org/api_docs/python/tf/RaggedTensor), shape: `[4,<wbr style="box-sizing: inherit;"> None]` |
    
    
    image.png

    普通 Tensor 处理不了长短不一的情况

    ragged_list = [
        [0, 1, 2, 3],
        [4, 5],
        [6, 7, 8],
        [9]]
    
    try:
      tensor = tf.constant(ragged_list)
    except Exception as e:
      print(f"{type(e).__name__}: {e}")
    ---------------------------------------------------------------------
    ValueError: Can't convert non-rectangular Python sequence to Tensor.
    
    ragged_tensor = tf.ragged.constant(ragged_list)
    print(ragged_tensor)
    ---------------------------------------------------------------------
    <tf.RaggedTensor [[0, 1, 2, 3], [4, 5], [6, 7, 8], [9]]>
    
    print(ragged_tensor.shape)
    ---------------------------------------------------------------------
    (4, None)
    

    String tensors

    tf.string是dtype,也就是说您可以将数据表示为张量中的字符串(可变长度字节数组)。

    这些字符串是原子的,无法像Python字符串那样被索引。字符串的长度不是张量的轴之一。有关操作它们的功能,请参见tf.strings

    # Tensors can be strings, too here is a scalar string.
    scalar_string_tensor = tf.constant("Gray wolf")
    print(scalar_string_tensor)
    ---------------------------------------------------------------------
    tf.Tensor(b'Gray wolf', shape=(), dtype=string)
    
    image.png
    # If you have three string tensors of different lengths, this is OK.
    tensor_of_strings = tf.constant(["Gray wolf",
                                     "Quick brown fox",
                                     "Lazy dog"])
    # Note that the shape is (3,). The string length is not included.
    print(tensor_of_strings)
    ---------------------------------------------------------------------
    tf.Tensor([b'Gray wolf' b'Quick brown fox' b'Lazy dog'], shape=(3,), dtype=string)
    

    在上面的打印输出中,b前缀表示tf.string dtype不是unicode字符串,而是字节字符串。有关在TensorFlow中处理Unicode文本的更多信息,请参见Unicode教程。

    如果传递unicode字符,则它们是utf-8编码的。

    tf.constant("🥳👍")
    ---------------------------------------------------------------------
    <tf.Tensor: shape=(), dtype=string, numpy=b'\xf0\x9f\xa5\xb3\xf0\x9f\x91\x8d'>
    

    可以在tf.strings中找到一些带有字符串的基本功能,包括tf.strings.split。

    其他更多关于 String Tensor ,可以参考 string_tensors

    Sparse tensors

    Sparse tensors 用来存储稀疏矩阵类型的数据。

    image.png
    # Sparse tensors store values by index in a memory-efficient manner
    sparse_tensor = tf.sparse.SparseTensor(indices=[[0, 0], [1, 2]],
                                           values=[1, 2],
                                           dense_shape=[3, 4])
    print(sparse_tensor, "\n")
    
    # You can convert sparse tensors to dense
    print(tf.sparse.to_dense(sparse_tensor))
    ---------------------------------------------------------------------
    SparseTensor(indices=tf.Tensor(
    [[0 0]
     [1 2]], shape=(2, 2), dtype=int64), values=tf.Tensor([1 2], shape=(2,), dtype=int32), dense_shape=tf.Tensor([3 4], shape=(2,), dtype=int64)) 
    
    tf.Tensor(
    [[1 0 0 0]
     [0 0 2 0]
     [0 0 0 0]], shape=(3, 4), dtype=int32)
    
    

    相关文章

      网友评论

        本文标题:TF2 基础 (2) : Tensor 介绍

        本文链接:https://www.haomeiwen.com/subject/ztiiaktx.html