生活中的类比:写小说的过程
假设你是一位小说作家(解码器),正在写一篇小说。你参考了前一章节的内容(前一时刻的隐藏状态 prev_hidden)以及整本书的摘要(编码器的输出 encoder_outputs)来决定当前要写的内容(当前时刻的输入 input)。
初始化与输入
- input (query):解码器当前时刻的输入,形状为 (1, 1)。
○ 类比:你当前要写的单词的索引。比如,你决定要写的单词编号是3。 - prev_hidden (key):解码器前一时刻的隐藏状态,形状为 (1, 256)。
○ 类比:你前一章节的写作状态,包括前一章的情节、风格等。这是256维的信息,比如你之前写的风格、主要情节线索等等。 - encoder_outputs (value):编码器的输出,形状为 (1, 10, 256)。
○ 类比:整本书的摘要,每个章节有 256 个特征。这意味着你对每个章节都有256维的总结,整本书有10个章节,所以有10组256维的信息。
嵌入与 Dropout
- 嵌入 (embedding):将 input 转换为嵌入表示,假设嵌入层输出的维度为256。
○ 输入形状:(1, 1)
○ 输出形状:(1, 1, 256)
○ 类比:将你要写的单词编号转换为一个256维的词向量。这就像你把单词3转化为一段256维的描述,比如“英雄”,“战争”,“勇敢”等特征。 - Dropout (dropout):对嵌入层的输出应用 dropout,保持形状不变。
○ 输入形状:(1, 1, 256)
○ 输出形状:(1, 1, 256)
○ 类比:在写作过程中,你随机忽略一些特征,以防止过拟合(保持多样性)。就像你在写作时有意忽略一些细节,以便让故事保持灵活和多样。
注意力机制
- 拼接 Query 和 Key:将 embedded 和 prev_hidden 在最后一个维度上拼接。
○ embedded 形状:(1, 1, 256)
○ prev_hidden 形状:(1, 256)
○ 拼接后形状:(1, 1, 512)
○ 类比:将当前写作的词向量和前一章节的状态拼接在一起,作为写作决策的基础。就像你把当前要写的单词的特征和前一章的总结信息结合在一起,形成一个更完整的信息块。 - 注意力层 (attn):通过一个线性层处理拼接后的输入以计算注意力得分。
○ 输入形状:(1, 1, 512)
○ 输出形状:(1, 1, 10)(这里 10 表示 encoder 输出序列的长度)
○ 类比:通过一种评分机制(线性层)来决定整本书的摘要中哪些章节对当前写作最重要。这就像你通过一套规则(线性层),给每个章节打分,决定哪些章节对当前的写作最有帮助。 - Softmax (attn_softmax):对这些得分应用 softmax 函数,获得注意力权重。
○ 输入形状:(1, 1, 10)
○ 输出形状:(1, 1, 10)
○ 类比:将评分转换为概率,表示当前写作时参考各个章节的比例。就像你给每个章节分配一个比例,表示你在写当前内容时会参考这些章节的程度。
应用注意力权重
- 批量矩阵乘法 (bmm):使用注意力权重对 encoder_outputs 进行加权求和。
○ 注意力权重形状:(1, 1, 10)
○ encoder_outputs 形状:(1, 10, 256)
○ 结果形状:(1, 1, 256)
○ 类比:根据注意力权重,从整本书的摘要中提取相关信息,形成一个新的256维上下文向量。这就像你根据每个章节的重要性,从中提取出有用的信息,组合成一个新的总结。
结合上下文和查询
- 拼接上下文和查询:将 attn_applied 和 embedded 在最后一个维度上拼接。
○ attn_applied 形状:(1, 1, 256)
○ embedded 形状:(1, 1, 256)
○ 拼接后形状:(1, 1, 512)
○ 类比:将提取的上下文信息和当前词向量拼接在一起,作为写作的输入。就像你把从各章节提取的摘要信息和当前单词的描述结合在一起。 - 注意力结合层 (attn_combine):通过线性层处理拼接后的输入。
○ 输入形状:(1, 1, 512)
○ 输出形状:(1, 1, 256)
○ 类比:通过一个新的转换(线性层)将拼接后的输入压缩成256维,准备进行进一步处理。就像你通过一套规则,把这些信息进行压缩和总结,形成新的写作状态。 - ReLU 激活:应用 ReLU 激活函数。
○ 输入形状:(1, 1, 256)
○ 输出形状:(1, 1, 256)
○ 类比:通过激活函数引入非线性,增强表达能力。就像你对信息进行加工,使其更有表现力。
循环神经网络 (GRU)
- GRU 层:将上述处理后的张量传入 GRU 层。
○ 输入形状:(1, 1, 256)
○ 输出 output 形状:(1, 1, 256)
○ 新的隐藏状态 hidden 形状:(1, 1, 256)
○ 类比:在写作的过程中,将当前状态和前一状态结合,生成新的写作状态。就像你在写作时,根据当前的信息和前一章节的信息,生成新的写作灵感和状态。
线性层和 Softmax
- 线性层 (linear):将 GRU 的输出传入线性层。
○ 输入形状:(1, 1, 256)
○ 输出形状:(1, 4345)(假设输出词典大小为 4345)
○ 类比:将当前的写作状态转换为词汇表中每个词的概率分布。就像你根据当前的写作状态,决定下一个要写的单词。 - Softmax:对线性层的输出应用 softmax 函数。
○ 输入形状:(1, 4345)
○ 输出形状:(1, 4345)
○ 类比:将转换后的结果通过 softmax 函数得到词汇表中每个词的概率分布。就像你给每个可能的单词分配一个概率,表示你会选择它们的可能性。
最终输出
- 输出 output:表示解码器在当前时刻的输出。
○ 形状:(1, 4345)
○ 类比:表示在当前时刻,你写作时选择每个词的概率。你现在知道了每个单词出现在当前写作中的可能性。 - 新的隐藏状态 hidden:用于下一时刻的解码器输入。
○ 形状:(1, 1, 256)
计算示例
线性变换示例
- 注意力层 (attn):通过一个线性层处理拼接后的输入