{"id":15034752,"url":"https://github.com/huwcampbell/grenade","last_synced_at":"2025-04-08T08:16:11.938Z","repository":{"id":38707934,"uuid":"61802157","full_name":"HuwCampbell/grenade","owner":"HuwCampbell","description":"Deep Learning in Haskell","archived":false,"fork":false,"pushed_at":"2023-12-08T21:23:07.000Z","size":357,"stargazers_count":1451,"open_issues_count":24,"forks_count":83,"subscribers_count":60,"default_branch":"master","last_synced_at":"2025-04-08T08:15:53.281Z","etag":null,"topics":["convolutional-neural-networks","deep-learning","deep-neural-networks","generative-adversarial-networks","haskell","machine-learning"],"latest_commit_sha":null,"homepage":"","language":"Haskell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-2-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/HuwCampbell.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-06-23T12:04:52.000Z","updated_at":"2025-03-07T21:00:17.000Z","dependencies_parsed_at":"2022-09-16T06:53:47.134Z","dependency_job_id":"b58cd1ec-a72d-483b-968d-fae04f47df65","html_url":"https://github.com/HuwCampbell/grenade","commit_stats":{"total_commits":168,"total_committers":20,"mean_commits":8.4,"dds":"0.36309523809523814","last_synced_commit":"83cb4e4ec27ece8e7a7540d096bcf6c5ef3e8e7d"},"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/HuwCampbell%2Fgrenade","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/HuwCampbell%2Fgrenade/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/HuwCampbell%2Fgrenade/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/HuwCampbell%2Fgrenade/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/HuwCampbell","download_url":"https://codeload.github.com/HuwCampbell/grenade/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247801175,"owners_count":20998339,"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","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":["convolutional-neural-networks","deep-learning","deep-neural-networks","generative-adversarial-networks","haskell","machine-learning"],"created_at":"2024-09-24T20:26:13.490Z","updated_at":"2025-04-08T08:16:11.910Z","avatar_url":"https://github.com/HuwCampbell.png","language":"Haskell","funding_links":[],"categories":[],"sub_categories":[],"readme":"Grenade\n=======\n\n[![Build Status](https://api.travis-ci.org/HuwCampbell/grenade.svg?branch=master)](https://travis-ci.org/HuwCampbell/grenade)\n[![Hackage page (downloads and API reference)][hackage-png]][hackage]\n[![Hackage-Deps][hackage-deps-png]][hackage-deps]\n\n\n```\nFirst shalt thou take out the Holy Pin, then shalt thou count to three, no more, no less.\nThree shall be the number thou shalt count, and the number of the counting shall be three.\nFour shalt thou not count, neither count thou two, excepting that thou then proceed to three.\nFive is right out.\n```\n\n💣 Machine learning which might blow up in your face 💣\n\nGrenade is a composable, dependently typed, practical, and fast recurrent neural network library\nfor concise and precise specifications of complex networks in Haskell.\n\nAs an example, a network which can achieve ~1.5% error on MNIST can be\nspecified and initialised with random weights in a few lines of code with\n```haskell\ntype MNIST\n  = Network\n    '[ Convolution 1 10 5 5 1 1, Pooling 2 2 2 2, Relu\n     , Convolution 10 16 5 5 1 1, Pooling 2 2 2 2, Reshape, Relu\n     , FullyConnected 256 80, Logit, FullyConnected 80 10, Logit]\n    '[ 'D2 28 28\n     , 'D3 24 24 10, 'D3 12 12 10 , 'D3 12 12 10\n     , 'D3 8 8 16, 'D3 4 4 16, 'D1 256, 'D1 256\n     , 'D1 80, 'D1 80, 'D1 10, 'D1 10]\n\nrandomMnist :: MonadRandom m =\u003e m MNIST\nrandomMnist = randomNetwork\n```\n\nAnd that's it. Because the types are so rich, there's no specific term level code\nrequired to construct this network; although it is of course possible and\neasy to construct and deconstruct the networks and layers explicitly oneself.\n\nIf recurrent neural networks are more your style, you can try defining something\n[\"unreasonably effective\"](http://karpathy.github.io/2015/05/21/rnn-effectiveness/)\nwith\n```haskell\ntype Shakespeare\n  = RecurrentNetwork\n    '[ R (LSTM 40 80), R (LSTM 80 40), F (FullyConnected 40 40), F Logit]\n    '[ 'D1 40, 'D1 80, 'D1 40, 'D1 40, 'D1 40 ]\n```\n\nDesign\n------\n\nNetworks in Grenade can be thought of as a heterogeneous lists of layers, where\ntheir type includes not only the layers of the network, but also the shapes of\ndata that are passed between the layers.\n\nThe definition of a network is surprisingly simple:\n```haskell\ndata Network :: [*] -\u003e [Shape] -\u003e * where\n    NNil  :: SingI i\n          =\u003e Network '[] '[i]\n\n    (:~\u003e) :: (SingI i, SingI h, Layer x i h)\n          =\u003e !x\n          -\u003e !(Network xs (h ': hs))\n          -\u003e Network (x ': xs) (i ': h ': hs)\n```\n\nThe `Layer x i o` constraint ensures that the layer `x` can sensibly perform a\ntransformation between the input and output shapes `i` and `o`.\n\nThe lifted data kind `Shape` defines our 1, 2, and 3 dimension types, used to\ndeclare what shape of data is passed between the layers.\n\nIn the MNIST example above, the input layer can be seen to be a two dimensional\n(`D2`), image with 28 by 28 pixels. When the first *Convolution* layer runs, it\noutputs a three dimensional (`D3`) 24x24x10 image. The last item in the list is\none dimensional (`D1`) with 10 values, representing the categories of the MNIST\ndata.\n\nUsage\n-----\n\nTo perform back propagation, one can call the eponymous function\n```haskell\nbackPropagate :: forall shapes layers.\n                 Network layers shapes -\u003e S (Head shapes) -\u003e S (Last shapes) -\u003e Gradients layers\n```\nwhich takes a network, appropriate input and target data, and returns the\nback propagated gradients for the network. The shapes of the gradients are\nappropriate for each layer, and may be trivial for layers like `Relu` which\nhave no learnable parameters.\n\nThe gradients however can always be applied, yielding a new (hopefully better)\nlayer with\n```haskell\napplyUpdate :: LearningParameters -\u003e Network ls ss -\u003e Gradients ls -\u003e Network ls ss\n```\n\nLayers in Grenade are represented as Haskell classes, so creating one's own is\neasy in downstream code. If the shapes of a network are not specified correctly\nand a layer can not sensibly perform the operation between two shapes, then\nit will result in a compile time error.\n\nComposition\n-----------\n\nNetworks and Layers in Grenade are easily composed at the type level. As a `Network`\nis an instance of `Layer`, one can use a trained Network as a small component in a\nlarger network easily. Furthermore, we provide 2 layers which are designed to run\nlayers in parallel and merge their output (either by concatenating them across one\ndimension or summing by pointwise adding their activations). This allows one to\nwrite any Network which can be expressed as a\n[series parallel graph](https://en.wikipedia.org/wiki/Series-parallel_graph).\n\nA residual network layer specification for instance could be written as\n```haskell\ntype Residual net = Merge Trivial net\n```\nIf the type `net` is an instance of `Layer`, then `Residual net` will be too. It will\nrun the network, while retaining its input by passing it through the `Trivial` layer,\nand merge the original image with the output.\n\nSee the [MNIST](https://github.com/HuwCampbell/grenade/blob/master/examples/main/mnist.hs)\nexample, which has been overengineered to contain both residual style learning as well\nas inception style convolutions.\n\nGenerative Adversarial Networks\n-------------------------------\n\nAs Grenade is purely functional, one can compose its training functions in flexible\nways. [GAN-MNIST](https://github.com/HuwCampbell/grenade/blob/master/examples/main/gan-mnist.hs)\nexample displays an interesting, type safe way of writing a generative adversarial\ntraining function in 10 lines of code.\n\nLayer Zoo\n---------\n\nGrenade layers are normal haskell data types which are an instance of `Layer`, so\nit's easy to build one's own downstream code. We do however provide a decent set\nof layers, including convolution, deconvolution, pooling, pad, crop, logit, relu,\nelu, tanh, and fully connected.\n\nBuild Instructions\n------------------\nGrenade is most easily built with the [mafia](https://github.com/ambiata/mafia)\nscript that is located in the repository. You will also need the `lapack` and\n`blas` libraries and development tools. Once you have all that, Grenade can be\nbuild using:\n\n```\n./mafia build\n```\n\nand the tests run using:\n\n```\n./mafia test\n```\n\nGrenade builds with ghc 7.10, 8.0, 8.2 and 8.4.\n\nThanks\n------\nWriting a library like this has been on my mind for a while now, but a big shout\nout must go to [Justin Le](https://github.com/mstksg), whose\n[dependently typed fully connected network](https://blog.jle.im/entry/practical-dependent-types-in-haskell-1.html)\ninspired me to get cracking, gave many ideas for the type level tools I\nneeded, and was a great starting point for writing this library.\n\nPerformance\n-----------\nGrenade is backed by hmatrix, BLAS, and LAPACK, with critical functions optimised\nin C. Using the im2col trick popularised by Caffe, it should be sufficient for\nmany problems.\n\nBeing purely functional, it should also be easy to run batches in parallel, which\nwould be appropriate for larger networks, my current examples however are single\nthreaded.\n\nTraining 15 generations over Kaggle's 41000 sample MNIST training set on a single\ncore took around 12 minutes, achieving 1.5% error rate on a 1000 sample holdout set.\n\nContributing\n------------\nContributions are welcome.\n\n [hackage]: http://hackage.haskell.org/package/grenade\n [hackage-png]: http://img.shields.io/hackage/v/grenade.svg\n [hackage-deps]: http://packdeps.haskellers.com/reverse/grenade\n [hackage-deps-png]: https://img.shields.io/hackage-deps/v/grenade.svg\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhuwcampbell%2Fgrenade","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhuwcampbell%2Fgrenade","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhuwcampbell%2Fgrenade/lists"}