├── .gitignore ├── nnet ├── mnistCNN.h5 ├── mnistCNN.mlmodel ├── convert.py ├── train.py └── MNIST CNN.ipynb ├── Screenshots ├── IMG_0016.PNG ├── IMG_0017.PNG ├── IMG_0018.PNG ├── IMG_0019.PNG ├── IMG_0020.PNG ├── IMG_0021.PNG ├── IMG_0022.PNG ├── IMG_0023.PNG ├── IMG_0024.PNG ├── IMG_0025.PNG └── IMG_0026.PNG ├── iOS-CoreML-MNIST ├── Assets.xcassets │ ├── Contents.json │ └── AppIcon.appiconset │ │ └── Contents.json ├── mnistCNN.mlmodel ├── Info.plist ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard ├── ViewController.swift ├── AppDelegate.swift └── DrawView.swift ├── iOS-CoreML-MNIST.xcodeproj ├── xcuserdata │ ├── sriraghu95.xcuserdatad │ │ ├── xcdebugger │ │ │ └── Breakpoints_v2.xcbkptlist │ │ └── xcschemes │ │ │ └── xcschememanagement.plist │ ├── r4ghu.xcuserdatad │ │ └── xcschemes │ │ │ └── xcschememanagement.plist │ └── sri.xcuserdatad │ │ └── xcschemes │ │ └── xcschememanagement.plist ├── project.xcworkspace │ ├── contents.xcworkspacedata │ ├── xcuserdata │ │ ├── sri.xcuserdatad │ │ │ └── UserInterfaceState.xcuserstate │ │ ├── r4ghu.xcuserdatad │ │ │ └── UserInterfaceState.xcuserstate │ │ └── sriraghu95.xcuserdatad │ │ │ └── UserInterfaceState.xcuserstate │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist └── project.pbxproj ├── .github └── FUNDING.yml └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | build/ 3 | -------------------------------------------------------------------------------- /nnet/mnistCNN.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/r4ghu/iOS-CoreML-MNIST/HEAD/nnet/mnistCNN.h5 -------------------------------------------------------------------------------- /nnet/mnistCNN.mlmodel: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/r4ghu/iOS-CoreML-MNIST/HEAD/nnet/mnistCNN.mlmodel -------------------------------------------------------------------------------- /Screenshots/IMG_0016.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/r4ghu/iOS-CoreML-MNIST/HEAD/Screenshots/IMG_0016.PNG -------------------------------------------------------------------------------- /Screenshots/IMG_0017.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/r4ghu/iOS-CoreML-MNIST/HEAD/Screenshots/IMG_0017.PNG -------------------------------------------------------------------------------- /Screenshots/IMG_0018.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/r4ghu/iOS-CoreML-MNIST/HEAD/Screenshots/IMG_0018.PNG -------------------------------------------------------------------------------- /Screenshots/IMG_0019.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/r4ghu/iOS-CoreML-MNIST/HEAD/Screenshots/IMG_0019.PNG -------------------------------------------------------------------------------- /Screenshots/IMG_0020.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/r4ghu/iOS-CoreML-MNIST/HEAD/Screenshots/IMG_0020.PNG -------------------------------------------------------------------------------- /Screenshots/IMG_0021.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/r4ghu/iOS-CoreML-MNIST/HEAD/Screenshots/IMG_0021.PNG -------------------------------------------------------------------------------- /Screenshots/IMG_0022.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/r4ghu/iOS-CoreML-MNIST/HEAD/Screenshots/IMG_0022.PNG -------------------------------------------------------------------------------- /Screenshots/IMG_0023.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/r4ghu/iOS-CoreML-MNIST/HEAD/Screenshots/IMG_0023.PNG -------------------------------------------------------------------------------- /Screenshots/IMG_0024.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/r4ghu/iOS-CoreML-MNIST/HEAD/Screenshots/IMG_0024.PNG -------------------------------------------------------------------------------- /Screenshots/IMG_0025.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/r4ghu/iOS-CoreML-MNIST/HEAD/Screenshots/IMG_0025.PNG -------------------------------------------------------------------------------- /Screenshots/IMG_0026.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/r4ghu/iOS-CoreML-MNIST/HEAD/Screenshots/IMG_0026.PNG -------------------------------------------------------------------------------- /iOS-CoreML-MNIST/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /iOS-CoreML-MNIST/mnistCNN.mlmodel: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/r4ghu/iOS-CoreML-MNIST/HEAD/iOS-CoreML-MNIST/mnistCNN.mlmodel -------------------------------------------------------------------------------- /iOS-CoreML-MNIST.xcodeproj/xcuserdata/sriraghu95.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /iOS-CoreML-MNIST.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /iOS-CoreML-MNIST.xcodeproj/project.xcworkspace/xcuserdata/sri.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/r4ghu/iOS-CoreML-MNIST/HEAD/iOS-CoreML-MNIST.xcodeproj/project.xcworkspace/xcuserdata/sri.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /iOS-CoreML-MNIST.xcodeproj/project.xcworkspace/xcuserdata/r4ghu.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/r4ghu/iOS-CoreML-MNIST/HEAD/iOS-CoreML-MNIST.xcodeproj/project.xcworkspace/xcuserdata/r4ghu.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /iOS-CoreML-MNIST.xcodeproj/project.xcworkspace/xcuserdata/sriraghu95.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/r4ghu/iOS-CoreML-MNIST/HEAD/iOS-CoreML-MNIST.xcodeproj/project.xcworkspace/xcuserdata/sriraghu95.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /iOS-CoreML-MNIST.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /iOS-CoreML-MNIST.xcodeproj/xcuserdata/sriraghu95.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | iOS-CoreML-MNIST.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /iOS-CoreML-MNIST.xcodeproj/xcuserdata/r4ghu.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | iOS-CoreML-MNIST.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /iOS-CoreML-MNIST.xcodeproj/xcuserdata/sri.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | iOS-CoreML-MNIST.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # srimalireddi # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: ["https://www.paypal.me/SMalireddi"]# Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 13 | -------------------------------------------------------------------------------- /nnet/convert.py: -------------------------------------------------------------------------------- 1 | import coremltools 2 | 3 | output_labels = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'] 4 | scale = 1/255. 5 | coreml_model = coremltools.converters.keras.convert('./mnistCNN.h5', 6 | input_names='image', 7 | image_input_names='image', 8 | output_names='output', 9 | class_labels=output_labels, 10 | image_scale=scale) 11 | 12 | coreml_model.author = 'Sri Raghu Malireddi' 13 | coreml_model.license = 'MIT' 14 | coreml_model.short_description = 'Model to classify hand written digit' 15 | 16 | coreml_model.input_description['image'] = 'Grayscale image of hand written digit' 17 | coreml_model.output_description['output'] = 'Predicted digit' 18 | 19 | coreml_model.save('mnistCNN.mlmodel') 20 | -------------------------------------------------------------------------------- /iOS-CoreML-MNIST/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UILaunchStoryboardName 24 | LaunchScreen 25 | UIMainStoryboardFile 26 | Main 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /iOS-CoreML-MNIST/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /nnet/train.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | import keras 4 | 5 | from keras.datasets import mnist 6 | from keras.models import Sequential 7 | from keras.layers import Dense, Dropout, Flatten 8 | from keras.layers.convolutional import Conv2D, MaxPooling2D 9 | from keras.utils import np_utils 10 | 11 | # (Making sure) Set backend as tensorflow 12 | from keras import backend as K 13 | K.set_image_dim_ordering('tf') 14 | 15 | # Define some variables 16 | num_rows = 28 17 | num_cols = 28 18 | num_channels = 1 19 | num_classes = 10 20 | 21 | # Import data 22 | (X_train, y_train), (X_test, y_test) = mnist.load_data() 23 | 24 | X_train = X_train.reshape(X_train.shape[0], num_rows, num_cols, num_channels).astype(np.float32) / 255 25 | X_test = X_test.reshape(X_test.shape[0], num_rows, num_cols, num_channels).astype(np.float32) / 255 26 | 27 | y_train = np_utils.to_categorical(y_train) 28 | y_test = np_utils.to_categorical(y_test) 29 | 30 | # Model 31 | model = Sequential() 32 | 33 | model.add(Conv2D(32, (5, 5), input_shape=(28, 28, 1), activation='relu')) 34 | model.add(MaxPooling2D(pool_size=(2, 2))) 35 | model.add(Dropout(0.5)) 36 | model.add(Conv2D(64, (3, 3), activation='relu')) 37 | model.add(MaxPooling2D(pool_size=(2, 2))) 38 | model.add(Dropout(0.2)) 39 | model.add(Conv2D(128, (1, 1), activation='relu')) 40 | model.add(MaxPooling2D(pool_size=(2, 2))) 41 | model.add(Dropout(0.2)) 42 | model.add(Flatten()) 43 | model.add(Dense(128, activation='relu')) 44 | model.add(Dense(num_classes, activation='softmax')) 45 | 46 | model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy']) 47 | 48 | # Training 49 | model.fit(X_train, y_train, validation_data=(X_test, y_test), epochs=20, batch_size=200, verbose=2) 50 | 51 | # Prepare model for inference 52 | for k in model.layers: 53 | if type(k) is keras.layers.Dropout: 54 | model.layers.remove(k) 55 | 56 | # Print model summary 57 | print(model.summary()) 58 | 59 | # Save the model 60 | model.save('mnistCNN.h5') -------------------------------------------------------------------------------- /iOS-CoreML-MNIST/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "20x20", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "20x20", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "29x29", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "29x29", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "size" : "40x40", 66 | "scale" : "1x" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "size" : "40x40", 71 | "scale" : "2x" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "size" : "76x76", 76 | "scale" : "1x" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "size" : "76x76", 81 | "scale" : "2x" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "size" : "83.5x83.5", 86 | "scale" : "2x" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "size" : "1024x1024", 91 | "scale" : "1x" 92 | } 93 | ], 94 | "info" : { 95 | "version" : 1, 96 | "author" : "xcode" 97 | } 98 | } -------------------------------------------------------------------------------- /iOS-CoreML-MNIST/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // iOS-CoreML-MNIST 4 | // 5 | // Created by Sri Raghu Malireddi on 02/08/18. 6 | // Copyright © 2018 Sri Raghu Malireddi. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class ViewController: UIViewController { 12 | 13 | @IBOutlet weak var drawView: DrawView! 14 | @IBOutlet weak var predictLabel: UILabel! 15 | 16 | let model = mnistCNN() 17 | let context = CIContext() 18 | var pixelBuffer: CVPixelBuffer? 19 | 20 | override func viewDidLoad() { 21 | super.viewDidLoad() 22 | // Do any additional setup after loading the view, typically from a nib. 23 | predictLabel.isHidden = true 24 | 25 | // Set the pixel buffer dimensions - Remember it's grayscale 26 | let attrs = [kCVPixelBufferCGImageCompatibilityKey: kCFBooleanTrue, 27 | kCVPixelBufferCGBitmapContextCompatibilityKey: kCFBooleanTrue] as CFDictionary 28 | CVPixelBufferCreate(kCFAllocatorDefault, 29 | 28, 30 | 28, 31 | kCVPixelFormatType_OneComponent8, 32 | attrs, 33 | &pixelBuffer) 34 | } 35 | 36 | @IBAction func tappedClear(_ sender: Any) { 37 | drawView.lines = [] 38 | drawView.setNeedsDisplay() 39 | predictLabel.isHidden = true 40 | } 41 | 42 | @IBAction func tappedDetect(_ sender: Any) { 43 | // Check if user has drawn anything 44 | if drawView.lines.count <= 0 { 45 | // User didn't draw anything, return 46 | return 47 | } 48 | // Fancy Image conversions 49 | let viewContext = drawView.getViewContext() 50 | let cgImage = viewContext?.makeImage() 51 | let ciImage = CIImage(cgImage: cgImage!) 52 | context.render(ciImage, to: pixelBuffer!) 53 | // Predict 54 | let output = try? model.prediction(image: pixelBuffer!) 55 | // Output 56 | predictLabel.text = output?.classLabel 57 | predictLabel.isHidden = false 58 | } 59 | } 60 | 61 | 62 | -------------------------------------------------------------------------------- /iOS-CoreML-MNIST/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // iOS-CoreML-MNIST 4 | // 5 | // Created by Sri Raghu Malireddi on 02/08/18. 6 | // Copyright © 2018 Sri Raghu Malireddi. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | var window: UIWindow? 15 | 16 | 17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 18 | // Override point for customization after application launch. 19 | return true 20 | } 21 | 22 | func applicationWillResignActive(_ application: UIApplication) { 23 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 24 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 25 | } 26 | 27 | func applicationDidEnterBackground(_ application: UIApplication) { 28 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 29 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 30 | } 31 | 32 | func applicationWillEnterForeground(_ application: UIApplication) { 33 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 34 | } 35 | 36 | func applicationDidBecomeActive(_ application: UIApplication) { 37 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 38 | } 39 | 40 | func applicationWillTerminate(_ application: UIApplication) { 41 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 42 | } 43 | 44 | 45 | } 46 | 47 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # iOS-CoreML-MNIST 2 | 3 | This is the implementation of Number recognition using Keras-MNIST model on Apple's CoreML Framework. 4 | 5 | The app fetches image from your hand writing and perform number recognition in real-time. 6 | 7 | ## Requirements 8 | 9 | - Xcode 12.0 10 | - iOS 14.0 11 | - For training: Python 3.6 (Keras 2.1.6, TensorFlow 1.5.0, CoreMLTools 2.0b1) 12 | 13 | ## Usage 14 | 15 | To use this app, open **iOS-CoreML-MNIST.xcodeproj** in Xcode 12 and run it on a device with iOS 14. (You can also use simulator) 16 | 17 | ## Training 18 | 19 | If you want to train your own custom model, follow the tutorial given below to create an anaconda environment. Enter the environment and run the following commands in terminal with `./nnet` as master directory. 20 | 21 | ``` 22 | (coreml) $ python train.py 23 | (coreml) $ python convert.py 24 | ``` 25 | 26 | I also included a jupyter notebook for better understanding the above code. You need to use it with root permissions for mainly converting the keras model to CoreML model. Initialise the jupyter notebook instance with the following command: 27 | 28 | ``` 29 | (coreml) $ jupyter notebook --allow-root 30 | ``` 31 | 32 | ## Tutorial 33 | 34 | If you are interested in training your custom MNIST model from scratch, a **step-by-step tutorial** is available at - [**Link**](https://sriraghu.com/2017/07/06/computer-vision-in-ios-coremlkerasmnist/) 35 | 36 | ## Results 37 | 38 | These are the results of the app when tested on iPhone 7. 39 | 40 | Result 1 Result 1 Result 1 Result 1 Result 1 Result 1 Result 1 Result 1 Result 1 Result 1 Result 1 41 | 42 | 43 | ## Author 44 | 45 | Sri Raghu Malireddi / [@r4ghu](https://sriraghu.com) 46 | -------------------------------------------------------------------------------- /iOS-CoreML-MNIST/DrawView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DrawView.swift 3 | // iOS-CoreML-MNIST 4 | // 5 | // Created by Sri Raghu Malireddi on 15/06/17. 6 | // Copyright © 2017 Sri Raghu Malireddi. All rights reserved. 7 | // 8 | 9 | // CREDITS: Code taken with inspiration from Apple's Metal-2 sample MPSCNNHelloWorld 10 | import UIKit 11 | 12 | /** 13 | This class is used to handle the drawing in the DigitView so we can get user input digit, 14 | This class doesn't really have an MPS or Metal going in it, it is just used to get user input 15 | */ 16 | class DrawView: UIView { 17 | 18 | // some parameters of how thick a line to draw 15 seems to work 19 | // and we have white drawings on black background just like MNIST needs its input 20 | var linewidth = CGFloat(15) { didSet { setNeedsDisplay() } } 21 | var color = UIColor.white { didSet { setNeedsDisplay() } } 22 | 23 | // we will keep touches made by user in view in these as a record so we can draw them. 24 | var lines: [Line] = [] 25 | var lastPoint: CGPoint! 26 | 27 | override func touchesBegan(_ touches: Set, with event: UIEvent?) { 28 | lastPoint = touches.first!.location(in: self) 29 | } 30 | 31 | override func touchesMoved(_ touches: Set, with event: UIEvent?) { 32 | let newPoint = touches.first!.location(in: self) 33 | // keep all lines drawn by user as touch in record so we can draw them in view 34 | lines.append(Line(start: lastPoint, end: newPoint)) 35 | lastPoint = newPoint 36 | // make a draw call 37 | setNeedsDisplay() 38 | } 39 | 40 | override func draw(_ rect: CGRect) { 41 | super.draw(rect) 42 | 43 | let drawPath = UIBezierPath() 44 | drawPath.lineCapStyle = .round 45 | 46 | for line in lines{ 47 | drawPath.move(to: line.start) 48 | drawPath.addLine(to: line.end) 49 | } 50 | 51 | drawPath.lineWidth = linewidth 52 | color.set() 53 | drawPath.stroke() 54 | } 55 | 56 | 57 | /** 58 | This function gets the pixel data of the view so we can put it in MTLTexture 59 | 60 | - Returns: 61 | Void 62 | */ 63 | func getViewContext() -> CGContext? { 64 | // our network takes in only grayscale images as input 65 | let colorSpace:CGColorSpace = CGColorSpaceCreateDeviceGray() 66 | 67 | // we have 3 channels no alpha value put in the network 68 | let bitmapInfo = CGImageAlphaInfo.none.rawValue 69 | 70 | // this is where our view pixel data will go in once we make the render call 71 | let context = CGContext(data: nil, width: 28, height: 28, bitsPerComponent: 8, bytesPerRow: 28, space: colorSpace, bitmapInfo: bitmapInfo) 72 | 73 | // scale and translate so we have the full digit and in MNIST standard size 28x28 74 | context!.translateBy(x: 0 , y: 28) 75 | context!.scaleBy(x: 28/self.frame.size.width, y: -28/self.frame.size.height) 76 | 77 | // put view pixel data in context 78 | self.layer.render(in: context!) 79 | 80 | return context 81 | } 82 | } 83 | 84 | /** 85 | 2 points can give a line and this class is just for that purpose, it keeps a record of a line 86 | */ 87 | class Line{ 88 | var start, end: CGPoint 89 | 90 | init(start: CGPoint, end: CGPoint) { 91 | self.start = start 92 | self.end = end 93 | } 94 | } 95 | 96 | 97 | -------------------------------------------------------------------------------- /iOS-CoreML-MNIST/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 35 | 46 | 47 | 48 | 49 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /iOS-CoreML-MNIST.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 54; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | A80B55D92114219600A213C2 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = A80B55D82114219600A213C2 /* AppDelegate.swift */; }; 11 | A80B55DB2114219600A213C2 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A80B55DA2114219600A213C2 /* ViewController.swift */; }; 12 | A80B55DE2114219700A213C2 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = A80B55DC2114219700A213C2 /* Main.storyboard */; }; 13 | A80B55E0211421A200A213C2 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A80B55DF211421A200A213C2 /* Assets.xcassets */; }; 14 | A80B55E3211421A200A213C2 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = A80B55E1211421A200A213C2 /* LaunchScreen.storyboard */; }; 15 | A80B55EB2114227200A213C2 /* mnistCNN.mlmodel in Sources */ = {isa = PBXBuildFile; fileRef = A80B55EA2114227200A213C2 /* mnistCNN.mlmodel */; }; 16 | A80B55ED211422F700A213C2 /* DrawView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A80B55EC211422F700A213C2 /* DrawView.swift */; }; 17 | /* End PBXBuildFile section */ 18 | 19 | /* Begin PBXFileReference section */ 20 | A80B55D52114219600A213C2 /* iOS-CoreML-MNIST.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "iOS-CoreML-MNIST.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 21 | A80B55D82114219600A213C2 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 22 | A80B55DA2114219600A213C2 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 23 | A80B55DD2114219700A213C2 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 24 | A80B55DF211421A200A213C2 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 25 | A80B55E2211421A200A213C2 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 26 | A80B55E4211421A200A213C2 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 27 | A80B55EA2114227200A213C2 /* mnistCNN.mlmodel */ = {isa = PBXFileReference; lastKnownFileType = file.mlmodel; path = mnistCNN.mlmodel; sourceTree = ""; }; 28 | A80B55EC211422F700A213C2 /* DrawView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DrawView.swift; sourceTree = ""; }; 29 | /* End PBXFileReference section */ 30 | 31 | /* Begin PBXFrameworksBuildPhase section */ 32 | A80B55D22114219600A213C2 /* Frameworks */ = { 33 | isa = PBXFrameworksBuildPhase; 34 | buildActionMask = 2147483647; 35 | files = ( 36 | ); 37 | runOnlyForDeploymentPostprocessing = 0; 38 | }; 39 | /* End PBXFrameworksBuildPhase section */ 40 | 41 | /* Begin PBXGroup section */ 42 | A80B55CC2114219600A213C2 = { 43 | isa = PBXGroup; 44 | children = ( 45 | A80B55D72114219600A213C2 /* iOS-CoreML-MNIST */, 46 | A80B55D62114219600A213C2 /* Products */, 47 | ); 48 | sourceTree = ""; 49 | }; 50 | A80B55D62114219600A213C2 /* Products */ = { 51 | isa = PBXGroup; 52 | children = ( 53 | A80B55D52114219600A213C2 /* iOS-CoreML-MNIST.app */, 54 | ); 55 | name = Products; 56 | sourceTree = ""; 57 | }; 58 | A80B55D72114219600A213C2 /* iOS-CoreML-MNIST */ = { 59 | isa = PBXGroup; 60 | children = ( 61 | A80B55EA2114227200A213C2 /* mnistCNN.mlmodel */, 62 | A80B55D82114219600A213C2 /* AppDelegate.swift */, 63 | A80B55DA2114219600A213C2 /* ViewController.swift */, 64 | A80B55DC2114219700A213C2 /* Main.storyboard */, 65 | A80B55DF211421A200A213C2 /* Assets.xcassets */, 66 | A80B55E1211421A200A213C2 /* LaunchScreen.storyboard */, 67 | A80B55E4211421A200A213C2 /* Info.plist */, 68 | A80B55EC211422F700A213C2 /* DrawView.swift */, 69 | ); 70 | path = "iOS-CoreML-MNIST"; 71 | sourceTree = ""; 72 | }; 73 | /* End PBXGroup section */ 74 | 75 | /* Begin PBXNativeTarget section */ 76 | A80B55D42114219600A213C2 /* iOS-CoreML-MNIST */ = { 77 | isa = PBXNativeTarget; 78 | buildConfigurationList = A80B55E7211421A200A213C2 /* Build configuration list for PBXNativeTarget "iOS-CoreML-MNIST" */; 79 | buildPhases = ( 80 | A80B55D12114219600A213C2 /* Sources */, 81 | A80B55D22114219600A213C2 /* Frameworks */, 82 | A80B55D32114219600A213C2 /* Resources */, 83 | ); 84 | buildRules = ( 85 | ); 86 | dependencies = ( 87 | ); 88 | name = "iOS-CoreML-MNIST"; 89 | productName = "iOS-CoreML-MNIST"; 90 | productReference = A80B55D52114219600A213C2 /* iOS-CoreML-MNIST.app */; 91 | productType = "com.apple.product-type.application"; 92 | }; 93 | /* End PBXNativeTarget section */ 94 | 95 | /* Begin PBXProject section */ 96 | A80B55CD2114219600A213C2 /* Project object */ = { 97 | isa = PBXProject; 98 | attributes = { 99 | LastSwiftUpdateCheck = 1000; 100 | LastUpgradeCheck = 1200; 101 | ORGANIZATIONNAME = "Sri Raghu Malireddi"; 102 | TargetAttributes = { 103 | A80B55D42114219600A213C2 = { 104 | CreatedOnToolsVersion = 10.0; 105 | LastSwiftMigration = 1120; 106 | }; 107 | }; 108 | }; 109 | buildConfigurationList = A80B55D02114219600A213C2 /* Build configuration list for PBXProject "iOS-CoreML-MNIST" */; 110 | compatibilityVersion = "Xcode 12.0"; 111 | developmentRegion = en; 112 | hasScannedForEncodings = 0; 113 | knownRegions = ( 114 | en, 115 | Base, 116 | ); 117 | mainGroup = A80B55CC2114219600A213C2; 118 | productRefGroup = A80B55D62114219600A213C2 /* Products */; 119 | projectDirPath = ""; 120 | projectRoot = ""; 121 | targets = ( 122 | A80B55D42114219600A213C2 /* iOS-CoreML-MNIST */, 123 | ); 124 | }; 125 | /* End PBXProject section */ 126 | 127 | /* Begin PBXResourcesBuildPhase section */ 128 | A80B55D32114219600A213C2 /* Resources */ = { 129 | isa = PBXResourcesBuildPhase; 130 | buildActionMask = 2147483647; 131 | files = ( 132 | A80B55E3211421A200A213C2 /* LaunchScreen.storyboard in Resources */, 133 | A80B55E0211421A200A213C2 /* Assets.xcassets in Resources */, 134 | A80B55DE2114219700A213C2 /* Main.storyboard in Resources */, 135 | ); 136 | runOnlyForDeploymentPostprocessing = 0; 137 | }; 138 | /* End PBXResourcesBuildPhase section */ 139 | 140 | /* Begin PBXSourcesBuildPhase section */ 141 | A80B55D12114219600A213C2 /* Sources */ = { 142 | isa = PBXSourcesBuildPhase; 143 | buildActionMask = 2147483647; 144 | files = ( 145 | A80B55DB2114219600A213C2 /* ViewController.swift in Sources */, 146 | A80B55EB2114227200A213C2 /* mnistCNN.mlmodel in Sources */, 147 | A80B55ED211422F700A213C2 /* DrawView.swift in Sources */, 148 | A80B55D92114219600A213C2 /* AppDelegate.swift in Sources */, 149 | ); 150 | runOnlyForDeploymentPostprocessing = 0; 151 | }; 152 | /* End PBXSourcesBuildPhase section */ 153 | 154 | /* Begin PBXVariantGroup section */ 155 | A80B55DC2114219700A213C2 /* Main.storyboard */ = { 156 | isa = PBXVariantGroup; 157 | children = ( 158 | A80B55DD2114219700A213C2 /* Base */, 159 | ); 160 | name = Main.storyboard; 161 | sourceTree = ""; 162 | }; 163 | A80B55E1211421A200A213C2 /* LaunchScreen.storyboard */ = { 164 | isa = PBXVariantGroup; 165 | children = ( 166 | A80B55E2211421A200A213C2 /* Base */, 167 | ); 168 | name = LaunchScreen.storyboard; 169 | sourceTree = ""; 170 | }; 171 | /* End PBXVariantGroup section */ 172 | 173 | /* Begin XCBuildConfiguration section */ 174 | A80B55E5211421A200A213C2 /* Debug */ = { 175 | isa = XCBuildConfiguration; 176 | buildSettings = { 177 | ALWAYS_SEARCH_USER_PATHS = NO; 178 | CLANG_ANALYZER_NONNULL = YES; 179 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 180 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 181 | CLANG_CXX_LIBRARY = "libc++"; 182 | CLANG_ENABLE_MODULES = YES; 183 | CLANG_ENABLE_OBJC_ARC = YES; 184 | CLANG_ENABLE_OBJC_WEAK = YES; 185 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 186 | CLANG_WARN_BOOL_CONVERSION = YES; 187 | CLANG_WARN_COMMA = YES; 188 | CLANG_WARN_CONSTANT_CONVERSION = YES; 189 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 190 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 191 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 192 | CLANG_WARN_EMPTY_BODY = YES; 193 | CLANG_WARN_ENUM_CONVERSION = YES; 194 | CLANG_WARN_INFINITE_RECURSION = YES; 195 | CLANG_WARN_INT_CONVERSION = YES; 196 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 197 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 198 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 199 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 200 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 201 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 202 | CLANG_WARN_STRICT_PROTOTYPES = YES; 203 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 204 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 205 | CLANG_WARN_UNREACHABLE_CODE = YES; 206 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 207 | CODE_SIGN_IDENTITY = "iPhone Developer"; 208 | COPY_PHASE_STRIP = NO; 209 | DEBUG_INFORMATION_FORMAT = dwarf; 210 | ENABLE_STRICT_OBJC_MSGSEND = YES; 211 | ENABLE_TESTABILITY = YES; 212 | GCC_C_LANGUAGE_STANDARD = gnu11; 213 | GCC_DYNAMIC_NO_PIC = NO; 214 | GCC_NO_COMMON_BLOCKS = YES; 215 | GCC_OPTIMIZATION_LEVEL = 0; 216 | GCC_PREPROCESSOR_DEFINITIONS = ( 217 | "DEBUG=1", 218 | "$(inherited)", 219 | ); 220 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 221 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 222 | GCC_WARN_UNDECLARED_SELECTOR = YES; 223 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 224 | GCC_WARN_UNUSED_FUNCTION = YES; 225 | GCC_WARN_UNUSED_VARIABLE = YES; 226 | IPHONEOS_DEPLOYMENT_TARGET = 14.0; 227 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 228 | ONLY_ACTIVE_ARCH = YES; 229 | SDKROOT = iphoneos; 230 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 231 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 232 | }; 233 | name = Debug; 234 | }; 235 | A80B55E6211421A200A213C2 /* Release */ = { 236 | isa = XCBuildConfiguration; 237 | buildSettings = { 238 | ALWAYS_SEARCH_USER_PATHS = NO; 239 | CLANG_ANALYZER_NONNULL = YES; 240 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 241 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 242 | CLANG_CXX_LIBRARY = "libc++"; 243 | CLANG_ENABLE_MODULES = YES; 244 | CLANG_ENABLE_OBJC_ARC = YES; 245 | CLANG_ENABLE_OBJC_WEAK = YES; 246 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 247 | CLANG_WARN_BOOL_CONVERSION = YES; 248 | CLANG_WARN_COMMA = YES; 249 | CLANG_WARN_CONSTANT_CONVERSION = YES; 250 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 251 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 252 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 253 | CLANG_WARN_EMPTY_BODY = YES; 254 | CLANG_WARN_ENUM_CONVERSION = YES; 255 | CLANG_WARN_INFINITE_RECURSION = YES; 256 | CLANG_WARN_INT_CONVERSION = YES; 257 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 258 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 259 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 260 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 261 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 262 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 263 | CLANG_WARN_STRICT_PROTOTYPES = YES; 264 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 265 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 266 | CLANG_WARN_UNREACHABLE_CODE = YES; 267 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 268 | CODE_SIGN_IDENTITY = "iPhone Developer"; 269 | COPY_PHASE_STRIP = NO; 270 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 271 | ENABLE_NS_ASSERTIONS = NO; 272 | ENABLE_STRICT_OBJC_MSGSEND = YES; 273 | GCC_C_LANGUAGE_STANDARD = gnu11; 274 | GCC_NO_COMMON_BLOCKS = YES; 275 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 276 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 277 | GCC_WARN_UNDECLARED_SELECTOR = YES; 278 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 279 | GCC_WARN_UNUSED_FUNCTION = YES; 280 | GCC_WARN_UNUSED_VARIABLE = YES; 281 | IPHONEOS_DEPLOYMENT_TARGET = 14.0; 282 | MTL_ENABLE_DEBUG_INFO = NO; 283 | SDKROOT = iphoneos; 284 | SWIFT_COMPILATION_MODE = wholemodule; 285 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 286 | VALIDATE_PRODUCT = YES; 287 | }; 288 | name = Release; 289 | }; 290 | A80B55E8211421A200A213C2 /* Debug */ = { 291 | isa = XCBuildConfiguration; 292 | buildSettings = { 293 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 294 | CODE_SIGN_STYLE = Automatic; 295 | DEVELOPMENT_TEAM = HAFX6G88W7; 296 | INFOPLIST_FILE = "iOS-CoreML-MNIST/Info.plist"; 297 | IPHONEOS_DEPLOYMENT_TARGET = 14.0; 298 | LD_RUNPATH_SEARCH_PATHS = ( 299 | "$(inherited)", 300 | "@executable_path/Frameworks", 301 | ); 302 | PRODUCT_BUNDLE_IDENTIFIER = "com.sri.iOS.iOS-CoreML-MNIST"; 303 | PRODUCT_NAME = "$(TARGET_NAME)"; 304 | SWIFT_VERSION = 5.0; 305 | TARGETED_DEVICE_FAMILY = "1,2"; 306 | }; 307 | name = Debug; 308 | }; 309 | A80B55E9211421A200A213C2 /* Release */ = { 310 | isa = XCBuildConfiguration; 311 | buildSettings = { 312 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 313 | CODE_SIGN_STYLE = Automatic; 314 | DEVELOPMENT_TEAM = HAFX6G88W7; 315 | INFOPLIST_FILE = "iOS-CoreML-MNIST/Info.plist"; 316 | IPHONEOS_DEPLOYMENT_TARGET = 14.0; 317 | LD_RUNPATH_SEARCH_PATHS = ( 318 | "$(inherited)", 319 | "@executable_path/Frameworks", 320 | ); 321 | PRODUCT_BUNDLE_IDENTIFIER = "com.sri.iOS.iOS-CoreML-MNIST"; 322 | PRODUCT_NAME = "$(TARGET_NAME)"; 323 | SWIFT_VERSION = 5.0; 324 | TARGETED_DEVICE_FAMILY = "1,2"; 325 | }; 326 | name = Release; 327 | }; 328 | /* End XCBuildConfiguration section */ 329 | 330 | /* Begin XCConfigurationList section */ 331 | A80B55D02114219600A213C2 /* Build configuration list for PBXProject "iOS-CoreML-MNIST" */ = { 332 | isa = XCConfigurationList; 333 | buildConfigurations = ( 334 | A80B55E5211421A200A213C2 /* Debug */, 335 | A80B55E6211421A200A213C2 /* Release */, 336 | ); 337 | defaultConfigurationIsVisible = 0; 338 | defaultConfigurationName = Release; 339 | }; 340 | A80B55E7211421A200A213C2 /* Build configuration list for PBXNativeTarget "iOS-CoreML-MNIST" */ = { 341 | isa = XCConfigurationList; 342 | buildConfigurations = ( 343 | A80B55E8211421A200A213C2 /* Debug */, 344 | A80B55E9211421A200A213C2 /* Release */, 345 | ); 346 | defaultConfigurationIsVisible = 0; 347 | defaultConfigurationName = Release; 348 | }; 349 | /* End XCConfigurationList section */ 350 | }; 351 | rootObject = A80B55CD2114219600A213C2 /* Project object */; 352 | } 353 | -------------------------------------------------------------------------------- /nnet/MNIST CNN.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Import necessary libraries" 8 | ] 9 | }, 10 | { 11 | "cell_type": "code", 12 | "execution_count": 1, 13 | "metadata": {}, 14 | "outputs": [ 15 | { 16 | "name": "stderr", 17 | "output_type": "stream", 18 | "text": [ 19 | "Using TensorFlow backend.\n" 20 | ] 21 | } 22 | ], 23 | "source": [ 24 | "import numpy as np\n", 25 | "import matplotlib.pyplot as plt\n", 26 | "%matplotlib inline\n", 27 | "\n", 28 | "import keras\n", 29 | "\n", 30 | "from keras.datasets import mnist\n", 31 | "from keras.models import Sequential\n", 32 | "from keras.layers import Dense, Dropout, Flatten\n", 33 | "from keras.layers.convolutional import Conv2D, MaxPooling2D\n", 34 | "from keras.utils import np_utils\n", 35 | "\n", 36 | "# (Making sure) Set backend as tensorflow\n", 37 | "from keras import backend as K\n", 38 | "K.set_image_dim_ordering('tf')" 39 | ] 40 | }, 41 | { 42 | "cell_type": "markdown", 43 | "metadata": {}, 44 | "source": [ 45 | "# Dataset\n", 46 | "Keras has helper functions to setup the MNIST dataset. Let us create the train and test split." 47 | ] 48 | }, 49 | { 50 | "cell_type": "code", 51 | "execution_count": 2, 52 | "metadata": {}, 53 | "outputs": [ 54 | { 55 | "name": "stdout", 56 | "output_type": "stream", 57 | "text": [ 58 | "X_train: (60000, 28, 28) y_train: (60000,)\n", 59 | "X_test : (10000, 28, 28) y_test : (10000,)\n" 60 | ] 61 | } 62 | ], 63 | "source": [ 64 | "(X_train, y_train), (X_test, y_test) = mnist.load_data()\n", 65 | "print \"X_train:\", X_train.shape, \"y_train:\", y_train.shape\n", 66 | "print \"X_test :\", X_test.shape, \"y_test :\", y_test.shape" 67 | ] 68 | }, 69 | { 70 | "cell_type": "markdown", 71 | "metadata": {}, 72 | "source": [ 73 | "# Re-format Input\n", 74 | "Let us reshape the data into TensorFlow friendly format: (batch_size, num_rows, num_cols, num_channels)" 75 | ] 76 | }, 77 | { 78 | "cell_type": "code", 79 | "execution_count": 3, 80 | "metadata": {}, 81 | "outputs": [ 82 | { 83 | "name": "stdout", 84 | "output_type": "stream", 85 | "text": [ 86 | "X_train: (60000, 28, 28, 1) X_test: (10000, 28, 28, 1)\n" 87 | ] 88 | } 89 | ], 90 | "source": [ 91 | "num_rows = 28\n", 92 | "num_cols = 28\n", 93 | "num_channels = 1\n", 94 | "num_classes = 10\n", 95 | "\n", 96 | "X_train = X_train.reshape(X_train.shape[0], num_rows, num_cols, num_channels).astype(np.float32) / 255\n", 97 | "X_test = X_test.reshape(X_test.shape[0], num_rows, num_cols, num_channels).astype(np.float32) / 255\n", 98 | "\n", 99 | "print \"X_train:\", X_train.shape, \"X_test:\", X_test.shape" 100 | ] 101 | }, 102 | { 103 | "cell_type": "markdown", 104 | "metadata": {}, 105 | "source": [ 106 | "# Re-format Output\n", 107 | "The output is classification among ten classes [0..9]. " 108 | ] 109 | }, 110 | { 111 | "cell_type": "code", 112 | "execution_count": 4, 113 | "metadata": {}, 114 | "outputs": [ 115 | { 116 | "name": "stdout", 117 | "output_type": "stream", 118 | "text": [ 119 | "y_train: (60000, 10) y_test: (10000, 10)\n" 120 | ] 121 | } 122 | ], 123 | "source": [ 124 | "y_train = np_utils.to_categorical(y_train)\n", 125 | "y_test = np_utils.to_categorical(y_test)\n", 126 | "\n", 127 | "print \"y_train:\", y_train.shape, \"y_test:\", y_test.shape" 128 | ] 129 | }, 130 | { 131 | "cell_type": "markdown", 132 | "metadata": {}, 133 | "source": [ 134 | "# Visualize the data" 135 | ] 136 | }, 137 | { 138 | "cell_type": "code", 139 | "execution_count": 5, 140 | "metadata": {}, 141 | "outputs": [ 142 | { 143 | "data": { 144 | "image/png": "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\n", 145 | "text/plain": [ 146 | "" 147 | ] 148 | }, 149 | "metadata": {}, 150 | "output_type": "display_data" 151 | }, 152 | { 153 | "name": "stdout", 154 | "output_type": "stream", 155 | "text": [ 156 | "Label: 7\n" 157 | ] 158 | } 159 | ], 160 | "source": [ 161 | "im = X_train[1001,:,:,0]\n", 162 | "plt.imshow(im,cmap='gray')\n", 163 | "plt.show()\n", 164 | "\n", 165 | "print 'Label:',np.nonzero(y_train[1001,:])[0][0]" 166 | ] 167 | }, 168 | { 169 | "cell_type": "code", 170 | "execution_count": 6, 171 | "metadata": {}, 172 | "outputs": [ 173 | { 174 | "data": { 175 | "image/png": "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\n", 176 | "text/plain": [ 177 | "" 178 | ] 179 | }, 180 | "metadata": {}, 181 | "output_type": "display_data" 182 | }, 183 | { 184 | "name": "stdout", 185 | "output_type": "stream", 186 | "text": [ 187 | "Label: 3\n" 188 | ] 189 | } 190 | ], 191 | "source": [ 192 | "im = X_train[5036,:,:,0]\n", 193 | "plt.imshow(im,cmap='gray')\n", 194 | "plt.show()\n", 195 | "\n", 196 | "print 'Label:',np.nonzero(y_train[5036,:])[0][0]" 197 | ] 198 | }, 199 | { 200 | "cell_type": "markdown", 201 | "metadata": {}, 202 | "source": [ 203 | "# Build the model" 204 | ] 205 | }, 206 | { 207 | "cell_type": "code", 208 | "execution_count": 7, 209 | "metadata": { 210 | "collapsed": true 211 | }, 212 | "outputs": [], 213 | "source": [ 214 | "model = Sequential()\n", 215 | "\n", 216 | "model.add(Conv2D(32, (5, 5), input_shape=(28, 28, 1), activation='relu'))\n", 217 | "model.add(MaxPooling2D(pool_size=(2, 2)))\n", 218 | "model.add(Dropout(0.5))\n", 219 | "model.add(Conv2D(64, (3, 3), activation='relu'))\n", 220 | "model.add(MaxPooling2D(pool_size=(2, 2)))\n", 221 | "model.add(Dropout(0.2))\n", 222 | "model.add(Conv2D(128, (1, 1), activation='relu'))\n", 223 | "model.add(MaxPooling2D(pool_size=(2, 2)))\n", 224 | "model.add(Dropout(0.2))\n", 225 | "model.add(Flatten())\n", 226 | "model.add(Dense(128, activation='relu'))\n", 227 | "model.add(Dense(num_classes, activation='softmax'))\n", 228 | "\n", 229 | "model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])" 230 | ] 231 | }, 232 | { 233 | "cell_type": "code", 234 | "execution_count": 8, 235 | "metadata": {}, 236 | "outputs": [ 237 | { 238 | "name": "stdout", 239 | "output_type": "stream", 240 | "text": [ 241 | "_________________________________________________________________\n", 242 | "Layer (type) Output Shape Param # \n", 243 | "=================================================================\n", 244 | "conv2d_1 (Conv2D) (None, 24, 24, 32) 832 \n", 245 | "_________________________________________________________________\n", 246 | "max_pooling2d_1 (MaxPooling2 (None, 12, 12, 32) 0 \n", 247 | "_________________________________________________________________\n", 248 | "dropout_1 (Dropout) (None, 12, 12, 32) 0 \n", 249 | "_________________________________________________________________\n", 250 | "conv2d_2 (Conv2D) (None, 10, 10, 64) 18496 \n", 251 | "_________________________________________________________________\n", 252 | "max_pooling2d_2 (MaxPooling2 (None, 5, 5, 64) 0 \n", 253 | "_________________________________________________________________\n", 254 | "dropout_2 (Dropout) (None, 5, 5, 64) 0 \n", 255 | "_________________________________________________________________\n", 256 | "conv2d_3 (Conv2D) (None, 5, 5, 128) 8320 \n", 257 | "_________________________________________________________________\n", 258 | "max_pooling2d_3 (MaxPooling2 (None, 2, 2, 128) 0 \n", 259 | "_________________________________________________________________\n", 260 | "dropout_3 (Dropout) (None, 2, 2, 128) 0 \n", 261 | "_________________________________________________________________\n", 262 | "flatten_1 (Flatten) (None, 512) 0 \n", 263 | "_________________________________________________________________\n", 264 | "dense_1 (Dense) (None, 128) 65664 \n", 265 | "_________________________________________________________________\n", 266 | "dense_2 (Dense) (None, 10) 1290 \n", 267 | "=================================================================\n", 268 | "Total params: 94,602\n", 269 | "Trainable params: 94,602\n", 270 | "Non-trainable params: 0\n", 271 | "_________________________________________________________________\n" 272 | ] 273 | } 274 | ], 275 | "source": [ 276 | "model.summary()" 277 | ] 278 | }, 279 | { 280 | "cell_type": "markdown", 281 | "metadata": {}, 282 | "source": [ 283 | "# Train the model" 284 | ] 285 | }, 286 | { 287 | "cell_type": "code", 288 | "execution_count": 11, 289 | "metadata": {}, 290 | "outputs": [ 291 | { 292 | "name": "stdout", 293 | "output_type": "stream", 294 | "text": [ 295 | "Train on 60000 samples, validate on 10000 samples\n", 296 | "Epoch 1/10\n", 297 | "98s - loss: 0.0581 - acc: 0.9815 - val_loss: 0.0346 - val_acc: 0.9891\n", 298 | "Epoch 2/10\n", 299 | "81s - loss: 0.0553 - acc: 0.9823 - val_loss: 0.0317 - val_acc: 0.9911\n", 300 | "Epoch 3/10\n", 301 | "89s - loss: 0.0512 - acc: 0.9836 - val_loss: 0.0298 - val_acc: 0.9910\n", 302 | "Epoch 4/10\n", 303 | "79s - loss: 0.0492 - acc: 0.9842 - val_loss: 0.0271 - val_acc: 0.9921\n", 304 | "Epoch 5/10\n", 305 | "105s - loss: 0.0463 - acc: 0.9857 - val_loss: 0.0270 - val_acc: 0.9927\n", 306 | "Epoch 6/10\n", 307 | "104s - loss: 0.0462 - acc: 0.9854 - val_loss: 0.0264 - val_acc: 0.9913\n", 308 | "Epoch 7/10\n", 309 | "88s - loss: 0.0447 - acc: 0.9861 - val_loss: 0.0239 - val_acc: 0.9928\n", 310 | "Epoch 8/10\n", 311 | "85s - loss: 0.0432 - acc: 0.9864 - val_loss: 0.0257 - val_acc: 0.9922\n", 312 | "Epoch 9/10\n", 313 | "79s - loss: 0.0414 - acc: 0.9865 - val_loss: 0.0255 - val_acc: 0.9925\n", 314 | "Epoch 10/10\n", 315 | "80s - loss: 0.0388 - acc: 0.9875 - val_loss: 0.0269 - val_acc: 0.9910\n" 316 | ] 317 | }, 318 | { 319 | "data": { 320 | "text/plain": [ 321 | "" 322 | ] 323 | }, 324 | "execution_count": 11, 325 | "metadata": {}, 326 | "output_type": "execute_result" 327 | } 328 | ], 329 | "source": [ 330 | "model.fit(X_train, y_train, validation_data=(X_test, y_test), epochs=10, batch_size=200, verbose=2)" 331 | ] 332 | }, 333 | { 334 | "cell_type": "markdown", 335 | "metadata": {}, 336 | "source": [ 337 | "# Remove Dropouts for Inference" 338 | ] 339 | }, 340 | { 341 | "cell_type": "code", 342 | "execution_count": 15, 343 | "metadata": { 344 | "collapsed": true 345 | }, 346 | "outputs": [], 347 | "source": [ 348 | "for k in model.layers:\n", 349 | " if type(k) is keras.layers.Dropout:\n", 350 | " model.layers.remove(k)" 351 | ] 352 | }, 353 | { 354 | "cell_type": "code", 355 | "execution_count": 16, 356 | "metadata": {}, 357 | "outputs": [ 358 | { 359 | "name": "stdout", 360 | "output_type": "stream", 361 | "text": [ 362 | "_________________________________________________________________\n", 363 | "Layer (type) Output Shape Param # \n", 364 | "=================================================================\n", 365 | "conv2d_1 (Conv2D) (None, 24, 24, 32) 832 \n", 366 | "_________________________________________________________________\n", 367 | "max_pooling2d_1 (MaxPooling2 (None, 12, 12, 32) 0 \n", 368 | "_________________________________________________________________\n", 369 | "conv2d_2 (Conv2D) (None, 10, 10, 64) 18496 \n", 370 | "_________________________________________________________________\n", 371 | "max_pooling2d_2 (MaxPooling2 (None, 5, 5, 64) 0 \n", 372 | "_________________________________________________________________\n", 373 | "conv2d_3 (Conv2D) (None, 5, 5, 128) 8320 \n", 374 | "_________________________________________________________________\n", 375 | "max_pooling2d_3 (MaxPooling2 (None, 2, 2, 128) 0 \n", 376 | "_________________________________________________________________\n", 377 | "flatten_1 (Flatten) (None, 512) 0 \n", 378 | "_________________________________________________________________\n", 379 | "dense_1 (Dense) (None, 128) 65664 \n", 380 | "_________________________________________________________________\n", 381 | "dense_2 (Dense) (None, 10) 1290 \n", 382 | "=================================================================\n", 383 | "Total params: 94,602\n", 384 | "Trainable params: 94,602\n", 385 | "Non-trainable params: 0\n", 386 | "_________________________________________________________________\n" 387 | ] 388 | } 389 | ], 390 | "source": [ 391 | "model.summary()" 392 | ] 393 | }, 394 | { 395 | "cell_type": "code", 396 | "execution_count": 17, 397 | "metadata": { 398 | "collapsed": true 399 | }, 400 | "outputs": [], 401 | "source": [ 402 | "# Save the model\n", 403 | "model.save('mnistCNN.h5')" 404 | ] 405 | }, 406 | { 407 | "cell_type": "code", 408 | "execution_count": 2, 409 | "metadata": {}, 410 | "outputs": [ 411 | { 412 | "name": "stdout", 413 | "output_type": "stream", 414 | "text": [ 415 | "0 : conv2d_1_input, \n", 416 | "1 : conv2d_1, \n", 417 | "2 : conv2d_1__activation__, \n", 418 | "3 : max_pooling2d_1, \n", 419 | "4 : conv2d_2, \n", 420 | "5 : conv2d_2__activation__, \n", 421 | "6 : max_pooling2d_2, \n", 422 | "7 : conv2d_3, \n", 423 | "8 : conv2d_3__activation__, \n", 424 | "9 : max_pooling2d_3, \n", 425 | "10 : flatten_1, \n", 426 | "11 : dense_1, \n", 427 | "12 : dense_1__activation__, \n", 428 | "13 : dense_2, \n", 429 | "14 : dense_2__activation__, \n" 430 | ] 431 | } 432 | ], 433 | "source": [ 434 | "import coremltools\n", 435 | "\n", 436 | "output_labels = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']\n", 437 | "scale = 1/255.\n", 438 | "coreml_model = coremltools.converters.keras.convert('./mnistCNN.h5',\n", 439 | " input_names='image',\n", 440 | " image_input_names='image',\n", 441 | " output_names='output',\n", 442 | " class_labels=output_labels,\n", 443 | " image_scale=scale)\n", 444 | "\n", 445 | "coreml_model.author = 'Sri Raghu Malireddi'\n", 446 | "coreml_model.license = 'MIT'\n", 447 | "coreml_model.short_description = 'Model to classify hand written digit'\n", 448 | "\n", 449 | "coreml_model.input_description['image'] = 'Grayscale image of hand written digit'\n", 450 | "coreml_model.output_description['output'] = 'Predicted digit'\n", 451 | "\n", 452 | "coreml_model.save('mnistCNN.mlmodel')" 453 | ] 454 | }, 455 | { 456 | "cell_type": "code", 457 | "execution_count": null, 458 | "metadata": { 459 | "collapsed": true 460 | }, 461 | "outputs": [], 462 | "source": [] 463 | } 464 | ], 465 | "metadata": { 466 | "kernelspec": { 467 | "display_name": "Python 2", 468 | "language": "python", 469 | "name": "python2" 470 | }, 471 | "language_info": { 472 | "codemirror_mode": { 473 | "name": "ipython", 474 | "version": 2 475 | }, 476 | "file_extension": ".py", 477 | "mimetype": "text/x-python", 478 | "name": "python", 479 | "nbconvert_exporter": "python", 480 | "pygments_lexer": "ipython2", 481 | "version": "2.7.13" 482 | } 483 | }, 484 | "nbformat": 4, 485 | "nbformat_minor": 2 486 | } 487 | --------------------------------------------------------------------------------