背景
在深度学习框架中,张量(Tensor)是数据表示和运算的核心载体,Paddle作为国产主流深度学习框架,提供了丰富且高效的张量操作算子,覆盖从基础创建到复杂运算的全流程。本文将系统梳理Paddle中最常用的张量相关算子,结合代码示例与应用场景,助你快速掌握张量操作的核心技能。
一、张量创建:从基础初始化到随机生成
张量创建是所有深度学习的任务起点,Paddle提供了多种灵活创建Tensor的方式,满足不同场景下的数据初始化需求。
1、基础数值初始化
paddle.to_tensor
将Python列表、Numpy数据转换为张量
ini
import paddle
x = paddle.to_tensor([1,2,3])
arr = np.array([[4,5],[6,7]])
y = paddle.to_tensor(arr)
paddle.zeros/paddle.ones/paddle.full
创建全0、1或者指定的张量
ini
zeros = paddle.zeros(shape=[2,3])
ones = paddle.ones(shape=[2,3])
filled = paddle.full(shape=[2,3], fill_value=5)
paddle.arange
生成等差数列张量
ini
seq = paddle.arange(start=0, end=10, step=2) # [0,2,4,6,8]
2、随机张量生成
paddle.rand
随机张量生成
ini
random_uniform = paddle.rand(shape=[2,3])
paddle.randn
标准正态分布随机数(均值0,方差1)
ini
random_normal = paddle.randn(shape=[2,3])
二、张量切片与索引:精准访问数据元素
灵活的索引与切片操作是张量数据处理的基础,Paddle支持与Numpy类似的索引语法,同时提供高级操作接口
1、基础索引与切片
- 单元素索引:通过[维度1,维度2]访问元素
lua
x = paddle.to_tensor([[1,2],[3,4]])
print(x[0,1])
x[0,1] = 5
- 切片操作:使用
start:end:step
格式截取子张量
ini
arr = paddle.arange(10)
print(arr[2:7:2] ) # 2,4,6 从索引2到6,步长为2
2、高级索引结构
paddle.gather
:根据索引收集元素
ini
x = paddle.to_tensor([10,20,30,40])
indices = paddle.to_tensor([0,2,3])
gatherd = paddle.gather(x, indices) # 结果:[10,30,40]
paddle.where
根据条件选择元素
ini
cond = paddle.to_tensor([True, False, True])
a = paddle.to_tensor([1,2,3])
b = paddle.to_tensor([10,20,30])
result = paddle.where(cond, a, b) # 结果[1,20,3], 如果a对应的元素为True就选a,否则选b
三、张量形状变换:重塑与维度操作
在模型结构构建中,张量形状的灵活变换是适配网络层输入输出的关键,Paddle提供了丰富的形状操作算子。
1、维度调整
paddle.reshape
改变张量形状
ini
x = paddle.arange(6) # 形状[6]
reshape = paddle.reshape(x, [2,3])
paddle.squeeze/paddle.unsqueeze
移除或添加维度为1的轴
ini
x = paddle.ones([1,3,1,5])
squeezed = paddle.squeeze(x) # 形状变为[3,5]
unsqueezed = paddle.unsqueeze(squeezed, 0) 形状变为[1,2,5]
2、张量拼接与分割
paddle.concat
沿指定轴连接多个张量
ini
a = paddle.ones([2,3])
b = paddle.zeros([2,3])
concatenated = paddle.concat([a,b], axis=0) # 形状变为[4,3]
paddle.stack
在新轴上堆叠张量
ini
stacked = paddle.stack([a,b], axis=1) # 形状变为[2,2,3]
四、张量数学运算:从逐元素到矩阵操作
张量运算是深度学习模型的核心计算逻辑,Paddle支持高效的向量化运算,大幅提升计算效率。
1、逐元素运算
- 基础算术运算:加(paddle.add)、减(paddle.subtract)、乘(paddle.multiply)、除(paddle.divide)
css
a = paddle.to_tensor([1,2,3])
b = paddle.to_tensor([4,5,6])
add_result = a + b
- 数学函数:绝对值paddle.abs、平方根paddle.sqrt、指数对数paddle.exp/paddle.log
ini
x = paddle.to_tensor([-1, 4, 9])
abs_x = paddle.abs(x) # [1, 4, 9]
sqrt_x = paddle.sqrt(x) # [1, 2, 3]
2、矩阵与归约运算
- 矩阵乘法 :
paddle.matmul
(支持广播机制)
lua
x = paddle.to_tensor([[1, 2], [3, 4]])
y = paddle.to_tensor([[5, 6], [7, 8]])
matmul_xy = paddle.matmul(x, y) # 矩阵乘法,结果[[19, 22], [43, 50]]
- 归约运算 :求和(
paddle.sum
)、均值(paddle.mean
)、最大值(paddle.max
)
ini
x = paddle.to_tensor([[1, 2], [3, 4]])
sum_all = paddle.sum(x) # 总和10
mean_cols = paddle.mean(x, axis=0) # 按列求均值[2, 3]
五、广播机制:不同形状的张量的高效运算
Paddle 的广播机制允许形状不同的张量直接进行运算,系统会自动扩展维度以适配运算需求,大幅简化代码逻辑。
1、广播规则示例
当张量 A 形状为 [2, 1]
,张量 B 形状为 [1, 3]
,二者相加时:
- A 会被广播为
[2, 3]
(列维度扩展),B 会被广播为[2, 3]
(行维度扩展)。
ini
a = paddle.ones([2, 1])
b = paddle.ones([1, 3])
c = a + b # c的形状为[2, 3],每个元素值为2
2、广播与性能优化
广播机制避免了显式扩展张量维度带来的内存开销,但在处理超大张量时,仍需注意隐含的计算量。建议在明确广播逻辑后,根据实际场景选择显式reshape
或直接使用广播。
六、特殊张量操作:高级功能与应用场景
除基础操作外,Paddle 还提供了一系列解决特定问题的高级张量算子,助力复杂模型构建。
1、 独热编码与维度变换
paddle.nn.functional.one_hot
:生成独热编码张量
ini
labels = paddle.to_tensor([0, 2, 1])
one_hot = paddle.nn.functional.one_hot(labels, num_classes=3)
# 结果:[[1, 0, 0], [0, 0, 1], [0, 1, 0]]
2、张量散射与聚合
paddle.scatter
:将值按索引散布到张量中
ini
x = paddle.zeros([5])
indices = paddle.to_tensor([1, 3])
updates = paddle.to_tensor([10, 20])
scattered = paddle.scatter(x, indices, updates) # 结果:[0, 10, 0, 20, 0]
七、动态图与静态图的张量操作差异
Paddle 支持动态图(Eager Mode)与静态图(Static Mode)两种编程模式,张量操作在细节上略有不同:
- 动态图 :直接使用 Python 控制流(
if/for
),张量操作与 Python 语法无缝衔接,适合调试与快速开发。 - 静态图 :需使用
paddle.static.nn.cond
和paddle.static.nn.while_loop
实现条件与循环,适合生产环境的性能优化。
总结与实践建议
掌握张量操作是学习 PaddlePaddle 的基础,以上算子覆盖了从数据输入到模型计算的全流程。在实际应用中,建议:
- 通过
paddle.to_tensor
或paddle.zeros_like
等算子显式指定张量数据类型,避免类型推导错误; - 利用广播机制简化代码,但注意检查广播后的形状是否符合预期;
- 复杂操作优先使用 Paddle 内置算子(如
paddle.matmul
)而非循环,以提升计算效率; - 结合动态图调试模型逻辑,再切换至静态图进行部署优化。