I want to save the MLMultiArray
output generated from the CoreML model, to make it a persistent storage data.
let predictions = try model.prediction(from: input)
and the predictions
is as below, as you can see, it's a MultiArray(Float32)
type data.
However, in Core Data, it does not support this type. I noticed there was a type named Transformable
, but I don't know whether it could works.
So I wonder if there is a feasible way to persist this kind of data ?
Since MLMultiArray
conforms to NSSecureCoding
I was able to encode it to Data
using NSKeyedArchiver
, and decode using NSKeyedUnarchiver
. The resulting Data
instance could then be stored in Core Data or however else you might want to store it.
Since I don't have your model, I just created an instance of MLMultiArray
explicitly, and set some values.
let predictions: MLMultiArray = try! .init(shape: [5, 5], dataType: .float32)
let p = predictions.dataPointer.bindMemory(to: Float32.self, capacity: 25)
for i in 0..<25 {
p[i] = Float32(i)
}
I put the encoding/decoding code in functions, and made them generic, just in case you need it for other types:
import Foundation
func encode<T: NSSecureCoding>(_ value: T, secure: Bool = false) -> Data?
{
let archiver = NSKeyedArchiver(requiringSecureCoding: secure)
predictions.encode(with: archiver)
archiver.finishEncoding()
return archiver.encodedData
}
func decode<T: NSSecureCoding>(_ data: Data, as type: T.Type) -> T?
{
guard let unarchiver = try? NSKeyedUnarchiver(forReadingFrom: data) else {
return nil
}
return T.init(coder: unarchiver)
}
then to use it:
guard let data = encode(predictions) else {
fatalError("Encode failed")
}
// You can now save data to Core Data, or however else you want to persist it
guard let recoveredPredictions = decode(data, as: MLMultiArray.self) else {
fatalError("Decode failed")
}
I also wrote some code to test that it works:
print(" original predictions: \(predictions)")
print("recovered predictions: \(recoveredPredictions)")
let r = recoveredPredictions.dataPointer
.bindMemory(to: Float32.self, capacity: 25)
for i in 0..<25
{
guard p[i] == r[i] else {
fatalError("recoveredPredictions does not match predictions")
}
}
print("Success")
The output is
original predictions: Float32 5 × 5 matrix
[0,1,2,3,4;
5,6,7,8,9;
10,11,12,13,14;
15,16,17,18,19;
20,21,22,23,24]
recovered predictions: Float32 5 × 5 matrix
[0,1,2,3,4;
5,6,7,8,9;
10,11,12,13,14;
15,16,17,18,19;
20,21,22,23,24]
Success