- list
- Sequential
- ModuleList
- 总结
import torch import torch.nn as nnlist
class a(nn.Module):
def __init__(self):
super(a,self).__init__()
self.mods=[nn.Linear(2,3),nn.Linear(3,4)]
def forward(self,x):
for i in range(len(self.mods)):
x=self.mods[i](x)
return x
model=a() b=torch.rand(1,2) model(b)
前向传播一切正常。
tensor([[-0.6185, -0.0559, 0.2114, -0.2635]], grad_fn=)
其实反向传播计算梯度也正常,不过我们此处不展示。但是其有一个问题,由于我们总是用torch.optim中的优化器来更新参数,这个时候传入的是model.parameters(),然而,这个参数并不会包括list中的那两个线性层的参数。
for param in model.parameters():
print(param.data.shape)
#没有任何输出,也就是说没有收录。
这意味着,optim不会帮你将那两个线性层的参数更新以及梯度清零,你需要手动做,太麻烦。
所以我们使用另外两种解决方案:ModuleList和Sequential。其也像list那样,是一个容器,但是好处在于会帮我们将其参数收录到model.parameters()中。
Sequentialclass a(nn.Module):
def __init__(self):
super(a,self).__init__()
self.mods=nn.Sequential(nn.Linear(2,3),
nn.Linear(3,4))
def forward(self,x):
return self.mods(x)
上面展示了nn.Sequential的用法,其要求其内部的模型有顺序,前一个模型的输出是下一个模型的输入,即数据流是这样的:(2,3)->(3,4)。
model=a() b=torch.rand(1,2) model(b)
for param in model.parameters():
print(param.data.shape)
#收录。
解释:其中第二和第四行是偏置。
拓展:上述Sequential我们的构造很简单,直接写在()里面的,下面介绍一种更加通用的做法:
class a(nn.Module):
def __init__(self):
super(a,self).__init__()
self.mods=nn.Sequential()
for i in range(2,4):
self.mods.add_module(name="mymodel{}".format(i),module=nn.Linear(i,i+1))
def forward(self,x):
return self.mods(x)
其他一模一样。但是要注意一个事情,就是对于Sequential这个东西,里面的任何一个module的forward函数中,除了self这个参数,只能还有一个参数,否则报错。
ModuleList同样,也是一个容器,可以将容器中的所有module的参数加入到外面的那个model.parameters()中。但其和Sequential不一样,里面的module是无序的,前一个module的输出未必是下一个module的输入。操作它,就像操作列表一样。
class a(nn.Module):
def __init__(self):
super(a,self).__init__()
self.mods=[nn.Linear(2,3),nn.Linear(3,4)]
self.mods=nn.ModuleList(self.mods)
def forward(self,x):
for i in range(len(self.mods)):
x=self.mods[i](x)
return x
model=a() b=torch.rand(1,2) model(b)
for param in model.parameters():
print(param.data.shape)
#收录。
总结
会自动将参数注册到主模型的有:
- 子模型的参数(即继承了nn.Module的模型)。
其实,平常我们用的nn.Linear()其实就是一个子模型(继承了nn.Module的模型),所以其参数会注册到主模型。 - nn.ModuleList
- nn.Sequential
- nn.Parameter



