Apple Accelerate Framework масштабирует и нормализует вектор - PullRequest
3 голосов
/ 23 ноября 2010

Какие функции я могу использовать в Accelerate.framework для масштабирования вектора по скаляру и нормализации вектора?Я нашел один, который, я думаю, может работать для масштабирования в документации, но я запутался в его работе.

vDSP_vsma
Vector scalar multiply and vector add; single precision.

void vDSP_vsma (
   const float *__vDSP_A,
   vDSP_Stride __vDSP_I,
   const float *__vDSP_B,
   const float *__vDSP_C,
   vDSP_Stride __vDSP_K,
   float *__vDSP_D,
   vDSP_Stride __vDSP_L,
   vDSP_Length __vDSP_N
);

1 Ответ

5 голосов
/ 23 ноября 2010

Самый простой способ нормализовать вектор на месте - это что-то вроде

int n = 3;
float v[3] = {1, 2, 3};
cblas_sscal(n, 1.0 / cblas_snrm2(n, v, 1), v, 1);

Вам нужно будет

#include <cblas.h>

или

#include <vblas.h>

(или оба). Обратите внимание, что некоторые функции находятся в разделе «матрица», когда они работают с векторами.

Если вы хотите использовать функции vDSP, см. Раздел Vector-Scalar Division . Вы можете сделать несколько вещей:

  • vDSP_dotpr(), sqrt() и vDSP_vsdiv()
  • vDSP_dotpr(), vrsqrte_f32() и vDSP_vsmul() (vrsqrte_f32() является встроенным в NEON GCC, поэтому вам нужно проверить, что вы компилируете для armv7).
  • vDSP_rmsqv(), умножить на sqrt(n) и vDSP_vsdiv()

Причина, по которой нет функции нормализации вектора, заключается в том, что «вектор» в vDSP означает «много вещей одновременно» (примерно до 4096 / 8192) и обязательно «вектор» из линейная алгебра. Нормализовать вектор 1024 -элемента довольно бессмысленно, а быстрая функция для нормализации вектора 3 -элемента не сделает ваше приложение значительно быстрее, поэтому его нет.

Предполагаемое использование vDSP больше похоже на нормализацию векторов 1024 2 - или 3. Я могу найти несколько способов сделать это:

  • Используйте vDSP_vdist(), чтобы получить вектор длин, а затем vDSP_vdiv(). Вы должны использовать vDSP_vdist() несколько раз для векторов длиной больше 2.
  • Используйте vDSP_vsq() для возведения в квадрат всех входов, vDSP_vadd() несколько раз, чтобы добавить их все, что эквивалентно vDSP_vsqrt() или vDSP_vrsqrt() и vDSP_vmul() или vDSP_vdiv() в зависимости от ситуации. Не должно быть слишком сложно написать эквивалент vDSP_vsqrt() или vDSP_vrsqrt().
  • Различные способы, которые притворяются, что ваш ввод - сложный вектор. Вряд ли будет быстрее.

Конечно, если у вас нет 1024 векторов для нормализации, не переусердствуйте.

Примечания:

  1. Я не использую «2-вектор» и «3-вектор», чтобы избежать путаницы с «вектором» из теории относительности.
  2. Хороший выбор n - это тот, который почти заполняет ваш кэш данных L1. Это не сложно; они были относительно фиксированными на 32K около десяти лет или более (они могут быть разделены между виртуальными ядрами в многопоточном ЦП, а у некоторых старых / более дешевых процессоров может быть 16 КБ), поэтому самое большее, что вам нужно сделать, это около 8192 для эксплуатации на месте на поплавках. Возможно, вы захотите немного вычесть пространство стека, и если вы делаете несколько последовательных операций, вы, вероятно, захотите сохранить все это в кэше; 1024 или 2048 кажутся довольно разумными и, вероятно, больше будут попадать в убывающую отдачу. Если вам все равно, измерьте производительность ...
...