自然语言处理如何检查拼写错误?(Tensorflow实例教程&源代码)-阿里云开发者社区

开发者社区> 行者武松> 正文

自然语言处理如何检查拼写错误?(Tensorflow实例教程&源代码)

简介:
+关注继续查看

机器学习的一个最重要的问题就是,我们需要干净的数据。自然语言处理项目存在着一个问题——使用人类书写的文本。而不幸的是,我们并不擅长写作。想象一下,如果在Reddit上的有关帖子和评论的数据集中存在着许多拼写错误,这对于机器来说,是不是有些不好处理呢?


因此,制作一个拼写检查器将会是一个非常有价值的项目,这将有助于缓解这些问题。


我们即将用于此项目的模型与我在文章“亚马逊评论中的文本汇总”https://medium.com/towards-data-science/text-summarization-with-amazon-reviews-41801c2210b(都是seq2seq模型)中写的是很相似的,但是我添加了一些额外的代码行,以便可以使用grid search来调整整个架构和超参数,并且可以使用TensorBoard来分析结果。如果你想要更详细地演示如何在你的代码中添加TensorBoard,请查看“使用TensorFlow和TensorBoard预测Movie Review Sentiment”https://medium.com/@Currie32/predicting-movie-review-sentiment-with-tensorflow-and-tensorboard-53bf16af0acf


本文的着重点将在于如何为模型准备数据,同时我还将讨论该模型的一些其他功能。我们将在此项目中使用Python 3和TensorFlow 1.1。数据是由古腾堡项目中的二十本流行书籍组成。如果你有兴趣扩大这个项目以使其更准确,那么你可以在古腾堡项目上下载数百本图书。此外,如果看到人们使用这种模式制作出的拼写检查器是多么的好用,那将是非常有趣的。


如果你想要查看完整的代码,可以在GitHub页面查看:https://github.com/Currie32/Spell-Checker


为了让你预览这个模型所具有的能力,这里有一些策划的例子可以当做参考:


Spellin is difficult, whch is wyh you need to study everyday.

Spelling is difficult, which is why you need to study everyday.

The first days of her existence in th country were vrey hard for Dolly.

The first days of her existence in the country were very hard for Dolly.

Thi is really something impressiv thaat we should look into right away!

This is really something impressive that we should look into right away!


为了使事情更有条理,我把我们将使用的所有书籍放在他们自己的文件夹中,名称定为“books”。这是我们将用来加载所有书籍的函数:


def load_book(path):
   input_file = os.path.join(path)
   with open(input_file) as f:
       book = f.read()
   return book


同时,我们还需要为每本书定下一个唯一的文件名:


path = './books/'
book_files = [f for f in listdir(path) if isfile(join(path, f))]
book_files = book_files[1:]


当我们将这两个代码块放在一起时,我们将能够将所有书籍中的文本加载到列表中。


books = []
for book in book_files:
   books.append(load_book(path+book))

  

如果你有兴趣了解每本书中有多少单词,你可以使用以下代码行:


for i in range(len(books)):
   print("There are {} words in {}.".format(len(books[i].split()), book_files[i]))


注意:如果你的代码中不包括.split(),那么它将返回的是每本书中的字符数。

 

清理这些书的文本是相当简单的。由于我们将使用的是字符,而不是单词作为我们模型的输入,所以我们不需要担心去除停用词,或者将单词缩短到只留下主干。我们只需要删除我们不想要的字符和多余的空格。


def clean_text(text):
   '''Remove unwanted characters and extra spaces from the text'''
   text = re.sub(r'\n', ' ', text)
   text = re.sub(r'[{}
@_*>()\\#%+=\[\]]','', text)
   text = re.sub('a0','', text)
   text = re.sub('\'92t','\'t', text)
   text = re.sub('\'92s','\'s', text)
   text = re.sub('\'92m','\'m', text)
   text = re.sub('\'92ll','\'ll', text)
   text = re.sub('\'91','', text)
   text = re.sub('\'92','', text)
   text = re.sub('\'93','', text)
   text = re.sub('\'94','', text)
   text = re.sub('\.','. ', text)
   text = re.sub('\!','! ', text)
   text = re.sub('\?','? ', text)
   text = re.sub(' +',' ', text) # Removes extra spaces
   return text


我将跳过如何来制作vocab_to_int和int_to_vocab字典,因为这是非常标准的东西,你可以在这个项目的GitHub页面(https://github.com/Currie32/Spell-Checker)上找到它。但是,我认为值得向你展示输入数据中包含的字符:


The vocabulary contains 78 characters.
[' ', '!', '"', '$', '&', "'", ',', '-', '.', '/', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<EOS>', '<GO>', '<PAD>', '?', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']


我们可以删除更多的特殊字符,或者使文本全部小写,但是我想让这个拼写检查器尽可能有用。


数据在被输入到模型之前被组织成句子。我们将在每个时间段后跟一个空格(“.”)来拆分数据。一个问题是,一些句子是以问号或感叹号结尾的,但我们说话的时候不是这样的。幸运的是,我们的模型仍然能够理解使用问号和感叹号,只要与以下句子相结合,不超过最大句子长度。


举个例子来说明这个问题:


Today is a lovely day. I want to go to the beach. (这将被拆分为两个输入句子)

Is today a lovely day? I want to go to the beach. (这将是一个长的输入句子)


sentences = []
for book in clean_books:
   for sentence in book.split('. '):
       sentences.append(sentence + '.')


我在floydhub.com(https://www.floydhub.com/)上使用GPU来训练我的模型(我强烈推荐他们的服务),这节省了我几个小时的训练时间。尽管如此,为了正确调整这个模型,运行迭代仍然需要30-60分钟的时间,这就是为什么我要限制数据,从而不需要花费更长的时间来做这件事情。这当然会降低我们的模型的准确性,但由于这只是一个个人项目,所以,我不是很在乎。


max_length = 92
min_length = 10


good_sentences = []


for sentence in int_sentences:
   if len(sentence) <= max_length and len(sentence) >= min_length:
       good_sentences.append(sentence)


为了跟踪这个模型的性能,我将把数据拆分成一个训练集和一个测试集。测试集将由数据15%的组成。


training, testing = train_test_split(good_sentences,
                                    test_size = 0.15,
                                    random_state = 2)


就像我最近的一些项目一样,我将按照长度来给数据进行排序。这导致一批量的句子具有相似的长度,因此只需要使用较少的填充,并且模型训练的速度将更快。


training_sorted = []
testing_sorted = []


for i in range(min_length, max_length+1):
   for sentence in training:
       if len(sentence) == i:
           training_sorted.append(sentence)
   for sentence in testing:
       if len(sentence) == i:
           testing_sorted.append(sentence)


也许这个项目最有趣/最重要的部分就是将句子转换为含有错误的句子的函数,这些函数将被用作输入数据。在这个函数中创建的错误的方式将以下面三种之一的一种进行:


两个字符的顺序将被交换(hlelo〜hello)

将添加一个额外的字母(heljlo〜hello)

其中一个字符没有被打印出来(helo〜hello)


这三个错误发生的可能性是相等的,任一个错误发生的可能性为5%。因此,平均而言,每20个字符中就会有一个包含一个错误。


letters = ['a','b','c','d','e','f','g','h','i','j','k','l','m',
          'n','o','p','q','r','s','t','u','v','w','x','y','z',]


def noise_maker(sentence, threshold):
   
   noisy_sentence = []
   i = 0
   while i < len(sentence):
       random = np.random.uniform(0,1,1)
       if random < threshold:
           noisy_sentence.append(sentence[i])
       else:
           new_random = np.random.uniform(0,1,1)
           if new_random > 0.67:
               if i == (len(sentence) - 1):
                   continue
               else:
                   noisy_sentence.append(sentence[i+1])
                   noisy_sentence.append(sentence[i])
                   i += 1
           elif new_random < 0.33:
               random_letter = np.random.choice(letters, 1)[0]
               noisy_sentence.append(vocab_to_int[random_letter])
               noisy_sentence.append(sentence[i])
           else:
               pass    
       i += 1
   return noisy_sentence


在本文中,我想向你展示的最后一件事是如何创建批次。通常,在训练他们的模型之前,会先创建他们的输入数据,这意味着他们具有固定数量的训练数据。然而,当我们训练我们的模型时,通过将noise_maker应用于每个批次,我们将要创建新的输入数据。这意味着对于每个时期,目标(正确的)句子将通过noise_maker进行反馈,并应该接收一个新的输入句子。使用这种方法的话,我们略微夸张地说,将会有无数量的训练数据。


def get_batches(sentences, batch_size, threshold):
   
   for batch_i in range(0, len(sentences)//batch_size):
       start_i = batch_i * batch_size
       sentences_batch = sentences[start_i:start_i + batch_size]
       
       sentences_batch_noisy = []
       for sentence in sentences_batch:
           sentences_batch_noisy.append(
               noise_maker(sentence, threshold))
           
       sentences_batch_eos = []
       for sentence in sentences_batch:
           sentence.append(vocab_to_int['<EOS>'])
           sentences_batch_eos.append(sentence)
           
       pad_sentences_batch = np.array(
           pad_sentence_batch(sentences_batch_eos))
       pad_sentences_noisy_batch = np.array(
           pad_sentence_batch(sentences_batch_noisy))
       
       pad_sentences_lengths = []
       for sentence in pad_sentences_batch:
           pad_sentences_lengths.append(len(sentence))
       
       pad_sentences_noisy_lengths = []
       for sentence in pad_sentences_noisy_batch:
           pad_sentences_noisy_lengths.append(len(sentence))
       
       yield (pad_sentences_noisy_batch,
              pad_sentences_batch,
              pad_sentences_noisy_lengths,
              pad_sentences_lengths)


这就是整个这个项目!虽然结果是令人鼓舞的,但这种模式仍然存在着一定的局限性。我真的会很感激,如果有人可以扩大这个模型或改进其设计!如果你可以这样做,请在评论中发表一下。新设计的想法将会应用到Facebook AI实验室最新的CNN模型


原文发布时间为:2017-05-26 

本文作者:Dave Currie

本文来自云栖社区合作伙伴“数据派THU”,了解相关信息可以关注“数据派THU”微信公众号

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
阿里云Redis实例慢查剖析
Redis常见超时原因分析
2483 0
哈工大自然语言处理ltp在windows10下的源代码安装时builtin_converters.cpp报错
安装LTP的环境要求比较复杂,首先cmake,VS2010等等。今天要说的时编译过程中出现的一个坑,python setup.py install,编译到后面会报错。直接上错误代码: patch\libs\python\src\converter\builtin_converters.
3241 0
[推荐]ORACLE PL/SQL编程之五:异常错误处理(知已知彼、百战不殆)
原文:[推荐]ORACLE PL/SQL编程之五:异常错误处理(知已知彼、百战不殆) [推荐]ORACLE PL/SQL编程之五: 异常错误处理(知已知彼、百战不殆)       继上三篇:ORACLE PL/SQL编程之八:把触发器说透               ORACLE PL/SQL编程之六:把过程与函数说透(穷追猛打,把根儿都拔起!)               [推荐]ORACLE PL/SQL编程之四:把游标说透(不怕做不到,只怕想不到)  得到了大家的强力支持与建议,万分感谢。
758 0
【软件测试】3、代码检查与Code Review
对于一家技术研发流程完善的技术公司来说,代码审查都是必不可少的一部分。虽然大部分代码审查工作都是研发团队的工程师完成,广义上讲,代码审查也是软件测试的一部分。
819 0
检查HTTP 的 Basic认证代码示例-JSP
检查HTTP 的 Basic认证. since http1.0 代码如下所示: R U OK? R U OK? . Your Password is 请参考代码中的注释,具体信息,还可以参考《图解HTTP》。
725 0
+关注
行者武松
杀人者,打虎武松也。
17142
文章
2569
问答
来源圈子
更多
+ 订阅
文章排行榜
最热
最新
相关电子书
更多
《2021云上架构与运维峰会演讲合集》
立即下载
《零基础CSS入门教程》
立即下载
《零基础HTML入门教程》
立即下载