class_docstr: Class of experiment configuration. Check the reference_ for explaination of each field.
  
  When used in Python experiment API, it can be constructed in two favors:
  
  1. Create an empty project then set each field
  
  .. code-block:: python
  
      config = ExperimentConfig('local')
      config.search_space = {...}
      config.tuner.name = 'random'
      config.training_service.use_active_gpu = True
  
   2. Use kwargs directly
  
   .. code-block:: python
  
      config = ExperimentConfig(
          search_space = {...},
          tuner = AlgorithmConfig(name='random'),
          training_service = LocalConfig(
              use_active_gpu = True
          )
      )
  
  .. _reference: https://nni.readthedocs.io/en/stable/reference/experiment_config.html
class_docstr_tok: ["Class","of","experiment","configuration",".","Check","the","reference_","for","explaination","of","each","field",".","When","used","in","Python","experiment","API",",","it","can","be","constructed","in","two","favors",":","1",".","Create","an","empty","project","then","set","each","field","..","code-block",":",":","python","config","=","ExperimentConfig","(","'local","'",")","config.search_space","=","{","...","}","config.tuner.name","=","'random'","config.training_service.use_active_gpu","=","True","2",".","Use","kwargs","directly","..","code-block",":",":","python","config","=","ExperimentConfig","(","search_space","=","{","...","}",",","tuner","=","AlgorithmConfig","(","name='random","'",")",",","training_service","=","LocalConfig","(","use_active_gpu","=","True",")",")","..","_reference",":","https",":","\/\/nni.readthedocs.io\/en\/stable\/reference\/experiment_config.html"]
code: def _validate_canonical(self):
      super()._validate_canonical()
  
      space_cnt = (self.search_space is not None) + (
          self.search_space_file is not None
      )
      if self.use_annotation and space_cnt != 0:
          raise ValueError(
              "ExperimentConfig: search space must not be set when annotation is enabled"
          )
      if not self.use_annotation and space_cnt < 1:
          raise ValueError(
              "ExperimentConfig: search_space and search_space_file must be set one"
          )
  
      # to make the error message clear, ideally it should be:
      # `if concurrency < 0: raise ValueError('trial_concurrency ({concurrency}) must greater than 0')`
      # but I believe there will be hardy few users make this kind of mistakes, so let's keep it simple
      assert self.trial_concurrency > 0
      assert (
          self.max_experiment_duration is None
          or utils.parse_time(self.max_experiment_duration) > 0
      )
      assert self.max_trial_number is None or self.max_trial_number > 0
      assert (
          self.max_trial_duration is None
          or utils.parse_time(self.max_trial_duration) > 0
      )
      assert self.log_level in [
          "fatal",
          "error",
          "warning",
          "info",
          "debug",
          "trace",
      ]
  
      # following line is disabled because it has side effect
      # enable it if users encounter problems caused by failure in creating experiment directory
      # currently I have only seen one issue of this kind
      # Path(self.experiment_working_directory).mkdir(parents=True, exist_ok=True)
  
      if type(self).__name__ != "NasExperimentConfig":
          utils.validate_gpu_indices(self.tuner_gpu_indices)
  
          if self.tuner is None:
              raise ValueError("ExperimentConfig: tuner must be set")
  
file_path: nni/nni/experiment/config/experiment_config.py
imports: from dataclasses import dataclass
  import json
  import logging
  from pathlib import Path
  from typing import Any, List, Optional, Union
  from typing_extensions import Literal
  import yaml
  from .algorithm import _AlgorithmConfig
  from .base import ConfigBase
  from .shared_storage import SharedStorageConfig
  from .training_service import TrainingServiceConfig
  from .None import utils
label_desc: Use image node_id 4 for calling the ExperimentConfig obj's underlying member method code with example usage: obj._validate_canonical() without return types