模型基本测试及运行
(1)构建数据生成器
def data_generator(V, batch, num_batch):
""" 用于随机生成copy任务的数据
:param V: 随机生成数字的最大值+1
:param batch: 每次输送给模型更新一次参数的数据量
:param num_batch: 输送多少次完成一轮
:return:
"""
# 遍历nbatches
for i in range(num_batch):
# 在循环中使用np的random.randint方法随机生成[1, v)的整数
# 每批次10个样本,分布在(batch, 10)形状的矩阵中,然后再把numpy形式转换成torch中的tensor
data = torch.from_numpy(np.random.randint(1, V, size=(batch, 10)))
# 生成起始标志,使数据矩阵中的第一列数字都为1,这一列也就成为了起始标志列
# 当解码器进行第一次解码的时候,会使用起始标志列作为输入
data[:, 0] = 1
# 因为是copy任务,所有source与target是完全相同的,且数据样本作用变量不需要求梯度
# 因此requires_grad设置为False
with torch.no_grad():
target = source = data
# 使用Batch对source和target进行对应批次的掩码张量生成,最后使用yield返回
yield Batch(source, target)
示例
V = 11 # 将生成0-10的整数
batch = 20 # 每次喂给模型20个数据进行参数更新
num_batch = 30 # 连续喂30次完成全部数据的遍历
res = data_generator(V, batch, num_batch)
print(f"res {res}")
res <generator object data_generator at 0x000001BD670E4D60>
(2) 获得Transformer模型及其优化器和损失函数
# 获得Transformer模型机及其优化器和损失函数
from pyitcast.transformer_utils import get_std_opt # 导入优化器工具包,用于获得标准的针对Transformer模型的优化器
from pyitcast.transformer_utils import LabelSmoothing # 导入标签平滑工具包,用于标签平滑(小幅度的改变原有标签值的值域)
from pyitcast.transformer_utils import SimpleLossCompute # 导入损失计算工具包,能够使标签平滑后的结果进行损失计算
# 使用make_mode获得model
model = make_model(V, V, N=2)
# 使用get_std_opt获得模拟优化器
model_optimizer = get_std_opt(model)
# 使用LabelSmoothing获得平滑对象
criterion = LabelSmoothing(size=V, padding_idx=0, smoothing=0.0) # 输入目标词汇的总数
# 使用SimpleLossCompute获得利用标签平滑结果的损失计算方法
loss = SimpleLossCompute(model.generator, criterion, model_optimizer)
from pyitcast.transformer_utils import get_std_opt
:该标准优化器基于Adam优化器,使其对序列到序列的任务更有效from pyitcast.transformer_utils import LabelSmoothing
:因为在理论上人工标注的数据可能并非完全正确,会受一些外界隐私影响而产涩会给你一些微笑的偏差,因此使用标签平滑来弥补这种偏差,减少模型对某一条规律的绝对认知,以防过拟合。from pyitcast.transformer_utils import SimpleLossCompute
:损失的计算方法可以认为使交叉熵损失函数。
(3)运行模型进行训练和评估
# 导入模型单轮训练工具包run_epoch,该工具将对模型使用给定的损失函数计算方法进行单轮参数更新,同时,打印每轮参数更新的损失结果
from pyitcast.transformer_utils import run_epoch
def run(model, loss, epochs=10):
""" 模型训练函数
:param model: 要进行训练的模型
:param loss: 使用的损失计算方法
:param epochs: 模型的训练轮数
:return:
"""
for epoch in range(epochs):
# 使用训练模式,进行反向传播,所有参数将被更新
model.train()
run_epoch(data_generator(V, 8, 20), model, loss) # batch_size = 20
# 使用评估模型,不进行反向传播,所有参数不会被更新
model.eval()
run_epoch(data_generator(V, 8, 5), model, loss) # batch_size = 5
示例
run(model, loss)
(4)使用模型进行贪婪解码
# 贪婪解码
from pyitcast.transformer_utils import greedy_decode # 导入贪婪解码工具包greedy_decode,每次预测都是选择概率最大的结果作为输出
def greedy_run(model, loss, epochs=10):
for epoch in range(epochs):
model.train()
run_epoch(data_generator(V, 8, 20), model, loss)
model.eval()
run_epoch(data_generator(V, 8, 5), model, loss)
# 模型训练结束,进入评估模式
model.eval()
# 初始化一个输入张量
source = torch.LongTensor([[1,3,2,5,4,6,7,8,9,10]])
# 定义源数据掩码张量,因为元素都是1,这里1代表不遮掩,因此相当于对数据源没有遮掩
source_mask = torch.ones(1, 1, 10)
# 起始标志默认为1
result = greedy_decode(model, source, source_mask, max_len=10, start_symbol=1)
print(result)
示例
greedy_run(model, loss)
(5)小结