知识蒸馏 示例代码实现及下载

本文详细介绍了知识蒸馏的代码实现过程,包括数据集准备、教师模型和学生模型的构建、知识蒸馏步骤及实验结果。教师模型为4层MLP,学生模型为2层MLP。通过知识蒸馏,学生模型(2层MLP)达到了0.8365的准确率,而独立训练的准确率为0.8302,验证了知识蒸馏的有效性。

知识蒸馏 代码实现

论文《Distilling the Knowledge in a Neural Network》

* 源码以Github为准

Github链接:https://github.com/yeqiwang/KnowledgeDistilling

1. 数据集

本文使用fashion_mnist数据集,输入图像大小为28*28,共分为10类。

通过tensoflow加载数据,并对label进行one hot编码。

import tensorflow as tf
from tensorflow import keras
import numpy as np

fashion_mnist = tf.keras.datasets.fashion_mnist
(train_images, train_labels), (test_images, test_labels) = fashion_mnist.load_data()
train_images = train_images/255
test_images = test_images/255
train_labels = tf.one_hot(train_labels, depth=10)
test_labels = tf.one_hot(test_labels, depth=10)

2. 教师模型

本文中使用一个4层MLP来作为教师模型。

训练过程中,模型最后使用softmax层来计算损失值。

训练结束后,更改最后的softmax层,以便生成软标签,其中T=2。同时,为了防止误操作,将教师模型冻结。

需要注意的是,虽然更改后教师模型不再进行训练,但仍需要使用compile函数进行配置,否则无法调用predict函数。

# 构建并训练教师模型
inputs = keras.layers.Input(shape=(28,28))
x = keras.layers.Flatten()(inputs)
x = keras.layers.Dense(128, activation='relu')(x)
x = keras.layers.Dense(128, activation='relu')(x)
x = keras.layers.Dense(128, activation='relu')(x)
x = keras.layers.Dense(10)(x)
outputs = keras.layers.Softmax()(x)

t_model = keras.Model(inputs, outputs)
t_model.summary()

callback = [keras.callbacks.EarlyStopping(patience=10 ,restore_best_weights=True)]
t_model.compile(optimizer='adam',
              loss=tf.keras.losses.CategoricalCrossentropy(from_logits=False),
              metrics=['accuracy'])

t_model.fit(train_images, train_labels, epochs=500, validation_data=(test_images, test_labels),callbacks=callback)

# 更改教师模型以便后续生成软标签
x = t_model.get_layer(index=-2).output
outputs = keras.layers.Softmax()(x/3)
Teacher_model = keras.Model(t_model.input, outputs)
Teacher_model.summary()
Teacher_model.trainable = False

Teacher_model.compile(optimizer='adam',
              loss=tf.keras.losses.CategoricalCrossentropy(from_logits=False),
              metrics=['accuracy'])

3. 学生模型

本文使用一个2层MLP作为学生模型。

学生模型构建完成后不进行训练,在后续的蒸馏过程中进行训练。

需要注意的是,学生模型最后一层不加Softmax层

inputs = keras.layers.Input(shape=(28,28))
x = keras.layers.Flatten()(inputs)
x = keras.layers.Dense(128, activation='relu')(x)
outputs = keras.layers.Dense(10)(x)

Student_model = keras.Model(inputs, outputs)
Student_model.summary()

4. 知识蒸馏过程

学生模型进行蒸馏时,损失函数包括两部分:

  • Loss1:学生模型softmax输出值与真实标签的之间的损失(交叉熵);

  • Loss2:学生模型软化后的softmax输出值(T=2)与教师模型生成的软标签之间的损失(KL散度)。

则,Loss = 0.1*Loss1 + 0.9*Loss2。

本文通过重写Model类来实现。

class Distilling(keras.Model):
  def __init__(self, student_model, teacher_model, T, alpha):
    super(Distilling, self).__init__()
    self.student_model = student_model
    self.teacher_model = teacher_model
    self.T = T
    self.alpha = alpha

  def train_step(self, data):
    x, y = data
    softmax = keras.layers.Softmax()
    kld = keras.losses.KLDivergence()
    with tf.GradientTape() as tape:
      logits = self.student_model(x)
      soft_labels = self.teacher_model(x)
      loss_value1 = self.compiled_loss(y, softmax(logits))
      loss_value2 = kld(soft_labels, softmax(logits/self.T))
      loss_value = self.alpha* loss_value2 + (1-self.alpha) * loss_value1
    grads = tape.gradient(loss_value, self.student_model.trainable_weights)
    self.optimizer.apply_gradients(zip(grads, self.student_model.trainable_weights))
    self.compiled_metrics.update_state(y, softmax(logits))
    return {'sum_loss':loss_value, 'loss1': loss_value1, 'loss2':loss_value2, }
  
  def test_step(self, data):
    x, y = data
    softmax = keras.layers.Softmax()
    logits = self.student_model(x)
    loss_value = self.compiled_loss(y, softmax(logits))
    return {'loss':loss_value}

  def call(self, inputs):
    return self.student_model(inputs)
 

蒸馏过程加入早停止机制,监视val_loss。

distill = Distilling(Student_model, Teacher_model, 2, 0.9)
distill.compile(optimizer='adam',
              loss=tf.keras.losses.CategoricalCrossentropy(from_logits=False))

callback = [keras.callbacks.EarlyStopping(patience=20, restore_best_weights=True)]

distill.fit(train_images, train_labels, epochs=500, validation_data=(test_images, test_labels), callbacks=callback)

5. 实验结果

为了验证结果,本文独立训练学生模型(加入Softmax层),与使用知识蒸馏训练的学生模型进行对比。

实验结果如下:

  • 教师模型准确度 0.8682
  • 学生模型准确度 0.8365 (知识蒸馏)
  • 学生模型准确度 0.8302 (独立训练)

这表明,知识蒸馏方法确实有效。


欢迎评论留言讨论交流!

目标检测知识蒸馏(Object Detection Knowledge Distillation,ODKD)是一种将复杂的目标检测模型的知识迁移到小型模型中的方法。下面是一个简单的代码实现,以使用Faster R-CNN模型为教师模型,将其知识迁移到MobileNetV2模型为学生模型为例: 首先,我们需要定义教师模型和学生模型,并载它们的预训练权重: ```python import torch import torchvision # 定义教师模型 teacher_model = torchvision.models.detection.fasterrcnn_resnet50_fpn(pretrained=True) teacher_model.eval() # 定义学生模型 student_model = torchvision.models.mobilenet_v2(pretrained=True) student_model.classifier[1] = torch.nn.Linear(1280, 4) student_model.eval() ``` 在知识蒸馏中,我们需要使用教师模型生成目标检测的标签,然后将这些标签传递给学生模型进行训练。下面是一个简单的函数,用于生成标签: ```python def generate_labels(images, teacher_model): # 使用教师模型生成目标检测的标签 targets = [] for image in images: with torch.no_grad(): output = teacher_model([image]) targets.append(output) return targets ``` 接下来,我们需要定义损失函数。在知识蒸馏中,我们使用两个损失函数:原始的目标检测损失函数和知识蒸馏损失函数。知识蒸馏损失函数用于鼓励学生模型输出与教师模型相似的概率分布。下面是一个简单的函数,用于计算知识蒸馏损失: ```python def kd_loss(student_outputs, teacher_outputs, T): # 计算知识蒸馏损失 student_logits, student_boxes = student_outputs teacher_logits, teacher_boxes = teacher_outputs # 计算分类损失 kd_loss_cls = torch.nn.functional.kl_div(torch.nn.functional.log_softmax(student_logits/T, dim=1), torch.nn.functional.softmax(teacher_logits/T, dim=1), reduction='batchmean') * T * T # 计算回归损失 kd_loss_reg = torch.nn.functional.smooth_l1_loss(student_boxes, teacher_boxes, reduction='mean') # 将分类损失和回归损失相 kd_loss = kd_loss_cls + kd_loss_reg return kd_loss ``` 最后,我们需要定义训练循环。在每个训练迭代中,我们将使用教师模型生成目标检测的标签,并将这些标签传递给学生模型进行训练。然后,我们将计算目标检测损失和知识蒸馏损失,并将它们相。 ```python def train_one_epoch(student_model, teacher_model, data_loader, optimizer, T): student_model.train() teacher_model.eval() total_loss = 0 total_kd_loss = 0 for images, targets in data_loader: # 使用教师模型生成目标检测的标签 teacher_outputs = [] for target in targets: with torch.no_grad(): teacher_outputs.append(teacher_model([target['image']])) # 将图像和标签传递给学生模型进行训练 optimizer.zero_grad() student_outputs = student_model(images) loss = sum([l['loss'] for l in student_outputs]) total_loss += loss.item() # 计算知识蒸馏损失 kd_loss_value = kd_loss(student_outputs, teacher_outputs, T) total_kd_loss += kd_loss_value.item() # 将目标检测损失和知识蒸馏损失相 loss += kd_loss_value # 反向传播和优化 loss.backward() optimizer.step() return total_loss / len(data_loader), total_kd_loss / len(data_loader) ``` 这里只是一个简单的示例,实际上还有许多优化和改进可以进行。
评论 67
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值