本次讨论班分享一篇关于中文拼写纠错(以下简称CSC)的论文,该文章提出了一种新的通用检测器-校正器多任务框架,其中校正器使用BERT来捕获原始句子中每个字符的视觉和语音特征,并使用后期融合策略来融合校正器和检测器的隐藏状态,以最大限度地减少拼写错误对字符的误导影响。在基准测试上的综合实验表明,本文提出的方法在CSC任务中的性能明显优于最新的方法。
中文拼写纠正(CSC)是一项旨在自动检测和纠正中文文本中的拼写错误的基础性工作。这些拼写错误通常是由人类书写、自动语音识别(ASR)或光学字符识别(OCR)系统引起的。CSC是必不可少的,因为它对许多下游任务至关重要,如搜索引擎和论文评分。
近年来,随着BERT预训练模型的出现,许多方法被提出,并在CSC中取得了很大的进展。其中大多数工作使用基于BERT的语言模型和混淆集直接更正输入句子的每个字符。然而,这些方法通过上下文信息难以区分地纠正句子的每个字符,而上下文信息容易被错误拼写的字符误导。如下表1中的大写字母所示,上下文受到错误字符“以”的影响,这使得更正模型错误地将原来的正确字符“关”更改为“所”。为了解决上述问题,其他一些工作提出使用错误检测器来检测错误的位置,这些错误被用作通过masking进行校正的先验知识。然而,这些方法反过来又会削弱拼写错误的字符的视觉或语音特征,这可能是纠正的关键。如下表1中较小的字母所示,尽管模型正确地找到了错误位置,但它未能将错误更改为更正字符“变”,因为它遗漏了拼写错误的字符“遍”的音素特征。因此,如何利用拼写错误的汉字的视觉和语音特征,同时消除它们对语境的误导影响,仍然是CSC任务中的一个悬而未决的问题。

为了解决上述问题,我们提出了一种新的通用多任务检测器-校正器CSC框架(MDCSpell),该框架既可以利用拼写错误字符的视觉和语音特征,又可以消除它们对上下文的误导影响。具体地,纠错和检测任务被同时执行,其中校正器使用BERT直接从原始句子捕捉所有字符的视觉和语音特征,并且检测器使用轻量级transformer来检测拼写错误的字符的位置。采用后期融合策略将校正器的隐藏状态与检测器的隐藏状态进行融合,并通过端到端的联合训练消除拼写错误字符的误导性影响。该框架易于实现,任何基于BERT的CSC模型都可以很容易地在该框架中进行调整。在三个开放基准上的实验结果表明,MDCSpell可以显著优于竞争对手。
中文拼写纠正(CSC)任务可以形式化为以下任务。给定n个汉字\(X=(x_1,x_2,\dots ,x_n)\)的文本序列,目标是输出\(Y=(y_1,y_2,\dots,y_n)\),其中X表示包含一些错误字符的原始文本,Y表示更正后的正确文本。X和Y的长度相同。因此,CSC任务可以看作是一种序列标注任务。通常,一个句子中没有或只有一小部分拼写错误的字符,应该复制所有或大部分字符。
我们的Motivation如图1所示。大多数现有的最先进的CSC方法都将校正视为一项序列标记任务,如图1(a)所示,即使用更正模块来分类对应的token应该转换为哪些字符。这种方法的缺点是,他们对拼写错误的字符的位置缺乏认识,并且仅通过上下文更正每个字符,而上下文很容易被拼写错误的字符误导。
为了解决这个问题,如图1(b)所示的方法,在纠正模块之前增加了检测模块,以mask可能发生错误的位置,并预测被mask位置中的正确字符。虽然该方案在一定程度上减弱了拼写错误的误导影响,但也带来了一个新的问题:由于mask抑制了拼写错误字符的语音和视觉信息,这些信息可能与正确字符高度相似,有助于纠正,因此纠错性能仍然可能是次优的。
因此,上述问题启发我们寻找一种利用错误检测信息的新方案。具体而言,如图1(c)所示,原始句子直接用作更正模块的输入,以保持拼错字符的视觉和语音特征,而更正模块的隐藏状态最近与检测模块的隐藏状态融合。通过端到端的联合训练,将拼写错误字符的误导性影响降至最低。在以下部分中,我们将说明如何基于此方案实现多任务框架。

如图2所示。MDCSpell由基于transformer的检测网络和基于BERT的校正网络组成。这两个网络使用相同的词嵌入作为输入。在校正网络的末端,来自校正和检测网络的隐藏状态被融合到分类密集层中作为输入,以生成校正结果。这两项任务可以端到端的方式同时进行训练。

更具体地说,我们首先为每个字符生成BERT所需的embedding,具体为word embedding、position embedding和segment embedding的总和。然后将输入文本的embedding序列分别输入检测网络和校正网络,得到编码后的向量。检测网络是一种基于多层transformer的结构,它需要适应每个位置的字符是否为拼写错误。因此,检测网络的输出编码向量包含每个位置可能出错的概率信息。纠错网络是一种基于BERT的结构,它需要检测每个位置需要输出哪些字符。接下来,将两个编码向量的信息进行融合,生成最终的编码向量。最后,由词嵌入表的转置初始化参数的致密层将最终的编码向量作为输入并生成预测结果。
检测网络是基于transformer结构的二分类任务,用于确定字符在每个位置的错误概率。对于长度为\(n\)的输入文本,检测网络的输入是字符的embedding序列\(E=(e_1,e_2,\dots,e_n)\),它是word embedding、position embedding和segment embedding的总和。然后使用上下文编码器得到检测编码向量。最后,使用投影层将编码向量投影到二维空间,该二维空间分别表示位置字符的正确概率和错误概率。具体来说,为了更好的捕获上下文语义,我们使用多层transformer进行编码,其中每一层使用相同的块结构。每个transformer块的定义如下
其中,Q、K和V表示当前输入序列,这可能是字符的embedding或前一个transformer块的输出。\(MultiHead\)和\(FFN\)分别代表多头自注意力机制和前馈网络,它们是transformer的基本部件。我们将transformer块最后一层的隐藏状态序列表示为\(H^d=(h^d_1, h^d_2, \dots, h^d_n)\)
隐藏状态\(H^d\)既用于预测拼写错误的字符的位置,也用于将位置信息传递给校正网络。具体地说,我们使用致密层作为输出层,并使用Softmax函数来确定是否发生错误。对于原始输入的每个字符,错误检测的概率定义为
其中,\(P^d(g_i=1|X)\)是表示对应于\(h^d_i\)的字符的拼写错误概率的条件概率,σ表示我们使用的Sigmoid函数,\(h^d_i\)表示基于transformer的检测网络的最后一层,W和b是致密层的参数。
我试图在一个项目中使用rake,如果我把所有东西都放到Rakefile中,它会很大并且很难读取/找到东西,所以我试着将每个命名空间放在lib/rake中它自己的文件中,我添加了这个到我的rake文件的顶部:Dir['#{File.dirname(__FILE__)}/lib/rake/*.rake'].map{|f|requiref}它加载文件没问题,但没有任务。我现在只有一个.rake文件作为测试,名为“servers.rake”,它看起来像这样:namespace:serverdotask:testdoputs"test"endend所以当我运行rakeserver:testid时
如何使用RSpec::Core::RakeTask初始化RSpecRake任务?require'rspec/core/rake_task'RSpec::Core::RakeTask.newdo|t|#whatdoIputinhere?endInitialize函数记录在http://rubydoc.info/github/rspec/rspec-core/RSpec/Core/RakeTask#initialize-instance_method没有很好的记录;它只是说:-(RakeTask)initialize(*args,&task_block)AnewinstanceofRake
几个月前,我读了一篇关于rubygem的博客文章,它可以通过阅读代码本身来确定编程语言。对于我的生活,我不记得博客或gem的名称。谷歌搜索“ruby编程语言猜测”及其变体也无济于事。有人碰巧知道相关gem的名称吗? 最佳答案 是这个吗:http://github.com/chrislo/sourceclassifier/tree/master 关于ruby-寻找通过阅读代码确定编程语言的rubygem?,我们在StackOverflow上找到一个类似的问题:
一、引擎主循环UE版本:4.27一、引擎主循环的位置:Launch.cpp:GuardedMain函数二、、GuardedMain函数执行逻辑:1、EnginePreInit:加载大多数模块int32ErrorLevel=EnginePreInit(CmdLine);PreInit模块加载顺序:模块加载过程:(1)注册模块中定义的UObject,同时为每个类构造一个类默认对象(CDO,记录类的默认状态,作为模板用于子类实例创建)(2)调用模块的StartUpModule方法2、FEngineLoop::Init()1、检查Engine的配置文件找出使用了哪一个GameEngine类(UGame
我写了一个非常简单的rake任务来尝试找到这个问题的根源。namespace:foodotaskbar::environmentdoputs'RUNNING'endend当在控制台中执行rakefoo:bar时,输出为:RUNNINGRUNNING当我执行任何rake任务时会发生这种情况。有没有人遇到过这样的事情?编辑上面的rake任务就是写在那个.rake文件中的所有内容。这是当前正在使用的Rakefile。requireFile.expand_path('../config/application',__FILE__)OurApp::Application.load_tasks这里
我最喜欢的Google文档功能之一是它会在我工作时不断自动保存我的文档版本。这意味着即使我在进行关键更改之前忘记在某个点进行保存,也很有可能会自动创建一个保存点。至少,我可以将文档恢复到错误更改之前的状态,并从该点继续工作。对于在MacOS(或UNIX)上运行的Ruby编码器,是否有具有等效功能的工具?例如,一个工具会每隔几分钟自动将Gitcheckin我的本地存储库以获取我正在处理的文件。也许我有点偏执,但这点小保险可以让我在日常工作中安心。 最佳答案 虚拟机有些人可能讨厌我对此的回应,但我在编码时经常使用VIM,它具有自动保存功
我希望用户从一个模型的三个选项中选择一个。即我有一个模型视频,可以被评为正面/负面/未知目前我有三列bool值(pos/neg/unknown)。这是处理这种情况的最佳方式吗?为此,表单应该是什么样的?目前我有类似的东西但显然它允许多项选择,而我试图将它限制为只有一个..怎么办? 最佳答案 如果要使用字符串列,让我们说rating。然后在你的表单中:#...#...它只允许一个选择编辑完全相同但使用radio_button_tag: 关于ruby-on-rails-Rails单选按钮-模
a=[3,4,7,8,3]b=[5,3,6,8,3]假设数组长度相同,是否有办法使用each或其他一些惯用方法从两个数组的每个元素中获取结果?不使用计数器?例如获取每个元素的乘积:[15,12,42,64,9](0..a.count-1).eachdo|i|太丑了...ruby1.9.3 最佳答案 使用Array.zip怎么样?:>>a=[3,4,7,8,3]=>[3,4,7,8,3]>>b=[5,3,6,8,3]=>[5,3,6,8,3]>>c=[]=>[]>>a.zip(b)do|i,j|c[[3,5],[4,3],[7,6],
我以前没有使用过cron,所以我不能确定我这样做是对的。我想要自动化的任务似乎没有运行。我在终端中执行了这些步骤:sudogeminstall每当切换到应用程序目录无论何时。(这创建了文件schedule.rb)我将此代码添加到schedule.rb:every10.minutesdorunner"User.vote",environment=>"development"endevery:hourdorunner"Digest.rss",:environment=>"development"end我将此代码添加到deploy.rb:after"deploy:symlink","depl
如何在Rake任务中运行Capybara功能?例如:访问('http://google.com')谢谢! 最佳答案 在任务中尝试这样的事情:require'capybara'require'capybara/dsl'Capybara.current_driver=:seleniumBrowser=Class.new{includeCapybara::DSL}page=Browser.new.pagepage.visit("http://www.google.com")puts(page.html)