深度学习与PyTorch入门视频课程完整教程
简介:深度学习作为人工智能核心技术,通过模拟人脑神经网络实现图像识别、自然语言处理等复杂任务。PyTorch作为Facebook开发的开源深度学习框架,凭借其动态计算图、易用性和强大社区支持,成为研究和实践的首选工具。本视频课程系统讲解深度学习基础概念与PyTorch实战应用,涵盖环境搭建、张量操作、模型构建、自动梯度、数据预处理、训练优化、模型保存及评估调优等内容,并结合图像分类、文本情感分析等实战项目,帮助初学者全面掌握PyTorch在深度学习中的实际应用。课程采用音视频形式,教学直观生动,适合零基础学习者快速入门并进阶。
深度学习与PyTorch实战:从零构建可落地的模型系统
你有没有遇到过这样的情况——明明训练损失一路下降,信心满满地准备上线模型,结果一跑测试集,准确率惨不忍睹?😅 或者调试反向传播时一头雾水, loss.backward() 执行后梯度却像幽灵一样莫名其妙地消失或爆炸?💥
这背后往往不是算法本身的问题,而是我们对深度学习框架底层机制理解不够透彻。今天,我们就以 PyTorch 为核心工具,来一次“庖丁解牛”式的深入剖析。不玩虚的,不堆术语,咱们直接从最基础的张量操作讲起,一直打通到真实项目中的评估调优闭环。目标只有一个:让你写出的每一段代码都 知其然,更知其所以然 。
环境搭建的艺术:别让第一行 import torch 就卡住
你说奇怪不奇怪,搞AI的人,第一个拦路虎居然常常是环境配置?🤯 很多初学者在激动地敲下 pip install torch 后,满怀期待运行 torch.cuda.is_available() ,结果返回个 False ,瞬间从天堂跌入谷底。
问题出在哪?其实很简单: 你装的是“假”GPU版 。
别再用全局Python了!虚拟环境才是正道
还记得当年你在系统里直接 pip install 各种库,最后导致不同项目之间版本冲突、互相打架的日子吗?👋 那套老方法在深度学习领域早该淘汰了。
现在最推荐的方式是使用 Miniconda —— 轻量级的 Conda 发行版,专为数据科学和机器学习而生。它能帮你:
- 隔离项目依赖(再也不怕A项目要用PyTorch 1.12,B项目要用2.0)
- 自动解决复杂的C++依赖(比如CUDA、cuDNN这些编译好的二进制包)
- 支持跨平台部署(Windows/Linux/macOS一套流程走天下)
Windows 用户看这里 👇
别再去官网下一个又大又慢的 Anaconda 了!去 Miniconda官网 下载一个不到50MB的安装包就行。
安装时记得勾选 “Add to PATH” ,这样你才能在命令行里直接使用 conda 命令。
打开 Anaconda Prompt (不是普通CMD!),输入:
conda create -n pt_env python=3.10
conda activate pt_env
恭喜!你现在进入了一个干净、独立的Python宇宙 🌌,名字叫 pt_env 。接下来所有的操作都在这个环境中进行,完全不影响其他项目。
然后根据你的硬件选择安装命令:
# 如果没有NVIDIA显卡(纯CPU训练,适合入门)
conda install pytorch torchvision torchaudio cpuonly -c pytorch
# 如果有NVIDIA GPU(强烈建议!)
conda install pytorch torchvision torchaudio pytorch-cuda=11.8 -c pytorch -c nvidia
✅ 小贴士:
-c pytorch表示从PyTorch官方频道下载,确保是最稳定版本。pytorch-cuda=11.8是关键!这意味着你安装的是支持CUDA 11.8的PyTorch构建版本。- 不要盲目追求最新CUDA版本,要匹配驱动!
Linux服务器用户请收好这份自动化脚本 🐧
如果你是在Ubuntu上部署训练任务,可以用下面这段shell脚本一键搞定:
#!/bin/bash
# 安装Miniconda
wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh
bash Miniconda3-latest-Linux-x86_64.sh -b -p $HOME/miniconda
export PATH="$HOME/miniconda/bin:$PATH"
source ~/.bashrc
# 创建环境并激活
conda create -n pt_train python=3.10 -y
conda activate pt_train
# 使用pip安装(更快!)
pip3 install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118
为什么这里用 pip 而不用 conda ?因为Conda的依赖解析器有时候太“谨慎”,会花十几分钟分析依赖关系。而PyTorch官方提供了预编译的wheel包,用pip安装通常只要1-2分钟,效率高得多⚡️。
macOS用户注意啦 ⌘
苹果芯片(M1/M2)虽然有自己的Metal加速(MPS),但目前还处于实验阶段,兼容性和性能都不够稳定。
建议做法:
conda create -n pt_mac python=3.10
conda activate pt_mac
pip3 install torch torchvision torchaudio # CPU版本
验证是否成功:
import torch
print(f"PyTorch Version: {torch.__version__}")
print(f"CUDA Available: {torch.cuda.is_available()}")
print(f"MPS Available: {torch.backends.mps.is_available()}")
如果输出类似这样:
PyTorch Version: 2.1.0
CUDA Available: True
MPS Available: False
那就说明一切正常,可以开始下一步了!🎉
| 操作系统 | 推荐包管理器 | GPU支持方式 | 安装源 |
|---|---|---|---|
| Windows | Conda | CUDA via nvidia channel | -c pytorch -c nvidia |
| Linux | Conda/Pip | CUDA 11.8/12.1 | PyPI 或 Conda |
| macOS | Pip | MPS(实验性) | PyPI |
📌 记住这张表,下次部署再也不慌!
GPU加速的灵魂拷问:驱动、CUDA Toolkit、PyTorch三者到底啥关系?
很多人搞不清楚这三个东西的区别,结果装了半天还是跑不了GPU。我们来打个比方:
- NVIDIA驱动 :就像汽车的发动机控制系统,必须先装好才能识别GPU。
- CUDA Toolkit :相当于油箱+输油管,提供运行CUDA程序所需的库和编译器。
- PyTorch CUDA构建版 :是一辆已经加满油、可以直接开走的车🚗。
重点来了: PyTorch自带嵌入式CUDA runtime !也就是说,只要你驱动支持某个CUDA版本,PyTorch就能跑,不需要你自己单独安装完整版CUDA Toolkit!
验证方法:
nvidia-smi
输出中你会看到:
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 525.60.13 Driver Version: 525.60.13 CUDA Version: 12.0 |
+-----------------------------------------------------------------------------+
这里的 CUDA Version: 12.0 表示驱动最高支持到CUDA 12.0。那你就可以放心安装支持CUDA 11.8或12.1的PyTorch版本。
常见对应关系如下:
| PyTorch 版本 | 支持的 CUDA 版本 |
|---|---|
| 2.0 – 2.1 | 11.8, 12.1 |
| 1.13 | 11.7, 11.8 |
| 1.12 | 11.6 |
⚠️ 注意:不要被
nvidia-smi显示的CUDA版本迷惑!它只是驱动支持的最大版本,并不代表你装了那个版本的Toolkit。
多卡训练怎么控制?环境变量了解一下 🛠️
在共享服务器上跑实验,最怕别人占用了所有GPU资源。怎么办?
用这个环境变量:
export CUDA_VISIBLE_DEVICES=0,1
python train.py
这句命令的意思是:“我只允许我的程序看到编号为0和1的GPU”。即使服务器上有8块卡,你也只能用这两块,避免影响他人工作。
是不是很贴心?😉
graph TD
A[用户安装 PyTorch] --> B{是否有 NVIDIA GPU?}
B -->|Yes| C[检查 nvidia-smi 输出]
C --> D[确认 CUDA 驱动版本 >= 所需版本]
D --> E[安装匹配的 PyTorch CUDA 构建版]
E --> F[运行 torch.cuda.is_available()]
F -->|True| G[启用 GPU 计算]
F -->|False| H[回退至 CPU 或排查错误]
B -->|No| I[使用 CPU-only 版本]
I --> J[正常运行,无 GPU 加速]
这张图清晰展示了GPU启用的全流程逻辑。照着走,99%的问题都能解决。
张量(Tensor):PyTorch世界的原子单位 🔬
如果说神经网络是一座大厦,那张量就是一块块砖头🧱。无论你是处理一张图片、一段文本,还是一个标量损失值,在PyTorch里它们统统都是张量。
创建张量:从零开始造数据
import torch
# 标量(0维张量)
scalar = torch.tensor(3.14)
print(scalar.shape) # torch.Size([])
# 向量(1维)
vector = torch.tensor([1, 2, 3])
print(vector.shape) # torch.Size([3])
# 矩阵(2维)
matrix = torch.tensor([[1., 2.], [3., 4.]])
print(matrix.shape) # torch.Size([2, 2])
💡 提醒:别用 torch.Tensor([1,2,3]) 这种旧写法了!它不会自动推断类型,而且行为不稳定。统一用 torch.tensor() 就完事了。
快速初始化常用张量
zeros = torch.zeros(2, 3) # 全零矩阵
ones = torch.ones(3, 4) # 全一矩阵
eye = torch.eye(3) # 单位矩阵
rand_uniform = torch.rand(2, 2) # [0,1)均匀分布
rand_normal = torch.randn(3, 3) # 标准正态分布
seq = torch.arange(0, 10, step=2) # 类似range,生成[0,2,4,6,8]
这些函数在权重初始化、生成测试数据时超级实用!
NumPy无缝转换 💞
如果你已经有现成的NumPy数组,可以直接转:
import numpy as np
np_array = np.random.rand(2, 3)
tensor_from_np = torch.from_numpy(np_array)
print(tensor_from_np.dtype) # torch.float64(保持原类型)
⚠️ 但要注意: from_numpy() 是 共享内存 的!改一边,另一边也会变:
np_array[0, 0] = 999
print(tensor_from_np[0, 0]) # 输出 999.0
如果不想共享,就用 .clone() 或 torch.tensor() 复制一份:
safe_copy = torch.tensor(np_array) # 完全独立的新对象
查看张量属性:你是谁?你从哪来?你要到哪去?
每个张量都藏着一堆元信息,关键时刻能救命:
t = torch.randn(4, 5, dtype=torch.float32).cuda()
print(t.shape) # torch.Size([4, 5]) → 维度结构
print(t.size()) # 同shape,兼容写法
print(t.ndim) # 2 → 维度数量(秩)
print(t.dtype) # torch.float32 → 数据精度
print(t.device) # cuda:0 → 当前设备
print(t.requires_grad) # False → 是否追踪梯度
| 属性名 | 返回类型 | 用途说明 |
|---|---|---|
.shape |
torch.Size |
获取维度结构 |
.size() |
同 .shape |
方法形式调用 |
.ndim |
int | 查看张量阶数(秩) |
.dtype |
torch.dtype |
控制精度与内存占用 |
.device |
torch.device |
决定计算所在硬件 |
.requires_grad |
bool | 触发 Autograd 机制的关键开关 |
举个例子:当你发现模型报错 “expected device cuda:0 but got device cpu”,八成是因为某个张量没移到GPU上。这时候 .device 属性就是排错神器🔍!
张量操作三板斧:切片、拼接、变形
索引与切片(NumPy风格真香)
x = torch.arange(10).reshape(2, 5)
print(x[0]) # 第一行: [0,1,2,3,4]
print(x[:, 1:3]) # 第二、三列: [[1,2],[6,7]]
print(x[1, -1]) # 最后一个元素: 9
还能用布尔掩码筛选:
mask = x > 5
print(x[mask]) # [6,7,8,9]
拼接与堆叠(合并的艺术)
a = torch.ones(2, 3)
b = torch.zeros(2, 3)
# 按dim=0拼接(垂直叠加)
cat_0 = torch.cat([a, b], dim=0) # shape: [4,3]
# 按dim=1拼接(水平连接)
cat_1 = torch.cat([a, b], dim=1) # shape: [2,6]
# 堆叠(新增一个维度)
stacked = torch.stack([a, b], dim=0) # shape: [2,2,3]
区别记住一句话:
- cat 是“粘合”,不增维度;
- stack 是“摞起来”,增加新维度。
形状变换(reshape背后的秘密)
x = torch.randn(6, 4)
y = x.reshape(3, 8) # 只要总元素数不变就行
z = x.transpose(0, 1) # 交换维度 → [4,6]
w = torch.randn(2, 3, 4).permute(2, 0, 1) # 重排 → [4,2,3]
但是!有个坑你一定要知道👇
graph LR
A[原始张量] --> B{需要改变形状?}
B -->|是| C[reshape / view]
B -->|否| D[继续运算]
C --> E{是否连续内存?}
E -->|是| F[成功变形]
E -->|否| G[先调用 contiguous()]
G --> F
F --> H[进行后续操作]
当一个张量经过 transpose() 或 permute() 后,它的内存布局可能就不再连续了。这时候直接 view() 会报错 ❌。
正确姿势:
transposed = x.transpose(0, 1)
reshaped = transposed.contiguous().view(-1) # 展平安全无忧 ✅
.contiguous() 的作用就是重新分配一块连续内存,保证后续变形顺利进行。
动态计算图与自动微分:PyTorch的灵魂所在 🧠
终于到了最核心的部分—— Autograd 。
你可以把它想象成一个“梯度黑匣子”✈️:你往前走一步(前向传播),它默默记下路线;等你需要回头时(反向传播),它立刻告诉你该怎么走才能最快回到起点。
requires_grad:开启梯度追踪的开关 🔘
a = torch.ones(3, 3) # 默认不追踪
b = torch.ones(3, 3, requires_grad=True) # 开启追踪
print(a.requires_grad) # False
print(b.requires_grad) # True
只有设置了 requires_grad=True 的张量,才会被纳入计算图管理。通常用于:
- 模型权重(W)
- 偏置项(b)
- 任何你想优化的参数
grad_fn:计算图的“路标”
一旦参与了可导运算,张量就会带上 grad_fn 属性:
c = a + 2 # a不可导 → c.grad_fn = None
d = b + 2 # b可导 → d的grad_fn存在
e = d * 3
print(c.grad_fn) # None
print(d.grad_fn) # <AddBackward0 object>
print(e.grad_fn) # <MulBackward0 object>
这些 Function 对象不仅记录了操作类型,还保存了反向传播所需的局部导数信息。
来看看上面那个简单计算的完整计算图:
graph TD
A[x=2] --> C[Mul]
B[w=3] --> C
C --> D[Add]
E[b=1] --> D
D --> F[Sq]
F --> G[loss=49]
style A fill:#f9f,stroke:#333
style B fill:#f9f,stroke:#333
style E fill:#f9f,stroke:#333
style G fill:#bbf,stroke:#333
粉色节点是叶子张量(输入参数),蓝色是最终输出。前向顺着箭头走,反向逆着传梯度。
让我们来手动验证一下梯度对不对:
x = torch.tensor(2.0, requires_grad=True)
w = torch.tensor(3.0, requires_grad=True)
b = torch.tensor(1.0, requires_grad=True)
y = w * x + b
loss = y ** 2
loss.backward()
print(f"dx: {x.grad}") # 应该是 42
print(f"dw: {w.grad}") # 应该是 28
print(f"db: {b.grad}") # 应该是 14
数学推导:
- loss = (wx + b)^2 = (6 + 1)^2 = 49
- ∂loss/∂x = 2(wx+b)·w = 2×7×3 = 42 ✅
- ∂loss/∂w = 2(wx+b)·x = 2×7×2 = 28 ✅
- ∂loss/∂b = 2(wx+b) = 14 ✅
完美吻合!🎯
梯度清零:为什么每次都要 optimizer.zero_grad()?
这是新手最容易忽略却最致命的一步。
PyTorch默认将梯度 累加 而不是覆盖。这意味着:
x = torch.tensor(2., requires_grad=True)
y1 = x ** 2
y2 = x ** 3
y1.backward(retain_graph=True)
print(x.grad) # 4 (dy1/dx = 2x)
y2.backward()
print(x.grad) # 4 + 12 = 16 (dy2/dx = 3x² = 12)
看到了吗?第二次backward之后,梯度被叠加了!
在标准训练循环中,我们希望每个batch的梯度是独立的,所以必须清零:
for epoch in range(100):
optimizer.zero_grad() # ←←← 关键!清除旧梯度
output = model(data)
loss = criterion(output, target)
loss.backward() # 新梯度写入 .grad
optimizer.step() # 更新参数
否则,梯度会越积越多,模型直接炸掉💣。
sequenceDiagram
participant User as 用户代码
participant Forward as 前向传播
participant Backward as 反向传播
participant Optimizer as 优化器
User->>Forward: 执行 forward pass
Forward->>Forward: 构建动态计算图
Forward-->>User: 返回输出 tensor(含 grad_fn)
User->>Backward: 调用 loss.backward()
Backward->>Backward: 遍历计算图反向传播
Backward-->>Parameter: 累加梯度至 .grad
User->>Optimizer: 调用 optimizer.step()
Optimizer->>Parameter: 使用 .grad 更新参数
User->>Optimizer: 下一轮前 zero_grad()
Optimizer->>Parameter: 清空 .grad 缓冲区
这张序列图清楚展示了训练循环中各个组件如何协作。记住: zero_grad 必须在 每一次前向传播之前 调用,顺序不能错!
模型评估:别让“过拟合”毁了你的努力 📊
训练完了就万事大吉?Too young too simple!真正考验模型能力的是它在 没见过的数据 上的表现。
分类指标全家桶:准确率之外的世界
from sklearn.metrics import precision_score, recall_score, f1_score, accuracy_score
y_true = [0, 1, 1, 0, 1, 1, 0, 0, 1, 0]
y_pred = [0, 1, 0, 0, 1, 1, 0, 1, 1, 0]
print(f"Accuracy: {accuracy_score(y_true, y_pred):.3f}") # 0.800
print(f"Precision: {precision_score(y_true, y_pred):.3f}") # 0.833
print(f"Recall: {recall_score(y_true, y_pred):.3f}") # 0.750
print(f"F1-score: {f1_score(y_true, y_pred):.3f}") # 0.789
解释一下这几个指标的实际意义:
| 指标 | 公式 | 适用场景 |
|---|---|---|
| 精确率(Precision) | TP / (TP + FP) | 重视预测为正类的准确性,如垃圾邮件识别(宁可漏判也不能误删重要邮件) |
| 召回率(Recall) | TP / (TP + FN) | 强调找出所有正例的能力,如癌症筛查(宁可误报也不能漏诊) |
| F1-score | 2×(P×R)/(P+R) | 平衡精度与召回,综合评估性能 |
损失曲线诊断:一眼看出过拟合 📈
画出训练集和验证集的损失曲线,是判断模型健康状况的“听诊器”:
import matplotlib.pyplot as plt
epochs = range(1, 11)
train_loss = [1.25, 0.98, 0.82, 0.69, 0.60, 0.52, 0.46, 0.41, 0.37, 0.33]
val_loss = [1.10, 0.92, 0.85, 0.78, 0.75, 0.74, 0.76, 0.80, 0.85, 0.92]
plt.plot(epochs, train_loss, label='Train Loss')
plt.plot(epochs, val_loss, label='Val Loss')
plt.xlabel('Epochs'); plt.ylabel('Loss')
plt.legend(); plt.title('Training vs Validation Loss')
plt.grid(True); plt.show()
如果出现 验证损失先降后升 的情况,说明已经开始过拟合了。此时应立即启动 早停(Early Stopping) 策略,防止模型“学傻了”。
混淆矩阵可视化:细节决定成败 🔍
from sklearn.metrics import confusion_matrix
import seaborn as sns
cm = confusion_matrix(y_true, y_pred)
sns.heatmap(cm, annot=True, fmt='d', cmap='Blues',
xticklabels=['Negative', 'Positive'],
yticklabels=['Negative', 'Positive'])
plt.ylabel('True Label'); plt.xlabel('Predicted Label')
plt.title('Confusion Matrix'); plt.show()
热力图能直观展示哪些样本被误判了,帮助你调整分类阈值或采样策略。
实验管理:高手都是这么炼成的 🏆
最后送大家一个小技巧:把每次实验的关键信息存下来!
eval_report = {
"epoch": 10,
"train_loss": 0.33,
"val_loss": 0.92,
"accuracy": 0.80,
"precision": 0.833,
"recall": 0.750,
"f1": 0.789,
"batch_size": 32,
"lr": 0.001,
"optimizer": "Adam",
"model_arch": "MLP"
}
把这些结构化日志保存成JSON或CSV文件,后期做横向对比、复现实验、写论文报告都方便得不行!
graph TD
A[训练完成] --> B{评估指标达标?}
B -->|否| C[调整超参数/网络结构]
C --> D[重新训练]
D --> B
B -->|是| E[保存模型]
E --> F[部署推理]
整个建模流程形成闭环,这才是真正的工程化思维!
看到这里,相信你已经不再是那个只会复制粘贴代码的新手了。👏
从环境配置、张量操作,到自动微分、模型评估,每一个环节我们都深入到底层机制去理解。这种“穿透式”的学习方式,才能让你在未来面对任何复杂问题时,都有底气说一句:
“我知道问题出在哪。” 💪
愿你在深度学习的道路上越走越稳,早日做出能改变世界的AI系统!🚀
简介:深度学习作为人工智能核心技术,通过模拟人脑神经网络实现图像识别、自然语言处理等复杂任务。PyTorch作为Facebook开发的开源深度学习框架,凭借其动态计算图、易用性和强大社区支持,成为研究和实践的首选工具。本视频课程系统讲解深度学习基础概念与PyTorch实战应用,涵盖环境搭建、张量操作、模型构建、自动梯度、数据预处理、训练优化、模型保存及评估调优等内容,并结合图像分类、文本情感分析等实战项目,帮助初学者全面掌握PyTorch在深度学习中的实际应用。课程采用音视频形式,教学直观生动,适合零基础学习者快速入门并进阶。
更多推荐

所有评论(0)