transformer的学习记录【完整代码+详细注释】(系列七)

第一节:transformer的架构介绍 + 输入部分的实现
链接:https://editor.csdn.net/md/?articleId=124648718


第二节 编码器部分实现(一)
链接:https://editor.csdn.net/md/?articleId=124648718


第三节 编码器部分实现(二)
链接:https://editor.csdn.net/md/?articleId=124724264


第四节 编码器部分实现(三)
链接:https://editor.csdn.net/md/?articleId=124746022


第五节 解码器部分实现
链接:https://editor.csdn.net/md/?articleId=124750632


第六节 输出部分实现+ 完整模型搭建
链接:https://editor.csdn.net/md/?articleId=124757450


第七节 模型的基本运行


1 模型基本测试运行——copy任务

  • 了解 Transformer 模型基本测试的copy任务
  • copy任务的四部曲:
    (1)构建数据生成器
    (2)获得 Transformer 模型 及其优化器和损失函数
    (3)运行模型,进行训练评估 train+val
    (4)使用模型进行 贪婪解码
# 构建数据生成器
def data_generator(V, batch_size, num_batch):
    # 随机生成数据的最大值=1, 假设V=101, 生成的数据是 1-100
    # batch_size : 每次喂给模型的样本数量
    # num_batch ;一共喂模型 多少轮
    for i in range(num_batch):
        # 使用numpy中的random.randint()来随机生产 [1, V)
        # 分布的形状是 (batch, 10)
        data = torch.from_numpy(np.random.randint(1, V, size=(batch_size, 10)))

        # 将数据的一列全部设置为1, 作为起始标志
        data[:, 0] = 1

        # 因为是copy任务,所以源数据和目标数据完全一致
        # 设置参数 requires_grad=False,样本的参数不需要参与梯度的计算
        source = Variable(data, requires_grad=False)
        target = Variable(data, requires_grad=False)

        yield Batch(source, target)

2 介绍优化器和损失函数

  1. 导入优化器工具包 get_std_opt , 是标准针对transformer模型的优化器;
    该优化器基于Adam优化器,对序列的任务更有效

  2. 导入标签平滑工具包 LabelSmoothing 就是小幅度的改变原有便签的值域;
    防止过拟合

  3. 导入损失计算工具包,SimpleLossCompute

2.1 优化器和损失函数的代码

  • 注意:需要 pip install pyitcast 在命令行里面执行这句代码就好了。
from pyitcast.transformer_utils import Batch
from pyitcast.transformer_utils import get_std_opt
from pyitcast.transformer_utils import LabelSmoothing
from pyitcast.transformer_utils import SimpleLossCompute
from pyitcast.transformer_utils import run_epoch
from pyitcast.transformer_utils import greedy_decode

V = 11
batch_size = 20
num_batch = 30

# 首先使用make_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)

2.2 介绍 标签平滑函数

2.2.1 理论知识

  1. 在多分类任务中,神经网络会输出一个当前数据 对应于 哥哥类别的置信度分数,将这些分数通过 softmax进行归一化处理,最终会得到当前数据属于每个类别的概率。
    在这里插入图片描述
    然后计算交叉熵损失函数:
    在这里插入图片描述
    训练神经网络时,Min( 预测概率和标签真实概率之间的交叉熵 ) ,从而得到最优的预测概率分布。
    在这里插入图片描述
    神经网络会促使自身往正确的标签和错误标签差值最大的方向学习,在训练数据较少,不足以表征所有的样本特征的情况下,会导致网络过拟合。

labelsmoothing 是一种正则化策略,通过加入噪声,减少真是样本标签的类别在计算损失函数时的权重,最终起到过拟合的效果。 使得网络有更强的泛化能力!

2.2.2 具体的参数以及代码展示

  1. 一般设置 padding_idx=0 , 这表示不需要将tensor中的数字转化成0,这也是最常用的方法;
  2. smothing=x : 假如原来标签的表示值为1,那么经过平滑之后,它的值域就变成 [1-smothing, 1+smothing]
from pyitcast.transformer_utils import LabelSmoothing
import matplotlib.pyplot as plt
from torch.autograd import Variable
import torch

crit = LabelSmoothing(size=5, padding_idx=0, smoothing=0.5)
predict = Variable(torch.FloatTensor([[0, 0.2, 0.7, 0.1, 0],
                                     [0, 0.2, 0.7, 0.1, 0],
                                     [0, 0.2, 0.7, 0.1, 0]]))

target = Variable(torch.LongTensor([2, 1, 0]))

crit(predict, target)
print(crit.true_dist)
plt.imshow(crit.true_dist)
plt.show()
  • 输出:
tensor([[0.0000, 0.1667, 0.5000, 0.1667, 0.1667],
        [0.0000, 0.5000, 0.1667, 0.1667, 0.1667],
        [0.0000, 0.0000, 0.0000, 0.0000, 0.0000]])

在这里插入图片描述

  • 图像分析:
    重点关注黄色区域,它的横坐标横跨的值域就是标签平滑后的正向平滑值域,[0.5, 2.5]
    他的纵坐标横跨的值域就是标签平滑后的负向平滑值域,[-0.5, 1.5]
    总的值域空间,由原来的[0, 2] 变成了 [-0.5, 2.5], 也就是因为我们的 smooth=0.5

2.3 训练和预测

# 首先使用make_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)


def run(model, loss, epochs=10):
    # model : 代表将要训练的模型
    # loss : 代表使用的损失计算方法
    # epochs : 代表模型训练的轮次数
    for epoch in range(epochs):
        # 先训练,所有的参数都会被更新、
        model.train()
        run_epoch(data_generator(V, 8, 20), model, loss)
        print("在跑哪")
        # 再评估, 参数不会更新
        model.eval()
        # 评估时,batch_size=5
        run_epoch(data_generator(V, 8, 5), model, loss)


# 进行 10 轮训练
epochs = 10
# model和loss都是来自上一步的结果

if __name__ == '__main__':
    run(model, loss)

猜你喜欢

转载自blog.csdn.net/weixin_42521185/article/details/124768029