Pull to refresh
68
0
Roman Samarev @rssdev10

User

Send message

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

Если предстоит заниматься научными вычислениями или изобретать новые математические методы, то ответ да, однозначно надо изучать Julia. В остальных случаях неоднозначно. Но как язык со своими инструментами разработки Julia довольно приятна.

За последние 4 года и фреймворк Genie успел выйти в свет. Вместе с расширением VS Code для генерации приложений - https://marketplace.visualstudio.com/items?itemName=GenieBuilder.geniebuilder

А также, при создании сервисов, сейчас очень внимательно стоит посмотреть на https://github.com/JuliaComputing/OpenAPI.jl и генераторы клиента - https://openapi-generator.tech/docs/generators/julia-client/ и сервера - https://openapi-generator.tech/docs/generators/julia-server/ по спецификации OpenAPI. На основании которой также можно сгенерировать документацию и формы Swagger.

Проблема, что для того чтобы пересадить людей с Питона на Джулию

Первый же вопрос - а нужно ли это делать?...

Структура ЯП в области DS/ML/научные исследования - это довольно тёмный вопрос. Не надо думать, что все тут знают и используют Python. Стоит ли переносить на что-то проекты с R? Не факт. С Matlab? Если только по санкционным или лицензионно/экономическим причинам. Переносить готовые проекты с них на Python? Это вряд ли.

В бизнес-задачах по аналитике и прогнозированию устойчивый тренд - машинное обучение без программирования. Всякие Amazon SageMaker Canvas и пр. Тут никакой ЯП не нужен. Всё визуально через формочки.

В нише научных исследований, где занимаются статистической обработкой результатов, нужны "типовые калькуляторы", а не язык программирования как таковой. И даже если какой-нибудь Python используется, то на минимально уровне для решения вполне типовых задач, решение которых выглядит примерно одинаково везде. С одинаковыми же именами функций стандартных библиотек. Безразлично какой ЯП.

Ниша, где требуется создание новых методов анализа информации и новых алгоритмов (биоинформатика, математика) - это вообще не ниша Python, хотя его и пытаются навязывать. Если кто-то здесь говорит, что он пишет на чистом Python, почти наверное, недоговаривает, что по факту пишет на каком-нибудь C++, а на Python изредка приделывает обёртки. И, как раз, здесь и есть ниша Julia с её основным аргументом - один язык для всего и без проблем с производительностью (как в части скорости написания кода, так и в части исполнения кода).

С другой стороны, любой ЯП живёт только до тех пор, пока есть люди, готовые им пользоваться. И тут мы знаем и пример с Коболом, на котором до сих пор работают некоторые программы и до сих пор требуются программисты для поддержки (потому как те кто писал код уже буквально вымерли). И пример с Паскалем, на котором совсем недавно в наших университетах учили абсолютно всех, но последние лет 20 он крайне мало кому был нужен.

При этом, за 10-20 лет рельеф ЯП и библиотек меняется довольно сильно. Проектов создаётся много. Но много ли из них выживает 3-5 лет, даже если нахватали звёзд на github? Исследовательские проекты, часто, вообще пишут под одну публикацию. Год спустя проект никому не нужен. Поддерживать старый код не надо.

Да и программисты - не вечны. За 20 лет трудовой деятельности мало кто остаётся программистом и продолжает поддерживать старый код. Ну а молодёжь после университетов вообще без проблем переучится на что угодно реально востребованное, и совместимость библиотек 1 в 1 им тоже не нужна.

PS: перенос библиотек с сохранением интерфейсов один в один возможен только на близких языках. Перенос же библиотеки на ЯП с другими концептами, но 100% сохранением интерфейса - это потенциально неэффективный по исполнению или визуально громоздкий код.

NumPy в Julia точно не нужна, поскольку векторные операции - часть её синтаксиса. А оптимизация циклов же выполняется компилятором. Касаемо "портов" - вообще-то она разработана именно под математику и научные вычисления. И тащить в неё библиотеки с чужим синтаксисом - не факт, что нужно. Но если очень надо, можно и PyCall вызвать. В целом, код на Julia будет компактнее, чем Python, поэтому тащить из него API библиотек как есть - это создавать ненужные надстройки.

Вместо PyTorch можно использовать родную Flux.jl, либо оптимизированную ONNXRuntime.

Люди занимающиеся наукой и исследованиями используют пайтон.


Сейчас уже есть возможность почти безболезненно от него отказаться в этой области. Джулийный мир развивается довольно активно.

Julia собирает все пакеты в локальную директорию ~/.julia. Если один раз пакет закачан, второй раз менеджер пакетов за ним не полезет. А вот если будет добавление нового пакета с новой зависимостью по тем, которые были установлены ранее, то да, потребует докачать. И будет хранить обе версии.

Артифакты и наборы данных закачиваются туда же в ~/.julia/artifacts и ~/.julia/datadeps/, но произойдёт это тогда, когда будет запущен код из пакетов. Собственно, если надо гарантировать что всё закачано, надо либо глобально для всех пакетов запустить встроенные тесты, либо запустить тесты по своей программе, чтобы закачать только то, что нужно.

По-хорошему, директория ~/.julia вполне переносима с машины на машину.

Касаемо juliapackages.com - для этого есть механизм реестров. Разворачивайте в своей сети свой собственный LocalPackageServer и делайте с ним что хотите - полную копию внешнего реестра или только то, что нужно. Официальный репозиторий с реестром - https://github.com/JuliaRegistries/General

using BenchmarkTools

function isPrime(num::Int64)::Bool
    (num == 2) && return true;
    (num <= 1 || num % 2 == 0) && return false;

    @simd for i = 3:2:round(Int, sqrt(num))
        (num % i == 0) && return false;
    end
    return true;
end

function measure()
    for i = 1:10_000_000
        isPrime(i);
    end
end

@benchmark measure()

versioninfo()

Куда же без Julia… Код выше выдаст оценку времени в REPL.


Впрочем, есть оптимизированный алгоритм расчёта простых чисел, который почти в 3 быстрее. https://github.com/JuliaMath/Primes.jl/blob/master/src/Primes.jl#L144

Добавьте что ли Julia в опрос… Самый современный язык для математики, а в списке его нет....

Главный недостаток Stanford CoreNLP — двойное лицензирование. Если хотите использовать в коммерческом проекте, лицензия обойдётся >$100k в год. Поэтому, если Java NLP, то, скорее, OpenNLP. С перспективой самостоятельного обучения моделей. Впрочем, OpenNLP работает намного быстрее и требует меньше машинных ресурсов в силу куда более простой архитектуры.

Для Julia здесь очень много кода… Варианты, которые более вероятно встретятся:


mandelbrot(a) = reduce((z, _) -> z^2 + a, 1:50 )

function mandelbrot(a)
    reduce((z, _) -> z^2 + a, 1:50 )
end

И даже вариант с блоком do..end в рубийном стиле:


mandelbrot(a) = reduce(1:50) do z,_
    z^2 + a
end

Julia тяготеет к функциональному стилю программирования. Поэтому конструкции map/filter/reduce и производные от них здесь используются очень широко. Плюс векторизация вычислений везде где можно. Всё это позволяет писать код очень компактно.


а что же они begin не ввели? так и паскаль переизобретут.

Касаемо do, begin, end. Эти конструкции позволяют сохранять человечность языка программирования. Естественно, можно даже переменные как в Perl называть именами $', $`, $_ и пр. И наделать каких-нибудь специальных знаков для разделения блоков. Но программа, хотя и пишется для работы машины, в первую очередь должна быть написана так, чтобы люди легко могли понять этот код. К слову, как и в Ruby, у Julia слово return является опциональным, поскольку любой метод всегда возвращает результат последней операции. И поэтому, слово return пишется тогда, когда без него не обойтись, либо для улучшения читаемости. Добавлю, что и тип аргументов в Julia пишется почти как и в Паскале.


mandelbrot(a::Number) = reduce((z, _) -> z^2 + a, 1:50 )

зачем тут end если табуляцией подпрограмма обосабливается

Табуляции или пробелы расставит автоформатирование. Задача программиста — думать об алгоритмах, а не о том, какую фигуру операторами кода на листе нарисовать.

Статья очень кособокая при весьма амбициозном заголовке. Очевидный современный тренд — переезд Data Science на Julia. Лишь несколько примеров. Лаборатория Stanford Intelligent Systems Laboratory полностью переехала на Julia — https://github.com/sisl. Причём, проекты есть весьма интересные, занимаются они, в том числе, автономными автомобилями. Активный проект из Berkeley — https://bids.berkeley.edu/research/data-science-software-stack-julia. MIT, с их https://julia.mit.edu/, вообще уже ни о чём, кроме Julia, не думают. И во всех их проектах вполне можно поучаствовать.

Оптимальный вариант сейчас для первого языка — Julia. Простая, современная, без ООП, но с типизацией. При этом синтаксически гибкая и быстрая в исполнении. Самое замечательное то, что на Julia очень легко учить алгоритмам. Хочешь — сортировку пиши, хочешь — кластеризацию векторов, хочешь — операции над тензорами. И всё чисто на Julia. И это не код "только для демонстрации", как в интеграционных языках, а код, который можно реально использовать. Для школьников и студентов она хороша тем, что любые расчётно-иллюстративные работы могут быть сделаны именно на Julia. Причём, переход с неё на низкоуровневые языки не будет вызывать когнитивный диссонанс, как в случае чистых интеграционных языков в качестве первого.

Напрямую в строке — только зная индекс начала UNICODE-символа. Но можно преобразовать её в массив, после чего работать с символами позиционно.


julia> str = "строка"
"строка"

julia> str[2] # пытаемся взять второй байт, а он - часть первого символа
ERROR: StringIndexError("строка", 2)
Stacktrace:
 [1] string_index_err(::String, ::Int64)

julia> collect(eachindex(str)) # получаем все допустимые индексы
6-element Array{Int64,1}:
  1
  3
  5
  7
  9
 11

Однако, можно сделать:


julia> ar = collect("строка")
6-element Array{Char,1}:
 'с'
 'т'
 'р'
 'о'
 'к'
 'а'

julia> ar[2:4]
3-element Array{Char,1}:
 'т'
 'р'
 'о'

Есть пакет https://github.com/JuliaString/Strs.jl и целая группа пакетов для работы со строками https://github.com/JuliaString


julia> using Strs
[ Info: Precompiling Strs [7bddbee9-b4ee-5d4f-bf0b-c84b4398bbf6]

julia> str = Str("строка")
"строка"

julia> str[1]
'с': Unicode U+0441 (category Ll: Letter, lowercase)

julia> str[2:3]
"тр"

Embeddings по структуре довольно простая:
https://github.com/JuliaText/Embeddings.jl/tree/master/src


Собственно, надо реализовать их интерфейс и обернуть код, который я привёл выше в секции Transformers.jl. С этого можно и начать. Дальше, надо будет аккуратно в load_embeddings(BERT) вписать код загрузки наборов данных.


#use wordpiece and tokenizer from pretrain
const wordpiece = pretrain"bert-uncased_L-12_H-768_A-12:wordpiece"
const tokenizer = pretrain"bert-uncased_L-12_H-768_A-12:tokenizer"
const vocab = Vocabulary(wordpiece)

const bert_model = gpu(
  FromScratch ? create_bert() : pretrain"bert-uncased_L-12_H-768_A-12:bert_model"
)
Flux.testmode!(bert_model) 

Ну и, надо поковыряться с lazy-активацией библиотеки Transformers. В общем-то, думаю, всё. Математики там точно нет. Если что, думаю, что товарищи из Transformers помогут.

В StringDistances.jl, в целом, всё хорошо. Но когда размерность сравниваемых списков строк становится большой, придётся делать внешние оптимизации (сортировки и пр.) и, иногда, просто выдёргивать код из библиотеки. Впрочем, то же верно и для обычных Distances.jl. Если же есть множественные сравнения со списками >10^4, то надо хранить промежуточные результаты. Например, в косинусной мере, предварительно подсчитанные нормы для списка векторов, ускоряют вычисление на порядок. Но да, формулу надо разобрать на части.


Embeddings.jl позиционируется как унифицированная библиотека. Но Transformers.jl — более совершенный метод векторизации. И в состав Embedings не входит. К слову, работа по его интеграции технически не сложная. Но вопрос — кто бы за это взялся. Авторы Transformers, когда писали свой пакет, не ориентировались на Embedings.jl вообще. Потому, некоторые части надо немного переписать, а не просто обернуть (подгрузка наборов данных). Но зато, эту работу вполне может осилить начинающий в Julia.
Ну и, в очередной раз обращаю внимание на то, что все Embeddings очень прожорливы к оперативной памяти. 16ГБ — минимально рекомендуемы размер для экспериментов. Меньше — уже будут возникать проблемы. Либо словари будут маленькими, либо перед запуском, надо выгружать всё, включая браузеры.


Ну и на счёт статей, в целом, думаю, что эту статью можно было бы разбить на 4-5 фрагментиков по пакетам отдельно, но методичка нужна сейчас, а времени на подготовку отдельных мелких заметок надо затратить сильно больше. Пока об NLP писать не буду.

Возможно, что просто никто не хотел разбираться. Ставили через https://github.com/JuliaPy/Conda.jl


Но в любом случае, DataFrames быстрее.


PS: Если PyTorch заведётся из под Julia, то это лишний аргумент проектировать продукты именно на Julia, постепенно заменяя питоновские куски.

Нашел стек. Это была машинка с CentOS 7, но что-то подобное я ловил и на MacOS. Именно проблема с некоторыми питоновскими библиотеками в их зависимостях libstdc++. Возможно, это можно исправить полной пересборкой на своей платформе, но кому же эта красота нужна....


Возможно, надо править пути поиска или делать ссылки, но, тоже, не слишком интересное занятие. Тот код просто вычистили от pandas.


Resolving package versions…
loaded
ERROR: LoadError: LoadError: LoadError: InitError: PyError ($(Expr(:escape, :(ccall(#= /home/ml/.julia/packages/PyCall/RQjD7/src/pyeval.jl:39 =# @pysym(:PyEval_EvalCode), PyPtr, (PyPtr, PyPtr, PyPtr), o, globals, locals))))) <class 'ImportError'>
ImportError("/usr/bin/../lib64/libstdc++.so.6: version `GLIBCXX_3.4.21' not found (required by /home/ml/anaconda3/lib/python3.6/site-packages/pandas/_libs/window.cpython-36m-x86_64-linux-gnu.so)",)
File "/home/ml/.julia/packages/PyCall/RQjD7/src/pyeval.jl", line 2, in const Py_file_input = 257
File "/home/ml/anaconda3/lib/python3.6/site-packages/pandas/init.py", line 42, in from pandas.core.api import *
File "/home/ml/anaconda3/lib/python3.6/site-packages/pandas/core/api.py", line 10, in from pandas.core.groupby.groupby import Grouper
File "/home/ml/anaconda3/lib/python3.6/site-packages/pandas/core/groupby/init.py", line 2, in from pandas.core.groupby.groupby import (
File "/home/ml/anaconda3/lib/python3.6/site-packages/pandas/core/groupby/groupby.py", line 49, in from pandas.core.frame import DataFrame
File "/home/ml/anaconda3/lib/python3.6/site-packages/pandas/core/frame.py", line 74, in from pandas.core.series import Series
File "/home/ml/anaconda3/lib/python3.6/site-packages/pandas/core/series.py", line 3978, in Series._add_series_or_dataframe_operations()
File "/home/ml/anaconda3/lib/python3.6/site-packages/pandas/core/generic.py", line 8891, in _add_series_or_dataframe_operations
from pandas.core import window as rwindow
File "/home/ml/anaconda3/lib/python3.6/site-packages/pandas/core/window.py", line 36, in import pandas._libs.window as _window
Да, я его как раз и пробовал. Но для меня пока и процесс компиляции, и результат оказались довольно тяжеловесными. Надеюсь, что компилятор будет постепенно совершенствоваться.

Это не сложно делается. На тестовом сервисе мы это отработали. Но в статью, пока, не готов оформить. Хотелось бы ещё мелочи с докером и HTTP.jl вычистить. А вообще, разбирались с этим тут: https://discourse.julialang.org/t/packagecompiler-sockets-web-app/28793


Там есть ссылки на проектик, который я использую как полигон. Но, хотелось бы его почистить перед тем, как статью делать.

Information

Rating
Does not participate
Registered
Activity