深度学习详解
从神经元到深度神经网络,全面讲解深度学习原理
大量图解和代码,通俗易懂
适合想深入理解深度学习的工程师
目录
- 第一章 神经网络基础
- 1.1 从生物神经元到人工神经元
- 1.2 感知机:最简单的神经网络
- 1.3 多层神经网络
- 1.4 激活函数详解
- 第二章 神经网络如何学习
- 2.1 前向传播
- 2.2 损失函数
- 2.3 反向传播算法
- 2.4 梯度下降优化器
- 第三章 卷积神经网络CNN
- 3.1 为什么需要CNN
- 3.2 卷积操作详解
- 3.3 池化操作
- 3.4 经典CNN架构
- 第四章 循环神经网络RNN
- 4.1 为什么需要RNN
- 4.2 RNN基本原理
- 4.3 LSTM详解
- 4.4 GRU详解
- 第五章 Transformer架构
- 5.1 注意力机制
- 5.2 自注意力
- 5.3 Transformer完整结构
- 第六章 训练技巧
- 6.1 正则化技术
- 6.2 优化技巧
- 6.3 迁移学习
第一章 神经网络基础
1.1 从生物神经元到人工神经元
1.1.1 生物神经元是如何工作的
大脑的神奇之处:
人脑有约860亿个神经元
每个神经元可以与数千个其他神经元连接
正是这些连接,让我们能够思考、学习、记忆
生物神经元的结构:
树突(接收信号)
↓ ↓ ↓
┌───────────────┐
│ 细胞体 │ ← 整合信号
│ (处理) │
└───────┬───────┘
│
轴突(发送信号)
│
↓
突触(连接其他神经元)
工作流程:
1. 树突接收来自其他神经元的信号
2. 细胞体整合所有信号
3. 如果信号超过阈值,神经元"激活"
4. 通过轴突发送信号给其他神经元
5. 突触强度决定了信号的强弱
6. 学习过程就是调整突触强度
1.1.2 人工神经元模型
把生物神经元抽象成数学模型:
输入 x₁ ────→ w₁ ──┐
│
输入 x₂ ────→ w₂ ──┼──→ 求和 ──→ 激活函数 ──→ 输出 y
│
输入 x₃ ────→ w₃ ──┘
↑
偏置 b
数学表达式:
y = f(w₁×x₁ + w₂×x₂ + w₃×x₃ + b)
简化写法:
y = f(Σwᵢxᵢ + b)
或
y = f(W·X + b)
各部分含义:
| 符号 | 含义 | 类比 |
|---|---|---|
| xᵢ | 输入信号 | 树突接收的信号 |
| wᵢ | 权重 | 突触强度 |
| b | 偏置 | 激活阈值 |
| f | 激活函数 | 决定是否激活 |
| y | 输出 | 轴突发送的信号 |
1.1.3 一个具体的例子
场景:决定要不要出去玩
输入:
x₁ = 天气好不好(0或1)
x₂ = 有没有朋友约(0或1)
x₃ = 有没有作业(0或1)
权重:
w₁ = 0.5(天气重要)
w₂ = 0.8(朋友约很重要)
w₃ = -0.6(有作业就不想出去)
偏置:
b = 0.1(比较喜欢宅)
激活函数:
如果得分 > 0,就出去玩
否则不出去
计算过程:
假设:天气好(1),有朋友约(1),没作业(0)
得分 = w₁×x₁ + w₂×x₂ + w₃×x₃ + b
= 0.5×1 + 0.8×1 + (-0.6)×0 + 0.1
= 0.5 + 0.8 + 0 + 0.1
= 1.4
因为 1.4 > 0,所以出去玩!
1.1.4 代码实现
import torch
import torch.nn as nn
# 单个神经元
neuron = nn.Linear(3, 1) # 3个输入,1个输出
# 输入
x = torch.tensor([[1.0, 1.0, 0.0]]) # 天气好,有朋友约,没作业
# 前向传播
output = neuron(x)
print(f"输出: {output}")
# 加上激活函数
import torch.nn.functional as F
activated = F.relu(output) # 如果output>0,输出output;否则输出0
print(f"激活后: {activated}")
1.2 感知机:最简单的神经网络
1.2.1 什么是感知机
感知机:最简单的神经网络,只有一个神经元。
1958年由Frank Rosenblatt发明
是深度学习的鼻祖
感知机的局限:
只能解决线性可分的问题
什么是线性可分?
- 可以用一条直线分开两类点
经典例子:AND、OR问题可以解决,XOR问题不能解决
XOR问题:
(0,0) → 0 (0,1) → 1
(1,0) → 1 (1,1) → 0
画出来:
1(×) 0(○)
0(○) 1(×)
无法用一条直线分开!
1.2.2 感知机代码实现
import numpy as np
class Perceptron:
def __init__(self, input_size, lr=0.1, epochs=100):
self.weights = np.zeros(input_size)
self.bias = 0
self.lr = lr
self.epochs = epochs
def activation(self, x):
return 1 if x >= 0 else 0
def predict(self, x):
z = np.dot(x, self.weights) + self.bias
return self.activation(z)
def train(self, X, y):
for epoch in range(self.epochs):
for i in range(len(X)):
pred = self.predict(X[i])
error = y[i] - pred
# 更新权重和偏置
self.weights += self.lr * error * X[i]
self.bias += self.lr * error
# 测试AND问题
X = np.array([[0, 0], [0, 1], [1, 0], [1, 1]])
y = np.array([0, 0, 0, 1]) # AND
perceptron = Perceptron(input_size=2)
perceptron.train(X, y)
print("AND问题测试:")
for x in X:
print(f"{x} → {perceptron.predict(x)}")
1.3 多层神经网络
1.3.1 为什么需要多层
问题:单层感知机无法解决XOR问题。
解决:用多层网络!
单层网络: 多层网络:
输入层 输入层
│ │
输出层 隐藏层
│
输出层
多层网络如何解决XOR:
第一层:把问题变换到另一个空间
第二层:在新空间中线性分开
原始空间: 变换后的空间:
1 0 1 1
0 1 0 0
无法分开 可以分开!
1.3.2 多层感知机(MLP)
输入层 隐藏层 输出层
x₁ h₁ y₁
x₂ → h₂ → y₂
x₃ h₃ y₃
数学表达:
隐藏层:
H = f(W₁·X + b₁)
输出层:
Y = g(W₂·H + b₂)
其中:
- f, g 是激活函数
- W₁, W₂ 是权重矩阵
- b₁, b₂ 是偏置向量
1.3.3 代码实现
import torch
import torch.nn as nn
class MLP(nn.Module):
def __init__(self, input_size, hidden_size, output_size):
super().__init__()
self.hidden = nn.Linear(input_size, hidden_size)
self.output = nn.Linear(hidden_size, output_size)
def forward(self, x):
x = torch.relu(self.hidden(x))
x = self.output(x)
return x
# 创建网络
model = MLP(input_size=3, hidden_size=4, output_size=2)
# 输入
x = torch.randn(1, 3)
# 前向传播
output = model(x)
print(f"输出: {output}")
1.3.4 深度神经网络
什么是"深度"?
浅层网络:1-2个隐藏层
深层网络:多个隐藏层(几十甚至上百层)
为什么深度网络厉害?
- 每一层学习不同层次的特征
- 浅层:简单特征(边缘、纹理)
- 深层:复杂特征(形状、物体)
1.4 激活函数详解
1.4.1 为什么需要激活函数
关键问题:如果没有激活函数会怎样?
答案:无论网络多深,都等价于一个线性变换!
证明:
假设没有激活函数:
第一层:y₁ = W₁x + b₁
第二层:y₂ = W₂y₁ + b₂ = W₂(W₁x + b₁) + b₂
合并:
y₂ = W₂W₁x + W₂b₁ + b₂ = W'x + b'
还是线性变换!
结论:激活函数引入非线性,让网络能学习复杂的模式。
1.4.2 常用激活函数
1. Sigmoid
公式:σ(x) = 1 / (1 + e⁻ˣ)
特点:
- 输出范围:(0, 1)
- S形曲线
- 可以解释为概率
问题:
- 梯度消失:当|x|很大时,梯度接近0
- 输出非零中心
适用场景:
- 二分类输出层
- 需要输出概率
import torch
import matplotlib.pyplot as plt
x = torch.linspace(-10, 10, 100)
y = torch.sigmoid(x)
plt.plot(x, y)
plt.title('Sigmoid')
plt.grid(True)
plt.show()
2. Tanh
公式:tanh(x) = (eˣ - e⁻ˣ) / (eˣ + e⁻ˣ)
特点:
- 输出范围:(-1, 1)
- 零中心化
- S形曲线
问题:
- 仍然存在梯度消失
适用场景:
- RNN隐藏层
3. ReLU(最常用)
公式:ReLU(x) = max(0, x)
特点:
- 计算极其简单
- 正区间梯度恒为1,缓解梯度消失
- 稀疏激活(负区间输出0)
问题:
- Dead ReLU:某些神经元可能永远不会激活
适用场景:
- 大多数隐藏层
x = torch.linspace(-10, 10, 100)
y = torch.relu(x)
plt.plot(x, y)
plt.title('ReLU')
plt.grid(True)
plt.show()
4. Leaky ReLU
公式:LeakyReLU(x) = max(αx, x)
其中α是很小的正数,如0.01
特点:
- 解决Dead ReLU问题
- 负区间也有梯度
5. GELU
公式:GELU(x) = x × Φ(x)
其中Φ(x)是标准正态分布的累积分布函数
特点:
- 平滑的ReLU替代品
- 在Transformer中表现优异
适用场景:
- Transformer隐藏层
- BERT、GPT等模型
1.4.3 如何选择激活函数
| 位置 | 推荐激活函数 | 原因 |
|---|---|---|
| 隐藏层 | ReLU | 简单高效 |
| 隐藏层(有Dead ReLU问题) | Leaky ReLU | 解决神经元死亡 |
| Transformer隐藏层 | GELU | 效果更好 |
| 二分类输出层 | Sigmoid | 输出概率 |
| 多分类输出层 | Softmax | 输出概率分布 |
| 回归输出层 | 无 | 直接输出数值 |
第二章 神经网络如何学习
2.1 前向传播
2.1.1 什么是前向传播
定义:数据从输入层开始,一层一层地通过网络,最终到达输出层的过程。
类比:水流过一系列的过滤器,每经过一层,数据就被处理一次。
2.1.2 前向传播的计算过程
假设有一个3层网络:
输入层:X
隐藏层1:H₁ = f(W₁·X + b₁)
隐藏层2:H₂ = f(W₂·H₁ + b₂)
输出层:Y = g(W₃·H₂ + b₃)
其中f、g是激活函数
2.1.3 代码实现
import torch
import torch.nn as nn
class SimpleNet(nn.Module):
def __init__(self):
super().__init__()
self.layer1 = nn.Linear(784, 256)
self.layer2 = nn.Linear(256, 128)
self.layer3 = nn.Linear(128, 10)
def forward(self, x):
# 前向传播
x = torch.relu(self.layer1(x))
x = torch.relu(self.layer2(x))
x = self.layer3(x)
return x
# 创建网络
model = SimpleNet()
# 输入(假设是MNIST图像,28×28=784像素)
x = torch.randn(1, 784)
# 前向传播
output = model(x)
print(f"输出形状: {output.shape}") # [1, 10]
2.2 损失函数
2.2.1 什么是损失函数
定义:衡量模型预测与真实值之间差距的函数。
目标:让损失函数尽可能小。
2.2.2 常用损失函数
1. 均方误差(MSE)- 用于回归
公式:MSE = (1/n) × Σ(yᵢ - ŷᵢ)²
特点:
- 对大误差惩罚更重
- 梯度计算简单
适用场景:
- 回归问题
import torch.nn as nn
criterion = nn.MSELoss()
y_true = torch.tensor([1.0, 2.0, 3.0])
y_pred = torch.tensor([1.1, 2.2, 2.8])
loss = criterion(y_pred, y_true)
print(f"MSE损失: {loss.item():.4f}")
2. 交叉熵损失 - 用于分类
公式:CE = -Σyᵢlog(ŷᵢ)
特点:
- 预测越准确,损失越小
- 与softmax配合使用
适用场景:
- 分类问题
# 多分类交叉熵
criterion = nn.CrossEntropyLoss()
y_true = torch.tensor([1]) # 真实类别
y_pred = torch.tensor([[0.1, 0.8, 0.1]]) # 预测概率
loss = criterion(y_pred, y_true)
print(f"交叉熵损失: {loss.item():.4f}")
3. 二分类交叉熵
# 二分类交叉熵
criterion = nn.BCEWithLogitsLoss()
y_true = torch.tensor([1.0, 0.0, 1.0])
y_pred = torch.tensor([0.9, 0.1, 0.8])
loss = criterion(y_pred, y_true)
print(f"二分类交叉熵损失: {loss.item():.4f}")
2.3 反向传播算法
2.3.1 什么是反向传播
定义:一种高效计算梯度的算法,从输出层向输入层逐层计算每个参数的梯度。
核心思想:利用链式法则。
2.3.2 链式法则
如果 y = f(g(x)),那么:
dy/dx = dy/dg × dg/dx
例子:y = (x²)³
dy/dx = 3(x²)² × 2x = 6x⁵
2.3.3 反向传播的计算过程
前向传播:
输入 x → 层1 → 层2 → 层3 → 输出 y → 损失 L
反向传播:
损失 L → ∂L/∂y → ∂L/∂层3 → ∂L/∂层2 → ∂L/∂层1
计算步骤:
1. 计算损失对输出的梯度:∂L/∂y
2. 计算输出对层3输出的梯度:∂y/∂z₃
3. 计算损失对层3参数的梯度:∂L/∂W₃ = ∂L/∂y × ∂y/∂z₃ × ∂z₃/∂W₃
4. 继续向后传播...
2.3.4 PyTorch自动计算梯度
import torch
# 定义参数(需要计算梯度)
w = torch.tensor([2.0], requires_grad=True)
b = torch.tensor([1.0], requires_grad=True)
# 前向传播
x = torch.tensor([3.0])
y = w * x + b
loss = (y - 10) ** 2
print(f"预测值: {y.item()}")
print(f"损失: {loss.item()}")
# 反向传播(自动计算梯度)
loss.backward()
print(f"\n梯度:")
print(f"∂L/∂w = {w.grad.item()}")
print(f"∂L/∂b = {b.grad.item()}")
2.4 梯度下降优化器
2.4.1 梯度下降的基本原理
公式:
θ = θ - η × ∇L(θ)
其中:
- θ:参数
- η:学习率
- ∇L:梯度
直观理解:
想象你在山上,想下山到最低点:
1. 看看周围哪个方向最陡(梯度)
2. 往那个方向走一步(学习率)
3. 重复1-2,直到到达山谷
2.4.2 常用优化器
1. SGD(随机梯度下降)
optimizer = torch.optim.SGD(model.parameters(), lr=0.01)
2. SGD with Momentum
optimizer = torch.optim.SGD(model.parameters(), lr=0.01, momentum=0.9)
3. Adam(最常用)
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)
4. AdamW
optimizer = torch.optim.AdamW(model.parameters(), lr=0.001, weight_decay=0.01)
2.4.3 完整训练代码
import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader, TensorDataset
# 1. 创建数据
X = torch.randn(1000, 784)
y = torch.randint(0, 10, (1000,))
dataset = TensorDataset(X, y)
dataloader = DataLoader(dataset, batch_size=32, shuffle=True)
# 2. 创建模型
model = SimpleNet()
# 3. 定义损失函数和优化器
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=0.001)
# 4. 训练循环
for epoch in range(10):
total_loss = 0
for batch_x, batch_y in dataloader:
# 前向传播
outputs = model(batch_x)
loss = criterion(outputs, batch_y)
# 反向传播
optimizer.zero_grad() # 清零梯度
loss.backward() # 计算梯度
optimizer.step() # 更新参数
total_loss += loss.item()
print(f"Epoch {epoch+1}, Loss: {total_loss/len(dataloader):.4f}")
第三章 卷积神经网络CNN
3.1 为什么需要CNN
3.1.1 全连接网络处理图像的问题
一张224×224的彩色图像:
- 像素数:224 × 224 × 3 = 150,528
- 如果第一层有1000个神经元
- 参数量:150,528 × 1000 = 1.5亿!
问题:
1. 参数太多,容易过拟合
2. 没有利用图像的空间结构
3. 计算量太大
3.1.2 CNN的优势
1. 局部连接:每个神经元只看一小块区域
2. 参数共享:同一个卷积核扫描整张图
3. 平移不变性:无论物体在哪,都能检测到
3.2 卷积操作详解
3.2.1 什么是卷积
通俗理解:用一个小的"窗口"(卷积核)在图像上滑动,提取特征。
图像(5×5): 卷积核(3×3):
1 2 3 4 5 1 0 -1
6 7 8 9 10 1 0 -1
11 12 13 14 15 1 0 -1
16 17 18 19 20
21 22 23 24 25
卷积过程:
卷积核放在图像左上角,对应位置相乘再求和:
1×1 + 2×0 + 3×(-1) + 6×1 + 7×0 + 8×(-1) + 11×1 + 12×0 + 13×(-1)
= 1 - 3 + 6 - 8 + 11 - 13 = -6
然后滑动卷积核,继续计算...
3.2.2 卷积的关键参数
1. 卷积核大小(Kernel Size)
常用:3×3, 5×5, 7×7
越大感受野越大,但参数越多
2. 步长(Stride)
步长=1:每次移动1格
步长=2:每次移动2格(输出尺寸减半)
3. 填充(Padding)
在边缘填充0
保持输出尺寸不变
4. 输出尺寸计算
输出尺寸 = (输入尺寸 + 2×填充 - 卷积核大小) / 步长 + 1
例子:
输入:224×224,卷积核:3×3,步长:1,填充:1
输出 = (224 + 2×1 - 3) / 1 + 1 = 224
3.2.3 代码实现
import torch
import torch.nn as nn
# 卷积层
conv = nn.Conv2d(
in_channels=3, # 输入通道数(RGB=3)
out_channels=64, # 输出通道数(卷积核数量)
kernel_size=3, # 卷积核大小
stride=1, # 步长
padding=1 # 填充
)
# 输入:batch × channels × height × width
x = torch.randn(32, 3, 224, 224) # 32张RGB图像
# 卷积
output = conv(x)
print(f"输入形状: {x.shape}")
print(f"输出形状: {output.shape}") # [32, 64, 224, 224]
3.3 池化操作
3.3.1 什么是池化
作用:降低特征图尺寸,减少计算量,增加感受野。
最大池化:
取每个窗口内的最大值
输入(4×4): 输出(2×2):
1 2 3 4 2 4
5 6 7 8 → 6 8
9 10 11 12
13 14 15 16
2×2窗口,步长2:
[1,2,5,6] → max=6
[3,4,7,8] → max=8
...
3.3.2 代码实现
# 最大池化
maxpool = nn.MaxPool2d(kernel_size=2, stride=2)
x = torch.randn(1, 64, 224, 224)
output = maxpool(x)
print(f"池化后形状: {output.shape}") # [1, 64, 112, 112]
# 平均池化
avgpool = nn.AvgPool2d(kernel_size=2, stride=2)
# 全局平均池化
gap = nn.AdaptiveAvgPool2d(1)
output = gap(x)
print(f"全局池化后形状: {output.shape}") # [1, 64, 1, 1]
3.4 经典CNN架构
3.4.1 LeNet(1998)
输入 → 卷积 → 池化 → 卷积 → 池化 → 全连接 → 输出
32×32 28×28 14×14 10×10 5×5 120 10
意义:开创了CNN时代
3.4.2 AlexNet(2012)
创新:
- ReLU激活函数
- Dropout正则化
- 数据增强
- GPU训练
意义:开启了深度学习时代
3.4.3 VGG(2014)
核心思想:用小卷积核堆叠
两个3×3卷积 = 一个5×5卷积的感受野
但参数更少,非线性更多
3.4.4 ResNet(2015)
核心创新:残差连接
普通网络:y = f(x)
残差网络:y = f(x) + x
为什么有效?
- 梯度可以直接通过恒等映射传播
- 解决了深层网络的退化问题
import torchvision.models as models
# 使用预训练的ResNet
model = models.resnet50(pretrained=True)
# 修改最后一层
num_classes = 10
model.fc = nn.Linear(2048, num_classes)
第四章 循环神经网络RNN
4.1 为什么需要RNN
4.1.1 序列数据的特点
序列数据:文本、语音、时间序列...
特点:
- 长度不固定
- 前后有关联
- 顺序很重要
4.1.2 全连接网络处理序列的问题
问题:
1. 无法处理变长序列
2. 无法利用上下文信息
3. 参数无法共享
4.2 RNN基本原理
4.2.1 RNN的核心思想
用隐藏状态保存历史信息
h_t = f(W_hh × h_{t-1} + W_xh × x_t + b)
其中:
- h_t:当前时刻的隐藏状态
- h_{t-1}:上一时刻的隐藏状态
- x_t:当前时刻的输入
4.2.2 RNN的结构
时间步t的展开:
x₁ x₂ x₃ x₄
│ │ │ │
↓ ↓ ↓ ↓
┌───┐ ┌───┐ ┌───┐ ┌───┐
│RNN│→│RNN│→│RNN│→│RNN│
└───┘ └───┘ └───┘ └───┘
│ │ │ │
y₁ y₂ y₃ y₄
→ 表示隐藏状态的传递
4.2.3 代码实现
import torch
import torch.nn as nn
# PyTorch中的RNN
rnn = nn.RNN(
input_size=10, # 输入维度
hidden_size=20, # 隐藏状态维度
num_layers=2, # 层数
batch_first=True # 输入格式:(batch, seq, feature)
)
# 输入
x = torch.randn(32, 5, 10) # batch=32, seq_len=5, input_size=10
h0 = torch.zeros(2, 32, 20) # 初始隐藏状态
# 前向传播
output, hn = rnn(x, h0)
print(f"输出形状: {output.shape}") # [32, 5, 20]
print(f"最终隐藏状态形状: {hn.shape}") # [2, 32, 20]
4.3 LSTM详解
4.3.1 RNN的问题
梯度消失:在长序列中,梯度会逐渐衰减,导致无法学习长期依赖。
4.3.2 LSTM的解决方案
用门控机制控制信息的流动
LSTM有三个门:
1. 遗忘门:决定丢弃哪些旧信息
2. 输入门:决定写入哪些新信息
3. 输出门:决定输出哪些信息
还有一个"细胞状态":长期记忆的传送带
4.3.3 代码实现
# LSTM
lstm = nn.LSTM(
input_size=10,
hidden_size=20,
num_layers=2,
batch_first=True
)
x = torch.randn(32, 5, 10)
h0 = torch.zeros(2, 32, 20)
c0 = torch.zeros(2, 32, 20)
output, (hn, cn) = lstm(x, (h0, c0))
print(f"输出形状: {output.shape}")
4.4 GRU详解
GRU = 简化版的LSTM
gru = nn.GRU(
input_size=10,
hidden_size=20,
num_layers=2,
batch_first=True
)
output, hn = gru(x, h0)
第五章 Transformer架构
5.1 注意力机制
5.1.1 核心思想
让模型知道"关注哪里"
例子:翻译句子
"I love you" → "我爱你"
翻译"爱"时,应该关注"love"
翻译"我"时,应该关注"I"
注意力机制让模型学会这种关注
5.2 自注意力
5.2.1 计算过程
1. 把输入转换为Query、Key、Value
Q = W_q × X (查询:我要找什么)
K = W_k × X (键:我是什么)
V = W_v × X (值:我的内容)
2. 计算注意力分数
Score = Q × K^T
3. 缩放和Softmax
Attention = Softmax(Score / √d_k)
4. 加权求和
Output = Attention × V
5.2.2 代码实现
import torch
import torch.nn as nn
import math
class SelfAttention(nn.Module):
def __init__(self, embed_dim):
super().__init__()
self.query = nn.Linear(embed_dim, embed_dim)
self.key = nn.Linear(embed_dim, embed_dim)
self.value = nn.Linear(embed_dim, embed_dim)
self.scale = math.sqrt(embed_dim)
def forward(self, x):
Q = self.query(x)
K = self.key(x)
V = self.value(x)
scores = torch.matmul(Q, K.transpose(-2, -1)) / self.scale
attention = torch.softmax(scores, dim=-1)
output = torch.matmul(attention, V)
return output
5.3 Transformer完整结构
编码器层:
输入 → 多头注意力 → 前馈网络 → 输出
解码器层:
输入 → 掩码多头注意力 → 编码器-解码器注意力 → 前馈网络 → 输出
from transformers import BertModel, BertTokenizer
# 使用预训练的BERT
tokenizer = BertTokenizer.from_pretrained('bert-base-uncased')
model = BertModel.from_pretrained('bert-base-uncased')
inputs = tokenizer("Hello world", return_tensors='pt')
outputs = model(**inputs)
第六章 训练技巧
6.1 正则化技术
6.1.1 Dropout
原理:训练时随机"关掉"一些神经元
dropout = nn.Dropout(0.5) # 丢弃50%
x = torch.randn(1, 100)
y = dropout(x)
6.1.2 批归一化
原理:把每层的输入归一化
bn = nn.BatchNorm1d(100)
x = torch.randn(32, 100)
y = bn(x)
6.2 优化技巧
6.2.1 学习率调度
from torch.optim.lr_scheduler import StepLR, CosineAnnealingLR
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)
# 阶梯衰减
scheduler = StepLR(optimizer, step_size=30, gamma=0.1)
# 余弦退火
scheduler = CosineAnnealingLR(optimizer, T_max=100)
for epoch in range(100):
train(...)
scheduler.step()
6.2.2 梯度裁剪
# 防止梯度爆炸
torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0)
6.3 迁移学习
import torchvision.models as models
# 加载预训练模型
model = models.resnet50(pretrained=True)
# 冻结参数
for param in model.parameters():
param.requires_grad = False
# 修改最后一层
model.fc = nn.Linear(2048, num_classes)
# 只训练最后一层
optimizer = torch.optim.Adam(model.fc.parameters(), lr=0.001)
总结
深度学习的核心概念
1. 神经网络:由神经元组成的网络
2. 激活函数:引入非线性
3. 损失函数:衡量预测好坏
4. 反向传播:计算梯度
5. 优化器:更新参数
深度学习的三大架构
| 架构 | 适用场景 | 代表模型 |
|---|---|---|
| CNN | 图像处理 | ResNet, VGG |
| RNN | 序列数据 | LSTM, GRU |
| Transformer | NLP, 多模态 | BERT, GPT |
学习建议
1. 理解基本原理
2. 多写代码实践
3. 阅读经典论文
4. 尝试实际项目
恭喜你完成了深度学习的学习!