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

《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)

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

<think> 我们正在讨论一个完整的基于自编码器(Autoencoder, AE)的工业图像缺陷检测模型架构。根据之前的讨论,我们知道自编码器通过学习正常样本的重构来实现缺陷检测,缺陷区域会表现出较高的重构误差。现在,我们将构建一个完整的架构,包括输入处理、编码器、解码器、损失函数、后处理以及评估等部分。 ### 完整架构设计 一个完整的工业缺陷检测系统通常包括以下几个模块: 1. **数据预处理**:适应工业图像的特点。 2. **自编码器网络**:包括编码器和解码器。 3. **损失函数**:用于训练网络。 4. **异常分数计算**:将重构误差转化为缺陷概率或热力图。 5. **后处理**:优化检测结果。 6. **评估指标**:量化模型性能。 下面我们详细展开每个部分。 #### 1. 数据预处理 工业图像通常具有高分辨率,且可能存在光照不均、噪声等问题。预处理步骤包括: - **归一化**:将像素值归一化到$[0,1]$或$[-1,1]$。 - **调整尺寸**:调整为网络输入的固定尺寸(如$256\times256$)。 - **数据增强**:仅对正常样本使用,如旋转、翻转、亮度调整等,增加训练数据的多样性[^1]。 - **灰度化**:如果颜色信息不重要,可转为灰度图以减少计算量。 #### 2. 自编码器网络 我们设计一个卷积自编码器(Convolutional Autoencoder, CAE),它由编码器和解码器组成,中间通过一个潜在向量(bottleneck)连接。 **编码器(Encoder)**:由多个卷积层和下采样层(如最大池化或步长卷积)组成,逐步减小空间尺寸,增加通道数,提取高级特征。例如: - 输入:$256\times256\times3$(RGB图像) - 经过4个卷积块(每个块包含卷积、批归一化、ReLU激活),每次空间尺寸减半,通道数加倍。 - 最终输出潜在向量:$16\times16\times512$(即bottleneck层)。 **解码器(Decoder)**:编码器对称,由多个上采样层(如转置卷积或插值)和卷积层组成,逐步恢复原始尺寸。 - 输入:潜在向量($16\times16\times512$) - 经过4个上采样块(每个块包含上采样、卷积、批归一化、ReLU激活),每次空间尺寸加倍,通道数减半。 - 最终输出重构图像:$256\times256\times3$,使用Sigmoid激活将输出值限制在$[0,1]$。 为了保留更多细节,我们可以引入跳跃连接(Skip Connections)构建类似U-Net的结构,将编码器的特征图解码器的对应层连接,帮助重构细节[^2]。 #### 3. 损失函数 训练时仅使用正常样本,损失函数衡量原始图像重构图像之间的差异。常用的损失函数包括: - **像素级均方误差(MSE)**:$L_{MSE} = \frac{1}{N}\sum_{i=1}^{N} \| \mathbf{x}_i - \mathbf{\hat{x}}_i \|^2$,其中$N$为像素总数。 - **结构相似性指数(SSIM)损失**:$L_{SSIM} = 1 - \text{SSIM}(\mathbf{x}, \mathbf{\hat{x}})$,SSIM考虑了亮度、对比度和结构信息,对图像结构变化更敏感[^3]。 - **混合损失**:结合MSE和SSIM,例如:$L_{total} = \alpha L_{MSE} + \beta L_{SSIM}$,其中$\alpha$和$\beta$为权重系数。 #### 4. 异常分数计算 在测试阶段,对于输入图像$\mathbf{x}$,模型输出重构图像$\mathbf{\hat{x}}$,然后计算每个像素的异常分数: - **重构误差图**:$M(x,y) = \| \mathbf{I}_{orig}(x,y) - \mathbf{I}_{rec}(x,y) \|$(绝对值或平方差)。 - **异常热力图**:将误差图归一化到$[0,1]$,并通过高斯滤波平滑,得到热力图。 - **图像级异常分数**:取整个热力图的最大值或平均值,用于判断该图像是否包含缺陷。 #### 5. 后处理 - **阈值分割**:对热力图应用阈值(如Otsu方法或固定阈值)生成二值缺陷掩码。 - **形态学操作**:使用开运算、闭运算去除噪声和小区域。 - **连通区域分析**:筛选面积大于阈值的区域作为最终缺陷。 #### 6. 评估指标 - **图像级AUROC**:衡量模型区分正常图像和缺陷图像的能力。 - **像素级AUROC**:衡量缺陷定位的准确性。 - **F1-score**:综合考虑精确率和召回率。 ### 示例代码(PyTorch实现核心架构) ```python import torch import torch.nn as nn import torch.nn.functional as F class ConvBlock(nn.Module): def __init__(self, in_channels, out_channels): super().__init__() self.conv = nn.Sequential( nn.Conv2d(in_channels, out_channels, kernel_size=3, padding=1), nn.BatchNorm2d(out_channels), nn.ReLU(inplace=True) ) def forward(self, x): return self.conv(x) class Encoder(nn.Module): def __init__(self, channels=[3, 32, 64, 128, 256, 512]): super().__init__() self.blocks = nn.ModuleList() for i in range(len(channels)-1): self.blocks.append(ConvBlock(channels[i], channels[i+1])) self.blocks.append(nn.MaxPool2d(2)) def forward(self, x): features = [] for block in self.blocks: x = block(x) if isinstance(block, ConvBlock): features.append(x) # 保存特征图用于跳跃连接 return x, features[:-1] # 返回bottleneck和特征图(去掉最后一个卷积块后的特征) class Decoder(nn.Module): def __init__(self, channels=[512, 256, 128, 64, 32]): super().__init__() self.upsamples = nn.ModuleList() self.conv_blocks = nn.ModuleList() for i in range(len(channels)-1): self.upsamples.append(nn.Upsample(scale_factor=2, mode='bilinear', align_corners=True)) self.conv_blocks.append(ConvBlock(channels[i] + channels[i], channels[i+1])) # 跳跃连接拼接 def forward(self, x, encoder_features): for i, (upsample, conv_block) in enumerate(zip(self.upsamples, self.conv_blocks)): x = upsample(x) # 跳跃连接:拼接编码器对应层的特征图 x = torch.cat([x, encoder_features[-(i+1)]], dim=1) # 从后往前取特征 x = conv_block(x) return x class Autoencoder(nn.Module): def __init__(self): super().__init__() self.encoder = Encoder() self.decoder = Decoder() self.final_conv = nn.Conv2d(32, 3, kernel_size=3, padding=1) self.sigmoid = nn.Sigmoid() def forward(self, x): latent, features = self.encoder(x) x = self.decoder(latent, features) x = self.final_conv(x) return self.sigmoid(x) # 损失函数示例:MSE + SSIM def loss_function(original, reconstructed, alpha=0.5, beta=0.5): mse_loss = F.mse_loss(original, reconstructed) ssim_loss = 1 - ssim(original, reconstructed) # 需要实现SSIM函数 return alpha * mse_loss + beta * ssim_loss ``` ### 训练测试流程 **训练**: 1. 使用正常图像数据集,输入自编码器。 2. 计算重构损失,反向传播更新参数。 **测试**: 1. 输入测试图像,得到重构图像。 2. 计算重构误差图,生成热力图。 3. 根据热力图进行缺陷定位和分类。 ### 挑战优化方向 - **提高小缺陷检测能力**:使用多尺度特征融合(如特征金字塔)[^1]。 - **减少误检**:在潜在空间引入正则化(如VAE)或记忆模块(MemAE)[^2]。 - **适应复杂背景**:结合注意力机制,让模型聚焦于关键区域。 §§相关问题§§ 1. 如何选择自编码器的潜在空间维度? 2. 工业缺陷检测中,如何处理不同尺寸的缺陷? 3. 除了自编码器,还有哪些无监督方法可用于工业缺陷检测? 4. 如何在资源受限的工业设备上部署自编码器模型? </think> ### 完整的基于自编码器(AE)的工业图像缺陷检测模型架构 以下是一个端到端的工业缺陷检测系统架构设计,融合了数据预处理、核心网络、异常检测和后处理等关键模块: ```mermaid graph TD A[工业图像输入] --> B[数据预处理] B --> C[自编码器AE] C --> D[重构图像输出] D --> E[异常检测] E --> F[后处理] F --> G[缺陷报告] subgraph 核心网络 C --> C1[编码器] C1 --> C2[潜在空间] C2 --> C3[解码器] end subgraph 异常检测 E --> E1[重构误差计算] E1 --> E2[异常热力图] E1 --> E3[全局异常分数] end ``` #### 一、数据预处理模块 1. **图像归一化** 将像素值归一化到$[0,1]$范围: $$ \text{normalized} = \frac{\text{image} - \min(\text{image})}{\max(\text{image}) - \min(\text{image})} $$ 2. **尺寸标准化** 使用双线性插值统一图像尺寸(如$256\times256$),确保网络输入一致。 3. **数据增强(仅训练阶段)** - 随机旋转($±5^\circ$) - 亮度调整($±20\%$) - 高斯噪声($\sigma=0.01$) *注意:仅对正常样本增强,避免学习缺陷模式* #### 二、核心自编码器架构 ```python import torch import torch.nn as nn class IndustrialAE(nn.Module): def __init__(self, latent_dim=128): super().__init__() # 编码器(下采样) self.encoder = nn.Sequential( nn.Conv2d(3, 32, 3, padding=1), # 输入通道, 输出通道, 核大小 nn.BatchNorm2d(32), nn.ReLU(), nn.MaxPool2d(2), # 128x128 nn.Conv2d(32, 64, 3, padding=1), nn.BatchNorm2d(64), nn.ReLU(), nn.MaxPool2d(2), # 64x64 nn.Conv2d(64, 128, 3, padding=1), nn.BatchNorm2d(128), nn.ReLU(), nn.MaxPool2d(2) # 32x32 ) # 潜在空间瓶颈层 self.latent = nn.Linear(128*32*32, latent_dim) # 解码器(上采样) self.decoder = nn.Sequential( nn.Linear(latent_dim, 128*32*32), nn.Unflatten(1, (128, 32, 32)), nn.ConvTranspose2d(128, 64, 3, stride=2, padding=1, output_padding=1), nn.BatchNorm2d(64), nn.ReLU(), # 64x64 nn.ConvTranspose2d(64, 32, 3, stride=2, padding=1, output_padding=1), nn.BatchNorm2d(32), nn.ReLU(), # 128x128 nn.ConvTranspose2d(32, 3, 3, stride=2, padding=1, output_padding=1), nn.Sigmoid() # 256x256 ) def forward(self, x): encoded = self.encoder(x) encoded = torch.flatten(encoded, start_dim=1) latent = self.latent(encoded) decoded = self.decoder(latent) return decoded ``` #### 三、损失函数设计 1. **像素级重构损失** $$ \mathcal{L}_{MSE} = \frac{1}{WH}\sum_{i=1}^{W}\sum_{j=1}^{H} \| x_{ij} - \hat{x}_{ij} \|^2 $$ 2. **结构相似性损失(SSIM)** $$ \mathcal{L}_{SSIM} = 1 - \frac{(2\mu_x\mu_{\hat{x}} + c_1)(2\sigma_{x\hat{x}} + c_2)}{(\mu_x^2 + \mu_{\hat{x}}^2 + c_1)(\sigma_x^2 + \sigma_{\hat{x}}^2 + c_2)} $$ 3. **组合损失函数** $$ \mathcal{L}_{total} = \alpha \mathcal{L}_{MSE} + \beta \mathcal{L}_{SSIM} $$ 其中$\alpha=0.7$, $\beta=0.3$为平衡系数[^1] #### 四、异常检测模块 1. **像素级异常热力图** $$ M(x,y) = \| I_{\text{original}}(x,y) - I_{\text{recon}}(x,y) \|_1 $$ 2. **全局异常分数** $$ S_{\text{global}} = \frac{1}{WH} \sum_{x=1}^{W} \sum_{y=1}^{H} M(x,y) $$ 3. **动态阈值算法** $$ \text{threshold} = \mu_{\text{train}} + k \cdot \sigma_{\text{train}} $$ 其中$k$根据验证集调整(通常$k=3\sim5$) #### 五、后处理模块 1. **热力图优化** - 高斯滤波($\sigma=2$)平滑噪声 - 形态学开运算去除小连通区域 2. **缺陷定位** ```python def detect_defects(heatmap, threshold): binary_map = (heatmap > threshold).astype(np.uint8) contours, _ = cv2.findContours(binary_map, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) return [c for c in contours if cv2.contourArea(c) > min_area] ``` 3. **缺陷量化** - 面积占比:$\frac{\text{缺陷像素数}}{\text{总像素数}}$ - 最大缺陷尺寸:$\max(\text{contour areas})$ #### 六、训练推理流程 **训练阶段**: ```mermaid graph LR A[正常样本] --> B[数据增强] B --> C[自编码器] C --> D[计算重构损失] D --> E[反向传播] E --> F[更新网络权重] ``` **推理阶段**: ```mermaid graph LR A[测试图像] --> B[预处理] B --> C[自编码器] C --> D[重构图像] D --> E[计算热力图] E --> F[阈值分割] F --> G[缺陷定位] G --> H[生成报告] ``` #### 七、性能优化技巧 1. **多尺度特征融合** 在编码器中添加金字塔池化模块,提升小缺陷检测能力[^2] 2. **注意力机制** 在瓶颈层添加CBAM模块: $$ \text{Attention} = \sigma(\text{MLP}(\text{AvgPool}(F)) + \text{MLP}(\text{MaxPool}(F))) $$ 3. **轻量化部署** - 知识蒸馏:大模型→小模型 - 量化感知训练(INT8精度) ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值