关键词:轻量化 、 蒸馏 、 根底蒸馏 、 担任蒸馏 、 自适应蒸馏 、自适应蒸馏
导读
深度学习中的蒸馏机制是一种有用的模型紧缩办法,能够将大型神经网络紧缩为小型神经网络,一起能够最大极限的坚持原始网络的性能。在实践运用中,蒸馏机制能够协助咱们在资源受限的设备上部署愈加高效的神经网络模型,然后在保证准确性的前提下提高核算功率。本文将会深入探讨蒸馏机制的作业原理、运用场景和完成办法,并为读者提供实践案例和代码完成,协助咱们更好地了解和运用蒸馏机制。
前言
在本文中的实验数据集为花朵数据集,该数据集类别数经过挑选总共为5类,数据集划分为练习集与测验集,练习:测验 = 500 : 150。
在网络的挑选方面,咱们挑选高精度的大模型为Vgg11,小模型为轻量级的 shufflenet_v2_x0_5。这两个模型在torchvision\models中都能够找到,有现成的,不需求咱们自己手撸代码。这两个权重的大小分别为:
实操蒸馏
常见的蒸馏有四大类:根底蒸馏、担任蒸馏、鼓励蒸馏和自适应蒸馏,下面咱们会对这四大类蒸馏进行实操演示。
根底模块
在实操之前,咱们有一些代码是公共的,这儿包含数据集的获取,网络的界说及调用,能够构建一个【init.py】文件进行界说根底公共代码部分:
import torch
import torchvision
from torch.utils.data import DataLoader
from shufflenetv2 import shufflenet_v2_x0_5
from vgg import vgg11
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
def get_Data():
train_root = 'D:/Data_ALL/datas/train/'
test_root = 'D:/Data_ALL/datas/test/'
# 将文件夹的内容载入dataset
train_dataset = torchvision.datasets.ImageFolder(root=train_root, transform=torchvision.transforms.ToTensor())
test_dataset = torchvision.datasets.ImageFolder(root=test_root, transform=torchvision.transforms.ToTensor())
train_dataloader = DataLoader(train_dataset, batch_size=12,shuffle=True)
test_dataloader = DataLoader(test_dataset, batch_size=8)
train_num = len(train_dataset)
test_num = len(test_dataset)
return train_dataloader, test_dataloader, train_num, test_num
def get_net():
model_t = vgg11(pretrained=False, num_classes=5).to(device)
model_s = shufflenet_v2_x0_5(pretrained=False, num_classes=5).to(device)
return model_t, model_s
def Soomth_temp(init_temp, global_step, decay_steps=0.07):
temp = init_temp - (global_step * decay_steps)
if temp < 1:
temp = 1
return temp
测验模块
一起再构建【demo.py】函数对中心代码部分的main部分进行设定好丢失函数以及优化器和读取init.py数据。
def test(dataloader):
size = len(dataloader.dataset)
test_loss, correct = 0, 0
with torch.no_grad():
for test_image, test_label in dataloader:
test_image, test_label = test_image.to(device), test_label.to(device)
test_pred = model_s(test_image)
test_loss += criterion(test_pred, test_label).item()
correct += (test_pred.argmax(1) == test_label).type(torch.float).sum().item()
test_loss /= test_num
correct /= size
print(f"Test Error: \n Accuracy: {(100 * correct):>0.1f}%, Avg loss: {test_loss:>8f} \n")
if __name__ == "__main__":
# 设置网络的部分
model_t, model_s = get_net()
# 设置数据集的部分
train_dataloader, test_dataloader, train_num, test_num = get_Data()
# 界说温度参数T
T = 10
# 界说穿插熵丢失函数
criterion = nn.CrossEntropyLoss()
# 界说优化器
optimizer = optim.Adam(net_s.parameters(), lr=0.001)
# 设置超参数的部分
scheduler = torch.optim.lr_scheduler.ExponentialLR(optimizer, gamma=0.94) # LR变化的学习率
epochs = 100
for epoch in range(epochs):
train(train_dataloader)
test(test_dataloader)
需求留意的是,在练习完毕后,咱们需求运用小型模型进行预测,而不是运用带有温度参数的“软方针”进行预测。
根底蒸馏
根底蒸馏是最简略的蒸馏机制,它经过让小型模型学习大型模型的预测结果来传递常识。在这种办法中,大型模型的输出被视为“软方针”,并被用作小型模型的练习方针。这种办法的长处是简略易用,可是它一般需求运用较高的温度参数,导致模型的精度不如其他办法。
from torch import optim, nn
from init import *
import torch.nn.functional as F
# 界说练习函数
def train(dataloader):
model_s.train()
for batch, (inputs, labels) in enumerate(dataloader):
inputs, labels = inputs.to(device), labels.to(device)
optimizer.zero_grad()
outputs = model_s(inputs)
# 对大型模型输出进行softmax转化并缩放温度参数
teacher_outputs = model_t(inputs).detach()
teacher_outputs = nn.functional.softmax(teacher_outputs / T, dim=1)
# 核算丢失函数,其中运用“软方针”作为辅佐丢失
loss = criterion(outputs, labels) + nn.KLDivLoss()(nn.functional.log_softmax(outputs / T, dim=1),
teacher_outputs) * T * T
# 反向传达更新参数
loss.backward()
optimizer.step()
if batch % 100 == 0:
loss = loss.item()
print(f"loss: {loss:>7f}")
在练习函数中,咱们首要将大型模型的输出进行softmax转化,并运用温度参数对其进行缩放,然后得到“软方针”的散布。然后,咱们运用“软方针”作为辅佐丢失来协助小型模型进行练习。终究,咱们将两个丢失函数相加,得到终究的丢失函数,并运用反向传达更新参数。在练习过程中,咱们运用KL散度来衡量小型模型输出散布与“软方针”散布之间的间隔,然后提高小型模型的泛化能力。
担任蒸馏
担任蒸馏是一种依据网络层次结构的蒸馏办法。它的基本思想是让小型模型学习大型模型中的“特定”层次信息,如中心层的特征图。这些信息能够被看作是大型模型的“中心方针”,并被用作小型模型的练习方针。这种办法的长处是能够更准确地传递常识,然后取得更高的模型精度。
def train(dataloader):
alpha = 0.5
model_s.train()
for batch, (inputs, labels) in enumerate(dataloader):
inputs, labels = inputs.to(device), labels.to(device)
optimizer.zero_grad()
outputs = model_s(inputs)
# 对大型模型输出进行softmax转化并缩放温度参数
teacher_outputs = model_t(inputs).detach()
teacher_outputs = nn.functional.softmax(teacher_outputs / T, dim=1)
# 核算丢失函数,其中运用“软方针”作为辅佐丢失
loss = (1 - alpha) * criterion(outputs, labels) + alpha * nn.KLDivLoss()(
nn.functional.log_softmax(outputs / T, dim=1), teacher_outputs) * T * T
# 反向传达更新参数
loss.backward()
optimizer.step()
if batch % 100 == 0:
loss = loss.item()
print(f"loss: {loss:>7f}")
咱们运用VGG11作为大型模型,ShuffleNet V2 x0.5作为小型模型。在练习函数中,咱们首要对大型模型的输出进行softmax转化,并运用温度参数对其进行缩放,然后得到“软方针”的散布。然后,咱们对小型模型的输出进行相同的操作。接着,咱们经过对所有层的输出核算KL散度来界说辅佐丢失函数,并将所有辅佐丢失函数相加,得到总辅佐丢失。终究,咱们将穿插熵丢失函数和总辅佐丢失加权相加,得到终究的丢失函数,并运用反向传达更新参数。在练习过程中,咱们运用KL散度来衡量小型模型输出散布与“软方针”散布之间的间隔,并运用权重参数。
鼓励蒸馏
鼓励蒸馏是一种依据激活函数的蒸馏办法,它经过让小型模型学习大型模型中的激活函数来传递常识。详细而言,咱们能够经过让小型模型学习大型模型中的激活函数输出,来取得愈加准确的模型紧缩作用。这种办法的长处是能够更准确地操控模型的软硬程度,然后取得更好的模型紧缩作用。
alpha = 0.5
def train(dataloader):
model_s.train()
model_t.eval()
for batch, (inputs, labels) in enumerate(dataloader):
inputs, labels = inputs.to(device), labels.to(device)
optimizer.zero_grad()
outputs = model_s(inputs)
# 获取大模型的中心层激活
with torch.no_grad():
teacher_outputs = model_t.features(inputs) # 咱们能够自行寻找
# 获取小模型的中心层激活
student_outputs = model_s.features(inputs) # 咱们能够自行寻找
# 界说辅佐丢失函数
loss = 0
for i in range(len(teacher_outputs)):
# 对大模型和小模型的中心层激活进行softmax转化并缩放温度参数
teacher_activation = nn.functional.softmax(teacher_outputs[i] / T, dim=1)
student_activation = nn.functional.softmax(student_outputs[i] / T, dim=1)
# 核算中心层激活的KL散度作为辅佐丢失
loss += nn.KLDivLoss()(student_activation, teacher_activation.detach()) * T * T
# 核算首要丢失函数
loss += (1 - alpha) * criterion(outputs, labels)
# 反向传达更新参数
loss.backward()
optimizer.step()
if batch % 100 == 0:
loss = loss.item()
print(f"loss: {loss:>7f}")
自适应蒸馏
自适应蒸馏是一种依据动态温度操控的蒸馏办法,它经过动态调整温度参数来完成更好的模型紧缩作用。详细而言,咱们能够依据小型模型的练习进展来自适应地调整温度参数,然后到达更好的模型紧缩作用。这种办法的长处是能够自适应地调整模型的软硬程度,然后取得更好的紧缩作用。
alpha = 0.5
def train(dataloader):
model_s.train()
model_t.eval()
for batch, (inputs, labels) in enumerate(dataloader):
inputs, labels = inputs.to(device), labels.to(device)
optimizer.zero_grad()
outputs = model_s(inputs)
# 获取大模型的中心层激活
with torch.no_grad():
teacher_outputs = model_t.features(inputs)
# 获取小模型的中心层激活
student_outputs = model_s.features(inputs)
# 界说辅佐丢失函数
loss = 0
for i in range(len(teacher_outputs)):
# 核算大模型和小模型中心层激活的L2范数,作为动态的温度参数
T = torch.norm(teacher_outputs[i] - student_outputs[i], p=2) / torch.numel(teacher_outputs[i])
# 对大模型和小模型的中心层激活进行softmax转化并缩放温度参数
teacher_activation = nn.functional.softmax(teacher_outputs[i] / T, dim=1)
student_activation = nn.functional.softmax(student_outputs[i] / T, dim=1)
# 核算中心层激活的KL散度作为辅佐丢失
loss += nn.KLDivLoss()(student_activation, teacher_activation.detach()) * T * T
# 核算首要丢失函数
loss += criterion(outputs, labels)
# 反向传达更新参数
loss.backward()
optimizer.step()
if batch % 100 == 0:
loss = loss.item()
print(f"loss: {loss:>7f}")
在上述示例中,咱们运用了 PyTorch 的 vgg11
和 shufflenet_v2_x0_5
模型,并经过 features
属性获取了这些模型的中心层激活。咱们经过核算大模型和小模型中心层激活的L2范数来动态地确定温度参数T。
结语
蒸馏机制是一种有用的深度学习模型紧缩技术,它能够将一个杂乱的模型紧缩成一个简略的模型,一起坚持高精度。在实践运用中,蒸馏机制已经被广泛运用于各种场景,例如移动端深度学习模型的紧缩、模型部署以及高效模型练习等方面。不同的蒸馏机制适用于不同的运用场景,需求依据详细的运用需求进行挑选
*本文正在参加 人工智能创作者扶持方案 ” *