草庐IT

深入理解TDNN(Time Delay Neural Network)——兼谈x-vector网络结构

DEDSEC_Roger 2023-04-09 原文

概述

  • TDNN(Time Delay Neural Network,时延神经网络)是用于处理序列数据的,比如:一段语音、一段文本
  • 将TDNN和统计池化(Statistics Pooling)结合起来,正如x-vector的网络结构,可以处理任意长度的序列
  • TDNN出自Phoneme recognition using time-delay neural networks
  • x-vector出自X-Vectors: Robust DNN Embeddings for Speaker Recognition
  • 此外,TDNN还演化成了ECAPA-TDNN,而ECAPA-TDNN则是当前说话人识别领域,在VoxCeleb1数据集的三个测试集VoxCeleb1 (cleaned)、VoxCeleb1-H (cleaned)、VoxCeleb1-E (cleaned)上的最强模型,因此学习TDNN还是很有必要的

x-vector的网络结构

  • x-vector是用于文本无关的说话人识别的,因此需要处理任意长度的序列,其网络结构如下图所示:
  • 上图的迷惑性其实非常大,有必要好好讲解一下,现在我给出从frame1到frame4层(frame5与frame4本质上是一样的,只不过卷积核数量不同)的可视化结果
  • 输入:每个特征图表示一帧,特征图的通道数为24,表示一帧的特征数(原文是24维fbank特征),特征图的分辨率是1,在这里需要明确:语音是1维数据,因此特征图并不是二维图,而是一个值,24个特征图堆叠起来构成24维fbank特征
  • frame1
    • frame1的特征图经过1维卷积得到,卷积核大小 i n c h a n n e l s × k e r n e l s i z e × o u t c h a n n e l s = 24 × 5 × 512 inchannels \times kernelsize \times outchannels=24\times5\times512 inchannels×kernelsize×outchannels=24×5×512
    • frame1的每个特征图下面连接的5条线,表示卷积核。这5条线不是5根细线,而是5根麻花线,每根麻花线由 i n c h a n n e l s = 24 inchannels=24 inchannels=24根细线组成,每根细线连接一个特征。每根细线的权重都是一样的,每根麻花线的权重不一样
    • k e r n e l s i z e = 5 kernelsize=5 kernelsize=5,对应闭区间 [ t − 2 , t + 2 ] [t-2,t+2] [t2,t+2]一共5帧的上下文,也可以表示为 { t − 2 , t − 1 , t , t + 1 , t + 2 } \left \{ t-2,t-1,t,t+1,t+2 \right \} {t2,t1,t,t+1,t+2},之所以表格说frame1的输入是120,是因为将5帧上下文的特征都计算进去了 5 × 24 = 120 5\times24=120 5×24=120
    • o u t c h a n n e l s = 512 outchannels=512 outchannels=512,表示卷积核的厚度是512,可以理解为5根麻花线堆叠了512次,每次堆叠都得到新的5根麻花线,都符合“每根细线的权重都是一样的,每根麻花线的权重不一样”。5根麻花线同时运算,得到一个值,从而frame1的每个特征图其实也是一个值,且通道数为512,对应表格中的frame1的输出是512
  • frame2
    • frame2的特征图经过1维膨胀卷积得到,卷积核大小 i n c h a n n e l s × k e r n e l s i z e × o u t c h a n n e l s = 512 × 3 × 512 inchannels \times kernelsize \times outchannels=512\times3\times512 inchannels×kernelsize×outchannels=512×3×512
    • 不要被膨胀卷积吓到了,膨胀卷积的 k e r n e l s i z e = 3 kernelsize=3 kernelsize=3,表示3根麻花线中,第2根麻花线连接第t帧,第1根麻花线连接第t-2帧,第3根麻花线连接第t+2帧,对应表格中的 { t − 2 , t , t + 2 } \left \{ t-2,t,t+2 \right \} {t2,t,t+2}共3帧的上下文,这就是膨胀卷积和标准卷积的不同之处,隔帧连接
    • 在PyTorch中,1维卷积的api为
      t o r c h . n n . C o n v 1 d ( i n c h a n n e l s , o u t c h a n n e l s , k e r n e l s i z e , s t r i d e = 1 , p a d d i n g = 0 , d i l a t i o n = 1 , g r o u p s = 1 , b i a s = T r u e , p a d d i n g m o d e = ′ z e r o s ′ , d e v i c e = N o n e , d t y p e = N o n e ) torch.nn.Conv1d(inchannels, outchannels, kernelsize, stride=1, padding=0, dilation=1, groups=1, bias=True, paddingmode='zeros', device=None, dtype=None) torch.nn.Conv1d(inchannels,outchannels,kernelsize,stride=1,padding=0,dilation=1,groups=1,bias=True,paddingmode=zeros,device=None,dtype=None)
      其中, d i l a t i o n = 1 dilation=1 dilation=1表示标准卷积,frame2的膨胀卷积需要设置 d i l a t i o n = 2 dilation=2 dilation=2
    • 在这里我们也发现一点:TDNN其实是卷积的前身,后世提出的膨胀卷积,在TDNN里已经有了雏形,只不过TDNN是用于1维数据的
  • frame3、frame4没有引进新的运算。frame3需要设置 d i l a t i o n = 3 dilation=3 dilation=3,而frame4的卷积核大小 i n c h a n n e l s × k e r n e l s i z e × o u t c h a n n e l s = 512 × 1 × 512 inchannels \times kernelsize \times outchannels=512\times1\times512 inchannels×kernelsize×outchannels=512×1×512,因为 k e r n e l s i z e = 1 kernelsize=1 kernelsize=1,所以与MLP(dense layer)没有本质区别,卷积核通过在每一帧上移动,实现全连接,因此可以看到有些代码实现用 k e r n e l s i z e = 1 kernelsize=1 kernelsize=1的卷积替代全连接
  • 从frame1到frame5,每次卷积的步长 s t r i d e stride stride都等于1,从而对每一帧都有对应的输出,也就是说,对于任意长度的帧序列,frame5的输出也是一个同等长度的序列,长度记为 T T T,而由于frame5的 o u t c h a n n e l s = 1500 outchannels=1500 outchannels=1500,所以表格中统计池化的输入是 1500 × T 1500 \times T 1500×T
  • 统计池化的原理颇为简单,本质是在序列长度 T T T这一维度求均值和标准差,然后将均值和标准差串联(concatenate)起来,所以池化后,序列长度 T T T这一维度消失了,得到了 1500 1500 1500个均值和 1500 1500 1500个标准差,串联起来就是长度为 3000 3000 3000的向量
  • segment6、segment7和Softmax都是标准的MLP,不再赘述
  • 最后segment6输出的 512 512 512长度的向量,被称为x-vector,用于训练一个PLDA模型,进行说话人识别,可以计算一下,提取x-vector所需的参数
    f r a m e 1 + f r a m e 2 + f r a m e 3 + f r a m e 4 + f r a m e 5 + s e g m e n t 6 = 120 × 512 + 1536 × 512 + 1536 × 512 + 512 × 512 + 512 × 1500 + 3000 × 512 = 420 , 0448 \begin{aligned} &frame1+frame2+frame3+frame4+frame5+segment6 \\ =&120 \times 512 + 1536 \times 512 + 1536 \times 512 + 512 \times 512 + 512 \times 1500 + 3000 \times 512 \\ =&420,0448 \end{aligned} ==frame1+frame2+frame3+frame4+frame5+segment6120×512+1536×512+1536×512+512×512+512×1500+3000×512420,0448
  • 参数量并不能代表计算量,因为输入网络的是任意长度的帧序列

有关深入理解TDNN(Time Delay Neural Network)——兼谈x-vector网络结构的更多相关文章

  1. ruby - 使用 ruby​​ 将 HTML 转换为纯文本并维护结构/格式 - 2

    我想将html转换为纯文本。不过,我不想只删除标签,我想智能地保留尽可能多的格式。为插入换行符标签,检测段落并格式化它们等。输入非常简单,通常是格式良好的html(不是整个文档,只是一堆内容,通常没有anchor或图像)。我可以将几个正则表达式放在一起,让我达到80%,但我认为可能有一些现有的解决方案更智能。 最佳答案 首先,不要尝试为此使用正则表达式。很有可能你会想出一个脆弱/脆弱的解决方案,它会随着HTML的变化而崩溃,或者很难管理和维护。您可以使用Nokogiri快速解析HTML并提取文本:require'nokogiri'h

  2. ruby - 用 Ruby 编写一个简单的网络服务器 - 2

    我想在Ruby中创建一个用于开发目的的极其简单的Web服务器(不,不想使用现成的解决方案)。代码如下:#!/usr/bin/rubyrequire'socket'server=TCPServer.new('127.0.0.1',8080)whileconnection=server.acceptheaders=[]length=0whileline=connection.getsheaders想法是从命令行运行这个脚本,提供另一个脚本,它将在其标准输入上获取请求,并在其标准输出上返回完整的响应。到目前为止一切顺利,但事实证明这真的很脆弱,因为它在第二个请求上中断并出现错误:/usr/b

  3. ruby - 是否有用于序列化和反序列化各种格式的对象层次结构的模式? - 2

    给定一个复杂的对象层次结构,幸运的是它不包含循环引用,我如何实现支持各种格式的序列化?我不是来讨论实际实现的。相反,我正在寻找可能会派上用场的设计模式提示。更准确地说:我正在使用Ruby,我想解析XML和JSON数据以构建复杂的对象层次结构。此外,应该可以将该层次结构序列化为JSON、XML和可能的HTML。我可以为此使用Builder模式吗?在任何提到的情况下,我都有某种结构化数据-无论是在内存中还是文本中-我想用它来构建其他东西。我认为将序列化逻辑与实际业务逻辑分开会很好,这样我以后就可以轻松支持多种XML格式。 最佳答案 我最

  4. 网络编程套接字 - 2

    网络编程套接字网络编程基础知识理解源`IP`地址和目的`IP`地址理解源MAC地址和目的MAC地址认识端口号理解端口号和进程ID理解源端口号和目的端口号认识`TCP`协议认识`UDP`协议网络字节序socket编程接口`sockaddr``UDP`网络程序服务器端代码逻辑:需要用到的接口服务器端代码`udp`客户端代码逻辑`udp`客户端代码`TCP`网络程序服务器代码逻辑多个版本服务器单进程版本多进程版本多线程版本线程池版本服务器端代码客户端代码逻辑客户端代码TCP协议通讯流程TCP协议的客户端/服务器程序流程三次握手(建立连接)数据传输四次挥手(断开连接)TCP和UDP对比网络编程基础知识

  5. CAN协议的学习与理解 - 2

    最近在学习CAN,记录一下,也供大家参考交流。推荐几个我觉得很好的CAN学习,本文也是在看了他们的好文之后做的笔记首先是瑞萨的CAN入门,真的通透;秀!靠这篇我竟然2天理解了CAN协议!实战STM32F4CAN!原文链接:https://blog.csdn.net/XiaoXiaoPengBo/article/details/116206252CAN详解(小白教程)原文链接:https://blog.csdn.net/xwwwj/article/details/105372234一篇易懂的CAN通讯协议指南1一篇易懂的CAN通讯协议指南1-知乎(zhihu.com)视频推荐CAN总线个人知识总

  6. TimeSformer:抛弃CNN的Transformer视频理解框架 - 2

    Transformers开始在视频识别领域的“猪突猛进”,各种改进和魔改层出不穷。由此作者将开启VideoTransformer系列的讲解,本篇主要介绍了FBAI团队的TimeSformer,这也是第一篇使用纯Transformer结构在视频识别上的文章。如果觉得有用,就请点赞、收藏、关注!paper:https://arxiv.org/abs/2102.05095code(offical):https://github.com/facebookresearch/TimeSformeraccept:ICML2021author:FacebookAI一、前言Transformers(VIT)在图

  7. ruby-on-rails - 一般建议和推荐的文件夹结构 - Sinatra - 2

    您将如何构建一个简单的Sinatra应用程序?我正在制作,我希望该应用具有以下功能:“应用程序”更像是一个包含所有信息的管理仪表板。然后另一个应用程序将通过REST访问信息。我还没有创建仪表板,只是从数据库中获取东西session和身份验证(尚未实现)您可以上传图片,其他应用可以显示这些图片我已经使用RSpec创建了一个测试文件通过Prawn生成报告目前的设置是这样的:app.rbtest_app.rb因为我实际上只有应用程序和测试文件。到目前为止,我已经将Datamapper用于ORM,将SQLite用于数据库。这是我的第一个Ruby/Sinatra项目,所以欢迎任何和所有建议-我应

  8. ruby - 易于初学者理解的 Ruby 库 - 2

    关闭。这个问题不符合StackOverflowguidelines.它目前不接受答案。我们不允许提问寻求书籍、工具、软件库等的推荐。您可以编辑问题,以便用事实和引用来回答。关闭3年前。Improvethisquestion我正处于学习Ruby的阶段,我想查看一些小型库的源代码以了解它们是如何构建的。我不知道什么是小型图书馆,但希望SO能推荐一些易于理解的图书馆来学习。因此,如果有人知道一两个非常小的库,这是新手Rubyists学习的好例子,请推荐!我想使用Manveru'sInnatelib,因为它试图保持在2000LOC以下,但我还不熟悉其中经常使用的Ruby速记。也许大约100-5

  9. ruby - 无法理解 `puts{}.class` 和 `puts({}.class)` 之间的区别 - 2

    由于匿名block和散列block看起来大致相同。我正在玩它。我做了一些严肃的观察,如下所示:{}.class#=>Hash好的,这很酷。空block被视为Hash。print{}.class#=>NilClassputs{}.class#=>NilClass为什么上面的代码和NilClass一样,下面的代码又显示了Hash?puts({}.class)#Hash#=>nilprint({}.class)#Hash=>nil谁能帮我理解上面发生了什么?我完全不同意@Lindydancer的观点你如何解释下面几行:print{}.class#NilClassprint[].class#A

  10. ruby - 如何在 ruby​​ 中复制目录结构,不包括某些文件扩展名 - 2

    我想编写一个ruby​​脚本来递归复制目录结构,但排除某些文件类型。因此,给定以下目录结构:folder1folder2file1.txtfile2.txtfile3.csfile4.htmlfolder2folder3file4.dll我想复制这个结构,但不包含.txt和.cs文件。因此,生成的目录结构应如下所示:folder1folder2file4.htmlfolder2folder3file4.dll 最佳答案 您可以使用查找模块。这是一个代码片段:require"find"ignored_extensions=[".cs"

随机推荐