Подробное объяснение модели Tacotron2

алгоритм

Это второй день моего участия в ноябрьском испытании обновлений, подробности о мероприятии:Вызов последнего обновления 2021 г.

1 Обзор

Tacotron2 — это фреймворк сквозного синтеза речи, предложенный Google Brain в 2017 году. Модель можно рассматривать как состоящую из двух частей снизу вверх:

  1. Сеть прогнозирования спектра: сеть кодировщик-внимание-декодер для прогнозирования входной последовательности символов как последовательности кадров спектра Мел.
  2. вокодер: модифицированная версия WaveNet для генерации сигналов во временной области из предсказанных последовательностей мел-спектральных кадров.

2 энкодера

Ввод кодировщика - это несколько предложений, и основной единицей каждого предложения является символ, например

  • Английский «hello world» будет разделен на «h e l low w o r l d» в качестве ввода.
  • Китайский «привет, мир» сначала идентифицирует пиньинь, чтобы получить «ni hao shi jie», а затем разделяет его на «nih ao sh ij ie» в соответствии с согласными и гласными или напрямую разделяет его на «nihaoshijie». аналогично английскому"

Конкретный процесс Encoder:

  1. Измерение входных данных[batch_size, char_seq_length]
  2. Используя 512-мерное встраивание символов, сопоставьте каждый символ с 512-мерным вектором, и выходное измерение будет[batch_size, char_seq_length, 512]
  3. 3 одномерные свертки, каждая свертка включает 512 ядер, размер каждого ядра 5*1 (то есть каждый раз просматривается 5 символов). После каждой свертки выполняются BatchNorm, ReLU и Dropout. Выходной размер[batch_size, char_seq_length, 512](Для обеспечения неизменности размерности каждой свертки используется прокладка)
  4. Вывод, полученный выше, бросьтеОднослойный BiLSTM, размер скрытого слоя равен 256, так как это двунаправленный LSTM, окончательный выходной размер равен[batch_size, char_seq_length, 512]

3 Механизм внимания

На приведенном выше рисунке показаны вход и выход первого внимания. в,y0y_0является начальным вводом PreNet<S>кодированное представление,c0c_0является текущим «контекстом внимания». На начальном первом шагеy0y_0иc0c_0инициализируются вектором со всеми нулями, тогдаy0y_0иc0c_0Конкатенация для получения 768-мерного вектораy0,cy_{0,c}, вектор используется в качестве входных данных LSTMcell вместе с вниманием_скрытым и вниманием_ячейки (внимание_скрытый на самом деле является скрытым_состоянием LSTMcell, а внимание_ячейка на самом деле является состоянием ячейки LSTMcell). Полученный результатh1h_1И внимание_ячейка, здесь нет отдельного имени для внимания_ячейки, в основном с учетом того, что это "соевый соус", потому что кроме внимания_рнн, внимание_ячейка больше нигде не используется

Attention_Layer принимает всего пять входных данных:

  1. h1h_1- переменная, связанная со спектром mel
  2. mmФункции, извлеченные из исходной последовательности символов через слой кодировщика
  3. m'm'даmmПосле прохождения линейного
  4. Attention_weights_cat получается путем сращивания исторических (последний момент)
  5. Маска вся фальшивая, в принципе бесполезна

Детали расчета следующие:

Основная часть — это get_alignment_energies, которая вводит позиционные функции внутри этой функции, поэтому онаГибридный механизм внимания

Гибридный механизм внимания на самом деле является комбинацией механизма внимания содержания (регулярное внимание) и механизму позиционного внимания:

eij=score(si1,αi1,hj)e_{ij}=score(s_{i-1},\alpha_{i-1},h_j)

в,si1s_{i-1}скрытое состояние предыдущего декодера,αi1\alpha_{i-1}вес предыдущего внимания,hjh_jпервыйjjскрытое состояние кодировщика. добавить к нему смещениеbb, итоговая функция оценки рассчитывается следующим образом:

eij=vaTtanh(Wsi1+Vhj+Ufi,j+b)e_{ij}=v_a^T\mathop{tanh}(Ws_{i-1}+Vh_j+Uf_{i,j}+b)

в,vav_a,WW,VV,UUиbbпараметры для обучения,fi,jf_{i,j}это предыдущий вес вниманияαi,j\alpha_{i,j}Признак местоположения, полученный путем свертки,fi=F*αi1f_i=F*\alpha_{i-1}

Механизм внимания Tancotron2 в основном такой же, как гибридный механизм внимания, но он немного отличается.

ei,j=score(si,cαi1,hj)=vaTtanh(Wsi+Vhj+Ufi,j+b)e_{i,j}=score(s_i,c\alpha_{i-1},h_j)=v_a^T\mathop{tanh}(Ws_i+Vh_j+Uf_{i,j}+b)

в,sis_iСмещение для текущего скрытого состояния декодера, а не для предыдущего шагаbbИнициализирован до 0, функция местоположенияfif_iсовокупный вес вниманияcαic\alpha_iСвертка происходит от:

fi=F*cαi1cαi=j=1i1αj\begin{aligned} f_i&=F*c\alpha_{i-1}\\ c\alpha_i&=\sum_{j=1}^{i-1}\alpha_j \end{aligned}

Функция get_alignment_energies показана следующим образом:

4 декодера

Декодер представляет собой авторегрессионную структуру, которая предсказывает спектрограмму из закодированной входной последовательности, по одному кадру за раз.

  1. Спектр, предсказанный на предыдущем шаге, сначала передается в PreNet, который содержит два слоя нейронных сетей PreNet выступает в роли информационного узкого места (узкого места), необходимого для обучения вниманию.
  2. Выходные данные PreNet объединяются с вектором контекста внимания и передаются в двухуровневый LSTM с 1024 единицами. Выходные данные LSTM снова объединяются с вектором контекста внимания, а затем подвергаются линейной проекции для прогнозирования целевого спектра.
  3. Наконец, целевой спектральный кадр проходит через 5-уровневую свертку PostNet (сеть постобработки), а затем вывод добавляется к выводу Linear Projection (остаточное соединение) в качестве окончательного вывода.
  4. С другой стороны, выходные данные LSTM объединяются вместе с вектором контекста внимания, проецируются в скаляр, а затем передаются сигмовидной функции активации, чтобы предсказать, была ли предсказана выходная последовательность.

Схема и код уровня PreNet следующие:

class LinearNorm(torch.nn.Module):
    def __init__(self, in_dim, out_dim, bias=True, w_init_gain='linear'):
        super(LinearNorm, self).__init__()
        self.linear_layer = torch.nn.Linear(in_dim, out_dim, bias=bias)

        torch.nn.init.xavier_uniform_(
            self.linear_layer.weight,
            gain=torch.nn.init.calculate_gain(w_init_gain))

    def forward(self, x):
        return self.linear_layer(x)

class Prenet(nn.Module):
    def __init__(self, in_dim, sizes):
        super(Prenet, self).__init__()
        in_sizes = [in_dim] + sizes[:-1]
        self.layers = nn.ModuleList(
            [LinearNorm(in_size, out_size, bias=False)
             for (in_size, out_size) in zip(in_sizes, sizes)])

    def forward(self, x):
        for linear in self.layers:
            x = F.dropout(F.relu(linear(x)), p=0.5, training=True)
        return x

Иллюстрация слоя PostNet показана ниже:

Из приведенной ниже части инициализации декодера видно, что декодер состоит из prenet,attention_rnn,Attention_layer,decoder_rnn, linear_projection, gate_layer.

Reference