FFmpeg深度學習模塊2019年小結

FFmpeg是什麼,通俗的說,在看片子的時候,需要用到視頻播放器,而很多視頻播放器的底層用的就是FFmpeg。這是我在2019年在FFmpeg深度學習模塊中所做事情的總結,由於我在19年是這個模塊的主要貢獻者,所以,這個總結也差不多就是FFmpeg深度學習模塊的現狀總結了。

在2018年的時候,Pedro Arthur ([email protected])帶着學生Sergey Lavrushkin ([email protected])完成了一個GSoC項目,將TensorFlow引入FFmpeg,並且增加了一個超分辨率(super resolution)的video filer(vf_sr.c),來演示如何使用深度學習模型。

這裏簡單介紹一下GSoC,即Google Summer of Code,是Google公司贊助的項目,每年一次,到2020年將是第16次,用來鼓勵學生參與各種開源項目的實際代碼開發(不限於Google的開源項目,當然此項目也需要Google的同意),還有一定的經濟資助。如果你是學生身份,強烈建議儘量參加。

回到FFmpeg,在18年的時候,我參與了這個模塊的討論,當時我的想法是,支持各種深度學習框架的模型,根據傳入模型的類型,再調用相應的深度學習框架在後端加載執行。在今天事後來看,這個建議存在的一個問題是,有些深度學習框架沒有提供C接口(可能提供了C++接口),而FFmpeg社區要求使用C接口,這個問題我現在也還沒有解決方法。另外,我當時還建議把這個作爲單獨的模塊,或者起碼放在libavutil中,但是,最終還是放在了libavfilter目錄下面,因爲考慮到目前主要是被filter調用。

最後完成的代碼支持深度學習框架TensorFlow,FFmpeg可以接受TensorFlow的網絡模型文件(.pb),準備好輸入輸出後,再在後端調用TensorFlow的C庫文件加載並執行這個模型。另外,考慮到某些系統可能沒有TensorFlow,所以,在FFmpeg中增加了native cpu path的支持,即可以fallback到cpu path,這個native後端也定義了一套模型文件格式,即native model。爲什麼在native模式下不是直接接受.pb文件呢,因爲在不使用第三方庫(比如protobuf)的情況下解析加載pb文件也是挺麻煩的事情,需要很多的代碼支持,沒必要也不應該在FFmpeg中增加這樣的代碼。

由於其中不少代碼都是hard code形式寫死的,所以,我在2019年的時候,開始發patch來改進這裏的代碼,並且思考和實踐如何讓FFmpeg的用戶將深度學習的相關功能用起來。大致總結如下。

  • 調整了深度學習模塊的目錄結構

雖然我把這個寫在第一點,剛好可以順便先做一個框架性的介紹。但是,實際是在發了不少patch被社區初步信任後,才做的目錄調整,這也是參加開源社區工作的一個經驗,僅供參考。

原先所有的代碼文件都直接放在libavfilter目錄下面,考慮到支持native mode將會需要很多代碼,所以,在libavfilter目錄下創建了子目錄dnn,除了將dnn_interface.h這個接口文件繼續直接放在libavfilter目錄下,其他的dnn相關文件都被移到了dnn子目錄中,當然,基於dnn的filter文件還是直接在libavfilter目錄中。如下圖所示。
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-sJpVLRW9-1587431701089)(https://graph.baidu.com/resource/22267e493fadf4daff84301579486798.png)]

其中,vf_sr.c就是前面介紹的2018年GSoC完成的超分辨率filter;而去除雨點等功能的vf_derain.c則是劉歧(網名悟空,Steven Liu [email protected])帶着學生Xuewei Meng ([email protected])完成的GSoC2019項目;vf_dnn_processing.c是我做的基於dnn模型的一個通用的圖像處理filter,希望所有隻改變AVFrame內容的功能都可以用這一個filter來實現,目前已支持RGB和Gray等格式,而YUV相關格式的支持還在完成中;vf_dnn_analytic.c則是我設想中的filter,可以基於dnn模型從frame中提取一些信息,比如目標檢測、人臉識別等等,可能會擴展成多個不同用途的filter,初步計劃在2020年完成。

在libavfilter/dnn目錄下,目前有兩部分的內容,一是調用TensorFlow C library的接口層,二是實現native layer的代碼,如果以後有需要,還可以增加更多的深度學習框架的C庫支持。因爲DNN interface接口層的存在,dnn的實現和基於dnn的filter之間是解耦的。

我在2019年在FFmpeg中的主要工作,除了從頭開始支持ROI encoding外,就是從dnn filter到DNN interface再到dnn實現的全覆蓋。filter和dnn實現互爲表裏,相互促進,目前兩者都還處於比較初始的階段,我希望可以做好初始推動力的作用,使得兩者可以儘快形成良性循環正反饋,可以吸引更多的開發者和用戶參加進來,也歡迎您的參與!

  • 模型文件轉換的python腳本

在初始代碼中,native模型文件的生成方法,是根據相應的TensorFlow模型,手工一句句地寫代碼將模型導出到文件中。如果TF模型略有調整,也必須手工修改相應的代碼,再重新生成native模型文件。這樣的方法,無法擴展也不實用。所以,我寫了個python腳本,輸入是TF模型文件,輸出是native模型文件,並且在native模型文件中增加了文件頭和版本號等信息。這個腳本文件目前只支持當前FFmpeg支持的layer,需要繼續完善。

  • native layer代碼的重構

在原來代碼中,native模型的加載由一個函數完成,我將其拆分爲了一個入口函數和若干子函數,每個子函數對應一個layer的加載。在原來代碼中,所有nativer layer的執行函數放在一個文件中。我爲每個layer在libavfilter/dnn目錄下創建了一個新文件,對應的加載函數和執行函數都放在這個文件中,實現了不同layer之間在文件級別的隔離。在入口函數中,則用函數指針數組的方式來直接調用相應layer的函數,不使用if/else或者switch的方式,避免了大量的重複代碼。

所以,現在如果要修改某個layer的實現,只需要修改相應的一個文件即可,不太會造成side effect。如果要增加一個layer,則只需要增加一個新的代碼文件(.c和.h),然後註冊到函數指針數組中即可,也不會存在誤操作影響到已有代碼的功能。

  • 增加FATE測試

FATE (FFmpeg Automated Testing Environment) 是FFmpeg社區開發的自動化測試框架,要持續維護一個良好質量的軟件項目,快速的自動化測試(包括單元測試、迴歸測試等等)都是必不可少的看門人角色,非常重要。基於FATE框架,我爲每一個navier layer都增加了單元測試,以後有新的layer加入,只要依葫蘆畫瓢再增加就可以了。我也爲vf_dnn_processing增加了測試。由於當前native layer中的卷積層conv2d的性能不佳,所以,還無法爲vf_sr和vf_derain增加FATE測試,否則,耗時太久,反而影響了自動化測試的初始目的。

  • DNN interface接口調整

    • 在使用TF後端的時候,之前代碼要求模型的輸入變量的名字必須是x,輸出變量名字必須是y。我調整了接口,輸入輸出變量名字可以在filter層次指定。
    • 在使用native後端的時候,之前代碼將第一個layer的輸入作爲模型的輸入,將最後一個layer的輸出作爲模型的輸出。我增加了name的支持,可以通過name字符串來找到模型的輸入輸出變量,也使得行爲和TF一致。
    • 之前代碼假設模型的輸入輸出都是float32格式的數據。我調整了數據結構,使得float32和uint8格式都可以指定。
    • 將native模型的輸出變量從一個增加到了多個,以適合目標檢測等模型的要求。
    • 增加了一個查詢接口,在模型文件被加載後,FFmpeg就可以查詢模型的輸入格式,比如width、height、channel和format等信息,方便檢查模型文件是否正確,或者做一些諸如圖片縮放等預處理。
  • 增加了更多native layer的支持

爲了上述DNN接口層的調整,需要有實際的例子來表明這些調整是需要的,也爲了不產生regression問題,需要增加更多nativer layer。另外,從項目本身來說,增加更多的nativer layer以支持更多的深度學習模型,比如目標檢測等模型,也是題中應有之義。在19年下半年,帶了上海交大密歇根學院5位同學的本科畢業設計課程,增加了一些native layer的實現,但沒有upstream。

  • 爲native mode引入Operand的概念

在之前的代碼中,nativer layer是依次順序排列,第i層的輸出就是第i+1層的輸入,無法支持一個層的輸出作爲多個層的輸入,也不支持一個層的輸入來自多個層。增加了Operand操作數概念後,層和層之間用Operand連接,就可以實現這些分支合併功能。如何使得Operand更好的節約內存、減少內存拷貝,目前還只有想法,尚未代碼實現。

  • 已有代碼的一些bug的fix等

這部分工作,趙軍Jun Zhao ([email protected])、劉歧Steven Liu( [email protected])還有leozhang ([email protected])、Zhao Zhili ([email protected])等也做了不少貢獻。話說這樣的統計功能怎麼做啊,我是手工地肉眼看了一遍,大概率會遺漏什麼,,,如有漏人,請告訴我。

最後,感謝老闆的支持和社區的認可,我在2019年底成爲了FFmpeg深度學習模塊的maintainer。另外,我的大部分代碼都是Pedro Arthur ([email protected]) review的,在此也表示感謝。

以上內容是本人業餘時間興趣之作,限於水平,差錯難免,僅代表個人觀點,和本人任職公司無關。

本文首發於微信公衆號:那遁去的一

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