Search code examples
pythondatabricksazure-databricksfb-hydra

I'm trying to use Config Management Tool Hydra(As a decorator) for a Multirun experimentation in Azure Databricks Environment. It does not work


I'm trying to use Config Management Tool Hydra in a Azure Databricks environment(Client Specific requirement). The idea is to do multiruns using config files. I have tried a few codes on my local, it works like a charm. But the same does not work in my Databricks set-up. I have installed the latest Hydra Wheel file downloaded from the Hydra official website onto my Databricks cluster.

Here is how my code looks like. Initially Im trying to simply print my config file and subsequently I want to have multirun from this possible and see if the parameters are being sweeped or not. I face an error while using a basic Hydra decorator style function itself. Using hydra's compose API's I can read one single YAML config, but according to Hydra's official documentation, compose does not allow multirun and my task is to have multirun. Has anybody faced a similar error or Is there any quick fix I can try?

config_test.yaml

network:
    inputs: 2
    outputs: 3
    layer_size: 60
    nr_layers: 8

optimiser:
    lr: 1e-3
    scheduler: exponential_lr
    iter: 5000
    
hydra:
    mode: MULTIRUN
    sweeper:
        params:
          +n: 5,10

Code

import hydra
from omegaconf import DictConfig, OmegaConf

@hydra.main(version_base= None, config_path="conf", config_name="config_test.yaml")
def main(cfg : DictConfig) -> None:
    print(OmegaConf.to_yaml(cfg))


if __name__ == '__main__':
    main()

The high level error says

- **LexerNoViableAltException: 39187**
and
- **object of type 'NoneType' has no len()</sub>**

**The detailed error looks something like this**

<sub>
LexerNoViableAltException: 39187
                           ^
See https://hydra.cc/docs/1.2/advanced/override_grammar/basic for details

Set the environment variable HYDRA_FULL_ERROR=1 for a complete stack trace.
ERROR:root:Internal Python error in the inspect module.
Below is the traceback from this internal error.

Traceback (most recent call last):
  File "/databricks/python/lib/python3.8/site-packages/hydra/_internal/utils.py", line 220, in run_and_report
    return func()
  File "/databricks/python/lib/python3.8/site-packages/hydra/_internal/utils.py", line 458, in <lambda>
    lambda: hydra.run(
  File "/databricks/python/lib/python3.8/site-packages/hydra/_internal/hydra.py", line 105, in run
    cfg = self.compose_config(
  File "/databricks/python/lib/python3.8/site-packages/hydra/_internal/hydra.py", line 594, in compose_config
    cfg = self.config_loader.load_configuration(
  File "/databricks/python/lib/python3.8/site-packages/hydra/_internal/config_loader_impl.py", line 142, in load_configuration
    return self._load_configuration_impl(
  File "/databricks/python/lib/python3.8/site-packages/hydra/_internal/config_loader_impl.py", line 244, in _load_configuration_impl
    parsed_overrides, caching_repo = self._parse_overrides_and_create_caching_repo(
  File "/databricks/python/lib/python3.8/site-packages/hydra/_internal/config_loader_impl.py", line 228, in _parse_overrides_and_create_caching_repo
    parsed_overrides = parser.parse_overrides(overrides=overrides)
  File "/databricks/python/lib/python3.8/site-packages/hydra/core/override_parser/overrides_parser.py", line 96, in parse_overrides
    raise OverrideParseException(
hydra.errors.OverrideParseException: LexerNoViableAltException: 39187
                           ^
See https://hydra.cc/docs/1.2/advanced/override_grammar/basic for details

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/databricks/python/lib/python3.8/site-packages/IPython/core/interactiveshell.py", line 3437, in run_code
    exec(code_obj, self.user_global_ns, self.user_ns)
  File "<command-229383469694947>", line 28, in <module>
    main()
  File "/databricks/python/lib/python3.8/site-packages/hydra/main.py", line 94, in decorated_main
    _run_hydra(
  File "/databricks/python/lib/python3.8/site-packages/hydra/_internal/utils.py", line 394, in _run_hydra
    _run_app(
  File "/databricks/python/lib/python3.8/site-packages/hydra/_internal/utils.py", line 457, in _run_app
    run_and_report(
  File "/databricks/python/lib/python3.8/site-packages/hydra/_internal/utils.py", line 303, in run_and_report
    sys.exit(1)
SystemExit: 1

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/databricks/python/lib/python3.8/site-packages/IPython/core/ultratb.py", line 1101, in get_records
    return _fixed_getinnerframes(etb, number_of_lines_of_context, tb_offset)
  File "/databricks/python/lib/python3.8/site-packages/IPython/core/ultratb.py", line 248, in wrapped
    return f(*args, **kwargs)
  File "/databricks/python/lib/python3.8/site-packages/IPython/core/ultratb.py", line 281, in _fixed_getinnerframes
    records = fix_frame_records_filenames(inspect.getinnerframes(etb, context))
  File "/usr/lib/python3.8/inspect.py", line 1515, in getinnerframes
    frameinfo = (tb.tb_frame,) + getframeinfo(tb, context)
AttributeError: 'tuple' object has no attribute 'tb_frame'

The Main Error looks something like this

TypeError: object of type 'NoneType' has no len()
---------------------------------------------------------------------------
OverrideParseException                    Traceback (most recent call last)
/databricks/python/lib/python3.8/site-packages/hydra/_internal/utils.py in run_and_report(func)
    219     try:
--> 220         return func()
    221     except Exception as ex:

/databricks/python/lib/python3.8/site-packages/hydra/_internal/utils.py in <lambda>()
    457         run_and_report(
--> 458             lambda: hydra.run(
    459                 config_name=config_name,

/databricks/python/lib/python3.8/site-packages/hydra/_internal/hydra.py in run(self, config_name, task_function, overrides, with_log_configuration)
    104     ) -> JobReturn:
--> 105         cfg = self.compose_config(
    106             config_name=config_name,

/databricks/python/lib/python3.8/site-packages/hydra/_internal/hydra.py in compose_config(self, config_name, overrides, run_mode, with_log_configuration, from_shell, validate_sweep_overrides)
    593 
--> 594         cfg = self.config_loader.load_configuration(
    595             config_name=config_name,

/databricks/python/lib/python3.8/site-packages/hydra/_internal/config_loader_impl.py in load_configuration(self, config_name, overrides, run_mode, from_shell, validate_sweep_overrides)
    141         try:
--> 142             return self._load_configuration_impl(
    143                 config_name=config_name,

/databricks/python/lib/python3.8/site-packages/hydra/_internal/config_loader_impl.py in _load_configuration_impl(self, config_name, overrides, run_mode, from_shell, validate_sweep_overrides)
    243         self.ensure_main_config_source_available()
--> 244         parsed_overrides, caching_repo = self._parse_overrides_and_create_caching_repo(
    245             config_name, overrides

/databricks/python/lib/python3.8/site-packages/hydra/_internal/config_loader_impl.py in _parse_overrides_and_create_caching_repo(self, config_name, overrides)
    227         parser = OverridesParser.create()
--> 228         parsed_overrides = parser.parse_overrides(overrides=overrides)
    229         caching_repo = CachingConfigRepository(self.repository)

/databricks/python/lib/python3.8/site-packages/hydra/core/override_parser/overrides_parser.py in parse_overrides(self, overrides)
     95                     msg = f"Error parsing override '{override}'" f"\n{e}"
---> 96                 raise OverrideParseException(
     97                     override=override,

OverrideParseException: LexerNoViableAltException: 39187
                           ^
See https://hydra.cc/docs/1.2/advanced/override_grammar/basic for details

During handling of the above exception, another exception occurred:

SystemExit                                Traceback (most recent call last)
    [... skipping hidden 1 frame]

<command-229383469694947> in <module>
     27 if __name__ == '__main__':
---> 28     main()
     29 

/databricks/python/lib/python3.8/site-packages/hydra/main.py in decorated_main(cfg_passthrough)
     93                     # multiple times (--multirun)
---> 94                     _run_hydra(
     95                         args=args,

/databricks/python/lib/python3.8/site-packages/hydra/_internal/utils.py in _run_hydra(args, args_parser, task_function, config_path, config_name, caller_stack_depth)
    393             run_mode = hydra.get_mode(config_name=config_name, overrides=overrides)
--> 394             _run_app(
    395                 run=args.run,

/databricks/python/lib/python3.8/site-packages/hydra/_internal/utils.py in _run_app(run, multirun, mode, hydra, config_name, task_function, overrides)
    456     if mode == RunMode.RUN:
--> 457         run_and_report(
    458             lambda: hydra.run(

/databricks/python/lib/python3.8/site-packages/hydra/_internal/utils.py in run_and_report(func)
    302                 raise ex
--> 303         sys.exit(1)
    304 

SystemExit: 1

During handling of the above exception, another exception occurred:

TypeError                                 Traceback (most recent call last)
    [... skipping hidden 1 frame]

/databricks/python/lib/python3.8/site-packages/IPython/core/interactiveshell.py in showtraceback(self, exc_tuple, filename, tb_offset, exception_only, running_compiled_code)
   2052                     stb = ['An exception has occurred, use %tb to see '
   2053                            'the full traceback.\n']
-> 2054                     stb.extend(self.InteractiveTB.get_exception_only(etype,
   2055                                                                      value))
   2056                 else:

/databricks/python/lib/python3.8/site-packages/IPython/core/ultratb.py in get_exception_only(self, etype, value)
    752         value : exception value
    753        
--> 754         return ListTB.structured_traceback(self, etype, value)
    755 
    756     def show_exception_only(self, etype, evalue):

/databricks/python/lib/python3.8/site-packages/IPython/core/ultratb.py in structured_traceback(self, etype, evalue, etb, tb_offset, context)
    627             chained_exceptions_tb_offset = 0
    628             out_list = (
--> 629                 self.structured_traceback(
    630                     etype, evalue, (etb, chained_exc_ids),
    631                     chained_exceptions_tb_offset, context)

/databricks/python/lib/python3.8/site-packages/IPython/core/ultratb.py in structured_traceback(self, etype, value, tb, tb_offset, number_of_lines_of_context)
   1365         else:
   1366             self.tb = tb
-> 1367         return FormattedTB.structured_traceback(
   1368             self, etype, value, tb, tb_offset, number_of_lines_of_context)
   1369 

/databricks/python/lib/python3.8/site-packages/IPython/core/ultratb.py in structured_traceback(self, etype, value, tb, tb_offset, number_of_lines_of_context)
   1265         if mode in self.verbose_modes:
   1266             # Verbose modes need a full traceback
-> 1267             return VerboseTB.structured_traceback(
   1268                 self, etype, value, tb, tb_offset, number_of_lines_of_context
   1269             )

/databricks/python/lib/python3.8/site-packages/IPython/core/ultratb.py in structured_traceback(self, etype, evalue, etb, tb_offset, number_of_lines_of_context)
   1122         Return a nice text document describing the traceback.
   1123 
-> 1124         formatted_exception = self.format_exception_as_a_whole(etype, evalue, etb, number_of_lines_of_context,
   1125                                                                tb_offset)
   1126 

/databricks/python/lib/python3.8/site-packages/IPython/core/ultratb.py in format_exception_as_a_whole(self, etype, evalue, etb, number_of_lines_of_context, tb_offset)
   1080 
   1081 
-> 1082         last_unique, recursion_repeat = find_recursion(orig_etype, evalue, records)
   1083 
   1084         frames = self.format_records(records, last_unique, recursion_repeat)

/databricks/python/lib/python3.8/site-packages/IPython/core/ultratb.py in find_recursion(etype, value, records)
    380     # first frame (from in to out) that looks different.
    381     if not is_recursion_error(etype, value, records):
--> 382         return len(records), 0
    383 
    384     # Select filename, lineno, func_name to track frames with

TypeError: object of type 'NoneType' has no len() 

Now if I use COMPOSE API, it does work, but my sweep parameters do not get printed. For ex, in the above YAML my sweep parameter is n. N should be changing once to 5 and once to 10 in two different runs(Multiruns). But I dont see that happening

Code:

from hydra import compose, initialize_config_dir
from omegaconf import OmegaConf

def main() -> None:
with initialize_config_dir(version_base="1.3", config_dir="/Workspace/Repos/some_path/conf"):
    cfg = compose(config_name="config_test.yaml", overrides=[])
    print(OmegaConf.to_yaml(cfg))
    
if  __name__ == "__main__":
main()

Output:

experiment_name: 10-08-2023_t2
network:
  inputs: 2
  outputs: 3
  layer_size: 60
  nr_layers: 8
optimiser:
  lr: 0.001
  scheduler: exponential_lr
  iter: 5000

As you can see above the config gets printed only once without the sweep multirun parameter (n).

When I try it with decorator on my local this is the output I get

[2023-08-15 02:36:02,432][HYDRA] Launching 2 jobs locally
[2023-08-15 02:36:02,433][HYDRA]        #0 : +n=5
experiment_name: 10-08-2023_t2
network:
  inputs: 2
  outputs: 3
  layer_size: 60
  nr_layers: 8
optimiser:
  lr: 0.001
  scheduler: exponential_lr
  iter: 5000
'n': 5

[2023-08-15 02:36:02,525][HYDRA]        #1 : +n=10
experiment_name: 10-08-2023_t2
  inputs: 2
  outputs: 3
  layer_size: 60
  nr_layers: 8
optimiser:
  lr: 0.001
  scheduler: exponential_lr
  iter: 5000

As you can see above the config has run with respect to two sweep parameters, n=5 and n=10


Solution

  • I tried with .py file and called in notebook using %sh command.

    Below is your data i used.

    enter image description here

    Next, created new .py file.

    %sh
    echo  'import hydra
    from omegaconf import DictConfig, OmegaConf
    
    @hydra.main(version_base=None, config_path="/Workspace/Users/Your_folder_path/", config_name="config")
    def my_app(cfg : DictConfig) -> None:
        print(OmegaConf.to_yaml(cfg))
        
    if __name__ == "__main__":
        my_app()
    ' > /Workspace/Users/Your_folder_path/hydra_py.py
    

    Next, call it.

    %sh
    python3 /Workspace/Users/Your_folder_path/hydra_py.py
    

    Output:

    enter image description here