Я пытаюсь сократить свою модель в PyTorch с помощью torch.nn.utils.prune
, который предоставляет 2 тензора,
- один - исходный вес и
- другой - маска, содержащая 0 и 1, которые помогают нам закрыть определенные соединения в сети.
Я пробовал оба решения, но ни одно не улучшило скорость вывода:
- Используйте сеть после обрезки, чтобы сделать вывод, который сначала закроет некоторые соединения с маской, а затем выполнит вывод.
- Обнуляет исходные веса с помощью маски, а затем удаляет маску из state_dict, чтобы сделать вывод.
Есть ли способ улучшить скорость с помощью тензора модели и маски? Разве умножение на ненулевое число с плавающей запятой с 0 будет быстрее, чем умножение двух чисел с плавающей запятой друг на друга?
Вот моя функция сокращения и процедура вычисления скорости сокращения:
def prune_net(net):
"""Prune 20% net's weights that have abs(value) approx. 0
Function that will be use when an iteration is reach
Args:
Return:
newnet (nn.Module): a newnet contain mask that help prune network's weight
"""
if not isinstance(net,nn.Module):
print('Invalid input. Must be nn.Module')
return
newnet = copy.copy(net)
modules_list = []
for name, module in newnet.named_modules():
if isinstance(module, torch.nn.Conv2d):
modules_list += [(module,'weight'),(module,'bias')]
if isinstance(module, torch.nn.Linear):
modules_list += [(module,'weight'),(module,'bias')]
prune.global_unstructured(
modules_list,
pruning_method=prune.L1Unstructured,
amount=0.2,)
return newnet
Скорость вывода теста 1-й случай:
import torch
from torch import nn
import torch.nn.utils.prune as prune
import torch.nn.functional as F
import time
from torch.autograd import Variable
torch.set_default_tensor_type('torch.cuda.FloatTensor')
old_net = init_your_net()
new_net = prune_net(old_net)
new_net = prune_net(new_net)
old_net.eval()
new_net.eval()
old_net = old_net.cuda()
new_net = new_net.cuda()
dataset = load_your_dataset()
for i in range(100):
x = dataset[i]
x = x.cuda()
y = x.cuda()
#new infer
start_time = time.perf_counter()
detections = new_net(x).data
time_new += time.perf_counter() - start_time
#old infer
start_time = time.perf_counter()
detections = old_net(y).data
time_old += time.perf_counter() - start_time
print('old ',time_old)
print('new ', time_new)
Скорость вывода теста 2-й случай:
import torch
from torch import nn
import torch.nn.utils.prune as prune
import torch.nn.functional as F
import time
from torch.autograd import Variable
torch.set_default_tensor_type('torch.cuda.FloatTensor')
old_net = init_your_net()
new_net = prune_net(old_net)
new_net = prune_net(new_net)
# Apply mask to model tensor and remove mask from state_dict
for name, module in new_net.named_modules():
if isinstance(module, torch.nn.Conv2d):
prune.remove(module,'weight')
prune.remove(module,'bias')
if isinstance(module, torch.nn.Linear):
prune.remove(module,'weight')
prune.remove(module,'bias')
old_net.eval()
new_net.eval()
old_net = old_net.cuda()
new_net = new_net.cuda()
dataset = load_your_dataset()
for i in range(100):
x = dataset[i]
x = x.cuda()
y = x.cuda()
#new infer
start_time = time.perf_counter()
detections = new_net(x).data
time_new += time.perf_counter() - start_time
#old infer
start_time = time.perf_counter()
detections = old_net(y).data
time_old += time.perf_counter() - start_time
print('old ',time_old)
print('new ', time_new)
ОБНОВЛЕНИЕ
Я обнаружил, что torch имеет разреженный модуль, который может уменьшить использование памяти, если мы сократим достаточно параметров, но он еще не поддерживает nn.Module, только объект Tensor. Вот полезная ссылка:
https://github.com/pytorch/pytorch/issues/36214#issuecomment-619586452
https://pytorch.org/docs/stable/sparse.html.