一个例子练习知识蒸馏

【知识蒸馏】知识蒸馏(Knowledge Distillation)技术详解 知识蒸馏综述 阅读详情

本文通过一个图像分类的例子练习一下如何做知识蒸馏。

数据集选用CIFAR10.
知识蒸馏是用一个比较大的教师模型的output来训练较小的学生模型,paper可以参考这篇。

本文用一个简单的教师模型resnet18,resnet18本来用于imageNet, 现在cifar10的图片太小,需要修改一下防止图片被下采样没信息了,改卷积层的kernel size和maxpool layer. 另外,不要直接调用model.forward, 那样会调用修改之前的模型,还是会报错,因为修改之前的resnet18针对的是imageNet的图片尺寸,不适用于cifar10.

class TeacherNet(nn.Module):
    def __init__(self):
        super(TeacherNet, self).__init__()
        self.model = torchvision.models.resnet18(pretrained=True)
        # 修改第一层以适应32x32输入
        self.model.conv1 = nn.Conv2d(3, 64, kernel_size=3, stride=1, padding=1, bias=False)
        self.model.maxpool = nn.Identity()
        # 修改最后一层以适应CIFAR-10的10个类别
        self.model.fc = nn.Linear(512, 10)

    def forward(self, x):
        x = self.model.conv1(x)
        x = self.model.bn1(x)
        x = self.model.relu(x)
        x = self.model.maxpool(x)

        x = self.model.layer1(x)
        x = self.model.layer2(x)
        x = self.model.layer3(x)
        x = self.model.layer4(x)

        x = self.model.avgpool(x)
        x = torch.flatten(x, 1)
        x = self.model.fc(x)
        return x

先把这个教师模型训练出来。加上early stop机制。

class EarlyStopping:
    def __init__(self, patience=7, min_delta=0):
        self.patience = patience
        self.min_delta = min_delta
        self.counter = 0
        self.best_loss = None
        self.early_stop = False

    def __call__(self, val_loss):
        if self.best_loss is None:
            self.best_loss = val_loss
        elif val_loss > self.best_loss - self.min_delta:
            self.counter += 1
            if self.counter >= self.patience:
                self.early_stop = True
        else:
            self.best_loss = val_loss
            self.counter = 0
            
def train_teacher(train_loader, val_loader, model, epochs=50, device='cuda'):
    model = model.to(device)
    criterion = nn.CrossEntropyLoss()
    optimizer = optim.Adam(model.parameters(), lr=1e-3)
    scheduler = optim.lr_scheduler.ReduceLROnPlateau(optimizer, 'min', patience=5, factor=0.5)
    early_stopping = EarlyStopping(patience=5)

    train_losses = []
    train_accs = []
    val_losses = []
    val_accs = []

    best_val_acc = 0

    for epoch in range(epochs):
        model.train()
        running_loss = 0.0
        correct = 0
        total = 0

        for i, (inputs, labels) in enumerate(train_loader):
            inputs, labels = inputs.to(device), labels.to(device)

            optimizer.zero_grad()
            outputs = model(inputs)
            loss = criterion(outputs, labels)
            loss.backward()
            optimizer.step()

            running_loss += loss.item()
            _, predicted = torch.max(outputs.data, 1)
            total += labels.size(0)
            correct += predicted.eq(labels).sum().item()

            if i % 100 == 99:
                print(
                    f'[Epoch {epoch + 1}, Batch {i + 1}] loss: {running_loss / 100:.3f} acc: {100. * correct / total:.2f}%')
                running_loss = 0.0

        train_loss, train_acc = evaluate(model, train_loader, criterion, device)
        val_loss, val_acc = evaluate(model, val_loader, criterion, device)

        train_losses.append(train_loss)
        train_accs.append(train_acc)
        val_losses.append(val_loss)
        val_accs.append(val_acc)

        print(f'Epoch {epoch + 1}/{epochs}:')
        print(f'Train Loss: {train_loss:.4f}, Train Acc: {train_acc:.2f}%')
        print(f'Val Loss: {val_loss:.4f}, Val Acc: {val_acc:.2f}%')

        # 保存最佳模型
        if val_acc > best_val_acc:
            best_val_acc = val_acc
            torch.save(model.state_dict(), 'best_teacher.pth')

        scheduler.step(val_loss)

        early_stopping(val_loss)
        if early_stopping.early_stop:
            print(f'Early stopping triggered at epoch {epoch + 1}')
            break

    plot_training_curves(train_losses, train_accs, val_losses, val_accs)

    return train_losses, train_accs, val_losses, val_accs

接下来用这个教师模型去指导一个小型的学生模型。
定义一个只有3个卷积层的学生模型。

class StudentNet(nn.Module):
    def __init__(self):
        super(StudentNet, self).__init__()
        self.conv1 = nn.Conv2d(3, 16, 3, padding=1)
        self.conv2 = nn.Conv2d(16, 32, 3, padding=1)
        self.conv3 = nn.Conv2d(32, 64, 3, padding=1)
        self.pool = nn.MaxPool2d(2, 2)
        self.fc1 = nn.Linear(64 * 4 * 4, 256)
        self.fc2 = nn.Linear(256, 10)
        self.relu = nn.ReLU()

    def forward(self, x):
        x = self.pool(self.relu(self.conv1(x)))
        x = self.pool(self.relu(self.conv2(x)))
        x = self.pool(self.relu(self.conv3(x)))
        x = x.view(-1, 64 * 4 * 4)
        x = self.relu(self.fc1(x))
        x = self.fc2(x)
        return x

定义知识蒸馏的损失函数,损失包含hard label部分和soft label部分,hard label是标注的label, soft label是教师模型的output经过温度的变化。
而且要注意,由于soft target产生的梯度幅度 相当于缩放了 1/T2 ,因此在同时使用hard 和 soft targets时将其乘以 T2.
其中hard loss用的是CE loss, soft loss用的是KL散度。

class DistillationLoss(nn.Module):
    def __init__(self, T=4):
        super(DistillationLoss, self).__init__()
        self.T = T

    def forward(self, student_logits, teacher_logits, labels, alpha=0.5):
        soft_targets = nn.functional.softmax(teacher_logits / self.T, dim=1)
        soft_prob = nn.functional.log_softmax(student_logits / self.T, dim=1)
        #KL散度:Loss = -Σ P(x) * log(Q(x))    [忽略常数项 Σ P(x) * log(P(x))]
        #除以soft_prob.size(0)是为了取平均,使得批大小的改变不会影响损失的规模
        soft_targets_loss = -torch.sum(soft_targets * soft_prob) / soft_prob.size(0)

        hard_loss = nn.functional.cross_entropy(student_logits, labels)
        #用温度T软化概率分布时,梯度会被同时缩小T^2倍
        #为了保持梯度的数量级与硬目标损失相近,需要乘上T^2进行补偿
        loss = alpha * hard_loss + (1 - alpha) * (self.T ** 2) * soft_targets_loss
        return loss

知识蒸馏训练

def main():
    set_seed(225)
    device = 'cuda' if torch.cuda.is_available() else 'cpu'
    transform_train = transforms.Compose([
        transforms.RandomCrop(32, padding=4),
        transforms.RandomHorizontalFlip(),
        transforms.ToTensor(),
        transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))
    ])

    transform_test = transforms.Compose([
        transforms.ToTensor(),
        transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))
    ])

    trainset = torchvision.datasets.CIFAR10(root='./dataset', train=True, download=True, transform=transform_train)
    trainloader = DataLoader(trainset, batch_size=128, shuffle=True, num_workers=2)

    testset = torchvision.datasets.CIFAR10(root='./dataset', train=False, download=True, transform=transform_test)
    testloader = DataLoader(testset, batch_size=100, shuffle=False, num_workers=2)


    teacher_model = TeacherNet().to(device)
    student_model = StudentNet().to(device)

    teacher_weights = torch.load('best_teacher.pth', map_location=device)
    teacher_model.load_state_dict(teacher_weights)
    print("成功加载教师模型权重!")

    train_student(teacher_model, student_model, trainloader, epochs=15, device=device)

    teacher_acc = evaluate(teacher_model, testloader, device)
    student_acc = evaluate(student_model, testloader, device)

    print(f"教师网络测试准确率: {teacher_acc:.2f}%")
    print(f"知识蒸馏后的学生网络测试准确率: {student_acc:.2f}%")

    # 保存学生模型权重
    torch.save(student_model.state_dict(), 'student_distill.pth')

if __name__ == '__main__':
    main()

你可以通过改变温度T,hard loss和soft loss的占比alpha来看不同的温度T和不同的比例对知识蒸馏的影响。

知识蒸馏(Knowledge Distillation) 快乐学习 阅读详情

相关推荐

知识蒸馏算法和代码(Pytorch)笔记分享,一个必须要了解的算法

知识蒸馏算法和代码(Pytorch)笔记分享,一个必须要了解的算法

互相学习的小博客 1万+

知识蒸馏之自蒸馏

Attention Distillation@TOC Attention Distillation in CVPR\AAAI (from 2021 to 2022) 本文整理了AAAI2021/AAAI2022/CVPR2021中的注意力蒸馏类文章(强调feature-based knowledge distillation),后续可能会继续更新其他计算机视觉领域顶会中的相关工作,欢迎各位伙伴相互探讨。 背景知识-注意力蒸馏 1.定义:注意力蒸馏 (Attention distillation):用于把大网

qq_35561971的博客 3万+

知识蒸馏 | 知识蒸馏的算法原理与其他拓展介绍

如有错误,恳请指出。 这篇博客将记录我看视频后对知识蒸馏的笔记,视频链接见参考资料[1],其中包含知识蒸馏的算法原理(训练流程与测试流程),以及知识蒸馏能够正常工作的背后机理与其发展的趋势及展望。 在这篇博客中,主要都是介绍没有涉及具体的代码,我另外还将会记录一下知识蒸馏的测试过程,见另外的一篇博客。 文章目录框架1. 知识蒸馏的算法原理1.1 知识的表示与迁移1.2 训练流程1.3 推理过程1.4 KD与Labe Smoothing的区别2. 知识蒸馏的应用场景3. 知识蒸馏的背后机理4. 知识蒸馏.

Clichong 8010

全网最细图解知识蒸馏(涉及知识点:知识蒸馏实现代码,知识蒸馏训练过程,推理过程,蒸馏温度,蒸馏损失函数)

hard targets的预测结果不科学,因为马和驴比马和汽车相似的多。所以驴和汽车都是0,没有表现出这个信息,所以要用soft targets.第二行和第三行是使用百分之3的训练样本并分别用hard target和soft target,结果显示。soft target使我们常用的概率版的标签值。比如输入下面的图片预测。教师网络预测出的soft target具有很多信息。此时学生网络已经训练好,把X输入到学生网络得到结果。学生网络的输入是教师网络的输出。【精读AI论文】知识蒸馏。最后对这两项加权求和。

分享计算机视觉,C++,网络摄像头研发,音视频开发,嵌入式等知识。 2万+

知识蒸馏介绍及比较

文章目录1 知识蒸馏(knowledge)背景2 知识蒸馏原理2.1 概念2.2 如何蒸馏3 常见的几种BERT蒸馏模型3.1 BERT蒸馏3.2 Distiled BiLSTM3.2 BERT-PKD(2019)——精调阶段的蒸馏3.3 DistilBERT(hugging face2019)——预训练阶段蒸馏3.4 TinyBERT(HW,2019)——两阶段蒸馏1 通用蒸馏2 针对特定任务的蒸馏3.5 MobileBERT(ACL2020) 1 知识蒸馏(knowledge)背景 在训练模型时,我们通

weiyaner的博客 1万+

知识蒸馏

目录 一 引言 1.1 深度学习的优点 1.2 深度学习的缺点 二 什么是知识蒸馏 2.1 模型压缩 2.2 什么是学习 2.3 什么是知识蒸馏 2.4 知识蒸馏的一般流程 三 知识蒸馏的分类 3.1 模型结构的种类 3.2 知识的分类 3.3 如何蒸馏 四 输出层知识蒸馏 《Distilling the Knowledge in a Neural Network 》 2015 五 中间层知识蒸馏 《Learning Metrics from Teachers: Comp

oldsummer 2万+

一文搞懂【知识蒸馏】【Knowledge Distillation】算法原理

知识蒸馏就是把一个大的教师模型的知识萃取出来,把他浓缩到一个小的学生模型,可以理解为一个大的教师神经网络把他的知识教给小的学生网络,这里有一个知识的迁移过程,从教师网络迁移到了学生网络身上,教师网络一般是比较臃肿,所以教师网络把知识教给学生网络,学生网络是一个比较小的网络,这样就可以用学生网络去做一些轻量化网络做的事情。

Coding... 8万+

目标检测中的知识蒸馏方法

知识蒸馏 知识蒸馏指的是模型压缩的思想,用压缩之前的模型作为老师,压缩之后的模型作为学生,通过一步一步地使用一个较大的已经训练好的网络去教导一个较小的网络确切地去做什么。“软标签”指的是大网络在每一层卷积后输出的feature map。然后,通过尝试复制大网络在每一层的输出(不仅仅是最终的损失),小网络被训练以学习大网络的准确行为。 ...........................

dnty00的博客 1万+

知识蒸馏(总结篇)

知识蒸馏 (Knowledge Distillation)综述 目录知识蒸馏 (Knowledge Distillation)综述0. 导向1.下面将对知识蒸馏做全面的综述性介绍 0. 导向 关于轻量化网络,目前来说,大致可分成两大块:基于网络架构本身的设计和对模型进行压缩,我自觉网络架构本身设计难于上青天,这块都是Google大佬,facebook大佬等走在最前沿,比如使用NAS的方法去自动寻找对应任务的网络架构,嗯,听起来很玄学。整个轻量型网络目前来说有下面主要工作,直接上图 科学理论只有联系实际才能

wj113149的博客 1万+

知识蒸馏简介(Knowledge Distillation)

知识蒸馏的背景,概念,知识传递形式,不同蒸馏方法的优缺点,例子的相关介绍

qq_46684028的博客 1万+

知识蒸馏研究综述

知识蒸馏综述阅读

LiuAmber的博客 3863

【目标检测】YOLOv5遇上知识蒸馏

本文主要来研究知识蒸馏的相关知识,并尝试用知识蒸馏的方法对YOLOv5进行改进。

兴趣使然的创作者 1万+

什么是特征蒸馏?什么是知识蒸馏?

​​特征蒸馏是一种知识迁移方法,它将教师模型在中间层学到的特征表示(如语义、结构、上下文信息)迁移到学生模型中,让学生模型不仅学会“做什么”(输出),还学会“怎么看”(特征),从而提升整体性能。​​。

m0_74027860的博客 2425

知识蒸馏之自蒸馏【附代码】

本篇文章为在线蒸馏,将以Resnet为例进行代码详解,主要涉及到逻辑蒸馏和特征蒸馏。内容比较多,系好安全带,发车~ 在学习本篇文章时需要各位对Resnet代码有很深的了解,这样才好学习本篇文章

z240626191s的博客 6645

一文详解什么是知识蒸馏

在蒸馏过程中,将相同输入同时输入教师模型和学生模型,教师模型为学生模型提供知识指导,通过最小化学生模型输出与教师模型输出之间的差异(如使用交叉熵损失、均方误差损失等),优化学生模型参数,使学生模型学习教师模型的知识。教师模型训练过程中,能学习到数据中的“暗知识”,如数据分布规律、特征之间的隐含关系等。它通过将一个复杂的大模型(称为教师模型,Teacher Model)的知识转移到一个较小的模型(称为学生模型,Student Model)中,使得学生模型在保持较小规模的同时,能够尽可能地接近教师模型的性能。

Python栈 2550

NLP中知识蒸馏

nlp中知识蒸馏

qq_41980734的博客 3130

知识蒸馏算法原理

知识蒸馏算法原理 “蒸馏”的概念大概就是将本身不够纯净的水通过加热变成水蒸气,冷凝之后就成更纯净的水 知识蒸馏同样使用这种原理,将不太纯净的“知识”通过“蒸馏”的方式获得更加有用或者纯净的“知识” 体现在神经网络中如下图所示: 一个大而臃肿,但知识丰富且高效的“教师网络”,通过转换精准将特定领域的知识传授给“学生网络”,让“学生网络”在某个方面做得很好,并且不那么臃肿,类似“模型压缩” 为什么不直接使用教师网络?因为将算法应用在现实生活中很多设备的算力会被限制,因此需要尽可能.

charles_zhang_的博客 1万+

【AI系统】知识蒸馏原理

知识蒸馏 (Knowledge Distillation, KD) 是一种用于模型压缩和优化的技术,最初由 Hinton 在文章“Distilling the Knowledge in a Neural Network”中提出,核心思想是从一个复杂的较大的模型(通常称为教师模型)中提取知识,将这些知识转移到一个精简的小模型(通常称为学生模型)中。这个过程能够显著减少模型的复杂度和计算开销,同时尽可能保留较大模型的性能。

ZOMI酱 3173
上一篇: 模型的多GPU并行训练,DDP (附代码)
下一篇: xfeat paper笔记
蓝羽飞鸟
博客等级 码龄8年 1万+粉丝 727原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

蓝羽飞鸟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值