Как стать автором
Обновить

Комментарии 4

Отличная статья!
Не подскажете, может в каких-то библиотеках применяются некоторые из описанных методов для "сжатия" готовой сети?

Имеет ли смысл смотреть дисперсию собственных чисел для слоёв RNN, как некую "метрику" их качества?

Спасибо. Боюсь соврать, но не встречал таких готовых оптимизаций. Может из-за недостатка кругозора.

Тем более не возьмусь судить о RNN, - на практике не сталкивался, особо не вникал.

С одной стороны статистика она и в Африке статистика: если есть набор случайных переменных и данные о взаимной корреляции, то можно оценить и размерность скрытых независимых переменных. С другой, - если по факту распределение зависит и от внутреннего состояния, то какие тут стационарные корреляции.

Я попробовал сделать что-то такое на pytorch, получилось интересно.

Во-первых, если построить ковариационную матрицу, найти собственные значения и отсортировать их по убыванию - хорошо видно, если какой-нибудь из слоёв сети избыточный.
Вот здесь я выучил сетку на mnist, проанализировал выходы разных слоёв и на их основе подобрал количество каналов на выходе каждой свёртки: https://github.com/Kright/mySmallProjects/blob/master/2023/ml_experiments/mnist_nets/mnist_baseline_analyse_internals.ipynb
Количество каналов не увеличивал, только уменьшал, точность почти такая же.

Во-вторых, я попробовал сжимать свётки - допустим, заменять свёртку 64 -> 64 канала с ядром 3х3 на последовательность двух свёрток - например, 64 -> 32 канала с ядром 3х3 и потом поточечную свёртку из 32 каналов в 64.
Попробовал два подхода:
1. выучить "тяжёлую" сеть, пересчитать слои и сконвертировать в более "лёгкую"
2. сразу взять более "лёгкую" сеть и обучить её с нуля.
В итоге и в том и в другом случае точность сети практически равна точности исходной.
https://github.com/Kright/mySmallProjects/blob/master/2023/ml_experiments/mnist_nets/mnist_baseline_shrinking.ipynb

Технически я сделал так:
1. Тренировал два слоя (свёртка с ядром 3х3, допустим из 64 каналов в 64, и потом батч-нормализацияю
2. Пересчитывал веса в одну эквивалентную свёртку.
3. После неё добавлял две поточечных свёртки - одна уменьшает размерность (из 64 каналов в 32) и другая увеличивает обратно (32 -> 64). Веса - первые N собственныx векторов и обратное преобразование. Получались три свёртки: (3х3 64 -> 64), (1x1 64 -> 32), (1x1, 32 -> 64), точность немножко терялась.
4. Группировал две первые свёртки в одну эквивалентную, оставалось два слоя: (3x3 64 -> 32, 1x1 32 -> 64).
В итоге вместо одной вычислительно тяжёлой свёртки становилось две более лёгких.

В третьих, я попробовал не пересчитывать слои, а брать "альтернативный" слой и учить его на выходы оригинального. В качестве ошибки брал mse, в качестве входов-выходов - реальные наборы данных на входе и выходе слоя внутри сети. Возможно, я где-то ошибся, но такой подход у меня практически не работал - альтернативный слой учился очень долго, неустойчиво и довольно посредственно имитировал реальный слой. Собственно, поэтому я от этой идеи отказался и попробовал вместо обучения пересчитывать слои математическими подходами с помощью PCA.

Понятно, что у меня пара единичных экспериментов и обобщать нельзя, но предварительно - идеи вполне рабочие. Можно сконвертировать веса и подменить слой на другой без сильного влияния на точность работы сети.

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории