{ "info": { "author": "Timothy Moore", "author_email": "mtimothy984@gmail.com", "bugtrack_url": null, "classifiers": [ "License :: CC0 1.0 Universal (CC0 1.0) Public Domain Dedication", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Topic :: Utilities" ], "description": "# PyTorch Fluent Models\n\nA small package that provides a fluent interface for creating pytorch models.\n\n## Summary\n\nA fluent interface is roughly one where you chain method calls. Read more about\nfluent interfaces [here](https://en.wikipedia.org/wiki/Fluent_interface).\n\nThis library allows for dense layers, convolution layers, max pooling,\nand nonlinearities or other operators (i.e. normalization). This calculates\nthe new shape after each layer, meaning you do not have to redundantly\nspecify features.\n\nConsider the following pure PyTorch code:\n\n```py\nimport torch.nn as nn\n\nnet = nn.Sequential(\n nn.Linear(28*28, 128),\n nn.Linear(128, 10)\n)\n```\n\nThe input to the second layer (128) must always match the output of the first\nlayer. This redundancy is very small but can be improved. The issue becomes\neven more apparent when you consider convolution layers.\n\nFurthermore, the official PyTorch library does not include some common glue\ncode for extensive sequential blocks. One possible reason for this is that\nFluent API's are unlikely to be as exhaustive as conventional API's so\none will often have to fall back on the more verbose module definition anyway.\n\nFinally, this has the extremely versatile `then` and `then_with` which\nwork for transposed convolution layers and unpooling while still avoiding\nredundant layer sizes or channel numbers.\n\n## API Reference\n\nhttps://tjstretchalot.github.io/torchluent/\n\n## Usage\n\nCreate an instance of `torchluent.FluentModule` with the shape of your input.\nThere are a few meta functions on FluentModule, such as `.verbose()` which\nwill print how the shape changes through progressive calls. For layers which\nchange the number of features one can call `.transform` in the generic sense\nor use one of the provided functions such as `.dense` which will calculate the\nnew number of features. For layers which do not change the shape of the data,\nrather than including a function for each one you may use `.operator` which\naccepts the name of the attribute in `torch.nn` as well as an arguments or\nkeyword arguments.\n\n## Installation\n\n```pip install torchluent```\n\n## Examples\n\n```py\nfrom torchluent import FluentModule\n\nprint('Network:')\nnet = (\n FluentModule((1, 28, 28))\n .verbose()\n .conv2d(32, kernel_size=5)\n .maxpool2d(kernel_size=3)\n .operator('LeakyReLU', negative_slope=0.05)\n .flatten()\n .dense(128)\n .operator('ReLU')\n .dense(10)\n .operator('ReLU')\n .build()\n)\n\nprint(net)\n```\n\nProduces:\n\n```\nNetwork:\n (1, 28, 28)\n Conv2d -> (32, 24, 24)\n MaxPool2d -> (32, 8, 8)\n LeakyReLU\n Reshape -> (2048,)\n Linear -> (128,)\n ReLU\n Linear -> (10,)\n ReLU\n\nSequential(\n (0): Conv2d(1, 32, kernel_size=(5, 5), stride=(1, 1))\n (1): MaxPool2d(kernel_size=3, stride=3, padding=0, dilation=1, ceil_mode=False)\n (2): LeakyReLU(negative_slope=0.05)\n (3): Reshape(2048)\n (4): Linear(in_features=2048, out_features=128, bias=True)\n (5): ReLU()\n (6): Linear(in_features=128, out_features=10, bias=True)\n (7): ReLU()\n)\n```\n\n## Wrapping and Unwrapping\n\nOne concept which is not in PyTorch by default is a way to consider the hidden\nstate of an arbitrary network in an abstract way. The idea is\nbasically that it is often nice if a module returns an array in addition to\nthe transformed output, where each element in the returned array is a snapshot\nof the input as it propagated through the network.\n\nThe following is a contrived example that illustrates what such a module might\nlook like:\n\n```py\nimport torch.nn as nn\n\nclass HiddenStateModule(nn.Module):\n def forward(self, x):\n result = []\n result.append(x) # initial state always there\n x = x ** 2\n result.append(x) # where relevant\n x = x * 3 + 2\n x = torch.relu(x)\n result.append(x)\n return x, result\n```\n\nThis module means to expose this concept without having to modify the\nunderlying transformations (i.e. `nn.Linear`) nor be forced to fallback on\ncreating a custom Module just for this extremely common situation.\n\nHowever, another problem that arises with this type of module is that this\nresult will break much of your codebase if it expects a single output. This\nis most problematic when combined with some abstract training paradigm such as\nPyTorch Ignite. Luckily, it's very easy to just drop the second output from\nsuch a module, as if by the following\n\n```py\nimport torch.nn as nn\n\nclass StrippedStateModule(nn.Module):\n def __init__(self, mod):\n super().__init__()\n self.mod = mod\n\n def forward(self, x):\n return self.mod(x)[0]\n```\n\nBy including the array in the main implementation and then using such an\n\"unwrapping\" module you can get the best of both worlds. For training and\ngeneric usage which does not need the hidden state, use the stripped version.\nFor analysis which desires the hidden state, use the pre-stripped version.\n\nWith this context in mind, the following code snippet will produce both the\nwrapped and unwrapped versions of the network:\n\n```py\nfrom torchluent import FluentModule\n\nprint('Network:')\nnet, stripped_net = (\n FluentModule((28*28,))\n .verbose()\n .wrap(with_input=True) # create array and initialize with input\n .dense(128)\n .operator('ReLU')\n .save_state() # pushes to the array\n .dense(128)\n .operator('ReLU')\n .save_state()\n .dense(10)\n .operator('ReLU')\n .save_state()\n .build(with_stripped=True)\n)\nprint()\nprint(net)\n```\n\nProduces\n\n```\nNetwork:\n (784,)\n Linear -> (128,)\n ReLU\n Linear -> (128,)\n ReLU\n Linear -> (10,)\n ReLU\n\nSequential(\n (0): InitListModule(include_first=True)\n (1): WrapModule(\n (child): Linear(in_features=784, out_features=128, bias=True)\n )\n (2): WrapModule(\n (child): ReLU()\n )\n (3): SaveStateModule()\n (4): WrapModule(\n (child): Linear(in_features=128, out_features=128, bias=True)\n )\n (5): WrapModule(\n (child): ReLU()\n )\n (6): SaveStateModule()\n (7): WrapModule(\n (child): Linear(in_features=128, out_features=10, bias=True)\n )\n (8): WrapModule(\n (child): ReLU()\n )\n (9): SaveStateModule()\n)\n```\n\n## Limitations\n\nFor non-trivial networks there will likely be significant usage of the `then`\nand `then_with` functions which aren't quite as nice as the examples shown\nabove, but I believe they are still a significant improvement.\n\n\n", "description_content_type": "text/markdown", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/tjstretchalot/torchluent", "keywords": "torch fluent models machinelearning", "license": "CC0", "maintainer": "", "maintainer_email": "", "name": "torchluent", "package_url": "https://pypi.org/project/torchluent/", "platform": "", "project_url": "https://pypi.org/project/torchluent/", "project_urls": { "Homepage": "https://github.com/tjstretchalot/torchluent" }, "release_url": "https://pypi.org/project/torchluent/0.0.4/", "requires_dist": [ "torch (>=1.1.0)", "torchvision (>=0.3.0)", "numpy", "pytypeutils" ], "requires_python": ">=3.6", "summary": "Build pytorch models in a fluent interface", "version": "0.0.4" }, "last_serial": 5620886, "releases": { "0.0.2": [ { "comment_text": "", "digests": { "md5": "72ea1f47de071b11683bc59f18763622", "sha256": "23bece1ee213bb3e4490107808e7bb7499253e92a0c3580f91253e997c3b2989" }, "downloads": -1, "filename": "torchluent-0.0.2-py3-none-any.whl", "has_sig": false, "md5_digest": "72ea1f47de071b11683bc59f18763622", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.6", "size": 12106, "upload_time": "2019-08-01T20:40:36", "url": "https://files.pythonhosted.org/packages/7c/13/091c37e1277745f61abd5591feff76eea56a31cdbff040de6f97163ded86/torchluent-0.0.2-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "6dda061801c13e2fc62a15c34934c85f", "sha256": "4bd5a37591a9148a0d6456229193014b6dd9f58dd11e35e75377653cbda5d217" }, "downloads": -1, "filename": "torchluent-0.0.2.tar.gz", "has_sig": false, "md5_digest": "6dda061801c13e2fc62a15c34934c85f", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 11548, "upload_time": "2019-08-01T20:40:39", "url": "https://files.pythonhosted.org/packages/97/11/7bde12e5a296ee92d830038d02240a581e88d54f049439f31b4629ad10aa/torchluent-0.0.2.tar.gz" } ], "0.0.3": [ { "comment_text": "", "digests": { "md5": "2322ecfe47a44a48d07db10a0daa3ff5", "sha256": "f57d4fb2e1e4ae08f0720021099e448a564447c504dffaed1b38863b5562c92a" }, "downloads": -1, "filename": "torchluent-0.0.3-py3-none-any.whl", "has_sig": false, "md5_digest": "2322ecfe47a44a48d07db10a0daa3ff5", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.6", "size": 12132, "upload_time": "2019-08-01T20:45:30", "url": "https://files.pythonhosted.org/packages/5b/c0/9dd9a74a5b01fac489154f303b1786d62f411150b97843cb67cd33c612a1/torchluent-0.0.3-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "d083be618daf6b9c9481da61e27355a8", "sha256": "50625fb72c15c06cbb5e03bd401facf9aa27f40e1e7e5d92dbc434fd5082c004" }, "downloads": -1, "filename": "torchluent-0.0.3.tar.gz", "has_sig": false, "md5_digest": "d083be618daf6b9c9481da61e27355a8", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 11570, "upload_time": "2019-08-01T20:45:31", "url": "https://files.pythonhosted.org/packages/aa/ec/2eb81cd1160bc8462947daeaacd55bc86e4bac1e7d7ce44ce8ca61b01fc8/torchluent-0.0.3.tar.gz" } ], "0.0.4": [ { "comment_text": "", "digests": { "md5": "b0312bd0f80f7ee5238d6ec9e2ff649c", "sha256": "f5b7bdf145b6d159959e3e353833ddce369178c60474814cee754865b9923e23" }, "downloads": -1, "filename": "torchluent-0.0.4-py3-none-any.whl", "has_sig": false, "md5_digest": "b0312bd0f80f7ee5238d6ec9e2ff649c", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.6", "size": 12136, "upload_time": "2019-08-01T21:17:29", "url": "https://files.pythonhosted.org/packages/a8/0d/e69230b5ec5a20a3d1b00bad69c4b78e4d8da5796bd093a413c2f761dccb/torchluent-0.0.4-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "1ed33d3fd11720968c076b39abb4c83f", "sha256": "6683137ff0f007d7862b3140ac9ada632001ed358f3572caeb78d857247dc51e" }, "downloads": -1, "filename": "torchluent-0.0.4.tar.gz", "has_sig": false, "md5_digest": "1ed33d3fd11720968c076b39abb4c83f", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 11576, "upload_time": "2019-08-01T21:17:30", "url": "https://files.pythonhosted.org/packages/fb/e4/6f658fa70985af9825125eb35c737280534d80bb7d72005e995bb56390d8/torchluent-0.0.4.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "b0312bd0f80f7ee5238d6ec9e2ff649c", "sha256": "f5b7bdf145b6d159959e3e353833ddce369178c60474814cee754865b9923e23" }, "downloads": -1, "filename": "torchluent-0.0.4-py3-none-any.whl", "has_sig": false, "md5_digest": "b0312bd0f80f7ee5238d6ec9e2ff649c", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.6", "size": 12136, "upload_time": "2019-08-01T21:17:29", "url": "https://files.pythonhosted.org/packages/a8/0d/e69230b5ec5a20a3d1b00bad69c4b78e4d8da5796bd093a413c2f761dccb/torchluent-0.0.4-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "1ed33d3fd11720968c076b39abb4c83f", "sha256": "6683137ff0f007d7862b3140ac9ada632001ed358f3572caeb78d857247dc51e" }, "downloads": -1, "filename": "torchluent-0.0.4.tar.gz", "has_sig": false, "md5_digest": "1ed33d3fd11720968c076b39abb4c83f", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 11576, "upload_time": "2019-08-01T21:17:30", "url": "https://files.pythonhosted.org/packages/fb/e4/6f658fa70985af9825125eb35c737280534d80bb7d72005e995bb56390d8/torchluent-0.0.4.tar.gz" } ] }