WWDC 2018:更快更強的 Core ML 2.0

本文是 WWDC 2018 Session 708 和 Session 709 的讀後感,其視頻及配套 PDF 文稿鏈接如下:
What is New in Core ML, Part 1
What is New in Core ML, Part 2
本文會首先回顧 Core ML 的基本背景知識,其後着重介紹 Core ML 在應用上和工具上的更新。

Core ML 回顧

Core ML 是蘋果在2017年推出的機器學習框架。主要支持圖像分類和文本信息處理兩大功能。其基本流程是獲取模型、導入並生成接口、使用接口編程3個步驟。我們來詳細分析每一步:

  1. 獲取模型。2017年時主要有兩種方式:從官網下載和轉化第三方框架生成的模型爲 Core ML 模型。爲了方便轉化,蘋果推出了 Python 編寫的 Core ML Tools。2018年又推出了原生的 Create ML 框架來直接從數據生成 Core ML 模型。Core ML Tools 的優點在於其語法簡單直接,缺點在於支持的第三方框架少、生成的模型尺寸過大且不能定製化。

  2. 導入並生成接口。這裏直接拖拽模型進入 Xcode,Xcode 會自動生成相應的機器學習模型接口。無需任何手動或其他操作,十分方便友好。美中不足的是生成的接口是固定的、無法增加定製化接口。

  3. 使用編程接口。根據生成的 API 進行編程。2017年 Core ML 模型只支持對單一對象進行預測,無法批量預測,運行效率比較低下。

可以說2017年推出的 Core ML 框架十分易用,但其功能也十分簡陋。開發者們只能在一開始模型生成上做定製化操作,且很有可能要依賴第三方框架。之後只能使用 Core ML 生成的固定模型進行編程,十分侷限:無法優化預測效率、無法精簡尺寸、無法增加新的層級、無法自定義模型。

針對這些缺陷,蘋果在今年的 Core ML 2.0 上做出瞭如下改進——更小。更快。高度定製化。

新功能

Core ML 這次的新功能主要在於模型的接口生成新增了一個可以批量預測的 API。下面代碼展示了原來的 API 和 新的 API:

// 預測單一輸入
public func prediction(from: MLFeatureProvider,
options: MLPredictionOptions) throws -> MLFeatureProvider

// 預測多個輸入
public func predictions(from: MLBatchProvider,
options: MLPredictionOptions) throws -> MLBatchProvider

以前需要用 for 循環完成的操作現在可以用一個方法完成。不進如此,新的批量預測方法相對於 for 循環嵌套單一預測的實現,還用了 batch 進行優化。

原來的 for 循環單一預測方法需要完整地讀入每一個數據,將其預處理後發送給 GPU,GPU 計算完畢後再把結果從 GPU 中取出並在程序中輸出結果。新的批量預測方法則是消除了預處理和取出的操作,將所有數據一次性發給 GPU,利用 GPU Pipeline 將其逐個計算的同時依次取出結果。另外因爲 GPU 一直在運算狀態,GPU 可以對計算進行統一優化,使得相似數據的處理越來越快。這樣整體的性能就要快上不少,具體邏輯如下圖所示:

蘋果當場展示了兩種方法之間的效率之差:處理40張圖片,新的批量預測方法比 for 循環的單一預測方法比要快將近5秒鐘,效率上幾乎提高了一倍。

除此之外,Core ML Tools 增加了第三方機器學習框架數量,從原來的6個增加到了11個,包括了最知名的 TensorFlow、IBM Watson、MXNet,數量和質量都有大幅提升。

性能優化

性能優化是 Core ML 的重頭戲,蘋果宣稱 Core ML 2 的速度提高了30%。我們來看看蘋果做了哪些工作:

  • 量化權重。Core ML 的模型可以根據需求對權重進行量化。權重越低,模型尺寸越小,運轉速度越快,佔用內存資源也就越少,但是處理效果也就越差。

  • 多尺寸支持。針對圖片處理,Core ML 現在只需一個模型,就能處理不同分辨率的圖片。相對於之前單一分辨率圖片的模型,該模型更加靈活,且因爲在底層大量共享代碼,使得模型的體積也遠遠小於原來多個單獨模型體積之和。

我們來重點看下量化權重。2017年時 Core ML 的所有模型權重都是32位,也就是說每個模型可以識別 2^32 個不同的特徵值。這雖然帶來了非常之高的準確度,但同時也使得 Core ML 模型非常之大(20+M)。對於 App 開發來說,尺寸大小是非常值得注意的因素。借鑑 App Thinning 的思路,蘋果針對 Core ML 的模型大小進行了優化。現在開發者可以使用 Core ML Tools 對原來32位權重的模型進行量化,根據需要,蘋果支持16位、8位、4位等權重。權重越低。模型尺寸越小,運轉速度越快,但是處理效果也就越差。所以還是要根據實際需求進行選擇,下圖中我們可以看到不同模型尺寸和處理效果的對比。

在權重量化上我們可以針對需求做出最小體積的模型;同時針對多尺寸圖片我們可以合併多個類似功能的模型;同時 Core ML Tools 又提供了自由定製權重的 API。在多重措施的優化之下,Core ML 的模型可以最大限度的縮小尺寸,從而帶來更合適的加載和運算效率。

定製化

蘋果在定製化方面推出了兩種方案:定製化神經網絡層和定製化模型。我們先來看定製化神經網絡層。

很多 Core ML 模型的內部實現是多層神經網絡,每一層接受上一層的輸入,然後做出相應處理再將結果輸出給下一層。例如,識別照片中動物是馬的過程如下圖所示:

這個神經網絡每一層都是固定的、由 Core ML 框架自動生成並優化,我們不能做任何操作。這使得模型的功能大大受到侷限:試想我們如果要基於上述模型生成一個新模型,使得該模型不僅能識別馬,還能識別鳥、魚、貓、狗等各種動物,最簡單的做法就是將上述模型中判別動物是馬的層級給替換掉。Core ML 2 現在提供了這種功能,具體操作步驟是:

  1. 獲取生成含有特定的層級的模型。一般獲取方法是依靠第三方神經網絡庫,比如 Keras。
  2. 用 Core ML Tools 將含有特定層級的模型轉化成對應的 Core ML 模型。這其中我們要自定義特殊層轉化方法。具體代碼如下:
# 用 keras 神經網絡庫生成模型,其中特殊層爲 GridSampler
model = keras.model.load_model('spatial_transformer_MNIST.h5', custom_object: {'GridSampler': GridSampler})

# 自定義 Core ML 模型中對應特殊層 GridSampler 的轉化方法
def convert_grid_sampler(keras_layer):

  params = NerualNetwork_pb2.customLayerParams()

  # 定義名稱和描述
  params.className = 'AAPLGridSampler'
  params.description = 'Custom grid sampler layer for the spatial transformer network'

  # 定義層級參數,這裏我們只要處理圖片的長和寬
  params.parameters["output_height"].intValue = keras_layer.output_size[0]
  params.parameters["output_width"].intValue = keras_layer.output_size[1]

  return params

# 用 Core ML Tools 將 Keras 模型轉化,其中特定層 GridSampler 的轉化方法定義爲 convert_grid_sampler
coreml_model = coremltools.converters.keras.convert(model, custom_conversion_functions = {'GridSampler': convert_grid_sampler})
  1. 將 Core ML 模型導入 Xcode 中,自定義特殊層的接口。其對應類務必實現 MLCustomLayer 協議,它是自定義神經網絡層的行爲協議,每個方法的具體解釋可以參照蘋果的官方文檔:MLCustomLayer
public protocol MLCustomLayer {
  public init(parameters: [String : Any]) throws

  public func setWeightData(_ weights: [Data]) throws

  public func outputShapes(forInputShapes: [[NSNumber]]) throws -> [[NSNumber]]

  public func evaluate(inputs: [MLMultiArray], outputs: [MLMultiArray]) throws
 }

同時,上文中提到的GridSampler的具體實現如下圖:

當然並不是所有模型的實現都是神經網絡。所以蘋果還推出了定製化模型。實現一個定製化模型的方法十分簡單,就是實現 MLCustomModel協議:

public protocol MLCustomModel {
  public init(modelDescription: MLModelDescription, parameters: [String : Any]) throws
  
  public func prediction(from: MLFeatureProvider,
options: MLPredictionOptions) throws -> MLFeatureProvider
 
  optional public func predictions(from: MLBatchProvider,
options: MLPredictionOptions) throws -> MLBatchProvider
}

其具體說明亦可以參考蘋果官方文檔

總結

Core ML 2 在2017年的基礎上增加了新功能,同時對模型大小和運轉效率進行了相應優化。其配套工具 Core ML Tools 也增加了可支持的機器學習框架,同時開發者可以藉助工具自定義神經網絡層和 Core ML 模型。除此之外,蘋果推出的 Create ML 也極大地解決了模型獲取方面的侷限。目前 Core ML 已經深度應用於 Siri、Photos、QuickType 等原生應用上,採用 Core ML 的第三方應用也多達182個,相信在不久的將來,Core ML 會成爲所有主流 App 的標配。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章