子层结构搭建 - 代码测试
1 课程概览
本课测试子层连接结构。步骤:准备输入数据(词嵌入+位置编码)→ 实例化子层连接结构 → 定义子层函数(用多头注意力作为示例,采用函数嵌套/闭包写法)→ 通过子层连接处理输入。子层函数是一个可调用对象,接收 x 返回处理结果。结果形状仍为 (2, 4, 512)。
2 核心概念与定义
- 子层函数:可调用对象,接收 x 返回处理结果。
- 函数嵌套(闭包):定义子层函数的写法。
- 子层对象:可以是多头注意力或前馈全连接。
3 模型与算法详解
测试流程
1. 准备输入数据(词嵌入+位置编码)
2. 实例化子层连接结构
3. 定义子层函数(用多头注意力作为示例)
4. 通过子层连接处理输入
子层函数定义
采用函数嵌套(闭包)写法,实现定义子层函数。
def sublayer(x):
# 创建多头注意力对象
multi_attention = MultiHeadAttention(512, 8)
# 计算注意力(自注意力机制 Q=K=V=x)
return multi_attention(x, x, x)
形状变化
| 步骤 | 形状 | 说明 |
|---|---|---|
| 输入数据 | (2, 4, 512) | 词嵌入+位置编码 |
| 子层处理 | (2, 4, 512) | 多头注意力 |
| 残差连接 | (2, 4, 512) | x + sublayer(x) |
| 规范化 | (2, 4, 512) | 形状不变 |
子层连接的处理过程
x → sublayer(x) → x + dropout(sublayer(x)) → norm(...) → 输出
4 数学原理与推导
残差连接 + 规范化
$$\text{output} = \text{LayerNorm}(x + \text{dropout}(\text{sublayer}(x)))$$
子层函数
$$\text{sublayer}(x) = \text{MultiHeadAttention}(x, x, x)$$
5 代码示例
import torch
from dm01_input import Embeddings, PositionalEncoding
from dm04_attention import MultiHeadAttention
from dm07_sublayer import SubLayerConnection
def use_sublayer():
"""测试子层连接结构"""
# 1. 准备输入数据(词嵌入+位置编码)
x = use_position() # (2, 4, 512)
# 2. 实例化子层连接结构
sublayer_connection = SubLayerConnection(512)
# 3. 定义子层函数(用多头注意力作为示例)
# 采用函数嵌套(闭包)写法
def sublayer(x):
# 3.1 创建多头注意力对象
multi_attention = MultiHeadAttention(512, 8)
# 3.2 计算注意力(自注意力机制 Q=K=V=x)
return multi_attention(x, x, x)
# 4. 通过子层连接处理输入
result = sublayer_connection(x, sublayer)
print(f"输入形状: {x.shape}")
print(f"输出形状: {result.shape}")
return result
def use_position():
"""获取位置编码结果"""
VOCAB_SIZE = 1000
D_MODEL = 512
my_embedding = Embeddings(D_MODEL, VOCAB_SIZE)
x = torch.LongTensor([[1, 2, 3, 4], [5, 6, 7, 8]])
embedded_x = my_embedding(x)
my_position = PositionalEncoding(D_MODEL, dropout=0.1, max_len=60)
position_x = my_position(embedded_x)
return position_x
# 测试
if __name__ == "__main__":
result = use_sublayer()
print(f"最终结果形状: {result.shape}")
代码说明
| 代码 | 说明 |
|---|---|
use_position() | 准备输入数据 |
SubLayerConnection(512) | 实例化子层连接结构 |
def sublayer(x): | 定义子层函数(闭包) |
MultiHeadAttention(512, 8) | 创建多头注意力对象 |
multi_attention(x, x, x) | 计算注意力(Q=K=V=x) |
sublayer_connection(x, sublayer) | 通过子层连接处理 |
6 重难点与易错提醒
- ❗重点:子层函数采用函数嵌套(闭包)写法。
- ❗重点:子层函数是可调用对象,接收 x 返回处理结果。
- ⚠️易错:子层函数可以是多头注意力或前馈全连接。
- 💡深入理解:自注意力机制 Q=K=V=x。
7 课堂问答精选
Q1:如何测试子层连接结构?
A:步骤:①准备输入数据(词嵌入+位置编码);②实例化子层连接结构;③定义子层函数(用多头注意力作为示例);④通过子层连接处理输入。
Q2:子层函数如何定义?
A:采用函数嵌套(闭包)写法。子层函数是一个可调用对象,接收 x 返回处理结果。例如:
def sublayer(x):
multi_attention = MultiHeadAttention(512, 8)
return multi_attention(x, x, x)
Q3:子层函数可以用什么组件?
A:可以用多头注意力或前馈全连接。如果传入多头注意力,就是多头注意力子层;如果传入前馈全连接,就是前馈全连接子层。
Q4:子层连接的处理过程是什么?
A:x → sublayer(x) → x + dropout(sublayer(x)) → norm(...) → 输出。即残差连接加规范化。
8 本课小结
- 测试步骤:准备数据 → 实例化子层连接 → 定义子层函数 → 处理输入。
- 子层函数采用闭包写法。
- 子层函数是可调用对象,接收 x 返回处理结果。
- 可以用多头注意力或前馈全连接。
- 结果形状仍为 (2, 4, 512)。
9 延伸思考
- 编码器层如何搭建?
- 编码器层如何包含两个子层?