Gradius
> В случае обучения рекуррентной сети очень остро встал вопрос - как правильно запитывать сеть обучающими данными?
>
> Тут фигурирует размер батча, который собственно определяет возможность обучению распараллеливаться. А в случае рекуррентной сети батч, бОльший 1 - нарушает причинность данных.
>
> Проще говоря, как распараллелить обучение при размере батча >1, но при этом не потерять причинность данных?
Решил этот вопрос. Ответ оказался очень даже не тривиальным. Ниже изложены шаги и действия, которые в итоге привели меня к тому, что именно мне и нужно.
1) Первым делом, нашёл норамальную библиотеку, в которой реализована нужная мне архитектура рекуррентного кодека:
https://github.com/shobrook/sequitur
Конкретно: LSTM_AE
Ему нужно несколько N примеров серий TIME векторов размерностью MEL. Тоесть - лист шейпов (TIME,MEL) *N
В моём случае: выбрал TIME=4 (4 смежных фрейма спектрограммы), MEL=80 (размерность одного фрейма).
Обучил сеть и проверил. Пришлось вытащить функцию train_model(), так как штатная quick_train() не работает с LSTM_AE
Число эпох обучения и обучающий набор сделал небольшими, чтобы посмотреть важное - насколько хорошо или плохо стыкуются между собой фреймы на границах примеров (в данном случае стык будет через TIME=4).
Мои ожидания оправдались: стык между примерами нарушен:

Видны вертикальные полосы - через каждые 4 фрейма.
Значит, данная библиотека не поддерживала сохранение скрытых состояний между набором примеров.
Так и есть: модуль lstm_ae.py в функциях кодирования и декодирования игнорируется работа со скрытым состоянием:
x, (h_n, c_n) = layer( x)
2) Далее сосредоточился на поиске решения, как сохранять скрытые состояния между наборами.
Нашёл вот что: https://discuss.pytorch.org/t/lstm-how-to-remember-hidden-and-cel… batches/11957
Конкретно здесь:
out, hidden = lstm(inputs, hidden)
В глобальный кортеж тензоров hidden мы должны сохранить следующее состояние. А в инициализации или в отдельном методе (reset предположим) этот кортеж тензоров должен обнуляться.
И это всё прекрасно работает в инференсе: обученную сеть переглючило, так как учёт скрытого состояния был введён ПОСЛЕ обучения:

Из рисунка видно, что перыве 4 фрейма слева - идут нормально, а потом постепенно нарастают глюки из-за накопления ошибки.
Придётся переобучить сеть заново.
3) Как оказалось, при обучении сети это НЕ работает, так как проблема в градиенте:
RuntimeError: Trying to backward through the graph a second time (or directly access saved tensors after they have already been freed). Saved intermediate values of the graph are freed when you call .backward() or autograd.grad(). Specify retain_graph=True if you need to backward through the graph a second time or if you need to access saved tensors after calling backward.
Решение нашёл здесь: https://stackoverflow.com/questions/48274929/pytorch-runtimeerror… cond-time-but
Конкретно помогло это:
hidden = hidden.detach()
В итоге код по обновлению скрытого состояния вышел таким (в кодере и декодере - аналогично):
hidden=[(self.A,self.B),( self.C,self.D)] x,tmp=layer( x,hidden[t]) self.A=tmp[0].detach( ) self.B=tmp[1].detach( )
Без детача обучение заканчивается ошибкой с текстом выше.
В конечном итоге - удалось добиться бесшовной спектрограммы:

Здесь по-прежнему обучение было на скорую руку - с малым числом обучающих выборок и минимум эпох, чтобы проверить.
Ещё раз убедился в том, что готoвых решений - нет и не будет :) Всё приходится изучать и пробовать самостоятельно.
Восстановленная спектрограмма - на обученном рекуррентном автоэнкодере (временная серия 4 фрейма, число полос 80, скрытый вектор размерность 80, общее число обучающих векторов 600 000. По сути сжатие по времени 4x ):

Если присмотреться - видны дефекты - стыки между сериями по 4 фрейма, так как картинка была сделана раньше, чем была введена поддержка сохранения скрытых состояний между примерами/батчами.
Ну что я могу сказать... Сделал автоэнкодер на базе рекуррентных ячеек, перепробовал все три: RNN, GRU, LSTM. Лосс минимальный у GRU и LSTM, самая простя ячейка - это RNN, но у неё есть проблемы взрыва и затухания градиента.
Из 4-х смежных фреймов спектрограммы - получаю одно скрытое представление размерностью в 2 раза меньше. Тоесть:
Вход: 4 фрейма 80-полосной спектрограммы (1 фрейм 16 мс)
Выход: 1 скрытое состояние размерностью 40
Выход квантую NSVQ - 12 бит. Обучение долгое, из-за того что рекуррентная сеть.
Плюс регуляризация входных фреймов - слоем Time Jitter с вероятностью 0.5
Итого после 10 эпох, спектр выглядит так:

Смотрится весьма убого по сравнению с оригиналом, но на слух даёт разборчивую речь, правда голос изменился (что неважно) - он стал сиплым. А также появился иностранный акцент: что указывает о захвате сетью каких-то более крупных признаков речи, так как обучение шло на образцах англоязычной речи, а тестирование - на русских высказываниях.
Итого здесь выходит:
4 фрейма по 16 мс = 64 мс = 12 бит, значит битрейт: (1000/64)*12 = 187,5 бит/c
По сути, рекуррентные сети дали эффективное сжатие по временной оси, что не дают сверточные сети.
Теперь нужно совместить сверточные слои(сжатие по оси частот) с рекуррентными(сжатие по оси времени) и посмотреть что изменится.
По идее, это всё позволит отбросить несущественное и оставить только важное, а также вектор меньшей размерности - лучше квантуется векторными квантователями, что уменьшит ошибку определения ближайшего из кодовой книги
1) Впервые столкнулся с таким поведением во время обучения нейросети, когда достаточно 2-х/3-х эпох обучения:
Epoch 1/100, Loss: 0.284877
Epoch 2/100, Loss: 0.261488
Epoch 3/100, Loss: 0.278799
Epoch 4/100, Loss: 0.257852
Epoch 5/100, Loss: 0.264374
Epoch 6/100, Loss: 0.270392
Epoch 7/100, Loss: 0.271651
Epoch 8/100, Loss: 0.274381
Epoch 9/100, Loss: 0.262498
Epoch 10/100, Loss: 0.263773
Epoch 11/100, Loss: 0.266983
Epoch 12/100, Loss: 0.260020
Epoch 13/100, Loss: 0.259852
Epoch 14/100, Loss: 0.266786
Epoch 15/100, Loss: 0.269370
Epoch 16/100, Loss: 0.274770
Epoch 17/100, Loss: 0.278780
Epoch 18/100, Loss: 0.267804
Epoch 19/100, Loss: 0.265802
Epoch 20/100, Loss: 0.263646
Epoch 21/100, Loss: 0.265057
Epoch 22/100, Loss: 0.262379
Epoch 23/100, Loss: 0.256146
Epoch 24/100, Loss: 0.263446
Epoch 25/100, Loss: 0.273561
Обучающая выборка: 9,5 миллионов векторов. Речевые высказывания многих людей обоих полов.
2) Добавление шума uniform во внутренний слой сети при обучении - лучшая регуляризация, насильно заставляющая нейросеть именно обобщать(генерализировать), а не заучивать:
z=self.encoder(x) # z [-1..1] Alpha=0.95 #5% Noise noise=uniform_dist.Uniform( -1.0,+1.0).sample( [z.shape[0],z.shape[1]]) z=( Alpha*z)+( ( 1.0-Alpha)*noise) #Blend
3) То же добавление шума во входной слой (блендиг в исходные данные) - ведёт к возможности разделять речевые высказывания от тишины и шума
Подборка квантователей на любой вкус и цвет: https://github.com/lucidrains/vector-quantize-pytorch
Пока испытал только FSQ. Работает. https://arxiv.org/pdf/2309.15505
Ниже - результат работы кодека на 5 кбит/c: восстановленная спектрограмма. Параметры: 1 фрейм = 16 мс, рекуррентный авто-энкодер с тайм-слотом 4 фрейма, скрытое состояние - 80 измерений, квантование скрытого состояния - FSQ : 16 уровней - 4 бита на каждое измерение.
Обучающий набор: 2 400 000 речевых сегментов размером 80x4. Англоязычная речь, несколько разных голосов обоих полов. Проверочный набор - высказывания на русском.
При этом я не дополнял датасет примерами со сдвигами на +1/+2/+3 фрейма(как об этом писал ранее, когда экспериментировал со свёрточными сетями) - для улучшения к временной инвариантности. Подразумевалось, что рекуррентная нейросеть должна самостоятельно вывозить временные корреляции между соседними фреймами.
Итого итоговый битрейт: 1000 ms*80 band *4 bits /(4 frames *16 ms) = 5000 бит/c.
На слух - практически нет различий по сравнению с оригинальной спектрограммой. Озвучка спектрограммы - через MELGAN.
Чисто субъективно лучше, чем кодек CELP на 4800 бит/c и GSM 9600 бит/c. Не говоря уже о том, что частота семплирования 16 кГц, а не 8 кГц(как принято в телефонии).
Лосс реконструкции: классический MSE - на 20-й эпохе Loss: 0.000414. Лосс применялся к сегменту спектрограммы размером 80x4 пикселей (80 полос, 4 фрейма по времени). Спектрограмма глобально нормирована в диапазоне [0..1)

P.S. Вот чем мне нравятся скалярные квантователи, так это тем, что им нужен только STE, без дополнительных лоссов. И что очень важно: более предсказуемый результат на проверочных/незнакомых данных, так как кодовых книг у скалярных квантователей нет.
Векторные квантователи на тестовых/незнакомых данных вносят очень большой лосс реконструкции.
P.P.S. Всё больше и больше убеждаюсь, что Torch (и его реализация на Питоне - PyTorch) - очень гибкий и стабильный фреймворк. Ещё ни разу не было такого, чтобы скачанный с гитхаба сорец на Торче отказался запускаться.
Ну и граф вычислений более удачно сделан, чем в Keras/Tensorflow : можно без проблем смешивать обучение с инференсом другой сети, или получать доступ к весам слоёв напрямую. Чего не скажешь о tensorflow и тем более Keras.
Они там кстати новый фреймворк на базе tensorflow запилили Sonnet: https://github.com/google-deepmind/sonnet
Проверил его на примере VQ-VAE: работает. Даже ничего править не пришлось. Секрет прост: они как-то изнасиловали tensorflow, заставив его современную версию работать по-старому, отбросив все придурошные нововведения, которые только мешали собирать проекты.
Gradius
> При этом я не дополнял датасет примерами со сдвигами на +1/+2/+3 фрейма(как об этом писал ранее, когда экспериментировал со свёрточными сетями) - для улучшения к временной инвариантности.
Мне кажется, это зря: на халяву увеличить обучающий набор в несколько раз — дорого стоит.
}:+()___ [Smile]
> Мне кажется, это зря: на халяву увеличить обучающий набор в несколько раз — дорого стоит.
Дополнил датасет примерами со сдвигами 1/2/3 - дообучил сеть. Качество спектрограммы осталось тем же, лосс почти не уменьшился.
———
Сократил битрейт кодека вчетверо: с 5000 бит/c - до 1250 бит/c. Просто добавил пару линейных слоёв: 80=>20 и 20=>80 без активаций, после- и до- реккурентных ячеек. Дополнительно сделал стейк из трёх LSTM в кодере и декодере, раньше был только 1 слой.
Применение 2-х стейков/слоёв LSTM вместо одного - уже уменьшает лосс почти в 2 раза при прочих равных условиях.
Лосс после 40 эпох обучения MSE=0.000654
Визуально спектрограмма немного хуже, чем в случае с 5000 бит/c, но на слух терпимо - разборчивость сохраняется (она вообще всегда сохраняется при использовании MELGAN, чего не скажешь о PyWorld).
Чисто субъективно, качество и разборчивость вышла намного превосходящей аналогичные кодеки MELP 2400 бит/c и LPC-10 2400 бит/c.
Проверяю, естественно, на данных, которые не были в обучении.

А это латентное пространство (проекция скрытого состояния последнего слоя LSTM ячейки - на линейный слой ), квантованный выход после кодера - сжатие по времени в 4 раза, число уникальных цветов - 16 (квантование 4 бита на каждое измерение скрытого состояния):

Смотрю на это, и собственно не вижу ничего похожего на фонемы - в скрытом пространстве. Больше похоже на шум - в сегментах где речь.
Gradius
> Больше похоже на шум
Это, как раз, не удивительно: идеальное сжатие выглядит неотличимо от шума.
Если видно какую-то структуру, то это только значит, что еще остался потенциал для уменьшения битрейта.
}:+()___ [Smile]
> Это, как раз, не удивительно: идеальное сжатие выглядит неотличимо от шума.
> Если видно какую-то структуру, то это только значит, что еще остался потенциал для уменьшения битрейта.
В таком случае векторное квантование в пролёте. Так как из кодовой книги ищутся вектора, ближайшие по минимальной евклидовой дистанции (или по косинусному сходству - для нормированных векторов). А тут - что ни вектор - так резко отличается от других.
И кстати, неизвестно что выдаст, если взять среднее двух векторов.
Остаётся только скалярное квантование - когда каждое измерение квантуется отдельно.
В случае с кодеком на 1250 бит/c, скалярное квантование 16 значений на кажое из 20 измерений. Даёт многообразие, какое давала бы кодовая книга с 16^20 = 1 208 925 819 614 629 174 706 176 значений. Это офигеть как много.
В то же время, обучающая выборка: всего 2 400 000 записей.
Векторные квантователи на 4096 записей (и даже 65536 записей) - дают очень плохой результат на валидационных данных. На обучающих данных - результат удовлетворительный.
Из чего я делаю вывод, что сеть при обучении - просто подстраивается под конкретный векторный квантователь и под эти данные. На валидации будет облом.
Я бы хотел увидеть протяжённости в скрытом пространстве, которые монотонно переходили из одного в другое, типо фонем/слогов/дифонов/трифонов. При этом количество их было бы жёстко задано. При этом обучение шло без ручных меток - сеть должна сама научиться находить и выделять участки речи и кластеризовать их в фонемное или слоговое множество.
А этого нет. Вместо этого - просто шум: между соседними сегментами 80x4(64 мс) - в латентном пространстве 20x1 - нет плавности перехода.
Вот для сравнения, вместо скалярного квантования - векторное 16 бит (кодовая книга на 64K записей).
Восстановленный спектр, выглядит намного хуже, чем при скалярном квантовании:

А вот его латентное пространство - снова шум в речевых сегментах:

Выходит, что на спектре по временной оси всё перетекает плавно, а когда сжали по времени (по 4 фрейма - в 1 сегмент) - получается шум.
Хотя длина фонемы/слога может быть и до 200 мс, что намного больше чем 64 мс (1 сегмент).
В идеале, хотелось бы представления в латентном пространстве - что-то типа такого:

Возвращаясь к фокальной модуляции: https://arxiv.org/pdf/2203.11926
По результатам уделала аттеншены:

Немаловажно проверять распределение в скрытом пространстве - с целью, чтобы оценить насколько качественно и без зазоров кластеризованы векторы.
Как вариант - t-SNE. При таком подходе можно представить многомерные вектора, как 2- или 3- мерные и вывести их на плоскость/куб.
Ниже - результат SFVQ квантования скрытого пространства автоэнкодера на 32 значения:

Более крупнее:
Получились спагетти, что ожидаемо :)
Внутреннее представление (непрерывно):

Внутреннее представление (SFVQ квантование на 32 значения):

P.S. Пытаюсь найти "фонемы" в скрытом пространстве, экспериментируя с лоссами и регуляризациями.
Точнее - вылепить пространство, которе содержало бы подобия фонем, позволяющих дискретизировать участки по времени.
Итак, что мы имеем на сегодняшний день.
1) Модель речевого кодека на 5000/2500/1250/625 бит/c на базе рекуррентных ячеек сети, работающий со спектрограммой и дающий разборчивый и натуральный голос с минимальными искажениями: на спектрограмме и на слух.
2) Модель речевого кодека на 5000/2500 бит/c на базе свёрточных 1D ячеек сети, работающий также со спектрограммой и дающий звук того же качества, что и в п. 1).
Все попытки получить битрейт ещё ниже (200 - 300 бит/c), не меняя стратегии (работа со спектрограммой): редуцирование по оси частот или по оси времени - приводят к одному результату: искажения сильно растут, спектрограмма "разваливается": звук становится дрожащим и/или сиплым. Разборчивость снижается, но остаётся удовлетворительной.
Поэтому, как писал в предыдущем посте, копаю далее в сторону "вылепливания фонемо-подобных паттернов" в скрытом представлении.
Начал читать про контрастно-предиктированное кодирование (CPC). Основы изложены здесь: https://arxiv.org/pdf/1807.03748
Суть метода - обучить кодер давать репрезентативные представления (не тривиальные, а богатые признаками) входных данных. Это именно то, чего не хватает спектрограммам. Проще говоря, нужна токенизация, "трансформер" своего рода:

При этом не требуется разметки данных, что само по себе очень ценно.
В простейшем случае CPC-сеть состоит из кодера (ячейка свёртки) и авто-регрессора (рекуррентная ячейка). Сеть выводит представления векторов, которые похожи на смежные вектора и различны с дальними. В идеале - на основе речевых данных сеть должна вывести элементы языка(алфавит из токенов), что близко к фонемам.
Удалось запустить обучение по методу CPC, пока на WAV-форме. Под спектрограмму адаптирую позже.
Распределение после кластеризации(квантования) выходит таким:
Визуально вижу "цветок" - более равномерное и упорядоченное покрытие.
Но есть проблемы:
1) При переобучении вектора на выходе настолько контрастируют друг с другом - что между соседними появляется шум. Надо будет проверить как со спeктрограммой пойдёт обучение.
Может придётся срезать градиент, чтобы не допустить его взрыва, и поиграться с температурой в функции потерь InfoNCE.
2) Более того, CPC метод(также, как и классический метод обучения авто-энкодера) может дать коллапс скрытого пространства (только снижение размерности) при:
а) неправильно подобранных параметрах обучения
б) отстуствии нужной регуляризации
в) неправильной архитектуре сети

В этом случае решение будет тривиальным. Слева - вариант колапсирования векторов в близко похожие (случай известен, как - "постоянное кодирование"), справа - снижение размерности скрытого пространства - вектора после обучения попали на плоскость. А должны быть на всей сфере.
Более детально про коллапс и методы его обхода здесь: https://arxiv.org/pdf/2110.09348v3
Gradius
> Ниже - результат SFVQ квантования скрытого пространства автоэнкодера на 32 значения
Это же график точек? Как я и говорил ранее, выглядит ужасно: вдоль линий плотность сильно завышена, поперек — явно недостаточна. Либо это артефакт визуализации и точки не вплотную стоят, а разнесены поперек экрана, либо теряешь несколько битов на каждой точке. По идее, качество можно оценить по распределению попарных расстояний, но тут я не специалист.
> Все попытки получить битрейт ещё ниже (200 - 300 бит/c), не меняя стратегии (работа со спектрограммой): редуцирование по оси частот или по оси времени - приводят к одному результату: искажения сильно растут, спектрограмма "разваливается": звук становится дрожащим и/или сиплым.
Математику не обманешь: каждое сообщение имеет свою энтропию, ниже которой сжать нельзя. Можно только выбрать, какую часть данных допустимо выкинуть, с соответствующей потерей информации.
}:+()___ [Smile]
> Это же график точек?
Да.
}:+()___ [Smile]
> Как я и говорил ранее, выглядит ужасно: вдоль линий плотность сильно завышена, поперек — явно недостаточна. Либо это артефакт визуализации и точки не вплотную стоят, а разнесены поперек экрана, либо теряешь несколько битов на каждой точке.
Это из-за архитектуры SFVQ.
}:+()___ [Smile]
> Математику не обманешь: каждое сообщение имеет свою энтропию, ниже которой сжать нельзя. Можно только выбрать, какую часть данных допустимо выкинуть, с соответствующей потерей информации.
Не обязательно сжимать, а потом восстанавливать. Можно пойти по пути извлечения фич, далее на синтезирующей стороне строить по эталонным фонемам полноценную речь.
———
1) Запустил Tacotron: https://github.com/bshall/Tacotron
Это фонетический синтезатор человеческой речи. На вход коды фонем, на выходе Mel-спектрограмма.
Воспроизводить любой читалкой спектра. Штатная читалка спектра у автора репозитория UniVoc - слишком медленно работает. MELGAN работает намного быстрее.
Вопрос, который актуален как никогда: возможно ли этот Tacotron переобучить не на языковые фонемы, а на некие фонетические представления, которые даёт энкодер в своём латентном пространстве?
В этом случае можно было бы передавать не дискретные значения фонемо-подобных элементов, а непрерывные апостериоры со слоя софт-макса кодера.
2) Обнаружил замечательный факт: свёртка спектрограммы во времени даёт более качественную восстановленную спектрограмму на выходе.
Ранее я делал свёртку по частотам. Это приводило к заметному искажению спектрограммы при квантовании - особенно терялись формантные полосы.
Корифеи науки нейросетей в своих трудах пишут, что спектрограмма - это довольно бедное (не репрезентативное) представление в качестве входных данных. И чтобы из неё сеть извлекла признаки - идут на ухищрение: размножают частотные каналы, пропуская их через несколько сверток во времени, применяют контрастивно-предиктивное кодирование, добавляют дельты (производные), дополняют ДКП и их дельтами,... Чтобы хоть как-то увеличить информативность на входе.
Поэтому свёртка по частотам - в моём случае убивало фичность входных данных ещё больше. Что делало разультат векторного квантования просто ужасным.
Лучше использовать WAV-форму вместо спектрограммы, но тогда возрастают сильно требования к памяти и вычислительным ресурсам, что недопустимо в моих целях.
Ниже спектрограмма, полученная с помощью временной свёртки в кодере и рекуррентной ячейке декодера. Сжатие во времени здесь 4 фрейма (16 мс * 4), квантование фич - 12 бит. Квантователь - NSVQ (который дышит шумом при обучении, обнуляя лоссы квантователя - что очень хорошо).

И это уже: 1000*12/64 = 188 бит/c ! :)
Сохранены формантные полосы. Из минусов: видны вертикальные стыки блоков шириной по 32 полосы - пока не понял, как с этим бороться на уровне нейросети. Вижу, что проще всего - интерполировать шов, как писал об этом ранее.
Внутреннее представление (с выхода квантователя) - сжатие по времени в 4 раза. Здесь я не уменьшаю число фич, так как векторному квантованию без разницы какой размерности вектор хранить в кодовой книге:

И тут тоже видны швы :)
Намного лучше, чем вот эта предыдущая попытка, которая получена свёрткой по частотам:

Gradius
> Из минусов: видны вертикальные стыки блоков шириной по 32 полосы - пока не понял, как с этим бороться на уровне нейросети.
Стыки возникали, потому что подавал спектрограмму частями, кратными 32. Отрешейпил тестовую спектрограмму в одну большую часть, получилось без швов:


Звучит на слух разборчиво, мягко, без хрипа и дрожания. С иностранным акцентом: напоминает результат, как в FocalCodec.
Здесь MSE лосс по всей спектрограмме: 0.003592. Причем это результат квантования на 4096 записей(12 бит) из кодовой книги.
В FocalCodec используется 8192 записей(13 бит)
Можно попытаться уменьшить лосс путём более тщательной подборки слоёв кодека, что и собираюсь попробовать.
Gradius
> 2) Обнаружил замечательный факт: свёртка спектрограммы во времени даёт более качественную восстановленную спектрограмму на выходе.
>
> Ранее я делал свёртку по частотам. Это приводило к заметному искажению спектрограммы при квантовании - особенно терялись формантные полосы.
Здесь важно другое: свёртка и квантование должны быть ортогональны по направлениям.
Раньше направление свертки (частоты) было параллельно квантованию (по частотам).
Только в случае перпендикулярности получается эффективное квантование. Все нейронные кодеки, которые смотрел, применяют свёртку по времени, а квантование по фичам (частотным банкам).
Но никто из них не делает 1D свертку по частотам и квантование по ним.
Gradius
> Квантователь - NSVQ
1) Обнаружил у данного квантователя недостаток: скорость обучения нейросети происходит намного быстрее, чем обучение векторов кодовой книги квантователя.
В связи с этим, значение лосса при обучении становится намного ниже, чем лосс валидации.
Потому что согласно концепции NSVQ, обучение квантователя никак не влияет на градиент сети в целом (так как происходит компенсация скачка градиента шумом), а вот вектора отливаются запоздало.
В итоге наблюдаю монотонное уменьшение лосса сети при обучении (что правильно), и скачки лосса валидации - от неприлично высокого, до редко низкого.
При этом, я контроллирую степень использования записей кодовой книги - те, что сильно редкие (допустим - менее 10% использования) - я выкидываю и перераспределяю заново (это всё может делать функционал NSVQ).
Выходит, что книга не схлопывается (что собственно и нужно), но результат не всегда оптимален и обобщаем.
Но опять же: это - дилемма. Сильно использованные вектора - нарушают кластеризацию, делая распределение, близкое к Гауссову, а мало используемые вектора - снижают эффективность кодовой книги, но эти вектора могут быть ценными - например содержать в себе переходы с одной фонемы на другую.
Сейчас пробую другие квантователи (у которых дополнительный лосс).
2) Обнаружил, что MELGAN даёт звук по качеству хуже, чем Vocos. Но Vocos не подходит из-за его огромной модели, которая к тому же ест много вычислительных ресурсов.
Нужен спектральный вокодер, но с превосходным качеством звука, по сравнению с MELGAN.
Оценил субъективно, сравнивая на слух одни и те же звуковые данные. Vocos звучит намного приятнее MelGAN'а.
3) Удалось подключить к своему кодеку блоки фокальной модуляции. Про FocalNet я говорил выше. Хорошо замещает устаревшие Attention.
С примнением ячеек FocalNet сходимость сети ускоряется по сравнению со свёрточными блоками и ячейками ResNet.
Общий лосс сети упал на 28%.