Telegram Web Link
Channel created
Открытие вчерашнего вечера: pdbpp, т.е. pdb++ - еще один python-дебаггер с автодополнением и прочими обязательными фичами. Я обычно пользовался ipdb, но у pdbpp есть одна исключительно полезная фича - он заменяет дефолтный pdb в интеграциях. Значит, можно, например, легко влезть дебаггером в падающий тест.
$ cat test_me.py
def test_something():
x = 5
assert False

$ pytest --pdb
======= test session starts =======
platform linux -- Python 3.6.6, pytest-5.1.2, py-1.8.0, pluggy-0.13.0
rootdir: /home/arseny/candy-store/adhoc
plugins: cov-2.7.1
collected 1 item

test_me.py F
>>>>>>> traceback >>>>>>>

def test_something():
x = 5
> assert False
E assert False

test_me.py:3: AssertionError
>>>>>>> entering PDB >>>>>>>

>>>>>>> PDB post_mortem (IO-capturing turned off) >>>>>>>
[11] > /home/arseny/candy-store/adhoc/test_me.py(3)test_something()
-> assert False
6 frames hidden (try 'help hidden_frames')
(Pdb++) x
5
(Pdb++)
Когда пишешь говнокод и немного стесняешься
Недавно в ods.ai случилось некоторое нашествие постов (например) почти по шаблону "подскажите самую крутую нейросетку для {узкая_задача}". Там в комментариях и родилась простая и понятная псевдоформула для подобных вопросов: sota(task, domain) ≈ sota(task, most_popular_domain) + sota(domain_dataset).

Иными словами, чтобы получить крутое решение на своей непопулярной подзадаче, нужно взять state of the art в задаче на более популярном домене (например, вместо детекции рук посмотреть подходы к детекции лиц) и закидать ее хорошими данными из своего домена.
pytorch до сих пор умеет удивлять неподготовленных
siberia.slides.html
4 MB
Слайды с моего выступления на сибирском датафесте
На Data Fest Siberia несколько раз обнаружил воспроизводимый способ задавать плохие вопросы из зала. Шаблон примерно такой:

Докладчик: у нас была маленькая команда, мало данных, не хватало железа, и еще какие-то проблемы. Превозмогая невзгоды, мы из говна и палок смогли собрать такой-то пайплайн, и он заработал! 🎉 Спасибо за внимание.
Слушатель: а почему вы не использовали SuperGAN, AlphaPlus RL и еще какие-то баззворды?
У меня был совершенно чудесный коллега, который обычно не читал статьи, а просматривал по диагонали, через 30 секунд восклицал "А, ну тут все понятно" и начинал имплементировать ровно то, что успевал уловить (и додумать) за это время. Эдакая платоновская пещера.

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

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

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

Все закончилось хорошо: советы более опытного в метрик лернинге человека и вдумчивое чтение матчасти помогли все починить и обучить (hard example mining рулит, если что). А мораль простая: если ты почему-то думаешь, что понимаешь как что-то работает, это совсем не всегда значит, что можно (высокомерно) игнорировать написанное умными людьми.
продуктовый computer vision со стороны: нужно читать свежие статьи c CVPR и ICCV и имплементировать моднейшие архитектуры
продуктовый computer vision изнутри: бля, опять инстаграм забанил все скраперы
Видел недавно образец карго-культа с привкусом ООП.

Дано: старый плохой код, состоящий из двух функций process и upload_to_s3, примерно 500 строк в сумме.
Задача: отрефакторить, в первую очередь сделать модульно и тестируемо.

Результат выглядел примерно так:

class AbstractProcessor: 
def __init__():
pass

@abc.abstractmethod
def process():
pass

@abc.abstractmethod
def upload_to_s3():
pass


class Processor:
def __init__():
super().__init__()

def process():
# 300 строк старого говна

def upload_to_s3():
# 200 строк старого говна


Monkey see, monkey do.
#мысли_из_душа

Придумал бесполезную метрику: соотношение yaml-кода (или где вы там храните свои конфигурации) к python-коду для одного ML эксперимента.

Если для каждого нового эксперимента нужно писать много кода и мало конфигурации, представляются такие варианты:

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

Такая двойственность делает метрику абсолютно бесполезной. А раз так, то это и не метрика, а просто херня какая-то.
Если бы я стремился прославиться в computer vision тусовке, я бы начал с написания human-friendly обертки вокруг python-обертки вокруг OpenCV.

Понятно, что хардкорные плюсовики привыкли к нечитаемым ошибкам, но нам, нежным хипстерам, очень грустно от этих всяких *** SystemError: <built-in function> returned NULL without setting an error
Я сейчас на той стадии технической (не)зрелости, что довольно много думаю об абстракциях. Точнее, о нужном и допустимом уровне абстракции для разных задач.

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

Если подняться слишком высоко, то программирование превращается в шаманство. Трижды стукни в бубен в полнолуние, переодевшись в петуха, и тогда твои тесты позеленеют, а логистическая регрессия покажет точность 146%.

Хороший пример: https://habr.com/ru/post/471282/#comment_20748088. Статья уже слегка отредактирована, потому перескажу вкратце историю (можно частично восстановить из комментариев): чувак вооружился сверхвысокоуровневой абстракцией fastai, забил на train/val/test разбиение (библиотека все сделает за него), получил близкие к идеальным результаты и начал хвастаться, как легко превзойти предыдущий state of the art.

Кажется, что опыт именно тем и полезен: со временем инженер примерно чувствует нужный уровень абстракции для задачи. Настоящие сеньоры - те, чьи абстракции протекают не сразу.

Если вы знаете, что почитать на эту тему - напишите мне (@arsenyinfo) и посоветуйте!
Классический шаблон вопроса на собеседовании: "у тебя есть неатомарный кусочек софта [примерное описание этого софта], и он работает плохо [сырое описание проблемы]. как исправить?". Например, в случае deep learning собеседования вопрос может быть сформулирован так: "у тебя есть пайплайн обучения сети, но она обучается слишком медленно. как ускорить?"

Если собеседуемый претендует на не совсем junior роль, от него ожидаются встречные вопросы. Например: что такое медленно? как это определили? почему это плохо и важно? В случае с обучением модели кто-то может иметь в виду просто некую неэффективность пайплайна в вакууме, а кто-то - несоответствие конкретным хотелкам (нужно обновлять модель ежедневно, а она тренируется три дня).

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

Дано: модель для сегментации, на выходе логиты. Человек, который должен прикрутить ее к продакшен приложению, слышал, что выход сегментации должен быть [0..1], а значит, он должен добавить какой-то постпроцессинг.

После расследования обнаружилось, что постпроцессинг делался примерно так: std::clamp(x, 0, 1).
Два дня боролся с утечкой памяти в доставшемся по наследству deep learning пайплайне. Оказалось, что на самом деле их две, а ведь в языках с автоматической очисткой памяти это довольно редкий зверь.

Первый лик нашелся относительно легко при помощи pympler. Дальше началось странное, потому что pympler не видел новые объекты, а память потихоньку утекала - медленно, но верно.

Для победы пришлось отбросить ковбойский подход "ща я тут дебаггером влезу, на код гляну и все быстро пойму" и перейти к divide and conquer:
- беру кусок пайплайна;
- вместо настоящего выполнения кэширую;
- смотрю, течет или нет.

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

Пришлось добавить статистики и вместо графиков смотреть на p-value, что проще и не требует умственных усилий. Так удалось локализовать проблему до одной функции, изолировать ее и найти проблему: подвыборка из тензора по индексам оставляла неявный референс.

Мораль такая: даже если ты не разбираешься в проблеме, декомпозиция и базовая автоматизация (инструменты, склеенные скотчем) помогут.
Полгода назад я выступал на Bulbacon и, отвечая на вопросы, сказал что-то вроде: "Через год называть себя дата сайнтистом станет зашкваром", подразумевая дурную славу некачественного кода в духе "я тут чего-то нафигачил в jupyter notebook" и намекая, что всем машинлернерам стоит учиться писать более или менее чистый код.

Тем временем в Python developers survey 2019 появился провокационный вопрос.
Обнаружил сервис для не самых умных, но не безответственных unix-пользователей.

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

Собственно, для этого и нужен explain shell. Пример с классическим sudo rm -rf.
2025/07/05 06:10:53
Back to Top
HTML Embed Code: