Размер сокращенной модели такой же, как и у необрезанной модели [PyTorch]

Я пытаюсь реализовать обрезку модели на PyTorch с помощью ResNet18. Учитывая экземпляр ResNet18, я запускаю следующий код, чтобы загрузить предварительно обученную модель, сократить ее и сохранить сокращенную модель:

def random_unstructured_pruning(pruning_rate: float, device, log_file):
    trained_model=retrieve_file(folder = "./models", file_name='trained_model.pth')
    model=ResNet18(num_classes=10, input_channels=1).to(device)
    model.load_state_dict(torch.load(trained_model))
    
    modules_list=filter(lambda x: isinstance(x[1], (nn.Conv2d, nn.Linear, nn.BatchNorm2d)), model.named_modules())
    modules_list = map(lambda x: (x[1], 'weight'), modules_list)
    modules_list=tuple(modules_list)
 
  
    prune.global_unstructured(modules_list, pruning_method=prune.L1Unstructured, amount=0.8)
    for module in modules_list:
        prune.remove(module[0], module[1])
        
        
        
    pruning_rate_str= "{:02d}".format(int(pruning_rate * 10))
    path=f"{model_saving_path}pruned_{pruning_rate_str}.pth"
    # 
    torch.save(model.state_dict(), f"{path}")

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

Может кто-нибудь объяснить мне, почему это происходит? Что я не так? Спасибо!!

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

возможно, стоит попробовать сохранить модель в разреженном формате

The Guy with The Hat 10.04.2024 01:54

Я так и сделал, но PyTorch не поддерживает прямое копирование данных между плотными и разреженными тензорами на устройствах CUDA. Я получил эту ошибку: '('copy_() между плотными и разреженными тензорами не реализован! Найден собственный тип = torch.cuda.FloatTensor и тип src = torch.cuda.sparse.FloatTensor',)'

Alessandro Masci 10.04.2024 16:49
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
2
183
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Утилита обрезки в Pytorch действует как маскирующая оболочка слоя, который подвергается обрезке. Это означает, что у вас по-прежнему есть доступ к исходным весам модели, а размер сети остается неизменным, если не больше, из-за инициализации маски для каждого сокращенного тензора.

Если вы посмотрите страницу документации prune.global_unstructured:

Изменяет модули на месте:

  • добавление именованного буфера с именем name+'_mask', соответствующего двоичному файлу маска, применяемая к имени параметра методом сокращения.

  • заменив имя параметра его сокращенной версией, в то время как исходное (необрезанный) параметр сохраняется в новом параметре с именем name+'_orig'.

Вот минимальный пример, показывающий, что необрезанные веса все еще доступны:

net = nn.Sequential(OrderedDict(
    f1=nn.Linear(10, 5),
    f2=nn.Linear(5, 1)))

pruned = ((net.f1, 'weight'),)
prune.global_unstructured(pruned, prune.L1Unstructured, amount=0.8)

Затем вы можете получить доступ к обрезанным весам:

>>> net.f1.weight
tensor([[0.0000, 0.0000, 0.0000, -0.0000, 0.0000],
        [0.0000, 0.3599, 0.0000, -0.0000, 0.4034]])

Исходный необрезанный вес:

>>> net.f1.weight_orig
Parameter containing:
tensor([[ 0.1312,  0.1105,  0.0910, -0.2650,  0.3439],
        [ 0.0412,  0.3599,  0.2040, -0.2672,  0.4034]])

И маска для обрезки:

>>> net.f1.weight_mask
tensor([[0., 0., 0., 0., 0.],
        [0., 1., 0., 0., 1.]])

Спасибо за ответ и разъяснение, теперь все более понятно! У меня все еще есть сомнения: какие показатели я могу сравнить, чтобы показать эффективность моей стратегии сокращения? Я думал о размере модели, но, как вы сказали, он не меняется при обрезке; Я также думал о ненулевых параметрах, и они уменьшаются, когда я применяю обрезку к своей модели, но что еще? Время обучения? Использование графического процессора?

Alessandro Masci 10.04.2024 16:44

Возможно, посмотрите на флопы, но, как правило, для такого подхода важно сообщать о размере модели.

Ivan 10.04.2024 17:33

Извините, но я немного в замешательстве. Вначале вы сказали мне, что размер файла .pth не должен меняться после сокращения, так как я могу вычислить размер модели, чтобы увидеть эффект сокращения?

Alessandro Masci 10.04.2024 18:46

Размер часто указывается в виде количества параметров, поэтому нет необходимости сравнивать размеры файлов.

Ivan 10.04.2024 20:53

Хорошо, спасибо. И последнее: предлагаете ли вы какую-нибудь библиотеку Python для оценки количества FLOP во время обучения или вывода?

Alessandro Masci 10.04.2024 21:50

Я не использовал такие инструменты, но, возможно, вы можете обратиться к этой другой теме.

Ivan 10.04.2024 21:52

Другие вопросы по теме