
"""
    Transformer框架的结构：
        编码器端_输入部分
            词嵌入层
            位置编码

        编码器
            多头自注意力子层：多头自注意力 + 层归一化 + 残差连接
            前馈网络子层：前馈网络 + 层归一化 + 残差连接

        解码器端_输入部分
            词嵌入层
            位置编码

        解码器
            掩码多头自注意力子层：掩码多头自注意力 + 层归一化 + 残差连接
            多头注意力子层（交叉注意力）：多头注意力 + 层归一化 + 残差连接
            前馈网络子层：前馈网络 + 层归一化 + 残差连接

        输出部分
            线性层
            Softmax激活函数

        结果
"""
from demo04_decoder import *
from demo05_output import *

# 创建Transformer框架类
class MyTransformer(nn.Module):
    def __init__(self, en_embde_pos, encoder, de_embde_pos, decoder, output):
        """
        将前面开发的各个部分组织得到完整的Transformer框架
        :param en_embde_pos: 编码器端_输入部分 实例对象
        :param encoder: 编码器 实例对象
        :param de_embde_pos: 解码器端_输入部分 实例对象
        :param decoder: 解码器 实例对象
        :param output: 输出部分 实例对象
        """
        # 1- 初始化父类
        super().__init__()

        # 2- 设置属性值
        self.en_embde_pos = en_embde_pos
        self.encoder = encoder
        self.de_embde_pos = de_embde_pos
        self.decoder = decoder
        self.output = output

    def forward(self,en_input,de_input,mask):
        """
        Transformer前向传播
        :param en_input: 输入到编码器端的词索引数据
        :param de_input: 输入到解码器端的词索引数据
        :param mask: 解码器使用的掩码
        :return:
        """

        # 1- 编码器端_输入部分：词嵌入层、位置编码
        encoder_data = self.en_embde_pos(en_input)

        # 2- 编码器
        encoder_data = self.encoder(encoder_data)

        # 3- 解码器端_输入部分：词嵌入层、位置编码
        decoder_data = self.de_embde_pos(de_input)

        # 4- 解码器
        decoder_data = self.decoder(
            data=decoder_data,
            mask=mask,
            encoder_output=encoder_data
        )

        # 5- 输出部分
        return self.output(decoder_data)

# 调用Transformer框架
def get_mytransformer():
    # 常用变量
    d_model = 512
    dropout = 0.1
    de_vocab_size = 4345

    # ---------------- 编码器部分 ----------------
    # 词嵌入层
    en_ebd = Embedding(vocab_size=1000, d_model=d_model)
    # 位置编码
    en_pos = PositionalEncoding(d_model=d_model, dropout=dropout, max_len=60)
    # 多头自注意力
    en_multi_self_attn = MultiHeadAttention(d_model=d_model, head=8, dropout_p=dropout)
    # 前馈网络
    en_ff = FeedForward(d_model=d_model, output_dim=1024, dropout_p=dropout)
    # 组装得到编码器层
    encoder_layer = EncoderLayer(
        d_model=d_model,
        multi_head_self_attn=en_multi_self_attn,
        feed_forward=en_ff,
        dropout_p=dropout
    )
    # 得到编码器
    encoder = Encoder(encoder_layer=encoder_layer, N=6)

    # ---------------- 解码器部分 ----------------
    # 词嵌入层
    de_ebd = Embedding(vocab_size=de_vocab_size, d_model=d_model)
    # 位置编码
    de_pos = PositionalEncoding(d_model=d_model, dropout=dropout, max_len=60)
    # 掩码多头自注意力
    de_multi_self_attn = MultiHeadAttention(d_model=d_model, head=8, dropout_p=dropout)
    # 多头注意力
    de_multi_attn = MultiHeadAttention(d_model=d_model, head=8, dropout_p=dropout)
    # 前馈网络
    de_ff = FeedForward(d_model=d_model, output_dim=1024, dropout_p=dropout)
    # 组装得到编码器层
    decoder_layer = DecoderLayer(
        d_model=d_model,
        mask_multi_head_self_attn=de_multi_self_attn,
        multi_head_attn=de_multi_attn,
        feed_forward=de_ff,
        dropout_p=dropout
    )
    # 得到编码器
    decoder = Decoder(decoder_layer=decoder_layer, N=6)

    # ---------------- 输出部分 ----------------
    output = Output(d_model=d_model, vocab_size=de_vocab_size)

    # ---------------- 组装得到Transformer框架 ----------------
    my_transformer = MyTransformer(
        en_embde_pos=nn.Sequential(en_ebd, en_pos),  # 表示 词先经过词嵌入层的处理，然后再经过位置编码的处理。注意：位置不能乱
        encoder=encoder,
        de_embde_pos=nn.Sequential(de_ebd, de_pos),
        decoder=decoder,
        output=output
    )
    print(f"框架结构信息：{my_transformer}")
    return my_transformer

# 测试Transformer框架
def use_mytransformer():
    # 1- 获得我们自己的Transformer框架的实例对象
    my_transformer = get_mytransformer()

    # 2- 准备数据：以前面的英译法案例为例讲解
    # 2.1- 输入到编码器端的原始数据：也就是英语句子
    en_input = torch.tensor([
        [1,2,3,4],
        [5,6,7,8]
    ])

    # 2.2- 输入到解码器端的原始数据：也就是法语句子
    de_input = torch.tensor([
        [223,2344,456,356],
        [2456,131,456,67]
    ])

    # 2.3- 解码器的掩码
    mask = torch.triu(torch.ones(size=(8,4,4)),diagonal=0)

    # 3- 调用Transformer框架
    result = my_transformer(
        en_input,de_input,mask
    )

    print(f"最终输出结果的张量形状：{result.shape}")
    print(f"最终输出结果的张量求和结果：{result.sum()}")

if __name__ == '__main__':
    use_mytransformer()































