This is a basic example of train and use a basic Keras neural network model (XOR) on iPhone using Apple's coremltools on iOS11. Note that showing the integration starting from a Keras model to having it running in the iOS app is the main point and not the particular choice of model, in principle a similar approach could be used for any kind of Deep Learning model, e.g. generator part of Generative Adversarial Networks, a Recurrent Neural Network (or LSTM) or a Convolutional Neural Network.
For easy portability I chose to run the Keras part inside docker (i.e. could e.g. use nvidia-docker for a larger model that would need a GPU to train e.g. in the cloud or on a desktop or a powerful laptop). The current choice of Keras backend was TensorFlow, but believe it should also work for other backends (e.g. CNTK, Theano or MXNet). The code for this blog post is available at github.com/atveit/keras2ios
Best regards,
0 xor 0 = 0 # 0 xor 1 = 1 # 1 xor 0 = 1 # 1 xor 1 = 0 X = np.array([[0,0],[0,1],[1,0],[1,1]]) y = np.array([[0],1,1,[0]])
| ----- | | |
X = np.array([[0,0],[0,1],[1,0],[1,1]])
|
model = Sequential() model.add(Dense(8, input_dim=2)) # fully connected layer with 8 hidden nodes and input dimension of 2 model.add(Activation('tanh')) model.add(Dense(1)) model.add(Activation('sigmoid')) # 1 output, either 0 or 1
| ----- | | |
model = Sequential()
model.add(Dense(8, input_dim=2)) # fully connected layer with 8 hidden nodes and input dimension of 2
model.add(Activation('tanh'))
model.add(Dense(1))
model.add(Activation('sigmoid')) # 1 output, either 0 or 1
|
sgd = SGD(lr=0.1) model.compile(loss='binary_crossentropy', optimizer=sgd) model.fit(X, y, nb_epoch=1000, batch_size=1)
| ----- | | |
sgd = SGD(lr=0.1)
model.compile(loss='binary_crossentropy', optimizer=sgd)
model.fit(X, y, nb_epoch=1000, batch_size=1)
|
import coremltools coreml_model = coremltools.converters.keras.convert(model) coreml_model.save("keras_model.mlmodel")
| ----- | | |
import coremltools
coreml_model = coremltools.converters.keras.convert(model)
coreml_model.save("keras_model.mlmodel")
|
func xor_with_keras(x:NSNumber,y:NSNumber) -> String{ // input data is a float32 array with 2 elements guard let input_data = try? MLMultiArray(shape:2, dataType:MLMultiArrayDataType.float32) else { fatalError("Unexpected runtime error. MLMultiArray") } input_data[0] = x input_data1 = y let i = keras_modelInput(input1: input_data) // actual prediction guard let xor_prediction = try? model.prediction(input: i) else { fatalError("Unexpected runtime error. model.prediction") } let result = String(describing: xor_prediction.output1[0]) print(input_data[0].stringValue + " XOR " + input_data1.stringValue + " = " + result) return result }
| ----- | |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
func xor_with_keras(x:NSNumber,y:NSNumber) -> String{
// input data is a float32 array with 2 elements
guard let input_data = try? MLMultiArray(shape:[2], dataType:MLMultiArrayDataType.float32) else {
fatalError("Unexpected runtime error. MLMultiArray")
}
input_data[0] = x
input_data[1] = y
let i = keras_modelInput(input1: input_data)
// actual prediction
guard let xor_prediction = try? model.prediction(input: i) else {
fatalError("Unexpected runtime error. model.prediction")
}
let result = String(describing: xor_prediction.output1[0])
print(input_data[0].stringValue + " XOR " + input_data[1].stringValue + " = " + result)
return result
}
|
0 xor 0 = 1 xor 1 = 0 (if rounding down), and 1 xor 0 = 0 xor 1 = 1 (if rounding up)
LGTM!