Using the tutorial found at https://blog.keras.io/building-powerful-image-classification-models-using-very-little-data.html , I trained the Keras model to find out the difference between cats and dogs.
''' Directory structure: data/ train/ dogs/ dog001.jpg dog002.jpg ... cats/ cat001.jpg cat002.jpg ... validation/ dogs/ dog001.jpg dog002.jpg ... cats/ cat001.jpg cat002.jpg ... ''' from keras.preprocessing.image import ImageDataGenerator from keras.models import Sequential from keras.layers import Conv2D, MaxPooling2D from keras.layers import Activation, Dropout, Flatten, Dense from keras import backend as K from PIL import Image import numpy as np
Using the coremltools documentation as a guide, I tried to convert my model to coreml format:
import coremltools import h5py coreml_model = coremltools.converters.keras.convert('first_try.h5',input_names='image',output_names='class',image_input_names = 'image',class_labels = ['cat', 'dog'], is_bgr=True) coreml_model.save('cats_dogs.mlmodel')
When I import a model into Xcode and run it with the following code (which works with the resnet50 and inceptionv3 models found on the Apple website), the code snippet guard let prediction = try? model.prediction(image: pixelBuffer!) else {print("error!") return } guard let prediction = try? model.prediction(image: pixelBuffer!) else {print("error!") return } prints "error!". and code snippet textView.text = "I think this is a \(String(describing: prediction.classLabel))." never achieved.
import UIKit import Vision import CoreML class ViewController: UIViewController, UINavigationControllerDelegate { //MARK: - Properties @IBOutlet weak var imageView: UIImageView! @IBOutlet weak var textView: UITextView! let imagePicker = UIImagePickerController() //MARK: - ViewController override func viewDidLoad() { super .viewDidLoad() self.imagePicker.delegate = self } @IBAction func openImagePicker(_ sender: Any) { imagePicker.allowsEditing = false imagePicker.sourceType = .photoLibrary present(imagePicker, animated: true, completion: nil) } @IBAction func camera(_ sender: Any) { if !UIImagePickerController.isSourceTypeAvailable(.camera) { return } let cameraPicker = UIImagePickerController() cameraPicker.delegate = self cameraPicker.sourceType = .camera cameraPicker.allowsEditing = false present(cameraPicker, animated: true) } } extension ViewController: UIImagePickerControllerDelegate { func imagePickerControllerDidCancel(_ picker: UIImagePickerController) { dismiss(animated: true, completion: nil) } func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) { picker.dismiss(animated: true) textView.text = "Analyzing Image..." guard let image = info["UIImagePickerControllerOriginalImage"] as? UIImage else { return } UIGraphicsBeginImageContextWithOptions(CGSize(width: 150, height: 150), true, 2.0) image.draw(in: CGRect(x: 0, y: 0, width: 150, height: 150)) let newImage = UIGraphicsGetImageFromCurrentImageContext()! UIGraphicsEndImageContext() let attrs = [kCVPixelBufferCGImageCompatibilityKey: kCFBooleanTrue, kCVPixelBufferCGBitmapContextCompatibilityKey: kCFBooleanTrue] as CFDictionary var pixelBuffer : CVPixelBuffer? let status = CVPixelBufferCreate(kCFAllocatorDefault, Int(newImage.size.width), Int(newImage.size.height), kCVPixelFormatType_32ARGB, attrs, &pixelBuffer) guard (status == kCVReturnSuccess) else { return } CVPixelBufferLockBaseAddress(pixelBuffer!, CVPixelBufferLockFlags(rawValue: 0)) let pixelData = CVPixelBufferGetBaseAddress(pixelBuffer!) let rgbColorSpace = CGColorSpaceCreateDeviceRGB() let context = CGContext(data: pixelData, width: Int(newImage.size.width), height: Int(newImage.size.height), bitsPerComponent: 8, bytesPerRow: CVPixelBufferGetBytesPerRow(pixelBuffer!), space: rgbColorSpace, bitmapInfo: CGImageAlphaInfo.noneSkipFirst.rawValue) //3 context?.translateBy(x: 0, y: newImage.size.height) context?.scaleBy(x: 1.0, y: -1.0) UIGraphicsPushContext(context!) newImage.draw(in: CGRect(x: 0, y: 0, width: newImage.size.width, height: newImage.size.height)) UIGraphicsPopContext() CVPixelBufferUnlockBaseAddress(pixelBuffer!, CVPixelBufferLockFlags(rawValue: 0)) imageView.image = newImage guard let prediction = try? model.prediction(image: pixelBuffer!) else { print("error!") return } textView.text = "I think this is a \(String(describing: prediction.classLabel))." } }
Xcode Error Implementing Keras-CoreML Custom Model
I was looking for stackoverflow to solve this problem. Help in fixing this issue would be greatly appreciated!
==================================================== =========================== EDIT # 1:
Using "print (try! Model.prediction (image: pixelBuffer!) As Any)" I printed the following error:
2017-07-13 15: 33: 49.034967-0400 cats_dogs [60441: 1198094] fatal error: 'try!' the expression unexpectedly caused an error: Error Domain = com.apple.CoreML Code = 0 "Level dimensions" output "is not the same size as the number of class labels." UserInfo = {NSLocalizedDescription = The sizes of the output layer level do not match the number of class labels.}:
Not sure what “layer size” means, not the same as the number of class labels.
==================================================== ===========================
Edit # 2:
This is the code I use to convert the model to .mlmodel format
import coremltools import h5py output_labels = ['cat','dog'] coreml_model = coremltools.converters.keras.convert('first_try.h5',input_names='image',image_input_names = 'image',class_labels = output_labels, is_bgr=False) coreml_model.author = '' coreml_model.short_description = 'Model to classify images as either cats or dogs' coreml_model.input_description['image'] = 'Image of a cat or dog' print coreml_model coreml_model.save('cats_dogs.mlmodel')
This is the terminal output:
0 : conv2d_1_input, <keras.engine.topology.InputLayer object at 0x1194c6c50> 1 : conv2d_1, <keras.layers.convolutional.Conv2D object at 0x1194c6c90> 2 : activation_1, <keras.layers.core.Activation object at 0x119515b90> 3 : max_pooling2d_1, <keras.layers.pooling.MaxPooling2D object at 0x119501e50> 4 : conv2d_2, <keras.layers.convolutional.Conv2D object at 0x119520cd0> 5 : activation_2, <keras.layers.core.Activation object at 0x1194e8150> 6 : max_pooling2d_2, <keras.layers.pooling.MaxPooling2D object at 0x11955cc50> 7 : conv2d_3, <keras.layers.convolutional.Conv2D object at 0x11955ce50> 8 : activation_3, <keras.layers.core.Activation object at 0x11954d9d0> 9 : max_pooling2d_3, <keras.layers.pooling.MaxPooling2D object at 0x119594cd0> 10 : flatten_1, <keras.layers.core.Flatten object at 0x1195a08d0> 11 : dense_1, <keras.layers.core.Dense object at 0x119579f10> 12 : activation_4, <keras.layers.core.Activation object at 0x1195c94d0> 13 : dense_2, <keras.layers.core.Dense object at 0x1195ea450> 14 : activation_5, <keras.layers.core.Activation object at 0x119614b10> input { name: "image" shortDescription: "Image of a cat or dog" type { imageType { width: 150 height: 150 colorSpace: RGB } } } output { name: "output1" type { dictionaryType { stringKeyType { } } } } output { name: "classLabel" type { stringType { } } } predictedFeatureName: "classLabel" predictedProbabilitiesName: "output1" metadata { shortDescription: "Model to classify images as either cats or dogs" author: "" }