Pull to refresh

Comments 6

Правильно ли я понимаю, что есть две версии библиотеки: одна использует только скалярный код, вторая RVV 0.7.1? Если это так, не могли бы вы привести аналогичное сравнение производительности для этих версий библиотеки, интересно какой эффект дает использование векторных инструкций.

Есть ли вас или еще кого-то у планы по добавлению поддержки RVV 0.7.1 в LLVM? Насколько я понимаю там не очень большая разница в командах, зато код будет работать на многих доступных сейчас платах RISC-V.

И еще каким образом у вас вычисляются функции вроде exp и log в векторной реализации библиотеки?

Спасибо за интересные вопросы! Постараюсь ответить по порядку.

Правильно ли я понимаю, что есть две версии библиотеки: одна использует только скалярный код, вторая RVV 0.7.1?

Вернее будет сказать, что для операций в этой библиотеке есть несколько вариантов реализации (скалярная, RVV 0.7, RVV 1.0). Скалярные реализации использовались в основном в качестве референса для тестирования и отладки, в их оптимизацию особо не вкладывались. Векторный код для разных версий был реализован либо отдельными функциями (с выбором на этапе компиляции через #ifdef), либо через использование С-интринзик компилятора (для большинства операций они совпадали, что позволяло держать одну версию кода для обеих версий векторного расширения).

интересно какой эффект дает использование векторных инструкций.

Т.к. скалярные версии операций в библиотеки не были специально оптимизированы, сравнение с ними было не особо интересно. Вместо этого нашей командой было произведено сравнение с библиотекой XNNPACK. Это достаточно известная библиотека оптимизированных операций, применяемая в основном для ARM устройств. Она также работает и на RISC-V, но в данный момент в ней нет отдельных векторных реализация для этой архитектуры, только оптимизированный скалярный код.

Сравнение делалось на другом наборе моделей и на другой плате (LicheePI - https://sipeed.com/licheepi4a), замерялось число инференсов-в-cекунду (FPS, больше-лучше). Наши RVV оптимизации показали 2х и больше преимущество по сравнению с инференсом через связку TfLite+XNNPACK.

|      Model     | Our Library RVV, FPS | XNNPACK scalar, FPS |
| face_mesh      | 73,3                 | 28                  |
| face_detection | 84,8                 | 40,6                |
| selfie         | 38,3                 | 15,8                |
| mobilefacenet  | 14,4                 | 5,4                 |
| anti-spoof-mn3 | 25,3                 | 12,3                |

Есть ли вас или еще кого-то у планы по добавлению поддержки RVV 0.7.1 в LLVM?

В рамках другой активности (тестирование Halide под RISC-V - https://github.com/dkurt/halide_riscv) были осуществлены некоторые наработки для поддержки RVV 0.7.1 в LLVM (https://github.com/dkurt/llvm-rvv-071). С полноценной реализацией поддержки RVV 0.7.1 в LLVM есть ряд нюансов:

  1. Мейнтейнеры LLVM не особо настроены видеть эту поддержку в официальной версии LLVM. В интернете можно найти обсуждения по этой теме. Основной посыл от разработчиков LLVM - он поддерживает только официально ратифицированные версии расширений, что не относится к RVV 0.7.

  2. Одновременная поддержка нескольких версий может быть не тривиальна. Лично мне тут трудно судить, ибо я плохо знаком с устройством бекендов в LLVM.

  3. Есть вероятность, что в ближайшее время на рынке появятся устройства с поддержкой RVV 1.0 и эта задача потеряет актуальность.

каким образом у вас вычисляются функции вроде exp и log в векторной реализации библиотеки?

log пока не реализован из-за отсутствия необходимости, exp реализована через аппроксимацию полиномом.

А собственно тензорный компилятор для RISC-V на базе OpenVINO/MLIR/DNNL/llvm, которому посвящена данная статья, - это opensource-проект? Под какой он лицензией? Добавляется или свой диалект для RISC-V в рамках тензорного компилятора? Оптимизации разрабатываемые в MLIR будут работать только для RISC-V или и для x86/arm/mips?

Верно ли, что для riscv был создан транслятор OpenVINO -> MLIR и ранее MLIR вместе с OpenVINO не использовался?

Упоминаемых 6 абстракций - это по аналогии с gcc/llvm 6 pass'ов, которые постепенно выполняют lowering от входных операций к выходным операциям? Выполнили lowering для циклов, выполнили lowering для call'ов и т.д., попутно выполняя некоторые арх.-независимые оптимизации? И все это на представлении MLIR, причем после очереднного lowering-pass'а получаемое состояние называется диалектом MLIR?

Спасибо за вопросы)

А собственно тензорный компилятор для RISC-V на базе OpenVINO/MLIR/DNNL/llvm, которому посвящена данная статья, - это opensource-проект? Под какой он лицензией?

На данный момент проект не доступен в opensource, но мы планируем это сделать (как для компилятора, так и для библиотеки оптимизированных операций).

Добавляется или свой диалект для RISC-V в рамках тензорного компилятора?

Нет, используются стандартные платформо-независимые диалекты MLIR, такие как vector, arith, math, llvm.

Оптимизации разрабатываемые в MLIR будут работать только для RISC-V или и для x86/arm/mips?

Большая часть компилятора использует платформо-независимые оптимизации. Уже в начале разработки компилятор также работал и на x86 платформе, хотя это больше использовалось для разработки и отладки. На данный момент мы также начинаем более углубленное тестирование на ARM архитектуре.

Верно ли, что для riscv был создан транслятор OpenVINO -> MLIR и ранее MLIR вместе с OpenVINO не использовался?

Да, был разработан свой транслятор OpenVINO -> MLIR и свой OV диалект для представления OpenVINO модели в терминах MLIR. Сам OpenVINO на данные момент не использует MLIR ни в каком виде, но есть отдельный плагин (https://github.com/openvinotoolkit/npu_plugin) для NPU устройств, который также использует MLIR для реализации собственного тензорного компилятора.

Упоминаемых 6 абстракций - это по аналогии с gcc/llvm 6 pass'ов, которые постепенно выполняют lowering от входных операций к выходным операциям? Выполнили lowering для циклов, выполнили lowering для call'ов и т.д., попутно выполняя некоторые арх.-независимые оптимизации? И все это на представлении MLIR, причем после очередного lowering-pass'а получаемое состояние называется диалектом MLIR?

В MLIR диалектом называется коллекция операций (а также типов и атрибутов), объединённых общим доменом. Например, диалект для OpenVINO модели, диалект для взаимодействия с GPU и т.п. Уровни абстракция - это скорее логическое разделение этапов работы компилятора. При этом тут нет однозначной 1-к-1 связи между диалектами и уровнями абстракций. Диалекты могут комбинироваться в рамках одного уровня, некоторые диалекты могут существовать на протяжении нескольких этапов компиляции. В данной статье указаны ключевые диалекты для каждого уровня, на самом деле на каждом уровне используются несколько диалектов. Так, например, диалекты linalg, affine, scf описывают итерации по тензорам на разном уровне абстракций, а для описания самих операций используются диалекты arith/math/vector. При lowering'е мы трансформируем linalg в affine, а затем affine в scf. При этом тело "цикла" не меняется. Векторизация происходит на этапе linalg диалекта.

Sign up to leave a comment.