自然语言处理实战第二版(MEAP)(四)(3)

简介: 自然语言处理实战第二版(MEAP)(四)

自然语言处理实战第二版(MEAP)(四)(2)https://developer.aliyun.com/article/1517993

7.4.3 迁移学习

另一个可以帮助你的 CNN 模型的优化方法是使用预训练的词嵌入,如 GloVe。这并不是作弊,因为这些模型是以无监督的方式训练的,没有使用你的灾难推文数据集的任何标签。你可以将这些 GloVe 向量中所包含的所有学习迁移到您训练模型所使用的与灾难相关的词汇集上,通过使用单词的更一般的含义。你只需要调整嵌入层的大小,以容纳你希望用来初始化 CNN 的 GloVe 嵌入的大小。

代码清单 7.22:为 GloVE 嵌入腾出空间
>>> from torch import nn
>>> embedding = nn.Embedding(
...     num_embeddings=2000,  # #1
...     embedding_dim=50,  # #2
...     padding_idx=0)

就是这样。一旦 PyTorch 知道嵌入的数量和它们的维度,它就可以分配内存来保存嵌入矩阵,其中有 num_embedding 行和 embedding_dim 列。这将同时训练你的嵌入和其余的 CNN 部分。你的领域特定的词汇和嵌入将根据你的语料库进行自定义。但是,从头开始训练你的嵌入没有利用到单词在许多领域中共享的含义。

如果你希望你的管道能"跨域适应",你可以使用在其他领域训练的嵌入。这种词嵌入的"跨训练"被称为迁移学习。通过使用在更广泛的文本语料库上训练的预训练词嵌入,这为你的嵌入层提前了解了单词的含义。为此,你需要过滤掉其他领域中使用的所有单词,以便你的 CNN 管道的词汇仅基于你的数据集中的单词。然后,你可以将这些单词的嵌入加载到你的nn.Embedding层中。

代码清单 7.23:加载嵌入并与你的词汇对齐
>>> from nessvec.files import load_vecs_df
>>> glove = load_vecs_df(HOME_DATA_DIR / 'glove.6B.50d.txt')
>>> zeroes = [0.] * 50
>>> embed = []
>>> for tok in vocab:  # #1
...     if tok in glove.index:
...         embed.append(glove.loc[tok])
...     else:
...         embed.append(zeros.copy())  # #2
>>> embed = np.array(embed)
>>> embed.shape
(4000, 50)

现在你已经将 4000 个标记的词汇表转换为一个 4000×5 的嵌入矩阵。embed数组中的每一行都表示一个具有 50 维向量的词汇表标记的含义。如果在你的词汇表中一个标记的 GloVe 嵌入不存在,那么它将有一个全为零的向量。这本质上使得那个标记对于理解你的文档毫无用处,就像一个 OOV(词汇表外)标记一样。

>>> pd.Series(vocab)
0               a
1              in
2              to
          ...
3831         43rd
3832    beginners
3833        lover
Length: 3834, dtype: object

你已经从推文中取出了最常见的 4000 个标记。在这 4000 个词中,最小的 GloVE 词嵌入词汇表中有 3834 个可用的。因此,你用零向量填充了那 166 个缺失词的未知嵌入。当你在神经网络中训练嵌入层时,你的模型会学习这些词的意义并计算它们的嵌入。

现在你有了一种将标记转换为整数的一致方法,你可以将 GloVe 嵌入矩阵加载到你的 nn.Embedding层中。

代码清单 7.24 初始化使用 GloVE 向量的嵌入层
embed = torch.Tensor(embed)  # #1
print(f'embed.size(): {embed.size()}')
embed = nn.Embedding.from_pretrained(embed, freeze=False)  # #2
print(embed)
检测有意义的模式

你说话的方式、单词的顺序,都很重要。你组合单词以创建对你来说具有重要意义的模式,以便将那个意义传达给其他人。

如果你希望你的机器成为一个有意义的自然语言处理器,它需要能够检测到更多不仅仅是特定标记的存在或不存在。你希望你的机器能够检测到隐藏在单词序列中的有意义的模式。^([23])

卷积是过滤器,它可以从单词中提取有意义的模式。最好的部分是,你不再需要将这些模式硬编码到卷积核中。训练过程将搜索最佳的模式匹配卷积,以解决你遇到的问题。每次将标记数据的错误通过网络向后传递时(反向传播),优化器会调整每个过滤器中的权重,使它们在检测意义和分类文本示例方面变得越来越好。

7.4.4 使用丢弃进行卷积神经网络的健壮性增强

大多数神经网络容易受到对抗样本的影响,这些样本会欺骗它们输出错误的分类或文本。有时,神经网络容易受到同义词替换、拼写错误或俚语插入等简单变化的影响。有时候只需要一点“语词沙拉”——无意义的随机词语——就能分散并困惑 NLP 算法。人类知道如何忽略噪音和过滤干扰,但机器有时会遇到麻烦。

*鲁棒化自然语言处理(NLP)*是研究处理来自不同来源的非常规文本的方法和技术。事实上,鲁棒化 NLP 的研究可能会揭示通向人工通用智能的路径。人类能够从极少的例子中学习新词和概念。而我们的泛化能力很好,既不过多也不过少。机器需要一点帮助。如果你能找出我们人类擅长之处的“秘密酱料”,然后将其编码到 NLP 流程中,那你就能够让机器具备类似的能力。

增强神经网络鲁棒性的一种常见技术是随机丢弃法。由于其简便性和有效性,随机丢弃法或简称丢弃法已经变得非常流行。你的神经网络几乎总会从丢弃层中受益。丢弃层会随机隐藏部分神经元的输出,使其不被其他神经元接收。这会导致你人造脑中的某条路径变得静音,并迫使其他神经元在丢弃期间学习当前的特定示例。

这似乎与直觉相悖,但丢弃法有助于使你的神经网络学习更广泛。如果没有丢弃层,你的网络将专注于帮助提高最大准确度的单词、模式和卷积滤波器。但你需要神经元们扩展他们的模式,以便你的网络能够对自然语言文本上的常见变化保持“健壮性”。

在神经网络中安装丢弃层的最佳位置是靠近末尾,就在运行完全连接的线性层之前。这个向量通过线性层传递的权重是来自 CNN 和池化层的输出。每个值代表一系列单词或意义和语法模式。通过隐藏一些模式,迫使你的预测层扩展其“思考”。虽然你的软件并没有真正考虑什么,但如果将其拟人化一点能够帮助你对为什么随机丢弃等技术可以提高模型准确度产生直觉。

7.5 使用 PyTorch CNN 处理灾难推文

现在进入有趣的部分。你要构造一个真实世界的 CNN,可以区分真实新闻和煽动性报道。你的模型可以帮助你过滤掉与文化战争有关的推文,让你专注于来自真实战区的新闻。

首先,你将看到新的卷积层在管道中的位置。然后你将组装所有组件,来训练一个基于“灾难推文”数据集的 CNN。如果负能量滚动和灾难不是你的菜的话,这个 CNN 也很容易适应任何带标签的推文数据集。你甚至可以选择一个你喜欢的话题作为目标标签,即使推文的作者不知道如何使用标签,你也可以找到与该标签话题相匹配的推文。

7.5.1 网络架构

这里是 CNN NLP 管道的每个阶段的处理步骤和张量的相应形状。构建新 CNN 中最棘手的事情之一是跟踪您张量的形状。您需要确保一个层的输出形状与下一层的输入形状相匹配,对于此示例与以前的示例相同。

  1. 令牌化⇒(N_, )
  2. 填充⇒(N,)
  3. 嵌入⇒(M, N)
  4. 卷积(s)⇒(M, N - K)
  5. 激活⇒(M, N - K)
  6. 池化⇒(M, N - K)
  7. 丢弃(可选)⇒(M, N - K)
  8. 线性组合⇒(L, )
  9. Argmax、softmax 或阈值化⇒(L, )

  • N_是您输入文本中的标记数。
  • N是您填充序列中的标记数。
  • M是您的单词嵌入中的维度数。
  • K是您的核大小。
  • L是您想要预测的类标签或值的数量。

您的 CNN 的 PyTorch 模型比第 5 和第六章中的要多一些超参数。然而,与以前一样,将超参数设置在CNNTextClassifier模型的*init*构造函数中是一个好主意。

列表 7.25 CNN 超参数
class CNNTextClassifier(nn.Module):
    def __init__(self, embeddings):
        super().__init__()
        self.seq_len = 40  # #1
        self.vocab_size = 10000  # #2
        self.embedding_size = 50  # #3
        self.out_channels = 5  # #4
        self.kernel_lengths = [2, 3, 4, 5, 6]  # #5
        self.stride = 1  # #6
        self.dropout = nn.Dropout(0)  # #7
        self.pool_stride = self.stride  # #8
        self.conv_out_seq_len = calc_out_seq_len(  # #9
            seq_len=self.seq_len,
            kernel_lengths=self.kernel_lengths,
            stride=self.stride,
            )

就像本章前面手工制作的卷积一样,每个卷积操作都会减少序列长度。缩短的量取决于内核的大小和步幅。Conv1d层的 PyTorch 文档提供了这个公式和对术语的详细解释。^([25])

def calc_conv_out_seq_len(seq_len, kernel_len,
                          stride=1, dilation=1, padding=0):
    """
    L_out =     (L_in + 2 * padding - dilation * (kernel_size - 1) - 1)
            1 + _______________________________________________________
                                        stride
    """
    return (
        1 + (seq_len +
             2 * padding - dilation * (kernel_len - 1) - 1
            ) //
        stride
        )

您的第一个 CNN 层是一个nn.Embedding层,它将一系列单词 ID 整数转换为一系列嵌入向量。它的行数与词汇表中唯一标记的数量相同(包括新的填充标记)。它的每个嵌入向量的维度都有一列。您可以从 GloVe 或任何其他预训练的嵌入中加载这些嵌入向量。

列表 7.26 初始化 CNN 嵌入
self.embed = nn.Embedding(
    self.vocab_size,  # #1
    self.embedding_size,  # #2
    padding_idx=0)
state = self.embed.state_dict()
state['weight'] = embeddings  # #3
self.embed.load_state_dict(state)

接下来,您想构建卷积和池化层。每个卷积层的输出大小可以用来定义一个池化层,其核占据整个卷积层输出序列。这就是您在 PyTorch 中完成“全局”最大池化的方法,以产生每个卷积滤波器(核)输出的单个最大值。这就是自然语言处理专家如克里斯托弗·曼宁和 Yoon Kim 在他们的研究论文中所做的,这些论文取得了最先进的性能。([26])([27])

列表 7.27 构建卷积和池化层
self.convolvers = []
self.poolers = []
total_out_len = 0
for i, kernel_len in enumerate(self.kernel_lengths):
    self.convolvers.append(
        nn.Conv1d(in_channels=self.embedding_size,
                  out_channels=self.out_channels,
                  kernel_size=kernel_len,
                  stride=self.stride))
    print(f'conv[{i}].weight.shape: {self.convolvers[-1].weight.shape}')
    conv_output_len = calc_conv_out_seq_len(
        seq_len=self.seq_len, kernel_len=kernel_len, stride=self.stride)
    print(f'conv_output_len: {conv_output_len}')
    self.poolers.append(
        nn.MaxPool1d(kernel_size=conv_output_len, stride=self.stride))
    total_out_len += calc_conv_out_seq_len(
        seq_len=conv_output_len, kernel_len=conv_output_len,
        stride=self.stride)
    print(f'total_out_len: {total_out_len}')
    print(f'poolers[{i}]: {self.poolers[-1]}')
print(f'total_out_len: {total_out_len}')
self.linear_layer = nn.Linear(self.out_channels * total_out_len, 1)
print(f'linear_layer: {self.linear_layer}')

与以前的例子不同,你现在要创建多个卷积和池化层。对于这个例子,我们不会像在计算机视觉中经常做的那样将它们一层层叠加。相反,你将连接卷积和池化的输出。这是有效的,因为你通过执行全局最大池化限制了卷积和池化输出的维度,并保持了输出通道的数量远远小于嵌入维度的数量。

你可以使用打印语句来帮助调试 CNN 每一层的矩阵形状不匹配的问题。并且你要确保不会无意间创建太多可训练参数,导致过度拟合超过你的预期:你的池化输出每个包含一个长度为 1 的序列,但它们也包含了在卷积期间组合在一起的 5 个通道的嵌入维度。因此,连接和池化的卷积输出是一个 5x5 张量,产生了一个 25-D 线性层的输出张量,编码了每个文本的含义。

列表 7.28 CNN 层形状
conv[0].weight.shape: torch.Size([5, 50, 2])
conv_output_len: 39
total_pool_out_len: 1
poolers[0]: MaxPool1d(kernel_size=39, stride=1, padding=0, dilation=1,
    ceil_mode=False)
conv[1].weight.shape: torch.Size([5, 50, 3])
conv_output_len: 38
total_pool_out_len: 2
poolers[1]: MaxPool1d(kernel_size=38, stride=1, padding=0, dilation=1,
    ceil_mode=False)
conv[2].weight.shape: torch.Size([5, 50, 4])
conv_output_len: 37
total_pool_out_len: 3
poolers[2]: MaxPool1d(kernel_size=37, stride=1, padding=0, dilation=1,
    ceil_mode=False)
conv[3].weight.shape: torch.Size([5, 50, 5])
conv_output_len: 36
total_pool_out_len: 4
poolers[3]: MaxPool1d(kernel_size=36, stride=1, padding=0, dilation=1,
    ceil_mode=False)
conv[4].weight.shape: torch.Size([5, 50, 6])
conv_output_len: 35
total_pool_out_len: 5
poolers[4]: MaxPool1d(kernel_size=35, stride=1, padding=0, dilation=1,
     ceil_mode=False)
total_out_len: 5
linear_layer: Linear(in_features=25, out_features=1, bias=True)

最终结果是一个迅速过拟合的语言模型和文本分类器。你的模型在第 55 个时期达到了最大的测试准确率 73%,在最后一个时期,第 75 个时期达到了最大的训练集准确率 81%。通过增加卷积层的通道数,你甚至可以实现更多的过拟合。通常,你希望确保你的第一次训练运行能够完成过拟合,以确保所有层都正确配置,并为特定问题或数据集设置一个可实现的准确率的上限。

Epoch:  1, loss: 0.76782, Train accuracy: 0.59028, Test accuracy: 0.64961
Epoch:  2, loss: 0.64052, Train accuracy: 0.65947, Test accuracy: 0.67060
Epoch:  3, loss: 0.51934, Train accuracy: 0.68632, Test accuracy: 0.68766
...
Epoch: 55, loss: 0.04995, Train accuracy: 0.80558, Test accuracy: 0.72966
Epoch: 65, loss: 0.05682, Train accuracy: 0.80835, Test accuracy: 0.72178
Epoch: 75, loss: 0.04491, Train accuracy: 0.81287, Test accuracy: 0.71522

通过将每个嵌入的通道数从 5 减少到 3,你可以将总输出维度从 25 减少到 15。这将限制过度拟合,但会降低收敛速率,除非你增加学习系数:

Epoch:  1, loss: 0.61644, Train accuracy: 0.57773, Test accuracy: 0.58005
Epoch:  2, loss: 0.52941, Train accuracy: 0.63232, Test accuracy: 0.64567
Epoch:  3, loss: 0.45162, Train accuracy: 0.67202, Test accuracy: 0.65486
...
Epoch: 55, loss: 0.21011, Train accuracy: 0.79200, Test accuracy: 0.69816
Epoch: 65, loss: 0.21707, Train accuracy: 0.79434, Test accuracy: 0.69423
Epoch: 75, loss: 0.20077, Train accuracy: 0.79784, Test accuracy: 0.70079

7.5.2 池化

池化将大张量中的数据聚合以将信息压缩为较少的值。在“大数据”领域,这通常被称为“减少”操作,其中 map-reduce 软件模式很常见。卷积和池化非常适合 map-reduce 软件模式,并且可以在 GPU 中自动并行化使用 PyTorch。你甚至可以使用多服务器的 HPC(高性能计算)系统来加速训练。但是 CNN 是如此高效,你可能不太需要这种计算能力。

你习惯计算的所有矩阵数据上的统计量都可以作为 CNN 的池化函数有用:

  • min
  • max
  • std
  • sum
  • mean

最常见和最成功的聚合

7.5.3 线性层

连接编码方法为你提供了关于每条微博的大量信息。编码向量有 1856 个值。你在第六章中使用的最大词向量是 300 维。而对于这个特定的流水线,你真正想要的只是对问题“是否新闻值得报道?”的二进制答案。

你还记得第六章中当你试图让神经网络预测关于特定单词出现或缺失的“是或否”问题时,你是如何做的吗?尽管你并没有真正关注这几千个问题的答案(词汇表中每个词一个问题),但现在你面临的问题是一样的。所以你可以采用相同的方法,一个torch.nn.Linear层将会最优地将来自高维向量的所有信息组合在一起,以回答你提出的任何问题。

因此,你需要添加一个线性层,其中包含与从池化层输出的编码维度数量相同的权重。

清单 7.26 显示了计算线性层大小的代码。

清单 7.29 计算 1D 卷积输出的张量大小
out_pool_total = 0
for kernel_len, stride in zip(kernel_lengths, strides):
    out_conv = (
        (in_seq_len - dilation * (kernel_len - 1) - 1) // stride) + 1
    out_pool = (
        (out_conv - dilation * (kernel_len - 1) - 1) // stride) + 1
    out_pool_total += out_pool

7.5.4 得到拟合

在你训练卷积神经网络之前,你需要告诉它如何根据每一批训练数据来调整权重(参数)。你需要计算两个部分,权重相对于损失函数(梯度)的斜率,以及尝试下降该斜率的距离(学习率)。在前面章节中的单层感知机甚至逻辑回归中,你可以使用一些通用的优化器如“Adam”来实现。你通常可以为卷积神经网络设置一个固定的学习率,并且这些方法对卷积神经网络也适用。然而,如果你想加快训练速度,可以尝试找到一个更聪明的优化器,它可以更好地调整模型的所有参数。Geoffrey Hinton 称这种方法为“rmsprop”,因为他使用了均方根(RMS)公式来计算最近梯度的移动平均值。RMSprop 对每一批数据聚合一个指数衰减的窗口来改善参数梯度(斜率)的估计并加快学习速度。它通常是卷积神经网络在自然语言处理中反向传播的一个不错选择。

7.5.5 超参数调优

探索超参数空间,看看是否可以超过我的性能。Fernando Lopez 和其他人已经使用 1-D 卷积在这个数据集上实现了 80%的验证和测试集准确率。可能还有很大的提升空间。

nlpia2 包含一个命令行脚本,它接受许多你可能想要调整的超参数的参数。试一试,看看是否可以找到超参数空间中更丰富的部分。你可以在清单 7.27 中看到我的最新尝试。

清单 7.30 用于优化超参数的命令行脚本
python train.py --dropout_portion=.35 --epochs=16 --batch_size=8 --win=True
Epoch:  1, loss: 0.44480, Train accuracy: 0.58152, Test accuracy: 0.64829
Epoch:  2, loss: 0.27265, Train accuracy: 0.63640, Test accuracy: 0.69029
...
Epoch: 15, loss: 0.03373, Train accuracy: 0.83871, Test accuracy: 0.79396
Epoch: 16, loss: 0.09545, Train accuracy: 0.84718, Test accuracy: 0.79134

您注意到清单 7.27 中的 win=True 标志了吗?这是我在我的 CNN 流水线中为自己创建的一个彩蛋或秘籍代码。每当我在“彩票假设”游戏中发现一个中奖票时,我就会把它硬编码到我的流水线中。为了使其生效,您必须跟踪您使用的随机种子、精确的数据集和软件。如果您能重现所有这些组件,通常可以重新创建一个特别幸运的“抽签”,以便在后续思考新的架构或参数调整时进行改进。

实际上,这个获胜的随机数序列初始化了模型的权重,以至于测试准确性开始时比训练集准确性更好。训练准确性超过测试集准确性需要 8 个时期。在通过数据集进行 16 次传递(时期)后,模型对训练集的拟合程度比测试集提高了 5%。

如果您想要获得更高的测试集准确性并减少过拟合,您可以尝试添加一些正则化或增加在 Dropout 层中忽略的数据量。对于大多数神经网络来说,30% 到 50% 的丢弃比率通常可以很好地防止过拟合,而不会延迟学习太久。单层 CNN 并不会因为丢弃比率超过 20% 而受益太多。

清单 7.31 CNN 超参数调优
learning  seq  case vocab           training      test
 kernel_sizes    rate  len  sens  size dropout  accuracy  accuracy
          [2]  0.0010   32 False  2000     NaN    0.5790    0.5459
[1 2 3 4 5 6]  0.0010   40 False  2000     NaN    0.7919    0.7100
    [2 3 4 5]  0.0015   40 False  2000     NaN    0.8038    0.7152
[1 2 3 4 5 6]  0.0010   40  True  2000     NaN    0.7685    0.7520
          [2]  0.0010   32  True  2000     0.2    0.8472    0.7533
    [2 3 4 5]  0.0010   32  True  2000     0.2    0.8727    0.7900

您能找到更好的超参数组合来提高此模型的准确性吗?不要期望能够达到比 80% 更好的测试集准确性,因为这是一个困难的问题。即使是人类读者也无法可靠地判断一条推文是否代表了真实的新闻灾难。毕竟,其他人类(和机器人)正在撰写这些推文,试图欺骗读者。这是一个对抗性问题。即使是一个小的单层 CNN 也能做出体面的工作。

图 7.17 我们找到的最佳超参数的学习曲线


超参数调优的关键是要认真记录每一个实验,并对下一个实验中进行的超参数调整做出深思熟虑的决定。您可以使用贝叶斯优化器自动化这个决策过程。但在大多数情况下,如果您使用生物神经网络来完成贝叶斯优化,您可以培养自己的直觉并更快地调整超参数。如果您对转置操作对嵌入层的影响感兴趣,您可以尝试两种方法,看看哪种在您的问题上效果最好。但是如果您想在困难问题上获得最先进的结果,您可能想听取专家的意见。不要相信互联网上的一切,特别是涉及 NLP 的 CNN。

7.6 自我测试

  1. 对于长度为 3 的核和长度为 8 的输入数组,输出的长度是多少?
  2. 在本章中使用的秘密消息音频文件中,用于检测“SOS”求救信号(Save Our Souls,或 Save Our Ship)的内核是什么?
  3. 调整超参数后,你能够为新闻价值微博问题达到的最佳训练集准确率是多少?
  4. 你如何扩展模型以容纳额外的类?在 gitlab 上提供的 nlpia2 包中的 news.csv 文件包含了一些著名的引语,可以让你尝试用你的卷积神经网络进行分类。
  5. 编写 3 个内核,分别用于检测点、短划线和停顿。编写一个 计数 这些符号的唯一出现次数的池化函数。奖励:创建一个将秘密消息音频文件转换成符号 ".""-"" " 的函数系统。
  6. 找到一些超参数(不要忘记随机种子),以在灾难推文数据集的测试集上达到超过 80% 的准确率。
  7. 使用 Hugging Face 上的数据集和示例创建一个基于单词的 CNN 的讽刺检测器(huggingface.co)。有几篇发表的论文声称可以从单个推文中,不需要上下文,检测到 91% 的讽刺准确率。^([30]) ^([31])

摘要

  • 卷积是一个窗口滤波器,它在你的单词序列上滑动以将其含义压缩为编码向量。
  • 手工制作的卷积滤波器对可预测的信号(如摩尔斯电码)效果很好,但是你需要为自然语言处理训练自己的卷积神经网络来学习它们自己的滤波器。
  • 神经网络可以提取出一系列单词中的模式,而其他自然语言处理方法可能会错过。
  • 在训练过程中,如果你通过使用一个 dropout 层稍微阻碍你的模型,你可以防止它在训练数据上过度表现(过拟合)。
  • 神经网络的超参数调整给你比传统的机器学习模型更多的发挥空间。
  • 如果你的卷积神经网络将嵌入维度与卷积通道对齐,你可以在 NLP 竞赛中超过 90% 的博主。
  • 传统的 CNN 可能会让你惊讶地发现它们在解决诸如检测新闻推文之类的难题时的效率。

Digits 技术描述( digits.com/technology

《连线》杂志在一篇 2014 年的文章中提出了数据作为新石油的概念( www.wired.com/insights/2014/07/data-new-oil-digital-economy/

谷歌 AI 博客上的路径语言模型,或称为 PaLM,( ai.googleblog.com/2022/04/pathways-language-model-palm-scaling-to.html)

GPT-J 至少需要 48GB 的 RAM( huggingface.co/docs/transformers/model_doc/gptj

由陈秋睿撰写的《T5 - 详细解释》( archive.today/M2EM6

维基百科上的数字图像处理en.wikipedia.org/wiki/Digital_image_processing#Filtering

[7] 维基百科上的"Sobel filter"(en.wikipedia.org/wiki/Sobel_operator

[8] “高斯滤波器”(en.wikipedia.org/wiki/Gaussian_filter

[9] 2015 年 5 月,《自然》杂志,Hinton、LeCunn 和 Benjio 的"深度学习"(www.nature.com/articles/nature14539

[10] Andrey Kurenkov 撰写的"神经网络和深度学习的简要历史"(www.skynettoday.com/overviews/neural-net-history

[11] SpaCy NER 文档(spacy.io/universe/project/video-spacys-ner-model

[12] LeCun, Y 和 Bengio, Y 撰写的"图像、语音和时间序列的卷积网络"(www.iro.umontreal.ca/~lisa/pointeurs/handbook-convo.pdf

[13] 有时称为"反馈三明治"或"sh-t 三明治"。

[14] Michelle Moerel 等人撰写的"人类听觉皮层区域的解剖和功能地形学"(www.ncbi.nlm.nih.gov/pmc/articles/PMC4114190/

[15] Mastodon 是一个由社区拥有的、无广告的社交网络:joinmastodon.org/

[16] Mastodon 是一个类似于 Twitter 的 FOSS 无广告微博平台,具有用于检索 NLP 数据集的开放标准 API(mastodon.social

[17] GreenPill 是一个鼓励加密货币投资者为公共产品做出贡献的再生经济倡议(greenpill.party)。

[18] GDFL(GNU 自由文档许可证)pt.wikipedia.org pt.wikipedia.org/wiki/Zebra#/media/Ficheiro:Zebra_standing_alone_crop.jpg

[19] 维基百科上的"Morse code"文章(en.wikipedia.org/wiki/Morse_code

[20] 维基共享资源中的秘密信息波形文件(upload.wikimedia.org/wikipedia/commons/7/78/1210secretmorzecode.wav

[21] “Ham” 最初是对于笨拙的摩尔斯电码"打字员"的蔑称(en.wikipedia.org/wiki/Amateur_radio#Ham_radio

[22] Ronan Collobert 和 Jason Weston 撰写的"自然语言处理的统一架构"(thetalkingmachines.com/sites/default/files/2018-12/unified_nlp.pdf

[23] 国际促进者协会手册mng.bz/xjEg

[24] Robin Jia 关于 Robust NLP 的论文(robinjia.github.io/assets/pdf/robinjia_thesis.pdf)以及他与 Kai-Wei Chang、He He 和 Sameer Singh 的演讲(robustnlp-tutorial.github.io

[25]pytorch.org/docs/stable/generated/torch.nn.Conv1d.html

[26] “自然语言处理中的卷积神经网络” 由 Christopher Manning 撰写(mng.bz/1Meq

[27] “《CNNs 用于句子分类的敏感性分析》” 由 Ye Zhang 和 Brian Wallace 撰写(arxiv.org/pdf/1510.03820.pdf

[28] 来自 Hinton 的《梯度下降小批量概览》的幻灯片 14 “加速机器学习的四种方法”(www.cs.toronto.edu/~tijmen/csc321/slides/lecture_slides_lec6.pdf

[29] Tijmen Tieleman 的博士论文《优化生成图像的神经网络》(www.cs.toronto.edu/~tijmen/tijmen_thesis.pdf

[30] Ivan Helin 在 Hugging Face 上声称他们的模型达到了 92%的准确率(huggingface.co/helinivan/english-sarcasm-detector

[31] “通过 CNN 深入研究讽刺推文” 由 Soujanya Poria 等人撰写,声称达到了 91%的准确率(arxiv.org/abs/1610.08815

第八章:减少、重用和回收单词(RNN 和 LSTMs)

本章涵盖的内容

  • 卷积递归展开,以便您可以了解如何将其用于 NLP。
  • 在 PyTorch 中实现基于单词和字符的 RNN。
  • 识别 RNN 是您最好的选择的应用程序。
  • 重新设计您的数据集以进行 RNN 训练。
  • 定制和调整您的 RNN 结构以解决 NLP 问题。
  • 理解时间反向传播(backprop)。
  • 将长期和短期记忆机制相结合,使您的 RNN 变得更加智能。

一个 RNN(递归神经网络)会重复使用词汇。为什么要重复和重用您的单词?当然是为了构建更可持续的 NLP 管道!😉 递归 只是另一个词汇,用于循环利用。RNN 使用递归来记住它已经阅读过的标记,并重复利用这种理解来预测目标变量。如果您使用 RNN 来预测下一个单词,RNN 可以生成一直生成,直到你告诉它停止。 RNN 的这种可持续性或再生能力是它们的超级能力。

原来,您的 NLP 管道可以更好地预测句子中的下一个标记,如果它记得它已经阅读并理解了什么。但是,等一下,之前的 CNN 是用一组权重来“记住”附近的标记的吗?是的!但是 CNN 只能 记住 有限的窗口,即几个单词长。通过在转到下一个标记之前循环利用机器对每个标记的理解,RNN 可以记住关于它阅读过的 所有 标记的内容。这使得您的机器阅读器更具可持续性,它可以不停地读下去……您喜欢多久它就能读多久。

但是等一下,递归不危险吗?如果您在读到递归时第一个想到的是危险,那么您并不孤单。任何学过算法的人都可能使用不正确的递归方式,破坏了函数、整个程序,甚至拖垮了整个网络服务器。正确和安全地使用递归的关键是您必须始终确保您的算法在每次输入回收时减少它必须进行的工作量。这意味着您需要在再次使用该输入之前从输入中删除一些内容。对于您的 NLP RNN,这是自然而然的,因为您会在将输入馈送回网络之前,弹出(删除)堆栈(文本字符串)上的一个标记。

从技术上讲,“循环”和“递归”是两个不同的概念。3(#_footnotedef_1) 但是大多数数学家和计算机科学家使用这两个词来解释相同的概念 - 将部分输出循环回输入,以便重复执行序列中的操作。4(#_footnotedef_2) 但是像所有自然语言词汇一样,这些概念是模糊的,当构建 循环 神经网络时理解它们可能会有所帮助。正如你将在本章的代码中看到的那样,RNN 并没有像你通常认为的那样具有调用自身的递归函数。.forward(x) 方法是在 RNN 本身之外的 for 循环中调用的。

RNN 是 类神经形 的。这是一种花哨的说法,意思是研究人员在设计诸如 RNN 这样的人工神经网络时模仿了他们认为大脑如何工作的方式。你可以利用你对自己大脑运作方式的了解来想出如何使用人工神经元处理文本的方法。你的大脑正在循环处理你正在阅读的标记。所以循环必定是一种聪明、高效的利用大脑资源来理解文本的方式。

当你阅读这段文字时,你会利用你已经了解的先前单词的知识来更新你对接下来会发生什么的预测。并且在你达到句子、段落或者你试图理解的任何东西的结尾之前,你不会停止预测。然后你可以在文本的结尾停顿一下,处理你刚刚阅读过的所有内容。就像本章中的 RNN 一样,你大脑中的 RNN 利用这个结尾的停顿来对文本进行编码、分类和 得到一些 信息。由于 RNN 总是在预测,你可以用它们来预测你的 NLP 流水线应该说的单词。所以 RNN 不仅适用于阅读文本数据,还适用于标记和撰写文本。

RNN 对 NLP 是一个颠覆性的改变。它们引发了深度学习和人工智能的实际应用和进步的爆炸性增长。

8.1 RNN 适用于什么?

你已经学过的先前的深度学习架构对处理短小的文本片段非常有效 - 通常是单个句子。 RNN 承诺打破文本长度的限制,并允许你的自然语言处理流水线摄入无限长的文本序列。它们不仅可以处理无穷尽的文本,还可以 生成 你喜欢的文本。RNN 打开了一系列全新的应用,如生成式对话聊天机器人和将来自文档的许多不同地方的概念结合起来的文本摘要器。

类型 描述 应用
一对多 一个输入张量用于生成一系列输出张量 生成聊天消息、回答问题、描述图像
多对一 被收集成单个输出张量的输入张量序列 根据语言、意图或其他特征对文本进行分类或标记
多对多 一系列输入张量用于生成一系列输出张量 在一系列标记中翻译、标记或匿名化标记,回答问题,参与对话

这就是 RNNs 的超能力,它们处理标记或向量的序列。你不再受限于处理单个、固定长度的向量。因此,你不必截断和填充输入文本,使你的圆形文本形状适合于方形洞。如果愿意,RNN 可以生成永无止境的文本序列。你不必在预先决定的任意最大长度处停止或截断输出。你的代码可以在足够的时候动态决定什么是足够的。

图 8.1 回收标记创建了无尽的选项


你可以使用 RNNs 在许多你已经熟悉的任务上取得最先进的性能,即使你的文本比无穷小 ;) 还要短。

  • 翻译
  • 摘要
  • 分类
  • 问答

RNNs 是实现一些新的 NLP 任务最有效和准确的方法之一,你将在本章中了解到:

  • 生成新的文本,如释义、摘要甚至是问题的答案
  • 对单个标记进行标记
  • 绘制句子的语法框图,就像你在英语课上做的那样
  • 创建预测下一个标记的语言模型

如果你阅读过论文榜上的 RNNs,你会发现 RNNs 是许多应用中最有效的方法。

RNNs 不仅仅是给研究人员和学者使用的。让我们来认真对待。在现实世界中,人们正在使用 RNNs 来:

  • 拼写检查和更正
  • 自然语言或编程语言表达的自动补全
  • 对句子进行语法检查或 FAQ 聊天机器人进行分类
  • 对问题进行分类或生成这些问题的答案
  • 为聊天机器人生成有趣的对话文本
  • 命名实体识别(NER)和提取
  • 对人、婴儿和企业进行分类、预测或生成名称
  • 分类或预测子域名(用于安全漏洞扫描)

你可能可以猜到这些应用的大部分内容,但你可能对最后一个应用(子域名预测)感到好奇。子域名是 URL 中域名的第一部分,比如 www.lesswrong.com 中的 wwwen.wikipedia.org 中的 en。为什么有人要预测或猜测子域名?Dan Meisler 在他的网络安全工具箱中讨论了子域名猜测器发挥的关键作用。一旦你知道一个子域名,黑客或渗透测试人员就可以扫描域名,找出服务器安全的漏洞。

一旦你很快就能熟练地使用 RNNs 生成全新的单词、短语、句子、段落,甚至整页的文字。使用 RNNs 玩耍可以非常有趣,你可能会不经意间创造出开启全新业务机会的应用程序。

  • 建议公司、产品或领域名称 ^([5])
  • 建议婴儿姓名
  • 句子标注和标记
  • 文本字段的自动完成
  • 对句子进行释义和改写
  • 发明俚语词汇和短语

8.1.1 RNNs 可以处理任何序列

除了 NLP 之外,RNNs 对于任何数值数据序列都是有用的,比如时间序列。你只需要将序列中的对象表示为数值向量。对于自然语言词汇,这通常是词嵌入。但你也可以看到一个城市政府如何将每日或每小时的电动滑板车租赁、高速公路交通或天气条件表示为向量。而且通常他们希望一次性在一个向量中预测所有这些。

因为 RNNs 可以为序列中的每个元素输出结果,所以你可以创建一个 RNN,用于预测“明天”——当前已知元素之后的下一个序列元素。然后,你可以使用该预测来预测下一个预测,递归地进行。这意味着一旦你掌握了时序反向传播,你就能够使用 RNNs 来预测诸如:

  • 明天的天气
  • 下一分钟的网站流量量
  • 下一秒的分布式拒绝服务(DDOS)网络请求
  • 汽车驾驶员在接下来的 100 毫秒内将采取的动作
  • 视频剪辑序列中的下一帧图像

一旦你对目标变量有了预测,你就可以衡量错误——模型输出与期望输出之间的差异。这通常发生在你正在处理的事件序列中的最后一个时间步骤。

自然语言处理实战第二版(MEAP)(四)(4)https://developer.aliyun.com/article/1517996

相关文章
|
20天前
|
机器学习/深度学习 人工智能 自然语言处理
自然语言处理实战第二版(MEAP)(六)(1)
自然语言处理实战第二版(MEAP)(六)
25 2
|
3天前
|
机器学习/深度学习 自然语言处理 PyTorch
【从零开始学习深度学习】48.Pytorch_NLP实战案例:如何使用预训练的词向量模型求近义词和类比词
【从零开始学习深度学习】48.Pytorch_NLP实战案例:如何使用预训练的词向量模型求近义词和类比词
|
5天前
|
机器学习/深度学习 人工智能 自然语言处理
Python自然语言处理实战:文本分类与情感分析
本文探讨了自然语言处理中的文本分类和情感分析技术,阐述了基本概念、流程,并通过Python示例展示了Scikit-learn和transformers库的应用。面对多义性理解等挑战,研究者正探索跨域适应、上下文理解和多模态融合等方法。随着深度学习的发展,这些技术将持续推动人机交互的进步。
15 1
|
7天前
|
自然语言处理 监控 数据挖掘
NLP实战:Python中的情感分析
6月更文挑战第6天
14 2
|
20天前
|
自然语言处理 API 数据库
自然语言处理实战第二版(MEAP)(六)(5)
自然语言处理实战第二版(MEAP)(六)
27 3
|
20天前
|
机器学习/深度学习 自然语言处理 机器人
自然语言处理实战第二版(MEAP)(六)(4)
自然语言处理实战第二版(MEAP)(六)
25 2
|
20天前
|
机器学习/深度学习 自然语言处理 机器人
自然语言处理实战第二版(MEAP)(六)(3)
自然语言处理实战第二版(MEAP)(六)
27 1
|
20天前
|
机器学习/深度学习 人工智能 自然语言处理
自然语言处理实战第二版(MEAP)(六)(2)
自然语言处理实战第二版(MEAP)(六)
24 2
|
6天前
|
机器学习/深度学习 人工智能 自然语言处理
探索未来AI技术的前沿——自然语言处理的发展与应用
本文将深入探讨自然语言处理技术在人工智能领域中的重要性和应用前景。通过分析当前自然语言处理技术的发展趋势和实际应用案例,揭示了其在改善用户体验、提升工作效率以及推动产业创新方面的巨大潜力。
|
7天前
|
自然语言处理 前端开发 Java
探索自然语言生成技术的进展与应用
本文将介绍自然语言生成技术在不同领域的进展和应用。从前端到后端,从Java到Python,从C到PHP,从Go到数据库,我们将深入探讨这些技术的发展趋势和应用场景,并展示它们在实际项目中的价值。

热门文章

最新文章