Skip to content

Keep the elasticity batch overrides out of the caller's config dict - #8329

Open
alanhuangyoo wants to merge 1 commit into
deepspeedai:masterfrom
alanhuangyoo:fix/elasticity-writes-into-caller-config
Open

Keep the elasticity batch overrides out of the caller's config dict#8329
alanhuangyoo wants to merge 1 commit into
deepspeedai:masterfrom
alanhuangyoo:fix/elasticity-writes-into-caller-config

Conversation

@alanhuangyoo

Copy link
Copy Markdown
Contributor

DeepSpeedConfig keeps the dict it is handed by reference:

if isinstance(config, dict):
    self._param_dict = config

#8289 established that parsing must not write back into it — the caller owns that dict and may reuse it after initialization.

The elasticity branch still does, two lines above the comment that says otherwise:

        self._param_dict[TRAIN_BATCH_SIZE] = final_batch_size
        self._param_dict[TRAIN_MICRO_BATCH_SIZE_PER_GPU] = micro_batch_size
        self._param_dict[GRADIENT_ACCUMULATION_STEPS] = gradient_accu_steps

    # Pass a copy so that user json is unmodified, e.g. for logging
    self._initialize_params(copy.copy(self._param_dict))

A caller that enables elasticity gets three keys back that it never set. print_user_config() dumps self._param_dict, so it then reports them as though the user had written them.

The elasticity path also forbids those keys in the input unless ignore_non_elastic_batch_info is set:

One or more batch related parameters were found in your ds_config (...).
These parameters *will not be used* since elastic training is enabled ...

so a config that was rejected on the first pass would be accepted on a re-parse of the same dict, since the second time around the keys are there.

The fix

Collect the overrides and apply them to the copy. All three are top-level keys, so the existing shallow copy keeps them off the caller's dict.

Test

config_dict = {"elasticity": {"enabled": True, "max_train_batch_size": 4,
                              "micro_batch_sizes": [1, 2], "min_gpus": 1, "max_gpus": 4,
                              "min_time": 0, "version": 0.1,
                              "ignore_non_elastic_batch_info": True}}
keys_before = set(config_dict)
ds_config = DeepSpeedConfig(config_dict)

before

caller dict gained: ['gradient_accumulation_steps', 'train_batch_size', 'train_micro_batch_size_per_gpu']
parsed:             train_batch_size=4  micro=2  gas=2

after

caller dict gained: nothing
parsed:             train_batch_size=4  micro=2  gas=2

Same parsed values, so this only removes the write-back.

Added test_elasticity_leaves_caller_config_untouched next to #8289's test_max_grad_norm_leaves_caller_config_untouched. It fails on master with

AssertionError: assert {'elasticity', 'train_batch_size', 'train_micro_batch_size_per_gpu',
                        'gradient_accumulation_steps'} == {'elasticity'}

and passes with the fix.

tests/unit/runtime/test_ds_config_dict.py   27 passed, 5 skipped
tests/unit/elasticity/test_elastic.py       23 passed, 3 skipped
yapf --diff / flake8                        clean

DeepSpeedConfig stores the dict it is handed by reference, and deepspeedai#8289
established that parsing must not write back into it -- the caller owns
that dict and may reuse it afterwards.

The elasticity branch still does, two lines above the comment that says
otherwise: it assigns train_batch_size, train_micro_batch_size_per_gpu
and gradient_accumulation_steps into self._param_dict before the copy is
taken. A caller that passes a config with elasticity enabled gets three
keys back that it never set, and print_user_config() then reports them
as though the user had.

Collect the overrides and apply them to the copy instead. All three are
top-level keys, so the existing shallow copy is enough to keep them off
the caller's dict, and the parsed values are unchanged.

Signed-off-by: alanhuangyoo <alanhuangyoo@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant