2017-07-11 5 views
8

Mit Hilfe des Tutorials unter https://blog.keras.io/building-powerful-image-classification-models-using-very-little-data.html trainierte ich ein Keras Modell, um den Unterschied zwischen Katzen und Hunden zu erkennen.Konvertiert das trainierte Keras Bildklassifikationsmodell in coreml und integriert es in iOS11

''' 
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 // batch_size, 
    epochs=epochs, 
    validation_data=validation_generator, 
    validation_steps=nb_validation_samples // batch_size) 

model.save('first_try.h5') 

die coremltools Mit documentation als Leitfaden, versuchte ich mein Modell zum coreml-Format zu konvertieren:

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') 

Als ich das Modell in XCode importieren und mit dem folgenden Code ausführen (die mit arbeitet die Modelle resnet50 und inceptionv3 auf Apples Website), das Code-Snippet guard let prediction = try? model.prediction(image: pixelBuffer!) else {print("error!") return } druckt "error!" und das Code-Snippet textView.text = "I think this is a \(String(describing: prediction.classLabel))." wird nie erreicht.

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 Custom Keras-CoreML model

ich gesucht habe Stackoverflow ausgiebig um dieses Problem zu lösen. Hilfe zur Behebung dieses Problems wäre sehr willkommen!

============================================== ========================== EDIT # 1:

Verwendung von "Drucken (versuchen! Model.Prediction (Bild: pixelBuffer!) as Any) "Ich habe folgenden Fehler ausgegeben:

2017-07-13 15: 33: 49.034967-0400 cats_dogs [60441: 1198094] fataler Fehler: 'try!' Ausdruck hat unerwarteterweise einen Fehler ausgelöst: Fehler Domain = com.apple.CoreML Code = 0 "Die Abmessungen des Layers 'output' haben nicht dieselbe Größe wie die Anzahl der Klassenbezeichnungen." Userinfo = {NSLocalizedDescription = Maße der Schicht ‚Output‘ ist nicht die gleiche Größe wie die Anzahl der Klassen Labeln.}:

nicht sicher, was „Dimensionen der Schicht‚Output‘ist nicht die gleiche Größe wie die Anzahl der Klasse-Etiketten " meint.

============================================== =============================

Edit # 2:

Dies ist der Code, den ich das verwenden konvertieren Modell zum .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') 

Dies ist die Terminal-Ausgabe:

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: "" 
} 

Antwort

0

Not sure what "Dimensions of layer 'output' is not the same size as the number of class labels" means.

Dies bedeutet, dass die letzte Ebene Ihres Modells eine andere Dimension hat als Ihre Klassenbeschriftungen (von denen ich annahm, dass sie die Dimension 2 haben). Ich würde empfehlen, diesen Parameter zu entfernen:

class_labels = output_labels

aus dem Modell-Konvertierung und sehen, ob es das Problem behebt

Verwandte Themen