fastspeech2复现github项目--模型构建

这篇具有很好参考价值的文章主要介绍了fastspeech2复现github项目--模型构建。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

在完成fastspeech论文学习后,对github上一个复现的仓库进行学习,帮助理解算法实现过程中的一些细节;所选择的仓库复现仓库是基于pytorch实现,链接为https://github.com/ming024/FastSpeech2。该仓库是基于https://github.com/xcmyz/FastSpeech中的FastSpeech复现代码完成的,很多代码基本一致。作者前期已对该FastSpeech复现仓库进行注释分析,感兴趣的读者可见此专栏。

通过论文可知,FastSpeech2模型整体架构与FastSpeech基本一致,只是除了Duration Predicator外,还增加了Pitch Predictor和Energy Predictor两部分,并且此三部分的网络架构是一样的。所以,本仓库中transformer路径下的文件基本与https://github.com/xcmyz/FastSpeech中基本一致,在搭建FastSpeech2模型时,主要使用到其中定义的Encoder, Decoder, PostNet模块,可以进入专栏中详细了解。在本仓库中,FastSpeech2模型搭建主要涉及的两个文件为fastspeech.py和model路径下的modules.py文件。

model/modules.py

本文件主要是定义Variance Adaptor,其中主要包括Duration Predictor、Length Regulator、Pitch Predictor和Energy Predictor,详细代码和注释解析如下所示

import os
import json
import copy
import math
from collections import OrderedDict

import torch
import torch.nn as nn
import numpy as np
import torch.nn.functional as F

from utils.tools import get_mask_from_lengths, pad

device = torch.device("cuda" if torch.cuda.is_available() else "cpu")


# 完整Variance Adaptor
class VarianceAdaptor(nn.Module):
    """Variance Adaptor"""

    def __init__(self, preprocess_config, model_config):
        super(VarianceAdaptor, self).__init__()
        self.duration_predictor = VariancePredictor(model_config)
        self.length_regulator = LengthRegulator()
        self.pitch_predictor = VariancePredictor(model_config)
        self.energy_predictor = VariancePredictor(model_config)
        # 设置pitch和energy的级别
        self.pitch_feature_level = preprocess_config["preprocessing"]["pitch"]["feature"]
        self.energy_feature_level = preprocess_config["preprocessing"]["energy"]["feature"]
        assert self.pitch_feature_level in ["phoneme_level", "frame_level"]
        assert self.energy_feature_level in ["phoneme_level", "frame_level"]
        # 设置pitch和energy的量化方式
        pitch_quantization = model_config["variance_embedding"]["pitch_quantization"]
        energy_quantization = model_config["variance_embedding"]["energy_quantization"]
        n_bins = model_config["variance_embedding"]["n_bins"]
        assert pitch_quantization in ["linear", "log"]
        assert energy_quantization in ["linear", "log"]
        # 加载pitch和energy的正则化所需参数
        with open(os.path.join(preprocess_config["path"]["preprocessed_path"], "stats.json")) as f:
            stats = json.load(f)
            pitch_min, pitch_max = stats["pitch"][:2]
            energy_min, energy_max = stats["energy"][:2]

        if pitch_quantization == "log":
            self.pitch_bins = nn.Parameter(
                torch.exp(torch.linspace(np.log(pitch_min), np.log(pitch_max), n_bins - 1)),
                requires_grad=False,)
        else:
            self.pitch_bins = nn.Parameter(
                torch.linspace(pitch_min, pitch_max, n_bins - 1),
                requires_grad=False,)

        if energy_quantization == "log":
            self.energy_bins = nn.Parameter(
                torch.exp(torch.linspace(np.log(energy_min), np.log(energy_max), n_bins - 1)),
                requires_grad=False,)
        else:
            self.energy_bins = nn.Parameter(
                torch.linspace(energy_min, energy_max, n_bins - 1),
                requires_grad=False,)
        # pitch和energy的嵌入层
        self.pitch_embedding = nn.Embedding(n_bins, model_config["transformer"]["encoder_hidden"])
        self.energy_embedding = nn.Embedding(n_bins, model_config["transformer"]["encoder_hidden"])

    # 计算pitch嵌入层
    def get_pitch_embedding(self, x, target, mask, control):
        prediction = self.pitch_predictor(x, mask)  # pitch预测器预测的数值
        if target is not None:  # target存在,训练过程,使用target计算embedding
            embedding = self.pitch_embedding(torch.bucketize(target, self.pitch_bins))
        else:  # target不存在,预测过程,使用prediction计算embedding
            prediction = prediction * control  # control是用于控制的系数
            embedding = self.pitch_embedding(torch.bucketize(prediction, self.pitch_bins))
        return prediction, embedding  # prediction用于训练过程计算损失,embedding与x相加进行后续计算

    # # 计算energy嵌入层
    def get_energy_embedding(self, x, target, mask, control):
        prediction = self.energy_predictor(x, mask)  # energy预测器预测的数值
        if target is not None:  # target存在,训练过程,使用target计算embedding
            embedding = self.energy_embedding(torch.bucketize(target, self.energy_bins))
        else:  # target不存在,预测过程,使用prediction计算embedding
            prediction = prediction * control  # control是用于控制的系数
            embedding = self.energy_embedding(torch.bucketize(prediction, self.energy_bins))
        return prediction, embedding  # prediction用于训练过程计算损失,embedding与x相加进行后续计算

    def forward(
        self,
        x,
        src_mask,
        mel_mask=None,
        max_len=None,
        pitch_target=None,
        energy_target=None,
        duration_target=None,
        p_control=1.0,
        e_control=1.0,
        d_control=1.0,
    ):

        log_duration_prediction = self.duration_predictor(x, src_mask)  # 对音素序列预测的持续时间
        if self.pitch_feature_level == "phoneme_level":
            pitch_prediction, pitch_embedding = self.get_pitch_embedding(x, pitch_target, src_mask, p_control)
            x = x + pitch_embedding  # 累加pitch嵌入层
        if self.energy_feature_level == "phoneme_level":
            energy_prediction, energy_embedding = self.get_energy_embedding(x, energy_target, src_mask, p_control)
            x = x + energy_embedding  # 累加energy嵌入层

        if duration_target is not None:  # duration_target,训练过程,使用duration_target计算
            x, mel_len = self.length_regulator(x, duration_target, max_len)  # 使用duration_target调整x
            duration_rounded = duration_target
        else:  # 预测过程
            # 基于log_duration_prediction构建duration_rounded,用于调整x
            duration_rounded = torch.clamp((torch.round(torch.exp(log_duration_prediction) - 1) * d_control), min=0,)
            x, mel_len = self.length_regulator(x, duration_rounded, max_len)
            mel_mask = get_mask_from_lengths(mel_len)

        # 同上,与phoneme_level一致
        if self.pitch_feature_level == "frame_level":
            pitch_prediction, pitch_embedding = self.get_pitch_embedding(x, pitch_target, mel_mask, p_control)
            x = x + pitch_embedding
        if self.energy_feature_level == "frame_level":
            energy_prediction, energy_embedding = self.get_energy_embedding(x, energy_target, mel_mask, p_control)
            x = x + energy_embedding

        return (
            x,
            pitch_prediction,  # 此处三个prediction用于后续计算损失
            energy_prediction,
            log_duration_prediction,
            duration_rounded,
            mel_len,
            mel_mask,
        )


# 长度调节器
class LengthRegulator(nn.Module):
    """Length Regulator"""

    def __init__(self):
        super(LengthRegulator, self).__init__()

    # 对输入的音素序列x进行长度调正
    def LR(self, x, duration, max_len):
        """
        基于音素持续时间将音素序列长度与mel谱图长度对齐
        @param x: 经过FFT块转换后的音素序列,[batch_size, max_sequence_len, encoder_dim]
        @param duration: 音素持续时间矩阵,[batch_size, max_sequence_len]
        @param max_len: 音素谱图序列中最大长度
        @return: 长度经过调整后的音素序列,[batch_size, max_len, encoder_dim]
        """
        output = list()
        mel_len = list()
        for batch, expand_target in zip(x, duration):
            expanded = self.expand(batch, expand_target)  # 获得一个长度完整调整之后音素序列
            output.append(expanded)
            mel_len.append(expanded.shape[0])  # 记录mel谱图长度大小,方便后续生成mask

        # 如果传入max_len就按其进行pad,如果没有就以output中最长序列大小进行pad
        if max_len is not None:
            output = pad(output, max_len)
        else:
            output = pad(output)

        return output, torch.LongTensor(mel_len).to(device)

    def expand(self, batch, predicted):
        """
        将输入的一个音素序列的长度按其对应的持续时间调整
        @param batch:一个音频对应文本的音素序列,[max_sequence_len, encoder_dim]
        @param predicted:音素序列中每个音素对应的持续序列,长度为max_sequence_len
        @return:长度调整后的音素序列,长度与mel谱图长度一致
        """
        out = list()

        for i, vec in enumerate(batch):
            expand_size = predicted[i].item()  # i对应的音素对应持续时间,即需要重复的次数
            out.append(vec.expand(max(int(expand_size), 0), -1))  # 将i对应的音素的表征向量vec重复expand_size次
        out = torch.cat(out, 0)  # 将整个音素序列cat起来

        return out

    def forward(self, x, duration, max_len):
        output, mel_len = self.LR(x, duration, max_len)
        return output, mel_len


class VariancePredictor(nn.Module):
    """Duration, Pitch and Energy Predictor"""

    def __init__(self, model_config):
        super(VariancePredictor, self).__init__()

        self.input_size = model_config["transformer"]["encoder_hidden"]  # 输入尺寸
        self.filter_size = model_config["variance_predictor"]["filter_size"]  # 输出尺寸
        self.kernel = model_config["variance_predictor"]["kernel_size"]  # 卷积核大小
        self.conv_output_size = model_config["variance_predictor"]["filter_size"]
        self.dropout = model_config["variance_predictor"]["dropout"]
        # 定义一个包含激活函数和正则项的卷积序列,即[Con1D+Relu+LN+Dropout]+[Con1D+Relu+LN+Dropout]
        self.conv_layer = nn.Sequential(
            OrderedDict(
                [
                    (
                        "conv1d_1",
                        Conv(
                            self.input_size,
                            self.filter_size,
                            kernel_size=self.kernel,
                            padding=(self.kernel - 1) // 2,
                        ),
                    ),
                    ("relu_1", nn.ReLU()),
                    ("layer_norm_1", nn.LayerNorm(self.filter_size)),
                    ("dropout_1", nn.Dropout(self.dropout)),
                    (
                        "conv1d_2",
                        Conv(
                            self.filter_size,
                            self.filter_size,
                            kernel_size=self.kernel,
                            padding=1,
                        ),
                    ),
                    ("relu_2", nn.ReLU()),
                    ("layer_norm_2", nn.LayerNorm(self.filter_size)),
                    ("dropout_2", nn.Dropout(self.dropout)),
                ]
            )
        )

        self.linear_layer = nn.Linear(self.conv_output_size, 1)

    def forward(self, encoder_output, mask):
        out = self.conv_layer(encoder_output)  # [Con1D+Relu+LN+Dropout]+[Con1D+Relu+LN+Dropout]
        out = self.linear_layer(out)  # 最后输出前的线性层
        out = out.squeeze(-1)  # 因为线性层返回的是1,即输出的尺寸的最后一维是1,将其压缩掉

        if mask is not None:
            out = out.masked_fill(mask, 0.0)  # 将mask对应地方设置为0

        return out


# 自定义的一维卷积网络
class Conv(nn.Module):
    """
    Convolution Module
    """

    def __init__(
        self,
        in_channels,
        out_channels,
        kernel_size=1,
        stride=1,
        padding=0,
        dilation=1,
        bias=True,
        w_init="linear",
    ):
        """
        :param in_channels: dimension of input
        :param out_channels: dimension of output
        :param kernel_size: size of kernel
        :param stride: size of stride
        :param padding: size of padding
        :param dilation: dilation rate
        :param bias: boolean. if True, bias is included.
        :param w_init: str. weight inits with xavier initialization.
        """
        super(Conv, self).__init__()

        self.conv = nn.Conv1d(
            in_channels,
            out_channels,
            kernel_size=kernel_size,
            stride=stride,
            padding=padding,
            dilation=dilation,
            bias=bias,
        )

    def forward(self, x):
        x = x.contiguous().transpose(1, 2)
        x = self.conv(x)
        x = x.contiguous().transpose(1, 2)

        return x

model/fastspeech2.py

本文件将Encoder, Decoder, PostNet和Variance Adaptor模块集成在一起,完成FastSpeech2模型搭建

import os
import json

import torch
import torch.nn as nn
import torch.nn.functional as F

from transformer import Encoder, Decoder, PostNet
from .modules import VarianceAdaptor
from utils.tools import get_mask_from_lengths


class FastSpeech2(nn.Module):
    """ FastSpeech2 """

    def __init__(self, preprocess_config, model_config):
        super(FastSpeech2, self).__init__()
        self.model_config = model_config

        self.encoder = Encoder(model_config)  # Variance Adaptor之前网络,为编码器
        self.variance_adaptor = VarianceAdaptor(preprocess_config, model_config)  # Variance Adaptor
        self.decoder = Decoder(model_config)  # Variance Adaptor之后网络,为解码器
        self.mel_linear = nn.Linear(
            model_config["transformer"]["decoder_hidden"],
            preprocess_config["preprocessing"]["mel"]["n_mel_channels"],)
        self.postnet = PostNet()

        self.speaker_emb = None
        if model_config["multi_speaker"]:  # 如果为多speaker
            # 加载speaker文件
            with open(os.path.join(preprocess_config["path"]["preprocessed_path"], "speakers.json"),) as f:
                n_speaker = len(json.load(f))
            # 构建speaker嵌入层
            self.speaker_emb = nn.Embedding(n_speaker, model_config["transformer"]["encoder_hidden"],)

    def forward(
        self,
        speakers,
        texts,
        src_lens,
        max_src_len,
        mels=None,
        mel_lens=None,
        max_mel_len=None,
        p_targets=None,
        e_targets=None,
        d_targets=None,
        p_control=1.0,  # 控制系数
        e_control=1.0,
        d_control=1.0,
    ):
        src_masks = get_mask_from_lengths(src_lens, max_src_len)  # 原始文本序列mask
        mel_masks = (
            get_mask_from_lengths(mel_lens, max_mel_len)
            if mel_lens is not None
            else None)  # mel谱图序列mask

        output = self.encoder(texts, src_masks)  # 编码

        if self.speaker_emb is not None:  # 如果存在speaker嵌入层,将其和output相加
            output = output + self.speaker_emb(speakers).unsqueeze(1).expand(-1, max_src_len, -1)

        # 通过Variance Adaptor模块计算
        (
            output,
            p_predictions,
            e_predictions,
            log_d_predictions,
            d_rounded,
            mel_lens,
            mel_masks,
        ) = self.variance_adaptor(
            output,
            src_masks,
            mel_masks,
            max_mel_len,
            p_targets,
            e_targets,
            d_targets,
            p_control,
            e_control,
            d_control,
        )

        output, mel_masks = self.decoder(output, mel_masks)  # 解码
        output = self.mel_linear(output)  # 线性转换

        postnet_output = self.postnet(output) + output  # 后处理

        return (
            output,
            postnet_output,
            p_predictions,
            e_predictions,
            log_d_predictions,
            d_rounded,
            src_masks,
            mel_masks,
            src_lens,
            mel_lens,
        )

本笔记主要记录所选择的fastspeech2复现仓库中模型构建相关的代码,结合之前FastSppech2论文阅读笔记笔记中的模型部分进行理解。本笔记主要是对代码进行详细的注释,读者若发现问题或错误,请评论指出,互相学习。文章来源地址https://www.toymoban.com/news/detail-420708.html

到了这里,关于fastspeech2复现github项目--模型构建的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Github复现-测试基于transformer的变化检测模型BIT_CD

    源码链接:  GitHub - justchenhao/BIT_CD: Official Pytorch Implementation of \\\"Remote Sensing Image Change Detection with Transformers\\\" Official Pytorch Implementation of \\\"Remote Sensing Image Change Detection with Transformers\\\" - GitHub - justchenhao/BIT_CD: Official Pytorch Implementation of \\\"Remote Sensing Image Change Detection with Transformers\\\" htt

    2024年02月02日
    浏览(20)
  • 【通义千问】大模型Qwen GitHub开源工程学习笔记(3)-- 通过Qwen预训练语言模型自动完成给定的文本

    本笔记分析了使用预训练的模型生成文本的示例代码。它的步骤如下: 使用已加载的分词器 tokenizer 对输入文本进行处理,转换为模型可以理解的格式。输入文本是国家和首都的信息,最后一句是未完成的,需要模型来生成。 将处理后的输入转移到模型所在的设备上(例如

    2024年02月07日
    浏览(35)
  • Deepfake检测模型-PyDeepFakeDet项目复现实验报告-深度学习

    实验说明    该实验是对于https://github.com/wangjk666/PyDeepFakeDet模型的复现。 PyDeepFakeDet 是一款集成的、可扩展的 Deepfake 检测工具。目标是提供最先进的 Deepfake 检测模型以及用于在常用 Deepfake 数据集上训练和评估新模型的接口 。 该库 包括基于 CNN 和基于 Transformer 的方法的实现

    2024年02月08日
    浏览(124)
  • 构建企业级大语言模型应用的秘诀:GitHub Copilot 的实践之路

    GitHub Copilot 的开发团队分享了他们在构建能够同时为个人和企业用户带来价值的大语言模型(LLM)应用的心得体会。 本文经授权转载宝玉老师的个人博客(微博@宝玉xp),链接:https://baoyu.io/translations/llm/how-to-build-an-enterprise-llm-application-lessons-from-github-copilot 责编 | 夏萌 出处

    2024年02月04日
    浏览(35)
  • 『GitHub项目圈选01』一款构建AI数字人项目开源了!自动实现音视频同步!

    从本周开始,小圈正式推出『GitHub项目圈选周刊』计划,精选一些小圈遇到的或行业内大佬们推荐的好玩、有趣、实用、超前的开源项目,以周刊文章形式分享给大家观阅学习,以望一起学习,共同进步。 🔥🔥🔥 本周GitHub项目圈选****: 主要包含音视频同步、多代理框架、

    2024年02月04日
    浏览(135)
  • (一) Docker Hub网站仓库国内进不去了?手把手教你通过GitHub项目构建自己的镜像仓库站!

    目录 (一) 问题背景 (二) 搭建阿里云ARC镜像仓库站对接GitHub项目构建镜像 (1)添加项目分支  (2)创建阿里云ARC镜像仓库站 (3) 设置更改GitHub项目内容,触发阿里云镜像构建 ①Brash触发构建 ②Tag模式触发: (三) 最后的最后     今天我本来准备做 kube-state-metrics 的项目案列的时候,

    2024年02月07日
    浏览(39)
  • 李沐大模型公司细节曝光,项目GitHub空仓标星超500

    衡宇 发自 凹非寺 量子位 | 公众号 QbitAI AI大神李沐大模型创业方向,终于“水落石出”: 利用大模型能力, 做游戏引擎,且是面向4A游戏 。 关于4A游戏这个概念,目前业内没有统一的“名词解释”,但通常理解为比3A游戏更强大一点的游戏(doge)。 被曝从亚马逊首席科学家

    2024年02月05日
    浏览(141)
  • 【大模型】基于 LlaMA2 的高 star 的 GitHub 开源项目汇总

    2023年7月19日:Meta 发布开源可商用模型 Llama2。 Llama2 是一个预训练和微调的生成文本模型的集合,其规模从70亿到700亿个参数不等。 LLaMA2 的详细介绍可以参考这篇文章:【大模型】更强的 LLaMA2 来了,开源可商用、与 ChatGPT 齐平 下面介绍几个高 star 的 GitHub 开源项目: star 数

    2024年02月10日
    浏览(28)
  • TinyLlama-1.1B(小羊驼)模型开源-Github高星项目分享

    简介 TinyLlama项目旨在在3万亿tokens上进行预训练,构建一个拥有11亿参数的Llama模型。经过精心优化,我们\\\"仅\\\"需16块A100-40G的GPU,便可在90天内完成这个任务🚀🚀。训练已于2023-09-01开始。 项目地址: https://github.com/jzhang38/TinyLlama/ 特点 采用了与Llama 2完全相同的架构和分词器。

    2024年02月01日
    浏览(27)
  • 【NLP相关】GPT-X合集:GPT类模型介绍(附相关论文和Github项目地址)

    ❤️觉得内容不错的话,欢迎点赞收藏加关注😊😊😊,后续会继续输入更多优质内容❤️ 👉有问题欢迎大家加关注私戳或者评论(包括但不限于NLP算法相关,linux学习相关,读研读博相关......)👈 GPT(Generative Pre-trained Transformer)是一类基于Transformer架构的预训练语言模型

    2024年02月01日
    浏览(42)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包