class_docstr: Config for NAS experiment.
  
  Other than training service fields which also exists in a HPO experiment,
  additional fields provided by NAS include execution engine and model format.
  Execution engine is used to specify how to (e.g., distributedly or sequentially) run a trial,
  and model format specifies the format of the converted model space used throughout the NAS experiment.
  
  It can be constructed via 3 approaches.
  
  1. Create a default config and then modify some fields (recommended).
     The default config should be good enough for most cases. Users only need to update some fields like concurrency.
     See details in :meth:`default`. Example::
  
      config = NasExperimentConfig.default(model_space, evaluator, strategy)
      config.trial_concurrency = 4
  
  2. Create an object by providing several required fields, and then set other fields.
     Though marked as optional in function signature, it's recommended to set all three fields.
  
      config = NasExperimentConfig('ts', 'graph', 'local')
      config.experiment_name = 'hello'
      config.execution_engine.dummy_input = [1, 3, 224, 224]
  
  3. Create an empty object and set all fields manually. Put the fields into kwargs should also work::
  
      config = NasExperimentConfig()
      config.execution_engine = TrainingServiceEngineConfig()
      config.model_format = SimplifiedModelFormatConfig()
      config.training_service = LocalConfig(use_active_gpu=True)
  
      # equivalent to
      config = NasExperimentConfig(
          execution_engine=TrainingServiceEngineConfig(),
          model_format=SimplifiedModelFormatConfig(),
          training_service=LocalConfig(use_active_gpu=True)
      )
code: def _canonicalize(self, parents):
      if self.search_space != RESERVED and self.search_space != {}:
          raise ValueError(
              "`search_space` field can not be customized in NAS experiment."
          )
      self.search_space = {}
  
      if not Path(self.trial_code_directory).samefile(Path.cwd()):
          raise ValueError(
              "`trial_code_directory` field can not be customized in NAS experiment."
          )
  
      trial_command_suffix = (
          "-m nni.nas.execution.training_service trial"
      )
      trial_command_template = "{envs} {python} " + trial_command_suffix
      if self.trial_command and not self.trial_command.endswith(
          trial_command_suffix
      ):
          raise ValueError(
              "`trial_command` field can not be customized in NAS experiment."
          )
  
      _trial_command_params = {
          # Default variables
          "envs": "",
          # TODO: maybe use sys.executable rendered in trial side (e.g., trial_runner)
          "python": sys.executable,
          # This should override the parameters above.
          **(self._trial_command_params or {}),
      }
  
      self.trial_command = trial_command_template.format(
          **_trial_command_params
      ).strip()
  
      if isinstance(self.execution_engine, SequentialEngineConfig):
          if (
              not utils.is_missing(self.trial_concurrency)
              and self.trial_concurrency != 1
          ):
              raise ValueError(
                  "`trial_concurrency` must be 1 for sequential execution engine."
              )
          self.trial_concurrency = 1
  
          if not utils.is_missing(self.training_service):
              _logger.warning(
                  "`training_service` will be ignored for sequential execution engine."
              )
  
          self.training_service = utils.training_service_config_factory(
              "local"
          )
  
      super()._canonicalize([self] + parents)
  
file_path: nni/nni/nas/experiment/config/experiment.py
imports: import logging
  import sys
  from dataclasses import dataclass
  from pathlib import Path
  from typing import Any, Dict, Optional, TYPE_CHECKING, Union, List
  from typing_extensions import Literal
  from nni.experiment.config import utils, ExperimentConfig
  from .engine import ExecutionEngineConfig, SequentialEngineConfig
  from .format import ModelFormatConfig
label_desc: Use image node_id 3 for calling the NasExperimentConfig obj's underlying member method code with example usage: obj._canonicalize(parents) without return types