模型压缩与知识蒸馏(PyTorch)

模型压缩与知识蒸馏

模型压缩技术就像就像经验丰富的老师教学生的过程。大而复杂的教师模型已经学到了很多“知识”,包括不仅限于准确预测的能力,还包括对输入数据细微差别的敏感度。学生模型则相对简单,通过模仿教师模型的输出以及中间层特征分布来学习这些知识,这样即使学生模型结构简单、参数少,也能达到接近甚至超越教师模型的表现。模型压缩就像给模型做“断舍离”,它通过剪枝(丢掉不那么重要的参数)、量化(把复杂的数字变简单)、智能结构设计(NAS帮你找最优架构)和模块替换(换上高效的小部件),巧妙的缩小模型体积,还不影响表现力。

知识蒸馏则是师傅带徒弟的好戏。大而强的教师模型传授经验给小而精的学生模型,教会学生模仿自己识别图像、做决策的能力,结果小模型也能接近甚至超越师傅的水平,但体积却迷你的多。为什么这两种技术非常重要呢?

  • 资源效率UP:大大减少计算、存储和传输数据的需求,在手机,物联网设备这些地方超实用。
  • 实时响应GET:压缩后的模型推理速度更快,满足各种实时应用需求。
  • 理解力&适应性PLUS:只是蒸馏可以提炼关键特征,让模型更好解释且能更好应对新情况。
  • 轻松部署无压力:小模型轻轻松松在各种硬件平台上安家落户,尤其适合资源有限的环境。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
import torch
import torch.nn as nn
import torch.optim as optim
from torchvision.models import resnet18, resnet50

# 定义教师模型(复杂模型)
teacher_model = resnet50(weights=True) # 使用预训练好的resnet50作为教师模型
teacher_model.eval() # 设置为评估模式,因为这里我们不需要进一步训练教师模型

# 定义学生模型(较小模型)
student_model = resnet18(num_classes = teacher_model.fc.out_features) # 学生模型的输出类别数与教师模型相同

# 定义损失函数(只是蒸馏通常用KL散度作为损失)
loss_fn = nn.KLDivLoss(reduction='batchmean') # Kullback-Leibler Divergence用于比较两个概率分布

# 假设我们有一个数据加载器data_loader
data_loader = []
tempperature = 1.0

optimizer = optim.SGD(student_model.parameters(), lr=0.01)

for images, labels in data_loader:
# 将图像输入到教师和学生模型中得到预测结果
with torch.no_grad():
# 教师模型不更新参数,所以关闭梯度计算
teacher_outputs = teacher_model(images)
# 软化教师模型的输出(tempperature时刻调节的温度参数)
teacher_probs = torch.softmax(teacher_outputs / tempperature, dim=1)

student_outputs = student_model(images)
# 对学生模型的输出同样进行软化
student_probs = torch.softmax(student_outputs / tempperature, dim=1)

# 计算KL散度损失
loss = loss_fn(student_probs, teacher_probs)

# 反向传播并优化学生模型
optimizer.zero_grad()
loss.backward()
optimizer.step()

# 这里省略了实际训练过程中循环、学习率调整和验证等细节