03-第一个 Paddle 程序:Tensor 创建、计算与设备管理

概述

安装 PaddlePaddle 之后,很多初学者会直接搜索"如何训练模型"。这一步不算错,但有点早。深度学习模型训练的底层对象是 Tensor,模型输入、模型参数、预测结果、损失值和梯度,最终都会落到 Tensor 上。

所以第一个 Paddle 程序不应该急着堆网络结构,而应该先回答几个基础问题:

  • 如何把 Python 列表、标量、NumPy 数组变成 Paddle Tensor
  • 如何查看 Tensor 的形状、数据类型、设备位置和梯度开关?
  • 如何做基本数学计算、矩阵乘法和统计计算?
  • 如何把 Tensor 转回 NumPy,方便打印、调试或和其他 Python 库交互?
  • 如何判断当前程序运行在 CPU 还是 GPU?
  • 如何写出一段 CPU/GPU 都能运行的最小 Paddle 程序?

这篇文章会围绕一个完整脚本展开。你可以先完整运行,再逐段拆开理解。

text 复制代码
Python 数据
    |
paddle.to_tensor()
    |
Paddle Tensor
    |
数学计算 / 矩阵计算 / 统计计算
    |
查看 shape / dtype / place / numpy
    |
CPU 或 GPU 设备执行

读完这篇文章,你应该能独立写出一个 Paddle Tensor 程序,并能判断它在什么设备上执行、每个 Tensor 的基本属性是什么。

前置条件:确认 Paddle 已经可用

在写第一个程序之前,建议先执行一次环境检查:

bash 复制代码
python -c "import paddle; paddle.utils.run_check()"

如果输出类似下面的信息,说明 Paddle 基础安装可用:

text 复制代码
PaddlePaddle is installed successfully!

你还可以查看当前版本:

bash 复制代码
python -c "import paddle; print(paddle.__version__)"

本文示例按 PaddlePaddle 3.x 的常用写法组织。如果你使用的是旧版本,个别输出格式可能略有差异,但核心概念一致。

完整示例:先跑通第一个 Paddle 脚本

新建文件 first_paddle_program.py

python 复制代码
import numpy as np
import paddle


def print_tensor(name, tensor):
    print(f"\n{name}")
    print("-" * 60)
    print(tensor)
    print("shape:", tensor.shape)
    print("dtype:", tensor.dtype)
    print("place:", tensor.place)
    print("stop_gradient:", tensor.stop_gradient)


def choose_device():
    if paddle.device.is_compiled_with_cuda():
        paddle.device.set_device("gpu:0")
    else:
        paddle.device.set_device("cpu")
    return paddle.device.get_device()


def main():
    paddle.seed(2026)
    np.random.seed(2026)

    device = choose_device()
    print("Paddle version:", paddle.__version__)
    print("Current device:", device)

    x = paddle.to_tensor(
        [[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]],
        dtype="float32",
    )
    print_tensor("x: created from Python list", x)

    y_np = np.array([[10, 20, 30], [40, 50, 60]], dtype="float32")
    y = paddle.to_tensor(y_np)
    print_tensor("y: created from NumPy array", y)

    z_add = x + y
    z_mul = x * 2
    z_matmul = paddle.matmul(x, y, transpose_y=True)

    print_tensor("z_add: x + y", z_add)
    print_tensor("z_mul: x * 2", z_mul)
    print_tensor("z_matmul: x @ y.T", z_matmul)

    mean_value = paddle.mean(x)
    row_sum = paddle.sum(x, axis=1)
    col_max = paddle.max(x, axis=0)

    print_tensor("mean_value: mean(x)", mean_value)
    print_tensor("row_sum: sum(x, axis=1)", row_sum)
    print_tensor("col_max: max(x, axis=0)", col_max)

    zeros = paddle.zeros([2, 3], dtype="float32")
    ones = paddle.ones([2, 3], dtype="float32")
    random_normal = paddle.randn([2, 3], dtype="float32")
    sequence = paddle.arange(0, 6, dtype="float32").reshape([2, 3])

    print_tensor("zeros", zeros)
    print_tensor("ones", ones)
    print_tensor("random_normal", random_normal)
    print_tensor("sequence", sequence)

    result_np = z_add.numpy()
    print("\nz_add converted to NumPy:")
    print(type(result_np))
    print(result_np)


if __name__ == "__main__":
    main()

运行:

bash 复制代码
python first_paddle_program.py

如果你的环境只有 CPU,输出中的设备位置通常会出现 Place(cpu)。如果你安装的是 GPU 版,并且 GPU 可用,输出中会出现类似 Place(gpu:0) 的设备信息。

这个脚本虽然不训练模型,但已经覆盖了 Paddle 入门的关键链路:

text 复制代码
创建 Tensor -> 查看属性 -> 做计算 -> 做统计 -> 管理设备 -> 转 NumPy

下面逐段拆解。

Tensor 创建:从 Python 数据进入 Paddle 世界

Paddle 中最常见的 Tensor 创建方式是 paddle.to_tensor()。官方 API 当前形式如下:

python 复制代码
paddle.to_tensor(data, dtype=None, place=None, stop_gradient=True)

它可以把下面几类数据变成 paddle.Tensor

  • Python 标量,例如 13.14
  • Python list
  • Python tuple
  • numpy.ndarray
  • 已有的 paddle.Tensor

从 Python 列表创建

python 复制代码
import paddle

x = paddle.to_tensor(
    [[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]],
    dtype="float32",
)

print(x)

这里创建的是一个二维 Tensor,形状是 [2, 3]。你可以把它理解成一个有 2 行、3 列的矩阵。

从 NumPy 数组创建

python 复制代码
import numpy as np
import paddle

arr = np.array([[1, 2], [3, 4]], dtype="float32")
x = paddle.to_tensor(arr)

print(x)

这在真实项目中非常常见。很多数据清洗、读取、预处理流程会先用 NumPy 或 Pandas 完成,进入模型前再转换成 Paddle Tensor

从标量创建 0 维 Tensor

python 复制代码
import paddle

x = paddle.to_tensor(3.14)
print(x)
print(x.shape)

标量会变成 0 维 Tensor。它不是 Python 的 float,而是 Paddle 能参与计算图、设备调度和自动微分的 Tensor。

paddle.to_tensor() 是把普通 Python/NumPy 数据接入 Paddle 计算体系的入口。

Tensor 属性:shape、dtype、place、stop_gradient

看到一个 Tensor 时,初学者不要只看它的数值,还要看它的四个关键属性。

属性 含义 为什么重要
shape Tensor 的形状 决定矩阵计算、广播、模型输入是否匹配
dtype 数据类型 影响精度、显存、算子支持和损失计算
place 设备位置 判断 Tensor 在 CPU、GPU 或其他设备上
stop_gradient 是否阻断梯度 决定后续自动微分是否追踪它

示例:

python 复制代码
import paddle

x = paddle.to_tensor([[1.0, 2.0], [3.0, 4.0]], dtype="float32")

print("shape:", x.shape)
print("dtype:", x.dtype)
print("place:", x.place)
print("stop_gradient:", x.stop_gradient)

通常情况下,刚创建的普通 Tensor 默认 stop_gradient=True。这表示它默认不需要计算梯度。后续讲自动微分时,我们会专门使用 stop_gradient=False 来让某些 Tensor 参与梯度计算。

shape:先看维度再写计算

shape 是理解 Tensor 的第一入口。

python 复制代码
x = paddle.to_tensor([[1, 2, 3], [4, 5, 6]])
print(x.shape)

输出形状是 [2, 3],表示 2 行 3 列。

在模型训练中,常见形状包括:

数据类型 常见 shape 含义
单个向量 [feature_dim] 一个样本的特征
一批向量 [batch_size, feature_dim] 一批样本
灰度图像 [batch_size, 1, height, width] NCHW 格式
彩色图像 [batch_size, 3, height, width] RGB 三通道
文本 token [batch_size, seq_len] 一批文本序列

初学时,只要计算报错,第一反应应该是打印 shape

dtype:不要忽略数据类型

深度学习里最常见的数据类型是 float32。标签、索引、类别 ID 常用 int64

python 复制代码
features = paddle.to_tensor([[1.0, 2.0]], dtype="float32")
labels = paddle.to_tensor([1], dtype="int64")

print(features.dtype)
print(labels.dtype)

如果把类别标签误写成浮点数,某些损失函数会直接报错;如果把模型输入误写成整数,很多连续数学运算也会不符合预期。

经验规则

  • 模型输入特征:优先用 float32
  • 回归目标:通常用 float32
  • 分类标签:通常用 int64
  • 布尔掩码:使用 bool

place:确认数据在哪里计算

place 表示 Tensor 的设备位置。

python 复制代码
import paddle

paddle.device.set_device("cpu")
x = paddle.ones([2, 3])
print(x.place)

如果当前使用 CPU,通常会看到 Place(cpu)。如果当前使用 GPU,可能看到 Place(gpu:0)

设备位置很重要,因为不同设备上的 Tensor 不能随意混在一起计算。真实训练中,如果模型参数在 GPU,而输入数据在 CPU,就可能触发设备不一致错误或隐式拷贝开销。

常用创建方式:不只是 to_tensor

除了 paddle.to_tensor(),Paddle 还提供了一组常用的初始化函数。

函数 作用 示例
paddle.zeros() 创建全 0 Tensor paddle.zeros([2, 3])
paddle.ones() 创建全 1 Tensor paddle.ones([2, 3])
paddle.full() 创建指定填充值 Tensor paddle.full([2, 3], 7)
paddle.arange() 创建等差序列 paddle.arange(0, 6)
paddle.linspace() 创建指定数量的等间隔序列 paddle.linspace(0, 1, 5)
paddle.randn() 创建正态分布随机 Tensor paddle.randn([2, 3])
paddle.randint() 创建随机整数 Tensor paddle.randint(0, 10, [2, 3])

示例:

python 复制代码
import paddle

zeros = paddle.zeros([2, 3], dtype="float32")
ones = paddle.ones([2, 3], dtype="float32")
sevens = paddle.full([2, 3], 7, dtype="int64")
seq = paddle.arange(0, 6, dtype="float32").reshape([2, 3])
grid = paddle.linspace(0, 1, 5)
noise = paddle.randn([2, 3], dtype="float32")

print(zeros)
print(ones)
print(sevens)
print(seq)
print(grid)
print(noise)

这些函数在模型开发中很常见。例如:

  • zeros 初始化缓存。
  • ones 构造掩码。
  • arange 构造位置索引。
  • randn 生成测试输入。
  • full 构造固定填充值。

to_tensor 适合把已有数据转成 Tensor,zeros/ones/randn/arange 适合直接按规则生成 Tensor。

基本计算:逐元素运算和矩阵乘法

Tensor 创建之后,就可以进行计算。先看逐元素运算:

python 复制代码
import paddle

x = paddle.to_tensor([[1.0, 2.0], [3.0, 4.0]])
y = paddle.to_tensor([[10.0, 20.0], [30.0, 40.0]])

print(x + y)
print(x - y)
print(x * y)
print(y / x)
print(x ** 2)

这些运算会逐位置进行:

text 复制代码
[[1, 2],       [[10, 20],       [[11, 22],
 [3, 4]]   +    [30, 40]]   =    [33, 44]]

标量与 Tensor 运算

python 复制代码
x = paddle.to_tensor([[1.0, 2.0], [3.0, 4.0]])

print(x + 1)
print(x * 10)

标量会自动广播到 Tensor 的每个位置。广播机制后面会单独讲,这里先记住:形状不同也可能能运算,但必须符合广播规则。

矩阵乘法

矩阵乘法使用 paddle.matmul()

python 复制代码
import paddle

a = paddle.to_tensor([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]])
b = paddle.to_tensor([[1.0, 2.0], [3.0, 4.0], [5.0, 6.0]])

c = paddle.matmul(a, b)
print(c)
print(c.shape)

这里:

  • a.shape[2, 3]
  • b.shape[3, 2]
  • 结果 c.shape[2, 2]

如果矩阵乘法报错,优先检查内侧维度是否一致:

text 复制代码
[2, 3] @ [3, 2] -> [2, 2]
        ^   ^
        这两个维度必须匹配

神经网络中的线性层、注意力计算、特征变换,本质上都会大量使用类似矩阵乘法的操作。

统计计算:mean、sum、max 和 axis

统计计算是训练中经常出现的操作。例如求损失平均值、按 batch 聚合指标、找最大类别概率。

python 复制代码
import paddle

x = paddle.to_tensor(
    [[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]],
    dtype="float32",
)

print("mean:", paddle.mean(x))
print("sum all:", paddle.sum(x))
print("sum rows:", paddle.sum(x, axis=1))
print("max columns:", paddle.max(x, axis=0))

这里最值得注意的是 axis

对于一个形状为 [2, 3] 的 Tensor:

text 复制代码
axis=0:沿着第 0 维聚合,结果保留列方向,形状变成 [3]
axis=1:沿着第 1 维聚合,结果保留行方向,形状变成 [2]

可以这样理解:

text 复制代码
x = [[1, 2, 3],
     [4, 5, 6]]

paddle.sum(x, axis=0) -> [5, 7, 9]
paddle.sum(x, axis=1) -> [6, 15]

遇到 axis,不要死记参数,先把 Tensor 的 shape 写出来,再判断沿哪一维聚合。

NumPy 转换:调试时非常实用

Paddle Tensor 可以用 .numpy() 转为 NumPy 数组:

python 复制代码
import paddle

x = paddle.to_tensor([[1.0, 2.0], [3.0, 4.0]])
arr = x.numpy()

print(type(arr))
print(arr)

这在调试中很有用:

  • 需要用 NumPy 检查结果。
  • 需要把结果交给 Matplotlib 画图。
  • 需要打印更熟悉的数组格式。
  • 需要和其他 Python 数据处理库交互。

不过要注意:训练主流程中不要频繁 .numpy()。如果 Tensor 在 GPU 上,转 NumPy 通常意味着要把数据拷回 CPU,这会带来额外开销。调试可以用,性能敏感代码中要谨慎。

设备管理:CPU、GPU 与全局设备

Paddle 支持在 CPU、GPU、XPU、NPU、MLU 等多种设备上执行。入门阶段最常见的是 CPU 和 GPU。

查看当前设备

python 复制代码
import paddle

print(paddle.device.get_device())

官方文档说明,如果没有显式设置全局设备,CUDA 可用时通常返回 gpu:0,CUDA 不可用时返回 cpu

设置当前设备

python 复制代码
import paddle

paddle.device.set_device("cpu")
print(paddle.device.get_device())

如果你安装的是 GPU 版,并且 GPU 可用:

python 复制代码
import paddle

paddle.device.set_device("gpu:0")
print(paddle.device.get_device())

官方 set_device 支持类似下面的字符串:

  • cpu
  • gpu
  • gpu:0
  • xpu
  • xpu:0
  • npu
  • npu:0
  • mlu
  • mlu:0

初学阶段通常只需要 cpugpu:0

写一个 CPU/GPU 自适应选择函数

为了让代码在不同机器上都能运行,可以这样写:

python 复制代码
import paddle


def choose_device():
    if paddle.device.is_compiled_with_cuda():
        paddle.device.set_device("gpu:0")
    else:
        paddle.device.set_device("cpu")
    return paddle.device.get_device()


device = choose_device()
print("Current device:", device)

这段代码的逻辑是:

  • 如果当前 Paddle 是 CUDA 编译版本,就使用第 0 张 GPU。
  • 否则使用 CPU。

注意,is_compiled_with_cuda() 判断的是当前 Paddle 包是否具备 CUDA 能力。实际 GPU 是否能稳定运行,还依赖驱动、硬件和安装包匹配情况。第二篇安装文章中的 paddle.utils.run_check() 仍然是必要的。

全局设备只影响后续创建的 Tensor

这是一个很容易踩坑的点。

python 复制代码
import paddle

paddle.device.set_device("cpu")
x = paddle.ones([2, 2])

if paddle.device.is_compiled_with_cuda():
    paddle.device.set_device("gpu:0")
    y = paddle.ones([2, 2])

    print("x place:", x.place)
    print("y place:", y.place)

set_device("gpu:0") 会影响后续创建的 Tensor,但不会自动把已经存在的 x 从 CPU 移到 GPU。也就是说:

text 复制代码
先创建的 Tensor 保持原设备
后创建的 Tensor 使用新的全局设备

这也是为什么训练代码通常会在程序开始阶段就先设置设备,然后再创建模型和数据。

设备管理要尽早做,避免模型、输入和中间结果出现在不同设备上。

创建时指定 place:更精确地控制设备

除了设置全局设备,也可以在创建 Tensor 时通过 place 指定设备。

CPU 示例:

python 复制代码
import paddle

x = paddle.to_tensor([1, 2, 3], place=paddle.CPUPlace())
print(x.place)

GPU 示例:

python 复制代码
import paddle

if paddle.device.is_compiled_with_cuda():
    x = paddle.to_tensor([1, 2, 3], place=paddle.CUDAPlace(0))
    print(x.place)

一般建议:

  • 简单脚本:使用 paddle.device.set_device() 设置全局设备。
  • 特殊场景:创建 Tensor 时用 place 精确指定。
  • 初学阶段:不要在同一段代码里随意混用多个设备,先保证逻辑清晰。

第一个小练习:手写一个线性计算

为了让 Tensor 计算更接近模型训练,我们写一个简单的线性函数:

y=xW+b y = xW + b y=xW+b

代码如下:

python 复制代码
import paddle

paddle.device.set_device("cpu")

x = paddle.to_tensor(
    [[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]],
    dtype="float32",
)

w = paddle.to_tensor(
    [[0.1, 0.2], [0.3, 0.4], [0.5, 0.6]],
    dtype="float32",
)

b = paddle.to_tensor([0.01, 0.02], dtype="float32")

y = paddle.matmul(x, w) + b

print("x shape:", x.shape)
print("w shape:", w.shape)
print("b shape:", b.shape)
print("y shape:", y.shape)
print(y)

形状关系是:

text 复制代码
x: [2, 3]
w: [3, 2]
b: [2]

x @ w: [2, 2]
(x @ w) + b: [2, 2]

这里的 b 会被广播到每一行:

text 复制代码
[[... , ...],
 [... , ...]]
   +
[0.01, 0.02]

这个例子已经非常接近神经网络里的 Linear 层。后面学习 paddle.nn.Linear 时,你会发现框架只是把参数管理、初始化和调用方式封装得更方便。

常见错误

错误一:装了多个 Python,运行环境不是安装环境

现象:

text 复制代码
ModuleNotFoundError: No module named 'paddle'

排查:

bash 复制代码
python -c "import sys; print(sys.executable)"
python -m pip show paddlepaddle
python -m pip show paddlepaddle-gpu

确认 pythonpip 指向同一个虚拟环境。

错误二:矩阵乘法维度不匹配

错误写法:

python 复制代码
a = paddle.randn([2, 3])
b = paddle.randn([2, 3])
c = paddle.matmul(a, b)

[2, 3] @ [2, 3] 的内侧维度 32 不一致,所以不能直接矩阵乘法。

正确写法之一:

python 复制代码
c = paddle.matmul(a, b, transpose_y=True)

此时相当于:

text 复制代码
[2, 3] @ [3, 2] -> [2, 2]

错误三:dtype 不符合算子要求

例如分类标签通常应该是整数类型:

python 复制代码
labels = paddle.to_tensor([0, 1, 2], dtype="int64")

模型输入通常用浮点类型:

python 复制代码
features = paddle.to_tensor([[0.1, 0.2]], dtype="float32")

当损失函数或模型层报 dtype 相关错误时,先打印:

python 复制代码
print(tensor.dtype)

错误四:以为 set_device 会移动已有 Tensor

错误理解:

python 复制代码
paddle.device.set_device("cpu")
x = paddle.ones([2, 2])

paddle.device.set_device("gpu:0")
print("x 仍然在原来的设备上")

实际情况是:x 仍然在 CPU。set_device 影响的是后续 OP 运行的全局设备,以及后续创建 Tensor 时默认使用的设备。

错误五:训练代码里频繁 numpy

.numpy() 对调试很方便,但训练循环里频繁调用会带来性能开销,尤其是 GPU 训练场景。除非确实要打印、记录或交给外部库处理,否则尽量让数据保持 Tensor 形式。

总结

这篇文章没有训练模型,但已经覆盖了 Paddle 编程的最小基础:

  • paddle.to_tensor():把 Python/NumPy 数据变成 Paddle Tensor。
  • shape:描述 Tensor 的结构,是排查维度问题的第一信息。
  • dtype:描述数据类型,影响精度、算子和损失函数。
  • place:描述设备位置,帮助判断 CPU/GPU 执行情况。
  • stop_gradient:描述是否阻断梯度,是后续自动微分的关键属性。
  • paddle.matmul():完成矩阵乘法,是神经网络计算的重要基础。
  • paddle.mean/sum/max():完成常用统计聚合。
  • paddle.device.set_device():设置全局设备。
  • paddle.device.get_device():查看当前全局设备。
  • .numpy():把 Tensor 转回 NumPy,适合调试和外部库交互。
相关推荐
Maynor9962 小时前
AI Coding 零基础实战教程|第七部分:Codex Desktop 安装和使用教程
人工智能·ai编程·codex·claude code·ai coding
CClaris2 小时前
大模型量化从0到1(九):用 llama.cpp 把模型转成 GGUF 并跑本地推理
人工智能·pytorch·python·深度学习·llama
学编程的小虎3 小时前
SenseVoice微调
人工智能·python·自然语言处理
不爱土豆唯爱马铃薯3 小时前
aipy漫画系列创作分享之漫画技能分享
人工智能
诸葛说抛光3 小时前
国内大型汽车改装展览会定展 佛山改装 佛山汽车赛事
python·汽车
字节跳动视频云技术团队3 小时前
豆包视频通话背后,火山引擎重构 Agent 时代多模态传输底座
人工智能·agent·音视频开发
chouchuang3 小时前
day-030-综合练习-笔记管理器
开发语言·笔记·python
乖巧的妹子3 小时前
Python基础核心知识点详解:内置函数、运算符、字符串方法、数据结构与类型转换
python
大公产经晚间消息3 小时前
《寻访独角兽》首期走进太仓,探访小科智行的硬科技“突围”
网络·人工智能·科技