进口 数据类
进口 数据集
进口 火炬
进口 火炬。恩 作为 恩
进口 全面质量管理
@数据类。数据类
班级 伯特配置:
””“BERT 模型的配置。”””
词汇大小: 整数 = 30522
层数: 整数 = 12
隐藏大小: 整数 = 第768章
头数: 整数 = 12
辍学概率: 漂浮 = 0.1
焊盘编号: 整数 = 0
最大序列长度: 整数 = 第512章
数量类型: 整数 = 2
班级 伯特·布洛克(恩。模块):
””“BERT 中的一个变压器块。”””
定义 __初始化__(自己, 隐藏大小: 整数, 头数: 整数, 辍学概率: 漂浮):
极好的()。__初始化__()
自己。注意力 = 恩。多头注意力(隐藏大小, 头数,
辍学=辍学概率, 批量优先=真的)
自己。attn_norm = 恩。层规范(隐藏大小)
自己。ff_范数 = 恩。层规范(隐藏大小)
自己。辍学 = 恩。辍学(辍学概率)
自己。前馈 = 恩。顺序(
恩。线性(隐藏大小, 4 * 隐藏大小),
恩。刮胡子(),
恩。线性(4 * 隐藏大小, 隐藏大小),
)
定义 向前(自己, x: 火炬。张量, 焊盘掩码: 火炬。张量) -> 火炬。张量:
# 具有填充掩码和后规范的自注意力
attn_输出, _ = 自己。注意力(x, x, x, 键填充掩码=焊盘掩码)
x = 自己。attn_norm(x + attn_输出)
# 使用 GeLU 激活和后范数进行前馈
ff_输出 = 自己。前馈(x)
x = 自己。ff_范数(x + 自己。辍学(ff_输出))
返回 x
班级 伯特·普勒(恩。模块):
””“BERT 的池化层处理 [CLS] 令牌输出。”””
定义 __初始化__(自己, 隐藏大小: 整数):
极好的()。__初始化__()
自己。稠密 = 恩。线性(隐藏大小, 隐藏大小)
自己。激活 = 恩。腥()
定义 向前(自己, x: 火炬。张量) -> 火炬。张量:
x = 自己。稠密(x)
x = 自己。激活(x)
返回 x
班级 伯特模型(恩。模块):
””“BERT 模型的支柱。”””
定义 __初始化__(自己, 配置: 伯特配置):
极好的()。__初始化__()
# 嵌入层
自己。词嵌入 = 恩。嵌入(配置。词汇大小, 配置。隐藏大小,
填充IDX=配置。焊盘编号)
自己。类型嵌入 = 恩。嵌入(配置。数量类型, 配置。隐藏大小)
自己。位置嵌入 = 恩。嵌入(配置。最大序列长度, 配置。隐藏大小)
自己。嵌入规范 = 恩。层规范(配置。隐藏大小)
自己。嵌入_dropout = 恩。辍学(配置。辍学概率)
# 变压器块
自己。块 = 恩。模块列表([
BertBlock(config.hidden_size, config.num_heads, config.dropout_prob)
for _ in range(config.num_layers)
])
# [CLS] 池层
自己。水池 = 伯特·普勒(配置。隐藏大小)
定义 向前(自己, 输入ID: 火炬。张量, 令牌类型 ID: 火炬。张量, 焊盘编号: 整数 = 0
) -> 元组[torch.Tensor, torch.Tensor]:
# 为填充标记创建注意掩码
焊盘掩码 = 输入ID == 软垫_ID
# 将整数标记转换为嵌入向量
批量大小, 序列长度 = 输入ID。形状
位置 ID = 火炬。文章(序列长度, 设备=输入ID。设备)。松开(0)
位置嵌入 = 自己。位置嵌入(位置 ID)
类型嵌入 = 自己。类型嵌入(令牌类型 ID)
令牌嵌入 = 自己。词嵌入(输入ID)
x = 令牌嵌入 + 类型嵌入 + 位置_嵌入
x = 自己。嵌入规范(x)
x = 自己。嵌入_dropout(x)
# 使用转换器块处理序列
为了 堵塞 在 自己。块:
x = 堵塞(x, 焊盘掩码)
# 池化`的隐藏状态[CLS]` 标记
汇集输出 = 自己。水池(x[:, 0, :])
返回 x, 汇集输出
班级 Bert预训练模型(恩。模块):
定义 __初始化__(自己, 配置: 伯特配置):
极好的()。__初始化__()
自己。伯特 = 伯特模型(配置)
自己。传销头 = 恩。顺序(
恩。线性(配置。隐藏大小, 配置。隐藏大小),
恩。刮胡子(),
恩。层规范(配置。隐藏大小),
恩。线性(配置。隐藏大小, 配置。词汇大小),
)
自己。nsp_头 = 恩。线性(配置。隐藏大小, 2)
定义 向前(自己, 输入ID: 火炬。张量, 令牌类型 ID: 火炬。张量, 焊盘编号: 整数 = 0
) -> 元组[torch.Tensor, torch.Tensor]:
# 使用 BERT 模型主干处理序列
x, 汇集输出 = 自己。伯特(输入ID, 令牌类型 ID, 焊盘编号)
# 预测 MLM 任务的屏蔽标记和 NSP 任务的分类
传销日志 = 自己。传销头(x)
nsp_logits = 自己。nsp_头(汇集输出)
返回 传销日志, 纳米粒子_逻辑数
# 训练参数
纪元 = 10
学习率 = 1e–4
批量大小 = 32
# 加载数据集并设置数据加载器
数据集 = 数据集。数据集。来自镶木地板(“Wikittext-2_train_data.Parquet”)
定义 整理_fn(批: 列表[dict]):
””“自定义整理函数来处理数据集中的可变长度序列。”””
# 始终为最大长度:tokens、segment_ids;始终单例:is_random_next
输入ID = 火炬。张量([item[“tokens”] 为了 物品 在 批])
令牌类型 ID = 火炬。张量([item[“segment_ids”] 为了 物品 在 批])。腹肌()
是_随机_下一个 = 火炬。张量([item[“is_random_next”] 为了 物品 在 批])。到(整数)
# 可变长度:masked_positions、masked_labels
屏蔽位置 = [(idx, pos) for idx, item in enumerate(batch) for pos in item[“masked_positions”]]
屏蔽标签 = 火炬。张量([label for item in batch for label in item[“masked_labels”]])
返回 输入ID, 令牌类型 ID, 是_随机_下一个, 屏蔽位置, 屏蔽标签
数据加载器 = 火炬。实用程序。数据。数据加载器(数据集, 批量大小=批量大小, 随机播放=真的,
整理_fn=整理_fn, 工人数=8)
# 训练模型
设备 = 火炬。设备(“库达” 如果 火炬。库达。可用() 别的 “中央处理器”)
模型 = Bert预训练模型(伯特配置())。到(设备)
模型。火车()
优化器 = 火炬。优化。亚当·W(模型。参数(), LR=学习率)
调度程序 = 火炬。优化。lr_调度程序。步LR(优化器, 步长=1, 伽玛=0.1)
损失函数 = 恩。交叉熵损失()
为了 时代 在 范围(纪元):
巴巴 = 全面质量管理。全面质量管理(数据加载器, 描述=f“纪元 {纪元+1}/{纪元}”)
为了 批 在 巴巴:
# 获取批量数据
输入ID, 令牌类型 ID, 是_随机_下一个, 屏蔽位置, 屏蔽标签 = 批
输入ID = 输入ID。到(设备)
令牌类型 ID = 令牌类型 ID。到(设备)
是_随机_下一个 = 是_随机_下一个。到(设备)
屏蔽标签 = 屏蔽标签。到(设备)
# 从模型中提取输出
传销日志, nsp_logits = 模型(输入ID, 令牌类型 ID)
# MLM损失:masked_positions是(B,S)的元组列表,提取
# 形状为 (B, S, V) 的张量 mlm_logits 的对应 logits
批次索引, 代币位置 = 拉链(*屏蔽位置)
传销日志 = 传销日志[batch_indices, token_positions]
传销损失 = 损失函数(传销日志, 屏蔽标签)
# 计算 NSP 任务的损失
nsp_loss = 损失函数(nsp_logits, 是_随机_下一个)
# 完全损失后退
总损失 = 传销损失 + nsp_loss
巴巴。设置后缀(传销=传销损失。物品(), 国家标准计划=nsp_loss。物品(), 全部的=总损失。物品())
优化器。零梯度()
总损失。落后()
优化器。步()
调度程序。步()
巴巴。更新(1)
巴巴。关闭()
# 保存模型
火炬。节省(模型。状态字典(), “bert_pretraining_model.pth”)
火炬。节省(模型。伯特。状态字典(), “bert_model.pth”)

