文章语音声学特征提取:MFCC和LogFBank算法的原理
几乎任何做自动语音识别的系统,第一步就是对语音信号,进行特征的提取。通过提取语音信号的相关特征,有利于识别相关的语音信息,并丢弃携带的其他不相关的所有信息,如背景噪声、情绪等。 我们都知道,人类说话是通过体内的发声器产生的初始声音,被包括舌头和牙齿在内的其他物体形成的声道的形状进行滤波,从而产生出各种各样的语音的。传统的语音特征提取算法正是基于这一点,通过一些数字信号处理算法,能够更准确地包含相关的特征,从而有助于后续的语音识别过程。常见的语音特征提取算法有MFCC、FBank、LogFBank等。 1 MFCC MFCC的中文全称是“梅尔频率倒谱系数”,这种语音特征提取算法是这几十年来,最常用的算法之一。这种算法是通过在声音频率中,对非线性梅尔刻度的对数能量频谱,进行线性变换得到的[1]。 MFCC特征提取算法的主体流程如下: 图1 MFCC算法流程 1.1 分帧由于存储在计算机硬盘中的原始wav音频文件是不定长的,我们首先需要将其按一定方法切分为固定长度的多个小片段,也就是分帧。根据语音信号变化迅速的特性,每一帧的时间长度一般取10-30毫秒,以保证一帧内有足够多的周期,且变化不会过于剧烈,因此,更适合这种适用于分析平稳信号的傅里叶变换。由于数字音频的采样率不同,分帧所得的每一帧向量的维度也不同。 为了避免时间窗的边界导致信息遗漏的问题,因此,在对从信号中取每一帧的时间窗进行偏移的时候,帧和帧之间需要有一部分的重叠区域。这个时间窗的偏移量,我们一般取为帧长的一半,即每一步都偏移一帧的大约二分之一之后的位置,作为时间窗取下一帧的最终位置。这样做的好处是,避免了帧与帧之间的特性变化过大。 通常来说,我们选取时间窗长度为25毫秒,时间窗的偏移量为10毫秒。 1.2 预加重由于声音信号从人的声门发出后,存在12dB/倍频程的衰减,在通过口唇辐射后,还存在6dB/倍频程的衰减,因而在进行快速傅里叶变换之后,高频信号部分中的成分较少。所以,对语音信号进行预加重操作,其主要目的是加强语音信号的每一帧中,那些高频部分的信号,以提高其高频信号的分辨率。我们需要通过采用如下公式的一阶高通滤波器进行预加重操作: 在上式中,α是预加重的系数,其一般的取值范围是0.9 < α < 1.0,通常取0.97。n表示当前处理的是第n帧,其中,第一个n=0的帧需要特别处理。 1.3 加窗在之前的分帧过程中,直接将一个连续的语音信号切分为若干个片段,会造成截断效应产生的频谱泄漏,加窗操作的目的是消除每个帧的短时信号在其两端边缘处出现的信号不连续性问题。MFCC算法中,选取的窗函数通常是汉明窗,也可以使用矩形窗和汉宁窗。需要注意的是,预加重必须在加窗之前进行。 汉明窗的窗函数为: 1.4 快速傅里叶变换在经过上述的一系列的处理过程之后,我们得到的仍然是时域的信号,而时域中可直接获取的语音信息量较少。在进行进一步的语音信号特征提取时,还需要将每一帧的时域信号对应转换到其频域信号。对于存储在计算机上的语音信号,我们需要使用离散的傅里叶变换,由于普通的离散傅里叶变换的计算复杂度较高,通常使用快速傅里叶变换来实现。由于MFCC算法经过分帧之后,每一帧都是短时间内的时域信号,所以这一步也成为短时快速傅里叶变换。 根据奈奎斯特定理,如果要再次从离散的数字信号无损地转换到模拟信号上,在对模拟信号进行采样时,我们需要采用模拟信号最高频率值的2倍以上的采样率,对模拟信号进行模数转换的采样。对于语音识别常用的16kHz采样率音频,傅里叶变换之后的频率范围为0到8kHz之间。 1.5 计算幅度谱(对复数取模)在完成了快速傅里叶变换之后,得到的语音特征是一个复数矩阵,它是一个能量谱,由于能量谱中的相位谱包含的信息量极少,所以我们一般选择丢弃相位谱,而保留幅度谱。 丢弃相位谱保留幅度谱的方法一般是两种,对每一个复数求绝对值或者求平方值。 1.6 Mel滤波Mel滤波的过程是MFCC和fBank特征的关键之一。Mel滤波器是由20个三角形带通滤波器组成的,将线性频率转换为非线性分布的Mel频率。 图2 Mel滤波器原理图 1.7 取对数在得到上一步的fBank特征之后,由于人耳对声音的感受是成对数值增长的,所以需要将数值再进行一次对数运算,以模拟人耳的感受。我们需要对纵轴通过取对数进行缩放,可以放大低能量处的能量差异。 1.8 离散余弦变换离散余弦变换是MFCC相对于fBank所特有的一步特征提取运算。在上一步取了对数之后,我们还需要对得到的N维特征向量值,再进行一次离散余弦变换(DCT)。做DCT的根本原因是,不同阶数信号值之间具有一定的相关性,而我们需要去掉这种相关性,将信号再映射到低维的空间中。由于最有效的特征聚集在前12个特征里,所以在实际中,一般仅保留前12-20个结果值,通常取13个,这样一来,就进一步压缩了数据。 离散余弦变换公式如下: 1.9 计算动态特征上述MFCC算法仅仅体现了MFCC的静态特征,而其动态特征还需要使用静态特征的差分来表示。通过将得到的动态的特征,和前一步得到的静态特征相结合,可以有效地提高这种语音识别系统的识别性能。 差分参数的计算公式: 式中,dt是第t个一阶差分值,Ct是第t个倒谱系数值,Q是倒谱系数的最大阶数,K是一阶差分的时间差,一般可取1或取2。二阶差分则将上式的结果再代入进行计算即可。 最后,再将静态特征和动态特征的一阶、二阶差分值合并起来,当静态特征是13维的特征向量时,合并动态特征后,总共有39维特征。 2 logfBanklogfBank特征提取算法类似于MFCC算法,都是基于fBank特征提取结果的基础上,再进行一些处理的。不过logfBank跟MFCC算法的主要区别在于,是否再进行离散余弦变换。logfBank特征提取算法在跟上述步骤一样得到fBank特征之后,直接做对数变换作为最终的结果,计算量相对MFCC较小,且特征的相关性较高,所以传统的语音识别技术常常使用MFCC算法。 随着DNN和CNN的出现,尤其是深度学习的发展,由于fBank以及logfBank特征之间的相关性可以更好地被神经网络利用,以提高最终语音识别的准确率,降低WER,因此,可以省略掉离散余弦变换这一步骤。 3 总结本文主要介绍了MFCC和LogFBank语音特征提取算法的数学原理及计算过程方法,之后AI柠檬博客还将更新另一种语音识别特征提取算法:语谱图特征,敬请期待! 参考资料 RefferenceDavis S, Mermelstein P. Comparison of parametric representations for monosyllabic word recognition in continuously spoken sentences[J]. IEEE transactions on acoustics, speech, and signal processing, 1980, 28(4): 357-366 版权声明本博客的文章除特别说明外均为原创,本人版权所有。欢迎转载,转载请注明作者及来源链接,谢谢。本文地址: https://blog.ailemon.me/2021/03/01/speech-acoustic-feature-extraction-the-principle-of-mfcc-and-logfbank-algorithm/All articles are under Attribution-NonCommercial-ShareAlike 4.0

0

语音识别

AI小助手·今天11:57 0 阅读 13
文章人工智能十年回顾:CNN、AlphaGo、GAN……它们曾这样改变世界
过去十年间,人工智能技术突飞猛进,最疯狂的科幻小说场景现在已经成为我们生活中不可或缺的一部分。十年前,人们在谈论 AI 的理论化和实验,但这些年来,AI 变得更加切实了,也变成了主流。无论是国际标准课程、平台、库、框架、硬件,一切都顺理成章。就算说这十年里取得的成绩奠定了未来的基础,也不为过。 这篇文章将盘点 AI 十年来取得的重要突破。 卷积2012 年是深度学习历史上重要的一年。那一年,卷积神经网络(CNN)在著名的 ImageNet 挑战赛中大放异彩。由 Alex Krizhevsky 等人设计的卷积神经网络「Alexnet」以远超第二名的成绩夺冠,在 ImageNet 数据集上的视觉识别错误率为 15.3%,降低了一半。该神经网络对猫的检测准确度达到了 74.8%,在 YouTube 视频中检测人脸的准确率为 81.7%。 现在,手机和商场中的人脸识别应用都应该归功于 2012 年的这项工作,识别准确率的提升使研究者能够进行医学成像模型的部署,这些模型具备高置信度。 与 AI 对话Vaswani 等人 2017 年发表的《Attention Is All You Need》带来了级联效应,使得机器能够以前所未有的方式去理解语言。得益于 Transformer 架构,AI 现在能够撰写假的新闻、推文,甚至可能引起政治动荡。继 Transformer 之后,谷歌又推出了 BERT 模型,将其用于关键字预测和 SEO 排名等。BERT 如今已经变成了自然语言处理领域的实际标准,诸如 Microsoft 和 NVIDIA 之类的公司开始堆积更多参数来追赶该模型。 NVIDIA 的 Megatron 具有 80 亿个参数,而 Microsoft 的 Turing NLG 模型具有 170 亿个参数。OpenAI 的 GPT 模型后来居上,1750 亿参数的 GPT-3 目前是历史记录的保持者。 GPT-3 也是 Transformer 的扩展,是目前较大的模型,它可以编码、写散文、生成商业创意,只有人类想不到,没有它做不到。 将人类一军 AI 早已在国际象棋中击败了人类。而更加复杂的人类游戏,如 Jeopardy! 游戏、围棋、德州扑克等,也没有挡住算法的脚步。人工智能近几年来最广为人知的事件就是 AlphaGo 在最复杂棋类游戏——「围棋」上击败了人类较高级选手。与此同时,在这个十年中,IBM 的 Watson 也在 Jeopardy! 决赛中击败了两位人类,最终 Watson 获得了 77147 美元奖金,而两位人类分别获得了 24000 和 21600 美元。 Facebook 和卡耐基梅隆大学共同开发的德扑 AI Pluribus 战胜了五名专家级人类玩家,实现了前辈 Libratus(冷扑大师)未能完成的任务,该研究还登上了 2019 年的《科学》杂志。2020 年 12 月,DeepMind 提出的 MuZero 让一种人工智能模型掌握多种游戏,包括将棋、国际象棋和围棋。 解码生命 每一个生物体的行为都可以在其蛋白质中寻踪溯源。蛋白质承载着秘密,破解蛋白质或许有助于击败新冠大流行。但蛋白质结构非常复杂,需要不断地运行模拟。DeepMind 尝试解决这一难题,其开发的深度学习算法「Alphafold」破解了出现五十年之久的蛋白质分子折叠问题。计算机视觉被证明可以帮助诊断,而解决蛋白质折叠问题甚至能够帮助研发人员开发新药。 AI:是艺术家,也是骗子 去年,在一则视频中,比利时首相谈论着解决经济和气候危机的紧急需求,后来人们发现这其实是 Deepfake 视频。在机器学习和 AI 对比利时首相声音和表达方式的操纵下,这则假视频让首相发表了一场关于全球变暖影响的演讲。 这些伪造内容的背后是精心设计的算法——生成对抗网络(GAN)。该算法在 2014 年提出,并得到广泛应用,甚至已经侵入了人类工作的最后一道壁垒:创作。这种网络可以生成从未存在的人脸、互换人脸,让一国总统胡言乱语。GAN 生成的一幅画甚至在佳士得拍卖会上以破纪录的价格——40 万美元成交了。GAN 的另一面是被用于恶意目的,以致于像 Adobe 这种公司不得不研究新技术来鉴别伪造内容。GAN 在下一个十年里仍将是被广泛讨论的对象。 秘密武器——硅 神经网络的概念诞生了半个世纪,今天流行的反向传播方法也出现三十年了。但是,我们仍然缺少能够运行这些计算的硬件。过去十年,我们见证了十多家公司研究专门的机器学习芯片。这些年来,芯片技术得到了极大发展,我们可以在手掌大小的设备上执行百万次运算。这些芯片被用到数据中心,用户可以观看自己喜欢的 Netflix 电影、使用智能手机等。接下来,专为边缘设备定制的 AI 芯片蕴含着价值数十亿美元的商机。 苹果等公司已经开发了定制化机器学习芯片(如 A14 Bionic)来提供智能服务。即使是依赖英伟达和英特尔的 AWS,也正在慢慢进入芯片行业。随着芯片变得越来越小,这一趋势只会更加明显:例如使用英伟达 Jetson AGX Xavier 开发者套件,你可以轻松创建和部署端到端 AI 机器人应用,用于制造、零售、智能城市等等。谷歌的 Coral 工具包可将机器学习带到边缘设备上。安全、实时输出是目前的主题。 开源文化逐渐成熟 图源:MIT Tech Review 2015 年,TensorFlow 开源。一年后,Facebook AI 又开源了基于 Python 的深度学习框架 PyTorch。今天,TensorFlow 和 PyTorch 已经成为使用最广泛的框架。通过不断的版本更新,谷歌和 Facebook 为机器学习社区带来了极大便利。自定义库、软件包、框架和工具的爆发式增长,使得更多人进入了 AI 领域,也为 AI 研究带来了更多人才。 开源是近几年的一个主要特性。开源工具和越来越多的可用资源(如 arxiv 或 Coursera)促进了 AI 变革。另一个催化剂是流行的竞赛平台——Kaggle。Kaggle 和 GitHub 滋养了一批高质量 AI 开发者。 更多学习,更少规则Schmidhuber 教授上世纪 90 年代初提出的元学习概念,最近才逐渐得到关注。元学习指在有限训练示例的基础上,使机器学习模型学习新技能并适应不断变化的环境。通过操纵超参数对特定任务优化机器学习模型需要大量用户输入的话,过程会较为繁琐,而使用元学习后,这一负担将得到极大缓解,因为元学习将优化部分自动化了。自动优化带来了一个新的行业 MLaaS(机器学习即服务)。 未来方向 关于一些专家预测以下领域或许将发挥主要作用: 可复现性差分隐私几何深度学习神经形态计算强化学习 尽管 AI 已经进入许多我们未曾想象的领域,但它仍需应用到更流行的应用中,如自动驾驶汽车。然而,挑战更多地在于数学层面:目前已有能够做出准确决策的算法,也有能够处理这些算法的处理器,但何时能够部署到应用上仍未可知。不管是医疗还是自动驾驶汽车,AI 仍需要继续进展,而这只有在透明性和可复现性得到建立时才会发生。

1

CNN

AI小助手·2021-03-03 13:42 0 阅读 15
文章激活函数
激活函数的性质 非线性:为模型引入非线性因素 几乎处处可微:有限的不可微点有左右导数(左右导数可能不同,如Relu)。 便于反向传播,利于优化 计算简单:激活函数在神经网络前向的计算次数与神经元的个数成正比,因此简单的非线性函数自然更适合用作激活函数。这也是ReLU之流比其它使用Exp等操作的激活函数更受欢迎的其中一个原因。 非饱和性:饱和指的是在某些区间梯度接近于零(即梯度消失),使得参数无法继续更新的问题。 单调性:当激活函数是单调的时候,单层网络能够保证是凸函数; $ f(x)≈x $: 当激活函数满足这个性质的时候,如果参数的初始化是随机的较小值,那么神经网络的训练将会很高效;如果不满足这个性质,那么就需要详细地去设置初始值。 由于这个条件与非线性有点矛盾,因此激活函数基本只是部分满足这个条件,如 relu 只再 x>0 时为线性。 输出值的范围有限 :当激活函数输出值是有限的时候,基于梯度的优化方法会更加稳定,因为特征的表示受有限权值的影响更显著;但这导致了前面提到的梯度消失问题,而且强行让每一层的输出限制到固定范围会限制其表达能力。 当激活函数的输出是无限的时候,模型的训练会更加高效,不过在这种情况小,一般需要更小的 Learning Rate。 参数少: 大部分激活函数都是没有参数的。 归一化 :主要思想是使样本分布自动归一化到零均值、单位方差的分布,从而稳定训练。 激活函数Step Identity Bent Identity ReLU 优点: 解决了gradient vanishing问题 (在正区间)计算速度非常快,只需要判断输入是否大于0收敛速度远快于sigmoid和tanh 存在的问题: ReLU的输出不是zero-centeredDead ReLU Problem,指的是某些神经元可能永远不会被激活,导致相应的参数永远不能被更新。有两个主要原因可能导致这种情况产生: 非常不幸的参数初始化,这种情况比较少见 learning rate太高导致在训练过程中参数更新太大,不幸使网络进入这种状态。解决方法是可以采用Xavier初始化方法,以及避免将learning rate设置太大或使用adagrad等自动调节learning rate的算法。 代码def relu(x): ''' 定义relu函数 ''' return np.where(x<0,0,x) def reluDerivative(x): ''' 定义relu的导函数 ''' return np.where(x<0,0,1) Leaky ReLU 人们为了解决Dead ReLU Problem,提出了将ReLU的前半段设为$0.01x$而非0。另外一种直观的想法是基于参数的方法,即Parametric ReLU:$f(x)=max(\alpha x,x)$,其中$\alpha$可由back propagation学出来。理论上来讲,Leaky ReLU有ReLU的所有优点,外加不会有Dead ReLU问题,但是在实际操作当中,并没有完全证明Leaky ReLU总是好于ReLU。 代码def leakyrelu(x,a=0.01): ''' 定义leakyrelu函数 leakyrelu激活函数是relu的衍变版本,主要就是为了解决relu输出为0的问题 ''' return np.where(x<0,a*x,x) def leakyreluDerivative(x,a=0.01): ''' 定义leakyrelu导函数 ''' return np.where(x<0,a,1) PReLU RReLU ELU ELU也是为解决ReLU存在的问题而提出,显然,ELU有ReLU的基本所有优点,以及: 不会有Dead ReLU问题输出的均值接近0,zero-centered 它的一个小问题在于计算量稍大。类似于Leaky ReLU,理论上虽然好于ReLU,但在实际使用中目前并没有好的证据ELU总是优于ReLU。 代码def elu(x,a=0.01): ''' 定义elu函数 elu和relu的区别在负区间,relu输出为0,而elu输出会逐渐接近-α,更具鲁棒性。 elu激活函数另一优点是它将输出值的均值控制为0(这一点确实和BN很像,BN将分布控制到均值为0,标准差为1) ''' return np.where(x<0,a*(np.exp(x)-1),x) def eluDerivative(x,a=0.01): ''' 定义elu导函数 ''' return np.where(x<0,a*np.exp(x),1) SELU 代码def selu(x): ''' 定义selu函数 ''' alpha=1.6732632423543772848170429916717 scale=1.0507009873554804934193349852946 return np.where(x<0,scale*alpha*(np.exp(x)-1),scale*x) def seluDerivative(x): ''' 定义selu导函数 ''' alpha=1.6732632423543772848170429916717 scale=1.0507009873554804934193349852946 return np.where(x<0,alpha*np.exp(x),scale) SReLU sigmoid 梯度消失优化神经网络的方法是Back Propagation,即导数的后向传递:先计算输出层对应的loss,然后将loss以导数的形式不断向上一层网络传递,修正相应的参数,达到降低loss的目的。 Sigmoid函数在深度网络中常常会导致导数逐渐变为0,使得参数无法被更新,神经网络无法被优化。原因在于两点: 在上图中容易看出,当$\sigma(x)$中$x$较大或较小时,导数接近0,而后向传递的数学依据是微积分求导的链式法则,当前层的导数需要之前各层导数的乘积,几个小数的相乘,结果会很接近0 .Sigmoid导数的最大值是0.25,这意味着导数在每一层至少会被压缩为原来的1/4,通过两层后被变为1/16,…,通过10层后为$\frac{1}{4^10}$。请注意这里是“至少”,导数达到最大值这种情况还是很少见的。 优点:平滑、易于求导。缺点:激活函数计算量大,反向传播求误差梯度时,求导涉及除法;反向传播时,很容易就会出现梯度消失的情况,从而无法完成深层网络的训练。幂运算相对耗时 代码def sigmoid(x): ''' 定义sigmoid函数 ''' return 1.0/(1.0+np.exp(-x)) def sigmoidDerivative(x): ''' 定义sigmoid导函数 ''' return sigmoid(x)*(1-sigmoid(x)) Hard Sigmoid Symmetrical Sigmoid Tanh 代码def tanh(x): ''' 定义tanh函数 ''' return (np.exp(x)-np.exp(-x))/(np.exp(x)+np.exp(-x)) def tanhDerivative(x): ''' 定义tanh导函数 ''' return 1-tanh(x)*tanh(x) Hard Tanh LeCun Tanh ArcTan SoftSign 代码def softsign(x): ''' 定义softsign函数 ''' return x/(np.abs(x)+1) def softsignDerivative(x): ''' 定义softsign导函数 ''' return 1/(1+abs(x)*abs(x)) Softplus 代码def softplus(x): ''' 定义softplus函数 ''' return np.log(np.exp(x)+1) def softplusDerivative(x): ''' 定义softplus导函数 ''' return sigmoid(x) Signum Cos Sinc Log Log Gaussian Absolute Sinusoid 常见问题如何选择激活函数 如果是二分类问题, 输出层是sigmoid,其余层是Relu一般隐层采用Relu, 有时也要试试 tanh, 这两大函数的变体都有必要试试 为什么Relu 不是全程可微也能用于基于梯度的学习?虽然 ReLU 在 0 点不可导,但是它依然存在左导数和右导数,只是它们不相等(相等的话就可导了),于是在实现时通常会返回左导数或右导数的其中一个,而不是报告一个导数不存在的错误。 为何加入非线性因素能够加强网络的表示能力? 神经网络的万能近似定理:神经网络只要具有至少一个非线性隐藏层,那么只要给予网络足够数量的隐藏单元,它就可以以任意的精度来近似任何从一个有限维空间到另一个有限维空间的函数。如果不使用非线性激活函数,那么每一层输出都是上层输入的线性组合;此时无论网络有多少层,其整体也将是线性的,这会导致失去万能近似的性质但仅部分层是纯线性是可以接受的,这有助于减少网络中的参数。 为何 tanh 比 sigmoid 收敛快?tanh^{‘}(x)=1-tanh(x)^{2}\in (0,1) \sigmoid^{‘}(x)=sigmoid(x)*(1-sigmoid(x))\in (0,\frac{1}{4}] 画图代码def allFuncPloter(start=-10,end=10,save_path='tanh.png'): ''' 所有激活函数曲线绘制 ''' x=np.arange(start,end,0.1) y1,y11=sigmoid(x),sigmoidDerivative(x) y2,y22=tanh(x),tanhDerivative(x) y3,y33=relu(x),reluDerivative(x) y4,y44=leakyrelu(x,a=0.01),leakyreluDerivative(x) y5,y55=elu(x,a=0.01),eluDerivative(x) y6,y66=softplus(x),softplusDerivative(x) y7,y77=softsign(x),softsignDerivative(x) y8,y88=selu(x),seluDerivative(x) data=[[y1,y11],[y2,y22],[y3,y33],[y4,y44],[y5,y55],[y6,y66],[y7,y77],[y8,y88]] label=['sigmoid','tanh','relu','leakyrelu','elu','softplus','softsign','selu'] plt.clf() plt.figure(figsize=(10,8)) for i in range(len(data)): plt.plot(x,data[i][0],label=label[i],c=color_list[i]) plt.plot(x,data[i][1],label=label[i]+'Derivative',c=color_list[i]) plt.legend(loc='best',ncol=2) plt.savefig(save_path) def singleFuncPloter(start=-10,end=10,name='tanh'): ''' 单个指定激活函数曲线绘制 ''' x=np.arange(start,end,0.1) y1,y11=sigmoid(x),sigmoidDerivative(x) y2,y22=tanh(x),tanhDerivative(x) y3,y33=relu(x),reluDerivative(x) y4,y44=leakyrelu(x,a=0.01),leakyreluDerivative(x) y5,y55=elu(x,a=0.01),eluDerivative(x) y6,y66=softplus(x),softplusDerivative(x) y7,y77=softsign(x),softsignDerivative(x) y8,y88=selu(x),seluDerivative(x) data=[[y1,y11],[y2,y22],[y3,y33],[y4,y44],[y5,y55],[y6,y66],[y7,y77],[y8,y88]] label=['sigmoid','tanh','relu','leakyrelu','elu','softplus','softsign','selu'] plt.clf() #plt.figure(figsize=(10,8)) i=label.index(name) plt.plot(x,data[i][0],label=label[i],c=color_list[i]) plt.plot(x,data[i][1],label=label[i]+'Derivative',c=color_list[i+1]) plt.legend(loc='best',ncol=2) plt.savefig(name+'.png')

1

深度学习

ㅤ1574493559·2021-03-01 18:21 1 阅读 47
文章win10+vs2019+libtorch的安装
网上有了很多的方法了已经,虽然前人之述备矣,但是还是有两个细节问题是自己再查不同的方法才找到的,算是一篇杂文了,哈哈。 一,查看CUDA的版本:在cmd中输入命令nvidia-smi查看我的CUDA的版本号。可以看到,我的CUDA Version为10.1。 二,下载匹配的libtorch打开地址https://pytorch.org/ 选择自己电脑匹配的libtorch。两条链接,一个为debug版本的,一个是release版本的,建议都下下来,以后都可能用得到。我使用的是debug版本的。解压后我的路径如下:大家的路径名一定不一样,所以这里是本文和大家唯一的不一样的地方,大家要注意。而且注意的是,libtorch库是64位的,采用的是c++14的标准,所以不建议用vs2017以下的版本,我用的是vs2019,正好算是鸟枪换炮了这次。 三,vs2019的下载安装与项目创建我这里不太好演示了,目前vs2019基本都变成了在线安装,和以前的很大一个压缩包再安装不一样了。就在上面这个安装包中,我只选了“使用c++的桌面开发”。大概一点几个G,安装好了重启一下,就可以创建一个C++项目了。 四,vs2019使用libtorch的六项配置(一)64位项目的选择这一步非常重要,如果选错了,后面的五部肯定是要重新来一遍,血泪史。就是在下面的x64处,选择x64就可以了。它默认好像是x86。 (二)头文件目录配置配置头文件目录路径的地方为:项目——[项目名称]属性——VC++目录——包含目录D:\users\libtorch_debug\includeD:\users\libtorch_debug\include\torch\csrc\api\include所有需要加入路径的头文件夹,就只有这两个 (三)lib文件路径配置配置lib文件路径的地方为:项目——[项目名称]属性——VC++目录——库目录D:\users\libtorch_debug\lib (四)lib文件配置配置lib文件的地方为:项目——[项目名称]属性——链接器——输入——附加依赖项我把要敲入的lib库写在下面,这样直接复制粘贴就可以了。asmjit.libc10.libc10_cuda.libc10d.libcaffe2_detectron_ops_gpu.libcaffe2_module_test_dynamic.libcaffe2_nvrtc.libclog.libcpuinfo.libdnnl.libfbgemm.libgloo.libgloo_cuda.liblibprotobufd.liblibprotobuf-lited.liblibprotocd.libmkldnn.libtorch.libtorch_cpu.libtorch_cuda.lib (五)调试路径配置配置调试路径的地方为:项目——[项目名称]属性——调试——环境同样在这里把库路径填上。填的方法为:PATH=D:\users\libtorch_debug\lib;%PATH%这一块要稍微注意一下。 (六)GPU使用配置配置GPU地方为:项目——[项目名称]属性——链接器——命令行——其他选项 /INCLUDE:?warp_size@cuda@at@@YAHXZ 如果不配置这个, torch::cuda::is_available() 会返回0,就是不能使用CUDA。 五,测试我们用一个最简单的测试测试自己有没有配置正确 #include <iostream> #include <memory> #include <torch/torch.h> int main() { torch::Tensor tensor = torch::rand({ 5,3 }); std::cout << tensor << std::endl; std::cout << torch::cuda::is_available() << std::endl; return EXIT_SUCCESS; } 输出结果为:可以知道,我们的配置正常。

2

PyTorch

江枫与火·2021-02-26 10:47 1 阅读 44
文章事件抽取-plmee
plmeeplmee事件抽取用于裁判文书事件抽取 触发器的抽取触发器抽取器的目的是预测出触发了事件的token,形式化为token级别的多类别分类任务,分类标签是事件类型。在BERT上添加一个多类分类器就构成了触发器抽取器。 触发器抽取器的输入和BERT的一样,是WordPiece嵌入、位置嵌入和segment嵌入的和。因为输入只有一个句子,所以所有的segment ids设为0。句子首尾的token分别是[CLS]和[SEP]。 触发词有时不是一个单词而是一个词组。因此,作者令连续的tokens共享同一个预测标签,作为一个完整的触发词。 采用交叉熵损失函数用于微调(fine-tune)。 模型class TriggerExtractor(BaseModel): def __init__(self, bert_path, bert_train, dropout,event_type_num): super(TriggerExtractor,self).__init__() self.bert = BertModel.from_pretrained(bert_path) # 对bert进行训练 for name, param in self.bert.named_parameters(): param.requires_grad = bert_train self.dropout = nn.Dropout(dropout) self.taggers = nn.ModuleList([nn.Linear(self.bert.config.to_dict()['hidden_size'],2) for i in range(event_type_num)]) def forward(self, text_lengths, text_ids, masks): bert_out,bert_cls = self.bert(text_ids,attention_mask=masks) bert_out = self.dropout(bert_out) outputs = [] for tagger in self.taggers: out = tagger(bert_out).unsqueeze(-2) outputs.append(out[:,1:,:]) return torch.cat(outputs,dim=-2) 评测指标 位置正确位置正确且类别正确 元素的抽取给定触发器的条件下,元素抽取器的目的是抽取出和触发器所对应事件相关的元素,以及这些元素扮演的角色。 和触发器抽取相比较,元素的抽取更加复杂,主要有3个原因: 元素对触发器的依赖;大多数元素是较长的名词短语;角色重叠问题。 和触发器抽取器一样,元素抽取器也需要3种嵌入相加作为输入,但还需要知道哪些tokens组成了触发器,因此特征表示输入的segment将触发词所在的span设为1。 为了克服元素抽取面临的后2个问题,作者在BERT上添加了多组二类分类器(多组分类器设为所有角色标签的集合,对每个元素判断所有类型角色的概率)。每组分类器服务于一个角色,以确定所有属于它的元素的范围(span:每个span都包括start和end)。 由于预测和角色是分离的,所以一个元素可以扮演多个角色(对一个元素使用一组二类分类器,一组二类分类器中有多个分类器,对应多个角色),一个token可以属于不同的元素。这就缓解了角色重叠问题。 class ArgumentExtractor(BaseModel): def __init__(self, bert_path, bert_train, role_type_num, dropout): super(ArgumentExtractor, self).__init__() self.bert = BertModel.from_pretrained(bert_path) # 对bert进行训练 for name, param in self.bert.named_parameters(): param.requires_grad = bert_train self.start_taggers = nn.ModuleList( [nn.Linear(self.bert.config.to_dict()['hidden_size'], 2) for i in range(role_type_num)]) self.end_taggers = nn.ModuleList( [nn.Linear(self.bert.config.to_dict()['hidden_size'], 2) for i in range(role_type_num)]) self.dropout = nn.Dropout(dropout) def forward(self, text_lengths, text_ids, masks, type_ids): bert_out, bert_cls = self.bert(text_ids, attention_mask=masks, token_type_ids=type_ids) bert_out = self.dropout(bert_out) start_outputs = [] end_outputs = [] for start_tagger, end_tagger in zip(self.start_tagger, self.end_taggers): start_out = start_tagger(bert_out).unsqueeze(-2) end_out = end_tagger(bert_out).unsqueeze(-2) start_outputs.append(start_out[:, 1:, :]) end_outputs.append(end_out[:, 1:, :]) return torch.cat(start_outputs, dim=-2), torch.cat(end_outputs, dim=-2) 评测指标 位置正确位置正确且类别正确 AF-IEFRole Frequency (RF)RF定义为角色r在类型为v的事件中出现的频率:\operatorname{RF}(r, v)=\frac{N{v}^{r}}{\sum{k \in \mathcal{R}} N_{v}^{k}}Inverse Event Frequency (IEF) log内的分母表示论元角色r在多少个事件从出现\operatorname{IEF}(r)=\log \frac{|\mathcal{V}|}{|{v \in \mathcal{V}: r \in v}|} def compute_AF_IEF(self, dataset): event_num = len(self.schema.event_type_2_id) role_num = len(self.schema.role_type_2_id) self.rf = np.zeros((event_num, role_num), dtype=float) self.ief = np.zeros((role_num, ), dtype=float) with open(os.path.join(self.data_dir, file), 'r') as f: for line in f: json_item = json.loads(line) for event in json_item['events'].values(): event_id = self.schema.event_type_2_id[event['event_type']] for argu in event['argument']: role_id = self.schema.role_type_2_id[argu['role_type']] self.rf[event_id, role_id] += 1 for idx in range(role_num): self.ief[idx] = np.log(event_num/np.sum(self.af[:,idx] != 0)) role_count_per_event = np.sum(self.rf, axis=1) self.rf = self.rf / (role_count_per_event+1e-13) 将$RF(r,v)$和$IEF(r)$相乘得到$RF−IEF(r,v)$,使用RF-IEF度量角色r对于v类型事件的重要性: I(r, v)=\frac{\exp ^{\operatorname{RF}-\operatorname{IEF}}(r, v)}{\sum{r^{\prime} \in R} \exp ^{\operatorname{RF}-\operatorname{IEF}}\left(r^{\prime}, v\right)}给定输入的事件类型v,根据每个角色对于v类型事件的重要性,计算损失L_s和L_e ,将两者取平均就得到最终的损失。\begin{aligned}\mathcal{L}{s} &=\sum{r \in \mathcal{R}} \frac{I(r, v)}{|\mathcal{S}|} \mathrm{CE}\left(P{s}^{r}, \boldsymbol{y}{s}^{r}\right) \\mathcal{L}{e} &=\sum{r \in \mathcal{R}} \frac{I(r, v)}{|\mathcal{S}|} \mathrm{CE}\left(P{e}^{r}, \boldsymbol{y}_{e}^{r}\right)\end{aligned} rf_ief = ief * rf batch_weight = torch.exp(rf_ief) batch_weight_sum = torch.sum(batch_weight) batch_weight = batch_weight / batch_weight_sum batch_loss = batch_loss * batch_weight

2

自然语言处理

ㅤ1574493559·2021-02-26 10:45 2 阅读 47
文章龙泉寺贤超法师:用 AI 为古籍经书识别、断句、翻译
摘要: 坐落在京郊凤凰岭脚下的龙泉寺,称得上全国甚至全球科研实力最强的佛教寺庙。凭借当年学诚法师的一句「佛教是古老的,但佛教徒是现代的」,推动了龙泉寺里的高僧们搞科研、写代码,将佛学与新技术结合,将项目大众化 … 坐落在京郊凤凰岭脚下的龙泉寺,称得上全国甚至全球科研实力最强的佛教寺庙。 凭借当年学诚法师的一句「佛教是古老的,但佛教徒是现代的」,推动了龙泉寺里的高僧们搞科研、写代码,将佛学与新技术结合,将项目大众化、国际化。成果不断,屡上热搜,被外界持续关注。 近期,龙泉寺的贤超法师参加了国内某技术大会,分享了使用人工智能对《大藏经》进行整理和校勘的技术实践。 1、佛系 AI 的诞生:让佛经更易读贤超法师原是北京大学物理学院凝聚态物理硕士,2007 年他从北大毕业,2008 年在龙泉寺皈依,此后一直致力于龙泉大藏经的编修与佛学义理研究。2016 年,AlphaGo 在战胜李世石的历史性事件,引起了贤超法师对 AI 的关注。从那时候起,他便开始尝试将 AI 和自己正在研究的 OCR 技术以及自动标点相结合。 图注:贤超法师在 Techo Park 开发者大会上介绍其研究成果 2、佛原生 AI 解决古籍经文痛点龙泉寺在整理和校勘的《大藏经》为佛教经典的总集,也称为一切经。在汉传佛教的两千多年里,历朝历代都对《大藏经》进行了翻译、增补、修订。流传至今有数十个版本,少的有五千多字,多的有一亿两千万字。 图注:《乾隆版大藏经》雕版,修订参与官员、学者、高僧达 60 余人,刻字、刷印和装帧等工匠 860 余人,历时六年完成 2012 年,龙泉寺就着手整理《大藏经》,计划用整整十年的时间完成。因为传统方法对古籍的整理主要有版本校对、校勘、标点,这些步骤能够保证当代读者,也可以尽可能理解晦涩、生僻的经文。 三年后,龙泉寺整理出版了《南山八大部》;再次年,龙泉寺的藏经办公室成立,旨在探索利用人工智能技术,研发出基于深度学习的单字识别引擎;2017年,龙泉寺成立人工智能与信息技术中心,研发出能识别各种不同大藏经版本的整列识别引擎,并成功的将《六十华严》的大藏经版本进行电子化。 贤超法师目前担任藏经办公室主任,负责《大藏经》的整理工作。 3、自动标点:OCR+深度学习为了降低人们阅读古文典籍的门槛,提高学者的工作效率,在近年来贤超法师团队,运用了包括深度学习、OCR 在内的技术改变传统《大藏经》的解读方式,目前已经取得了颇为惊艳的效果。 图注:现代汉语中,句号、引号、书名号等常用标点近十种,古汉语中仅有的句号、顿号,经文中也很少出现,难以阅读 贤超法师介绍道,所谓自动标点,是指在没有人工干预的前提下,根据算法给古籍文本自动标注现代中文标点的技术,这主要是为了方便现代读者阅读。 此前,已有人工智能为古文加标点的相关研究,不过贤超法师表示,之前基本只是为古文加句号,他认为这个做法「比较保守,比较学术性」。 而他的团队将深度学习运用到了自动标点上,可以以更高的准确性,给古文添加句号、逗号、问号、感叹号、冒号、分号和顿号其中标点符号。经过验证,他们所研发的 Transformer 标注结果,和人类的标注结果「几乎已经无法区分」。 4、RNN+LSTM+ResNet 效果全面提升自动标点,在 NLP 领域来说,就是一个简单的序列标注问题。解决这类问题的标准方法,就是使用循环神经网络(RNN)。 为了增强 RNN 的性能,在此基础上又发展出来了双向 RNN,也就是每一时刻的输出不仅仅取决于之前时刻的所有输入,而是同时取决于之前和之后的输入。之后,贤超法师团队又将 LSTM 方法引入。 但是此前基于这些技术所实现的自动标点,效果仍不是很令人满意。贤超法师团队之所以达到出乎意料的效果,是因为他们在此前的基础上,引入了 ResNet 残差网络(Residual network)。 图注:团队 2019 年发表论文《大藏经的汇编:当 AI 遇见佛教》,介绍了其自动标点技术 贤超法师解释道,以往的神经网络最多就是十几层、二十多层的结构,如果层数再多,训练结果就不太容易收敛了。而残差网络动辄几百层,甚至上千层。更深的网络有助于捕捉到更深层的语义信息,这是其大获成功的关键。 团队也曾尝试使用卷积神经网络(CNN),最终效果是,残差网络比卷积神经网络的标点准确率平均高出 20-30% 左右。 AI 自动标点工具效率如何呢?贤超法师用一天时间完成了 2 万字左右规模的古文标点,按照古籍标点每千字 15 元的一般稿酬水平,相当于一天创造了 300 元的经济价值。即使自动标点的准确率只按照 60% 来算,其每天也创造了 180 元的价值。 图注:团队对该自动标点工具也在不断升级,目前一代的准确率达到 93.3% 目前,由于贤超法师团队的训练数据多取自佛经,因此其自动标点更适合标点佛教典籍。不过,他表示,未来该技术也将应用在,经史子集等更多领域的古文献整理工作之中,从而让学者们摆脱机械、重复性的劳动。 今后的古籍点校工作模式有希望改为:AI 先断句、加标点;专业学者进行后期校对、修改。贤超法师团队在 18 年就开源了这一自动标点的在线服务,访问古籍·酷(http://gj.cool)可以试用,还可以申请免费调用 API。 5、识别、翻译:AI 成为佛经汉化百宝箱除了自动标点,贤超法师还将 AI 应用古籍研究的多个方面。 1)文白对句:对齐 & 翻译文白对句,也就是古文到现代文的对齐和翻译。为了实现 AI 文白对句,贤超法师首先构建了一个文白对齐的语料库,然后设计了一个对齐算法,取得了很好的效果。根据相似度和差异度这两个独立指标,可以非常容易地定位出对齐错误的句子。 图注:将《大藏经》翻译并单句分离开对齐,有助于人工后期检索与校对 由于《大藏经》专业名词众多,且历代翻译著作语料繁杂,因此并非古文相关专业就能搞定。《大藏经》的总字数以亿计,如果仅依靠有限的几位专家,工作量将十分巨大,所以,AI 的介入,为专家们分担了不少工作量。 2)基于深度学习的 OCR,识别古籍文字目前市面上的 OCR 软件都是针对印刷体的,因此不能很好地识别古籍文献中的字体。 贤超法师及其合作团队,基于 CNN+LSTM+CTC 框架,开发了新的 OCR 引擎。然后基于《大藏经(高丽版)》的七万多张整图,168 万条文本行图像的数据集进行训练。 3)基于弱监督学习的较精确文字分割最终,其开发的 OCR 方法能够进行古籍的单字识别、单列识别和半自动的多列识别,能够有效地完成各类古籍的电子化工作。 图注:OCR 软件识别古文将其数字化 贤超法师还在其公众号「贤超小和尚」(微信号:xianchaofashi)中,分享了更多项目实践和学佛感悟,感兴趣的朋友可以关注。 6、科技与佛法:以悲悯为内同的不同外化佛法与科技,距离并不遥远。 我们也曾在《本世纪,佛祖派机器人来弘扬佛法》一文中,对佛教与科技融合的趋势做出过报道,近年来涌现的贤二机器人、机器观音、智能佛珠等等,早已讲科技深刻和谐地融入进佛法。 图注:科技与佛学的融合中佳作频出,吸引关注 龙泉寺的另一位知名高僧、IT 禅修营的创办者贤信法师,在一次访谈里被提问佛法和科技的关系。 他回答:「科技,是追求物质世界的真。佛法,是内心世界的真。很多在科学上做出探索、在技术上做出探索的人,最开始是抱着想为人类做贡献的心,跟佛教提出最慈悲的追求也是相共的,这就是科技与佛法的共同点。」 参考资料:贤超小和尚公众号:《人工智能与中华文明的碰撞交融》2050 云栖大会:《贤度法师——龙泉寺的科技实践》龙泉寺自动标点工具:http://gj.cool/gjcool/index

1

自然语言处理

AI小助手·2021-02-26 10:45 1 阅读 57
文章盘点近期大热对比学习模型:MoCo/SimCLR/BYOL/SimSiam
很多大佬认为,深度学习的本质就是做两件事情:Representation Learning(表示学习)和 Inductive Bias Learning(归纳偏好学习)。在表示学习方面,如果直接对语义进行监督学习,虽然表现很好,但是它需要很多的样本并且往往是需要对特定的任务进行设计,很难具有迁移性。所以难怪各位大佬们都纷纷为自监督学习站台,自监督是未来! 自监督学习有大类方法,一个是生成方法一个对比方法,如上图。生成方法往往会对像素级损失进行约束,关于这一类笔者已经在之前的文章中进行了整理,而对比学习在表示学习上做的事情就是:其实模型不必要知道关于特征的细节,只要学到的特征足以使其和其他样本区别开来就行。 Contrastive loss对比损失 Contrastive loss,简单的解释就是,利用对比正-负样本来学习表示。学习的目的为: 这里 x+ 是与 x 相似或相等的数据点,称为正样本。x− 是与 x 不同的数据点,称为负样本。score 函数是一个度量两个特征之间相似性的指标,直接算内积来表示: 然后尝试优化以下期望,即让正例样本越相似,要负例样本越远就好。 其实这个叫法最初似乎出自 Yann LeCun “Dimensionality Reduction by Learning an Invariant Mapping”,本来是用于处理在降维空间中正样本和负样本之间的相似/不相似的远近距离关系,式子为: 损失函数主要惩罚如果原本相似的样本 y=1,但在特征空间的欧式距离较大,则说明当前的模型不好,损失变大。同样的如果原本不相似 y=0,但其特征空间的欧式距离反而小的话,损失也会变大。上图是 loss 与样本特征的欧式距离 d 之间的关系,其中红色虚线表示的是相似样本的损失值,蓝色实线表示的不相似样本的损失值。 def contrastive_loss(self, y,d,batch_size): tmp= y *tf.square(d) #tmp= tf.mul(y,tf.square(d)) tmp2 = (1-y) *tf.square(tf.maximum((1 - d),0)) return tf.reduce_sum(tmp +tmp2)/batch_size/2 而这种成对 loss 的思想在其他领域如搜索推荐会有其他的变体: 如何选择正-负例pair?Easy negative example 比较容易识别,所以相对来说找一些较难的 pair 是有利于训练的。一般可分为: Offline mining:计算所有的数据的 embedding,然后计算所以 pair 之间的距离判断其难易程度,主要选择 hard 或者 semi-hard 的数据。 Online mining:为每一 batch 动态挖掘有用的数据,将一个 batch 输入到神经网络中,得到这个 batch 数据的 embedding,Batch all 的方式还是会计算所有的合理的,Batch hard 偏向于选择距离较大的正样本和距离最小的负样本。 这里需要思考的问题是这种 pair 对究竟多少数量是合适的? 一般来说,对比方法在有更多的负样本的情况下效果更好,因为假定更多的负样本可以更有效地覆盖底层分布,从而给出更好的训练信号。 所以回到 MoCo 的图了,既然样本数量对于学习到的样本质量有很大的影响,那么我们就扩展负样本的数量就好!但是目前对于 batch size 是没有很好的解决办法的,实际上如下图 a,loss 的梯度会流过编码器的正样本 q 和负样本 k 的 Encoder。 这意味着样本的数量被限制在 mini-batch 的尺寸上,即我们并不能采样无穷多的样本,GPU 负载能力有限。 end-to-end:先编码 encoder(可同可不同),然后内积算 loss 再梯度。但是这种方法由于 dictionary size 和 mini-batch 的强耦合性(负例样本对也会为 loss 产生贡献,也会回传梯度),在 batch 大的时候优化难,而在 batch 小的时候,batch 之间的参数会不一样,也就是 GPU 大小限制了模型的性能。 memory bank:把 dictionary size 从 mini-batch 中解耦出来,即先把所有样本的特征保存下来 bank,然后每次随机采样,再梯度 query 的 encoder 的参数。但是这样只有当所有 key 被 sample 完以后才会更新 memory bank,不同的 key 在和 query 是不一致的和滞后的,因为每一次 sample encoder 都会更新虽有 memory bank 后面也加入了 momentum,但是是针对 sample 来的,在更新 memory bank 时会保留一部分上一轮的特征值。 MoCo:是以上两者的融合版本,将 dictionary 作为一个 queue 进行维护当前的negative candidates pool,且它是改成了 queue 的动态更新机制,每 sample 一个 batch key(所以一个 trick 就是会使用 Shuffling BN,打乱再 BN),进队后相对于一些最早进入队列的 mini-batch 对应的 key 进行出队操作,这样保证一些过时的、一致性较弱的 key 可以被清除掉。这样就同样是解耦,K 是队列长度,K 可以设置很大,同时更新也不会有问题。 按照以上伪码,可以简单看看 MoCo 的三个比较重要的函数: @torch.no_grad() def _momentum_update_key_encoder(self): """ key encoder的Momentum update """ for param_q, param_k in zip(self.encoder_q.parameters(), self.encoder_k.parameters()): param_k.data = param_k.data * self.m + param_q.data * (1. - self.m) @torch.no_grad() def _dequeue_and_enqueue(self, keys): """ 完成对队列的出队和入队更新 """ # 在更新队列前得到keys keys = concat_all_gather(keys)#合并所有keys batch_size = keys.shape[0] ptr = int(self.queue_ptr) assert self.K % batch_size == 0 # for simplicity # 出队入队完成队列的更新 self.queue[:, ptr:ptr + batch_size] = keys.T ptr = (ptr + batch_size) % self.K # 用来移动的指针 self.queue_ptr[0] = ptr def forward(self, im_q, im_k): # 计算query features q = self.encoder_q(im_q) # queries: NxC q = nn.functional.normalize(q, dim=1) # 计算key features with torch.no_grad(): # 对于keys是没有梯度的反向的 self._momentum_update_key_encoder() # 用自己的来更新key encoder # 执行shuffle BN im_k, idx_unshuffle = self._batch_shuffle_ddp(im_k) k = self.encoder_k(im_k) # keys: NxC k = nn.functional.normalize(k, dim=1) # 还原shuffle k = self._batch_unshuffle_ddp(k, idx_unshuffle) # 计算概率 # positive logits: Nx1 l_pos = torch.einsum('nc,nc->n', [q, k]).unsqueeze(-1) #用爱因斯坦求和来算sum # negative logits: NxK l_neg = torch.einsum('nc,ck->nk', [q, self.queue.clone().detach()]) # logits: Nx(1+K) logits = torch.cat([l_pos, l_neg], dim=1) # 平滑softmax的分布,T越大越平 logits /= self.T # labels是正例index labels = torch.zeros(logits.shape[0], dtype=torch.long).cuda() # 出队入队更新 self._dequeue_and_enqueue(k) return logits, labels 论文链接:https://arxiv.org/abs/1911.05722 代码链接:https://github.com/facebookresearch/moco 完整的中文源码阅读笔记:https://github.com/nakaizura/Source-Code-Notebook/tree/master/MoCo SimCLRMoCo 强调 pair 对的样本数量对对比学习很重要,SimCLR 认为构建负例的方式也很重要。先说结论: 多个数据增强方法组合对于对比预测任务产生有效表示非常重要。此外,与有监督学习相比,数据增强对于无监督学习更加有用; 在表示和对比损失之间引入一个可学习的非线性变换可以大幅提高模型学到的表示的质量; 与监督学习相比,对比学习得益于更大的批量和更多的训练步骤。 模型过程如下: 作者认为多种数据增强操作的组合是学习良好表示的关键,论文里面主要讨论过的有如下: 推荐有一个 github 用于数据增强很好用,pip install imgaug:https://github.com/aleju/imgaug 为什么要用非线性的projection head?由图可知在 representation 与 contrastive loss 间使用了可学习的 non-linear projection,这个其实是非常简单的单层 MLP+ReLU 的架构。其优势在于避免计算 similarity 的 loss function 在训练时丢掉一些重要的 feature,可以改善之前的层的表示质量。 损失函数 NT-Xent(the normalized temperature-scaled cross entropy loss), 和 是从 Projection Head 获得的输出矢量,output∈{0,1} if k≠i,τ 表示温度参数可以用来放缩概率。 值得注意的一个 trick 就是会算两次(即公式中间的 2N,会把 i-j 的计算,用 j-i 成对的再算一次) 做完训练后,特征表示可以拿去下游做微调,比如用于图像分类等下游任务。整体的框架图如下: 论文链接:https://arxiv.org/abs/2002.05709 代码链接:https://github.com/google-research/simclr 注:他们用了 128 块 GPU/TPU,来处理每个 minibatch 9000 个以上样本(这是为了获得足够的负样本对比,所以必须要比普通的 batch 要大),并完成 1000 轮的训练。 MoCo v2在 MoCo 的基础上加入了 SimCLR 的 projection head 和多种数据增强手段如模糊等。ImageNet 任务提升了 6%。 SimCLR v2结合无监督预训练、半监督训练、有监督的微调和未标记数据的蒸馏等等一系列的训练手段。具体如下图: 左边,非监督的方法学习一个任务无关的通用的表征,这里直接用 SimCLR,不同点在于网络变大和也借用了 MoCo 部分架构。 中间,用监督的方法进行 fine-turning 右边,在 unlabeled 大数据集上进行蒸馏 这种架构显然很适合在工业界落地。 BYOL无需负样本也能够取得好的效果?!出自 DeepMind的 NIPS20’的Bootstrap Your Own Latent(BYOL),BYOL 认为之前的方法都基于 negative pairs,而它们很大程度上取决于图像增强的选择,所以为什么不直接从图像增强视角出发呢?框架图如下: 没有 pair,但是 BYOL 使用两个相互交互并相互学习的神经网络,分别称为在线网络和目标网络。架构如上: 上面的分支是 online network,包括了 embedding,projection 以及 prediction,其中嵌入的使我们最要想要的模块。 下面的分支是 target network,包括 embedding 和 projection 。 online 网络参数使用 L2 的梯度进行更新,而 target 网络直接通过 online 的 momentum 得到,这里 target 的就充当了之前负样本的功能。 即 target 可以随机开始得到输出比如一开始的结果为 1.4% 非常差,此时新开一个分支训练 online 去预测同一图像在不同增强视角下的 target 的表示(从一个分支直接预测了另一个分支的输出,用滚动编码方法更新),此时结果居然就可以到非常高的程度了。 也正是 BYOL 主打其 不需要进行 negative 样本的 idea。所以因此它的性能对 batch size 的大小不是特别敏感,在同等参数量的情况下,BYOL 的效果也是非常好。 为什么BYOL有效?最近有一篇论文对其做了细致的测试,其中最关键的结论就是:BYOL 移除 BN 之后的表现就和随机瞎猜一样了。由于 BN 的出现本来就是为了克服 domain 和 target 的差异问题,即预防 mode collapse,可以将正负样本的距离拉开,所以 BYOL 可能也是做了这样的事情,做了对图片均值和方差的学习,然后重新分配结果和特征值。 BYOL和MoCo、SimCLR的区别MoCo、SimCLR 更偏向于问这两张图片之间有何差异?BYOL 可能是在问这张图片与这些图片的平均有什么差异? 论文链接: https://arxiv.org/abs/2006.07733 SimSiam孪生网络已成为无监督表达学习领域的通用架构,现有方法通过较大化同一图像的两者增广之后的相似性使其避免“崩溃解(collapsing solutions)”问题。即在训练网络的时候,网络会很迅速找了一个退化解并达到了最小可能损失 -1。 但是在 kaiming 大神的这篇文章中,他们提出的 Simple Siamese(SimSiam)网络不仅可以没有 negative sample pairs;没有 arge batch;甚至没有 momentum encoders 就学到有意义的特征表达。 主要是提出 stop-grad 的概念,结构如下: # Algorithm1 SimSiam Pseudocode, Pytorch-like # f: backbone + projection mlp。f是backbone+projection head部分组成 # h: prediction mlp for x in loader: # load a minibatch x with n samples x1, x2 = aug(x), aug(x) # random augmentation,随机增强后的x1和x2 #分别做两次投影操作 z1, z2 = f(x1), f(x2) # projections, n-by-d p1, p2 = h(z1), h(z2) # predictions, n-by-d #计算不对称的两个D得到loss L L = D(p1, z2)/2 + D(p2, z1)/2 # loss L.backward() # back-propagate,反向传播 update(f, h) # SGD update,梯度更新 def D(p, z): # negative cosine similarity z = z.detach() # stop gradient,在这里使用detach做stopgrad的操作 p = normalize(p, dim=1) # l2-normalize z = normalize(z, dim=1) # l2-normalize return -(p*z).sum(dim=1).mean() 其实 stopgrad 的本质就是一个交替方案(固定一个,求解另一个)的近似求解。 论文链接:https://arxiv.org/abs/2011.10566 最后再看个对比方便分清楚:

1

深度学习

AI小助手·2021-02-24 14:32 1 阅读 58
文章Flyai人工智能社区参赛指南—非官方版
Flyai人工智能社区参赛指南—非官方版        牛年新春马上到来,在这里,先祝小伙伴们新春大吉,工作顺利,合家幸福!再祝小助手,天天美美哒!         不知不觉,在社区混迹有两年余,通过打怪升级,从一个AI新手成功的晋升为AI菜鸟!别人是天才,我是“抄添裁”,代码靠抄,适度增添,合理剪裁!ctrl+C(V)法力无边,千秋万代,一统江湖!为了给新手们提供点方便,让他们尽快上手,于是就想写个参赛指南,尽一个菜鸟应尽的责任和义务(主要还是因为新手看完官方的指南,往往找不着北)。下面,是依据flyai2.0 windows版本,结合自己的经验编写,不足之处,大家多多指正。          一、主页面         在浏览器中,输入www.flyai.com,进入官方网站主页面:         主页面上方有赛事、学习圈、实验室,以及自己的用户名。         当前主页面就是赛事页面,可以看到当前的比赛,你可以参加自己感兴趣的比赛。学习圈发布的主要是小助手不知道从哪里抄来的文章、其他小伙伴的水文和答辩经历等。实验室,是个什么东东,估计和google colab类似的东西吧,我也想进去看看。         参加比赛活动,需要个人注册,很简单,微信一扫基本OK了,然后官方会送1000的FlyAI分值,这些分值比赛会用到,基本是线上训练一分钟,就消耗1个FlyAI分值。曾经就有1000分在我面前,我没珍惜,直到用光,我才后悔莫急……现在主要靠每日签到赚个二三十分,痛并快乐着!         二、项目页面         注册好后,现在我们选取一个比赛来参加吧,比如上图第一个,心率不齐病症检测赛。         页面上,我们可以看到赛事介绍,竞赛排行榜,讨论等内容。我们通过阅读赛事介绍,可以了解比赛的相关内容,竞赛排行榜可以看到小伙伴们的比赛成绩,你还可以在讨论页面发表高论,赚个20FlyAI分。         好吧,我们现在要做的就是报名参赛,点击右上方那个金光灿灿的“报名参赛“按钮,然后,报名参赛就变成了查看样例,再点击”查看样例“,进入代码页面。         左侧边栏,是代码的文件,这里有五个,分别是app.json,main.py,path.py,prediction.py和requirements.txt。        app.json:这个是该项目的配置文件,不用管它。         main.py:这是代码的主要文件,将代码上传到服务器后,服务器就会自动执行该文件的代码,这个也可以说是代码的入口文件,我们将在这个文件中实现程序的主要功能,比如说建立模型、处理数据、训练模型、保存模型等。         path.py:这里面是路径的配置,默认有DATA_PATH和MODEL_PATH,你可以添加自己的路径配置。         prediction.py:main.py执行完毕后,服务器将调用该文件的Prediction类,依次调用这个类的load_model和predict功能,完成模型的验证,根据模型提交的结果,给出得分。         requirements.txt:这里面是该项目用到的包,比如你代码里面用的pytorch版本是1.4,那么,你可以在这个文件里面加入torch==1.4.0,官方服务器一般会把常用的包安装好了,比如说numpy、pandas等,一些不常用的,而你的代码里需要用到的,就可以在这个文件里面添加。         理论上,我们只要按照代码框架,完成main.py和prediction.py这两个文件代码的编写就行了。         右侧栏,就是相应文件的内容,我们可以在电脑上进行更改,完成后,点击下方的提交训练,就可以上传代码到服务器端进行训练。         右侧栏上方最右边,有三个按钮,分别是下载代码、上传代码、查看代码。下载代码,即可将代码下载到本地编辑,完成后,再打包,点击上传代码,即可将线下代码上传到线上;点击查看代码,可以查看以前提交过的代码,方便修改。         三、下载代码         线上编写,有很多不方便,我们可以下载下来线下编写调试。点击下载代码,解压后,可以得到如下文件:         可以看到,会比线上多出几个文件,多出的文件不用管它,我们只看这个flyai.exe,双击运行它,如下图:         在这里,可以点击“下载数据“按钮,下载部分数据到线下,这时会在当前文件下建立一个data文件夹,用来保存下载数据。点击”提交GPU训练“按钮,即可以将当前目录下的相关文件上传到服务器端进行训练。         我们先来看看下载下来的样例数据,样例数据只是全部数据的一部分,主要是用来线下调试代码的。比如,在路径“data/input/ArrhythmiaClassification/“下,有个train.csv文件,打开看看:         其中,data就是模型训练需要用到的数据,label是标签。在图像类的比赛,第一栏一般是图片的路径,不同的比赛,略有不同。         现在,就可以按照main.py和prediction.py里面样例框架,编写自己的代码,值得注意的是,训练好的模型文件要保存在“data/output/model”路径下面。根据需要,也可以另外新建文件夹或者文件。完成代码编写后,可先用线下数据,本地运行一下,看有没有什么BUG,确定无误后,就可以上传代码,到线上训练了。         四、上传代码         上传代码有两种方式,一种是直接点击上面flyai.exe图中的“提交GPU训练”,程序就会自动将当前文件夹下面的文件上传到线上,这里需要注意的是,有些我们自己建立的文件夹可能不会上传,所以,如果有新建的文件夹,建议不要采取这种方式上传代码。         另外一种上传方式是手动打包上传,这里要将app.json、main.py、prediction.py、path.py、requirements.txt这五个文件,加上我们新建的文件和文件夹,一起打包成压缩包,然后点击下图中“下载代码”旁边的上传按钮,就可以把我们的文件上传到线上了,再点击“提交训练”按钮,就可以训练了。        五、线上运行         这时候,我们可以查看程序运行状态,如下图:         由于线上服务器数量有限,可能需要排队,只能耐心等待,如果不想等,可以点击“取消排队”,但是不能重复提交代码训练,一次只能训练一个任务,如果提交两个以上任务,就会出现上图中的“已加入队列!之前任务完成后,将自动开始训练”,不过有时候,网站后台代码有问题,也会出现这种情况,这时候,就需要我们美丽的Flyai小助手出场了,将你遇见的问题,跟她反馈,一般都能很好解决。         训练日志内容会显示requirement.txt里面安装包的安装状况,之后就会显示执行main.py输出显示的内容,比如print。如果程序有错误,会显示错误提示,停止训练。         每训练一次,都会消耗我们的FLYAI分值,如果分值为零,就不能再进行训练了。获取积分的方式有每日签到、每日讨论、写写文章,邀请朋友和充钱等等,也可以坚持签到,像我一样发发文章,Fai值自然而来!         好了,基本上,常用的东西就是这样了,不过,各位一定确定以及肯定还会碰到各种问题,可以问小助手,边打怪边升级,钢铁就是这样练废的!

3

数据分析

天涯·明月·刀·2021-02-22 17:04 1 阅读 89
文章堪比当年的LSTM,Transformer引燃机器学习圈:它是万能的
谷歌研究科学家 David Ha:Transformer 是新的 LSTM。 2017 年 6 月谷歌发布论文《Attention is All You Need》时,我们或许都没有意识到它提出的 Transformer 架构将带来多少惊喜。 在诞生至今不足四年的时间里,Transformer 不仅成为自然语言处理领域的主流模型(基于 Transformer 的预训练语言模型成为主流),还开始了向其他领域的跨界,近几个月来出现了大量将 Transformer 应用于计算机视觉领域的研究。 2020 年 10 月,谷歌提出了 Vision Transformer (ViT),可以直接利用 transformer 对图像进行分类,而不需要卷积网络。ViT 模型取得了与当前最优卷积网络相媲美的结果,但其训练所需的计算资源大大减少。 2020 年 12 月,复旦、牛津、腾讯等机构的研究者提出了 SEgmentation TRansformer(SETR),将语义分割视为序列到序列的预测任务,该模型在 ADE20K 上排名第一,性能优于 OCNet、GCNet 等网络。 2021 年 1 月初,OpenAI 又连放大招 ,用 DALL·E 和 CLIP 打破了自然语言与视觉的次元壁。两个模型都利用 Transformer 达到了很好的效果,前者可以基于本文直接生成图像,后者则能完成图像与文本类别的匹配。 由此,「Transformer 是万能的吗?」成为了近期机器学习社区的热门话题。谷歌大脑研究员 David Ha 发推表示:Transformer 是新的 LSTM。 他否定了自己在 2017 年 5 月发表的言论:「LSTM 就像神经网络中的 AK47。不管我们多么努力地想用新事物取代它,都是白费力气。从现在起它还将应用 50 年。」LSTM 由 Sepp Hochreiter 和 Jürgen Schmidhuber 于 1997 年联合提出,当时已诞生 20 年。 David Ha 不会想到,这句预言被一个月后出现的 Transformer 打破,而这仅用了 4 年时间。 著名机器学习资源网站 Papers with Code 在 1 月 20 日发布的 Newsletter 中列举了近期应用 Transformer 的十大新任务: 图像合成论文:Taming Transformers for High-Resolution Image Synthesis链接:https://arxiv.org/pdf/2012.09841v1.pdf 多目标追踪论文:TransTrack: Multiple-Object Tracking with Transformer链接:https://arxiv.org/pdf/2012.15460v1.pdf 音乐生成论文:Compound Word Transformer: Learning to Compose Full-Song Music over Dynamic Directed Hypergraphs链接:https://arxiv.org/pdf/2101.02402v1.pdf 舞蹈生成论文:Dance Revolution: Long-Term Dance Generation with Music via Curriculum Learning链接:https://arxiv.org/pdf/2006.06119v5.pdf 3D 目标检测论文:Self-Attention Based Context-Aware 3D Object Detection链接:https://arxiv.org/pdf/2101.02672v1.pdf 点云处理论文:PCT: Point Cloud Transformer链接:https://arxiv.org/pdf/2012.09688v1.pdf 时序预测论文:Temporal Fusion Transformers for Interpretable Multi-horizon Time Series Forecasting链接:https://arxiv.org/pdf/1912.09363v3.pdf 视觉 - 语言建模论文:VinVL: Making Visual Representations Matter in Vision-Language Models链接:https://arxiv.org/pdf/2101.00529v1.pdf 车道形状预测论文:End-to-end Lane Shape Prediction with Transformers链接:https://arxiv.org/pdf/2011.04233v2.pdf 端到端目标检测论文:Deformable DETR: Deformable Transformers for End-to-End Object Detection链接:https://arxiv.org/pdf/2010.04159v2.pdf 而除了 David Ha 以外,另一位研究者英伟达研究科学家、前 OpenAI 研究科学家 Ankur Handa 也表示「Transformers are all you need」: is All You Need? Transformer 引领了不止一种潮流。 在其论文《Attention is All You Need》发表后,各种「** is All You Need」论文纷纷出现。就连 LSTM 提出者 Sepp Hochreiter 也写过一篇《Hopfield Networks is All You Need》。有趣的是,这篇论文正是对 Transformer 核心注意力机制新颖性的驳斥:Transformer 中的注意力机制等价于 Hopfield 网络中的更新规则。 Transformer 的强大主要归功于其中的注意力机制。注意力机制在 NLP 领域的应用最早可以追溯到 2014 年 Bengio 团队将其引入神经机器翻译任务,但那时模型的核心架构还是 RNN。相比之下,Transformer 完全抛弃了传统的 CNN 和 RNN,整个网络结构完全由注意力机制组成,这种改变所带来的效果提升也是颠覆性的。 然而,Sepp Hochreiter 等人在 2020 年 7 月发表的论文《Hopfield Networks is All You Need》中表示,Transformer 中的注意力机制其实等价于扩展到连续状态的 modern Hopfield 网络中的更新规则。 Sepp 这篇论文发表时,Transformer 的跨界之旅已经开始。2020 年 5 月,Facebook AI 推出了 较早的将 Transformer 成功整合为检测 pipeline 中心构建块的目标检测框架——Detection Transformer(DETR),用于目标检测和全景分割。6 月,OpenAI 将基于 Transformer 的模型 GPT-2 应用到图像领域,用于图像分类任务。 半年过去,越来越多的工作开始探索如何将 Transformer 应用于计算机视觉等其他领域,最近更是出现了「Transformers are all you need」、「Transformers are the new LSTMs」的说法。 Transformer是新的LSTM吗?1997 年,Sepp Hochreiter 与 Jürgen Schmidhuber 联合发表了长短期记忆网络(LSTM)论文,被认为是机器学习发展史上的一座里程碑。 LSTM 是一种特殊的循环神经网络(RNN)。Sepp Hochreiter 在 1991 年分析了随时间反向传播(BPTT)带来的梯度爆炸和梯度消失问题;1997 年,Sepp Hochreiter 与 Jürgen Schmidhuber 在 LSTM 论文中引入 CEC 单元解决 BPTT 带来的梯度爆炸和消失问题。之后又有许多研究者对其进行了改进和普及。 LSTM 单元的基本结构(图源:https://en.wikipedia.org/wiki/Long_short-term_memory) 2020 年 2 月,LSTM 提出者 Jürgen Schmidhuber 撰文综述了 LSTM 的十年发展史,介绍了它在机器翻译、语音识别、机器人学、时序预测、聊天机器人等多个领域的应用。 而 Transformer 诞生伊始就完全舍弃了 RNN,在 LSTM 占优势的 NLP 领域逐渐站稳脚跟。现在,许多研究又将它应用于时序预测、音乐生成、图像分类等跨界任务中。在 Papers with Code 最近发布的 Transformer 应用十大新任务中,过去都有着 LSTM 的活跃身影。 Transformer 是新的 LSTM 吗?从模型应用领域的多样性来看,这似乎已见雏形。 不知道如果现在发表「Transformer 无法被替代,还可以再用 50 年」的预言,多久之后会被打破。 参考链接:https://paperswithcode.com/newsletter/3https://twitter.com/hardmaru

4

深度学习

AI小助手·2021-02-06 18:04 1 阅读 216
文章介绍一篇深度学习图像分类中处理noisy labels方法的综述
该文最早2019年在arXiv上发表,2021年1月11给出修正版 “Image Classification with Deep Learning in the Presence of Noisy Labels: A Survey“。 label noise是难以避免的,深度学习网络由于数据过拟合的原因对这种问题还是很脆弱,造成泛化能力下降。对付的方法提出不少,主要分成noise model-free和noise model-based两种。前者采用robust loss、正则化或其他学习手段,后者采用噪声结构估计方法,如Noise channels、data cleaning、importance weighting和dataset pruning等。 一般提到两种噪声:feature noise和label noise。这里讨论后者,其破坏力远远大于前者。传统方法讨论这个问题也是有历史的,比如Frenay & Verleysen “Classification in the presence of label noise: a survey“ (2014)。本文则是讨论DL NN的方法。Label noise 受影响有三个因素: data features, true label of data, labeler characteristics。这样噪声也就分成三类:random noise(类别和特征无关),Y-dependent noise (类别有关)和XY-dependent noise (和特征和类别都有关)。注:这里不考虑multi labelled情况。如下表列出文章讨论的方法: 先说Noise model-based方法,找到最佳估计器是其主要目标。Noise channels设置如图:在base classifier基础上加入noise channel,其中有noise transition matrix将网络预测映射到noisy labels,该过程称为loss correction。 注:定义noise channel的方法有几种,explicit、iterative和complex等。Label noise cleaning方法依赖于feature extractor,也是一个迭代过程。有的利用clean labels,融合无噪声标记结构于noisy labels做矫正;有的利用noise labels和clean labels,从混乱的标记中提取噪声结构;还有只用noise labels,直接incrementally估计干净的后验标记分布,这里需要regularizers使后验分布均匀。data pruning去除label noise数据,有两种途径:一是完全去除,再训练;二是去除noisy data的标记,这样变成unlabeled,采用semi-supervised学习方法。sampling choosing方法,不同于data pruning,这里选择是动态的迭代过程,连续监控base classifier。两种最主要的方法是curriculum learning和multiple classifiers。前者从easy sample开始,然后加入hard examples,也叫self paced learning;后者采用多模型,彼此矫正错误,其中初始化最关键。sample importance weighting方法,不同于sample choosing,在于weight不是binary。labeler quality assessment涉及labeler characteristic。如下是这些方法的示意图: 从左开始,1)2d空间中单个类别的样本表示,绿色代表干净样本,红色代表噪声样本;2)label噪声清除算法旨在纠正噪声数据label;3)数据集修剪方法旨在消除噪声数据(或仅抹去label);4)样本重要性加权算法旨在提高干净样本权重和降低噪声样本权重(按大小显示)。 再说Noise model free方法。类似overfit avoidance,其依赖分类器噪声忍耐性,加正则化提升性能。robust losses阻止使用任何先验知识,对noisy和clean数据一视同仁。比如categorical cross entropy (CCE) loss,Improved mean absolute value of error (IMAE)。Meta learning学习不仅是复杂的任务函数,同时学习这个学习本身,目的是避免人工设计的因素,如loss,architecture和optimizer等等。regularizers很有名的,比如weight decay,dropout,BN,adversarial training,mixup 和 label smoothing。ensemble也是常用的,bagging和boosting。其他方法还有一些,比如complementary labels、Prototype learning和multi-instance-learning等。 最后还有一个实验比较: 一般噪声结构是专门域特有,并且没有先验信息假设等,那么采用noise model方法更合适。如果噪声随机,性能下降多是overfit原因,则noise model-free实现容易。理解DL的NN结构,明白label noise影响哪一部分,这样更能分析其不利效果。有了处理noisy label能力,收集大量数据就方便了。另外,semi-supervised方法可以处理unlabelled data,这也是其解决noisy label的途径。 注:可以和另外一篇2020年发表的综述“Learning from Noisy Labels with Deep Neural Networks: A Survey“做对比,其分类是有些不同,如图所示: 如下表做比较: 作者:黄浴链接:https://zhuanlan.zhihu.com/p/345028496来源:知乎

0

深度学习

AI小助手·2021-02-04 14:51 1 阅读 168
没有更多了