前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >使用PyTorch进行知识蒸馏的代码示例

使用PyTorch进行知识蒸馏的代码示例

作者头像
deephub
发布于 2023-02-01 02:05:52
发布于 2023-02-01 02:05:52
1.1K00
代码可运行
举报
文章被收录于专栏:DeepHub IMBADeepHub IMBA
运行总次数:0
代码可运行

随着机器学习模型的复杂性和能力不断增加。提高大型复杂模型在小数据集性能的一种有效技术是知识蒸馏,它包括训练一个更小、更有效的模型来模仿一个更大的“教师”模型的行为。

在本文中,我们将探索知识蒸馏的概念,以及如何在PyTorch中实现它。我们将看到如何使用它将一个庞大、笨重的模型压缩成一个更小、更高效的模型,并且仍然保留原始模型的准确性和性能。

我们首先定义知识蒸馏要解决的问题。

我们训练了一个大型深度神经网络来执行复杂的任务,比如图像分类或机器翻译。这个模型可能有数千层和数百万个参数,这使得它很难部署在现实应用程序、边缘设备等中。并且这个超大的模型还需要大量的计算资源来运行,这使得它在一些资源受限的平台上无法工作。

解决这个问题的一种方法是使用知识蒸馏将大模型压缩成较小的模型。这个过程包括训练一个较小的模型来模仿给定任务中大型模型的行为。

我们将使用来自Kaggle的胸部x光数据集进行肺炎分类来进行知识蒸馏的示例。我们使用的数据集被组织成3个文件夹(train, test, val),并包含每个图像类别的子文件夹(Pneumonia/Normal)。共有5,863张x射线图像(JPEG)和2个类别(肺炎/正常)。

比较一下这两个类的图片:

数据的加载和预处理与我们是否使用知识蒸馏或特定模型无关,代码片段可能如下所示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 transforms_train = transforms.Compose([
     transforms.Resize((224, 224)),
     transforms.RandomHorizontalFlip(),
     transforms.ToTensor(),
     transforms.Normalize([0.485, 0.456, 0.406],
                          [0.229, 0.224, 0.225])])
 
 transforms_test = transforms.Compose([
     transforms.Resize((224, 224)),
     transforms.ToTensor(),
     transforms.Normalize([0.485, 0.456, 0.406],
                          [0.229, 0.224, 0.225])])
 
 train_data = ImageFolder(root=train_dir, transform=transforms_train)
 test_data = ImageFolder(root=test_dir, transform=transforms_test)
 
 train_loader = DataLoader(train_data, batch_size=32, shuffle=True)
 test_loader = DataLoader(test_data, batch_size=32, shuffle=True)

教师模型

在这个背景中教师模型我们使用Resnet-18并且在这个数据集上进行了微调。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 import torch
 import torch.nn as nn
 import torchvision
 
 class TeacherNet(nn.Module):
     def __init__(self):
         super().__init__()
         self.model = torchvision.models.resnet18(pretrained=True)
         for params in self.model.parameters():
             params.requires_grad_ = False
 
         n_filters = self.model.fc.in_features
         self.model.fc = nn.Linear(n_filters, 2)
 
     def forward(self, x):
         x = self.model(x)
         return x

微调训练的代码如下

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 def train(model, train_loader, test_loader, optimizer, criterion, device):
     dataloaders = {'train': train_loader, 'val': test_loader}
 
     for epoch in range(30):
         print('Epoch {}/{}'.format(epoch, num_epochs - 1))
         print('-' * 10)
 
         for phase in ['train', 'val']:
             if phase == 'train':
                 model.train()
             else:
                 model.eval()
 
             running_loss = 0.0
             running_corrects = 0
 
             for inputs, labels in tqdm.tqdm(dataloaders[phase]):
                 inputs = inputs.to(device)
                 labels = labels.to(device)
 
                 optimizer.zero_grad()
 
                 with torch.set_grad_enabled(phase == 'train'):
                     outputs = model(inputs)
                     loss = criterion(outputs, labels)
 
                     _, preds = torch.max(outputs, 1)
 
                     if phase == 'train':
                         loss.backward()
                         optimizer.step()
 
                 running_loss += loss.item() * inputs.size(0)
                 running_corrects += torch.sum(preds == labels.data)
 
             epoch_loss = running_loss / len(dataloaders[phase].dataset)
             epoch_acc = running_corrects.double() / len(dataloaders[phase].dataset)
 
             print('{} Loss: {:.4f} Acc: {:.4f}'.format(phase, epoch_loss, epoch_acc))

这是一个标准的微调训练步骤,训练后我们可以看到该模型在测试集上达到了91%的准确性,这也就是我们没有选择更大模型的原因,因为作为测试91的准确率已经足够作为基类模型来使用了。

我们知道模型有1170万个参数,因此不一定能够适应边缘设备或其他特定场景。

学生模型

我们的学生是一个更浅的CNN,只有几层和大约100k个参数。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 class StudentNet(nn.Module):
     def __init__(self):
         super().__init__()
         self.layer1 = nn.Sequential(
             nn.Conv2d(3, 4, kernel_size=3, padding=1),
             nn.BatchNorm2d(4),
             nn.ReLU(),
             nn.MaxPool2d(kernel_size=2, stride=2)
         )
         self.fc = nn.Linear(4 * 112 * 112, 2)
 
     def forward(self, x):
         out = self.layer1(x)
         out = out.view(out.size(0), -1)
         out = self.fc(out)
         return out

看代码就非常的简单,对吧。

如果我可以简单地训练这个更小的神经网络,我为什么还要费心进行知识蒸馏呢?我们最后会附上我们通过超参数调整等手段从头训练这个网络的结果最为对比。

但是现在我们继续我们的知识蒸馏的步骤

知识蒸馏训练

训练的基本步骤是不变的,但是区别是如何计算最终的训练损失,我们将使用教师模型损失,学生模型的损失和蒸馏损失一起来计算最终的损失。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 class DistillationLoss:
     def __init__(self):
         self.student_loss = nn.CrossEntropyLoss()
         self.distillation_loss = nn.KLDivLoss()
         self.temperature = 1
         self.alpha = 0.25
 
     def __call__(self, student_logits, student_target_loss, teacher_logits):
         distillation_loss = self.distillation_loss(F.log_softmax(student_logits / self.temperature, dim=1),
                                                    F.softmax(teacher_logits / self.temperature, dim=1))
 
         loss = (1 - self.alpha) * student_target_loss + self.alpha * distillation_loss
         return loss

损失函数是下面两个东西的加权和:

  • 分类损失,称为student_target_loss
  • 蒸馏损失,学生对数和教师对数之间的交叉熵损失

简单的讲,我们的教师模型需要教导学生如何“思考”的,这就是指的是它的不确定性;例如,如果教师模型的最终输出概率是[0.53,0.47],我们希望学生也得到同样类似结果,这些预测之间的差异就是蒸馏损失。

为了控制损失,还有有两个主要参数:

  • 蒸馏损失的权重:0意味着我们只考虑蒸馏损失,反之亦然。
  • 温度:衡量教师预测的不确定性。

在上面的要点中,alpha和temperature的值都是根据我们尝试过一些组合得到的最佳结果的值。

结果对比

这是这个实验的表格摘要。

我们可以清楚地看到使用更小(99.14%),更浅的CNN所获得的巨大好处:与无蒸馏训练相比,准确率提升了10点,并且比Resnet-18快11倍!也就是说,我们的小模型真的从大模型中学到了有用的东西。

作者:Alessandro Lamberti

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-12-17,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 DeepHub IMBA 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
zabbix发送报警信息带图片
zabbix 发送报警内容调用 zabbix 的 api 生成原始图数据,然后将图片上传到远方图床取出图片 URL 进行展示;
cuijianzhe
2022/06/14
7370
zabbix发送报警信息带图片
zabbix最新SQL注入漏洞+EXP
最近zabbix又出大事了,高危的SQL注入漏洞,影响V3.0.4以下所有版本,请小伙伴及时修复。 漏洞概述: zabbix是一个开源的企业级性能监控解决方案。 官方网站:http://www.zab
逸鹏
2018/04/11
1.6K0
zabbix最新SQL注入漏洞+EXP
[PYTHON] 使用python实现一个miniWorkNote来记录工作内容
对于我这种记忆力不好的人来说, 是需要一个工具来记录 已完成 和 待完成 的事情的. 比如一个记事本就行, 但我没法一眼就能找到还有哪些事情未做(都一个色儿). 那么就需要一个工具来帮我了.
大大刺猬
2024/06/26
1600
[PYTHON] 使用python实现一个miniWorkNote来记录工作内容
自定义admin组件
1 新建一个项目, 创建一个app01和stark应用,stark创建一个service包,并在service下创建stark.py。然后注册app
py3study
2020/01/16
1.7K0
自定义admin组件
Zabbix告警发送邮件时附带性能图
zabbix告警传入item.ky参数 -> 利用item.key获取当前的性能图 -> 保存到本地 -> 在发送邮件的时候构建邮件文本内容
星哥玩云
2022/07/13
3110
Zabbix告警发送邮件时附带性能图
2021最新微博爬虫——根据话题名称获取所有相关微博与评论
-首先确定抓取微博内容、评论数、点赞数、发布时间、发布者名称等主要字段。选择weibo.com作为主要数据来源。(就是因为搜索功能好使)
MinChess
2022/12/27
4.5K1
2021最新微博爬虫——根据话题名称获取所有相关微博与评论
python开发_HTMLParser_html文档解析
=============================================
Hongten
2022/05/06
4380
23.Django基础
Django基本配置 Python的WEB框架有Django、Tornado、Flask 等多种,Django相较与其他WEB框架其优势为:大而全,框架本身集成了ORM、模型绑定、模板引擎、缓存、Session等诸多功能 1.安装 # windows 直接用pip进行安装 pip install django # 生成的django文件加入到系统环境变量 2.创建并启动 创建 django-admin startproject mysite 运行 python manage.py runserver
zhang_derek
2018/04/11
9530
23.Django基础
readability-lxml 源码解析(三):`readability.py`
ApacheCN_飞龙
2023/10/13
2640
Python自动化开发学习-Django
django amdin是django提供的一个后台管理页面,该管理页面提供完善的html和css,使得你在通过Model创建完数据库表之后,就可以对数据进行增删改查。
py3study
2020/01/09
1.8K0
Zabbix监控调用map.get并且下载图文件
#!/usr/bin/env python # -*- coding: utf-8 -*- # @Time : 17/8/28 上午9:09 # @Author : lee # @File : ZabbixMaps.py # @Software: PyCharm # 说明: 输入机器要查询的园区 知道序号后,第二次 园区+序号出图 阿里 m6 园区命令分别是(ali,m6,yq) import urllib.request import http.cookiejar import htt
98k
2018/04/12
1.1K0
v$和v_$的一些玄机
原因是该用户缺少一些动态性能视图的访问权限,但是当我们尝试将提示的v$session授予用户(例如hr)时,提示了这个错,
bisal
2021/09/06
8560
【Zabbix】Zabbix 分布式监控—创建Proxy主机
zabbix镜像-zabbix下载地址-zabbix安装教程-阿里巴巴开源镜像站 (aliyun.com)
宝耶需努力
2022/12/13
5960
【Zabbix】Zabbix 分布式监控—创建Proxy主机
【说站】python中htmlparser解析html
它根据树形结构将html页面中的标签分析成一个节点,一种类型的节点对应一个类,通过调用它可以轻松访问标签中的内容。
很酷的站长
2022/11/23
6530
【说站】python中htmlparser解析html
通达OAの漏洞合集
两三个月之前实习的时候通达OA的漏洞学习笔记,赶紧发了清一下库存,免得文件夹吃灰。
h0cksr
2023/05/18
5.9K0
CVE-2024-22120|Zabbix Server SQL注入漏洞(POC)
Zabbix是一个基于WEB界面的提供分布式系统监视以及网络监视功能的企业级的开源解决方案。
信安百科
2024/05/22
2.6K0
CVE-2024-22120|Zabbix Server SQL注入漏洞(POC)
构建ASP.NET MVC4+EF5+EasyUI+Unity2.x注入的后台管理系统(9)-MVC与EasyUI结合增删改查
文章于2016-12-17日重写 在第八讲中,我们已经做到了怎么样分页。这一讲主要讲增删改查。第六讲的代码已经给出,里面包含了增删改,大家可以下载下来看下。 这讲主要是,制作漂亮的工具栏,虽然ea
用户1149182
2018/01/16
2K0
构建ASP.NET MVC4+EF5+EasyUI+Unity2.x注入的后台管理系统(9)-MVC与EasyUI结合增删改查
小鲤AI志愿填报助手:一键探索最适合你的大学专业
每年六月,随着高考的落幕,一个新的挑战随之而来——如何在全国范围内的激烈竞争中抢占一席之地。今年,超过1300万的学生参加了这场决定未来命运的考试,每一个人都希望能进入心仪的大学,学习理想的专业。然而,选择的过程并不简单,错综复杂的分数线、众多的院校和专业以及地域和预算的限制,构成了一张巨大的迷宫。在这个迷宫中,每一步选择都可能影响未来职业路径和生活质量。
AI Inception
2024/06/19
2210
小鲤AI志愿填报助手:一键探索最适合你的大学专业
测试开发:Python + Flask 实现接口接收 Disk 信息
今天分享的内容是基于:测试开发:Python + Flask 实现接口接收内存信息 来进一步分享如何使用 Python + Flask 实现接收 Disk 的信息。
Wu_Candy
2022/07/04
3480
测试开发:Python + Flask 实现接口接收 Disk 信息
python3 下 Zabbix监控调用graph.get并且下载监控图
这个代码是如何访问三个不同机房并将传入的zabbix中的监控机器的ip进行判断(因为后来需要登陆网站,不同的机房名称不一样) 可以输入两个参数 只输入IP 返回监控列表 需要准备的包: pre
98k
2018/04/11
2K0
python3 下 Zabbix监控调用graph.get并且下载监控图
相关推荐
zabbix发送报警信息带图片
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档