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

Что под капотом у нейронной сети. Нейросеть c точки зрения математики и программирования

Уровень сложности Простой
Время на прочтение 3 мин
Количество просмотров 4.5K
Python *Искусственный интеллект
Из песочницы
Всего голосов 22: ↑13 и ↓9 +4
Комментарии 13

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

Это очень здорово, но гораздо интереснее было бы рассказать, как именно происходит обучение пакетами на GPU.
1) Весь пакет прогоняется на GPU параллельно? Обычно, столько памяти нет.
2) На CPU сделан цикл по элементам пакета. Один элемент копируется на GPU и производится обучение на нём с сумированием весов. В этом случае непонятно, как делать нормализацию?
3) На GPU копируется пакет и один слой сети. Выполняется проход по одному слою сети для всех элементов пакета. Далее, пакет выбрасывается и выход слоя является новым пакетом для следующего слоя. Памяти нужно меньше, чем в пункте 1, но все промежуточные результаты придётся копировать на CPU (они нужны для обратного прохода). А такое копирование очень медленное.

Судя по минусаторам, все они, конечно, знают, как же сделано на практике в пакетах типа keras и tensorflow? Не так ли? ;) Но при этом они не знают по какой математике считается нейрон, раз аплодируют этой абсолютно примитивной статье?

Нейрон - это взвешивающий сумматор с (опционально) нелинейным выходом. Хорошо, если функция активации дифференцируема на R. Тогда его можно учить методом обратного распространения ошибки. Если нет - таким способом учить его невозможно (только Больцманом - закреплением случайных флуктуаций весов по локально-лучшему результату)

Тут автору каждой сотой статьи про то как работают нейронные сети ачивку выдают, или в чем смысл их постоянно постить?)

Каждый автор считает своим долгом донести внезапно полученные знания о нейросетях (часто очень примитивные). :) Жаль только, что в математике и принципах обучения они редко что-то понимают, ибо популярные пакеты всё это тщательно скрывают. В результате по тем же свёрточным сетям хрен найдёшь как их обучать. Или по сетям GAN как считать ошибку выходного слоя дискриминатора. Или как делать нормализацию на пальцах. Или как же обучать пакетом на GPU. Или как сделать быструю свёртку, обратную свёртку и коррекцию коэффициентов на GPU. А в остальном да, все специалисты. :)


А здесь статья с очень громким названием "Что под капотом у нейронной сети. Нейросеть c точки зрения математики и программирования". То есть, ожидается как минимум вся подноготная. Но… имеем то, что имеем. Мой вон вопрос-предложение выше вызывает у многих баттхерт. А я всего лишь спросил ту информацию, которую я не сумел пока ещё нигде найти.

Информацию в смысле как на GPU много данных обсчитывается? Если да - то ответ прост - батчами, т.е. не все примеры сразу загоняются в память, а столько, сколько влазит, после каждого прогона батча обновляются веса. Да, при этом градиент считается не по всему обучающему множеству сразу, но зато в память влазит. Мне кажется во всех современных нейросетевых библиотеках есть параметр batch_size, который надо подгонять под то чтобы побольше памяти за раз использовать, но не поймать Out Of Memory. Как то так.

Нет, ответ не прост. Даже для достаточно примитивных сетей требуется весьма много памяти, и пакет у вас будет очень маленьким (и вообще выродится в один образ). Потом, от размера пакета будет зависеть нормализация.
Вот тут я делал на С++ такую сеть с самодельной работой с GPU.



Так вот, в мою карту 1060 с 3 ГБ поместилось за раз не более 100 входных изображений из 60000. Для более сложной сети вообще помещается один образ и не более. И как нормализацию делать в таком случае? Вот именно.

Ну 100 - это уже хорошо, на то они и мини-батчи. А один пример за раз - тоже не новость, называется "online learning". Вот тут сравнение всех трех вариантов с примерами и т.п.: Full batch, mini-batch, and online learning

Так 100 — это для очень-очень простой сети. Когда я 160x120 генерировать пытался на свёрточной сети, там вообще штук 5 образов влезало за раз. И всю память жрут полносвязаные слои (матрицы весов быстро нарастают). Сами ядра свёрток мало жрут.
Поэтому мне вот кажется, вероятно, послойно там всё обрабатывается внутри с выбросом использованных слоёв.


Есть ещё вопросы к быстрой свёртке. Вот есть алгоритм свёртки через умножение. Я его сделал влоб сперва. Какой наивный! :) Одна (!) матрица такой свёртки для картинки 300x300 весила больше 8 ГБ. Ладно, переделал с генерацией матрицы на лету и умножением матрицы с shared-памятью. Заработало. Но скорость упала в 100 раз по сравнению с простой распараллеленой свёрткой без shared-памяти на GPU — оно и понятно, очень много лишних умножений. Мда.

Кстати! Вот смотрите, есть у вас CUDA. Там у вас есть трёхмерные блоки и трёхмерные потоки внутри блоков. Смотрите какая штука вас ожидает.
Быстрое матричное умножение (а оно потребуется для полносвязных сетей) требует задать в потоках блок x=16, y=16,z=1 (число всех потоков внутри блока сильно ограничено! 512, 1024 и, может, уже чуть больше на новых картах. То есть, размерность полной матрицы вы в него не вставите никогда для матриц превышающих по размеру число потоков). Осталась размерность по Z, но что там поместится? 1024/(256)=4. Вот максимум размерности по Z. Вообще не используем её в этом случае. Как видите, мы уже заняли размерность потока. Теперь берём блоки. В x и y мы помещаем номер блока 16x16 (который обрабатывают потоки) по x и по y внутри матрицы результата умножения. А что в z? Номер батча? Ну уж нет. У нас не матрицы, а 3D-тензоры в общем случае, поэтому там z для тензора.
То есть, мы уже заняли всю параллельную работу на видяхе на одну только матрицу. :)

Ну если так микроскопом гвозди забивать - конечно никаких ресурсов не хватит 😀Откуда матрицы свертки на 8 Gb? Обычно они по сотне байтов занимают (зависит от размера, конечно). Я на MNIST первую сверточную сеть запускал LeNet или AlexNet - не помню, но она обучилась нормально на двухядерном процессоре с 4Gb памяти, без всяких GPU. Посмотрели бы как это сделано в том же TensorFlow - он на C++ написан, а на питоне только биндинги для удобного взаимодействия (а Keras - это ещё немного абстракций на питоне для того же TensorFlow, не более). PyTorch - так же, как и numpy и т.д.

Вот откуда:



Или так нагляднее:



Имея быстрое умножение матриц на GPU (на shared-памяти) очень хочется его использовать для ускорения свётки (так как shared-память я пока использовать для произвольных параметров свёртки не придумал как).
И вот есть статья.


Посмотрели бы как это сделано в том же TensorFlow

Это не так-то просто будет понять.

а разве только с параметрами работает нейросеть?

Параметрическая адаптация означает, что подстраиваются числовые параметры модели, минимизируются различные ошибки и пр.

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

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