跟香蕉君一起舞♂蹈

原文:Background removal with deep learning

翻譯:HW_哈威

校對:Kaiser

本文首發在集智專欄:深度學習帶你摳像表演 - 集智專欄

本文描述了我們在greenScreen.ai方面的工作與研究。我們很樂意傾聽你的建議與評價!

前情

回顧這些年機器學習的進展,我也一直想弄點真正的機器學習產品。

幾個月前,我參加了超棒的Fast.ai深度學習課程之後,我好像就開竅了,我也有了機會:得益於深度學習技術,很多以前不可想像的事情,現在都已不在話下。新開發的工具也使得部署進程比以往更方便。

在之前提到過的課程里,我遇到了Alon Burg,他是位富有經驗的Web開發者,我們在合作以求實現這個目標。

我們一同給自己設立了以下目標:

  1. 提高我們自身的深度學習技巧
  2. 提高我們AI產品的部署技巧
  3. 製作一款有市場需求的實用產品
  4. 要有趣(對我們倆和使用者都是)
  5. 分享我們的經驗

考慮到以上目標,我們正在探索的點子如下:

  1. 還沒人做過的(或者還沒人做好的)
  2. 計劃與實施起來不會太難的——我們的計劃是用2-3個月的時間完成,以及每周只有一個工作日的負荷。
  3. 簡潔走心的用戶界面——我們想做一款讓人們願意用,而不是僅僅用作展示的產品
  4. 訓練數據什麼的一應俱全——正如任何機器學習從業者所知,有時數據比演算法更寶貴。
  5. 會使用前沿的深度學習技術(谷歌、亞馬遜及其雲平台夥伴目前仍未將其商業化),但又不那麼過於前沿(這樣我們就能在網上找到一些例子啦)
  6. 會有潛力達到「可以商品化」這個級別。

我們的早期想法是試試醫療項目,但因為這個領域與我們息息相關,然後我們那時感覺(現在也感覺)在醫療領域短期內就會被深度學習顛覆。但是,我們也意識到我們會碰上數據收集的問題,這或許會涉及合法性及法律法規等問題,而這並不符合我們想要讓成果簡化這一目標。我們的第二選擇就是摳圖產品了。

背景移除是手動或半手動操作起來都很簡單的任務(Photoshop,甚至PowerPoint都有這類工具),用某種虛擬「馬克筆」和邊緣檢測就可以實現,這裡有個例子 。但是,全自動摳像就很有挑戰性了,而且就我們所知,雖然已經有人在嘗試,但目前還沒有出現令人滿意的產品。

我們會移除什麼樣的背景呢?這還真是個重要的問題,因為在一群對象、角度及其他因素中的目標越具體,剝離的質量就會越高。當我們開始著手工作時,我們的野心很大:一個適用於各類圖片的綜合性摳像神器。但在我們完成對首個模型的訓練後,我們明白,最好還是專註於特定類型的圖片。因此我們決定的圖片類型是自拍與人像。

熏肉味的笑容

自拍就是有著顯著和集中的前景(一個或更多人),可以保證我們可以順利使之與其他對象(臉+上身)和背景分離,以及有著相當恆定的角度,也總是含有相同的對象(人)。

基於這些假設,我們開始了研究、實施、訓練的旅程, 來創造一個簡單易用的背景去除工具,只需一鍵點擊。

我們工作的主要內容就是對整個模型進行訓練,但我們也不能低估妥善部署的重要性。好的分離模型仍然不如分類模型那樣簡潔(比如 SqueezeNet),而且我們也主動檢查了伺服器和瀏覽器的部署選項。

如果你想了解更多關於我們產品的部署過程的細節,歡迎閱讀我們關於服務端和客戶端的文章。

如果你想了解該模型及其訓練過程,那就接著往下看吧。

語義分割Semantic Segmentation

當檢測和我們類似的深度學習和計算機視覺任務時,很容易看出,我們的最佳選項就是邏輯語義分割任務了。

其他的策略,比如景深檢測分離 ,但對我們來說還不夠成熟。

語義分割是個廣為人知的計算機視覺任務,與分類及對象檢測共佔3甲地位。分割,實際上就是一種分類任務,在該意義上,將每一個像素都進行分類。不像圖像分類或檢測,分割模型真的會展現出一些對圖像的「理解」,不只是能識別出「這個圖裡有隻貓」這樣的程度,而是在像素級別上識別出這隻貓是哪裡的哪個。

所以,這種分割是如何生效的呢?為了更好地理解,我們將會檢驗本領域的一些早期成果。 早期想法是採用一些早期分類網路,比如 VGGAlexnet 。VGG 是2014年圖像分類領域最先進的模型,因其簡單直接的架構,即使在今天也很實用。當檢查VGG的前幾層時,我們或許會發現在分類目標的周圍激活程度很高,以用於分類。更深的層甚至擁有更強的激活程度,然而由於重複的池化行為,它們本質上卻是粗糙的。現在懂了這些,我們假設分類訓練也可以被用於在伴有調整的狀況下進行尋找/分割對象。

語義分割的早期成果是與分類演算法融合的。在這篇文章中,你可以看到更多來自使用VGG的粗糙的分割結果:

上車,走吧

深層結果:

淺紫色是校車

經過雙線性上採樣之後:

這些結果僅來自於將完全連接的層轉換(或維護)為原始形狀,保持其空間特徵,獲得完全的卷積網路。在上面的例子中,我們把一張7681024的圖片輸入VGG,然後得到一層24321000的圖像。2432 是合併版本的圖像(by 32),而1000是圖像網路類別數。從中我們可以導出上述分割。

為了讓預測更加精細,研究者們使用了未經處理的雙線性插值層。

在這篇FCN論文中,研究者們改進了以上思路。他們將一些層連在了一起,使得解讀更加豐富,根據向上採樣率分別命名為FCN-32,FCN-16,和FCN-8:

在層之間添加一些跨層連接可使預測從原始圖像編碼出更完整的細節。進一步的訓練甚至提高了成果。

該技術本身並不像我們以前所認為的那麼糟糕,並且證明了其在深入學習中語義分割方面確實很有潛力。

來自論文的FCN 結果

FCN解鎖了分割的概念,研究者們也為該任務嘗試不同的架構。主要的思路還是相似的:使用已知的架構、向上分析、然後使用跨層連接,在較新的模型中依然是這個套路。

你可以在這裡找到關於該領域的新進展:here, here and here。你也可以找到很多保留編碼-解碼架構的架構。

回到我們的項目上來

在做過一些研究之後,我們確定了適用於我們項目的三個模型:FCN, Unet和Tiramisu?——它們都有深層次的編碼-解碼架構。我們也對mask-RCNN有些意向,但實施起來好像和我們的項目目標不太一致。

FCN 看起來並不相關,因為其結果比我們想像的差一些(即便是初試期),但我們提到的另外兩個模型給出的結果還不錯:在 CamVid 數據集上的 Tiramisu ,以及 Unet 的主要優勢是其緊湊性和速度。在實施方面,Unet 很直接地就實現了(我們用的是Keras),而Tiramisu 也是可實施的。為了啟動我們的項目,我們在傑里米·霍華德(Jeremy Howard)強大的深度學習課程的最後一課中使用了Tiramisu進行了一次很好的實現。

有了這兩個模型,我們得以繼續前進並開始在一些數據集上進行訓練。不得不說,在第一次試用Tiramisu後,我們發現其結果對我們而言擁有更多潛力,因為它擁有捕獲圖片中鋒利邊緣的能力。另一方面,Unet看起來就不夠優秀,結果看上去也不太OK。

Unet 的不OK


數據

在設定了我們模型的總體方向後,我們開始尋找合適的數據集。分割數據並不像分類甚至檢測那樣常見。另外,手動標記也真的不太做得來。最常見的適合分割的數據集是 COCO 數據集,其中包括大概90個類別的8萬張圖像,還有包含20個類別的1萬1千張圖像的 VOC pascal 數據集,以及更新的 ADE20K 數據集。

我們選擇用COCO數據集,因為它包含了非常多帶有「人」這個分類的圖像,正好符合我們的目標。

考慮到我們的任務,我們考慮是否僅使用那些和我們相關性較強的圖像,還是要使用相對來說更加綜合的數據集。一方面,使用圖片更多、分類更多的更綜合的數據集會讓模型見識更多,處理更多挑戰。另一方面,在連夜的訓練進程中,我們能夠處理超過~15萬張圖像。如果我們繼續引入包含整個COCO 數據集的模型,我們將可以讓模型(平均)檢視每張圖像兩次,因此做出一點修改還是有些額外的好處的,這會讓模型更加專註於我們的目標。

還有一件值得一提的事——Tiramisu模型原本是在 CamVid 數據集上進行訓練的,有一些缺陷,但最重要的是,那些圖像非常單一:全部圖像都是汽車的路拍。這就很好理解了,從這樣的數據集(即使裡面包含人)中進行學習對我們的任務來說毫無益處,所以在簡短的試驗之後,我們就上道了。

CamVid 數據集的圖像

COCO 數據集帶來了非常直接的 API,使得我們可以準確獲知每張圖片上都有什麼物體(根據已有的90個預分類)。

在進行一些實驗後,我們決定要稀釋這些數據集:首先我們篩選出了其中只包含1個人的圖像,大概是4萬張。接著我們選出了包含多於1個人的圖像,然後只剩下一兩張,這就是我們的模型應該找出來的。最後,我們只留下了那些20%-70% 的標記為「人」的圖像,去除了背景中包含很小的人或是其他迷之生物(很不幸,並沒有排查完全)的圖像。我們最終的數據集包含了1萬1千張圖片,在本階段夠用了。

左:好圖——中:人物較多——右:對象太小


Tiramisu 模型

就像剛才說的,我們在Jeremy Howard』s的課程中接觸了 Tiramisu 模型。雖然它的全稱「100層Tiramisu」意味著它是個巨大的模型,有9百萬的參數,但和擁有1億3千萬參數的VGG16比起來還是蠻經濟的。

Tiramisu模型基於DensNet,是最新的圖像分類模型,所有的層都是互聯的。此外,Tiramisu像Unet一樣給向上採樣層加入了跨層連接。

如果你能回想起來,這種架構與FCN中提出的想法是一致的:為了精細度而使用分類架構、向上識別以及加入跨層連接。

Tiramisu整體架構

DenseNet 模型可被視作Resnet模型的一種自然進化版,但並不是在有新的層進來之後「記住」每一層,Densenet會記住模型中所有的層。這些連接被稱為高速路連接。它會導致濾波器數量增長,這被定義為「增長率」。Tiramisu擁有16的增長率,因此每一層都會增加16個新的濾波器,直到達到1072個濾波器。你或許在想,因為是100層的Tiramisu,所以應該會有1600層吧?但是,向上識別層會丟棄一些濾波器。

Densenet模型草圖——淺層濾波器在整個模型中堆疊

訓練

我們採用原論文所述的時間表訓練我們的模型:標準交叉熵損失,有1e-3學習率和小規模衰減的RMSProp優化器。我們把1萬1千張圖像分為70% 用於訓練,20% 用於驗證,10%用於測試。以下全部圖像都來自我們的測試組。

為了讓我們的訓練進度與原論文保持一致,我們在500張圖像上設置了時間段大小。因為我們已經用更多數據對其進行了訓練(本文中使用的CamVid 數據集包含了不到1千張圖片),這使得我們可以在一段時間裡用結果中的每個改進來對模型進行積累。

另外,我們只在兩個類別上對其進行訓練:背景與人,當然原論文里包含了12個分類。我們首先嘗試在COCO的類別上進行訓練,但我們發現這對訓練來說幫助不大。

數據問題

一些數據集的缺陷妨礙了我們的核心:

  • 動物——我們的模型有時會分割出動物。這當然要歸咎於比較低的IOU。在我們任務中同樣的主要分類里加入動物或其他對象,或許會移除我們的結果。
  • 身體部位——因為我們程序化地過濾數據集,使得我們無法分辨「人」這個分類到底是「人」還是像手或腳這樣的身體部位。這些圖像不在我們的目標範圍里,但依然會出現在各種地方。

動物、身體部位,手持物體

  • 手持物體——數據集中的許多圖像都是運動相關的。棒球棒、網球拍和滑雪板到處都是。這樣的話模型就會懵X,不知究竟該如何分割這些對象。比如在這個有動物的圖裡,將其加入作為主類的一部分或者單獨的類別在我們看來將有助於模型的表現。

包含物體的運動圖片

  • 粗劣的正確標記??——COCO數據集並不是逐個像素注釋的,而是用多邊形。有時這就足夠了,但其他時候參考標準就十分粗劣,很可能會阻礙模型從細節中學習。

圖像和(非常)粗劣的正確標記

他可能會遲到,但不會缺席。

成果

我們的成果雖然還達不到特別完美,但還是比較令人滿意的:我們已經在測試組中達到了84.6的IoU,目前的狀態則是85。但這個數字很狡猾:它會在不同的數據集和分類中產生波動。這裡有些本來就很容易分割的類別,比如房屋、道路等,大多數模型都能輕易達到90 IoU的結果。其他更有挑戰性的類別就是樹木和人類了,在這些類別上,模型只能達到大概60 IoU。為了衡量這個困難,我們幫助網路專註於一個單一的分類,同時也限制了照片的類型。

我們仍然感覺我們還沒能達到之前期望的「可以商品化」的程度,但我們是時候該停下來,討論一下我們的成果了,因為已經有大概50%的照片可以給出不錯的結果了。

這裡是一些該程序所具備的能力的優秀例子:

調試和日誌記錄

訓練神經網路的一個重要部分就是調試。當我們著手我們的項目時,我們非常想直搗黃龍,搞來數據和網路、開始訓練,然後看看能出來什麼樣的成果。但是我們發現,跟蹤每一步動作,以及為我們自己製作可以檢測每一步結果的工具都至關重要。

這裡是一些常見的挑戰,以及我們是如何應對的:

  1. 早期問題——模型或許沒有經過訓練。或許是因為一些遺留問題,或者因為某類預處理錯誤,比如忘記將一些數據標準化。不管咋說,將結果簡單地可視化會非常有幫助。這裡有一篇關於這個主題的[好文章]。

2.調試網路自身——?在確保沒有嚴重問題後,就可以用預定義的損失和指標開始訓練了。在分割中,主要的測量指標就是IoU——交叉點結合。我們經過了好幾輪的訓練才開始使用 IoU 作為我們模型的主要測量指標(而不是交叉熵損失)。另一個有幫助的實踐,就是展示一些模型在每個時段的預測。這裡有一篇很棒的關於調試機器學習模型的文章。要記住,IoU 在Keras中不是一個標準的指標/損失,但你很容易就可以在網上找到,比如這裡。我們也使用這個行動 gist 來繪製每個時期的損失與一些預測。

3.機器學習版本控制——當訓練一個模型時會需要很多參數,其中有些很難跟蹤。我不得不說,除了熱切地編寫我們的配置(以及用Keras的召回功能自動保存最好的模型,見下文),我們依然沒能找到完美的方法。

4.調試工具——在做完上述全部之後,我們終於可以檢驗我們的每一步工作了,但那並不是無縫銜接的。因此,最重要的一步是將上述步驟結合在一起,並創造一個Jupyter 筆記本,這樣我們就可以無縫載入每個模型與每個圖像,並快速檢測其結果。通過這種方式我們可以簡單地看出模型間的區別、缺陷和其他問題。

這是我們模型在調整參數和額外的訓練時改進的例子:

用目前最好的驗證IoU來保存模型:(Keras提供了一個非常好的召回功能 callbacks 讓這些事情變得更加簡單)

callbacks = [keras.callbacks.ModelCheckpoint(hist_model, verbose=1,save_best_only =True, monitor= 』val_IOU_calc_loss』), plot_losses]

除了對可能的代碼錯誤進行正常調試外,我們也注意到了模型錯誤是「可預測的」,比如 「切掉」 身體部分似乎超出了總體的身體計數、在大片分割上的「缺塊」、不必要地延續身體部位、照明差、質量差、以及很多細節。其中一些注意事項在添加特定的來自不同數據集的圖像時會被處理,但其他的就有待解決了。為了改進下一個版本的結果,我們將對模型使用特定於「困難」圖像的擴充。

我們之前已經提到過這個問題了,即數據集的問題。現在來看看我們模型遇到的困難:

  1. 衣物——顏色要麼很深要麼很淺的衣服有時傾向於被解讀為背景
  2. 「缺塊」——從另一個角度看,有一些缺塊也不錯

衣物與缺塊

  1. 光線——光線的缺乏和模糊在圖像中很常見,但在COCO 數據集中不是。因此,除了模型處理這些問題的一般困難外,我們的模型甚至還不能處理更難的圖像。這個可以通過獲得更多的數據,另外也可以通過數據增加來改進。與此同時,也盡量別在晚上測試我們的應用 :)嘻嘻嘻

--

展望前景

進一步訓練

我們的產品成果經過了~300個時段的數據訓練。在這段時間後,模型開始過擬合。我們已經達到非常接近可發布狀態的結果了,因此我們還沒有機會應用數據擴充的基本實踐。

在將圖像調整到224X224後我們也訓練過模型了。用更多數據和更大的圖像(COCO圖像的原始大小大概是600X1000)進行進一步的訓練預計也會對成果有所提升。

CRF 和其他增強

在某些階段,我們發現我們的成果在邊緣部分有些不平整。一個可以對這一點進行改進的模型就是CRF了。在這篇博文中,作者展示了略微無修正地使用CRF的例子。

但是,這對我們來說幫助不大,也許是因為只有結果更粗糙時才會有總體上的效果。

Matting

即使以我們的當前成果來看,分割也不是那麼完美。頭髮、精美的衣服、樹枝和其他精細的對象也許還無法被完美地分割開來,因為參考標準的分割也不包含這些細節。分離這種細微分割的任務叫做Matting,並定義了一種不同的挑戰。這裡是一個最先進的Matting的例子,今年早些時候發表於英偉達大會。

Matting示例——輸入也包括三分圖

Matting任務不同於其他圖像相關的任務,因為它的輸入不僅包括圖片,也包括了一張三分圖?——?圖像邊緣的輪廓,使其成為了一個「半監督」問題。

我們用Matting實驗了一下,使用我們的分割作為三分圖,但我們沒能取得重大成果。

還有一個問題就是缺少適當的用於訓練的數據集。

總結

正如開頭所說,我們的目標是製作一款出色的深度學習產品。正如你在 Alon 的文章里看到的,部署變得比以往更加簡單更加快速。另一方面,訓練一個模型又很棘手——訓練,尤其是要求徹夜完成時,就需要縝密的計劃、調試和結果記錄。

要平衡研究與嘗試新事物之間也不簡單,還有無聊的訓練與改進。自從我們使用了深度學習,我們總有一種感覺,就是我們需要的最好的模型,或者最準確的模型,就近在咫尺,再谷歌搜索一下或者再看一篇文章就找到了。但在實踐中,我們真正的改進卻是來自於簡單地從我們的原始模型里往外「擠」出更多東西。也正如之前所說的,我們仍然感覺可以擠出更多東西來。

做個總結,我們在做這些事情時超開心的,之前的幾個月對我們而言就像科幻小說一般。我們會開心地討論並回答任何問題,也很期待你訪問我們的網站 :)

推薦閱讀

推薦閱讀:是直是彎?爆照判斷 - 集智專欄

課程免費體驗:深度學習的理論基礎 - 集智課堂 深度學習之Hello World - 集智課堂


推薦閱讀:

《Deep Layer Aggregation》論文筆記
圖像的信噪比是個什麼概念?怎麼算的?
對圖像進行顏色識別時,如何解決攝像頭偏色的問題?
圖普科技是一家怎樣的公司?
matlab對圖像進行濾波,濾波器應該是個幾乘幾的矩陣?

TAG:集智https:jizhiim | 图像处理 | 图像识别 |