使用PyTorch训练神经网络时,本质上相当于训练一个函数,输入数据 经过这个函数 输出一个预测,而我们给定这个函数的结构(如卷积、全连接等)之后,能够学习的就是这个函数的参数了。
所以,可以把 torch.nn.Parameter() 理解为类型转换函数,将一个不可训练的类型Tensor转换成可以训练的类型parameter,并将这个parameter绑定到这个module里面,经过类型转换这个 self.v 变成了模型的一部分,成为模型中根据训练可以改动的参数。
使用 torch.nn.Parameter() 的目的是想让某些变量在学习的过程中不断地修改自身值以达到最优化。
在实际应用中,设计一个损失函数,配合梯度下降法,使得我们学习到的神经网络更加准确地完成预测任务。
经典的应用场景有:
- 注意力机制中的权重参数(基本上)
如下(从一个文本分类任务中截取的):
# 定义Attention
# 这里,Attention的输入是sent_hiddens和sent_masks。
class Attention(nn.Module):
def __init__(self, hidden_size):
super(Attention, self).__init__()
self.weight = nn.Parameter(torch.Tensor(hidden_size, hidden_size)) # 注意力机制权重设置为可学习参数
self.weight.data.normal_(mean=0.0, std=0.05) # 返回一个随机数字的张量,该张量是从给定均值mean和标准差std的独立正态分布中提取的
# 希望对tensor进行操作,但是又不被autograd记录,使用tensor.data或tensor.detach()
self.bias = nn.Parameter(torch.Tensor(hidden_size)) # 偏置可学习
b = np.zeros(hidden_size, dtype=np.float32)
self.bias.data.copy_(torch.from_numpy(b)) # torch.from_numpy(b) 把数组b转换成张量,且二者共享内存
self.query = nn.Parameter(torch.Tensor(hidden_size))
self.query.data.normal_(mean=0.0, std=0.05)
def forward(self, batch_hidden, batch_masks):
# linear
# 1、输入sent_hiddens首先经过线性变化得到key,维度不变 (batch_size, doc_len, 512)
key = torch.matmul(batch_hidden, self.weight) + self.bias # b * len * hidden
# compute attention
# 2、然后key和query相乘,得到outputs。 这就是我们需要的attention,表示分配到每个句子的权重
outputs = torch.matmul(key, self.query) # batch_size * doc_len
# 根据query和key计算两者的相似性或相关性,基本方法就是向量积matmul。
masked_outputs = outputs.masked_fill((1-batch_masks).bool(), float(-1e32))
# 将没有单词的地方(0)用一个比较小的值替换(比如 -1e32) 即padding_mask
# 3、做softmax操作,得到注意力权重矩阵
attn_scores = F.softmax(masked_outputs, dim=1) # b * len
# 4、使用另一个输入sent_masks,把没有单词的句子权重置为-1e32,得到masked_attn_scores
masked_attn_scores = attn_scores.masked_fill((1-batch_masks).bool(), 0.0)
# sum weighted sources
# 5、将masked_attn_scores和key相乘,得到batch_outputs,形状是(batch_size, 512)
batch_outputs = torch.bmm(masked_attn_scores.unsqueeze(1), key).squeeze(1) # b * hidden # 加权求和
return batch_outputs, attn_scores