参考:飞桨PaddlePaddle-源于产业实践的开源深度学习平台
#导入Paddle
import paddle
创建类似于vector的一维Tensor,其 ndim 为1
# 可通过dtype来指定Tensor数据类型,否则会创建float32类型的Tensor
tensor_1 = paddle.to_tensor([2.0, 3.0, 4.0], dtype='float64')
print(tensor_1)
# Tensor(shape=[3], dtype=float64, place=CUDAPlace(0), stop_gradient=True, [2., 3., 4.])
特殊地,如果仅输入单个scalar类型数据(例如float/int/bool类型的单个元素),则会创建shape为[1]的Tensor, 下面两种创建方式完全一致,shape均为[1]
paddle.to_tensor(2)
paddle.to_tensor([2])
同样地,还可以创建 ndim 为2、3、4...N等更复杂的多维Tensor
# Tensor可以有任意数量的轴(也称为维度)
tensor_2 = paddle.to_tensor([[[1, 2, 3, 4, 5],
[6, 7, 8, 9, 10]],
[[11, 12, 13, 14, 15],
[16, 17, 18, 19, 20]]])
print(tensor_2)
'''
Tensor(shape=[2, 2, 5], dtype=int32, place=CUDAPlace(0), stop_gradient=True,
[[[1 , 2 , 3 , 4 , 5 ],
[6 , 7 , 8 , 9 , 10]],
[[11, 12, 13, 14, 15],
[16, 17, 18, 19, 20]]])
'''
不同ndim的Tensor可视化表示:
通过 Tensor.numpy() 方法方便地将 Tensor 转化为 Numpy array:
tensor_2.numpy()
'''
array([[[1, 2, 3, 4, 5],
[ 6, 7, 8, 9, 10]],
[[11, 12, 13, 14, 15],
[16, 17, 18, 19, 20]]], dtype=int64)
'''
查看一个Tensor的形状可以通过 Tensor.shape,shape是 Tensor 的一个重要属性,以下为相关概念:
shape:描述了tensor的每个维度上元素的数量
ndim: tensor的维度数量,例如vector的 ndim 为1,matrix的 ndim 为2.
axis或者dimension:指tensor某个特定的维度
size:指tensor中全部元素的个数
对于一个4-D Tensor,下图为其以上几个概念间的关系
ndim_3_tensor = paddle.to_tensor([[[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]]])
print("the shape of ndim_3_tensor:", ndim_3_tensor.shape)
'''
the shape of ndim_3_tensor: [3, 2, 5]
'''
Paddle提供了reshape接口来改变Tensor的shape
ndim_3_tensor = paddle.reshape(ndim_3_tensor, [2, 5, 3])
print("After reshape:", ndim_3_tensor.shape)
'''
After reshape: [2, 5, 3]
'''
Tensor的数据类型,可以通过 Tensor.dtype 来查看,dtype支持:'bool','float16','float32','float64','uint8','int8','int16','int32','int64'。
通过Python元素创建的Tensor,可以通过dtype来进行指定,如果未指定:
对于python整型数据,则会创建int64型Tensor
对于python浮点型数据,默认会创建float32型Tensor,并且可以通过set_default_type来调整浮点型数据的默认类型。
通过Numpy array创建的Tensor,则与其原来的dtype保持相同。
通过索引或切片方便地访问或修改 Tensor。Paddle 使用标准的 Python 索引规则与 Numpy 索引规则,与 Indexing a list or a string in Python类似。具有以下特点:
基于 0-n 的下标进行索引,如果下标为负数,则从尾部开始计算
通过冒号 :
分隔切片参数 start:stop:step
来进行切片操作,其中 start、stop、step 均可缺省
# 针对1-D Tensor,则仅有单个轴上的索引或切片:
ndim_1_tensor = paddle.to_tensor([0, 1, 2, 3, 4, 5, 6, 7, 8])
print("Origin Tensor:", ndim_1_tensor.numpy())
print("First element:", ndim_1_tensor[0].numpy())
print("Last element:", ndim_1_tensor[-1].numpy())
print("All element:", ndim_1_tensor[:].numpy())
print("Before 3:", ndim_1_tensor[:3].numpy())
print("From 6 to the end:", ndim_1_tensor[6:].numpy())
print("From 3 to 6:", ndim_1_tensor[3:6].numpy())
print("Interval of 3:", ndim_1_tensor[::3].numpy())
print("Reverse:", ndim_1_tensor[::-1].numpy())
'''
Origin Tensor: [0 1 2 3 4 5 6 7 8])
First element: [0]
Last element: [8]
All element: [0 1 2 3 4 5 6 7 8]
Before 3: [0 1 2]
From 6 to the end: [6 7 8]
From 3 to 6: [3 4 5]
Interval of 3: [0 3 6]
Reverse: [8 7 6 5 4 3 2 1 0]
'''
# 针对2-D及以上的 Tensor,则会有多个轴上的索引或切片:
ndim_2_tensor = paddle.to_tensor([[0, 1, 2, 3],
[4, 5, 6, 7],
[8, 9, 10, 11]])
print("Origin Tensor:", ndim_2_tensor.numpy())
print("First row:", ndim_2_tensor[0].numpy())
print("First row:", ndim_2_tensor[0, :].numpy())
print("First column:", ndim_2_tensor[:, 0].numpy())
print("Last column:", ndim_2_tensor[:, -1].numpy())
print("All element:", ndim_2_tensor[:].numpy())
print("First row and second column:", ndim_2_tensor[0, 1].numpy())
'''
Origin Tensor: [[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]]
First row: [0 1 2 3]
First row: [0 1 2 3]
First column: [0 4 8]
Last column: [ 3 7 11]
All element: [[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]]
First row and second column: [1]
'''
索引或切片的第一个值对应 axis 0,第二个值对应 axis 1,以此类推,如果某个 axis 上未指定索引,则默认为 :
。
注意:
请慎重通过索引或切片修改 Tensor,该操作会原地修改该 Tensor 的数值,且原值不会被保存。如果被修改的 Tensor 参与梯度计算,将仅会使用修改后的数值,这可能会给梯度计算引入风险。Paddle 之后将会对具有风险的操作进行检测和报错。
与访问 Tensor 类似,修改 Tensor 可以在单个或多个轴上通过索引或切片操作。同时,支持将多种类型的数据赋值给该 Tensor,当前支持的数据类型有:int
, float
, numpy.ndarray
, Tensor
。
同时,Paddle 还提供了丰富的 Tensor 操作的 API,包括数学运算符、逻辑运算符、线性代数相关等100余种 API,这些 API 调用有两种方法
x = paddle.to_tensor([[1.1, 2.2], [3.3, 4.4]], dtype="float64")
y = paddle.to_tensor([[5.5, 6.6], [7.7, 8.8]], dtype="float64")
print(paddle.add(x, y), "\n")
print(x.add(y), "\n")
可以看出,使用 Tensor 类成员函数 和 Paddle API 具有相同的效果,由于 类成员函数 操作更为方便,以下均从 Tensor 类成员函数 的角度,对常用 Tensor 操作进行介绍。
#数学运算
x.abs() #逐元素取绝对值
x.ceil() #逐元素向上取整
x.floor() #逐元素向下取整
x.round() #逐元素四舍五入
x.exp() #逐元素计算自然常数为底的指数
x.log() #逐元素计算x的自然对数
x.reciprocal() #逐元素求倒数
x.square() #逐元素计算平方
x.sqrt() #逐元素计算平方根
x.sin() #逐元素计算正弦
x.cos() #逐元素计算余弦
x.add(y) #逐元素相加
x.subtract(y) #逐元素相减
x.multiply(y) #逐元素相乘
x.divide(y) #逐元素相除
x.mod(y) #逐元素相除并取余
x.pow(y) #逐元素幂运算
x.max() #指定维度上元素最大值,默认为全部维度
x.min() #指定维度上元素最小值,默认为全部维度
x.prod() #指定维度上元素累乘,默认为全部维度
x.sum() #指定维度上元素的和,默认为全部维度
# 逻辑运算
x.isfinite() #判断tensor中元素是否是有限的数字,即不包括inf与nan
x.equal_all(y) #判断两个tensor的全部元素是否相等,并返回shape为[1]的bool Tensor
x.equal(y) #判断两个tensor的每个元素是否相等,并返回shape相同的bool Tensor
x.not_equal(y) #判断两个tensor的每个元素是否不相等
x.less_than(y) #判断tensor x的元素是否小于tensor y的对应元素
x.less_equal(y) #判断tensor x的元素是否小于或等于tensor y的对应元素
x.greater_than(y) #判断tensor x的元素是否大于tensor y的对应元素
x.greater_equal(y) #判断tensor x的元素是否大于或等于tensor y的对应元素
x.allclose(y) #判断tensor x的全部元素是否与tensor y的全部元素接近,并返回shape为[1]的bool Tensor
# 线性代数相关
x.t() #矩阵转置
x.transpose([1, 0]) #交换axis 0 与axis 1的顺序
x.norm('fro') #矩阵的Frobenius 范数
x.dist(y, p=2) #矩阵(x-y)的2范数
x.matmul(y) #矩阵乘法
注意,Paddle中Tensor的操作符均为非inplace操作,即 x.add(y)
不会在tensor x上直接进行操作,而会返回一个新的Tensor来表示运算结果。
更多Tensor操作相关的API,请参考 class paddle.Tensor