{"id":10194,"date":"2020-06-29T18:45:00","date_gmt":"2020-06-29T15:45:00","guid":{"rendered":"https:\/\/handoli.com\/index.php\/2020\/06\/29\/apple-machine-learning-in-2020-whats-new\/"},"modified":"2020-06-29T18:45:00","modified_gmt":"2020-06-29T15:45:00","slug":"apple-machine-learning-in-2020-whats-new","status":"publish","type":"post","link":"https:\/\/handoli.com\/index.php\/2020\/06\/29\/apple-machine-learning-in-2020-whats-new\/","title":{"rendered":"Apple machine learning in 2020: What&#8217;s new?"},"content":{"rendered":"<p>2020 is the year where machine learning on mobile is no longer the hot new thing. Adding some kind of intelligence to apps has become standard practice.<\/p>\n<p>Fortunately, that doesn\u2019t mean Apple has stopped innovating. \ud83d\ude05<\/p>\n<figure class=\"image\">\n  <a href=\"https:\/\/machinethink.net\/images\/coreml-new-2020\/wwdc2020.png\"><img decoding=\"async\" src=\"https:\/\/machinethink.net\/images\/coreml-new-2020\/wwdc2020.png\" alt=\"WWDC 2020 logo\"\/><\/a><br \/>\n<\/figure>\n<p>In this blog post, I\u2019ll summarize <strong>what\u2019s new<\/strong> in Core ML and the other AI and ML technologies from the Apple ecosystem.<\/p>\n<h2>Core ML<\/h2>\n<p>Last year was a big update for Core ML, but this year the improvements are much more modest: a few new layer types, support for encrypting models, and the ability to host model updates on CloudKit.<\/p>\n<p>It looks like the version number got dropped. Last year\u2019s update was called Core ML 3, but now the name is simply Core ML without a number. However, coremltools did get bumped to version 4.<\/p>\n<div class=\"note\">\n<p><strong>Note:<\/strong> The internal mlmodel specification version number is now 5, so new models will show up as \u201cCore ML v5\u201d in <a href=\"https:\/\/github.com\/lutzroeder\/Netron\">Netron<\/a>.<\/p>\n<\/div>\n<h3>New layer types in Core ML<\/h3>\n<p>The new layers are:<\/p>\n<ul>\n<li>\n<p><code>Convolution3DLayer<\/code>, <code>Pooling3DLayer<\/code>, <code>GlobalPooling3DLayer<\/code>: these are especially useful for processing video data, something you can now do with the Vision framework. (Core ML still has no explicit support for 1D convolutions, although you can use the regular 2D convolution layer for that.)<\/p>\n<\/li>\n<li>\n<p><code>OneHotLayer<\/code>: for one-hot encoding the input.<\/p>\n<\/li>\n<li>\n<p><code>ClampedReLULayer<\/code>: a ReLU activation that has a maximum value (useful for making ReLU6).<\/p>\n<\/li>\n<li>\n<p><code>ArgSortLayer<\/code>: for sorting the input tensor. This returns the sorted indices instead of the actual sorted values. There is no regular sorting layer, but you could use a <code>GatherLayer<\/code> to reorder the elements from the argsort output.<\/p>\n<\/li>\n<li>\n<p><code>CumSumLayer<\/code>: computes the cumulative sum of the input tensor.<\/p>\n<\/li>\n<li>\n<p><code>SliceBySizeLayer<\/code>: Core ML already had several types of slicing layers. This one lets you pass in a tensor containing the index to start slicing from; the size of the slice is always fixed.<\/p>\n<\/li>\n<\/ul>\n<p>These layer types can only be used with specification version 5 or greater, which means iOS 14 and macOS 11.0 or higher.<\/p>\n<p>Another useful improvement is <strong>8-bit quantized operations<\/strong> for the following layers:<\/p>\n<ul>\n<li><code>InnerProductLayer<\/code><\/li>\n<li><code>BatchedMatMulLayer<\/code><\/li>\n<\/ul>\n<p>In previous versions of Core ML you could quantize the weights, but they would be dequantized back to floating point when the model got loaded. With the new <code>int8DynamicQuantize<\/code> feature, the weights stay 8-bit integer values and the actual computations are performed using integers as well.<\/p>\n<p>Computations with INT8 have the potential to be much faster than floating point operations, but I wonder if that is only an advantage for the CPU and not the GPU, since GPUs really like floating point. Perhaps the upcoming Neural Engine update will support INT8 operations natively. (Apple did <a href=\"https:\/\/www.geekwire.com\/2020\/exclusive-apple-acquires-xnor-ai-edge-ai-spin-paul-allens-ai2-price-200m-range\/\">buy Xnor.ai<\/a> a while back\u2026)<\/p>\n<p>Core ML on the CPU can now also use <strong>16-bit floating point<\/strong> operations instead of 32-bit floats (on A11 Bionic and up). As mentioned in the <a href=\"https:\/\/developer.apple.com\/videos\/play\/wwdc2020\/10217\/\">Explore numerical computing in Swift<\/a> video, <code>Float16<\/code> is now a first-class Swift data type. With 16-bit floats supported natively on the CPU, Core ML can be more than twice as fast!<\/p>\n<div class=\"note\">\n<p><strong>Note:<\/strong> Core ML already used <code>Float16<\/code> on the GPU and Neural Engine, so this only makes a difference when using the CPU.<\/p>\n<\/div>\n<p>Other (small) changes:<\/p>\n<ul>\n<li>\n<p><code>UpsampleLayer<\/code> can now have a fractional scaling factor. In <code>BILINEAR<\/code> mode, there are new options for how the grid points are sampled (\u201calign corners\u201d). This should solve most of the issues I pointed out in <a href=\"https:\/\/machinethink.net\/blog\/coreml-upsampling\/\">this blog post<\/a>.<\/p>\n<\/li>\n<li>\n<p><code>ReorganizeDataLayerParams<\/code> has a <code>PIXEL_SHUFFLE<\/code> mode. This is another method for doing upsampling. Previously you could implement pixel shuffle using several permute and reshape layers but it\u2019s cool to have it built-in now.<\/p>\n<\/li>\n<li>\n<p><code>SliceStaticLayer<\/code> and <code>SliceDynamicLayer<\/code> now have a <code>squeezeMasks<\/code> property for even more slicing fun.<\/p>\n<\/li>\n<li>\n<p><code>TileLayer<\/code> accepts a second input tensor, so that you can specify the number of repetitions dynamically.<\/p>\n<\/li>\n<\/ul>\n<p>There appear to be no changes to on-device training: still only fully-connected and convolution layers are supported. The <code>MLParameterKey<\/code> class in CoreML.framework now has a configuration option for the <strong>RMSprop<\/strong> optimizer but this is currently not listed in <a href=\"https:\/\/github.com\/apple\/coremltools\/blob\/master\/mlmodel\/format\/NeuralNetwork.proto\">NeuralNetwork.proto<\/a>. It might be added in a later beta.<\/p>\n<p>The following <strong>new model types<\/strong> were added:<\/p>\n<ul>\n<li>\n<p><code>VisionFeaturePrint.Object<\/code>, a feature extractor that is optimized for doing object detection.<\/p>\n<\/li>\n<li>\n<p><code>SerializedModel<\/code>. Not sure what this is for. This is a \u201cprivate\u201d definition that is \u201csubject to change with no notice or support\u201d. Maybe this is a way for Apple to embed proprietary model formats inside an mlmodel?<\/p>\n<\/li>\n<\/ul>\n<h3>Hosting model updates on CloudKit<\/h3>\n<figure class=\"image\">\n  <a href=\"https:\/\/machinethink.net\/images\/coreml-new-2020\/HostedUpdates@2x.jpg\"><img decoding=\"async\" src=\"https:\/\/machinethink.net\/images\/coreml-new-2020\/HostedUpdates.jpg\" alt=\"Hosting model updates on CloudKit\"\/><\/a><br \/>\n<\/figure>\n<p>This new Core ML feature lets you update your models independently of the app.<\/p>\n<p>Instead of having to publish an app update, the existing app can simply download a new version of the mlmodel file. To be fair, this is not a new idea and several third-party vendors have SDKs for this. It\u2019s also not that hard to build this yourself. The advantage of using Apple\u2019s solution is that the models get <strong>hosted on Apple Cloud<\/strong>.<\/p>\n<p>Because you may have more than one model in your app, the new concept of <strong>model collections<\/strong> lets you bundle multiple models together and the app will update all of them at once. You create these collections on the CloudKit dashboard.<\/p>\n<p>In the app, you use the <code>MLModelCollection<\/code> class to download and manage the model updates. The <a href=\"https:\/\/developer.apple.com\/videos\/play\/wwdc2020\/10152\/\">WWDC video<\/a> shows code snippets for this.<\/p>\n<p>To prepare a Core ML model for deployment, there is now a <strong>Create Model Archive<\/strong> button in Xcode. This writes a <strong>.mlarchive<\/strong> file. You can upload this version of the model to your CloudKit dashboard and then put it into a model collection. (It looks like mlarchive is really just a zip file with the contents of your mlmodelc folder.)<\/p>\n<p>A nice feature is that you can deploy different model collections to different users. For example, the camera on the iPhone is different than the camera on the iPad, so you may want to create two versions of a model and send one to iPhone users of the app and the other to iPad users.<\/p>\n<p>You can create targeting rules for the device class (iPhone \/ iPad \/ TV \/ Watch), operating system and version, region code, language code, and app version.<\/p>\n<p>There appears to be no mechanism for dividing your users into groups by other criteria, such as for A\/B testing model updates, or for targeting specific device types such as \u201ciPhone X or lower\u201d. However, you can still do this manually by creating collections with different names and then explicitly asking <code>MLModelCollection<\/code> to fetch the appropriate collection by name at runtime.<\/p>\n<p>Deploying a new model version <strong>isn\u2019t always immediate<\/strong>. The app will at some point detect that a new model is available, and will automatically download it and place it in the app\u2019s sandbox. But you don\u2019t get any control over when or how this happens \u2014 Core ML might perform the download in the background while the phone is not being used, for example.<\/p>\n<p>Because of this, it\u2019s a good idea to already ship your app with a built-in model as a fallback option, such as a generic model that handles both iPhone and iPad.<\/p>\n<p>Even though this is a convenient solution and you don\u2019t have to worry about hosting the models yourself, do keep in mind that your app is now using CloudKit. From what I understood, the model collections do count towards your storage quotas and downloading the models counts towards your network traffic quotas.<\/p>\n<p>See also:<\/p>\n<ul>\n<li><a href=\"https:\/\/developer.apple.com\/videos\/play\/wwdc2020\/10152\/\">Use model deployment and security with Core ML<\/a> (WWDC video)<\/li>\n<li><a href=\"https:\/\/developer.apple.com\/documentation\/coreml\/core_ml_api\/creating_and_deploying_a_model_collection\">Creating and Deploying a Model Collection<\/a><\/li>\n<li><a href=\"https:\/\/developer.apple.com\/documentation\/coreml\/core_ml_api\/retrieving_a_model_collection_from_a_deployment\">Retrieving a Model Collection from a Deployment<\/a><\/li>\n<\/ul>\n<div class=\"note\">\n<p><strong>Note:<\/strong> If you want to do on-device personalization of the model, there\u2019s no easy way to combine that with this new CloudKit update feature. There is no straightforward way to transfer what the personalized model has learned into the new model, or to combine these models somehow.<\/p>\n<\/div>\n<h3>Model encryption<\/h3>\n<p>Until now, it was really easy for someone to steal your Core ML model and stick it into their own app. As of iOS 14 \/ macOS 11.0, Core ML can automatically encrypt and decrypt models so that strangers can no longer peek inside your mlmodelc folders. You can use encryption with or without the new CloudKit deployment.<\/p>\n<figure class=\"image\">\n  <a href=\"https:\/\/machinethink.net\/images\/coreml-new-2020\/Encryption@2x.jpg\"><img decoding=\"async\" src=\"https:\/\/machinethink.net\/images\/coreml-new-2020\/Encryption.jpg\" alt=\"Encrypting models\"\/><\/a><br \/>\n<\/figure>\n<p>Xcode encrypts the compiled model, <strong>mlmodelc<\/strong>, not the original mlmodel file. The model always stays in encrypted form on the user\u2019s device. Only when the app instantiates the model, Core ML automatically decrypts it. This decrypted version only exists in memory, it is not stored as a file anywhere.<\/p>\n<p>First, you need an encryption key. The good news is that you don\u2019t need to manage this key yourself! There is now a <strong>Create Encryption Key<\/strong> button in Xcode\u2019s Core ML model viewer. When you click this, Xcode generates a new encryption key that is associated with your Apple developer team account. No need to mess around with CSRs and Keychain Access for this one. \ud83e\udd2a<\/p>\n<p>This process creates a new <strong>.mlmodelkey<\/strong> file. This key is stored on Apple\u2019s servers but you also get a local copy that you need for encrypting the models in Xcode. You don\u2019t need to embed this encryption key in your app \u2014 and shouldn\u2019t!<\/p>\n<p>To encrypt a Core ML model, you can add <code>--encrypt YourModel.mlmodelkey<\/code> to the compiler flags for the model, or, if you\u2019re going to use CloudKit deployment, you need to supply the encryption key when creating the model archive.<\/p>\n<p>To decrypt the model when the app instantiates it, Core ML will need to fetch the encryption key <strong>over the network<\/strong> from Apple\u2019s servers, so that obviously requires a network connection. Core ML only needs to do this the very first time you\u2019re using that model.<\/p>\n<p>Naturally, if the network is down and the encryption key hasn\u2019t been downloaded yet, your app won\u2019t be able to instantiate the Core ML model. For this reason, you should use the new <code>YourModel.load()<\/code> function. This has a completion handler that lets you respond to loading errors. For example, the <code>modelKeyFetch<\/code> error code tells you that Core ML was unable to load the decryption key from Apple\u2019s servers.<\/p>\n<p>Pretty cool feature \u2014 if you\u2019re worried that people will steal your proprietary tech \u2014 and fairly easy to implement in your app.<\/p>\n<p>See also:<\/p>\n<ul>\n<li><a href=\"https:\/\/developer.apple.com\/videos\/play\/wwdc2020\/10152\/\">Use model deployment and security with Core ML<\/a> (WWDC video)<\/li>\n<li><a href=\"https:\/\/developer.apple.com\/documentation\/coreml\/core_ml_api\/generating_a_model_encryption_key\">Generating a Model Encryption Key<\/a><\/li>\n<li><a href=\"https:\/\/developer.apple.com\/documentation\/coreml\/core_ml_api\/encrypting_a_model_in_your_app\">Encrypting a Model in Your App<\/a><\/li>\n<\/ul>\n<div class=\"note\">\n<p><strong>Note:<\/strong> According to <a href=\"https:\/\/developer.apple.com\/forums\/thread\/651016\">this forum post<\/a>, encrypted models cannot be used with on-device personalization. Makes sense.<\/p>\n<\/div>\n<h3>CoreML.framework<\/h3>\n<p>The <a href=\"https:\/\/developer.apple.com\/documentation\/coreml\/core_ml_api\">iOS API for using Core ML models<\/a> hasn\u2019t changed much. Still, there are a few interesting things to point out.<\/p>\n<p>The only new class is <code>MLModelCollection<\/code>, which is for CloudKit deployment.<\/p>\n<p>As you know, when you add an mlmodel file to your project, Xcode automatically generates a Swift or Objective-C source file with classes that make it easier to use the model. There are a couple of changes in these generated classes:<\/p>\n<ul>\n<li>\n<p>The default <code>init()<\/code> is now deprecated, so writing <code>let model = YourModel()<\/code> will result in a compiler warning. Instead, use <code>YourModel(configuration:)<\/code> or the new <code>YourModel.load()<\/code> method, which lets you handle model loading errors such as when an encrypted model cannot be decrypted.<\/p>\n<\/li>\n<li>\n<p>If your model works on images, instead of having to deal with <code>CVPixelBuffer<\/code> objects, you can now create a <code>YourModelInput<\/code> object using a <code>CGImage<\/code> or the URL to a local PNG or JPG file, and do the prediction on that. However, this doesn\u2019t let you set the <code>cropAndScale<\/code> method or the <code>cropRect<\/code>, so if you want more control over how the images are resized, these new methods aren\u2019t very useful.<\/p>\n<\/li>\n<\/ul>\n<p>A new warning has appeared in the <a href=\"https:\/\/developer.apple.com\/documentation\/coreml\/mlmodel\">MLModel docs<\/a>:<\/p>\n<blockquote>\n<p>Use an MLModel instance on one thread or one dispatch queue at a time. You do this by either serializing method calls to the model, or by creating a separate model instance for each thread and dispatch queue.<\/p>\n<\/blockquote>\n<p>Whoops, I\u2019m guilty of doing this. \ud83d\ude48 I was led to believe that <code>MLModel<\/code> internally used a serial queue for handling requests \u2014 but this may not have been true, or perhaps it has changed. Anyway, best to follow the advice from now on.<\/p>\n<p><code>MLMultiArray<\/code> has a new <code>init(concatenating:axis:dataType:)<\/code> initializer, which makes a new multi-array by concatenating several existing multi-arrays. These must all have the same shape except for the specified axis, along which they\u2019ll be concatenated. It looks like this was added specifically for doing predictions on videos, as with the new Action Classifier models from Create ML. Handy!<\/p>\n<div class=\"note\">\n<p><strong>Note:<\/strong> The <code>MLMultiArrayDataType<\/code> enum now has static <code>.float<\/code> and <code>.float64<\/code> properties. Not sure what these are for, as it already had <code>.float32<\/code> and <code>.double<\/code> cases. Beta glitch?<\/p>\n<\/div>\n<h3>Xcode model viewer<\/h3>\n<p>Xcode now shows a lot more information about models, such as the class labels and any custom metadata that you added to the model. It also shows statistics about the types of layers inside the model.<\/p>\n<figure class=\"image\">\n  <a href=\"https:\/\/machinethink.net\/images\/coreml-new-2020\/ModelViewer@2x.jpg\"><img decoding=\"async\" src=\"https:\/\/machinethink.net\/images\/coreml-new-2020\/ModelViewer.jpg\" alt=\"The Xcode model viewer\"\/><\/a><br \/>\n<\/figure>\n<p>There is a handy <strong>interactive preview<\/strong> that lets you play with the model without having to run the app. You can drag-and-drop images, videos, or text into this preview window and immediately view the model\u2019s predictions. Very nice!<\/p>\n<p>You can also use Core ML <strong>models in playgrounds<\/strong> now. Xcode will auto-generate the class for it and you can use it as usual. That\u2019s another way you can interactively play with the model before putting it into the app.<\/p>\n<h3>coremltools 4<\/h3>\n<p>Building your own models with Create ML is fun for simple projects, but it\u2019s much more common to train in TensorFlow or PyTorch. To use such a model with Core ML, you need to convert it to the mlmodel file format first. That\u2019s what coremltools is for.<\/p>\n<p>Good news: the <a href=\"https:\/\/coremltools.readme.io\/docs\">documentation is greatly improved<\/a>. You should check it out. Let\u2019s hope they keep this user guide up-to-date because the old documentation wasn\u2019t always the latest version.<\/p>\n<div class=\"note\">\n<p><strong>Note:<\/strong> Unfortunately, the Jupyter notebook examples have disappeared. These examples are now part of the user\u2019s guide, but no longer as notebooks.<\/p>\n<\/div>\n<p>The way to <strong>convert models has changed<\/strong> quite a bit. The old neural network converters are pretty much deprecated and have been replaced by a newer, more flexible design.<\/p>\n<p>There are now three types of converters:<\/p>\n<ul>\n<li>Modern converters for TensorFlow (both 1.x and 2.x), tf.keras, and PyTorch. All of these converters are built on the same stack and use something called MIL or Model Intermediate Language. You no longer need to use tfcoreml or onnx-coreml for these kinds of models.<\/li>\n<li>Old converters for Keras 1.x, Caffe, and ONNX neural networks. These all have their own special-purpose converter. These will not be developed further and will only get bug fixes. It\u2019s not recommended to use ONNX to convert PyTorch models anymore!<\/li>\n<li>Converters for non neural-network models such as scikit-learn and XGBoost.<\/li>\n<\/ul>\n<p>To convert a TensorFlow 1.x or 2.x, PyTorch, or tf.keras model, you use the new <strong>unified conversion API<\/strong>. It looks like this:<\/p>\n<pre><code class=\"language-python\">import coremltools as ct\n\nclass_labels = [ \"cat\", \"dog\" ]\n\nimage_input = ct.ImageType(shape=(1, 224, 224, 3),\n                           bias=[-1, -1, -1],\n                           scale=2\/255.)\n\nmodel = ct.convert(\n    keras_model, \n    inputs=[ image_input ],\n    classifier_config=ct.ClassifierConfig(class_labels)\n)\n\nmodel.save(\"YourModel.mlmodel\")\n<\/code><\/pre>\n<p>The <code>ct.convert()<\/code> function inspects the model file to see what format it is and automatically chooses the appropriate converter. The arguments are somewhat different than before: the preprocessing arguments are passed in using an <code>ImageType<\/code> object, classifier labels using a <code>ClassifierConfig<\/code> object, and so on.<\/p>\n<p>This new conversion API converts the model into an <a href=\"https:\/\/coremltools.readme.io\/docs\/model-intermediate-language\">intermediate representation<\/a> called <strong>MIL<\/strong>. There are currently converters for TensorFlow 1.x to MIL, TensorFlow 2.x to MIL \u2014 including tf.keras \u2014 and PyTorch to MIL. If at some point a new deep learning framework becomes popular, it can get its own MIL converter.<\/p>\n<figure class=\"image\">\n  <a href=\"https:\/\/files.readme.io\/156ec59-mil.png\"><img decoding=\"async\" src=\"https:\/\/files.readme.io\/156ec59-mil.png\" alt=\"MIL in coremltools\"\/><\/a><br \/>\n<\/figure>\n<p>Once the model is in MIL format, it can be optimized according to general rules, such as stripping out unnecessary operations or fusing different layers together. Finally, it is converted from MIL to the mlmodel format.<\/p>\n<p>I haven\u2019t looked at it in detail yet, but this new approach makes me believe that coremltools 4 produces much more efficient mlmodel files than before, especially for TF 2.x graphs.<\/p>\n<p>What I like about MIL is that it allows you to tell the converter how to deal with <strong>layers that it doesn\u2019t understand yet<\/strong>. If your model has a layer that is not directly supported by Core ML, you might be able to split it up into more primitive MIL operations, such as matrix multiplications or other arithmetic.<\/p>\n<p>The converter can then use this so-called \u201ccomposite operation\u201d whenever it encounters a layer of that type. That\u2019s way easier than implementing unsupported operations with a custom layer, although that\u2019s still possible. The documentation has a <a href=\"https:\/\/coremltools.readme.io\/docs\/composite-operators\">nice example<\/a> of how to use such composite operations.<\/p>\n<p>See also:<\/p>\n<ul>\n<li><a href=\"https:\/\/developer.apple.com\/videos\/play\/wwdc2020\/10153\/\">Get models on device using Core ML Converters<\/a> (WWDC video)<\/li>\n<li><a href=\"https:\/\/coremltools.readme.io\/docs\">coremltools documentation<\/a><\/li>\n<\/ul>\n<h2>Other Apple frameworks that use ML<\/h2>\n<p>There are several high-level frameworks in the iOS and macOS SDKs that perform machine learning-related tasks. Let\u2019s quicky look at what\u2019s new here.<\/p>\n<h3>Vision<\/h3>\n<p>The <a href=\"https:\/\/developer.apple.com\/documentation\/vision?changes=latest_minor\">Vision framework<\/a> for computer vision got a bunch of new functionality.<\/p>\n<p>Vision already had detection models for faces, face landmarks and human bodies. This new release adds the following:<\/p>\n<ul>\n<li>Hand pose detection (<code>VNDetectHumanHandPoseRequest<\/code>)<\/li>\n<li>Multi-person <strong>full body pose<\/strong> detection (<code>VNDetectHumanBodyPoseRequest<\/code>)<\/li>\n<\/ul>\n<p>It\u2019s actually really cool of Apple to include pose estimation in the OS. There are several open source models for this but they aren\u2019t really that great, or are slow, while commercial solutions are expensive. Now you get high-quality body pose detection for free!<\/p>\n<p>Rather than just looking at static images, there is now also more emphasis on <strong>detecting things in video<\/strong>, both offline and from the camera in real-time. For convenience, you can use <code>CMSampleBuffer<\/code> objects straight from the camera with your request handlers.<\/p>\n<p>New is <code>VNStatefulRequest<\/code>, a subclass of <code>VNImageBasedRequest<\/code> that builds up <strong>evidence over time<\/strong> of having detected the thing you\u2019re looking for. Unlike a typical <code>VNImageBasedRequest<\/code>, you re-use a stateful request over multiple frames. It performs an analysis operation every N frames of the video.<\/p>\n<p>Once the thing you\u2019re looking for has been observed, the completion handler is called with a <code>VNObservation<\/code> object, which now has a <code>timeRange<\/code> property that tells you when the observation started and stopped in the video.<\/p>\n<p>You don\u2019t use <code>VNStatefulRequest<\/code> directly \u2014 it\u2019s an abstract base class that is currently only subclassed by <code>VNDetectTrajectoriesRequest<\/code> for doing trajectory detection. This can detect shapes moving along a parabolic path, like <a href=\"https:\/\/developer.apple.com\/documentation\/vision\/identifying_trajectories_in_video\">a ball being kicked or thrown<\/a>. (This appears to be the only built-in video task right now.)<\/p>\n<p>To perform offline analysis of videos, you can use <code>VNVideoProcessor<\/code>. This object takes a URL to a local movie file and performs one or more Vision requests every N frames or seconds.<\/p>\n<p>An important traditional computer vision technique for analyzing video is <strong>optical flow<\/strong>. Vision now has <code>VNGenerateOpticalFlowRequest<\/code> that computes the direction each pixel is moving from one frame to the next (dense optical flow). The output is a <code>VNPixelBufferObservation<\/code> containing a new image that has two 32-bit or 16-bit floats for each pixel.<\/p>\n<p>Also new is <code>VNDetectContoursRequest<\/code>, for detecting the <strong>outlines of objects<\/strong> in an image. These outlines are returned as vector paths. <code>VNGeometryUtils<\/code> has helper functions for post-processing on the detected contours, such as simplifying them to basic geometric shapes.<\/p>\n<p>The final new thing in Vision is a new variant of the built-in feature extractor, VisionFeaturePrint. iOS already came with VisionFeaturePrint.Scene, which is useful for making image classifiers. There is now a new <strong>VisionFeaturePrint.Object<\/strong> model that is optimized for extracting features that are useful for object detection.<\/p>\n<p>It works on a 299\u00d7299 input image and outputs two multi-arrays of shape (288, 35, 35) and (768, 17, 17), respectively. These are not bounding box predictions yet, only \u201craw\u201d features. A full object detector still needs to add logic to turn these features into bounding boxes and class labels. Create ML does that when you train an object detector using transfer learning.<\/p>\n<p>See also:<\/p>\n<ul>\n<li><a href=\"https:\/\/developer.apple.com\/videos\/play\/wwdc2020\/10673\/\">Explore Computer Vision APIs<\/a> (WWDC video)<\/li>\n<li><a href=\"https:\/\/developer.apple.com\/videos\/play\/wwdc2020\/10653\/\">Detect Body and Hand Pose with Vision<\/a> (WWDC video)<\/li>\n<li><a href=\"https:\/\/developer.apple.com\/videos\/play\/wwdc2020\/10099\/\">Explore the Action &amp; Vision app<\/a> (WWDC video)<\/li>\n<\/ul>\n<h3>Natural Language Processing<\/h3>\n<p>For NLP tasks, you can use the Natural Language framework. It works closely together with models trained in Create ML.<\/p>\n<p>Only a few new features this year:<\/p>\n<ul>\n<li>\n<p><code>NLTagger<\/code> and <code>NLModel<\/code> can now find multiple tags and predict their confidences. Previously, all you got was the highest scoring tag.<\/p>\n<\/li>\n<li>\n<p>Sentence embeddings. It was already possible to use word embeddings but now <code>NLEmbedding<\/code> also supports sentences.<\/p>\n<\/li>\n<\/ul>\n<p>Sentence embeddings use a built-in neural network to encode the entire sentence into a 512-dimensional vector, in order to capture the context in which the words appear in the sentence (something that word embeddings by themselves can\u2019t do).<\/p>\n<p>See also:<\/p>\n<ul>\n<li><a href=\"https:\/\/developer.apple.com\/videos\/play\/wwdc2020\/10657\/\">Make apps smarter with Natural Language<\/a> (WWDC video)<\/li>\n<\/ul>\n<h3>Speech &amp; SoundAnalysis<\/h3>\n<p>There do not appear to be any changes to these frameworks.<\/p>\n<h2>Training models<\/h2>\n<p>We\u2019ve been able to train models with Apple APIs since iOS 11.3 and the Metal Performance Shaders framework. Over the years new training APIs have been added, and this year we get a few more \u2014 by my count, we now have 7 different APIs for training neural networks on iOS and\/or macOS!<\/p>\n<figure class=\"image\">\n  <a href=\"https:\/\/machinethink.net\/images\/coreml-new-2020\/Train@2x.jpg\"><img decoding=\"async\" src=\"https:\/\/machinethink.net\/images\/coreml-new-2020\/Train.jpg\" alt=\"The training steps\"\/><\/a><br \/>\n<\/figure>\n<p>Currently, these are the Apple APIs you can use for training machine learning models, in particular neural networks, on iOS and macOS:<\/p>\n<ul>\n<li>\n<p><strong><a href=\"https:\/\/machinethink.net\/blog\/coreml-training-part1\/\">On-device training<\/a><\/strong> with Core ML.<\/p>\n<\/li>\n<li>\n<p><strong>Create ML<\/strong>: you may know this as an app but it\u2019s also a framework that\u2019s available on macOS.<\/p>\n<\/li>\n<li>\n<p><strong>Metal Performance Shaders<\/strong>: for inference and training on the GPU. This is actually two different APIs and they\u2019re not particularly easy to use if you\u2019re not familiar with Metal. There is now also a new \u201cMetal Performance Shaders Graph\u201d framework that appears to be a replacement for these older APIs.<\/p>\n<\/li>\n<li>\n<p><strong>BNNS<\/strong>: part of the Accelerate framework. Previously, BNNS only had routines for doing inference but this year it has added support for training.<\/p>\n<\/li>\n<li>\n<p><strong>ML compute<\/strong>: a brand-new framework that looks very exciting.<\/p>\n<\/li>\n<li>\n<p><strong>Turi Create<\/strong>: basically the Python version of Create ML. It doesn\u2019t look like it got a lot of love recently, although it still appears to be maintained.<\/p>\n<\/li>\n<\/ul>\n<p>Let\u2019s look at what\u2019s new with these APIs in more detail.<\/p>\n<h3>On-device training with Core ML<\/h3>\n<p>Nothing much seems to have changed here. It\u2019s possible more layer types have been made updatable, but I haven\u2019t seen any documentation of this.<\/p>\n<p>One new addition that might still be coming in a later beta is the RMSprop optimizer, but it\u2019s not part of the current beta yet.<\/p>\n<h3>Create ML<\/h3>\n<p>Create ML started out as a framework that can only be used on macOS. You can use this from a Swift Playground to train your models with just a few lines of code.<\/p>\n<figure class=\"image\">\n  <a href=\"https:\/\/machinethink.net\/images\/coreml-new-2020\/CreateML@2x.jpg\"><img decoding=\"async\" src=\"https:\/\/machinethink.net\/images\/coreml-new-2020\/CreateML.jpg\" alt=\"Create ML logo\"\/><\/a><br \/>\n<\/figure>\n<p>Last year, Create ML was turned into a rather limited app and I\u2019m happy to see that the app is much improved this year. It\u2019s also still a framework so you can still use it from code. The app is really just a convenient GUI around the framework.<\/p>\n<p>In the previous version of the Create ML app you could only train a model once. If you wanted to tweak something, you had to train again from scratch, which could take a long time.<\/p>\n<p>With the new version from Xcode 12, you can <strong>pause training and resume<\/strong> later, save model checkpoints (snapshots), and preview how well the model is doing. You get much more control over the training process. This update makes the Create ML app actually useful!<\/p>\n<p>In CreateML.framework there are also new APIs for setting up training sessions, handling model checkpoints, and so on. I expect most people will simply use the Create ML app, but it\u2019s nice to see that this functionality is publicly exposed in the framework as well.<\/p>\n<p>New things you can do with Create ML (both framework and app):<\/p>\n<ul>\n<li>\n<p>Style transfer on images and videos<\/p>\n<\/li>\n<li>\n<p>Action classification on humans in videos<\/p>\n<\/li>\n<li>\n<p>Transfer learning for object detection<\/p>\n<\/li>\n<li>\n<p>Word tagging transfer learning with dynamic word embeddings<\/p>\n<\/li>\n<\/ul>\n<p>Let\u2019s take a closer look at the new <strong>action classification<\/strong> model. This uses the human body pose model from Vision. The action classifier is a neural network that takes an input of shape <code>(window_size, 3, 18)<\/code> where the first dimension is the window size in number of frames (typically two seconds\u2019 worth of video), and <code>(3, 18)<\/code> are the pose keypoints.<\/p>\n<p>The neural network does not use recurrent layers but 1-dimensional convolutions. It appears to be a variation of STGCN or Spatio-Temporal Graph Convolutional Networks, a type of model that\u2019s designed for time series predictions. You don\u2019t need to worry about those details in order to use these models in your app, but I always like to peek under the hood. \ud83d\ude43<\/p>\n<p>For object detection models you can choose between training a full network based on TinyYOLOv2, or the new transfer learning mode, which uses the new feature extractor <strong>VisionFeaturePrint.Object<\/strong>. The rest of the model still looks like YOLO and SSD, but thanks to transfer learning it should be much faster to train than the full YOLO-based model.<\/p>\n<p>See also:<\/p>\n<ul>\n<li><a href=\"https:\/\/developer.apple.com\/videos\/play\/wwdc2020\/10043\/\">Build an Action Classifier with Create ML<\/a> (WWDC video)<\/li>\n<li><a href=\"https:\/\/developer.apple.com\/videos\/play\/wwdc2020\/10642\/\">Build Image and Video Style Transfer models in Create ML<\/a> (WWDC video)<\/li>\n<li><a href=\"https:\/\/developer.apple.com\/videos\/play\/wwdc2020\/10156\/\">Control training in Create ML with Swift<\/a> (WWDC video)<\/li>\n<\/ul>\n<h3>Metal Performance Shaders<\/h3>\n<p>Metal Performance Shaders (MPS) is a framework with handy Metal compute kernels, mostly for image processing but it has had support for neural networks since 2016. I have written extensively about it here on this blog.<\/p>\n<p>These days, most people would use Core ML instead of MPS. Of course, Core ML still uses MPS under the hood when running the model on the GPU. But you can also use MPS directly, especially if you want to do your own training. (However, there is now a new ML Compute framework that you should probably use instead, see below.)<\/p>\n<p>This year there is not much new stuff in MPSCNN, just some refinements.<\/p>\n<p>New classes are <code>MPSImageCanny<\/code> for edge detection and <code>MPSImageEDLines<\/code> for line segment detection. Very useful for computer vision tasks.<\/p>\n<p>Other notable changes:<\/p>\n<ul>\n<li>\n<p><code>MPSCNNConvolutionDataSource<\/code> has a new <code>kernelWeightsDataType<\/code> property, so that the data type of the weights does not have to be the same as the data type the convolution is performed with. Interestingly, the weights cannot be INT8, even though Core ML does allow this for certain layers now.<\/p>\n<\/li>\n<li>\n<p>If you return <code>.float32<\/code> from <code>kernelWeightsDataType<\/code>, convolution and fully-connected layers will run using 32-bit floats rather than 16-bit floats. Before, they could only work in 16-bit.<\/p>\n<\/li>\n<li>\n<p>Loss functions can now <code>reduceAcrossBatch<\/code>.<\/p>\n<\/li>\n<\/ul>\n<p>Using MPSCNN is still fine if Metal doesn\u2019t scare you off, but there is now a new framework that makes it easier to create and run such graphs: MPS Graph.<\/p>\n<div class=\"note\">\n<p><strong>Note:<\/strong> The <a href=\"https:\/\/machinethink.net\/blog\/new-in-apple-machine-learning-2020\/\">WWDC video<\/a> also says <code>MPSNDArray<\/code> is new, but this API was introduced last year already. This is a more flexible data structure than <code>MPSImage<\/code> because not all tensors in your model will necessarily be images.<\/p>\n<\/div>\n<h3>New: Metal Performance Shaders Graph<\/h3>\n<figure class=\"image\">\n  <a href=\"https:\/\/machinethink.net\/images\/coreml-new-2020\/Graph@2x.jpg\"><img decoding=\"async\" src=\"https:\/\/machinethink.net\/images\/coreml-new-2020\/Graph.jpg\" alt=\"Graph of GeLU operation\"\/><\/a><br \/>\n<\/figure>\n<p>MPS has had the <code>MPSNNGraph<\/code> API for a while now, but those graphs are limited to describing neural networks. However, not all graphs need to be neural networks and that\u2019s where Metal Performance Shaders Graph comes in.<\/p>\n<p>You can use this new framework to build general-purpose graphs of GPU compute operations. MPS Graph is separate from the regular Metal Performance Shaders framework, but does sit on top of it.<\/p>\n<p>One limitation of the old <code>MPSNNGraph<\/code> API is that you couldn\u2019t put your own custom operations into the graph, but this new Graph framework is more flexible. Although it appears that you can\u2019t actually add your own Metal compute kernels \u2014 you must express all your computations using existing primitives.<\/p>\n<p>Fortunately, the <code>MPSGraph<\/code> compiler can fuse these primitives into one single compute kernel, to make it run as efficiently as possible on the GPU. However, if you have an operation that is impossible or really awkward to implement using the provided primitives, this isn\u2019t going to work. I don\u2019t really understand why Apple always leaves out the ability to do completely custom stuff when they introduce a new API such as this?! Oh well.<\/p>\n<p>The new <code>MPSGraph<\/code> is a fairly lightweight structure that describes how a bunch of <code>MPSGraphOperations<\/code> relate to each other through <code>MPSGraphTensors<\/code>, which contain the results of the operation. You can also define control dependencies, to force certain nodes to run before others. Once you\u2019ve set up the graph, you run it or encode it into a command buffer, then wait for the results.<\/p>\n<p><code>MPSGraph<\/code> has a whole bunch of instance methods to add all kinds of mathematical and neural network operations to the graph.<\/p>\n<p>It can also do training, which consists of adding a loss operation to the graph, followed by \u201cgradient\u201d operations for all the layers in reverse order, just like with the old <code>MPSNNGraph<\/code>. For convenience, an automatic differentiation mode is also provided, so that <code>MPSGraph<\/code> can automatically put the gradient operations into the graph, which saves a lot of work.<\/p>\n<p>I like that they\u2019ve created a new, clean, API for building these compute graphs. It\u2019s definitely easier to use than the old graph API \u2014 you no longer need to be an expert in Metal. It reminds me a lot of TensorFlow 1.x graphs, with the added benefit that the graph gets aggressively optimized to avoid as much overhead as possible. Still, it\u2019s too bad that you can\u2019t insert arbitrary compute kernels into the graph.<\/p>\n<p>See also:<\/p>\n<ul>\n<li><a href=\"https:\/\/developer.apple.com\/videos\/play\/wwdc2020\/10677\/\">Build customized ML models with the Metal Performance Shaders Graph<\/a> (WWDC video)<\/li>\n<li><a href=\"https:\/\/developer.apple.com\/documentation\/metalperformanceshadersgraph\/adding_custom_functions_to_a_shader_graph\">Adding Custom Functions to a Shader Graph<\/a><\/li>\n<\/ul>\n<h3>BNNS (Basic Neural Network Subroutines)<\/h3>\n<p>When Core ML runs on the CPU, it uses BNNS, which is part of the Accelerate framework. I\u2019ve written about BNNS in <a href=\"https:\/\/machinethink.net\/blog\/the-hello-world-of-neural-networks\/\">this old blog post<\/a>. Those BNNS functions are now mostly deprecated and are replaced by a whole new set of functionality.<\/p>\n<p>Previously, there was only support for fully-connected layers, convolution, pooling, and activation functions. With this update, BNNS gets support for n-dimensional arrays, pretty much all the layer types from Core ML, as well as backwards versions of these layers for training \u2014 including layers that currently aren\u2019t trainable by Core ML, such LSTM.<\/p>\n<p>Also notable is the presence of a <strong>multihead attention<\/strong> layer, which are very common in Transformer models such as BERT. Oh, and tensor contractions, also interesting.<\/p>\n<p>You probably wouldn\u2019t use these BNNS functions yourself, just like you wouldn\u2019t use MPS for training on the GPU. Instead, there is now a higher-level framework, ML Compute, that abstracts away the processor that\u2019s being used. ML Compute uses BNNS and MPS under the hood, but at least you, the developer, don\u2019t need to worry about such details.<\/p>\n<p>See also: <a href=\"https:\/\/developer.apple.com\/documentation\/accelerate\/bnns\">BNNS framework documentation<\/a><\/p>\n<h3>New: ML Compute<\/h3>\n<p>ML Compute is a new framework for training neural networks on the CPU or on your GPUs (but not the Neural Engine, apparently). On a Mac Pro with multiple GPUs, it can automatically use all of them for training.<\/p>\n<p>I was a bit surprised to get yet another training framework, but this one will actually make things easier, as it hides away the low-level stuff from BNNS and MPS \u2014 and maybe in the future the Neural Engine. \ud83d\ude09<\/p>\n<p>What\u2019s interesting about ML Compute is that it also works on iOS, not just on the Mac. Curiously, there is no mention of Core ML in all of this \u2014 ML Compute seems to be a completely separate thing. You can\u2019t use it to create Core ML models.<\/p>\n<p>From what I can tell, the goal of ML Compute is mostly to <strong>accelerate third-party deep learning tools<\/strong>. You\u2019re not really expected to write code to use ML Compute directly \u2014 I think the assumption (hope?) is that tools such as TensorFlow will start using this to also make hardware-accelerated training possible on the Mac.<\/p>\n<p>The available layers seem to be the same as in BNNS. You put the layers inside a graph and then execute the graph. (No \u201ceager mode\u201d here.)<\/p>\n<p>To create a graph, you instantiate an <code>MLCGraph<\/code> object and add nodes to it. The node is an <code>MLCLayer<\/code> subclass and it is connected to other nodes through <code>MLCTensor<\/code> objects, which are the outputs from other layers.<\/p>\n<p>Interestingly, split, concatenate, reshape, and transpose operations are not separate layer types but are operations on the graph itself.<\/p>\n<p>A cool feature for debugging is <code>summarizedDOTDescription<\/code> which returns a DOT description of the graph that you can then plot with a program such as Graphviz or OmniGraffle. (This is also how Keras generates its model plots.)<\/p>\n<p>ML Compute makes a distinction between an inference graph and a training graph. The latter has additional nodes, such as a loss layer and an optimizer.<\/p>\n<p>There does not seem to be a way to create your own custom layers, so you\u2019re stuck with the layer types that ML Compute offers.<\/p>\n<p>Strangely enough, there was no WWDC session on this new framework and the documentation is very sparse. Anyway, I\u2019m keeping my eye on this one as it seems to be <em>the<\/em> API to use for training on Apple devices.<\/p>\n<p>See also: <a href=\"https:\/\/developer.apple.com\/documentation\/mlcompute\">ML Compute framework documentation<\/a><\/p>\n<h2>Conclusion<\/h2>\n<p><strong>Core ML<\/strong> got some useful new features such as automatic model updates and encryption. There really isn\u2019t much need for lots of new layer types, as the layers that were added last year basically cover everything. I\u2019m happy enough with this update.<\/p>\n<p><strong>coremltools 4<\/strong> is a big update with a new converter architecture and native support for TensorFlow 2 and PyTorch. I\u2019m glad that we no longer have to go through ONNX to convert PyTorch models!<\/p>\n<p><strong>Vision<\/strong> got a bunch of cool new stuff. I like that Apple is including functionality for analyzing videos. While it\u2019s possible to run ML on each video frame individually, doing so ignores the temporal dimension. Since mobile devices are now fast enough to perform real-time ML on video data, I expect to see video take a more prominent role in computer vision research in the near future.<\/p>\n<p>About <strong>training<\/strong>\u2026 I\u2019m not sure why we need 7 different APIs for this. I guess Apple doesn\u2019t want to deprecate the old ones until the new APIs have all their kinks worked out. Not much is known yet about ML Compute \u2014 but we\u2019re only just at beta 1 as I write this, so who knows\u2026 \ud83d\ude06<\/p>","protected":false},"excerpt":{"rendered":"<p>2020 is the year where machine learning on mobile is no longer the hot new thing. Adding some kind of intelligence to apps has become standard practice. Fortunately, that doesn\u2019t mean Apple has stopped innovating. \ud83d\ude05 In this blog post, I\u2019ll summarize what\u2019s new in Core ML and the other AI and ML technologies from [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":10195,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"rop_custom_images_group":[],"rop_custom_messages_group":[],"rop_publish_now":"initial","rop_publish_now_accounts":[],"rop_publish_now_history":[],"rop_publish_now_status":"pending","footnotes":""},"categories":[1],"tags":[],"class_list":["post-10194","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-explore"],"_links":{"self":[{"href":"https:\/\/handoli.com\/index.php\/wp-json\/wp\/v2\/posts\/10194","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/handoli.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/handoli.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/handoli.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/handoli.com\/index.php\/wp-json\/wp\/v2\/comments?post=10194"}],"version-history":[{"count":0,"href":"https:\/\/handoli.com\/index.php\/wp-json\/wp\/v2\/posts\/10194\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/handoli.com\/index.php\/wp-json\/wp\/v2\/media\/10195"}],"wp:attachment":[{"href":"https:\/\/handoli.com\/index.php\/wp-json\/wp\/v2\/media?parent=10194"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/handoli.com\/index.php\/wp-json\/wp\/v2\/categories?post=10194"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/handoli.com\/index.php\/wp-json\/wp\/v2\/tags?post=10194"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}