SME в Apple M4: 65 тысяч резонаторов на коротком аудиоблоке
SME (Scalable Matrix Extension) добавляет в набор инструкций Arm операции над матрицами. Apple включила поддержку SME в чипы поколения M4. Эти инструкции доступны из нативного кода, без отправки задачи в очередь GPU.
Я попробовал применить SME к обработке звука. На Mac mini M4 расчёт банка из 65 536 резонаторов сократился с 1,59 до 0,44 мс по медиане. При буфере 64 сэмпла и частоте 48 кГц это позволило укладываться в срок: в проверенной серии не было ни одного опоздавшего вызова.
Звуковой движок с такими настройками вызывает обработчик примерно каждые 1,33 мс. Опоздание может обернуться щелчком или обрывом. Увеличение буфера даёт больше времени на расчёт, но музыкант дольше ждёт звук при игре или мониторинге. Меня интересовал выигрыш при сохранении короткого блока.
Как колебания превратились в матрицы
Банк резонаторов складывает звук из затухающих колебаний со своей частотой и амплитудой. Так можно синтезировать перкуссию и резонансные тембры. Первая версия обновляла каждый резонатор на каждом сэмпле векторными инструкциями NEON.
Между ударами поведение резонатора известно заранее. Его комплексное состояние s умножается на постоянный коэффициент z: модуль z задаёт затухание, аргумент задаёт частоту. Для монофонической суммы в точной арифметике можно записать:
s_m[t+1] = z_m * s_m[t]
y[16a+b] = Σ_m Re((s_m[0] * z_m^(16a)) * z_m^b)
sourcecraft.dev
m обозначает резонатор, a нумерует группы по 16 сэмплов, b задаёт позицию в группе. Состояние переношу сразу к началу группы, а её сэмплы рассчитываю через заранее подготовленные степени z от 0 до 15.
В матрице A заранее хранятся действительные части z^b и мнимые части с обратным знаком. В B находятся действительные и мнимые части состояния в начале группы, умноженные на коэффициенты панорамы. Каждому резонатору соответствуют две строки A и B. Произведение C = AᵀB складывает их вклады.
У C шестнадцать строк для позиций b. Столбцы идут парами: левый и правый канал очередной группы. Для блока 64 сэмпла использую четыре группы, то есть восемь столбцов результата. Состояние между группами переношу умножением на заранее рассчитанное z^16. Вот один шаг матричного ядра:
// В streaming-функции, ZA обнулён до цикла.
// Маска pg включает все 16 FP32-элементов M4.
svmopa_za32_f32_m(0, pg, pg,
svld1_f32(pg, A + 16*k), // Коэффициенты z^b.
svld1_f32(pg, B + 16*k)); // Состояния с панорамой.
// ZA0[i,j] += A[k,i] * B[k,j].
sourcecraft.dev
В полном цикле чередую четыре накопителя ZA, затем складываю их. Меняющиеся данные обрабатываю порциями по 2048 резонаторов, чтобы сократить временные буферы. Если внутри аудиоблока приходит новый удар, делю обработку в этой точке; остатки короче 16 сэмплов считаю векторным кодом. Дополнительного входного сигнала ждать не требуется.
Выходы NEON, Accelerate и SME я сверил с независимой посэмпловой рекурсией double. В первой таблице сравниваются посэмпловый NEON и весь переработанный вариант с SME.
Что показали измерения
Испытания проходили на Mac mini M4 с 16 ГБ памяти, в колбэке CoreAudio при 48 кГц и буфере 64 сэмпла. Все резонаторы были возбуждены. Измерял весь расчёт стереовыхода, по три секунды на режим. p99 обозначает время, в которое уложились примерно 99% вызовов.
Число резонаторов
NEON, медиана, мкс
SME, медиана, мкс
SME, p99, мкс
SME, максимум, мкс
16 384
395,96
91,42
134,83
183,83
65 536
1591,88
438,12
574,17
806,08
131 072
3441,00
916,58
1123,62
1290,08
На 65 536 резонаторах медианное время уменьшилось примерно в 3,6 раза. Посэмпловый NEON превысил бюджет 1333 мкс во всех 1129 вызовах. Блочный вариант с SME уложился во всех 2250. На 131 072 резонаторах максимум 1290,08 мкс оставил около 43 мкс запаса. Этот размер характеризует наблюдаемую границу нагрузки в короткой серии.
Чтобы проверить выбор матричного ядра, провёл отдельный прогретый тест без CoreAudio. Блочный алгоритм, матрицы и подготовка данных одинаковы; меняется только умножение. На вариант пришлось 4 прогрева и 40 измерений, порядок вызовов чередовался. Измерял весь стереорасчёт с подготовкой B и переносом состояний.
На 65 536 резонаторах медианы составили 838,96 мкс для блочного NEON, 425,27 мкс для Accelerate и 343,77 мкс для SME. При одной блочной формулировке путь SME оказался быстрее в 2,44 раза относительно моего NEON-ядра и в 1,24 раза относительно Accelerate. Это отдельная серия; её числа не заменяют результаты аудиоколбэка.
Точность проверил на 21 635 временных позициях стереовыхода относительно независимого эталона double. Отношение сигнала к численной ошибке, SNR, составило 98,73 дБ, максимальная абсолютная ошибка 2,39 × 10⁻⁶. В эталоне использовались те же квантованные коэффициенты резонаторов.
Для рабочего режима оставил 8192 резонатора. За десять секунд на блоке 64 получил медиану 41,12 мкс и максимум 264,25 мкс. Медиана занимает около 3,1% интервала обработки. Собственная алгоритмическая задержка синтезатора составляет 0 сэмплов: дополнительной очереди внутри него нет. Задержка аудиоустройства сохраняется.
Audio Unit прошли штатную валидацию. Во всех 40 проверенных наборах параметров выход через API Audio Unit побитно совпал с выходом процессора напрямую. Функциональные тесты прошли при 32, 44,1, 48, 96 и 192 кГц и размерах блоков от 1 до 511 сэмплов.
Что получилось со свёртками
Следующий тест относился к слою аудионейросети: случайные веса, блок 64 сэмпла, ядро длиной 3 и dilation 2, то есть шаг между элементами ядра в два сэмпла. Постоянные веса упакованы заранее; подготовка входа входит в измерение.
Входных и выходных каналов
Eigen 3.4.0, мкс
Accelerate, мкс
SME, мкс
8
0,49
0,85
1,08
32
4,45
1,55
1,37
64
16,74
3,03
2,30
128
71,21
8,32
5,95
После прогрева на 128 каналах SME оказался примерно в 12 раз быстрее реализации на Eigen из стенда и в 1,4 раза быстрее Accelerate. Eigen складывал три матричных произведения. Для Accelerate и SME вход собирался в матрицу методом im2col: элементы для свёртки копировались в строки. Таблица сравнивает реализации слоя вместе с этой подготовкой.
Для проверки целой сети взял обученный вокодер GeneratorNSF с выходом 48 кГц и закреплённой конфигурацией. Заменил 76 свёрток кодом с SME и Accelerate; остальные операции оставил в PyTorch.
На одном потоке CPU после 3 прогревов и 20 измерений медиана синтеза порции длительностью 20 мс сократилась с 10,18 до 6,38 мс, примерно в 1,6 раза. На одинаковых синтетических входных признаках SNR относительно исходного расчёта составил от 113,5 до 119,7 дБ. Это время вокодера целиком, без анализа входа и аудиоустройства.
Что из этого можно использовать
Для резонансного эффекта, который обрабатывает входящий звук, к свободному затуханию я добавил причинную свёртку входа и поправку состояния. Дополнительная буферная задержка не понадобилась. На 1024 входных сэмплах максимальное расхождение с независимой посэмпловой рекурсией составило 5,13 × 10⁻⁸ по всем 12 проверенным настройкам.
Вспомогательные аудиопотоки можно объединять через Audio Workgroups, чтобы macOS учитывала их общий срок готовности.
Выигрыш зависит от размеров матриц и общего матричного ресурса кластера. Серии по 3 и 10 секунд проверяют выполнимость задачи; устойчивость длительного мониторинга с несколькими экземплярами ещё предстоит проверить. Ускорение также не отменяет ожидание будущих данных, заложенное в модель.
Банк резонаторов стал успевать к следующему вызову, а обученный вокодер быстрее считал ту же порцию синтеза. Полученный запас можно потратить на более сложный тембр, больше одновременно звучащих голосов или дополнительную обработку при прежнем размере буфера.
Mentions
10 நிமிடக் குரல் போதும்.. RVC அதை வேறு குரலாக மாற்றுகிறது. நேரலையில் தாமதம் 90 மில்லி விநாடி மட்டுமே. தமிழ் பாடல் படைப்பாளருக்கு ஏற்றது. முதலில் பாடலா, பேச்சா? RVC-Project/Retrieval-based-Voice-Conversion-WebUI Instagram-லும் பின்தொடருங்கள்: instagram.com
SME в Apple M4: 65 тысяч резонаторов на коротком аудиоблоке SME (Scalable Matrix Extension) добавляет в набор инструкций Arm операции над матрицами. Apple включила поддержку SME в чипы поколения M4. Эти инструкции доступны из нативного кода, без отправки задачи в очередь GPU. Я попробовал применить SME к обработке звука. На Mac mini M4 расчёт банка из 65 536 резонаторов сократился с 1,59 до 0,44 мс по медиане. При буфере 64 сэмпла и частоте 48 кГц это позволило укладываться в срок: в проверенной серии не было ни одного опоздавшего вызова. Звуковой движок с такими настройками вызывает обработчик примерно каждые 1,33 мс. Опоздание может обернуться щелчком или обрывом. Увеличение буфера даёт больше времени на расчёт, но музыкант дольше ждёт звук при игре или мониторинге. Меня интересовал выигрыш при сохранении короткого блока. Как колебания превратились в матрицы Банк резонаторов складывает звук из затухающих колебаний со своей частотой и амплитудой. Так можно синтезировать перкуссию и резонансные тембры. Первая версия обновляла каждый резонатор на каждом сэмпле векторными инструкциями NEON. Между ударами поведение резонатора известно заранее. Его комплексное состояние s умножается на постоянный коэффициент z: модуль z задаёт затухание, аргумент задаёт частоту. Для монофонической суммы в точной арифметике можно записать: s_m[t+1] = z_m * s_m[t] y[16a+b] = Σ_m Re((s_m[0] * z_m^(16a)) * z_m^b) sourcecraft.dev m обозначает резонатор, a нумерует группы по 16 сэмплов, b задаёт позицию в группе. Состояние переношу сразу к началу группы, а её сэмплы рассчитываю через заранее подготовленные степени z от 0 до 15. В матрице A заранее хранятся действительные части z^b и мнимые части с обратным знаком. В B находятся действительные и мнимые части состояния в начале группы, умноженные на коэффициенты панорамы. Каждому резонатору соответствуют две строки A и B. Произведение C = AᵀB складывает их вклады. У C шестнадцать строк для позиций b. Столбцы идут парами: левый и правый канал очередной группы. Для блока 64 сэмпла использую четыре группы, то есть восемь столбцов результата. Состояние между группами переношу умножением на заранее рассчитанное z^16. Вот один шаг матричного ядра: // В streaming-функции, ZA обнулён до цикла. // Маска pg включает все 16 FP32-элементов M4. svmopa_za32_f32_m(0, pg, pg, svld1_f32(pg, A + 16*k), // Коэффициенты z^b. svld1_f32(pg, B + 16*k)); // Состояния с панорамой. // ZA0[i,j] += A[k,i] * B[k,j]. sourcecraft.dev В полном цикле чередую четыре накопителя ZA, затем складываю их. Меняющиеся данные обрабатываю порциями по 2048 резонаторов, чтобы сократить временные буферы. Если внутри аудиоблока приходит новый удар, делю обработку в этой точке; остатки короче 16 сэмплов считаю векторным кодом. Дополнительного входного сигнала ждать не требуется. Выходы NEON, Accelerate и SME я сверил с независимой посэмпловой рекурсией double. В первой таблице сравниваются посэмпловый NEON и весь переработанный вариант с SME. Что показали измерения Испытания проходили на Mac mini M4 с 16 ГБ памяти, в колбэке CoreAudio при 48 кГц и буфере 64 сэмпла. Все резонаторы были возбуждены. Измерял весь расчёт стереовыхода, по три секунды на режим. p99 обозначает время, в которое уложились примерно 99% вызовов. Число резонаторов NEON, медиана, мкс SME, медиана, мкс SME, p99, мкс SME, максимум, мкс 16 384 395,96 91,42 134,83 183,83 65 536 1591,88 438,12 574,17 806,08 131 072 3441,00 916,58 1123,62 1290,08 На 65 536 резонаторах медианное время уменьшилось примерно в 3,6 раза. Посэмпловый NEON превысил бюджет 1333 мкс во всех 1129 вызовах. Блочный вариант с SME уложился во всех 2250. На 131 072 резонаторах максимум 1290,08 мкс оставил около 43 мкс запаса. Этот размер характеризует наблюдаемую границу нагрузки в короткой серии. Чтобы проверить выбор матричного ядра, провёл отдельный прогретый тест без CoreAudio. Блочный алгоритм, матрицы и подготовка данных одинаковы; меняется только умножение. На вариант пришлось 4 прогрева и 40 измерений, порядок вызовов чередовался. Измерял весь стереорасчёт с подготовкой B и переносом состояний. На 65 536 резонаторах медианы составили 838,96 мкс для блочного NEON, 425,27 мкс для Accelerate и 343,77 мкс для SME. При одной блочной формулировке путь SME оказался быстрее в 2,44 раза относительно моего NEON-ядра и в 1,24 раза относительно Accelerate. Это отдельная серия; её числа не заменяют результаты аудиоколбэка. Точность проверил на 21 635 временных позициях стереовыхода относительно независимого эталона double. Отношение сигнала к численной ошибке, SNR, составило 98,73 дБ, максимальная абсолютная ошибка 2,39 × 10⁻⁶. В эталоне использовались те же квантованные коэффициенты резонаторов. Для рабочего режима оставил 8192 резонатора. За десять секунд на блоке 64 получил медиану 41,12 мкс и максимум 264,25 мкс. Медиана занимает около 3,1% интервала обработки. Собственная алгоритмическая задержка синтезатора составляет 0 сэмплов: дополнительной очереди внутри него нет. Задержка аудиоустройства сохраняется. Audio Unit прошли штатную валидацию. Во всех 40 проверенных наборах параметров выход через API Audio Unit побитно совпал с выходом процессора напрямую. Функциональные тесты прошли при 32, 44,1, 48, 96 и 192 кГц и размерах блоков от 1 до 511 сэмплов. Что получилось со свёртками Следующий тест относился к слою аудионейросети: случайные веса, блок 64 сэмпла, ядро длиной 3 и dilation 2, то есть шаг между элементами ядра в два сэмпла. Постоянные веса упакованы заранее; подготовка входа входит в измерение. Входных и выходных каналов Eigen 3.4.0, мкс Accelerate, мкс SME, мкс 8 0,49 0,85 1,08 32 4,45 1,55 1,37 64 16,74 3,03 2,30 128 71,21 8,32 5,95 После прогрева на 128 каналах SME оказался примерно в 12 раз быстрее реализации на Eigen из стенда и в 1,4 раза быстрее Accelerate. Eigen складывал три матричных произведения. Для Accelerate и SME вход собирался в матрицу методом im2col: элементы для свёртки копировались в строки. Таблица сравнивает реализации слоя вместе с этой подготовкой. Для проверки целой сети взял обученный вокодер GeneratorNSF с выходом 48 кГц и закреплённой конфигурацией. Заменил 76 свёрток кодом с SME и Accelerate; остальные операции оставил в PyTorch. На одном потоке CPU после 3 прогревов и 20 измерений медиана синтеза порции длительностью 20 мс сократилась с 10,18 до 6,38 мс, примерно в 1,6 раза. На одинаковых синтетических входных признаках SNR относительно исходного расчёта составил от 113,5 до 119,7 дБ. Это время вокодера целиком, без анализа входа и аудиоустройства. Что из этого можно использовать Для резонансного эффекта, который обрабатывает входящий звук, к свободному затуханию я добавил причинную свёртку входа и поправку состояния. Дополнительная буферная задержка не понадобилась. На 1024 входных сэмплах максимальное расхождение с независимой посэмпловой рекурсией составило 5,13 × 10⁻⁸ по всем 12 проверенным настройкам. Вспомогательные аудиопотоки можно объединять через Audio Workgroups, чтобы macOS учитывала их общий срок готовности. Выигрыш зависит от размеров матриц и общего матричного ресурса кластера. Серии по 3 и 10 секунд проверяют выполнимость задачи; устойчивость длительного мониторинга с несколькими экземплярами ещё предстоит проверить. Ускорение также не отменяет ожидание будущих данных, заложенное в модель. Банк резонаторов стал успевать к следующему вызову, а обученный вокодер быстрее считал ту же порцию синтеза. Полученный запас можно потратить на более сложный тембр, больше одновременно звучащих голосов или дополнительную обработку при прежнем размере буфера.
Retrieval-based-Voice-Conversion-WebUI#2854 相変わらず本家にはスルーされてるな。俺の指針と違うから勝手にやってろぐらいはいってもいいのにな🌱 せっかくインテル問題解消したのに
@coah80 RVC is pretty good though atp its a ancient project github.com/RVC-Project/Retrieval-based-Voice-Conv…
@AkaWhacked Ok I did it from the command line but it should still work. What I did is i pasted this link and said "follow the instructions and install this" github.com/RVC-Project/Retrieval-based-Voice-Conv…
给你推个开源变声神器 RVC,GitHub 上已经攒到 3.7 万+ Star。 准备好大约 10 分钟的干净人声喂给它,就能训出自己的音色模型,拿来做 AI 翻唱、声音转换、实时变声都挺方便。项目自带 WebUI,还支持人声伴奏分离和 RMVPE 音高提取。 RVC-Project/Retrieval-based-Voice-Conversion-WebUI t.co