Почему я больше не рекомендую Julia

в 12:17, , рубрики: Julia, визуализация данных, математические вычисления, Программирование, статистика, языки программирования
Почему я больше не рекомендую Julia - 1

Много лет я пользовался языком программирования Julia для преобразования, очистки, анализа и визуализации данных, расчёта статистики и выполнения симуляций.

Я опубликовал несколько опенсорсных пакетов для работы с такими вещами, как поля расстояний со знаком, поиск ближайших соседей и паттерны Тьюрингатакже с другими), создавал визуальные объяснения таких концепций Julia, как broadcasting и массивы, а ещё применял Julia при создании генеративной графики для моих визиток.

Какое-то время назад я перестал пользоваться Julia, но иногда мне задают о нём вопросы. Когда люди спрашивают меня, я отвечаю, что больше не рекомендую его. Мне подумалось, что стоит написать, почему.

После многолетнего использования Julia я пришёл к выводу, что в его экосистеме слишком много багов корректности и сочетаемости, и это не позволяет использовать этот язык в контекстах, где важна корректность.

По моему опыту, Julia и его пакеты имеют наибольшую частоту серьёзных багов корректности из всех использованных мной программных систем, а ведь я начинал программировать с Visual Basic 6 в середине 2000-х.

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

Вот проблемы корректности, о которых я составил отчёты:

Вот похожие проблемы, о которых сообщали другие люди:

Я сталкивался с багами подобного уровня серьёзности достаточно часто, поэтому это заставило меня подвергнуть сомнению корректность любых вычислений умеренной сложности на Julia.

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

Иногда проблемы возникают из-за несочетаемых друг с другом пакетов, в других случаях к неожиданному сбою приводит неожиданное сочетание возможностей Julia внутри одного пакета.

Например, я выяснил, что евклидово расстояние из пакета Distances не работает с векторами Unitful. Другие люди обнаружили, что функция Julia для запуска внешних команд не работает с подстроками. Кто-то выяснил, что поддержка отсутствующих значений Julia в некоторых случаях ломает матричное умножение. И что макрос стандартной библиотеки @distributed не работал с OffsetArray.

OffsetArray вообще оказался серьёзным источником багов корректности. Пакет предоставляет тип массива, использующий гибкую функцию настраиваемых индексов Julia, позволяющую создавать массивы, индексы которых не обязаны начинаться с нуля или единицы.

Их использование часто приводит к доступу к памяти out-of-bounds, с которым вы могли встречаться в C или C++. Если повезёт, это приведёт к segfault, а если нет, то результаты будут неверными без сообщений об ошибках. Однажды я нашёл баг в ядре Julia, который может привести к доступу к памяти out-of-bounds, даже если и пользователь, и создатели библиотеки написали корректный код.

Я отправил множество отчётов о проблемах индексации в организацию JuliaStats, занимающуюся обслуживанием статистических пакетов наподобие Distributions, от которого зависят 945 пакетов, и StatsBase, от которого зависят 1660 пакетов. Вот некоторые из них:

Первопричиной этих проблем является не сама индексация, а её совместное использование с другой фичей Julia под названием @inbounds, позволяющей Julia удалять проверки границ при доступе к массивам.

Пример:

function sum(A::AbstractArray)
    r = zero(eltype(A))
    for i in 1:length(A)
        @inbounds r += A[i] # ← 🌶
    end
    return r
end

Показанный выше код выполняет итерации i от 1 до длины массива. Если передать массив с необычным диапазоном индексов, код выполнит доступ к памяти out-of-bounds: операции доступа к массив аннотированы @inbounds, что убирает проверку границ.

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

Почему я больше не рекомендую Julia - 2

Эту проблему уже устранили, однако вызывает беспокойство то, что @inbounds можно так легко использовать неверно, что приводит к незаметному повреждению данных и некорректным математическим результатам.

По моему опыту, подобные ошибки касаются не только математической части экосистемы Julia.

Я сталкивался с багами библиотек в процессе выполнения повседневных задач, например, при кодировании JSON, отправке HTTP-запросов, использовании файлов Arrow совместно с DataFrames и редактировании кода Julia в реактивной среде ноутбуков Pluto.

Когда мне стало интересно, репрезентативен ли мой опыт, множество пользователей Julia поделилось со мной похожими историями. Недавно стали появляться и публичные отчёты о подобном опыте.

Например, в этом посте Патрик Киджер описывает свои попытки использовать Julia для исследований машинного обучения:

На Julia Discourse довольно часто встречаются посты «Библиотека XYZ не работает», на которые следуют ответы одного из мейнтейнеров библиотеки: «Это апстрим-баг в новой версии a.b.c библиотеки ABC, от которой зависит XYZ. Мы запушим исправление ASAP».

Вот каким был опыт Патрика по выявлению бага корректности (выделено мной):

Чётко помню момент, когда одна из моих моделей Julia отказывалась обучаться. Я много месяцев пыталась заставить её работать, пробуя все трюки, которые мог придумать.

В конце концов, я нашёл ошибку: Julia/Flux/Zygote возвращал некорректные градиенты. После того, как я потратил так много энергии на указанные выше пункты 1 и 2, на этом пункте я просто сдался. Спустя ещё два часа разработки я успешно обучил модель… в PyTorch.

В обсуждении этого поста другие пользователи писали, что у них тоже был похожий опыт.

@Samuel_Ainsworth:

Как и @patrick-kidger, я пострадал от багов с некорректными градиентами в Zygote/ReverseDiff.jl. Это стоило мне недель жизни и заставило меня серьёзно пересмотреть уровень своего опыта во всей системе Julia AD. За все годы работы PyTorch/TF/JAX я ни разу не столкнулся с багом некорректных градиентов.

@JordiBolibar:

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

Учитывая чрезвычайную обобщённость Julia, не очевидно, можно ли решить проблемы корректности. В Julia нет формального понятия интерфейсов, в generic-функциях часто в пограничных случаях семантика не указывается, а природа самых общих косвенных интерфейсов не сделана чёткой (например, в сообществе Julia нет согласия по поводу того, что является числом).

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

Например, в то время, когда экосистема машинного обучения Julia была ещё более незрелой, один из создателей языка с энтузиазмом рассказывал об использовании Julia в продакшене для беспилотных автомобилей:

Почему я больше не рекомендую Julia - 3

И хотя с тех пор, как я перестал быть активным участником, отношение к этому могло измениться, следующая цитата ещё одного создателя языка, произнесённая примерно в то же время, стала хорошей иллюстрацией разницы восприятий (выделено мной):

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

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

Примеры:

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

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

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

Автор:
PatientZero

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js