基于AvgPool与自编码器的语音识别

发布于:2025-04-02 ⋅ 阅读:(29) ⋅ 点赞:(0)

《DeepSeek大模型高性能核心技术与多模态融合开发(人工智能技术丛书)》(王晓华)【摘要 书评 试读】- 京东图书

在上一章中,我们深入探讨了多种语音识别融合技术及其实现方法。具体而言,我们通过压缩相加以及拼接的策略,有效地融合了语音与文本特征。但是需要注意,在特征处理层面,我们直接对语音特征做了操作,而并未引入压缩机制。

本节将采纳前述的AvgPool技术,对语音特征向量进行压缩处理。这一步骤至关重要,因为它能够在保留关键信息的同时,降低特征维度,从而提升模型的运算效率与准确性。

此外,我们还将探索一种全新的语音识别方法—自编码语音识别。自编码器以其独特的无监督学习机制,在特征学习与表示方面展现出卓越性能。在自编码语音识别的框架下,我们将利用自编码器对语音数据进行深层次的特征提取与重构,以期在复杂的语音环境中,实现更加稳健与高效的识别性能。通过这一系列的技术创新与融合,我们期望能够推动语音识别领域的发展,为实际应用场景中的语音交互体验带来质的提升。

12.2.1  修改后的AvgPool函数

我们计划利用AvgPool技术来实现语音文本的压缩。相较于上一章中严谨设定的、专门用于图像压缩的AvgPool方法,针对当前的2D特征矩阵,我们可以对AvgPool进行适当修改,以适应语音特征的处理需求,从而有效地完成特征的压缩。通过调整AvgPool的参数和操作方式,我们可以更好地捕捉和提炼语音数据中的关键信息,为后续的语音识别任务奠定坚实基础。这种改进不仅有助于提升语音识别的准确性和效率,也为语音处理领域带来了新的思路和方法。

新的AvgPool类如下所示。

class AvgPoolProjector(torch.nn.Module):

    def __init__(
            self,
            layer_num: int = 2,
            query_num: int = 20,    #这里是输出的seq_length
            mm_hidden_size: int = 688,  #图片经过patch_embedding后的d_model,也就是输入的维度
            llm_hidden_size: int = model_cfg.dim, #语言模型的d_model,也就是输出的维度
    ):
        super().__init__()
        self.layer_num = layer_num
        self.query_num = query_num
        self.mm_hidden_size = mm_hidden_size
        self.llm_hidden_size = llm_hidden_size
        self.build_net()

    def build_net(self):

        sampler = torch.nn.AdaptiveAvgPool1d(self.query_num)
        self.sampler = sampler
        modules = [torch.nn.Linear(self.mm_hidden_size, self.llm_hidden_size)]
        for _ in range(1, self.layer_num):
            modules.append(torch.nn.GELU())
            modules.append(torch.nn.Linear(self.llm_hidden_size, self.llm_hidden_size))
        modules.append(torch.nn.RMSNorm(self.llm_hidden_size))
        self.mlp_projector = torch.nn.Sequential(*modules)

    def forward(self, visual_feat: torch.Tensor):
        shaped_visual_feat = einops.rearrange(visual_feat, 'b l d -> b d l')
        pooled_visual_feat = self.sampler(shaped_visual_feat)
        reshaped_visual_feat = einops.rearrange(pooled_visual_feat, 'b d l-> b l d')
        output_feat = self.mlp_projector(reshaped_visual_feat)  # [64, 144, 4096])

        return output_feat

在上面代码中,我们将原有的AdaptiveAvgPool2d替换成AdaptiveAvgPool1d,并将对应的压缩维度进行调整。modules的作用是建立了多个全连接层对维度特征进行处理,从而对特征进行计算。

12.2.2  自编码器语音识别模型1:数据准备

下面我们将使用自编码器进行语音识别,直接将输入的语音特征与文本内容相匹配,并输出结果。首先需要完成对应的数据准备,代码如下所示。

class TextSamplerDataset(torch.utils.data.Dataset):
    def __init__(self, token_list = token_list,wav_image_list = wav_image_list):
        super().__init__()
        self.token_list = token_list
        self.wav_image_list = wav_image_list

    def __getitem__(self, index):
        token = self.token_list[index]
        token = torch.tensor(token).long()
        token_tgt = token

        wav_image = self.wav_image_list[index]#sound_untils.audio_to_image(audio, sampling_rate, 128, 0, sampling_rate//2) #输出的是(128, 688)
        wav_image = torch.tensor(wav_image,dtype=torch.float).float()
        return wav_image,token_tgt

    def __len__(self):
        return len(self.token_list)

我们可以直接使用上一节提取后的语音特征与文本内容。在输出端,我们无需使用“错位”输入法,而只需输出结果文本,目标是将语音特征与文本内容对齐即可。

12.2.3  自编码器语音识别模型2:模型设计

接下来就是使用自编码器进行语音识别的模型设计。我们需要首先将语音特征压缩,之后使用自注意模型对语音进行识别,我们的语音识别模型如下所示。

from 第十三章_speed2text.moudle import blocks
class GLMSimple(torch.nn.Module):
    def __init__(self,dim = model_cfg.dim,num_tokens = model_cfg.num_tokens,device = all_config.device):
        super().__init__()
        self.num_tokens = num_tokens
        self.causal = model_cfg.causal
        self.device = device
        self.head_num = model_cfg.head_num
        self.token_emb = torch.nn.Embedding(num_tokens,dim)
        self.layers = torch.nn.ModuleList([])
        self.dim = model_cfg.dim
        self.seq_len = 20

        self.avg_pool_layer = AvgPoolProjector()
        self.avg_position = (torch.nn.Parameter(data=torch.Tensor(self.seq_len,self.dim), requires_grad=True))
        for _ in range(model_cfg.depth):
            block = blocks.ResidualAttention(dim,self.head_num)
            self.layers.append(block)

        self.norm = torch.nn.RMSNorm(dim)
        self.to_logits = torch.nn.Linear(dim, num_tokens, bias=False)

    def forward(self,image):
        embedding = self.avg_pool_layer(image) + self.avg_position
        for id,layer in enumerate(self.layers):
            embedding = self.norm(embedding)
            embedding = layer(embedding)

        embedding = torch.nn.Dropout(0.1)(embedding)
        logits = self.to_logits(embedding)

        return logits

可以看到,在上面自编码语音识别模型中,直接对输入的语音内容进行压缩,之后通过一个多层自注意力模型完成对特征的转换,从而最终完成文本的自编码回归输出。

12.2.4  自编码器语音识别模型3:模型的训练与预测

在对自编码器进行模型的训练上,我们可以遵循上一章介绍的自回归模型训练方法,并使用相同的训练模块和步骤完成模型的训练,此时我们只需要调整模型的输入即可,部分代码如下所示。

pbar = tqdm(train_loader,total=len(train_loader))
for wav_image,token_tgt in pbar:

wav_image = wav_image.to(device)
token_tgt = token_tgt.to(device)
logits = model(wav_image)
loss = criterion(logits.view(-1, logits.size(-1)), token_tgt.view(-1))

在上面代码中,根据我们设置的数据载入类,只需要根据输出的语音特征以及文本进行对齐后,计算损失值即可。

而在模型的预测部分,我们也只需要把待预测的内容在包装后装入模型,并输入到自编码模型中进行预测部分的推断。完整的模型预测代码如下所示。

import torch

# constants
LEARNING_RATE = 2e-4
BATCH_SIZE = 48

# helpers
from 第十四章.自编码语音转换 import all_config
model_cfg = all_config.ModelConfig
device = "cpu"

from 第十四章.自编码语音转换.moudle import glm_model_1 as glm_model
model = glm_model.GLMSimple(num_tokens=model_cfg.vocab_size,dim=model_cfg.dim)
model.to(device)

save_path = "./saver/glm_generator.pth"
model.load_state_dict(torch.load(save_path))

target_text = "我要查一下我刚刚下载的游戏"
sound_file = "../dataset/aidatatang_200zh/G0013/T0055G0013S0002.wav"
audio, orig_sr = sf.read(sound_file, dtype="float32")
audio = sound_untils.crop_or_pad(audio, length=16000 * 22)
wav_image = sound_untils.audio_to_image(audio, 16000, 128, 0, 16000//2) #输出的是(128, 688)
wav_image = torch.tensor(wav_image,dtype=torch.float).unsqueeze(0).to(device)

logits = model(wav_image)
logits = torch.nn.functional.softmax(logits, dim=-1)
result_token = torch.argmax(logits, dim=-1)[0]


_text = [vocab[id] for id in result_token]
_text = "".join(_text)
print("目标:",target_text)
print("输出:",_text)

请读者自行运行代码查看结果。