2022-C4AI-基于飞浆的齿轮箱异常声音“听诊”系统

★★★ 本文源自AI Studio社区精品项目,【点击此处】查看更多精品内容 >>>


项目意义

当今世界正经历百年未有之大变局,全球产业发展格局正在深刻调整,“十四五”规划提出要加快发展现代产业体系,巩固壮大实体经济根基。当前和今后一个时期,我国机械工业亟需增强产业基础能力、提高产业链基础水平,以应对国内外经济环境变化所带来的一系列新机遇新挑战。而齿轮作为绝大多数机械设备的核心部件,在工业生产中有着广泛的应用,其一旦发生故障,会造成重大经济损失甚至人员伤亡等严重后果。因此,进行适应实际工况的智能故障诊断研究,提高齿轮箱故障诊断的准确性、减少人为干预和人工成本,以保障其乃至整个设备、生产线的安全和稳定运行。

设计目标

本项目以齿轮箱声音信号为基础,以深度神经网络为理论手段,挖掘异常声音和故障工况之间的潜在规律,构建具有高精度和高泛化能力的异常检测模型,旨在解决实际生产中缺乏大量可用的异常样本、不同工况导致的域间差异大以及类内分布差异大等实际生产问题。我们的“听诊”系统可以只用源域数据训练但能在目标域中工作,避免在更改机器设置或噪音条件时收集机器的新记录和重新训练异常检测系统的需要。

项目特色

此项目的实施推动了深度学习理论在工业大数据分析尤其是工业故障诊断领域的应用。据了解,83%的工业企业基于平台开展工业设备和产品状态在线监测、故障在线诊断、预测性维护、远程运维等应用服务。68%的工业企业基于平台处理分析生产制造、企业运营管理等各类数据,开展生产过程优化、能耗优化、质量优化、安全管理、作业指导、采销决策优化等业务运营优化服务。人工智能与工业故障诊断交叉融合应用成效主要可分为四大类:成本降低、效率提升、产品和服务能力提升、业务和模式创新等,具体应用场景案例分布与应用案例成效见图1,因此本项目具有理论研究价值和实用意义。

                     图1 具体应用场景案例分布与应用案例成效图

市场价值

1、可普及、可泛化程度

我们团队的机器“听诊”系统旨在解决实际生产中缺乏大量可用的异常样本、不同工况导致的域间差异大以及类内分布差异大等实际生产问题,避免在更改机器设置或噪音条件时收集机器的新记录和重新训练异常检测系统的需要。并且泛化能力强,除了齿轮箱外,对电机、泵、阀门和滑轨等等都有较好的检测效果,根据企业需要还可以针对专门的机器进行优化,以此达到更好的检测效果。并且信号采集成本和服务器成本低,可以以硬件销售与服务订阅形式推广。

2、外部验证和调查

                     图2 2015-2021机器异常检测行业的收入

由上图可知,我国机器异常检测行业的收入逐年增加,到2022年有望突破6000亿。因为我国是机器大国,有很多机器化企业,每天在工作的机器达到数百亿台,这些机器设备无时无刻都需要进行异常检测,这不仅是对机器是一种保护而且还是保护工人的生命财产安全,并且还满足国家在十四五规划中提出的加快发展现代产业体系,巩固壮大实体经济根基,因此设计出一种用于机器异常检测的产品是目前社会发展的必然趋势。我们团队走访调研了重庆、成都一些带有齿轮的大型工厂,发现目前市面上在齿轮异常检测中用到的是齿轮检测仪,它可以用来检测齿轮传动精度;齿轮检测概论;圆柱齿轮单项测量等,齿轮检测仪的优点是轻质量的外罩减少了整机的重量,从而提高了效率,电机远程放置减少了移动质量,提高了速度,也避免了电机发热对机器性能带来的影响,但是它的缺点是小型加工企业不能够检测,只适合精度要求不是太高的大批量检测,并且设备昂贵。我们分析了齿轮检测仪的优缺点,提出了一种用声音作为信号检测的仪器,在齿轮检测仪基础之上进行了改进,继承了齿轮检测仪的优点,并克服了齿轮检测仪的缺点,声音信号采集、非接触式测量、故障敏感性强,检测精度高,适合进行大批量检测,同时我们的设备轻便,成本较低,提高了检测速度并且不会对机械设备造成任何干扰。同时我们还参考了2021-2027全球与中国机器异常检测解决方案市场现状及未来发展趋势的报告、以及深度学习在机器异常检测中的应用等30余篇参考文献与资料。

作品内容

1、数据处理

本项目齿轮箱数据集来自声学场景和事件的检测和分类2021(Detection and Classification of Acoustic Scenes and Events 2021)任务2中MIMII DUE的gearbox数据集,该数据集与实际生产环境十分接近,包含警铃,钟声,机器声等等环境干扰声音。
数据集如图3所示。表3.1中,gearbox数据集包括3个子集,00到02,称为“section”,每个section对应于情况相似的单个齿轮箱。自采数据集视为一个section。每个section由来自两个域的数据组成,分别为源域和目标域,两个域之间具有不同的齿轮箱工况条件,如机器负载、粘度、加热温度、环境噪声、信噪比等方面存在不同。

                       图3 数据集概述

由于原始声音样本是一维时域信号,无法直观得到频域的变化规律,且包含的有效信息较少,不能直接作为声音识别的输入,在进行声音识别之前,需要将音频样本中的原始数据转化为更有意义的表示。本项目选择使用Log—Mel来进行表示,因为梅尔刻度上的声音信号更加符合人耳的听觉特征,使用对数操作也是考虑到人耳对声音强度感受不是线性的。不同于MFCC表示频谱图的轮廓特征,梅尔谱图含有的信息量更充分,比较能反映全部的频谱图信息。为了禁止模型过度拟合特定的训练数据,本项目结合声音频谱图的特性,对频谱图进行了CutMix数据增强,进行增强后的logmel频谱图如图4所示。

                    图4 Logmel谱图Cutmix数据增强
#  CutMix 的切块功能
def rand_bbox(size, lam):
    if len(size) == 4:
        W = size[3]
        H = size[2]
    elif len(size) == 3:
        W = size[1]
        H = size[0]
    else:
        raise Exception
    cut_rat = np.sqrt(1. - lam)
    cut_w = int(W * cut_rat)
    cut_h = int(H * cut_rat)
    # uniform
    cx = np.random.randint(W)
    cy = np.random.randint(H)
    bbx1 = 0
    bby1 = 0
    bbx2 = np.clip(cx + cut_w // 2, 0, W)
    bby2 = 128
    return bbx1, bby1, bbx2, bby2
    
class traindata(Dataset):
def __init__(self,dict,category,xc,train=False):
    super(traindata, self).__init__()
    self.dict=dict
    self.category=category
    self.xc=xc
    self.path=os.path.join(self.dict,self.category,self.xc)
    self.path_list=os.listdir(self.path)
    self.train=train
def __getitem__(self, item):
    n_log_mel=128
    file_path= self.path_list[item]
    file_item_path=os.path.join(self.dict,self.category,self.xc,file_path)
    wav, sr = librosa.load(file_item_path,sr=16000)
    id=int(file_path.split('_')[1])
    # label=id
    label=paddle.zeros([3])
    label[id]=1
    target_sr=16000
    raw = librosa.core.to_mono(wav.transpose()).transpose()[:10 * target_sr]
    mel_spectrogram = librosa.feature.melspectrogram(
        y=wav,
        sr=16000,
        n_fft=1024,
        n_mels=128,
        win_length=1024,
        hop_length=512,
        power=2.0
    )
    log_mel_spectrogram = librosa.power_to_db(mel_spectrogram, ref=np.max)
    log_mel_spectrogram = np.expand_dims(log_mel_spectrogram,2)
    #------------cutmix---------------
    prob=10
    if random.randint(0, 99) < prob and self.train:
        rand_index = random.randint(0, len(self.path_list) - 1)
        rand_file_path = self.path_list[rand_index]
        rand_file_item_path=os.path.join(self.dict,self.category,self.xc,rand_file_path)
        rand_wav, sr = librosa.load(rand_file_item_path,sr=16000)
        target_sr=16000
        rand_raw = librosa.core.to_mono(rand_wav.transpose()).transpose()[:10 * target_sr]
        rand_mel_spectrogram = librosa.feature.melspectrogram(
            y=rand_wav,
            sr=16000,
            n_fft=1024,
            n_mels=128,
            win_length=1024,
            hop_length=512,
            power=2.0
        )
        rand_log_mel_spectrogram = librosa.power_to_db(rand_mel_spectrogram, ref=np.max)
        # add channel dimension
        rand_log_mel_spectrogram = np.expand_dims(rand_log_mel_spectrogram,2)
        lam = np.random.beta(1,1)
        bbx1, bby1, bbx2, bby2 = rand_bbox(rand_log_mel_spectrogram.shape, lam)
        log_mel_spectrogram[bbx1:bbx2, bby1:bby2, :]=rand_log_mel_spectrogram[bbx1:bbx2, bby1:bby2, :]
        lam = 1 - ((bbx2 - bbx1) * (bby2 - bby1) / (log_mel_spectrogram.shape[1] * log_mel_spectrogram.shape[0]))
        rand_id=int(rand_file_path.split('_')[1])
        # num_classes=len(np.unique(rand_ids))
        rand_label=paddle.zeros([3])
        rand_label[rand_id]=1
        label = label * lam + rand_label * (1. - lam)
    # log_mel_spectrogram=log_mel_spectrogram/255.0
    #     mean=np.mean(log_mel_spectrogram,0,keepdims=True)
    #     std=np.std(log_mel_spectrogram,0,keepdims=True)
    #     log_mel_spectrogram=(log_mel_spectrogram-mean)/(std+1e-7)
    #     mean1=np.mean(raw)
    #     std1=np.std(raw)
    #     raw=(raw-mean1)/(std1+1e-7)
    return raw,log_mel_spectrogram,label,id
def __len__(self):
    return len(self.path_list)

2、自适应Arcface损失

多年来,softmax 函数与作为损失函数的分类交叉熵相结合,一直是神经网络解决分类任务的标准输出层。但是在训练神经网络以提取数据的低维表示(所谓的嵌入)时,softmax 函数只会导致线性可分的表示,而不会显式减少类内并增加样本的类间距离。为了解决这个问题,提出了基于欧几里得距离的损失,而诸如 ArcFace 之类的角边距损失函数已被证明具有比基于欧几里德距离的损失更好的泛化能力,方法是在属于不同类别的样本的角度之间强制执行边距。然而,通过角边距损失获得的特定任务的性能在很大程度上依赖于微调它们的超参数,即尺度参数 s 和角边距参数 m,本项目使用自适应尺度参数且不依赖于任何手动设置的超参数的Arcface。

class ArcFace(nn.Layer):
    def __init__(self,embedding_dim:int,n_classes: int,norm: str = None,m: float = 0.50,easy_margin: bool = False) -> None:
        super().__init__()
        if norm is None:
            self.layer_norm = nn.Identity(embedding_dim)
        elif norm.upper()=="BATCH":
            self.layer_norm = nn.BatchNorm1D(embedding_dim)
        elif norm.upper()=="LAYER":
            self.layer_norm = nn.LayerNorm(embedding_dim)
        self.embedding_dim = embedding_dim
        self.n_classes = n_classes
        self.s = math.sqrt(2) * math.log(n_classes - 1)
        self.m = m
        self.weight = paddle.static.create_parameter(shape=[embedding_dim,n_classes],dtype='float32')
        nn.initializer.XavierUniform(self.weight)
        self.easy_margin = easy_margin
        self.cos_m = math.cos(m)
        self.sin_m = math.sin(m)
        self.th = math.cos(math.pi - m)
        self.mm = math.sin(math.pi - m) * m

    def forward(self, input, labels):
        input = self.layer_norm(input)
        x=F.normalize(input)
        w=F.normalize(self.weight)
        cosine = F.linear(x,w)
        sine = paddle.sqrt((1.0 - paddle.pow(cosine, 2)).clip(0, 1))
        phi = cosine * self.cos_m - sine * self.sin_m
        if self.easy_margin:
            phi = paddle.where(cosine > 0, phi, cosine)
        else:
            phi = paddle.where(cosine > self.th, phi, cosine - self.mm)
        out = (labels * phi) + ((1.0 - labels) * cosine)
        out *= self.s
        softmax=nn.Softmax()
        softout=softmax(out)

        return softout

3、特征提取网络

使用梅尔滤波器组来捕获各种频率的信息它可能会滤除异常声音的高频分量,其中可能存在不同的特征。因此,log-Mel 频谱图特征可能无法完全区分正常和用于异常声音,因此本项目使用时间信息来补充 log-Mel 频谱图。在本项目中使用Tnet从原始音频中提取时间特征,结构如图5所示,以补充从 log-Mel 频谱图中无法获得的异常信息。然后使用根据任务需要改进的Resnet对Logmel进行特征提取,结构如图6所示,最后将Log-mel和Tnet提取的时间特征进行异构融合并进行异常检测,具体结构如图7所示。

            图5 Tnet结构

                           图6 Resnet结构

                          图7 异常检测总体结构
class Block(nn.Layer):
    def __init__(self, in_dim, out_dim, stride):
        super().__init__()
        self.conv1 = nn.Conv2D(in_dim, out_dim, 3, stride=stride, padding=1,bias_attr=False)
        self.bn1 = nn.BatchNorm2D(out_dim)
        self.conv2 = nn.Conv2D(out_dim, out_dim, 3, stride=1,padding=1,bias_attr=False)
        self.bn2 = nn.BatchNorm2D(out_dim)
        self.relu = nn.LeakyReLU()
        if stride == 2 or in_dim != out_dim:
            self.downsample = nn.Sequential(*[
                nn.Conv2D(in_dim, out_dim, 1, stride = stride),
                nn.BatchNorm2D(out_dim)])
        else:
            self.downsample = Identity()

    def forward(self, x):
        # shortcut
        h = x
        x = self.conv1(x)
        x = self.bn1(x)
        x = self.relu(x)
        x = self.conv2(x)
        x = self.bn2(x)
        identity = self.downsample(h)
        x = x + identity
        x = self.relu(x)
        return x

class ResNet18(nn.Layer):
    def __init__(self, in_dim=16, num_classes=3):
        super().__init__()
        self.in_dim = in_dim
        self.conv1 = nn.Conv2D(in_channels=1,out_channels=in_dim,kernel_size=7,stride=2,padding=3,bias_attr=False)
        self.bn1 = nn.BatchNorm2D(in_dim)
        self.relu = nn.LeakyReLU()
        self.maxpool = nn.MaxPool2D(kernel_size=3, stride=2, padding=1)
        self.layer1 = self._make_layer(out_dim=16,  n_blocks=2, stride=1)
        self.layer2 = self._make_layer(out_dim=32, n_blocks=2, stride=2)
        self.layer3 = self._make_layer(out_dim=64, n_blocks=2, stride=2)
        self.layer4 = self._make_layer(out_dim=128, n_blocks=2, stride=2)

        self.avgpool = nn.MaxPool2D(10)
        self.classifier = nn.Linear(128, 128)

    def _make_layer(self, out_dim, n_blocks, stride):
        layers = []
        layers.append(Block(self.in_dim,out_dim,stride=stride))
        self.in_dim = out_dim
        for i in range(1, n_blocks):
            layers.append(Block(self.in_dim, out_dim, stride=1))
        return nn.Sequential(*layers)


    def forward(self, x):
        ## stem
        x = self.conv1(x)
        x = self.bn1(x)
        x = self.relu(x)
        x = self.maxpool(x)
        x = self.layer1(x)
        x = self.layer2(x)
        x = self.layer3(x)
        x = self.layer4(x)
        x = self.avgpool(x)
        x = x.flatten(1)
        x = self.classifier(x)
        return x

class Tnet(nn.Layer):
    def __init__(self,n_layer=3,mel_bins=128,win_len=1024,hop_len=512):
        super(Tnet, self).__init__()
        self.conv_extrctor = nn.Conv1D(1,mel_bins,win_len,hop_len,win_len//2,bias_attr=False)
        self.conv_emb=nn.Sequential(
            *[nn.Sequential(nn.LayerNorm(313),
                            nn.LeakyReLU(0.2),
                            nn.Conv1D(mel_bins,mel_bins,3,1,1,bias_attr=False)) for _ in range(n_layer)]
        )
        self.linear=nn.Linear(128*313,1024)
        self.linear1=nn.Linear(1024,128)



    def forward(self, x):
        out=self.conv_extrctor(x)
        out=self.conv_emb(out)
        out=out.flatten(1)
        out=self.linear(out)
        out=self.linear1(out)


        return out
acrface=ArcFace(256,3)
class TMnet(nn.Layer):
    def __init__(self,in_dim=16,n_layer=3,mel_bins=128,win_len=1024,hop_len=512):
        super(TMnet, self).__init__()
        self.acrface=ArcFace
        self.Tnet=Tnet(n_layer=n_layer,mel_bins=mel_bins,win_len=win_len,hop_len=hop_len)
        self.Resnet18=ResNet18(in_dim=in_dim)

    def forward(self, x,mel,label):
        x=x.unsqueeze(1)
        raw_emb=self.Tnet(x)
        mel=mel.transpose([0,3,1,2])
        mel_emb=self.Resnet18(mel)
        con=paddle.concat((raw_emb,mel_emb),axis=-1)

        output=acrface(con,label)
        return con,output

异常检测训练模型损失函数如图8所示,特征可视化如图9所示。

                             图9 损失函数

                            图10 特征可视化

4、计算异常分数

本项目使用具有完整协方差矩阵的高斯混合模型 (GMM) 来估计嵌入的分布和计算异常分数。因为余弦相似度等价于使用具有球面协方差矩阵的高斯分布,即所有条目都相等的对角矩阵。在进行闭集分类时这不是问题,因为只有最接近的类均值很重要。但是对于异常检测来说具有全协方差矩阵的高斯分布可以更准确地估计正常样本的分布,以防它稍微偏离球形分布,使得异常检测更加稳健。

技术路线

项目以齿轮箱异为研究对象,以dcase2021 MIMII DUE数据集为信息载体,以无监督学习和迁移学习为核心,深入研究齿轮箱异常检测系统的频谱融合的异常检测方法。以研究任务的先后为序设计如图11所示的技术路线。

                            11 技术路线图

该齿轮箱异常声音“听诊”系统结果如图12所示,由于时间关系模型还未调试完全,可能存在过拟合等情况,导致检测结果效果不高,但是由结果和调试过程可以看出,使用该方法是可行的。

                          图12 源域和目标域检测结果

引用:
@inproceedings{wilkinghoff2021sub, title={Sub-Cluster {A}da{C}os: Learning Representations for Anomalous Sound Detection}, author={Wilkinghoff, Kevin}, booktitle={International Joint Conference on Neural Networks (IJCNN)}, year={2021}, publisher={IEEE} }
@INPROCEEDINGS{9747868,author={Liu, Youde and Guan, Jian and Zhu, Qiaoxi and Wang, Wenwu}, booktitle={ICASSP 2022 - 2022 IEEE International Conference on Acoustics, Speech and Signal Processing (ICASSP)}, title={Anomalous Sound Detection Using Spectral-Temporal Information Fusion}, year={2022},volume={},number={},pages={816-820},doi={10.1109/ICASSP43922.2022.9747868}}

请点击此处查看本环境基本用法.

Please click here for more detailed instructions.

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值