自蒸馏和rdropout方法比较

该博客探讨了深度学习中的知识蒸馏技术,通过一个小模型(学生模型)学习一个大模型(教师模型)的预测分布,利用KL散度作为损失函数的一部分来传递大模型的知识。文中使用了LSTM模型作为示例,展示了如何构建和训练这两个模型,并计算它们之间的KL散度和交叉熵损失。这种方法类似于rdropout,但区别在于它涉及不同规模的模型,而不是同一模型的多次运行。
摘要由CSDN通过智能技术生成
import torch
import torch.nn as nn
import numpy as np

from torch.nn import CrossEntropyLoss
from torch.utils.data import TensorDataset,DataLoader,SequentialSampler

class model(nn.Module):
    def __init__(self,input_dim,hidden_dim,output_dim):
        super(model,self).__init__()
        self.layer1 = nn.LSTM(input_dim,hidden_dim,output_dim,batch_first = True)
        self.layer2 = nn.Linear(hidden_dim,output_dim)
        #学生模型(2,8)->(8,4)
        #教师模型(2,16)->(16,4)
    def forward(self,inputs):
        layer1_output,layer1_hidden = self.layer1(inputs)
        layer2_output = self.layer2(layer1_output)
        layer2_output = layer2_output[:,-1,:]#取出一个batch中每个句子最后一个单词的输出向量即该句子的语义向量!!!!!!!!!
        return layer2_output

#建立小模型
model_student = model(input_dim = 2,hidden_dim = 8,output_dim = 4)

#建立大模型(此处仍然使用LSTM代替,可以使用训练好的BERT等复杂模型)
model_teacher = model(input_dim = 2,hidden_dim = 16,output_dim = 4)

#设置输入数据,此处只使用随机生成的数据代替
inputs = torch.randn(4,6,2)
true_label = torch.tensor([0,1,0,0])

#生成dataset
dataset = TensorDataset(inputs,true_label)

#生成dataloader
sampler = SequentialSampler(inputs)
dataloader = DataLoader(dataset = dataset,sampler = sampler,batch_size = 2)

loss_fun = CrossEntropyLoss()
criterion  = nn.KLDivLoss()#KL散度
optimizer = torch.optim.SGD(model_student.parameters(),lr = 0.1,momentum = 0.9)#优化器,优化器中只传入了学生模型的参数,因此此处只对学生模型进行参数更新,正好实现了教师模型参数不更新的目的

for step,batch in enumerate(dataloader):
    inputs = batch[0]
    labels = batch[1]

    #分别使用学生模型和教师模型对输入数据进行计算
    output_student = model_student(inputs)
    output_teacher = model_teacher(inputs)
    r"""
    #建立小模型
    model_student = model(input_dim = 2,hidden_dim = 8,output_dim = 4)

    #建立大模型(此处仍然使用LSTM代替,可以使用训练好的BERT等复杂模型)
    model_teacher = model(input_dim = 2,hidden_dim = 16,output_dim = 4)
    """
    
    #计算学生模型和真实标签之间的交叉熵损失函数值
    loss_hard = loss_fun(output_student,labels)
    
    #计算学生模型预测结果和教师模型预测结果之间的KL散度
    loss_soft = criterion(output_student,output_teacher)

    loss = 0.9*loss_soft + 0.1*loss_hard
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()

学生模型的结构相对小一点

model_student = model(input_dim = 2,hidden_dim = 8,output_dim = 4)

教学模型的结构相对大一点

model_teacher = model(input_dim = 2,hidden_dim = 16,output_dim = 4)

最终求得的内容为model_student和model_teacher的KL散度的损失内容

loss = 0.9*loss_soft + 0.1*loss_hard

感觉这里的自蒸馏有点像rdropout的操作,使用两个模型,然后求两个模型之间的KL散度差

import torch.nn.functional as F

# define your task model, which outputs the classifier logits
model = TaskModel()

def compute_kl_loss(self, p, q pad_mask=None):
    
    p_loss = F.kl_div(F.log_softmax(p, dim=-1), F.softmax(q, dim=-1), reduction='none')
    q_loss = F.kl_div(F.log_softmax(q, dim=-1), F.softmax(p, dim=-1), reduction='none')
    
    # pad_mask is for seq-level tasks
    if pad_mask is not None:
        p_loss.masked_fill_(pad_mask, 0.)
        q_loss.masked_fill_(pad_mask, 0.)

    # You can choose whether to use function "sum" and "mean" depending on your task
    p_loss = p_loss.sum()
    q_loss = q_loss.sum()

    loss = (p_loss + q_loss) / 2
    return loss

# keep dropout and forward twice
logits = model(x)

logits2 = model(x)

# cross entropy loss for classifier
ce_loss = 0.5 * (cross_entropy_loss(logits, label) + cross_entropy_loss(logits2, label))

kl_loss = compute_kl_loss(logits, logits2)

# carefully choose hyper-parameters
loss = ce_loss + α * kl_loss

这里的rdropout也是跑模型两次,与自蒸馏的区别在于自蒸馏是跑不同大小的模型两次,而rdropout是跑同样的模型两次,同样都是使用kl散度作为损失内容的参数,都是跑两次模型求两次模型的误差。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值