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)
  • 4
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
好的,以下是基于Transformer的图像分类代码注释代码中: ```python import torch import torch.nn as nn import torch.nn.functional as F from torch.autograd import Variable # 定义Transformer Encoder层 class TransformerEncoderLayer(nn.Module): def __init__(self, d_model, nhead, dim_feedforward=2048, dropout=0.1): super(TransformerEncoderLayer, self).__init__() self.self_attn = nn.MultiheadAttention(d_model, nhead, dropout=dropout) self.linear1 = nn.Linear(d_model, dim_feedforward) self.dropout = nn.Dropout(dropout) self.linear2 = nn.Linear(dim_feedforward, d_model) self.norm1 = nn.LayerNorm(d_model) self.norm2 = nn.LayerNorm(d_model) self.dropout1 = nn.Dropout(dropout) self.dropout2 = nn.Dropout(dropout) def forward(self, src, src_mask=None, src_key_padding_mask=None): # Multi-Head Attention src2 = self.self_attn(src, src, src, attn_mask=src_mask, key_padding_mask=src_key_padding_mask)[0] # Layer Normalization src = self.norm1(src + self.dropout1(src2)) # Feed Forward Network src2 = self.linear2(self.dropout(F.relu(self.linear1(src)))) # Dropout src = self.norm2(src + self.dropout2(src2)) return src # 定义Transformer Encoder模块 class TransformerEncoder(nn.Module): def __init__(self, encoder_layer, num_layers, norm=None): super(TransformerEncoder, self).__init__() self.layers = nn.ModuleList([encoder_layer for i in range(num_layers)]) self.num_layers = num_layers self.norm = norm def forward(self, src, mask=None, src_key_padding_mask=None): output = src for layer in self.layers: output = layer(output, src_mask=mask, src_key_padding_mask=src_key_padding_mask) if self.norm is not None: output = self.norm(output) return output # 定义Transformer模型 class TransformerModel(nn.Module): def __init__(self, d_model, nhead, num_layers, num_classes): super(TransformerModel, self).__init__() self.embedding = nn.Linear(224 * 224 * 3, d_model) self.encoder = TransformerEncoder(TransformerEncoderLayer(d_model, nhead), num_layers) self.fc = nn.Linear(d_model, num_classes) def forward(self, x): # 将图像展开成一维向量 x = x.view(x.size(0), -1) # 进行embedding x = self.embedding(x) # Transformer Encoder x = self.encoder(x) # 全连接层 x = self.fc(x[:, 0, :]) return x ``` 这里的代码是一个简单的图像分类模型,使用Transformer Encoder来提取图像特征,并使用全连接层来进行分类。需要注意的是,这里的输入是224x224x3大小的图像,经过线性变换之后变成了一维向量,因此需要将图像展开成一维向量再进行embedding。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值