Я создаю приложение для своей диссертации, и до сих пор мне удалось создать обновляемую модель классификации изображений, которую я обучал с помощью Keras и конвертировал с помощью coremltools. (Я предоставлю код для обучения и преобразования модели, поскольку я думаю, что это как-то связано с моей проблемой, а также код, который я использую для обновления модели в приложении.) Я могу успешно классифицировать изображение, и модель работает как предназначено для этого, но часть обновления не делает. После того, как я выполню обновление с изображением и попытаюсь классифицировать то же изображение с «обновленной» моделью, я получаю ту же классификацию. Даже небольшая разница в достоверности.
Генерация и преобразование модели выполняется в Python. Приложение написано на языке Swift.
Вот код для создания модели:
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, BatchNormalization
from keras import backend as K
img_width, img_height = 224, 224
train_data_dir = 'data/train/'
validation_data_dir = 'data/validate/'
nb_train_samples = 500
nb_validation_samples = 40
epochs = 20
batch_size = 25
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, (2, 2), input_shape=input_shape))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(BatchNormalization())
model.add(Conv2D(64, (2, 2)))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(BatchNormalization())
model.add(Flatten())
model.add(Dense(64))
model.add(Activation('relu'))
model.add(Dropout(0.5))
model.add(Dense(2))
model.add(Activation('softmax'))
model.summary()
model.compile(loss = 'categorical_crossentropy',
optimizer = 'sgd',
metrics = ['accuracy'])
train_datagen = ImageDataGenerator()
test_datagen = ImageDataGenerator()
train_generator = train_datagen.flow_from_directory(train_data_dir,
target_size =(img_width, img_height),
batch_size = batch_size, class_mode ='categorical')
validation_generator = test_datagen.flow_from_directory(
validation_data_dir,
target_size =(img_width, img_height),
batch_size = batch_size, class_mode ='categorical')
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('ModelsH5/catndog_small.h5')
Вот код для преобразования его в CoreML и обеспечения возможности его обновления:
import coremltools
from coremltools.models.neural_network import SgdParams
from coremltools.models import MLModel
model = "catndog_small"
coreml_model_path = 'ModelsML/' + model + '.mlmodel'
neuralnetwork_spec = coremltools.utils.load_spec(coreml_model_path)
builder = coremltools.models.neural_network.NeuralNetworkBuilder(spec=neuralnetwork_spec)
builder.inspect_layers(last=3)
builder.inspect_input_features()
neuralnetwork_spec.description.metadata.author = 'Ervins Balodis'
neuralnetwork_spec.description.metadata.license = 'No license'
neuralnetwork_spec.description.metadata.shortDescription = ('Cat and Dog Classifier converted from a Keras model')
model_spec = builder.spec
builder.make_updatable(['dense_2'])
builder.set_categorical_cross_entropy_loss(name='lossLayer', input='classLabelProbs')
from coremltools.models.neural_network import SgdParams
builder.set_sgd_optimizer(SgdParams(lr=0.1, batch=1))
builder.set_epochs(10)
model_spec.isUpdatable = True
model_spec.specificationVersion = coremltools._MINIMUM_UPDATABLE_SPEC_VERSION
model_spec.description.trainingInput[0].shortDescription = 'Image for training and updating the model'
model_spec.description.trainingInput[1].shortDescription = 'Set the value as Cat or Dog and update the model'
updateableModel = 'ModelsML/' + model + '_updateable' + '.mlmodel'
coremltools.utils.save_spec(model_spec, updateableModel)
Вот код для обновления модели из приложения:
func createTrainingData(imageArray: [UIImage], outputLabel: String) -> MLArrayBatchProvider{
var featureProviders = [MLFeatureProvider]()
let inputName = "image"
let outputName = outputLabel
var trainingImages = [UIImage]()
trainingImages.append(theImage!)
for image in trainingImages {
let inputValue = try? MLFeatureValue(cgImage: image.cgImage!,
pixelsWide: 224,
pixelsHigh: 224,
pixelFormatType: kCVPixelFormatType_OneComponent8,
options: nil)
let outputValue = MLFeatureValue(string: String(outputName))
let dataPointFeatures: [String: MLFeatureValue] = [inputName: inputValue!,
outputName: outputValue]
if let provider = try? MLDictionaryFeatureProvider(dictionary: dataPointFeatures) {
featureProviders.append(provider)
}
else{
print("Failed to append feature provider.")
}
}
return MLArrayBatchProvider(array: featureProviders)
}
func updateModel(at url: URL,
with trainingData: MLArrayBatchProvider,
completionHandler: @escaping (MLUpdateContext) -> Void) {
// Create an Update Task.
guard let updateTask = try? MLUpdateTask(forModelAt: url,
trainingData: trainingData,
configuration: nil,
completionHandler: completionHandler)
else {
print("Couldn't create an MLUpdateTask.")
return
}
updateTask.resume()
}
func performUpdate(){
//Might need to change from a batch to a single image
let updateImages: [UIImage] = [theImage!]
let imageBatch = createTrainingData(imageArray: updateImages, outputLabel: "dog") // temp outputLabel
updateModel(at: globalCompiledModel!, with: imageBatch, completionHandler:{ param in
print("Model updated!")
})
}