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

上一篇:《人工智能模型训练中的数据之美——探索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="<OOV>")

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)

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

{'<OOV>': 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]]

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

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

理解填充(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标签(比如<br>),以下代码可以将它们移除:

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)技术以使数据形状一致,适用于模型训练。这些步骤为文本清理和建模提供了坚实的基础,但在实际应用中应灵活调整以应对不同数据集的需求。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/914603.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

第8章 利用CSS制作导航菜单

8.1 水平顶部导航栏 水平莱单导航栏是网站设计中应用范围最广的导航设计&#xff0c;一般放置在页面的顶部。水平 导航适用性强&#xff0c;几乎所有类型的网站都可以使用&#xff0c;设计难度较低。 如果导航过于普通&#xff0c;无法容纳复杂的信息结构&#xff0c;就需要在…

企望制造ERP系统 drawGrid.action SQL注入致RCE漏洞复现

0x01 产品简介 企望制造ERP系统是一款专为制造企业设计的企业资源计划(ERP)软件,旨在优化企业的资源配置,提高运营效率,并增强企业的竞争力。系统集成了财务管理、生产管理、供应链管理、客户关系管理(CRM)、人力资源管理(HRM)等多个核心功能模块,能够全面覆盖企业的…

基于JDBC的书库系统(MySQL)

一、创建数据库中的表 1、需求 有一张表叫javabook【创建表要求使用sql语句进行】 表中列 bookid 整数自增类型 表中列 bprice 小数类型 表中列 bookname 字符串类型 长度不能小于50 工程和包要求&#xff1a; domain dao …

内置RTK北斗高精度定位的4G执法记录仪、国网供电服务器记录仪

内置RTK北斗高精度定位的4G执法记录仪、国网供电服务器记录仪BD311R 发布时间: 2024-10-23 11:28:42 一、 产品图片&#xff1a; 二、 产品特性&#xff1a; 4G性能&#xff1a;支持2K超高清图传&#xff0c;数据传输不掉帧&#xff0c;更稳定。 独立北…

腾讯音乐2024Q3财报:“稳”是核心,再进一步

11月12日&#xff0c;腾讯音乐娱乐集团&#xff08;以下简称“腾讯音乐”&#xff09;发布了截至2024年9月30日止的第三季度未经审计财务报告&#xff0c;各项核心财务指标均符合市场预期。本季度总收入为70.2亿元&#xff0c;同比增长6.8%&#xff1b;调整后净利润为19.4亿元&…

地宫取宝(摘花生+最长上升子序列)C++

1212. 地宫取宝 - AcWing题库 #include <iostream>using namespace std;const int N 55; const int MOD 1000000007;int w[N][N],f[N][N][13][14]; int n,m,k;int main() {cin >> n >> m >> k;for (int i 1;i < n;i) {for (int j 1;j < m;j)…

2024 年 8 个最佳 API 设计工具图文介绍

8 个最佳 API 设计工具推荐&#xff0c;包括 Apifox、Postman、Swagger、Insomnia、Stoplight、Hoppscotch、RapidAPI和Paw。 详细介绍&#xff1a;2024 年 8 个最佳 API 设计工具推荐

minio 分布式

方案设计 需要5台服务器&#xff0c;一台nginx用作分发请求&#xff0c;4台minio服务器&#xff0c;每个minio服务器上至少2个盘。在这个方法中&#xff0c;我使用了lvm的缓存&#xff0c;在同种固态盘的情况下&#xff0c;可以使读性能提高数倍到十倍&#xff0c;使写性能提高…

kettle开发-Day43-数据对比

前言&#xff1a; 随着数字化的深入&#xff0c;各种系统及烟囱的建立&#xff0c;各系统之间的架构和数据存储方式不同&#xff0c;导致做数据仓库或数据湖时发现&#xff0c;因自建的系统或者非标准化的系统经常存在物理删除而不是软删除。这就延伸出一个问题&#xff0c;经常…

vscode中执行git合并操作需要输入合并commit信息,打开的nano小型文本编辑器说明-

1.前提&#xff1a; VScode中的git组件执行任何合并动作的时候需要提交远程合并的commit信息&#xff0c;然后编辑器自动打开的是nano文本编辑器 2.nano编辑器说明&#xff1a; 1.保存文件&#xff1a;按 Ctrl O&#xff0c;然后按 Enter 来保存文件。 2.退出编辑器&#xf…

Android音视频直播低延迟探究之:WLAN低延迟模式

Android WLAN低延迟模式 Android WLAN低延迟模式是 Android 10 引入的一种功能&#xff0c;允许对延迟敏感的应用将 Wi-Fi 配置为低延迟模式&#xff0c;以减少网络延迟&#xff0c;启动条件如下&#xff1a; Wi-Fi 已启用且设备可以访问互联网。应用已创建并获得 Wi-Fi 锁&a…

如何详细查询全球药品研发的进度信息?

药品的研发进展对于医药研发人员来说&#xff0c;不仅是知识和技能的积累&#xff0c;更是职业精神和价值观的塑造。通过了解药品的研发进展&#xff0c;研发人员可以更好地提高自己的专业知识和技能&#xff0c;激发创新思维&#xff0c;保持专业竞争力&#xff0c;提高研发效…

摄像机视频分析软件下载LiteAIServer视频智能分析软件抖动检测的技术实现

在现代社会中&#xff0c;视频监控系统扮演着至关重要的角色&#xff0c;其可靠性和有效性在很大程度上取决于视频质量。然而&#xff0c;由于多种因素&#xff0c;如摄像机安装不当、外部环境振动或视频信号传输的不稳定&#xff0c;视频画面常常出现抖动问题&#xff0c;这不…

Jmeter中的监听器(一)

监听器 1--查看结果树 用途 调试测试计划&#xff1a;查看每个请求的详细信息&#xff0c;帮助调试和修正测试计划。分析响应数据&#xff1a;查看服务器返回的响应数据&#xff0c;验证请求是否成功。检查错误&#xff1a;识别和分析请求失败的原因。 配置步骤 添加查看结果…

PaaS云原生:分布式集群中如何构建自动化压测工具

场景 测试环境中&#xff0c;压测常常依赖环境中的各种工具获取基础信息&#xff0c;而这些工具可能集中在某个中控机上&#xff0c;此时想打造的自动化工具的运行模式是&#xff1a; 通过中控机工具获取压测所需的基本信息在中控机部署压测工具&#xff0c;实际压测任务分发…

数据结构-递归函数的调用栈过程

这道题考察的是递归函数的调用栈过程。 逐步分析程序的执行过程&#xff1a; main() 函数首先被调用&#xff0c;此时栈底是 main() 的信息。main() 函数调用 S(1)&#xff0c;此时 S(1) 的信息被压入栈中&#xff0c;位于 main() 之上。S(1) 函数内部调用 S(0)&#xff0c;因…

华为OD机试 - 芯片资源限制(Python/JS/C/C++ 2024 C卷 100分)

华为OD机试 2024E卷题库疯狂收录中&#xff0c;刷题点这里 专栏导读 本专栏收录于《华为OD机试真题&#xff08;Python/JS/C/C&#xff09;》。 刷的越多&#xff0c;抽中的概率越大&#xff0c;私信哪吒&#xff0c;备注华为OD&#xff0c;加入华为OD刷题交流群&#xff0c;…

基于 Python 的 Django 框架开发的电影推荐系统

项目简介&#xff1a;本项目是基于 Python 的 Django 框架开发的电影推荐系统&#xff0c;主要功能包括&#xff1a; 电影信息爬取&#xff1a;获取并更新电影数据。数据展示&#xff1a;提供电影数据的列表展示。推荐系统&#xff1a;基于协同过滤算法实现个性化推荐。用户系…

使用 Web Search 插件扩展 GitHub Copilot 问答

GitHub Copilot 是一个由 GitHub 和 OpenAI 合作开发的人工智能代码提示工具。它可以根据上下文提示代码&#xff0c;还可以回答各种技术相关的问题。但是 Copilot 本身不能回答非技术类型的问题。为了扩展 Copilot 的功能&#xff0c;微软发布了一个名为 Web Search 的插件&am…

Sorting 排序

Goto Data Grid 数据网格 Sorting 排序 Sort Data 对数据进行排序 默认情况下&#xff0c;最终用户可以按任何列对数据进行排序&#xff0c;但具有 MemoExEdit、ImageEdit 和 PictureEdit 就地编辑器的列除外。在运行时&#xff0c;单击列标题一次可对数据进行升序排序。后续…