|
| 1 | +.. _config_tutorial_label: |
| 2 | + |
| 3 | +================= |
| 4 | +Configs Deep-Dive |
| 5 | +================= |
| 6 | + |
| 7 | +This tutorial will guide you through writing configs for running recipes and |
| 8 | +designing params for custom recipes. |
| 9 | + |
| 10 | +.. grid:: 2 |
| 11 | + |
| 12 | + .. grid-item-card:: :octicon:`mortar-board;1em;` What you will learn |
| 13 | + |
| 14 | + * How to write a YAML config and run a recipe with it |
| 15 | + * How to create a params dataclass for custom recipe |
| 16 | + * How to effectively use configs, CLI overrides, and dataclasses for running recipes |
| 17 | + |
| 18 | + .. grid-item-card:: :octicon:`list-unordered;1em;` Prerequisites |
| 19 | + |
| 20 | + * Be familiar with the :ref:`overview of TorchTune<overview_label>` |
| 21 | + * Make sure to :ref:`install TorchTune<install_label>` |
| 22 | + * Understand the :ref:`fundamentals of recipes<recipe_deepdive>` |
| 23 | + |
| 24 | + |
| 25 | +Where do parameters live? |
| 26 | +------------------------- |
| 27 | + |
| 28 | +There are two primary entry points for you to configure parameters: **configs** and |
| 29 | +**CLI overrides**. Configs are YAML files that define all the |
| 30 | +parameters needed to run a recipe within a single location. These can be overridden on the |
| 31 | +command-line for quick changes and experimentation without modifying the config. |
| 32 | + |
| 33 | +If you are planning to make a custom recipe, you will need to become familiar |
| 34 | +with the **recipe dataclass**, which collects all of your arguments from config and |
| 35 | +CLI, and passes it into the recipe itself. Here, we will discuss all three concepts: |
| 36 | +**configs**, **CLI**, and **dataclasses**. |
| 37 | + |
| 38 | + |
| 39 | +Recipe dataclasses |
| 40 | +------------------ |
| 41 | + |
| 42 | +Parameters should be organized in a single dataclass that is passed into the recipe. |
| 43 | +This serves as a single source of truth for the details of a fine-tuning run that can be easily validated in code and shared with collaborators for reproducibility. |
| 44 | + |
| 45 | +.. code-block:: python |
| 46 | +
|
| 47 | + class FullFinetuneParams: |
| 48 | + # Model |
| 49 | + model: str = "" |
| 50 | + model_checkpoint: str = "" |
| 51 | +
|
| 52 | +In the dataclass, all fields should have defaults assigned to them. |
| 53 | +If a reasonable value cannot be assigned or it is a required argument, |
| 54 | +use the null value for that data type as the default and ensure that it is set |
| 55 | +by the user in the :code:`__post_init__` (see :ref:`Parameter Validation<parameter_validation_label>`). |
| 56 | +The dataclass should go in the :code:`recipes/params/` folder and the name of |
| 57 | +the file should match the name of the recipe file you are creating. |
| 58 | + |
| 59 | +In general, you should expose the minimal amount of parameters you need to run and experiment with your recipes. |
| 60 | +Exposing an excessive number of parameters will lead to bloated configs, which are more error prone, harder to read, and harder to manage. |
| 61 | +On the other hand, hardcoding all parameters will prevent quick experimentation without a code change. Only parametrize what is needed. |
| 62 | + |
| 63 | +To link the dataclass object with config and CLI parsing, |
| 64 | +you can use the :class:`~torchtune.utils.argparse.TuneArgumentParser` object and |
| 65 | +funnel the parsed arguments into your dataclass. |
| 66 | + |
| 67 | +.. code-block:: python |
| 68 | +
|
| 69 | + if __name__ == "__main__": |
| 70 | + parser = utils.TuneArgumentParser( |
| 71 | + description=FullFinetuneParams.__doc__, |
| 72 | + formatter_class=argparse.RawDescriptionHelpFormatter, |
| 73 | + ) |
| 74 | + # Get user-specified args from config and CLI and create params for recipe |
| 75 | + args, _ = parser.parse_known_args() |
| 76 | + args = vars(args) |
| 77 | + params = FullFinetuneParams(**args) |
| 78 | +
|
| 79 | + logger = utils.get_logger("DEBUG") |
| 80 | + logger.info(msg=f"Running finetune_llm.py with parameters {params}") |
| 81 | +
|
| 82 | + recipe(params) |
| 83 | +
|
| 84 | +.. _parameter_validation_label: |
| 85 | + |
| 86 | +Parameter validation |
| 87 | +-------------------- |
| 88 | +To validate arguments for your dataclass and recipe, use the :code:`__post_init__` method to house any checks and raised exceptions. |
| 89 | + |
| 90 | +.. code-block:: python |
| 91 | +
|
| 92 | + def __post_init__(self): |
| 93 | + for param in fields(self): |
| 94 | + if getattr(self, param.name) == "": |
| 95 | + raise TypeError(f"{param.name} needs to be specified") |
| 96 | +
|
| 97 | +Writing configs |
| 98 | +--------------- |
| 99 | +Once you've set up a recipe and its params, you need to create a config to run it. |
| 100 | +Configs serve as the primary entry point for running recipes in TorchTune. They are |
| 101 | +expected to be YAML files and simply list out values for parameters you want to define |
| 102 | +for a particular run. The config parameters should be a subset of the dataclass parameters; |
| 103 | +there should not be any new fields that are not already in the dataclass. Any parameters that |
| 104 | +are not specified in the config will take on the default value defined in the dataclass. |
| 105 | + |
| 106 | +.. code-block:: yaml |
| 107 | +
|
| 108 | + dataset: alpaca |
| 109 | + seed: null |
| 110 | + shuffle: True |
| 111 | + model: llama2_7b |
| 112 | + ... |
| 113 | +
|
| 114 | +Command-line overrides |
| 115 | +---------------------- |
| 116 | +To enable quick experimentation, you can specify override values to parameters in your config |
| 117 | +via the :code:`tune` command. These should be specified with the flag :code:`--override k1=v1 k2=v2 ...` |
| 118 | + |
| 119 | +For example, to run the :code:`full_finetune` recipe with custom model and tokenizer directories and using GPUs, you can provide overrides: |
| 120 | + |
| 121 | +.. code-block:: bash |
| 122 | +
|
| 123 | + tune full_finetune --config alpaca_llama2_full_finetune --override model_directory=/home/my_model_checkpoint tokenizer_directory=/home/my_tokenizer_checkpoint device=cuda |
| 124 | +
|
| 125 | +The order of overrides from these parameter sources is as follows, with highest precedence first: CLI, Config, Dataclass defaults |
| 126 | + |
| 127 | + |
| 128 | +Testing configs |
| 129 | +--------------- |
| 130 | +If you plan on contributing your config to the repo, we recommend adding it to the testing suite. TorchTune has testing for every config added to the library, namely ensuring that it instantiates the dataclass and runs the recipe correctly. |
| 131 | + |
| 132 | +To add your config to this test suite, simply update the dictionary in :code:`recipes/tests/configs/test_configs`. |
| 133 | + |
| 134 | +.. code-block:: python |
| 135 | +
|
| 136 | + config_to_params = { |
| 137 | + os.path.join(ROOT_DIR, "alpaca_llama2_full_finetune.yaml"): FullFinetuneParams, |
| 138 | + ..., |
| 139 | + } |
| 140 | +
|
| 141 | +Linking recipes and configs with :code:`tune` |
| 142 | +--------------------------------------------- |
| 143 | + |
| 144 | +In order to run your custom recipe and configs with :code:`tune`, you must update the :code:`_RECIPE_LIST` |
| 145 | +and :code:`_CONFIG_LISTS` in :code:`recipes/__init__.py` |
| 146 | + |
| 147 | +.. code-block:: python |
| 148 | +
|
| 149 | + _RECIPE_LIST = ["full_finetune", "lora_finetune", "alpaca_generate", ...] |
| 150 | + _CONFIG_LISTS = { |
| 151 | + "full_finetune": ["alpaca_llama2_full_finetune"], |
| 152 | + "lora_finetune": ["alpaca_llama2_lora_finetune"], |
| 153 | + "alpaca_generate": [], |
| 154 | + "<your_recipe>": ["<your_config"], |
| 155 | + } |
| 156 | +
|
| 157 | +Running your recipe |
| 158 | +------------------- |
| 159 | +If everything is set up correctly, you should be able to run your recipe just like the existing library recipes using the :code:`tune` command: |
| 160 | + |
| 161 | +.. code-block:: bash |
| 162 | +
|
| 163 | + tune <recipe> --config <config> --override ... |
0 commit comments