{"id":16683650,"url":"https://github.com/liulietlee/nn","last_synced_at":"2026-04-13T07:11:54.340Z","repository":{"id":82776613,"uuid":"219155686","full_name":"LiulietLee/nn","owner":"LiulietLee","description":"A toy convolutional neural network framework, written by Swift and Metal, for iOS and macOS","archived":false,"fork":false,"pushed_at":"2020-02-07T16:01:17.000Z","size":1493,"stargazers_count":2,"open_issues_count":1,"forks_count":1,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-01-20T08:28:25.168Z","etag":null,"topics":["convolutional-neural-network","cs231n","ios","macos","metal","neural-network","swift"],"latest_commit_sha":null,"homepage":"","language":"Swift","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/LiulietLee.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":"2019-11-02T13:11:05.000Z","updated_at":"2020-04-29T13:34:26.000Z","dependencies_parsed_at":null,"dependency_job_id":"e8016ca4-d1d5-4196-b94c-3c5a15765c78","html_url":"https://github.com/LiulietLee/nn","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LiulietLee%2Fnn","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LiulietLee%2Fnn/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LiulietLee%2Fnn/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LiulietLee%2Fnn/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/LiulietLee","download_url":"https://codeload.github.com/LiulietLee/nn/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243403245,"owners_count":20285380,"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-network","cs231n","ios","macos","metal","neural-network","swift"],"created_at":"2024-10-12T14:25:40.032Z","updated_at":"2025-12-29T07:57:25.229Z","avatar_url":"https://github.com/LiulietLee.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"# nn\n\u003e A toy convolutional neural network framework, written by Swift and Metal, for iOS and macOS devices.\n\n## Usage\n\n### Train a handwritten digit classifier\n\n### On [macOS](https://github.com/LiulietLee/nn/tree/master/Example/mnist-mac)\n\n1. Donwload MNIST dataset\n```\ncurl -O http://yann.lecun.com/exdb/mnist/train-images-idx3-ubyte.gz\ncurl -O http://yann.lecun.com/exdb/mnist/train-labels-idx1-ubyte.gz\ncurl -O http://yann.lecun.com/exdb/mnist/t10k-images-idx3-ubyte.gz\ncurl -O http://yann.lecun.com/exdb/mnist/t10k-labels-idx1-ubyte.gz\ngunzip t*-ubyte.gz\n```\n\n2. Define a network\n```swift\nlet net = Sequential([\n    Conv(3, count: 3, padding: 1),\n    Conv(3, count: 3, padding: 1),\n    Conv(3, count: 3, padding: 1),\n    ReLU(),\n    MaxPool(2, step: 2),\n    Conv(3, count: 6, padding: 1),\n    Conv(3, count: 6, padding: 1),\n    Conv(3, count: 6, padding: 1),\n    ReLU(),\n    MaxPool(2, step: 2),\n    Dense(inFeatures: 6 * 7 * 7, outFeatures: 120),\n    Dense(inFeatures: 120, outFeatures: 10)\n])\n```\n\n3. Create a data reader\n```swift\nlet reader = MNISTReader(\n    root: \"/.../mnist\", // path to your dataset\n    batchSize: 64\n)\n```\n\n4. Use GPU (or the computation will be extremely slow)\n```swift\nCore.device = MTLCreateSystemDefaultDevice()\n```\n\n5. Train\n```swift\nfunc train() {\n    ModelStorage.load(net, path: \"mnistmodel01.nnm\")\n\n    for i in 0..\u003c3 {\n        var j = 0\n        var runningLoss: Float = 0.0\n        while let (img, label) = reader.nextTrain() {\n            net.zeroGrad()\n            let _ = net.forward(img)\n            let loss = net.loss(label)\n            net.backward(label)\n            net.step(lr: 0.0001, momentum: 0.99)\n            runningLoss = max(runningLoss, loss)\n            \n            if j % 100 == 99 {\n                print(\"[\\(i), \\(j)] loss: \\(runningLoss)\")\n                runningLoss = 0.0\n                ModelStorage.save(net, path: \"mnistmodel01.nnm\")\n            }\n            \n            j += 1\n        }\n    }\n    \n    ModelStorage.save(net, path: \"mnistmodel01.nnm\")\n}\n\ntrain()\n```\nIt's very easy to understand the `train()` function if you have used PyTorch.\n\nTotal training time is about 24 minutes on my computer (MacBook Pro Retina, 13-inch, Mid 2014)\n\nMaybe you think that it's very slow.\n\nYes. So it's recommended to start training before you having lunch.\n\n6. Test\n```swift\nfunc test() {\n    ModelStorage.load(net, path: \"mnistmodel01.nnm\")\n    \n    var cor = 0\n    var tot = 0\n    while let (img, label) = reader.nextTest() {\n        let score = net.forward(img)\n        let pred = score.indexOfMax()\n        if pred == label {\n            cor += 1\n            print(\"\\(tot): Y \\(pred) == \\(label)\")\n        } else {\n            print(\"\\(tot): N \\(pred) != \\(label)\")\n        }\n        tot += 1\n    }\n    print(\"correct: \\(cor) / \\(tot)\")\n}\n\ntest()\n```\nSince we only trained for three epochs, the accuracy rate won't be very high (about 86%).\n\nIf you wanna improve it, you can train more epochs.\n\n### On [iOS](https://github.com/LiulietLee/nn/tree/master/Example/mnist-ios)\n\n1. Move pretrained model [mnistmodel01.nnm](https://github.com/LiulietLee/nn/blob/master/Example/mnist-ios/mnist-ios/mnistmodel01.nnm) file to your iOS project. Make sure the **Target Membership** is selected.\n\n2. Create a model with the same structure as before.\n```swift\nlet model = Sequential([\n    Conv(3, count: 3, padding: 1),\n    ...\n    Dense(inFeatures: 120, outFeatures: 10)\n])\n```\n\n3. Load model parameters and enable GPU computation in `viewDidLoad()`.\n```swift\noverride func viewDidLoad() {\n    super.viewDidLoad()\n    let path = Bundle.main.path(forResource: \"mnistmodel01\", ofType: \"nnm\")!\n    ModelStorage.load(model, path: path)\n    Core.device = MTLCreateSystemDefaultDevice()\n}\n```\n\n4. Use `forward()` function to predict.\n```swift\n@IBAction func check() {\n    let img = getViewImage() // this function convert UIView to NNArray\n    let res = model.forward(img)\n    let pred = res.indexOfMax()\n    button.setTitle(\"\\(pred)\", for: .normal)\n}\n```\nYou can read the [source](https://github.com/LiulietLee/nn/blob/master/Example/mnist-ios/mnist-ios/ViewController.swift) for detail.\n\n## Avaliable Layer\n- Conv (2D convolutional layer)\n- Dense (fully connected layer)\n- ReLU (leaky relu)\n- MaxPool (2D max pooling layer)\n- AveragePool (2D average pooling layer (uncompleted ver.))\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fliulietlee%2Fnn","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fliulietlee%2Fnn","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fliulietlee%2Fnn/lists"}