- Вектор имеет 81 столбец.
- Матрица имеет 90 000 строк и 81 столбец и уже транспонирована. . Таким образом, можно использовать скалярное произведение по строкам.
- Выводом является вектор с 90 000 строк.
- Все лежат в одномерном массиве с плавающей запятой.
Как следует использовать как можно меньше стандартных библиотек (без std::vector для пример)
[*]Не следует использовать никакие сторонние библиотеки (поэтому для меня тоже не нужны Eigen или Blas)
Это мой (упрощенный, где я предполагаю, что ввод полностью заблокирован для удобства чтения) код,
Код: Выделить всё
// input_height = 90000
// input_width = 81
for (uint32_t y = 0; y < input_height; y += 4) {
float32x4_t sum0 = vmovq_n_f32(0);
float32x4_t sum1 = vmovq_n_f32(0);
float32x4_t sum2 = vmovq_n_f32(0);
float32x4_t sum3 = vmovq_n_f32(0);
for (uint32_t x = 0; x < input_width; x += 16) {
float32x4x4_t A = load_matrix_transpose(kernel + x);
float32x4x4_t B0 = load_matrix_transpose(input + y * input_width + x);
float32x4x4_t B1 = load_matrix_transpose(input + (y + 1) * input_width + x);
float32x4x4_t B2 = load_matrix_transpose(input + (y + 2) * input_width + x);
float32x4x4_t B3 = load_matrix_transpose(input + (y + 3) * input_width + x);
matrix_element_wise_multiplication(A, B0, sum0);
matrix_element_wise_multiplication(A, B1, sum1);
matrix_element_wise_multiplication(A, B2, sum2);
matrix_element_wise_multiplication(A, B3, sum3);
}
output[y] = vaddvq_f32(sum0);
output[y + 1] = vaddvq_f32(sum1);
output[y + 2] = vaddvq_f32(sum2);
output[y + 3] = vaddvq_f32(sum3);
}
Код: Выделить всё
inline float32x4x4_t load_matrix_transpose(float *a) {
float32x4x4_t ret;
ret.val[0] = simd_load(a);
ret.val[1] = simd_load(a + 4);
ret.val[2] = simd_load(a + 8);
ret.val[3] = simd_load(a + 12);
return ret;
}
inline void simd_matrix_element_wise_multiplication(float32x4x4_t & A, float32x4x4_t & B, float32x4x4_t & C) {
C = vmlaq_f32(C, A.val[0], B.val[0]);
C = vmlaq_f32(C, A.val[1], B.val[1]);
C = vmlaq_f32(C, A.val[2], B.val[2]);
C = vmlaq_f32(C, A.val[3], B.val[3]);
}
В долгосрочной перспективе (много циклов) версия с регистром Neon работает ровно в два раза быстрее, чем обычный код.
Мой вопрос: можно ли как-нибудь оптимизировать код дальше? ? Я перепробовал многое, но не смог добиться каких-либо улучшений по сравнению с обычным кодом.
Подробнее здесь: https://stackoverflow.com/questions/666 ... -raspberry