hypot


Namehypot JSON
Version 0.0.1 PyPI version JSON
download
home_page
SummaryHypot: A dataclass-based hyperparameter managing system
upload_time2023-05-05 07:54:41
maintainer
docs_urlNone
author
requires_python>=3.8
licenseMIT License Copyright (c) 2023 Jiseob Kim Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
keywords hyperparameter dataclass command-line
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # Hypot: A dataclass-based hyperparameter managing system

## Overview
Deep learning models are often composed of multiple networks, where each of the networks is composed of multiple layers, and the class of each layer or its hyperparameters differ by experiments. `Hypot` simplifies managing this complex hierarchy of hyperparameters utilizing the built-in `dataclass`.

The `dataclass` derives the following benefits.
* Defining a group of hyperaparameters is easy with **type annotation** support.
* Creating it is easy with the auto-defined `__init__`.
* Many IDE's (e.g., PyCharm, VSCode) support "jump to the definition".

However, difficulties for using it "as-is" in hyperparameter-managing are:
* Handling nested dataclasses is not so good.
* Parsing the strings or sys.argv to create a dataclass is not natively supported.
* Switching between multiple child dataclasses using a simple "tag" is cumbersome.

`Hypot` will handle all these difficulties for you with following advantages.
* Fast, lightweight implementation using the built-in `dataclass` and descriptors
* Minimal dependency
* Type-checking (based on annotation)
* Parsing a stringified object or YAML to create the corresponding nested dataclass
* Ability to auto-make the corresponding module (e.g., layer, network), when defined as an inner class of that module.

### Comparison with other packages
* [Hydra](https://github.com/facebookresearch/hydra): Hydra is a popular package with the same purpose. Its _structured config_ mode allows defining a config with `dataclass` as well. However, Hydra converts a config into `DictConfig` object (from another package `omegaconf`) even when it is originally defined with `dataclass`. Thus, all the operations (modifying, getting values, merging) are done with `DictConfig` and this brings the following drawbacks compared to Hypot, which uses `dataclass` object all the time.
  * `DictConfig` is not type annotated.
  * "Go to the definition" in IDE cannot be done with `DictConfig`.
  * Inheritance strcuture of configs cannot be checked.
  * Complex value interpolation is difficult or impossible to implement. In Hypot `dataclass`, it can be done using built-in `__post_init__()` function (see `examples/advanced_usage.py`).


### Etymology
Hypot stands for **"A Pot of Hyperparameters, or A Hyperparameters-Pot"**. You can put various Hyperparameters in a Pot and mix them with others as you wish.

## Quick start
### Install the package
`pip install hypot`

### Basic Usage
```python
from dataclasses import dataclass
from hypot import hypot

@dataclass
@hypot
class LayerHP:
    in_features: int
    out_features: int
    init_scale: float = 0.9
    

@dataclass
@hypot
class NetworkHP:
    num_layers: int
    layer_hp: LayerHP 


if __name__ == "__main__":
    # Hypot can be created in the same manner as dataclass.
    net_hp1 = NetworkHP(num_layers=3, layer_hp=LayerHP(64, 32))
    print(net_hp1)
    # Hypot can be also created from parsing stringified objects.
    net_hp2 = NetworkHP(num_layers="3", layer_hp=LayerHP("64", 32))
    print(net_hp2)
    # Hypot class itself can be also created from a dictionary.
    net_hp3 = NetworkHP(num_layers=3, layer_hp=dict(in_features=64, out_features=32))
    print(net_hp3)
    
```

### Command-line Usage
With the Hypot classes defined the same as above, define the main function as follows.
```python
# main.py
from hypot import hypot_main

@hypot_main()  # parses sys.argv to construct the hypot in the first argument, `net_hp`
def main(net_hp: NetworkHP):
    print(net_hp)

if __name__ == "__main__":
    main()
```
Then, in the command-line type as follows to obtain the same results as before.
`python main.py num_layers=3 layer_hp.in_features=64 layer_hp.out_features=32`


### Inheritance
Hypot can be subclassed with a **tag**.
```python
from dataclasses import dataclass

from hypot import hypot


@dataclass
@hypot
class Data:
    path: str
    batch_size: int = 4


@dataclass
@hypot
class FFHQData(Data, tag="ffhq"):
    path: str = "/path/to/FFHQ"
    meta: str = "Flicker-Faces HQ Data, containing 70k images"


@dataclass
@hypot
class FFHQDataLargeBatch(FFHQData, tag="ffhq_lg"):
    batch_size: int = 16


@dataclass
@hypot
class Model:
    data: Data
    net: NetworkHP


if __name__ == "__main__":
    model_with_ffhq = Model(
        data="ffhq", net=NetworkHP(num_layers=3, layer_hp=LayerHP(64, 32)),
    )
    print(model_with_ffhq)

    model_with_ffhq_lg = Model(
        data=dict(_tag="ffhq_lg"),  # Also can be created from dict with "_tag" key.
        net=NetworkHP(num_layers=3, layer_hp=LayerHP(64, 32)),
    )
    print(model_with_ffhq_lg)

    model_with_cifar10 = Model(
        data=dict(path="/path/to/cifar10"),
        net=NetworkHP(num_layers=3, layer_hp=LayerHP(64, 32)),
    )
    print(model_with_cifar10)
```

### Command-line Usage with Inheritance
With the Hypot classes defined the same as above, define the main function as follows.
```python
# main.py
from hypot import hypot_main

@hypot_main()  # parses sys.argv to construct the hypot in the first argument, `net_hp`
def main(model: Model):
    print(model)

if __name__ == "__main__":
    main()
```
Then, in the command-line type as follows to obtain the same results as before.
`python main.py model.data=ffhq model.net.num_layers=3 model.net.layer_hp.in_features=64 model.net.layer_hp.out_features=32`
I.e., tag can be fed in the CLI as the root argument.

### Advanced Usage (Value Interpolation)
* Please refer to `advanced_usage.py` in the `examples` directory.
* Please note that manually updating the fields of a Hypot object is prohibited. You should always use [`replace`](https://docs.python.org/3/library/dataclasses.html#dataclasses.replace) which will automatically call `__post_init__()` to correctly process the value interpolation.



### FAQ
* (Q) When creating Hypot from dict, how does it know which hypot to create? 
  * (A) Via type annotation.
* (Q) Is `typing.Union` supported? 
  * (A) Yes. But when it is a union of `str` or `dict`, there are ambiguities in parsing the stringified objects. A warning or an error will be raised in this case.
* (Q) Does tag-based creation still work when `typing.Union` is used?
  * (A) Yes. The tag search will be done over all the types in the union.
* (Q) Are `typing.List` or other generic types supported?
  * (A) Yes.
* (Q) How can I use value interpolation?
  * (A) `dataclass` provides `__post_init__()` function where you can define a .
* (Q) Why not using `typing.dataclass_transform()` in implementing Hypot?
  * (A) Because requirement of Python>=3.11 is too strict for now.

            

Raw data

            {
    "_id": null,
    "home_page": "",
    "name": "hypot",
    "maintainer": "",
    "docs_url": null,
    "requires_python": ">=3.8",
    "maintainer_email": "",
    "keywords": "hyperparameter,dataclass,command-line",
    "author": "",
    "author_email": "Jiseob Kim <justjest@gmail.com>",
    "download_url": "https://files.pythonhosted.org/packages/8a/4f/508ff5adffa42b25fbb47d63cec3d9834902f97ad0c9228bceae8b84ebb8/hypot-0.0.1.tar.gz",
    "platform": null,
    "description": "# Hypot: A dataclass-based hyperparameter managing system\n\n## Overview\nDeep learning models are often composed of multiple networks, where each of the networks is composed of multiple layers, and the class of each layer or its hyperparameters differ by experiments. `Hypot` simplifies managing this complex hierarchy of hyperparameters utilizing the built-in `dataclass`.\n\nThe `dataclass` derives the following benefits.\n* Defining a group of hyperaparameters is easy with **type annotation** support.\n* Creating it is easy with the auto-defined `__init__`.\n* Many IDE's (e.g., PyCharm, VSCode) support \"jump to the definition\".\n\nHowever, difficulties for using it \"as-is\" in hyperparameter-managing are:\n* Handling nested dataclasses is not so good.\n* Parsing the strings or sys.argv to create a dataclass is not natively supported.\n* Switching between multiple child dataclasses using a simple \"tag\" is cumbersome.\n\n`Hypot` will handle all these difficulties for you with following advantages.\n* Fast, lightweight implementation using the built-in `dataclass` and descriptors\n* Minimal dependency\n* Type-checking (based on annotation)\n* Parsing a stringified object or YAML to create the corresponding nested dataclass\n* Ability to auto-make the corresponding module (e.g., layer, network), when defined as an inner class of that module.\n\n### Comparison with other packages\n* [Hydra](https://github.com/facebookresearch/hydra): Hydra is a popular package with the same purpose. Its _structured config_ mode allows defining a config with `dataclass` as well. However, Hydra converts a config into `DictConfig` object (from another package `omegaconf`) even when it is originally defined with `dataclass`. Thus, all the operations (modifying, getting values, merging) are done with `DictConfig` and this brings the following drawbacks compared to Hypot, which uses `dataclass` object all the time.\n  * `DictConfig` is not type annotated.\n  * \"Go to the definition\" in IDE cannot be done with `DictConfig`.\n  * Inheritance strcuture of configs cannot be checked.\n  * Complex value interpolation is difficult or impossible to implement. In Hypot `dataclass`, it can be done using built-in `__post_init__()` function (see `examples/advanced_usage.py`).\n\n\n### Etymology\nHypot stands for **\"A Pot of Hyperparameters, or A Hyperparameters-Pot\"**. You can put various Hyperparameters in a Pot and mix them with others as you wish.\n\n## Quick start\n### Install the package\n`pip install hypot`\n\n### Basic Usage\n```python\nfrom dataclasses import dataclass\nfrom hypot import hypot\n\n@dataclass\n@hypot\nclass LayerHP:\n    in_features: int\n    out_features: int\n    init_scale: float = 0.9\n    \n\n@dataclass\n@hypot\nclass NetworkHP:\n    num_layers: int\n    layer_hp: LayerHP \n\n\nif __name__ == \"__main__\":\n    # Hypot can be created in the same manner as dataclass.\n    net_hp1 = NetworkHP(num_layers=3, layer_hp=LayerHP(64, 32))\n    print(net_hp1)\n    # Hypot can be also created from parsing stringified objects.\n    net_hp2 = NetworkHP(num_layers=\"3\", layer_hp=LayerHP(\"64\", 32))\n    print(net_hp2)\n    # Hypot class itself can be also created from a dictionary.\n    net_hp3 = NetworkHP(num_layers=3, layer_hp=dict(in_features=64, out_features=32))\n    print(net_hp3)\n    \n```\n\n### Command-line Usage\nWith the Hypot classes defined the same as above, define the main function as follows.\n```python\n# main.py\nfrom hypot import hypot_main\n\n@hypot_main()  # parses sys.argv to construct the hypot in the first argument, `net_hp`\ndef main(net_hp: NetworkHP):\n    print(net_hp)\n\nif __name__ == \"__main__\":\n    main()\n```\nThen, in the command-line type as follows to obtain the same results as before.\n`python main.py num_layers=3 layer_hp.in_features=64 layer_hp.out_features=32`\n\n\n### Inheritance\nHypot can be subclassed with a **tag**.\n```python\nfrom dataclasses import dataclass\n\nfrom hypot import hypot\n\n\n@dataclass\n@hypot\nclass Data:\n    path: str\n    batch_size: int = 4\n\n\n@dataclass\n@hypot\nclass FFHQData(Data, tag=\"ffhq\"):\n    path: str = \"/path/to/FFHQ\"\n    meta: str = \"Flicker-Faces HQ Data, containing 70k images\"\n\n\n@dataclass\n@hypot\nclass FFHQDataLargeBatch(FFHQData, tag=\"ffhq_lg\"):\n    batch_size: int = 16\n\n\n@dataclass\n@hypot\nclass Model:\n    data: Data\n    net: NetworkHP\n\n\nif __name__ == \"__main__\":\n    model_with_ffhq = Model(\n        data=\"ffhq\", net=NetworkHP(num_layers=3, layer_hp=LayerHP(64, 32)),\n    )\n    print(model_with_ffhq)\n\n    model_with_ffhq_lg = Model(\n        data=dict(_tag=\"ffhq_lg\"),  # Also can be created from dict with \"_tag\" key.\n        net=NetworkHP(num_layers=3, layer_hp=LayerHP(64, 32)),\n    )\n    print(model_with_ffhq_lg)\n\n    model_with_cifar10 = Model(\n        data=dict(path=\"/path/to/cifar10\"),\n        net=NetworkHP(num_layers=3, layer_hp=LayerHP(64, 32)),\n    )\n    print(model_with_cifar10)\n```\n\n### Command-line Usage with Inheritance\nWith the Hypot classes defined the same as above, define the main function as follows.\n```python\n# main.py\nfrom hypot import hypot_main\n\n@hypot_main()  # parses sys.argv to construct the hypot in the first argument, `net_hp`\ndef main(model: Model):\n    print(model)\n\nif __name__ == \"__main__\":\n    main()\n```\nThen, in the command-line type as follows to obtain the same results as before.\n`python main.py model.data=ffhq model.net.num_layers=3 model.net.layer_hp.in_features=64 model.net.layer_hp.out_features=32`\nI.e., tag can be fed in the CLI as the root argument.\n\n### Advanced Usage (Value Interpolation)\n* Please refer to `advanced_usage.py` in the `examples` directory.\n* Please note that manually updating the fields of a Hypot object is prohibited. You should always use [`replace`](https://docs.python.org/3/library/dataclasses.html#dataclasses.replace) which will automatically call `__post_init__()` to correctly process the value interpolation.\n\n\n\n### FAQ\n* (Q) When creating Hypot from dict, how does it know which hypot to create? \n  * (A) Via type annotation.\n* (Q) Is `typing.Union` supported? \n  * (A) Yes. But when it is a union of `str` or `dict`, there are ambiguities in parsing the stringified objects. A warning or an error will be raised in this case.\n* (Q) Does tag-based creation still work when `typing.Union` is used?\n  * (A) Yes. The tag search will be done over all the types in the union.\n* (Q) Are `typing.List` or other generic types supported?\n  * (A) Yes.\n* (Q) How can I use value interpolation?\n  * (A) `dataclass` provides `__post_init__()` function where you can define a .\n* (Q) Why not using `typing.dataclass_transform()` in implementing Hypot?\n  * (A) Because requirement of Python>=3.11 is too strict for now.\n",
    "bugtrack_url": null,
    "license": "MIT License  Copyright (c) 2023 Jiseob Kim  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.  THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.",
    "summary": "Hypot: A dataclass-based hyperparameter managing system",
    "version": "0.0.1",
    "project_urls": {
        "repository": "https://github.com/delta-func/hypot"
    },
    "split_keywords": [
        "hyperparameter",
        "dataclass",
        "command-line"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "459c2134c9d2ed9627c39d3a74914d0e93018a59b7ca0973b18ed0e081f64fe2",
                "md5": "86ea2d2c3ad8936d396f72687bd03c92",
                "sha256": "261115fe5364270ebca6f007528f6fcde990c0bf5c3b5cecf4bd5177d0e66e35"
            },
            "downloads": -1,
            "filename": "hypot-0.0.1-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "86ea2d2c3ad8936d396f72687bd03c92",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.8",
            "size": 10163,
            "upload_time": "2023-05-05T07:53:53",
            "upload_time_iso_8601": "2023-05-05T07:53:53.630452Z",
            "url": "https://files.pythonhosted.org/packages/45/9c/2134c9d2ed9627c39d3a74914d0e93018a59b7ca0973b18ed0e081f64fe2/hypot-0.0.1-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "8a4f508ff5adffa42b25fbb47d63cec3d9834902f97ad0c9228bceae8b84ebb8",
                "md5": "57b518b4e023becec6c6064f00ad4bf2",
                "sha256": "a58e1b084a90f9fa8a35ca1bcac5bff8697aefea2c6ce0198132dc2cb229071d"
            },
            "downloads": -1,
            "filename": "hypot-0.0.1.tar.gz",
            "has_sig": false,
            "md5_digest": "57b518b4e023becec6c6064f00ad4bf2",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.8",
            "size": 11881,
            "upload_time": "2023-05-05T07:54:41",
            "upload_time_iso_8601": "2023-05-05T07:54:41.682238Z",
            "url": "https://files.pythonhosted.org/packages/8a/4f/508ff5adffa42b25fbb47d63cec3d9834902f97ad0c9228bceae8b84ebb8/hypot-0.0.1.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2023-05-05 07:54:41",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "delta-func",
    "github_project": "hypot",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": false,
    "requirements": [],
    "lcname": "hypot"
}
        
Elapsed time: 0.06067s