Pull to refresh

Comments 16

Спасибо за статью! Было бы интересно почитать о работе с ML.NET в формате «для чайников». Если у вас найдутся время и желание писать такое, конечно.
Спасибо! Желание есть, время буду искать. Практика показывает, что лучше всего понимаешь то, что пытаешься объяснить другим )))
Linq. Они намного удобнее, чем List Comprehension (LC) в Питоне.

Так в ML у вас pandas / numpy стек должен быть, и list comprehensions в норме в коде вообще не должны встретиться.

Интересно, кто как встраивает Python-код в свои проекты на .Net. Опишите свои сценарии и ощущения от них в комментариях, пожалуйста.

Микросервисы. Однажды был вариант, где из другой инфраструктуры Python дергали через баш как скрипты — после этого точно микросервисы.

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

Очень спорное утверждение. Scientific Python stack позволяет писать хорошо векторизированный код очень легко, а C# с ним по перфомансу никогда не сравнится.
Спасибо за ваш кейс.

В основном соглашусь — Pandas/Numpy позволяют многое легко и элегантно векторизовать. При этом код получается простой и производительный. Но такими кейсами все не ограничивается. По крайней мере у меня. Нередко, приходится фичи выводить на деревьях. Или тот момент, который я приводил в статье — когда в качестве фичи передается то, что классификатор выдал для предыдущих сэмплах. В таких случаях и векторизация ломается, и со списками приходится работать, и еще много чего нестандартного. Вот в таких случаях большая производительность чистого C#-кода заметна. Просто рабочий момент, на который обращается внимание, когда один и тот же код пишешь там и здесь.
Вот в таких случаях большая производительность чистого C#-кода заметна. Просто рабочий момент, на который обращается внимание, когда один и тот же код пишешь там и здесь.

Справедливо. Но тогда Python-код можно скомпилировать через numba и опять таки получить перфоманс, который в C# так просто не выжать.

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

Код я не смотрел, а в статье я такого почему-то не вижу.
Код я не смотрел, а в статье я такого почему-то не вижу.

В коде этой фичи сейчас и нет, а в статье — как раз в пункте о скорости:
В коде на Питоне пришлось отказаться от фич, которые были завязаны на то, какое решение по склейке было принято в прошлых предложениях — если подавать классификатору предложения по-одному, то общая скорость получится ниже плинтуса.


Насчет numba — какие преимущества и недостатки по сравнению с Cython на практике?
UFO just landed and posted this here
достаточно только проверить, по какую сторону от границы они
находятся.
Поиск таких границ метод опорных векторов осуществляет в два
этапа:

На основании чего здесь делается вывод о конце абзаца (между предложениями)?
Вы имеете в виду, на основании чего делает такой вывод алгоритм? Или аннотатор (т.е., я)? Я, в данном случае, смотрю на «геометрию» строк. В предыдущей строке только одно слово, заканчивается знаком препинания. Следующая строка достаточно длинная, начинается с заглавного символа. Это характерно для абзаца. В реальности, конечно же, я так не взвешиваю, а быстро вставляю символ "*" в начало строки и перевожу курсор к следующей.

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

Если же пруф, что абзац тут есть — то вот оригинальный фрагмент. Это фрагмент книги «Глубокое обучение на Python»
Т.е. если предложение тянется до правой границы, то переноса абзаца не будет? Есть ли в таком случае смысл переходить от логики к статистике?
Вот в другой встречающейся задаче по определению кодировки текста без статистики тяжело.
Т.е. если предложение тянется до правой границы, то переноса абзаца не будет? Есть ли в таком случае смысл переходить от логики к статистике?

Смысл есть как раз потому, что тексты бывают разные. Для данной задачи — с разной типичной длиной строки (разные шрифты, разное количество колонок). И как только окажется, что какой-то текст плохо обрабатывается — логические правила нужно подправлять. Когда их количество превышает определенное число — их поддержание становится очень трудозатратным. ML же сильно упрощает адаптацию к новым условиям.

И я бы не формулировал, что ML=статистика. Те же деревья решений (их тоже можно применить с минимальным изменением программы) — это уже больше похоже на логические правила. Очень большой набор правил.

Вот в другой встречающейся задаче по определению кодировки текста без статистики тяжело.

Не поверите, но эту (точнее, очень похожую — определение языка) задачу также решал без машинного обучения. Основа — подсчет количества уникальных для языка фрагментов (1..4 буквы и целых слов). Это если очень упрощенно. Но ML-подход опять-таки, позволяет решить её более качественно именно для тех текстов, которых у вас больше. Статистика текстов очень отличается в зависимости от вашей предметной области. Твиты и статьи из журналов имеют существенно отличающиеся языковые модели.
Подправлять правила несложно, есть же параметризация программ. Вопрос в их количестве. И поскольку я тоже, правда очень давно, решал аналогичую задачу (обрезанный по правому краю текст -> HTML), то не могу назвать несколько десятков правил (при практическом отсутствии вероятностых) стимулом перехода к стат.методам (или к деревьям, раз уж упомянули).

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

К чему я все это написал? Мне кажется, что задачка детектирования кодировки или даже языка выглядела бы гораздо нагляднее для демонстрации пользы от применения ML.
Несколько десятков правил — мне такое уже сложно поддерживать. Именно поэтому сейчас, когда освоил азы (как минимум) sklearn, пошел именно этим путем. У каждого свой порог, когда лучше отходить от логики жесткого алгоритма в ML. Например, подзадача восстановления разбитых жесткими переносами слов решалась без ML. Хотя, не исключено, что когда все процессоры будут квантовыми, и тут станет проще научить, чем запрограммировать. Просто удивительно, что творят нейросети с последовательностями символов — вот тут недавно скрещивал базу от гугла и пример переводчика для кераса: github.com/serge-sotnyk/seq2seq-compress. После такого начинаешь верить, что если есть достаточно данных и времени, то нейросеть можно обучить чему угодно…

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

Это действительно актуальная для многих задача. Но в общем виде она практически решена. Вот хороший список библиотек для Питона: stackoverflow.com/a/47106810/4884761

А задача постобработки PDF мне понравилась тем, что она пошла практически по классическому сюжету:

1. Посмотрели — не видно публичных готовых библиотек.
2. Собрали данные для обучения.
3. Проаннотировали.
4. Выбрали метрики качества.
5. Обучили бэйзлайн-решение. Так получилось, что оно удовлетворило по качеству. Это просто приятный бонус. Иначе нужен был бы этап 6.
6. Улучшаем качество.

Так получилось, что все необходимые компоненты уже есть и в .NET — поэтому была возможность еще и сравнить особенности решения и там, и там.

Где применение ML оправдано — каждый решает для себя сам. В данном случае, решая задачу уже не первый раз, я получил большее удовольствие от работы и большую уверенность в легкости поддержки. Поэтому мне показалось оправданным. Раньше, до того, как на практике закрепил навыки по ML, тоже часто предпочитал все сделать и настроить своими руками.
ML — молоток полезный, поэтому есть опасность уверовать, что все задачи вокруг суть гвозди :)
Основное отличие классического программирования в детерминированности: отлаженная программа дает 100% результат на исходных тестах. В ML всегда будет присутствовать вероятность ошибки (10% в вашем примере).
Если не брать вероятностных по своей сути задачи, то выбор идет между ценой ошибки и сложностью программирования.
Притягательность нейросетей в ощущении «магии», хотя бы и зная, что внутри нее неонка все та же неявно сформированная очень сложная статистическая функция(и), пробразующая входы в выходы.

С переносами как-то жестоко захардкоженно обошлись.
Явно же просматриваются случаи:


  • не-буквенные сочетания — дефис надо оставлять (8-800- / 223-322)
  • буква-Буква — дефис, наверное, надо оставлять (вряд ли в тексте будет кемелКейс)
  • буква-буква, БУКВА-БУКВА — надо смотреть в словарь или как-то отдельно классифицировать
Согласен, что здесь можно сделать лучше. Почему не сделано:

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

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

Лучше всего — открытием ишью на гитхабе проекта. Если же сделаете пул-риквест, вообще будет идеально.
Sign up to leave a comment.

Articles