import torch
import numpy as np

# 使用PyTorch实现掩码。【掌握】
"""
    总结：
        1- 上三角掩码：右上角的值为1，左下角的值为0
        2- 下三角掩码：右上角的值为0，左下角的值为1
        3- 相同的规律：对角线的时候diagonal为0；如果是正数，并且越来越大，那么往右上角移动；反之往左下角移动；diagonal的取值超过范围不会报错
        4- 【掌握】掩码的作用：为了防止解码器端当前时间步偷看后面时间步的数据，你只能看到你前面时间步已经预测出来的数据。核心是防止模型训练效果不好
        5- 【掌握】代码：torch.triu(t,diagonal=0)
"""
def torch_mask():
    # 创建初始张量
    t = torch.ones(size=(5,5))
    print(f"原始张量：{t}")

    # 进行掩码操作
    # 上三角掩码
    u_0_mask = torch.triu(t,diagonal=0)
    print(f"上三角掩码0：{u_0_mask}")

    u_1_mask = torch.triu(t, diagonal=1)
    print(f"上三角掩码1：{u_1_mask}")

    u__1_mask = torch.triu(t, diagonal=-1)
    print(f"上三角掩码_1：{u__1_mask}")

    u_n_mask = torch.triu(t, diagonal=1000)
    print(f"上三角掩码n：{u_n_mask}")

    print("-"*30)

    # 下三角掩码
    l_0_mask = torch.tril(t, diagonal=0)
    print(f"下三角掩码0：{l_0_mask}")

    l_1_mask = torch.tril(t, diagonal=1)
    print(f"下三角掩码1：{l_1_mask}")

    l__1_mask = torch.tril(t, diagonal=-1)
    print(f"下三角掩码-1：{l__1_mask}")

def np_mask():
    # 1- 准备数据
    arr = np.ones(shape=(5,5))

    # 2- 上三角掩码
    # k和PyTorch中diagonal参数的作用完全一样
    u_result = np.triu(arr,k=0)
    print(f"上三角掩码0：\n{u_result}")

    u_result = np.triu(arr, k=1)
    print(f"上三角掩码1：\n{u_result}")

    u_result = np.triu(arr, k=-1)
    print(f"上三角掩码-1：\n{u_result}")

    # 3- 下三角掩码
    l_result = 1 - u_result
    print(f"下三角掩码：\n{l_result}")

    l_result = np.tril(arr,k=0)
    print(f"下三角掩码0：\n{l_result}")

    l_result = np.tril(arr, k=1)
    print(f"下三角掩码1：\n{l_result}")

    l_result = np.tril(arr, k=-1)
    print(f"下三角掩码-1：\n{l_result}")

def assert_demo(d_model,head):
    print("assert之前")
    assert d_model % head == 0
    print("assert之后")

def mask():
    mask = torch.ones(size=(1,2,4,5))
    scores = torch.ones(size=(2,2,4,5))
    scores = scores.masked_fill(mask == 0, value=-1e9)
    print(scores)

def k_multi_data():
    """
        return self.k * (data - mean)/(std+self.eps) + self.b
        演示 为什么 self.k * data 能够相乘？-> 广播机制
        k的形状是[512]，data形状[2,4,512]
    """

    k = torch.randint(low=1,high=5,size=(3,))
    data = torch.randint(low=1,high=5,size=(2,4,3))

    print(k)
    print(data)
    print(k*data)

if __name__ == '__main__':
    # torch版的掩码
    # torch_mask()

    # np_mask()

    # assert_demo(512,8)
    # assert_demo(512,7)

    # mask()

    k_multi_data()