{ "info": { "author": "Max Kochurov", "author_email": "maxim.v.kochurov@gmail.com", "bugtrack_url": null, "classifiers": [], "description": "Experiment Manager (exman)\n==========================\n\nSimple and minimalistic utility to manage many experiments runs and\ncustom analysis of results\n\nWhy another custom solution?\n----------------------------\n\nMy job is to do research in Deep Learning and I have dozens of different\nexperiments. Testing one hypothesis usually required several runs over\nparameter grid. Plotting and visualizing results is often ad-hoc and\nupdating code producing output is a kind of overhead. Instead I decided\nto collect all results in Jupyter notebook and create plots kind of\n``interest ~ parameters``. As I said, plotting that is a separate task\nalmost every time. Such tools as\n`ModelDB `__ provide you with simple\nvisualizations so that they can be easily aggregated for model\ncomparison. Testing a hypothesis is not about model comparison and thus\nrequires special treatment.\n\nVisualizing results became a kind of pain, you had to remember a mapping\n``parameters -> results``, separating results into different folders\nmade even more mess. I had really bad experience in visualizations. I\ngot that all I need was to iterate over folder with results and apply\nthe same function to it.\n\nInstallation\n------------\n\n.. code:: bash\n\n pip install -U git+https://github.com/ferrine/exman.git#egg=exman\n # or\n pip install exman\n\nSimple Start\n------------\n\nSimple drop in replacement of standard ``argparse.ArgumentParser``\n\n.. code:: python\n\n #file: main.py\n import exman\n # you should always use `exman.simpleroot(__file__)` unless you want another dir\n parser = exman.ExParser(root=exman.simpleroot(__file__)) # `root = ./exman` relative to the main file\n parser.add_argument(...)\n\nYou then just add arguments as you did before without any change.\n\nBest Practices\n--------------\n\nError Handling in main\n~~~~~~~~~~~~~~~~~~~~~~\n\nSince 0.0.3 you can use the following context manager. If ``main()``\nfunction fails it will be moved to ``exman/fails``\n\n.. code:: python\n\n import exman\n # you should always use `exman.simpleroot(__file__)` unless you want another dir\n parser = exman.ExParser(root=exman.simpleroot(__file__)) # `root = ./exman` relative to the main file\n parser.add_argument(...)\n ...\n if __name__ == '__main__':\n args = parser.parse_args()\n with args.safe_experiment:\n # do your stuff\n main(args)\n\n\nKeep Your Repository Clean\n~~~~~~~~~~~~~~~~~~~~~~~~~~\nTo avoid non reproducible results you can ensure you have commited all changes. Exman will take care and will log\n``hash`` for the commit and ``diff`` if any. To use these features you should hint the parser with the repo.\n\n.. code:: python\n\n import exman\n\n parser = exman.ExParser(root=exman.simpleroot(__file__), git=True)\n # less fragile solution, but works only locally\n parser = exman.ExParser(root=exman.simpleroot(__file__), git=\"/abs/path/to/repo\")\n # an ok solution, if you are sure in the relative path\n parser = exman.ExParser(root=exman.simpleroot(__file__),\n git=os.path.join(os.path.dirname(__file__), \"relative\", \"path\", \"goes\", \"here\"),\n git_assert_clean=True # run assertion check before each run. False by default.\n )\n\nIn cli of your favorite experiment you can skip the assertion if you want to:\n\n.. code:: bash\n\n python train.py --git-dirty --other-args\n\nOptional Parameters\n~~~~~~~~~~~~~~~~~~~\n\nTo avoid issues in `reproducing experiments <#rerunning-experiment>`__\nyou should consider using ``exman.optional(type)`` for optional\narguments\n\n.. code:: python\n\n import exman\n # you should always use `exman.simpleroot(__file__)` unless you want another dir\n parser = exman.ExParser(root=exman.simpleroot(__file__)) # `root = ./exman` relative to the main file\n parser.add_argument('--myarg', type=exman.optional(int))\n\nValidators\n~~~~~~~~~~\n\nIn simple argparser you cant easily validate multiple arguments, it is\neasy in Exman. You can create an informative error message\n\n.. code:: python\n\n import exman\n # you should always use `exman.simpleroot(__file__)` unless you want another dir\n parser = exman.ExParser(root=exman.simpleroot(__file__)) # `root = ./exman` relative to the main file\n parser.add_argument(...)\n # here `p` stands for initial namespace parsed from arguments\n parser.register_validator(lambda p: p.arg1 != p.arg2 or p.arg3 == p.arg4,\n # next line will be autoformatted for you using .format\n 'You have provided wrong set of arguments: {arg1}, {arg2}, {arg3}, {arg4}')\n\nAdvanced validators can raise `exman.ArgumentError` that contains a better message than the one in validators function\n\nMarry Pandas with Exman\n~~~~~~~~~~~~~~~~~~~~~~~\n\nPandas is a great tool to work with table data. Experiments are the same\ndata and can be loaded in python. So all you need is to run batch of\nexperiments and open a Jupyter notebook.\n\n.. code:: python\n\n import exman\n index = exman.Index(exman.simpleroot('/path/to/main.py'))\n experiments = index.info()\n\nTable has columns ``time (datetime64[ns])`` of experiment and\n``root (pathlib.Path)`` path to results. Moreover this table has all\nother parameters of the experiment. You later can filter/order the\nresults according to them and have easy-breezy access to results folder\nand it's content.\n\n.. code:: python\n\n for i, ex in experiments.iterrows():\n # do some actions\n # use ex.param for parameters\n # ex.root / 'plot.png' for file paths\n ...\n\nLocal Configuration\n~~~~~~~~~~~~~~~~~~~\n\nYou can store local configuration files in your experiment folder. You\nshould provide the filename to ExParser as well.\n\n.. code:: python\n\n import exman\n # you should always use `exman.simpleroot(__file__)` unless you want another dir\n parser = exman.ExParser(\n root=exman.simpleroot(__file__),\n default_config_files=['local.cfg']\n )\n\nLocal configuration stores globally defined default values, they\noverride defaults set in main file\n\nAuto Structure\n~~~~~~~~~~~~~~\n\nIf you want argument specific human friendly directory structure you can\ntie specific argument names for that\n\n.. code:: python\n\n import exman\n # you should always use `exman.simpleroot(__file__)` unless you want another dir\n parser = exman.ExParser(\n root=exman.simpleroot(__file__),\n automark=['arg1', 'constant']\n )\n parser.add_argument('--arg1')\n\nLater you can see your `marked folder <#directory-structure-and-cli>`__\nlooks like this\n\n::\n\n exman/marked/arg1//constant//...\n\nThis can be usefull if you work in a team. Write in ``main.py``\n\n.. code:: python\n\n import exman\n # you should always use `exman.simpleroot(__file__)` unless you want another dir\n parser = exman.ExParser(\n root=exman.simpleroot(__file__),\n automark=['user'],\n # store `user: myuser` content in local.cfg\n default_config_files=['local.cfg']\n )\n parser.add_argument('--user')\n\nAfter you've done that, your team runs can be stored in a single exman\ndirectory assuming all access rights are correctly set up.\n\n::\n\n exman/marked/user//constant//...\n\nDirectory Structure and CLI\n---------------------------\n\nIn command line runs will look also the same:\n\n::\n\n python main.py --param1 foo --param2 bar\n\nThings change if you actually run the program. It dumps all the parsed\nparameters combined with defaults into Yaml style file into location\n``root/runs//params.yaml``. ``name-of-experiment``\nis generic and autocreated on the fly. For quick look or search there\nare symlinks in the ``index`` folder e.g.\n``root/index/.yaml``. Since a lot of experiments are\ncreated and debugging is sometimes needed, you might want not to create\ndebug experiments in ``runs`` folder. For that case you just add\n``--tmp`` flag and new filed will be written to\n``root/tmp/`` folder. That is convenient as you both\ndo not loose important info about experiment and results and can restore\nthese symlinks in index by hand if needed.\n\n::\n\n root\n |-- runs\n | `-- xxxxxx-YYYY-mm-dd-HH-MM-SS\n | |-- params.yaml\n | `-- ...\n |-- fails\n |-- index\n | `-- xxxxxx-YYYY-mm-dd-HH-MM-SS.yaml (symlink)\n |-- marked\n | `-- \n | `-- xxxxxx-YYYY-mm-dd-HH-MM-SS (symlink)\n | |-- params.yaml\n | `-- ...\n `-- tmp\n `-- xxxxxx-YYYY-mm-dd-HH-MM-SS\n |-- params.yaml\n `-- ...\n\nRerunning experiment\n~~~~~~~~~~~~~~~~~~~~\n\nIf you want to reproduce an experiment, you can provide source\nconfiguration file in yaml format. For example:\n\n.. code:: bash\n\n python main.py --config root/index/.yaml\n\nAll the values will be restored from the previous run. You can also\nmodify old values in ``--config ...`` using\n\n.. code:: bash\n\n python main.py --config root/index/.yaml --override-param=new_value\n\nIn case you do not want to restore some argument from saved config (it\nmay be some dynamic setted variable) you should use ``volatile=True`` in\n``add_argument``:\n\n.. code:: python\n\n parser.add_argument('--my_dynamic_id', default=os.environ.get('AUTOSETTED_ID'), volatile=True)\n\nMarking experiments\n-------------------\n\nIf you like some experiments you can mark them for easier later access.\n\n::\n\n cd root_of_exman_dir\n exman mark <#ex1> [<#ex2> <#ex3> ...]\n\nand later in Jupyter\n\n.. code:: python\n\n index = exman.Index(exman.simpleroot('/path/to/main.py'))\n experiments = index.info('')\n # assuming you work in a team and use best practice advice\n user_experiments = index.info('user/username')\n\nDeleting experiments\n--------------------\n\n::\n\n cd root_of_exman_dir\n # delete only index\n exman delete <#ex1> [<#ex2> <#ex3> ...]\n # delete all files\n exman delete --all <#ex1> [<#ex2> <#ex3> ...]\n\n\n", "description_content_type": "", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "", "keywords": "", "license": "", "maintainer": "", "maintainer_email": "", "name": "exman", "package_url": "https://pypi.org/project/exman/", "platform": "", "project_url": "https://pypi.org/project/exman/", "project_urls": null, "release_url": "https://pypi.org/project/exman/0.1.6/", "requires_dist": [ "configargparse (>=0.14.0)", "PyYAML", "strconv", "pandas", "filelock", "joblib", "gitpython" ], "requires_python": ">=3.5", "summary": "Simple and minimalistic utility to manage many experiments runs and custom analysis of results", "version": "0.1.6" }, "last_serial": 5954889, "releases": { "0.1.0": [ { "comment_text": "", "digests": { "md5": "7fdd12dc4ff061a0e73e3c06d20d4500", "sha256": "d76ee26925afebe64f8ffdec7d147dcb53cb318ceb74dfaa4cc87fbf6dec12c0" }, "downloads": -1, "filename": "exman-0.1.0-py3-none-any.whl", "has_sig": false, "md5_digest": "7fdd12dc4ff061a0e73e3c06d20d4500", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.5", "size": 6799, "upload_time": "2019-01-14T17:43:12", "url": "https://files.pythonhosted.org/packages/3e/07/d10f26a9add3d009e93484d30a9b27051eaaf81faa3bbb03fdd23bda4bf2/exman-0.1.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "0b08f92aa20fec92efddd3f5ee097212", "sha256": "3beed36fc32776da7d5843604098c97048b19f06d96ed672d56077bdf6f02caf" }, "downloads": -1, "filename": "exman-0.1.0.tar.gz", "has_sig": false, "md5_digest": "0b08f92aa20fec92efddd3f5ee097212", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.5", "size": 8695, "upload_time": "2019-01-14T17:43:16", "url": "https://files.pythonhosted.org/packages/cd/27/1c4b29bfe1d15e5636c3b982263e07d7495ef3a5cbcd849bf841ab753c26/exman-0.1.0.tar.gz" } ], "0.1.1": [ { "comment_text": "", "digests": { "md5": "bb6befbbee1b45921a768f83cef29e24", "sha256": "8df2c8d48f001a9e15884dcc4689b4c5d67d99a5d34afff784dd76fe3e45f763" }, "downloads": -1, "filename": "exman-0.1.1-py3-none-any.whl", "has_sig": false, "md5_digest": "bb6befbbee1b45921a768f83cef29e24", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.5", "size": 9865, "upload_time": "2019-01-14T17:43:15", "url": "https://files.pythonhosted.org/packages/9d/81/98c0d424cd0b2d0e9c6d302f057592869a0408a34790ebcb4a039507f531/exman-0.1.1-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "7b40e431e56825fc9b2c2358fcba56cb", "sha256": "7c87f3e557743ee8bc12dc37c7044099b28adcc0002f40bab7b63b7e96da6f57" }, "downloads": -1, "filename": "exman-0.1.1.tar.gz", "has_sig": false, "md5_digest": "7b40e431e56825fc9b2c2358fcba56cb", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.5", "size": 10786, "upload_time": "2019-01-14T17:43:18", "url": "https://files.pythonhosted.org/packages/fc/46/4f85fe8790712ba3130ab943bb0a1aa2c7e2f16c05d94f170efe5d970e3d/exman-0.1.1.tar.gz" } ], "0.1.2": [ { "comment_text": "", "digests": { "md5": "4435c5c61a6529fdd2ea6990ddb4ca53", "sha256": "86d98593e2e13ee7071744421c1df7e98145c0418acb608a3136ecf64dfa217f" }, "downloads": -1, "filename": "exman-0.1.2-py3-none-any.whl", "has_sig": false, "md5_digest": "4435c5c61a6529fdd2ea6990ddb4ca53", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.5", "size": 9882, "upload_time": "2019-01-14T17:49:21", "url": "https://files.pythonhosted.org/packages/d5/37/2e7c755e8874a1b667be61aa6b7557d534e7aa710634f71c8a4fd93f229b/exman-0.1.2-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "fedc477079d6b08119b9181880bc3931", "sha256": "39a59565c3fd04a9319d033677bd7f0c21bf23623ca6293d8cabecedf403adb8" }, "downloads": -1, "filename": "exman-0.1.2.tar.gz", "has_sig": false, "md5_digest": "fedc477079d6b08119b9181880bc3931", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.5", "size": 10800, "upload_time": "2019-01-14T17:49:24", "url": "https://files.pythonhosted.org/packages/2b/a9/b40b0f48938a8326c85a7fe267c95a78a5c6a1721e5a47bd8784eaea4830/exman-0.1.2.tar.gz" } ], "0.1.3": [ { "comment_text": "", "digests": { "md5": "a4aa415ea9671e856fa9d827693a3f2b", "sha256": "87591d0d486c93a54724646cc6090b988655d700b8bc5c6fcbe6eea199e15461" }, "downloads": -1, "filename": "exman-0.1.3-py3-none-any.whl", "has_sig": false, "md5_digest": "a4aa415ea9671e856fa9d827693a3f2b", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.5", "size": 10001, "upload_time": "2019-01-18T20:09:13", "url": "https://files.pythonhosted.org/packages/f9/43/d60b88858aef4ca4498a208b30666dad8750382863ddfb939dbe907da1b0/exman-0.1.3-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "376e1b74597a4e374be3f98a97e0b20e", "sha256": "0ae209569a03ad4ccaf71eddb4f23bc1681bd3ef276302e960dd9dda20049123" }, "downloads": -1, "filename": "exman-0.1.3.tar.gz", "has_sig": false, "md5_digest": "376e1b74597a4e374be3f98a97e0b20e", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.5", "size": 10927, "upload_time": "2019-01-18T20:09:17", "url": "https://files.pythonhosted.org/packages/8b/68/3b0df4e49a51eabb2505fb4a5424f12b7d2df2b0e4a3e873826059eb009e/exman-0.1.3.tar.gz" } ], "0.1.4": [ { "comment_text": "", "digests": { "md5": "b3b9f0086fb143b91e16574b426b94a1", "sha256": "738e801f94a9f7e1d1fd876e36232b71db335044939e4f82d9062772f12faf25" }, "downloads": -1, "filename": "exman-0.1.4-py3-none-any.whl", "has_sig": false, "md5_digest": "b3b9f0086fb143b91e16574b426b94a1", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.5", "size": 10089, "upload_time": "2019-02-05T21:17:02", "url": "https://files.pythonhosted.org/packages/a9/49/2e67265b47ce61409df38ace7ab2c25aebdcf8103de021e68ff013d389de/exman-0.1.4-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "fa7e3a3a64d75ece0fb7443619881521", "sha256": "3f7dac4b114bea29fbbaa8a7b31be330319f85352a7b5a903f1082d140917cee" }, "downloads": -1, "filename": "exman-0.1.4.tar.gz", "has_sig": false, "md5_digest": "fa7e3a3a64d75ece0fb7443619881521", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.5", "size": 11322, "upload_time": "2019-02-05T21:17:07", "url": "https://files.pythonhosted.org/packages/cf/ce/4a7ce296c95c1bb8430c72c774b295553ffd9de383eabef54a8b3ffc5d90/exman-0.1.4.tar.gz" } ], "0.1.5": [ { "comment_text": "", "digests": { "md5": "45e1b6cd6afd5891fe4d73f45382f2e4", "sha256": "f797a16fe816aee34e22c18cfaf3f4040ac118c8cd410f7794ac873a5752bb36" }, "downloads": -1, "filename": "exman-0.1.5-py3-none-any.whl", "has_sig": false, "md5_digest": "45e1b6cd6afd5891fe4d73f45382f2e4", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.5", "size": 10224, "upload_time": "2019-09-06T15:17:36", "url": "https://files.pythonhosted.org/packages/a2/c1/b942d1513ee954cfa9dbe979e09ef0b0b17e114a1de7a08294da2fcbb5ef/exman-0.1.5-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "327ee3c54c8ca461a614500aa5fc395c", "sha256": "5bce6d2c722fe89302dc838425069676e155db60924704943a72ed1d7246887e" }, "downloads": -1, "filename": "exman-0.1.5.tar.gz", "has_sig": false, "md5_digest": "327ee3c54c8ca461a614500aa5fc395c", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.5", "size": 12075, "upload_time": "2019-09-06T15:17:38", "url": "https://files.pythonhosted.org/packages/5a/38/74d0b53ab803db4cb8e068ed71979d43e1c533052f1a487b0bd70ee4de0a/exman-0.1.5.tar.gz" } ], "0.1.6": [ { "comment_text": "", "digests": { "md5": "3ef558f1e92f5d9d4ed1efa92dafa10a", "sha256": "679eb51e6314a2cf75f759db767a0f879b0499ff9ff3f7a7b83684313a242b65" }, "downloads": -1, "filename": "exman-0.1.6-py3-none-any.whl", "has_sig": false, "md5_digest": "3ef558f1e92f5d9d4ed1efa92dafa10a", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.5", "size": 10998, "upload_time": "2019-10-10T13:45:23", "url": "https://files.pythonhosted.org/packages/af/e3/681a3331bb322989b41defd15ff05621bddbe171ea45efb4ed13d6bf8c65/exman-0.1.6-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "a23a8dca2e45af1438936b9886845c1e", "sha256": "d4c0a3e565d00fe414d30050888a2c682b886cbbe44ac5cc2ab025dc23dab0a6" }, "downloads": -1, "filename": "exman-0.1.6.tar.gz", "has_sig": false, "md5_digest": "a23a8dca2e45af1438936b9886845c1e", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.5", "size": 13883, "upload_time": "2019-10-10T13:45:41", "url": "https://files.pythonhosted.org/packages/85/69/f95d6380b0eebb7a1a199ad9fd0074af8beff31ca353f8ae8be1dafbda15/exman-0.1.6.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "3ef558f1e92f5d9d4ed1efa92dafa10a", "sha256": "679eb51e6314a2cf75f759db767a0f879b0499ff9ff3f7a7b83684313a242b65" }, "downloads": -1, "filename": "exman-0.1.6-py3-none-any.whl", "has_sig": false, "md5_digest": "3ef558f1e92f5d9d4ed1efa92dafa10a", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.5", "size": 10998, "upload_time": "2019-10-10T13:45:23", "url": "https://files.pythonhosted.org/packages/af/e3/681a3331bb322989b41defd15ff05621bddbe171ea45efb4ed13d6bf8c65/exman-0.1.6-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "a23a8dca2e45af1438936b9886845c1e", "sha256": "d4c0a3e565d00fe414d30050888a2c682b886cbbe44ac5cc2ab025dc23dab0a6" }, "downloads": -1, "filename": "exman-0.1.6.tar.gz", "has_sig": false, "md5_digest": "a23a8dca2e45af1438936b9886845c1e", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.5", "size": 13883, "upload_time": "2019-10-10T13:45:41", "url": "https://files.pythonhosted.org/packages/85/69/f95d6380b0eebb7a1a199ad9fd0074af8beff31ca353f8ae8be1dafbda15/exman-0.1.6.tar.gz" } ] }