CUDA Эффективная нарезка nd-массива (тензор)

Скажем, у меня есть трехмерный массив в виде плоского 1d с размерами [N, M, K]. И я хочу обработать с него кусочек как [0:N, 1:M, 0:K]. Я создал вспомогательную функцию, которая обращается к базовому массиву по индексам из нарезанного массива (для простоты я разрезаю только по второму измерению).

#define N somevalue
#define M somevalue
#define K somevalue
// i is an index in sliced array so we need to translate it into original one
template<class T, int FROM>
 __device__   __forceinline__ T slice(const T * const __restrict__ x, const size_t i) {
    auto batch_size = (M - FROM) * K;
    auto batch_index = i / batch_size;
    auto offset_0 = i % batch_size;
    auto offset_1 = offset_0 / STATES;
    auto offset_2 = offset_0 % STATES;

    return x[batch_index * M * K + (offset_1 + FROM) * K + offset_2];
}

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

Что посоветуете? Насколько я знаю, нарезка - довольно распространенная операция в TF, так как же они ее решили?

Вам нужно всегда использовать произвольный доступ или во многих случаях вы можете использовать конструкции типа foreach?

Marc Glisse 25.08.2018 11:24

Не совсем понимаю ваш вопрос. Вычислительное ядро ​​использует функцию для обработки всего среза [0:N, 1:M, 0:K].

sh1ng 25.08.2018 11:29

Обязательно ли ядро ​​должно иметь вид: for(int i=0;i<...;++i) f(slice(x,i))? У меня нет опыта работы с cuda ...

Marc Glisse 25.08.2018 11:31

Я немного по-другому работаю в cuda, но да. Весь диапазон должен быть обработан.

sh1ng 25.08.2018 11:40
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
4
390
1

Ответы 1

Cuda - это объединенный доступ к памяти и simd. А срезы произвольный - полная противоположность. Итак, ответ как обычно: это зависит от обстоятельств.

Если ваше смещение равно и остается 1, измените макет памяти в сторону MN K. Если игнорируемые записи действительно очень редки, используйте традиционный способ и просто простаивайте несколько потоков (да, это больно, но некоторые threadIdx calc без modulo могут быть быстрее ). В противном случае вам нужно будет вычислить это биективное сопоставление идентификатора потока / блока с идентификатором элемента, как вы написали в своем вопросе.

Есть несколько способов представить по модулю некоторые другие операции. Но обычно лучше потратить время на улучшение других частей ядра.

Другие вопросы по теме