什么是深度学习
深度学习是机器学习的一个分支 ,核心是用多层人工神经网络从数据中自动学习特征和规律。传统机器学习往往需要人工设计特征,而深度学习可以端到端地从原始数据(如图像像素、文本词向量、声音波形)中逐层提取特征,从低级特征到高级语义。
"深度"通常指神经网络有很多层,通过多层非线性变换,模型能表达非常复杂的函数。
深度学习的特点
-
层次化特征学习:浅层学边缘、纹理,深层学物体、语义。
-
端到端训练:输入到输出整体优化,减少人工特征工程。
-
数据驱动:依赖大量标注或非标注数据。
-
依赖算力:通常需要 GPU/TPU 加速。
-
可扩展性强:模型和数据越大,性能往往还能提升。
-
通用性强:同一套方法可用于图像、文本、语音、图结构等。
-
黑箱与可解释性差:尤其大模型,内部决策难以解释。
-
容易过拟合、对超参数敏感:需要正则化、调参和大量实验。
常见的深度学习模型
-
MLP / 全连接网络:最基础的前馈网络。
-
CNN 卷积神经网络:擅长图像、视频,如 LeNet、AlexNet、VGG、ResNet。
-
RNN / LSTM / GRU:处理序列数据,如文本、语音、时间序列。
-
Transformer:基于自注意力,是现代 NLP 和大模型的基础,如 BERT、GPT。
-
Autoencoder / VAE:用于降维、表征学习、生成。
-
GAN 生成对抗网络:生成图像、视频等。
-
Diffusion 扩散模型:如 Stable Diffusion,当前主流生成模型之一。
-
GNN 图神经网络:处理社交网络、分子结构、知识图谱。
-
深度强化学习:如 DQN、PPO,用于游戏、机器人控制。
-
多模态大模型:同时处理文本、图像、音频、视频,如 GPT-4V、CLIP。
深度学习的应用场景
-
计算机视觉:图像分类、目标检测、分割、人脸识别、医学影像。
-
自然语言处理:翻译、摘要、问答、聊天机器人、搜索。
-
语音:语音识别、语音合成、声纹识别。
-
推荐与广告:点击率预测、个性化推荐。
-
自动驾驶:感知、车道检测、障碍物识别、决策规划。
-
机器人与控制:抓取、导航、运动控制。
-
医疗与生物:疾病诊断、药物发现、蛋白质结构预测,如 AlphaFold。
-
生成式 AI:文生图、文生视频、代码生成、写作助手。
-
科学计算:气象预测、物理模拟、材料设计。
-
金融风控:欺诈检测、信用评分。
深度学习的发展史
-
1943:McCulloch-Pitts 神经元模型。
-
1958:Rosenblatt 提出感知机。
-
1969:Minsky 和 Papert 指出感知机不能解决 XOR,神经网络进入低谷。
-
1986:反向传播算法推广,神经网络重新受到关注。
-
1989/1998:LeCun 提出 CNN 和 LeNet-5,用于手写数字识别。
-
2006:Hinton 提出深度信念网络,深度学习开始复兴。
-
2012:AlexNet 在 ImageNet 夺冠,深度学习爆发。
-
2014:GAN、Seq2Seq、VGG 等出现。
-
2015:ResNet 提出残差连接,训练超深网络成为可能。
-
2017:Transformer 提出,注意力机制成为主流。
-
2018:BERT、GPT 出现,预训练大模型兴起。
-
2020:GPT-3 展示大模型少样本能力。
-
2021---2022:CLIP、扩散模型、ChatGPT、Stable Diffusion 推动生成式 AI 普及。
-
2023 至今:GPT-4、多模态大模型、开源大模型快速发展。
PyTorch框架介绍
PyTorch 是由 Meta 开源的主流深度学习框架,以灵活、易调试、Python 优先著称,广泛用于研究和工业界。
核心概念:
-
Tensor 张量:类似 NumPy 数组,但支持 GPU 加速。
-
Autograd 自动求导:自动计算梯度,支持反向传播。
-
动态计算图:运行时构建计算图,调试直观。
-
nn.Module:定义网络层和模型。
-
Optim 优化器:如 SGD、Adam。
-
DataLoader:批量加载和打乱数据。
-
GPU/分布式训练:支持 CUDA、多卡 DDP、FSDP。
生态工具:
-
torchvision:图像模型、数据集、变换。
-
torchaudio:音频处理。
-
torchtext:文本处理。
-
TorchScript / TorchServe:模型导出与部署。
-
Hugging Face Transformers:大量预训练模型。
什么是张量
张量(Tensor)是 PyTorch 中最核心的数据结构,可以理解为多维数组:
-
0 维张量:标量,如
torch.tensor(3.14) -
1 维张量:向量,如
torch.tensor([1, 2, 3]) -
2 维张量:矩阵,如
torch.tensor([[1, 2], [3, 4]]) -
3 维及以上:高维张量,如图像
(C, H, W)、批量图像(N, C, H, W)
它和 NumPy 数组很像,但多了几个关键能力:
-
可在 GPU 上计算
-
支持自动微分
-
支持广播、原地操作等
-
是神经网络参数和梯度的载体
常用属性:
import torch
x = torch.tensor([[1, 2], [3, 4]], dtype=torch.float32)
print(x.shape) # torch.Size([2, 2])
print(x.dtype) # torch.float32
print(x.device) # cpu
print(x.requires_grad) # False
print(x.grad) # None
print(x.grad_fn) # None
print(x.is_leaf) # True
2. 张量的创建
常见创建方式:
import torch
import numpy as np
# 从 Python 列表创建
a = torch.tensor([1, 2, 3]) # int64
b = torch.tensor([1.0, 2.0, 3.0]) # float32
c = torch.tensor([[1, 2], [3, 4]], dtype=torch.float64)
# 创建未初始化、全 0、全 1、指定值
d = torch.empty(2, 3)
e = torch.zeros(2, 3)
f = torch.ones(2, 3, dtype=torch.float64)
g = torch.full((2, 3), 7)
# 序列
h = torch.arange(0, 10, 2) # tensor([0, 2, 4, 6, 8])
i = torch.linspace(0, 1, 5) # 0 到 1 均匀取 5 个点
# 随机
j = torch.rand(2, 3) # [0,1) 均匀分布
k = torch.randn(2, 3) # 标准正态分布
l = torch.randint(0, 10, (2, 3)) # 整数随机
# 单位矩阵
m = torch.eye(3)
# 从 NumPy 创建,共享内存
n = np.array([1, 2, 3])
o = torch.from_numpy(n)
p = torch.as_tensor(n)
# 指定设备和梯度
q = torch.tensor([1.0, 2.0], device="cpu", requires_grad=True)
注意:
-
torch.tensor(...)通常会复制数据。 -
torch.from_numpy(...)和torch.as_tensor(...)可能共享内存。 -
torch.Tensor(2, 3)是旧式写法,创建未初始化的float32张量。 -
requires_grad=True一般只用于浮点张量。
3. 张量的类型转换
x = torch.tensor([1, 2, 3])
# 转 dtype
x_float = x.float() # torch.float32
x_long = x.long() # torch.int64
x_double = x.double() # torch.float64
x_bool = x.bool() # torch.bool
x_half = x.half() # torch.float16
# 通用方式
y = x.to(torch.float64)
z = x.to("cpu")
# z = x.to("cuda") # 有 GPU 时可用
# 按另一个张量的 dtype/device 转换
other = torch.randn(3, dtype=torch.float64)
w = x.to(other)
# 旧式写法
v = x.type(torch.FloatTensor)
注意:
-
浮点转整数会截断小数部分。
-
整数转布尔:0 为
False,非 0 为True。 -
.to()通常返回新张量,除非 dtype 和 device 都不变。 -
原地转换可用
.float_()、.long_()等,但慎用。
4. 张量数值计算
逐元素运算:
a = torch.tensor([1.0, 2.0, 3.0])
b = torch.tensor([4.0, 5.0, 6.0])
print(a + b)
print(a - b)
print(a * b)
print(a / b)
print(a ** 2)
print(torch.sqrt(a))
print(torch.exp(a))
print(torch.log(a))
print(torch.abs(torch.tensor([-1.0, 2.0])))
print(torch.ceil(torch.tensor([1.2, 2.8])))
print(torch.floor(torch.tensor([1.2, 2.8])))
print(torch.round(torch.tensor([1.2, 2.8])))
print(torch.clamp(a, min=1.5, max=2.5))
矩阵运算:
A = torch.randn(2, 3)
B = torch.randn(3, 4)
print(A @ B) # 矩阵乘法
print(torch.mm(A, B)) # 二维矩阵乘法
print(torch.matmul(A, B)) # 支持广播的矩阵乘法
v1 = torch.tensor([1.0, 2.0])
v2 = torch.tensor([3.0, 4.0])
print(torch.dot(v1, v2)) # 点积
A3 = torch.randn(10, 2, 3)
B3 = torch.randn(10, 3, 4)
print(torch.bmm(A3, B3)) # 批量矩阵乘法
比较和条件:
x = torch.tensor([1, 2, 3])
print(x > 1)
print(torch.eq(x, torch.tensor([1, 0, 3])))
print(torch.where(x > 1, x, torch.zeros_like(x)))
原地操作通常带下划线:
python
x = torch.tensor([1.0, 2.0])
x.add_(1) # x 变为 [2.0, 3.0]
x.mul_(2) # x 变为 [4.0, 6.0]
5. 张量运算函数
常见统计和聚合函数:
x = torch.tensor([[1.0, 2.0, 3.0],
[4.0, 5.0, 6.0]])
print(x.sum())
print(x.sum(dim=0)) # 按列求和
print(x.sum(dim=1)) # 按行求和
print(x.sum(dim=1, keepdim=True))# 保持维度
print(x.mean())
print(x.mean(dim=0))
print(x.std())
print(x.var())
print(x.max())
print(x.max(dim=1)) # 返回 values 和 indices
print(x.argmax(dim=1))
print(x.min(dim=0))
print(x.argmin(dim=0))
print(x.prod())
print(x.cumsum(dim=1))
print(torch.norm(x))
print(torch.softmax(x, dim=-1))
print(torch.log_softmax(x, dim=-1))
注意:
-
dim表示沿哪个维度操作。 -
keepdim=True会保留被聚合的维度,方便广播。 -
x.max(dim=1)返回的是命名元组(values, indices)。
6. 张量索引操作
基本索引、切片:
x = torch.arange(12).reshape(3, 4)
# tensor([[ 0, 1, 2, 3],
# [ 4, 5, 6, 7],
# [ 8, 9, 10, 11]])
print(x[0]) # 第一行
print(x[1, 2]) # 第 1 行第 2 列
print(x[:, 1]) # 第二列
print(x[0:2, 1:3]) # 切片
print(x[::2]) # 步长 2
print(x[..., 0]) # 省略号
布尔索引:
mask = x > 5
print(mask)
print(x[mask])
print(torch.masked_select(x, mask))
花式索引:
idx = torch.tensor([0, 2])
print(x[idx])
print(torch.index_select(x, dim=0, index=idx))
print(torch.nonzero(x > 5))
gather 和 scatter:
x = torch.tensor([[1, 2],
[3, 4]])
index = torch.tensor([[0, 1],
[1, 0]])
print(torch.gather(x, dim=1, index=index))
# tensor([[1, 2],
# [4, 3]])
out = torch.zeros(2, 2)
src = torch.tensor([[10, 20],
[30, 40]])
out.scatter_(dim=1, index=index, src=src)
print(out)
# tensor([[10, 20],
# [40, 30]])
7. 张量形状操作
x = torch.arange(12)
print(x.shape) # torch.Size([12])
# view 和 reshape
a = x.view(3, 4) # 要求内存连续
b = x.reshape(2, 6) # 更灵活,必要时复制
# 增加/删除维度
c = torch.randn(3, 4)
print(c.unsqueeze(0).shape) # (1, 3, 4)
print(c.unsqueeze(1).shape) # (3, 1, 4)
d = torch.randn(1, 3, 1, 4)
print(d.squeeze().shape) # (3, 4)
print(d.squeeze(0).shape) # (3, 1, 4)
# 交换维度
e = torch.randn(3, 4)
print(e.transpose(0, 1).shape) # (4, 3)
f = torch.randn(2, 3, 4)
print(f.permute(2, 0, 1).shape) # (4, 2, 3)
# 展平
print(f.flatten().shape) # (24,)
print(f.flatten(start_dim=1).shape) # (2, 12)
# 扩展和重复
g = torch.randn(1, 3, 4)
print(g.expand(2, 3, 4).shape) # (2, 3, 4)
print(g.repeat(2, 1, 1).shape) # (2, 3, 4)
# 连续性
h = e.transpose(0, 1)
print(h.is_contiguous()) # 通常 False
h = h.contiguous()
广播示例:
a = torch.ones(3, 4)
b = torch.ones(4)
print((a + b).shape) # (3, 4)
8. 张量拼接操作
a = torch.tensor([[1, 2],
[3, 4]])
b = torch.tensor([[5, 6],
[7, 8]])
# cat:沿已有维度拼接
print(torch.cat([a, b], dim=0))
# tensor([[1, 2],
# [3, 4],
# [5, 6],
# [7, 8]])
print(torch.cat([a, b], dim=1))
# tensor([[1, 2, 5, 6],
# [3, 4, 7, 8]])
# stack:沿新维度堆叠
print(torch.stack([a, b], dim=0).shape) # (2, 2, 2)
print(torch.stack([a, b], dim=1).shape) # (2, 2, 2)
# vstack / hstack / dstack
print(torch.vstack([a, b]).shape) # (4, 2)
print(torch.hstack([a, b]).shape) # (2, 4)
# split / chunk / unbind
x = torch.arange(12).reshape(3, 4)
print(torch.split(x, 1, dim=0)) # 每块 1 行
print(torch.chunk(x, 3, dim=0)) # 分成 3 块
print(torch.unbind(x, dim=0)) # 去掉第 0 维,返回元组
注意:
-
cat要求除拼接维度外,其他维度大小一致。 -
stack要求所有张量形状完全一致。 -
split按块大小拆,chunk按块数量拆。
9. 自动微分模块
PyTorch 的自动微分模块是 torch.autograd。它会记录前向传播中的操作,形成动态计算图,然后通过反向传播自动求梯度。
基本用法:
x = torch.tensor([2.0, 3.0], requires_grad=True)
y = x ** 2 + 3 * x + 1
z = y.sum()
z.backward()
print(x.grad)
# tensor([7., 9.]),因为 dy/dx = 2x + 3
梯度会累加:
x = torch.tensor([1.0], requires_grad=True)
for _ in range(3):
y = x ** 2
y.backward()
print(x.grad)
# 每次都会累加,通常需要手动清零
x.grad.zero_()
关闭梯度:
with torch.no_grad():
y = x * 2
print(y.requires_grad) # False
detach():
x = torch.tensor([1.0], requires_grad=True)
y = x * 2
z = y.detach()
print(y.requires_grad) # True
print(z.requires_grad) # False
非标量反向传播:
x = torch.tensor([1.0, 2.0], requires_grad=True)
y = x ** 2
# y 不是标量,需要传入与 y 同形的梯度
y.backward(torch.tensor([1.0, 1.0]))
print(x.grad) # tensor([2., 4.])
直接求梯度:
x = torch.tensor([2.0, 3.0], requires_grad=True)
y = x ** 2
grad = torch.autograd.grad(y.sum(), x)
print(grad) # (tensor([4., 6.]),)
简单线性回归示例:
X = torch.randn(100, 1)
true_w = 2.0
true_b = 1.0
y = true_w * X + true_b + 0.01 * torch.randn(100, 1)
w = torch.randn(1, requires_grad=True)
b = torch.zeros(1, requires_grad=True)
lr = 0.1
for epoch in range(100):
y_pred = X * w + b
loss = ((y_pred - y) ** 2).mean()
loss.backward()
with torch.no_grad():
w -= lr * w.grad
b -= lr * b.grad
w.grad.zero_()
b.grad.zero_()
print(w, b)
关键点:
-
requires_grad=True的张量会参与计算图。 -
叶子节点的梯度保存在
.grad。 -
反向传播后梯度默认累加,更新前通常要
zero_grad()。 -
推理或手动更新参数时用
torch.no_grad()。 -
detach()可以从计算图中分离张量。 -
非标量调用
backward()需要提供gradient参数。
总结
PyTorch 的张量操作可以概括为:
-
创建 :
tensor、zeros、ones、randn、arange、from_numpy -
转换 :
.to()、.float()、.long()、.bool() -
计算:逐元素运算、矩阵乘法、广播
-
函数 :
sum、mean、max、argmax、softmax -
索引 :切片、布尔索引、
gather、index_select -
形状 :
view、reshape、unsqueeze、transpose、permute -
拼接 :
cat、stack、split、chunk -
自动微分 :
requires_grad、backward、.grad、no_grad、detach