代码演示bert的12层和一层 代码上区别
在代码实现上,BERT 的层数差异主要体现在Transformer 编码器堆叠的数量和参数规模上。以下通过 PyTorch 代码对比单层 BERT 和 12 层 BERT 的核心差异(为简化说明,省略部分非关键细节):
一、核心结构对比
1. 单层 BERT(仅 1 个 Transformer 编码器)
python
运行
import torch
import torch.nn as nn
import torch.nn.functional as F
class SingleLayerBERT(nn.Module):
def __init__(self, vocab_size, d_model=768, nhead=12, dim_feedforward=3072):
super().__init__()
# 词嵌入和位置嵌入
self.token_embedding = nn.Embedding(vocab_size, d_model)
self.position_embedding = nn.Embedding(512, d_model)
self.layer_norm = nn.LayerNorm(d_model)
self.dropout = nn.Dropout(0.1)
# 单层Transformer编码器
encoder_layer = nn.TransformerEncoderLayer(
d_model=d_model,
nhead=nhead,
dim_feedforward=dim_feedforward,
dropout=0.1,
activation="gelu"
)
self.encoder = nn.TransformerEncoder(encoder_layer, num_layers=1) # 仅1层
# MLM预测头
self.mlm_head = nn.Sequential(
nn.Linear(d_model, d_model),
nn.GELU(),
nn.LayerNorm(d_model),
nn.Linear(d_model, vocab_size)
)
# NSP预测头
self.nsp_head = nn.Linear(d_model, 2)
def forward(self, input_ids, attention_mask=None):
# 构建输入表示
seq_length = input_ids.size(1)
position_ids = torch.arange(seq_length, device=input_ids.device).unsqueeze(0)
# 嵌入层
x = self.token_embedding(input_ids) + self.position_embedding(position_ids)
x = self.layer_norm(x)
x = self.dropout(x)
# 注意力掩码转换(Transformer期望的形状)
if attention_mask is not None:
attention_mask = attention_mask.unsqueeze(1).unsqueeze(2)
attention_mask = attention_mask.to(dtype=torch.float32)
attention_mask = (1.0 - attention_mask) * -10000.0
# 通过编码器(仅1层)
encoder_output = self.encoder(x.transpose(0, 1), src_key_padding_mask=None).transpose(0, 1)
# MLM预测
mlm_output = self.mlm_head(encoder_output)
# NSP预测(取[CLS] token)
cls_output = encoder_output[:, 0, :]
nsp_output = self.nsp_head(cls_output)
return mlm_output, nsp_output

2. 12 层 BERT(标准配置)
python
运行
class TwelveLayerBERT(nn.Module):
def __init__(self, vocab_size, d_model=768, nhead=12, dim_feedforward=3072):
super().__init__()
# 词嵌入和位置嵌入(与单层相同)
self.token_embedding = nn.Embedding(vocab_size, d_model)
self.position_embedding = nn.Embedding(512, d_model)
self.layer_norm = nn.LayerNorm(d_model)
self.dropout = nn.Dropout(0.1)
# 12层Transformer编码器
encoder_layer = nn.TransformerEncoderLayer(
d_model=d_model,
nhead=nhead,
dim_feedforward=dim_feedforward,
dropout=0.1,
activation="gelu"
)
self.encoder = nn.TransformerEncoder(encoder_layer, num_layers=12) # 12层
# 预测头(与单层相同)
self.mlm_head = nn.Sequential(
nn.Linear(d_model, d_model),
nn.GELU(),
nn.LayerNorm(d_model),
nn.Linear(d_model, vocab_size)
)
self.nsp_head = nn.Linear(d_model, 2)
def forward(self, input_ids, attention_mask=None):
# 构建输入表示(与单层相同)
seq_length = input_ids.size(1)
position_ids = torch.arange(seq_length, device=input_ids.device).unsqueeze(0)
x = self.token_embedding(input_ids) + self.position_embedding(position_ids)
x = self.layer_norm(x)
x = self.dropout(x)
# 注意力掩码转换
if attention_mask is not None:
attention_mask = attention_mask.unsqueeze(1).unsqueeze(2)
attention_mask = attention_mask.to(dtype=torch.float32)
attention_mask = (1.0 - attention_mask) * -10000.0
# 通过编码器(12层)
encoder_output = self.encoder(x.transpose(0, 1), src_key_padding_mask=None).transpose(0, 1)
# 预测头(与单层相同)
mlm_output = self.mlm_head(encoder_output)
cls_output = encoder_output[:, 0, :]
nsp_output = self.nsp_head(cls_output)
return mlm_output, nsp_output
二、核心差异点分析
| 对比项 | 单层 BERT | 12 层 BERT |
|---|---|---|
| 编码器层数 | num_layers=1 |
num_layers=12 |
| 参数量 | 约 11M(主要来自嵌入层) | 约 110M(12 层编码器的堆叠) |
| 计算复杂度 | 低(单遍 Transformer 计算) | 高(12 遍 Transformer 计算) |
| 特征提取能力 | 浅层次特征(如局部语法) | 深层次特征(如全局语义关系) |
| 训练难度 | 易收敛,数据需求少 | 需大规模数据和更长训练时间 |
| 下游任务表现 | 简单任务(如短文本分类) | 复杂任务(如问答、长文本理解) |
三、实际应用中的选择
1. 单层 BERT 的适用场景
- 资源受限的设备(如移动终端)。
- 简单任务或小规模数据集(如关键词提取)。
- 快速原型验证。
2. 12 层 BERT 的适用场景
- 标准 NLP 任务(如 GLUE 基准测试)。
- 需要深层语义理解的场景(如语义相似度计算)。
- 有足够计算资源和训练数据。
四、性能对比示例
python
运行
# 对比参数量
single_layer_bert = SingleLayerBERT(vocab_size=30522)
twelve_layer_bert = TwelveLayerBERT(vocab_size=30522)
def count_parameters(model):
return sum(p.numel() for p in model.parameters() if p.requires_grad)
print(f"单层BERT参数量: {count_parameters(single_layer_bert):,}") # 约11M
print(f"12层BERT参数量: {count_parameters(twelve_layer_bert):,}") # 约110M
# 对比前向传播速度(伪代码)
import time
input_ids = torch.randint(0, 30522, (1, 128))
attention_mask = torch.ones(1, 128)
# 单层BERT推理时间
start_time = time.time()
single_layer_bert(input_ids, attention_mask)
print(f"单层BERT推理时间: {time.time() - start_time:.4f}秒")
# 12层BERT推理时间
start_time = time.time()
twelve_layer_bert(input_ids, attention_mask)
print(f"12层BERT推理时间: {time.time() - start_time:.4f}秒") # 通常慢10倍以上
五、层数对模型能力的影响
- 单层 BERT:只能捕获局部特征,类似于 LSTM 的能力,难以处理长距离依赖。
- 多层 BERT:通过堆叠,每层可以捕获不同抽象级别的信息(如底层捕获语法,高层捕获语义),符合人类语言理解的层级结构。
实际应用中,若算力有限但任务简单,可选择单层 BERT 并增加训练数据;若任务复杂,建议使用预训练的多层 BERT 并微调。

浙公网安备 33010602011771号