PyTorch 张量入门:从零搭建环境到 Tensor 操作

深度学习入门第一关:装好 PyTorch,玩转 Tensor。本文带你从 VSCode 配置开始,一路到 GPU 张量运算。


一、先搭环境,再谈学习

1.1 安装 PyTorch

# 创建虚拟环境(推荐 Python 3.9~3.11)
python -m venv dl_env

# 激活
# Windows:
dl_env\Scripts\activate
# macOS / Linux:
source dl_env/bin/activate

# 安装 PyTorch(CPU 版,先跑起来)
pip install torch torchvision torchaudio

# 如果有 NVIDIA 显卡,去 pytorch.org 复制 CUDA 版安装命令

1.2 VSCode 配置要点

// settings.json 关键配置
{
  "python.defaultInterpreterPath": "${workspaceFolder}/dl_env/Scripts/python.exe",
  "python.analysis.extraPaths": ["./src"],
  "ruff.enable": true,
  "editor.formatOnSave": true,
  "editor.rulers": [88],
  "files.autoSave": "afterDelay"
}

必装扩展:

  • Python(微软官方,调试 + 智能提示)
  • Pylance(类型检查,代码跳转)
  • Ruff(极速 lint + format,替代 flake8/black/isort)
  • Jupyter(数据科学必备,边写边跑)

装完别忘了:把 Python 解释器路径指向你刚建的 dl_env,否则 VSCode 还在用系统 Python。

1.3 验证环境

import torch
print(torch.__version__)       # 2.x.x
print(torch.cuda.is_available())  # True 如果有 GPU
print(torch.cuda.device_count())  # GPU 数量

二、张量(Tensor)是什么

一句话:Tensor 就是 PyTorch 里的"数组",地位等于 NumPy 的 ndarray。但它比 ndarray 多一个关键能力——能在 GPU 上跑

类比理解:

维度 数学概念 PyTorch Tensor NumPy
0 维 标量(scalar) torch.tensor(3) np.array(3)
1 维 向量(vector) torch.tensor([1,2,3]) np.array([1,2,3])
2 维 矩阵(matrix) torch.rand(3,4) np.random.rand(3,4)
3 维 立方体 torch.rand(2,3,4) np.random.rand(2,3,4)
N 维 张量 torch.rand(2,3,4,5) np.random.rand(2,3,4,5)

深度学习里最常见的是 2D(全连接层权重矩阵)和 4D(卷积层的图像批次 NCHW)。


三、创建 Tensor 的 8 种方式

3.1 从 Python 数据创建

import torch
import numpy as np

# 从列表
a = torch.tensor([1, 2, 3])
print(a)  # tensor([1, 2, 3])

# 从 NumPy 数组
b = torch.tensor(np.array([4, 5, 6]))
print(b)  # tensor([4, 5, 6])

# 指定数据类型
c = torch.tensor([1, 2, 3], dtype=torch.float32)
print(c.dtype)  # torch.float32

3.2 全零 / 全一 / 指定值

zeros = torch.zeros(3, 4)          # 3×4 全零矩阵
ones = torch.ones(2, 3)            # 2×3 全一矩阵
full = torch.full((2, 2), 7)       # 2×2 全是 7

# 仿照已有张量的形状
x = torch.rand(3, 4)
zeros_like = torch.zeros_like(x)   # 和 x 形状一样的全零
ones_like = torch.ones_like(x)     # 和 x 形状一样的全一

3.3 随机张量

torch.manual_seed(42)  # 设定随机种子,保证可复现

rand = torch.rand(3, 4)           # 0~1 均匀分布
randn = torch.randn(3, 4)         # 标准正态分布(均值 0,方差 1)
randint = torch.randint(0, 10, (3, 4))  # [0, 10) 随机整数

💡 训练模型前一定要 torch.manual_seed(42),否则每次跑结果不一样,debug 到怀疑人生。

3.4 线性 / 序列张量

arange = torch.arange(0, 10, 2)    # tensor([0, 2, 4, 6, 8])
linspace = torch.linspace(0, 1, 5) # tensor([0.00, 0.25, 0.50, 0.75, 1.00])

四、Tensor 的属性:shape、dtype、device

拿到一个张量,先看三样东西:

x = torch.randn(2, 3, 4)

print(x.shape)   # torch.Size([2, 3, 4])  — 形状
print(x.dtype)   # torch.float32          — 数据类型
print(x.device)  # cpu                    — 在哪个设备上

数据类型速查

dtype 说明 典型用途
torch.float32 32 位浮点(默认) 模型权重、激活值
torch.float16 16 位浮点 混合精度训练
torch.int64 64 位整数(默认) 标签、索引
torch.int32 32 位整数 部分旧代码
torch.bool 布尔 掩码、条件筛选

类型转换

x = torch.tensor([1, 2, 3])          # 默认 int64
x = x.float()                         # 转 float32
x = x.int()                           # 转 int32
x = torch.tensor([1.0, 2.0], dtype=torch.float16)  # 创建时指定

五、Tensor 基本操作

5.1 加减乘除

a = torch.tensor([1.0, 2.0, 3.0])
b = torch.tensor([4.0, 5.0, 6.0])

print(a + b)        # tensor([5., 7., 9.])
print(a - b)        # tensor([-3., -3., -3.])
print(a * b)        # tensor([ 4., 10., 18.])  — 逐元素乘法
print(a / b)        # tensor([0.2500, 0.4000, 0.5000])
print(a @ b)        # 点积:1*4 + 2*5 + 3*6 = 32.0

5.2 矩阵乘法

A = torch.rand(3, 4)   # 3×4
B = torch.rand(4, 5)   # 4×5

# 三种写法,结果完全一样
C = A @ B
C = torch.matmul(A, B)
C = torch.mm(A, B)     # 仅限 2D 矩阵

print(C.shape)  # torch.Size([3, 5])

5.3 索引与切片

x = torch.arange(12).reshape(3, 4)
# tensor([[ 0,  1,  2,  3],
#         [ 4,  5,  6,  7],
#         [ 8,  9, 10, 11]])

print(x[0])        # 第 0 行:tensor([0, 1, 2, 3])
print(x[:, 0])     # 第 0 列:tensor([0, 4, 8])
print(x[1:, 2:])   # 第 1 行起、第 2 列起
# tensor([[ 6,  7],
#         [10, 11]])

5.4 变形(reshape / view)

x = torch.arange(12)

a = x.reshape(3, 4)   # 变成 3×4
b = x.view(3, 4)      # 同上,但要求内存连续
c = x.reshape(3, -1)  # -1 表示"自动算":12/3=4

# 展平
flat = x.reshape(-1)  # 回到一维

reshape 始终安全(会自动拷贝),view 更快但要求内存连续。不确定时用 reshape

5.5 拼接与堆叠

a = torch.tensor([[1, 2], [3, 4]])
b = torch.tensor([[5, 6], [7, 8]])

cat_dim0 = torch.cat([a, b], dim=0)   # 沿行拼接
# tensor([[1, 2],
#         [3, 4],
#         [5, 6],
#         [7, 8]])

cat_dim1 = torch.cat([a, b], dim=1)   # 沿列拼接
# tensor([[1, 2, 5, 6],
#         [3, 4, 7, 8]])

stacked = torch.stack([a, b], dim=0)  # 新增一维堆叠
# shape: torch.Size([2, 2, 2])

六、Tensor 与 NumPy 互转

import numpy as np

# Tensor → NumPy(共享内存,修改一个会影响另一个)
x = torch.rand(3, 3)
arr = x.numpy()
arr[0, 0] = 999
print(x[0, 0])  # 也变成 999!

# 不想共享?加 .copy()
arr_safe = x.numpy().copy()

# NumPy → Tensor
arr = np.array([[1, 2], [3, 4]])
t = torch.from_numpy(arr)  # 共享内存
t2 = torch.tensor(arr)     # 深拷贝,不共享

经验:训练时数据处理用 NumPy,进模型前转 Tensor,出来再转回 NumPy 画图。


七、GPU 加速

把计算搬到 GPU 上,核心就一个操作:

# 检查 GPU 是否可用
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
print(f"使用设备: {device}")

# 创建时直接指定
x = torch.rand(1000, 1000, device=device)

# 或者创建后迁移
x = torch.rand(1000, 1000)
x = x.to(device)   # 搬到 GPU

# 在 GPU 上做矩阵乘法,速度碾压 CPU
y = torch.rand(1000, 1000, device=device)
z = x @ y   # 瞬间完成

一个简单的速度对比:

import time

size = 5000
x_cpu = torch.rand(size, size)
y_cpu = torch.rand(size, size)

# CPU 计时
t0 = time.time()
_ = x_cpu @ y_cpu
print(f"CPU: {time.time() - t0:.3f}s")

if torch.cuda.is_available():
    x_gpu = x_cpu.to("cuda")
    y_gpu = y_cpu.to("cuda")
    torch.cuda.synchronize()  # 预热
    t0 = time.time()
    _ = x_gpu @ y_gpu
    torch.cuda.synchronize()  # 等 GPU 算完
    print(f"GPU: {time.time() - t0:.3f}s")

八、实战:用 Tensor 写一个线性回归

import torch

torch.manual_seed(42)

# 1. 造数据:y = 3x + 2 + 噪声
X = torch.rand(100, 1) * 10        # 100 个样本,0~10
y = 3 * X + 2 + torch.randn(100, 1) * 2

# 2. 初始化参数(用 Tensor,不是 nn.Module)
w = torch.randn(1, requires_grad=True)   # 权重
b = torch.randn(1, requires_grad=True)   # 偏置

# 3. 训练
lr = 0.01
for epoch in range(200):
    # 前向
    y_pred = X @ w + b
    loss = ((y_pred - y) ** 2).mean()  # MSE

    # 反向传播
    loss.backward()

    # 梯度下降(手动更新,不用 optimizer)
    with torch.no_grad():
        w -= lr * w.grad
        b -= lr * b.grad
        w.grad.zero_()
        b.grad.zero_()

    if epoch % 40 == 0:
        print(f"Epoch {epoch:3d} | Loss: {loss.item():.4f}")

print(f"\n真实参数: w=3.0, b=2.0")
print(f"拟合参数: w={w.item():.3f}, b={b.item():.3f}")

# 输出:
# Epoch   0 | Loss: 207.8994
# Epoch  40 | Loss: 19.0575
# Epoch  80 | Loss: 9.3985
# Epoch 120 | Loss: 6.1175
# Epoch 160 | Loss: 5.0025
# 真实参数: w=3.0, b=2.0
# 拟合参数: w=2.958, b=2.203

用纯 Tensor 写一个完整的训练循环,把"前向传播 → 计算损失 → 反向传播 → 更新参数"这四步走一遍,比直接调 nn.Linear 更能理解底层发生了什么。


九、总结

掌握点 核心 API
创建 Tensor torch.tensor(), torch.zeros(), torch.randn(), torch.arange()
查属性 .shape, .dtype, .device
类型转换 .float(), .int(), dtype=
索引切片 [row, col], [start:end], [:, col]
变形 .reshape(), .view(), -1 自动推导
拼接 torch.cat(), torch.stack()
NumPy 互转 .numpy(), torch.from_numpy()
GPU .to("cuda"), torch.cuda.is_available()
自动求导 requires_grad=True, .backward(), .grad

Tensor 就是深度学习的"基本粒子"。后面接触的全连接层、卷积层、RNN……本质上都是对 Tensor 的封装和运算。这一关过了,后面的路会顺畅很多。

更多推荐