首页 > 其他分享 >人工智能--自然语言处理简介

人工智能--自然语言处理简介

时间:2024-11-08 12:19:14浏览次数:4  
标签:word -- day 单词 人工智能 sequences 自然语言 句子 today

上一篇:《人工智能模型训练中的数据之美——探索TFRecord》

序言:自然语言处理(NLP)是人工智能中的一种技术,专注于理解基于人类语言的内容。它包含了编程技术,用于创建可以理解语言、分类内容,甚至生成和创作人类语言的新作品的模型。在接下来的几章中,我们将会探讨这些技术。此外,现在有许多利用 NLP 的服务来创建应用程序,比如聊天机器人(它们属于应用,属于Agent应用开发),但这些内容不在知识的范围之内——我们将专注于 NLP 的基础知识(实现原理),以及如何进行语言建模,使您可以训练神经网络,教导电脑去理解和分类文本。

我们将从本节开始,先了解如何将语言分解成数字,以及这些数字如何用于神经网络,所谓‘分解’其实就给用一个数字代替语言句子中的字词或者词根,因为计算机只能处理数字;人们把语言转换成数字交由电脑处理后,再重新转回语言文字就可以被人类识别并知道电脑做了什么了。

将语言编码为数字

有多种方法可以将语言编码成数字。最常见的是通过字母进行编码,就像字符串在程序中存储时的自然形式一样。不过,在内存中,您存储的不是字母本身,而是它的编码——可能是 ASCII、Unicode 值,或者其他形式。例如,考虑单词“listen”。用 ASCII 编码的话,这个单词可以被表示为数字 76、73、83、84、69 和 78。这种编码方式的好处是,您现在可以用数字来表示这个单词。但如果考虑“silent”这个词,它是“listen”的一个字母异位词。尽管这两个单词的编码数字相同,但顺序不同,这可能会让建立一个理解文本的模型变得有些困难。

一个“反义词异构词”是指一个单词的字母顺序颠倒后形成的另一个单词,且二者具有相反的含义。例如,“united”和“untied”就是一对反义词异构词,另外还有“restful”和“fluster”,“Santa”和“Satan”,“forty-five”和“over fifty”。我之前的职位名称是“Developer Evangelist”,后来改成了“Developer Advocate”——这是个好事,因为“Evangelist”就是“Evil’s Agent”(邪恶代理人)的反义词异构词!

一种更好的替代方法可能是用数字来编码整个单词,而不是逐个字母编码。在这种情况下,“silent”可以用数字x表示,“listen”可以用数字y表示,它们彼此不会重叠。

使用这种技术,考虑一个句子比如“I love my dog.”您可以将它编码为数字 [1, 2, 3, 4]。如果您想要编码“I love my cat.”,可以是 [1, 2, 3, 5]。您已经可以看出这些句子在数值上相似——[1, 2, 3, 4] 看起来很像 [1, 2, 3, 5],因此可以推测它们的含义相似。

这个过程叫做“分词”,接下来您将探索如何在代码中实现它。

分词入门

TensorFlow Keras 包含一个称为“preprocessing”的库,它提供了许多非常实用的工具来为机器学习准备数据。其中之一是“Tokenizer”,它可以将单词转化为令牌。让我们通过一个简单的示例来看它的实际操作:

import tensorflow as tf

from tensorflow import keras

from tensorflow.keras.preprocessing.text import Tokenizer

sentences = [

'Today is a sunny day',

'Today is a rainy day'

]

tokenizer = Tokenizer(num_words=100)

tokenizer.fit_on_texts(sentences)

word_index = tokenizer.word_index

print(word_index)

在这个例子中,我们创建了一个 Tokenizer 对象,并指定了它可以分词的单词数量。这将是从词库中生成的最大令牌数。我们这里的词库非常小,只包含六个独特的单词,所以远小于所指定的一百个。

一旦我们有了一个分词器,调用 fit_on_texts 就会创建出令牌化的单词索引。打印出来会显示词库中的键/值对集合,类似于这样:

{'today': 1, 'is': 2, 'a': 3, 'day': 4, 'sunny': 5, 'rainy': 6}

这个分词器非常灵活。例如,如果我们将语料库扩展,添加另一个包含单词“today”且带有问号的句子,结果会显示它足够智能,可以将“today?”过滤成“today”:

sentences = [

'Today is a sunny day',

'Today is a rainy day',

'Is it sunny today?'

]

输出结果为:{'today': 1, 'is': 2, 'a': 3, 'sunny': 4, 'day': 5, 'rainy': 6, 'it': 7}

这种行为是由分词器的filters参数控制的,默认情况下会移除除撇号外的所有标点符号。因此,例如,“Today is a sunny day”将根据之前的编码变成一个包含 [1, 2, 3, 4, 5] 的序列,而“Is it sunny today?”将变成 [2, 7, 4, 1]。当您已将句子中的单词分词后,下一步就是将句子转换为数字列表,其中数字是单词在词典中的键值对所对应的值。

将句子转换为序列

现在您已经了解了如何将单词分词并转化为数字,接下来的一步是将句子编码为数字序列。分词器有一个名为text_to_sequences的方法,您只需传递句子的列表,它就会返回序列的列表。例如,如果您修改之前的代码如下:

sentences = [

'Today is a sunny day',

'Today is a rainy day',

'Is it sunny today?'

]

tokenizer = Tokenizer(num_words=100)

tokenizer.fit_on_texts(sentences)

word_index = tokenizer.word_index

sequences = tokenizer.texts_to_sequences(sentences)

print(sequences)

您将得到表示这三句话的序列。回想一下词汇索引是这样的:

{'today': 1, 'is': 2, 'a': 3, 'sunny': 4, 'day': 5, 'rainy': 6, 'it': 7}

输出结果将如下所示:

[[1, 2, 3, 4, 5], [1, 2, 3, 6, 5], [2, 7, 4, 1]]

然后,您可以将数字替换成单词,这样句子就会变得有意义了。

现在考虑一下,当您用一组数据训练神经网络时会发生什么。通常的模式是,您有一组用于训练的数据,但您知道它无法涵盖所有的需求,只能尽量覆盖多一些。在 NLP 的情况下,您的训练数据中可能包含成千上万个单词,出现在不同的上下文中,但您不可能在所有的上下文中涵盖所有可能的单词。所以,当您向神经网络展示一些新的、之前未见过的文本,包含未见过的单词时,会发生什么呢?您猜对了——它会感到困惑,因为它完全没有那些单词的上下文,结果它的预测就会出错。

使用“词汇表外”令牌

处理这些情况的一个工具是“词汇表外”(OOV)令牌。它可以帮助您的神经网络理解包含未见过的文本的数据上下文。例如,假设您有以下的小型语料库,希望处理这样的句子:

test_data = [

'Today is a snowy day',

'Will it be rainy tomorrow?'

]

请记住,您并没有将这些输入添加到已有的文本语料库中(可以视作您的训练数据),而是考虑预训练网络如何处理这些文本。如果您使用已有的词汇和分词器来分词这些句子,如下所示:

test_sequences = tokenizer.texts_to_sequences(test_data)

print(word_index)

print(test_sequences)

输出结果如下:

{'today': 1, 'is': 2, 'a': 3, 'sunny': 4, 'day': 5, 'rainy': 6, 'it': 7}

[[1, 2, 3, 5], [7, 6]]

那么新的句子,在将令牌换回单词后,变成了“today is a day”和“it rainy”。

正如您所见,几乎完全失去了上下文和意义。这里可以用“词汇表外”令牌来帮助,您可以在分词器中指定它。只需添加一个名为 oov_token 的参数,您可以将其设置为任意字符串,但确保它不会出现在您的语料库中:

tokenizer = Tokenizer(num_words=100, oov_token="")

tokenizer.fit_on_texts(sentences)

word_index = tokenizer.word_index

sequences = tokenizer.texts_to_sequences(sentences)

test_sequences = tokenizer.texts_to_sequences(test_data)

print(word_index)

print(test_sequences)

您会看到输出有了一些改进:

{'': 1, 'today': 2, 'is': 3, 'a': 4, 'sunny': 5, 'day': 6, 'rainy': 7, 'it': 8}

[[2, 3, 4, 1, 6], [1, 8, 1, 7, 1]]

您的令牌列表中多了一个新的项“”,并且您的测试句子保持了它们的长度。现在反向编码后得到的是“today is a day”和“ it rainy ”。

前者更加接近原始含义,而后者由于大部分单词不在语料库中,仍然缺乏上下文,但这算是朝正确方向迈出了一步。

理解填充(padding)

在训练神经网络时,通常需要所有数据的形状一致。回忆一下之前章节中提到的,训练图像时需要将图像格式化为相同的宽度和高度。在文本处理中也面临相似的问题——一旦您将单词分词并将句子转换为序列后,它们的长度可能会各不相同。为了使它们的大小和形状一致,可以使用填充(padding)。

为了探索填充,让我们在语料库中再添加一个更长的句子:

sentences = [

'Today is a sunny day',

'Today is a rainy day',

'Is it sunny today?',

'I really enjoyed walking in the snow today'

]

当您将它们转换为序列时,您会看到数字列表的长度不同:

[

[2, 3, 4, 5, 6],

[2, 3, 4, 7, 6],

[3, 8, 5, 2],

[9, 10, 11, 12, 13, 14, 15, 2]

]

(当您打印这些序列时,它们会显示在一行上,为了清晰起见,我在这里分成了多行。)

如果您想让这些序列的长度一致,可以使用 pad_sequences API。首先,您需要导入它:

from tensorflow.keras.preprocessing.sequence import pad_sequences

使用这个 API 非常简单。要将您的(未填充的)序列转换为填充后的集合,只需调用 pad_sequences,如下所示:

padded = pad_sequences(sequences)

print(padded)

您会得到一个格式整齐的序列集合。它们会在单独的行上,像这样:

[[ 0 0 0 2 3 4 5 6]

[ 0 0 0 2 3 4 7 6]

[ 0 0 0 0 3 8 5 2]

[ 9 10 11 12 13 14 15 2]]

这些序列被填充了 0,而 0 并不是我们单词列表中的令牌。如果您曾疑惑为什么令牌列表从 1 开始而不是 0,现在您知道原因了!

现在,您得到了一个形状一致的数组,可以用于训练。不过在此之前,让我们进一步探索这个 API,因为它提供了许多可以优化数据的选项。

首先,您可能注意到在较短的句子中,为了使它们与最长的句子形状一致,必要数量的 0 被添加到了开头。这被称为“前填充”,它是默认行为。您可以通过 padding 参数来更改它。例如,如果您希望序列在末尾填充 0,可以使用:

padded = pad_sequences(sequences, padding='post')

其输出如下:

[[ 2 3 4 5 6 0 0 0]

[ 2 3 4 7 6 0 0 0]

[ 3 8 5 2 0 0 0 0]

[ 9 10 11 12 13 14 15 2]]

现在您可以看到单词在填充序列的开头,而 0 位于末尾。

另一个默认行为是,所有句子都被填充到与最长句子相同的长度。这是一个合理的默认设置,因为这样您不会丢失任何数据。权衡之处在于您会得到大量填充。如果不想这样做,比如因为某个句子太长导致填充过多,您可以使用 maxlen 参数来指定所需的最大长度,如下所示:

padded = pad_sequences(sequences, padding='post', maxlen=6)

其输出如下:

[[ 2 3 4 5 6 0]

[ 2 3 4 7 6 0]

[ 3 8 5 2 0 0]

[11 12 13 14 15 2]]

现在您的填充序列长度一致,且填充量不多。不过,您会发现最长句子的一些单词被截断了,它们是从开头截断的。如果您不想丢失开头的单词,而是希望从句子末尾截断,可以通过 truncating 参数来覆盖默认行为,如下所示:

padded = pad_sequences(sequences, padding='post', maxlen=6, truncating='post')

结果显示最长的句子现在从末尾截断,而不是开头:

[[ 2 3 4 5 6 0]

[ 2 3 4 7 6 0]

[ 3 8 5 2 0 0]

[ 9 10 11 12 13 14]]

TensorFlow 支持使用“稀疏”(形状不同的)张量进行训练,这非常适合 NLP 的需求。使用它们比本书的内容稍微进阶一些,但在您完成接下来几章提供的 NLP 入门后,可以进一步查阅文档了解更多。

移除停用词和清理文本

在接下来的章节中,我们会看一些真实的文本数据集,并发现数据中经常有不想要的文本内容。你可能需要过滤掉一些所谓的“停用词”,这些词过于常见,不带任何实际意义,比如“the”,“and”和“but”。你也可能会遇到很多HTML标签,去除它们可以使文本更加干净。此外,其他需要过滤的内容还包括粗话、标点符号或人名。稍后我们会探索一个推文的数据集,其中经常包含用户的ID,我们也会想要去除这些内容。

虽然每个任务会因文本内容的不同而有所差异,但通常有三种主要的方法可以编程地清理文本。第一步是去除HTML标签。幸运的是,有一个名叫BeautifulSoup的库可以让这项任务变得简单。例如,如果你的句子包含HTML标签(比如
),以下代码可以将它们移除:

from bs4 import BeautifulSoup

soup = BeautifulSoup(sentence)

sentence = soup.get_text()

一种常见的去除停用词方法是创建一个停用词列表,然后预处理句子,移除其中的停用词。以下是一个简化的例子:

stopwords = ["a", "about", "above", ... "yours", "yourself", "yourselves"]

一个完整的停用词列表可以在本章的一些在线示例中找到。然后,当你遍历句子时,可以使用如下代码来移除句子中的停用词:

words = sentence.split()

filtered_sentence = ""

for word in words:

if word not in stopwords:

filtered_sentence = filtered_sentence + word + " "

sentences.append(filtered_sentence)

另一件可以考虑的事情是去除标点符号,它可能会干扰停用词的移除。上面展示的代码是寻找被空格包围的词语,因此如果停用词后紧跟一个句号或逗号,它将不会被识别出来。

Python的string库提供的翻译功能可以轻松解决这个问题。它还带有一个常量string.punctuation,其中包含了常见的标点符号列表,因此可以使用如下代码将其从单词中移除:

import string

table = str.maketrans('', '', string.punctuation)

words = sentence.split()

filtered_sentence = ""

for word in words:

word = word.translate(table)

if word not in stopwords:

filtered_sentence = filtered_sentence + word + " "

sentences.append(filtered_sentence)

在这里,每个句子在过滤停用词之前,单词中的标点符号已经被移除。因此,如果将句子拆分后得到“it;”,它会被转换为“it”,然后作为停用词被过滤掉。不过,注意当这样处理时,你可能需要更新停用词列表。通常,这些列表中会包含一些缩略词和缩写形式,比如“you’ll”。翻译器会将“you’ll”转换为“youll”,如果想要将它过滤掉,就需要在停用词列表中添加它。

遵循这三个步骤后,你将获得一组更加干净的文本数据。但当然,每个数据集都有其独特之处,你需要根据具体情况进行调整

本节总结,本节介绍了自然语言处理(NLP)的基础概念,包括文本编码、分词、去停用词和清理文本等技术。首先,探讨了如何将语言转为数字以便于计算机处理,并通过编码方法将单词分解为数值。接着,介绍了分词工具(如Tokenizer)在文本预处理中分配和管理单词索引。还讨论了处理未见过的词汇(OOV)以减少模型误差的策略。在清理文本方面,使用BeautifulSoup库去除HTML标签,并利用停用词列表和标点符号过滤功能对数据集进一步清理。此外,为确保数据一致性,介绍了填充(padding)技术以使数据形状一致,适用于模型训练。这些步骤为文本清理和建模提供了坚实的基础,但在实际应用中应灵活调整以应对不同数据集的需求。

标签:word,--,day,单词,人工智能,sequences,自然语言,句子,today
From: https://www.cnblogs.com/jellyai/p/18534832

相关文章

  • c++多态学习:多态含义与使用
    目录 多态的概念多态的定义多态的实现注意事项 多态的概念多态是面向对象编程中的一个重要概念,它指的是同一个行为具有多个不同表现形式或形态的能力。在C++中,多态主要通过虚函数来实现,允许将子类类型的指针赋值给父类类型的指针,并在运行时根据实际对象类型调用相......
  • 251 麦当劳
    //704麦当劳.cpp:此文件包含"main"函数。程序执行将在此处开始并结束。///*http://oj.daimayuan.top/course/5/problem/251喜欢吃麦当劳的蜗蜗要在学校呆n天,如果第i天蜗蜗吃到了麦当劳,他可以获得ai点快乐值。然而蜗蜗不能吃太多麦当劳,在连续的m天中,他最......
  • Vuex的基本使用
    文章目录一、Vuex概述1.是什么2.使用场景3.优势4.注意二、如何构建vuex多组件共享数据环境1.创建项目2.创建三个组件3.源代码三、vuex的使用-创建仓库1.安装vuex2.新建`store/index.js`专门存放vuex3.创建仓库`store/index.js`4在main......
  • 少儿编程教育的多维度对比:软件类、硬件类与软硬件结合课程的选择
    随着少儿编程教育的不断发展,市场上涌现出多种类型的编程课程,主要分为软件类课程、硬件类课程和软硬件结合类课程。三种课程各有特色,针对不同的编程对象和教学目标。本文将从多个维度深入对比这三类课程的特点、教学目的和学习难点,帮助家长和学生更好地选择适合的编程学习路径......
  • [AI大模型通过以下方式重塑软件开发流程]
     •代码自动生成:AI驱动的代码生成工具可以根据开发者输入的需求或注释自动生成代码,减少了手动编写代码的时间和工作量,提高了编码效率。  •智能调试与测试:AI可以分析代码库、错误日志以及用户反馈,自动识别潜在的缺陷和错误,并给出修复建议。同时,AI还能自动生成测试......
  • SoccerPredictor:AI智能分析在足球预测中的优势
    一、引言在全球体育的璀璨星空中,足球无疑是最耀眼的星辰之一。即便是在全球疫情阴霾笼罩的2020年,欧洲杯依然吸引了52.3亿观众的瞩目,而刚刚过去的2024年欧洲杯,更是刷新赛事观众人数的历史记录。对于广大球迷而言,观看比赛之余,预测赛事走向亦成为了一种独特的乐趣与挑战。然......
  • 3D Gaussian Splatting in Robotics: A Survey(1)
    AbstractDense3Drepresentationsoftheenvironmenthavebeenalong-termgoalintheroboticsfield.WhilepreviousNeRF representationhavebeenprevalentforitsimplicit,coordinate-basedmodel,therecentemergenceof3DGS hasdemonstratedremarkab......
  • 从单层到 MVC,再到 DDD:架构演进的思考与实践
    引言在日常开发中,我们之前工作中经常接手的大多数都是传统MVC架构体系的项目。然而,随着现在分布式和微服务架构的普及,越来越多的项目开始重构、拆分,传统的MVC架构也逐渐向DDD架构演进。为什么需要将传统架构重构为DDD架构?MVC架构相比如今备受关注的DDD架构又有......
  • 力扣21 打卡16 判断矩形的两个角落是否可达
    思路:首先,检查矩形的起点和终点是否在任何一个圆的范围内,如果是则不存在合法路径。接着,判断每个圆是否与矩形的左上角边界或右下角边界相交。对于与左上边界相交的圆,使用深度优先搜索(DFS),查找是否存在一组相连的圆,最终能连接到右下边界。若找到这样的路径,则矩形被封锁,返回Fa......
  • 清晨早安问候祝福语精选,开心每一天,幸福安康
    晨曦照耀,温暖万物,问候送到,快乐永驻。愿你好运相伴,健康幸福。让我的祝福,带给你一天的快乐心情!祝福朋友:平安喜乐、万事胜意、好运连连!快乐,可以延长生命旅程;友谊,可以升华美妙人生;问候足以温暖彼此心灵;祝福,永远是真诚的心声。让我们永远幸福快乐,吉祥如意!早晨阳光照满床,起床快乐......