昨天看了沐神的动手学深度学习,看了这一节,今天凭记忆把小程序给梳理一遍。书籍分享在专栏置顶了。
书中的例子是,生成了一个关于函数
的50个训练数据和测试数据,训练数据在以上函数的基础上增加了正态分布的随机噪声项。然后,使用简单的示例“注意力机制”对原函数曲线进行预测。
首先,生成训练数据
import torch
x = torch.arange(0, 5, 0.1)
x
f = torch.sin(x)
add_errors = torch.normal(mean=0, std=0.1, size=[50])
add_errors
y = torch.sin(x)
y
y = y + add_errors
y
其中,训练样本加入了均值为0,标准差为0.1的正态分布噪声项。
下面通过核函数引入“注意力机制”。
导入绘图包和softmax函数所在包
import matplotlib.pyplot as plt
import torch.nn.functional as F
生成新的横坐标x
new_x = torch.arange(0, 5, 0.1)
new_x
将new_x进行扩维得到new_x1
new_x1 = new_x.expand(50, 50)
new_x1
new_x1结构如下
tensor([[0.0000, 0.1000, 0.2000, ..., 4.7000, 4.8000, 4.9000], [0.0000, 0.1000, 0.2000, ..., 4.7000, 4.8000, 4.9000], [0.0000, 0.1000, 0.2000, ..., 4.7000, 4.8000, 4.9000], ..., [0.0000, 0.1000, 0.2000, ..., 4.7000, 4.8000, 4.9000], [0.0000, 0.1000, 0.2000, ..., 4.7000, 4.8000, 4.9000], [0.0000, 0.1000, 0.2000, ..., 4.7000, 4.8000, 4.9000]])
再修改结构得到new_x2
new_x2 = new_x.reshape(50, 1)
new_x2
new_x2 = new_x2.expand(50, 50)
new_x2
new_x2结构如下
tensor([[0.0000, 0.0000, 0.0000, ..., 0.0000, 0.0000, 0.0000], [0.1000, 0.1000, 0.1000, ..., 0.1000, 0.1000, 0.1000], [0.2000, 0.2000, 0.2000, ..., 0.2000, 0.2000, 0.2000], ..., [4.7000, 4.7000, 4.7000, ..., 4.7000, 4.7000, 4.7000], [4.8000, 4.8000, 4.8000, ..., 4.8000, 4.8000, 4.8000], [4.9000, 4.9000, 4.9000, ..., 4.9000, 4.9000, 4.9000]])
上面两步得到的new_x1和new_x2主要是为了方便使用张量计算软最大,也就是下一步
new_x = -torch.abs(new_x1 - new_x2)**2
new_x
k = F.softmax(new_x, dim=0)
k
得到张量k的结构如下
tensor([[1.0681e-01, 9.5636e-02, 8.4927e-02, ..., 2.2535e-11, 9.5240e-12, 3.9922e-12], [1.0575e-01, 9.6597e-02, 8.7514e-02, ..., 5.7115e-11, 2.4626e-11, 1.0531e-11], [1.0262e-01, 9.5636e-02, 8.8393e-02, ..., 1.4189e-10, 6.2415e-11, 2.7230e-11], ..., [2.7230e-11, 6.2415e-11, 1.4189e-10, ..., 8.8393e-02, 9.5636e-02, 1.0262e-01], [1.0531e-11, 2.4626e-11, 5.7114e-11, ..., 8.7513e-02, 9.6597e-02, 1.0575e-01], [3.9922e-12, 9.5240e-12, 2.2535e-11, ..., 8.4927e-02, 9.5636e-02, 1.0681e-01]])
可以对k的0维求和看
k.sum(0)
结果如下
tensor([1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000])
可以看到softmax计算维度元素相加为1,是对的。
修改之前生成的训练样本值y的维度
y = y.unsqueeze(0)
y.size()
使用注意力机制进行预测(这里就是简单的矩阵相乘)
pred = torch.mm(y, k)
结果如下
tensor([[ 0.4356, 0.4640, 0.4938, 0.5246, 0.5562, 0.5883, 0.6206, 0.6526, 0.6837, 0.7133, 0.7406, 0.7650, 0.7856, 0.8018, 0.8127, 0.8179, 0.8166, 0.8086, 0.7934, 0.7711, 0.7416, 0.7051, 0.6619, 0.6123, 0.5569, 0.4962, 0.4309, 0.3616, 0.2891, 0.2140, 0.1370, 0.0590, -0.0193, -0.0972, -0.1740, -0.2490, -0.3215, -0.3909, -0.4568, -0.5187, -0.5764, -0.6297, -0.6784, -0.7227, -0.7627, -0.7985, -0.8304, -0.8586, -0.8836, -0.9054]])
对预测pred缩维,便于之后可视化
pred.squeeze(0)
tensor([ 0.4356, 0.4640, 0.4938, 0.5246, 0.5562, 0.5883, 0.6206, 0.6526, 0.6837, 0.7133, 0.7406, 0.7650, 0.7856, 0.8018, 0.8127, 0.8179, 0.8166, 0.8086, 0.7934, 0.7711, 0.7416, 0.7051, 0.6619, 0.6123, 0.5569, 0.4962, 0.4309, 0.3616, 0.2891, 0.2140, 0.1370, 0.0590, -0.0193, -0.0972, -0.1740, -0.2490, -0.3215, -0.3909, -0.4568, -0.5187, -0.5764, -0.6297, -0.6784, -0.7227, -0.7627, -0.7985, -0.8304, -0.8586, -0.8836, -0.9054])
可视化
plt.title("show", fontsize=20)
plt.xlabel("x", fontsize=15)
plt.ylabel("y", fontsize=15)
plt.scatter(x, y, c='red', s=20)
plt.scatter(x, pred, c='gray', s=20)
plt.plot(x, f, c='blue')
plt.plot(x, torch.Tensor().new_full([50], fill_value=y.mean()), c='green')
plt.show()
其中,蓝色曲线是目标曲线即sin函数,红色圆点是我们生成的训练样本,绿色横线是训练样本均值,而灰色圆点是“注意力”预测结果,可以看到在没有经过任何训练的情况下,核函数+softmax机制就能比较好的接近目标曲线了。