zoukankan      html  css  js  c++  java
  • TensorFlow2.0(1):基本数据结构--张量

    1 创建

    1.1 constant()方法

    import tensorflow as tf
    tf.constant(1)      #创建一个整型张量
    <tf.Tensor: id=4, shape=(), dtype=int32, numpy=1>
    tf.constant(1.) #创建一个浮点型张量 <tf.Tensor: id=5, shape=(), dtype=float32, numpy=1.0>
    tf.constant(2., dtype=tf.double) #创建的同时指定数据类 <tf.Tensor: id=6, shape=(), dtype=float64, numpy=2.0>
    tf.constant([[1,2,3],[4,5,6]]) #通过传入一个list创建 <tf.Tensor: id=7, shape=(2, 3), dtype=int32, numpy= array([[1, 2, 3], [4, 5, 6]], dtype=int32)>

          tf.is_tensor(a)可以用来判断a是否为一个tensor。

          系统的每个模块使用的数据类型、数值精度可能各不相同,对于不符合要求的张量的类型及精度,需要通过tf.cast函数进行转换。例如:将数据类型为浮点型的a转换为整型:tf.cast(a, tf.int32)。

          为了区分需要计算梯度信息的张量和不需要计算梯度信息的张量,TensorFlow增加了一种专门的数据类型来支持梯度信息的记录:tf.Variable。tf.Variable类型在普通的张量类型基础上添加了name,trainable等属性来支持计算图的构建。由于梯度运算会消耗大量的计算资源,而且会自动更新相关参数,对于不需要优化的张量,如神经网络的输入X,不需要通过tf.Variable封装;相反,对于需要计算梯度并优化的张量,如神经网络层的W和b,需要通过tf.Variable包裹以便TensorFlow跟踪相关梯度信息。

          通过tf.Variable()函数可以将普通张量转换为待优化张量:

    a = tf.constant([-1,0,1,2])
    aa = tf.Variable(a)
    aa.name, aa.trainable
    ('Variable:0', True)

          其中张量的name和trainable属性是Variable特有的属性,name属性用于命名计算图的变量,这套命名体系是TensorFlow内部维护的,一般不需要用户关注name属性;trainable表征当前张量是否需要被优化,创建Variable对象时默认启用优化标志,可以设置trainable=False来设置张量不需要优化。

          除了通过普通张量方式创建Variable,也可以直接创建:

    a = tf.Variable([[1,2],[3,4]])

    1.2 convert_to_tensor()方法

    import numpy as np
    tf.convert_to_tensor(np.ones([2,3])) <tf.Tensor: id=8, shape=(2, 3), dtype=float64, numpy= array([[1., 1., 1.], [1., 1., 1.]])>
    tf.convert_to_tensor([[2., 3.],[3., 4.]]) <tf.Tensor: id=10, shape=(2, 2), dtype=float32, numpy= array([[2., 3.], [3., 4.]], dtype=float32)>

          需要注意的是,numpy中浮点数数组默认使用64-Bit精度保存数据,转换到Tensor类型时精度为tf.float64,可以在需要的时候转换到tf.float32类型。 

    1.3 创建元素为指定值的tensor

          如果熟悉numpy创建数组的方法,一定见过zeros()、ones()等方法,TensorFlow中也有这些方法。

          (1)zeros()和ones()

    a = tf.zeros([2, 3, 3])     #创建一个元素全为0,形状为[2,3,3]的tensor
    b = tf.ones([2, 3])     #创建一个元素全为1,形状为[2,3]的tensor

          (2)zeros_like()和ones_like()

    tf.zeros_like(b)     #仿照b的shape创建一个全为0的tensor

    tf.ones_like(a)     #仿照a的shape创建一个全为1的tensor

          (3)fill()。通过tf.fill(shape, value)可以创建全为自定义数值value的张量。

    tf.fill([2,3],5)     #创建元素全为5,形状为[2,3]的tensor
    

    1.4 随机初始化

          在实际应用中,经常需要随机初始化元素服从某种分布的tensor,TensorFlow中也提供了这种功能。

          (1)从指定正态分布中随机取值:tf.random.normal()

          例如,随机初始化一个元素服从均值为1,方差为1的正态分布且形状为[2, 3]的tensor 。

    tf.random.normal([2, 3], mean=1, stddev=1) # mean为均值,stddev为标准差
    

          (2)从指定的截断正态分布中随机取值:truncated_normal()

          意思是从指定的正态分布中取值,但是取值范围在两个标准差范围内,也就是:[mean - 2 * stddev, mean + 2 * stddev]。

    tf.random.truncated_normal([2, 3], mean=1, stddev=1)
    

          (3)从指定均匀分布中随机取值:tf.random.uniform()

    tf.random.uniform([2, 3], minval=1, maxval=2)     #在1-2之间均匀分布
    

          在循环计算或者对张量进行索引时,经常需要创建一段连续的整型序列,可以通过tf.range()函数实现。tf.range(limit, delta=1)可以 创建[0,limit)之间,步长为delta的整型序列。例如,创建0~9,步长为2的整型序列:

    tf.range(10,delta=2)
    <tf.Tensor: id=34, shape=(5,), dtype=int32, numpy=array([0, 2, 4, 6, 8], dtype=int32)>

    2 索引

    2.1 基础索引

          TensorFlow支持Python原生的基础索引方式,即多个方括号逐步索引取值:[idx][idx][idx],每个方括号对应一个维度。

    a = tf.convert_to_tensor(np.arange(80).reshape(2,2,4,5))
    a
    <tf.Tensor: id=43, shape=(2, 2, 4, 5), dtype=int64, numpy=
    array([[[[ 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],
             [30, 31, 32, 33, 34],
             [35, 36, 37, 38, 39]]],
    
    
           [[[40, 41, 42, 43, 44],
             [45, 46, 47, 48, 49],
             [50, 51, 52, 53, 54],
             [55, 56, 57, 58, 59]],
    
            [[60, 61, 62, 63, 64],
             [65, 66, 67, 68, 69],
             [70, 71, 72, 73, 74],
             [75, 76, 77, 78, 79]]]])>
    a[0]     #取第一个维度
    <tf.Tensor: id=47, shape=(2, 4, 5), dtype=int64, numpy=
    array([[[ 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],
            [30, 31, 32, 33, 34],
            [35, 36, 37, 38, 39]]])>
    a[0][1]     #同时筛选两个维度
    <tf.Tensor: id=55, shape=(4, 5), dtype=int64, numpy=
    array([[20, 21, 22, 23, 24],
           [25, 26, 27, 28, 29],
           [30, 31, 32, 33, 34],
           [35, 36, 37, 38, 39]])>
    a[0][1][3][3]     #同时对4个维度进行筛选
    <tf.Tensor: id=71, shape=(), dtype=int64, numpy=38>

          这种索引数据的方法简单,易于理解,但是可读性差,只能按维度依次索引数据,也不能索引列。

    2.2 numpy索引

          (1)[idx1, idx2, idx3]

          这种索引方式是在一个方括号内写下所有的索引,每个索引序号之间用逗号隔开。

    a[1]     #筛选第一维度,这跟基础索引一样
    <tf.Tensor: id=75, shape=(2, 4, 5), dtype=int64, numpy=
    array([[[40, 41, 42, 43, 44],
            [45, 46, 47, 48, 49],
            [50, 51, 52, 53, 54],
            [55, 56, 57, 58, 59]],
    
           [[60, 61, 62, 63, 64],
            [65, 66, 67, 68, 69],
            [70, 71, 72, 73, 74],
            [75, 76, 77, 78, 79]]])>
    a[1, 1, 3]     #同时筛选3个维度
    <tf.Tensor: id=79, shape=(5,), dtype=int64, numpy=array([75, 76, 77, 78, 79])>

          (2)冒号切片与步长:[start:end:step]

          这种索引方式在Python原生的list类型中也是常见的,而且使用方法也是一样的。

    a[1,:,0:2]     #对第一维度选第二块数据,对第二维度选所有数据,对第三维度选前两行
    <tf.Tensor: id=83, shape=(2, 2, 5), dtype=int64, numpy=
    array([[[40, 41, 42, 43, 44],
            [45, 46, 47, 48, 49]],
    
           [[60, 61, 62, 63, 64],
            [65, 66, 67, 68, 69]]])>
    a[1,:,0:2,0:4]     #继续上面的例子,对第4维度筛选去前4列
    <tf.Tensor: id=87, shape=(2, 2, 4), dtype=int64, numpy=
    array([[[40, 41, 42, 43],
            [45, 46, 47, 48]],
    
           [[60, 61, 62, 63],
            [65, 66, 67, 68]]])>
    a[1,:,0:2,0:4:2]     #对第4维度加上步长,每隔一个数据取一次
    <tf.Tensor: id=91, shape=(2, 2, 2), dtype=int64, numpy=
    array([[[40, 42],
            [45, 47]],
    
           [[60, 62],
            [65, 67]]])>

          也可以使用负值步长表示逆序索引,但需要注意,负数步长时,原本的[start:end:step]也要跟着变成[end:start:step]。

    a[1,:,0:2,4:0:-1]
    <tf.Tensor: id=95, shape=(2, 2, 4), dtype=int64, numpy=
    array([[[44, 43, 42, 41],
            [49, 48, 47, 46]],
    
           [[64, 63, 62, 61],
            [69, 68, 67, 66]]])>

          在numpy和TensorFlow中还有“...”(三个英文句号)的使用,“...”用于表示连续多个维度全选。

    a[1,...,0:4]     #等同于a[1,:,:,0:4]
    <tf.Tensor: id=99, shape=(2, 4, 4), dtype=int64, numpy=
    array([[[40, 41, 42, 43],
            [45, 46, 47, 48],
            [50, 51, 52, 53],
            [55, 56, 57, 58]],
    
           [[60, 61, 62, 63],
            [65, 66, 67, 68],
            [70, 71, 72, 73],
            [75, 76, 77, 78]]])>
    a[0,0,...]     #等同于a[0,0,:,:]
    <tf.Tensor: id=103, shape=(4, 5), dtype=int64, numpy=
    array([[ 0,  1,  2,  3,  4],
           [ 5,  6,  7,  8,  9],
           [10, 11, 12, 13, 14],
           [15, 16, 17, 18, 19]])>

     2.3 gather与gather_nd

          gather与gather_nd是指TensorFlow通过gather()方法和gather_nd()方法提供的两种索引方式。在numpy中,可以通过嵌套list的方式来指定无规则的索引。

    b = print(np.arange(20).reshape(4,5))
    array([[ 0,  1,  2,  3,  4],
           [ 5,  6,  7,  8,  9],
           [10, 11, 12, 13, 14],
           [15, 16, 17, 18, 19]])

    b[1, [0,3,4]]     #选取第2行的第1列、第4列、第5列
    array([5, 8, 9])

          但是在TensorFlow中,这种索引方式并没有从numpy中继承下来,所以如果在Tensor中使用这种方式,会抛出异常。在TensorFlow中通过gather()方法和gather_nd()方法提供了这种索引方式。

          (1)gather()方法

    tf.gather(b,axis=0,indices=[0,2,3])     #选取第1行,第3行,第4行
    <tf.Tensor: id=107, shape=(3, 5), dtype=int64, numpy=
    array([[ 0,  1,  2,  3,  4],
           [10, 11, 12, 13, 14],
           [15, 16, 17, 18, 19]])>
    tf.gather(b,axis=1,indices=[0,2,3])     #选取第1列,第3列,第4列
    <tf.Tensor: id=111, shape=(4, 3), dtype=int64, numpy=
    array([[ 0,  2,  3],
           [ 5,  7,  8],
           [10, 12, 13],
           [15, 17, 18]])>

          通过上面gather()方法的例子可以看出,第一个参数是数据源,还有两个参数中,axis指的是将要的维度,indices指的是需要选取的序号。

          (2)gather_nd()

          gather()方法一次只能对一个维度进行索引,gather_nd()方法可以同时对多个维度进行索引。

    tf.gather_nd(b,[[0,2],[3,3]])     #选取第1行第三列的数据,以及第4行第4列的数据
    <tf.Tensor: id=114, shape=(2,), dtype=int64, numpy=array([ 2, 18])>

     2.4 条件索引

          可以结合一些简单的逻辑运算符进行索引取值。

    a = tf.random.uniform([3,3],minval=-10,maxval=10,dtype=tf.int32)
    a
    <tf.Tensor: id=118, shape=(3, 3), dtype=int32, numpy=
    array([[-5, -6,  1],
           [ 5,  2, -7],
           [ 3, -2, -3]], dtype=int32)>
    mask = a < 0
    mask
    <tf.Tensor: id=120, shape=(3, 3), dtype=bool, numpy=
    array([[ True,  True, False],
           [False, False,  True],
           [False,  True,  True]])>

          可以看到,返回的是一个shape与a相同的tensor,在a小于0的位置是True,大于0的位置为False。进一步地,我们可以用boolean_mask()方法直接获取符合条件的元素。

    tf.boolean_mask(a,mask)
    <tf.Tensor: id=147, shape=(5,), dtype=int32, numpy=array([-5, -6, -7, -2, -3], dtype=int32)>

          可以结合where()方法取出符合条件元素的索引。

    m_index = tf.where(mask)
    m_index
    <tf.Tensor: id=148, shape=(5, 2), dtype=int64, numpy=
    array([[0, 0],
           [0, 1],
           [1, 2],
           [2, 1],
           [2, 2]])>

          再使用之前说过的gather_nd()方法取值。

    tf.gather_nd(a,m_index)
    <tf.Tensor: id=149, shape=(5,), dtype=int32, numpy=array([-5, -6, -7, -2, -3], dtype=int32)>

          where()方法还有第二种用法--从两个tensor中取出符合条件的值,这时候where()方法必须接收3个参数。

    condition = tf.random.uniform([3,3],minval=0,maxval=2,dtype=tf.int32)
    condition = tf.cast(condition,tf.bool)
    condition
    <tf.Tensor: id=154, shape=(3, 3), dtype=bool, numpy=
    array([[False, False, False],
           [ True,  True,  True],
           [ True, False, False]])>
    a = tf.range(1,10)
    a = tf.reshape(a,[3,3])
    a
    <tf.Tensor: id=160, shape=(3, 3), dtype=int32, numpy=
    array([[1, 2, 3],
           [4, 5, 6],
           [7, 8, 9]], dtype=int32)>
    b = tf.range(-9,0)
    b = tf.reshape(b,[3,3])
    b
    <tf.Tensor: id=166, shape=(3, 3), dtype=int32, numpy=
    array([[-9, -8, -7],
           [-6, -5, -4],
           [-3, -2, -1]], dtype=int32)>
    tf.where(condition,a,b)
    <tf.Tensor: id=167, shape=(3, 3), dtype=int32, numpy=
    array([[-9, -8, -7],
           [ 4,  5,  6],
           [ 7, -2, -1]], dtype=int32)>

          上面where()方法返回的结果在True的位置取指是a中对应位置元素的值,在False位置是b中对应元素的值。

    3 维度变换

    3.1 reshape()

          numpy中的ndarray数组有一个reshape()方法,用来改变数组的shape,TensorFlow中的reshape()方法,功能也是一样的,不过TensorFlow中的reshape()没有绑定到tensor中。

    a = tf.ones([2,3,4])
    a.shape
    TensorShape([2, 3, 4])
    a
    <tf.Tensor: id=170, shape=(2, 3, 4), dtype=float32, numpy=
    array([[[1., 1., 1., 1.],
            [1., 1., 1., 1.],
            [1., 1., 1., 1.]],
    
           [[1., 1., 1., 1.],
            [1., 1., 1., 1.],
            [1., 1., 1., 1.]]], dtype=float32)>
    b = tf.reshape(a,[2,2,6])
    b.shape
    TensorShape([2, 2, 6])
    b
    <tf.Tensor: id=172, shape=(2, 2, 6), dtype=float32, numpy=
    array([[[1., 1., 1., 1., 1., 1.],
            [1., 1., 1., 1., 1., 1.]],
    
           [[1., 1., 1., 1., 1., 1.],
            [1., 1., 1., 1., 1., 1.]]], dtype=float32)>

          从上面的例子可以看出,通过reshape()方法可以很方便的改变tensor的形状,得到一个新的tensor,需要注意的是在进行维度变换时,数据的总量是不变的,如果对应不上,就会产生异常。

    3.2 转置:transpose()

    a = tf.constant([[1,2,3],[4,5,6]])
    a.shape
    TensorShape([2, 3])
    b = tf.transpose(a)
    b.shape
    TensorShape([3, 2])

    3.3 添加维度:tf.expand_dims(x,axis)可在指定的axis轴前插入一个新的维度

    a = tf.constant([[1,2,3],[4,5,6]])
    a
    <tf.Tensor: id=183, shape=(2, 3), dtype=int32, numpy=
    array([[1, 2, 3],
           [4, 5, 6]], dtype=int32)>
    tf.expand_dims(a,axis=0)
    <tf.Tensor: id=185, shape=(1, 2, 3), dtype=int32, numpy=
    array([[[1, 2, 3],
            [4, 5, 6]]], dtype=int32)>
    tf.expand_dims(a,axis=1)
    <tf.Tensor: id=187, shape=(2, 1, 3), dtype=int32, numpy=
    array([[[1, 2, 3]],
    
           [[4, 5, 6]]], dtype=int32)>
    tf.expand_dims(a,axis=-1)
    <tf.Tensor: id=189, shape=(2, 3, 1), dtype=int32, numpy=
    array([[[1],
            [2],
            [3]],
    
           [[4],
            [5],
            [6]]], dtype=int32)>
    tf.expand_dims(a,axis=2)
    <tf.Tensor: id=191, shape=(2, 3, 1), dtype=int32, numpy=
    array([[[1],
            [2],
            [3]],
    
           [[4],
            [5],
            [6]]], dtype=int32)>

          expand_dims()方法添加维度时,通过axis参数指定添加维度的位置,正数表示从前往后数,负数表示从后往前数。

    3.4 压缩维度:squeeze()

          squeeze()方法与expand_dims()方法作用刚好相反,其作用是删除张量中dim为1的维度。

    a = tf.ones([1,3,1,2])
    a
    <tf.Tensor: id=194, shape=(1, 3, 1, 2), dtype=float32, numpy=
    array([[[[1., 1.]],
    
            [[1., 1.]],
    
            [[1., 1.]]]], dtype=float32)>
    tf.squeeze(a)  # 也可以用axis来指定删除的维度:tf.squeeze(a,axis=2)
    <tf.Tensor: id=195, shape=(3, 2), dtype=float32, numpy=
    array([[1., 1.],
           [1., 1.],
           [1., 1.]], dtype=float32)>
  • 相关阅读:
    C# 时间+三位随机数
    dataGridView加行标识方法与制作
    MySql多列查询
    php 去掉字符串的最后一个字符
    DataTable 排序
    汇编第一个程序 Hello World (初学者与入门)
    C# 获取前一天,明天,本周,上周,本季度等!
    php 字符串中任意添加
    天涯论坛的经典回帖!!!
    系统时间同步
  • 原文地址:https://www.cnblogs.com/chenjin2018/p/13708327.html
Copyright © 2011-2022 走看看