Using the tutorial found at blog.keras.io/building-powerful-image-classification-models-using-very-little-data.html, I trained a Keras model to recognize 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
# dimensions of our images.
img_width, img_height = 150, 150
train_data_dir = 'data/train'
validation_data_dir = 'data/validation'
nb_train_samples = 2000
nb_validation_samples = 800
epochs = 50
batch_size = 16
if K.image_data_format() == 'channels_first':
input_shape = (3, img_width, img_height)
else:
input_shape = (img_width, img_height, 3)
model = Sequential()
model.add(Conv2D(32, (3, 3), input_shape=input_shape))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Conv2D(32, (3, 3)))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Conv2D(64, (3, 3)))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Flatten()) model.add(Dense(64))
model.add(Activation('relu'))
model.add(Dropout(0.5))
model.add(Dense(1))
model.add(Activation('sigmoid'))
model.compile(loss='binary_crossentropy', optimizer='rmsprop', metrics=['accuracy'])
# this is the augmentation configuration we will use for training
train_datagen = ImageDataGenerator( rescale=1. / 255, shear_range=0.2, zoom_range=0.2, horizontal_flip=True)
# this is the augmentation configuration we will use for testing:
# only rescaling
test_datagen = ImageDataGenerator(rescale=1. / 255)
train_generator = train_datagen.flow_from_directory( train_data_dir, target_size=(img_width, img_height), batch_size=batch_size, class_mode='binary')
validation_generator = test_datagen.flow_from_directory( validation_data_dir, target_size=(img_width, img_height), batch_size=batch_size, class_mode='binary')
model.fit_generator( train_generator, steps_per_epoch=nb_train_samples / epochs=epochs, validation_data=validation_generator, validation_steps=nb_validation_samples /
model.save('first_try.h5')
Using the coremltools documentation as a guide, I tried converting my model to the 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 the model into XCode and run it with the following code (which works with the resnet50 and inceptionv3 models found on Apple's website), I get the error "Thread 8: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)." I have attached a screenshot of the error as it appears in XCode.
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 imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
if let pickedImage = info[UIImagePickerControllerOriginalImage] as? UIImage {
imageView.contentMode = .scaleAspectFit
imageView.image = pickedImage
textView.text = "Guessing..."
processImage(pickedImage.cgImage!) { [weak self] text in
self?.textView.text = text
}
}
picker.dismiss(animated: true, completion: nil)
}
}
//MARK: - CoreML
extension ViewController {
func processImage(_ image: CGImage, completion: @escaping (String)->Void ){
DispatchQueue.global(qos: .background).async {
//Init Core Vision Model
guard let vnCoreModel = try? VNCoreMLModel(for: cats_dogs().model) else { return }
//Init Core Vision Request
let request = VNCoreMLRequest(model: vnCoreModel) { (request, error) in
guard let results = request.results as? [VNClassificationObservation] else { fatalError("Failure") }
var text = ""
for classification in results {
text.append("\n" + "\(classification.identifier, classification.confidence)")
}
DispatchQueue.main.async {
completion(text)
}
}
//Init Core Vision Request Handler
let handler = VNImageRequestHandler(cgImage: image)
//Perform Core Vision Request
do {
try handler.perform([request])
} catch {
print("did throw on performing a VNCoreRequest")
}
}
}
}
I have searched the web extensively to solve this issue. Help to fix this issue would be much appreciated!