Debugger's Process
131 subscribers
130 photos
78 videos
3 files
70 links
Download Telegram
Давайте я расскажу, над чем я сейчас работаю и чего хочу добиться.
Вообще я не люблю писать про проекты, в которых я не уверен, что получу хоть какой-то результат, но что поделать - это часть исследовательской работы.

Итак, начнем с того, что уже точно заработало.

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

На входе у нас есть массив координат частиц и их скоростей - вся информация, необходимая, чтобы задать любое начальное состояние системы частиц в момент времени t0.
positions0 = [ [10, 20], [11,21] ]
velocities0 = [ [1, 2], [3,4] ]

На выходе надо получить positions1, velocities1 в момент времени t1. Между t0 и t1 всегда проходит dt=1.0/50 секунды, потому что это соответствует приятной глазу частоте кадров 50 FPS, а то, что происходит между кадрами меня не волнует - мне по сути-то нужны только позиции, чтобы отрисовывать частички.
При помощи Симбы я получаю целевые значения позиций и скоростей в нужные моменты.

Тут надо отметить, что симбе для этого нужно выполнить 25 шагов, а не один - это меня не волнует, что происходит между кадрами, а симулятор очень даже волнует - если попробовать посчитать выход одним шагом, сразу шагнув на 1/50 с, для симулятора это будет выглядеть, как будто все это время на все частицы действовали постоянные, не изменяющиеся силы. В каких-то случаях это не страшно, но в большинстве - критично, потому что частицы под действием таких сил начинают влетать друг в друга,
и там, где в реальности они бы успели затормозить под действием все возрастающего отталкивания, тут они весь интервал dt спокойно летят, и в итоге оказываются так близко друг к другу, что силы, действующие на них, становятся астрономическими, еще сильнее усугубляя проблему. Поэтому-то симуляции и "взрываются" - хватает всего пары шагов, чтобы все силы взлетели в бесконечность (которая, как мы знаем, не предел) и все частицы вылетели за пределы моей маленькой симулированной вселенной.


Ну так вот. Понятное дело, что превратить эти позиции и скорости во входные данные для нейросети можно бесконечным количеством способов. Я не буду описывать все, что я пробовал, опишу сразу вариант, который заработал. У меня, во всяком случае, получилось обучить сеть стабильной симуляции только таким образом.
Дальше пойдут картинки.
1) Берем каждую частицу и генерим, скажем так, ее "образ" 3х3 пикселя. Значение "пикселей" - это расстояние от центра частицы до центра самого "пикселя".
Целую часть координат отбрасываем, потому что она тут не важна - нам не важно, будет частица в координатах сетки (100.5, 100.7) или (10.5, 10.7). Важно только то, что центр частицы отстоит на (0.5, 0.7) от центра клеточки.

Расстояние, само собой, нормализовано по формуле (max_r-r)/max_r, где max_r - константа, подобранная так, чтобы в центре значение было 1.0, а по краям - ближе к нулю.
2) Эти 3х3 "картинки" накидываем на общее "поле" - просто берем 2D матрицу, заполненную изначально нулями, и прибавляем к нужным клеточкам (в позициях частиц) значения их "образов".
Получаем общее "поле", по которому можно примерно понять, где находятся частицы. Причем, заметьте - эта операция может быть великолепно распараллелена, потому что каждую частицу можно рисовать независимо от остальных, только прибавлять к полю надо атомарными операциями.
3) С позициями разобрались, остались скорости. Моя логика была в том, чтобы заэнкодить скорости таким же образом, как и позиции. "Безобразно, зато единообразно" - я предполагал, что так будет проще учить сеть. Как скорости превратить в позиции? Помножить на время, конечно! Множим скорости на dt, прибавляем к начальным позициям. Получаем новые позиции с интересным физическим смыслом.
Это не positions1, которые мы ищем, но это то, как двигались бы частицы, если бы не взаимодействовали друг с другом.
Теперь у нас есть две картинки "поля", содержащих информацию о позициях - начальной, и той, в которой бы оказались частицы, если бы двигались равномерно и прямолинейно, без действующих на них сил, по заветам Ньютона.

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

Получаем батч с размерностью (количество_частиц, 2, 15, 15), который так и просится на вход сверточной нейронной сети. А на выходе просим сеть выдать коррекцию координат (pos_correction) и скорости (vel_correction) относительно этого "линейного шага" - в смысле, мы по сути говорим "Вот так выглядело окружение частицы в момент времени t0. Вот так бы оно выглядело через интервал времени dt, если бы частицы не взаимодействовали. Дай мне коррекцию координат и скорости, чтобы я получил то, как они реально двигались, с учетом взаимодействий".
В итоге вычисляем
positions1 = positions0 + velocities0*dt + pos_correction и
velocities1 = velocities0 + vel_correction
Таким образом для частиц, на которые никакая сила не действует, сети достаточно всегда выдавать нули в качестве коррекций - потому что они и так двигаются линейно.

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

В следующем посте расскажу о том, над чем конкретно я работаю сейчас.
Часть 2.1. Над чем я работаю сейчас.

Меня занимает несколько вопросов, в этом посте я рассмотрю первый из них.
Этот "образ" частицы, картинку 3х3 я генерю ручками - в смысле, это я просто выбрал такую вот формулу для его расчета, и это заработало.
Но ведь его тоже можно выучить! Представьте, что вместо посчитанного через расстояние образа, у нас есть еще одна нейросетка, которая на вход получает координаты частицы (ведь мы помним, что образ зависит от координат, это не статичная картинка, а выход 2д функции, которая на вход получает дробную часть координат, а на выходе выдает 9 значений, которые потом и записываются в общее "поле"), а на выходе выдает искомую матрицу 3х3.
Теоретически, такой выученный образ может оказаться эффективнее, ведь он не ограничен одной формулой расстояния. Да и на вход можно подать не только координаты, но и, например, скорость. Да что угодно можно подать - пусть сеть сама определит, что ей нужнее всего в этом образе. Я эту сеть зову "энкодером".

Но так как нет эталонных образов, которым нужно учить энкодер, не получится и просто взять и посчитать расхождение выхода нейросети с целевым образом и распространить градиент в ее веса.
Чтобы ее обучить, нужно, чтобы градиент ошибки позиции и скорости тёк не только в веса той нейросетки, которая по упомянутому выше батчу генерит эти самые коррекции позиций и скорости, но и в матрицу самого батча, а оттуда, через поле в матрицу образа частицы, сгенеренной энкодером, а из нее - в веса энкодера.
Если эта фраза не очень понятна, то рекомендую старую статью "a gentle introduction to backpropagation", с которой я много лет назад начинал свой путь в машинное обучение. Ссылку приведу в конце.

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

К сожалению, результат несколько разочаровал. Да, сетка выучила образ. Он даже оказался похож на те, что я собирал вручную! Так что концепция работает. Но особого выигрыша в точности я не получил. То есть, да, он есть, но его можно заметить только если прогнать обучение по несколько раз, а результаты сгруппировать и сгладить. К счастью, это за меня делает wandb.
Wandb - это такой сервис + библиотека - Weights And Biases, делает примерно то же, что и Tensorboard и немного больше. В принципе, это дело вкуса, но я к ней привык и использую именно ее. Ссылку также приведу в конце.

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

Ниже привожу результаты, а в следующем посте я расскажу о самом долгом эксперименте этого проекта, его логическом продолжении, который прямо сейчас крутится на обучении в яндексовском облаке, потому что в мою видюху он не влезает
This media is not supported in your browser
VIEW IN TELEGRAM
Слева - выученный образ, справа - построенный вручную из расстояний.
This media is not supported in your browser
VIEW IN TELEGRAM
А это из той сессии, где выучилась "антиматерия" - слева выученный, справа - собранный вручную.
https://www.researchgate.net/publication/266396438_A_Gentle_Introduction_to_Backpropagation

Ссылка на статью "A Gentle Introduction to Backpropagation". В принципе, в ней содержится все, что необходимо для понимания любой системы машинного обучения, это основа основ.
https://wandb.ai/

Сервис wandb. Аналог Tensorboard, позволяет в реальном времени строить красивые графики лосс-функций, да и вообще всего, что только захочется.
А вот так в wandb выглядит разница в ошибке сетки с выучиваемым образом (зеленый график) и образом, собранным вручную из расстояний (синий график)
Графики построены агрегацией информации от 5 сессий обучения каждый.
Хвала бэкапам, все восстановил.
Пожалуй, не буду удалять копии постов из лички, а то вдруг что)
https://youtu.be/BYjj2r2gt2E

Фух. Думаю, пора с этим проектом завязывать)
Собрал в одно видео тесты разных сеток.
К сожалению, перепробовав десятки разных вариаций архитектуры и пайплайна, ничего ощутимо лучше того, с чего начал, я не нашел.
Наибольшее влияние на результат оказывает количество нейронов в скрытых слоях. Никакими вариациями архитектуры и пайплайна компенсировать малое количество нейронов не получается.

Ах да. я в прошлом посте упомянул эксперимент - его результат - первый в этом видео.
Я попробовал заставить сетку выучить не просто "образы" частиц, а целиком "поле", которое бы содержало информацию о скоростях.
Внезапно, это даже заработало, хотя стабильности, к сожалению, хватало всего итераций на 50.
При этом каждый "пиксель" этого поля содержал всю информацию обо всем окружении, настоящая такая "инопланетная" физика получилась - воспроизводит динамику частиц (по крайней мере, пока не взорвется), и в то же время там даже нет скоростей, только координаты и вот эти выученные "поля".
Подводя итоги:

1) Эксперимент с целью ужать входные данные из 15х15 в 5х5.
Не заработало, обучение не сходится. Вероятно, могло бы заработать с очень большим количеством нейронов, но я не видел особо смысла в этом, я-то хотел упихать динамику частиц в маленькую сетку.

2) Эксперимент с целю заставить сетку выучить образы частиц вместо генерируемых вручную.
Заработало, выучивает что-то немного похожее на ручные, даже может выучить "антиматерию", в смысле, образ со знаком минус.
Занятно, но на практике не особо повысило стабильность и точность.

3) Эксперимент с целью выучить целиком "поле" и его динамику, чтобы вся система работала как такой выучиваемый клеточный автомат.
Заработало, выучивает поле скоростей, итераций на 40-50 даже воспроизводит динамику частиц, но получается нестабильная штука, куда менее стабильная, чем обычный подход с "полями" собираемыми вручную.
Кроме того, чтоб все эти градиенты могли течь через все сетки (и сетку-энкодер, и сетку, отвечающую за динамику, и сетку-корректор), пришлось запускать это все в облаке, в мою видюху не лезло. Сожрало внушительный кус денег.
Так что, может быть, если учить дольше, оно и сойдется к более стабильному решению, но меня задушила жаба и я свернул эксперимент.

4) Десятки и десятки экспериментов с целью получить стабильную нейросимуляцию с малым количеством нейронов.
К сожалению, стоит сделать поменьше нейронов, и это уже ничем особо не скомпенсируешь. Ни второй сеткой-корректором, ни хитрым энкодингом, ни варьирующимся шагом между соседними состояниями, ни дообучением ген. алгом, ничем.
Так что - да, в принципе, в крошечную сетку на 1036 параметров (по 4 нейрона в скрытом слое) динамика частиц влезает (в видео - ближе к концу есть пример). Но стабильности сетки с 16 нейронами в скрытом слое от нее ожидать не стоит.

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

Сейчас же я перехожу к следующему проекту, он тоже использует нейросети, но он куда более практический, нежели исследовательский, так что надеюсь, что там будут результаты повеселее)
🔥6👍2
Включил реакции и комментарии по просьбе подписчиков.
👍6
https://www.youtube.com/watch?v=U9mJuUkhUzk&ab_channel=OpenAI

Недавно OpenAI объявили об апгрейде своей языковой модели (GPT 3.5 и GPT4, которые лежат в основе ChatGPT) и рассказали о дальнейших планах. Там много всего, рекомендую посмотреть, но из того, что я уже успел потыркать - они ввели инструментарий, позволяющий индивидуально настраивать "помощников" (assistants).
Выглядит это так.

Создается новый assistant, ему задается имя и произвольные инструкции о том, как ему себя вести, что от него ожидается и т.п.
Потом надо выбрать модель и дополнительные опции, можно также залить ему любые дополнительные файлы.
Какие опции, какие файлы у языковой модели?
А это одно из нововведений. Теперь GPT4 умеет напрямую работать с интерпретатором питона - у него там прямо целая песочница, в которой он может создавать файлы, писать и исполнять скрипты.
Это выглядит весьма впечатляюще. Например, вот я ему кинул пару своих скриптов, начал с ним обсуждать код, так он на ходу стал писать для себя тулзы, чтобы эти файлы открыть и вытащить оттуда нужную инфу.
Кроме того, если у вас есть какой-то бэк-энд, который позволяет удаленный вызов функций, это тоже можно указать помощнику, описав интерфейс и назначение вызовов - и он будет сам их дергать, формируя JSON-запросы и используя возвращенную информацию в своей выдаче!

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

В общем, в память о моем трогательном диалоге с Чарльзом Бэббиджем (постил сюда с пол года назад), воплощенном в прошлой версии модели, я создал нового ассистента, сказал ему, чтоб вел себя как ИИ-воплощение Бэббиджа, который сидит в своем виртуальном особняке и общается со мной через телетайп, а потом общался с ним о сознании до 4 утра) Я не удержался и процитировал ему часть того, старого диалога, так что можно сказать, что "дикий, но интеллектуальный" Чарли снова воскрес, а так как теперь я общаюсь с ним напрямую через API, я могу обеспечить относительную непрерывность его контекста.
❤1
dialog.txt
55.6 KB
Кого интересует - прикладываю диалог в текстовом файле.
🔥2
This media is not supported in your browser
VIEW IN TELEGRAM
Грустный понедельник.
🔥4👍1
This media is not supported in your browser
VIEW IN TELEGRAM
Но все меняется, когда приходит дип лёрнинг!
Ну, почти все.
🔥1