|
- # Copyright (c) Microsoft Corporation.
- # Licensed under the MIT license.
-
- import logging
- from collections import OrderedDict
-
- import numpy as np
- import torch
- import nni.retiarii.nn.pytorch as nn
- from nni.nas.pytorch.mutables import Mutable, InputChoice, LayerChoice
-
- _logger = logging.getLogger(__name__)
-
-
- def to_device(obj, device):
- """
- Move a tensor, tuple, list, or dict onto device.
- """
- if torch.is_tensor(obj):
- return obj.to(device)
- if isinstance(obj, tuple):
- return tuple(to_device(t, device) for t in obj)
- if isinstance(obj, list):
- return [to_device(t, device) for t in obj]
- if isinstance(obj, dict):
- return {k: to_device(v, device) for k, v in obj.items()}
- if isinstance(obj, (int, float, str)):
- return obj
- raise ValueError("'%s' has unsupported type '%s'" % (obj, type(obj)))
-
-
- def to_list(arr):
- if torch.is_tensor(arr):
- return arr.cpu().numpy().tolist()
- if isinstance(arr, np.ndarray):
- return arr.tolist()
- if isinstance(arr, (list, tuple)):
- return list(arr)
- return arr
-
-
- class AverageMeterGroup:
- """
- Average meter group for multiple average meters.
- """
-
- def __init__(self):
- self.meters = OrderedDict()
-
- def update(self, data):
- """
- Update the meter group with a dict of metrics.
- Non-exist average meters will be automatically created.
- """
- for k, v in data.items():
- if k not in self.meters:
- self.meters[k] = AverageMeter(k, ":4f")
- self.meters[k].update(v)
-
- def __getattr__(self, item):
- return self.meters[item]
-
- def __getitem__(self, item):
- return self.meters[item]
-
- def __str__(self):
- return " ".join(str(v) for v in self.meters.values())
-
- def summary(self):
- """
- Return a summary string of group data.
- """
- return " ".join(v.summary() for v in self.meters.values())
-
-
- class AverageMeter:
- """
- Computes and stores the average and current value.
-
- Parameters
- ----------
- name : str
- Name to display.
- fmt : str
- Format string to print the values.
- """
-
- def __init__(self, name, fmt=":f"):
- self.name = name
- self.fmt = fmt
- self.reset()
-
- def reset(self):
- """
- Reset the meter.
- """
- self.val = 0
- self.avg = 0
- self.sum = 0
- self.count = 0
-
- def update(self, val, n=1):
- """
- Update with value and weight.
-
- Parameters
- ----------
- val : float or int
- The new value to be accounted in.
- n : int
- The weight of the new value.
- """
- self.val = val
- self.sum += val * n
- self.count += n
- self.avg = self.sum / self.count
-
- def __str__(self):
- fmtstr = "{name} {val" + self.fmt + "} ({avg" + self.fmt + "})"
- return fmtstr.format(**self.__dict__)
-
- def summary(self):
- fmtstr = "{name}: {avg" + self.fmt + "}"
- return fmtstr.format(**self.__dict__)
-
-
- def get_module_order(root_module):
- key2order = {}
-
- def apply(m):
- for name, child in m.named_children():
- if isinstance(child, Mutable):
- key2order[child.key] = child.order
- else:
- apply(child)
-
- apply(root_module)
- return key2order
-
-
- def sort_replaced_module(k2o, modules):
- modules = sorted(modules, key=lambda x: k2o[x[0]])
- return modules
-
-
- def _replace_module_with_type(root_module, init_fn, type_name, modules):
- if modules is None:
- modules = []
-
- def apply(m):
- for name, child in m.named_children():
- if isinstance(child, type_name):
- setattr(m, name, init_fn(child))
- modules.append((child.key, getattr(m, name)))
- else:
- apply(child)
-
- apply(root_module)
- return modules
-
-
- def replace_layer_choice(root_module, init_fn, modules=None):
- """
- Replace layer choice modules with modules that are initiated with init_fn.
-
- Parameters
- ----------
- root_module : nn.Module
- Root module to traverse.
- init_fn : Callable
- Initializing function.
- modules : dict, optional
- Update the replaced modules into the dict and check duplicate if provided.
-
- Returns
- -------
- List[Tuple[str, nn.Module]]
- A list from layer choice keys (names) and replaced modules.
- """
- return _replace_module_with_type(
- root_module, init_fn, (LayerChoice, nn.LayerChoice), modules
- )
-
-
- def replace_input_choice(root_module, init_fn, modules=None):
- """
- Replace input choice modules with modules that are initiated with init_fn.
-
- Parameters
- ----------
- root_module : nn.Module
- Root module to traverse.
- init_fn : Callable
- Initializing function.
- modules : dict, optional
- Update the replaced modules into the dict and check duplicate if provided.
-
- Returns
- -------
- List[Tuple[str, nn.Module]]
- A list from layer choice keys (names) and replaced modules.
- """
- return _replace_module_with_type(
- root_module, init_fn, (InputChoice, nn.InputChoice), modules
- )
|