{"id":15175868,"url":"https://github.com/sea-snell/micro_config","last_synced_at":"2025-10-02T19:31:40.927Z","repository":{"id":37246788,"uuid":"495616912","full_name":"Sea-Snell/micro_config","owner":"Sea-Snell","description":"an opinionated config framework for deep learning based on hierarchical python dataclasses","archived":false,"fork":false,"pushed_at":"2022-07-10T01:06:45.000Z","size":4656,"stargazers_count":9,"open_issues_count":0,"forks_count":0,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-09-03T16:08:53.264Z","etag":null,"topics":["config","dataclasses","deep-learning","python","pytorch"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Sea-Snell.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2022-05-24T00:33:24.000Z","updated_at":"2024-09-15T17:29:49.000Z","dependencies_parsed_at":"2022-08-18T20:20:19.529Z","dependency_job_id":null,"html_url":"https://github.com/Sea-Snell/micro_config","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/Sea-Snell/micro_config","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Sea-Snell%2Fmicro_config","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Sea-Snell%2Fmicro_config/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Sea-Snell%2Fmicro_config/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Sea-Snell%2Fmicro_config/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Sea-Snell","download_url":"https://codeload.github.com/Sea-Snell/micro_config/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Sea-Snell%2Fmicro_config/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":278061428,"owners_count":25923514,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-02T02:00:08.890Z","response_time":67,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["config","dataclasses","deep-learning","python","pytorch"],"created_at":"2024-09-27T12:43:21.438Z","updated_at":"2025-10-02T19:31:39.686Z","avatar_url":"https://github.com/Sea-Snell.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# micro_config.py\n*an opinionated python dataclass config framework for deep learning*\n\n\n\nI hope this approach to configurations can make your life easier, but if it doesn't, please submit a pull request or an issue and I'll see what I can do. This config system is certaintly under development, so open to any new ideas or suggestions.\n\n# Installation\n\npip install:\n\n``` shell\npip install micro-config\n```\n\nor install from source:\n\n\u003e Place `micro_config.py` at the root of your project.\n\n# Repo Guide\n\nThe config framework is defined in `micro_config.py`.\n\nThe rest of the repo provides a demo for how one might actually want to use `micro_config.py` in a pytorch deep learning project. Specifically, I implement transformer language model training on wikitext in pytorch. For another example of how to use `micro_config.py` in jax (flax or haiku), see this [jax_v_pytorch repo](https://github.com/Sea-Snell/jax_v_pytorch/tree/main).\n\nTo run the demo:\n1. navigate to the root directory\n2. `pip install -r requirements.txt`\n3. `export PYTHONPATH=\"$PWD\"`\n4. `cd scripts`\n5. `python train_lm.py`\n\nOptionally you can define commandline arguments to `train_lm.py` like:\n``` shell\npython train_lm.py epochs=1 bsize=16 model.transformer_config.hidden_dim=256\n```\n\noverview of demo project code:\n* `scripts/train_lm.py` defines the training configuration and script execution.\n* `base_config.py` defines config schema and defaults for all main config objects: `WikiDataConfig`, `TransformerConfig`, `LMModelConfig`, `AdamWConfig`\n* `general_train_loop.py` defines the config schema and script for training models.\n* `src/` defines all of the core demo project code.\n\n# Quick Start / Walkthrough\n\n*Most demo code in this section is adopted from the demo project provided in the repo.*\n\n## Python dataclasses provide a more natural and flexible config definition interface than `.yaml` files.\n\n* All config schema should be defined as an instance of `ConfigScript` or `ConfigScriptModel` and include a `@dataclass` decorator\n* ConfigScripts firstly define a parameter schema and optionally default config values.\n\nFor example, a simple dataset object configuration:\n``` python\nfrom dataclasses import dataclass, adsict\nfrom micro_config import ConfigScript\n\n# data config\n@dataclass\nclass WikiDataConfig(ConfigScript):\n    f_path: str='data/wikitext-2-raw/wiki.train.raw'\n    max_len: int=256\n```\n\n## `ConfigScript`s load associated objects or functions.\n* To do this, all `ConfigScript`s implement `unroll(self, metaconfig: MetaConfig)`.\n* The `metaconfig` parameter is another dataclass which specifies configs for the config framework. Feel free to subclass `MetaConfig`.\n\nFor example, loading the dataset from the config:\n``` python\nfrom dataclasses import dataclass, adsict\nfrom micro_config import ConfigScript, MetaConfig\nfrom src.data import WikitextDataset\nimport torch\nimport os\n\n# data config\n@dataclass\nclass WikiDataConfig(ConfigScript):\n    f_path: str='data/wikitext-2-raw/wiki.train.raw'\n    max_len: int=256\n\n    def unroll(self, metaconfig: MetaConfig):\n        # metaconfig.convert_path converts paths reletive to metaconfig.project_root into absolute paths\n        return WikitextDataset(metaconfig.convert_path(self.f_path), self.max_len)\n\nif __name__ == \"__main__\":\n    metaconfig = MetaConfig(project_root=os.path.dirname(__file__), \n                            verbose=True)\n    \n    data_config = WikiDataConfig(max_len=512)\n    data = data_config.unroll(metaconfig)\n```\n\n## Configurations can be defined hierarchically.\n* You can define `ConfigScripts` as paremeters of other `ConfigScripts`\n* You can define lists or dictionaries of `ConfigScript`s as parameters of a `ConfigScript` by wrapping your list or dict in `ConfigScriptList` or `ConfigScriptDict` respectively.\n\nFor example, the LM model config below defines `ConfigScript`s for both a dataset and a `transformer_config` as parameters:\n``` python\nfrom micro_config import MetaConfig\nfrom base_configs import ConfigScriptModel\nfrom dataclasses import field\nfrom src.lm import LMModel\nimport os\n\n# model config\n@dataclass\nclass LMModelConfig(ConfigScriptModel):\n    dataset: WikiDataConfig=field(default_factory=lambda: WikiDataConfig())\n    transformer_config: TransformerConfig=field(default_factory=lambda: TransformerConfig(max_len=256))\n\n    def unroll(self, metaconfig: MetaConfig):\n        dataset = self.dataset.unroll(metaconfig)\n        transformer_config = self.transformer_config.unroll(metaconfig)\n        return LMModel(dataset, transformer_config, self.device)\n\nif __name__ == \"__main__\":\n    metaconfig = MetaConfig(project_root=os.path.dirname(__file__), \n                            verbose=True)\n\n    model_config = LMModelConfig(\n        checkpoint_path=None, \n        strict_load=True, \n        device='cpu', \n        dataset=WikiDataConfig(f_path='data/wikitext-2-raw/wiki.train.raw', max_len=256), \n        transformer_config=TransformerConfig(\n            max_length=256, \n            heads=12, \n            hidden_dim=768, \n            attn_dim=64, \n            intermediate_dim=3072, \n            num_blocks=12, \n            dropout=0.1\n        )\n    )\n    model = model_config.unroll(metaconfig)\n```\n\n`ConfigScriptModel` (not provided with `micro_config` out of the box), as used above, is a subclass of `ConfigScript` which defines some default functionality for loading a pytorch module returned by unroll and placing it on a specified device. You can look inside `base_configs.py` (or in the [jax_v_pytorch repo](https://github.com/Sea-Snell/jax_v_pytorch/tree/main)) to see examples of how to implement special functionality like this.\n\n## Configs and scripts are unified: a config is to a script as a script is to a config.\n* `unroll(self, metaconfig: MetaConfig)` can not only be used to load objects, but also to define script logic.\n\nFor example, let's define a simple configurable training loop:\n``` python\nfrom src.utils import combine_logs\nfrom micro_config import ConfigScript, MetaConfig\nfrom base_configs import ConfigScriptModel\n\n@dataclass\nclass TrainLoop(ConfigScript):\n    train_dataset: ConfigScript\n    eval_dataset: ConfigScript\n    model: ConfigScriptModel\n    optim: ConfigScript\n    epochs: int=10\n    bsize: int=32\n    \n    def unroll(self, metaconfig: MetaConfig):\n        print('using config:', asdict(self))\n        device = metaconfig.device\n        train_dataset = self.train_dataset.unroll(metaconfig)\n        eval_dataset = self.eval_dataset.unroll(metaconfig)\n        model = self.model.unroll(metaconfig)\n        model.train()\n        train_dataloader = DataLoader(train_dataset, batch_size=self.bsize)\n        eval_dataloader = DataLoader(eval_dataset, batch_size=self.bsize)\n        optim = self.optim.unroll(metaconfig)(model)\n        for epoch in range(epochs):\n            for x in tqdm(train_dataloader):\n                loss, logs = model.get_loss(x.to(device))\n                optim.zero_grad()\n                loss.backward()\n                optim.step()\n                model.eval()\n                val_x = next(iter(eval_dataloader))\n                _, val_logs = model.get_loss(val_x.to(device))\n                out_log = print({'train': combine_logs([logs]), 'val': combine_logs([val_logs]), 'step': (step+1)})\n                model.train()\n        return model\n```\n\n## Objects returned by `unroll(self, metaconfig: MetaConfig)` respect the reference structure of the config hierarchy.\n\n* If the same config object is referenced multiple times in a config hierarchy, the object's `unroll(self, metaconfig: MetaConfig)` method will only be called once and its output cached, subsequent calls will return the cached output. If you don't want this caching behavior, you can subclass `ConfigScriptNoCache` instead.\n\nFor example, `train_dataset` is referenced twice in `train_config_script`:\n``` python\nimport torch\nimport os\n\ntrain_dataset = WikiDataConfig(f_path='data/wikitext-2-raw/wiki.train.raw', max_len=256)\neval_dataset = WikiDataConfig(f_path='data/wikitext-2-raw/wiki.valid.raw', max_len=256)\n\nmodel = LMModelConfig(\n            checkpoint_path=None, \n            strict_load=True, \n            device='cpu', \n            dataset=train_dataset, \n            transformer_config=TransformerConfig(\n                max_length=256, \n                heads=12, \n                hidden_dim=768, \n                attn_dim=64, \n                intermediate_dim=3072, \n                num_blocks=12, \n                dropout=0.1\n            )\n        )\n\ntrain_config_script = TrainLoop(\n    train_dataset=train_dataset, \n    eval_dataset=eval_dataset, \n    model=model, \n    optim=AdamWConfig(lr=1e-4, weight_decay=0.01), \n    epochs=10, \n    bsize=16, \n)\n\nif __name__ == \"__main__\":\n    metaconfig = MetaConfig(project_root=os.path.dirname(__file__), \n                            verbose=True)\n    # run the script\n    train_config_script.unroll(metaconfig)\n```\n\nThe dataset object configured by `train_dataset` will only be loaded once in the above hiararchy, even though both `LMModelConfig` and `TrainLoop` take it in as input.\n\n## A method for parsing commandline args is provided.\n\n* `parse_args(config)` parses the command line arguments into a dictionary\n* `deep_replace(config, **kwargs)` implements a nested version of the standard `dataclasses.replace` function\n\n``` python\nfrom micro_config import parse_args, deep_replace, MetaConfig\nimport os\n\nif __name__ == \"__main__\":\n    metaconfig = MetaConfig(project_root=os.path.dirname(__file__), \n                            verbose=True)\n    train_config_script = deep_replace(train_config_script, **parse_args())\n    # run the script\n    train_config_script.unroll(metaconfig)\n```\n\nTo edit any arguments in the hierarchy through the commandline, call the script like so:\n\n``` shell\npython train_lm.py epochs=1 bsize=16 model.transformer_config.hidden_dim=256\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsea-snell%2Fmicro_config","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsea-snell%2Fmicro_config","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsea-snell%2Fmicro_config/lists"}