序列分类是循环神经网络的一种常见且重要的应用。它的目标是为整个输入序列分配一个单一的类别标签。可以设想这样的任务,例如确定电影评论的情感(积极或消极),识别新闻文章的主题,或者对用户查询背后的意图进行分类。序列分类需要将整个输入序列的信息汇总成一个单一的决定。与预测序列中的下一个元素或生成完整输出序列的任务不同,RNN、LSTM和GRU非常适合此目的,因为它们的隐藏状态充当了已处理序列的不断变化的概括。使用循环层进行分类基本思想是使用循环层(SimpleRNN、LSTM或GRU)逐步处理输入序列。当网络处理每个元素时,它会更新其隐藏状态,将当前输入和先前状态的信息纳入其中。当网络处理到序列末尾时,最终的隐藏状态(或者在双向RNN的情况下是多个状态)应该能够理想地捕捉到整个序列内容的有意义表示,这与分类任务相关。然后,这个最终表示通常被送入一个或多个标准的前馈层(常被称为全连接层或密集层)以执行最终的分类。常见架构模式有几种主要方式可以利用循环层的输出来进行分类:使用最终隐藏状态: 这是最常见的方法。RNN处理序列,并且仅将最后时间步的隐藏状态用作后续分类层的输入。这个最终状态被假定为封装了整个序列的必要信息。框架API通常有一个参数(例如Keras中的return_sequences=False),它控制该层是只在最后时间步输出状态,还是输出所有时间步的隐藏状态。对于这种模式,您通常只希望从堆栈中最终循环层的最后一步获取输出。digraph G { rankdir=LR; node [shape=box, style=filled, fontname="sans-serif", margin=0.2]; subgraph cluster_input { label="输入序列"; bgcolor="#e9ecef"; X1 [label="X₁", shape=plaintext]; X2 [label="X₂", shape=plaintext]; XN [label="...", shape=plaintext]; XT [label="Xₜ", shape=plaintext]; } subgraph cluster_rnn { label="循环层 (LSTM/GRU)"; bgcolor="#a5d8ff"; rnn_cell [label="RNN单元\n(处理 X₁, X₂, ..., Xₜ)", shape=box, style=filled, fillcolor="#74c0fc"]; hT [label="hₜ\n(最终隐藏状态)", shape=box, style=filled, fillcolor="#4dabf7"]; rnn_cell -> hT [style=dashed, arrowhead=none, label=" 提取最终状态"]; } subgraph cluster_output { label = "分类层"; bgcolor="#b2f2bb"; dense [label="全连接层", shape=box, style=filled, fillcolor="#8ce99a"]; output [label="输出\n(Softmax/Sigmoid)", shape=box, style=filled, fillcolor="#69db7c"]; dense -> output; } {X1, X2, XN, XT} -> rnn_cell [style=invis]; // 确保正确的布局顺序 rnn_cell -> dense [label=" 使用 hₜ"]; label="使用最终隐藏状态进行序列分类的架构"; fontsize=12; fontname="sans-serif"; }一种常见的架构,其中循环层的最终隐藏状态被传递给全连接层进行分类。使用池化隐藏状态: 除了仅仅依赖最终隐藏状态外,您还可以使用所有时间步的隐藏状态。return_sequences=True参数(或等效参数)将设置在最后一个循环层上。这些状态随后通过池化操作进行聚合,然后传递给分类层。常见的池化策略包括:最大池化: 获取隐藏状态中每个特征在时间维度上的最大值。这可以捕捉到序列中任何位置检测到的最重要的特征。平均池化: 获取隐藏状态中每个特征在时间维度上的平均值。这提供了序列中所有特征的概括。如果分类的重要信息可能出现在序列的任何位置,而不仅仅是末尾,池化有时会有益。然而,使用最终隐藏状态通常更简单且表现良好,特别是对于旨在在长序列中保持相关信息的LSTM和GRU而言。实现注意事项输入准备: 如第8章所述,您的输入序列(例如文本)需要转换为数值格式(整数编码),可能需要通过嵌入层,并进行填充以确保批次中的所有序列具有相同的长度。通常应使用掩码来通知循环层忽略这些填充的步长。循环层的输入形状通常为(batch_size, time_steps, feature_dimension)。输出层: 最终的全连接层需要根据分类任务的性质使用适当的激活函数:二元分类: 使用一个输出单元和sigmoid激活函数。相应的损失函数通常是BinaryCrossentropy。多类别分类(单一标签): 使用 $N$ 个输出单元(其中 $N$ 为类别数量)和softmax激活函数。典型的损失函数是CategoricalCrossentropy。返回序列: 请记住根据您是使用最终隐藏状态(最后一层设为False)还是池化(最后一层设为True),正确配置循环层的return_sequences参数。如果堆叠循环层,中间层必须将return_sequences设置为True,以便将完整的隐藏状态序列传递给下一层。双向RNN: 对于许多分类任务,特别是在自然语言处理中,使用双向LSTM或GRU(第7章)可以提高性能。通过在正向和反向两个方向处理序列,模型可以基于任何给定元素两侧的上下文形成表示。最终的正向隐藏状态和最终的反向隐藏状态通常在传递给分类层之前进行连接(或有时平均/求和)。实际应用示例情感分析: 给定表示产品评论的词语序列,将其分类为“积极”、“消极”或“中性”。RNN逐词读取评论,最终状态概括了所表达的整体情感。主题分类: 给定来自文档的词语序列,将其分类为预定义类别之一,如“科技”、“体育”、“金融”等。RNN处理文档文本以捕捉其主要主题。意图识别: 给定表示用户对语音助手命令的词语序列(例如,“明天天气怎么样?”),分类用户的意图(例如,“获取天气”、“播放音乐”、“设置计时器”)。序列分类是一种强大的技术,其中RNN处理有序数据和保持状态的能力使其能够有效地概括序列信息以进行分类。通过理解如何构建模型架构,特别是如何运用循环层的输出,您可以为广泛的基于序列的问题构建有效的分类器。