Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion skorch/net.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
from skorch.exceptions import SkorchAttributeError
from skorch.exceptions import SkorchTrainingImpossibleError
from skorch.history import History
from skorch.setter import format_param_group_msg
from skorch.setter import optimizer_setter
from skorch.utils import _TorchLoadUnpickler
from skorch.utils import _identity
Expand Down Expand Up @@ -2030,7 +2031,13 @@ def _get_params_for_optimizer(self, prefix, named_parameters):
matches = [i for i, (name, _) in enumerate(params) if
fnmatch.fnmatch(name, pattern)]
if matches:
p = [params.pop(i)[1] for i in reversed(matches)]
# pop high indices first so earlier indices stay valid
matched = [params.pop(i) for i in reversed(matches)]
p = [param for _, param in matched]
if self.verbose:
# show names in the order they were matched
matched_names = [name for name, _ in reversed(matched)]
print(format_param_group_msg(group, matched_names))
pgroups.append({'params': p, **group})

if params:
Expand Down
36 changes: 34 additions & 2 deletions skorch/setter.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,27 @@
import re


def format_param_group_msg(group_config, param_names):
"""Message for which module params a param group config applies to."""
return "Setting param group {} for {}.".format(
group_config,
', '.join(param_names),
Comment thread
aiedwardyi marked this conversation as resolved.
Outdated
)


def _param_names_for_tensors(net, tensors):
"""Map optimizer tensors back to module parameter names when possible."""
tensor_ids = {id(t) for t in tensors}
names = []
get_params = getattr(net, 'get_all_learnable_params', None)
if get_params is None:
return names
for name, p in get_params():
if id(p) in tensor_ids:
names.append(name)
return names


def _extract_optimizer_param_name_and_group(optimizer_name, param):
"""Extract param group and param name from the given parameter name.
Raises an error if the param name doesn't match one of
Expand Down Expand Up @@ -44,6 +65,8 @@ def _set_optimizer_param(optimizer, param_group, param_name, value):
for group in groups:
group[param_name] = value

return groups


def optimizer_setter(
net, param, value, optimizer_attr='optimizer_', optimizer_name='optimizer'
Expand All @@ -62,9 +85,18 @@ def optimizer_setter(
param_group, param_name = _extract_optimizer_param_name_and_group(
optimizer_name, param)

_set_optimizer_param(
optimizer=getattr(net, optimizer_attr),
optimizer = getattr(net, optimizer_attr)
groups = _set_optimizer_param(
optimizer=optimizer,
Comment thread
aiedwardyi marked this conversation as resolved.
Outdated
param_group=param_group,
param_name=param_name,
value=value
)

if getattr(net, 'verbose', 0):
tensors = []
for group in groups:
tensors.extend(group.get('params', []))
param_names = _param_names_for_tensors(net, tensors)
if param_names:
print(format_param_group_msg({param_name: value}, param_names))
Comment thread
aiedwardyi marked this conversation as resolved.
Outdated
27 changes: 27 additions & 0 deletions skorch/tests/test_net.py
Comment thread
aiedwardyi marked this conversation as resolved.
Original file line number Diff line number Diff line change
Expand Up @@ -1396,6 +1396,33 @@ def test_optimizer_param_groups(self, net_cls, module_cls):
assert net.optimizer_.param_groups[1]['lr'] == 0.5
assert net.optimizer_.param_groups[2]['lr'] == net.lr

def test_optimizer_param_groups_verbose_prints(self, net_cls, module_cls, capsys):
net = net_cls(
module_cls,
verbose=1,
optimizer__param_groups=[
('sequential.0.*', {'lr': 0.1}),
],
)
net.initialize()
out = capsys.readouterr().out
assert "Setting param group {'lr': 0.1} for" in out
assert 'sequential.0.weight' in out
assert 'sequential.0.bias' in out

def test_optimizer_param_groups_silent_when_verbose_0(
self, net_cls, module_cls, capsys):
net = net_cls(
module_cls,
verbose=0,
optimizer__param_groups=[
('sequential.0.*', {'lr': 0.1}),
],
)
net.initialize()
out = capsys.readouterr().out
assert 'Setting param group' not in out

def test_module_params_in_init(self, net_cls, module_cls, data):
X, y = data

Expand Down
11 changes: 11 additions & 0 deletions skorch/tests/test_setter.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,3 +73,14 @@ def test_only_specific_param_group_updated(self, setter, net_optim_dummy,
assert updated_group_new[0][sub_param] == value
assert all(old[sub_param] == new[sub_param] for old, new in zip(
static_groups_pre, static_groups_new))

def test_set_params_verbose_prints_param_group(self, setter, capsys):
from skorch import NeuralNetClassifier
from skorch.toy import make_classifier

net = NeuralNetClassifier(make_classifier(), verbose=1, max_epochs=1)
net.initialize()
setter(net, 'optimizer__param_groups__0__lr', 0.03)
out = capsys.readouterr().out
assert "Setting param group {'lr': 0.03} for" in out
assert 'sequential.0.weight' in out