PyTorch 小试牛刀:完整笔记与实操指南
本笔记涵盖 PyTorch 的核心概念:张量、自动求导、神经网络模块、优化器、自定义模块及动态图。每个知识点均配有可运行的代码示例,从最基础的 NumPy 实现逐步过渡到 PyTorch 的高级特性,帮助你快速上手。
1. PyTorch 两大核心特征
-
张量(Tensor):类似 NumPy 的 ndarray,但可运行在 GPU 上,加速计算。
-
自动求导(Autograd):自动计算梯度,无需手动实现反向传播。
本章示例:使用全连接 ReLU 网络拟合随机数据。网络结构:输入 → 隐藏层(ReLU)→ 输出。通过梯度下降最小化欧氏距离损失。
2. 热身:用 NumPy 实现两层网络
目的:不依赖任何深度学习框架,手动实现前向传播、损失计算、反向传播和参数更新。 关键点:纯 NumPy 无法利用 GPU,且需要手写梯度。
python
# -*- coding: utf-8 -*-
import numpy as np
# 超参数
N, D_in, H, D_out = 64, 1000, 100, 10 # batch大小,输入维度,隐藏层维度,输出维度
# 随机数据
x = np.random.randn(N, D_in)
y = np.random.randn(N, D_out)
# 随机初始化权重
w1 = np.random.randn(D_in, H)
w2 = np.random.randn(H, D_out)
learning_rate = 1e-6
for t in range(500):
# —– 前向传播 —–
h = x.dot(w1) # (N, H)
h_relu = np.maximum(h, 0) # ReLU
y_pred = h_relu.dot(w2) # (N, D_out)
# 计算损失(均方误差和)
loss = np.square(y_pred – y).sum()
if t % 100 == 0:
print(t, loss)
# —– 反向传播(手动求导)—–
grad_y_pred = 2.0 * (y_pred – y)
grad_w2 = h_relu.T.dot(grad_y_pred)
grad_h_relu = grad_y_pred.dot(w2.T)
grad_h = grad_h_relu.copy()
grad_h[h < 0] = 0 # ReLU 导数
grad_w1 = x.T.dot(grad_h)
# —– 更新权重 —–
w1 -= learning_rate * grad_w1
w2 -= learning_rate * grad_w2
解释:
-
前向:x @ w1 -> ReLU -> @ w2
-
反向:链式法则手动计算每个梯度
-
缺点:网络复杂时反向传播容易出错,且无法利用 GPU。
3. PyTorch 张量(Tensor)实现
改进:使用 PyTorch 张量,语法与 NumPy 类似,但可指定 device 运行在 GPU 上。仍然手动实现反向传播。
# -*- coding: utf-8 -*-
import torch
dtype = torch.float
device = torch.device(\”cpu\”) # 或 \”cuda:0\” 使用 GPU
N, D_in, H, D_out = 64, 1000, 100, 10
# 创建张量,并移至设备
x = torch.randn(N, D_in, device=device, dtype=dtype)
y = torch.randn(N, D_out, device=device, dtype=dtype)
w1 = torch.randn(D_in, H, device=device, dtype=dtype)
w2 = torch.randn(H, D_out, device=device, dtype=dtype)
learning_rate = 1e-6
for t in range(500):
# 前向传播
h = x.mm(w1) # 矩阵乘法
h_relu = h.clamp(min=0) # ReLU
y_pred = h_relu.mm(w2)
# 损失
loss = (y_pred – y).pow(2).sum().item()
if t % 100 == 0:
print(t, loss)
# 手动反向传播
grad_y_pred = 2.0 * (y_pred – y)
grad_w2 = h_relu.t().mm(grad_y_pred)
grad_h_relu = grad_y_pred.mm(w2.t())
grad_h = grad_h_relu.clone()
grad_h[h < 0] = 0
grad_w1 = x.t().mm(grad_h)
# 更新权重
w1 -= learning_rate * grad_w1
w2 -=

