Day 78:【99天精通Python】深度学习入门 (PyTorch) 上篇 - 张量与自动求导
Day 78:【99天精通Python】深度学习入门 (PyTorch) 上篇 - 张量与自动求导
前言
欢迎来到第78天!
从今天开始,我们将触及 AI 技术皇冠上的明珠——深度学习 (Deep Learning)。
无论是 ChatGPT、AI 绘画,还是自动驾驶,它们背后的核心都是神经网络。而要搭建和训练神经网络,我们需要一个趁手的框架。
PyTorch 是目前学术界和工业界最流行的深度学习框架之一(另一个是 TensorFlow)。它以动态图机制著称,代码写起来就像普通的 Python 代码一样自然、易调试。
本节内容:
- PyTorch 安装与环境配置
- 核心数据结构:张量 (Tensor)
- 张量 vs NumPy 数组
- 自动求导 (Autograd) 机制
- 线性回归实战:手写第一个神经网络
一、环境准备
推荐安装 CPU 版本(学习足够用了)。如果你有 NVIDIA 显卡,可以安装 CUDA 版本。
# 访问 pytorch.org 查看适合你系统的命令
pip install torch torchvision
验证安装:
import torch
print(torch.__version__)
print(torch.cuda.is_available()) # True 表示可以使用 GPU
二、张量 (Tensor):PyTorch 的基石
张量本质上就是一个多维数组,这和 NumPy 的 ndarray 非常像。
区别在于:张量可以运行在 GPU 上,且支持自动求导。
2.1 创建张量
import torch
import numpy as np
# 1. 直接创建
x = torch.tensor([1, 2, 3])
print(x)
# 2. 从 NumPy 创建
arr = np.array([[1, 2], [3, 4]])
x_np = torch.from_numpy(arr)
# 3. 随机/全0/全1 (API 和 NumPy 几乎一样)
rand = torch.rand(2, 3) # 0-1 均匀分布
zeros = torch.zeros(2, 3)
ones = torch.ones(2, 3)
2.2 张量运算
x = torch.tensor([10, 20, 30])
y = torch.tensor([1, 2, 3])
# 加减乘除 (Element-wise)
print(x + y) # tensor([11, 22, 33])
print(x * y) # tensor([10, 40, 90])
# 矩阵乘法 (@ 或 matmul)
a = torch.tensor([[1, 2], [3, 4]])
b = torch.tensor([[5, 6], [7, 8]])
print(a @ b)
# 1*5+2*7=19 ...
2.3 GPU 加速 (如果有显卡)
if torch.cuda.is_available():
device = torch.device("cuda")
x = x.to(device) # 把张量搬到显存
y = y.to(device)
z = x + y # 在 GPU 上计算
print(z)
# 结果无法直接转 numpy,必须先搬回 cpu
# print(z.cpu().numpy())
三、自动求导 (Autograd)
深度学习的核心算法是反向传播 (Backpropagation),即根据误差计算梯度(导数),从而更新模型参数。
PyTorch 的 autograd 模块帮我们自动完成了这一复杂的微积分过程。
3.1 requires_grad
# 创建张量,并告诉 PyTorch:我要对它求导
w = torch.tensor([1.0], requires_grad=True)
x = torch.tensor([2.0])
b = torch.tensor([3.0], requires_grad=True)
# 前向传播 (Forward):构建计算图
# y = w * x + b
y = w * x + b # 1*2 + 3 = 5
# 后向传播 (Backward):自动计算梯度
# 计算 dy/dw, dy/db
y.backward()
# 查看梯度
print(w.grad) # dy/dw = x = 2.0
print(b.grad) # dy/db = 1.0
原理:PyTorch 会在后台构建一张动态计算图,记录所有的操作历史。调用
backward()时,它会沿着图反向走一遍,算出所有叶子节点(w,b)的梯度。
四、实战:手动实现线性回归
我们来模拟一个最简单的机器学习任务:拟合直线 y = 2x + 5。
4.1 准备数据
# 生成 100 个数据点
# y = 2x + 5 + 噪声
x_train = torch.rand(100, 1) * 10 # 0-10 之间
y_train = 2 * x_train + 5 + torch.randn(100, 1) * 0.5 # 加点高斯噪声
# 查看前5个
print(x_train[:5], y_train[:5])
4.2 训练模型
我们要训练两个参数 w 和 b,让 w*x + b 尽可能接近 y_train。
# 1. 初始化参数 (随机猜一个)
w = torch.randn(1, 1, requires_grad=True)
b = torch.randn(1, 1, requires_grad=True)
learning_rate = 0.01 # 学习率
for epoch in range(1000):
# 2. 前向传播:计算预测值
y_pred = x_train @ w + b
# 3. 计算损失 (Loss):均方误差 (MSE)
loss = (y_pred - y_train).pow(2).mean()
# 4. 反向传播:计算梯度
# 每次 backward 前必须清零梯度,否则会累加!
if w.grad is not None:
w.grad.zero_()
b.grad.zero_()
loss.backward()
# 5. 更新参数 (Gradient Descent)
# 使用 torch.no_grad(),因为更新参数的操作不需要记录进计算图
with torch.no_grad():
w -= learning_rate * w.grad
b -= learning_rate * b.grad
if epoch % 100 == 0:
print(f"Epoch {epoch}: Loss = {loss.item():.4f}")
print(f"训练结果: w={w.item():.2f}, b={b.item():.2f}")
# 预期接近 w=2.00, b=5.00
五、常见问题
Q1:为什么要 grad.zero_()?
PyTorch 设计为梯度累加。如果不清零,第 2 轮的梯度 = 第 1 轮梯度 + 第 2 轮梯度,这会导致更新方向错误。
Q2:with torch.no_grad(): 是什么?
在更新参数 w -= lr * w.grad 时,这只是一个数值更新操作,我们不希望 PyTorch 把它也算作计算图的一部分(否则下次 backward 会出错)。这也用于推理阶段(Inference)以节省内存。
Q3:tensor.item()?
当张量只包含一个数值时(scalar),用 .item() 把它转为 Python 的 float/int。
六、小结
关键要点:
- Tensor 是深度学习的数据容器。
- Autograd 让反向传播变得自动化。
- 训练循环 4 步走:算预测 -> 算 Loss -> Backward -> 更新参数。
七、课后作业
- 二次函数拟合:修改上面的代码,尝试拟合曲线
y = 3x^2 + 2x + 1。(提示:你需要三个参数w1, w2, b,或者构造特征x^2)。 - GPU 加速体验:如果你的电脑有显卡(或使用 Colab),尝试将张量移动到
.to('cuda')上运行,对比大数据量下的矩阵乘法速度。 - 手动求导:复习一下高数,手动计算
y = w*x + b对w的偏导数,看看和w.grad的值是不是一样。
下节预告
Day 79:深度学习入门 (PyTorch) 下篇 - 神经网络 (nn.Module) - 手动更新参数太累了。明天我们学习 PyTorch 的高级 API,用搭积木的方式构建真正的神经网络!
系列导航:
- 上一篇:Day 77 - 计算机视觉OpenCV
- 下一篇:Day 79 - 深度学习PyTorch下(待更新)
更多推荐


所有评论(0)