Когда я должен использовать библиотеку линейной алгебры, такую ​​как Math.NET?

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

В качестве тестового примера я написал код для вычисления расстояния между вектором и ближайшим вектором в списке с тремя версиями: работа с массивами, работа с плотными векторами и работа с плотными векторами с поставщиком MKL. Работа с массивами работала примерно в 4 раза быстрее, чем над векторами, и в 3 раза быстрее, чем при использовании поставщика MKL.

Недостатком является то, что мне пришлось писать вручную вычисление расстояния вместо использования встроенной функции Norm. Плюс в том, что это намного быстрее. Примечание: я не опубликовал код, буду рад сделать это при необходимости, возможно, я неправильно использую Math.NET.

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

Если это так, я бы склонялся к мысли, что использование части линейной алгебры в Math.NET будет в основном полезно для "настоящей" алгебры, которая включает в себя матрицы, чтобы избежать повторной реализации более сложных вычислений / алгоритмов и, возможно, для читабельности кода., но для операций, которые являются более простыми векторно-векторными операциями, может быть лучше работать с необработанными массивами.

Буду признателен за любую информацию о том, когда лучше использовать библиотеку, чем о том, когда нужно делать свою собственную!

1 ответ

Решение

Отказ от ответственности: я поддерживаю Math.NET Numerics.

Основное значение, которое пытается предложить инструментарий, такой как Math.NET Numerics, - это производительность труда разработчиков, особенно для тех, у кого нет докторской степени по этому вопросу, которым было бы трудно или тратить много времени на реализацию самих этих иногда довольно сложных алгоритмов, возможно, плохо - вместо этого. тратить время на их актуальную проблему.

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

Это все в духе комментария Коди Грея: используйте его, если он работает и достаточно быстр, иначе либо помогите исправить это и заставьте его работать (и быстро), выберите другой работающий инструментарий или реализуйте именно то, что вам нужно. К счастью, для Math.NET Numerics есть еще несколько опций, см. Ниже.

Таким образом, я согласен с вашим выводом: если вам на самом деле не нужны никакие сложные операции, не работайте с очень большими данными, но важна производительность, нет ничего плохого в непосредственном использовании массивов или другой структуры данных (особенно в F#, где я лично я бы рассматривал исходную структуру данных чаще, чем в C#). Конечно, это происходит за счет потери некоторого удобства и риска того, что когда вы начнете нуждаться в большем количестве операций после всего, вы можете в конечном итоге повторно внедрить инструментарий. В конце концов, это также зависит от того, насколько это важно для вашего проекта, и можете ли вы тратить ресурсы и время на поддержку своего собственного математического кода.

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

Специфично для Math.NET Numerics

  • Очень специфическая управляемая реализация всегда может превзойти общую управляемую реализацию. Однако наша управляемая реализация не должна быть на несколько медленнее, чем любые управляемые альтернативы. В конце концов, наши алгоритмы работают непосредственно с массивами, а также внутренне (если должным образом оптимизированы). Если альтернативный алгоритм намного быстрее, кажется, что нам лучше заменить нашу реализацию этой альтернативой, поэтому, пожалуйста, сообщите нам об этом (или даже лучше внесите изменения).
  • Если вам случится найти путь, на котором мы сможем и действительно используем такого собственного провайдера, как MKL, и вы будете работать с большими данными, я бы ожидал, что Math.NET будет на несколько быстрее, несмотря на более высокий уровень абстракции.
  • Не все пути кода в Math.NET Numerics еще оптимизированы одинаково или используют собственных поставщиков. За последние несколько минорных версий была проделана большая работа по линейной алгебре, поэтому мы поправляемся, но медленно; впереди еще много работы (особенно для редких типов). Вполне возможно, что вы выбрали какой-то едва оптимизированный путь в вашем случае. Так что я на самом деле был бы очень заинтересован в вашем примере кода, чтобы мы могли работать над этим конкретным случаем.

Math.NET Числовые Советы Perf

  • Используйте родного провайдера
  • Немного поэкспериментируйте с настройками распараллеливания в классе Control (но обратите внимание, что мы поняли, что реализация распараллеливания до v2.4 на самом деле была довольно плохой, и планируем полностью заменить ее в v2.5. Первые тесты обещают)
  • Старайтесь избегать доступа к любому At / indexer при реализации ваших собственных операций, но вместо этого обращайтесь напрямую к необработанному массиву (см..Storage)
  • Многие операции позволяют указать вектор / матрицу результата, которые иногда могут быть такими же, как один из операндов (на месте). Избегает создания нового массива в каждой операции и, таким образом, снижает нагрузку на память, если вы работаете с очень большими данными. К сожалению, также сделать код некрасивым.
Другие вопросы по тегам