pytorch - 在pytorch中构造参数组
问题描述
在torch.optim
文档中,指出可以使用不同的优化超参数对模型参数进行分组和优化。它说
例如,当想要指定每层学习率时,这非常有用:
optim.SGD([ {'params': model.base.parameters()}, {'params': model.classifier.parameters(), 'lr': 1e-3} ], lr=1e-2, momentum=0.9)
这意味着
model.base
的参数将使用 的默认学习率1e-2
,model.classifier
的参数将使用 的学习率,并且所有参数都将使用1e-3
的动量。0.9
我想知道如何定义具有parameters()
属性的此类组。我想到的是某种形式的东西
class MyModel(nn.Module):
def __init__(self):
super(MyModel, self).__init__()
self.base()
self.classifier()
self.relu = nn.ReLU()
def base(self):
self.fc1 = nn.Linear(1, 512)
self.fc2 = nn.Linear(512, 264)
def classifier(self):
self.fc3 = nn.Linear(264, 128)
self.fc4 = nn.Linear(128, 964)
def forward(self, y0):
y1 = self.relu(self.fc1(y0))
y2 = self.relu(self.fc2(y1))
y3 = self.relu(self.fc3(y2))
return self.fc4(y3)
我应该如何修改上面的代码片段才能得到model.base.parameters()
?是定义 ann.ParameterList
并明确将所需层的weight
s 和es 添加到该列表的唯一方法吗?bias
最佳做法是什么?
解决方案
我将展示解决此问题的三种方法。最后,它归结为个人喜好。
- 用 分组参数nn.ModuleDict
。
我在这里注意到一个答案,nn.Sequential
用于对允许parameters
使用nn.Sequential
. 事实上base
,分类器可能不仅仅是顺序层。我相信更通用的方法是保持模块不变,而是初始化一个附加nn.ModuleDict
模块,该模块将包含优化组在单独nn.ModuleList
的 s 中排序的所有参数:
class MyModel(nn.Module):
def __init__(self):
super().__init__()
self.fc1 = nn.Linear(1, 512)
self.fc2 = nn.Linear(512, 264)
self.fc3 = nn.Linear(264, 128)
self.fc4 = nn.Linear(128, 964)
self.params = nn.ModuleDict({
'base': nn.ModuleList([self.fc1, self.fc2]),
'classifier': nn.ModuleList([self.fc3, self.fc4])})
def forward(self, y0):
y1 = self.relu(self.fc1(y0))
y2 = self.relu(self.fc2(y1))
y3 = self.relu(self.fc3(y2))
return self.fc4(y3)
然后你可以定义你的优化器:
optim.SGD([
{'params': model.params.base.parameters()},
{'params': model.params.classifier.parameters(), 'lr': 1e-3}
], lr=1e-2, momentum=0.9)
请注意MyModel
'parameters
生成器不会包含重复的参数。
- 创建用于访问参数组的界面。
一个不同的解决方案是在 中提供一个接口nn.Module
来将参数分成组:
class MyModel(nn.Module):
def __init__(self):
super().__init__()
self.fc1 = nn.Linear(1, 512)
self.fc2 = nn.Linear(512, 264)
self.fc3 = nn.Linear(264, 128)
self.fc4 = nn.Linear(128, 964)
def forward(self, y0):
y1 = self.relu(self.fc1(y0))
y2 = self.relu(self.fc2(y1))
y3 = self.relu(self.fc3(y2))
return self.fc4(y3)
def base_params(self):
return chain(m.parameters() for m in [self.fc1, self.fc2])
def classifier_params(self):
return chain(m.parameters() for m in [self.fc3, self.fc4])
导入itertools.chain
为chain
.
然后定义你的优化器:
optim.SGD([
{'params': model.base_params()},
{'params': model.classifier_params(), 'lr': 1e-3}
], lr=1e-2, momentum=0.9)
- 使用 child nn.Module
s。
最后,您可以将模块部分定义为子模块(这里归结为方法作为nn.Sequential
一个,但您可以将其推广到任何子模块)。
class Base(nn.Sequential):
def __init__(self):
super().__init__(nn.Linear(1, 512),
nn.ReLU(),
nn.Linear(512, 264),
nn.ReLU())
class Classifier(nn.Sequential):
def __init__(self):
super().__init__(nn.Linear(264, 128),
nn.ReLU(),
nn.Linear(128, 964))
class MyModel(nn.Module):
def __init__(self):
super().__init__()
self.base = Base()
self.classifier = Classifier()
def forward(self, y0):
features = self.base(y0)
out = self.classifier(features)
return out
在这里,您可以再次使用与第一种方法相同的接口:
optim.SGD([
{'params': model.base.parameters()},
{'params': model.classifier.parameters(), 'lr': 1e-3}
], lr=1e-2, momentum=0.9)
我认为这是最佳实践。但是,它会强制您将每个组件定义为单独的nn.Module
,这在尝试更复杂的模型时可能会很麻烦。
推荐阅读
- reactjs - React Apollo 客户端查询抛出错误“提供给`Query`的`array`类型的无效prop`children`,预期`function`”
- django - 使用 Postgres 在 Django 中将 GinIndex 添加到模型时出错
- swift - Swift Async 调用未立即更新数据
- mysql - 如何根据别名对 SQL statemnet 进行排序
- javascript - GeoJSON中传单坐标的变量未定义?
- attributeerror - Discord.py:“上下文”对象没有属性“id”错误
- python - Django - 你的 sql 语法有错误
- css - matriel -ui ToggleButton 看起来像按钮
- javascript - 如何在页面加载时自动单击链接?
- clojure - datomic 和 clojure 入门 - 无法在类路径上找到 datomic/api__init.class