Search
Write a publication
Pull to refresh
17
0
Ilia Udalov @shaggyboo

User

Send message

Отвечу тут коротко про ML часть, по хорошему надо бы написать отдельную статью, но не уверен что доберусь. Если крупными мазками:

  • Генерация фоток проходит в 3 этапа: процессинг входных фоток пользователя (1), обучение модели (2), постфильтрация (3).

  • (1) сделали чекер фоток которые загружает пользователь (face id + эвристики). От того какие фотки попадут в обучение сильно зависит похожесть и вообще всё. Например, нельзя что бы на фотке был еще один человек, нельзя слишком далёкие, слишком близкие, слишком размытые. Иначе всё это просочится в модель.

  • (2) обучение: наше итоговое решение работает через dreambooth с SD 1.5 (это плагин который позволяет делать fine tune модели). Для хорошей похожести нужно минимум 7 фото, а лучше 15+. Параметры подбирались вручную.

  • (3) постфильтрация: мы отдаём пользовтелю порядка 40 фоток, но под капотом генерим 200+ и с помощью вспомогатеьной модели выбираем top40.

  • В продукте самое долгое - finetune, 4 часа долго, но что делать, в системе есть размен качества vs время, мы решили что всё что меньше 6 часов более менее ок (первая версия работала 12 часов, конкуренты от часа). Мы выкрутили ручку в качество. Считаю что это наше конкурентное преимущество.

  • Мы арендуем GPU на RunPod и гоняем там наш docker: там дешево, простой и понятный API. Мы не использовали готовые API в которые можно подсунуть чекпоинты потому что дальше всё равно есть кастомный постпроцессинг для которого лучше иметь GPU.

Тут нет универсального способа, есть много разных методик.

Для приложений есть вот такой сайт sensortower.com, он даёт ±2x верную оценку по приложениям в сторе. Если компания большая - есть crunchbase.

Ещё есть несколько косвенных тактик, например можно примерно прикинуть порядки используя Ad Transparency программы у Instagram, TikTok и Google, посмотреть какую рекламу закупают конкуренты + использовать данные о кампании и навыки математики.

Примерно на момент анализа рынка были 2 приложения зарабатывающих где-то около по $500К в месяц. Еще с 5-7 с доходом около $10-20К в месяц. (доход ≠ выручка)

Какой то hate speech.

Человек пилит в своё свободное время проект под лицензией MIT и может в нем делать всё что душе заблагорассудится.

Не нравится - форкни.

Зашел в репозиторий и поставил лайк.

Есть несколько UI, правда они для установки требуют минимальные навыки работы в консоли. Вот 2, как мне кажется, популярных
- простой Fooocs
- более гибкий комбайн Automatic1111

Для того что бы поиграться c генераций изображений нужна GPU на 6-8Гб видеопамяти.

Что угодно с getAbstract.
Agda, Idris и Coq — не языки для промышленной разработки.
Они больше представляют исследовательский интерес.

Мне всё понятно, но у меня Haskell бэкграунд.
Функциональщина — не сакральное знание, ее можно понять, например, по этой книжке с картинками.
Еще есть bitcode. При сборке приложения в итоговый бинарник добавляется кроме машинного кода промежуточный LLVM IR ассемблер.

После выпуска нового процессора можно уже написанные и существующие программы оптимизировать под новые «фишки» из bitcode. ABI при этом не меняется.
Bitcode используется около 4х лет для приложений в AppStore.
Про самую короткую программу

Ответ неправильный. Правило «implicit int» было полностью удалено из языка С в стандарте С99. Но даже в самом первом — «классическом» — стандарте С (ANSI/ISO C89/90) грамматически запрещались объявления с пустым decl-specifier-seq. То есть, пользуясь правилом «implicit int» вы могли написать объявление extern var; или const var;, но ни в коем случае не просто var;. Поэтому ни о каком main; в языке С не может быть и речи.
Более того, легальность использования идентификатора main для «посторонних» целей зависит от того, работаем ли мы в hosted evironment или в freestanding environment

Легальность такого хака, конечно, под вопросом. Но и GCC и Clang переваривают такой код. Правда выдают warning'и -Wimplicit-int и -Wmain.

Про fork

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

Какие например? Кроме буфера std::cout?

Про move и лямбду

Ответ странный: «компилятор не умеет с ней работать»? Шито? Компилятор все прекрасно умеет: он работает совершенно верно, в полном соответствии с правилами overload resolution.

Да. Он умеет работать с const Foo&&. Это корректная ситуация. Но кажется, это не очевидно с первого взгляда.

Я проверял с последним clang 7 и GCC 8 на godbolt.org.
Компилируется с warning'ами копилятором C (не С++).
  1. Зависит от реализации. Для поддержки исключений, на сколько я знаю, в стек кладутся дополнительные данные. Это ухудшает локальность. Не пробовал считать насколько это плохо.


  2. Нет совместимости с C. Если исключение полетит через функцию скомпилированную С компилятором, то буде плохо.


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



8-9. Ну никто не придумал лучшей реализации.


  1. Ну представим что у нас есть legacy проект на С. И мы начинаем кусочками переписывать его на C++. Нужно быть предельно внимательным, если исключение пролетит через старый не RAII код, будет беда.
Я тоже все не вспомню. Но вот ещё 3 из моего поста:
1. по сигнатуре функции невозможно понять какое исключение может вылететь из функции.
2. размер бинарного файла увеличивается за счёт дополнительного кода поддержки исключений.
3. нельзя выбрасывать исключения из деструкторов.

Из комментария выше ещё 3:
4. долгая раскрутка стека и не соблюдение принципа «не плати за то что не используешь».
5. несовместимость с «чужими функциями».
6. нелокальнось (код обработки ошибки может быть далеко от того места где она произошла).

Ещё из практики:
7. на некоторых платформах, например новом android ndk и clang нельзя полагаться на исключения между .so на версиях ниже 5.
8. необходимо генерировать `typeid` и экспортировать его из .so для всех типов Увеличивает время линковки.
9. если не соблюдать RAII, то исключения легко ведут к утечке ресурсов, появляются неявные выходы из функций.
10. исключения тяжело внедрять постепенно в legacy код, который изначально не написан exception safety.

Вот. Ровно 10. Хотя п7-8 это особенности реализации.
Современный мир устроен так, что чтобы оставаться на месте, надо интенсивно двигаться. А чтобы идти вперед, надо бежать. С учетом этого С++ идет назад относительно других. И мне просто обидно, что такое происходит.

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


С++ потихоньку вбирает в себя фичи которые прижились в других языках, старается не ломать то что уже есть и не замедлять производительность неиспользуемой функциональностью языка.
ИМХО — адекватный подход.


По пунктам:


1. Возможность выбирать между быстротой и безопасностью.

Пожалуйста, выбирай! кто ж мешает. Напиши class safe_int и дели на 0.


2. Выделять явно куски кода, где я хочу разных гарантий.

Кажется noexcept, [[nodiscard]], контракты и концепты как раз движение в эту сторону.


3. Иметь иерархическую модель обработки исключений.

Исключения не панацея. У них есть уйма минусов с которыми нужно считаться. Не всем они подходят.

Рад что моя статья понравилась и побудила написать этот пост!

Считаю что «фатализм» это удобно. В новых мейнстримных языках go/rust/swift есть механизмы для unrecoverable error.

Да. Можно свести все к исключениям. Но, кажется, понятности это не добавит, лишь повлечёт неявную логику для таких исключений в catch(...).
Наверно я погорячился с «плохо».
Могу с натяжкой придумать 2 тонкости.

1. Как уже упоминали ранее, деструктор не будет вызван, но для делегирующего конструктора будет.
2. Это может приводить к boilerplate при написании биндингов для не RAII примитивов. Например, когда есть объект владеющий двумя файловыми дескрипторами.
Но это все мелочи.

Интересно, но похоже `std::expected` никак не поможет сообщить об ошибке из конструктора.

И как же?
На сколько я знаю, там есть подобие [nodiscard] и предупреждение в switch о необработанных case. Но это не панацея.

Конечно должен. Сложно написать сразу без багов код, который нельзя скомпилировать.
Не досмотрел, поправил.
Зато с С++ никогда не скучно.
1

Information

Rating
Does not participate
Registered
Activity