滴滴開源了一個終端側 AI 集成運行時環境(IRE)—— AoE(AI on Edge)。AoE 以 「穩定性、易用性、安全性」 為設計原則,可以幫助開發者將不同框架的深度學習演算法輕鬆部署到終端高效執行。
滴滴之所以要做這樣一個運行時框架,原因有兩個:
一是隨著人工智慧技術快速發展,這兩年湧現出了許多運行在終端的推理框架,在給開發者帶來更多選擇的同時,也增加了將 AI 布署到終端的成本;
二是通過推理框架直接接入 AI 的流程比較繁瑣,涉及到動態庫接入、資源載入、前處理、后處理、資源釋放、模型升級,以及如何保障穩定性等問題。
根據介紹,當前有以下 8 種終端運行的主流推理框架:
從本質上來說,無論是什麼推理框架,都必然包含初使化、前處理、執行推理、后處理、釋放資源這 5 個處理過程,對這些推理過程進行抽象,是 AoE 支持各種推理框架的基礎。目前 AoE 實現了對兩種推理框架 NCNN 和 TensorFlow Lite 的支持。
具體來說,AoE 集成運行環境最基本的便是抽象推理操作,通過依賴倒置的設計,使得業務只依賴 AoE 的上層抽象,而不用關心具體推理框架的接入實現。這種設計帶來的最大的好處是開發者隨時可以添加新的推理框架,而不用修改框架實現,做到了業務開發和 AoE SDK 開發完全解耦。
在 AoE SDK 中這一個抽象是:
InterpreterComponent:用來處理模型的初使化、執行推理和釋放資源。
Convertor:用來處理模型輸入的前處理和模型輸出的后處理。
InterpreterComponent 具體實現如下:
/** * 模型翻譯組件 */ interface InterpreterComponentextends Component { /** * 初始化,推理框架載入模型資源 * * @param context 上下文,用與服務綁定 * @param modelOptions 模型配置列表 * @return 推理框架載入 */ boolean init(@NonNull Context context, @NonNull ListmodelOptions); /** * 執行推理操作 * * @param input 業務輸入數據 * @return 業務輸出數據 */ @Nullable TOutput run(@NonNull TInput input); /** * 釋放資源 */ void release(); /** * 模型是否正確載入完成 * * @return true,模型正確載入 */ boolean isReady(); }
Convertor 的具體實現如下:
interface Convertor{ /** * 數據預處理,將輸入數據轉換成模型輸入數據 * * @param input 業務輸入數據 * @return 模型輸入數據 */ @Nullable TModelInput preProcess(@NonNull TInput input); /** * 數據后處理,將模型輸出數據轉換成業務輸出數據 * * @param modelOutput 模型輸出數據 * @return */ @Nullable TOutput postProcess(@Nullable TModelOutput modelOutput); }
AoE 還有另一個特性是具有穩定性保障。眾所周知,Android 平台開發的一個重要的問題是機型適配,尤其是包含大量 Native 操作的場景,機型適配的問題尤其重要,一旦應用在某款機型上面崩潰,造成的體驗損害是巨大的。
有數據表明,因為性能問題,移動 App 每天流失的活躍用戶佔比 5%,這些流失的用戶,6 成的用戶選擇了沉默,不再使用應用,3 成用戶改投競品,剩下的用戶會直接卸載應用。因此,對於一個用戶群龐大的移動應用來說,保證任何時候 App 主流程的可用性是一件最基本、最重要的事。
結合 AI 推理過程來看,不可避免地,會有大量的操作發生在 Native 過程中,不僅僅是推理操作,還有一些前處理和資源回收的操作也比較容易出現兼容問題。為此,AoE 運行時環境 SDK 為 Android 平台上開發了獨立進程的機制,讓 Native 操作運行在獨立進程中,同時保證了推理的穩定性(偶然性的崩潰不會影響後續的推理操作)和主進程的穩定性(主進程任何時候不會崩潰)。
具體實現過程主要有三個部分:註冊獨立進程、異常重新綁定進程以及跨進程通信優化。
第一個部分,註冊獨立進程,在 Manifest 中增加一個 RemoteService 組件,代碼如下:
第二個部分,異常重新綁定獨立進程,在推理時,如果發現 RemoteService 終止了,執行 「bindService()」 方法,重新啟動 RemoteService。
@Override public Object run(@NonNull Object input) { if (isServiceRunning()) { ...(代碼省略)//執行推理 } else { bindService();//重啟獨立進程 } return null; }
第三個部分,跨進程通信優化,因為獨立進程,必然涉及到跨進程通信,在跨進程通信里最大的問題是耗時損失,這裡,有兩個因素造成了耗時損失:
傳輸耗時
序列化/反序列化耗時
相比較使用 binder 機制的傳輸耗時,序列化/反序列化佔了整個通信耗時的 90%。由此可見,對序列化/反序列化的優化是跨進程通信優化的重點。對比了當下主流的序列化/反序列化工具,最終 AoE 集成運行環境使用了 kryo 庫進行序列化/反序列。以下是對比結果,數據參考《各種 Java 的序列化庫的性能比較測試結果》。
目前 AoE SDK 已經在滴滴銀行卡 OCR 上應用使用,想更加清晰地理解 AoE 和推理框架、宿主 App 的關係,可以通過下面的業務集成示意圖來了解它:
已經開源的運行時環境 SDK 包括 Android 和 iOS 平台,此外 Linux 平台運行時環境 SDK 正在緊鑼密鼓地開發中,預計在 9 月底也會釋出。
詳情查看:
[admin
]