Модель Prunning не улучшает скорость вывода и не уменьшает размер модели

Я пытаюсь сократить свою модель в PyTorch с помощью torch.nn.utils.prune, который предоставляет 2 тензора,

  1. один - исходный вес и
  2. другой - маска, содержащая 0 и 1, которые помогают нам закрыть определенные соединения в сети.

Я пробовал оба решения, но ни одно не улучшило скорость вывода:

  1. Используйте сеть после обрезки, чтобы сделать вывод, который сначала закроет некоторые соединения с маской, а затем выполнит вывод.
  2. Обнуляет исходные веса с помощью маски, а затем удаляет маску из 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.


person manaclan    schedule 11.06.2020    source источник


Ответы (2)


Важно понимать разницу между неструктурированным сокращением и структурированным сокращением.

  • Структурированное сокращение: размеры тензоров веса уменьшаются за счет удаления целых строк / столбцов тензоров. Это означает удаление нейронов со всеми их входящими и исходящими соединениями (в плотных слоях) или целыми сверточными фильтрами (в сверточных слоях).

  • Неструктурированная обрезка: отдельные веса могут быть удалены (обнулены) без ограничений формы конечного тензора. Это означает удаление отдельных связей между нейронами (в плотных слоях) или удаление отдельных весов сверточных фильтров (в сверточных слоях). Обратите внимание, что результирующие тензоры веса могут быть разреженными, но сохранять свою первоначальную форму.

В настоящее время torch.nn.utils.prune поддерживает только неструктурированное сокращение, что вряд ли помогает снизить стоимость вывода, поскольку графические процессоры не оптимизированы для умножения разреженных матриц. Хотя вы, возможно, захотите уменьшить размеры ваших тензоров веса, чтобы уменьшить количество операций с плавающей запятой, неструктурированное сокращение создает тензоры веса с большим количеством нулей, но не уменьшает автоматически размер таких тензоров.

Неструктурированная обрезка может помочь повысить производительность только при удалении большого веса. В этом случае вы можете полагаться на разреженные операции PyTorch или попытаться найти строки / столбцы. которые содержат все нули и поэтому могут быть удалены.

Вместо этого, если вы хотите изучить структурированную обрезку, вы можете взглянуть на TorchPruner, библиотеку, которая Я разработал себя для исследовательских целей, и в нем есть утилиты для поиска наименее важных нейронов и соответствующего нарезания тензоров веса.

person Marco Ancona    schedule 09.08.2020

Я также пытаюсь обрезать, чтобы увеличить скорость вывода. Но что я нашел более полезным, так это использование ONNX и ONNXRuntime. Вот ссылка со всеми шагами:

https://pytorch.org/tutorials/advanced/super_resolution_with_onnxruntime.html

Это позволит сократить время до 85% без потери точности.

person Farah    schedule 30.06.2020
comment
Как бы это сделать? Разве это не сервер логических выводов? Вы говорите о кешировании веб-запросов и их выводе в пакете? - person Akshay Rana; 13.10.2020
comment
@AkshayRana Я применил ModelPruning PyTorch Lighning в своем проекте и обнаружил, что скорость вывода идентична (в пределах 1 стандартного отклонения) для моделей с разреженностью 0, 35 и 50 процентов. Я читал, что улучшения скорости от обрезки следует ожидать только в том случае, если вы можете обнулить целые строки / столбцы матриц - person Addison Klinke; 10.06.2021
comment
@Farah Не могли бы вы прояснить архитектуру модели и подход к сокращению, которые позволили вам добиться ускорения на 85% - вы использовали канальную или какую-либо другую структурированную обрезку? - person Addison Klinke; 10.06.2021