code: def generate_variants(unresolved_spec):
      
      for resolved_vars, spec in _generate_variants(unresolved_spec):
          assert not _unresolved_values(spec)
          yield format_vars(resolved_vars), spec
docs: Generates variants from a spec (dict) with unresolved values.
  
      There are two types of unresolved values:
  
          Grid search: These define a grid search over values. For example, the
          following grid search values in a spec will produce six distinct
          variants in combination:
  
              "activation": grid_search(["relu", "tanh"])
              "learning_rate": grid_search([1e-3, 1e-4, 1e-5])
  
          Lambda functions: These are evaluated to produce a concrete value, and
          can express dependencies or conditional distributions between values.
          They can also be used to express random search (e.g., by calling
          into the `random` or `np` module).
  
              "cpu": lambda spec: spec.config.num_workers
              "batch_size": lambda spec: random.uniform(1, 1000)
  
      Finally, to support defining specs in plain JSON / YAML, grid search
      and lambda functions can also be defined alternatively as follows:
  
          "activation": {"grid_search": ["relu", "tanh"]}
          "cpu": {"eval": "spec.config.num_workers"}