1.torch.nn.Parameter()函数
self.v = torch.nn.Parameter(torch.FloatTensor(hidden_size))
含义是将一个固定不可训练的tensor转换成可以训练的类型parameter,并将这个parameter绑定到这个module里面(net.parameter()中就有这个绑定的 parameter,所以在参数优化的时候可以进行优化),所以经过类型转换这个变量就变成了模型的一部分,成为了模型中根据训练可以改动的参数。
nn.Parameter()添加的参数会被添加到Parameters列表中,会被送入优化器中随训练一起学习更新 。以上摘自torcn.nn.parameter
访问其中元素时
print(net.parameters())
一个线性的实例:
(1)使用 self.test = torch.rand(1, 2)
import torch
class LinearModel(torch.nn.Module):
def __init__(self):
super(LinearModel, self).__init__()
self.test = torch.rand(1, 2)
self.linear = torch.nn.Linear(1, 1) # 构造linear对象,参数包括w,b (1,1)为输入,输出样本维度(特征数量)
def forward(self, x): # 重写,覆盖Module里的forward
y_pred = self.linear(x)
return y_pred
model = LinearModel() # 实例化
print("模型",model)
print("参数",list(model.named_parameters()))
模型 LinearModel(
(linear): Linear(in_features=1, out_features=1, bias=True)
)
参数 [('linear.weight', Parameter containing:
tensor([[-0.3734]], requires_grad=True)), ('linear.bias', Parameter containing:
tensor([0.9272], requires_grad=True))]
(2)使用self.test = torch.nn.Parameter(torch.rand(1, 2))#注意:Parameter大写P
import torch
class LinearModel(torch.nn.Module):
def __init__(self):
super(LinearModel, self).__init__()
self.test = torch.nn.Parameter(torch.rand(1, 2))#注意:Parameter大写P
self.linear = torch.nn.Linear(1, 1) # 构造linear对象,参数包括w,b (1,1)为输入,输出样本维度(特征数量)
def forward(self, x): # 重写,覆盖Module里的forward
y_pred = self.linear(x)
return y_pred
model = LinearModel() # 实例化
print("模型",model)
print("参数",list(model.named_parameters()))
模型 LinearModel(
(linear): Linear(in_features=1, out_features=1, bias=True)
)
参数 [('test', Parameter containing:
tensor([[0.3915, 0.7876]], requires_grad=True)), ('linear.weight', Parameter containing:
tensor([[-0.3052]], requires_grad=True)), ('linear.bias', Parameter containing:
tensor([-0.1999], requires_grad=True))]
2.nn.embedding
torch.nn.Embedding(num_embeddings, embedding_dim, padding_idx=None, max_norm=None, norm_type=2.0, scale_grad_by_freq=False, sparse=False, _weight=None)
其为一个简单的存储固定大小的词典的嵌入向量的查找表,意思就是说,给一个编号,嵌入层就能返回这个编号对应的嵌入向量,嵌入向量反映了各个编号代表的符号之间的语义关系。
输入为一个编号列表,输出为对应的符号嵌入向量列表。
第1个参数 num_embeddings 就是生成num_embeddings个嵌入向量。第2个参数 embedding_dim 就是嵌入向量的维度,即用embedding_dim值的维数来表示一个基本单位。
比如下面的代码embedding = nn.Embedding(6, 2),生成6个嵌入向量,每个嵌入向量的维度是2,
以上摘自详见
使⽤了嵌⼊层(embedding layer)来获得输⼊序列中每个词元的特征向量。嵌⼊层的权重是⼀个矩阵,其⾏数等于输⼊词表的⼤小(vocab_size),其列数等于特征向量的维度(embed_size)。对于任意输⼊词元的索引i,嵌⼊层获取权重矩阵的第i⾏(从0开始)以返回其特征向量。
embedding = torch.nn.Embedding(6, 2)
print(embedding.weight)
x=torch.ones(1,2).to(int)
print("x",x)
print("x.shape",x.shape)
y=embedding(x)
print("y",y)
print("y.shape",y.shape)#(,,embed_size)
输出:
Parameter containing:
tensor([[-0.5130, -1.2553],
[-0.5915, 0.7818],
[ 0.0382, 0.2250],
[-0.9197, -0.3909],
[-1.2444, 0.0630],
[-1.8657, -0.6756]], requires_grad=True)
x tensor([[1, 1]])
x.shape torch.Size([1, 2])
y tensor([[[-0.5915, 0.7818],
[-0.5915, 0.7818]]], grad_fn=<EmbeddingBackward>)
y.shape torch.Size([1, 2, 2])
实例:
import collections
import math
import torch
from torch import nn
from d2l import torch as d2l
#@save
class Seq2SeqEncoder(d2l.Encoder):
"""用于序列到序列学习的循环神经网络编码器"""
def __init__(self, vocab_size, embed_size, num_hiddens, num_layers,
dropout=0, **kwargs):
super(Seq2SeqEncoder, self).__init__(**kwargs)
# 嵌入层
self.embedding = nn.Embedding(vocab_size, embed_size)##获得每个词元的特征向量
self.rnn = nn.GRU(embed_size, num_hiddens, num_layers,
dropout=dropout)
#没有dense全连接的输出层,因为encoder不需要输出最终标号
def forward(self, X, *args):
# 输出'X'的形状:(batch_size,num_steps,embed_size)
X = self.embedding(X)
# 在循环神经网络模型中,第一个轴对应于时间步
X = X.permute(1, 0, 2)#(num_step,batch_size,)
# 如果未提及状态,则默认为0
output, state = self.rnn(X)#拿到最后输出,output是每个时刻最上面的输出,state是最后时刻每一层的输出
# output的形状:(num_steps,batch_size,num_hiddens)
# state的形状:(num_layers,batch_size,num_hiddens)
return output, state
encoder = Seq2SeqEncoder(vocab_size=10, embed_size=8, num_hiddens=16,
num_layers=2)
encoder.eval()#dropout不生效
X = torch.zeros((4, 7), dtype=torch.long)#(batch_size,num_step)
output, state = encoder(X)
output.shape#(num_steps,batch_size,num_hiddens)
class Seq2SeqDecoder(d2l.Decoder):
"""用于序列到序列学习的循环神经网络解码器"""
def __init__(self, vocab_size, embed_size, num_hiddens, num_layers,
dropout=0, **kwargs):
super(Seq2SeqDecoder, self).__init__(**kwargs)
self.embedding = nn.Embedding(vocab_size, embed_size)#获得每个词元的特征向量
self.rnn = nn.GRU(embed_size + num_hiddens, num_hiddens, num_layers,
dropout=dropout)
self.dense = nn.Linear(num_hiddens, vocab_size)#输出vacab_size的分类
def init_state(self, enc_outputs, *args):#encoder的state
return enc_outputs[1]
def forward(self, X, state):
# 输出'X'的形状:(batch_size,num_steps,embed_size)
X = self.embedding(X).permute(1, 0, 2)
# 广播context,使其具有与X相同的num_steps
'''上下文操作。这里state[-1]拿到的是“最右上角的”H(这个H融合和所有的信息)如果state是【2,4,16】的,
那state[-1]就是【1,4,16】的。repeat重复时间步次。
这样,可以用到每一个时间步最后的H信息,
与新的输入X做concat操作(这也是为什么解码器的self.rnn是ebd_size + num_hiddens的原因)。
如果state[-1]是【1,4,16】,时间步是7,那重复完之后就是【7,4,16】的?????
(7个时间步,4是batch_size,16是state隐藏单元的个数)。'''
context = state[-1].repeat(X.shape[0], 1, 1)#state[-1]最后时刻最后一层的输出,它包括了最后所有浓缩的信息
#X_and_context(num_step,batch_size,ebd_size + num_hidden)
X_and_context = torch.cat((X, context), 2)#DEcoder输入是ENcoder的state和最后context上下文拼在一起
output, state = self.rnn(X_and_context, state)
output = self.dense(output).permute(1, 0, 2)
# output的形状:(batch_size,num_steps,vocab_size)
# state的形状:(num_layers,batch_size,num_hiddens)
return output, state
decoder = Seq2SeqDecoder(vocab_size=10, embed_size=8, num_hiddens=16,
num_layers=2)
decoder.eval()
state = decoder.init_state(encoder(X))
output, state = decoder(X, state)
output.shape, state.shape