【PaddlePaddle】创建Tensor的两种方式:指定数据和指定形状

创建Tensor

指定数据,进行创建

使用paddle.to_tensor()函数可以创建一个任意维度的tensor,其数据结构为paddle.Tensor类

a = [[1, 2, 3],
     [4, 5, 6],
     [7, 8, 9]]
a_tensor = paddle.to_tensor(a)
pring(a)

"""
输出:
Tensor(shape=[3, 3], dtype=int64, place=Place(gpu:0), stop_gradient=True,
       [[1, 2, 3],
        [4, 5, 6],
        [7, 8, 9]])
"""

paddle.to_tensor()函数可以接受以下四种参数:

  1. data,即要创建的tensor的数据元素内容,可以传入scalar标量常数list列表tuple元组numpy ndarraypaddle Tensor五种数据类型中的任意一种,均可以成功创建tensor

  2. dtype,指定创建的tensor的数据类型,可以是boolfloat16float32float64int8int16int32int64uint8complex64complex128中的任意一种,tensor中所有元素的数据类型是保持一致的

    如果未指定数据类型,则与输入的data的type保持一致

  3. place,tensor存放的地方,可以是字符串'cpu''gpu_pinned''gpu:x'中的任意一种,其中"x"表示GPU的索引;

    注意:paddle.CPUPlacepaddle.CUDAPinnedPlacepaddle.CUDAPlacepaddle.XPUPlacepaddle.IPUPlace是不可以当作参数传入place。

    当不传入任何参数时,会对环境进行解析,paddle源码中做如下操作:

    def _current_expected_place():
        global _global_expected_place_
        if _global_expected_place_ is None:
            if core.is_compiled_with_cuda():
                try:
                    device_count = core.get_cuda_device_count()
                except Exception as e:
                    device_count = 0
                if device_count > 0:
                    _global_expected_place_ = core.CUDAPlace(_cuda_ids()[0])
                else:
                    warnings.warn(
                        "You are using GPU version Paddle, but your CUDA device is not set properly. CPU device will be used by default."
                    )
                    _global_expected_place_ = core.CPUPlace()
            elif core.is_compiled_with_xpu():
                try:
                    device_count = core.get_xpu_device_count()
                except Exception as e:
                    device_count = 0
                if device_count > 0:
                    _global_expected_place_ = core.XPUPlace(_xpu_ids()[0])
                else:
                    warnings.warn(
                        "You are using XPU version Paddle, but your XPU device is not set properly. CPU device will be used by default."
                    )
                    _global_expected_place_ = core.CPUPlace()
            elif len(core.get_all_custom_device_type()) > 0:
                dev_type = core.get_all_custom_device_type()[0]
                try:
                    device_count = core.get_custom_device_count(dev_type)
                except Exception as e:
                    device_count = 0
                if device_count > 0:
                    _global_expected_place_ = core.CustomPlace(
                        dev_type, _custom_device_ids(dev_type)[0]
                    )
                else:
                    warnings.warn(
                        "You are using CUSTOM_DEVICE version Paddle, but your custom device is not set properly. CPU device will be used by default."
                    )
                    _global_expected_place_ = core.CPUPlace()
            else:
                _global_expected_place_ = core.CPUPlace()
    
        return _global_expected_place_
    

    可以看到,不传入参数时会进行判断:

    • 如果paddle内核是由cuda编译的,则将place设置为0号显卡,否则继续向下判断
    • 如果paddle内核是xpu编译的,则放在0号xpu上,否则继续向下判断
    • 寻找除cpu外可以使用的设备,如果没有,则放在cpu上

    因此我们需要知道,和pytorch不同,paddle会首先采取将数据放在GPU上的策略

  4. stop_gradient,默认为True,指禁止该tensor进行自动求梯度和梯度回传

从输出也可以看出,paddle.Tensor类也拥有以上四种属性,同时还增加了shape这一属性,那么就可以直接对这些属性进行访问:

print(a_tensor.shape)
print(a_tensor.dtype)
print(a_tensor.place)

"""
输出:
[3, 3]
paddle.int64
Place(gpu:0)
"""

但是我们发现,无法使用a_tensor.data来对数据内容直接进行访问,但是可以通过.value.values.item访问到一个中间类,和Tensor类可以说是一模一样:

pring(a_tensor.item)

"""
输出:
<bound method monkey_patch_tensor.<locals>.item of Tensor(shape=[3, 3], dtype=int64, place=Place(gpu:0), stop_gradient=True,
       [[1, 2, 3],
        [4, 5, 6],
        [7, 8, 9]])>
"""

最后我们需要明确:基于给定数据创建 Tensor 时,paddle是通过拷贝方式创建,与原始数据不共享内存。也就是说对a_tensor的操作并不会影响到a的值,二者是独立的两个个体。

指定形状,进行创建

这种方法并不严格规定需要指定数据元素的内容,而是聚焦于tensor的形状上,主要有以下两种类型:

有其他tensor做模板

即创建一个与其他 Tensor 具有相同 shape 与 dtype 的 Tensor,常用的是以下4种函数:

  1. paddle.empty_like(x, dtype=None, name=None)

    创建一个和tensor x的shape和dtype相同的空的Tensor类对象(尚未初始化元素值的tensor),如果指定dtype,则会进行类型转换。

    empty_tensor = paddle.empty_like(a_tensor)
    print(empty_tensor)
    
    """
    输出:
    Tensor(shape=[3, 3], dtype=int64, place=Place(gpu:0), stop_gradient=True,
           [[4620693218757967872, 4620693218757967872, 4652218416156901376],
            [4652218416156901376, 0                  , 0                  ],
            [0                  , 0                  , 0                  ]])
    """
    

    可以看出,该函数并不初始化元素值,读到的元素值的内容取决于内存中未被覆盖的值

  2. paddle.zeros_like(x, dtype=None, name=None)

    创建一个和tensor x的shape和dtype相同的元素全为0的Tensor类对象,如果指定dtype,则会进行类型转换。

  3. paddle.ones_like(x, dtype=None, name=None)

    创建一个和tensor x的shape和dtype相同的元素全为1的Tensor类对象,如果指定dtype,则会进行类型转换。

  4. paddle.full_like(x, fill_value, dtype=None, name=None)

    创建一个和tensor x的shape和dtype相同的Tensor类对象,元素值均为fill_value指定的常量数据,如果指定dtype,则会进行类型转换。

    注意:fill_value不要超过数据类型的范围。

  5. paddle.clone(x, name=None)

    对输入 tensor x 进行拷贝,并返回一个新的 Tensor类对象。

    除此之外,该 API 提供梯度计算,在计算反向时,输出 Tensor 的梯度将会回传给输入 Tensor(这里的回传应该是对clone_x求梯度也会导致对x求梯度,共享梯度?)

    x = paddle.ones([2])
    x.stop_gradient = False
    clone_x = paddle.clone(x)
    
    y = clone_x**3
    y.backward()
    print(clone_x.grad)          # [3]
    print(x.grad)                # [3]
    

没有其他tensor做模板

即根据 shape 和 dtype 创建一个满足特定分布的Tensor,常用的是以下10种函数,一些参数的用法和上文中的基本保持一致:

  1. paddle.empty(shape, dtype=None, name=None)

    创建形状大小为 shape 并且数据类型为 dtype 的 Tensor,其中元素值和上文中一样,是未初始化的。

    shape指明了Tensor的形状,其数据结构可以是list列表tuple元组numpy ndarraypaddle Tensor四种数据类型中的任意一种,只要能表示一个数组就可以(甚至可以是Tensor组成的list)。

    # shape = 3  # error
    # shape = [3]  # ok
    # shape = (3)  # error
    # shape = (3, 2)  # ok
    # shape = np.array([3, 2])  # ok
    shape = paddle.to_tensor([3, 2])  # ok
    empty_tensor = paddle.empty(shape=shape)
    print(empty_tensor)
    

    显然,3和(3)都表示的是一个int整数,所以会报错。

    注意:shape的内容表示的是各个维度的大小,因此,只能为int32或int64中的其中一种

  2. paddle.zeros(shape, dtype=None, name=None)

    创建形状为 shape 、数据类型为 dtype 且值全为 0 的 Tensor。

  3. paddle.ones(shape, dtype=None, name=None)

    创建一个形状为 shape、数据类型为 dtype且值全为 1 的 Tensor。

  4. paddle.full(shape, fill_value, dtype=None, name=None)

    创建形状大小为 shape 并且数据类型为 dtype 的 Tensor,其中元素值均为 fill_value 。

  5. paddle.arange(start=0, end=None, step=1, dtype=None, name=None)

    返回的Tensor对象是一个一维tensor,元素内容为给定区间 [ s t a r t , e n d ) [start,end) [start,end) 以step为均匀间隔的连续元素。

    注意:当 dtype 表示浮点类型时,为了避免浮点计算误差,建议给 end 加上一个极小值 epsilon,使边界可以更加明确。

    arange_tensor1 = paddle.arange(10)
    arange_tensor2 = paddle.arange(10, 2, step=-1)
    arange_tensor3 = paddle.arange(10, step=2)
    print(arange_tensor1)
    print(arange_tensor2)
    print(arange_tensor3)
    
    """
    输出:
    Tensor(shape=[10], dtype=int64, place=Place(gpu:0), stop_gradient=True,
           [0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
    
    Tensor(shape=[8], dtype=int64, place=Place(gpu:0), stop_gradient=True,
           [10, 9 , 8 , 7 , 6 , 5 , 4 , 3 ])
    
    Tensor(shape=[5], dtype=int64, place=Place(gpu:0), stop_gradient=True,
           [0, 2, 4, 6, 8])
    """
    

    start默认为0,当该函数只传入一个参数时规定的是end值,当传入2个及以上参数的时候建议显式指明参数名称,避免将step错传给end

  6. paddle.linspace(start, stop, num, dtype=None, name=None)

    返回的Tensor对象是一个一维tensor,元素内容为给定区间 [ s t a r t , e n d ) [start,end) [start,end) 数量为num个的均匀间隔的连续元素。

    data = paddle.linspace(0, 10, 5, 'float32') # [0.0,  2.5,  5.0,  7.5, 10.0]
    data = paddle.linspace(0, 10, 1, 'float32') # [0.0]
    

    arange和linspace两种函数的区别:

    上面的paddle.arange()函数是指定了生成的间隔,所含元素的数量是根据区间和间隔而变化的,而paddle.linspace()函数指定的是生成的元素数量,所含元素的数量是给定的,间隔是根据区间和数量进行变化的

  7. paddle.rand(shape, dtype=None, name=None)paddle.randn(shape, dtype=None, name=None)paddle.randint(low=0, high=None, shape=[1], dtype=None, name=None)paddle.randperm(n, dtype='int64', name=None)

    这四个函数的用法都非常相似,只是随机的内容不一样

    • rand产生的是范围在0到1之间的、符合均匀概率分布的随机数

    • randn产生的是符合标准正态分布的随机数

    • randint产生的是范围在low到high之间的、符合均匀概率分布的随机数

    • randperm产生的是范围在0到n之间的连续数(step=1),但排列顺序随机

      out1 = paddle.randperm(5)
      # [4, 1, 2, 3, 0]  # random
      out2 = paddle.randperm(7, 'int32')
      # [1, 6, 2, 0, 4, 3, 5]  # random
      

值得注意的是,这些创建的Tensor中的stop_gradient的属性均为True,意味着单独创建的Tensor并不参与梯度计算和梯度回传,需要自己进行更改。

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值