创建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()
函数可以接受以下四种参数:
-
data,即要创建的tensor的数据元素内容,可以传入
scalar标量常数
、list列表
、tuple元组
、numpy ndarray
和paddle Tensor
五种数据类型中的任意一种,均可以成功创建tensor -
dtype,指定创建的tensor的数据类型,可以是
bool
、float16
、float32
、float64
、int8
、int16
、int32
、int64
、uint8
、complex64
、complex128
中的任意一种,tensor中所有元素的数据类型是保持一致的;如果未指定数据类型,则与输入的data的type保持一致
-
place,tensor存放的地方,可以是字符串
'cpu'
、'gpu_pinned'
和'gpu:x'
中的任意一种,其中"x"表示GPU的索引;注意:
paddle.CPUPlace
、paddle.CUDAPinnedPlace
、paddle.CUDAPlace
、paddle.XPUPlace
和paddle.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上的策略
-
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种函数:
-
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 ]]) """
可以看出,该函数并不初始化元素值,读到的元素值的内容取决于内存中未被覆盖的值。
-
paddle.zeros_like(x, dtype=None, name=None)
创建一个和tensor
x
的shape和dtype相同的元素全为0的Tensor类对象,如果指定dtype,则会进行类型转换。 -
paddle.ones_like(x, dtype=None, name=None)
创建一个和tensor
x
的shape和dtype相同的元素全为1的Tensor类对象,如果指定dtype,则会进行类型转换。 -
paddle.full_like(x, fill_value, dtype=None, name=None)
创建一个和tensor
x
的shape和dtype相同的Tensor类对象,元素值均为fill_value指定的常量数据,如果指定dtype,则会进行类型转换。注意:
fill_value
不要超过数据类型的范围。 -
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种函数,一些参数的用法和上文中的基本保持一致:
-
paddle.empty(shape, dtype=None, name=None)
创建形状大小为 shape 并且数据类型为 dtype 的 Tensor,其中元素值和上文中一样,是未初始化的。
shape指明了Tensor的形状,其数据结构可以是
list列表
、tuple元组
、numpy ndarray
和paddle 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中的其中一种。
-
paddle.zeros(shape, dtype=None, name=None)
创建形状为 shape 、数据类型为 dtype 且值全为 0 的 Tensor。
-
paddle.ones(shape, dtype=None, name=None)
创建一个形状为 shape、数据类型为 dtype且值全为 1 的 Tensor。
-
paddle.full(shape, fill_value, dtype=None, name=None)
创建形状大小为 shape 并且数据类型为 dtype 的 Tensor,其中元素值均为 fill_value 。
-
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
。 -
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()
函数指定的是生成的元素数量,所含元素的数量是给定的,间隔是根据区间和数量进行变化的 -
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并不参与梯度计算和梯度回传,需要自己进行更改。