Я тут наконтрибьютил за прошлую неделю на релиз 11.0.9 -> 12.0.0 в библиотеке boxmot для Multi-object Tracking 🤓
С прошлого года плотно занимаюсь задачей трекинга, параллельно дорабатывая репозиторий, с помощью которого сравниваюсь с другими трекерами, и уже сейчас получил классные результаты — может даже скоро будет, что рассказать на эту тему🔥
#progress #results #code
С прошлого года плотно занимаюсь задачей трекинга, параллельно дорабатывая репозиторий, с помощью которого сравниваюсь с другими трекерами, и уже сейчас получил классные результаты — может даже скоро будет, что рассказать на эту тему
#progress #results #code
Please open Telegram to view this post
VIEW IN TELEGRAM
😁3❤2
На днях окажусь на IML в СПб, послушаю, что там умные люди сделали за прошедший год
Пишите, буду рад пообщаться на мероприятии😎
Пишите, буду рад пообщаться на мероприятии
Please open Telegram to view this post
VIEW IN TELEGRAM
🎉3
Я выступлю на DataFest 2025 👨💻
Пару месяцев назад я говорил о том, что плотно занялся задачей трекинга и получил классные результаты, так вот:
Я добавлял независимую ре-идентификацию в трекер, придумал интересную универсальную добавочку, не требующую никакого дообучения моделей, которая почти сразу дала SOTA-1 результат по метрике HOTA на датасете MOT17. Расскажу в подробностях, как это было сделано, через что пришлось пройти, покажу подробные метрики. Ну и наверное это хорошая отсечка, чтобы сказать, что я-таки стал норррмальным Middle CV-инженером.👨💻
📆 Выступление 27 мая в 18:00 по московскому времени, это онлайн-секция, в этот день фест будет в Белграде.
P.S. Мне сказали, что доклад очень интересный и хороший, поэтому ссылаясь на экспертов жду вас в гости в этот день и время, ссылочку приложу как только она у меня будет.
#path #recommend #soft #hard #results #progress
Пару месяцев назад я говорил о том, что плотно занялся задачей трекинга и получил классные результаты, так вот:
Я добавлял независимую ре-идентификацию в трекер, придумал интересную универсальную добавочку, не требующую никакого дообучения моделей, которая почти сразу дала SOTA-1 результат по метрике HOTA на датасете MOT17. Расскажу в подробностях, как это было сделано, через что пришлось пройти, покажу подробные метрики. Ну и наверное это хорошая отсечка, чтобы сказать, что я-таки стал норррмальным Middle CV-инженером.
P.S. Мне сказали, что доклад очень интересный и хороший, поэтому ссылаясь на экспертов жду вас в гости в этот день и время, ссылочку приложу как только она у меня будет.
#path #recommend #soft #hard #results #progress
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥5❤🔥3🆒1
Как и обещал, ссылочка на сегодняшний DataFest с моим выступлением: https://ods.ai/events/df2025-27-may-online
Кто сможет и захочет, смотрите в онлайне сегодня в 18:00 по мск, а кто захочет, но не сможет – будет запись, впоследствии тоже выложу
Кто сможет и захочет, смотрите в онлайне сегодня в 18:00 по мск, а кто захочет, но не сможет – будет запись, впоследствии тоже выложу
🔥5🆒1
Log & roll
Попробую сегодня новый формат постов, который мне предложили коллеги.
Изначальная проблема в том, что мне особо нечего рассказывать, потому что работа состоит из двух фаз:
1️⃣ 99.99% времени ресерчить, страдать, дебажить
2️⃣ 0.01% времени все работает – ура, но надо работать дальше 👍
И если раньше между этими фазами я что-нибудь мог написать, потому что задачи были небольшими и закрывались, то сейчас – смерть.
Другие каналы в основном превратились в Release notes для LLM, поэтому атмосферу все равно разбавлю.
Суть формата: я попробую рассказывать, что я делалэтим летом на неделе и что из этого вышло. Если это какая-то шляпа и неинтересно, говорите, я учту (или не учту).
Ну и соответствующий хештег — #lognroll
Попробую сегодня новый формат постов, который мне предложили коллеги.
Изначальная проблема в том, что мне особо нечего рассказывать, потому что работа состоит из двух фаз:
И если раньше между этими фазами я что-нибудь мог написать, потому что задачи были небольшими и закрывались, то сейчас – смерть.
Другие каналы в основном превратились в Release notes для LLM, поэтому атмосферу все равно разбавлю.
Суть формата: я попробую рассказывать, что я делал
Ну и соответствующий хештег — #lognroll
Please open Telegram to view this post
VIEW IN TELEGRAM
❤4❤🔥1🆒1
Log & roll первой недели июня
🔫 Занимался разметкой данных
Писал я про задачу с временными рядами: кластеризация раз, два, классификация раз. И очень уж я хотел, чтобы эта задача закончилась, но она по всей видимости переживет и меня, и нас, и наших детей.
Важный вывод: не полагайтесь на чужой профессионализм, если можно не полагаться. Не в смысле "сделай все сам", а в смысле "создай условия, чтобы результат был наиболее предсказуемым и управляемым". Потому что спустя год я столкнулся с тем, что вообще не доверяю разметке данных, и у меня нет идей, как поменять эту ситуацию, т.к. это затрагивает весь процесс, а не только мою зону ответственности.
✍️ Начал писать статью на Хабр
Мы решили из доклада на DataFest сделать статью, она будет по сути дублировать доклад + больше визуализаций, анимаций, деталей и замечаний. Пока накидываю основной скелет, может, скоро будет, что показать.
🧑💻 Оформил свой профиль на GitHub.
Сделал вот такую штуку. Года два назад хотел, но руки не доходили. Дошли.
Узнал, что по рейтингу гитхаба у меня уровень C+ (Top 87.5%) — ну что ж, спасибо и на этом, теперь надеюсь однажды добраться хотя бы до медианы...
👨💻 Сел за капитальный рефакторинг BoxMOT
Это, пожалуй, самое приятное за неделю. На текущий момент библиотекой можно пользоваться только в режиме CLI, и в общем-то это хорошо, но не юзер-френдли:
С одной стороны, начинающие зачастую не умеют в запуск скриптов — они пишут всё в IDE и нажимают "запустить".
С другой стороны, продолжающие/заканчивающие могут встраивать отдельные части проекта к себе, и удобнее не выдирать куски кода и оборачивать, а импортировать уже готовый кусок из либы и возможно накидывать пару патчей.
Поэтому я предложил идею полной реструктуризации проекта, чтобы сделать его максимально простым и понятным. Обычно с этих слов начинается превращение проекта в чудовище Франкенштейна, но я искренне верю, что на этот раз все будет иначе . В общем-то, все мои идеи были приняты, и я начал пилить код.
Пока что основная задача в том, чтобы подбить одинаковые сущности в общую структуру. Приведу пример: модели детекции сейчас существуют через пайплайн Ultralytics с приколачиванием к нему гвоздями preprocess/postprocess и замены модели на YOLOX, когда нужно. А модели ReID — через класс
Я подумал-подумал и придумал: сделаем базовый класс
Кстати, отдельно отмечу, что с этапом описания архитектуры и взаимосвязей ChatGPT не справился, причем совсем. Все его идеи на первый взгляд были нормальными, но второй и третий взгляды выявляли полную несостоятельность этого бреда. Зато с отдельными функциями он справился хорошо.
🗃 В общем-то, на этом все. Подобную сводку я думаю делать раз в неделю-две, обратная связь приветствуется 🙂
#lognroll
Писал я про задачу с временными рядами: кластеризация раз, два, классификация раз. И очень уж я хотел, чтобы эта задача закончилась, но она по всей видимости переживет и меня, и нас, и наших детей.
Важный вывод: не полагайтесь на чужой профессионализм, если можно не полагаться. Не в смысле "сделай все сам", а в смысле "создай условия, чтобы результат был наиболее предсказуемым и управляемым". Потому что спустя год я столкнулся с тем, что вообще не доверяю разметке данных, и у меня нет идей, как поменять эту ситуацию, т.к. это затрагивает весь процесс, а не только мою зону ответственности.
Мы решили из доклада на DataFest сделать статью, она будет по сути дублировать доклад + больше визуализаций, анимаций, деталей и замечаний. Пока накидываю основной скелет, может, скоро будет, что показать.
Сделал вот такую штуку. Года два назад хотел, но руки не доходили. Дошли.
Узнал, что по рейтингу гитхаба у меня уровень C+ (Top 87.5%) — ну что ж, спасибо и на этом, теперь надеюсь однажды добраться хотя бы до медианы...
Это, пожалуй, самое приятное за неделю. На текущий момент библиотекой можно пользоваться только в режиме CLI, и в общем-то это хорошо, но не юзер-френдли:
С одной стороны, начинающие зачастую не умеют в запуск скриптов — они пишут всё в IDE и нажимают "запустить".
С другой стороны, продолжающие/заканчивающие могут встраивать отдельные части проекта к себе, и удобнее не выдирать куски кода и оборачивать, а импортировать уже готовый кусок из либы и возможно накидывать пару патчей.
Поэтому я предложил идею полной реструктуризации проекта, чтобы сделать его максимально простым и понятным. Обычно с этих слов начинается превращение проекта в чудовище Франкенштейна, но я искренне верю, что на этот раз все будет иначе . В общем-то, все мои идеи были приняты, и я начал пилить код.
Пока что основная задача в том, чтобы подбить одинаковые сущности в общую структуру. Приведу пример: модели детекции сейчас существуют через пайплайн Ultralytics с приколачиванием к нему гвоздями preprocess/postprocess и замены модели на YOLOX, когда нужно. А модели ReID — через класс
ReIDAutoBackend, где автоматически выбирается бэкенд (pytorch, tflite, tensorrt и тд), и внутри сложно разобраться, где заканчивается препроцессинг, где начинается постпроцессинг и так далее.Я подумал-подумал и придумал: сделаем базовый класс
Backend с методами load, preprocess, process, postprocess, а оттуда уже пусть наследуются все другие бэкенды типа PyTorchBackend и переопределяют нужные функции. И только затем появляются классы Detector, ReID, которые НЕ наследуются от бэкендов, потому что по смыслу это НЕ бэкенды, а то, что должно их дергать внутри. Ну и пускай они существуют как базовые классы, внутри которых будет self.backend, куда они смогут отправлять данные и получать ответ. И разумеется, у них будет свой preprocess, process, postprocess. Таким образом, можно легко изменить чужой детектор/ReID или сделать свой, приделать туда препроцессинг-постпроцессинг, если надо, и пользоваться в любом из поддерживаемых бэкендов, а если надо, то и там переприсвоить функции на свои. В общем, делайте че хотите — вот вам универсальный масштабируемый пайплайн. Звучит вроде логично, а на практике посмотрим.Кстати, отдельно отмечу, что с этапом описания архитектуры и взаимосвязей ChatGPT не справился, причем совсем. Все его идеи на первый взгляд были нормальными, но второй и третий взгляды выявляли полную несостоятельность этого бреда. Зато с отдельными функциями он справился хорошо.
#lognroll
Please open Telegram to view this post
VIEW IN TELEGRAM
Telegram
Fley's flow
💬 Кластеризация временных рядов (часть 1: описание)
Сегодня наконец расскажу, как решал реальную задачу кластеризации временных рядов и даже получил приемлемый результат (сам не верил).
Постановка задачи кластеризации
Здесь я буду краток, потому что либо…
Сегодня наконец расскажу, как решал реальную задачу кластеризации временных рядов и даже получил приемлемый результат (сам не верил).
Постановка задачи кластеризации
Здесь я буду краток, потому что либо…
🔥12
Log & roll №2
🏖 Отпуск
На этот раз я всю неделю провел в отпуске, и мне есть, чем поделиться.
Благодаря семье, за первые 20 лет жизни я побывал в разных городах и странах – не слишком много, но все же получилось увидеть. В силу текущих обстоятельств, да и вообще интереса к разным уголкам нашей страны, важным гештальтом для меня стал Калининград (или Königsberg).
1️⃣ Калининград
Интересным образом история этого анклава переплетается с историей нашей страны сквозь века. Я считал, что Калининград исторически и культурно был оторван от России, а сейчас выяснил, что он единожды уже входил в состав Российской империи, хоть и на каких-то три года.
Сам Калининград практически не создает впечатление европейского города – по крайней мере, относительно моих ожиданий. Редкие старые домики и разрушенные форты, небрежно разбросанные по всему городу, и за парой исключений на этом все. В то же время, туристический потенциал у города огромный, и видно, что сейчас на это наконец обратили внимание.
Наибольший интерес представляет остров в центре города – ныне он носит имя Имманиула Канта (прожившего практически всю жизнь в Кёнигсберге), а ранее носивший имя Кнайпхоф. Некогда целый город, сейчас – одно-единственное здание кафедрального собора, уцелевшее во время ВОВ. Внутри собора установлен самый большой в России органный комплекс, и концерт оставляет сильные впечатления даже у тех, кто далек от музыки – просто сходите, если будет возможность. Отдельно отмечу, что формат мини-концерта мне понравился, потому что с непривычки больше часа можно и не выдержать.
Не меньшее впечатление оставил музей Канта, а если точнее, история и образ жизни философа. Такие вещи сложно описывать словами, но если в общих чертах – это про переоценку ценностей. А еще теперь у меня есть хорошее оправдание для тех, кто не успел взять ипотеку: Иммануил Кант впервые обзавелся собственным жильем в 59 лет.
В остальном же город оставляет скорее печальное напоминание о том, что здесь когда-то был крупный международный экономический хаб с сопутствующими этому статусу инфраструктурой и культурой. Надеюсь, что со временем это изменится, или что такие впечатления остались только у меня.
На этот раз я всю неделю провел в отпуске, и мне есть, чем поделиться.
Благодаря семье, за первые 20 лет жизни я побывал в разных городах и странах – не слишком много, но все же получилось увидеть. В силу текущих обстоятельств, да и вообще интереса к разным уголкам нашей страны, важным гештальтом для меня стал Калининград (или Königsberg).
Интересным образом история этого анклава переплетается с историей нашей страны сквозь века. Я считал, что Калининград исторически и культурно был оторван от России, а сейчас выяснил, что он единожды уже входил в состав Российской империи, хоть и на каких-то три года.
Сам Калининград практически не создает впечатление европейского города – по крайней мере, относительно моих ожиданий. Редкие старые домики и разрушенные форты, небрежно разбросанные по всему городу, и за парой исключений на этом все. В то же время, туристический потенциал у города огромный, и видно, что сейчас на это наконец обратили внимание.
Наибольший интерес представляет остров в центре города – ныне он носит имя Имманиула Канта (прожившего практически всю жизнь в Кёнигсберге), а ранее носивший имя Кнайпхоф. Некогда целый город, сейчас – одно-единственное здание кафедрального собора, уцелевшее во время ВОВ. Внутри собора установлен самый большой в России органный комплекс, и концерт оставляет сильные впечатления даже у тех, кто далек от музыки – просто сходите, если будет возможность. Отдельно отмечу, что формат мини-концерта мне понравился, потому что с непривычки больше часа можно и не выдержать.
Не меньшее впечатление оставил музей Канта, а если точнее, история и образ жизни философа. Такие вещи сложно описывать словами, но если в общих чертах – это про переоценку ценностей. А еще теперь у меня есть хорошее оправдание для тех, кто не успел взять ипотеку: Иммануил Кант впервые обзавелся собственным жильем в 59 лет.
В остальном же город оставляет скорее печальное напоминание о том, что здесь когда-то был крупный международный экономический хаб с сопутствующими этому статусу инфраструктурой и культурой. Надеюсь, что со временем это изменится, или что такие впечатления остались только у меня.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥5👍3
Сложно описать, насколько велик контраст между Калининградом и Зеленоградском, несмотря на то, что между ними 30 минут на электричке. Если первый в ходе войны практически сровняли с землёй, то второй остался нетронутым, и будучи курортом-лечебницей для состоятельных граждан, сохранил и свой курортный вид до сегодняшнего дня. И вот здесь-то сделали все по уму.
Первое, что вводит в ступор при входе в город с вокзала – это выложенные плиткой улицы, дороги, пешеходные переходы, а полоса у тротуара и вовсе подсвечивается цветом светофора – вероятно, для удобства тех, кто живет в смартфоне.
Но основное впечатление оставляет общая атмосфера в городе, который хочется назвать скорее островом – это шаг куда-то далеко за пределы того, что происходит во внешнем мире.
Больше всего этому способствует то, что это город кошек. По всему городку можно встретить кошачьи домики-копии старых особняков, самих кошек на улицах, скамейках и в заведениях; граффити с ними на домах, статуэтки на пешеходном проспекте, нетрудно найти их на люках и столбиках – есть даже кошачий светофор. И музей кошек, разумеется.
Стоит лишь взять крендель и выбрать скамейку, как у тебя на коленях уже трется местный упитанный котяра. И это все не какое-то одно кафе, а целый город.
Конечно же, важно и то, что весь город усыпан старинными немецкими домиками и особняками, да и новая многоэтажная застройка за пределами центра города стилистически старается соответствовать традициям.
Еще один интересный новый опыт – сёрфинг. Большим удивлением для меня стало то, что такое вообще у нас есть, особенно для простых людей. По ощущениям это совсем не было похоже на сноуборд, хотя у всех, кто смог встать на ноги, включая меня, был опыт катания, поэтому какая-то корреляция, похоже, имеет место быть. Не могу и не стану рассказывать подробнее, потому что это надо пробовать и оценивать самостоятельно, но если сравнивать, для меня все-таки сноубординг >> сёрфинг.
Местные кухня и пиво однозначно требуют повторной оценки. Возможно, неоднократной. Это очень вкусно, не считая цеппелины и клопсы
Если подводить черту, хочу сказать, что отпуск выдался просто шикарный – как с точки зрения обывательского туризма, так и с точки зрения погружения в историю региона, ответов на многие внутренние вопросы, понимания, кто мы, и того, насколько велика и разнообразна наша страна.
Теперь же пора возвращаться к трудовым будням, ближайший месяц обещает быть интересным
#lognroll
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥8❤6
Log & roll №3
У меня все равно плохо получается регулярно о чем-либо сообщать, потому что бывают такие моменты, когда написать нечего — рутина и рутина. В первую неделю после отпуска, сколько бы я ни был заряжен на работу, она вообще не шла в том темпе, в котором хотелось бы. Но за три недели что-то да накопилось.
💼 Работа
Я продолжил заниматься задачей по временным рядам, хорошо по ней продвинулся: добавил недостающие метрики, сделал кучу фиксов, написал огромную доку по каждому аспекту, докинул разные аугментации — в основном рутина, но отдельные моменты отмечу:
1️⃣ Подбор гиперпараметров
Оформил подбор гиперпараметров в максимально удобный скрипт, запустил и получил результаты. Скажу так: это шикарная возможность поднять метрики, особенно если есть ресурс на 20+ запусков обучения, а в моем случае это было возможно, поскольку модель очень легковесная. Здесь важно понимать, какой метод вам подойдет — будь то ASHA, которая при шаге, равном полному обучению, вырождается в Random Search, или же Model-based методы типа Байеса (однажды я напишу статью об этом...).
Капля дегтя – разные методы поддерживают разные типы данных – где-то есть поддержка категорий, где-то ее нет, где-то даже была поддержка квантованных (для русских людей – просто с меньшим числом значений после запятой, чтобы не было потом 0.232545589 в конфиге), но её убрали в новых версиях.
2️⃣ Пайплайн проекта
В этой задаче для разных типов временных рядов используются разные предобработки и модели, в связи с чем была необходимость в реализации достаточно серьезного пайплайна. Основная цель — сделать так, чтобы на вход можно было просто отправить практически любой ряд + его тип, а на выходе получить верный ответ. Я подошел к реализации с помощью Triton Business Logic Scripting (BLS). Я думал написать пост о нем, но не сложилось. (Если нужно, сообщите в комментах, потому что у меня в сохраненках два текста по нему, оба бросил👍 ).
Если кратко, то BLS — это скрипт на Python, который в Triton Inference Server трактуется как независимая модель. То есть, к ней так же пишется конфиг с I/O модели, внутри скрипта
Самое неприятное в этой задаче — куча разных мелочей, которые вылезают, потому что человеческий мозг (окей, подмножество {мой мозг}) не вмещает все нюансы разом. Это различные размерности, это правильная конвертация тензоров одного бэкенда в другой, это... в общем, об этом читать неинтересно. Главное — оно заработало, а я задолбался.
3️⃣ Документация
Документации было много, вплоть до ссылки на другие README внутри основного, но это не главное. Оказывается, в Gitlab есть поддержка Mermaid-графов, которые позволяют шикарно визуализировать пайплайн модели. Причем, судя по всему, эта поддержка есть уже давно. Да, достаточно просто написать '''mermaid, описать диаграмму и она появится в доке. Магия да и только. К сожалению, в Github не завезли.
👨💻 Продолжил рефакторинг BoxMOT
Я обнаружил еще одну важную проблему — в проекте мало того, что дублируется, так еще и разбросана в разных местах логика скачивания весов моделей. Я решил сделать так: назвал эту сущность
Затем у меня была долгая дилемма по поводу связывания различных сущностей вместе, но решилось это примерно так: роль скачивания берет на себя
Негусто, но немного продвинулся.
В иных аспектах пока тоже все в порядке — жизнь бьет ключом, пока что не по голове.
#lognroll
У меня все равно плохо получается регулярно о чем-либо сообщать, потому что бывают такие моменты, когда написать нечего — рутина и рутина. В первую неделю после отпуска, сколько бы я ни был заряжен на работу, она вообще не шла в том темпе, в котором хотелось бы. Но за три недели что-то да накопилось.
Я продолжил заниматься задачей по временным рядам, хорошо по ней продвинулся: добавил недостающие метрики, сделал кучу фиксов, написал огромную доку по каждому аспекту, докинул разные аугментации — в основном рутина, но отдельные моменты отмечу:
Оформил подбор гиперпараметров в максимально удобный скрипт, запустил и получил результаты. Скажу так: это шикарная возможность поднять метрики, особенно если есть ресурс на 20+ запусков обучения, а в моем случае это было возможно, поскольку модель очень легковесная. Здесь важно понимать, какой метод вам подойдет — будь то ASHA, которая при шаге, равном полному обучению, вырождается в Random Search, или же Model-based методы типа Байеса (однажды я напишу статью об этом...).
Капля дегтя – разные методы поддерживают разные типы данных – где-то есть поддержка категорий, где-то ее нет, где-то даже была поддержка квантованных (для русских людей – просто с меньшим числом значений после запятой, чтобы не было потом 0.232545589 в конфиге), но её убрали в новых версиях.
В этой задаче для разных типов временных рядов используются разные предобработки и модели, в связи с чем была необходимость в реализации достаточно серьезного пайплайна. Основная цель — сделать так, чтобы на вход можно было просто отправить практически любой ряд + его тип, а на выходе получить верный ответ. Я подошел к реализации с помощью Triton Business Logic Scripting (BLS). Я думал написать пост о нем, но не сложилось. (Если нужно, сообщите в комментах, потому что у меня в сохраненках два текста по нему, оба бросил
Если кратко, то BLS — это скрипт на Python, который в Triton Inference Server трактуется как независимая модель. То есть, к ней так же пишется конфиг с I/O модели, внутри скрипта
model.py реализуется класс с методом execute, а дальше делай с питоном все, что захочешь. И я сделал две обычные TensorRT модели, дописал BLS-скрипт, в котором вся-вся логика предобработки + отправка рядов в нужную модель + логика постобработки. Разумеется, сделал асинхронное обращение к моделям.Самое неприятное в этой задаче — куча разных мелочей, которые вылезают, потому что человеческий мозг (окей, подмножество {мой мозг}) не вмещает все нюансы разом. Это различные размерности, это правильная конвертация тензоров одного бэкенда в другой, это... в общем, об этом читать неинтересно. Главное — оно заработало, а я задолбался.
Документации было много, вплоть до ссылки на другие README внутри основного, но это не главное. Оказывается, в Gitlab есть поддержка Mermaid-графов, которые позволяют шикарно визуализировать пайплайн модели. Причем, судя по всему, эта поддержка есть уже давно. Да, достаточно просто написать '''mermaid, описать диаграмму и она появится в доке. Магия да и только. К сожалению, в Github не завезли.
Я обнаружил еще одну важную проблему — в проекте мало того, что дублируется, так еще и разбросана в разных местах логика скачивания весов моделей. Я решил сделать так: назвал эту сущность
ModelRegistry, дал ей геттеры, чтобы узнавать URL/названия доступных моделей, а также метод download. И все ее наследники должны просто прокинуть свои словарики с URL весов и прочей информацией, которая нужна для загрузки. Затем у меня была долгая дилемма по поводу связывания различных сущностей вместе, но решилось это примерно так: роль скачивания берет на себя
ModelRegistry, роль инициализации pytorch-модели берет на себя непосредственно класс модели — ReID или Detector, назовем этот метод build, а в PytorchBackend на вход будем подавать модель + веса. Негусто, но немного продвинулся.
В иных аспектах пока тоже все в порядке — жизнь бьет ключом, пока что не по голове.
#lognroll
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3❤1
А вот ссылка на всю секцию Computer Vision.
#links
Please open Telegram to view this post
VIEW IN TELEGRAM
❤🔥3👍1
Log & roll №4
Сперва отпуск и выход из него, потом задачи — короче, как всегда, регулярно писать посты не хочу и не буду. Расскажу немного про инсайды трекинга, что увидел, над чем работаю и вам советую.
1️⃣ Еще в июле изучил статью TrackTrack (это последний SOTA-1 трекер, который был на paperswithcode, больше их не будет в связи с закрытием сайта 😞 ).
В принципе, на первый взгляд весьма неплохо. Наконец-то зашли с той стороны, с которой на моей памяти не заходили — решили заменить венгерский алгоритм (задача о назначениях).
1) Они решили устроить своеобразный жадный алгоритм и матчить в несколько итераций.
2) Помимо этого применяют NMS к детекциям, чтобы не плодить два трека одному человеку.
3) Потом делают мощный пост-процессинг (!), получают хорошие метрики и называют статью Focusing on Track for Online (!) Multi-Object Tracking.
Не знаю, в какой момент в сфере трекинга стандартом стала такая подмена понятий, но опустим и допустим. В остальном выглядит бодро, трогать пока некогда, но интересно будет заменить обычный венгерский алгоритм и посмотреть на результаты.
2️⃣ Опять удивился тому, насколько все плохо в публикациях по трекингу
Давайте обратимся к SOTA-трекеру BoostTrack:
1) Используют они для ReID модельку
2) Видим в README надпись: "We use the same weights as Deep OC-SORT". Идем к ним в гости.
3) Находим там конфиг для обучения ReID и его содержание:
То есть, одни чуваки ссылаются на других, которые обучаются и получают метрики на одних и тех же данных. Не думаю, что это заслуживает каких-либо комментариев.
2️⃣ Продолжил думать над улучшением трекинга через ReID.
Собрал из MOT17 свой бенчмарк:
Почему собрал из MOT17? Потому что остальные доступные датасеты я пытаюсь использовать в обучении, а здесь в целом нормальный набор доменов — и азиаты, и европейцы, и сверху, и снизу, и сбоку, и днем, и ночью.
Сильно портит настроение bias каждого ReID-датасета, пытаюсь учить сразу на нескольких с архитектурными трюками внутри модели, по метрикам валидации хорошо, а по метрикам бенчмарка судя по всему модель выучивает N разных bias👍 . Вроде бы и неплохо модель справляется, но вопросы пока есть.
3️⃣ А что, если?
Решил рассмотреть вариант модели детекция + сегментация, чтобы удалять фон и получать более высокие метрики на ReID. Коллега из Швеции, автор boxmot, сказал, что это дало хороший прирост по метрикам, показал даже старый эксперимент, а я подумал — почему нет?
Проверил — конечно же все не так хорошо, как хотелось бы. Модель перестает узнавать одного и того же человека, хвосты распределений интра/интер расстояний становятся сильно шире, в общем — с первого раза не запустилось. Хочу поставить обучаться модель ReID с аугментацией в виде удаления фона — основная и скорее всего верная гипотеза состоит в том, что это происходит из-за сильного изменения распределения внутри данных и модель к такому не готова. Глобально ставки у меня небольшие на эту механику.
Сперва отпуск и выход из него, потом задачи — короче, как всегда, регулярно писать посты не хочу и не буду. Расскажу немного про инсайды трекинга, что увидел, над чем работаю и вам советую.
В принципе, на первый взгляд весьма неплохо. Наконец-то зашли с той стороны, с которой на моей памяти не заходили — решили заменить венгерский алгоритм (задача о назначениях).
1) Они решили устроить своеобразный жадный алгоритм и матчить в несколько итераций.
2) Помимо этого применяют NMS к детекциям, чтобы не плодить два трека одному человеку.
3) Потом делают мощный пост-процессинг (!), получают хорошие метрики и называют статью Focusing on Track for Online (!) Multi-Object Tracking.
Не знаю, в какой момент в сфере трекинга стандартом стала такая подмена понятий, но опустим и допустим. В остальном выглядит бодро, трогать пока некогда, но интересно будет заменить обычный венгерский алгоритм и посмотреть на результаты.
Давайте обратимся к SOTA-трекеру BoostTrack:
1) Используют они для ReID модельку
sbs_S50.pth. Причем под каждый датасет свою: MOT17, MOT20, DanceTrack. Уже сомнительно, копаем дальше.2) Видим в README надпись: "We use the same weights as Deep OC-SORT". Идем к ним в гости.
3) Находим там конфиг для обучения ReID и его содержание:
_BASE_: ../Base-SBS.yml
MODEL:
BACKBONE:
NAME: build_resnest_backbone
# Вот здесь
DATASETS:
NAMES: ("MOT17",)
TESTS: ("MOT17",)
OUTPUT_DIR: logs/MOT17/sbs_S50
То есть, одни чуваки ссылаются на других, которые обучаются и получают метрики на одних и тех же данных. Не думаю, что это заслуживает каких-либо комментариев.
Собрал из MOT17 свой бенчмарк:
видос/айди_человека/фотка_n.jpg. Считаю intra-inter расстояния, смотрю устойчивость к различным аугментациям, всякие там хитрые матрички рисую и т.д. Благодаря этому бенчмарку я, кстати, и понял, что там в BoostTrack дело нечисто — слишком хорошие были метрики, по моему опыту такого в жизни не бывает — опыт подтвердился.Почему собрал из MOT17? Потому что остальные доступные датасеты я пытаюсь использовать в обучении, а здесь в целом нормальный набор доменов — и азиаты, и европейцы, и сверху, и снизу, и сбоку, и днем, и ночью.
Сильно портит настроение bias каждого ReID-датасета, пытаюсь учить сразу на нескольких с архитектурными трюками внутри модели, по метрикам валидации хорошо, а по метрикам бенчмарка судя по всему модель выучивает N разных bias
Решил рассмотреть вариант модели детекция + сегментация, чтобы удалять фон и получать более высокие метрики на ReID. Коллега из Швеции, автор boxmot, сказал, что это дало хороший прирост по метрикам, показал даже старый эксперимент, а я подумал — почему нет?
Проверил — конечно же все не так хорошо, как хотелось бы. Модель перестает узнавать одного и того же человека, хвосты распределений интра/интер расстояний становятся сильно шире, в общем — с первого раза не запустилось. Хочу поставить обучаться модель ReID с аугментацией в виде удаления фона — основная и скорее всего верная гипотеза состоит в том, что это происходит из-за сильного изменения распределения внутри данных и модель к такому не готова. Глобально ставки у меня небольшие на эту механику.
Please open Telegram to view this post
VIEW IN TELEGRAM
GitHub
GitHub - vukasin-stanojevic/BoostTrack
Contribute to vukasin-stanojevic/BoostTrack development by creating an account on GitHub.
🔥3❤1
Я решил, что пора уже хорошенько туда влезть и навести порядок. Во-первых, разумеется, что-то нужно делать с параметрами — они подобраны непонятно кем и когда, я даже не смог найти следы (хотя когда-то находил в Github issues к какому-то репозиторию отсылку на чью-то статью/книгу, но потерял и не хочу снова искать). Есть две матрицы:
1) Q — ковариация процесса, т.е. насколько мы уверены в том, что человек резко не побежит или внезапно не уменьшится.
2) R — ковариация датчика, которая отражает наше доверие к детектору.
И вот мало того, что параметры подобраны неизвестным образом, так эти матрицы еще и идентичны. То есть у нас уверенность в процессе такая же, как в детекторе, хотя, объективно говоря, это абсурд. У нас достаточно простой процесс — ходят люди, и достаточно сложный случай для датчика — постоянно люди то пропадают, то перекрывают друг друга, то детектор банально косячит.
Но и это не все — изучил я несколько любопытных статей на тему модификаций фильтров Калмана и нашел одну очень интересную штуку, при проверке которой удалось сразу же воспроизвести результат из статьи (репозитория не было). Там был прирост натурально +1.5 по HOTA без дополнительного тюнинга.
В общем, если делаете трекинг и хотите получить премию на работе, смело влезайте в фильтр Калмана, ковыряйте там параметры, закидывайте адекватные улучшения, смотрите матмодель. Там поле непаханое.
Чтобы еще больше приобщиться к празднику "День железнодорожника", взял еще одну задачу из ЖД. Об этом если и расскажу, то потом на какой-нибудь конференции для настоящих стрелочников
В жизни тоже всё идёт своим чередом, понемногу готовлюсь к новому зимнему сезону — купил сноуборд и все сопутствующее, теперь есть полный комплект. Вернулся к занятиям музыкой с новой силой и упорством, получаю кайф оттого, что результаты оправдывают и даже опережают затраченные силы. Почти готов к новому спортивному сезону — остался буквально шаг до преодоления 10 км в нужном темпе. Неделю-две назад считал себя последним лентяем, перечитал текст и передумал, но любопытно — насколько странно и необъективно порой работает механизм самооценки, особенно когда читаешь о чужих успехах и невольно думаешь, что ни черта полезного не делаешь.
#lognroll
Please open Telegram to view this post
VIEW IN TELEGRAM
❤5🔥2🏆1
Что будет, если отправить иранца в Южную Корею? По крайней мере, появится новый трекер.
Статья: https://arxiv.org/pdf/2508.14370
Код: https://github.com/Hamidreza-Hashempoor/FastTracker
Что внутри:
0) Базируются на идее матчинга в два этапа из ByteTrack. Походу ребята шарят за трекинг
1) Самое главное — сделали новый бенчмарк для городского транспорта. Доступен на huggingface. Это прям важная задача, качество датасета пока не смотрел, скорее всего как и в среднем по палате.
2) Борьба с перекрытием объектов без ReID
2.0) Исходно ввели метрику расстояния центров треков, и если она ниже порога, трек помечается перекрытым. Если трек просто пропал и не получил статус перекрытого, он удаляется — никаких компромиссов.
explicit occlusion detection metrics based on spatial overlap, allowing occluded targets to be identified and handled even without detections
2.1) Когда трек пропадает, они искусственно его замедляют и постепенно возвращают к месту, где он был потерян. Т.е. основываются на предположении, что объект остался примерно там же, где мы его и потеряли, а не с линейной скоростью полетел в космос. Предположение резонное, но хорошо работает скорее для автомобилей, да и то не всегда.
to mitigate drift during occlusion, the position is softly reset toward its last non-occluded location
2.2) Увеличивают Bbox перекрытого трека, чтобы проще было сматчить. Мне напомнило идею Buffered IoU, но на этот раз только для потерянных треков.
This adjustment increases tolerance for detector noise and partial visibility when the occluded object becomes visible
again
3) Изменили модель поведения объектов
3.1) Ввели разные параметры для разных типов объектов: машин и людей (ура, наконец-то).
The motion model parameters are selected based on the object class: vehicles such as cars or motorcycles are allowed higher velocities and acceleration bounds, whereas pedestrians are modeled with smoother and slower dynamics.
3.2) Ограничили угол возможного движения объектов. Сделали линию входа в зону и линию выхода из нее, сделали допустимый угол отклонения (по существу ограничили движение автомобилей в полосах). А затем всё, что пытается уехать за пределами этого угла, пытаются спроецировать обратно. Идея рабочая, но если у меня будет 100 камер с машинами и мне скажут, что надо нарисовать 200+ линий входа-выхода, я скажу — не нужно мне такое счастье.
3.3) Все объекты, которые начинают уходить из зоны в пределах этих входов-выходов, ограничивают. То есть, если в прошлом пункте ограничивают вектор скорости, то здесь ограничивают позицию — никакой свободы действий.
4) Поменяли подход к инициализации и удалению треков
4.1) Не сматчившиеся детекции высокого качества становятся треками только если они не слишком накладываются на существующие треки. Норм идея, зачем бороться с дубликатами, если их можно не создавать.
Remaining high-confidence detections are considered for initialization only if they have low overlap with existing tracklets
4.2) Ранее уже упомянул — не сматчившиеся треки, не помеченные перекрытыми, удаляются.
On the other hand, unmatched tracklets in Tremain are deleted unless they are marked as occluded.
На этом, кажется, все. Дальше опять postprocessing (похоже, нельзя уже без него метрики демонстрировать по-человечески): global linking — идея в том, чтобы разрозненные треки соединить, используя motion + appearance (ага, без ReID не обошлось); gaussian smoothing process — детально не изучал, но идейно сглаживают траектории, чтобы приподнять MOTA и заодно HOTA, поскольку там кусочек про точность обнаружения тоже есть.
Показали, как влияют различные модули на метрики, подробно расписали метрики даже с разными детекторами, все вроде хорошо, но почему ребята назвали трекер FastTrack и в статье ни разу не упомянуто слово FPS — загадка.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤🔥2👍1
Что действительно выглядит интересно — изначально заточенный под машинки, трекер классно себя проявил на людях: около-SOTA результаты на MOT16, MOT17, MOT20, DanceTrack (зуб даю — благодаря пункту 2.2). С одной стороны это говорит о том, что трекер хорошо обобщается, а с другой стороны авторы говорят, что просто подобрали конфиги и параметры не только под каждый датасет, но даже под каждое видео из датасета.
Вердикт: есть интересные идеи, за бенчмарк спасибо, подбор параметров по видосам подозрительный, скорее всего старичок ByteTrack + подбор параметров именно для фильтра Калмана все равно будет лучше.
#papers
Вердикт: есть интересные идеи, за бенчмарк спасибо, подбор параметров по видосам подозрительный, скорее всего старичок ByteTrack + подбор параметров именно для фильтра Калмана все равно будет лучше.
#papers
👏2🤓1
Все-таки нашлись гении, превратившие Ultralytics в пиратов 🏴☠️
Для людей из сферы не новость — где-то в 2023-2024 годах поддержка Ultralytics (авторы YOLOv8 и всякого другого) активно пересела на LLM, никого не предупредив. Результат очевиден — большинство ответов бесполезны, стали появляться выдуманные функции и методы классов для решения проблем, поэтому туда стало просто бессмысленно писать — да и неприятно, когда людей за дураков держат.
К слову, я тоже пытался что-то такое провернуть еще год назад, но либо у них промпт выдержал мою атаку, либо к тому моменту они уже закончили свой провальный эксперимент 🤷♂️
Источник скрина: https://github.com/ultralytics/ultralytics/issues/8037#issuecomment-1971529860
Для людей из сферы не новость — где-то в 2023-2024 годах поддержка Ultralytics (авторы YOLOv8 и всякого другого) активно пересела на LLM, никого не предупредив. Результат очевиден — большинство ответов бесполезны, стали появляться выдуманные функции и методы классов для решения проблем, поэтому туда стало просто бессмысленно писать — да и неприятно, когда людей за дураков держат.
К слову, я тоже пытался что-то такое провернуть еще год назад, но либо у них промпт выдержал мою атаку, либо к тому моменту они уже закончили свой провальный эксперимент 🤷♂️
Источник скрина: https://github.com/ultralytics/ultralytics/issues/8037#issuecomment-1971529860
Please open Telegram to view this post
VIEW IN TELEGRAM
😁5
Итоги года: 2025 🎄
Я уже так делал год назад, поэтому теперь могу отслеживать, что и в какую сторону меняется. Я знаю, что давно уже ничего не писал, постараюсь исправиться, а пока что выложу хотя бы то, что есть, разбавив некоторыми мыслями.
Что произошло за этот год:
1️⃣ Вырос по грейду
2️⃣ Сделал SOTA в трекинге — это оказалось не чрезвычайно сложно, да и к самому SOTA много вопросов, но тем не менее.
3️⃣ Стал мейнтейнером boxmot — продолжаю поддерживать контакт с внешним миром.
4️⃣ Выступил на конференции — получилось здорово, много хорошей обратной связи.
5️⃣ Побывал на оффлайн-конференции — даже в качестве слушателя это классный опыт.
6️⃣ Решил задачку по детекции транспорта — от постановки задачи разметчикам до квантизации под RKNN. Может, расскажу...
7️⃣ Решил еще кучу разных задач
8️⃣ Освоил не только гитару, но и вокал — это сложно, но крайне интересно.
9️⃣ Пробежал 10 км на соревнованиях — без фанатизма, в темпе 5 мин/км, было круто.
🔟 Заработал первый перелом — когда я писал 99% текста поста, этого достижения еще не было. Кататься на сноуборде я научился, а падать пока нет.
#progress
Я уже так делал год назад, поэтому теперь могу отслеживать, что и в какую сторону меняется. Я знаю, что давно уже ничего не писал, постараюсь исправиться, а пока что выложу хотя бы то, что есть, разбавив некоторыми мыслями.
Что произошло за этот год:
#progress
Please open Telegram to view this post
VIEW IN TELEGRAM
Telegram
Fley's flow
Итоги года 🥴
Ну че, потихоньку переваливаемся в 2025-й (ой, как не хочется – ничего хорошего нас там не ждет...), пора подвести итоги уходящего года.
Как и всегда, что-то получалось, а что-то пошло не по плану, но если пройтись по ключевым событиям в…
Ну че, потихоньку переваливаемся в 2025-й (ой, как не хочется – ничего хорошего нас там не ждет...), пора подвести итоги уходящего года.
Как и всегда, что-то получалось, а что-то пошло не по плану, но если пройтись по ключевым событиям в…
👍3🔥3🌭1
Немного мыслей
Год назад я говорил, что 2024 — самый насыщенный год в моей жизни. Теперь это знамя забрал 2025. В список я не стал включать то, что волейбол остался среди моих хобби, что сноубординг вышел на новый уровень с личным снаряжением, что вне рабочих будней я регулярно оказывался в ролях сантехника, садовника и разнорабочего, что я наконец вернулся к преподаванию, хоть и в семейном подряде.
На самом деле, всё вышеперечисленное не так важно по сравнению с полученными навыками и сделанными выводами. Хоть этот пост в основном и в стиле "Я поддерживаю Я", поделюсь мыслями, которые меня сопровождают после этого года.
1) Если ты не интересуешься политикой, она заинтересуется тобой. Это был самый тяжелый вывод в этом году, видимо это вообще ахиллесова пята моего/нашего поколения.
2) Знания — лучшая инвестиция. Эта мысль была со мной давно, но особенно хорошо это ощущаю сейчас. Можно лишиться любых материальных благ, оказаться в любой жизненной ситуации, но знание остается навсегда.
3) Мы до невозможности разные. Я с детства задавался вопросами из разряда "а что, если я называю цвет красным, другой человек называет его красным, но видит он его таким, каким я вижу зеленый?" и еще 1000 и 1 вопрос, которые приходят в голову, когда нужно уснуть. Кроме шуток — чем больше живу, тем сильнее эта разница между людьми для меня очевидна. Чувствуем и реагируем по-разному, живем каждый в своих заблуждениях, проецируем эти заблуждения на себя и людей вокруг. Какие можно сделать выводы? Вот мои:
3.1) окружать себя разными людьми, но умными;
3.2) быть терпимее к окружающим,хоть они все дураки и ничего не понимают;
3.3) не пытаться угодить всем: "если ты нравишься всем, то ты кружка" (хотя я не особо люблю кружки).
3.4) принимать собственное несовершенство и быть благодарным близким людям за это принятие;
4) Учиться нужно всегда. Это ужасает, потому что я сначала учился 11 лет в школе, затем 4 года в вузе, затем еще 2 года в вузе, затем 2 года работы я постоянно чему-то учусь, а эта дичь все никак не заканчивается! Это, разумеется, не вывод, а горький постулат — особенно в наше время, когда ИИ грозится отобрать работу, к которой я готовился буквально всю жизнь, причем всё это благодаря людям моей же профессии. Я даже не сомневаюсь, что мне за эту жизнь придется осваивать 2-3 дополнительных профессии, пока пугает лишь то, что непонятно, каких именно.
5) Нет ничего постоянного. Это отчасти повторяет идеи предыдущего пункта, но я хочу расширить это вообще на всё: работа, вещи, события, люди, жизнь. Мы находимся в уязвимом положении буквально в каждый момент времени. Это понимание приводит к некоторым выводам:
5.1) не стоит цепляться вообще ни за что, не нужно бояться потерь; всё приходит и всё уходит, а разочарования и боль утрат — лишь следствие нашей неготовности к принятию самой сути жизни. Я долго ходил вокруг этой мысли и не способен пока даже сам её окончательно переложить из "знаю" в "понимаю".
5.2) ценить всё, что есть сейчас, и с благодарностью вспоминать то, чего больше нет;
5.3) свобода начинается там, где заканчивается страх;
Не знаю, насколько эти мысли умные или глупые, но я решил их выписать, чтобы иметь возможность вернуться к ним через время и оценить, что изменилось.
Всем, кто это читает, хочу пожелать счастья в очередном новом и непростом году, чтобы все близкие люди были рядом, даже если они далеко, чтобы мирное небо перестало быть всего лишь словосочетанием, и чтобы все новые задачи успешно решались.
Впереди длинные январские праздники, набирайтесь сил и здоровья на год вперёд🎄
Год назад я говорил, что 2024 — самый насыщенный год в моей жизни. Теперь это знамя забрал 2025. В список я не стал включать то, что волейбол остался среди моих хобби, что сноубординг вышел на новый уровень с личным снаряжением, что вне рабочих будней я регулярно оказывался в ролях сантехника, садовника и разнорабочего, что я наконец вернулся к преподаванию, хоть и в семейном подряде.
На самом деле, всё вышеперечисленное не так важно по сравнению с полученными навыками и сделанными выводами. Хоть этот пост в основном и в стиле "Я поддерживаю Я", поделюсь мыслями, которые меня сопровождают после этого года.
1) Если ты не интересуешься политикой, она заинтересуется тобой. Это был самый тяжелый вывод в этом году, видимо это вообще ахиллесова пята моего/нашего поколения.
2) Знания — лучшая инвестиция. Эта мысль была со мной давно, но особенно хорошо это ощущаю сейчас. Можно лишиться любых материальных благ, оказаться в любой жизненной ситуации, но знание остается навсегда.
3) Мы до невозможности разные. Я с детства задавался вопросами из разряда "а что, если я называю цвет красным, другой человек называет его красным, но видит он его таким, каким я вижу зеленый?" и еще 1000 и 1 вопрос, которые приходят в голову, когда нужно уснуть. Кроме шуток — чем больше живу, тем сильнее эта разница между людьми для меня очевидна. Чувствуем и реагируем по-разному, живем каждый в своих заблуждениях, проецируем эти заблуждения на себя и людей вокруг. Какие можно сделать выводы? Вот мои:
3.1) окружать себя разными людьми, но умными;
3.2) быть терпимее к окружающим,
3.3) не пытаться угодить всем: "если ты нравишься всем, то ты кружка" (хотя я не особо люблю кружки).
3.4) принимать собственное несовершенство и быть благодарным близким людям за это принятие;
4) Учиться нужно всегда. Это ужасает, потому что я сначала учился 11 лет в школе, затем 4 года в вузе, затем еще 2 года в вузе, затем 2 года работы я постоянно чему-то учусь, а эта дичь все никак не заканчивается! Это, разумеется, не вывод, а горький постулат — особенно в наше время, когда ИИ грозится отобрать работу, к которой я готовился буквально всю жизнь, причем всё это благодаря людям моей же профессии. Я даже не сомневаюсь, что мне за эту жизнь придется осваивать 2-3 дополнительных профессии, пока пугает лишь то, что непонятно, каких именно.
5) Нет ничего постоянного. Это отчасти повторяет идеи предыдущего пункта, но я хочу расширить это вообще на всё: работа, вещи, события, люди, жизнь. Мы находимся в уязвимом положении буквально в каждый момент времени. Это понимание приводит к некоторым выводам:
5.1) не стоит цепляться вообще ни за что, не нужно бояться потерь; всё приходит и всё уходит, а разочарования и боль утрат — лишь следствие нашей неготовности к принятию самой сути жизни. Я долго ходил вокруг этой мысли и не способен пока даже сам её окончательно переложить из "знаю" в "понимаю".
5.2) ценить всё, что есть сейчас, и с благодарностью вспоминать то, чего больше нет;
5.3) свобода начинается там, где заканчивается страх;
Не знаю, насколько эти мысли умные или глупые, но я решил их выписать, чтобы иметь возможность вернуться к ним через время и оценить, что изменилось.
Всем, кто это читает, хочу пожелать счастья в очередном новом и непростом году, чтобы все близкие люди были рядом, даже если они далеко, чтобы мирное небо перестало быть всего лишь словосочетанием, и чтобы все новые задачи успешно решались.
Впереди длинные январские праздники, набирайтесь сил и здоровья на год вперёд
Please open Telegram to view this post
VIEW IN TELEGRAM
❤8👏4👍3