-
Notifications
You must be signed in to change notification settings - Fork 1.8k
[Retiarii] support hypermodule: autoactivation #3868
[Retiarii] support hypermodule: autoactivation #3868
Conversation
@QuanluZhang do you have a minimal example that shows how to use this one? |
I have not added the example in this pr. you can refer to the following example: import random
from nni.retiarii import model_wrapper
import nni.retiarii.nn.pytorch as nn
import nni.retiarii.strategy as strategy
import nni.retiarii.evaluator.pytorch.lightning as pl
import torch.nn.functional as F
from nni.retiarii import serialize
from nni.retiarii.experiment.pytorch import RetiariiExeConfig, RetiariiExperiment, debug_mutated_model
from torch.utils.data import DataLoader
from torchvision import transforms
from torchvision.datasets import MNIST
#import nni
@model_wrapper
class Net(nn.Module):
def __init__(self, hidden_size):
#super(Net, self).__init__()
super().__init__()
self.conv1 = nn.Conv2d(1, 20, 5, 1)
self.conv2 = nn.Conv2d(20, 50, 5, 1)
self.fc1 = nn.Linear(4*4*50, hidden_size)
#self.fc1 = nn.LayerChoice([
# nn.Linear(4*4*50, hidden_size),
# nn.Linear(4*4*50, hidden_size, bias=False)
#])
#repeat = nn.Linear(hidden_size, hidden_size)
#self.repeat = nn.Repeat(repeat, [1, 4])
#self.act_cell = nn.Cell([nn.ReLU(), nn.Dropout(), nn.Linear(hidden_size, hidden_size)], 3, 3)
#self.fc2 = nn.Linear(hidden_size*3, 10)
self.fc2 = nn.Linear(hidden_size, 10)
self.act = nn.AutoActivation()
def forward(self, x):
x = F.relu(self.conv1(x))
x = F.max_pool2d(x, 2, 2)
x = F.relu(self.conv2(x))
x = F.max_pool2d(x, 2, 2)
x = x.view(-1, 4*4*50)
x = F.relu(self.fc1(x))
#x = self.repeat(x)
#x = self.act_cell([x])
x = self.act(self.fc2(x))
return F.log_softmax(x, dim=1)
if __name__ == '__main__':
base_model = Net(128)
transform = transforms.Compose([transforms.ToTensor(), transforms.Normalize((0.1307,), (0.3081,))])
train_dataset = serialize(MNIST, root='data/mnist', train=True, download=True, transform=transform)
test_dataset = serialize(MNIST, root='data/mnist', train=False, download=True, transform=transform)
trainer = pl.Classification(train_dataloader=pl.DataLoader(train_dataset, batch_size=100),
val_dataloaders=pl.DataLoader(test_dataset, batch_size=100),
max_epochs=1, gpus=1)
# uncomment the following two lines to debug a generated model
#debug_mutated_model(base_model, trainer, [])
#exit(0)
#simple_strategy = strategy.PolicyBasedRL()
simple_strategy = strategy.GridSearch()
exp = RetiariiExperiment(base_model, trainer, [], simple_strategy)
exp_config = RetiariiExeConfig('local')
exp_config.experiment_name = 'mnist_search'
exp_config.trial_concurrency = 3
exp_config.max_trial_number = 250
exp_config.trial_gpu_number = 1
exp_config.training_service.use_active_gpu = False
exp_config.execution_engine = 'py'
exp.run(exp_config, 8081 + random.randint(0, 100))
print('Final model:')
for model_code in exp.export_top_models(formatter='dict'):
print(model_code) |
Sure. Will give it a try. Would you folks prefer to have Colab Notebooks as they don't require any non-trivial setups and might be easier for anyone to get started? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great!
super().__init__() | ||
self.unaries = nn.ModuleList() | ||
self.binaries = nn.ModuleList() | ||
self.first_unary = LayerChoice([eval('{}()'.format(unary)) for unary in unary_modules], label='one_unary') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suggest globals()(unary)()
, which is semantically more clear that eval
.
self.binaries = nn.ModuleList() | ||
self.first_unary = LayerChoice([eval('{}()'.format(unary)) for unary in unary_modules], label='one_unary') | ||
for _ in range(unit_num): | ||
one_unary = LayerChoice([eval('{}()'.format(unary)) for unary in unary_modules], label='one_unary') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think they should have the same label?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, you are right, this is for easy testing, i will remove the label then.
@@ -544,3 +561,21 @@ def forward(self, x): | |||
except InvalidMutation: | |||
continue | |||
self.assertTrue(self._get_converted_pytorch_model(model)(torch.randn(2, 10)).size() == torch.Size([2, 16])) | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can write one in the base class and Python
will automatically inherit it.
hypermodule is a (PyTorch) module which contains many architecture/hyperparameter candidates for this module. By using hypermodule, NNI will automatically find the best architecture/hyperparameter for this module. This follows the design philosophy of Retiarii that users write DNN model as a space.
This pr is implementing
AutoActivation
from the paper "Search for activation Functions"