«Одна вещь, которой не хватает в открытом исходном коде, — это документация», — Аноним.

Этим летом я начал работать техническим писателем с FluxML в рамках Julia Season of Contributions, и, как и ожидалось, этот опыт сильно отличался от написания кода.

В начале лета я решил устроиться техническим писателем, который включал в себя написание документации и руководств по машинному обучению. В то же время я изучал Julia, и экосистема FluxML казалась мне идеальным местом. Я подал заявку на вакансию через Google Season of Docs, но, к сожалению, не смог попасть из-за ограниченного количества вакансий. К счастью, Julia Language решил финансировать меня в течение следующих нескольких месяцев для работы над FluxML в рамках Сезона вкладов Джулии!

В следующем блоге я поделюсь своим опытом и работой, которую я проделал в рамках Сезона вкладов Джулии!

Доктесты

В документации Flux отсутствовали doctests, из-за чего примеры кода устаревали после каждого выпуска. Кроме того, многие текущие примеры, которые, как считается, охватывались doctests, уже устарели.

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

Flux.jl теперь есть doctests, написанные для каждого общедоступного API, и большая часть примеров уценки также охватывается этими doctests. Некоторые из этих изменений еще не объединены, но они находятся на рассмотрении!

Отсутствующие строки документации

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

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

Помимо Flux, аналогичная проблема была и у других пакетов под FluxML. Некоторые из этих пакетов, такие как NNLib.jl, Zygote.jl, Optimisers.jl, Functors.jl и MLUtils.jl (под JuliaML), также упоминались в документации Flux. Отсутствующие строки документации в этих пакетах были переданы в документы Flux, что привело к еще большему количеству отсутствующих строк документации.

Все отсутствующие строки документации теперь добавлены в соответствующие руководства и функции, в том числе в другие пакеты FluxML!

Сломанная документация

Документация будет неполной без перекрестных ссылок, и замечательный пакет документации Julia упрощает эту задачу. В Flux есть эти перекрестные ссылки, но некоторые из них ведут в никуда.

Кроме того, некоторые строки документации отображались в руководстве неправильно. Эти экземпляры неработающей документации были исправлены, и после объединения PR пользователи больше не должны видеть 404 страниц или необработанных строк документации!

CI/CD

Работа с документацией, доступной для пользователей, обеспечивается службой CI/CD, которая поддерживает развертывание этой документации и доступность для пользователей в любое время. Для проектов с открытым исходным кодом также характерно открывать рецепты развертывания.

В экосистеме FluxML были небольшие проблемы с этой CI-службой. Zygote.jl провел доктесты дважды, затрачивая вдвое больше времени и ресурсов CI, а Flux.jl, с другой стороны, указал разные версии Julia в своем файле CI и make.jl.

Кроме того, Documenter.jl позволяет пользователю создавать предварительный просмотр документации для запросов на вытягивание, а Flux.jl настроил бота для облегчения этого, но он долгое время не работал. Кроме того, эти предварительные просмотры документации собраны в ветке gh-pages, которая становилась очень громоздкой и должна была быть очищена с помощью автоматизированного рабочего процесса. Я перезапустил этого бота и добавил рабочий процесс для периодической очистки этих сгенерированных превьюшек!

Наконец, я также исправил некоторые проблемы в документации Optimisers.jl, которые приводили к сбою его CI.

Экосистема FluxML

Экосистема FluxML, помимо Flux.jl, также имела некоторые проблемы с документацией. Например, у Optimisers.jl и Zygote.jl были недостатки в наборе CI, которые обсуждались выше. Точно так же Functors.jl и MLUtils.jl имели неработающую документацию, отсутствующие строки документации и неполное руководство, которое также подробно обсуждалось выше!

Наконец, страницы «экосистемы», представленные на веб-сайте и в документации Flux, были не синхронизированы и содержали избыточную информацию. Страница «экосистема» была полностью переработана и дополнена последними достижениями, связанными с машинным обучением в Julia!

Незначительные изменения кода

Да! Изменения в документации также сопровождались небольшими изменениями кода!

Публичный и внутренний API Flux очень сложно отличить, если вы новичок в кодовой базе; следовательно, новичкам было трудно ориентироваться в этом. API был прояснен путем удаления внутренних экземпляров из документации и добавления подчеркивания перед внутренним API.

Кроме того, я также наткнулся на ошибку при написании доктестов для tversky потерь. Потеря tversky имеет два параметра, α и β, и Flux внутренне вычисляет значение α как 1-β. Убыток математически определяется как 1-tversky index, а tversky index математически определяется как:

S(P, G; α, β) = |PG| / (|P G| + α|P \ G| + β|G \ P|)
где α и β контролируют величину штрафов для FP и FN соответственно.

Flux реализует потерю следующим образом:

1 — sum(|y .* ŷ| + 1) / (sum(y .* ŷ + β*(1 .- y) .* ŷ + (1 — β)*y .* (1 .- ŷ)) + 1)

со следующим кодом -

Обратите внимание, как термин (1 .- y) .* ŷ (ложные срабатывания) умножается на β, тогда как его следует умножать на α (то есть 1-β). Точно так же термин y .* (1 .- ŷ) умножается на α (то есть 1-β), тогда как его следует умножать на β.

Эта деталь приводит к тому, что функция потерь ведет себя не так, как описано в документации. Например -

Здесь потеря для ŷ_fnp, y должна была быть больше, чем потеря для ŷ_fp, y, поскольку потеря должна придавать больший вес или наказывать ложные отрицания (по умолчанию β равно 0.7; следовательно, это должно придавать больший вес FN), но происходит прямо противоположное.

Изменение реализации потери дает следующие результаты -

что выглядит правильно!

(Эта ошибка еще не была подтверждена кем-то, кроме меня, и исправление все еще находится на рассмотрении.)

Раздел «Начало работы»

Flux содержит множество руководств и примеров, но они разбросаны по всему миру, и в них очень сложно ориентироваться. Текущие разделы «Начало работы», «Обзор» и «Основы» содержат ценную информацию для начинающих, но эта информация разбросана по этим трем разделам.

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

Я начал работать над этим разделом, и два обширных руководства уже добавлены в качестве PR: одно по линейной регрессии (с Flux и без него) и одно по логистической регрессии (с Flux и без него). Эти PR в настоящее время пересматриваются и должны быть объединены в ближайшие недели.

Я отлично провел время, помогая Flux и его соседним репозиториям, и я надеюсь продолжать вносить свой вклад с той же скоростью. Я также многому научился, в том числе тому, что добавление документации требует больше обсуждений, чем добавление кода.

Эта работа была бы невозможна без моего наставника @DhairyaLGandhi и множества других сопровождающих FluxML (@ToucheSir, @mcabbott, @CarloLucibello, @darsnack). Они были очень терпеливы с моими вопросами и грязными пиарами😆

Приложение

Пулл-реквесты

Flux.jl

Zygote.jl

Оптимизаторы.jl

Functors.jl

MLUtils.jl

Вопросы/обсуждения

Flux.jl

Zygote.jl

Бонус