Вопрос или проблема
Когда я конвертирую модель Efficient net v2 m из Pytorch в Onnx с входами разных размеров, я замечаю странное и необъяснимое поведение. Я надеялся найти объяснение своим наблюдениям в сообществе.
На моем RTX 4090 модель ONNX на изображении размером 1280X1280 выводит результат за 35 мс для размера партии 1. Время выполнения почти постоянно, когда я уменьшаю размер изображения до примерно 192X192 (с тем же размером партии в 1). Это объяснимо из-за доминирования фиксированных накладных расходов, таких как время инициализации, разогрев пула потоков, неэффективная передача данных на GPU и обратно и, что наиболее важно, вычислительные библиотеки оптимизированы для векторизации и SIMD инструкций на GPU.
Однако, что смущает, так это то, что как только я начинаю уменьшать размер входного изображения ниже 192X192, время выполнения резко увеличивается. Для изображения 64X64 время выполнения составляет >100 мс при размере партии 1. Я полностью понимаю, почему вывод не должен быть быстрее на меньших изображениях, но не могу понять, почему он будет медленнее (и так значительно медленнее).
Когда я увеличиваю размер партии для меньших изображений, время выполнения на партию значительно улучшается (не только время выполнения на изображение). Для размера партии 16 вывод 192X192 изображений требует 25 мс на партию (<2 мс на изображение) в отличие от>100 мс при размере партии 1. Опять же, у меня нет объяснения этому. Фиксированные накладные расходы и оптимизированная SIMD векторизация должны бы указывать на то, что амортизированное время выполнения на изображение должно улучшаться с увеличением размеров партий. Однако я наблюдаю, что время выполнения для всей партии также улучшается.
Для больших изображений, таких как 1280X1280, увеличение размера партии увеличивает время выполнения на партию (хотя подлинейно, что совершенно ожидаемо — время выполнения на изображение все еще уменьшается с увеличением размера партии до определенного предела, после чего даже время выполнения на изображение увеличивается примерно на 10% для еще больших партий, которые едва помещаются в память GPU).
Тем не менее, при работе на CPU время обработки монотонически увеличивается с увеличением размера входа, как и ожидалось.
Я уже подтвердил, что модели ONNX успешно работают на GPU, когда я это запрашиваю для всех входов. Фактически, для небольших входов время вывода на CPU быстрее, чем на GPU (что объяснимо из-за фиксированных ввода-вывода и других накладных расходов)
Примечание: Поскольку я установил динамические оси как None на протяжении всего этого эксперимента, я сохранил несколько версий модели ONNX для одной и той же torch модели с разными размерами входов. Использование или не использование onnx-sim едва влияет на время выполнения (разница в скорости обработки менее 10-15%). Я запускаю модели onnx на C++ с OrtCUDAProviderOptions в качестве провайдера выполнения и использование или не использование GraphOptimizationLevel едва имеет значение.
Выходы нейронной сети соответствуют ожиданиям для всех входов, поэтому я не ожидаю ошибок в своем коде.
Кратко Моя модель ONNX работает быстрее для изображений среднего размера, чем для меньших изображений на GPU. Для меньших изображений увеличение размера партии приводит к резкому сокращению времени обработки на партию (не только амортизированного времени на изображение, что ожидается при SIMD параллелизации).
Ответ или решение
Почему модель ONNX EfficientNet V2 M работает медленнее на малых входных изображениях?
При анализе работы модели EfficientNet V2 M, преобразованной в формат ONNX, на различных размерах изображений на графическом процессоре (GPU) возникает несколько интересных наблюдений. На основании вашего описания, можно выделить несколько ключевых факторов, которые могли бы объяснить наблюдаемое поведение.
1. Низкие размеры изображений и эффективность обратного вызова
Когда вы работаете с изображениями небольших размеров (например, 64×64), общая продолжительность обработки растет. Это может быть связано с несколькими аспектами:
-
Использование GPU и фиксированные накладные расходы: Даже для незначительных вычислительных задач накладные расходы, связанные с инициализацией модельных структур, настройкой потоков и передачей данных, могут оказаться выше, чем фактическое время выполнения операций на GPU. В случае небольших изображений, где количество операций меньше, эти накладные расходы могут значительно влиять на общую продолжительность выполнения.
-
Недостаточная заполненность вычислительных ресурсов: Современные графические процессоры, такие как RTX 4090, оптимизированы для работы с векторными и матричными операциями. При обработке малых изображений вычислительная единица GPU может не быть полностью загруженной, что приводит к неэффективному использованию вычислительных мощностей. Это меньшая "загрузка" процессора приводит к увеличению общего времени обработки.
2. Повышение производительности при увеличении размера батча
По вашему наблюдению, при увеличении размера батча для малых изображений (например, 16) время обработки на весь батч значительно уменьшается. Стоит отметить следующие моменты:
-
Оптимизация параллелизма: Когда размер батча увеличивается, графический процессор получает возможность более эффективно использовать свои вычислительные ресурсы, выполняя множество операций одновременно. Это приводит к лучшей оптимизации работы памяти и более слаженному использованию потоков, что уменьшает середину накладных расходов на каждую отдельную операцию.
-
Составляющие S/MIMD: Увеличивая размер батча, вы не просто сокращаете время на один элемент входа, но и увеличиваете общую загруженность ядра GPU. Существует вероятность, что GPU гораздо быстрее и эффективнее обрабатывает параллельные запросы, достигая более высокой производительности при осуществлении больших объемов вычислений за раз.
3. Отличия в работе на CPU
Как вы указали, на CPU время обработки увеличивается с увеличением размера изображения. Это связано с тем, что CPU, как правило, работает лучше с небольшими данными ввода, поскольку многие вычислительные операции могут выполняться последовательно. На CPU накладные расходы на инициализацию ниже, а использование SIMD может быть ограничено в зависимости от архитектуры процессора.
Заключение
Наблюдаемое поведение ваших моделей ONNX, кажется, является побочным эффектом взаимодействий между архитектурой GPU, алгоритмами параллелизации и накладными расходами на инициализацию. Чтобы оптимизировать производительность на малых изображениях, можно рассмотреть возможность увеличения размера батча и адаптации потоков за счет использования инструментов для профилирования производительности, которые могли бы помочь в дальнейшем идентифицировать узкие места.
Рекомендации
- Рассмотрите возможность использования различных конфигураций размера батча в зависимости от размера изображения, чтобы достичь оптимальных результатов.
- Проверьте инициализацию модели и использование оптимизированных библиотек (например, cuDNN) для большего контроля над производительностью.
- Проведите профилирование на оборудовании, чтобы выявить узкие места и возможности для оптимизации кода и архитектуры модели.
Обратите внимание на вышеописанные аспекты и проведите дополнительные эксперименты, которые помогут лучше понять и, возможно, улучшить производительность вашей ONNX модели на малых входных данных.